@n1creator/openacp-cli 2026.712.3 → 2026.712.5

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/cli.js CHANGED
@@ -199,11 +199,11 @@ async function shutdownLogger() {
199
199
  logDir = void 0;
200
200
  initialized = false;
201
201
  if (transport) {
202
- await new Promise((resolve9) => {
203
- const timeout = setTimeout(resolve9, 3e3);
202
+ await new Promise((resolve8) => {
203
+ const timeout = setTimeout(resolve8, 3e3);
204
204
  transport.on("close", () => {
205
205
  clearTimeout(timeout);
206
- resolve9();
206
+ resolve8();
207
207
  });
208
208
  transport.end();
209
209
  });
@@ -345,21 +345,21 @@ function compareVersions(current, latest) {
345
345
  }
346
346
  async function runUpdate() {
347
347
  const { spawn: spawn9 } = await import("child_process");
348
- return new Promise((resolve9) => {
348
+ return new Promise((resolve8) => {
349
349
  const child = spawn9("npm", ["install", "-g", `${NPM_PACKAGE}@latest`], {
350
350
  stdio: "inherit",
351
351
  shell: false
352
352
  });
353
353
  const onSignal = () => {
354
354
  child.kill("SIGTERM");
355
- resolve9(false);
355
+ resolve8(false);
356
356
  };
357
357
  process.on("SIGINT", onSignal);
358
358
  process.on("SIGTERM", onSignal);
359
359
  child.on("close", (code) => {
360
360
  process.off("SIGINT", onSignal);
361
361
  process.off("SIGTERM", onSignal);
362
- resolve9(code === 0);
362
+ resolve8(code === 0);
363
363
  });
364
364
  });
365
365
  }
@@ -4996,12 +4996,203 @@ var init_groq = __esm({
4996
4996
  }
4997
4997
  });
4998
4998
 
4999
+ // src/plugins/speech/providers/local-whisper.ts
5000
+ import { execFile } from "child_process";
5001
+ import { existsSync as existsSync2 } from "fs";
5002
+ import { mkdtemp, rm, writeFile } from "fs/promises";
5003
+ import { tmpdir } from "os";
5004
+ import path9 from "path";
5005
+ import { fileURLToPath as fileURLToPath2 } from "url";
5006
+ import { promisify } from "util";
5007
+ function resolveLocalWhisperScriptPath() {
5008
+ const moduleDir = path9.dirname(fileURLToPath2(import.meta.url));
5009
+ const candidates = [
5010
+ path9.resolve(moduleDir, "../scripts/transcribe_audio.sh"),
5011
+ path9.resolve(moduleDir, "speech/transcribe_audio.sh")
5012
+ ];
5013
+ return candidates.find(existsSync2) ?? candidates[0];
5014
+ }
5015
+ function mimeToExt2(mimeType) {
5016
+ const normalized = mimeType.split(";", 1)[0]?.trim().toLowerCase();
5017
+ const extensions = {
5018
+ "audio/ogg": ".ogg",
5019
+ "audio/opus": ".ogg",
5020
+ "audio/wav": ".wav",
5021
+ "audio/x-wav": ".wav",
5022
+ "audio/mpeg": ".mp3",
5023
+ "audio/mp3": ".mp3",
5024
+ "audio/mp4": ".m4a",
5025
+ "audio/aac": ".aac",
5026
+ "audio/webm": ".webm",
5027
+ "audio/flac": ".flac"
5028
+ };
5029
+ return normalized && extensions[normalized] || ".bin";
5030
+ }
5031
+ function parseMetadata(stderr) {
5032
+ const language = /\blanguage=([^\s]+)/.exec(stderr)?.[1];
5033
+ const durationRaw = /\bduration=([0-9.]+)s\b/.exec(stderr)?.[1];
5034
+ const duration = durationRaw ? Number(durationRaw) : void 0;
5035
+ return { language, duration: Number.isFinite(duration) ? duration : void 0 };
5036
+ }
5037
+ function formatExecError(error) {
5038
+ if (!(error instanceof Error)) return String(error);
5039
+ const execError = error;
5040
+ const details = [execError.stderr, execError.stdout].filter(Boolean).join("\n").trim();
5041
+ const code = execError.code === void 0 ? "" : ` (exit ${execError.code})`;
5042
+ return details ? `${error.message}${code}: ${details}` : `${error.message}${code}`;
5043
+ }
5044
+ var execFileAsync, LOCAL_WHISPER_PROVIDER, LOCAL_WHISPER_DEFAULTS, LocalWhisperSTT;
5045
+ var init_local_whisper = __esm({
5046
+ "src/plugins/speech/providers/local-whisper.ts"() {
5047
+ "use strict";
5048
+ execFileAsync = promisify(execFile);
5049
+ LOCAL_WHISPER_PROVIDER = "local-whisper";
5050
+ LOCAL_WHISPER_DEFAULTS = {
5051
+ language: "ru",
5052
+ model: "base",
5053
+ beamSize: 5,
5054
+ vadFilter: false,
5055
+ device: "cpu",
5056
+ computeType: "int8",
5057
+ timeoutMs: 12e4
5058
+ };
5059
+ LocalWhisperSTT = class {
5060
+ name = LOCAL_WHISPER_PROVIDER;
5061
+ config;
5062
+ constructor(options = {}) {
5063
+ this.config = {
5064
+ scriptPath: options.scriptPath ?? resolveLocalWhisperScriptPath(),
5065
+ language: options.language ?? LOCAL_WHISPER_DEFAULTS.language,
5066
+ model: options.model ?? LOCAL_WHISPER_DEFAULTS.model,
5067
+ beamSize: options.beamSize ?? LOCAL_WHISPER_DEFAULTS.beamSize,
5068
+ vadFilter: options.vadFilter ?? LOCAL_WHISPER_DEFAULTS.vadFilter,
5069
+ device: options.device ?? LOCAL_WHISPER_DEFAULTS.device,
5070
+ computeType: options.computeType ?? LOCAL_WHISPER_DEFAULTS.computeType,
5071
+ timeoutMs: options.timeoutMs ?? LOCAL_WHISPER_DEFAULTS.timeoutMs,
5072
+ tempRoot: options.tempRoot
5073
+ };
5074
+ }
5075
+ async transcribe(audioBuffer, mimeType, options) {
5076
+ const tempDir = await mkdtemp(path9.join(this.config.tempRoot ?? tmpdir(), "openacp-local-whisper-"));
5077
+ const audioPath = path9.join(tempDir, `input${mimeToExt2(mimeType)}`);
5078
+ try {
5079
+ await writeFile(audioPath, audioBuffer);
5080
+ const { stdout, stderr } = await execFileAsync(this.config.scriptPath, this.buildArgs(audioPath, options), {
5081
+ timeout: this.config.timeoutMs,
5082
+ maxBuffer: 10 * 1024 * 1024
5083
+ });
5084
+ const text5 = stdout.trim();
5085
+ if (!text5) throw new Error("Local Whisper returned an empty transcript");
5086
+ return { text: text5, ...parseMetadata(stderr) };
5087
+ } catch (error) {
5088
+ throw new Error(`Local Whisper STT failed: ${formatExecError(error)}`);
5089
+ } finally {
5090
+ await rm(tempDir, { recursive: true, force: true });
5091
+ }
5092
+ }
5093
+ buildArgs(audioPath, options) {
5094
+ return [
5095
+ "--model",
5096
+ options?.model ?? this.config.model,
5097
+ "--language",
5098
+ options?.language ?? this.config.language,
5099
+ "--beam-size",
5100
+ String(this.config.beamSize),
5101
+ "--device",
5102
+ this.config.device,
5103
+ "--compute-type",
5104
+ this.config.computeType,
5105
+ this.config.vadFilter ? "--vad-filter" : "--no-vad-filter",
5106
+ audioPath
5107
+ ];
5108
+ }
5109
+ };
5110
+ }
5111
+ });
5112
+
4999
5113
  // src/plugins/speech/exports.ts
5000
5114
  var init_exports = __esm({
5001
5115
  "src/plugins/speech/exports.ts"() {
5002
5116
  "use strict";
5003
5117
  init_speech_service();
5004
5118
  init_groq();
5119
+ init_local_whisper();
5120
+ }
5121
+ });
5122
+
5123
+ // src/plugins/speech/native-stt.ts
5124
+ function readLocalWhisperSettings(raw) {
5125
+ return {
5126
+ scriptPath: readString(raw.localWhisperScriptPath, resolveLocalWhisperScriptPath()),
5127
+ language: readString(raw.localWhisperLanguage, LOCAL_WHISPER_DEFAULTS.language),
5128
+ model: readString(raw.localWhisperModel, LOCAL_WHISPER_DEFAULTS.model),
5129
+ beamSize: readNumber(raw.localWhisperBeamSize, LOCAL_WHISPER_DEFAULTS.beamSize),
5130
+ vadFilter: readBoolean(raw.localWhisperVadFilter, LOCAL_WHISPER_DEFAULTS.vadFilter),
5131
+ device: readString(raw.localWhisperDevice, LOCAL_WHISPER_DEFAULTS.device),
5132
+ computeType: readString(raw.localWhisperComputeType, LOCAL_WHISPER_DEFAULTS.computeType),
5133
+ timeoutMs: readNumber(raw.localWhisperTimeoutMs, LOCAL_WHISPER_DEFAULTS.timeoutMs)
5134
+ };
5135
+ }
5136
+ function buildSpeechServiceConfig(raw) {
5137
+ const groqApiKey = readOptionalString(raw.groqApiKey);
5138
+ const requestedProvider = readOptionalString(raw.sttProvider);
5139
+ const provider = requestedProvider === LOCAL_WHISPER_PROVIDER ? LOCAL_WHISPER_PROVIDER : groqApiKey ? "groq" : null;
5140
+ const providers = {};
5141
+ if (groqApiKey) providers.groq = { apiKey: groqApiKey };
5142
+ if (provider === LOCAL_WHISPER_PROVIDER) {
5143
+ providers[LOCAL_WHISPER_PROVIDER] = {
5144
+ apiKey: "local",
5145
+ ...readLocalWhisperSettings(raw)
5146
+ };
5147
+ }
5148
+ return {
5149
+ stt: { provider, providers },
5150
+ tts: {
5151
+ provider: readOptionalString(raw.ttsProvider) ?? "edge-tts",
5152
+ providers: {}
5153
+ }
5154
+ };
5155
+ }
5156
+ function createNativeSTTProviders(config) {
5157
+ const providers = /* @__PURE__ */ new Map();
5158
+ const groq = config.stt.providers.groq;
5159
+ if (groq?.apiKey) providers.set("groq", new GroqSTT(groq.apiKey, groq.model));
5160
+ const local = config.stt.providers[LOCAL_WHISPER_PROVIDER];
5161
+ if (local?.apiKey !== void 0) {
5162
+ providers.set(LOCAL_WHISPER_PROVIDER, new LocalWhisperSTT({
5163
+ scriptPath: readOptionalString(local.scriptPath),
5164
+ language: readOptionalString(local.language),
5165
+ model: readOptionalString(local.model),
5166
+ beamSize: readOptionalNumber(local.beamSize),
5167
+ vadFilter: typeof local.vadFilter === "boolean" ? local.vadFilter : void 0,
5168
+ device: readOptionalString(local.device),
5169
+ computeType: readOptionalString(local.computeType),
5170
+ timeoutMs: readOptionalNumber(local.timeoutMs)
5171
+ }));
5172
+ }
5173
+ return providers;
5174
+ }
5175
+ function readString(value, fallback) {
5176
+ return readOptionalString(value) ?? fallback;
5177
+ }
5178
+ function readOptionalString(value) {
5179
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
5180
+ }
5181
+ function readNumber(value, fallback) {
5182
+ return readOptionalNumber(value) ?? fallback;
5183
+ }
5184
+ function readOptionalNumber(value) {
5185
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
5186
+ }
5187
+ function readBoolean(value, fallback) {
5188
+ return typeof value === "boolean" ? value : fallback;
5189
+ }
5190
+ var init_native_stt = __esm({
5191
+ "src/plugins/speech/native-stt.ts"() {
5192
+ "use strict";
5193
+ init_groq();
5194
+ init_local_whisper();
5195
+ init_local_whisper();
5005
5196
  }
5006
5197
  });
5007
5198
 
@@ -5011,14 +5202,14 @@ __export(plugin_installer_exports, {
5011
5202
  importFromDir: () => importFromDir,
5012
5203
  installNpmPlugin: () => installNpmPlugin
5013
5204
  });
5014
- import { execFile } from "child_process";
5015
- import { promisify } from "util";
5205
+ import { execFile as execFile2 } from "child_process";
5206
+ import { promisify as promisify2 } from "util";
5016
5207
  import * as fs8 from "fs/promises";
5017
- import * as path9 from "path";
5208
+ import * as path10 from "path";
5018
5209
  import { pathToFileURL } from "url";
5019
5210
  async function importFromDir(packageName, dir) {
5020
- const pkgDir = path9.join(dir, "node_modules", ...packageName.split("/"));
5021
- const pkgJsonPath = path9.join(pkgDir, "package.json");
5211
+ const pkgDir = path10.join(dir, "node_modules", ...packageName.split("/"));
5212
+ const pkgJsonPath = path10.join(pkgDir, "package.json");
5022
5213
  let pkgJson;
5023
5214
  try {
5024
5215
  pkgJson = JSON.parse(await fs8.readFile(pkgJsonPath, "utf-8"));
@@ -5034,7 +5225,7 @@ async function importFromDir(packageName, dir) {
5034
5225
  } else {
5035
5226
  entry = pkgJson.main ?? "index.js";
5036
5227
  }
5037
- const entryPath = path9.join(pkgDir, entry);
5228
+ const entryPath = path10.join(pkgDir, entry);
5038
5229
  try {
5039
5230
  await fs8.access(entryPath);
5040
5231
  } catch {
@@ -5051,16 +5242,16 @@ async function installNpmPlugin(packageName, pluginsDir) {
5051
5242
  return await importFromDir(packageName, dir);
5052
5243
  } catch {
5053
5244
  }
5054
- await execFileAsync("npm", ["install", packageName, "--prefix", dir, "--save", "--ignore-scripts"], {
5245
+ await execFileAsync2("npm", ["install", packageName, "--prefix", dir, "--save", "--ignore-scripts"], {
5055
5246
  timeout: 6e4
5056
5247
  });
5057
5248
  return await importFromDir(packageName, dir);
5058
5249
  }
5059
- var execFileAsync, VALID_NPM_NAME;
5250
+ var execFileAsync2, VALID_NPM_NAME;
5060
5251
  var init_plugin_installer = __esm({
5061
5252
  "src/core/plugin/plugin-installer.ts"() {
5062
5253
  "use strict";
5063
- execFileAsync = promisify(execFile);
5254
+ execFileAsync2 = promisify2(execFile2);
5064
5255
  VALID_NPM_NAME = /^(@[a-z0-9][\w.-]*\/)?[a-z0-9][\w.-]*(@[\w.^~>=<|-]+)?$/i;
5065
5256
  }
5066
5257
  });
@@ -5070,12 +5261,13 @@ var speech_exports = {};
5070
5261
  __export(speech_exports, {
5071
5262
  default: () => speech_default
5072
5263
  });
5073
- import path10 from "path";
5264
+ import path11 from "path";
5074
5265
  var EDGE_TTS_PLUGIN, speechPlugin, speech_default;
5075
5266
  var init_speech = __esm({
5076
5267
  "src/plugins/speech/index.ts"() {
5077
5268
  "use strict";
5078
5269
  init_exports();
5270
+ init_native_stt();
5079
5271
  init_plugin_installer();
5080
5272
  EDGE_TTS_PLUGIN = "@openacp/msedge-tts-plugin";
5081
5273
  speechPlugin = {
@@ -5089,17 +5281,22 @@ var init_speech = __esm({
5089
5281
  inheritableKeys: ["ttsProvider", "ttsVoice"],
5090
5282
  async install(ctx) {
5091
5283
  const { terminal, settings } = ctx;
5092
- const pluginsDir = ctx.instanceRoot ? path10.join(ctx.instanceRoot, "plugins") : void 0;
5284
+ const pluginsDir = ctx.instanceRoot ? path11.join(ctx.instanceRoot, "plugins") : void 0;
5093
5285
  const enableStt = await terminal.confirm({
5094
5286
  message: "Enable speech-to-text (STT)?",
5095
5287
  initialValue: false
5096
5288
  });
5097
5289
  let sttProvider = null;
5098
5290
  let groqApiKey = "";
5291
+ let localWhisperLanguage = LOCAL_WHISPER_DEFAULTS.language;
5292
+ let localWhisperModel = LOCAL_WHISPER_DEFAULTS.model;
5099
5293
  if (enableStt) {
5100
5294
  sttProvider = await terminal.select({
5101
5295
  message: "STT provider:",
5102
- options: [{ value: "groq", label: "Groq (Whisper)", hint: "Fast and affordable" }]
5296
+ options: [
5297
+ { value: LOCAL_WHISPER_PROVIDER, label: "Local faster-whisper", hint: "Private and offline after the first model download" },
5298
+ { value: "groq", label: "Groq (Whisper)", hint: "Hosted API, requires an API key" }
5299
+ ]
5103
5300
  });
5104
5301
  if (sttProvider === "groq") {
5105
5302
  groqApiKey = await terminal.text({
@@ -5107,6 +5304,15 @@ var init_speech = __esm({
5107
5304
  validate: (v) => !v.trim() ? "API key cannot be empty" : void 0
5108
5305
  });
5109
5306
  groqApiKey = groqApiKey.trim();
5307
+ } else {
5308
+ localWhisperLanguage = (await terminal.text({
5309
+ message: "Local Whisper language:",
5310
+ defaultValue: LOCAL_WHISPER_DEFAULTS.language
5311
+ })).trim() || LOCAL_WHISPER_DEFAULTS.language;
5312
+ localWhisperModel = (await terminal.text({
5313
+ message: "Local Whisper model:",
5314
+ defaultValue: LOCAL_WHISPER_DEFAULTS.model
5315
+ })).trim() || LOCAL_WHISPER_DEFAULTS.model;
5110
5316
  }
5111
5317
  }
5112
5318
  const ttsProvider = await terminal.select({
@@ -5134,6 +5340,13 @@ var init_speech = __esm({
5134
5340
  await settings.setAll({
5135
5341
  sttProvider,
5136
5342
  groqApiKey,
5343
+ localWhisperLanguage,
5344
+ localWhisperModel,
5345
+ localWhisperBeamSize: LOCAL_WHISPER_DEFAULTS.beamSize,
5346
+ localWhisperVadFilter: LOCAL_WHISPER_DEFAULTS.vadFilter,
5347
+ localWhisperDevice: LOCAL_WHISPER_DEFAULTS.device,
5348
+ localWhisperComputeType: LOCAL_WHISPER_DEFAULTS.computeType,
5349
+ localWhisperTimeoutMs: LOCAL_WHISPER_DEFAULTS.timeoutMs,
5137
5350
  ttsProvider: ttsProvider === "none" ? null : ttsProvider,
5138
5351
  ttsVoice
5139
5352
  });
@@ -5151,13 +5364,34 @@ var init_speech = __esm({
5151
5364
  ]
5152
5365
  });
5153
5366
  if (choice === "stt") {
5154
- const key = await terminal.text({
5155
- message: "Groq API key (leave blank to disable STT):",
5156
- defaultValue: current.groqApiKey ?? ""
5367
+ const provider = await terminal.select({
5368
+ message: "STT provider:",
5369
+ options: [
5370
+ { value: LOCAL_WHISPER_PROVIDER, label: "Local faster-whisper", hint: "Private and offline after the first model download" },
5371
+ { value: "groq", label: "Groq (Whisper)", hint: "Hosted API, requires an API key" },
5372
+ { value: "none", label: "None (disable STT)" }
5373
+ ]
5157
5374
  });
5158
- const trimmed = key.trim();
5159
- await settings.set("sttProvider", trimmed ? "groq" : null);
5160
- await settings.set("groqApiKey", trimmed);
5375
+ await settings.set("sttProvider", provider === "none" ? null : provider);
5376
+ if (provider === "groq") {
5377
+ const key = await terminal.text({
5378
+ message: "Groq API key:",
5379
+ defaultValue: current.groqApiKey ?? "",
5380
+ validate: (v) => !v.trim() ? "API key cannot be empty" : void 0
5381
+ });
5382
+ await settings.set("groqApiKey", key.trim());
5383
+ } else if (provider === LOCAL_WHISPER_PROVIDER) {
5384
+ const language = await terminal.text({
5385
+ message: "Local Whisper language:",
5386
+ defaultValue: current.localWhisperLanguage ?? LOCAL_WHISPER_DEFAULTS.language
5387
+ });
5388
+ const model = await terminal.text({
5389
+ message: "Local Whisper model:",
5390
+ defaultValue: current.localWhisperModel ?? LOCAL_WHISPER_DEFAULTS.model
5391
+ });
5392
+ await settings.set("localWhisperLanguage", language.trim() || LOCAL_WHISPER_DEFAULTS.language);
5393
+ await settings.set("localWhisperModel", model.trim() || LOCAL_WHISPER_DEFAULTS.model);
5394
+ }
5161
5395
  terminal.log.success("STT settings updated");
5162
5396
  } else if (choice === "tts") {
5163
5397
  const voice = await terminal.text({
@@ -5176,37 +5410,26 @@ var init_speech = __esm({
5176
5410
  },
5177
5411
  async setup(ctx) {
5178
5412
  ctx.registerEditableFields([
5179
- { key: "sttProvider", displayName: "Speech to Text", type: "select", scope: "safe", hotReload: true, options: ["groq"] },
5180
- { key: "groqApiKey", displayName: "STT API Key", type: "string", scope: "sensitive", hotReload: true },
5413
+ { key: "sttProvider", displayName: "Speech to Text", type: "select", scope: "safe", hotReload: true, options: [LOCAL_WHISPER_PROVIDER, "groq"] },
5414
+ { key: "groqApiKey", displayName: "Groq STT API Key", type: "string", scope: "sensitive", hotReload: true },
5415
+ { key: "localWhisperLanguage", displayName: "Local Whisper Language", type: "string", scope: "safe", hotReload: true },
5416
+ { key: "localWhisperModel", displayName: "Local Whisper Model", type: "string", scope: "safe", hotReload: true },
5417
+ { key: "localWhisperBeamSize", displayName: "Local Whisper Beam Size", type: "number", scope: "safe", hotReload: true },
5418
+ { key: "localWhisperVadFilter", displayName: "Local Whisper VAD Filter", type: "toggle", scope: "safe", hotReload: true },
5419
+ { key: "localWhisperDevice", displayName: "Local Whisper Device", type: "select", scope: "safe", hotReload: true, options: ["cpu", "cuda", "auto"] },
5420
+ { key: "localWhisperComputeType", displayName: "Local Whisper Compute Type", type: "string", scope: "safe", hotReload: true },
5421
+ { key: "localWhisperTimeoutMs", displayName: "Local Whisper Timeout (ms)", type: "number", scope: "safe", hotReload: true },
5422
+ { key: "localWhisperScriptPath", displayName: "Local Whisper Script Path", type: "string", scope: "safe", hotReload: true },
5181
5423
  { key: "ttsProvider", displayName: "Text to Speech", type: "select", scope: "safe", hotReload: true, options: ["edge-tts"] }
5182
5424
  ]);
5183
- const pluginsDir = ctx.instanceRoot ? path10.join(ctx.instanceRoot, "plugins") : void 0;
5425
+ const pluginsDir = ctx.instanceRoot ? path11.join(ctx.instanceRoot, "plugins") : void 0;
5184
5426
  const config = ctx.pluginConfig;
5185
- const groqApiKey = config.groqApiKey;
5186
- const sttProvider = groqApiKey ? "groq" : null;
5187
- const speechConfig = {
5188
- stt: {
5189
- provider: sttProvider,
5190
- providers: groqApiKey ? { groq: { apiKey: groqApiKey } } : {}
5191
- },
5192
- tts: {
5193
- provider: config.ttsProvider ?? "edge-tts",
5194
- providers: {}
5195
- }
5196
- };
5427
+ const speechConfig = buildSpeechServiceConfig(config);
5197
5428
  const service = new SpeechService(speechConfig);
5198
- if (groqApiKey) {
5199
- service.registerSTTProvider("groq", new GroqSTT(groqApiKey));
5429
+ for (const [name, provider] of createNativeSTTProviders(speechConfig)) {
5430
+ service.registerSTTProvider(name, provider);
5200
5431
  }
5201
- service.setProviderFactory((cfg) => {
5202
- const sttMap = /* @__PURE__ */ new Map();
5203
- const ttsMap = /* @__PURE__ */ new Map();
5204
- const groqCfg = cfg.stt?.providers?.groq;
5205
- if (groqCfg?.apiKey) {
5206
- sttMap.set("groq", new GroqSTT(groqCfg.apiKey, groqCfg.model));
5207
- }
5208
- return { stt: sttMap, tts: ttsMap };
5209
- });
5432
+ service.setProviderFactory((cfg) => ({ stt: createNativeSTTProviders(cfg), tts: /* @__PURE__ */ new Map() }));
5210
5433
  ctx.registerService("speech", service);
5211
5434
  const setSessionVoiceMode = (pluginCtx, sessionId, voiceMode) => {
5212
5435
  if (!sessionId) return;
@@ -5534,7 +5757,7 @@ __export(agent_dependencies_exports, {
5534
5757
  });
5535
5758
  import { execFileSync as execFileSync2 } from "child_process";
5536
5759
  import * as fs9 from "fs";
5537
- import * as path11 from "path";
5760
+ import * as path12 from "path";
5538
5761
  function getAgentSetup(registryId) {
5539
5762
  return AGENT_SETUP[registryId];
5540
5763
  }
@@ -5558,9 +5781,9 @@ function commandExists(cmd) {
5558
5781
  }
5559
5782
  let dir = process.cwd();
5560
5783
  while (true) {
5561
- const binPath = path11.join(dir, "node_modules", ".bin", cmd);
5784
+ const binPath = path12.join(dir, "node_modules", ".bin", cmd);
5562
5785
  if (fs9.existsSync(binPath)) return true;
5563
- const parent = path11.dirname(dir);
5786
+ const parent = path12.dirname(dir);
5564
5787
  if (parent === dir) break;
5565
5788
  dir = parent;
5566
5789
  }
@@ -5826,7 +6049,7 @@ var init_agent_dependencies = __esm({
5826
6049
 
5827
6050
  // src/core/agents/agent-installer.ts
5828
6051
  import * as fs10 from "fs";
5829
- import * as path12 from "path";
6052
+ import * as path13 from "path";
5830
6053
  import * as os2 from "os";
5831
6054
  import crypto2 from "crypto";
5832
6055
  function validateArchiveContents(entries, destDir) {
@@ -5841,9 +6064,9 @@ function validateArchiveContents(entries, destDir) {
5841
6064
  }
5842
6065
  }
5843
6066
  function validateUninstallPath(binaryPath, agentsDir) {
5844
- const realPath = path12.resolve(binaryPath);
5845
- const realAgentsDir = path12.resolve(agentsDir);
5846
- if (!realPath.startsWith(realAgentsDir + path12.sep) && realPath !== realAgentsDir) {
6067
+ const realPath = path13.resolve(binaryPath);
6068
+ const realAgentsDir = path13.resolve(agentsDir);
6069
+ if (!realPath.startsWith(realAgentsDir + path13.sep) && realPath !== realAgentsDir) {
5847
6070
  throw new Error(`Refusing to delete path outside agents directory: ${realPath}`);
5848
6071
  }
5849
6072
  }
@@ -5897,7 +6120,7 @@ function buildInstalledAgent(registryId, name, version, dist, binaryPath) {
5897
6120
  binaryPath: null
5898
6121
  };
5899
6122
  }
5900
- const absCmd = path12.resolve(binaryPath, dist.cmd);
6123
+ const absCmd = path13.resolve(binaryPath, dist.cmd);
5901
6124
  return {
5902
6125
  registryId,
5903
6126
  name,
@@ -5963,7 +6186,7 @@ Install it with: pip install uv`;
5963
6186
  return { ok: true, agentKey, setupSteps: setupSteps.length > 0 ? setupSteps : void 0 };
5964
6187
  }
5965
6188
  async function downloadAndExtract(agentId, archiveUrl, progress, agentsDir) {
5966
- const destDir = path12.join(agentsDir ?? DEFAULT_AGENTS_DIR, agentId);
6189
+ const destDir = path13.join(agentsDir ?? DEFAULT_AGENTS_DIR, agentId);
5967
6190
  fs10.mkdirSync(destDir, { recursive: true });
5968
6191
  await progress?.onStep("Downloading...");
5969
6192
  log2.info({ agentId, url: archiveUrl }, "Downloading agent binary");
@@ -6010,15 +6233,15 @@ function validateExtractedPaths(destDir) {
6010
6233
  for (const entry of entries) {
6011
6234
  const dirent = entry;
6012
6235
  const parentPath = dirent.parentPath ?? dirent.path ?? destDir;
6013
- const fullPath = path12.join(parentPath, entry.name);
6236
+ const fullPath = path13.join(parentPath, entry.name);
6014
6237
  let realPath;
6015
6238
  try {
6016
6239
  realPath = fs10.realpathSync(fullPath);
6017
6240
  } catch {
6018
6241
  const linkTarget = fs10.readlinkSync(fullPath);
6019
- realPath = path12.resolve(path12.dirname(fullPath), linkTarget);
6242
+ realPath = path13.resolve(path13.dirname(fullPath), linkTarget);
6020
6243
  }
6021
- if (!realPath.startsWith(realDest + path12.sep) && realPath !== realDest) {
6244
+ if (!realPath.startsWith(realDest + path13.sep) && realPath !== realDest) {
6022
6245
  fs10.rmSync(destDir, { recursive: true, force: true });
6023
6246
  throw new Error(`Archive contains unsafe path: ${entry.name}`);
6024
6247
  }
@@ -6026,7 +6249,7 @@ function validateExtractedPaths(destDir) {
6026
6249
  }
6027
6250
  async function extractTarGz(buffer, destDir) {
6028
6251
  const { execFileSync: execFileSync9 } = await import("child_process");
6029
- const tmpFile = path12.join(destDir, "_archive.tar.gz");
6252
+ const tmpFile = path13.join(destDir, "_archive.tar.gz");
6030
6253
  fs10.writeFileSync(tmpFile, buffer);
6031
6254
  try {
6032
6255
  const listing = execFileSync9("tar", ["tf", tmpFile], { stdio: "pipe" }).toString().trim().split("\n").filter(Boolean);
@@ -6039,7 +6262,7 @@ async function extractTarGz(buffer, destDir) {
6039
6262
  }
6040
6263
  async function extractZip(buffer, destDir) {
6041
6264
  const { execFileSync: execFileSync9 } = await import("child_process");
6042
- const tmpFile = path12.join(destDir, "_archive.zip");
6265
+ const tmpFile = path13.join(destDir, "_archive.zip");
6043
6266
  fs10.writeFileSync(tmpFile, buffer);
6044
6267
  try {
6045
6268
  const listing = execFileSync9("unzip", ["-l", tmpFile], { stdio: "pipe" }).toString().trim().split("\n").filter(Boolean);
@@ -6068,7 +6291,7 @@ var init_agent_installer = __esm({
6068
6291
  init_log();
6069
6292
  init_agent_dependencies();
6070
6293
  log2 = createChildLogger({ module: "agent-installer" });
6071
- DEFAULT_AGENTS_DIR = path12.join(os2.homedir(), ".openacp", "agents");
6294
+ DEFAULT_AGENTS_DIR = path13.join(os2.homedir(), ".openacp", "agents");
6072
6295
  MAX_DOWNLOAD_SIZE = 500 * 1024 * 1024;
6073
6296
  validateTarContents = validateArchiveContents;
6074
6297
  ARCH_MAP = {
@@ -6085,12 +6308,12 @@ var init_agent_installer = __esm({
6085
6308
 
6086
6309
  // src/core/utils/install-binary.ts
6087
6310
  import fs11 from "fs";
6088
- import path13 from "path";
6311
+ import path14 from "path";
6089
6312
  import https from "https";
6090
6313
  import os3 from "os";
6091
6314
  import { execFileSync as execFileSync3 } from "child_process";
6092
6315
  function downloadFile(url, dest, maxRedirects = 10) {
6093
- return new Promise((resolve9, reject) => {
6316
+ return new Promise((resolve8, reject) => {
6094
6317
  const file = fs11.createWriteStream(dest);
6095
6318
  const cleanup = () => {
6096
6319
  try {
@@ -6109,7 +6332,7 @@ function downloadFile(url, dest, maxRedirects = 10) {
6109
6332
  }
6110
6333
  file.close(() => {
6111
6334
  cleanup();
6112
- downloadFile(response.headers.location, dest, maxRedirects - 1).then(resolve9).catch(reject);
6335
+ downloadFile(response.headers.location, dest, maxRedirects - 1).then(resolve8).catch(reject);
6113
6336
  });
6114
6337
  return;
6115
6338
  }
@@ -6133,7 +6356,7 @@ function downloadFile(url, dest, maxRedirects = 10) {
6133
6356
  }
6134
6357
  });
6135
6358
  response.pipe(file);
6136
- file.on("finish", () => file.close(() => resolve9(dest)));
6359
+ file.on("finish", () => file.close(() => resolve8(dest)));
6137
6360
  file.on("error", (err) => {
6138
6361
  file.close(() => {
6139
6362
  cleanup();
@@ -6160,7 +6383,7 @@ function getDownloadUrl(spec) {
6160
6383
  async function ensureBinary(spec, binDir) {
6161
6384
  const resolvedBinDir = binDir ?? DEFAULT_BIN_DIR;
6162
6385
  const binName = IS_WINDOWS ? `${spec.name}.exe` : spec.name;
6163
- const binPath = path13.join(resolvedBinDir, binName);
6386
+ const binPath = path14.join(resolvedBinDir, binName);
6164
6387
  if (commandExists(spec.name)) {
6165
6388
  log3.debug({ name: spec.name }, "Found in PATH");
6166
6389
  return spec.name;
@@ -6174,7 +6397,7 @@ async function ensureBinary(spec, binDir) {
6174
6397
  fs11.mkdirSync(resolvedBinDir, { recursive: true });
6175
6398
  const url = getDownloadUrl(spec);
6176
6399
  const isArchive = spec.isArchive?.(url) ?? false;
6177
- const downloadDest = isArchive ? path13.join(resolvedBinDir, `${spec.name}.tgz`) : binPath;
6400
+ const downloadDest = isArchive ? path14.join(resolvedBinDir, `${spec.name}.tgz`) : binPath;
6178
6401
  await downloadFile(url, downloadDest);
6179
6402
  if (isArchive) {
6180
6403
  const listing = execFileSync3("tar", ["-tf", downloadDest], { stdio: "pipe" }).toString().trim().split("\n").filter(Boolean);
@@ -6202,7 +6425,7 @@ var init_install_binary = __esm({
6202
6425
  init_agent_dependencies();
6203
6426
  init_agent_installer();
6204
6427
  log3 = createChildLogger({ module: "binary-installer" });
6205
- DEFAULT_BIN_DIR = path13.join(os3.homedir(), ".openacp", "bin");
6428
+ DEFAULT_BIN_DIR = path14.join(os3.homedir(), ".openacp", "bin");
6206
6429
  IS_WINDOWS = os3.platform() === "win32";
6207
6430
  }
6208
6431
  });
@@ -6245,7 +6468,7 @@ var init_install_cloudflared = __esm({
6245
6468
  // src/plugins/tunnel/providers/cloudflare.ts
6246
6469
  import { spawn } from "child_process";
6247
6470
  import fs12 from "fs";
6248
- import path14 from "path";
6471
+ import path15 from "path";
6249
6472
  var log4, SIGKILL_TIMEOUT_MS, CloudflareTunnelProvider;
6250
6473
  var init_cloudflare = __esm({
6251
6474
  "src/plugins/tunnel/providers/cloudflare.ts"() {
@@ -6282,7 +6505,7 @@ var init_cloudflare = __esm({
6282
6505
  if (this.options.domain) {
6283
6506
  args2.push("--hostname", String(this.options.domain));
6284
6507
  }
6285
- return new Promise((resolve9, reject) => {
6508
+ return new Promise((resolve8, reject) => {
6286
6509
  let settled = false;
6287
6510
  const settle = (fn) => {
6288
6511
  if (!settled) {
@@ -6310,7 +6533,7 @@ var init_cloudflare = __esm({
6310
6533
  clearTimeout(timeout);
6311
6534
  this.publicUrl = match[0];
6312
6535
  log4.info({ url: this.publicUrl }, "Cloudflare tunnel ready");
6313
- settle(() => resolve9(this.publicUrl));
6536
+ settle(() => resolve8(this.publicUrl));
6314
6537
  }
6315
6538
  };
6316
6539
  this.child.stdout?.on("data", onData);
@@ -6343,8 +6566,8 @@ var init_cloudflare = __esm({
6343
6566
  }
6344
6567
  child.kill("SIGTERM");
6345
6568
  const exited = await Promise.race([
6346
- new Promise((resolve9) => child.on("exit", () => resolve9(true))),
6347
- new Promise((resolve9) => setTimeout(() => resolve9(false), SIGKILL_TIMEOUT_MS))
6569
+ new Promise((resolve8) => child.on("exit", () => resolve8(true))),
6570
+ new Promise((resolve8) => setTimeout(() => resolve8(false), SIGKILL_TIMEOUT_MS))
6348
6571
  ]);
6349
6572
  if (!exited) {
6350
6573
  log4.warn("cloudflared did not exit after SIGTERM, sending SIGKILL");
@@ -6357,7 +6580,7 @@ var init_cloudflare = __esm({
6357
6580
  }
6358
6581
  findBinary() {
6359
6582
  if (commandExists("cloudflared")) return "cloudflared";
6360
- const binPath = path14.join(this.binDir, "cloudflared");
6583
+ const binPath = path15.join(this.binDir, "cloudflared");
6361
6584
  if (fs12.existsSync(binPath)) return binPath;
6362
6585
  return null;
6363
6586
  }
@@ -6397,7 +6620,7 @@ var init_ngrok = __esm({
6397
6620
  if (this.options.region) {
6398
6621
  args2.push("--region", String(this.options.region));
6399
6622
  }
6400
- return new Promise((resolve9, reject) => {
6623
+ return new Promise((resolve8, reject) => {
6401
6624
  let settled = false;
6402
6625
  const settle = (fn) => {
6403
6626
  if (!settled) {
@@ -6427,7 +6650,7 @@ var init_ngrok = __esm({
6427
6650
  clearTimeout(timeout);
6428
6651
  this.publicUrl = match[0];
6429
6652
  log5.info({ url: this.publicUrl }, "ngrok tunnel ready");
6430
- settle(() => resolve9(this.publicUrl));
6653
+ settle(() => resolve8(this.publicUrl));
6431
6654
  }
6432
6655
  };
6433
6656
  this.child.stdout?.on("data", onData);
@@ -6462,8 +6685,8 @@ var init_ngrok = __esm({
6462
6685
  }
6463
6686
  child.kill("SIGTERM");
6464
6687
  const exited = await Promise.race([
6465
- new Promise((resolve9) => child.on("exit", () => resolve9(true))),
6466
- new Promise((resolve9) => setTimeout(() => resolve9(false), SIGKILL_TIMEOUT_MS2))
6688
+ new Promise((resolve8) => child.on("exit", () => resolve8(true))),
6689
+ new Promise((resolve8) => setTimeout(() => resolve8(false), SIGKILL_TIMEOUT_MS2))
6467
6690
  ]);
6468
6691
  if (!exited) {
6469
6692
  log5.warn("ngrok did not exit after SIGTERM, sending SIGKILL");
@@ -6507,7 +6730,7 @@ var init_bore = __esm({
6507
6730
  if (this.options.secret) {
6508
6731
  args2.push("--secret", String(this.options.secret));
6509
6732
  }
6510
- return new Promise((resolve9, reject) => {
6733
+ return new Promise((resolve8, reject) => {
6511
6734
  let settled = false;
6512
6735
  const settle = (fn) => {
6513
6736
  if (!settled) {
@@ -6537,7 +6760,7 @@ var init_bore = __esm({
6537
6760
  clearTimeout(timeout);
6538
6761
  this.publicUrl = `http://${match[1]}:${match[2]}`;
6539
6762
  log6.info({ url: this.publicUrl }, "Bore tunnel ready");
6540
- settle(() => resolve9(this.publicUrl));
6763
+ settle(() => resolve8(this.publicUrl));
6541
6764
  }
6542
6765
  };
6543
6766
  this.child.stdout?.on("data", onData);
@@ -6572,8 +6795,8 @@ var init_bore = __esm({
6572
6795
  }
6573
6796
  child.kill("SIGTERM");
6574
6797
  const exited = await Promise.race([
6575
- new Promise((resolve9) => child.on("exit", () => resolve9(true))),
6576
- new Promise((resolve9) => setTimeout(() => resolve9(false), SIGKILL_TIMEOUT_MS3))
6798
+ new Promise((resolve8) => child.on("exit", () => resolve8(true))),
6799
+ new Promise((resolve8) => setTimeout(() => resolve8(false), SIGKILL_TIMEOUT_MS3))
6577
6800
  ]);
6578
6801
  if (!exited) {
6579
6802
  log6.warn("bore did not exit after SIGTERM, sending SIGKILL");
@@ -6622,7 +6845,7 @@ var init_tailscale = __esm({
6622
6845
  if (this.options.bg) {
6623
6846
  args2.push("--bg");
6624
6847
  }
6625
- return new Promise((resolve9, reject) => {
6848
+ return new Promise((resolve8, reject) => {
6626
6849
  let settled = false;
6627
6850
  const settle = (fn) => {
6628
6851
  if (!settled) {
@@ -6652,7 +6875,7 @@ var init_tailscale = __esm({
6652
6875
  clearTimeout(timeout);
6653
6876
  this.publicUrl = match[0];
6654
6877
  log7.info({ url: this.publicUrl }, "Tailscale funnel ready");
6655
- settle(() => resolve9(this.publicUrl));
6878
+ settle(() => resolve8(this.publicUrl));
6656
6879
  }
6657
6880
  };
6658
6881
  this.child.stdout?.on("data", onData);
@@ -6670,7 +6893,7 @@ var init_tailscale = __esm({
6670
6893
  this.publicUrl = `https://${hostname}:${localPort}`;
6671
6894
  this.child = null;
6672
6895
  log7.info({ url: this.publicUrl }, "Tailscale funnel ready (constructed from hostname)");
6673
- settle(() => resolve9(this.publicUrl));
6896
+ settle(() => resolve8(this.publicUrl));
6674
6897
  } else {
6675
6898
  settle(() => reject(new Error(`tailscale exited with code ${code} before establishing funnel`)));
6676
6899
  }
@@ -6694,8 +6917,8 @@ var init_tailscale = __esm({
6694
6917
  }
6695
6918
  child.kill("SIGTERM");
6696
6919
  const exited = await Promise.race([
6697
- new Promise((resolve9) => child.on("exit", () => resolve9(true))),
6698
- new Promise((resolve9) => setTimeout(() => resolve9(false), SIGKILL_TIMEOUT_MS4))
6920
+ new Promise((resolve8) => child.on("exit", () => resolve8(true))),
6921
+ new Promise((resolve8) => setTimeout(() => resolve8(false), SIGKILL_TIMEOUT_MS4))
6699
6922
  ]);
6700
6923
  if (!exited) {
6701
6924
  log7.warn("tailscale did not exit after SIGTERM, sending SIGKILL");
@@ -6713,7 +6936,7 @@ var init_tailscale = __esm({
6713
6936
  // src/plugins/tunnel/providers/openacp.ts
6714
6937
  import { spawn as spawn5 } from "child_process";
6715
6938
  import fs13 from "fs";
6716
- import path15 from "path";
6939
+ import path16 from "path";
6717
6940
  var log8, DEFAULT_WORKER_URL, DEFAULT_API_KEY, HEARTBEAT_INTERVAL_MS, STARTUP_TIMEOUT_MS, SIGKILL_TIMEOUT_MS5, STORAGE_KEY, OpenACPTunnelProvider;
6718
6941
  var init_openacp = __esm({
6719
6942
  "src/plugins/tunnel/providers/openacp.ts"() {
@@ -6813,7 +7036,7 @@ var init_openacp = __esm({
6813
7036
  }
6814
7037
  async spawnCloudflared(binaryPath, token, port) {
6815
7038
  const args2 = ["tunnel", "run", "--url", `http://localhost:${port}`, "--token", token];
6816
- return new Promise((resolve9, reject) => {
7039
+ return new Promise((resolve8, reject) => {
6817
7040
  let settled = false;
6818
7041
  const settle = (fn) => {
6819
7042
  if (!settled) {
@@ -6823,7 +7046,7 @@ var init_openacp = __esm({
6823
7046
  };
6824
7047
  const timeout = setTimeout(() => {
6825
7048
  log8.info({ port }, "cloudflared still running after startup window \u2014 assuming tunnel active");
6826
- settle(resolve9);
7049
+ settle(resolve8);
6827
7050
  }, STARTUP_TIMEOUT_MS);
6828
7051
  let child;
6829
7052
  try {
@@ -6839,7 +7062,7 @@ var init_openacp = __esm({
6839
7062
  if (/Registered tunnel connection/.test(line)) {
6840
7063
  clearTimeout(timeout);
6841
7064
  log8.info({ port }, "cloudflared connection registered");
6842
- settle(resolve9);
7065
+ settle(resolve8);
6843
7066
  }
6844
7067
  };
6845
7068
  child.stdout?.on("data", onData);
@@ -6915,7 +7138,7 @@ var init_openacp = __esm({
6915
7138
  }
6916
7139
  async resolveBinary() {
6917
7140
  if (commandExists("cloudflared")) return "cloudflared";
6918
- const binPath = path15.join(this.binDir, "cloudflared");
7141
+ const binPath = path16.join(this.binDir, "cloudflared");
6919
7142
  if (fs13.existsSync(binPath)) return binPath;
6920
7143
  log8.warn("cloudflared not found, attempting auto-install...");
6921
7144
  const { ensureCloudflared: ensureCloudflared2 } = await Promise.resolve().then(() => (init_install_cloudflared(), install_cloudflared_exports));
@@ -6927,7 +7150,7 @@ var init_openacp = __esm({
6927
7150
 
6928
7151
  // src/plugins/tunnel/tunnel-registry.ts
6929
7152
  import fs14 from "fs";
6930
- import path16 from "path";
7153
+ import path17 from "path";
6931
7154
  var log9, MAX_RETRIES, BASE_RETRY_DELAY_MS, TunnelRegistry;
6932
7155
  var init_tunnel_registry = __esm({
6933
7156
  "src/plugins/tunnel/tunnel-registry.ts"() {
@@ -7252,7 +7475,7 @@ var init_tunnel_registry = __esm({
7252
7475
  createdAt: l.entry.createdAt
7253
7476
  }));
7254
7477
  try {
7255
- const dir = path16.dirname(this.registryPath);
7478
+ const dir = path17.dirname(this.registryPath);
7256
7479
  fs14.mkdirSync(dir, { recursive: true });
7257
7480
  fs14.writeFileSync(this.registryPath, JSON.stringify(data, null, 2));
7258
7481
  } catch (err) {
@@ -7687,7 +7910,7 @@ var init_output_viewer = __esm({
7687
7910
  });
7688
7911
 
7689
7912
  // src/plugins/tunnel/viewer-routes.ts
7690
- import path17 from "path";
7913
+ import path18 from "path";
7691
7914
  function createViewerRoutes(store) {
7692
7915
  return async (app) => {
7693
7916
  app.get("/view/:id", async (request, reply) => {
@@ -7717,7 +7940,7 @@ function createViewerRoutes(store) {
7717
7940
  return reply.status(404).send({ error: "not found" });
7718
7941
  }
7719
7942
  return reply.send({
7720
- filePath: entry.filePath ? path17.basename(entry.filePath) : null,
7943
+ filePath: entry.filePath ? path18.basename(entry.filePath) : null,
7721
7944
  content: entry.content,
7722
7945
  language: entry.language
7723
7946
  });
@@ -7728,7 +7951,7 @@ function createViewerRoutes(store) {
7728
7951
  return reply.status(404).send({ error: "not found" });
7729
7952
  }
7730
7953
  return reply.send({
7731
- filePath: entry.filePath ? path17.basename(entry.filePath) : null,
7954
+ filePath: entry.filePath ? path18.basename(entry.filePath) : null,
7732
7955
  oldContent: entry.oldContent,
7733
7956
  newContent: entry.content,
7734
7957
  language: entry.language
@@ -7753,7 +7976,7 @@ var init_viewer_routes = __esm({
7753
7976
 
7754
7977
  // src/plugins/tunnel/viewer-store.ts
7755
7978
  import * as fs15 from "fs";
7756
- import * as path18 from "path";
7979
+ import * as path19 from "path";
7757
7980
  import { nanoid as nanoid2 } from "nanoid";
7758
7981
  var log10, MAX_CONTENT_SIZE, EXTENSION_LANGUAGE, ViewerStore;
7759
7982
  var init_viewer_store = __esm({
@@ -7909,24 +8132,24 @@ var init_viewer_store = __esm({
7909
8132
  let resolved;
7910
8133
  let workspace;
7911
8134
  try {
7912
- resolved = fs15.realpathSync(path18.resolve(workingDirectory, filePath));
8135
+ resolved = fs15.realpathSync(path19.resolve(workingDirectory, filePath));
7913
8136
  } catch {
7914
- resolved = path18.resolve(workingDirectory, filePath);
8137
+ resolved = path19.resolve(workingDirectory, filePath);
7915
8138
  }
7916
8139
  try {
7917
- workspace = fs15.realpathSync(path18.resolve(workingDirectory));
8140
+ workspace = fs15.realpathSync(path19.resolve(workingDirectory));
7918
8141
  } catch {
7919
- workspace = path18.resolve(workingDirectory);
8142
+ workspace = path19.resolve(workingDirectory);
7920
8143
  }
7921
8144
  if (caseInsensitive) {
7922
8145
  const rLower = resolved.toLowerCase();
7923
8146
  const wLower = workspace.toLowerCase();
7924
- return rLower.startsWith(wLower + path18.sep) || rLower === wLower;
8147
+ return rLower.startsWith(wLower + path19.sep) || rLower === wLower;
7925
8148
  }
7926
- return resolved.startsWith(workspace + path18.sep) || resolved === workspace;
8149
+ return resolved.startsWith(workspace + path19.sep) || resolved === workspace;
7927
8150
  }
7928
8151
  detectLanguage(filePath) {
7929
- const ext = path18.extname(filePath).toLowerCase();
8152
+ const ext = path19.extname(filePath).toLowerCase();
7930
8153
  return EXTENSION_LANGUAGE[ext];
7931
8154
  }
7932
8155
  destroy() {
@@ -8073,7 +8296,7 @@ var tunnel_exports = {};
8073
8296
  __export(tunnel_exports, {
8074
8297
  default: () => tunnel_default
8075
8298
  });
8076
- import path19 from "path";
8299
+ import path20 from "path";
8077
8300
  function createTunnelPlugin() {
8078
8301
  let service = null;
8079
8302
  return {
@@ -8179,10 +8402,10 @@ function createTunnelPlugin() {
8179
8402
  { key: "provider", displayName: "Provider", type: "select", scope: "safe", hotReload: false, options: ["openacp", "cloudflare", "ngrok", "bore", "tailscale"] }
8180
8403
  ]);
8181
8404
  const { default: fs57 } = await import("fs");
8182
- const settingsPath = path19.join(ctx.instanceRoot, "plugins", "data", ctx.pluginName, "settings.json");
8405
+ const settingsPath = path20.join(ctx.instanceRoot, "plugins", "data", ctx.pluginName, "settings.json");
8183
8406
  if (!fs57.existsSync(settingsPath)) {
8184
8407
  const defaults = { enabled: true, provider: "openacp", maxUserTunnels: 5, auth: { enabled: false } };
8185
- fs57.mkdirSync(path19.dirname(settingsPath), { recursive: true });
8408
+ fs57.mkdirSync(path20.dirname(settingsPath), { recursive: true });
8186
8409
  fs57.writeFileSync(settingsPath, JSON.stringify(defaults, null, 2));
8187
8410
  Object.assign(ctx.pluginConfig, defaults);
8188
8411
  ctx.log.info("Initialized tunnel settings with defaults (openacp provider)");
@@ -8218,8 +8441,8 @@ function createTunnelPlugin() {
8218
8441
  const instanceRoot = ctx.instanceRoot;
8219
8442
  const tunnelSvc = new TunnelService2(
8220
8443
  config,
8221
- path19.join(instanceRoot, "tunnels.json"),
8222
- path19.join(instanceRoot, "bin"),
8444
+ path20.join(instanceRoot, "tunnels.json"),
8445
+ path20.join(instanceRoot, "bin"),
8223
8446
  ctx.storage,
8224
8447
  (event, data) => ctx.emit(event, data)
8225
8448
  );
@@ -8318,7 +8541,7 @@ __export(token_store_exports, {
8318
8541
  TokenStore: () => TokenStore,
8319
8542
  parseDuration: () => parseDuration
8320
8543
  });
8321
- import { readFile as readFile2, writeFile } from "fs/promises";
8544
+ import { readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
8322
8545
  import { randomBytes as randomBytes2 } from "crypto";
8323
8546
  function generateTokenId() {
8324
8547
  return `tok_${randomBytes2(12).toString("hex")}`;
@@ -8387,7 +8610,7 @@ var init_token_store = __esm({
8387
8610
  tokens: Array.from(this.tokens.values()),
8388
8611
  codes: Array.from(this.codes.values())
8389
8612
  };
8390
- await writeFile(this.filePath, JSON.stringify(data, null, 2), "utf-8");
8613
+ await writeFile2(this.filePath, JSON.stringify(data, null, 2), "utf-8");
8391
8614
  }
8392
8615
  /**
8393
8616
  * Coalesces concurrent writes: if a save is in-flight, sets a pending flag
@@ -8595,22 +8818,22 @@ __export(config_registry_exports, {
8595
8818
  resolveOptions: () => resolveOptions,
8596
8819
  setFieldValueAsync: () => setFieldValueAsync
8597
8820
  });
8598
- function getFieldDef(path71) {
8599
- return CONFIG_REGISTRY.find((f) => f.path === path71);
8821
+ function getFieldDef(path72) {
8822
+ return CONFIG_REGISTRY.find((f) => f.path === path72);
8600
8823
  }
8601
8824
  function getSafeFields() {
8602
8825
  return CONFIG_REGISTRY.filter((f) => f.scope === "safe");
8603
8826
  }
8604
- function isHotReloadable(path71) {
8605
- const def = getFieldDef(path71);
8827
+ function isHotReloadable(path72) {
8828
+ const def = getFieldDef(path72);
8606
8829
  return def?.hotReload ?? false;
8607
8830
  }
8608
8831
  function resolveOptions(def, config) {
8609
8832
  if (!def.options) return void 0;
8610
8833
  return typeof def.options === "function" ? def.options(config) : def.options;
8611
8834
  }
8612
- function getConfigValue(config, path71) {
8613
- const parts = path71.split(".");
8835
+ function getConfigValue(config, path72) {
8836
+ const parts = path72.split(".");
8614
8837
  let current = config;
8615
8838
  for (const part of parts) {
8616
8839
  if (current && typeof current === "object" && part in current) {
@@ -9270,8 +9493,8 @@ __export(static_server_exports, {
9270
9493
  StaticServer: () => StaticServer
9271
9494
  });
9272
9495
  import * as fs16 from "fs";
9273
- import * as path20 from "path";
9274
- import { fileURLToPath as fileURLToPath2 } from "url";
9496
+ import * as path21 from "path";
9497
+ import { fileURLToPath as fileURLToPath3 } from "url";
9275
9498
  var MIME_TYPES, StaticServer;
9276
9499
  var init_static_server = __esm({
9277
9500
  "src/plugins/api-server/static-server.ts"() {
@@ -9293,17 +9516,17 @@ var init_static_server = __esm({
9293
9516
  constructor(uiDir) {
9294
9517
  this.uiDir = uiDir;
9295
9518
  if (!this.uiDir) {
9296
- const __filename = fileURLToPath2(import.meta.url);
9297
- const candidate = path20.resolve(path20.dirname(__filename), "../../ui/dist");
9298
- if (fs16.existsSync(path20.join(candidate, "index.html"))) {
9519
+ const __filename = fileURLToPath3(import.meta.url);
9520
+ const candidate = path21.resolve(path21.dirname(__filename), "../../ui/dist");
9521
+ if (fs16.existsSync(path21.join(candidate, "index.html"))) {
9299
9522
  this.uiDir = candidate;
9300
9523
  }
9301
9524
  if (!this.uiDir) {
9302
- const publishCandidate = path20.resolve(
9303
- path20.dirname(__filename),
9525
+ const publishCandidate = path21.resolve(
9526
+ path21.dirname(__filename),
9304
9527
  "../ui"
9305
9528
  );
9306
- if (fs16.existsSync(path20.join(publishCandidate, "index.html"))) {
9529
+ if (fs16.existsSync(path21.join(publishCandidate, "index.html"))) {
9307
9530
  this.uiDir = publishCandidate;
9308
9531
  }
9309
9532
  }
@@ -9321,9 +9544,9 @@ var init_static_server = __esm({
9321
9544
  serve(req, res) {
9322
9545
  if (!this.uiDir) return false;
9323
9546
  const urlPath = (req.url || "/").split("?")[0];
9324
- const safePath = path20.normalize(urlPath);
9325
- const filePath = path20.join(this.uiDir, safePath);
9326
- if (!filePath.startsWith(this.uiDir + path20.sep) && filePath !== this.uiDir)
9547
+ const safePath = path21.normalize(urlPath);
9548
+ const filePath = path21.join(this.uiDir, safePath);
9549
+ if (!filePath.startsWith(this.uiDir + path21.sep) && filePath !== this.uiDir)
9327
9550
  return false;
9328
9551
  let realFilePath;
9329
9552
  try {
@@ -9333,11 +9556,11 @@ var init_static_server = __esm({
9333
9556
  }
9334
9557
  if (realFilePath !== null) {
9335
9558
  const realUiDir = fs16.realpathSync(this.uiDir);
9336
- if (!realFilePath.startsWith(realUiDir + path20.sep) && realFilePath !== realUiDir)
9559
+ if (!realFilePath.startsWith(realUiDir + path21.sep) && realFilePath !== realUiDir)
9337
9560
  return false;
9338
9561
  }
9339
9562
  if (realFilePath !== null && fs16.existsSync(realFilePath) && fs16.statSync(realFilePath).isFile()) {
9340
- const ext = path20.extname(filePath);
9563
+ const ext = path21.extname(filePath);
9341
9564
  const contentType = MIME_TYPES[ext] ?? "application/octet-stream";
9342
9565
  const isHashed = /\.[a-zA-Z0-9]{8,}\.(js|css)$/.test(filePath);
9343
9566
  const cacheControl = isHashed ? "public, max-age=31536000, immutable" : "no-cache";
@@ -9348,7 +9571,7 @@ var init_static_server = __esm({
9348
9571
  fs16.createReadStream(realFilePath).pipe(res);
9349
9572
  return true;
9350
9573
  }
9351
- const indexPath = path20.join(this.uiDir, "index.html");
9574
+ const indexPath = path21.join(this.uiDir, "index.html");
9352
9575
  if (fs16.existsSync(indexPath)) {
9353
9576
  res.writeHead(200, {
9354
9577
  "Content-Type": "text/html; charset=utf-8",
@@ -10100,7 +10323,7 @@ var init_config = __esm({
10100
10323
 
10101
10324
  // src/core/config/config-migrations.ts
10102
10325
  import fs18 from "fs";
10103
- import path21 from "path";
10326
+ import path22 from "path";
10104
10327
  import os4 from "os";
10105
10328
  function applyMigrations(raw, migrationList = migrations, ctx) {
10106
10329
  let changed = false;
@@ -10150,7 +10373,7 @@ var init_config_migrations = __esm({
10150
10373
  if (!ctx?.configDir) return false;
10151
10374
  const instanceRoot = ctx.configDir;
10152
10375
  try {
10153
- const registryPath = path21.join(os4.homedir(), ".openacp", "instances.json");
10376
+ const registryPath = path22.join(os4.homedir(), ".openacp", "instances.json");
10154
10377
  const data = JSON.parse(fs18.readFileSync(registryPath, "utf-8"));
10155
10378
  const instances = data?.instances ?? {};
10156
10379
  const entry = Object.values(instances).find(
@@ -10179,13 +10402,13 @@ __export(config_exports, {
10179
10402
  });
10180
10403
  import { z as z4 } from "zod";
10181
10404
  import * as fs19 from "fs";
10182
- import * as path22 from "path";
10405
+ import * as path23 from "path";
10183
10406
  import * as os5 from "os";
10184
10407
  import { randomBytes as randomBytes3 } from "crypto";
10185
10408
  import { EventEmitter } from "events";
10186
10409
  function expandHome2(p2) {
10187
10410
  if (p2.startsWith("~")) {
10188
- return path22.join(os5.homedir(), p2.slice(1));
10411
+ return path23.join(os5.homedir(), p2.slice(1));
10189
10412
  }
10190
10413
  return p2;
10191
10414
  }
@@ -10259,7 +10482,7 @@ var init_config2 = __esm({
10259
10482
  * 4. Validate against Zod schema — exits on failure
10260
10483
  */
10261
10484
  async load() {
10262
- const dir = path22.dirname(this.configPath);
10485
+ const dir = path23.dirname(this.configPath);
10263
10486
  fs19.mkdirSync(dir, { recursive: true });
10264
10487
  if (!fs19.existsSync(this.configPath)) {
10265
10488
  fs19.writeFileSync(
@@ -10273,7 +10496,7 @@ var init_config2 = __esm({
10273
10496
  process.exit(1);
10274
10497
  }
10275
10498
  const raw = JSON.parse(fs19.readFileSync(this.configPath, "utf-8"));
10276
- const { changed: configUpdated } = applyMigrations(raw, void 0, { configDir: path22.dirname(this.configPath) });
10499
+ const { changed: configUpdated } = applyMigrations(raw, void 0, { configDir: path23.dirname(this.configPath) });
10277
10500
  if (configUpdated) {
10278
10501
  fs19.writeFileSync(this.configPath, JSON.stringify(raw, null, 2));
10279
10502
  }
@@ -10353,16 +10576,16 @@ var init_config2 = __esm({
10353
10576
  * (alphanumeric subdirectories under the base).
10354
10577
  */
10355
10578
  resolveWorkspace(input2) {
10356
- const workspaceBase = path22.dirname(path22.dirname(this.configPath));
10579
+ const workspaceBase = path23.dirname(path23.dirname(this.configPath));
10357
10580
  if (!input2) {
10358
10581
  fs19.mkdirSync(workspaceBase, { recursive: true });
10359
10582
  return workspaceBase;
10360
10583
  }
10361
10584
  const expanded = input2.startsWith("~") ? expandHome2(input2) : input2;
10362
- if (path22.isAbsolute(expanded)) {
10363
- const resolved = path22.resolve(expanded);
10364
- const base = path22.resolve(workspaceBase);
10365
- const isInternal = resolved === base || resolved.startsWith(base + path22.sep);
10585
+ if (path23.isAbsolute(expanded)) {
10586
+ const resolved = path23.resolve(expanded);
10587
+ const base = path23.resolve(workspaceBase);
10588
+ const isInternal = resolved === base || resolved.startsWith(base + path23.sep);
10366
10589
  if (!isInternal) {
10367
10590
  if (!this.config.workspace.allowExternalWorkspaces) {
10368
10591
  throw new Error(
@@ -10382,7 +10605,7 @@ var init_config2 = __esm({
10382
10605
  `Invalid workspace name: "${input2}". Only alphanumeric characters, hyphens, and underscores are allowed.`
10383
10606
  );
10384
10607
  }
10385
- const namedPath = path22.join(workspaceBase, input2.toLowerCase());
10608
+ const namedPath = path23.join(workspaceBase, input2.toLowerCase());
10386
10609
  fs19.mkdirSync(namedPath, { recursive: true });
10387
10610
  return namedPath;
10388
10611
  }
@@ -10396,7 +10619,7 @@ var init_config2 = __esm({
10396
10619
  }
10397
10620
  /** Writes a complete config object to disk, creating the directory if needed. Used during initial setup. */
10398
10621
  async writeNew(config) {
10399
- const dir = path22.dirname(this.configPath);
10622
+ const dir = path23.dirname(this.configPath);
10400
10623
  fs19.mkdirSync(dir, { recursive: true });
10401
10624
  fs19.writeFileSync(this.configPath, JSON.stringify(config, null, 2));
10402
10625
  }
@@ -10414,6 +10637,14 @@ var init_config2 = __esm({
10414
10637
  { envVar: "OPENACP_API_PORT", pluginName: "@openacp/api-server", key: "port", transform: (v) => Number(v) },
10415
10638
  { envVar: "OPENACP_SPEECH_STT_PROVIDER", pluginName: "@openacp/speech", key: "sttProvider" },
10416
10639
  { envVar: "OPENACP_SPEECH_GROQ_API_KEY", pluginName: "@openacp/speech", key: "groqApiKey" },
10640
+ { envVar: "OPENACP_SPEECH_LOCAL_WHISPER_LANGUAGE", pluginName: "@openacp/speech", key: "localWhisperLanguage" },
10641
+ { envVar: "OPENACP_SPEECH_LOCAL_WHISPER_MODEL", pluginName: "@openacp/speech", key: "localWhisperModel" },
10642
+ { envVar: "OPENACP_SPEECH_LOCAL_WHISPER_BEAM_SIZE", pluginName: "@openacp/speech", key: "localWhisperBeamSize", transform: (v) => Number(v) },
10643
+ { envVar: "OPENACP_SPEECH_LOCAL_WHISPER_VAD_FILTER", pluginName: "@openacp/speech", key: "localWhisperVadFilter", transform: (v) => v === "true" },
10644
+ { envVar: "OPENACP_SPEECH_LOCAL_WHISPER_DEVICE", pluginName: "@openacp/speech", key: "localWhisperDevice" },
10645
+ { envVar: "OPENACP_SPEECH_LOCAL_WHISPER_COMPUTE_TYPE", pluginName: "@openacp/speech", key: "localWhisperComputeType" },
10646
+ { envVar: "OPENACP_SPEECH_LOCAL_WHISPER_TIMEOUT_MS", pluginName: "@openacp/speech", key: "localWhisperTimeoutMs", transform: (v) => Number(v) },
10647
+ { envVar: "OPENACP_SPEECH_LOCAL_WHISPER_SCRIPT_PATH", pluginName: "@openacp/speech", key: "localWhisperScriptPath" },
10417
10648
  { envVar: "OPENACP_TELEGRAM_BOT_TOKEN", pluginName: "@openacp/telegram", key: "botToken" },
10418
10649
  { envVar: "OPENACP_TELEGRAM_CHAT_ID", pluginName: "@openacp/telegram", key: "chatId", transform: (v) => Number(v) },
10419
10650
  // Future adapters — no-ops if plugin settings don't exist
@@ -11131,7 +11362,7 @@ var plugins_exports = {};
11131
11362
  __export(plugins_exports, {
11132
11363
  pluginRoutes: () => pluginRoutes
11133
11364
  });
11134
- import path23 from "path";
11365
+ import path24 from "path";
11135
11366
  async function pluginRoutes(app, deps) {
11136
11367
  const { lifecycleManager } = deps;
11137
11368
  const admin = [requireScopes("system:admin")];
@@ -11196,7 +11427,7 @@ async function pluginRoutes(app, deps) {
11196
11427
  } else {
11197
11428
  const { importFromDir: importFromDir2 } = await Promise.resolve().then(() => (init_plugin_installer(), plugin_installer_exports));
11198
11429
  const instanceRoot = lifecycleManager.instanceRoot;
11199
- const pluginsDir = path23.join(instanceRoot, "plugins");
11430
+ const pluginsDir = path24.join(instanceRoot, "plugins");
11200
11431
  try {
11201
11432
  const mod = await importFromDir2(name, pluginsDir);
11202
11433
  pluginDef = mod.default ?? mod;
@@ -11272,11 +11503,11 @@ __export(instance_registry_exports, {
11272
11503
  readIdFromConfig: () => readIdFromConfig
11273
11504
  });
11274
11505
  import fs20 from "fs";
11275
- import path24 from "path";
11506
+ import path25 from "path";
11276
11507
  import { randomUUID } from "crypto";
11277
11508
  function readIdFromConfig(instanceRoot) {
11278
11509
  try {
11279
- const raw = JSON.parse(fs20.readFileSync(path24.join(instanceRoot, "config.json"), "utf-8"));
11510
+ const raw = JSON.parse(fs20.readFileSync(path25.join(instanceRoot, "config.json"), "utf-8"));
11280
11511
  return typeof raw.id === "string" && raw.id ? raw.id : null;
11281
11512
  } catch {
11282
11513
  return null;
@@ -11322,7 +11553,7 @@ var init_instance_registry = __esm({
11322
11553
  }
11323
11554
  /** Persist the registry to disk, creating parent directories if needed. */
11324
11555
  save() {
11325
- const dir = path24.dirname(this.registryPath);
11556
+ const dir = path25.dirname(this.registryPath);
11326
11557
  fs20.mkdirSync(dir, { recursive: true });
11327
11558
  fs20.writeFileSync(this.registryPath, JSON.stringify(this.data, null, 2));
11328
11559
  }
@@ -11392,7 +11623,7 @@ __export(instance_context_exports, {
11392
11623
  resolveInstanceRoot: () => resolveInstanceRoot,
11393
11624
  resolveRunningInstance: () => resolveRunningInstance
11394
11625
  });
11395
- import path25 from "path";
11626
+ import path26 from "path";
11396
11627
  import fs21 from "fs";
11397
11628
  import os6 from "os";
11398
11629
  function createInstanceContext(opts) {
@@ -11402,22 +11633,22 @@ function createInstanceContext(opts) {
11402
11633
  id,
11403
11634
  root,
11404
11635
  paths: {
11405
- config: path25.join(root, "config.json"),
11406
- sessions: path25.join(root, "sessions.json"),
11407
- agents: path25.join(root, "agents.json"),
11408
- registryCache: path25.join(globalRoot, "cache", "registry-cache.json"),
11409
- plugins: path25.join(root, "plugins"),
11410
- pluginsData: path25.join(root, "plugins", "data"),
11411
- pluginRegistry: path25.join(root, "plugins.json"),
11412
- logs: path25.join(root, "logs"),
11413
- pid: path25.join(root, "openacp.pid"),
11414
- running: path25.join(root, "running"),
11415
- apiPort: path25.join(root, "api.port"),
11416
- apiSecret: path25.join(root, "api-secret"),
11417
- bin: path25.join(globalRoot, "bin"),
11418
- cache: path25.join(root, "cache"),
11419
- tunnels: path25.join(root, "tunnels.json"),
11420
- agentsDir: path25.join(globalRoot, "agents")
11636
+ config: path26.join(root, "config.json"),
11637
+ sessions: path26.join(root, "sessions.json"),
11638
+ agents: path26.join(root, "agents.json"),
11639
+ registryCache: path26.join(globalRoot, "cache", "registry-cache.json"),
11640
+ plugins: path26.join(root, "plugins"),
11641
+ pluginsData: path26.join(root, "plugins", "data"),
11642
+ pluginRegistry: path26.join(root, "plugins.json"),
11643
+ logs: path26.join(root, "logs"),
11644
+ pid: path26.join(root, "openacp.pid"),
11645
+ running: path26.join(root, "running"),
11646
+ apiPort: path26.join(root, "api.port"),
11647
+ apiSecret: path26.join(root, "api-secret"),
11648
+ bin: path26.join(globalRoot, "bin"),
11649
+ cache: path26.join(root, "cache"),
11650
+ tunnels: path26.join(root, "tunnels.json"),
11651
+ agentsDir: path26.join(globalRoot, "agents")
11421
11652
  }
11422
11653
  };
11423
11654
  }
@@ -11426,50 +11657,50 @@ function generateSlug(name) {
11426
11657
  return slug || "openacp";
11427
11658
  }
11428
11659
  function expandHome3(p2) {
11429
- if (p2.startsWith("~")) return path25.join(os6.homedir(), p2.slice(1));
11660
+ if (p2.startsWith("~")) return path26.join(os6.homedir(), p2.slice(1));
11430
11661
  return p2;
11431
11662
  }
11432
11663
  function resolveInstanceRoot(opts) {
11433
11664
  const cwd = opts.cwd ?? process.cwd();
11434
11665
  const home = os6.homedir();
11435
11666
  const globalRoot = getGlobalRoot();
11436
- if (opts.dir) return path25.join(expandHome3(opts.dir), ".openacp");
11437
- if (opts.local) return path25.join(cwd, ".openacp");
11438
- const cwdRoot = path25.join(cwd, ".openacp");
11439
- if (fs21.existsSync(path25.join(cwdRoot, "config.json"))) return cwdRoot;
11440
- let dir = path25.resolve(cwd);
11667
+ if (opts.dir) return path26.join(expandHome3(opts.dir), ".openacp");
11668
+ if (opts.local) return path26.join(cwd, ".openacp");
11669
+ const cwdRoot = path26.join(cwd, ".openacp");
11670
+ if (fs21.existsSync(path26.join(cwdRoot, "config.json"))) return cwdRoot;
11671
+ let dir = path26.resolve(cwd);
11441
11672
  while (true) {
11442
- const parent = path25.dirname(dir);
11673
+ const parent = path26.dirname(dir);
11443
11674
  if (parent === dir) break;
11444
11675
  dir = parent;
11445
- const candidate = path25.join(dir, ".openacp");
11676
+ const candidate = path26.join(dir, ".openacp");
11446
11677
  if (candidate === globalRoot) {
11447
11678
  if (dir === home) break;
11448
11679
  continue;
11449
11680
  }
11450
- if (fs21.existsSync(path25.join(candidate, "config.json"))) return candidate;
11681
+ if (fs21.existsSync(path26.join(candidate, "config.json"))) return candidate;
11451
11682
  if (dir === home) break;
11452
11683
  }
11453
- if (path25.resolve(cwd) === path25.resolve(home)) {
11454
- const defaultWs = path25.join(home, "openacp-workspace", ".openacp");
11455
- if (fs21.existsSync(path25.join(defaultWs, "config.json"))) return defaultWs;
11684
+ if (path26.resolve(cwd) === path26.resolve(home)) {
11685
+ const defaultWs = path26.join(home, "openacp-workspace", ".openacp");
11686
+ if (fs21.existsSync(path26.join(defaultWs, "config.json"))) return defaultWs;
11456
11687
  }
11457
11688
  if (process.env.OPENACP_INSTANCE_ROOT) return process.env.OPENACP_INSTANCE_ROOT;
11458
11689
  return null;
11459
11690
  }
11460
11691
  function getGlobalRoot() {
11461
- return path25.join(os6.homedir(), ".openacp");
11692
+ return path26.join(os6.homedir(), ".openacp");
11462
11693
  }
11463
11694
  async function resolveRunningInstance(cwd) {
11464
11695
  const globalRoot = getGlobalRoot();
11465
11696
  const home = os6.homedir();
11466
- let dir = path25.resolve(cwd);
11697
+ let dir = path26.resolve(cwd);
11467
11698
  while (true) {
11468
- const candidate = path25.join(dir, ".openacp");
11699
+ const candidate = path26.join(dir, ".openacp");
11469
11700
  if (candidate !== globalRoot && fs21.existsSync(candidate)) {
11470
11701
  if (await isInstanceRunning(candidate)) return candidate;
11471
11702
  }
11472
- const parent = path25.dirname(dir);
11703
+ const parent = path26.dirname(dir);
11473
11704
  if (parent === dir) break;
11474
11705
  if (dir === home) break;
11475
11706
  dir = parent;
@@ -11477,7 +11708,7 @@ async function resolveRunningInstance(cwd) {
11477
11708
  return null;
11478
11709
  }
11479
11710
  async function isInstanceRunning(instanceRoot) {
11480
- const portFile = path25.join(instanceRoot, "api.port");
11711
+ const portFile = path26.join(instanceRoot, "api.port");
11481
11712
  try {
11482
11713
  const content = fs21.readFileSync(portFile, "utf-8").trim();
11483
11714
  const port = parseInt(content, 10);
@@ -11506,22 +11737,14 @@ __export(api_server_exports, {
11506
11737
  });
11507
11738
  import * as fs22 from "fs";
11508
11739
  import * as crypto3 from "crypto";
11509
- import * as path26 from "path";
11510
- import { fileURLToPath as fileURLToPath3 } from "url";
11740
+ import * as path27 from "path";
11511
11741
  function getVersion() {
11512
11742
  if (cachedVersion) return cachedVersion;
11513
- try {
11514
- const __filename = fileURLToPath3(import.meta.url);
11515
- const pkgPath = path26.resolve(path26.dirname(__filename), "../../../package.json");
11516
- const pkg = JSON.parse(fs22.readFileSync(pkgPath, "utf-8"));
11517
- cachedVersion = pkg.version ?? "0.0.0-dev";
11518
- } catch {
11519
- cachedVersion = "0.0.0-dev";
11520
- }
11743
+ cachedVersion = getCurrentVersion();
11521
11744
  return cachedVersion;
11522
11745
  }
11523
11746
  function loadOrCreateSecret(secretFilePath) {
11524
- const dir = path26.dirname(secretFilePath);
11747
+ const dir = path27.dirname(secretFilePath);
11525
11748
  fs22.mkdirSync(dir, { recursive: true });
11526
11749
  try {
11527
11750
  const existing = fs22.readFileSync(secretFilePath, "utf-8").trim();
@@ -11547,7 +11770,7 @@ function loadOrCreateSecret(secretFilePath) {
11547
11770
  return secret;
11548
11771
  }
11549
11772
  function writePortFile(portFilePath, port) {
11550
- const dir = path26.dirname(portFilePath);
11773
+ const dir = path27.dirname(portFilePath);
11551
11774
  fs22.mkdirSync(dir, { recursive: true });
11552
11775
  fs22.writeFileSync(portFilePath, String(port));
11553
11776
  }
@@ -11632,10 +11855,10 @@ function createApiServerPlugin() {
11632
11855
  { port: apiConfig.port, host: apiConfig.host, instanceRoot },
11633
11856
  "API server plugin setup \u2014 config loaded"
11634
11857
  );
11635
- portFilePath = path26.join(instanceRoot, "api.port");
11636
- const secretFilePath = path26.join(instanceRoot, "api-secret");
11637
- const jwtSecretFilePath = path26.join(instanceRoot, "jwt-secret");
11638
- const tokensFilePath = path26.join(instanceRoot, "tokens.json");
11858
+ portFilePath = path27.join(instanceRoot, "api.port");
11859
+ const secretFilePath = path27.join(instanceRoot, "api-secret");
11860
+ const jwtSecretFilePath = path27.join(instanceRoot, "jwt-secret");
11861
+ const tokensFilePath = path27.join(instanceRoot, "tokens.json");
11639
11862
  const startedAt = Date.now();
11640
11863
  const secret = loadOrCreateSecret(secretFilePath);
11641
11864
  const jwtSecret = loadOrCreateSecret(jwtSecretFilePath);
@@ -11674,7 +11897,7 @@ function createApiServerPlugin() {
11674
11897
  const { InstanceRegistry: InstanceRegistry2 } = await Promise.resolve().then(() => (init_instance_registry(), instance_registry_exports));
11675
11898
  const { getGlobalRoot: getGlobalRoot2 } = await Promise.resolve().then(() => (init_instance_context(), instance_context_exports));
11676
11899
  const globalRoot = getGlobalRoot2();
11677
- const instanceReg = new InstanceRegistry2(path26.join(globalRoot, "instances.json"));
11900
+ const instanceReg = new InstanceRegistry2(path27.join(globalRoot, "instances.json"));
11678
11901
  instanceReg.load();
11679
11902
  const instanceEntry = instanceReg.getByRoot(instanceRoot);
11680
11903
  const workspaceId = instanceEntry?.id ?? "main";
@@ -11706,7 +11929,7 @@ function createApiServerPlugin() {
11706
11929
  server.registerPlugin("/api/v1/plugins", async (app) => pluginRoutes2(app, deps));
11707
11930
  const appConfig = core.configManager.get();
11708
11931
  const workspaceName = appConfig.instanceName ?? "Main";
11709
- const workspaceDir = path26.dirname(instanceRoot);
11932
+ const workspaceDir = path27.dirname(instanceRoot);
11710
11933
  server.registerPlugin("/api/v1", async (app) => {
11711
11934
  await app.register(workspaceRoute2, {
11712
11935
  id: workspaceId,
@@ -11846,6 +12069,7 @@ var init_api_server = __esm({
11846
12069
  "use strict";
11847
12070
  init_events();
11848
12071
  init_log();
12072
+ init_version();
11849
12073
  log15 = createChildLogger({ module: "api-server" });
11850
12074
  api_server_default = createApiServerPlugin();
11851
12075
  }
@@ -12799,8 +13023,8 @@ function formatToolSummary(name, rawInput, displaySummary) {
12799
13023
  }
12800
13024
  if (lowerName === "grep") {
12801
13025
  const pattern = args2.pattern ?? "";
12802
- const path71 = args2.path ?? "";
12803
- return pattern ? `\u{1F50D} Grep "${pattern}"${path71 ? ` in ${path71}` : ""}` : `\u{1F527} ${name}`;
13026
+ const path72 = args2.path ?? "";
13027
+ return pattern ? `\u{1F50D} Grep "${pattern}"${path72 ? ` in ${path72}` : ""}` : `\u{1F527} ${name}`;
12804
13028
  }
12805
13029
  if (lowerName === "glob") {
12806
13030
  const pattern = args2.pattern ?? "";
@@ -12836,8 +13060,8 @@ function formatToolTitle(name, rawInput, displayTitle) {
12836
13060
  }
12837
13061
  if (lowerName === "grep") {
12838
13062
  const pattern = args2.pattern ?? "";
12839
- const path71 = args2.path ?? "";
12840
- return pattern ? `"${pattern}"${path71 ? ` in ${path71}` : ""}` : name;
13063
+ const path72 = args2.path ?? "";
13064
+ return pattern ? `"${pattern}"${path72 ? ` in ${path72}` : ""}` : name;
12841
13065
  }
12842
13066
  if (lowerName === "glob") {
12843
13067
  return String(args2.pattern ?? name);
@@ -13980,7 +14204,7 @@ __export(integrate_exports, {
13980
14204
  listIntegrations: () => listIntegrations,
13981
14205
  uninstallIntegration: () => uninstallIntegration
13982
14206
  });
13983
- import { existsSync as existsSync6, mkdirSync as mkdirSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync5, unlinkSync as unlinkSync4, chmodSync, rmdirSync } from "fs";
14207
+ import { existsSync as existsSync7, mkdirSync as mkdirSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync5, unlinkSync as unlinkSync4, chmodSync, rmdirSync } from "fs";
13984
14208
  import { join as join10, dirname as dirname7 } from "path";
13985
14209
  import { homedir as homedir3 } from "os";
13986
14210
  function isHooksIntegrationSpec(spec) {
@@ -14142,7 +14366,7 @@ function generateOpencodePlugin(spec) {
14142
14366
  function mergeSettingsJson(settingsPath, hookEvent, hookScriptPath) {
14143
14367
  const fullPath = expandPath(settingsPath);
14144
14368
  let settings = {};
14145
- if (existsSync6(fullPath)) {
14369
+ if (existsSync7(fullPath)) {
14146
14370
  const raw = readFileSync5(fullPath, "utf-8");
14147
14371
  writeFileSync5(`${fullPath}.bak`, raw);
14148
14372
  settings = JSON.parse(raw);
@@ -14165,7 +14389,7 @@ function mergeSettingsJson(settingsPath, hookEvent, hookScriptPath) {
14165
14389
  function mergeHooksJson(settingsPath, hookEvent, hookScriptPath) {
14166
14390
  const fullPath = expandPath(settingsPath);
14167
14391
  let config = { version: 1 };
14168
- if (existsSync6(fullPath)) {
14392
+ if (existsSync7(fullPath)) {
14169
14393
  const raw = readFileSync5(fullPath, "utf-8");
14170
14394
  writeFileSync5(`${fullPath}.bak`, raw);
14171
14395
  config = JSON.parse(raw);
@@ -14183,7 +14407,7 @@ function mergeHooksJson(settingsPath, hookEvent, hookScriptPath) {
14183
14407
  }
14184
14408
  function removeFromSettingsJson(settingsPath, hookEvent) {
14185
14409
  const fullPath = expandPath(settingsPath);
14186
- if (!existsSync6(fullPath)) return;
14410
+ if (!existsSync7(fullPath)) return;
14187
14411
  const raw = readFileSync5(fullPath, "utf-8");
14188
14412
  const settings = JSON.parse(raw);
14189
14413
  const hooks = settings.hooks;
@@ -14198,7 +14422,7 @@ function removeFromSettingsJson(settingsPath, hookEvent) {
14198
14422
  }
14199
14423
  function removeFromHooksJson(settingsPath, hookEvent) {
14200
14424
  const fullPath = expandPath(settingsPath);
14201
- if (!existsSync6(fullPath)) return;
14425
+ if (!existsSync7(fullPath)) return;
14202
14426
  const raw = readFileSync5(fullPath, "utf-8");
14203
14427
  const config = JSON.parse(raw);
14204
14428
  const hooks = config.hooks;
@@ -14264,7 +14488,7 @@ async function uninstallHooksIntegration(agentKey, spec) {
14264
14488
  const hooksDir = expandPath(spec.hooksDirPath);
14265
14489
  for (const filename of ["openacp-inject-session.sh", "openacp-handoff.sh"]) {
14266
14490
  const filePath = join10(hooksDir, filename);
14267
- if (existsSync6(filePath)) {
14491
+ if (existsSync7(filePath)) {
14268
14492
  unlinkSync4(filePath);
14269
14493
  logs.push(`Removed ${filePath}`);
14270
14494
  }
@@ -14273,7 +14497,7 @@ async function uninstallHooksIntegration(agentKey, spec) {
14273
14497
  if (spec.commandFormat === "skill") {
14274
14498
  const skillDir = expandPath(join10(spec.commandsPath, spec.handoffCommandName));
14275
14499
  const skillPath = join10(skillDir, "SKILL.md");
14276
- if (existsSync6(skillPath)) {
14500
+ if (existsSync7(skillPath)) {
14277
14501
  unlinkSync4(skillPath);
14278
14502
  try {
14279
14503
  rmdirSync(skillDir);
@@ -14283,7 +14507,7 @@ async function uninstallHooksIntegration(agentKey, spec) {
14283
14507
  }
14284
14508
  } else {
14285
14509
  const cmdPath = expandPath(join10(spec.commandsPath, `${spec.handoffCommandName}.md`));
14286
- if (existsSync6(cmdPath)) {
14510
+ if (existsSync7(cmdPath)) {
14287
14511
  unlinkSync4(cmdPath);
14288
14512
  logs.push(`Removed ${cmdPath}`);
14289
14513
  }
@@ -14310,11 +14534,11 @@ async function installPluginIntegration(_agentKey, spec) {
14310
14534
  const pluginsDir = expandPath(spec.pluginsPath);
14311
14535
  mkdirSync5(pluginsDir, { recursive: true });
14312
14536
  const pluginPath = join10(pluginsDir, spec.pluginFileName);
14313
- if (existsSync6(commandPath) && existsSync6(pluginPath)) {
14537
+ if (existsSync7(commandPath) && existsSync7(pluginPath)) {
14314
14538
  logs.push("Already installed, skipping.");
14315
14539
  return { success: true, logs };
14316
14540
  }
14317
- if (existsSync6(commandPath) || existsSync6(pluginPath)) {
14541
+ if (existsSync7(commandPath) || existsSync7(pluginPath)) {
14318
14542
  logs.push("Overwriting existing files.");
14319
14543
  }
14320
14544
  writeFileSync5(commandPath, generateOpencodeHandoffCommand(spec));
@@ -14332,13 +14556,13 @@ async function uninstallPluginIntegration(_agentKey, spec) {
14332
14556
  try {
14333
14557
  const commandPath = join10(expandPath(spec.commandsPath), spec.handoffCommandFile);
14334
14558
  let removedCount = 0;
14335
- if (existsSync6(commandPath)) {
14559
+ if (existsSync7(commandPath)) {
14336
14560
  unlinkSync4(commandPath);
14337
14561
  logs.push(`Removed ${commandPath}`);
14338
14562
  removedCount += 1;
14339
14563
  }
14340
14564
  const pluginPath = join10(expandPath(spec.pluginsPath), spec.pluginFileName);
14341
- if (existsSync6(pluginPath)) {
14565
+ if (existsSync7(pluginPath)) {
14342
14566
  unlinkSync4(pluginPath);
14343
14567
  logs.push(`Removed ${pluginPath}`);
14344
14568
  removedCount += 1;
@@ -14372,11 +14596,11 @@ function buildHandoffItem(agentKey, spec) {
14372
14596
  isInstalled() {
14373
14597
  if (isHooksIntegrationSpec(spec)) {
14374
14598
  const hooksDir = expandPath(spec.hooksDirPath);
14375
- return existsSync6(join10(hooksDir, "openacp-inject-session.sh")) && existsSync6(join10(hooksDir, "openacp-handoff.sh"));
14599
+ return existsSync7(join10(hooksDir, "openacp-inject-session.sh")) && existsSync7(join10(hooksDir, "openacp-handoff.sh"));
14376
14600
  }
14377
14601
  const commandPath = join10(expandPath(spec.commandsPath), spec.handoffCommandFile);
14378
14602
  const pluginPath = join10(expandPath(spec.pluginsPath), spec.pluginFileName);
14379
- return existsSync6(commandPath) && existsSync6(pluginPath);
14603
+ return existsSync7(commandPath) && existsSync7(pluginPath);
14380
14604
  },
14381
14605
  install: () => installIntegration(agentKey, spec),
14382
14606
  uninstall: () => uninstallIntegration(agentKey, spec)
@@ -14398,7 +14622,7 @@ function buildTunnelItem(spec) {
14398
14622
  name: "Tunnel",
14399
14623
  description: "Expose local ports to the internet via OpenACP tunnel",
14400
14624
  isInstalled() {
14401
- return existsSync6(getTunnelPath());
14625
+ return existsSync7(getTunnelPath());
14402
14626
  },
14403
14627
  async install() {
14404
14628
  const logs = [];
@@ -14417,7 +14641,7 @@ function buildTunnelItem(spec) {
14417
14641
  const logs = [];
14418
14642
  try {
14419
14643
  const skillPath = getTunnelPath();
14420
- if (existsSync6(skillPath)) {
14644
+ if (existsSync7(skillPath)) {
14421
14645
  unlinkSync4(skillPath);
14422
14646
  try {
14423
14647
  rmdirSync(dirname7(skillPath));
@@ -15180,7 +15404,7 @@ var init_config4 = __esm({
15180
15404
  // src/core/doctor/checks/agents.ts
15181
15405
  import { execFileSync as execFileSync4 } from "child_process";
15182
15406
  import * as fs24 from "fs";
15183
- import * as path27 from "path";
15407
+ import * as path28 from "path";
15184
15408
  function commandExists2(cmd) {
15185
15409
  try {
15186
15410
  execFileSync4("which", [cmd], { stdio: "pipe" });
@@ -15189,9 +15413,9 @@ function commandExists2(cmd) {
15189
15413
  }
15190
15414
  let dir = process.cwd();
15191
15415
  while (true) {
15192
- const binPath = path27.join(dir, "node_modules", ".bin", cmd);
15416
+ const binPath = path28.join(dir, "node_modules", ".bin", cmd);
15193
15417
  if (fs24.existsSync(binPath)) return true;
15194
- const parent = path27.dirname(dir);
15418
+ const parent = path28.dirname(dir);
15195
15419
  if (parent === dir) break;
15196
15420
  dir = parent;
15197
15421
  }
@@ -15213,7 +15437,7 @@ var init_agents3 = __esm({
15213
15437
  const defaultAgent = ctx.config.defaultAgent;
15214
15438
  let agents = {};
15215
15439
  try {
15216
- const agentsPath = path27.join(ctx.dataDir, "agents.json");
15440
+ const agentsPath = path28.join(ctx.dataDir, "agents.json");
15217
15441
  if (fs24.existsSync(agentsPath)) {
15218
15442
  const data = JSON.parse(fs24.readFileSync(agentsPath, "utf-8"));
15219
15443
  agents = data.installed ?? {};
@@ -15254,7 +15478,7 @@ __export(settings_manager_exports, {
15254
15478
  SettingsManager: () => SettingsManager
15255
15479
  });
15256
15480
  import fs25 from "fs";
15257
- import path28 from "path";
15481
+ import path29 from "path";
15258
15482
  var SettingsManager, SettingsAPIImpl;
15259
15483
  var init_settings_manager = __esm({
15260
15484
  "src/core/plugin/settings-manager.ts"() {
@@ -15297,7 +15521,7 @@ var init_settings_manager = __esm({
15297
15521
  }
15298
15522
  /** Resolve the absolute path to a plugin's settings.json file. */
15299
15523
  getSettingsPath(pluginName) {
15300
- return path28.join(this.basePath, pluginName, "settings.json");
15524
+ return path29.join(this.basePath, pluginName, "settings.json");
15301
15525
  }
15302
15526
  async getPluginSettings(pluginName) {
15303
15527
  return this.loadSettings(pluginName);
@@ -15327,7 +15551,7 @@ var init_settings_manager = __esm({
15327
15551
  }
15328
15552
  }
15329
15553
  writeFile(data) {
15330
- const dir = path28.dirname(this.settingsPath);
15554
+ const dir = path29.dirname(this.settingsPath);
15331
15555
  fs25.mkdirSync(dir, { recursive: true });
15332
15556
  fs25.writeFileSync(this.settingsPath, JSON.stringify(data, null, 2));
15333
15557
  this.cache = data;
@@ -15364,7 +15588,7 @@ var init_settings_manager = __esm({
15364
15588
  });
15365
15589
 
15366
15590
  // src/core/doctor/checks/telegram.ts
15367
- import * as path29 from "path";
15591
+ import * as path30 from "path";
15368
15592
  var BOT_TOKEN_REGEX, telegramCheck;
15369
15593
  var init_telegram = __esm({
15370
15594
  "src/core/doctor/checks/telegram.ts"() {
@@ -15380,7 +15604,7 @@ var init_telegram = __esm({
15380
15604
  return results;
15381
15605
  }
15382
15606
  const { SettingsManager: SettingsManager2 } = await Promise.resolve().then(() => (init_settings_manager(), settings_manager_exports));
15383
- const sm = new SettingsManager2(path29.join(ctx.pluginsDir, "data"));
15607
+ const sm = new SettingsManager2(path30.join(ctx.pluginsDir, "data"));
15384
15608
  const ps = await sm.loadSettings("@openacp/telegram");
15385
15609
  const botToken = ps.botToken;
15386
15610
  const chatId = ps.chatId;
@@ -15552,7 +15776,7 @@ var init_storage = __esm({
15552
15776
 
15553
15777
  // src/core/doctor/checks/workspace.ts
15554
15778
  import * as fs27 from "fs";
15555
- import * as path30 from "path";
15779
+ import * as path31 from "path";
15556
15780
  var workspaceCheck;
15557
15781
  var init_workspace2 = __esm({
15558
15782
  "src/core/doctor/checks/workspace.ts"() {
@@ -15562,7 +15786,7 @@ var init_workspace2 = __esm({
15562
15786
  order: 5,
15563
15787
  async run(ctx) {
15564
15788
  const results = [];
15565
- const workspace = path30.dirname(ctx.dataDir);
15789
+ const workspace = path31.dirname(ctx.dataDir);
15566
15790
  if (!fs27.existsSync(workspace)) {
15567
15791
  results.push({
15568
15792
  status: "warn",
@@ -15590,7 +15814,7 @@ var init_workspace2 = __esm({
15590
15814
 
15591
15815
  // src/core/doctor/checks/plugins.ts
15592
15816
  import * as fs28 from "fs";
15593
- import * as path31 from "path";
15817
+ import * as path32 from "path";
15594
15818
  var pluginsCheck;
15595
15819
  var init_plugins2 = __esm({
15596
15820
  "src/core/doctor/checks/plugins.ts"() {
@@ -15609,7 +15833,7 @@ var init_plugins2 = __esm({
15609
15833
  fix: async () => {
15610
15834
  fs28.mkdirSync(ctx.pluginsDir, { recursive: true });
15611
15835
  fs28.writeFileSync(
15612
- path31.join(ctx.pluginsDir, "package.json"),
15836
+ path32.join(ctx.pluginsDir, "package.json"),
15613
15837
  JSON.stringify({ name: "openacp-plugins", private: true, dependencies: {} }, null, 2)
15614
15838
  );
15615
15839
  return { success: true, message: "initialized plugins directory" };
@@ -15618,7 +15842,7 @@ var init_plugins2 = __esm({
15618
15842
  return results;
15619
15843
  }
15620
15844
  results.push({ status: "pass", message: "Plugins directory exists" });
15621
- const pkgPath = path31.join(ctx.pluginsDir, "package.json");
15845
+ const pkgPath = path32.join(ctx.pluginsDir, "package.json");
15622
15846
  if (!fs28.existsSync(pkgPath)) {
15623
15847
  results.push({
15624
15848
  status: "warn",
@@ -15673,12 +15897,12 @@ function isProcessAlive(pid) {
15673
15897
  }
15674
15898
  }
15675
15899
  function checkPortInUse(port) {
15676
- return new Promise((resolve9) => {
15900
+ return new Promise((resolve8) => {
15677
15901
  const server = net.createServer();
15678
- server.once("error", () => resolve9(true));
15902
+ server.once("error", () => resolve8(true));
15679
15903
  server.once("listening", () => {
15680
15904
  server.close();
15681
- resolve9(false);
15905
+ resolve8(false);
15682
15906
  });
15683
15907
  server.listen(port, "127.0.0.1");
15684
15908
  });
@@ -15765,7 +15989,7 @@ var init_daemon = __esm({
15765
15989
 
15766
15990
  // src/core/doctor/checks/tunnel.ts
15767
15991
  import * as fs30 from "fs";
15768
- import * as path32 from "path";
15992
+ import * as path33 from "path";
15769
15993
  import * as os7 from "os";
15770
15994
  import { execFileSync as execFileSync5 } from "child_process";
15771
15995
  var tunnelCheck;
@@ -15782,7 +16006,7 @@ var init_tunnel3 = __esm({
15782
16006
  return results;
15783
16007
  }
15784
16008
  const { SettingsManager: SettingsManager2 } = await Promise.resolve().then(() => (init_settings_manager(), settings_manager_exports));
15785
- const sm = new SettingsManager2(path32.join(ctx.pluginsDir, "data"));
16009
+ const sm = new SettingsManager2(path33.join(ctx.pluginsDir, "data"));
15786
16010
  const tunnelSettings = await sm.loadSettings("@openacp/tunnel");
15787
16011
  const tunnelEnabled = tunnelSettings.enabled ?? false;
15788
16012
  const provider = tunnelSettings.provider ?? "cloudflare";
@@ -15794,7 +16018,7 @@ var init_tunnel3 = __esm({
15794
16018
  results.push({ status: "pass", message: `Tunnel provider: ${provider}` });
15795
16019
  if (provider === "cloudflare") {
15796
16020
  const binName = os7.platform() === "win32" ? "cloudflared.exe" : "cloudflared";
15797
- const binPath = path32.join(ctx.dataDir, "bin", binName);
16021
+ const binPath = path33.join(ctx.dataDir, "bin", binName);
15798
16022
  let found = false;
15799
16023
  if (fs30.existsSync(binPath)) {
15800
16024
  found = true;
@@ -15842,7 +16066,7 @@ __export(doctor_exports, {
15842
16066
  DoctorEngine: () => DoctorEngine
15843
16067
  });
15844
16068
  import * as fs31 from "fs";
15845
- import * as path33 from "path";
16069
+ import * as path34 from "path";
15846
16070
  var ALL_CHECKS, CHECK_TIMEOUT_MS, DoctorEngine;
15847
16071
  var init_doctor = __esm({
15848
16072
  "src/core/doctor/index.ts"() {
@@ -15930,7 +16154,7 @@ var init_doctor = __esm({
15930
16154
  /** Constructs the shared context used by all checks — loads config if available. */
15931
16155
  async buildContext() {
15932
16156
  const dataDir = this.dataDir;
15933
- const configPath = process.env.OPENACP_CONFIG_PATH || path33.join(dataDir, "config.json");
16157
+ const configPath = process.env.OPENACP_CONFIG_PATH || path34.join(dataDir, "config.json");
15934
16158
  let config = null;
15935
16159
  let rawConfig = null;
15936
16160
  try {
@@ -15941,16 +16165,16 @@ var init_doctor = __esm({
15941
16165
  config = cm.get();
15942
16166
  } catch {
15943
16167
  }
15944
- const logsDir = config ? expandHome2(config.logging.logDir) : path33.join(dataDir, "logs");
16168
+ const logsDir = config ? expandHome2(config.logging.logDir) : path34.join(dataDir, "logs");
15945
16169
  return {
15946
16170
  config,
15947
16171
  rawConfig,
15948
16172
  configPath,
15949
16173
  dataDir,
15950
- sessionsPath: path33.join(dataDir, "sessions.json"),
15951
- pidPath: path33.join(dataDir, "openacp.pid"),
15952
- portFilePath: path33.join(dataDir, "api.port"),
15953
- pluginsDir: path33.join(dataDir, "plugins"),
16174
+ sessionsPath: path34.join(dataDir, "sessions.json"),
16175
+ pidPath: path34.join(dataDir, "openacp.pid"),
16176
+ portFilePath: path34.join(dataDir, "api.port"),
16177
+ pluginsDir: path34.join(dataDir, "plugins"),
15954
16178
  logsDir
15955
16179
  };
15956
16180
  }
@@ -17531,10 +17755,10 @@ var init_send_queue = __esm({
17531
17755
  const type = opts?.type ?? "other";
17532
17756
  const key = opts?.key;
17533
17757
  const category = opts?.category;
17534
- let resolve9;
17758
+ let resolve8;
17535
17759
  let reject;
17536
17760
  const promise = new Promise((res, rej) => {
17537
- resolve9 = res;
17761
+ resolve8 = res;
17538
17762
  reject = rej;
17539
17763
  });
17540
17764
  promise.catch(() => {
@@ -17545,12 +17769,12 @@ var init_send_queue = __esm({
17545
17769
  );
17546
17770
  if (idx !== -1) {
17547
17771
  this.items[idx].resolve(void 0);
17548
- this.items[idx] = { fn, type, key, category, resolve: resolve9, reject, promise };
17772
+ this.items[idx] = { fn, type, key, category, resolve: resolve8, reject, promise };
17549
17773
  this.scheduleProcess();
17550
17774
  return promise;
17551
17775
  }
17552
17776
  }
17553
- this.items.push({ fn, type, key, category, resolve: resolve9, reject, promise });
17777
+ this.items.push({ fn, type, key, category, resolve: resolve8, reject, promise });
17554
17778
  this.scheduleProcess();
17555
17779
  return promise;
17556
17780
  }
@@ -20507,10 +20731,10 @@ var install_context_exports = {};
20507
20731
  __export(install_context_exports, {
20508
20732
  createInstallContext: () => createInstallContext
20509
20733
  });
20510
- import path34 from "path";
20734
+ import path35 from "path";
20511
20735
  function createInstallContext(opts) {
20512
20736
  const { pluginName, settingsManager, basePath, instanceRoot } = opts;
20513
- const dataDir = path34.join(basePath, pluginName, "data");
20737
+ const dataDir = path35.join(basePath, pluginName, "data");
20514
20738
  return {
20515
20739
  pluginName,
20516
20740
  terminal: createTerminalIO(),
@@ -20538,13 +20762,13 @@ __export(api_client_exports, {
20538
20762
  waitForPortFile: () => waitForPortFile
20539
20763
  });
20540
20764
  import * as fs33 from "fs";
20541
- import * as path36 from "path";
20765
+ import * as path37 from "path";
20542
20766
  import { setTimeout as sleep } from "timers/promises";
20543
20767
  function defaultPortFile(root) {
20544
- return path36.join(root, "api.port");
20768
+ return path37.join(root, "api.port");
20545
20769
  }
20546
20770
  function defaultSecretFile(root) {
20547
- return path36.join(root, "api-secret");
20771
+ return path37.join(root, "api-secret");
20548
20772
  }
20549
20773
  async function waitForPortFile(portFilePath, timeoutMs = 5e3, intervalMs = 100) {
20550
20774
  const deadline = Date.now() + timeoutMs;
@@ -20639,9 +20863,9 @@ var init_suggest = __esm({
20639
20863
 
20640
20864
  // src/cli/instance-hint.ts
20641
20865
  import os8 from "os";
20642
- import path37 from "path";
20866
+ import path38 from "path";
20643
20867
  function printInstanceHint(root) {
20644
- const workspaceDir = path37.dirname(root);
20868
+ const workspaceDir = path38.dirname(root);
20645
20869
  const displayPath = workspaceDir.replace(os8.homedir(), "~");
20646
20870
  console.log(` Workspace: ${displayPath}`);
20647
20871
  }
@@ -20657,23 +20881,23 @@ __export(resolve_instance_id_exports, {
20657
20881
  resolveInstanceId: () => resolveInstanceId
20658
20882
  });
20659
20883
  import fs34 from "fs";
20660
- import path38 from "path";
20884
+ import path39 from "path";
20661
20885
  function resolveInstanceId(instanceRoot) {
20662
20886
  try {
20663
- const configPath = path38.join(instanceRoot, "config.json");
20887
+ const configPath = path39.join(instanceRoot, "config.json");
20664
20888
  const raw = JSON.parse(fs34.readFileSync(configPath, "utf-8"));
20665
20889
  if (raw.id && typeof raw.id === "string") return raw.id;
20666
20890
  } catch {
20667
20891
  }
20668
20892
  try {
20669
- const reg = new InstanceRegistry(path38.join(getGlobalRoot(), "instances.json"));
20893
+ const reg = new InstanceRegistry(path39.join(getGlobalRoot(), "instances.json"));
20670
20894
  reg.load();
20671
20895
  const entry = reg.getByRoot(instanceRoot);
20672
20896
  if (entry?.id) return entry.id;
20673
20897
  } catch (err) {
20674
20898
  log31.debug({ err: err.message, instanceRoot }, "Could not read instance registry, using fallback id");
20675
20899
  }
20676
- return path38.basename(path38.dirname(instanceRoot)).replace(/[^a-zA-Z0-9-]/g, "-") || "default";
20900
+ return path39.basename(path39.dirname(instanceRoot)).replace(/[^a-zA-Z0-9-]/g, "-") || "default";
20677
20901
  }
20678
20902
  var log31;
20679
20903
  var init_resolve_instance_id = __esm({
@@ -20705,18 +20929,18 @@ __export(daemon_exports, {
20705
20929
  });
20706
20930
  import { spawn as spawn6 } from "child_process";
20707
20931
  import * as fs35 from "fs";
20708
- import * as path39 from "path";
20932
+ import * as path40 from "path";
20709
20933
  function getPidPath(root) {
20710
- return path39.join(root, "openacp.pid");
20934
+ return path40.join(root, "openacp.pid");
20711
20935
  }
20712
20936
  function getLogDir(root) {
20713
- return path39.join(root, "logs");
20937
+ return path40.join(root, "logs");
20714
20938
  }
20715
20939
  function getRunningMarker(root) {
20716
- return path39.join(root, "running");
20940
+ return path40.join(root, "running");
20717
20941
  }
20718
20942
  function writePidFile(pidPath, pid) {
20719
- const dir = path39.dirname(pidPath);
20943
+ const dir = path40.dirname(pidPath);
20720
20944
  fs35.mkdirSync(dir, { recursive: true });
20721
20945
  fs35.writeFileSync(pidPath, String(pid));
20722
20946
  }
@@ -20765,8 +20989,8 @@ function startDaemon(pidPath, logDir2, instanceRoot) {
20765
20989
  }
20766
20990
  const resolvedLogDir = logDir2 ? expandHome2(logDir2) : getLogDir(instanceRoot);
20767
20991
  fs35.mkdirSync(resolvedLogDir, { recursive: true });
20768
- const logFile = path39.join(resolvedLogDir, "openacp.log");
20769
- const cliPath = path39.resolve(process.argv[1]);
20992
+ const logFile = path40.join(resolvedLogDir, "openacp.log");
20993
+ const cliPath = path40.resolve(process.argv[1]);
20770
20994
  const nodePath = process.execPath;
20771
20995
  const out = fs35.openSync(logFile, "a");
20772
20996
  const err = fs35.openSync(logFile, "a");
@@ -20788,7 +21012,7 @@ function startDaemon(pidPath, logDir2, instanceRoot) {
20788
21012
  return { pid: child.pid };
20789
21013
  }
20790
21014
  function sleep2(ms) {
20791
- return new Promise((resolve9) => setTimeout(resolve9, ms));
21015
+ return new Promise((resolve8) => setTimeout(resolve8, ms));
20792
21016
  }
20793
21017
  function isProcessAlive2(pid) {
20794
21018
  try {
@@ -20850,7 +21074,7 @@ async function stopDaemon(pidPath, instanceRoot) {
20850
21074
  }
20851
21075
  function markRunning(root) {
20852
21076
  const marker = getRunningMarker(root);
20853
- fs35.mkdirSync(path39.dirname(marker), { recursive: true });
21077
+ fs35.mkdirSync(path40.dirname(marker), { recursive: true });
20854
21078
  fs35.writeFileSync(marker, "");
20855
21079
  }
20856
21080
  function clearRunning(root) {
@@ -20883,19 +21107,19 @@ __export(autostart_exports, {
20883
21107
  });
20884
21108
  import { execFileSync as execFileSync6 } from "child_process";
20885
21109
  import * as fs36 from "fs";
20886
- import * as path40 from "path";
21110
+ import * as path41 from "path";
20887
21111
  import * as os9 from "os";
20888
21112
  function getLaunchdLabel(instanceId) {
20889
21113
  return `com.openacp.daemon.${instanceId}`;
20890
21114
  }
20891
21115
  function getLaunchdPlistPath(instanceId) {
20892
- return path40.join(os9.homedir(), "Library", "LaunchAgents", `${getLaunchdLabel(instanceId)}.plist`);
21116
+ return path41.join(os9.homedir(), "Library", "LaunchAgents", `${getLaunchdLabel(instanceId)}.plist`);
20893
21117
  }
20894
21118
  function getSystemdServiceName(instanceId) {
20895
21119
  return `openacp-${instanceId}`;
20896
21120
  }
20897
21121
  function getSystemdServicePath(instanceId) {
20898
- return path40.join(os9.homedir(), ".config", "systemd", "user", `${getSystemdServiceName(instanceId)}.service`);
21122
+ return path41.join(os9.homedir(), ".config", "systemd", "user", `${getSystemdServiceName(instanceId)}.service`);
20899
21123
  }
20900
21124
  function isAutoStartSupported() {
20901
21125
  return process.platform === "darwin" || process.platform === "linux";
@@ -20909,7 +21133,7 @@ function escapeSystemdValue(str) {
20909
21133
  }
20910
21134
  function generateLaunchdPlist(nodePath, cliPath, logDir2, instanceRoot, instanceId) {
20911
21135
  const label = getLaunchdLabel(instanceId);
20912
- const logFile = path40.join(logDir2, "openacp.log");
21136
+ const logFile = path41.join(logDir2, "openacp.log");
20913
21137
  return `<?xml version="1.0" encoding="UTF-8"?>
20914
21138
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
20915
21139
  <plist version="1.0">
@@ -20991,14 +21215,14 @@ function installAutoStart(logDir2, instanceRoot, instanceId) {
20991
21215
  return { success: false, error: "Auto-start not supported on this platform" };
20992
21216
  }
20993
21217
  const nodePath = process.execPath;
20994
- const cliPath = path40.resolve(process.argv[1]);
20995
- const resolvedLogDir = logDir2.startsWith("~") ? path40.join(os9.homedir(), logDir2.slice(1)) : logDir2;
21218
+ const cliPath = path41.resolve(process.argv[1]);
21219
+ const resolvedLogDir = logDir2.startsWith("~") ? path41.join(os9.homedir(), logDir2.slice(1)) : logDir2;
20996
21220
  try {
20997
21221
  migrateLegacy();
20998
21222
  if (process.platform === "darwin") {
20999
21223
  const plistPath = getLaunchdPlistPath(instanceId);
21000
21224
  const plist = generateLaunchdPlist(nodePath, cliPath, resolvedLogDir, instanceRoot, instanceId);
21001
- const dir = path40.dirname(plistPath);
21225
+ const dir = path41.dirname(plistPath);
21002
21226
  fs36.mkdirSync(dir, { recursive: true });
21003
21227
  fs36.writeFileSync(plistPath, plist);
21004
21228
  const uid = process.getuid();
@@ -21015,7 +21239,7 @@ function installAutoStart(logDir2, instanceRoot, instanceId) {
21015
21239
  const servicePath = getSystemdServicePath(instanceId);
21016
21240
  const serviceName = getSystemdServiceName(instanceId);
21017
21241
  const unit = generateSystemdUnit(nodePath, cliPath, instanceRoot, instanceId);
21018
- const dir = path40.dirname(servicePath);
21242
+ const dir = path41.dirname(servicePath);
21019
21243
  fs36.mkdirSync(dir, { recursive: true });
21020
21244
  fs36.writeFileSync(servicePath, unit);
21021
21245
  execFileSync6("systemctl", ["--user", "daemon-reload"], { stdio: "pipe" });
@@ -21084,8 +21308,8 @@ var init_autostart = __esm({
21084
21308
  "use strict";
21085
21309
  init_log();
21086
21310
  log32 = createChildLogger({ module: "autostart" });
21087
- LEGACY_LAUNCHD_PLIST_PATH = path40.join(os9.homedir(), "Library", "LaunchAgents", "com.openacp.daemon.plist");
21088
- LEGACY_SYSTEMD_SERVICE_PATH = path40.join(os9.homedir(), ".config", "systemd", "user", "openacp.service");
21311
+ LEGACY_LAUNCHD_PLIST_PATH = path41.join(os9.homedir(), "Library", "LaunchAgents", "com.openacp.daemon.plist");
21312
+ LEGACY_SYSTEMD_SERVICE_PATH = path41.join(os9.homedir(), ".config", "systemd", "user", "openacp.service");
21089
21313
  }
21090
21314
  });
21091
21315
 
@@ -21140,7 +21364,7 @@ var init_stop = __esm({
21140
21364
 
21141
21365
  // src/core/security/path-guard.ts
21142
21366
  import fs37 from "fs";
21143
- import path42 from "path";
21367
+ import path43 from "path";
21144
21368
  import ignore from "ignore";
21145
21369
  var DEFAULT_DENY_PATTERNS, PathGuard;
21146
21370
  var init_path_guard = __esm({
@@ -21169,15 +21393,15 @@ var init_path_guard = __esm({
21169
21393
  ig;
21170
21394
  constructor(options) {
21171
21395
  try {
21172
- this.cwd = fs37.realpathSync(path42.resolve(options.cwd));
21396
+ this.cwd = fs37.realpathSync(path43.resolve(options.cwd));
21173
21397
  } catch {
21174
- this.cwd = path42.resolve(options.cwd);
21398
+ this.cwd = path43.resolve(options.cwd);
21175
21399
  }
21176
21400
  this.allowedPaths = options.allowedPaths.map((p2) => {
21177
21401
  try {
21178
- return fs37.realpathSync(path42.resolve(p2));
21402
+ return fs37.realpathSync(path43.resolve(p2));
21179
21403
  } catch {
21180
- return path42.resolve(p2);
21404
+ return path43.resolve(p2);
21181
21405
  }
21182
21406
  });
21183
21407
  this.ig = ignore();
@@ -21201,19 +21425,19 @@ var init_path_guard = __esm({
21201
21425
  * @returns `{ allowed: true }` or `{ allowed: false, reason: "..." }`
21202
21426
  */
21203
21427
  validatePath(targetPath, operation) {
21204
- const resolved = path42.resolve(targetPath);
21428
+ const resolved = path43.resolve(targetPath);
21205
21429
  let realPath;
21206
21430
  try {
21207
21431
  realPath = fs37.realpathSync(resolved);
21208
21432
  } catch {
21209
21433
  realPath = resolved;
21210
21434
  }
21211
- if (operation === "write" && path42.basename(realPath) === ".openacpignore") {
21435
+ if (operation === "write" && path43.basename(realPath) === ".openacpignore") {
21212
21436
  return { allowed: false, reason: "Cannot write to .openacpignore" };
21213
21437
  }
21214
- const isWithinCwd = realPath === this.cwd || realPath.startsWith(this.cwd + path42.sep);
21438
+ const isWithinCwd = realPath === this.cwd || realPath.startsWith(this.cwd + path43.sep);
21215
21439
  const isWithinAllowed = this.allowedPaths.some(
21216
- (ap) => realPath === ap || realPath.startsWith(ap + path42.sep)
21440
+ (ap) => realPath === ap || realPath.startsWith(ap + path43.sep)
21217
21441
  );
21218
21442
  if (!isWithinCwd && !isWithinAllowed) {
21219
21443
  return {
@@ -21222,7 +21446,7 @@ var init_path_guard = __esm({
21222
21446
  };
21223
21447
  }
21224
21448
  if (isWithinCwd && !isWithinAllowed) {
21225
- const relativePath = path42.relative(this.cwd, realPath);
21449
+ const relativePath = path43.relative(this.cwd, realPath);
21226
21450
  if (relativePath === ".openacpignore") {
21227
21451
  return { allowed: true, reason: "" };
21228
21452
  }
@@ -21238,9 +21462,9 @@ var init_path_guard = __esm({
21238
21462
  /** Adds an additional allowed path at runtime (e.g. for file-service uploads). */
21239
21463
  addAllowedPath(p2) {
21240
21464
  try {
21241
- this.allowedPaths.push(fs37.realpathSync(path42.resolve(p2)));
21465
+ this.allowedPaths.push(fs37.realpathSync(path43.resolve(p2)));
21242
21466
  } catch {
21243
- this.allowedPaths.push(path42.resolve(p2));
21467
+ this.allowedPaths.push(path43.resolve(p2));
21244
21468
  }
21245
21469
  }
21246
21470
  /**
@@ -21248,7 +21472,7 @@ var init_path_guard = __esm({
21248
21472
  * Follows .gitignore syntax — blank lines and lines starting with # are skipped.
21249
21473
  */
21250
21474
  static loadIgnoreFile(cwd) {
21251
- const ignorePath = path42.join(cwd, ".openacpignore");
21475
+ const ignorePath = path43.join(cwd, ".openacpignore");
21252
21476
  try {
21253
21477
  const content = fs37.readFileSync(ignorePath, "utf-8");
21254
21478
  return content.split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
@@ -21328,15 +21552,15 @@ var init_env_filter = __esm({
21328
21552
  function nodeToWebWritable(nodeStream) {
21329
21553
  return new WritableStream({
21330
21554
  write(chunk) {
21331
- return new Promise((resolve9, reject) => {
21555
+ return new Promise((resolve8, reject) => {
21332
21556
  const ok3 = nodeStream.write(chunk);
21333
21557
  if (ok3) {
21334
- resolve9();
21558
+ resolve8();
21335
21559
  return;
21336
21560
  }
21337
21561
  const onDrain = () => {
21338
21562
  nodeStream.removeListener("error", onError);
21339
- resolve9();
21563
+ resolve8();
21340
21564
  };
21341
21565
  const onError = (err) => {
21342
21566
  nodeStream.removeListener("drain", onDrain);
@@ -21666,12 +21890,12 @@ var init_terminal_manager = __esm({
21666
21890
  signal: state.exitStatus.signal
21667
21891
  };
21668
21892
  }
21669
- return new Promise((resolve9) => {
21893
+ return new Promise((resolve8) => {
21670
21894
  state.process.on("exit", (code, signal) => {
21671
- resolve9({ exitCode: code, signal });
21895
+ resolve8({ exitCode: code, signal });
21672
21896
  });
21673
21897
  if (state.exitStatus !== null) {
21674
- resolve9({
21898
+ resolve8({
21675
21899
  exitCode: state.exitStatus.exitCode,
21676
21900
  signal: state.exitStatus.signal
21677
21901
  });
@@ -21725,7 +21949,7 @@ var init_mcp_manager = __esm({
21725
21949
 
21726
21950
  // src/core/utils/debug-tracer.ts
21727
21951
  import fs38 from "fs";
21728
- import path43 from "path";
21952
+ import path44 from "path";
21729
21953
  function createDebugTracer(sessionId, workingDirectory) {
21730
21954
  if (!DEBUG_ENABLED) return null;
21731
21955
  return new DebugTracer(sessionId, workingDirectory);
@@ -21739,7 +21963,7 @@ var init_debug_tracer = __esm({
21739
21963
  constructor(sessionId, workingDirectory) {
21740
21964
  this.sessionId = sessionId;
21741
21965
  this.workingDirectory = workingDirectory;
21742
- this.logDir = path43.join(workingDirectory, ".log");
21966
+ this.logDir = path44.join(workingDirectory, ".log");
21743
21967
  }
21744
21968
  sessionId;
21745
21969
  workingDirectory;
@@ -21757,7 +21981,7 @@ var init_debug_tracer = __esm({
21757
21981
  fs38.mkdirSync(this.logDir, { recursive: true });
21758
21982
  this.dirCreated = true;
21759
21983
  }
21760
- const filePath = path43.join(this.logDir, `${this.sessionId}_${layer}.jsonl`);
21984
+ const filePath = path44.join(this.logDir, `${this.sessionId}_${layer}.jsonl`);
21761
21985
  const seen = /* @__PURE__ */ new WeakSet();
21762
21986
  const line = JSON.stringify({ ts: Date.now(), ...data }, (_key, value) => {
21763
21987
  if (typeof value === "object" && value !== null) {
@@ -21781,21 +22005,21 @@ var init_debug_tracer = __esm({
21781
22005
  import { spawn as spawn8, execFileSync as execFileSync7 } from "child_process";
21782
22006
  import { Transform } from "stream";
21783
22007
  import fs39 from "fs";
21784
- import path44 from "path";
22008
+ import path45 from "path";
21785
22009
  import { ClientSideConnection, ndJsonStream } from "@agentclientprotocol/sdk";
21786
22010
  import { PROTOCOL_VERSION } from "@agentclientprotocol/sdk";
21787
22011
  function findPackageRoot(startDir) {
21788
22012
  let dir = startDir;
21789
- while (dir !== path44.dirname(dir)) {
21790
- if (fs39.existsSync(path44.join(dir, "package.json"))) {
22013
+ while (dir !== path45.dirname(dir)) {
22014
+ if (fs39.existsSync(path45.join(dir, "package.json"))) {
21791
22015
  return dir;
21792
22016
  }
21793
- dir = path44.dirname(dir);
22017
+ dir = path45.dirname(dir);
21794
22018
  }
21795
22019
  return startDir;
21796
22020
  }
21797
22021
  function commandForWindowsScript(filePath) {
21798
- const ext = path44.extname(filePath).toLowerCase();
22022
+ const ext = path45.extname(filePath).toLowerCase();
21799
22023
  if (process.platform === "win32" && (ext === ".cmd" || ext === ".bat")) {
21800
22024
  return { command: process.env.ComSpec ?? "cmd.exe", args: ["/d", "/s", "/c", `"${filePath}"`] };
21801
22025
  }
@@ -21809,8 +22033,8 @@ function resolveAgentCommand(cmd) {
21809
22033
  }
21810
22034
  for (const root of searchRoots) {
21811
22035
  const packageDirs = [
21812
- path44.resolve(root, "node_modules", "@zed-industries", cmd, "dist", "index.js"),
21813
- path44.resolve(root, "node_modules", cmd, "dist", "index.js")
22036
+ path45.resolve(root, "node_modules", "@zed-industries", cmd, "dist", "index.js"),
22037
+ path45.resolve(root, "node_modules", cmd, "dist", "index.js")
21814
22038
  ];
21815
22039
  for (const jsPath of packageDirs) {
21816
22040
  if (fs39.existsSync(jsPath)) {
@@ -21819,7 +22043,7 @@ function resolveAgentCommand(cmd) {
21819
22043
  }
21820
22044
  }
21821
22045
  for (const root of searchRoots) {
21822
- const localBin = path44.resolve(root, "node_modules", ".bin", cmd);
22046
+ const localBin = path45.resolve(root, "node_modules", ".bin", cmd);
21823
22047
  if (fs39.existsSync(localBin)) {
21824
22048
  const content = fs39.readFileSync(localBin, "utf-8");
21825
22049
  if (content.startsWith("#!/usr/bin/env node")) {
@@ -21827,7 +22051,7 @@ function resolveAgentCommand(cmd) {
21827
22051
  }
21828
22052
  const match = content.match(/"([^"]+\.js)"/);
21829
22053
  if (match) {
21830
- const target = path44.resolve(path44.dirname(localBin), match[1]);
22054
+ const target = path45.resolve(path45.dirname(localBin), match[1]);
21831
22055
  if (fs39.existsSync(target)) {
21832
22056
  return { command: process.execPath, args: [target] };
21833
22057
  }
@@ -21843,9 +22067,9 @@ function resolveAgentCommand(cmd) {
21843
22067
  candidates.push(dir);
21844
22068
  }
21845
22069
  };
21846
- addCandidate(path44.dirname(process.execPath));
22070
+ addCandidate(path45.dirname(process.execPath));
21847
22071
  try {
21848
- addCandidate(path44.dirname(fs39.realpathSync(process.execPath)));
22072
+ addCandidate(path45.dirname(fs39.realpathSync(process.execPath)));
21849
22073
  } catch {
21850
22074
  }
21851
22075
  addCandidate("/opt/homebrew/bin");
@@ -21854,8 +22078,8 @@ function resolveAgentCommand(cmd) {
21854
22078
  for (const dir of candidates) {
21855
22079
  if (cmd === "npx") {
21856
22080
  const npxCliCandidates = [
21857
- path44.join(dir, "node_modules", "npm", "bin", "npx-cli.js"),
21858
- path44.join(path44.dirname(dir), "lib", "node_modules", "npm", "bin", "npx-cli.js")
22081
+ path45.join(dir, "node_modules", "npm", "bin", "npx-cli.js"),
22082
+ path45.join(path45.dirname(dir), "lib", "node_modules", "npm", "bin", "npx-cli.js")
21859
22083
  ];
21860
22084
  for (const npxCli of npxCliCandidates) {
21861
22085
  if (fs39.existsSync(npxCli)) {
@@ -21865,7 +22089,7 @@ function resolveAgentCommand(cmd) {
21865
22089
  }
21866
22090
  }
21867
22091
  for (const name of executableNames) {
21868
- const candidate = path44.join(dir, name);
22092
+ const candidate = path45.join(dir, name);
21869
22093
  if (fs39.existsSync(candidate)) {
21870
22094
  const resolved = commandForWindowsScript(candidate);
21871
22095
  log33.info({ cmd, resolved: candidate }, "Resolved package runner from fallback search");
@@ -21877,7 +22101,7 @@ function resolveAgentCommand(cmd) {
21877
22101
  }
21878
22102
  try {
21879
22103
  const fullPath = execFileSync7("which", [cmd], { encoding: "utf-8" }).trim();
21880
- const isUnspawnableWindowsShim = process.platform === "win32" && (cmd === "npx" || cmd === "uvx") && !path44.extname(fullPath);
22104
+ const isUnspawnableWindowsShim = process.platform === "win32" && (cmd === "npx" || cmd === "uvx") && !path45.extname(fullPath);
21881
22105
  if (fullPath && !isUnspawnableWindowsShim) {
21882
22106
  try {
21883
22107
  const content = fs39.readFileSync(fullPath, "utf-8");
@@ -21894,7 +22118,7 @@ function resolveAgentCommand(cmd) {
21894
22118
  }
21895
22119
  function withAgentTimeout(promise, agentName, op, timeoutMs) {
21896
22120
  const timeout = timeoutMs ?? AGENT_INIT_TIMEOUT_MS;
21897
- return new Promise((resolve9, reject) => {
22121
+ return new Promise((resolve8, reject) => {
21898
22122
  const timer = setTimeout(() => {
21899
22123
  reject(new Error(
21900
22124
  `Agent "${agentName}" did not respond to ${op} within ${timeout / 1e3}s. The agent process may have hung during initialization.`
@@ -21903,7 +22127,7 @@ function withAgentTimeout(promise, agentName, op, timeoutMs) {
21903
22127
  promise.then(
21904
22128
  (val) => {
21905
22129
  clearTimeout(timer);
21906
- resolve9(val);
22130
+ resolve8(val);
21907
22131
  },
21908
22132
  (err) => {
21909
22133
  clearTimeout(timer);
@@ -22007,7 +22231,7 @@ var init_agent_instance = __esm({
22007
22231
  env: filterEnv(process.env, agentDef.env)
22008
22232
  }
22009
22233
  );
22010
- await new Promise((resolve9, reject) => {
22234
+ await new Promise((resolve8, reject) => {
22011
22235
  instance.child.on("error", (err) => {
22012
22236
  reject(
22013
22237
  new Error(
@@ -22015,7 +22239,7 @@ var init_agent_instance = __esm({
22015
22239
  )
22016
22240
  );
22017
22241
  });
22018
- instance.child.on("spawn", () => resolve9());
22242
+ instance.child.on("spawn", () => resolve8());
22019
22243
  });
22020
22244
  instance.stderrCapture = new StderrCapture(50);
22021
22245
  instance.child.stderr.on("data", (chunk) => {
@@ -22458,7 +22682,7 @@ ${stderr}`
22458
22682
  writePath = result.path;
22459
22683
  writeContent = result.content;
22460
22684
  }
22461
- await fs39.promises.mkdir(path44.dirname(writePath), { recursive: true });
22685
+ await fs39.promises.mkdir(path45.dirname(writePath), { recursive: true });
22462
22686
  await fs39.promises.writeFile(writePath, writeContent, "utf-8");
22463
22687
  return {};
22464
22688
  },
@@ -22641,15 +22865,15 @@ ${skipNote}`;
22641
22865
  this._destroying = true;
22642
22866
  this.terminalManager.destroyAll();
22643
22867
  if (this.child.exitCode !== null) return;
22644
- await new Promise((resolve9) => {
22868
+ await new Promise((resolve8) => {
22645
22869
  this.child.on("exit", () => {
22646
22870
  clearTimeout(forceKillTimer);
22647
- resolve9();
22871
+ resolve8();
22648
22872
  });
22649
22873
  this.child.kill("SIGTERM");
22650
22874
  const forceKillTimer = setTimeout(() => {
22651
22875
  if (this.child.exitCode === null) this.child.kill("SIGKILL");
22652
- resolve9();
22876
+ resolve8();
22653
22877
  }, 1e4);
22654
22878
  if (typeof forceKillTimer === "object" && forceKillTimer !== null && "unref" in forceKillTimer) {
22655
22879
  forceKillTimer.unref();
@@ -22894,8 +23118,8 @@ var init_prompt_queue = __esm({
22894
23118
  if (this.processing) {
22895
23119
  const position = this.queue.length + 1;
22896
23120
  this.onActuallyQueued?.(turnId, position, routing);
22897
- return new Promise((resolve9) => {
22898
- this.queue.push({ text: text5, userPrompt, attachments, routing, turnId, meta, resolve: resolve9 });
23121
+ return new Promise((resolve8) => {
23122
+ this.queue.push({ text: text5, userPrompt, attachments, routing, turnId, meta, resolve: resolve8 });
22899
23123
  });
22900
23124
  }
22901
23125
  await this.process(text5, userPrompt, attachments, routing, turnId, meta);
@@ -23031,8 +23255,8 @@ var init_permission_gate = __esm({
23031
23255
  this.request = request;
23032
23256
  this.settled = false;
23033
23257
  this.clearTimeout();
23034
- return new Promise((resolve9, reject) => {
23035
- this.resolveFn = resolve9;
23258
+ return new Promise((resolve8, reject) => {
23259
+ this.resolveFn = resolve8;
23036
23260
  this.rejectFn = reject;
23037
23261
  this.timeoutTimer = setTimeout(() => {
23038
23262
  this.reject("Permission request timed out (no response received)");
@@ -24718,7 +24942,7 @@ var init_extract_file_info = __esm({
24718
24942
  });
24719
24943
 
24720
24944
  // src/core/message-transformer.ts
24721
- import * as path45 from "path";
24945
+ import * as path46 from "path";
24722
24946
  function computeLineDiff(oldStr, newStr) {
24723
24947
  const oldLines = oldStr ? oldStr.split("\n") : [];
24724
24948
  const newLines = newStr ? newStr.split("\n") : [];
@@ -25024,7 +25248,7 @@ var init_message_transformer = __esm({
25024
25248
  );
25025
25249
  return;
25026
25250
  }
25027
- const fileExt = path45.extname(fileInfo.filePath).toLowerCase();
25251
+ const fileExt = path46.extname(fileInfo.filePath).toLowerCase();
25028
25252
  if (BINARY_VIEWER_EXTENSIONS.has(fileExt)) {
25029
25253
  log36.debug({ kind, filePath: fileInfo.filePath }, "enrichWithViewerLinks: skipping binary file");
25030
25254
  return;
@@ -25079,7 +25303,7 @@ var init_message_transformer = __esm({
25079
25303
 
25080
25304
  // src/core/sessions/session-store.ts
25081
25305
  import fs41 from "fs";
25082
- import path46 from "path";
25306
+ import path47 from "path";
25083
25307
  var log37, DEBOUNCE_MS3, JsonFileSessionStore;
25084
25308
  var init_session_store = __esm({
25085
25309
  "src/core/sessions/session-store.ts"() {
@@ -25171,7 +25395,7 @@ var init_session_store = __esm({
25171
25395
  version: 1,
25172
25396
  sessions: Object.fromEntries(this.records)
25173
25397
  };
25174
- const dir = path46.dirname(this.filePath);
25398
+ const dir = path47.dirname(this.filePath);
25175
25399
  if (!fs41.existsSync(dir)) fs41.mkdirSync(dir, { recursive: true });
25176
25400
  const tmpPath = `${this.filePath}.tmp`;
25177
25401
  fs41.writeFileSync(tmpPath, JSON.stringify(data, null, 2));
@@ -25940,7 +26164,7 @@ __export(agent_catalog_exports, {
25940
26164
  AgentCatalog: () => AgentCatalog
25941
26165
  });
25942
26166
  import * as fs42 from "fs";
25943
- import * as path47 from "path";
26167
+ import * as path48 from "path";
25944
26168
  function stripNpmVersion(pkg) {
25945
26169
  if (pkg.startsWith("@")) {
25946
26170
  const slashIdx = pkg.indexOf("/");
@@ -26007,7 +26231,7 @@ var init_agent_catalog = __esm({
26007
26231
  ttlHours: DEFAULT_TTL_HOURS,
26008
26232
  data
26009
26233
  };
26010
- fs42.mkdirSync(path47.dirname(this.cachePath), { recursive: true });
26234
+ fs42.mkdirSync(path48.dirname(this.cachePath), { recursive: true });
26011
26235
  fs42.writeFileSync(this.cachePath, JSON.stringify(cache, null, 2), { mode: 384 });
26012
26236
  this.enrichInstalledFromRegistry();
26013
26237
  log40.info({ count: this.registryAgents.length }, "Registry updated");
@@ -26249,9 +26473,9 @@ var init_agent_catalog = __esm({
26249
26473
  }
26250
26474
  try {
26251
26475
  const candidates = [
26252
- path47.join(import.meta.dirname, "data", "registry-snapshot.json"),
26253
- path47.join(import.meta.dirname, "..", "data", "registry-snapshot.json"),
26254
- path47.join(import.meta.dirname, "..", "..", "data", "registry-snapshot.json")
26476
+ path48.join(import.meta.dirname, "data", "registry-snapshot.json"),
26477
+ path48.join(import.meta.dirname, "..", "data", "registry-snapshot.json"),
26478
+ path48.join(import.meta.dirname, "..", "..", "data", "registry-snapshot.json")
26255
26479
  ];
26256
26480
  for (const candidate of candidates) {
26257
26481
  if (fs42.existsSync(candidate)) {
@@ -26276,7 +26500,7 @@ __export(agent_store_exports, {
26276
26500
  AgentStore: () => AgentStore
26277
26501
  });
26278
26502
  import * as fs43 from "fs";
26279
- import * as path48 from "path";
26503
+ import * as path49 from "path";
26280
26504
  import { z as z10 } from "zod";
26281
26505
  var log41, InstalledAgentSchema, AgentStoreSchema, AgentStore;
26282
26506
  var init_agent_store = __esm({
@@ -26353,7 +26577,7 @@ var init_agent_store = __esm({
26353
26577
  * may contain agent binary paths and environment variables.
26354
26578
  */
26355
26579
  save() {
26356
- fs43.mkdirSync(path48.dirname(this.filePath), { recursive: true });
26580
+ fs43.mkdirSync(path49.dirname(this.filePath), { recursive: true });
26357
26581
  const tmpPath = this.filePath + ".tmp";
26358
26582
  fs43.writeFileSync(tmpPath, JSON.stringify(this.data, null, 2), { mode: 384 });
26359
26583
  fs43.renameSync(tmpPath, this.filePath);
@@ -26672,7 +26896,7 @@ var init_error_tracker = __esm({
26672
26896
 
26673
26897
  // src/core/plugin/plugin-storage.ts
26674
26898
  import fs44 from "fs";
26675
- import path49 from "path";
26899
+ import path50 from "path";
26676
26900
  var PluginStorageImpl;
26677
26901
  var init_plugin_storage = __esm({
26678
26902
  "src/core/plugin/plugin-storage.ts"() {
@@ -26683,8 +26907,8 @@ var init_plugin_storage = __esm({
26683
26907
  /** Serializes writes to prevent concurrent file corruption */
26684
26908
  writeChain = Promise.resolve();
26685
26909
  constructor(baseDir) {
26686
- this.dataDir = path49.join(baseDir, "data");
26687
- this.kvPath = path49.join(baseDir, "kv.json");
26910
+ this.dataDir = path50.join(baseDir, "data");
26911
+ this.kvPath = path50.join(baseDir, "kv.json");
26688
26912
  fs44.mkdirSync(baseDir, { recursive: true });
26689
26913
  }
26690
26914
  readKv() {
@@ -27048,13 +27272,13 @@ var init_plugin_context = __esm({
27048
27272
 
27049
27273
  // src/core/plugin/lifecycle-manager.ts
27050
27274
  function withTimeout(promise, ms, label) {
27051
- return new Promise((resolve9, reject) => {
27275
+ return new Promise((resolve8, reject) => {
27052
27276
  const timer = setTimeout(() => reject(new Error(`Timeout: ${label} exceeded ${ms}ms`)), ms);
27053
27277
  if (typeof timer === "object" && timer !== null && "unref" in timer) {
27054
27278
  ;
27055
27279
  timer.unref();
27056
27280
  }
27057
- promise.then(resolve9, reject).finally(() => clearTimeout(timer));
27281
+ promise.then(resolve8, reject).finally(() => clearTimeout(timer));
27058
27282
  });
27059
27283
  }
27060
27284
  function resolvePluginConfig(pluginName, configManager) {
@@ -27809,7 +28033,7 @@ var init_core_items = __esm({
27809
28033
  });
27810
28034
 
27811
28035
  // src/core/core.ts
27812
- import path50 from "path";
28036
+ import path51 from "path";
27813
28037
  import { nanoid as nanoid6 } from "nanoid";
27814
28038
  var log45, OpenACPCore;
27815
28039
  var init_core = __esm({
@@ -27835,6 +28059,7 @@ var init_core = __esm({
27835
28059
  init_middleware_chain();
27836
28060
  init_error_tracker();
27837
28061
  init_log();
28062
+ init_native_stt();
27838
28063
  init_events();
27839
28064
  init_turn_context();
27840
28065
  log45 = createChildLogger({ module: "core" });
@@ -27979,21 +28204,7 @@ var init_core = __esm({
27979
28204
  const settingsMgr = this.settingsManager;
27980
28205
  if (settingsMgr) {
27981
28206
  const pluginCfg = await settingsMgr.loadSettings("@openacp/speech");
27982
- const groqApiKey = pluginCfg.groqApiKey;
27983
- const sttProviders = {};
27984
- if (groqApiKey) {
27985
- sttProviders.groq = { apiKey: groqApiKey };
27986
- }
27987
- const newSpeechConfig = {
27988
- stt: {
27989
- provider: groqApiKey ? "groq" : null,
27990
- providers: sttProviders
27991
- },
27992
- tts: {
27993
- provider: pluginCfg.ttsProvider ?? null,
27994
- providers: {}
27995
- }
27996
- };
28207
+ const newSpeechConfig = buildSpeechServiceConfig(pluginCfg);
27997
28208
  speechSvc.refreshProviders(newSpeechConfig);
27998
28209
  log45.info("Speech service config updated at runtime (from plugin settings)");
27999
28210
  }
@@ -28002,7 +28213,7 @@ var init_core = __esm({
28002
28213
  }
28003
28214
  );
28004
28215
  registerCoreMenuItems(this.menuRegistry);
28005
- this.assistantRegistry.setInstanceRoot(path50.dirname(ctx.root));
28216
+ this.assistantRegistry.setInstanceRoot(path51.dirname(ctx.root));
28006
28217
  this.assistantRegistry.register(createSessionsSection(this));
28007
28218
  this.assistantRegistry.register(createAgentsSection(this));
28008
28219
  this.assistantRegistry.register(createConfigSection(this));
@@ -28436,8 +28647,8 @@ ${text5}`;
28436
28647
  message: `Agent '${agentName}' not found`
28437
28648
  };
28438
28649
  }
28439
- const { existsSync: existsSync20 } = await import("fs");
28440
- if (!existsSync20(cwd)) {
28650
+ const { existsSync: existsSync21 } = await import("fs");
28651
+ if (!existsSync21(cwd)) {
28441
28652
  return {
28442
28653
  ok: false,
28443
28654
  error: "invalid_cwd",
@@ -30155,11 +30366,11 @@ __export(instance_copy_exports, {
30155
30366
  copyInstance: () => copyInstance
30156
30367
  });
30157
30368
  import fs45 from "fs";
30158
- import path51 from "path";
30369
+ import path52 from "path";
30159
30370
  async function copyInstance(src, dst, opts) {
30160
30371
  const { inheritableKeys = {}, onProgress } = opts;
30161
30372
  fs45.mkdirSync(dst, { recursive: true });
30162
- const configSrc = path51.join(src, "config.json");
30373
+ const configSrc = path52.join(src, "config.json");
30163
30374
  if (fs45.existsSync(configSrc)) {
30164
30375
  onProgress?.("Configuration", "start");
30165
30376
  const config = JSON.parse(fs45.readFileSync(configSrc, "utf-8"));
@@ -30183,44 +30394,44 @@ async function copyInstance(src, dst, opts) {
30183
30394
  }
30184
30395
  }
30185
30396
  }
30186
- fs45.writeFileSync(path51.join(dst, "config.json"), JSON.stringify(config, null, 2));
30397
+ fs45.writeFileSync(path52.join(dst, "config.json"), JSON.stringify(config, null, 2));
30187
30398
  onProgress?.("Configuration", "done");
30188
30399
  }
30189
- const pluginsSrc = path51.join(src, "plugins.json");
30400
+ const pluginsSrc = path52.join(src, "plugins.json");
30190
30401
  if (fs45.existsSync(pluginsSrc)) {
30191
30402
  onProgress?.("Plugin list", "start");
30192
- fs45.copyFileSync(pluginsSrc, path51.join(dst, "plugins.json"));
30403
+ fs45.copyFileSync(pluginsSrc, path52.join(dst, "plugins.json"));
30193
30404
  onProgress?.("Plugin list", "done");
30194
30405
  }
30195
- const pluginsDir = path51.join(src, "plugins");
30406
+ const pluginsDir = path52.join(src, "plugins");
30196
30407
  if (fs45.existsSync(pluginsDir)) {
30197
30408
  onProgress?.("Plugins", "start");
30198
- const dstPlugins = path51.join(dst, "plugins");
30409
+ const dstPlugins = path52.join(dst, "plugins");
30199
30410
  fs45.mkdirSync(dstPlugins, { recursive: true });
30200
- const pkgJson = path51.join(pluginsDir, "package.json");
30201
- if (fs45.existsSync(pkgJson)) fs45.copyFileSync(pkgJson, path51.join(dstPlugins, "package.json"));
30202
- const nodeModules = path51.join(pluginsDir, "node_modules");
30203
- if (fs45.existsSync(nodeModules)) fs45.cpSync(nodeModules, path51.join(dstPlugins, "node_modules"), { recursive: true });
30411
+ const pkgJson = path52.join(pluginsDir, "package.json");
30412
+ if (fs45.existsSync(pkgJson)) fs45.copyFileSync(pkgJson, path52.join(dstPlugins, "package.json"));
30413
+ const nodeModules = path52.join(pluginsDir, "node_modules");
30414
+ if (fs45.existsSync(nodeModules)) fs45.cpSync(nodeModules, path52.join(dstPlugins, "node_modules"), { recursive: true });
30204
30415
  onProgress?.("Plugins", "done");
30205
30416
  }
30206
- const agentsJson = path51.join(src, "agents.json");
30417
+ const agentsJson = path52.join(src, "agents.json");
30207
30418
  if (fs45.existsSync(agentsJson)) {
30208
30419
  onProgress?.("Agents", "start");
30209
- fs45.copyFileSync(agentsJson, path51.join(dst, "agents.json"));
30210
- const agentsDir = path51.join(src, "agents");
30211
- if (fs45.existsSync(agentsDir)) fs45.cpSync(agentsDir, path51.join(dst, "agents"), { recursive: true });
30420
+ fs45.copyFileSync(agentsJson, path52.join(dst, "agents.json"));
30421
+ const agentsDir = path52.join(src, "agents");
30422
+ if (fs45.existsSync(agentsDir)) fs45.cpSync(agentsDir, path52.join(dst, "agents"), { recursive: true });
30212
30423
  onProgress?.("Agents", "done");
30213
30424
  }
30214
- const binDir = path51.join(src, "bin");
30425
+ const binDir = path52.join(src, "bin");
30215
30426
  if (fs45.existsSync(binDir)) {
30216
30427
  onProgress?.("Tools", "start");
30217
- fs45.cpSync(binDir, path51.join(dst, "bin"), { recursive: true });
30428
+ fs45.cpSync(binDir, path52.join(dst, "bin"), { recursive: true });
30218
30429
  onProgress?.("Tools", "done");
30219
30430
  }
30220
- const pluginDataSrc = path51.join(src, "plugins", "data");
30431
+ const pluginDataSrc = path52.join(src, "plugins", "data");
30221
30432
  if (fs45.existsSync(pluginDataSrc)) {
30222
30433
  onProgress?.("Preferences", "start");
30223
- copyPluginSettings(pluginDataSrc, path51.join(dst, "plugins", "data"), inheritableKeys);
30434
+ copyPluginSettings(pluginDataSrc, path52.join(dst, "plugins", "data"), inheritableKeys);
30224
30435
  onProgress?.("Preferences", "done");
30225
30436
  }
30226
30437
  }
@@ -30235,10 +30446,10 @@ function copyPluginSettings(srcData, dstData, inheritableKeys) {
30235
30446
  if (key in settings) filtered[key] = settings[key];
30236
30447
  }
30237
30448
  if (Object.keys(filtered).length > 0) {
30238
- const relative = path51.relative(srcData, path51.dirname(settingsPath));
30239
- const dstDir = path51.join(dstData, relative);
30449
+ const relative = path52.relative(srcData, path52.dirname(settingsPath));
30450
+ const dstDir = path52.join(dstData, relative);
30240
30451
  fs45.mkdirSync(dstDir, { recursive: true });
30241
- fs45.writeFileSync(path51.join(dstDir, "settings.json"), JSON.stringify(filtered, null, 2));
30452
+ fs45.writeFileSync(path52.join(dstDir, "settings.json"), JSON.stringify(filtered, null, 2));
30242
30453
  }
30243
30454
  } catch {
30244
30455
  }
@@ -30249,15 +30460,15 @@ function walkPluginDirs(base, cb) {
30249
30460
  for (const entry of fs45.readdirSync(base, { withFileTypes: true })) {
30250
30461
  if (!entry.isDirectory()) continue;
30251
30462
  if (entry.name.startsWith("@")) {
30252
- const scopeDir = path51.join(base, entry.name);
30463
+ const scopeDir = path52.join(base, entry.name);
30253
30464
  for (const sub of fs45.readdirSync(scopeDir, { withFileTypes: true })) {
30254
30465
  if (!sub.isDirectory()) continue;
30255
30466
  const pluginName = `${entry.name}/${sub.name}`;
30256
- const settingsPath = path51.join(scopeDir, sub.name, "settings.json");
30467
+ const settingsPath = path52.join(scopeDir, sub.name, "settings.json");
30257
30468
  if (fs45.existsSync(settingsPath)) cb(pluginName, settingsPath);
30258
30469
  }
30259
30470
  } else {
30260
- const settingsPath = path51.join(base, entry.name, "settings.json");
30471
+ const settingsPath = path52.join(base, entry.name, "settings.json");
30261
30472
  if (fs45.existsSync(settingsPath)) cb(entry.name, settingsPath);
30262
30473
  }
30263
30474
  }
@@ -30270,14 +30481,14 @@ var init_instance_copy = __esm({
30270
30481
 
30271
30482
  // src/core/setup/git-protect.ts
30272
30483
  import fs46 from "fs";
30273
- import path52 from "path";
30484
+ import path53 from "path";
30274
30485
  function protectLocalInstance(projectDir) {
30275
30486
  ensureGitignore(projectDir);
30276
30487
  ensureClaudeMd(projectDir);
30277
30488
  printSecurityWarning();
30278
30489
  }
30279
30490
  function ensureGitignore(projectDir) {
30280
- const gitignorePath = path52.join(projectDir, ".gitignore");
30491
+ const gitignorePath = path53.join(projectDir, ".gitignore");
30281
30492
  const entry = ".openacp";
30282
30493
  if (fs46.existsSync(gitignorePath)) {
30283
30494
  const content = fs46.readFileSync(gitignorePath, "utf-8");
@@ -30297,7 +30508,7 @@ ${entry}
30297
30508
  }
30298
30509
  }
30299
30510
  function ensureClaudeMd(projectDir) {
30300
- const claudeMdPath = path52.join(projectDir, "CLAUDE.md");
30511
+ const claudeMdPath = path53.join(projectDir, "CLAUDE.md");
30301
30512
  const marker = "## Local OpenACP Workspace";
30302
30513
  if (fs46.existsSync(claudeMdPath)) {
30303
30514
  const content = fs46.readFileSync(claudeMdPath, "utf-8");
@@ -30340,7 +30551,7 @@ var init_git_protect = __esm({
30340
30551
  });
30341
30552
 
30342
30553
  // src/core/setup/wizard.ts
30343
- import * as path53 from "path";
30554
+ import * as path54 from "path";
30344
30555
  import * as fs47 from "fs";
30345
30556
  import * as os10 from "os";
30346
30557
  import * as clack7 from "@clack/prompts";
@@ -30388,7 +30599,7 @@ async function runSetup(configManager, opts) {
30388
30599
  const instanceRoot = opts?.instanceRoot;
30389
30600
  let instanceName = opts?.instanceName;
30390
30601
  if (!instanceName) {
30391
- const defaultName = path53.basename(path53.dirname(instanceRoot));
30602
+ const defaultName = path54.basename(path54.dirname(instanceRoot));
30392
30603
  const locationHint = instanceRoot.replace(/\/.openacp$/, "").replace(os10.homedir(), "~");
30393
30604
  const nameResult = await clack7.text({
30394
30605
  message: `Name for this workspace (${locationHint})`,
@@ -30399,13 +30610,13 @@ async function runSetup(configManager, opts) {
30399
30610
  instanceName = nameResult.trim();
30400
30611
  }
30401
30612
  const globalRoot = getGlobalRoot();
30402
- const registryPath = path53.join(globalRoot, "instances.json");
30613
+ const registryPath = path54.join(globalRoot, "instances.json");
30403
30614
  const instanceRegistry = new InstanceRegistry(registryPath);
30404
30615
  instanceRegistry.load();
30405
30616
  let didCopy = false;
30406
30617
  if (opts?.from) {
30407
- const fromRoot = path53.join(opts.from, ".openacp");
30408
- if (fs47.existsSync(path53.join(fromRoot, "config.json"))) {
30618
+ const fromRoot = path54.join(opts.from, ".openacp");
30619
+ if (fs47.existsSync(path54.join(fromRoot, "config.json"))) {
30409
30620
  const inheritableMap = buildInheritableKeysMap();
30410
30621
  await copyInstance(fromRoot, instanceRoot, { inheritableKeys: inheritableMap });
30411
30622
  didCopy = true;
@@ -30416,7 +30627,7 @@ async function runSetup(configManager, opts) {
30416
30627
  }
30417
30628
  if (!didCopy) {
30418
30629
  const existingInstances = instanceRegistry.list().filter(
30419
- (e) => fs47.existsSync(path53.join(e.root, "config.json")) && e.root !== instanceRoot
30630
+ (e) => fs47.existsSync(path54.join(e.root, "config.json")) && e.root !== instanceRoot
30420
30631
  );
30421
30632
  if (existingInstances.length > 0) {
30422
30633
  let singleLabel;
@@ -30424,7 +30635,7 @@ async function runSetup(configManager, opts) {
30424
30635
  const e = existingInstances[0];
30425
30636
  let name = e.id;
30426
30637
  try {
30427
- const cfg = JSON.parse(fs47.readFileSync(path53.join(e.root, "config.json"), "utf-8"));
30638
+ const cfg = JSON.parse(fs47.readFileSync(path54.join(e.root, "config.json"), "utf-8"));
30428
30639
  if (cfg.instanceName) name = cfg.instanceName;
30429
30640
  } catch {
30430
30641
  }
@@ -30447,7 +30658,7 @@ async function runSetup(configManager, opts) {
30447
30658
  options: existingInstances.map((e) => {
30448
30659
  let name = e.id;
30449
30660
  try {
30450
- const cfg = JSON.parse(fs47.readFileSync(path53.join(e.root, "config.json"), "utf-8"));
30661
+ const cfg = JSON.parse(fs47.readFileSync(path54.join(e.root, "config.json"), "utf-8"));
30451
30662
  if (cfg.instanceName) name = cfg.instanceName;
30452
30663
  } catch {
30453
30664
  }
@@ -30542,9 +30753,9 @@ async function runSetup(configManager, opts) {
30542
30753
  if (channelId.startsWith("official:")) {
30543
30754
  const npmPackage = channelId.slice("official:".length);
30544
30755
  const { execFileSync: execFileSync9 } = await import("child_process");
30545
- const pluginsDir = path53.join(instanceRoot, "plugins");
30546
- const nodeModulesDir = path53.join(pluginsDir, "node_modules");
30547
- const installedPath = path53.join(nodeModulesDir, npmPackage);
30756
+ const pluginsDir = path54.join(instanceRoot, "plugins");
30757
+ const nodeModulesDir = path54.join(pluginsDir, "node_modules");
30758
+ const installedPath = path54.join(nodeModulesDir, npmPackage);
30548
30759
  if (!fs47.existsSync(installedPath)) {
30549
30760
  try {
30550
30761
  clack7.log.step(`Installing ${npmPackage}...`);
@@ -30558,9 +30769,9 @@ async function runSetup(configManager, opts) {
30558
30769
  }
30559
30770
  }
30560
30771
  try {
30561
- const installedPkgPath = path53.join(nodeModulesDir, npmPackage, "package.json");
30772
+ const installedPkgPath = path54.join(nodeModulesDir, npmPackage, "package.json");
30562
30773
  const installedPkg = JSON.parse(fs47.readFileSync(installedPkgPath, "utf-8"));
30563
- const pluginModule = await import(path53.join(nodeModulesDir, npmPackage, installedPkg.main ?? "dist/index.js"));
30774
+ const pluginModule = await import(path54.join(nodeModulesDir, npmPackage, installedPkg.main ?? "dist/index.js"));
30564
30775
  const plugin2 = pluginModule.default;
30565
30776
  if (plugin2?.install) {
30566
30777
  const installCtx = createInstallContext2({
@@ -30590,8 +30801,8 @@ async function runSetup(configManager, opts) {
30590
30801
  if (channelId.startsWith("community:")) {
30591
30802
  const npmPackage = channelId.slice("community:".length);
30592
30803
  const { execFileSync: execFileSync9 } = await import("child_process");
30593
- const pluginsDir = path53.join(instanceRoot, "plugins");
30594
- const nodeModulesDir = path53.join(pluginsDir, "node_modules");
30804
+ const pluginsDir = path54.join(instanceRoot, "plugins");
30805
+ const nodeModulesDir = path54.join(pluginsDir, "node_modules");
30595
30806
  try {
30596
30807
  execFileSync9("npm", ["install", npmPackage, "--prefix", pluginsDir, "--save", "--ignore-scripts"], {
30597
30808
  stdio: "inherit",
@@ -30603,9 +30814,9 @@ async function runSetup(configManager, opts) {
30603
30814
  }
30604
30815
  try {
30605
30816
  const { readFileSync: readFileSync18 } = await import("fs");
30606
- const installedPkgPath = path53.join(nodeModulesDir, npmPackage, "package.json");
30817
+ const installedPkgPath = path54.join(nodeModulesDir, npmPackage, "package.json");
30607
30818
  const installedPkg = JSON.parse(readFileSync18(installedPkgPath, "utf-8"));
30608
- const pluginModule = await import(path53.join(nodeModulesDir, npmPackage, installedPkg.main ?? "dist/index.js"));
30819
+ const pluginModule = await import(path54.join(nodeModulesDir, npmPackage, installedPkg.main ?? "dist/index.js"));
30609
30820
  const plugin2 = pluginModule.default;
30610
30821
  if (plugin2?.install) {
30611
30822
  const installCtx = createInstallContext2({
@@ -30658,7 +30869,7 @@ async function runSetup(configManager, opts) {
30658
30869
  workspace: { allowExternalWorkspaces: true, security: { allowedPaths: [], envWhitelist: [] } },
30659
30870
  logging: {
30660
30871
  level: "info",
30661
- logDir: path53.join(instanceRoot, "logs"),
30872
+ logDir: path54.join(instanceRoot, "logs"),
30662
30873
  maxFileSize: "10m",
30663
30874
  maxFiles: 7,
30664
30875
  sessionLogRetentionDays: 30
@@ -30685,7 +30896,7 @@ async function runSetup(configManager, opts) {
30685
30896
  instanceRegistry.register(instanceId, instanceRoot);
30686
30897
  await instanceRegistry.save();
30687
30898
  }
30688
- const projectDir = path53.dirname(instanceRoot);
30899
+ const projectDir = path54.dirname(instanceRoot);
30689
30900
  protectLocalInstance(projectDir);
30690
30901
  clack7.outro(`Config saved to ${configManager.getConfigPath()}`);
30691
30902
  if (!opts?.skipRunMode) {
@@ -30764,7 +30975,7 @@ async function runReconfigure(configManager, settingsManager) {
30764
30975
  await configureChannels(config, settingsManager);
30765
30976
  }
30766
30977
  if (choice === "agents") {
30767
- const reconfigRoot = path53.dirname(configManager.getConfigPath());
30978
+ const reconfigRoot = path54.dirname(configManager.getConfigPath());
30768
30979
  const { defaultAgent } = await setupAgents(reconfigRoot);
30769
30980
  await configManager.save({ defaultAgent });
30770
30981
  config = configManager.get();
@@ -30969,7 +31180,7 @@ __export(dev_loader_exports, {
30969
31180
  });
30970
31181
  import fs48 from "fs";
30971
31182
  import os11 from "os";
30972
- import path54 from "path";
31183
+ import path55 from "path";
30973
31184
  var loadCounter, DevPluginLoader;
30974
31185
  var init_dev_loader = __esm({
30975
31186
  "src/core/plugin/dev-loader.ts"() {
@@ -30979,24 +31190,24 @@ var init_dev_loader = __esm({
30979
31190
  pluginPath;
30980
31191
  lastTempDir = null;
30981
31192
  constructor(pluginPath) {
30982
- this.pluginPath = path54.resolve(pluginPath);
31193
+ this.pluginPath = path55.resolve(pluginPath);
30983
31194
  }
30984
31195
  async load() {
30985
- const distPath = path54.join(this.pluginPath, "dist");
30986
- const distIndex = path54.join(distPath, "index.js");
30987
- const srcIndex = path54.join(this.pluginPath, "src", "index.ts");
31196
+ const distPath = path55.join(this.pluginPath, "dist");
31197
+ const distIndex = path55.join(distPath, "index.js");
31198
+ const srcIndex = path55.join(this.pluginPath, "src", "index.ts");
30988
31199
  if (!fs48.existsSync(distIndex) && !fs48.existsSync(srcIndex)) {
30989
31200
  throw new Error(`Plugin not found at ${this.pluginPath}. Expected dist/index.js or src/index.ts`);
30990
31201
  }
30991
31202
  if (!fs48.existsSync(distIndex)) {
30992
31203
  throw new Error(`Built plugin not found at ${distIndex}. Run 'npm run build' first.`);
30993
31204
  }
30994
- const tempDir = path54.join(os11.tmpdir(), `openacp-dev-plugin-${Date.now()}-${++loadCounter}`);
31205
+ const tempDir = path55.join(os11.tmpdir(), `openacp-dev-plugin-${Date.now()}-${++loadCounter}`);
30995
31206
  fs48.cpSync(distPath, tempDir, { recursive: true });
30996
31207
  const previousTempDir = this.lastTempDir;
30997
31208
  this.lastTempDir = tempDir;
30998
31209
  try {
30999
- const mod = await import(`file://${path54.join(tempDir, "index.js")}`);
31210
+ const mod = await import(`file://${path55.join(tempDir, "index.js")}`);
31000
31211
  const plugin2 = mod.default;
31001
31212
  if (!plugin2 || !plugin2.name || !plugin2.setup) {
31002
31213
  throw new Error(`Invalid plugin at ${distIndex}. Must export default OpenACPPlugin with name and setup().`);
@@ -31019,7 +31230,7 @@ var init_dev_loader = __esm({
31019
31230
  }
31020
31231
  /** Returns the path to the plugin's dist directory (the source of truth — NOT the temp copy). */
31021
31232
  getDistPath() {
31022
- return path54.join(this.pluginPath, "dist");
31233
+ return path55.join(this.pluginPath, "dist");
31023
31234
  }
31024
31235
  };
31025
31236
  }
@@ -31031,7 +31242,7 @@ __export(main_exports, {
31031
31242
  RESTART_EXIT_CODE: () => RESTART_EXIT_CODE,
31032
31243
  startServer: () => startServer
31033
31244
  });
31034
- import path55 from "path";
31245
+ import path56 from "path";
31035
31246
  import { randomUUID as randomUUID4 } from "crypto";
31036
31247
  import fs49 from "fs";
31037
31248
  async function startServer(opts) {
@@ -31056,7 +31267,7 @@ async function startServer(opts) {
31056
31267
  process.exit(1);
31057
31268
  }
31058
31269
  const globalRoot = getGlobalRoot();
31059
- const reg = new InstanceRegistry(path55.join(globalRoot, "instances.json"));
31270
+ const reg = new InstanceRegistry(path56.join(globalRoot, "instances.json"));
31060
31271
  reg.load();
31061
31272
  const entry = reg.getByRoot(root);
31062
31273
  opts = { ...opts, instanceContext: createInstanceContext({ id: entry?.id ?? randomUUID4(), root }) };
@@ -31144,22 +31355,22 @@ async function startServer(opts) {
31144
31355
  try {
31145
31356
  let modulePath;
31146
31357
  if (name.startsWith("/") || name.startsWith(".")) {
31147
- const resolved = path55.resolve(name);
31148
- const pkgPath = path55.join(resolved, "package.json");
31358
+ const resolved = path56.resolve(name);
31359
+ const pkgPath = path56.join(resolved, "package.json");
31149
31360
  const pkg = JSON.parse(await fs49.promises.readFile(pkgPath, "utf-8"));
31150
- modulePath = path55.join(resolved, pkg.main || "dist/index.js");
31361
+ modulePath = path56.join(resolved, pkg.main || "dist/index.js");
31151
31362
  } else {
31152
- const nodeModulesDir = path55.join(ctx.paths.plugins, "node_modules");
31153
- let pkgDir = path55.join(nodeModulesDir, name);
31154
- if (!fs49.existsSync(path55.join(pkgDir, "package.json"))) {
31363
+ const nodeModulesDir = path56.join(ctx.paths.plugins, "node_modules");
31364
+ let pkgDir = path56.join(nodeModulesDir, name);
31365
+ if (!fs49.existsSync(path56.join(pkgDir, "package.json"))) {
31155
31366
  let found = false;
31156
31367
  const scopes = fs49.existsSync(nodeModulesDir) ? fs49.readdirSync(nodeModulesDir).filter((d) => d.startsWith("@")) : [];
31157
31368
  for (const scope of scopes) {
31158
- const scopeDir = path55.join(nodeModulesDir, scope);
31369
+ const scopeDir = path56.join(nodeModulesDir, scope);
31159
31370
  const pkgs = fs49.readdirSync(scopeDir);
31160
31371
  for (const pkg2 of pkgs) {
31161
- const candidateDir = path55.join(scopeDir, pkg2);
31162
- const candidatePkgPath = path55.join(candidateDir, "package.json");
31372
+ const candidateDir = path56.join(scopeDir, pkg2);
31373
+ const candidatePkgPath = path56.join(candidateDir, "package.json");
31163
31374
  if (fs49.existsSync(candidatePkgPath)) {
31164
31375
  try {
31165
31376
  const candidatePkg = JSON.parse(fs49.readFileSync(candidatePkgPath, "utf-8"));
@@ -31176,9 +31387,9 @@ async function startServer(opts) {
31176
31387
  if (found) break;
31177
31388
  }
31178
31389
  }
31179
- const pkgJsonPath = path55.join(pkgDir, "package.json");
31390
+ const pkgJsonPath = path56.join(pkgDir, "package.json");
31180
31391
  const pkg = JSON.parse(await fs49.promises.readFile(pkgJsonPath, "utf-8"));
31181
- modulePath = path55.join(pkgDir, pkg.main || "dist/index.js");
31392
+ modulePath = path56.join(pkgDir, pkg.main || "dist/index.js");
31182
31393
  }
31183
31394
  log.debug({ plugin: name, modulePath }, "Loading community plugin");
31184
31395
  const mod = await import(modulePath);
@@ -31350,7 +31561,7 @@ async function startServer(opts) {
31350
31561
  await core.start();
31351
31562
  try {
31352
31563
  const globalRoot = getGlobalRoot();
31353
- const registryPath = path55.join(globalRoot, "instances.json");
31564
+ const registryPath = path56.join(globalRoot, "instances.json");
31354
31565
  const instanceReg = new InstanceRegistry(registryPath);
31355
31566
  await instanceReg.load();
31356
31567
  if (!instanceReg.getByRoot(ctx.root)) {
@@ -31522,7 +31733,7 @@ var restart_exports = {};
31522
31733
  __export(restart_exports, {
31523
31734
  cmdRestart: () => cmdRestart
31524
31735
  });
31525
- import path56 from "path";
31736
+ import path57 from "path";
31526
31737
  import { randomUUID as randomUUID5 } from "crypto";
31527
31738
  async function cmdRestart(args2 = [], instanceRoot) {
31528
31739
  const json = isJsonMode(args2);
@@ -31562,7 +31773,7 @@ Stops the running daemon (if any) and starts a new one.
31562
31773
  if (!json && stopResult.stopped) {
31563
31774
  console.log(`Stopped daemon (was PID ${stopResult.pid})`);
31564
31775
  }
31565
- const cm = new ConfigManager2(path56.join(root, "config.json"));
31776
+ const cm = new ConfigManager2(path57.join(root, "config.json"));
31566
31777
  if (!await cm.exists()) {
31567
31778
  if (json) jsonError(ErrorCodes.CONFIG_NOT_FOUND, 'No config found. Run "openacp" first to set up.');
31568
31779
  console.error('No config found. Run "openacp" first to set up.');
@@ -31583,7 +31794,7 @@ Stops the running daemon (if any) and starts a new one.
31583
31794
  printInstanceHint(root);
31584
31795
  console.log("Starting in foreground mode...");
31585
31796
  const { startServer: startServer2 } = await Promise.resolve().then(() => (init_main(), main_exports));
31586
- const reg = new InstanceRegistry(path56.join(getGlobalRoot(), "instances.json"));
31797
+ const reg = new InstanceRegistry(path57.join(getGlobalRoot(), "instances.json"));
31587
31798
  reg.load();
31588
31799
  const existingEntry = reg.getByRoot(root);
31589
31800
  const ctx = createInstanceContext({
@@ -31632,7 +31843,7 @@ __export(status_exports, {
31632
31843
  readInstanceInfo: () => readInstanceInfo
31633
31844
  });
31634
31845
  import fs50 from "fs";
31635
- import path57 from "path";
31846
+ import path58 from "path";
31636
31847
  import os12 from "os";
31637
31848
  async function cmdStatus(args2 = [], instanceRoot) {
31638
31849
  const json = isJsonMode(args2);
@@ -31650,7 +31861,7 @@ async function cmdStatus(args2 = [], instanceRoot) {
31650
31861
  await showSingleInstance(root, json);
31651
31862
  }
31652
31863
  async function showAllInstances(json = false) {
31653
- const registryPath = path57.join(getGlobalRoot(), "instances.json");
31864
+ const registryPath = path58.join(getGlobalRoot(), "instances.json");
31654
31865
  const registry = new InstanceRegistry(registryPath);
31655
31866
  await registry.load();
31656
31867
  const instances = registry.list();
@@ -31693,7 +31904,7 @@ async function showAllInstances(json = false) {
31693
31904
  console.log("");
31694
31905
  }
31695
31906
  async function showInstanceById(id, json = false) {
31696
- const registryPath = path57.join(getGlobalRoot(), "instances.json");
31907
+ const registryPath = path58.join(getGlobalRoot(), "instances.json");
31697
31908
  const registry = new InstanceRegistry(registryPath);
31698
31909
  await registry.load();
31699
31910
  const entry = registry.get(id);
@@ -31708,7 +31919,7 @@ async function showSingleInstance(root, json = false) {
31708
31919
  const info = readInstanceInfo(root);
31709
31920
  if (json) {
31710
31921
  jsonSuccess({
31711
- id: path57.basename(root),
31922
+ id: path58.basename(root),
31712
31923
  name: info.name,
31713
31924
  status: info.pid ? "online" : "offline",
31714
31925
  pid: info.pid,
@@ -31739,13 +31950,13 @@ function readInstanceInfo(root) {
31739
31950
  channels: []
31740
31951
  };
31741
31952
  try {
31742
- const config = JSON.parse(fs50.readFileSync(path57.join(root, "config.json"), "utf-8"));
31953
+ const config = JSON.parse(fs50.readFileSync(path58.join(root, "config.json"), "utf-8"));
31743
31954
  result.name = config.instanceName ?? null;
31744
31955
  result.runMode = config.runMode ?? null;
31745
31956
  } catch {
31746
31957
  }
31747
31958
  try {
31748
- const pid = parseInt(fs50.readFileSync(path57.join(root, "openacp.pid"), "utf-8").trim());
31959
+ const pid = parseInt(fs50.readFileSync(path58.join(root, "openacp.pid"), "utf-8").trim());
31749
31960
  if (!isNaN(pid)) {
31750
31961
  process.kill(pid, 0);
31751
31962
  result.pid = pid;
@@ -31753,19 +31964,19 @@ function readInstanceInfo(root) {
31753
31964
  } catch {
31754
31965
  }
31755
31966
  try {
31756
- const port = parseInt(fs50.readFileSync(path57.join(root, "api.port"), "utf-8").trim());
31967
+ const port = parseInt(fs50.readFileSync(path58.join(root, "api.port"), "utf-8").trim());
31757
31968
  if (!isNaN(port)) result.apiPort = port;
31758
31969
  } catch {
31759
31970
  }
31760
31971
  try {
31761
- const tunnels = JSON.parse(fs50.readFileSync(path57.join(root, "tunnels.json"), "utf-8"));
31972
+ const tunnels = JSON.parse(fs50.readFileSync(path58.join(root, "tunnels.json"), "utf-8"));
31762
31973
  const entries = Object.values(tunnels);
31763
31974
  const systemEntry = entries.find((t) => t.type === "system");
31764
31975
  if (systemEntry?.port) result.tunnelPort = systemEntry.port;
31765
31976
  } catch {
31766
31977
  }
31767
31978
  try {
31768
- const plugins = JSON.parse(fs50.readFileSync(path57.join(root, "plugins.json"), "utf-8"));
31979
+ const plugins = JSON.parse(fs50.readFileSync(path58.join(root, "plugins.json"), "utf-8"));
31769
31980
  const adapterMap = [
31770
31981
  { pluginName: "@openacp/telegram", channelId: "telegram" },
31771
31982
  { pluginName: "@openacp/discord-adapter", channelId: "discord" },
@@ -31783,7 +31994,7 @@ function readInstanceInfo(root) {
31783
31994
  function formatInstanceStatus(root) {
31784
31995
  const info = readInstanceInfo(root);
31785
31996
  if (!info.pid) return null;
31786
- const workspaceDir = path57.dirname(root);
31997
+ const workspaceDir = path58.dirname(root);
31787
31998
  const displayPath = workspaceDir.replace(os12.homedir(), "~");
31788
31999
  const lines = [];
31789
32000
  lines.push(` PID: ${info.pid}`);
@@ -31852,7 +32063,7 @@ var config_editor_exports = {};
31852
32063
  __export(config_editor_exports, {
31853
32064
  runConfigEditor: () => runConfigEditor
31854
32065
  });
31855
- import * as path58 from "path";
32066
+ import * as path59 from "path";
31856
32067
  import * as clack8 from "@clack/prompts";
31857
32068
  async function select8(opts) {
31858
32069
  const result = await clack8.select({
@@ -32406,7 +32617,7 @@ async function runConfigEditor(configManager, mode = "file", apiPort, settingsMa
32406
32617
  await configManager.load();
32407
32618
  const config = configManager.get();
32408
32619
  const updates = {};
32409
- const instanceRoot = path58.dirname(configManager.getConfigPath());
32620
+ const instanceRoot = path59.dirname(configManager.getConfigPath());
32410
32621
  console.log(`
32411
32622
  ${c2.cyan}${c2.bold}OpenACP Config Editor${c2.reset}`);
32412
32623
  console.log(dim2(`Config: ${configManager.getConfigPath()}`));
@@ -32463,17 +32674,17 @@ ${c2.cyan}${c2.bold}OpenACP Config Editor${c2.reset}`);
32463
32674
  async function sendConfigViaApi(port, updates) {
32464
32675
  const { apiCall: call } = await Promise.resolve().then(() => (init_api_client(), api_client_exports));
32465
32676
  const paths = flattenToPaths(updates);
32466
- for (const { path: path71, value } of paths) {
32677
+ for (const { path: path72, value } of paths) {
32467
32678
  const res = await call(port, "/api/config", {
32468
32679
  method: "PATCH",
32469
32680
  headers: { "Content-Type": "application/json" },
32470
- body: JSON.stringify({ path: path71, value })
32681
+ body: JSON.stringify({ path: path72, value })
32471
32682
  });
32472
32683
  const data = await res.json();
32473
32684
  if (!res.ok) {
32474
- console.log(warn2(`Failed to update ${path71}: ${data.error}`));
32685
+ console.log(warn2(`Failed to update ${path72}: ${data.error}`));
32475
32686
  } else if (data.needsRestart) {
32476
- console.log(warn2(`${path71} updated \u2014 restart required`));
32687
+ console.log(warn2(`${path72} updated \u2014 restart required`));
32477
32688
  }
32478
32689
  }
32479
32690
  }
@@ -32541,7 +32752,7 @@ function showInteractiveMenu(options) {
32541
32752
  }
32542
32753
  }
32543
32754
  console.log("");
32544
- return new Promise((resolve9) => {
32755
+ return new Promise((resolve8) => {
32545
32756
  process.stdin.setRawMode(true);
32546
32757
  process.stdin.resume();
32547
32758
  const onData = async (buf) => {
@@ -32560,7 +32771,7 @@ function showInteractiveMenu(options) {
32560
32771
  console.error(err);
32561
32772
  process.exit(1);
32562
32773
  }
32563
- resolve9(true);
32774
+ resolve8(true);
32564
32775
  }
32565
32776
  };
32566
32777
  const cleanup = () => {
@@ -32583,24 +32794,24 @@ __export(migration_exports, {
32583
32794
  migrateGlobalInstance: () => migrateGlobalInstance
32584
32795
  });
32585
32796
  import fs55 from "fs";
32586
- import path68 from "path";
32797
+ import path69 from "path";
32587
32798
  import os15 from "os";
32588
32799
  import { randomUUID as randomUUID8 } from "crypto";
32589
32800
  async function migrateGlobalInstance() {
32590
32801
  const globalRoot = getGlobalRoot();
32591
- const globalConfig = path68.join(globalRoot, "config.json");
32802
+ const globalConfig = path69.join(globalRoot, "config.json");
32592
32803
  if (!fs55.existsSync(globalConfig)) return null;
32593
- let baseDir = path68.join(os15.homedir(), "openacp-workspace");
32804
+ let baseDir = path69.join(os15.homedir(), "openacp-workspace");
32594
32805
  try {
32595
32806
  const raw = JSON.parse(fs55.readFileSync(globalConfig, "utf-8"));
32596
32807
  if (raw.workspace?.baseDir) {
32597
32808
  const configured = raw.workspace.baseDir;
32598
- baseDir = configured.startsWith("~") ? path68.join(os15.homedir(), configured.slice(1)) : configured;
32809
+ baseDir = configured.startsWith("~") ? path69.join(os15.homedir(), configured.slice(1)) : configured;
32599
32810
  }
32600
32811
  } catch {
32601
32812
  }
32602
- const targetRoot = path68.join(baseDir, ".openacp");
32603
- if (path68.resolve(targetRoot) === path68.resolve(globalRoot)) {
32813
+ const targetRoot = path69.join(baseDir, ".openacp");
32814
+ if (path69.resolve(targetRoot) === path69.resolve(globalRoot)) {
32604
32815
  return null;
32605
32816
  }
32606
32817
  const instanceFiles = [
@@ -32614,34 +32825,34 @@ async function migrateGlobalInstance() {
32614
32825
  const instanceDirs = ["plugins", "logs", "history", "files"];
32615
32826
  fs55.mkdirSync(targetRoot, { recursive: true });
32616
32827
  for (const file of instanceFiles) {
32617
- const src = path68.join(globalRoot, file);
32618
- const dst = path68.join(targetRoot, file);
32828
+ const src = path69.join(globalRoot, file);
32829
+ const dst = path69.join(targetRoot, file);
32619
32830
  if (fs55.existsSync(src)) {
32620
32831
  fs55.cpSync(src, dst, { force: true });
32621
32832
  fs55.rmSync(src);
32622
32833
  }
32623
32834
  }
32624
32835
  for (const dir of instanceDirs) {
32625
- const src = path68.join(globalRoot, dir);
32626
- const dst = path68.join(targetRoot, dir);
32836
+ const src = path69.join(globalRoot, dir);
32837
+ const dst = path69.join(targetRoot, dir);
32627
32838
  if (fs55.existsSync(src)) {
32628
32839
  fs55.cpSync(src, dst, { recursive: true, force: true });
32629
32840
  fs55.rmSync(src, { recursive: true, force: true });
32630
32841
  }
32631
32842
  }
32632
- const srcCache = path68.join(globalRoot, "cache");
32633
- const dstCache = path68.join(targetRoot, "cache");
32843
+ const srcCache = path69.join(globalRoot, "cache");
32844
+ const dstCache = path69.join(targetRoot, "cache");
32634
32845
  if (fs55.existsSync(srcCache)) {
32635
32846
  fs55.mkdirSync(dstCache, { recursive: true });
32636
32847
  for (const entry of fs55.readdirSync(srcCache)) {
32637
32848
  if (entry === "registry-cache.json") continue;
32638
- const s = path68.join(srcCache, entry);
32639
- const d = path68.join(dstCache, entry);
32849
+ const s = path69.join(srcCache, entry);
32850
+ const d = path69.join(dstCache, entry);
32640
32851
  fs55.cpSync(s, d, { recursive: true, force: true });
32641
32852
  fs55.rmSync(s, { recursive: true, force: true });
32642
32853
  }
32643
32854
  }
32644
- const migratedConfigPath = path68.join(targetRoot, "config.json");
32855
+ const migratedConfigPath = path69.join(targetRoot, "config.json");
32645
32856
  try {
32646
32857
  const config = JSON.parse(fs55.readFileSync(migratedConfigPath, "utf-8"));
32647
32858
  if (config.workspace?.baseDir) {
@@ -32650,7 +32861,7 @@ async function migrateGlobalInstance() {
32650
32861
  fs55.writeFileSync(migratedConfigPath, JSON.stringify(config, null, 2));
32651
32862
  } catch {
32652
32863
  }
32653
- const registryPath = path68.join(globalRoot, "instances.json");
32864
+ const registryPath = path69.join(globalRoot, "instances.json");
32654
32865
  try {
32655
32866
  const registry = new InstanceRegistry(registryPath);
32656
32867
  registry.load();
@@ -32682,17 +32893,17 @@ __export(instance_prompt_exports, {
32682
32893
  promptForInstance: () => promptForInstance
32683
32894
  });
32684
32895
  import fs56 from "fs";
32685
- import path69 from "path";
32896
+ import path70 from "path";
32686
32897
  import os16 from "os";
32687
32898
  async function promptForInstance(opts) {
32688
32899
  const globalRoot = getGlobalRoot();
32689
- const globalConfigExists = fs56.existsSync(path69.join(globalRoot, "config.json"));
32900
+ const globalConfigExists = fs56.existsSync(path70.join(globalRoot, "config.json"));
32690
32901
  const cwd = process.cwd();
32691
- const isHomeDir = path69.resolve(cwd) === path69.resolve(os16.homedir());
32692
- const defaultWorkspace = path69.join(os16.homedir(), "openacp-workspace");
32693
- const createRoot = isHomeDir ? path69.join(defaultWorkspace, ".openacp") : path69.join(cwd, ".openacp");
32902
+ const isHomeDir = path70.resolve(cwd) === path70.resolve(os16.homedir());
32903
+ const defaultWorkspace = path70.join(os16.homedir(), "openacp-workspace");
32904
+ const createRoot = isHomeDir ? path70.join(defaultWorkspace, ".openacp") : path70.join(cwd, ".openacp");
32694
32905
  const detectedParent = findParentInstance(cwd, globalRoot);
32695
- const registryPath = path69.join(globalRoot, "instances.json");
32906
+ const registryPath = path70.join(globalRoot, "instances.json");
32696
32907
  const registry = new InstanceRegistry(registryPath);
32697
32908
  registry.load();
32698
32909
  const instances = registry.list().filter((e) => fs56.existsSync(e.root));
@@ -32724,24 +32935,24 @@ async function promptForInstance(opts) {
32724
32935
  const instanceOptions = instances.filter((e) => !detectedParent || e.root !== detectedParent).map((e) => {
32725
32936
  let name = e.id;
32726
32937
  try {
32727
- const raw = fs56.readFileSync(path69.join(e.root, "config.json"), "utf-8");
32938
+ const raw = fs56.readFileSync(path70.join(e.root, "config.json"), "utf-8");
32728
32939
  const parsed = JSON.parse(raw);
32729
32940
  if (parsed.instanceName) name = parsed.instanceName;
32730
32941
  } catch {
32731
32942
  }
32732
- const workspaceDir = path69.dirname(e.root);
32943
+ const workspaceDir = path70.dirname(e.root);
32733
32944
  const displayPath = workspaceDir.replace(os16.homedir(), "~");
32734
32945
  return { value: e.root, label: `${name} (${displayPath})` };
32735
32946
  });
32736
32947
  if (detectedParent) {
32737
- let name = path69.basename(path69.dirname(detectedParent));
32948
+ let name = path70.basename(path70.dirname(detectedParent));
32738
32949
  try {
32739
- const raw = fs56.readFileSync(path69.join(detectedParent, "config.json"), "utf-8");
32950
+ const raw = fs56.readFileSync(path70.join(detectedParent, "config.json"), "utf-8");
32740
32951
  const parsed = JSON.parse(raw);
32741
32952
  if (parsed.instanceName) name = parsed.instanceName;
32742
32953
  } catch {
32743
32954
  }
32744
- const workspaceDir = path69.dirname(detectedParent);
32955
+ const workspaceDir = path70.dirname(detectedParent);
32745
32956
  const displayPath = workspaceDir.replace(os16.homedir(), "~");
32746
32957
  instanceOptions.unshift({ value: detectedParent, label: `${name} (${displayPath})` });
32747
32958
  }
@@ -32780,11 +32991,11 @@ async function promptForInstance(opts) {
32780
32991
  return choice;
32781
32992
  }
32782
32993
  function findParentInstance(cwd, globalRoot) {
32783
- let dir = path69.dirname(cwd);
32994
+ let dir = path70.dirname(cwd);
32784
32995
  while (true) {
32785
- const candidate = path69.join(dir, ".openacp");
32786
- if (candidate !== globalRoot && fs56.existsSync(path69.join(candidate, "config.json"))) return candidate;
32787
- const parent = path69.dirname(dir);
32996
+ const candidate = path70.join(dir, ".openacp");
32997
+ if (candidate !== globalRoot && fs56.existsSync(path70.join(candidate, "config.json"))) return candidate;
32998
+ const parent = path70.dirname(dir);
32788
32999
  if (parent === dir) break;
32789
33000
  dir = parent;
32790
33001
  }
@@ -32800,7 +33011,7 @@ var init_instance_prompt = __esm({
32800
33011
 
32801
33012
  // src/cli.ts
32802
33013
  import { setDefaultAutoSelectFamily } from "net";
32803
- import path70 from "path";
33014
+ import path71 from "path";
32804
33015
 
32805
33016
  // src/cli/commands/help.ts
32806
33017
  function printHelp() {
@@ -32944,10 +33155,10 @@ Shows all plugins registered in the plugin registry.
32944
33155
  `);
32945
33156
  return;
32946
33157
  }
32947
- const path71 = await import("path");
33158
+ const path72 = await import("path");
32948
33159
  const { PluginRegistry: PluginRegistry2 } = await Promise.resolve().then(() => (init_plugin_registry(), plugin_registry_exports));
32949
33160
  const root = instanceRoot;
32950
- const registryPath = path71.join(root, "plugins.json");
33161
+ const registryPath = path72.join(root, "plugins.json");
32951
33162
  const registry = new PluginRegistry2(registryPath);
32952
33163
  await registry.load();
32953
33164
  const plugins = registry.list();
@@ -33083,10 +33294,10 @@ async function cmdPlugin(args2 = [], instanceRoot) {
33083
33294
  }
33084
33295
  async function setPluginEnabled(name, enabled, instanceRoot, json = false) {
33085
33296
  if (json) await muteForJson();
33086
- const path71 = await import("path");
33297
+ const path72 = await import("path");
33087
33298
  const { PluginRegistry: PluginRegistry2 } = await Promise.resolve().then(() => (init_plugin_registry(), plugin_registry_exports));
33088
33299
  const root = instanceRoot;
33089
- const registryPath = path71.join(root, "plugins.json");
33300
+ const registryPath = path72.join(root, "plugins.json");
33090
33301
  const registry = new PluginRegistry2(registryPath);
33091
33302
  await registry.load();
33092
33303
  const entry = registry.get(name);
@@ -33101,7 +33312,7 @@ async function setPluginEnabled(name, enabled, instanceRoot, json = false) {
33101
33312
  console.log(`Plugin ${name} ${enabled ? "enabled" : "disabled"}. Restart to apply.`);
33102
33313
  }
33103
33314
  async function configurePlugin(name, instanceRoot) {
33104
- const path71 = await import("path");
33315
+ const path72 = await import("path");
33105
33316
  const { corePlugins: corePlugins2 } = await Promise.resolve().then(() => (init_core_plugins(), core_plugins_exports));
33106
33317
  const { SettingsManager: SettingsManager2 } = await Promise.resolve().then(() => (init_settings_manager(), settings_manager_exports));
33107
33318
  const { createInstallContext: createInstallContext2 } = await Promise.resolve().then(() => (init_install_context(), install_context_exports));
@@ -33111,7 +33322,7 @@ async function configurePlugin(name, instanceRoot) {
33111
33322
  process.exit(1);
33112
33323
  }
33113
33324
  const root = instanceRoot;
33114
- const basePath = path71.join(root, "plugins", "data");
33325
+ const basePath = path72.join(root, "plugins", "data");
33115
33326
  const settingsManager = new SettingsManager2(basePath);
33116
33327
  const ctx = createInstallContext2({ pluginName: name, settingsManager, basePath });
33117
33328
  if (plugin2.configure) {
@@ -33124,7 +33335,7 @@ async function configurePlugin(name, instanceRoot) {
33124
33335
  }
33125
33336
  async function installPlugin(input2, instanceRoot, json = false) {
33126
33337
  if (json) await muteForJson();
33127
- const path71 = await import("path");
33338
+ const path72 = await import("path");
33128
33339
  const { execFileSync: execFileSync9 } = await import("child_process");
33129
33340
  const { getCurrentVersion: getCurrentVersion2 } = await Promise.resolve().then(() => (init_version(), version_exports));
33130
33341
  const { SettingsManager: SettingsManager2 } = await Promise.resolve().then(() => (init_settings_manager(), settings_manager_exports));
@@ -33175,9 +33386,9 @@ async function installPlugin(input2, instanceRoot, json = false) {
33175
33386
  if (!json) console.log(`Installing ${installSpec}...`);
33176
33387
  const { corePlugins: corePlugins2 } = await Promise.resolve().then(() => (init_core_plugins(), core_plugins_exports));
33177
33388
  const builtinPlugin = corePlugins2.find((p2) => p2.name === pkgName);
33178
- const basePath = path71.join(root, "plugins", "data");
33389
+ const basePath = path72.join(root, "plugins", "data");
33179
33390
  const settingsManager = new SettingsManager2(basePath);
33180
- const registryPath = path71.join(root, "plugins.json");
33391
+ const registryPath = path72.join(root, "plugins.json");
33181
33392
  const pluginRegistry = new PluginRegistry2(registryPath);
33182
33393
  await pluginRegistry.load();
33183
33394
  if (builtinPlugin) {
@@ -33197,8 +33408,8 @@ async function installPlugin(input2, instanceRoot, json = false) {
33197
33408
  console.log(`\u2713 ${builtinPlugin.name} installed! Restart to activate.`);
33198
33409
  return;
33199
33410
  }
33200
- const pluginsDir = path71.join(root, "plugins");
33201
- const nodeModulesDir = path71.join(pluginsDir, "node_modules");
33411
+ const pluginsDir = path72.join(root, "plugins");
33412
+ const nodeModulesDir = path72.join(pluginsDir, "node_modules");
33202
33413
  try {
33203
33414
  execFileSync9("npm", ["install", installSpec, "--prefix", pluginsDir, "--save"], {
33204
33415
  stdio: json ? "pipe" : "inherit",
@@ -33212,8 +33423,8 @@ async function installPlugin(input2, instanceRoot, json = false) {
33212
33423
  const cliVersion = getCurrentVersion2();
33213
33424
  const isLocalPath = pkgName.startsWith("/") || pkgName.startsWith(".");
33214
33425
  try {
33215
- const pluginRoot = isLocalPath ? path71.resolve(pkgName) : path71.join(nodeModulesDir, pkgName);
33216
- const installedPkgPath = path71.join(pluginRoot, "package.json");
33426
+ const pluginRoot = isLocalPath ? path72.resolve(pkgName) : path72.join(nodeModulesDir, pkgName);
33427
+ const installedPkgPath = path72.join(pluginRoot, "package.json");
33217
33428
  const { readFileSync: readFileSync18 } = await import("fs");
33218
33429
  const installedPkg = JSON.parse(readFileSync18(installedPkgPath, "utf-8"));
33219
33430
  const minVersion = installedPkg.engines?.openacp?.replace(/[>=^~\s]/g, "");
@@ -33228,7 +33439,7 @@ async function installPlugin(input2, instanceRoot, json = false) {
33228
33439
  }
33229
33440
  }
33230
33441
  }
33231
- const pluginModule = await import(path71.join(pluginRoot, installedPkg.main ?? "dist/index.js"));
33442
+ const pluginModule = await import(path72.join(pluginRoot, installedPkg.main ?? "dist/index.js"));
33232
33443
  const plugin2 = pluginModule.default;
33233
33444
  if (plugin2?.install) {
33234
33445
  const ctx = createInstallContext2({ pluginName: plugin2.name ?? pkgName, settingsManager, basePath });
@@ -33258,11 +33469,11 @@ async function installPlugin(input2, instanceRoot, json = false) {
33258
33469
  }
33259
33470
  async function uninstallPlugin(name, purge, instanceRoot, json = false) {
33260
33471
  if (json) await muteForJson();
33261
- const path71 = await import("path");
33472
+ const path72 = await import("path");
33262
33473
  const fs57 = await import("fs");
33263
33474
  const { PluginRegistry: PluginRegistry2 } = await Promise.resolve().then(() => (init_plugin_registry(), plugin_registry_exports));
33264
33475
  const root = instanceRoot;
33265
- const registryPath = path71.join(root, "plugins.json");
33476
+ const registryPath = path72.join(root, "plugins.json");
33266
33477
  const registry = new PluginRegistry2(registryPath);
33267
33478
  await registry.load();
33268
33479
  const entry = registry.get(name);
@@ -33282,7 +33493,7 @@ async function uninstallPlugin(name, purge, instanceRoot, json = false) {
33282
33493
  if (plugin2?.uninstall) {
33283
33494
  const { SettingsManager: SettingsManager2 } = await Promise.resolve().then(() => (init_settings_manager(), settings_manager_exports));
33284
33495
  const { createInstallContext: createInstallContext2 } = await Promise.resolve().then(() => (init_install_context(), install_context_exports));
33285
- const basePath = path71.join(root, "plugins", "data");
33496
+ const basePath = path72.join(root, "plugins", "data");
33286
33497
  const settingsManager = new SettingsManager2(basePath);
33287
33498
  const ctx = createInstallContext2({ pluginName: name, settingsManager, basePath });
33288
33499
  await plugin2.uninstall(ctx, { purge });
@@ -33290,7 +33501,7 @@ async function uninstallPlugin(name, purge, instanceRoot, json = false) {
33290
33501
  } catch {
33291
33502
  }
33292
33503
  if (purge) {
33293
- const pluginDir = path71.join(root, "plugins", name);
33504
+ const pluginDir = path72.join(root, "plugins", name);
33294
33505
  fs57.rmSync(pluginDir, { recursive: true, force: true });
33295
33506
  }
33296
33507
  registry.remove(name);
@@ -33331,12 +33542,12 @@ init_helpers();
33331
33542
  init_output();
33332
33543
  import { execSync as execSync2 } from "child_process";
33333
33544
  import * as fs32 from "fs";
33334
- import * as path35 from "path";
33545
+ import * as path36 from "path";
33335
33546
  async function cmdUninstall(args2, instanceRoot) {
33336
33547
  const json = isJsonMode(args2);
33337
33548
  if (json) await muteForJson();
33338
33549
  const root = instanceRoot;
33339
- const pluginsDir = path35.join(root, "plugins");
33550
+ const pluginsDir = path36.join(root, "plugins");
33340
33551
  if (!json && wantsHelp(args2)) {
33341
33552
  console.log(`
33342
33553
  \x1B[1mopenacp uninstall\x1B[0m \u2014 Remove a plugin adapter
@@ -33363,7 +33574,7 @@ async function cmdUninstall(args2, instanceRoot) {
33363
33574
  process.exit(1);
33364
33575
  }
33365
33576
  fs32.mkdirSync(pluginsDir, { recursive: true });
33366
- const pkgPath = path35.join(pluginsDir, "package.json");
33577
+ const pkgPath = path36.join(pluginsDir, "package.json");
33367
33578
  if (!fs32.existsSync(pkgPath)) {
33368
33579
  fs32.writeFileSync(pkgPath, JSON.stringify({ name: "openacp-plugins", private: true, dependencies: {} }, null, 2));
33369
33580
  }
@@ -34209,7 +34420,7 @@ init_helpers();
34209
34420
  init_output();
34210
34421
  init_instance_hint();
34211
34422
  init_resolve_instance_id();
34212
- import path41 from "path";
34423
+ import path42 from "path";
34213
34424
  async function cmdStart(args2 = [], instanceRoot) {
34214
34425
  const json = isJsonMode(args2);
34215
34426
  if (json) await muteForJson();
@@ -34239,7 +34450,7 @@ Requires an existing config \u2014 run 'openacp' first to set up.
34239
34450
  await checkAndPromptUpdate();
34240
34451
  const { startDaemon: startDaemon2, getPidPath: getPidPath2, isProcessRunning: isProcessRunning2 } = await Promise.resolve().then(() => (init_daemon2(), daemon_exports));
34241
34452
  const { ConfigManager: ConfigManager2 } = await Promise.resolve().then(() => (init_config2(), config_exports));
34242
- const cm = new ConfigManager2(path41.join(root, "config.json"));
34453
+ const cm = new ConfigManager2(path42.join(root, "config.json"));
34243
34454
  if (await cm.exists()) {
34244
34455
  await cm.load();
34245
34456
  const config = cm.get();
@@ -34265,12 +34476,12 @@ Requires an existing config \u2014 run 'openacp' first to set up.
34265
34476
  }
34266
34477
  if (json) {
34267
34478
  const { waitForPortFile: waitForPortFile2 } = await Promise.resolve().then(() => (init_api_client(), api_client_exports));
34268
- const port = await waitForPortFile2(path41.join(root, "api.port")) ?? 21420;
34479
+ const port = await waitForPortFile2(path42.join(root, "api.port")) ?? 21420;
34269
34480
  jsonSuccess({
34270
34481
  pid: result.pid,
34271
34482
  instanceId,
34272
34483
  name: config.instanceName ?? null,
34273
- directory: path41.dirname(root),
34484
+ directory: path42.dirname(root),
34274
34485
  dir: root,
34275
34486
  port
34276
34487
  });
@@ -34440,7 +34651,7 @@ start fresh with the setup wizard. The daemon must be stopped first.
34440
34651
  `);
34441
34652
  return;
34442
34653
  }
34443
- const path71 = await import("path");
34654
+ const path72 = await import("path");
34444
34655
  const root = instanceRoot;
34445
34656
  const { getStatus: getStatus2, getPidPath: getPidPath2 } = await Promise.resolve().then(() => (init_daemon2(), daemon_exports));
34446
34657
  const status = getStatus2(getPidPath2(root));
@@ -34602,14 +34813,14 @@ as a messaging thread. Requires a running daemon.
34602
34813
  // src/cli/commands/instances.ts
34603
34814
  init_instance_registry();
34604
34815
  init_instance_context();
34605
- import path60 from "path";
34816
+ import path61 from "path";
34606
34817
  import os13 from "os";
34607
34818
  import fs52 from "fs";
34608
34819
  import { randomUUID as randomUUID6 } from "crypto";
34609
34820
 
34610
34821
  // src/core/instance/instance-init.ts
34611
34822
  import fs51 from "fs";
34612
- import path59 from "path";
34823
+ import path60 from "path";
34613
34824
  function initInstanceFiles(instanceRoot, opts = {}) {
34614
34825
  fs51.mkdirSync(instanceRoot, { recursive: true });
34615
34826
  writeConfig(instanceRoot, opts);
@@ -34619,7 +34830,7 @@ function initInstanceFiles(instanceRoot, opts = {}) {
34619
34830
  writePluginsIfMissing(instanceRoot);
34620
34831
  }
34621
34832
  function writeConfig(instanceRoot, opts) {
34622
- const configPath = path59.join(instanceRoot, "config.json");
34833
+ const configPath = path60.join(instanceRoot, "config.json");
34623
34834
  let existing = {};
34624
34835
  if (opts.mergeExisting && fs51.existsSync(configPath)) {
34625
34836
  try {
@@ -34649,7 +34860,7 @@ function writeConfig(instanceRoot, opts) {
34649
34860
  fs51.writeFileSync(configPath, JSON.stringify(config, null, 2));
34650
34861
  }
34651
34862
  function writeAgentsIfMissing(instanceRoot, agents) {
34652
- const agentsPath = path59.join(instanceRoot, "agents.json");
34863
+ const agentsPath = path60.join(instanceRoot, "agents.json");
34653
34864
  if (fs51.existsSync(agentsPath)) return;
34654
34865
  const installed = {};
34655
34866
  for (const agentName of agents) {
@@ -34668,7 +34879,7 @@ function writeAgentsIfMissing(instanceRoot, agents) {
34668
34879
  fs51.writeFileSync(agentsPath, JSON.stringify({ version: 1, installed }, null, 2));
34669
34880
  }
34670
34881
  function writePluginsIfMissing(instanceRoot) {
34671
- const pluginsPath = path59.join(instanceRoot, "plugins.json");
34882
+ const pluginsPath = path60.join(instanceRoot, "plugins.json");
34672
34883
  if (!fs51.existsSync(pluginsPath)) {
34673
34884
  fs51.writeFileSync(pluginsPath, JSON.stringify({ version: 1, installed: {} }, null, 2));
34674
34885
  }
@@ -34679,7 +34890,7 @@ init_status();
34679
34890
  init_output();
34680
34891
  init_helpers();
34681
34892
  async function buildInstanceListEntries() {
34682
- const registryPath = path60.join(getGlobalRoot(), "instances.json");
34893
+ const registryPath = path61.join(getGlobalRoot(), "instances.json");
34683
34894
  const registry = new InstanceRegistry(registryPath);
34684
34895
  registry.load();
34685
34896
  const entries = registry.list();
@@ -34689,7 +34900,7 @@ async function buildInstanceListEntries() {
34689
34900
  return {
34690
34901
  id: entry.id,
34691
34902
  name: info.name,
34692
- directory: path60.dirname(entry.root),
34903
+ directory: path61.dirname(entry.root),
34693
34904
  root: entry.root,
34694
34905
  status,
34695
34906
  port: info.apiPort
@@ -34782,9 +34993,9 @@ async function cmdInstancesCreate(args2) {
34782
34993
  const agentIdx = args2.indexOf("--agent");
34783
34994
  const agent = agentIdx !== -1 ? args2[agentIdx + 1] : void 0;
34784
34995
  const noInteractive = args2.includes("--no-interactive");
34785
- const resolvedDir = path60.resolve(rawDir.replace(/^~/, os13.homedir()));
34786
- const instanceRoot = path60.join(resolvedDir, ".openacp");
34787
- const registryPath = path60.join(getGlobalRoot(), "instances.json");
34996
+ const resolvedDir = path61.resolve(rawDir.replace(/^~/, os13.homedir()));
34997
+ const instanceRoot = path61.join(resolvedDir, ".openacp");
34998
+ const registryPath = path61.join(getGlobalRoot(), "instances.json");
34788
34999
  const registry = new InstanceRegistry(registryPath);
34789
35000
  registry.load();
34790
35001
  if (fs52.existsSync(instanceRoot)) {
@@ -34809,8 +35020,8 @@ async function cmdInstancesCreate(args2) {
34809
35020
  const name = instanceName ?? `openacp-${registry.list().length + 1}`;
34810
35021
  const id = randomUUID6();
34811
35022
  if (rawFrom) {
34812
- const fromRoot = path60.join(path60.resolve(rawFrom.replace(/^~/, os13.homedir())), ".openacp");
34813
- if (!fs52.existsSync(path60.join(fromRoot, "config.json"))) {
35023
+ const fromRoot = path61.join(path61.resolve(rawFrom.replace(/^~/, os13.homedir())), ".openacp");
35024
+ if (!fs52.existsSync(path61.join(fromRoot, "config.json"))) {
34814
35025
  console.error(`Error: No OpenACP instance found at ${rawFrom}`);
34815
35026
  process.exit(1);
34816
35027
  }
@@ -34834,7 +35045,7 @@ async function outputInstance(json, { id, root }) {
34834
35045
  const entry = {
34835
35046
  id,
34836
35047
  name: info.name,
34837
- directory: path60.dirname(root),
35048
+ directory: path61.dirname(root),
34838
35049
  root,
34839
35050
  status: info.pid ? "running" : "stopped",
34840
35051
  port: info.apiPort
@@ -34843,7 +35054,7 @@ async function outputInstance(json, { id, root }) {
34843
35054
  jsonSuccess(entry);
34844
35055
  return;
34845
35056
  }
34846
- console.log(`Instance created: ${info.name ?? id} at ${path60.dirname(root)}`);
35057
+ console.log(`Instance created: ${info.name ?? id} at ${path61.dirname(root)}`);
34847
35058
  }
34848
35059
 
34849
35060
  // src/cli/commands/integrate.ts
@@ -35604,15 +35815,15 @@ Options:
35604
35815
  }
35605
35816
 
35606
35817
  // src/cli/commands/onboard.ts
35607
- import * as path61 from "path";
35818
+ import * as path62 from "path";
35608
35819
  async function cmdOnboard(instanceRoot) {
35609
35820
  const { ConfigManager: ConfigManager2 } = await Promise.resolve().then(() => (init_config2(), config_exports));
35610
35821
  const { SettingsManager: SettingsManager2 } = await Promise.resolve().then(() => (init_settings_manager(), settings_manager_exports));
35611
35822
  const { PluginRegistry: PluginRegistry2 } = await Promise.resolve().then(() => (init_plugin_registry(), plugin_registry_exports));
35612
35823
  const OPENACP_DIR = instanceRoot;
35613
- const PLUGINS_DATA_DIR = path61.join(OPENACP_DIR, "plugins", "data");
35614
- const REGISTRY_PATH = path61.join(OPENACP_DIR, "plugins.json");
35615
- const cm = new ConfigManager2(path61.join(OPENACP_DIR, "config.json"));
35824
+ const PLUGINS_DATA_DIR = path62.join(OPENACP_DIR, "plugins", "data");
35825
+ const REGISTRY_PATH = path62.join(OPENACP_DIR, "plugins.json");
35826
+ const cm = new ConfigManager2(path62.join(OPENACP_DIR, "config.json"));
35616
35827
  const settingsManager = new SettingsManager2(PLUGINS_DATA_DIR);
35617
35828
  const pluginRegistry = new PluginRegistry2(REGISTRY_PATH);
35618
35829
  await pluginRegistry.load();
@@ -35632,15 +35843,15 @@ init_instance_registry();
35632
35843
  init_instance_hint();
35633
35844
  init_output();
35634
35845
  init_resolve_instance_id();
35635
- import path62 from "path";
35846
+ import path63 from "path";
35636
35847
  import { randomUUID as randomUUID7 } from "crypto";
35637
35848
  async function cmdDefault(command2, instanceRoot) {
35638
35849
  const args2 = command2 ? [command2] : [];
35639
35850
  const json = isJsonMode(args2);
35640
35851
  if (json) await muteForJson();
35641
35852
  const root = instanceRoot;
35642
- const pluginsDataDir = path62.join(root, "plugins", "data");
35643
- const registryPath = path62.join(root, "plugins.json");
35853
+ const pluginsDataDir = path63.join(root, "plugins", "data");
35854
+ const registryPath = path63.join(root, "plugins.json");
35644
35855
  const forceForeground = command2 === "--foreground";
35645
35856
  if (command2 && !command2.startsWith("-")) {
35646
35857
  const { suggestMatch: suggestMatch2 } = await Promise.resolve().then(() => (init_suggest(), suggest_exports));
@@ -35672,7 +35883,7 @@ async function cmdDefault(command2, instanceRoot) {
35672
35883
  }
35673
35884
  await checkAndPromptUpdate();
35674
35885
  const { ConfigManager: ConfigManager2 } = await Promise.resolve().then(() => (init_config2(), config_exports));
35675
- const configPath = path62.join(root, "config.json");
35886
+ const configPath = path63.join(root, "config.json");
35676
35887
  const cm = new ConfigManager2(configPath);
35677
35888
  if (!await cm.exists()) {
35678
35889
  const { SettingsManager: SettingsManager2 } = await Promise.resolve().then(() => (init_settings_manager(), settings_manager_exports));
@@ -35709,12 +35920,12 @@ async function cmdDefault(command2, instanceRoot) {
35709
35920
  }
35710
35921
  if (json) {
35711
35922
  const { waitForPortFile: waitForPortFile2 } = await Promise.resolve().then(() => (init_api_client(), api_client_exports));
35712
- const port = await waitForPortFile2(path62.join(root, "api.port")) ?? 21420;
35923
+ const port = await waitForPortFile2(path63.join(root, "api.port")) ?? 21420;
35713
35924
  jsonSuccess({
35714
35925
  pid: result.pid,
35715
35926
  instanceId: instanceId2,
35716
35927
  name: config.instanceName ?? null,
35717
- directory: path62.dirname(root),
35928
+ directory: path63.dirname(root),
35718
35929
  dir: root,
35719
35930
  port
35720
35931
  });
@@ -35727,7 +35938,7 @@ async function cmdDefault(command2, instanceRoot) {
35727
35938
  markRunning2(root);
35728
35939
  printInstanceHint(root);
35729
35940
  const { startServer: startServer2 } = await Promise.resolve().then(() => (init_main(), main_exports));
35730
- const reg = new InstanceRegistry(path62.join(getGlobalRoot(), "instances.json"));
35941
+ const reg = new InstanceRegistry(path63.join(getGlobalRoot(), "instances.json"));
35731
35942
  reg.load();
35732
35943
  const existingEntry = reg.getByRoot(root);
35733
35944
  const instanceId = existingEntry?.id ?? randomUUID7();
@@ -35741,7 +35952,7 @@ async function cmdDefault(command2, instanceRoot) {
35741
35952
  pid: process.pid,
35742
35953
  instanceId,
35743
35954
  name: config.instanceName ?? null,
35744
- directory: path62.dirname(root),
35955
+ directory: path63.dirname(root),
35745
35956
  dir: root,
35746
35957
  port
35747
35958
  });
@@ -35810,7 +36021,7 @@ async function showAlreadyRunningMenu(root) {
35810
36021
  // src/cli/commands/dev.ts
35811
36022
  init_helpers();
35812
36023
  import fs53 from "fs";
35813
- import path63 from "path";
36024
+ import path64 from "path";
35814
36025
  async function cmdDev(args2 = []) {
35815
36026
  if (wantsHelp(args2)) {
35816
36027
  console.log(`
@@ -35837,12 +36048,12 @@ async function cmdDev(args2 = []) {
35837
36048
  console.error("Error: missing plugin path. Usage: openacp dev <plugin-path>");
35838
36049
  process.exit(1);
35839
36050
  }
35840
- const pluginPath = path63.resolve(pluginPathArg);
36051
+ const pluginPath = path64.resolve(pluginPathArg);
35841
36052
  if (!fs53.existsSync(pluginPath)) {
35842
36053
  console.error(`Error: plugin path does not exist: ${pluginPath}`);
35843
36054
  process.exit(1);
35844
36055
  }
35845
- const tsconfigPath = path63.join(pluginPath, "tsconfig.json");
36056
+ const tsconfigPath = path64.join(pluginPath, "tsconfig.json");
35846
36057
  const hasTsconfig = fs53.existsSync(tsconfigPath);
35847
36058
  if (hasTsconfig) {
35848
36059
  console.log("Compiling plugin TypeScript...");
@@ -35884,7 +36095,7 @@ async function cmdDev(args2 = []) {
35884
36095
 
35885
36096
  // src/cli/commands/attach.ts
35886
36097
  init_helpers();
35887
- import path64 from "path";
36098
+ import path65 from "path";
35888
36099
  async function cmdAttach(args2 = [], instanceRoot) {
35889
36100
  const root = instanceRoot;
35890
36101
  if (wantsHelp(args2)) {
@@ -35920,15 +36131,15 @@ Press Ctrl+C to detach.
35920
36131
  console.log("");
35921
36132
  const { spawn: spawn9 } = await import("child_process");
35922
36133
  const { expandHome: expandHome4 } = await Promise.resolve().then(() => (init_config2(), config_exports));
35923
- let logDir2 = path64.join(root, "logs");
36134
+ let logDir2 = path65.join(root, "logs");
35924
36135
  try {
35925
- const configPath = path64.join(root, "config.json");
36136
+ const configPath = path65.join(root, "config.json");
35926
36137
  const { readFileSync: readFileSync18 } = await import("fs");
35927
36138
  const config = JSON.parse(readFileSync18(configPath, "utf-8"));
35928
36139
  if (config.logging?.logDir) logDir2 = expandHome4(config.logging.logDir);
35929
36140
  } catch {
35930
36141
  }
35931
- const logFile = path64.join(logDir2, "openacp.log");
36142
+ const logFile = path65.join(logDir2, "openacp.log");
35932
36143
  const tail = spawn9("tail", ["-f", "-n", "50", logFile], { stdio: "inherit" });
35933
36144
  tail.on("error", (err) => {
35934
36145
  console.error(`Cannot tail log file: ${err.message}`);
@@ -35940,7 +36151,7 @@ Press Ctrl+C to detach.
35940
36151
  init_api_client();
35941
36152
  init_instance_registry();
35942
36153
  init_output();
35943
- import path65 from "path";
36154
+ import path66 from "path";
35944
36155
  import os14 from "os";
35945
36156
  import qrcode from "qrcode-terminal";
35946
36157
  async function cmdRemote(args2, instanceRoot) {
@@ -35956,7 +36167,7 @@ async function cmdRemote(args2, instanceRoot) {
35956
36167
  const scopes = scopesRaw ? scopesRaw.split(",").map((s) => s.trim()) : void 0;
35957
36168
  let resolvedInstanceRoot2 = instanceRoot;
35958
36169
  if (instanceId) {
35959
- const registryPath = path65.join(os14.homedir(), ".openacp", "instances.json");
36170
+ const registryPath = path66.join(os14.homedir(), ".openacp", "instances.json");
35960
36171
  const registry = new InstanceRegistry(registryPath);
35961
36172
  await registry.load();
35962
36173
  const entry = registry.get(instanceId);
@@ -36095,7 +36306,7 @@ function extractFlag(args2, flag) {
36095
36306
  init_output();
36096
36307
  init_instance_context();
36097
36308
  init_instance_registry();
36098
- import * as path66 from "path";
36309
+ import * as path67 from "path";
36099
36310
  import fs54 from "fs";
36100
36311
  function parseFlag(args2, flag) {
36101
36312
  const idx = args2.indexOf(flag);
@@ -36103,7 +36314,7 @@ function parseFlag(args2, flag) {
36103
36314
  }
36104
36315
  function readConfigField(instanceRoot, field) {
36105
36316
  try {
36106
- const raw = JSON.parse(fs54.readFileSync(path66.join(instanceRoot, "config.json"), "utf-8"));
36317
+ const raw = JSON.parse(fs54.readFileSync(path67.join(instanceRoot, "config.json"), "utf-8"));
36107
36318
  return typeof raw[field] === "string" ? raw[field] : null;
36108
36319
  } catch {
36109
36320
  return null;
@@ -36126,7 +36337,7 @@ async function cmdSetup(args2, instanceRoot) {
36126
36337
  }
36127
36338
  const runMode = rawRunMode;
36128
36339
  const agents = agentRaw.split(",").map((a) => a.trim());
36129
- const registryPath = path66.join(getGlobalRoot(), "instances.json");
36340
+ const registryPath = path67.join(getGlobalRoot(), "instances.json");
36130
36341
  const registry = new InstanceRegistry(registryPath);
36131
36342
  registry.load();
36132
36343
  const { id, registryUpdated } = registry.resolveId(instanceRoot);
@@ -36134,9 +36345,9 @@ async function cmdSetup(args2, instanceRoot) {
36134
36345
  if (registryUpdated) {
36135
36346
  registry.save();
36136
36347
  }
36137
- const name = readConfigField(instanceRoot, "instanceName") ?? path66.basename(path66.dirname(instanceRoot));
36348
+ const name = readConfigField(instanceRoot, "instanceName") ?? path67.basename(path67.dirname(instanceRoot));
36138
36349
  if (!readConfigField(instanceRoot, "instanceName")) {
36139
- const configPath = path66.join(instanceRoot, "config.json");
36350
+ const configPath = path67.join(instanceRoot, "config.json");
36140
36351
  try {
36141
36352
  const raw = JSON.parse(fs54.readFileSync(configPath, "utf-8"));
36142
36353
  raw.instanceName = name;
@@ -36145,17 +36356,17 @@ async function cmdSetup(args2, instanceRoot) {
36145
36356
  }
36146
36357
  }
36147
36358
  if (json) {
36148
- jsonSuccess({ id, name, directory: path66.dirname(instanceRoot), configPath: path66.join(instanceRoot, "config.json") });
36359
+ jsonSuccess({ id, name, directory: path67.dirname(instanceRoot), configPath: path67.join(instanceRoot, "config.json") });
36149
36360
  } else {
36150
36361
  console.log(`
36151
- \x1B[32m\u2713 Setup complete.\x1B[0m Config written to ${path66.join(instanceRoot, "config.json")}
36362
+ \x1B[32m\u2713 Setup complete.\x1B[0m Config written to ${path67.join(instanceRoot, "config.json")}
36152
36363
  `);
36153
36364
  }
36154
36365
  }
36155
36366
 
36156
36367
  // src/cli/commands/autostart.ts
36157
36368
  init_helpers();
36158
- import path67 from "path";
36369
+ import path68 from "path";
36159
36370
  async function cmdAutostart(args2 = [], instanceRoot) {
36160
36371
  const subcommand = args2[0];
36161
36372
  if (!subcommand || wantsHelp(args2)) {
@@ -36193,7 +36404,7 @@ async function cmdAutostart(args2 = [], instanceRoot) {
36193
36404
  let logDir2 = `${root}/logs`;
36194
36405
  try {
36195
36406
  const { ConfigManager: ConfigManager2 } = await Promise.resolve().then(() => (init_config2(), config_exports));
36196
- const cm = new ConfigManager2(path67.join(root, "config.json"));
36407
+ const cm = new ConfigManager2(path68.join(root, "config.json"));
36197
36408
  if (await cm.exists()) {
36198
36409
  await cm.load();
36199
36410
  logDir2 = cm.get().logging?.logDir ?? logDir2;
@@ -36381,7 +36592,7 @@ async function main() {
36381
36592
  if (envRoot) {
36382
36593
  const { createInstanceContext: createInstanceContext2, getGlobalRoot: getGlobal } = await Promise.resolve().then(() => (init_instance_context(), instance_context_exports));
36383
36594
  const { InstanceRegistry: InstanceRegistry2 } = await Promise.resolve().then(() => (init_instance_registry(), instance_registry_exports));
36384
- const registry = new InstanceRegistry2(path70.join(getGlobal(), "instances.json"));
36595
+ const registry = new InstanceRegistry2(path71.join(getGlobal(), "instances.json"));
36385
36596
  await registry.load();
36386
36597
  const entry = registry.getByRoot(envRoot);
36387
36598
  const { randomUUID: randomUUID9 } = await import("crypto");