// Force strict mode and setup for ESM
"use strict";
import {
  buildPermissionSettings
} from "./chunk-AKC232TB.js";
import {
  resolveVoiceStreamConfig,
  resolveVoiceTranscriptionConfig,
  transcribeVoiceAudio
} from "./chunk-7P5ASBH7.js";
import {
  getVoiceSettingsScope,
  isSelectableVoiceModel,
  isVoiceEnabled,
  readVoiceLanguage,
  readVoiceMode,
  readVoiceModel,
  resolveVoiceTransport
} from "./chunk-2WNF6DDX.js";
import {
  WorkspacePermissionRulesSessionRequiredError,
  WorkspaceSettingsPartialPersistError,
  WorkspaceSkillNotFoundError,
  WorkspaceSkillNotToggleableError
} from "./chunk-OA4JVLSA.js";
import {
  MCP_RESTART_SERVER_DEADLINE_MS,
  McpServerNotFoundError,
  McpServerRestartFailedError,
  SessionNotFoundError,
  WorkspaceInitConflictError,
  WorkspaceInitPathEscapeError,
  WorkspaceInitRaceError,
  WorkspaceInitSymlinkError
} from "./chunk-L4Y55KIS.js";
import {
  BridgeChannelClosedError,
  SERVE_CONTROL_EXT_METHODS,
  SERVE_STATUS_EXT_METHODS,
  STATUS_SCHEMA_VERSION,
  createIdleAcpPreflightCells,
  createIdleEnvStatus,
  createIdleWorkspaceExtensionsStatus,
  createIdleWorkspaceHooksStatus,
  createIdleWorkspaceMcpStatus,
  createIdleWorkspaceProvidersStatus,
  createIdleWorkspaceSkillsStatus,
  mapDomainErrorToErrorKind
} from "./chunk-LX3DYYB3.js";
import {
  getPersistScopeForModelSelection,
  loadSettings
} from "./chunk-BYFID5BL.js";
import {
  getWorkspaceTrustStatus
} from "./chunk-FXXY6GR5.js";
import {
  writeStderrLine
} from "./chunk-YUZI3WAC.js";
import {
  ModelsConfig
} from "./chunk-KN5EBZLT.js";
import {
  createDebugLogger
} from "./chunk-7NFB7LBQ.js";
import {
  init_esbuild_shims
} from "./chunk-5O2XNYP6.js";
import {
  __name
} from "./chunk-J2S4EL5Y.js";

// packages/cli/src/serve/workspace-service/index.ts
init_esbuild_shims();
import { promises as fs, constants as fsConstants } from "node:fs";
import * as path from "node:path";

