open-agents-ai 0.184.70 → 0.184.72
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +255 -23
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -560,6 +560,10 @@ var init_normalizeUrl = __esm({
|
|
|
560
560
|
"use strict";
|
|
561
561
|
PROVIDERS = [
|
|
562
562
|
// --- Cloud providers (specific domains) ---
|
|
563
|
+
{
|
|
564
|
+
match: (u) => /api\.anthropic\.com/i.test(u),
|
|
565
|
+
info: { id: "anthropic", label: "Anthropic (Claude)", local: false, authRequired: true, keyPrefix: "sk-ant-", modelsPath: "/v1/models" }
|
|
566
|
+
},
|
|
563
567
|
{
|
|
564
568
|
match: (u) => /api\.openai\.com/i.test(u),
|
|
565
569
|
info: { id: "openai", label: "OpenAI", local: false, authRequired: true, keyPrefix: "sk-", modelsPath: "/v1/models" }
|
|
@@ -11949,7 +11953,7 @@ function formatTime(seconds) {
|
|
|
11949
11953
|
const s = Math.floor(seconds % 60);
|
|
11950
11954
|
return `${String(m).padStart(2, "0")}:${String(s).padStart(2, "0")}`;
|
|
11951
11955
|
}
|
|
11952
|
-
var AUDIO_EXTS, VIDEO_EXTS, _tcModule, _tcChecked, TranscribeFileTool, TranscribeUrlTool;
|
|
11956
|
+
var AUDIO_EXTS, VIDEO_EXTS, _tcModule, _tcChecked, TranscribeFileTool, TranscribeUrlTool, YouTubeDownloadTool;
|
|
11953
11957
|
var init_transcribe_tool = __esm({
|
|
11954
11958
|
"packages/execution/dist/tools/transcribe-tool.js"() {
|
|
11955
11959
|
"use strict";
|
|
@@ -12267,6 +12271,90 @@ ${result.output}`,
|
|
|
12267
12271
|
}
|
|
12268
12272
|
}
|
|
12269
12273
|
};
|
|
12274
|
+
YouTubeDownloadTool = class {
|
|
12275
|
+
name = "youtube_download";
|
|
12276
|
+
description = "Download video or audio from YouTube. Saves mp4 (video) or mp3 (audio) to the working directory. Uses yt-dlp (auto-installed). Supports youtube.com/watch, youtu.be, shorts, live URLs.";
|
|
12277
|
+
parameters = {
|
|
12278
|
+
type: "object",
|
|
12279
|
+
properties: {
|
|
12280
|
+
url: {
|
|
12281
|
+
type: "string",
|
|
12282
|
+
description: "YouTube URL (youtube.com/watch?v=..., youtu.be/..., etc.)"
|
|
12283
|
+
},
|
|
12284
|
+
format: {
|
|
12285
|
+
type: "string",
|
|
12286
|
+
enum: ["mp3", "mp4"],
|
|
12287
|
+
description: "Output format: 'mp3' for audio only, 'mp4' for video (default: mp3)"
|
|
12288
|
+
},
|
|
12289
|
+
output_dir: {
|
|
12290
|
+
type: "string",
|
|
12291
|
+
description: "Directory to save the file (default: current working directory)"
|
|
12292
|
+
}
|
|
12293
|
+
},
|
|
12294
|
+
required: ["url"]
|
|
12295
|
+
};
|
|
12296
|
+
workingDir;
|
|
12297
|
+
constructor(workingDir) {
|
|
12298
|
+
this.workingDir = workingDir;
|
|
12299
|
+
}
|
|
12300
|
+
async execute(args) {
|
|
12301
|
+
const start = Date.now();
|
|
12302
|
+
const url = String(args.url ?? "").trim();
|
|
12303
|
+
const format = String(args.format ?? "mp3").toLowerCase();
|
|
12304
|
+
const outputDir = String(args.output_dir ?? this.workingDir);
|
|
12305
|
+
if (!url) {
|
|
12306
|
+
return { success: false, output: "", error: "URL is required", durationMs: Date.now() - start };
|
|
12307
|
+
}
|
|
12308
|
+
if (!isYouTubeUrl(url)) {
|
|
12309
|
+
return { success: false, output: "", error: "Not a recognized YouTube URL. Supported: youtube.com/watch, youtu.be, shorts, live, embed", durationMs: Date.now() - start };
|
|
12310
|
+
}
|
|
12311
|
+
if (!ensureYtDlp()) {
|
|
12312
|
+
return { success: false, output: "", error: "yt-dlp not available and auto-install failed. Install manually: pip install yt-dlp", durationMs: Date.now() - start };
|
|
12313
|
+
}
|
|
12314
|
+
mkdirSync7(outputDir, { recursive: true });
|
|
12315
|
+
try {
|
|
12316
|
+
let title = "download";
|
|
12317
|
+
try {
|
|
12318
|
+
title = execSync10(`yt-dlp --get-title "${url}"`, { timeout: 15e3, stdio: "pipe" }).toString().trim().replace(/[<>:"/\\|?*]/g, "_").slice(0, 100);
|
|
12319
|
+
} catch {
|
|
12320
|
+
}
|
|
12321
|
+
if (format === "mp4") {
|
|
12322
|
+
const outPath = join19(outputDir, `${title}.mp4`);
|
|
12323
|
+
const outTemplate = join19(outputDir, `${title}.%(ext)s`);
|
|
12324
|
+
execSync10(`yt-dlp -f "bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best" --merge-output-format mp4 -o "${outTemplate}" "${url}"`, { timeout: 6e5, stdio: "pipe", cwd: outputDir });
|
|
12325
|
+
const actualPath = existsSync16(outPath) ? outPath : outTemplate.replace("%(ext)s", "mp4");
|
|
12326
|
+
return {
|
|
12327
|
+
success: true,
|
|
12328
|
+
output: `Downloaded video: ${actualPath}
|
|
12329
|
+
Title: ${title}
|
|
12330
|
+
Format: mp4`,
|
|
12331
|
+
durationMs: Date.now() - start
|
|
12332
|
+
};
|
|
12333
|
+
} else {
|
|
12334
|
+
const outPath = join19(outputDir, `${title}.mp3`);
|
|
12335
|
+
const outTemplate = join19(outputDir, `${title}.%(ext)s`);
|
|
12336
|
+
execSync10(`yt-dlp -x --audio-format mp3 --audio-quality 0 -o "${outTemplate}" "${url}"`, { timeout: 6e5, stdio: "pipe", cwd: outputDir });
|
|
12337
|
+
const actualPath = existsSync16(outPath) ? outPath : outTemplate.replace("%(ext)s", "mp3");
|
|
12338
|
+
return {
|
|
12339
|
+
success: true,
|
|
12340
|
+
output: `Downloaded audio: ${actualPath}
|
|
12341
|
+
Title: ${title}
|
|
12342
|
+
Format: mp3`,
|
|
12343
|
+
durationMs: Date.now() - start
|
|
12344
|
+
};
|
|
12345
|
+
}
|
|
12346
|
+
} catch (err) {
|
|
12347
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
12348
|
+
const stderr = err?.stderr?.toString?.()?.slice(0, 500) ?? "";
|
|
12349
|
+
return {
|
|
12350
|
+
success: false,
|
|
12351
|
+
output: "",
|
|
12352
|
+
error: `YouTube download failed: ${msg}${stderr ? "\n" + stderr : ""}`,
|
|
12353
|
+
durationMs: Date.now() - start
|
|
12354
|
+
};
|
|
12355
|
+
}
|
|
12356
|
+
}
|
|
12357
|
+
};
|
|
12270
12358
|
}
|
|
12271
12359
|
});
|
|
12272
12360
|
|
|
@@ -22603,6 +22691,7 @@ __export(dist_exports, {
|
|
|
22603
22691
|
WebFetchTool: () => WebFetchTool,
|
|
22604
22692
|
WebSearchTool: () => WebSearchTool,
|
|
22605
22693
|
WorkingNotesTool: () => WorkingNotesTool,
|
|
22694
|
+
YouTubeDownloadTool: () => YouTubeDownloadTool,
|
|
22606
22695
|
applyPatch: () => applyPatch,
|
|
22607
22696
|
buildCompactDiff: () => buildCompactDiff,
|
|
22608
22697
|
buildCustomTools: () => buildCustomTools,
|
|
@@ -28402,11 +28491,14 @@ ${transcript}`
|
|
|
28402
28491
|
/** Multi-key pool — round-robin rotation per request for load distribution */
|
|
28403
28492
|
_keyPool = [];
|
|
28404
28493
|
_keyIndex = 0;
|
|
28494
|
+
/** Whether this backend targets Anthropic's Messages API */
|
|
28495
|
+
_isAnthropic = false;
|
|
28405
28496
|
constructor(baseUrl, model, apiKey, thinking) {
|
|
28406
28497
|
this.baseUrl = normalizeBaseUrl(baseUrl);
|
|
28407
28498
|
this.model = model;
|
|
28408
28499
|
this.apiKey = apiKey ?? "";
|
|
28409
28500
|
this.thinking = thinking ?? true;
|
|
28501
|
+
this._isAnthropic = /api\.anthropic\.com/i.test(baseUrl);
|
|
28410
28502
|
}
|
|
28411
28503
|
/** Set multiple API keys for round-robin rotation per request */
|
|
28412
28504
|
setKeyPool(keys) {
|
|
@@ -28417,7 +28509,7 @@ ${transcript}`
|
|
|
28417
28509
|
setAbortSignal(signal) {
|
|
28418
28510
|
this._abortSignal = signal;
|
|
28419
28511
|
}
|
|
28420
|
-
/** Build auth headers —
|
|
28512
|
+
/** Build auth headers — adapts to provider (Bearer for most, x-api-key for Anthropic).
|
|
28421
28513
|
* When a key pool is set, round-robins through keys per request. */
|
|
28422
28514
|
authHeaders() {
|
|
28423
28515
|
const headers = { "Content-Type": "application/json" };
|
|
@@ -28427,11 +28519,19 @@ ${transcript}`
|
|
|
28427
28519
|
this._keyIndex++;
|
|
28428
28520
|
}
|
|
28429
28521
|
if (key) {
|
|
28430
|
-
|
|
28522
|
+
if (this._isAnthropic) {
|
|
28523
|
+
headers["x-api-key"] = key;
|
|
28524
|
+
headers["anthropic-version"] = "2023-06-01";
|
|
28525
|
+
} else {
|
|
28526
|
+
headers["Authorization"] = `Bearer ${key}`;
|
|
28527
|
+
}
|
|
28431
28528
|
}
|
|
28432
28529
|
return headers;
|
|
28433
28530
|
}
|
|
28434
28531
|
async chatCompletion(request) {
|
|
28532
|
+
if (this._isAnthropic) {
|
|
28533
|
+
return this._anthropicChatCompletion(request);
|
|
28534
|
+
}
|
|
28435
28535
|
const body = {
|
|
28436
28536
|
model: this.model,
|
|
28437
28537
|
messages: request.messages,
|
|
@@ -28489,6 +28589,106 @@ ${transcript}`
|
|
|
28489
28589
|
} : void 0
|
|
28490
28590
|
};
|
|
28491
28591
|
}
|
|
28592
|
+
/** Anthropic Messages API translation — converts our standard format to/from Anthropic's. */
|
|
28593
|
+
async _anthropicChatCompletion(request) {
|
|
28594
|
+
const systemMsgs = request.messages.filter((m) => m.role === "system");
|
|
28595
|
+
const nonSystemMsgs = request.messages.filter((m) => m.role !== "system");
|
|
28596
|
+
const systemText = systemMsgs.map((m) => typeof m.content === "string" ? m.content : "").join("\n\n");
|
|
28597
|
+
const anthropicMessages = [];
|
|
28598
|
+
for (const msg of nonSystemMsgs) {
|
|
28599
|
+
if (msg.role === "tool") {
|
|
28600
|
+
anthropicMessages.push({
|
|
28601
|
+
role: "user",
|
|
28602
|
+
content: [{
|
|
28603
|
+
type: "tool_result",
|
|
28604
|
+
tool_use_id: msg.tool_call_id ?? "",
|
|
28605
|
+
content: typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content)
|
|
28606
|
+
}]
|
|
28607
|
+
});
|
|
28608
|
+
} else if (msg.role === "assistant" && msg.tool_calls?.length > 0) {
|
|
28609
|
+
const blocks = [];
|
|
28610
|
+
if (typeof msg.content === "string" && msg.content) {
|
|
28611
|
+
blocks.push({ type: "text", text: msg.content });
|
|
28612
|
+
}
|
|
28613
|
+
for (const tc of msg.tool_calls) {
|
|
28614
|
+
blocks.push({
|
|
28615
|
+
type: "tool_use",
|
|
28616
|
+
id: tc.id,
|
|
28617
|
+
name: tc.function?.name ?? tc.name,
|
|
28618
|
+
input: typeof tc.function?.arguments === "string" ? (() => {
|
|
28619
|
+
try {
|
|
28620
|
+
return JSON.parse(tc.function.arguments);
|
|
28621
|
+
} catch {
|
|
28622
|
+
return {};
|
|
28623
|
+
}
|
|
28624
|
+
})() : tc.function?.arguments ?? {}
|
|
28625
|
+
});
|
|
28626
|
+
}
|
|
28627
|
+
anthropicMessages.push({ role: "assistant", content: blocks });
|
|
28628
|
+
} else {
|
|
28629
|
+
anthropicMessages.push({
|
|
28630
|
+
role: msg.role === "user" ? "user" : "assistant",
|
|
28631
|
+
content: typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content ?? "")
|
|
28632
|
+
});
|
|
28633
|
+
}
|
|
28634
|
+
}
|
|
28635
|
+
const anthropicTools = (request.tools ?? []).filter((t) => t.type === "function" && t.function).map((t) => ({
|
|
28636
|
+
name: t.function.name,
|
|
28637
|
+
description: t.function.description,
|
|
28638
|
+
input_schema: t.function.parameters
|
|
28639
|
+
}));
|
|
28640
|
+
const body = {
|
|
28641
|
+
model: this.model,
|
|
28642
|
+
messages: anthropicMessages,
|
|
28643
|
+
max_tokens: request.maxTokens ?? 8192,
|
|
28644
|
+
temperature: request.temperature
|
|
28645
|
+
};
|
|
28646
|
+
if (systemText)
|
|
28647
|
+
body.system = systemText;
|
|
28648
|
+
if (anthropicTools.length > 0)
|
|
28649
|
+
body.tools = anthropicTools;
|
|
28650
|
+
const fetchOpts = {
|
|
28651
|
+
method: "POST",
|
|
28652
|
+
headers: this.authHeaders(),
|
|
28653
|
+
body: JSON.stringify(body)
|
|
28654
|
+
};
|
|
28655
|
+
if (this._abortSignal)
|
|
28656
|
+
fetchOpts.signal = this._abortSignal;
|
|
28657
|
+
const resp = await fetch(`${this.baseUrl}/v1/messages`, fetchOpts);
|
|
28658
|
+
if (!resp.ok) {
|
|
28659
|
+
const text = await resp.text().catch(() => "");
|
|
28660
|
+
throw new Error(`Anthropic HTTP ${resp.status}: ${text.slice(0, 300)}`);
|
|
28661
|
+
}
|
|
28662
|
+
const data = await resp.json();
|
|
28663
|
+
const contentBlocks = data.content ?? [];
|
|
28664
|
+
const usage = data.usage;
|
|
28665
|
+
let textContent = "";
|
|
28666
|
+
const toolCalls = [];
|
|
28667
|
+
for (const block of contentBlocks) {
|
|
28668
|
+
if (block.type === "text") {
|
|
28669
|
+
textContent += block.text ?? "";
|
|
28670
|
+
} else if (block.type === "tool_use") {
|
|
28671
|
+
toolCalls.push({
|
|
28672
|
+
id: block.id || crypto.randomUUID(),
|
|
28673
|
+
name: block.name,
|
|
28674
|
+
arguments: block.input ?? {}
|
|
28675
|
+
});
|
|
28676
|
+
}
|
|
28677
|
+
}
|
|
28678
|
+
return {
|
|
28679
|
+
choices: [{
|
|
28680
|
+
message: {
|
|
28681
|
+
content: textContent || null,
|
|
28682
|
+
toolCalls: toolCalls.length > 0 ? toolCalls : void 0
|
|
28683
|
+
}
|
|
28684
|
+
}],
|
|
28685
|
+
usage: usage ? {
|
|
28686
|
+
totalTokens: (usage.input_tokens ?? 0) + (usage.output_tokens ?? 0),
|
|
28687
|
+
promptTokens: usage.input_tokens,
|
|
28688
|
+
completionTokens: usage.output_tokens
|
|
28689
|
+
} : void 0
|
|
28690
|
+
};
|
|
28691
|
+
}
|
|
28492
28692
|
/**
|
|
28493
28693
|
* SSE streaming variant — yields StreamChunks as tokens arrive.
|
|
28494
28694
|
* Uses `stream: true` and the current thinking setting.
|
|
@@ -38528,9 +38728,15 @@ async function fetchOllamaModels(baseUrl) {
|
|
|
38528
38728
|
async function fetchOpenAIModels(baseUrl, apiKey) {
|
|
38529
38729
|
const normalized = normalizeBaseUrl(baseUrl);
|
|
38530
38730
|
const url = `${normalized}/v1/models`;
|
|
38731
|
+
const isAnthropic = /api\.anthropic\.com/i.test(baseUrl);
|
|
38531
38732
|
const headers = {};
|
|
38532
38733
|
if (apiKey) {
|
|
38533
|
-
|
|
38734
|
+
if (isAnthropic) {
|
|
38735
|
+
headers["x-api-key"] = apiKey;
|
|
38736
|
+
headers["anthropic-version"] = "2023-06-01";
|
|
38737
|
+
} else {
|
|
38738
|
+
headers["Authorization"] = `Bearer ${apiKey}`;
|
|
38739
|
+
}
|
|
38534
38740
|
}
|
|
38535
38741
|
const resp = await fetch(url, {
|
|
38536
38742
|
headers,
|
|
@@ -45959,26 +46165,45 @@ Error: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
|
45959
46165
|
const isArm = process.arch === "arm64" || process.arch === "arm";
|
|
45960
46166
|
if (isArm) {
|
|
45961
46167
|
renderInfo(" ARM device detected \u2014 installing build prerequisites then deps individually.");
|
|
46168
|
+
const isMac = process.platform === "darwin";
|
|
45962
46169
|
try {
|
|
45963
46170
|
const { spawnSync } = await import("node:child_process");
|
|
45964
|
-
|
|
45965
|
-
|
|
45966
|
-
|
|
45967
|
-
|
|
45968
|
-
|
|
45969
|
-
|
|
45970
|
-
|
|
45971
|
-
|
|
45972
|
-
"--
|
|
45973
|
-
|
|
45974
|
-
|
|
45975
|
-
|
|
45976
|
-
|
|
45977
|
-
"
|
|
45978
|
-
"
|
|
45979
|
-
|
|
46171
|
+
if (isMac) {
|
|
46172
|
+
renderInfo(" macOS ARM detected \u2014 installing build deps via Homebrew...");
|
|
46173
|
+
const brewCheck = spawnSync("which", ["brew"], { stdio: "pipe", timeout: 5e3 });
|
|
46174
|
+
if (brewCheck.status === 0) {
|
|
46175
|
+
spawnSync("brew", ["install", "llvm", "gcc", "openblas", "libsndfile"], {
|
|
46176
|
+
stdio: "inherit",
|
|
46177
|
+
timeout: 3e5
|
|
46178
|
+
});
|
|
46179
|
+
const llvmPrefix = spawnSync("brew", ["--prefix", "llvm"], { stdio: "pipe", timeout: 5e3 });
|
|
46180
|
+
if (llvmPrefix.stdout) {
|
|
46181
|
+
process.env.LLVM_CONFIG = `${llvmPrefix.stdout.toString().trim()}/bin/llvm-config`;
|
|
46182
|
+
}
|
|
46183
|
+
} else {
|
|
46184
|
+
renderWarning(" Homebrew not found. Install it: https://brew.sh");
|
|
46185
|
+
renderWarning(" Then run: brew install llvm gcc openblas libsndfile");
|
|
46186
|
+
}
|
|
45980
46187
|
} else {
|
|
45981
|
-
|
|
46188
|
+
renderInfo(" System build tools needed (llvm, gcc). Requesting sudo access...");
|
|
46189
|
+
const sudoCheck = spawnSync("sudo", ["-v"], { stdio: "inherit", timeout: 6e4 });
|
|
46190
|
+
if (sudoCheck.status === 0) {
|
|
46191
|
+
renderInfo(" Installing system build dependencies (this may take a minute)...");
|
|
46192
|
+
spawnSync("sudo", [
|
|
46193
|
+
"apt-get",
|
|
46194
|
+
"install",
|
|
46195
|
+
"-y",
|
|
46196
|
+
"--no-install-recommends",
|
|
46197
|
+
"llvm-dev",
|
|
46198
|
+
"gcc",
|
|
46199
|
+
"g++",
|
|
46200
|
+
"gfortran",
|
|
46201
|
+
"libopenblas-dev",
|
|
46202
|
+
"libsndfile1-dev"
|
|
46203
|
+
], { stdio: "inherit", timeout: 12e4 });
|
|
46204
|
+
} else {
|
|
46205
|
+
renderWarning(" sudo not available \u2014 skipping system build deps. librosa/lhotse may fail to compile.");
|
|
46206
|
+
}
|
|
45982
46207
|
}
|
|
45983
46208
|
} catch (err) {
|
|
45984
46209
|
renderWarning(` Could not install system build deps: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -50098,7 +50323,12 @@ async function handleEndpoint(arg, ctx, local = false) {
|
|
|
50098
50323
|
const healthUrl = `${normalizedUrl}${provider.modelsPath}`;
|
|
50099
50324
|
const headers = {};
|
|
50100
50325
|
if (apiKey) {
|
|
50101
|
-
|
|
50326
|
+
if (provider.id === "anthropic") {
|
|
50327
|
+
headers["x-api-key"] = apiKey;
|
|
50328
|
+
headers["anthropic-version"] = "2023-06-01";
|
|
50329
|
+
} else {
|
|
50330
|
+
headers["Authorization"] = `Bearer ${apiKey}`;
|
|
50331
|
+
}
|
|
50102
50332
|
}
|
|
50103
50333
|
const resp = await fetch(healthUrl, {
|
|
50104
50334
|
headers,
|
|
@@ -63749,9 +63979,10 @@ function buildTools(repoRoot, config, contextWindowSize) {
|
|
|
63749
63979
|
// Skill system (AIWG skills — discovery and execution)
|
|
63750
63980
|
new SkillListTool(repoRoot),
|
|
63751
63981
|
new SkillExecuteTool(repoRoot),
|
|
63752
|
-
// Transcription tools (transcribe-cli / faster-whisper)
|
|
63982
|
+
// Transcription + media download tools (transcribe-cli / faster-whisper / yt-dlp)
|
|
63753
63983
|
new TranscribeFileTool(repoRoot),
|
|
63754
63984
|
new TranscribeUrlTool(repoRoot),
|
|
63985
|
+
new YouTubeDownloadTool(repoRoot),
|
|
63755
63986
|
// Structured file generation (CSV, JSON, Markdown, Excel-compatible)
|
|
63756
63987
|
new StructuredFileTool(repoRoot),
|
|
63757
63988
|
// Code sandbox (isolated code execution)
|
|
@@ -64994,6 +65225,7 @@ async function startInteractive(config, repoPath) {
|
|
|
64994
65225
|
initOaDirectory(repoRoot);
|
|
64995
65226
|
const savedSettings = resolveSettings(repoRoot);
|
|
64996
65227
|
if (process.stdout.isTTY) {
|
|
65228
|
+
process.stdout.write("\x1B[2J\x1B[3J\x1B[H");
|
|
64997
65229
|
process.stdout.write("\x1B[?1002l\x1B[?1003l\x1B[?1006l\x1B[?1015l\x1B[?1049h\x1B[48;5;233m\x1B[2J\x1B[3J\x1B[H\x1B[?25l");
|
|
64998
65230
|
const restoreScreen = () => {
|
|
64999
65231
|
process.stdout.write("\x1B[?1002l\x1B[?1003l\x1B[?1006l\x1B[?1015l\x1B[?25h\x1B[?1049l");
|
package/package.json
CHANGED