@mingxy/ocosay 1.1.10 → 1.1.12
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/core/backends/index.d.ts +0 -7
- package/dist/core/backends/index.js +19 -19
- package/dist/core/backends/powershell-backend.js +10 -1
- package/dist/package.json +1 -1
- package/dist/plugin.js +137 -23
- package/package.json +1 -1
|
@@ -19,13 +19,6 @@ export declare enum BackendType {
|
|
|
19
19
|
HOWLER = "howler",
|
|
20
20
|
AUTO = "auto"
|
|
21
21
|
}
|
|
22
|
-
export declare function isWsl(): boolean;
|
|
23
|
-
/**
|
|
24
|
-
* 创建音频后端
|
|
25
|
-
* @param type 后端类型,默认 AUTO(自动选择)
|
|
26
|
-
* @param options 后端配置选项
|
|
27
|
-
* @returns 音频后端实例
|
|
28
|
-
*/
|
|
29
22
|
export declare function createBackend(type?: BackendType, options?: BackendOptions): AudioBackend;
|
|
30
23
|
export declare function supportsStreaming(type: BackendType): boolean;
|
|
31
24
|
export declare function getDefaultBackendType(): BackendType;
|
|
@@ -7,12 +7,25 @@ export { AfplayBackend } from './afplay-backend';
|
|
|
7
7
|
export { AplayBackend } from './aplay-backend';
|
|
8
8
|
export { PowerShellBackend } from './powershell-backend';
|
|
9
9
|
export { HowlerBackend } from './howler-backend';
|
|
10
|
+
import { execSync } from 'child_process';
|
|
10
11
|
import { NaudiodonBackend } from './naudiodon-backend';
|
|
11
12
|
import { AfplayBackend } from './afplay-backend';
|
|
12
13
|
import { AplayBackend } from './aplay-backend';
|
|
13
14
|
import { PowerShellBackend } from './powershell-backend';
|
|
14
15
|
import { HowlerBackend } from './howler-backend';
|
|
15
16
|
import { logger } from '../../utils/logger';
|
|
17
|
+
function execCmd(cmd) {
|
|
18
|
+
try {
|
|
19
|
+
const output = execSync(cmd, { stdio: 'pipe', encoding: 'utf8' });
|
|
20
|
+
return { success: true, output };
|
|
21
|
+
}
|
|
22
|
+
catch (err) {
|
|
23
|
+
return { success: false, output: err.message || '' };
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function isCommandAvailable(cmd) {
|
|
27
|
+
return execCmd(`which ${cmd}`).success;
|
|
28
|
+
}
|
|
16
29
|
/**
|
|
17
30
|
* 后端类型枚举
|
|
18
31
|
*/
|
|
@@ -50,22 +63,6 @@ function isNaudiodonAvailable() {
|
|
|
50
63
|
return false;
|
|
51
64
|
}
|
|
52
65
|
}
|
|
53
|
-
export function isWsl() {
|
|
54
|
-
if (process.platform !== 'linux')
|
|
55
|
-
return false;
|
|
56
|
-
try {
|
|
57
|
-
return require('fs').readFileSync('/proc/version', 'utf8').toLowerCase().includes('microsoft');
|
|
58
|
-
}
|
|
59
|
-
catch {
|
|
60
|
-
return false;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* 创建音频后端
|
|
65
|
-
* @param type 后端类型,默认 AUTO(自动选择)
|
|
66
|
-
* @param options 后端配置选项
|
|
67
|
-
* @returns 音频后端实例
|
|
68
|
-
*/
|
|
69
66
|
export function createBackend(type = BackendType.AUTO, options = {}) {
|
|
70
67
|
const platform = process.platform;
|
|
71
68
|
if (type !== BackendType.AUTO) {
|
|
@@ -90,10 +87,13 @@ export function createBackend(type = BackendType.AUTO, options = {}) {
|
|
|
90
87
|
case 'darwin':
|
|
91
88
|
return new AfplayBackend(options);
|
|
92
89
|
case 'linux':
|
|
93
|
-
if (
|
|
94
|
-
|
|
90
|
+
if (isCommandAvailable('aplay')) {
|
|
91
|
+
const test = execCmd('aplay -l');
|
|
92
|
+
if (test.success && !test.output.includes('no soundcards')) {
|
|
93
|
+
return new AplayBackend(options);
|
|
94
|
+
}
|
|
95
95
|
}
|
|
96
|
-
return new
|
|
96
|
+
return new HowlerBackend(options);
|
|
97
97
|
case 'win32':
|
|
98
98
|
return new PowerShellBackend(options);
|
|
99
99
|
default:
|
|
@@ -6,7 +6,16 @@ import { spawn } from 'child_process';
|
|
|
6
6
|
import { tmpdir } from 'os';
|
|
7
7
|
import { join } from 'path';
|
|
8
8
|
import { writeFileSync, unlinkSync, existsSync } from 'fs';
|
|
9
|
-
|
|
9
|
+
function isWsl() {
|
|
10
|
+
if (process.platform !== 'linux')
|
|
11
|
+
return false;
|
|
12
|
+
try {
|
|
13
|
+
return require('fs').readFileSync('/proc/version', 'utf8').toLowerCase().includes('microsoft');
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
10
19
|
// 白名单:Windows/WSL 路径格式(禁止 - 防止命令注入)
|
|
11
20
|
// 允许: 字母数字 \w, Windows盘符 : \:, 反斜杠 \\, 下划线 _, 点 ., $ @ /, 以及 -
|
|
12
21
|
const SAFE_PATH_REGEX = /^[\w\:\\_.\-$@\/]+$/i;
|
package/dist/package.json
CHANGED
package/dist/plugin.js
CHANGED
|
@@ -7156,6 +7156,14 @@ import { spawn } from "child_process";
|
|
|
7156
7156
|
import { tmpdir as tmpdir3 } from "os";
|
|
7157
7157
|
import { join as join4 } from "path";
|
|
7158
7158
|
import { writeFileSync as writeFileSync3, unlinkSync as unlinkSync3, existsSync as existsSync4 } from "fs";
|
|
7159
|
+
function isWsl() {
|
|
7160
|
+
if (process.platform !== "linux") return false;
|
|
7161
|
+
try {
|
|
7162
|
+
return __require("fs").readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft");
|
|
7163
|
+
} catch {
|
|
7164
|
+
return false;
|
|
7165
|
+
}
|
|
7166
|
+
}
|
|
7159
7167
|
var SAFE_PATH_REGEX3 = /^[\w\:\\_.\-$@\/]+$/i;
|
|
7160
7168
|
function wslPathToWindows(wslPath) {
|
|
7161
7169
|
if (wslPath.startsWith("//wsl$/")) {
|
|
@@ -7459,6 +7467,18 @@ var HowlerBackend = class {
|
|
|
7459
7467
|
};
|
|
7460
7468
|
|
|
7461
7469
|
// src/core/backends/index.ts
|
|
7470
|
+
import { execSync } from "child_process";
|
|
7471
|
+
function execCmd(cmd) {
|
|
7472
|
+
try {
|
|
7473
|
+
const output = execSync(cmd, { stdio: "pipe", encoding: "utf8" });
|
|
7474
|
+
return { success: true, output };
|
|
7475
|
+
} catch (err) {
|
|
7476
|
+
return { success: false, output: err.message || "" };
|
|
7477
|
+
}
|
|
7478
|
+
}
|
|
7479
|
+
function isCommandAvailable(cmd) {
|
|
7480
|
+
return execCmd(`which ${cmd}`).success;
|
|
7481
|
+
}
|
|
7462
7482
|
function isNaudiodonAvailable() {
|
|
7463
7483
|
try {
|
|
7464
7484
|
__require.resolve("naudiodon");
|
|
@@ -7468,14 +7488,6 @@ function isNaudiodonAvailable() {
|
|
|
7468
7488
|
return false;
|
|
7469
7489
|
}
|
|
7470
7490
|
}
|
|
7471
|
-
function isWsl() {
|
|
7472
|
-
if (process.platform !== "linux") return false;
|
|
7473
|
-
try {
|
|
7474
|
-
return __require("fs").readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft");
|
|
7475
|
-
} catch {
|
|
7476
|
-
return false;
|
|
7477
|
-
}
|
|
7478
|
-
}
|
|
7479
7491
|
function createBackend(type = "auto" /* AUTO */, options = {}) {
|
|
7480
7492
|
const platform = process.platform;
|
|
7481
7493
|
if (type !== "auto" /* AUTO */) {
|
|
@@ -7499,10 +7511,13 @@ function createBackend(type = "auto" /* AUTO */, options = {}) {
|
|
|
7499
7511
|
case "darwin":
|
|
7500
7512
|
return new AfplayBackend(options);
|
|
7501
7513
|
case "linux":
|
|
7502
|
-
if (
|
|
7503
|
-
|
|
7514
|
+
if (isCommandAvailable("aplay")) {
|
|
7515
|
+
const test = execCmd("aplay -l");
|
|
7516
|
+
if (test.success && !test.output.includes("no soundcards")) {
|
|
7517
|
+
return new AplayBackend(options);
|
|
7518
|
+
}
|
|
7504
7519
|
}
|
|
7505
|
-
return new
|
|
7520
|
+
return new HowlerBackend(options);
|
|
7506
7521
|
case "win32":
|
|
7507
7522
|
return new PowerShellBackend(options);
|
|
7508
7523
|
default:
|
|
@@ -9567,7 +9582,7 @@ import { readFileSync as readFileSync2, existsSync as existsSync6, writeFileSync
|
|
|
9567
9582
|
import { fileURLToPath } from "url";
|
|
9568
9583
|
import { dirname as dirname2, join as join7 } from "path";
|
|
9569
9584
|
import { homedir as homedir3 } from "os";
|
|
9570
|
-
import { execSync } from "child_process";
|
|
9585
|
+
import { execSync as execSync2 } from "child_process";
|
|
9571
9586
|
import { createRequire } from "module";
|
|
9572
9587
|
var logger8 = createModuleLogger("Plugin");
|
|
9573
9588
|
var require2 = createRequire(import.meta.url);
|
|
@@ -9581,12 +9596,89 @@ function markNaudiodonSkipped() {
|
|
|
9581
9596
|
try {
|
|
9582
9597
|
const dir = join7(homedir3(), ".config", "opencode");
|
|
9583
9598
|
if (!existsSync6(dir)) {
|
|
9584
|
-
|
|
9599
|
+
execSync2("mkdir -p", { cwd: dir });
|
|
9585
9600
|
}
|
|
9586
9601
|
writeFileSync5(getSkipFilePath(), Date.now().toString(), "utf-8");
|
|
9587
9602
|
} catch {
|
|
9588
9603
|
}
|
|
9589
9604
|
}
|
|
9605
|
+
async function verifyNaudiodonLoad() {
|
|
9606
|
+
try {
|
|
9607
|
+
require2("naudiodon");
|
|
9608
|
+
logger8.info("naudiodon loaded successfully");
|
|
9609
|
+
return true;
|
|
9610
|
+
} catch (err) {
|
|
9611
|
+
logger8.warn({ err }, "naudiodon load failed after rebuild");
|
|
9612
|
+
return false;
|
|
9613
|
+
}
|
|
9614
|
+
}
|
|
9615
|
+
async function rebuildNaudiodonDependency(dep) {
|
|
9616
|
+
const naudiodonPath = dirname2(require2.resolve("naudiodon"));
|
|
9617
|
+
try {
|
|
9618
|
+
notificationService.info(`\u6B63\u5728\u7F16\u8BD1 ${dep}...`, "Ocosay \u4F9D\u8D56", 4e3);
|
|
9619
|
+
execSync2(`npm rebuild ${dep}`, {
|
|
9620
|
+
cwd: naudiodonPath,
|
|
9621
|
+
stdio: "inherit"
|
|
9622
|
+
});
|
|
9623
|
+
logger8.info(`${dep} rebuilt successfully`);
|
|
9624
|
+
return true;
|
|
9625
|
+
} catch (err) {
|
|
9626
|
+
logger8.warn({ err }, `${dep} rebuild failed`);
|
|
9627
|
+
return false;
|
|
9628
|
+
}
|
|
9629
|
+
}
|
|
9630
|
+
async function fixNaudiodonDependencies(maxRetries = 5) {
|
|
9631
|
+
const naudiodonPath = dirname2(require2.resolve("naudiodon"));
|
|
9632
|
+
const criticalDeps = ["segfault-handler", "bindings", "node-pre-gyp"];
|
|
9633
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
9634
|
+
if (await verifyNaudiodonLoad()) {
|
|
9635
|
+
return true;
|
|
9636
|
+
}
|
|
9637
|
+
logger8.info({ attempt }, "naudiodon not loadable, trying dependency rebuild");
|
|
9638
|
+
notificationService.info(`\u6B63\u5728\u68C0\u67E5\u4F9D\u8D56 (${attempt + 1}/${maxRetries})...`, "Ocosay", 3e3);
|
|
9639
|
+
let anySuccess = false;
|
|
9640
|
+
for (const dep of criticalDeps) {
|
|
9641
|
+
try {
|
|
9642
|
+
require2.resolve(dep, { paths: [naudiodonPath] });
|
|
9643
|
+
if (await rebuildNaudiodonDependency(dep)) {
|
|
9644
|
+
anySuccess = true;
|
|
9645
|
+
}
|
|
9646
|
+
} catch {
|
|
9647
|
+
try {
|
|
9648
|
+
notificationService.info(`\u6B63\u5728\u5B89\u88C5 ${dep}...`, "Ocosay", 4e3);
|
|
9649
|
+
execSync2(`npm install ${dep}`, {
|
|
9650
|
+
cwd: naudiodonPath,
|
|
9651
|
+
stdio: "inherit"
|
|
9652
|
+
});
|
|
9653
|
+
logger8.info(`${dep} installed successfully`);
|
|
9654
|
+
anySuccess = true;
|
|
9655
|
+
} catch (installErr) {
|
|
9656
|
+
logger8.warn({ err: installErr }, `${dep} install failed`);
|
|
9657
|
+
}
|
|
9658
|
+
}
|
|
9659
|
+
}
|
|
9660
|
+
if (!anySuccess || !await verifyNaudiodonLoad()) {
|
|
9661
|
+
try {
|
|
9662
|
+
notificationService.info("\u6B63\u5728\u91CD\u65B0\u7F16\u8BD1 naudiodon...", "Ocosay", 4e3);
|
|
9663
|
+
execSync2("npm rebuild naudiodon", {
|
|
9664
|
+
cwd: naudiodonPath,
|
|
9665
|
+
stdio: "inherit"
|
|
9666
|
+
});
|
|
9667
|
+
logger8.info("naudiodon rebuilt");
|
|
9668
|
+
anySuccess = true;
|
|
9669
|
+
} catch (err) {
|
|
9670
|
+
logger8.warn({ err }, "naudiodon rebuild failed");
|
|
9671
|
+
}
|
|
9672
|
+
}
|
|
9673
|
+
if (await verifyNaudiodonLoad()) {
|
|
9674
|
+
return true;
|
|
9675
|
+
}
|
|
9676
|
+
if (anySuccess) {
|
|
9677
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
9678
|
+
}
|
|
9679
|
+
}
|
|
9680
|
+
return await verifyNaudiodonLoad();
|
|
9681
|
+
}
|
|
9590
9682
|
async function ensureNaudiodonCompiled() {
|
|
9591
9683
|
if (shouldSkipNaudiodon()) {
|
|
9592
9684
|
logger8.info("naudiodon skipped previously");
|
|
@@ -9603,12 +9695,23 @@ async function ensureNaudiodonCompiled() {
|
|
|
9603
9695
|
try {
|
|
9604
9696
|
const naudiodonPath = dirname2(require2.resolve("naudiodon"));
|
|
9605
9697
|
logger8.info({ naudiodonPath }, "found naudiodon, rebuilding");
|
|
9606
|
-
|
|
9698
|
+
execSync2("npm rebuild naudiodon", {
|
|
9607
9699
|
cwd: naudiodonPath,
|
|
9608
9700
|
stdio: "inherit"
|
|
9609
9701
|
});
|
|
9610
|
-
logger8.info("naudiodon compiled
|
|
9611
|
-
|
|
9702
|
+
logger8.info("naudiodon compiled, verifying...");
|
|
9703
|
+
const loadSuccess = await verifyNaudiodonLoad();
|
|
9704
|
+
if (loadSuccess) {
|
|
9705
|
+
notificationService.success("naudiodon \u7F16\u8BD1\u6210\u529F", "\u97F3\u9891\u540E\u7AEF\u5DF2\u5C31\u7EEA", 5e3);
|
|
9706
|
+
} else {
|
|
9707
|
+
notificationService.warning("naudiodon \u52A0\u8F7D\u5931\u8D25", "\u6B63\u5728\u68C0\u67E5\u4F9D\u8D56...", 5e3);
|
|
9708
|
+
const fixed = await fixNaudiodonDependencies();
|
|
9709
|
+
if (fixed) {
|
|
9710
|
+
notificationService.success("naudiodon \u4F9D\u8D56\u4FEE\u590D\u6210\u529F", "\u97F3\u9891\u540E\u7AEF\u5DF2\u5C31\u7EEA", 5e3);
|
|
9711
|
+
} else {
|
|
9712
|
+
throw new Error("naudiodon dependencies could not be fixed");
|
|
9713
|
+
}
|
|
9714
|
+
}
|
|
9612
9715
|
} catch (err) {
|
|
9613
9716
|
logger8.warn({ err }, "naudiodon rebuild failed, checking for PortAudio");
|
|
9614
9717
|
notificationService.warning("naudiodon \u7F16\u8BD1\u5931\u8D25", "\u6B63\u5728\u5C1D\u8BD5\u5B89\u88C5 PortAudio...", 5e3);
|
|
@@ -9617,12 +9720,23 @@ async function ensureNaudiodonCompiled() {
|
|
|
9617
9720
|
try {
|
|
9618
9721
|
const naudiodonPath = dirname2(require2.resolve("naudiodon"));
|
|
9619
9722
|
notificationService.info("\u6B63\u5728\u91CD\u65B0\u7F16\u8BD1 naudiodon...", "Ocosay", 5e3);
|
|
9620
|
-
|
|
9723
|
+
execSync2("npm rebuild naudiodon", {
|
|
9621
9724
|
cwd: naudiodonPath,
|
|
9622
9725
|
stdio: "inherit"
|
|
9623
9726
|
});
|
|
9624
9727
|
logger8.info("naudiodon compiled successfully after PortAudio install");
|
|
9625
|
-
|
|
9728
|
+
const loadSuccess = await verifyNaudiodonLoad();
|
|
9729
|
+
if (loadSuccess) {
|
|
9730
|
+
notificationService.success("naudiodon \u7F16\u8BD1\u6210\u529F", "\u97F3\u9891\u540E\u7AEF\u5DF2\u5C31\u7EEA", 5e3);
|
|
9731
|
+
} else {
|
|
9732
|
+
notificationService.warning("naudiodon \u52A0\u8F7D\u5931\u8D25", "\u6B63\u5728\u68C0\u67E5\u4F9D\u8D56...", 5e3);
|
|
9733
|
+
const fixed = await fixNaudiodonDependencies();
|
|
9734
|
+
if (fixed) {
|
|
9735
|
+
notificationService.success("naudiodon \u4F9D\u8D56\u4FEE\u590D\u6210\u529F", "\u97F3\u9891\u540E\u7AEF\u5DF2\u5C31\u7EEA", 5e3);
|
|
9736
|
+
} else {
|
|
9737
|
+
throw new Error("naudiodon dependencies could not be fixed");
|
|
9738
|
+
}
|
|
9739
|
+
}
|
|
9626
9740
|
} catch (retryErr) {
|
|
9627
9741
|
logger8.error({ err: retryErr }, "naudiodon compile failed even after PortAudio install");
|
|
9628
9742
|
notificationService.error("naudiodon \u7F16\u8BD1\u5931\u8D25", "\u81EA\u52A8\u5B89\u88C5\u5931\u8D25\uFF0C\u8BF7\u5C1D\u8BD5\u624B\u52A8\u5B89\u88C5", 8e3);
|
|
@@ -9635,9 +9749,9 @@ async function ensureNaudiodonCompiled() {
|
|
|
9635
9749
|
}
|
|
9636
9750
|
}
|
|
9637
9751
|
}
|
|
9638
|
-
function
|
|
9752
|
+
function execCmd2(cmd) {
|
|
9639
9753
|
try {
|
|
9640
|
-
const output =
|
|
9754
|
+
const output = execSync2(cmd, { stdio: "pipe", encoding: "utf8" });
|
|
9641
9755
|
return { success: true, output };
|
|
9642
9756
|
} catch (err) {
|
|
9643
9757
|
return { success: false, output: err.message || "" };
|
|
@@ -9652,9 +9766,9 @@ function isWsl2() {
|
|
|
9652
9766
|
}
|
|
9653
9767
|
}
|
|
9654
9768
|
function checkAlsa() {
|
|
9655
|
-
const result =
|
|
9769
|
+
const result = execCmd2("which aplay");
|
|
9656
9770
|
if (!result.success) return false;
|
|
9657
|
-
const test =
|
|
9771
|
+
const test = execCmd2("aplay -l");
|
|
9658
9772
|
return test.success && !test.output.includes("no soundcards");
|
|
9659
9773
|
}
|
|
9660
9774
|
async function installPortAudio() {
|
|
@@ -9665,7 +9779,7 @@ async function installPortAudio() {
|
|
|
9665
9779
|
logger8.info(`Running: ${cmd}`);
|
|
9666
9780
|
notificationService.info(desc, "\u6B63\u5728\u5B89\u88C5...", 5e3);
|
|
9667
9781
|
try {
|
|
9668
|
-
|
|
9782
|
+
execSync2(cmd, { stdio: "inherit" });
|
|
9669
9783
|
return true;
|
|
9670
9784
|
} catch (err) {
|
|
9671
9785
|
const msg = err.message || "";
|