// packages/cli/src/services/voice-service.ts
init_esbuild_shims();
var debugLogger = createDebugLogger("VOICE_SERVICE");
var EMPTY_WORKSPACE_VOICE_UPDATE_ERROR = "At least one of `enabled`, `mode`, `language`, or `voiceModel` must be provided";
var WorkspaceVoiceError = class extends Error {
  static {
    __name(this, "WorkspaceVoiceError");
  }
  status;
  code;
  constructor(status, code, message) {
    super(message);
    this.name = "WorkspaceVoiceError";
    this.status = status;
    this.code = code;
  }
};
function voiceSettingsScopeToWire(scope) {
  return scope === "Workspace" /* Workspace */ ? "workspace" : "user";
}
__name(voiceSettingsScopeToWire, "voiceSettingsScopeToWire");
function buildWorkspaceVoiceSettingsWrites(settings, update, opts = {}) {
  const voiceSettingsScope = opts.scopeOverride ?? getVoiceSettingsScope(settings, opts.workspaceTrusted);
  const writes = [];
  if (update.voiceModel !== void 0) {
    writes.push({
      scope: opts.scopeOverride ?? getPersistScopeForModelSelection(settings),
      key: "voiceModel",
      value: update.voiceModel
    });
  }
  if (update.mode !== void 0) {
    writes.push({
      scope: voiceSettingsScope,
      key: "general.voice.mode",
      value: update.mode
    });
  }
  if (update.language !== void 0) {
    writes.push({
      scope: voiceSettingsScope,
      key: "general.voice.language",
      value: update.language
    });
  }
  if (update.enabled !== void 0) {
    writes.push({
      scope: voiceSettingsScope,
      key: "general.voice.enabled",
      value: update.enabled
    });
  }
  return writes;
}
__name(buildWorkspaceVoiceSettingsWrites, "buildWorkspaceVoiceSettingsWrites");
function createVoiceModelSource(settings) {
  return new ModelsConfig({
    modelProvidersConfig: settings.merged.modelProviders
  });
}
__name(createVoiceModelSource, "createVoiceModelSource");
function listAvailableVoiceModels(settings) {
  const models = createVoiceModelSource(settings).getAllConfiguredModels();
  const idCounts = /* @__PURE__ */ new Map();
  for (const model of models) {
    idCounts.set(model.id, (idCounts.get(model.id) ?? 0) + 1);
  }
  const duplicateIds = [...idCounts.entries()].filter(([, count]) => count > 1).map(([id]) => id);
  if (duplicateIds.length > 0) {
    debugLogger.debug(
      `Skipping duplicate voice model ids: ${duplicateIds.join(", ")}`
    );
  }
  return models.filter((model) => (idCounts.get(model.id) ?? 0) === 1).filter(isSelectableVoiceModel).map((model) => ({
    id: model.id,
    transport: resolveVoiceTransport(model.id)
  })).filter(
    (model) => model.transport !== "unsupported"
  );
}
__name(listAvailableVoiceModels, "listAvailableVoiceModels");
function hasConfiguredBatchVoiceTranscriptionModel(settings, opts = {}) {
  for (const model of listAvailableVoiceModels(settings)) {
    if (model.transport !== "qwen-asr-chat") {
      continue;
    }
    try {
      validateWorkspaceVoiceConfig(settings, model.id, opts);
      return true;
    } catch (err) {
      debugLogger.debug(
        `Skipping unavailable batch voice model '${model.id}': ${err instanceof Error ? err.message : String(err)}`
      );
    }
  }
  return false;
}
__name(hasConfiguredBatchVoiceTranscriptionModel, "hasConfiguredBatchVoiceTranscriptionModel");
function buildWorkspaceVoiceStatus(workspaceCwd, settings) {
  return {
    v: 1,
    workspaceCwd,
    enabled: isVoiceEnabled(settings),
    mode: readVoiceMode(settings),
    language: readVoiceLanguage(settings),
    voiceModel: readVoiceModel(settings) ?? null,
    availableVoiceModels: listAvailableVoiceModels(settings)
  };
}
__name(buildWorkspaceVoiceStatus, "buildWorkspaceVoiceStatus");
function validateWorkspaceVoiceModel(settings, voiceModel) {
  const models = createVoiceModelSource(settings).getAllConfiguredModels();
  const matches = models.filter((model2) => model2.id === voiceModel);
  if (matches.length === 0) {
    throw new WorkspaceVoiceError(
      400,
      "unknown_voice_model",
      `Voice model '${voiceModel}' is not configured.`
    );
  }
  if (matches.length > 1) {
    throw new WorkspaceVoiceError(
      400,
      "ambiguous_voice_model",
      `Voice model '${voiceModel}' is ambiguous.`
    );
  }
  const [model] = matches;
  if (!model || !isSelectableVoiceModel(model)) {
    throw new WorkspaceVoiceError(
      400,
      "unsupported_voice_model",
      `Voice model '${voiceModel}' cannot be used for transcription.`
    );
  }
  const transport = resolveVoiceTransport(model.id);
  if (transport === "unsupported") {
    throw new WorkspaceVoiceError(
      400,
      "unsupported_voice_model",
      `Voice model '${voiceModel}' cannot be used for transcription.`
    );
  }
  return { id: model.id, transport };
}
__name(validateWorkspaceVoiceModel, "validateWorkspaceVoiceModel");
function validateWorkspaceVoiceConfig(settings, voiceModel, opts = {}) {
  const descriptor = validateWorkspaceVoiceModel(settings, voiceModel);
  try {
    const config = createVoiceModelSource(settings);
    if (descriptor.transport === "qwen-asr-chat") {
      resolveVoiceTranscriptionConfig({
        config,
        settings,
        voiceModel,
        env: opts.env
      });
    } else {
      resolveVoiceStreamConfig({
        config,
        settings,
        voiceModel,
        env: opts.env
      });
    }
  } catch (err) {
    throw new WorkspaceVoiceError(
      400,
      "invalid_voice_model",
      err instanceof Error ? err.message : `Voice model '${voiceModel}' is not configured for transcription.`
    );
  }
  return descriptor;
}
__name(validateWorkspaceVoiceConfig, "validateWorkspaceVoiceConfig");
function validateWorkspaceVoiceState(settings, update, opts = {}) {
  if (update.enabled === void 0 && update.mode === void 0 && update.language === void 0 && update.voiceModel === void 0) {
    throw new WorkspaceVoiceError(
      400,
      "invalid_voice_update",
      EMPTY_WORKSPACE_VOICE_UPDATE_ERROR
    );
  }
  const nextEnabled = update.enabled ?? isVoiceEnabled(settings);
  const nextVoiceModel = update.voiceModel ?? readVoiceModel(settings);
  if (update.voiceModel) {
    validateWorkspaceVoiceModel(settings, update.voiceModel);
  }
  if (!nextEnabled) {
    return;
  }
  if (!nextVoiceModel) {
    throw new WorkspaceVoiceError(
      400,
      "voice_model_required",
      "A valid voiceModel is required before enabling voice."
    );
  }
  validateWorkspaceVoiceConfig(settings, nextVoiceModel, opts);
}
__name(validateWorkspaceVoiceState, "validateWorkspaceVoiceState");
async function transcribeWorkspaceVoiceAudio(input) {
  const descriptor = validateWorkspaceVoiceModel(
    input.settings,
    input.voiceModel
  );
  if (descriptor.transport !== "qwen-asr-chat") {
    throw new WorkspaceVoiceError(
      400,
      "unsupported_voice_model",
      `Voice model '${input.voiceModel}' requires realtime transcription, which is not supported by this daemon endpoint.`
    );
  }
  const text = await transcribeVoiceAudio(
    { data: input.data, mimeType: input.mimeType },
    {
      config: createVoiceModelSource(input.settings),
      settings: input.settings,
      voiceModel: input.voiceModel,
      env: input.env,
      abortSignal: input.abortSignal
    }
  );
  return {
    text,
    model: input.voiceModel,
    transport: descriptor.transport
  };
}
__name(transcribeWorkspaceVoiceAudio, "transcribeWorkspaceVoiceAudio");

