@adhdev/daemon-core 0.9.82-rc.456 → 0.9.82-rc.458

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 ? "49032ec6c48a0cbe6f122e2615088b38407712b6" : void 0) ?? "unknown";
413
- const commitShort = readInjected(true ? "49032ec6" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
414
- const version = readInjected(true ? "0.9.82-rc.456" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
415
- const builtAt = readInjected(true ? "2026-07-04T07:05:38.214Z" : void 0);
412
+ const commit = readInjected(true ? "690e14cc1bdb099a0c52d7fffef41329cc5b15b5" : void 0) ?? "unknown";
413
+ const commitShort = readInjected(true ? "690e14cc" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
414
+ const version = readInjected(true ? "0.9.82-rc.458" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
415
+ const builtAt = readInjected(true ? "2026-07-04T09:53:14.279Z" : void 0);
416
416
  cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
417
417
  return cached;
418
418
  }
@@ -1586,6 +1586,8 @@ function normalizeConfig(raw) {
1586
1586
  ideSettings: isPlainObject(parsed.ideSettings) ? parsed.ideSettings : {},
1587
1587
  providerSourceMode: resolveProviderSourceMode(parsed.providerSourceMode, parsed.disableUpstream),
1588
1588
  providerDir: asOptionalString(parsed.providerDir),
1589
+ registryUrl: asOptionalString(parsed.registryUrl),
1590
+ providerTarballUrl: asOptionalString(parsed.providerTarballUrl),
1589
1591
  updateChannel: parsed.updateChannel === "preview" ? "preview" : "stable",
1590
1592
  terminalSizingMode: parsed.terminalSizingMode === "fit" ? "fit" : "measured"
1591
1593
  };
@@ -3702,7 +3704,7 @@ function buildRulesSection(coordinatorCliType) {
3702
3704
  - **Verify via git, not source.** Use \`mesh_git_status\` to confirm side effects. Treat agent summaries as self-reports, not verification.
3703
3705
  - **Limit parallelism.** Start with 1\u20132 tasks; scale only on success. Never duplicate a session because \`mesh_read_chat\` shows no final message while tool/terminal activity is ongoing. This caps *concurrent* load \u2014 it does not mean serialize independent work: when a new, independent request arrives and there is headroom under \`maxParallelTasks\`, dispatch it right away rather than waiting for an in-flight task or a user nudge (read-only diagnosis especially, since it has no merge cost).
3704
3706
  - **Check history first.** Call \`mesh_task_history\` at session start to avoid duplicate work and inform recovery. On failure, read task history before retrying.
3705
- - **Sequence shared-base-moving merges.** Parallel dispatch is encouraged, but merging one worktree can advance another in-flight worktree's base \u2014 especially the oss submodule pointer \u2014 turning a clean fast-forward into a diverged rebase (patch-equivalence correctly blocks this). Before merging an in-flight worktree while siblings are also in flight, land in an intentional order, re-clone long-running worktrees from the advanced base, or expect to manually rebase + ff-only the laggards; merging an independent fix mid-flight can strand siblings into a rebase.
3707
+ - **Sequence shared-base-moving merges.** Parallel dispatch is encouraged, but merging one worktree can advance another in-flight worktree's base \u2014 especially a shared submodule pointer \u2014 turning a clean fast-forward into a diverged rebase (patch-equivalence correctly blocks this). Before merging an in-flight worktree while siblings are also in flight, land in an intentional order, re-clone long-running worktrees from the advanced base, or expect to manually rebase + ff-only the laggards; merging an independent fix mid-flight can strand siblings into a rebase.
3706
3708
  - **Converge branches.** After worktree tasks: refine/fast-forward, or classify as \`pushed_feature_branch_needs_merge\` / \`blocked_review\` / \`cleanup_candidate\` / \`not_mergeable\`. Clean up with \`mesh_remove_node\`.
3707
3709
  - **Refinery is config-driven.** \`mesh_refine_node\` must run validation from \`.adhdev/refine.{json,yaml,yml}\` or \`repo-mesh.refine.*\`. Heuristics are scaffolding only.
3708
3710
  - **Submodule reachability = publish-needed.** \`submodule_reachability_failed\` \u2192 classify as \`blocked_review\`, request user approval to push to submodule main, then rerun \`mesh_refine_node\`.
@@ -8929,11 +8931,15 @@ var worktree_bootstrap_config_exports = {};
8929
8931
  __export(worktree_bootstrap_config_exports, {
8930
8932
  MESH_WORKTREE_BOOTSTRAP_CONFIG_LOCATIONS: () => MESH_WORKTREE_BOOTSTRAP_CONFIG_LOCATIONS,
8931
8933
  MESH_WORKTREE_BOOTSTRAP_CONFIG_SCHEMA: () => MESH_WORKTREE_BOOTSTRAP_CONFIG_SCHEMA,
8934
+ SUBMODULE_DEFAULT_BRANCH_FALLBACK: () => SUBMODULE_DEFAULT_BRANCH_FALLBACK,
8932
8935
  WORKTREE_BOOTSTRAP_STALE_RUNNING_MS: () => WORKTREE_BOOTSTRAP_STALE_RUNNING_MS,
8933
8936
  computeStaleInputsDigest: () => computeStaleInputsDigest,
8934
8937
  evaluateWorktreeBootstrapState: () => evaluateWorktreeBootstrapState,
8938
+ getRegisteredSubmodulePaths: () => getRegisteredSubmodulePaths,
8939
+ getSubmoduleConfiguredBranches: () => getSubmoduleConfiguredBranches,
8935
8940
  isWorktreeBootstrapStaleRunning: () => isWorktreeBootstrapStaleRunning,
8936
8941
  loadMeshWorktreeBootstrapConfig: () => loadMeshWorktreeBootstrapConfig,
8942
+ resolveSubmoduleDefaultBranch: () => resolveSubmoduleDefaultBranch,
8937
8943
  runMeshWorktreeBootstrap: () => runMeshWorktreeBootstrap,
8938
8944
  shouldDeferDispatchForBootstrap: () => shouldDeferDispatchForBootstrap,
8939
8945
  validateMeshWorktreeBootstrapConfig: () => validateMeshWorktreeBootstrapConfig
@@ -8958,6 +8964,81 @@ function getRegisteredSubmodulePaths(workspace) {
8958
8964
  }
8959
8965
  return paths;
8960
8966
  }
8967
+ function getSubmoduleConfiguredBranches(workspace) {
8968
+ const branchesByPath = /* @__PURE__ */ new Map();
8969
+ try {
8970
+ const out = (0, import_node_child_process3.execFileSync)(
8971
+ resolveWin32Executable("git"),
8972
+ ["config", "--file", ".gitmodules", "--list"],
8973
+ { cwd: workspace, encoding: "utf8", timeout: 1e4, windowsHide: true }
8974
+ );
8975
+ const pathByName = /* @__PURE__ */ new Map();
8976
+ const branchByName = /* @__PURE__ */ new Map();
8977
+ for (const line of String(out).split(/\r?\n/)) {
8978
+ const trimmed = line.trim();
8979
+ if (!trimmed) continue;
8980
+ const eq = trimmed.indexOf("=");
8981
+ if (eq < 0) continue;
8982
+ const key2 = trimmed.slice(0, eq);
8983
+ const value = trimmed.slice(eq + 1).trim();
8984
+ const match = /^submodule\.(.+)\.(path|branch)$/.exec(key2);
8985
+ if (!match) continue;
8986
+ const name = match[1];
8987
+ if (match[2] === "path") {
8988
+ const norm = value.replace(/\\/g, "/").replace(/\/+$/, "");
8989
+ if (norm) pathByName.set(name, norm);
8990
+ } else if (value) {
8991
+ branchByName.set(name, value);
8992
+ }
8993
+ }
8994
+ for (const [name, submodulePath] of pathByName) {
8995
+ const branch = branchByName.get(name);
8996
+ if (branch && branch !== ".") branchesByPath.set(submodulePath, branch);
8997
+ }
8998
+ } catch {
8999
+ }
9000
+ return branchesByPath;
9001
+ }
9002
+ function isPlausibleBranchName(name) {
9003
+ return typeof name === "string" && name.length > 0 && !/\s/.test(name) && name !== "HEAD";
9004
+ }
9005
+ async function resolveSubmoduleDefaultBranch(opts) {
9006
+ const remote = opts.remote?.trim() || "origin";
9007
+ const localTimeout = opts.timeoutMs ?? 1e4;
9008
+ const git = resolveWin32Executable("git");
9009
+ const execFileAsync4 = (0, import_node_util3.promisify)(import_node_child_process3.execFile);
9010
+ if (opts.superprojectWorkspace && opts.submodulePath) {
9011
+ try {
9012
+ const normalized = opts.submodulePath.replace(/\\/g, "/").replace(/\/+$/, "");
9013
+ const configured = getSubmoduleConfiguredBranches(opts.superprojectWorkspace).get(normalized);
9014
+ if (isPlausibleBranchName(configured)) return configured;
9015
+ } catch {
9016
+ }
9017
+ }
9018
+ try {
9019
+ const { stdout } = await execFileAsync4(
9020
+ git,
9021
+ ["symbolic-ref", "--short", `refs/remotes/${remote}/HEAD`],
9022
+ { cwd: opts.submoduleRepoPath, encoding: "utf8", timeout: localTimeout, windowsHide: true }
9023
+ );
9024
+ const short = String(stdout || "").trim();
9025
+ const prefix = `${remote}/`;
9026
+ const branch = short.startsWith(prefix) ? short.slice(prefix.length) : short;
9027
+ if (isPlausibleBranchName(branch)) return branch;
9028
+ } catch {
9029
+ }
9030
+ try {
9031
+ const { stdout } = await execFileAsync4(
9032
+ git,
9033
+ ["ls-remote", "--symref", remote, "HEAD"],
9034
+ { cwd: opts.submoduleRepoPath, encoding: "utf8", timeout: Math.max(localTimeout, 3e4), windowsHide: true }
9035
+ );
9036
+ const match = /^ref:\s+refs\/heads\/(\S+)\s+HEAD/m.exec(String(stdout || ""));
9037
+ if (match && isPlausibleBranchName(match[1])) return match[1];
9038
+ } catch {
9039
+ }
9040
+ return SUBMODULE_DEFAULT_BRANCH_FALLBACK;
9041
+ }
8961
9042
  function isCleanIgnoringSubmoduleGitlinks(porcelain, submodulePaths) {
8962
9043
  const lines = porcelain.split(/\r?\n/).filter((line) => line.length > 0);
8963
9044
  for (const line of lines) {
@@ -9200,7 +9281,7 @@ async function runMeshWorktreeBootstrap(mesh, workspace) {
9200
9281
  }
9201
9282
  return state;
9202
9283
  }
9203
- var import_fs9, import_path8, import_node_child_process3, import_node_crypto2, import_node_util3, yaml3, WORKTREE_BOOTSTRAP_STALE_RUNNING_MS, MESH_WORKTREE_BOOTSTRAP_CONFIG_LOCATIONS, MESH_WORKTREE_BOOTSTRAP_CONFIG_SCHEMA, DEFAULT_TIMEOUT_MS2, DEFAULT_OUTPUT_LIMIT_BYTES, OUTPUT_SUMMARY_CHARS;
9284
+ var import_fs9, import_path8, import_node_child_process3, import_node_crypto2, import_node_util3, yaml3, WORKTREE_BOOTSTRAP_STALE_RUNNING_MS, SUBMODULE_DEFAULT_BRANCH_FALLBACK, MESH_WORKTREE_BOOTSTRAP_CONFIG_LOCATIONS, MESH_WORKTREE_BOOTSTRAP_CONFIG_SCHEMA, DEFAULT_TIMEOUT_MS2, DEFAULT_OUTPUT_LIMIT_BYTES, OUTPUT_SUMMARY_CHARS;
9204
9285
  var init_worktree_bootstrap_config = __esm({
9205
9286
  "src/mesh/worktree-bootstrap-config.ts"() {
9206
9287
  "use strict";
@@ -9213,6 +9294,7 @@ var init_worktree_bootstrap_config = __esm({
9213
9294
  init_resolve_executable();
9214
9295
  init_refine_config();
9215
9296
  WORKTREE_BOOTSTRAP_STALE_RUNNING_MS = 10 * 60 * 1e3;
9297
+ SUBMODULE_DEFAULT_BRANCH_FALLBACK = "main";
9216
9298
  MESH_WORKTREE_BOOTSTRAP_CONFIG_LOCATIONS = [
9217
9299
  ".adhdev/worktree_bootstrap.json",
9218
9300
  ".adhdev/worktree_bootstrap.yaml",
@@ -9829,15 +9911,24 @@ async function resolveSubmodulePushes(status, options, execute, timeoutMs) {
9829
9911
  results.push({ ...base, code: "submodule_status_incomplete" });
9830
9912
  continue;
9831
9913
  }
9914
+ const remoteBranch = await resolveSubmoduleDefaultBranch({
9915
+ submoduleRepoPath: repoPath,
9916
+ superprojectWorkspace: status.repoRoot ?? status.workspace,
9917
+ submodulePath: submodule.path,
9918
+ timeoutMs
9919
+ });
9920
+ base.remoteBranch = remoteBranch;
9921
+ const remoteRef = `refs/remotes/origin/${remoteBranch}`;
9922
+ const fetchRefspec = `refs/heads/${remoteBranch}:${remoteRef}`;
9832
9923
  try {
9833
- await runGit(repoPath, ["-c", "protocol.file.allow=always", "fetch", "origin", "refs/heads/main:refs/remotes/origin/main"], { timeoutMs: timeoutMs ?? 3e4 });
9924
+ await runGit(repoPath, ["-c", "protocol.file.allow=always", "fetch", "origin", fetchRefspec], { timeoutMs: timeoutMs ?? 3e4 });
9834
9925
  } catch (error) {
9835
9926
  results.push({ ...base, code: "submodule_fetch_failed", error: formatGitError2(error) });
9836
9927
  continue;
9837
9928
  }
9838
9929
  let alreadyReachable = false;
9839
9930
  try {
9840
- await runGit(repoPath, ["merge-base", "--is-ancestor", submodule.commit, "refs/remotes/origin/main"], { timeoutMs: timeoutMs ?? 15e3 });
9931
+ await runGit(repoPath, ["merge-base", "--is-ancestor", submodule.commit, remoteRef], { timeoutMs: timeoutMs ?? 15e3 });
9841
9932
  alreadyReachable = true;
9842
9933
  } catch {
9843
9934
  }
@@ -9846,20 +9937,20 @@ async function resolveSubmodulePushes(status, options, execute, timeoutMs) {
9846
9937
  continue;
9847
9938
  }
9848
9939
  try {
9849
- await runGit(repoPath, ["merge-base", "--is-ancestor", "refs/remotes/origin/main", submodule.commit], { timeoutMs: timeoutMs ?? 15e3 });
9940
+ await runGit(repoPath, ["merge-base", "--is-ancestor", remoteRef, submodule.commit], { timeoutMs: timeoutMs ?? 15e3 });
9850
9941
  } catch (error) {
9851
9942
  results.push({ ...base, pushed: false, skipped: false, code: "submodule_non_fast_forward", error: formatGitError2(error) });
9852
9943
  continue;
9853
9944
  }
9854
- const refspec = `${submodule.commit}:refs/heads/main`;
9945
+ const refspec = `${submodule.commit}:refs/heads/${remoteBranch}`;
9855
9946
  if (!execute) {
9856
9947
  results.push({ ...base, pushed: false, skipped: false, code: "submodule_push_available", refspec });
9857
9948
  continue;
9858
9949
  }
9859
9950
  try {
9860
9951
  await runGit(repoPath, ["push", "origin", refspec], { timeoutMs: timeoutMs ?? 3e4 });
9861
- await runGit(repoPath, ["-c", "protocol.file.allow=always", "fetch", "origin", "refs/heads/main:refs/remotes/origin/main"], { timeoutMs: timeoutMs ?? 3e4 });
9862
- await runGit(repoPath, ["merge-base", "--is-ancestor", submodule.commit, "refs/remotes/origin/main"], { timeoutMs: timeoutMs ?? 15e3 });
9952
+ await runGit(repoPath, ["-c", "protocol.file.allow=always", "fetch", "origin", fetchRefspec], { timeoutMs: timeoutMs ?? 3e4 });
9953
+ await runGit(repoPath, ["merge-base", "--is-ancestor", submodule.commit, remoteRef], { timeoutMs: timeoutMs ?? 15e3 });
9863
9954
  results.push({ ...base, pushed: true, skipped: false, code: "submodule_pushed", refspec });
9864
9955
  } catch (error) {
9865
9956
  results.push({ ...base, pushed: false, skipped: false, code: "submodule_push_failed", refspec, error: formatGitError2(error) });
@@ -10127,6 +10218,7 @@ var init_mesh_fast_forward = __esm({
10127
10218
  "use strict";
10128
10219
  init_git_status();
10129
10220
  init_git_executor();
10221
+ init_worktree_bootstrap_config();
10130
10222
  STATUS_OPTIONS = { refreshUpstream: true, includeSubmodules: true, timeoutMs: 15e3, forceFresh: true };
10131
10223
  }
10132
10224
  });
@@ -18500,6 +18592,9 @@ var init_approval_utils = __esm({
18500
18592
  });
18501
18593
 
18502
18594
  // src/logging/debug-config.ts
18595
+ function isAlwaysOnTraceCategory(category) {
18596
+ return !!category && ALWAYS_ON_TRACE_CATEGORIES.includes(category);
18597
+ }
18503
18598
  function normalizeCategories(categories) {
18504
18599
  if (!Array.isArray(categories)) return [];
18505
18600
  return categories.map((category) => String(category || "").trim()).filter(Boolean);
@@ -18529,17 +18624,19 @@ function resetDebugRuntimeConfig() {
18529
18624
  }
18530
18625
  function shouldCollectTraceCategory(category) {
18531
18626
  const config = currentConfig;
18627
+ if (isAlwaysOnTraceCategory(category)) return true;
18532
18628
  if (!config.collectDebugTrace) return false;
18533
18629
  if (!category) return true;
18534
18630
  if (config.traceCategories.length === 0) return true;
18535
18631
  return config.traceCategories.includes(category);
18536
18632
  }
18537
- var NORMAL_TRACE_BUFFER_SIZE, DEV_TRACE_BUFFER_SIZE, DEFAULT_CONFIG2, currentConfig;
18633
+ var NORMAL_TRACE_BUFFER_SIZE, DEV_TRACE_BUFFER_SIZE, ALWAYS_ON_TRACE_CATEGORIES, DEFAULT_CONFIG2, currentConfig;
18538
18634
  var init_debug_config = __esm({
18539
18635
  "src/logging/debug-config.ts"() {
18540
18636
  "use strict";
18541
18637
  NORMAL_TRACE_BUFFER_SIZE = 200;
18542
18638
  DEV_TRACE_BUFFER_SIZE = 1e3;
18639
+ ALWAYS_ON_TRACE_CATEGORIES = ["completion-gate", "fsm-transition"];
18543
18640
  DEFAULT_CONFIG2 = {
18544
18641
  logLevel: "info",
18545
18642
  collectDebugTrace: false,
@@ -24060,6 +24157,7 @@ var init_require_whitelist = __esm({
24060
24157
  // src/index.ts
24061
24158
  var index_exports = {};
24062
24159
  __export(index_exports, {
24160
+ ALWAYS_ON_TRACE_CATEGORIES: () => ALWAYS_ON_TRACE_CATEGORIES,
24063
24161
  AcpProviderInstance: () => AcpProviderInstance,
24064
24162
  AgentStreamPoller: () => AgentStreamPoller,
24065
24163
  BUILTIN_CHAT_MESSAGE_KINDS: () => BUILTIN_CHAT_MESSAGE_KINDS,
@@ -24291,6 +24389,7 @@ __export(index_exports, {
24291
24389
  installGlobalInterceptor: () => installGlobalInterceptor,
24292
24390
  interactivePromptFromClaudeAskUserQuestion: () => interactivePromptFromClaudeAskUserQuestion,
24293
24391
  isActivityChatMessage: () => isActivityChatMessage,
24392
+ isAlwaysOnTraceCategory: () => isAlwaysOnTraceCategory,
24294
24393
  isBuiltinChatMessageKind: () => isBuiltinChatMessageKind,
24295
24394
  isCdpConnected: () => isCdpConnected,
24296
24395
  isExtensionInstalled: () => isExtensionInstalled,
@@ -30689,6 +30788,35 @@ var DaemonCdpInitializer = class {
30689
30788
 
30690
30789
  // src/commands/handler.ts
30691
30790
  init_builders();
30791
+ init_config();
30792
+
30793
+ // src/config/registry-resolver.ts
30794
+ var DEFAULT_REGISTRY_BASE_URL = "https://api.adhf.dev/api/v1/registry";
30795
+ var DEFAULT_PROVIDER_TARBALL_URL = "https://github.com/vilmire/adhdev-providers/archive/refs/heads/main.tar.gz";
30796
+ var REGISTRY_URL_ENV_VAR = "ADHDEV_REGISTRY_URL";
30797
+ var PROVIDER_TARBALL_URL_ENV_VAR = "ADHDEV_PROVIDER_TARBALL_URL";
30798
+ function cleanString(value) {
30799
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
30800
+ }
30801
+ function stripTrailingSlashes(url) {
30802
+ return url.replace(/\/+$/, "");
30803
+ }
30804
+ function resolveRegistryBaseUrl(configuredUrl, env = process.env) {
30805
+ const resolved = cleanString(configuredUrl) ?? cleanString(env[REGISTRY_URL_ENV_VAR]) ?? DEFAULT_REGISTRY_BASE_URL;
30806
+ return stripTrailingSlashes(resolved);
30807
+ }
30808
+ function resolveProviderTarballUrl(configuredUrl, env = process.env) {
30809
+ return cleanString(configuredUrl) ?? cleanString(env[PROVIDER_TARBALL_URL_ENV_VAR]) ?? DEFAULT_PROVIDER_TARBALL_URL;
30810
+ }
30811
+ function resolveProviderTarballTarget(configuredUrl, env = process.env) {
30812
+ const url = resolveProviderTarballUrl(configuredUrl, env);
30813
+ const parsed = new URL(url);
30814
+ return {
30815
+ url,
30816
+ hostname: parsed.hostname,
30817
+ path: parsed.pathname + (parsed.search || "")
30818
+ };
30819
+ }
30692
30820
 
30693
30821
  // src/sessions/reconcile.ts
30694
30822
  function upsertSessionTarget(sessionRegistry, target) {
@@ -31004,7 +31132,7 @@ function createDebugTraceStore(options) {
31004
31132
  const capacity = Math.max(1, Math.floor(options.capacity || 100));
31005
31133
  return {
31006
31134
  record(event) {
31007
- if (!options.enabled) return null;
31135
+ if (!options.enabled && !isAlwaysOnTraceCategory(event.category)) return null;
31008
31136
  const entry = createEntry(event);
31009
31137
  entries.push(entry);
31010
31138
  if (entries.length > capacity) {
@@ -35586,7 +35714,7 @@ var DaemonCommandHandler = class {
35586
35714
  const https = require("https");
35587
35715
  const fs40 = require("fs");
35588
35716
  const path44 = require("path");
35589
- const REGISTRY = "https://api.adhf.dev/api/v1/registry";
35717
+ const REGISTRY = resolveRegistryBaseUrl(loadConfig().registryUrl);
35590
35718
  function fetchText(url, timeoutMs) {
35591
35719
  return new Promise((resolve25, reject) => {
35592
35720
  const req = https.get(url, { headers: { "User-Agent": "adhdev-daemon", "Accept": "application/json" }, timeout: timeoutMs }, (res) => {
@@ -35948,7 +36076,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
35948
36076
  const installed = this.handleListInstalledProviders({});
35949
36077
  if (!installed.success) return installed;
35950
36078
  const https = require("https");
35951
- const REGISTRY = "https://api.adhf.dev/api/v1/registry";
36079
+ const REGISTRY = resolveRegistryBaseUrl(loadConfig().registryUrl);
35952
36080
  function fetchJson(url) {
35953
36081
  return new Promise((resolve25, reject) => {
35954
36082
  const req = https.get(url, { headers: { "User-Agent": "adhdev-daemon", "Accept": "application/json" }, timeout: 1e4 }, (res) => {
@@ -37551,6 +37679,7 @@ var CHANNEL_SERVER_URL = {
37551
37679
  stable: "https://api.adhf.dev",
37552
37680
  preview: "https://api-preview.adhf.dev"
37553
37681
  };
37682
+ var VENDOR_SERVER_URLS = new Set(Object.values(CHANNEL_SERVER_URL));
37554
37683
  function normalizeReleaseChannel(value) {
37555
37684
  if (typeof value !== "string") return null;
37556
37685
  const normalized = value.trim().toLowerCase();
@@ -37572,7 +37701,11 @@ var daemonLifecycleHandlers = {
37572
37701
  const npmTag = CHANNEL_NPM_TAG[channel];
37573
37702
  const latest = String(execNpmCommandSync(["view", `${pkgName}@${npmTag}`, "version"], { encoding: "utf-8", timeout: 1e4 }, npmSurface)).trim();
37574
37703
  LOG.info("Upgrade", `Latest ${pkgName}@${npmTag}: v${latest}`);
37575
- updateConfig({ updateChannel: channel, serverUrl: CHANNEL_SERVER_URL[channel] });
37704
+ const currentServerUrl = typeof loadConfig().serverUrl === "string" ? loadConfig().serverUrl.trim() : "";
37705
+ const useVendorServerUrl = currentServerUrl === "" || VENDOR_SERVER_URLS.has(currentServerUrl);
37706
+ updateConfig(
37707
+ useVendorServerUrl ? { updateChannel: channel, serverUrl: CHANNEL_SERVER_URL[channel] } : { updateChannel: channel }
37708
+ );
37576
37709
  let currentInstalled = null;
37577
37710
  try {
37578
37711
  const currentJson = String(execNpmCommandSync(["ls", "-g", pkgName, "--depth=0", "--json"], {
@@ -38280,6 +38413,7 @@ function applyPreLaunchTrust(trust, workingDir) {
38280
38413
 
38281
38414
  // src/providers/spec/fsm-driver.ts
38282
38415
  init_logger();
38416
+ init_debug_config();
38283
38417
  init_pty_write_chunking();
38284
38418
  function countNewlines(s2) {
38285
38419
  let n = 0;
@@ -38348,6 +38482,11 @@ var FsmDriver = class {
38348
38482
  * (−1 = whole screen), or a `section:<id>` / `<region>#ignore:<pat>` string
38349
38483
  * when the clause scopes to a section or declares an ignore_lines filter. */
38350
38484
  regionLastChangedAt = /* @__PURE__ */ new Map();
38485
+ /** COMPLETION-EARLYNOTIFY stable-eval trace: last stable/not-stable verdict
38486
+ * recorded per stable region, so the trace fires only when the verdict FLIPS
38487
+ * (not every quiet frame). Cleared on every transition alongside
38488
+ * regionLastChangedAt. Diagnostic-only — never consulted by the FSM. */
38489
+ stableVerdictCache = /* @__PURE__ */ new Map();
38351
38490
  /** Timer that re-runs evaluate() when a time-condition would flip true
38352
38491
  * with no PTY frame to trigger it. */
38353
38492
  wakeTimer = null;
@@ -38683,6 +38822,7 @@ var FsmDriver = class {
38683
38822
  this.currentStateId = fired.to;
38684
38823
  this.stateEnteredAt = now;
38685
38824
  this.regionLastChangedAt.clear();
38825
+ this.stableVerdictCache.clear();
38686
38826
  this.pushHistory(fired.to, stateById(this.spec, fired.to)?.label ?? fired.to, {
38687
38827
  reason: "transition",
38688
38828
  via: `${from}\u2192${fired.to}`,
@@ -38787,6 +38927,7 @@ var FsmDriver = class {
38787
38927
  trackRegionChanges(currentLines, cursor, now) {
38788
38928
  if (this.prevScreenLines.length === 0) return;
38789
38929
  const descs = this.stableRegionDescriptors();
38930
+ const stableTraceOn = shouldCollectTraceCategory("fsm-transition");
38790
38931
  const needsSections = descs.some((d) => !!d.section);
38791
38932
  const curSections = needsSections ? resolveSections(this.spec.sections ?? {}, currentLines) : [];
38792
38933
  const prevSections = needsSections ? resolveSections(this.spec.sections ?? {}, this.prevScreenLines) : [];
@@ -38807,6 +38948,28 @@ var FsmDriver = class {
38807
38948
  const cur = filterIgnoredLines(curLines, d.ignoreRe).join("\n");
38808
38949
  const prev = filterIgnoredLines(prevLines, d.ignoreRe).join("\n");
38809
38950
  if (cur !== prev) this.regionLastChangedAt.set(d.key, now);
38951
+ if (stableTraceOn && typeof d.holdMs === "number") {
38952
+ const lastChanged = this.regionLastChangedAt.get(d.key) ?? this.stateEnteredAt;
38953
+ const ageMs = now - lastChanged;
38954
+ const verdict = ageMs >= d.holdMs;
38955
+ if (this.stableVerdictCache.get(d.key) !== verdict) {
38956
+ this.stableVerdictCache.set(d.key, verdict);
38957
+ recordDebugTrace({
38958
+ category: "fsm-transition",
38959
+ stage: "stable-eval",
38960
+ level: "debug",
38961
+ payload: {
38962
+ state: this.currentStateId,
38963
+ regionKey: String(d.key),
38964
+ ignorePattern: d.ignoreRe?.source ?? null,
38965
+ fingerprintLen: cur.length,
38966
+ ageMs,
38967
+ holdMs: d.holdMs,
38968
+ verdict
38969
+ }
38970
+ });
38971
+ }
38972
+ }
38810
38973
  }
38811
38974
  }
38812
38975
  /** Every distinct stable-region descriptor referenced by stable_ms
@@ -39322,7 +39485,8 @@ function collectStableDescriptors(when, byKey) {
39322
39485
  const w = when;
39323
39486
  if ("stable_ms" in w) {
39324
39487
  const key2 = stableRegionKey(w);
39325
- if (!byKey.has(key2)) {
39488
+ const existing = byKey.get(key2);
39489
+ if (!existing) {
39326
39490
  let ignoreRe;
39327
39491
  if (w.ignore_lines) {
39328
39492
  try {
@@ -39330,7 +39494,9 @@ function collectStableDescriptors(when, byKey) {
39330
39494
  } catch {
39331
39495
  }
39332
39496
  }
39333
- byKey.set(key2, { key: key2, section: w.section, cursor_above: w.cursor_above, ignoreRe });
39497
+ byKey.set(key2, { key: key2, section: w.section, cursor_above: w.cursor_above, ignoreRe, holdMs: typeof w.stable_ms === "number" ? w.stable_ms : void 0 });
39498
+ } else if (existing.holdMs === void 0 && typeof w.stable_ms === "number") {
39499
+ existing.holdMs = w.stable_ms;
39334
39500
  }
39335
39501
  return;
39336
39502
  }
@@ -41102,6 +41268,7 @@ function createCliAdapter(provider, workingDir, cliArgs, extraEnv, transportFact
41102
41268
 
41103
41269
  // src/providers/cli-provider-instance.ts
41104
41270
  init_logger();
41271
+ init_debug_config();
41105
41272
  init_mesh_event_trace();
41106
41273
  init_control_effects();
41107
41274
  init_approval_utils();
@@ -42175,9 +42342,10 @@ var CliProviderInstance = class _CliProviderInstance {
42175
42342
  return restoredHistory.messages;
42176
42343
  }
42177
42344
  completionFinalAssistantEvidence(parsedMessages, turnStartedAt) {
42345
+ const turnClosed = !this.hasAdapterPendingResponse();
42178
42346
  if (this.completionHasFinalAssistantMessage(parsedMessages, turnStartedAt)) {
42179
42347
  return {
42180
- present: true,
42348
+ present: turnClosed,
42181
42349
  messages: Array.isArray(parsedMessages) ? parsedMessages : [],
42182
42350
  source: "parsed"
42183
42351
  };
@@ -42185,7 +42353,7 @@ var CliProviderInstance = class _CliProviderInstance {
42185
42353
  const externalMessages = this.readExternalCompletionMessages();
42186
42354
  if (externalMessages) {
42187
42355
  return {
42188
- present: this.completionHasFinalAssistantMessage(externalMessages, turnStartedAt),
42356
+ present: turnClosed && this.completionHasFinalAssistantMessage(externalMessages, turnStartedAt),
42189
42357
  messages: externalMessages,
42190
42358
  source: "external-native"
42191
42359
  };
@@ -42284,11 +42452,9 @@ var CliProviderInstance = class _CliProviderInstance {
42284
42452
  if (latestVisibleStatus !== "idle") return { reason: `status:${latestVisibleStatus}`, terminal: true };
42285
42453
  const adapterAny = this.adapter;
42286
42454
  const approvalResolvedIdle = pending.previousStatus === "waiting_approval";
42287
- if (!approvalResolvedIdle) {
42288
- if (adapterAny?.isWaitingForResponse === true) return { reason: "adapter_waiting_for_response", terminal: true };
42289
- if (adapterAny?.currentTurnScope) return { reason: "adapter_turn_scope_active", terminal: true };
42290
- if (this.hasAdapterPendingResponse()) return { reason: "adapter_pending_response", terminal: true };
42291
- }
42455
+ if (adapterAny?.isWaitingForResponse === true) return { reason: "adapter_waiting_for_response", terminal: !approvalResolvedIdle };
42456
+ if (adapterAny?.currentTurnScope) return { reason: "adapter_turn_scope_active", terminal: !approvalResolvedIdle };
42457
+ if (this.hasAdapterPendingResponse()) return { reason: "adapter_pending_response", terminal: !approvalResolvedIdle };
42292
42458
  const partial = typeof this.adapter.getPartialResponse === "function" ? this.adapter.getPartialResponse() : "";
42293
42459
  if (typeof partial === "string" && partial.trim()) return { reason: "partial_response_pending", terminal: true };
42294
42460
  let parsed;
@@ -42443,6 +42609,39 @@ var CliProviderInstance = class _CliProviderInstance {
42443
42609
  event
42444
42610
  };
42445
42611
  }
42612
+ // COMPLETION-EARLYNOTIFY instrumentation. A session-keyed FSM-transition +
42613
+ // completion-gate snapshot recorded into the shared debug-trace ring buffer
42614
+ // (secret-safe, length/role/pattern-name only — never screen or bubble text).
42615
+ // Retrieved via getRecentDebugTrace (chat_debug_bundle). Both categories are a
42616
+ // no-op unless collectDebugTrace is on AND the category is selected, so the
42617
+ // hot-path guards below (completionTraceOn / fsmTraceOn) keep production cost
42618
+ // at a single boolean check.
42619
+ completionTraceOn() {
42620
+ return shouldCollectTraceCategory("completion-gate");
42621
+ }
42622
+ fsmTraceOn() {
42623
+ return shouldCollectTraceCategory("fsm-transition");
42624
+ }
42625
+ recordCompletionGateTrace(stage, payload) {
42626
+ recordDebugTrace({
42627
+ category: "completion-gate",
42628
+ stage,
42629
+ level: "debug",
42630
+ sessionId: this.instanceId,
42631
+ providerType: this.type,
42632
+ payload
42633
+ });
42634
+ }
42635
+ recordFsmTransitionTrace(payload) {
42636
+ recordDebugTrace({
42637
+ category: "fsm-transition",
42638
+ stage: "transition",
42639
+ level: "debug",
42640
+ sessionId: this.instanceId,
42641
+ providerType: this.type,
42642
+ payload
42643
+ });
42644
+ }
42446
42645
  flushCompletedDebounceIfFinalized() {
42447
42646
  const pending = this.completedDebouncePending;
42448
42647
  if (!pending) {
@@ -42455,12 +42654,27 @@ var CliProviderInstance = class _CliProviderInstance {
42455
42654
  LOG.debug("CLI", `[${this.type}] flush attempt: adapterStatus=${latestStatus.status} latestVisible=${latestVisibleStatus} generatingStartedAt=${this.generatingStartedAt} isWaitingForResponse=${!!this.adapter?.isWaitingForResponse} hasPartial=${!!this.adapter.getPartialResponse?.()}`);
42456
42655
  if (latestVisibleStatus !== "idle") {
42457
42656
  LOG.info("CLI", `[${this.type}] cancelled pending completed (resumed ${latestVisibleStatus})`);
42657
+ if (this.completionTraceOn()) this.recordCompletionGateTrace("cancel", {
42658
+ blockReason: "resumed_status",
42659
+ latestVisibleStatus,
42660
+ previousStatus: pending.previousStatus,
42661
+ busyEpochAtArm: pending.busyEpochAtArm,
42662
+ busyEpoch: this.busyEpoch
42663
+ });
42458
42664
  this.completedDebouncePending = null;
42459
42665
  this.completedDebounceTimer = null;
42460
42666
  return;
42461
42667
  }
42462
42668
  if (typeof pending.busyEpochAtArm === "number" && this.busyEpoch !== pending.busyEpochAtArm) {
42463
42669
  LOG.info("CLI", `[${this.type}] cancelled pending completed (busy re-entry during settle: epoch ${pending.busyEpochAtArm}\u2192${this.busyEpoch})`);
42670
+ if (this.completionTraceOn()) this.recordCompletionGateTrace("cancel", {
42671
+ blockReason: "busy_reentry",
42672
+ latestVisibleStatus,
42673
+ previousStatus: pending.previousStatus,
42674
+ busyEpochAtArm: pending.busyEpochAtArm,
42675
+ busyEpoch: this.busyEpoch,
42676
+ busyEpochDelta: this.busyEpoch - pending.busyEpochAtArm
42677
+ });
42464
42678
  this.completedDebouncePending = null;
42465
42679
  this.completedDebounceTimer = null;
42466
42680
  return;
@@ -42468,6 +42682,14 @@ var CliProviderInstance = class _CliProviderInstance {
42468
42682
  const latestOutputAt = typeof latestStatus?.lastOutputAt === "number" ? latestStatus.lastOutputAt : void 0;
42469
42683
  if (typeof pending.lastOutputAtArm === "number" && typeof latestOutputAt === "number" && latestOutputAt > pending.lastOutputAtArm) {
42470
42684
  LOG.info("CLI", `[${this.type}] cancelled pending completed (new PTY output during settle: ${pending.lastOutputAtArm}\u2192${latestOutputAt})`);
42685
+ if (this.completionTraceOn()) this.recordCompletionGateTrace("cancel", {
42686
+ blockReason: "new_pty_output",
42687
+ latestVisibleStatus,
42688
+ previousStatus: pending.previousStatus,
42689
+ lastOutputAtArm: pending.lastOutputAtArm,
42690
+ lastOutputAt: latestOutputAt,
42691
+ lastOutputAtDelta: latestOutputAt - pending.lastOutputAtArm
42692
+ });
42471
42693
  this.completedDebouncePending = null;
42472
42694
  this.completedDebounceTimer = null;
42473
42695
  return;
@@ -42484,6 +42706,14 @@ var CliProviderInstance = class _CliProviderInstance {
42484
42706
  if (this.isMeshWorkerSession()) {
42485
42707
  traceMeshEventDrop("completion_gate_hold", this.meshTraceCtx(), `${blockReason} waited=${waitedMs}ms`);
42486
42708
  }
42709
+ if (this.completionTraceOn()) this.recordCompletionGateTrace("hold", {
42710
+ blockReason,
42711
+ latestVisibleStatus,
42712
+ terminal: block2.terminal === true,
42713
+ holdForTranscript: block2.holdForTranscript === true,
42714
+ approvalResolvedIdle: pending.previousStatus === "waiting_approval",
42715
+ waitedMs
42716
+ });
42487
42717
  pending.loggedBlockReason = blockReason;
42488
42718
  }
42489
42719
  this.scheduleCompletedDebounceFlush(COMPLETED_FINALIZATION_RETRY_MS);
@@ -42503,6 +42733,19 @@ var CliProviderInstance = class _CliProviderInstance {
42503
42733
  if (this.isMeshWorkerSession()) {
42504
42734
  traceMeshEventStage("fired", this.meshTraceCtx(), `forced after ${waitedMs}ms (${blockReason})`);
42505
42735
  }
42736
+ if (this.completionTraceOn()) this.recordCompletionGateTrace("fire", {
42737
+ path: isTranscriptEvidenceGate && !emittedAfterFinalizationTimeout ? "canon_c_decoupled" : "forced_timeout",
42738
+ blockReason,
42739
+ latestVisibleStatus,
42740
+ approvalResolvedIdle: pending.previousStatus === "waiting_approval",
42741
+ finalAssistantPresent: completionDiagnostic.finalAssistantPresent === true,
42742
+ evidenceSource: completionDiagnostic.finalAssistantEvidenceSource ?? null,
42743
+ lastVisibleRole: completionDiagnostic.lastVisibleRole ?? null,
42744
+ lastVisibleContentLen: completionDiagnostic.lastVisibleContentLength ?? null,
42745
+ emittedAfterFinalizationTimeout,
42746
+ waitedMs,
42747
+ busyEpoch: this.busyEpoch
42748
+ });
42506
42749
  this.pushEvent({
42507
42750
  event: "agent:generating_completed",
42508
42751
  chatTitle: pending.chatTitle,
@@ -42530,6 +42773,14 @@ var CliProviderInstance = class _CliProviderInstance {
42530
42773
  if (this.isMeshWorkerSession()) {
42531
42774
  traceMeshEventStage("fired", this.meshTraceCtx(), `duration=${pending.duration}s`);
42532
42775
  }
42776
+ if (this.completionTraceOn()) this.recordCompletionGateTrace("fire", {
42777
+ path: "clean",
42778
+ latestVisibleStatus,
42779
+ approvalResolvedIdle: pending.previousStatus === "waiting_approval",
42780
+ finalAssistantPresent: true,
42781
+ duration: pending.duration,
42782
+ busyEpoch: this.busyEpoch
42783
+ });
42533
42784
  this.pushEvent({
42534
42785
  event: "agent:generating_completed",
42535
42786
  chatTitle: pending.chatTitle,
@@ -42763,6 +43014,18 @@ var CliProviderInstance = class _CliProviderInstance {
42763
43014
  const previousStatus = this.lastStatus;
42764
43015
  if (newStatus !== this.lastStatus) {
42765
43016
  LOG.info("CLI", `[${this.type}] status: ${this.lastStatus} \u2192 ${newStatus}`);
43017
+ if (this.fsmTraceOn()) this.recordFsmTransitionTrace({
43018
+ from: this.lastStatus,
43019
+ to: newStatus,
43020
+ rawStatus,
43021
+ autoApproveActive,
43022
+ autoApproveHoldIdle,
43023
+ autoApproveBusy: this.autoApproveBusy,
43024
+ hasPending: this.hasAdapterPendingResponse(),
43025
+ busyEpoch: this.busyEpoch,
43026
+ lastOutputAt: typeof adapterStatus?.lastOutputAt === "number" ? adapterStatus.lastOutputAt : null,
43027
+ lastScreenChangeAt: typeof adapterStatus?.lastScreenChangeAt === "number" ? adapterStatus.lastScreenChangeAt : null
43028
+ });
42766
43029
  const startingToGeneratingWithActiveTurn = this.lastStatus === "starting" && newStatus === "generating" && this.hasAdapterPendingResponse();
42767
43030
  if (this.lastStatus === "idle" && newStatus === "generating" || startingToGeneratingWithActiveTurn) {
42768
43031
  if (this.completedDebouncePending && this.generatingStartedAt === 0) {
@@ -42889,6 +43152,17 @@ var CliProviderInstance = class _CliProviderInstance {
42889
43152
  if (this.isMeshWorkerSession()) {
42890
43153
  traceMeshEventStage("arm", this.meshTraceCtx(), `short-generating settle-arm (source=${shortEvidenceSource}, missingEvidence=${missingEvidence})`);
42891
43154
  }
43155
+ if (this.completionTraceOn()) this.recordCompletionGateTrace("arm", {
43156
+ branch: "short_generating",
43157
+ previousStatus: this.lastStatus,
43158
+ turnStartedAt: shortTurnStartedAt || null,
43159
+ busyEpochAtArm: this.busyEpoch,
43160
+ lastOutputAtArm: typeof adapterStatus?.lastOutputAt === "number" ? adapterStatus.lastOutputAt : null,
43161
+ flushDelay: NATIVE_HISTORY_MESH_IDLE_SETTLE_MS,
43162
+ evidenceSource: shortEvidenceSource,
43163
+ missingEvidence,
43164
+ hasFinalSummary: !!shortFinalSummary
43165
+ });
42892
43166
  this.scheduleCompletedDebounceFlush(NATIVE_HISTORY_MESH_IDLE_SETTLE_MS);
42893
43167
  } else if (missingEvidence) {
42894
43168
  LOG.info("CLI", `[${this.type}] short completion suppressed: missing final assistant evidence, non-mesh session (source=${shortEvidenceSource})`);
@@ -42937,6 +43211,16 @@ var CliProviderInstance = class _CliProviderInstance {
42937
43211
  const meshSettleSession = this.isAutonomousMeshSession();
42938
43212
  const flushDelay = ownsExternalHistory ? meshSettleSession ? NATIVE_HISTORY_MESH_IDLE_SETTLE_MS : 0 : 3e3;
42939
43213
  LOG.debug("CLI", `[${this.type}] set completedDebouncePending duration=${duration}s ownsExternalHistory=${ownsExternalHistory} meshSettle=${meshSettleSession} flushDelay=${flushDelay}ms generatingStartedAt=${this.generatingStartedAt}`);
43214
+ if (this.completionTraceOn()) this.recordCompletionGateTrace("arm", {
43215
+ branch: "normal",
43216
+ previousStatus: this.completedDebouncePending.previousStatus,
43217
+ turnStartedAt: this.completedDebouncePending.turnStartedAt ?? null,
43218
+ busyEpochAtArm: this.completedDebouncePending.busyEpochAtArm ?? null,
43219
+ lastOutputAtArm: this.completedDebouncePending.lastOutputAtArm ?? null,
43220
+ flushDelay,
43221
+ ownsExternalHistory,
43222
+ meshSettle: meshSettleSession
43223
+ });
42940
43224
  this.scheduleCompletedDebounceFlush(flushDelay);
42941
43225
  }
42942
43226
  } else if (newStatus === "idle" && this.lastStatus === "starting") {
@@ -47936,12 +48220,17 @@ var ProviderLoader = class _ProviderLoader {
47936
48220
  logFn;
47937
48221
  versionArchive = null;
47938
48222
  scriptsCache = /* @__PURE__ */ new Map();
48223
+ /**
48224
+ * Resolved registry base URL and provider tarball URL. Resolution order:
48225
+ * explicit config field (constructor option) → env var → vendor default.
48226
+ * See `config/registry-resolver.ts`.
48227
+ */
48228
+ registryBaseUrl;
48229
+ providerTarballUrl;
47939
48230
  /** Inject VersionArchive so resolve() can auto-detect installed versions */
47940
48231
  setVersionArchive(archive) {
47941
48232
  this.versionArchive = archive;
47942
48233
  }
47943
- static GITHUB_TARBALL_URL = "https://github.com/vilmire/adhdev-providers/archive/refs/heads/main.tar.gz";
47944
- static REGISTRY_BASE_URL = "https://api.adhf.dev/api/v1/registry";
47945
48234
  static META_FILE = ".meta.json";
47946
48235
  static REGISTRY_META_FILE = ".registry-meta.json";
47947
48236
  static REPO_PROVIDER_DIRNAME = "adhdev-providers";
@@ -48009,6 +48298,8 @@ var ProviderLoader = class _ProviderLoader {
48009
48298
  constructor(options) {
48010
48299
  this.logFn = options?.logFn || LOG.forComponent("Provider").asLogFn();
48011
48300
  this.probeStarts = options?.probeStarts ?? [process.cwd(), __dirname];
48301
+ this.registryBaseUrl = resolveRegistryBaseUrl(options?.registryUrl);
48302
+ this.providerTarballUrl = resolveProviderTarballUrl(options?.providerTarballUrl);
48012
48303
  this.defaultProvidersDir = path35.join(os25.homedir(), ".adhdev", "providers");
48013
48304
  const detected = this.detectDefaultUserDir();
48014
48305
  this.userDir = detected.path;
@@ -49041,7 +49332,7 @@ var ProviderLoader = class _ProviderLoader {
49041
49332
  this.log("Registry sync skipped (sourceMode=no-upstream)");
49042
49333
  return { updated: false };
49043
49334
  }
49044
- this.log(`Registry sync starting (${_ProviderLoader.REGISTRY_BASE_URL})...`);
49335
+ this.log(`Registry sync starting (${this.registryBaseUrl})...`);
49045
49336
  const https = require("https");
49046
49337
  const regMetaPath = path35.join(this.upstreamDir, _ProviderLoader.REGISTRY_META_FILE);
49047
49338
  let cachedChecksums = {};
@@ -49052,7 +49343,7 @@ var ProviderLoader = class _ProviderLoader {
49052
49343
  } catch {
49053
49344
  }
49054
49345
  try {
49055
- const listUrl = `${_ProviderLoader.REGISTRY_BASE_URL}/providers`;
49346
+ const listUrl = `${this.registryBaseUrl}/providers`;
49056
49347
  const listBody = await new Promise((resolve25, reject) => {
49057
49348
  const req = https.get(listUrl, { headers: { "User-Agent": "adhdev-daemon", "Accept": "application/json" }, timeout: 1e4 }, (res) => {
49058
49349
  if (res.statusCode !== 200) {
@@ -49076,7 +49367,7 @@ var ProviderLoader = class _ProviderLoader {
49076
49367
  const { type, category, checksum, version } = entry;
49077
49368
  const cacheKey = `${category}/${type}`;
49078
49369
  if (cachedChecksums[cacheKey] === checksum) continue;
49079
- const dlUrl = `${_ProviderLoader.REGISTRY_BASE_URL}/providers/${type}/${version}/download`;
49370
+ const dlUrl = `${this.registryBaseUrl}/providers/${type}/${version}/download`;
49080
49371
  const manifestBody = await new Promise((resolve25, reject) => {
49081
49372
  const req = https.get(dlUrl, { headers: { "User-Agent": "adhdev-daemon", "Accept": "application/json" }, timeout: 3e4 }, (res) => {
49082
49373
  if (res.statusCode !== 200) {
@@ -49143,12 +49434,13 @@ var ProviderLoader = class _ProviderLoader {
49143
49434
  this.log("Upstream check skipped (last check < 30min ago)");
49144
49435
  return { updated: false };
49145
49436
  }
49437
+ const tarballTarget = resolveProviderTarballTarget(this.providerTarballUrl);
49146
49438
  try {
49147
49439
  const etag = await new Promise((resolve25, reject) => {
49148
49440
  const options = {
49149
49441
  method: "HEAD",
49150
- hostname: "github.com",
49151
- path: "/vilmire/adhdev-providers/archive/refs/heads/main.tar.gz",
49442
+ hostname: tarballTarget.hostname,
49443
+ path: tarballTarget.path,
49152
49444
  headers: { "User-Agent": "adhdev-launcher" },
49153
49445
  timeout: 1e4
49154
49446
  };
@@ -49189,7 +49481,7 @@ var ProviderLoader = class _ProviderLoader {
49189
49481
  this.log("Downloading latest providers from GitHub...");
49190
49482
  const tmpTar = path35.join(os25.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
49191
49483
  const tmpExtract = path35.join(os25.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
49192
- await this.downloadFile(_ProviderLoader.GITHUB_TARBALL_URL, tmpTar);
49484
+ await this.downloadFile(tarballTarget.url, tmpTar);
49193
49485
  fs25.mkdirSync(tmpExtract, { recursive: true });
49194
49486
  await execAsync5(`tar -xzf "${tmpTar}" -C "${tmpExtract}"`, { timeout: 3e4 });
49195
49487
  const extracted = fs25.readdirSync(tmpExtract);
@@ -49289,7 +49581,7 @@ var ProviderLoader = class _ProviderLoader {
49289
49581
  etag,
49290
49582
  timestamp,
49291
49583
  lastCheck: new Date(timestamp).toISOString(),
49292
- source: _ProviderLoader.GITHUB_TARBALL_URL
49584
+ source: this.providerTarballUrl
49293
49585
  }, null, 2));
49294
49586
  } catch {
49295
49587
  }
@@ -50401,6 +50693,47 @@ async function decideOssCloneSync(ossCtx, worktreeOssSha, sourceSha, rg) {
50401
50693
  if (await isAncestor(worktreeOssSha, sourceSha)) return "advance";
50402
50694
  return "skip_diverged";
50403
50695
  }
50696
+ async function syncClonedWorktreeSubmodules(worktreePath, sourceWorkspace, rg) {
50697
+ const submodulePaths = getRegisteredSubmodulePaths(worktreePath);
50698
+ if (submodulePaths.size === 0) return;
50699
+ const sourceCtx = { workspace: sourceWorkspace, repoRoot: sourceWorkspace, isGitRepo: true };
50700
+ const worktreeCtx = { workspace: worktreePath, repoRoot: worktreePath, isGitRepo: true };
50701
+ const readStdout = (out) => (typeof out === "string" ? out : out?.stdout ?? "").trim();
50702
+ for (const submodulePath of submodulePaths) {
50703
+ try {
50704
+ const sourceStatusOut = await rg(sourceCtx, ["submodule", "status", submodulePath], { timeoutMs: 1e4 });
50705
+ const sourceSha = readStdout(sourceStatusOut).match(/^[+\- ]?([0-9a-f]{40})/)?.[1];
50706
+ if (!sourceSha) continue;
50707
+ const subCtx = {
50708
+ workspace: `${worktreePath}/${submodulePath}`,
50709
+ repoRoot: `${worktreePath}/${submodulePath}`,
50710
+ isGitRepo: true
50711
+ };
50712
+ const worktreeSubSha = readStdout(await rg(subCtx, ["rev-parse", "HEAD"], { timeoutMs: 1e4 }));
50713
+ if (!worktreeSubSha || worktreeSubSha === sourceSha) continue;
50714
+ await rg(subCtx, ["fetch", `${sourceWorkspace}/${submodulePath}`, "HEAD"], { timeoutMs: 6e4 });
50715
+ let action;
50716
+ try {
50717
+ action = await decideOssCloneSync(subCtx, worktreeSubSha, sourceSha, rg);
50718
+ } catch (decideErr) {
50719
+ action = "skip_diverged";
50720
+ console.warn(`[mesh] ${submodulePath} submodule sync guard could not resolve ancestry (kept fresh worktree HEAD): ${decideErr?.message ?? decideErr}`);
50721
+ }
50722
+ if (action === "advance") {
50723
+ await rg(subCtx, ["checkout", sourceSha], { timeoutMs: 1e4 });
50724
+ await rg(worktreeCtx, ["add", submodulePath], { timeoutMs: 1e4 });
50725
+ await rg(worktreeCtx, ["commit", "-m", `chore: sync ${submodulePath} to source node HEAD on clone`], { timeoutMs: 1e4 });
50726
+ console.log(`[mesh] Advanced ${submodulePath} submodule to newer source HEAD ${sourceSha.slice(0, 8)} in worktree`);
50727
+ } else if (action === "skip_rewind") {
50728
+ console.warn(`[mesh] Skipped ${submodulePath} submodule rewind on clone: source node ${submodulePath} ${sourceSha.slice(0, 8)} is an ancestor of the fresh worktree ${submodulePath} ${worktreeSubSha.slice(0, 8)} \u2014 kept fresher worktree HEAD`);
50729
+ } else if (action === "skip_diverged") {
50730
+ console.warn(`[mesh] Skipped ${submodulePath} submodule sync on clone: source node ${submodulePath} ${sourceSha.slice(0, 8)} diverged from the fresh worktree ${submodulePath} ${worktreeSubSha.slice(0, 8)} \u2014 kept worktree HEAD (coordinator reconciles)`);
50731
+ }
50732
+ } catch (subErr) {
50733
+ console.warn(`[mesh] ${submodulePath} submodule sync to source HEAD failed (best-effort):`, subErr?.message ?? subErr);
50734
+ }
50735
+ }
50736
+ }
50404
50737
  var meshCrudHandlers = {
50405
50738
  list_meshes: async (ctx, _args) => {
50406
50739
  try {
@@ -51105,42 +51438,8 @@ var meshCrudHandlers = {
51105
51438
  submodulesInitialized2 = true;
51106
51439
  const sourceWorkspace = sourceNode.repoRoot || sourceNode.workspace;
51107
51440
  if (sourceWorkspace) {
51108
- try {
51109
- const { runGit: rg } = await Promise.resolve().then(() => (init_git_executor(), git_executor_exports));
51110
- const sourceCtx = { workspace: sourceWorkspace, repoRoot: sourceWorkspace, isGitRepo: true };
51111
- const worktreeCtx = { workspace: result.worktreePath, repoRoot: result.worktreePath, isGitRepo: true };
51112
- const sourceStatusOut = await rg(sourceCtx, ["submodule", "status", "oss"], { timeoutMs: 1e4 });
51113
- const sourceStatusLine = (typeof sourceStatusOut === "string" ? sourceStatusOut : sourceStatusOut?.stdout ?? "").trim();
51114
- const sourceShaMatch = sourceStatusLine.match(/^[+\- ]?([0-9a-f]{40})/);
51115
- const sourceSha = sourceShaMatch?.[1];
51116
- if (sourceSha) {
51117
- const ossCtx = { workspace: `${result.worktreePath}/oss`, repoRoot: `${result.worktreePath}/oss`, isGitRepo: true };
51118
- const worktreeOssHeadOut = await rg(ossCtx, ["rev-parse", "HEAD"], { timeoutMs: 1e4 });
51119
- const worktreeOssSha = (typeof worktreeOssHeadOut === "string" ? worktreeOssHeadOut : worktreeOssHeadOut?.stdout ?? "").trim();
51120
- if (worktreeOssSha && worktreeOssSha !== sourceSha) {
51121
- await rg(ossCtx, ["fetch", `${sourceWorkspace}/oss`, "HEAD"], { timeoutMs: 6e4 });
51122
- let ossAction;
51123
- try {
51124
- ossAction = await decideOssCloneSync(ossCtx, worktreeOssSha, sourceSha, rg);
51125
- } catch (decideErr) {
51126
- ossAction = "skip_diverged";
51127
- console.warn(`[mesh] oss submodule sync guard could not resolve ancestry (kept fresh worktree HEAD): ${decideErr?.message ?? decideErr}`);
51128
- }
51129
- if (ossAction === "advance") {
51130
- await rg(ossCtx, ["checkout", sourceSha], { timeoutMs: 1e4 });
51131
- await rg(worktreeCtx, ["add", "oss"], { timeoutMs: 1e4 });
51132
- await rg(worktreeCtx, ["commit", "-m", "chore: sync oss to source node HEAD on clone"], { timeoutMs: 1e4 });
51133
- console.log(`[mesh] Advanced oss submodule to newer source HEAD ${sourceSha.slice(0, 8)} in worktree`);
51134
- } else if (ossAction === "skip_rewind") {
51135
- console.warn(`[mesh] Skipped oss submodule rewind on clone: source node oss ${sourceSha.slice(0, 8)} is an ancestor of the fresh worktree oss ${worktreeOssSha.slice(0, 8)} \u2014 kept fresher worktree HEAD`);
51136
- } else if (ossAction === "skip_diverged") {
51137
- console.warn(`[mesh] Skipped oss submodule sync on clone: source node oss ${sourceSha.slice(0, 8)} diverged from the fresh worktree oss ${worktreeOssSha.slice(0, 8)} \u2014 kept worktree HEAD (coordinator reconciles)`);
51138
- }
51139
- }
51140
- }
51141
- } catch (ossErr) {
51142
- console.warn("[mesh] oss submodule sync to source HEAD failed (best-effort):", ossErr.message);
51143
- }
51441
+ const { runGit: rg } = await Promise.resolve().then(() => (init_git_executor(), git_executor_exports));
51442
+ await syncClonedWorktreeSubmodules(result.worktreePath, sourceWorkspace, rg);
51144
51443
  }
51145
51444
  } catch (subErr) {
51146
51445
  console.warn("[mesh] Submodule init failed for worktree:", subErr.message);
@@ -52574,6 +52873,26 @@ var import_node_child_process4 = require("child_process");
52574
52873
  var import_node_fs4 = require("fs");
52575
52874
  var import_node_path2 = require("path");
52576
52875
  var PREVIEW_DEPLOY_RECORD = ".adhdev/preview-deploy.json";
52876
+ var PREVIEW_PIPELINE_SCRIPTS = [
52877
+ "scripts/preview-freshness.mjs",
52878
+ "scripts/smoke-preview-web.mjs",
52879
+ "scripts/deploy-preview-local.mjs"
52880
+ ];
52881
+ function hasDeployPreviewNpmScript(repoRoot) {
52882
+ const pkgPath = (0, import_node_path2.resolve)(repoRoot, "package.json");
52883
+ if (!(0, import_node_fs4.existsSync)(pkgPath)) return false;
52884
+ try {
52885
+ const pkg = JSON.parse((0, import_node_fs4.readFileSync)(pkgPath, "utf8"));
52886
+ return typeof pkg?.scripts?.["deploy:preview"] === "string";
52887
+ } catch {
52888
+ return false;
52889
+ }
52890
+ }
52891
+ function isPreviewPipelineConfigured(repoRoot) {
52892
+ if ((0, import_node_fs4.existsSync)((0, import_node_path2.resolve)(repoRoot, PREVIEW_DEPLOY_RECORD))) return true;
52893
+ if (PREVIEW_PIPELINE_SCRIPTS.some((rel) => (0, import_node_fs4.existsSync)((0, import_node_path2.resolve)(repoRoot, rel)))) return true;
52894
+ return hasDeployPreviewNpmScript(repoRoot);
52895
+ }
52577
52896
  function runGit2(repoRoot, args) {
52578
52897
  try {
52579
52898
  return (0, import_node_child_process4.execFileSync)("git", args, {
@@ -52625,6 +52944,7 @@ function readCurrentMainCommit(repoRoot) {
52625
52944
  return { currentMainCommit: null, currentMainCommitSource: "unknown" };
52626
52945
  }
52627
52946
  function buildPreviewFreshness(repoRoot) {
52947
+ if (!isPreviewPipelineConfigured(repoRoot)) return null;
52628
52948
  const current = readCurrentMainCommit(repoRoot);
52629
52949
  const record = readRecord6(repoRoot);
52630
52950
  const lastPreviewCommit = normalizeCommit(record?.lastPreviewCommit);
@@ -55440,6 +55760,7 @@ async function runMeshRefineSubmoduleReachabilityGate(repoRoot, mergedTree, opti
55440
55760
  commit: gitlink.commit,
55441
55761
  reachable: false
55442
55762
  };
55763
+ let submoduleDefaultBranch = "main";
55443
55764
  try {
55444
55765
  if (!fs30.existsSync(submodulePath)) {
55445
55766
  entry.error = `Submodule checkout missing at ${gitlink.path}`;
@@ -55492,9 +55813,14 @@ async function runMeshRefineSubmoduleReachabilityGate(repoRoot, mergedTree, opti
55492
55813
  entries.push(entry);
55493
55814
  continue;
55494
55815
  }
55495
- entry.remoteMainBranch = "main";
55816
+ submoduleDefaultBranch = await resolveSubmoduleDefaultBranch({
55817
+ submoduleRepoPath: submodulePath,
55818
+ superprojectWorkspace: repoRoot,
55819
+ submodulePath: gitlink.path
55820
+ });
55821
+ entry.remoteMainBranch = submoduleDefaultBranch;
55496
55822
  try {
55497
- await verifyRemoteMainContainsCommit(submodulePath, gitlink.commit, "main");
55823
+ await verifyRemoteMainContainsCommit(submodulePath, gitlink.commit, submoduleDefaultBranch);
55498
55824
  entry.fetchedFromOrigin = true;
55499
55825
  entry.remoteReachable = true;
55500
55826
  entry.remoteMainReachable = true;
@@ -55504,17 +55830,17 @@ async function runMeshRefineSubmoduleReachabilityGate(repoRoot, mergedTree, opti
55504
55830
  entry.remoteMainReachable = false;
55505
55831
  entry.publishRequired = true;
55506
55832
  const details = truncateValidationOutput(e?.stderr || e?.message || String(e));
55507
- entry.error = `Submodule remote main reachability check failed for origin/main: ${details}`;
55833
+ entry.error = `Submodule remote main reachability check failed for origin/${submoduleDefaultBranch}: ${details}`;
55508
55834
  if (options.allowAutoPublishSubmoduleMainCommits === true && entry.localReachable === true) {
55509
55835
  entry.autoPublishAllowed = true;
55510
55836
  entry.autoPublishAttempted = true;
55511
55837
  try {
55512
- const publish = await publishCommitToRemoteMain(submodulePath, gitlink.commit, "main");
55838
+ const publish = await publishCommitToRemoteMain(submodulePath, gitlink.commit, submoduleDefaultBranch);
55513
55839
  entry.autoPublishRefspec = publish.refspec;
55514
55840
  entry.publishStdout = truncateValidationOutput(publish.stdout);
55515
55841
  entry.publishStderr = truncateValidationOutput(publish.stderr);
55516
55842
  entry.autoPublishSucceeded = true;
55517
- await verifyRemoteMainContainsCommit(submodulePath, gitlink.commit, "main");
55843
+ await verifyRemoteMainContainsCommit(submodulePath, gitlink.commit, submoduleDefaultBranch);
55518
55844
  entry.fetchedFromOrigin = true;
55519
55845
  entry.remoteReachable = true;
55520
55846
  entry.remoteMainReachable = true;
@@ -55526,12 +55852,12 @@ async function runMeshRefineSubmoduleReachabilityGate(repoRoot, mergedTree, opti
55526
55852
  entry.autoPublishSucceeded = false;
55527
55853
  entry.autoPublishVerified = false;
55528
55854
  const publishDetails = truncateValidationOutput(publishError?.stderr || publishError?.message || String(publishError));
55529
- entry.error = `Submodule auto-publish to origin/main failed or could not be verified: ${publishDetails}`;
55855
+ entry.error = `Submodule auto-publish to origin/${submoduleDefaultBranch} failed or could not be verified: ${publishDetails}`;
55530
55856
  }
55531
55857
  } else if (options.allowAutoPublishSubmoduleMainCommits === true) {
55532
55858
  entry.autoPublishAllowed = true;
55533
55859
  entry.autoPublishAttempted = false;
55534
- entry.autoPublishSkippedReason = entry.autoPublishSkippedReason || "candidate commit is not reachable in the source checkout or worktree submodule, so Refinery cannot push it to origin/main";
55860
+ entry.autoPublishSkippedReason = entry.autoPublishSkippedReason || `candidate commit is not reachable in the source checkout or worktree submodule, so Refinery cannot push it to origin/${submoduleDefaultBranch}`;
55535
55861
  }
55536
55862
  }
55537
55863
  } catch (e) {
@@ -55539,7 +55865,7 @@ async function runMeshRefineSubmoduleReachabilityGate(repoRoot, mergedTree, opti
55539
55865
  entry.remoteMainReachable = false;
55540
55866
  entry.publishRequired = true;
55541
55867
  const details = truncateValidationOutput(e?.stderr || e?.message || String(e));
55542
- entry.error = `Submodule remote main reachability check failed for origin/main: ${details}`;
55868
+ entry.error = `Submodule remote main reachability check failed for origin/${submoduleDefaultBranch}: ${details}`;
55543
55869
  }
55544
55870
  } catch (e) {
55545
55871
  entry.error = truncateValidationOutput(e?.message || String(e));
@@ -66335,7 +66661,9 @@ async function initDaemonComponents(config) {
66335
66661
  const providerLoader = new ProviderLoader({
66336
66662
  logFn: config.providerLogFn,
66337
66663
  sourceMode: providerSourceMode,
66338
- userDir: appConfig.providerDir
66664
+ userDir: appConfig.providerDir,
66665
+ registryUrl: appConfig.registryUrl,
66666
+ providerTarballUrl: appConfig.providerTarballUrl
66339
66667
  });
66340
66668
  providerLoader.loadAll();
66341
66669
  providerLoader.registerToDetector();
@@ -66827,6 +67155,7 @@ var V1_ALL_PRIMITIVES = Object.freeze(
66827
67155
  var V1_CONTRACT_VERSION = "1.0.0";
66828
67156
  // Annotate the CommonJS export names for ESM import in node:
66829
67157
  0 && (module.exports = {
67158
+ ALWAYS_ON_TRACE_CATEGORIES,
66830
67159
  AcpProviderInstance,
66831
67160
  AgentStreamPoller,
66832
67161
  BUILTIN_CHAT_MESSAGE_KINDS,
@@ -67058,6 +67387,7 @@ var V1_CONTRACT_VERSION = "1.0.0";
67058
67387
  installGlobalInterceptor,
67059
67388
  interactivePromptFromClaudeAskUserQuestion,
67060
67389
  isActivityChatMessage,
67390
+ isAlwaysOnTraceCategory,
67061
67391
  isBuiltinChatMessageKind,
67062
67392
  isCdpConnected,
67063
67393
  isExtensionInstalled,