@phenx-inc/ctlsurf 0.5.2 → 0.6.0
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/electron-vite.config.ts +5 -0
- package/out/headless/index.mjs +2 -1
- package/out/headless/index.mjs.map +2 -2
- package/out/main/index.js +3 -0
- package/out/renderer/assets/{cssMode-D9-xaWSI.js → cssMode-DbMmcl1h.js} +3 -3
- package/out/renderer/assets/{freemarker2-CoRAVxnv.js → freemarker2-CvaHiy92.js} +1 -1
- package/out/renderer/assets/{handlebars-B0p9Wgkw.js → handlebars-D58lUIOu.js} +1 -1
- package/out/renderer/assets/{html-D_XFJJtO.js → html-D1h1aJbM.js} +1 -1
- package/out/renderer/assets/{htmlMode-naWw6PWr.js → htmlMode-BdkAp9qr.js} +3 -3
- package/out/renderer/assets/{index-DBt_rov1.js → index-B60JU1yI.js} +419 -107
- package/out/renderer/assets/{index-ezC-iarf.css → index-DJFYmHjz.css} +89 -0
- package/out/renderer/assets/{javascript-DDLsFUr-.js → javascript-CXqZcnvb.js} +2 -2
- package/out/renderer/assets/{jsonMode-Ixhcm5I6.js → jsonMode-BuVr-eSl.js} +3 -3
- package/out/renderer/assets/{liquid-BHgSYEHk.js → liquid-LKu0Wd0B.js} +1 -1
- package/out/renderer/assets/{lspLanguageFeatures-ClbEdD0U.js → lspLanguageFeatures-Cjr_4HGs.js} +1 -1
- package/out/renderer/assets/{mdx-DMngMjHR.js → mdx-Bl84ILla.js} +1 -1
- package/out/renderer/assets/ort-wasm-simd-threaded.asyncify-DMmc6YqF.wasm +0 -0
- package/out/renderer/assets/{python-D_czoeY2.js → python-0sFd9G1k.js} +1 -1
- package/out/renderer/assets/{razor-CLMDGvL7.js → razor-Cqcu1rLJ.js} +1 -1
- package/out/renderer/assets/transformers.web-DtSCnG36.js +33668 -0
- package/out/renderer/assets/{tsMode-EIuSGG42.js → tsMode-CYd3NUkW.js} +1 -1
- package/out/renderer/assets/{typescript-DQkV4kKA.js → typescript-rkc9lhpi.js} +1 -1
- package/out/renderer/assets/{xml-DJ0OOQTu.js → xml-EsHEUps1.js} +1 -1
- package/out/renderer/assets/{yaml-DxX26XLN.js → yaml-B9-nQ_s2.js} +1 -1
- package/out/renderer/index.html +2 -2
- package/package.json +2 -1
- package/src/main/index.ts +7 -0
- package/src/renderer/App.tsx +13 -1
- package/src/renderer/components/TerminalPanel.tsx +6 -0
- package/src/renderer/components/VoiceInput.tsx +313 -0
- package/src/renderer/lib/localWhisper.ts +88 -0
- package/src/renderer/styles.css +89 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./cssMode-
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./cssMode-DbMmcl1h.js","./lspLanguageFeatures-Cjr_4HGs.js","./htmlMode-BdkAp9qr.js","./jsonMode-BuVr-eSl.js","./javascript-CXqZcnvb.js","./typescript-rkc9lhpi.js"])))=>i.map(i=>d[i]);
|
|
2
2
|
function getDefaultExportFromCjs(x) {
|
|
3
3
|
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
|
|
4
4
|
}
|
|
@@ -18940,6 +18940,9 @@ function getOrCreateTerminal(tabId, onExit) {
|
|
|
18940
18940
|
_terminals.set(tabId, state);
|
|
18941
18941
|
return { terminal, fitAddon };
|
|
18942
18942
|
}
|
|
18943
|
+
function focusTerminal(tabId) {
|
|
18944
|
+
_terminals.get(tabId)?.terminal.focus();
|
|
18945
|
+
}
|
|
18943
18946
|
function destroyTerminal(tabId) {
|
|
18944
18947
|
const state = _terminals.get(tabId);
|
|
18945
18948
|
if (!state) return;
|
|
@@ -19073,6 +19076,393 @@ function TerminalPanel({ tabId, agent, onSpawn, onExit, isActive }) {
|
|
|
19073
19076
|
toast && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "term-toast", children: toast })
|
|
19074
19077
|
] });
|
|
19075
19078
|
}
|
|
19079
|
+
const scriptRel = /* @__PURE__ */ (function detectScriptRel() {
|
|
19080
|
+
const relList = typeof document !== "undefined" && document.createElement("link").relList;
|
|
19081
|
+
return relList && relList.supports && relList.supports("modulepreload") ? "modulepreload" : "preload";
|
|
19082
|
+
})();
|
|
19083
|
+
const assetsURL = function(dep, importerUrl) {
|
|
19084
|
+
return new URL(dep, importerUrl).href;
|
|
19085
|
+
};
|
|
19086
|
+
const seen = {};
|
|
19087
|
+
const __vitePreload = function preload(baseModule, deps, importerUrl) {
|
|
19088
|
+
let promise = Promise.resolve();
|
|
19089
|
+
if (deps && deps.length > 0) {
|
|
19090
|
+
let allSettled2 = function(promises) {
|
|
19091
|
+
return Promise.all(
|
|
19092
|
+
promises.map(
|
|
19093
|
+
(p) => Promise.resolve(p).then(
|
|
19094
|
+
(value) => ({ status: "fulfilled", value }),
|
|
19095
|
+
(reason) => ({ status: "rejected", reason })
|
|
19096
|
+
)
|
|
19097
|
+
)
|
|
19098
|
+
);
|
|
19099
|
+
};
|
|
19100
|
+
const links = document.getElementsByTagName("link");
|
|
19101
|
+
const cspNonceMeta = document.querySelector(
|
|
19102
|
+
"meta[property=csp-nonce]"
|
|
19103
|
+
);
|
|
19104
|
+
const cspNonce = cspNonceMeta?.nonce || cspNonceMeta?.getAttribute("nonce");
|
|
19105
|
+
promise = allSettled2(
|
|
19106
|
+
deps.map((dep) => {
|
|
19107
|
+
dep = assetsURL(dep, importerUrl);
|
|
19108
|
+
if (dep in seen) return;
|
|
19109
|
+
seen[dep] = true;
|
|
19110
|
+
const isCss = dep.endsWith(".css");
|
|
19111
|
+
const cssSelector = isCss ? '[rel="stylesheet"]' : "";
|
|
19112
|
+
const isBaseRelative = !!importerUrl;
|
|
19113
|
+
if (isBaseRelative) {
|
|
19114
|
+
for (let i2 = links.length - 1; i2 >= 0; i2--) {
|
|
19115
|
+
const link22 = links[i2];
|
|
19116
|
+
if (link22.href === dep && (!isCss || link22.rel === "stylesheet")) {
|
|
19117
|
+
return;
|
|
19118
|
+
}
|
|
19119
|
+
}
|
|
19120
|
+
} else if (document.querySelector(`link[href="${dep}"]${cssSelector}`)) {
|
|
19121
|
+
return;
|
|
19122
|
+
}
|
|
19123
|
+
const link2 = document.createElement("link");
|
|
19124
|
+
link2.rel = isCss ? "stylesheet" : scriptRel;
|
|
19125
|
+
if (!isCss) {
|
|
19126
|
+
link2.as = "script";
|
|
19127
|
+
}
|
|
19128
|
+
link2.crossOrigin = "";
|
|
19129
|
+
link2.href = dep;
|
|
19130
|
+
if (cspNonce) {
|
|
19131
|
+
link2.setAttribute("nonce", cspNonce);
|
|
19132
|
+
}
|
|
19133
|
+
document.head.appendChild(link2);
|
|
19134
|
+
if (isCss) {
|
|
19135
|
+
return new Promise((res, rej) => {
|
|
19136
|
+
link2.addEventListener("load", res);
|
|
19137
|
+
link2.addEventListener(
|
|
19138
|
+
"error",
|
|
19139
|
+
() => rej(new Error(`Unable to preload CSS for ${dep}`))
|
|
19140
|
+
);
|
|
19141
|
+
});
|
|
19142
|
+
}
|
|
19143
|
+
})
|
|
19144
|
+
);
|
|
19145
|
+
}
|
|
19146
|
+
function handlePreloadError(err) {
|
|
19147
|
+
const e = new Event("vite:preloadError", {
|
|
19148
|
+
cancelable: true
|
|
19149
|
+
});
|
|
19150
|
+
e.payload = err;
|
|
19151
|
+
window.dispatchEvent(e);
|
|
19152
|
+
if (!e.defaultPrevented) {
|
|
19153
|
+
throw err;
|
|
19154
|
+
}
|
|
19155
|
+
}
|
|
19156
|
+
return promise.then((res) => {
|
|
19157
|
+
for (const item of res || []) {
|
|
19158
|
+
if (item.status !== "rejected") continue;
|
|
19159
|
+
handlePreloadError(item.reason);
|
|
19160
|
+
}
|
|
19161
|
+
return baseModule().catch(handlePreloadError);
|
|
19162
|
+
});
|
|
19163
|
+
};
|
|
19164
|
+
const MODEL = "Xenova/whisper-base";
|
|
19165
|
+
const TARGET_SAMPLE_RATE = 16e3;
|
|
19166
|
+
let transcriberPromise = null;
|
|
19167
|
+
async function loadTranscriber(onProgress) {
|
|
19168
|
+
if (!transcriberPromise) {
|
|
19169
|
+
transcriberPromise = (async () => {
|
|
19170
|
+
const { pipeline, env: env2 } = await __vitePreload(async () => {
|
|
19171
|
+
const { pipeline: pipeline2, env: env3 } = await import("./transformers.web-DtSCnG36.js");
|
|
19172
|
+
return { pipeline: pipeline2, env: env3 };
|
|
19173
|
+
}, true ? [] : void 0, import.meta.url);
|
|
19174
|
+
env2.allowLocalModels = false;
|
|
19175
|
+
const common = { progress_callback: onProgress };
|
|
19176
|
+
const hasWebGpu = typeof navigator !== "undefined" && "gpu" in navigator;
|
|
19177
|
+
if (hasWebGpu) {
|
|
19178
|
+
try {
|
|
19179
|
+
return await pipeline("automatic-speech-recognition", MODEL, { ...common, device: "webgpu" });
|
|
19180
|
+
} catch (err) {
|
|
19181
|
+
console.warn("[voice] WebGPU backend failed, falling back to WASM", err);
|
|
19182
|
+
}
|
|
19183
|
+
}
|
|
19184
|
+
return await pipeline("automatic-speech-recognition", MODEL, common);
|
|
19185
|
+
})();
|
|
19186
|
+
transcriberPromise.catch(() => {
|
|
19187
|
+
transcriberPromise = null;
|
|
19188
|
+
});
|
|
19189
|
+
}
|
|
19190
|
+
return transcriberPromise;
|
|
19191
|
+
}
|
|
19192
|
+
async function blobToPcm16k(blob) {
|
|
19193
|
+
if (blob.size === 0) return null;
|
|
19194
|
+
const arrayBuffer = await blob.arrayBuffer();
|
|
19195
|
+
const AudioCtx = window.AudioContext || window.webkitAudioContext;
|
|
19196
|
+
const ctx = new AudioCtx();
|
|
19197
|
+
let decoded;
|
|
19198
|
+
try {
|
|
19199
|
+
decoded = await ctx.decodeAudioData(arrayBuffer);
|
|
19200
|
+
} catch {
|
|
19201
|
+
return null;
|
|
19202
|
+
} finally {
|
|
19203
|
+
ctx.close();
|
|
19204
|
+
}
|
|
19205
|
+
const length = Math.ceil(decoded.duration * TARGET_SAMPLE_RATE);
|
|
19206
|
+
if (length < 1) return null;
|
|
19207
|
+
const offline = new OfflineAudioContext(1, length, TARGET_SAMPLE_RATE);
|
|
19208
|
+
const source = offline.createBufferSource();
|
|
19209
|
+
source.buffer = decoded;
|
|
19210
|
+
source.connect(offline.destination);
|
|
19211
|
+
source.start();
|
|
19212
|
+
const rendered = await offline.startRendering();
|
|
19213
|
+
return rendered.getChannelData(0);
|
|
19214
|
+
}
|
|
19215
|
+
async function transcribeBlob(blob, onProgress) {
|
|
19216
|
+
const transcriber = await loadTranscriber(onProgress);
|
|
19217
|
+
const pcm = await blobToPcm16k(blob);
|
|
19218
|
+
if (!pcm) return "";
|
|
19219
|
+
const result = await transcriber(pcm);
|
|
19220
|
+
const text2 = Array.isArray(result) ? result.map((r) => r.text).join(" ") : result?.text;
|
|
19221
|
+
return (text2 || "").trim();
|
|
19222
|
+
}
|
|
19223
|
+
function getRecognitionCtor() {
|
|
19224
|
+
const w = window;
|
|
19225
|
+
return w.SpeechRecognition || w.webkitSpeechRecognition || null;
|
|
19226
|
+
}
|
|
19227
|
+
const ENGINE_KEY = "ctlsurf.voiceEngine";
|
|
19228
|
+
const WEB_SPEECH_SUPPORTED = getRecognitionCtor() !== null;
|
|
19229
|
+
const LOCAL_SUPPORTED = typeof navigator !== "undefined" && !!navigator.mediaDevices?.getUserMedia && typeof MediaRecorder !== "undefined" && typeof OfflineAudioContext !== "undefined";
|
|
19230
|
+
const ANY_SUPPORTED = WEB_SPEECH_SUPPORTED || LOCAL_SUPPORTED;
|
|
19231
|
+
function loadInitialEngine() {
|
|
19232
|
+
if (!WEB_SPEECH_SUPPORTED && LOCAL_SUPPORTED) return "local";
|
|
19233
|
+
try {
|
|
19234
|
+
if (localStorage.getItem(ENGINE_KEY) === "local" && LOCAL_SUPPORTED) return "local";
|
|
19235
|
+
} catch {
|
|
19236
|
+
}
|
|
19237
|
+
return WEB_SPEECH_SUPPORTED ? "web-speech" : "local";
|
|
19238
|
+
}
|
|
19239
|
+
function isEngineUnavailable(code) {
|
|
19240
|
+
return code === "network" || code === "service-not-allowed";
|
|
19241
|
+
}
|
|
19242
|
+
function describeMicError(err) {
|
|
19243
|
+
const name = err?.name;
|
|
19244
|
+
if (name === "NotAllowedError" || name === "SecurityError") return "Microphone access denied";
|
|
19245
|
+
if (name === "NotFoundError") return "No microphone found";
|
|
19246
|
+
return "Could not start microphone";
|
|
19247
|
+
}
|
|
19248
|
+
function VoiceInput({ onTranscript }) {
|
|
19249
|
+
const [engine, setEngine] = reactExports.useState(loadInitialEngine);
|
|
19250
|
+
const [phase, setPhase] = reactExports.useState("idle");
|
|
19251
|
+
const [interim, setInterim] = reactExports.useState("");
|
|
19252
|
+
const [modelPct, setModelPct] = reactExports.useState(null);
|
|
19253
|
+
const [error, setError] = reactExports.useState(null);
|
|
19254
|
+
const [notice, setNotice] = reactExports.useState(null);
|
|
19255
|
+
const recognitionRef = reactExports.useRef(null);
|
|
19256
|
+
const finalRef = reactExports.useRef("");
|
|
19257
|
+
const streamRef = reactExports.useRef(null);
|
|
19258
|
+
const recorderRef = reactExports.useRef(null);
|
|
19259
|
+
const chunksRef = reactExports.useRef([]);
|
|
19260
|
+
const cancelGestureRef = reactExports.useRef(false);
|
|
19261
|
+
const engineRef = reactExports.useRef(engine);
|
|
19262
|
+
reactExports.useEffect(() => {
|
|
19263
|
+
engineRef.current = engine;
|
|
19264
|
+
}, [engine]);
|
|
19265
|
+
const onTranscriptRef = reactExports.useRef(onTranscript);
|
|
19266
|
+
reactExports.useEffect(() => {
|
|
19267
|
+
onTranscriptRef.current = onTranscript;
|
|
19268
|
+
}, [onTranscript]);
|
|
19269
|
+
reactExports.useEffect(() => {
|
|
19270
|
+
if (!error) return;
|
|
19271
|
+
const t = setTimeout(() => setError(null), 4500);
|
|
19272
|
+
return () => clearTimeout(t);
|
|
19273
|
+
}, [error]);
|
|
19274
|
+
reactExports.useEffect(() => {
|
|
19275
|
+
if (!notice) return;
|
|
19276
|
+
const t = setTimeout(() => setNotice(null), 5e3);
|
|
19277
|
+
return () => clearTimeout(t);
|
|
19278
|
+
}, [notice]);
|
|
19279
|
+
const switchToLocal = reactExports.useCallback((reason) => {
|
|
19280
|
+
try {
|
|
19281
|
+
localStorage.setItem(ENGINE_KEY, "local");
|
|
19282
|
+
} catch {
|
|
19283
|
+
}
|
|
19284
|
+
setEngine("local");
|
|
19285
|
+
setNotice(reason);
|
|
19286
|
+
}, []);
|
|
19287
|
+
const stopStream = reactExports.useCallback(() => {
|
|
19288
|
+
streamRef.current?.getTracks().forEach((t) => t.stop());
|
|
19289
|
+
streamRef.current = null;
|
|
19290
|
+
}, []);
|
|
19291
|
+
const startWebSpeech = reactExports.useCallback(() => {
|
|
19292
|
+
const Ctor = getRecognitionCtor();
|
|
19293
|
+
if (!Ctor || recognitionRef.current) return;
|
|
19294
|
+
setError(null);
|
|
19295
|
+
setNotice(null);
|
|
19296
|
+
setInterim("");
|
|
19297
|
+
finalRef.current = "";
|
|
19298
|
+
const rec = new Ctor();
|
|
19299
|
+
rec.lang = navigator.language || "en-US";
|
|
19300
|
+
rec.continuous = true;
|
|
19301
|
+
rec.interimResults = true;
|
|
19302
|
+
rec.onresult = (event) => {
|
|
19303
|
+
let finalText = "";
|
|
19304
|
+
let interimText = "";
|
|
19305
|
+
for (let i2 = 0; i2 < event.results.length; i2++) {
|
|
19306
|
+
const res = event.results[i2];
|
|
19307
|
+
if (res.isFinal) finalText += res[0].transcript;
|
|
19308
|
+
else interimText += res[0].transcript;
|
|
19309
|
+
}
|
|
19310
|
+
finalRef.current = finalText;
|
|
19311
|
+
setInterim(interimText);
|
|
19312
|
+
};
|
|
19313
|
+
rec.onerror = (event) => {
|
|
19314
|
+
if (isEngineUnavailable(event.error) && LOCAL_SUPPORTED) {
|
|
19315
|
+
finalRef.current = "";
|
|
19316
|
+
switchToLocal("Voice service unavailable — switched to on-device. Press again.");
|
|
19317
|
+
} else if (event.error !== "no-speech" && event.error !== "aborted") {
|
|
19318
|
+
setError(event.error === "not-allowed" ? "Microphone access denied" : `Voice error: ${event.error}`);
|
|
19319
|
+
}
|
|
19320
|
+
};
|
|
19321
|
+
rec.onend = () => {
|
|
19322
|
+
const text2 = finalRef.current.trim();
|
|
19323
|
+
recognitionRef.current = null;
|
|
19324
|
+
setPhase("idle");
|
|
19325
|
+
setInterim("");
|
|
19326
|
+
if (text2) onTranscriptRef.current(text2);
|
|
19327
|
+
};
|
|
19328
|
+
recognitionRef.current = rec;
|
|
19329
|
+
try {
|
|
19330
|
+
rec.start();
|
|
19331
|
+
setPhase("listening");
|
|
19332
|
+
} catch (err) {
|
|
19333
|
+
recognitionRef.current = null;
|
|
19334
|
+
setPhase("idle");
|
|
19335
|
+
setError("Could not start microphone");
|
|
19336
|
+
console.error("[voice] web speech start failed", err);
|
|
19337
|
+
}
|
|
19338
|
+
}, [switchToLocal]);
|
|
19339
|
+
const stopWebSpeech = reactExports.useCallback(() => {
|
|
19340
|
+
try {
|
|
19341
|
+
recognitionRef.current?.stop();
|
|
19342
|
+
} catch {
|
|
19343
|
+
}
|
|
19344
|
+
}, []);
|
|
19345
|
+
const handleModelProgress = reactExports.useCallback((p) => {
|
|
19346
|
+
if (p.status === "progress" && typeof p.progress === "number") {
|
|
19347
|
+
setModelPct(Math.min(100, Math.round(p.progress)));
|
|
19348
|
+
}
|
|
19349
|
+
}, []);
|
|
19350
|
+
const runLocalTranscription = reactExports.useCallback(async (rec) => {
|
|
19351
|
+
stopStream();
|
|
19352
|
+
const blob = new Blob(chunksRef.current, { type: rec.mimeType || "audio/webm" });
|
|
19353
|
+
chunksRef.current = [];
|
|
19354
|
+
recorderRef.current = null;
|
|
19355
|
+
if (blob.size === 0) {
|
|
19356
|
+
setPhase("idle");
|
|
19357
|
+
return;
|
|
19358
|
+
}
|
|
19359
|
+
setPhase("transcribing");
|
|
19360
|
+
setInterim("");
|
|
19361
|
+
try {
|
|
19362
|
+
const text2 = await transcribeBlob(blob, handleModelProgress);
|
|
19363
|
+
if (text2) onTranscriptRef.current(text2);
|
|
19364
|
+
} catch (err) {
|
|
19365
|
+
setError("On-device transcription failed");
|
|
19366
|
+
console.error("[voice] local transcription failed", err);
|
|
19367
|
+
} finally {
|
|
19368
|
+
setPhase("idle");
|
|
19369
|
+
setModelPct(null);
|
|
19370
|
+
}
|
|
19371
|
+
}, [stopStream, handleModelProgress]);
|
|
19372
|
+
const startLocal = reactExports.useCallback(async () => {
|
|
19373
|
+
setError(null);
|
|
19374
|
+
setNotice(null);
|
|
19375
|
+
setInterim("");
|
|
19376
|
+
cancelGestureRef.current = false;
|
|
19377
|
+
try {
|
|
19378
|
+
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
19379
|
+
if (cancelGestureRef.current) {
|
|
19380
|
+
stream.getTracks().forEach((t) => t.stop());
|
|
19381
|
+
setPhase("idle");
|
|
19382
|
+
return;
|
|
19383
|
+
}
|
|
19384
|
+
streamRef.current = stream;
|
|
19385
|
+
chunksRef.current = [];
|
|
19386
|
+
const rec = new MediaRecorder(stream);
|
|
19387
|
+
rec.ondataavailable = (e) => {
|
|
19388
|
+
if (e.data.size) chunksRef.current.push(e.data);
|
|
19389
|
+
};
|
|
19390
|
+
rec.onstop = () => {
|
|
19391
|
+
void runLocalTranscription(rec);
|
|
19392
|
+
};
|
|
19393
|
+
recorderRef.current = rec;
|
|
19394
|
+
rec.start();
|
|
19395
|
+
setPhase("listening");
|
|
19396
|
+
} catch (err) {
|
|
19397
|
+
stopStream();
|
|
19398
|
+
setPhase("idle");
|
|
19399
|
+
setError(describeMicError(err));
|
|
19400
|
+
console.error("[voice] getUserMedia failed", err);
|
|
19401
|
+
}
|
|
19402
|
+
}, [runLocalTranscription, stopStream]);
|
|
19403
|
+
const stopLocal = reactExports.useCallback(() => {
|
|
19404
|
+
cancelGestureRef.current = true;
|
|
19405
|
+
const rec = recorderRef.current;
|
|
19406
|
+
if (rec && rec.state !== "inactive") {
|
|
19407
|
+
try {
|
|
19408
|
+
rec.stop();
|
|
19409
|
+
} catch {
|
|
19410
|
+
}
|
|
19411
|
+
}
|
|
19412
|
+
}, []);
|
|
19413
|
+
const handlePointerDown = (e) => {
|
|
19414
|
+
if (!ANY_SUPPORTED || phase !== "idle") return;
|
|
19415
|
+
e.preventDefault();
|
|
19416
|
+
e.currentTarget.setPointerCapture?.(e.pointerId);
|
|
19417
|
+
if (engineRef.current === "web-speech" && WEB_SPEECH_SUPPORTED) startWebSpeech();
|
|
19418
|
+
else if (LOCAL_SUPPORTED) void startLocal();
|
|
19419
|
+
};
|
|
19420
|
+
const handlePointerUp = (e) => {
|
|
19421
|
+
e.currentTarget.releasePointerCapture?.(e.pointerId);
|
|
19422
|
+
if (engineRef.current === "web-speech") stopWebSpeech();
|
|
19423
|
+
else stopLocal();
|
|
19424
|
+
};
|
|
19425
|
+
reactExports.useEffect(() => () => {
|
|
19426
|
+
try {
|
|
19427
|
+
recognitionRef.current?.abort();
|
|
19428
|
+
} catch {
|
|
19429
|
+
}
|
|
19430
|
+
try {
|
|
19431
|
+
recorderRef.current?.stop();
|
|
19432
|
+
} catch {
|
|
19433
|
+
}
|
|
19434
|
+
streamRef.current?.getTracks().forEach((t) => t.stop());
|
|
19435
|
+
}, []);
|
|
19436
|
+
const listening = phase === "listening";
|
|
19437
|
+
const busy = phase === "transcribing";
|
|
19438
|
+
const title = !ANY_SUPPORTED ? "Voice typing not supported in this build" : listening ? "Listening… release to insert" : busy ? "Transcribing…" : engine === "local" ? "Hold to talk (on-device) — speech is typed into the terminal" : "Hold to talk — speech is typed into the terminal";
|
|
19439
|
+
let chip = null;
|
|
19440
|
+
if (error && phase === "idle") chip = { kind: "error", text: error };
|
|
19441
|
+
else if (notice && phase === "idle") chip = { kind: "notice", text: notice };
|
|
19442
|
+
else if (listening) chip = { kind: "listening", text: interim || (engine === "local" ? "Recording…" : "Listening…") };
|
|
19443
|
+
else if (busy) chip = { kind: "busy", text: modelPct !== null ? `Downloading voice model… ${modelPct}%` : "Transcribing…" };
|
|
19444
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "voice-input-wrap", children: [
|
|
19445
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
19446
|
+
"button",
|
|
19447
|
+
{
|
|
19448
|
+
type: "button",
|
|
19449
|
+
className: `titlebar-btn titlebar-icon-btn voice-btn ${listening ? "listening" : ""} ${busy ? "busy" : ""}`,
|
|
19450
|
+
disabled: !ANY_SUPPORTED,
|
|
19451
|
+
onPointerDown: handlePointerDown,
|
|
19452
|
+
onPointerUp: handlePointerUp,
|
|
19453
|
+
onPointerCancel: handlePointerUp,
|
|
19454
|
+
onContextMenu: (e) => e.preventDefault(),
|
|
19455
|
+
title,
|
|
19456
|
+
"aria-label": "Voice typing (hold to talk)",
|
|
19457
|
+
children: [
|
|
19458
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "voice-icon", "aria-hidden": "true", children: "🎤" }),
|
|
19459
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `voice-dot ${listening ? "on" : busy ? "busy" : "off"}` })
|
|
19460
|
+
]
|
|
19461
|
+
}
|
|
19462
|
+
),
|
|
19463
|
+
chip && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `voice-chip ${chip.kind}`, children: chip.text })
|
|
19464
|
+
] });
|
|
19465
|
+
}
|
|
19076
19466
|
function CtlsurfPanel({ navigate }) {
|
|
19077
19467
|
const webviewRef = reactExports.useRef(null);
|
|
19078
19468
|
const [url, setUrl] = reactExports.useState(null);
|
|
@@ -19725,91 +20115,6 @@ function Ve({ defaultValue: e, defaultLanguage: r, defaultPath: n2, value: t, la
|
|
|
19725
20115
|
var fe = Ve;
|
|
19726
20116
|
var de = reactExports.memo(fe);
|
|
19727
20117
|
var Ft = de;
|
|
19728
|
-
const scriptRel = /* @__PURE__ */ (function detectScriptRel() {
|
|
19729
|
-
const relList = typeof document !== "undefined" && document.createElement("link").relList;
|
|
19730
|
-
return relList && relList.supports && relList.supports("modulepreload") ? "modulepreload" : "preload";
|
|
19731
|
-
})();
|
|
19732
|
-
const assetsURL = function(dep, importerUrl) {
|
|
19733
|
-
return new URL(dep, importerUrl).href;
|
|
19734
|
-
};
|
|
19735
|
-
const seen = {};
|
|
19736
|
-
const __vitePreload = function preload(baseModule, deps, importerUrl) {
|
|
19737
|
-
let promise = Promise.resolve();
|
|
19738
|
-
if (deps && deps.length > 0) {
|
|
19739
|
-
let allSettled2 = function(promises) {
|
|
19740
|
-
return Promise.all(
|
|
19741
|
-
promises.map(
|
|
19742
|
-
(p) => Promise.resolve(p).then(
|
|
19743
|
-
(value) => ({ status: "fulfilled", value }),
|
|
19744
|
-
(reason) => ({ status: "rejected", reason })
|
|
19745
|
-
)
|
|
19746
|
-
)
|
|
19747
|
-
);
|
|
19748
|
-
};
|
|
19749
|
-
const links = document.getElementsByTagName("link");
|
|
19750
|
-
const cspNonceMeta = document.querySelector(
|
|
19751
|
-
"meta[property=csp-nonce]"
|
|
19752
|
-
);
|
|
19753
|
-
const cspNonce = cspNonceMeta?.nonce || cspNonceMeta?.getAttribute("nonce");
|
|
19754
|
-
promise = allSettled2(
|
|
19755
|
-
deps.map((dep) => {
|
|
19756
|
-
dep = assetsURL(dep, importerUrl);
|
|
19757
|
-
if (dep in seen) return;
|
|
19758
|
-
seen[dep] = true;
|
|
19759
|
-
const isCss = dep.endsWith(".css");
|
|
19760
|
-
const cssSelector = isCss ? '[rel="stylesheet"]' : "";
|
|
19761
|
-
const isBaseRelative = !!importerUrl;
|
|
19762
|
-
if (isBaseRelative) {
|
|
19763
|
-
for (let i2 = links.length - 1; i2 >= 0; i2--) {
|
|
19764
|
-
const link22 = links[i2];
|
|
19765
|
-
if (link22.href === dep && (!isCss || link22.rel === "stylesheet")) {
|
|
19766
|
-
return;
|
|
19767
|
-
}
|
|
19768
|
-
}
|
|
19769
|
-
} else if (document.querySelector(`link[href="${dep}"]${cssSelector}`)) {
|
|
19770
|
-
return;
|
|
19771
|
-
}
|
|
19772
|
-
const link2 = document.createElement("link");
|
|
19773
|
-
link2.rel = isCss ? "stylesheet" : scriptRel;
|
|
19774
|
-
if (!isCss) {
|
|
19775
|
-
link2.as = "script";
|
|
19776
|
-
}
|
|
19777
|
-
link2.crossOrigin = "";
|
|
19778
|
-
link2.href = dep;
|
|
19779
|
-
if (cspNonce) {
|
|
19780
|
-
link2.setAttribute("nonce", cspNonce);
|
|
19781
|
-
}
|
|
19782
|
-
document.head.appendChild(link2);
|
|
19783
|
-
if (isCss) {
|
|
19784
|
-
return new Promise((res, rej) => {
|
|
19785
|
-
link2.addEventListener("load", res);
|
|
19786
|
-
link2.addEventListener(
|
|
19787
|
-
"error",
|
|
19788
|
-
() => rej(new Error(`Unable to preload CSS for ${dep}`))
|
|
19789
|
-
);
|
|
19790
|
-
});
|
|
19791
|
-
}
|
|
19792
|
-
})
|
|
19793
|
-
);
|
|
19794
|
-
}
|
|
19795
|
-
function handlePreloadError(err) {
|
|
19796
|
-
const e = new Event("vite:preloadError", {
|
|
19797
|
-
cancelable: true
|
|
19798
|
-
});
|
|
19799
|
-
e.payload = err;
|
|
19800
|
-
window.dispatchEvent(e);
|
|
19801
|
-
if (!e.defaultPrevented) {
|
|
19802
|
-
throw err;
|
|
19803
|
-
}
|
|
19804
|
-
}
|
|
19805
|
-
return promise.then((res) => {
|
|
19806
|
-
for (const item of res || []) {
|
|
19807
|
-
if (item.status !== "rejected") continue;
|
|
19808
|
-
handlePreloadError(item.reason);
|
|
19809
|
-
}
|
|
19810
|
-
return baseModule().catch(handlePreloadError);
|
|
19811
|
-
});
|
|
19812
|
-
};
|
|
19813
20118
|
function getNLSMessages() {
|
|
19814
20119
|
return globalThis._VSCODE_NLS_MESSAGES;
|
|
19815
20120
|
}
|
|
@@ -206752,7 +207057,7 @@ const lessDefaults = new LanguageServiceDefaultsImpl$3(
|
|
|
206752
207057
|
modeConfigurationDefault$2
|
|
206753
207058
|
);
|
|
206754
207059
|
function getMode$3() {
|
|
206755
|
-
return __vitePreload(() => import("./cssMode-
|
|
207060
|
+
return __vitePreload(() => import("./cssMode-DbMmcl1h.js"), true ? __vite__mapDeps([0,1]) : void 0, import.meta.url);
|
|
206756
207061
|
}
|
|
206757
207062
|
languages.onLanguage("less", () => {
|
|
206758
207063
|
getMode$3().then((mode2) => mode2.setupMode(lessDefaults));
|
|
@@ -206857,7 +207162,7 @@ const razorLanguageService = registerHTMLLanguageService(
|
|
|
206857
207162
|
);
|
|
206858
207163
|
const razorDefaults = razorLanguageService.defaults;
|
|
206859
207164
|
function getMode$2() {
|
|
206860
|
-
return __vitePreload(() => import("./htmlMode-
|
|
207165
|
+
return __vitePreload(() => import("./htmlMode-BdkAp9qr.js"), true ? __vite__mapDeps([2,1]) : void 0, import.meta.url);
|
|
206861
207166
|
}
|
|
206862
207167
|
function registerHTMLLanguageService(languageId, options = optionsDefault, modeConfiguration = getConfigurationDefault(languageId)) {
|
|
206863
207168
|
const defaults = new LanguageServiceDefaultsImpl$2(languageId, options, modeConfiguration);
|
|
@@ -206941,7 +207246,7 @@ const jsonDefaults = new LanguageServiceDefaultsImpl$1(
|
|
|
206941
207246
|
);
|
|
206942
207247
|
const getWorker$1 = () => getMode$1().then((mode2) => mode2.getWorker());
|
|
206943
207248
|
function getMode$1() {
|
|
206944
|
-
return __vitePreload(() => import("./jsonMode-
|
|
207249
|
+
return __vitePreload(() => import("./jsonMode-BuVr-eSl.js"), true ? __vite__mapDeps([3,1]) : void 0, import.meta.url);
|
|
206945
207250
|
}
|
|
206946
207251
|
languages.register({
|
|
206947
207252
|
id: "json",
|
|
@@ -207187,7 +207492,7 @@ const getJavaScriptWorker = () => {
|
|
|
207187
207492
|
return getMode().then((mode) => mode.getJavaScriptWorker());
|
|
207188
207493
|
};
|
|
207189
207494
|
function getMode() {
|
|
207190
|
-
return __vitePreload(() => import("./tsMode-
|
|
207495
|
+
return __vitePreload(() => import("./tsMode-CYd3NUkW.js"), true ? [] : void 0, import.meta.url);
|
|
207191
207496
|
}
|
|
207192
207497
|
languages.onLanguage("typescript", () => {
|
|
207193
207498
|
return getMode().then((mode) => mode.setupTypeScript(typescriptDefaults));
|
|
@@ -207382,49 +207687,49 @@ registerLanguage({
|
|
|
207382
207687
|
extensions: [".ftl", ".ftlh", ".ftlx"],
|
|
207383
207688
|
aliases: ["FreeMarker2", "Apache FreeMarker2"],
|
|
207384
207689
|
loader: () => {
|
|
207385
|
-
return __vitePreload(() => import("./freemarker2-
|
|
207690
|
+
return __vitePreload(() => import("./freemarker2-CvaHiy92.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAutoInterpolationDollar);
|
|
207386
207691
|
}
|
|
207387
207692
|
});
|
|
207388
207693
|
registerLanguage({
|
|
207389
207694
|
id: "freemarker2.tag-angle.interpolation-dollar",
|
|
207390
207695
|
aliases: ["FreeMarker2 (Angle/Dollar)", "Apache FreeMarker2 (Angle/Dollar)"],
|
|
207391
207696
|
loader: () => {
|
|
207392
|
-
return __vitePreload(() => import("./freemarker2-
|
|
207697
|
+
return __vitePreload(() => import("./freemarker2-CvaHiy92.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAngleInterpolationDollar);
|
|
207393
207698
|
}
|
|
207394
207699
|
});
|
|
207395
207700
|
registerLanguage({
|
|
207396
207701
|
id: "freemarker2.tag-bracket.interpolation-dollar",
|
|
207397
207702
|
aliases: ["FreeMarker2 (Bracket/Dollar)", "Apache FreeMarker2 (Bracket/Dollar)"],
|
|
207398
207703
|
loader: () => {
|
|
207399
|
-
return __vitePreload(() => import("./freemarker2-
|
|
207704
|
+
return __vitePreload(() => import("./freemarker2-CvaHiy92.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagBracketInterpolationDollar);
|
|
207400
207705
|
}
|
|
207401
207706
|
});
|
|
207402
207707
|
registerLanguage({
|
|
207403
207708
|
id: "freemarker2.tag-angle.interpolation-bracket",
|
|
207404
207709
|
aliases: ["FreeMarker2 (Angle/Bracket)", "Apache FreeMarker2 (Angle/Bracket)"],
|
|
207405
207710
|
loader: () => {
|
|
207406
|
-
return __vitePreload(() => import("./freemarker2-
|
|
207711
|
+
return __vitePreload(() => import("./freemarker2-CvaHiy92.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAngleInterpolationBracket);
|
|
207407
207712
|
}
|
|
207408
207713
|
});
|
|
207409
207714
|
registerLanguage({
|
|
207410
207715
|
id: "freemarker2.tag-bracket.interpolation-bracket",
|
|
207411
207716
|
aliases: ["FreeMarker2 (Bracket/Bracket)", "Apache FreeMarker2 (Bracket/Bracket)"],
|
|
207412
207717
|
loader: () => {
|
|
207413
|
-
return __vitePreload(() => import("./freemarker2-
|
|
207718
|
+
return __vitePreload(() => import("./freemarker2-CvaHiy92.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagBracketInterpolationBracket);
|
|
207414
207719
|
}
|
|
207415
207720
|
});
|
|
207416
207721
|
registerLanguage({
|
|
207417
207722
|
id: "freemarker2.tag-auto.interpolation-dollar",
|
|
207418
207723
|
aliases: ["FreeMarker2 (Auto/Dollar)", "Apache FreeMarker2 (Auto/Dollar)"],
|
|
207419
207724
|
loader: () => {
|
|
207420
|
-
return __vitePreload(() => import("./freemarker2-
|
|
207725
|
+
return __vitePreload(() => import("./freemarker2-CvaHiy92.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAutoInterpolationDollar);
|
|
207421
207726
|
}
|
|
207422
207727
|
});
|
|
207423
207728
|
registerLanguage({
|
|
207424
207729
|
id: "freemarker2.tag-auto.interpolation-bracket",
|
|
207425
207730
|
aliases: ["FreeMarker2 (Auto/Bracket)", "Apache FreeMarker2 (Auto/Bracket)"],
|
|
207426
207731
|
loader: () => {
|
|
207427
|
-
return __vitePreload(() => import("./freemarker2-
|
|
207732
|
+
return __vitePreload(() => import("./freemarker2-CvaHiy92.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAutoInterpolationBracket);
|
|
207428
207733
|
}
|
|
207429
207734
|
});
|
|
207430
207735
|
registerLanguage({
|
|
@@ -207445,7 +207750,7 @@ registerLanguage({
|
|
|
207445
207750
|
extensions: [".handlebars", ".hbs"],
|
|
207446
207751
|
aliases: ["Handlebars", "handlebars", "hbs"],
|
|
207447
207752
|
mimetypes: ["text/x-handlebars-template"],
|
|
207448
|
-
loader: () => __vitePreload(() => import("./handlebars-
|
|
207753
|
+
loader: () => __vitePreload(() => import("./handlebars-D58lUIOu.js"), true ? [] : void 0, import.meta.url)
|
|
207449
207754
|
});
|
|
207450
207755
|
registerLanguage({
|
|
207451
207756
|
id: "hcl",
|
|
@@ -207458,7 +207763,7 @@ registerLanguage({
|
|
|
207458
207763
|
extensions: [".html", ".htm", ".shtml", ".xhtml", ".mdoc", ".jsp", ".asp", ".aspx", ".jshtm"],
|
|
207459
207764
|
aliases: ["HTML", "htm", "html", "xhtml"],
|
|
207460
207765
|
mimetypes: ["text/html", "text/x-jshtm", "text/template", "text/ng-template"],
|
|
207461
|
-
loader: () => __vitePreload(() => import("./html-
|
|
207766
|
+
loader: () => __vitePreload(() => import("./html-D1h1aJbM.js"), true ? [] : void 0, import.meta.url)
|
|
207462
207767
|
});
|
|
207463
207768
|
registerLanguage({
|
|
207464
207769
|
id: "ini",
|
|
@@ -207481,7 +207786,7 @@ registerLanguage({
|
|
|
207481
207786
|
filenames: ["jakefile"],
|
|
207482
207787
|
aliases: ["JavaScript", "javascript", "js"],
|
|
207483
207788
|
mimetypes: ["text/javascript"],
|
|
207484
|
-
loader: () => __vitePreload(() => import("./javascript-
|
|
207789
|
+
loader: () => __vitePreload(() => import("./javascript-CXqZcnvb.js"), true ? __vite__mapDeps([4,5]) : void 0, import.meta.url)
|
|
207485
207790
|
});
|
|
207486
207791
|
registerLanguage({
|
|
207487
207792
|
id: "julia",
|
|
@@ -207520,7 +207825,7 @@ registerLanguage({
|
|
|
207520
207825
|
extensions: [".liquid", ".html.liquid"],
|
|
207521
207826
|
aliases: ["Liquid", "liquid"],
|
|
207522
207827
|
mimetypes: ["application/liquid"],
|
|
207523
|
-
loader: () => __vitePreload(() => import("./liquid-
|
|
207828
|
+
loader: () => __vitePreload(() => import("./liquid-LKu0Wd0B.js"), true ? [] : void 0, import.meta.url)
|
|
207524
207829
|
});
|
|
207525
207830
|
registerLanguage({
|
|
207526
207831
|
id: "m3",
|
|
@@ -207538,7 +207843,7 @@ registerLanguage({
|
|
|
207538
207843
|
id: "mdx",
|
|
207539
207844
|
extensions: [".mdx"],
|
|
207540
207845
|
aliases: ["MDX", "mdx"],
|
|
207541
|
-
loader: () => __vitePreload(() => import("./mdx-
|
|
207846
|
+
loader: () => __vitePreload(() => import("./mdx-Bl84ILla.js"), true ? [] : void 0, import.meta.url)
|
|
207542
207847
|
});
|
|
207543
207848
|
registerLanguage({
|
|
207544
207849
|
id: "mips",
|
|
@@ -207637,7 +207942,7 @@ registerLanguage({
|
|
|
207637
207942
|
extensions: [".py", ".rpy", ".pyw", ".cpy", ".gyp", ".gypi"],
|
|
207638
207943
|
aliases: ["Python", "py"],
|
|
207639
207944
|
firstLine: "^#!/.*\\bpython[0-9.-]*\\b",
|
|
207640
|
-
loader: () => __vitePreload(() => import("./python-
|
|
207945
|
+
loader: () => __vitePreload(() => import("./python-0sFd9G1k.js"), true ? [] : void 0, import.meta.url)
|
|
207641
207946
|
});
|
|
207642
207947
|
registerLanguage({
|
|
207643
207948
|
id: "qsharp",
|
|
@@ -207656,7 +207961,7 @@ registerLanguage({
|
|
|
207656
207961
|
extensions: [".cshtml"],
|
|
207657
207962
|
aliases: ["Razor", "razor"],
|
|
207658
207963
|
mimetypes: ["text/x-cshtml"],
|
|
207659
|
-
loader: () => __vitePreload(() => import("./razor-
|
|
207964
|
+
loader: () => __vitePreload(() => import("./razor-Cqcu1rLJ.js"), true ? [] : void 0, import.meta.url)
|
|
207660
207965
|
});
|
|
207661
207966
|
registerLanguage({
|
|
207662
207967
|
id: "redis",
|
|
@@ -207789,7 +208094,7 @@ registerLanguage({
|
|
|
207789
208094
|
aliases: ["TypeScript", "ts", "typescript"],
|
|
207790
208095
|
mimetypes: ["text/typescript"],
|
|
207791
208096
|
loader: () => {
|
|
207792
|
-
return __vitePreload(() => import("./typescript-
|
|
208097
|
+
return __vitePreload(() => import("./typescript-rkc9lhpi.js"), true ? [] : void 0, import.meta.url);
|
|
207793
208098
|
}
|
|
207794
208099
|
});
|
|
207795
208100
|
registerLanguage({
|
|
@@ -207834,14 +208139,14 @@ registerLanguage({
|
|
|
207834
208139
|
firstLine: "(\\<\\?xml.*)|(\\<svg)|(\\<\\!doctype\\s+svg)",
|
|
207835
208140
|
aliases: ["XML", "xml"],
|
|
207836
208141
|
mimetypes: ["text/xml", "application/xml", "application/xaml+xml", "application/xml-dtd"],
|
|
207837
|
-
loader: () => __vitePreload(() => import("./xml-
|
|
208142
|
+
loader: () => __vitePreload(() => import("./xml-EsHEUps1.js"), true ? [] : void 0, import.meta.url)
|
|
207838
208143
|
});
|
|
207839
208144
|
registerLanguage({
|
|
207840
208145
|
id: "yaml",
|
|
207841
208146
|
extensions: [".yaml", ".yml"],
|
|
207842
208147
|
aliases: ["YAML", "yaml", "YML", "yml"],
|
|
207843
208148
|
mimetypes: ["application/x-yaml", "text/x-yaml"],
|
|
207844
|
-
loader: () => __vitePreload(() => import("./yaml-
|
|
208149
|
+
loader: () => __vitePreload(() => import("./yaml-B9-nQ_s2.js"), true ? [] : void 0, import.meta.url)
|
|
207845
208150
|
});
|
|
207846
208151
|
var __defProp = Object.defineProperty;
|
|
207847
208152
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
@@ -212311,6 +212616,12 @@ function App() {
|
|
|
212311
212616
|
console.error("[tracking] toggle failed", err);
|
|
212312
212617
|
}
|
|
212313
212618
|
}, [trackingActive]);
|
|
212619
|
+
const handleVoiceTranscript = reactExports.useCallback((text2) => {
|
|
212620
|
+
const trimmed = text2.trim();
|
|
212621
|
+
if (!trimmed) return;
|
|
212622
|
+
window.worker.writePty(activeTabId, trimmed);
|
|
212623
|
+
focusTerminal(activeTabId);
|
|
212624
|
+
}, [activeTabId]);
|
|
212314
212625
|
const cwdRef = reactExports.useRef(null);
|
|
212315
212626
|
const handleSpawn = reactExports.useCallback(async (tabId, agent) => {
|
|
212316
212627
|
setTabs((prev) => prev.map((t) => t.id === tabId ? { ...t, agentStatus: "active" } : t));
|
|
@@ -212572,6 +212883,7 @@ function App() {
|
|
|
212572
212883
|
]
|
|
212573
212884
|
}
|
|
212574
212885
|
),
|
|
212886
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(VoiceInput, { onTranscript: handleVoiceTranscript }),
|
|
212575
212887
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "titlebar-separator" }),
|
|
212576
212888
|
agents.map((a) => {
|
|
212577
212889
|
const activeTab = tabs.find((t) => t.id === activeTabId);
|