// packages/cli/src/serve/workspace-service/index.ts
async function canonicalizeExistingAncestor(inputPath) {
  let current = inputPath;
  while (true) {
    try {
      return await fs.realpath(current);
    } catch (err) {
      const code = err?.code;
      if (code !== "ENOENT" && code !== "ENOTDIR" && code !== "ELOOP") {
        throw err;
      }
      const parent = path.dirname(current);
      if (parent === current) throw err;
      current = parent;
    }
  }
}
__name(canonicalizeExistingAncestor, "canonicalizeExistingAncestor");
async function verifyParentPostOpen(target, wsCanonical, _fh) {
  const parentCanonical = await canonicalizeExistingAncestor(
    path.dirname(target)
  );
  const within = parentCanonical === wsCanonical || parentCanonical.startsWith(wsCanonical + path.sep);
  if (within) return;
  throw new WorkspaceInitSymlinkError(
    target,
    "parent",
    `Workspace context file ${JSON.stringify(target)}'s parent moved outside the workspace between the pre-open canonicalize and the post-open verify (parent canonicalizes to ${JSON.stringify(parentCanonical)}, workspace canonicalizes to ${JSON.stringify(wsCanonical)}). Refusing to write \u2014 investigate the concurrent writer or the parent-directory permissions.`
  );
}
__name(verifyParentPostOpen, "verifyParentPostOpen");
var TimeoutError = class extends Error {
  static {
    __name(this, "TimeoutError");
  }
};
async function withTimeout(promise, timeoutMs, label) {
  return await new Promise((resolve2, reject) => {
    const timeout = setTimeout(() => {
      reject(new TimeoutError(`${label} timed out after ${timeoutMs}ms`));
    }, timeoutMs);
    promise.then(
      (value) => {
        clearTimeout(timeout);
        resolve2(value);
      },
      (err) => {
        clearTimeout(timeout);
        reject(err);
      }
    );
  });
}
__name(withTimeout, "withTimeout");
function createDaemonWorkspaceService(deps) {
  const {
    boundWorkspace,
    contextFilename,
    statusProvider,
    workspaceProvidersStatusProvider,
    workspaceSkillsStatusProvider,
    isChannelLive,
    persistDisabledTools,
    persistDisabledSkills,
    persistSetting,
    persistSettings,
    voiceEnv,
    voiceSettingsScope,
    preheatAcpChild: preheatAcpChildOnBridge,
    queryWorkspaceStatus,
    invokeWorkspaceCommand,
    refreshExtensionsForAllSessions: refreshExtensionsForAllSessionsOnBridge,
    publishWorkspaceEvent
  } = deps;
  let lastWorkspaceSkillsStatus;
  let inFlightAcpPreheat;
  const getWorkspaceSkillsStatus = /* @__PURE__ */ __name(async () => {
    let status;
    try {
      status = await queryWorkspaceStatus(
        SERVE_STATUS_EXT_METHODS.workspaceSkills,
        () => createIdleWorkspaceSkillsStatus(boundWorkspace)
      );
    } catch (err) {
      writeStderrLine(
        `qwen serve: getWorkspaceSkillsStatus query failed: ${err instanceof Error ? err.message : String(err)}`
      );
      status = createIdleWorkspaceSkillsStatus(boundWorkspace);
    }
    if (status.initialized) {
      lastWorkspaceSkillsStatus = status;
      return status;
    }
    if (lastWorkspaceSkillsStatus) return lastWorkspaceSkillsStatus;
    if (workspaceSkillsStatusProvider) {
      try {
        return await workspaceSkillsStatusProvider(boundWorkspace);
      } catch (err) {
        writeStderrLine(
          `qwen serve: getWorkspaceSkillsStatus local provider failed: ${err instanceof Error ? err.message : String(err)}`
        );
      }
    }
    return status;
  }, "getWorkspaceSkillsStatus");
  return {
    // -- Status queries (delegate to ACP child via queryWorkspaceStatus) --
    async getWorkspaceMcpStatus(_ctx) {
      return queryWorkspaceStatus(
        SERVE_STATUS_EXT_METHODS.workspaceMcp,
        () => createIdleWorkspaceMcpStatus(boundWorkspace)
      );
    },
    async getWorkspaceSkillsStatus(_ctx) {
      return getWorkspaceSkillsStatus();
    },
    async getWorkspaceProvidersStatus(_ctx) {
      if (workspaceProvidersStatusProvider) {
        return workspaceProvidersStatusProvider(
          boundWorkspace,
          isChannelLive?.() ?? false
        );
      }
      return queryWorkspaceStatus(
        SERVE_STATUS_EXT_METHODS.workspaceProviders,
        () => createIdleWorkspaceProvidersStatus(boundWorkspace)
      );
    },
    async preheatAcpChild(_ctx, opts) {
      const startedAt = Date.now();
      const channelLive = /* @__PURE__ */ __name(() => isChannelLive?.() ?? false, "channelLive");
      const finish = /* @__PURE__ */ __name((result) => ({
        ...result,
        durationMs: Date.now() - startedAt
      }), "finish");
      if (channelLive()) {
        return finish({ ready: true, channelLive: true });
      }
      if (!preheatAcpChildOnBridge) {
        return finish({
          ready: false,
          channelLive: false,
          reason: "error",
          error: "ACP preheat is not wired"
        });
      }
      if (!inFlightAcpPreheat) {
        inFlightAcpPreheat = preheatAcpChildOnBridge().finally(() => {
          inFlightAcpPreheat = void 0;
        });
        void inFlightAcpPreheat.catch((err) => {
          writeStderrLine(
            `qwen serve: ACP preheat failed: ${err instanceof Error ? err.message : String(err)}`
          );
        });
      }
      try {
        await withTimeout(
          inFlightAcpPreheat,
          opts?.timeoutMs ?? 5e3,
          "ACP preheat"
        );
      } catch (err) {
        if (err instanceof TimeoutError) {
          inFlightAcpPreheat = void 0;
          writeStderrLine(
            `qwen serve: ACP preheat timed out after ${opts?.timeoutMs ?? 5e3}ms`
          );
        }
        const live2 = channelLive();
        const message = err instanceof Error ? err.message : String(err);
        return finish({
          ready: live2,
          channelLive: live2,
          reason: err instanceof TimeoutError ? "timeout" : "error",
          error: message
        });
      }
      const live = channelLive();
      return finish({ ready: live, channelLive: live });
    },
    async getWorkspaceAcpStatus(_ctx) {
      return { channelLive: isChannelLive?.() ?? false };
    },
    async getWorkspaceEnvStatus(_ctx) {
      const acpChannelLive = isChannelLive?.() ?? false;
      if (!statusProvider) {
        return createIdleEnvStatus(boundWorkspace, acpChannelLive);
      }
      try {
        return await statusProvider.getEnvStatus(
          boundWorkspace,
          acpChannelLive
        );
      } catch (err) {
        writeStderrLine(
          `qwen serve: getEnvStatus failed: ${err instanceof Error ? err.message : String(err)}`
        );
        return createIdleEnvStatus(boundWorkspace, acpChannelLive);
      }
    },
    async getWorkspacePreflightStatus(_ctx) {
      const acpChannelLive = isChannelLive?.() ?? false;
      const idleCells = createIdleAcpPreflightCells();
      let daemonCells = [];
      if (statusProvider) {
        try {
          daemonCells = await statusProvider.getDaemonPreflightCells(boundWorkspace);
        } catch (err) {
          writeStderrLine(
            `qwen serve: getDaemonPreflightCells failed: ${err instanceof Error ? err.message : String(err)}`
          );
        }
      }
      let acpCells = idleCells;
      let errors;
      if (acpChannelLive) {
        try {
          const acpResult = await queryWorkspaceStatus(
            SERVE_STATUS_EXT_METHODS.workspacePreflight,
            () => ({ cells: idleCells })
          );
          if (acpResult && "cells" in acpResult) {
            const result = acpResult;
            acpCells = result.cells.filter((c) => c.locality !== "daemon");
            errors = result.errors;
          }
        } catch (err) {
          acpCells = idleCells;
          const errorKind = mapDomainErrorToErrorKind(err);
          errors = [
            {
              kind: "preflight",
              status: "error",
              error: err instanceof Error ? err.message : String(err),
              ...errorKind ? { errorKind } : {}
            }
          ];
        }
      }
      return {
        v: STATUS_SCHEMA_VERSION,
        workspaceCwd: boundWorkspace,
        initialized: true,
        acpChannelLive,
        cells: [...daemonCells, ...acpCells],
        ...errors && errors.length > 0 ? { errors } : {}
      };
    },
    async getWorkspaceHooksStatus(_ctx) {
      return queryWorkspaceStatus(
        SERVE_STATUS_EXT_METHODS.workspaceHooks,
        () => createIdleWorkspaceHooksStatus(boundWorkspace)
      );
    },
    async getWorkspaceExtensionsStatus(_ctx) {
      return queryWorkspaceStatus(
        SERVE_STATUS_EXT_METHODS.workspaceExtensions,
        () => createIdleWorkspaceExtensionsStatus(boundWorkspace)
      );
    },
    async getWorkspaceTrustStatus(_ctx) {
      return getWorkspaceTrustStatus(
        loadSettings(boundWorkspace).merged,
        boundWorkspace
      );
    },
    async getWorkspacePermissionsStatus(_ctx) {
      return buildPermissionSettings(loadSettings(boundWorkspace));
    },
    async getWorkspaceVoiceStatus(_ctx) {
      return buildWorkspaceVoiceStatus(
        boundWorkspace,
        loadSettings(
          boundWorkspace,
          voiceEnv ? { skipLoadEnvironment: true } : true
        )
      );
    },
    // -- Mutations --
    async requestWorkspaceTrustChange(ctx, request) {
      publishWorkspaceEvent({
        type: "trust_change_requested",
        data: {
          workspaceCwd: boundWorkspace,
          desiredState: request.desiredState,
          ...request.reason !== void 0 ? { reason: request.reason } : {}
        },
        originatorClientId: ctx.originatorClientId
      });
      return {
        accepted: false,
        desiredState: request.desiredState,
        requiresOperatorAction: true
      };
    },
    async setWorkspacePermissionRules(ctx, request) {
      const key = `permissions.${request.ruleType}`;
      try {
        const result = await invokeWorkspaceCommand(
          "qwen/permissions/setRules",
          {
            cwd: boundWorkspace,
            scope: request.scope,
            ruleType: request.ruleType,
            rules: request.rules
          }
        );
        publishWorkspaceEvent({
          type: "settings_changed",
          data: { key, value: request.rules, scope: request.scope },
          originatorClientId: ctx.originatorClientId
        });
        return result;
      } catch (err) {
        if (!(err instanceof SessionNotFoundError)) {
          throw err;
        }
        throw new WorkspacePermissionRulesSessionRequiredError();
      }
    },
    async setWorkspaceVoiceSettings(ctx, request) {
      if (!persistSettings && !persistSetting) {
        throw new WorkspaceVoiceError(
          501,
          "not_implemented",
          "Workspace voice settings persistence is not available"
        );
      }
      const settings = loadSettings(
        boundWorkspace,
        voiceEnv ? { skipLoadEnvironment: true } : true
      );
      validateWorkspaceVoiceState(settings, request, { env: voiceEnv });
      const workspaceTrusted = getWorkspaceTrustStatus(settings.merged, boundWorkspace).effective.state === "trusted";
      const writes = buildWorkspaceVoiceSettingsWrites(settings, request, {
        workspaceTrusted,
        ...voiceSettingsScope ? { scopeOverride: voiceSettingsScope } : {}
      });
      const publishWrite = /* @__PURE__ */ __name((write) => {
        publishWorkspaceEvent({
          type: "settings_changed",
          data: {
            key: write.key,
            value: write.value,
            scope: voiceSettingsScopeToWire(write.scope)
          },
          originatorClientId: ctx.originatorClientId
        });
      }, "publishWrite");
      if (persistSettings) {
        try {
          await persistSettings(boundWorkspace, writes);
        } catch (err) {
          if (err instanceof WorkspaceSettingsPartialPersistError) {
            for (const write of err.committedWrites) {
              publishWrite(write);
            }
          }
          throw err;
        }
        for (const write of writes) {
          publishWrite(write);
        }
      } else {
        const committed = [];
        for (const write of writes) {
          try {
            await persistSetting(
              boundWorkspace,
              write.scope,
              write.key,
              write.value
            );
          } catch (err) {
            writeStderrLine(
              `qwen serve: workspace voice partial persist error (workspace=${boundWorkspace}, committed=${committed.length}/${writes.length}, failedKey=${write.key}, failedScope=${voiceSettingsScopeToWire(write.scope)}): ${err instanceof Error ? err.message : String(err)}`
            );
            for (const committedWrite of committed) {
              publishWrite(committedWrite);
            }
            throw new WorkspaceSettingsPartialPersistError(
              `Voice settings partial persist failed: committed=${committed.length}/${writes.length}`,
              committed,
              err
            );
          }
          committed.push(write);
        }
        for (const write of committed) {
          publishWrite(write);
        }
      }
      return buildWorkspaceVoiceStatus(
        boundWorkspace,
        loadSettings(
          boundWorkspace,
          voiceEnv ? { skipLoadEnvironment: true } : true
        )
      );
    },
    async setWorkspaceToolEnabled(ctx, toolName, enabled) {
      await persistDisabledTools(boundWorkspace, toolName, enabled);
      publishWorkspaceEvent({
        type: "tool_toggled",
        data: { toolName, enabled },
        originatorClientId: ctx.originatorClientId
      });
      return { toolName, enabled };
    },
    async setWorkspaceSkillEnabled(ctx, requestedSkillName, enabled) {
      const normalizedName = requestedSkillName.trim().toLowerCase();
      const status = await getWorkspaceSkillsStatus();
      const skill = status.skills.find(
        (candidate) => candidate.name.trim().toLowerCase() === normalizedName
      );
      if (!skill) throw new WorkspaceSkillNotFoundError(requestedSkillName);
      if (skill.userInvocable === false) {
        throw new WorkspaceSkillNotToggleableError(
          skill.name,
          "not_user_invocable"
        );
      }
      const disabled = loadSettings(boundWorkspace).merged.skills?.disabled;
      const disabledNames = new Set(
        (Array.isArray(disabled) ? disabled : []).filter((name) => typeof name === "string").map((name) => name.trim().toLowerCase()).filter(Boolean)
      );
      if (skill.level === "extension" && skill.status === "disabled" && !disabledNames.has(normalizedName)) {
        throw new WorkspaceSkillNotToggleableError(
          skill.name,
          "inactive_extension"
        );
      }
      const persisted = await persistDisabledSkills(
        boundWorkspace,
        skill.name,
        enabled
      );
      const channelLive = isChannelLive?.() ?? false;
      let activation = channelLive ? "applied" : "deferred";
      let sessionsRefreshed = 0;
      let sessionsFailed = 0;
      if (persisted.changed) {
        lastWorkspaceSkillsStatus = void 0;
        if (channelLive) {
          try {
            const refreshed = await invokeWorkspaceCommand(
              SERVE_CONTROL_EXT_METHODS.workspaceSkillsRefresh,
              { cwd: boundWorkspace }
            );
            sessionsRefreshed = refreshed.sessionsRefreshed;
            sessionsFailed = refreshed.sessionsFailed;
            if (sessionsFailed > 0) activation = "partial";
          } catch (err) {
            if (err instanceof SessionNotFoundError || err instanceof BridgeChannelClosedError) {
              activation = "deferred";
            } else {
              activation = "partial";
              sessionsFailed = 1;
              writeStderrLine(
                `qwen serve: workspace skill refresh failed: ${err instanceof Error ? err.message : String(err)}`
              );
            }
          }
        }
        publishWorkspaceEvent({
          type: "settings_changed",
          data: {
            key: "skills.disabled",
            value: persisted.disabled.length > 0 ? persisted.disabled : void 0,
            scope: "workspace"
          },
          originatorClientId: ctx.originatorClientId
        });
      }
      return {
        skillName: skill.name,
        enabled,
        changed: persisted.changed,
        activation,
        sessionsRefreshed,
        sessionsFailed
      };
    },
    async initWorkspace(ctx, opts) {
      const filename = contextFilename;
      const target = path.resolve(boundWorkspace, filename);
      const withinWorkspace = target === boundWorkspace || target.startsWith(boundWorkspace + path.sep);
      if (!withinWorkspace) {
        throw new WorkspaceInitPathEscapeError(filename, boundWorkspace);
      }
      const wsCanonical = await fs.realpath(boundWorkspace);
      const parentCanonical = await canonicalizeExistingAncestor(
        path.dirname(target)
      );
      const parentWithinWorkspace = parentCanonical === wsCanonical || parentCanonical.startsWith(wsCanonical + path.sep);
      if (!parentWithinWorkspace) {
        throw new WorkspaceInitSymlinkError(
          target,
          "parent",
          `Configured workspace context filename ${JSON.stringify(filename)} has a parent path that resolves outside the bound workspace (parent canonicalizes to ${JSON.stringify(parentCanonical)}, workspace canonicalizes to ${JSON.stringify(wsCanonical)}). Refusing to write \u2014 replace any symlinked parent directory with a real directory before re-running init.`
        );
      }
      try {
        const lst = await fs.lstat(target);
        if (lst.isSymbolicLink()) {
          throw new WorkspaceInitSymlinkError(
            target,
            "target",
            `Workspace context file ${JSON.stringify(target)} is a symlink. Refusing to follow it for write \u2014 replace the symlink with a regular file (or remove it) before re-running init.`
          );
        }
        if (!lst.isFile()) {
          throw new WorkspaceInitSymlinkError(
            target,
            "target",
            `Workspace context file ${JSON.stringify(target)} is not a regular file (mode=${lst.mode.toString(8)}). Refusing to proceed \u2014 FIFOs, sockets, and device nodes can block or misbehave on read/write.`
          );
        }
      } catch (err) {
        if (err instanceof WorkspaceInitSymlinkError) throw err;
        const code = err?.code;
        if (code !== "ENOENT") throw err;
      }
      let action = "created";
      try {
        const existing = await fs.readFile(target, "utf8");
        if (existing.trim().length > 0) {
          const existingSize = Buffer.byteLength(existing, "utf8");
          if (opts.force !== true) {
            throw new WorkspaceInitConflictError(target, existingSize);
          }
          action = "overwrote";
        } else {
          action = "noop";
        }
      } catch (err) {
        if (err instanceof WorkspaceInitConflictError) throw err;
        const code = err?.code;
        if (code !== "ENOENT") throw err;
      }
      if (action === "created") {
        let fh;
        try {
          fh = await fs.open(target, "wx");
        } catch (err) {
          const code = err?.code;
          if (code === "EEXIST") {
            throw new WorkspaceInitRaceError(
              target,
              "eexist",
              `Workspace context file ${JSON.stringify(target)} appeared between our absence check and the create \u2014 refusing to proceed (a regular file or symlink was just placed at the target path, and following it could escape the workspace).`
            );
          }
          throw err;
        }
        try {
          await verifyParentPostOpen(target, wsCanonical, fh);
          await fh.writeFile("", "utf8");
        } finally {
          await fh.close();
        }
      } else if (action === "overwrote") {
        let overwriteFh;
        try {
          overwriteFh = await fs.open(
            target,
            fsConstants.O_WRONLY | (fsConstants.O_NOFOLLOW ?? 0)
          );
        } catch (err) {
          const code = err?.code;
          if (code === "ELOOP") {
            throw new WorkspaceInitSymlinkError(
              target,
              "target",
              `Workspace context file ${JSON.stringify(target)} could not be opened with O_NOFOLLOW (ELOOP); the path may have been swapped to a symlink between the content check and the overwrite. Refusing to follow it.`
            );
          }
          if (code === "ENOENT") {
            throw new WorkspaceInitRaceError(
              target,
              "enoent",
              `Workspace context file ${JSON.stringify(target)} was deleted between the content check and the overwrite (likely a concurrent writer). Refusing to recreate blindly; rerun init.`
            );
          }
          throw err;
        }
        try {
          await verifyParentPostOpen(target, wsCanonical, overwriteFh);
          await overwriteFh.truncate(0);
        } finally {
          await overwriteFh.close();
        }
      }
      publishWorkspaceEvent({
        type: "workspace_initialized",
        data: { path: target, action },
        originatorClientId: ctx.originatorClientId
      });
      return { path: target, action };
    },
    async restartMcpServer(ctx, serverName, opts) {
      const params = { serverName };
      if (opts?.entryIndex !== void 0) {
        params["entryIndex"] = opts.entryIndex;
      }
      let result;
      try {
        result = await invokeWorkspaceCommand(
          SERVE_CONTROL_EXT_METHODS.workspaceMcpRestart,
          params,
          { timeoutMs: MCP_RESTART_SERVER_DEADLINE_MS }
        );
      } catch (err) {
        const data = err?.data;
        if (data && typeof data === "object") {
          const kind = data.errorKind;
          const sn = data.serverName;
          if (kind === "mcp_server_not_found" && typeof sn === "string") {
            throw new McpServerNotFoundError(sn);
          }
          if (kind === "mcp_restart_failed" && typeof sn === "string") {
            const status = data.mcpStatus;
            throw new McpServerRestartFailedError(
              sn,
              typeof status === "string" ? status : "unknown"
            );
          }
        }
        throw err;
      }
      if ("entries" in result) {
        const entries = Array.isArray(result.entries) ? result.entries : [];
        if (!Array.isArray(result.entries)) {
          writeStderrLine(
            `qwen serve: pool restart response carried 'entries' field but it is not an array (server=${serverName}); treating as empty.`
          );
        }
        for (const entry of entries) {
          if (typeof entry !== "object" || entry === null || typeof entry.entryIndex !== "number") {
            writeStderrLine(
              `qwen serve: skipping malformed pool restart entry (server=${serverName}): ${JSON.stringify(entry)}`
            );
            continue;
          }
          if (entry.restarted) {
            publishWorkspaceEvent({
              type: "mcp_server_restarted",
              data: {
                serverName: result.serverName,
                durationMs: entry.durationMs ?? 0,
                entryIndex: entry.entryIndex
              },
              originatorClientId: ctx.originatorClientId
            });
          } else {
            publishWorkspaceEvent({
              type: "mcp_server_restart_refused",
              data: {
                serverName: result.serverName,
                reason: "restart_failed",
                entryIndex: entry.entryIndex,
                ...entry.reason ? { details: entry.reason } : {}
              },
              originatorClientId: ctx.originatorClientId
            });
          }
        }
      } else if (result.restarted === true) {
        publishWorkspaceEvent({
          type: "mcp_server_restarted",
          data: {
            serverName: result.serverName,
            durationMs: result.durationMs
          },
          originatorClientId: ctx.originatorClientId
        });
      } else {
        publishWorkspaceEvent({
          type: "mcp_server_restart_refused",
          data: {
            serverName: result.serverName,
            reason: result.reason
          },
          originatorClientId: ctx.originatorClientId
        });
      }
      return result;
    },
    async reload(ctx) {
      if (deps.reloadDaemonEnv) {
        try {
          await deps.reloadDaemonEnv(boundWorkspace);
        } catch (err) {
          writeStderrLine(
            `qwen serve: daemon reload failed: ${err instanceof Error ? err.message : String(err)}`
          );
        }
      }
      let childReloaded = false;
      let env = {
        updatedKeys: [],
        removedKeys: []
      };
      let changedKeys = [];
      let sessionsRefreshed;
      let sessionsSkipped;
      let childError;
      try {
        const childResult = await invokeWorkspaceCommand(
          SERVE_CONTROL_EXT_METHODS.workspaceReload,
          { cwd: boundWorkspace },
          { timeoutMs: 3e4 }
        );
        childReloaded = true;
        env = childResult.env;
        changedKeys = childResult.changedKeys;
        sessionsRefreshed = childResult.sessionsRefreshed;
        sessionsSkipped = childResult.sessionsSkipped;
      } catch (err) {
        if (err instanceof SessionNotFoundError) {
          childError = "ACP child not running";
        } else {
          childError = err instanceof Error ? err.message : String(err);
          writeStderrLine(`qwen serve: reload failed: ${childError}`);
        }
      }
      publishWorkspaceEvent({
        type: "settings_reloaded",
        data: {
          env,
          changedKeys,
          childReloaded,
          sessionsRefreshed,
          sessionsSkipped,
          childError
        },
        originatorClientId: ctx.originatorClientId
      });
      return {
        env,
        changedKeys,
        childReloaded,
        sessionsRefreshed,
        sessionsSkipped,
        childError
      };
    },
    invalidateWorkspaceSkillsStatus() {
      lastWorkspaceSkillsStatus = void 0;
    },
    async refreshExtensionsForAllSessions() {
      try {
        if (!refreshExtensionsForAllSessionsOnBridge) {
          throw new Error("refreshExtensionsForAllSessions is not wired");
        }
        return await refreshExtensionsForAllSessionsOnBridge();
      } catch (err) {
        writeStderrLine(
          `qwen serve: refreshExtensionsForAllSessions failed: ${err instanceof Error ? err.message : String(err)}`
        );
        return { refreshed: 0, failed: 1 };
      } finally {
        lastWorkspaceSkillsStatus = void 0;
      }
    }
  };
}
__name(createDaemonWorkspaceService, "createDaemonWorkspaceService");

export {
  EMPTY_WORKSPACE_VOICE_UPDATE_ERROR,
  WorkspaceVoiceError,
  voiceSettingsScopeToWire,
  buildWorkspaceVoiceSettingsWrites,
  hasConfiguredBatchVoiceTranscriptionModel,
  buildWorkspaceVoiceStatus,
  validateWorkspaceVoiceState,
  transcribeWorkspaceVoiceAudio,
  createDaemonWorkspaceService
};
/**
 * @license
 * Copyright 2025 Qwen
 * SPDX-License-Identifier: Apache-2.0
 */
/**
 * @license
 * Copyright 2025 Qwen Team
 * SPDX-License-Identifier: Apache-2.0
 */
