open-agents-ai 0.16.4 → 0.17.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/dist/index.js +2104 -218
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1285,7 +1285,7 @@ ${stdinInput ?? ""}`);
|
|
|
1285
1285
|
}
|
|
1286
1286
|
runCommand(command, timeout, stdinInput) {
|
|
1287
1287
|
const start = performance.now();
|
|
1288
|
-
return new Promise((
|
|
1288
|
+
return new Promise((resolve18) => {
|
|
1289
1289
|
const child = spawn("bash", ["-c", command], {
|
|
1290
1290
|
cwd: this.workingDir,
|
|
1291
1291
|
env: {
|
|
@@ -1338,7 +1338,7 @@ ${stdinInput ?? ""}`);
|
|
|
1338
1338
|
const combined = stdout + stderr;
|
|
1339
1339
|
const looksInteractive = /\? .+[›>]|y\/n|yes\/no|\(Y\/n\)|\[y\/N\]/i.test(combined);
|
|
1340
1340
|
const hint = looksInteractive ? " The command appears to be waiting for interactive input. Use non-interactive flags (e.g., --yes, --no-input) or provide input via the stdin parameter." : "";
|
|
1341
|
-
|
|
1341
|
+
resolve18({
|
|
1342
1342
|
success: false,
|
|
1343
1343
|
output: stdout,
|
|
1344
1344
|
error: `Command timed out after ${timeout}ms.${hint}`,
|
|
@@ -1347,7 +1347,7 @@ ${stdinInput ?? ""}`);
|
|
|
1347
1347
|
return;
|
|
1348
1348
|
}
|
|
1349
1349
|
const success = code === 0;
|
|
1350
|
-
|
|
1350
|
+
resolve18({
|
|
1351
1351
|
success,
|
|
1352
1352
|
output: stdout + (stderr && success ? `
|
|
1353
1353
|
STDERR:
|
|
@@ -1358,7 +1358,7 @@ ${stderr}` : ""),
|
|
|
1358
1358
|
});
|
|
1359
1359
|
child.on("error", (err) => {
|
|
1360
1360
|
clearTimeout(timer);
|
|
1361
|
-
|
|
1361
|
+
resolve18({
|
|
1362
1362
|
success: false,
|
|
1363
1363
|
output: stdout,
|
|
1364
1364
|
error: err.message,
|
|
@@ -1732,15 +1732,24 @@ var init_web_fetch = __esm({
|
|
|
1732
1732
|
});
|
|
1733
1733
|
|
|
1734
1734
|
// packages/execution/dist/tools/web-search.js
|
|
1735
|
-
|
|
1735
|
+
function detectSearchProvider() {
|
|
1736
|
+
if (process.env["TAVILY_API_KEY"])
|
|
1737
|
+
return "tavily";
|
|
1738
|
+
if (process.env["JINA_API_KEY"])
|
|
1739
|
+
return "jina";
|
|
1740
|
+
return "duckduckgo";
|
|
1741
|
+
}
|
|
1742
|
+
var DEFAULT_NUM_RESULTS, DUCKDUCKGO_HTML_URL, TAVILY_API_URL, JINA_SEARCH_URL, WebSearchTool;
|
|
1736
1743
|
var init_web_search = __esm({
|
|
1737
1744
|
"packages/execution/dist/tools/web-search.js"() {
|
|
1738
1745
|
"use strict";
|
|
1739
1746
|
DEFAULT_NUM_RESULTS = 5;
|
|
1740
1747
|
DUCKDUCKGO_HTML_URL = "https://html.duckduckgo.com/html/";
|
|
1748
|
+
TAVILY_API_URL = "https://api.tavily.com/search";
|
|
1749
|
+
JINA_SEARCH_URL = "https://s.jina.ai/";
|
|
1741
1750
|
WebSearchTool = class {
|
|
1742
1751
|
name = "web_search";
|
|
1743
|
-
description = "Search the web for information. Returns
|
|
1752
|
+
description = "Search the web for information. Returns search results with titles, URLs, and snippets. Supports DuckDuckGo (free), Tavily (structured, set TAVILY_API_KEY), and Jina AI (markdown, set JINA_API_KEY).";
|
|
1744
1753
|
parameters = {
|
|
1745
1754
|
type: "object",
|
|
1746
1755
|
properties: {
|
|
@@ -1751,6 +1760,11 @@ var init_web_search = __esm({
|
|
|
1751
1760
|
num_results: {
|
|
1752
1761
|
type: "number",
|
|
1753
1762
|
description: `Number of results to return (default: ${DEFAULT_NUM_RESULTS})`
|
|
1763
|
+
},
|
|
1764
|
+
provider: {
|
|
1765
|
+
type: "string",
|
|
1766
|
+
enum: ["duckduckgo", "tavily", "jina"],
|
|
1767
|
+
description: "Search provider (auto-detected from API keys if omitted). tavily: structured JSON results with AI answer. jina: markdown-formatted results. duckduckgo: free HTML scraping fallback."
|
|
1754
1768
|
}
|
|
1755
1769
|
},
|
|
1756
1770
|
required: ["query"]
|
|
@@ -1758,43 +1772,73 @@ var init_web_search = __esm({
|
|
|
1758
1772
|
async execute(args) {
|
|
1759
1773
|
const query = args["query"];
|
|
1760
1774
|
const numResults = args["num_results"] ?? DEFAULT_NUM_RESULTS;
|
|
1775
|
+
const requestedProvider = args["provider"];
|
|
1761
1776
|
const start = performance.now();
|
|
1777
|
+
const provider = requestedProvider ?? detectSearchProvider();
|
|
1762
1778
|
try {
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
success: false,
|
|
1775
|
-
output: "",
|
|
1776
|
-
error: `HTTP ${response.status} ${response.statusText} from DuckDuckGo`,
|
|
1777
|
-
durationMs: performance.now() - start
|
|
1778
|
-
};
|
|
1779
|
+
let response;
|
|
1780
|
+
switch (provider) {
|
|
1781
|
+
case "tavily":
|
|
1782
|
+
response = await this.#searchTavily(query, numResults);
|
|
1783
|
+
break;
|
|
1784
|
+
case "jina":
|
|
1785
|
+
response = await this.#searchJina(query, numResults);
|
|
1786
|
+
break;
|
|
1787
|
+
default:
|
|
1788
|
+
response = await this.#searchDuckDuckGo(query, numResults);
|
|
1789
|
+
break;
|
|
1779
1790
|
}
|
|
1780
|
-
|
|
1781
|
-
const results = this.#parseResults(html, numResults);
|
|
1782
|
-
if (results.length === 0) {
|
|
1791
|
+
if (response.results.length === 0) {
|
|
1783
1792
|
return {
|
|
1784
1793
|
success: true,
|
|
1785
1794
|
output: "No results found.",
|
|
1786
1795
|
durationMs: performance.now() - start
|
|
1787
1796
|
};
|
|
1788
1797
|
}
|
|
1789
|
-
const
|
|
1790
|
-
|
|
1791
|
-
|
|
1798
|
+
const parts = [];
|
|
1799
|
+
if (response.aiAnswer) {
|
|
1800
|
+
parts.push(`AI Answer: ${response.aiAnswer}
|
|
1801
|
+
`);
|
|
1802
|
+
}
|
|
1803
|
+
for (let i = 0; i < response.results.length; i++) {
|
|
1804
|
+
const r = response.results[i];
|
|
1805
|
+
let line = `${i + 1}. ${r.title}
|
|
1806
|
+
URL: ${r.url}`;
|
|
1807
|
+
if (r.score !== void 0) {
|
|
1808
|
+
line += `
|
|
1809
|
+
Relevance: ${(r.score * 100).toFixed(0)}%`;
|
|
1810
|
+
}
|
|
1811
|
+
if (r.snippet) {
|
|
1812
|
+
line += `
|
|
1813
|
+
${r.snippet}`;
|
|
1814
|
+
}
|
|
1815
|
+
parts.push(line);
|
|
1816
|
+
}
|
|
1817
|
+
const providerTag = provider !== "duckduckgo" ? ` [${provider}]` : "";
|
|
1792
1818
|
return {
|
|
1793
1819
|
success: true,
|
|
1794
|
-
output:
|
|
1820
|
+
output: parts.join("\n\n") + providerTag,
|
|
1795
1821
|
durationMs: performance.now() - start
|
|
1796
1822
|
};
|
|
1797
1823
|
} catch (error) {
|
|
1824
|
+
if (provider !== "duckduckgo") {
|
|
1825
|
+
try {
|
|
1826
|
+
const fallback = await this.#searchDuckDuckGo(query, numResults);
|
|
1827
|
+
if (fallback.results.length > 0) {
|
|
1828
|
+
const formatted = fallback.results.map((r, i) => `${i + 1}. ${r.title}
|
|
1829
|
+
URL: ${r.url}
|
|
1830
|
+
${r.snippet}`).join("\n\n");
|
|
1831
|
+
return {
|
|
1832
|
+
success: true,
|
|
1833
|
+
output: `[${provider} failed, fell back to DuckDuckGo]
|
|
1834
|
+
|
|
1835
|
+
${formatted}`,
|
|
1836
|
+
durationMs: performance.now() - start
|
|
1837
|
+
};
|
|
1838
|
+
}
|
|
1839
|
+
} catch {
|
|
1840
|
+
}
|
|
1841
|
+
}
|
|
1798
1842
|
return {
|
|
1799
1843
|
success: false,
|
|
1800
1844
|
output: "",
|
|
@@ -1803,7 +1847,109 @@ var init_web_search = __esm({
|
|
|
1803
1847
|
};
|
|
1804
1848
|
}
|
|
1805
1849
|
}
|
|
1806
|
-
|
|
1850
|
+
// -------------------------------------------------------------------------
|
|
1851
|
+
// Tavily provider — structured JSON search API
|
|
1852
|
+
// -------------------------------------------------------------------------
|
|
1853
|
+
async #searchTavily(query, numResults) {
|
|
1854
|
+
const apiKey = process.env["TAVILY_API_KEY"];
|
|
1855
|
+
if (!apiKey) {
|
|
1856
|
+
throw new Error("TAVILY_API_KEY not set. Set the env var or use provider=duckduckgo.");
|
|
1857
|
+
}
|
|
1858
|
+
const body = {
|
|
1859
|
+
query,
|
|
1860
|
+
max_results: numResults,
|
|
1861
|
+
include_answer: true,
|
|
1862
|
+
search_depth: "basic"
|
|
1863
|
+
};
|
|
1864
|
+
const resp = await fetch(TAVILY_API_URL, {
|
|
1865
|
+
method: "POST",
|
|
1866
|
+
headers: {
|
|
1867
|
+
"Content-Type": "application/json",
|
|
1868
|
+
Authorization: `Bearer ${apiKey}`
|
|
1869
|
+
},
|
|
1870
|
+
body: JSON.stringify(body),
|
|
1871
|
+
signal: AbortSignal.timeout(2e4)
|
|
1872
|
+
});
|
|
1873
|
+
if (!resp.ok) {
|
|
1874
|
+
throw new Error(`Tavily HTTP ${resp.status} ${resp.statusText}`);
|
|
1875
|
+
}
|
|
1876
|
+
const data = await resp.json();
|
|
1877
|
+
const results = (data.results ?? []).map((r) => ({
|
|
1878
|
+
title: r.title ?? "",
|
|
1879
|
+
url: r.url ?? "",
|
|
1880
|
+
snippet: r.content ?? "",
|
|
1881
|
+
score: r.score
|
|
1882
|
+
}));
|
|
1883
|
+
return {
|
|
1884
|
+
provider: "tavily",
|
|
1885
|
+
query,
|
|
1886
|
+
results,
|
|
1887
|
+
aiAnswer: data.answer
|
|
1888
|
+
};
|
|
1889
|
+
}
|
|
1890
|
+
// -------------------------------------------------------------------------
|
|
1891
|
+
// Jina AI provider — markdown-formatted search
|
|
1892
|
+
// -------------------------------------------------------------------------
|
|
1893
|
+
async #searchJina(query, numResults) {
|
|
1894
|
+
const apiKey = process.env["JINA_API_KEY"];
|
|
1895
|
+
if (!apiKey) {
|
|
1896
|
+
throw new Error("JINA_API_KEY not set. Set the env var or use provider=duckduckgo.");
|
|
1897
|
+
}
|
|
1898
|
+
const searchUrl = `${JINA_SEARCH_URL}${encodeURIComponent(query)}`;
|
|
1899
|
+
const headers = {
|
|
1900
|
+
Accept: "application/json",
|
|
1901
|
+
Authorization: `Bearer ${apiKey}`,
|
|
1902
|
+
"X-Retain-Images": "none"
|
|
1903
|
+
};
|
|
1904
|
+
const resp = await fetch(searchUrl, {
|
|
1905
|
+
method: "GET",
|
|
1906
|
+
headers,
|
|
1907
|
+
signal: AbortSignal.timeout(2e4)
|
|
1908
|
+
});
|
|
1909
|
+
if (!resp.ok) {
|
|
1910
|
+
throw new Error(`Jina HTTP ${resp.status} ${resp.statusText}`);
|
|
1911
|
+
}
|
|
1912
|
+
const data = await resp.json();
|
|
1913
|
+
const items = data.data ?? [];
|
|
1914
|
+
const results = items.slice(0, numResults).map((r) => ({
|
|
1915
|
+
title: r.title ?? "",
|
|
1916
|
+
url: r.url ?? "",
|
|
1917
|
+
snippet: r.description ?? r.content ?? ""
|
|
1918
|
+
}));
|
|
1919
|
+
return {
|
|
1920
|
+
provider: "jina",
|
|
1921
|
+
query,
|
|
1922
|
+
results
|
|
1923
|
+
};
|
|
1924
|
+
}
|
|
1925
|
+
// -------------------------------------------------------------------------
|
|
1926
|
+
// DuckDuckGo provider — free HTML scraping fallback
|
|
1927
|
+
// -------------------------------------------------------------------------
|
|
1928
|
+
async #searchDuckDuckGo(query, numResults) {
|
|
1929
|
+
const searchUrl = `${DUCKDUCKGO_HTML_URL}?q=${encodeURIComponent(query)}`;
|
|
1930
|
+
const response = await fetch(searchUrl, {
|
|
1931
|
+
method: "GET",
|
|
1932
|
+
headers: {
|
|
1933
|
+
"User-Agent": "Mozilla/5.0 (compatible; open-coding-agent/1.0; +https://github.com/open-agents)",
|
|
1934
|
+
Accept: "text/html"
|
|
1935
|
+
},
|
|
1936
|
+
signal: AbortSignal.timeout(15e3)
|
|
1937
|
+
});
|
|
1938
|
+
if (!response.ok) {
|
|
1939
|
+
throw new Error(`HTTP ${response.status} ${response.statusText} from DuckDuckGo`);
|
|
1940
|
+
}
|
|
1941
|
+
const html = await response.text();
|
|
1942
|
+
const results = this.#parseDDGResults(html, numResults);
|
|
1943
|
+
return {
|
|
1944
|
+
provider: "duckduckgo",
|
|
1945
|
+
query,
|
|
1946
|
+
results
|
|
1947
|
+
};
|
|
1948
|
+
}
|
|
1949
|
+
// -------------------------------------------------------------------------
|
|
1950
|
+
// DuckDuckGo HTML parsing (unchanged from original)
|
|
1951
|
+
// -------------------------------------------------------------------------
|
|
1952
|
+
#parseDDGResults(html, limit) {
|
|
1807
1953
|
const results = [];
|
|
1808
1954
|
const resultBlockRegex = /<div[^>]+class="[^"]*result[^"]*"[^>]*>([\s\S]*?)<\/div>\s*<\/div>/gi;
|
|
1809
1955
|
let blockMatch;
|
|
@@ -3862,12 +4008,12 @@ var init_image = __esm({
|
|
|
3862
4008
|
if (!existsSync7(fullPath)) {
|
|
3863
4009
|
return { success: false, output: "", error: `File not found: ${rawPath}`, durationMs: Date.now() - start };
|
|
3864
4010
|
}
|
|
3865
|
-
const
|
|
3866
|
-
if (
|
|
4011
|
+
const stat5 = statSync4(fullPath);
|
|
4012
|
+
if (stat5.size > maxSizeKb * 1024) {
|
|
3867
4013
|
return {
|
|
3868
4014
|
success: false,
|
|
3869
4015
|
output: "",
|
|
3870
|
-
error: `File too large: ${(
|
|
4016
|
+
error: `File too large: ${(stat5.size / 1024).toFixed(0)}KB (max: ${maxSizeKb}KB)`,
|
|
3871
4017
|
durationMs: Date.now() - start
|
|
3872
4018
|
};
|
|
3873
4019
|
}
|
|
@@ -3877,7 +4023,7 @@ var init_image = __esm({
|
|
|
3877
4023
|
const base64 = imageToBase64(fullPath);
|
|
3878
4024
|
const mime = getMimeType(fullPath);
|
|
3879
4025
|
const dims = getImageDimensions(fullPath);
|
|
3880
|
-
const sizeKb = (
|
|
4026
|
+
const sizeKb = (stat5.size / 1024).toFixed(1);
|
|
3881
4027
|
const parts = [
|
|
3882
4028
|
`File: ${basename(fullPath)}`,
|
|
3883
4029
|
`Size: ${sizeKb}KB`,
|
|
@@ -3955,12 +4101,12 @@ ${ocrText}`);
|
|
|
3955
4101
|
if (!existsSync7(outputPath)) {
|
|
3956
4102
|
return { success: false, output: "", error: "Screenshot file not created", durationMs: Date.now() - start };
|
|
3957
4103
|
}
|
|
3958
|
-
const
|
|
4104
|
+
const stat5 = statSync4(outputPath);
|
|
3959
4105
|
const base64 = imageToBase64(outputPath);
|
|
3960
4106
|
const dims = getImageDimensions(outputPath);
|
|
3961
4107
|
const parts = [
|
|
3962
4108
|
`Screenshot saved: ${outputPath}`,
|
|
3963
|
-
`Size: ${(
|
|
4109
|
+
`Size: ${(stat5.size / 1024).toFixed(1)}KB`
|
|
3964
4110
|
];
|
|
3965
4111
|
if (dims)
|
|
3966
4112
|
parts.push(`Dimensions: ${dims.width}x${dims.height}`);
|
|
@@ -4265,7 +4411,7 @@ var init_custom_tool = __esm({
|
|
|
4265
4411
|
}
|
|
4266
4412
|
/** Execute a single shell command and return output */
|
|
4267
4413
|
runCommand(command) {
|
|
4268
|
-
return new Promise((
|
|
4414
|
+
return new Promise((resolve18) => {
|
|
4269
4415
|
const child = spawn3("bash", ["-c", command], {
|
|
4270
4416
|
cwd: this.workingDir,
|
|
4271
4417
|
env: { ...process.env, CI: "true", NO_COLOR: "1" },
|
|
@@ -4290,11 +4436,11 @@ var init_custom_tool = __esm({
|
|
|
4290
4436
|
child.kill("SIGTERM");
|
|
4291
4437
|
} catch {
|
|
4292
4438
|
}
|
|
4293
|
-
|
|
4439
|
+
resolve18({ success: false, output: stdout, error: "Command timed out after 60s" });
|
|
4294
4440
|
}, 6e4);
|
|
4295
4441
|
child.on("close", (code) => {
|
|
4296
4442
|
clearTimeout(timer);
|
|
4297
|
-
|
|
4443
|
+
resolve18({
|
|
4298
4444
|
success: code === 0,
|
|
4299
4445
|
output: stdout + (stderr && code === 0 ? `
|
|
4300
4446
|
STDERR:
|
|
@@ -4304,7 +4450,7 @@ ${stderr}` : ""),
|
|
|
4304
4450
|
});
|
|
4305
4451
|
child.on("error", (err) => {
|
|
4306
4452
|
clearTimeout(timer);
|
|
4307
|
-
|
|
4453
|
+
resolve18({ success: false, output: stdout, error: err.message });
|
|
4308
4454
|
});
|
|
4309
4455
|
});
|
|
4310
4456
|
}
|
|
@@ -5240,7 +5386,775 @@ ${result.output}`,
|
|
|
5240
5386
|
return {
|
|
5241
5387
|
success: false,
|
|
5242
5388
|
output: "",
|
|
5243
|
-
error: `Failed to download/transcribe: ${err instanceof Error ? err.message : String(err)}`,
|
|
5389
|
+
error: `Failed to download/transcribe: ${err instanceof Error ? err.message : String(err)}`,
|
|
5390
|
+
durationMs: performance.now() - start
|
|
5391
|
+
};
|
|
5392
|
+
}
|
|
5393
|
+
}
|
|
5394
|
+
};
|
|
5395
|
+
}
|
|
5396
|
+
});
|
|
5397
|
+
|
|
5398
|
+
// packages/execution/dist/tools/structured-file.js
|
|
5399
|
+
import { writeFile as writeFile6, mkdir as mkdir3 } from "node:fs/promises";
|
|
5400
|
+
import { resolve as resolve13, dirname as dirname3, extname as extname4 } from "node:path";
|
|
5401
|
+
function jsonToCSV(data, separator = ",") {
|
|
5402
|
+
if (!Array.isArray(data) || data.length === 0)
|
|
5403
|
+
return "";
|
|
5404
|
+
const headers = Object.keys(data[0]);
|
|
5405
|
+
const esc = (val) => {
|
|
5406
|
+
const str = val === null || val === void 0 ? "" : String(val);
|
|
5407
|
+
if (str.includes(separator) || str.includes('"') || str.includes("\n")) {
|
|
5408
|
+
return `"${str.replace(/"/g, '""')}"`;
|
|
5409
|
+
}
|
|
5410
|
+
return str;
|
|
5411
|
+
};
|
|
5412
|
+
const lines = [
|
|
5413
|
+
headers.map((h) => esc(h)).join(separator),
|
|
5414
|
+
...data.map((row) => {
|
|
5415
|
+
const obj = row;
|
|
5416
|
+
return headers.map((h) => esc(obj[h])).join(separator);
|
|
5417
|
+
})
|
|
5418
|
+
];
|
|
5419
|
+
return lines.join("\n") + "\n";
|
|
5420
|
+
}
|
|
5421
|
+
function jsonToMarkdownTable(data) {
|
|
5422
|
+
if (!Array.isArray(data) || data.length === 0)
|
|
5423
|
+
return "";
|
|
5424
|
+
const headers = Object.keys(data[0]);
|
|
5425
|
+
const headerRow = `| ${headers.join(" | ")} |`;
|
|
5426
|
+
const sepRow = `| ${headers.map(() => "---").join(" | ")} |`;
|
|
5427
|
+
const dataRows = data.map((row) => {
|
|
5428
|
+
const obj = row;
|
|
5429
|
+
return `| ${headers.map((h) => String(obj[h] ?? "")).join(" | ")} |`;
|
|
5430
|
+
});
|
|
5431
|
+
return [headerRow, sepRow, ...dataRows].join("\n") + "\n";
|
|
5432
|
+
}
|
|
5433
|
+
var StructuredFileTool;
|
|
5434
|
+
var init_structured_file = __esm({
|
|
5435
|
+
"packages/execution/dist/tools/structured-file.js"() {
|
|
5436
|
+
"use strict";
|
|
5437
|
+
StructuredFileTool = class {
|
|
5438
|
+
name = "create_structured_file";
|
|
5439
|
+
description = "Create a structured file (CSV, JSON, Markdown table, or Excel-compatible) from data. Provide data as a JSON array of objects. Each object becomes a row, keys become columns.";
|
|
5440
|
+
parameters = {
|
|
5441
|
+
type: "object",
|
|
5442
|
+
properties: {
|
|
5443
|
+
path: {
|
|
5444
|
+
type: "string",
|
|
5445
|
+
description: "Output file path (extension determines format: .csv, .json, .md, .tsv, .xlsx)"
|
|
5446
|
+
},
|
|
5447
|
+
data: {
|
|
5448
|
+
type: "array",
|
|
5449
|
+
description: "Array of objects \u2014 each object is a row, keys are column headers",
|
|
5450
|
+
items: { type: "object" }
|
|
5451
|
+
},
|
|
5452
|
+
format: {
|
|
5453
|
+
type: "string",
|
|
5454
|
+
enum: ["csv", "json", "markdown", "tsv", "xlsx"],
|
|
5455
|
+
description: "Output format (auto-detected from file extension if omitted)"
|
|
5456
|
+
},
|
|
5457
|
+
title: {
|
|
5458
|
+
type: "string",
|
|
5459
|
+
description: "Optional title/heading for markdown output"
|
|
5460
|
+
},
|
|
5461
|
+
sheets: {
|
|
5462
|
+
type: "array",
|
|
5463
|
+
description: "For multi-sheet xlsx: array of {name, data} objects",
|
|
5464
|
+
items: {
|
|
5465
|
+
type: "object",
|
|
5466
|
+
properties: {
|
|
5467
|
+
name: { type: "string" },
|
|
5468
|
+
data: { type: "array", items: { type: "object" } }
|
|
5469
|
+
}
|
|
5470
|
+
}
|
|
5471
|
+
}
|
|
5472
|
+
},
|
|
5473
|
+
required: ["path"]
|
|
5474
|
+
};
|
|
5475
|
+
workingDir;
|
|
5476
|
+
constructor(workingDir) {
|
|
5477
|
+
this.workingDir = workingDir;
|
|
5478
|
+
}
|
|
5479
|
+
async execute(args) {
|
|
5480
|
+
const filePath = args["path"];
|
|
5481
|
+
const data = args["data"] ?? [];
|
|
5482
|
+
const title = args["title"];
|
|
5483
|
+
const sheets = args["sheets"];
|
|
5484
|
+
const start = performance.now();
|
|
5485
|
+
if (!filePath) {
|
|
5486
|
+
return { success: false, output: "", error: "path is required", durationMs: 0 };
|
|
5487
|
+
}
|
|
5488
|
+
const ext = extname4(filePath).toLowerCase();
|
|
5489
|
+
let format = args["format"] ?? "";
|
|
5490
|
+
if (!format) {
|
|
5491
|
+
switch (ext) {
|
|
5492
|
+
case ".csv":
|
|
5493
|
+
format = "csv";
|
|
5494
|
+
break;
|
|
5495
|
+
case ".tsv":
|
|
5496
|
+
format = "tsv";
|
|
5497
|
+
break;
|
|
5498
|
+
case ".json":
|
|
5499
|
+
format = "json";
|
|
5500
|
+
break;
|
|
5501
|
+
case ".md":
|
|
5502
|
+
case ".markdown":
|
|
5503
|
+
format = "markdown";
|
|
5504
|
+
break;
|
|
5505
|
+
case ".xlsx":
|
|
5506
|
+
case ".xls":
|
|
5507
|
+
format = "xlsx";
|
|
5508
|
+
break;
|
|
5509
|
+
default:
|
|
5510
|
+
format = "csv";
|
|
5511
|
+
}
|
|
5512
|
+
}
|
|
5513
|
+
try {
|
|
5514
|
+
const fullPath = resolve13(this.workingDir, filePath);
|
|
5515
|
+
await mkdir3(dirname3(fullPath), { recursive: true });
|
|
5516
|
+
let content;
|
|
5517
|
+
let byteInfo = "";
|
|
5518
|
+
switch (format) {
|
|
5519
|
+
case "csv":
|
|
5520
|
+
content = jsonToCSV(data, ",");
|
|
5521
|
+
byteInfo = `${data.length} rows`;
|
|
5522
|
+
break;
|
|
5523
|
+
case "tsv":
|
|
5524
|
+
case "xlsx":
|
|
5525
|
+
content = jsonToCSV(data, " ");
|
|
5526
|
+
byteInfo = `${data.length} rows (tab-separated)`;
|
|
5527
|
+
break;
|
|
5528
|
+
case "json":
|
|
5529
|
+
content = JSON.stringify(data, null, 2) + "\n";
|
|
5530
|
+
byteInfo = `${data.length} items`;
|
|
5531
|
+
break;
|
|
5532
|
+
case "markdown": {
|
|
5533
|
+
const parts = [];
|
|
5534
|
+
if (title)
|
|
5535
|
+
parts.push(`# ${title}
|
|
5536
|
+
`);
|
|
5537
|
+
if (sheets && sheets.length > 0) {
|
|
5538
|
+
for (const sheet of sheets) {
|
|
5539
|
+
parts.push(`## ${sheet.name}
|
|
5540
|
+
`);
|
|
5541
|
+
parts.push(jsonToMarkdownTable(sheet.data));
|
|
5542
|
+
parts.push("");
|
|
5543
|
+
}
|
|
5544
|
+
} else if (data.length > 0) {
|
|
5545
|
+
parts.push(jsonToMarkdownTable(data));
|
|
5546
|
+
}
|
|
5547
|
+
content = parts.join("\n");
|
|
5548
|
+
byteInfo = sheets ? `${sheets.length} sections, ${sheets.reduce((s, sh) => s + sh.data.length, 0)} total rows` : `${data.length} rows`;
|
|
5549
|
+
break;
|
|
5550
|
+
}
|
|
5551
|
+
default:
|
|
5552
|
+
return {
|
|
5553
|
+
success: false,
|
|
5554
|
+
output: "",
|
|
5555
|
+
error: `Unknown format: ${format}. Use csv, json, markdown, tsv, or xlsx.`,
|
|
5556
|
+
durationMs: performance.now() - start
|
|
5557
|
+
};
|
|
5558
|
+
}
|
|
5559
|
+
await writeFile6(fullPath, content, "utf-8");
|
|
5560
|
+
return {
|
|
5561
|
+
success: true,
|
|
5562
|
+
output: `Created ${format.toUpperCase()} file: ${fullPath} (${byteInfo}, ${content.length} bytes)`,
|
|
5563
|
+
durationMs: performance.now() - start
|
|
5564
|
+
};
|
|
5565
|
+
} catch (error) {
|
|
5566
|
+
return {
|
|
5567
|
+
success: false,
|
|
5568
|
+
output: "",
|
|
5569
|
+
error: error instanceof Error ? error.message : String(error),
|
|
5570
|
+
durationMs: performance.now() - start
|
|
5571
|
+
};
|
|
5572
|
+
}
|
|
5573
|
+
}
|
|
5574
|
+
};
|
|
5575
|
+
}
|
|
5576
|
+
});
|
|
5577
|
+
|
|
5578
|
+
// packages/execution/dist/tools/code-sandbox.js
|
|
5579
|
+
import { spawn as spawn5 } from "node:child_process";
|
|
5580
|
+
import { writeFile as writeFile7, mkdtemp, rm, readdir, stat } from "node:fs/promises";
|
|
5581
|
+
import { join as join14 } from "node:path";
|
|
5582
|
+
import { tmpdir as tmpdir2 } from "node:os";
|
|
5583
|
+
function runProcess(cmd, args, options) {
|
|
5584
|
+
return new Promise((resolve18) => {
|
|
5585
|
+
const proc = spawn5(cmd, args, {
|
|
5586
|
+
cwd: options.cwd,
|
|
5587
|
+
timeout: options.timeout,
|
|
5588
|
+
env: {
|
|
5589
|
+
PATH: process.env["PATH"] ?? "/usr/bin:/bin",
|
|
5590
|
+
HOME: options.cwd,
|
|
5591
|
+
TMPDIR: options.cwd,
|
|
5592
|
+
NODE_ENV: "sandbox",
|
|
5593
|
+
...options.env ?? {}
|
|
5594
|
+
},
|
|
5595
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
5596
|
+
});
|
|
5597
|
+
let stdout = "";
|
|
5598
|
+
let stderr = "";
|
|
5599
|
+
let timedOut = false;
|
|
5600
|
+
proc.stdout.on("data", (d) => {
|
|
5601
|
+
stdout += d.toString();
|
|
5602
|
+
if (stdout.length > 1e5) {
|
|
5603
|
+
stdout = stdout.slice(0, 1e5) + "\n[output truncated at 100KB]";
|
|
5604
|
+
proc.kill("SIGKILL");
|
|
5605
|
+
}
|
|
5606
|
+
});
|
|
5607
|
+
proc.stderr.on("data", (d) => {
|
|
5608
|
+
stderr += d.toString();
|
|
5609
|
+
if (stderr.length > 5e4) {
|
|
5610
|
+
stderr = stderr.slice(0, 5e4) + "\n[stderr truncated at 50KB]";
|
|
5611
|
+
}
|
|
5612
|
+
});
|
|
5613
|
+
proc.on("error", (err) => {
|
|
5614
|
+
resolve18({
|
|
5615
|
+
stdout,
|
|
5616
|
+
stderr: stderr || err.message,
|
|
5617
|
+
exitCode: 1,
|
|
5618
|
+
filesCreated: [],
|
|
5619
|
+
timedOut: false
|
|
5620
|
+
});
|
|
5621
|
+
});
|
|
5622
|
+
proc.on("close", (code, signal) => {
|
|
5623
|
+
if (signal === "SIGTERM" || signal === "SIGKILL") {
|
|
5624
|
+
timedOut = true;
|
|
5625
|
+
}
|
|
5626
|
+
resolve18({
|
|
5627
|
+
stdout,
|
|
5628
|
+
stderr,
|
|
5629
|
+
exitCode: code ?? (timedOut ? 124 : 1),
|
|
5630
|
+
filesCreated: [],
|
|
5631
|
+
timedOut
|
|
5632
|
+
});
|
|
5633
|
+
});
|
|
5634
|
+
if (options.stdin) {
|
|
5635
|
+
proc.stdin.write(options.stdin);
|
|
5636
|
+
}
|
|
5637
|
+
proc.stdin.end();
|
|
5638
|
+
});
|
|
5639
|
+
}
|
|
5640
|
+
async function listCreatedFiles(dir) {
|
|
5641
|
+
const files = [];
|
|
5642
|
+
try {
|
|
5643
|
+
const entries = await readdir(dir);
|
|
5644
|
+
for (const entry of entries) {
|
|
5645
|
+
if (entry.startsWith("_sandbox_script"))
|
|
5646
|
+
continue;
|
|
5647
|
+
const fullPath = join14(dir, entry);
|
|
5648
|
+
const s = await stat(fullPath);
|
|
5649
|
+
if (s.isFile()) {
|
|
5650
|
+
files.push(entry);
|
|
5651
|
+
}
|
|
5652
|
+
}
|
|
5653
|
+
} catch {
|
|
5654
|
+
}
|
|
5655
|
+
return files;
|
|
5656
|
+
}
|
|
5657
|
+
var LANGUAGE_CONFIG, CodeSandboxTool;
|
|
5658
|
+
var init_code_sandbox = __esm({
|
|
5659
|
+
"packages/execution/dist/tools/code-sandbox.js"() {
|
|
5660
|
+
"use strict";
|
|
5661
|
+
LANGUAGE_CONFIG = {
|
|
5662
|
+
javascript: { ext: ".js", cmd: "node", args: (f) => [f] },
|
|
5663
|
+
python: { ext: ".py", cmd: "python3", args: (f) => [f] },
|
|
5664
|
+
bash: { ext: ".sh", cmd: "bash", args: (f) => [f] },
|
|
5665
|
+
typescript: { ext: ".ts", cmd: "npx", args: (f) => ["tsx", f] }
|
|
5666
|
+
};
|
|
5667
|
+
CodeSandboxTool = class {
|
|
5668
|
+
name = "code_sandbox";
|
|
5669
|
+
description = "Execute code in an isolated sandbox environment. Safer than shell for running generated or untrusted code. Supports JavaScript, Python, Bash, and TypeScript. Returns stdout, stderr, exit code, and any files created.";
|
|
5670
|
+
parameters = {
|
|
5671
|
+
type: "object",
|
|
5672
|
+
properties: {
|
|
5673
|
+
code: {
|
|
5674
|
+
type: "string",
|
|
5675
|
+
description: "The code to execute"
|
|
5676
|
+
},
|
|
5677
|
+
language: {
|
|
5678
|
+
type: "string",
|
|
5679
|
+
enum: ["javascript", "python", "bash", "typescript"],
|
|
5680
|
+
description: "Programming language (default: javascript)"
|
|
5681
|
+
},
|
|
5682
|
+
timeout_ms: {
|
|
5683
|
+
type: "number",
|
|
5684
|
+
description: "Execution timeout in milliseconds (default: 30000, max: 120000)"
|
|
5685
|
+
},
|
|
5686
|
+
stdin: {
|
|
5687
|
+
type: "string",
|
|
5688
|
+
description: "Optional input to pass to stdin"
|
|
5689
|
+
},
|
|
5690
|
+
mode: {
|
|
5691
|
+
type: "string",
|
|
5692
|
+
enum: ["subprocess", "docker"],
|
|
5693
|
+
description: "Execution mode. subprocess (default): isolated process. docker: Docker container (requires Docker installed)."
|
|
5694
|
+
}
|
|
5695
|
+
},
|
|
5696
|
+
required: ["code"]
|
|
5697
|
+
};
|
|
5698
|
+
workingDir;
|
|
5699
|
+
constructor(workingDir) {
|
|
5700
|
+
this.workingDir = workingDir;
|
|
5701
|
+
}
|
|
5702
|
+
async execute(args) {
|
|
5703
|
+
const code = args["code"];
|
|
5704
|
+
const language = args["language"] ?? "javascript";
|
|
5705
|
+
const timeoutMs = Math.min(args["timeout_ms"] ?? 3e4, 12e4);
|
|
5706
|
+
const stdin = args["stdin"];
|
|
5707
|
+
const mode = args["mode"] ?? "subprocess";
|
|
5708
|
+
const start = performance.now();
|
|
5709
|
+
if (!code) {
|
|
5710
|
+
return { success: false, output: "", error: "code is required", durationMs: 0 };
|
|
5711
|
+
}
|
|
5712
|
+
const langConfig = LANGUAGE_CONFIG[language];
|
|
5713
|
+
if (!langConfig) {
|
|
5714
|
+
return {
|
|
5715
|
+
success: false,
|
|
5716
|
+
output: "",
|
|
5717
|
+
error: `Unsupported language: ${language}. Use javascript, python, bash, or typescript.`,
|
|
5718
|
+
durationMs: performance.now() - start
|
|
5719
|
+
};
|
|
5720
|
+
}
|
|
5721
|
+
try {
|
|
5722
|
+
let result;
|
|
5723
|
+
if (mode === "docker") {
|
|
5724
|
+
result = await this.#runDocker(code, language, langConfig, timeoutMs, stdin);
|
|
5725
|
+
} else {
|
|
5726
|
+
result = await this.#runSubprocess(code, langConfig, timeoutMs, stdin);
|
|
5727
|
+
}
|
|
5728
|
+
const parts = [];
|
|
5729
|
+
if (result.stdout) {
|
|
5730
|
+
parts.push(result.stdout.trimEnd());
|
|
5731
|
+
}
|
|
5732
|
+
if (result.stderr) {
|
|
5733
|
+
parts.push(`
|
|
5734
|
+
--- stderr ---
|
|
5735
|
+
${result.stderr.trimEnd()}`);
|
|
5736
|
+
}
|
|
5737
|
+
if (result.timedOut) {
|
|
5738
|
+
parts.push(`
|
|
5739
|
+
[Execution timed out after ${timeoutMs}ms]`);
|
|
5740
|
+
}
|
|
5741
|
+
if (result.filesCreated.length > 0) {
|
|
5742
|
+
parts.push(`
|
|
5743
|
+
--- files created ---
|
|
5744
|
+
${result.filesCreated.join("\n")}`);
|
|
5745
|
+
}
|
|
5746
|
+
parts.push(`
|
|
5747
|
+
[exit code: ${result.exitCode}]`);
|
|
5748
|
+
return {
|
|
5749
|
+
success: result.exitCode === 0,
|
|
5750
|
+
output: parts.join(""),
|
|
5751
|
+
error: result.exitCode !== 0 ? `Process exited with code ${result.exitCode}${result.timedOut ? " (timeout)" : ""}` : void 0,
|
|
5752
|
+
durationMs: performance.now() - start
|
|
5753
|
+
};
|
|
5754
|
+
} catch (error) {
|
|
5755
|
+
return {
|
|
5756
|
+
success: false,
|
|
5757
|
+
output: "",
|
|
5758
|
+
error: error instanceof Error ? error.message : String(error),
|
|
5759
|
+
durationMs: performance.now() - start
|
|
5760
|
+
};
|
|
5761
|
+
}
|
|
5762
|
+
}
|
|
5763
|
+
// -------------------------------------------------------------------------
|
|
5764
|
+
// Subprocess mode — temp directory + separate process
|
|
5765
|
+
// -------------------------------------------------------------------------
|
|
5766
|
+
async #runSubprocess(code, langConfig, timeoutMs, stdin) {
|
|
5767
|
+
const sandboxDir = await mkdtemp(join14(tmpdir2(), "oa-sandbox-"));
|
|
5768
|
+
try {
|
|
5769
|
+
const scriptFile = join14(sandboxDir, `_sandbox_script${langConfig.ext}`);
|
|
5770
|
+
await writeFile7(scriptFile, code, "utf-8");
|
|
5771
|
+
const result = await runProcess(langConfig.cmd, langConfig.args(scriptFile), {
|
|
5772
|
+
cwd: sandboxDir,
|
|
5773
|
+
timeout: timeoutMs,
|
|
5774
|
+
stdin
|
|
5775
|
+
});
|
|
5776
|
+
result.filesCreated = await listCreatedFiles(sandboxDir);
|
|
5777
|
+
return result;
|
|
5778
|
+
} finally {
|
|
5779
|
+
await rm(sandboxDir, { recursive: true, force: true }).catch(() => {
|
|
5780
|
+
});
|
|
5781
|
+
}
|
|
5782
|
+
}
|
|
5783
|
+
// -------------------------------------------------------------------------
|
|
5784
|
+
// Docker mode — run in container
|
|
5785
|
+
// -------------------------------------------------------------------------
|
|
5786
|
+
async #runDocker(code, language, langConfig, timeoutMs, stdin) {
|
|
5787
|
+
const images = {
|
|
5788
|
+
javascript: "node:22-slim",
|
|
5789
|
+
typescript: "node:22-slim",
|
|
5790
|
+
python: "python:3.12-slim",
|
|
5791
|
+
bash: "bash:5"
|
|
5792
|
+
};
|
|
5793
|
+
const image = images[language] ?? "node:22-slim";
|
|
5794
|
+
const sandboxDir = await mkdtemp(join14(tmpdir2(), "oa-docker-sandbox-"));
|
|
5795
|
+
try {
|
|
5796
|
+
const scriptFile = `_sandbox_script${langConfig.ext}`;
|
|
5797
|
+
await writeFile7(join14(sandboxDir, scriptFile), code, "utf-8");
|
|
5798
|
+
const dockerArgs = [
|
|
5799
|
+
"run",
|
|
5800
|
+
"--rm",
|
|
5801
|
+
"--network=none",
|
|
5802
|
+
// No network access
|
|
5803
|
+
"--memory=256m",
|
|
5804
|
+
// Memory limit
|
|
5805
|
+
"--cpus=1",
|
|
5806
|
+
// CPU limit
|
|
5807
|
+
"-v",
|
|
5808
|
+
`${sandboxDir}:/sandbox:rw`,
|
|
5809
|
+
"-w",
|
|
5810
|
+
"/sandbox",
|
|
5811
|
+
image,
|
|
5812
|
+
langConfig.cmd,
|
|
5813
|
+
...langConfig.args(`/sandbox/${scriptFile}`)
|
|
5814
|
+
];
|
|
5815
|
+
const result = await runProcess("docker", dockerArgs, {
|
|
5816
|
+
cwd: sandboxDir,
|
|
5817
|
+
timeout: timeoutMs,
|
|
5818
|
+
stdin
|
|
5819
|
+
});
|
|
5820
|
+
result.filesCreated = await listCreatedFiles(sandboxDir);
|
|
5821
|
+
return result;
|
|
5822
|
+
} finally {
|
|
5823
|
+
await rm(sandboxDir, { recursive: true, force: true }).catch(() => {
|
|
5824
|
+
});
|
|
5825
|
+
}
|
|
5826
|
+
}
|
|
5827
|
+
};
|
|
5828
|
+
}
|
|
5829
|
+
});
|
|
5830
|
+
|
|
5831
|
+
// packages/execution/dist/tools/structured-read.js
|
|
5832
|
+
import { readFile as readFile7, stat as stat2 } from "node:fs/promises";
|
|
5833
|
+
import { resolve as resolve14, extname as extname5 } from "node:path";
|
|
5834
|
+
function parseCSV(text, separator = ",") {
|
|
5835
|
+
const lines = text.split("\n").filter((l) => l.trim() !== "");
|
|
5836
|
+
if (lines.length < 2)
|
|
5837
|
+
return [];
|
|
5838
|
+
const parseLine = (line) => {
|
|
5839
|
+
const fields = [];
|
|
5840
|
+
let current = "";
|
|
5841
|
+
let inQuotes = false;
|
|
5842
|
+
for (let i = 0; i < line.length; i++) {
|
|
5843
|
+
const ch = line[i];
|
|
5844
|
+
if (inQuotes) {
|
|
5845
|
+
if (ch === '"' && line[i + 1] === '"') {
|
|
5846
|
+
current += '"';
|
|
5847
|
+
i++;
|
|
5848
|
+
} else if (ch === '"') {
|
|
5849
|
+
inQuotes = false;
|
|
5850
|
+
} else {
|
|
5851
|
+
current += ch;
|
|
5852
|
+
}
|
|
5853
|
+
} else {
|
|
5854
|
+
if (ch === '"') {
|
|
5855
|
+
inQuotes = true;
|
|
5856
|
+
} else if (ch === separator) {
|
|
5857
|
+
fields.push(current);
|
|
5858
|
+
current = "";
|
|
5859
|
+
} else {
|
|
5860
|
+
current += ch;
|
|
5861
|
+
}
|
|
5862
|
+
}
|
|
5863
|
+
}
|
|
5864
|
+
fields.push(current);
|
|
5865
|
+
return fields;
|
|
5866
|
+
};
|
|
5867
|
+
const headers = parseLine(lines[0]).map((h) => h.trim());
|
|
5868
|
+
const rows = [];
|
|
5869
|
+
for (let i = 1; i < lines.length; i++) {
|
|
5870
|
+
const values = parseLine(lines[i]);
|
|
5871
|
+
const row = {};
|
|
5872
|
+
for (let j = 0; j < headers.length; j++) {
|
|
5873
|
+
row[headers[j]] = (values[j] ?? "").trim();
|
|
5874
|
+
}
|
|
5875
|
+
rows.push(row);
|
|
5876
|
+
}
|
|
5877
|
+
return rows;
|
|
5878
|
+
}
|
|
5879
|
+
function parseMarkdownTables(text) {
|
|
5880
|
+
const tables = [];
|
|
5881
|
+
const lines = text.split("\n");
|
|
5882
|
+
let i = 0;
|
|
5883
|
+
while (i < lines.length) {
|
|
5884
|
+
const line = lines[i].trim();
|
|
5885
|
+
if (line.startsWith("|") && line.endsWith("|")) {
|
|
5886
|
+
const nextLine = (lines[i + 1] ?? "").trim();
|
|
5887
|
+
if (nextLine.startsWith("|") && /^\|[\s-:|]+\|$/.test(nextLine)) {
|
|
5888
|
+
let heading;
|
|
5889
|
+
for (let h = i - 1; h >= 0; h--) {
|
|
5890
|
+
const prev = lines[h].trim();
|
|
5891
|
+
if (prev === "")
|
|
5892
|
+
continue;
|
|
5893
|
+
if (prev.startsWith("#")) {
|
|
5894
|
+
heading = prev.replace(/^#+\s*/, "").trim();
|
|
5895
|
+
}
|
|
5896
|
+
break;
|
|
5897
|
+
}
|
|
5898
|
+
const headers = line.split("|").filter((c3) => c3.trim() !== "").map((c3) => c3.trim());
|
|
5899
|
+
const rows = [];
|
|
5900
|
+
i += 2;
|
|
5901
|
+
while (i < lines.length) {
|
|
5902
|
+
const dataLine = lines[i].trim();
|
|
5903
|
+
if (!dataLine.startsWith("|") || !dataLine.endsWith("|"))
|
|
5904
|
+
break;
|
|
5905
|
+
const values = dataLine.split("|").filter((c3) => c3.trim() !== "").map((c3) => c3.trim());
|
|
5906
|
+
const row = {};
|
|
5907
|
+
for (let j = 0; j < headers.length; j++) {
|
|
5908
|
+
row[headers[j]] = values[j] ?? "";
|
|
5909
|
+
}
|
|
5910
|
+
rows.push(row);
|
|
5911
|
+
i++;
|
|
5912
|
+
}
|
|
5913
|
+
if (rows.length > 0) {
|
|
5914
|
+
tables.push({ heading, rows });
|
|
5915
|
+
}
|
|
5916
|
+
continue;
|
|
5917
|
+
}
|
|
5918
|
+
}
|
|
5919
|
+
i++;
|
|
5920
|
+
}
|
|
5921
|
+
return tables;
|
|
5922
|
+
}
|
|
5923
|
+
function detectBinaryFormat(buffer) {
|
|
5924
|
+
if (buffer[0] === 80 && buffer[1] === 75) {
|
|
5925
|
+
const str = buffer.toString("utf-8", 0, Math.min(buffer.length, 2e3));
|
|
5926
|
+
if (str.includes("xl/") || str.includes("spreadsheetml"))
|
|
5927
|
+
return "xlsx";
|
|
5928
|
+
if (str.includes("word/") || str.includes("wordprocessingml"))
|
|
5929
|
+
return "docx";
|
|
5930
|
+
return "zip";
|
|
5931
|
+
}
|
|
5932
|
+
if (buffer[0] === 37 && buffer[1] === 80 && buffer[2] === 68 && buffer[3] === 70) {
|
|
5933
|
+
return "pdf";
|
|
5934
|
+
}
|
|
5935
|
+
return null;
|
|
5936
|
+
}
|
|
5937
|
+
var StructuredReadTool;
|
|
5938
|
+
var init_structured_read = __esm({
|
|
5939
|
+
"packages/execution/dist/tools/structured-read.js"() {
|
|
5940
|
+
"use strict";
|
|
5941
|
+
StructuredReadTool = class {
|
|
5942
|
+
name = "read_structured_file";
|
|
5943
|
+
description = "Read and parse a structured file (CSV, TSV, JSON, Markdown tables). Returns the file content as structured data the agent can work with. For binary formats (XLSX, PDF), detects the format and suggests tools.";
|
|
5944
|
+
parameters = {
|
|
5945
|
+
type: "object",
|
|
5946
|
+
properties: {
|
|
5947
|
+
path: {
|
|
5948
|
+
type: "string",
|
|
5949
|
+
description: "File path to read"
|
|
5950
|
+
},
|
|
5951
|
+
format: {
|
|
5952
|
+
type: "string",
|
|
5953
|
+
enum: ["csv", "tsv", "json", "markdown", "auto"],
|
|
5954
|
+
description: "File format (auto-detected from extension if omitted)"
|
|
5955
|
+
},
|
|
5956
|
+
max_rows: {
|
|
5957
|
+
type: "number",
|
|
5958
|
+
description: "Maximum rows to return (default: 100)"
|
|
5959
|
+
}
|
|
5960
|
+
},
|
|
5961
|
+
required: ["path"]
|
|
5962
|
+
};
|
|
5963
|
+
workingDir;
|
|
5964
|
+
constructor(workingDir) {
|
|
5965
|
+
this.workingDir = workingDir;
|
|
5966
|
+
}
|
|
5967
|
+
async execute(args) {
|
|
5968
|
+
const filePath = args["path"];
|
|
5969
|
+
const maxRows = args["max_rows"] ?? 100;
|
|
5970
|
+
const start = performance.now();
|
|
5971
|
+
if (!filePath) {
|
|
5972
|
+
return { success: false, output: "", error: "path is required", durationMs: 0 };
|
|
5973
|
+
}
|
|
5974
|
+
const fullPath = resolve14(this.workingDir, filePath);
|
|
5975
|
+
try {
|
|
5976
|
+
const fileStat = await stat2(fullPath);
|
|
5977
|
+
if (!fileStat.isFile()) {
|
|
5978
|
+
return {
|
|
5979
|
+
success: false,
|
|
5980
|
+
output: "",
|
|
5981
|
+
error: `Not a file: ${filePath}`,
|
|
5982
|
+
durationMs: performance.now() - start
|
|
5983
|
+
};
|
|
5984
|
+
}
|
|
5985
|
+
if (fileStat.size > 10 * 1024 * 1024) {
|
|
5986
|
+
return {
|
|
5987
|
+
success: false,
|
|
5988
|
+
output: "",
|
|
5989
|
+
error: `File too large (${(fileStat.size / 1024 / 1024).toFixed(1)}MB). Maximum is 10MB.`,
|
|
5990
|
+
durationMs: performance.now() - start
|
|
5991
|
+
};
|
|
5992
|
+
}
|
|
5993
|
+
const ext = extname5(filePath).toLowerCase();
|
|
5994
|
+
let format = args["format"] ?? "auto";
|
|
5995
|
+
if (format === "auto") {
|
|
5996
|
+
switch (ext) {
|
|
5997
|
+
case ".csv":
|
|
5998
|
+
format = "csv";
|
|
5999
|
+
break;
|
|
6000
|
+
case ".tsv":
|
|
6001
|
+
format = "tsv";
|
|
6002
|
+
break;
|
|
6003
|
+
case ".json":
|
|
6004
|
+
format = "json";
|
|
6005
|
+
break;
|
|
6006
|
+
case ".md":
|
|
6007
|
+
case ".markdown":
|
|
6008
|
+
format = "markdown";
|
|
6009
|
+
break;
|
|
6010
|
+
case ".xlsx":
|
|
6011
|
+
case ".xls":
|
|
6012
|
+
format = "xlsx";
|
|
6013
|
+
break;
|
|
6014
|
+
case ".pdf":
|
|
6015
|
+
format = "pdf";
|
|
6016
|
+
break;
|
|
6017
|
+
case ".docx":
|
|
6018
|
+
case ".doc":
|
|
6019
|
+
format = "docx";
|
|
6020
|
+
break;
|
|
6021
|
+
default:
|
|
6022
|
+
format = "auto";
|
|
6023
|
+
break;
|
|
6024
|
+
}
|
|
6025
|
+
}
|
|
6026
|
+
if (format === "xlsx" || format === "pdf" || format === "docx" || format === "auto") {
|
|
6027
|
+
const buffer = await readFile7(fullPath);
|
|
6028
|
+
const detected = detectBinaryFormat(buffer);
|
|
6029
|
+
if (detected === "xlsx") {
|
|
6030
|
+
return {
|
|
6031
|
+
success: true,
|
|
6032
|
+
output: `Detected Excel file (.xlsx), ${(fileStat.size / 1024).toFixed(1)}KB.
|
|
6033
|
+
To parse this file, use the shell tool to run:
|
|
6034
|
+
npx xlsx-cli "${filePath}" --json
|
|
6035
|
+
Or install exceljs for programmatic access.`,
|
|
6036
|
+
durationMs: performance.now() - start
|
|
6037
|
+
};
|
|
6038
|
+
}
|
|
6039
|
+
if (detected === "pdf") {
|
|
6040
|
+
return {
|
|
6041
|
+
success: true,
|
|
6042
|
+
output: `Detected PDF file, ${(fileStat.size / 1024).toFixed(1)}KB.
|
|
6043
|
+
To extract text, use the shell tool to run:
|
|
6044
|
+
pdftotext "${filePath}" -
|
|
6045
|
+
Or install pdf-parse for programmatic access.`,
|
|
6046
|
+
durationMs: performance.now() - start
|
|
6047
|
+
};
|
|
6048
|
+
}
|
|
6049
|
+
if (detected === "docx") {
|
|
6050
|
+
return {
|
|
6051
|
+
success: true,
|
|
6052
|
+
output: `Detected Word document (.docx), ${(fileStat.size / 1024).toFixed(1)}KB.
|
|
6053
|
+
To extract text, use the shell tool to run:
|
|
6054
|
+
pandoc "${filePath}" -t plain
|
|
6055
|
+
Or install mammoth for programmatic access.`,
|
|
6056
|
+
durationMs: performance.now() - start
|
|
6057
|
+
};
|
|
6058
|
+
}
|
|
6059
|
+
if (format === "auto") {
|
|
6060
|
+
const text2 = buffer.toString("utf-8");
|
|
6061
|
+
if (text2.trimStart().startsWith("{") || text2.trimStart().startsWith("[")) {
|
|
6062
|
+
format = "json";
|
|
6063
|
+
} else if (text2.includes(" ") && !text2.includes(",")) {
|
|
6064
|
+
format = "tsv";
|
|
6065
|
+
} else if (text2.includes("|") && /^\|[\s-:|]+\|$/m.test(text2)) {
|
|
6066
|
+
format = "markdown";
|
|
6067
|
+
} else {
|
|
6068
|
+
format = "csv";
|
|
6069
|
+
}
|
|
6070
|
+
}
|
|
6071
|
+
}
|
|
6072
|
+
const text = await readFile7(fullPath, "utf-8");
|
|
6073
|
+
switch (format) {
|
|
6074
|
+
case "csv": {
|
|
6075
|
+
const rows = parseCSV(text, ",");
|
|
6076
|
+
const limited = rows.slice(0, maxRows);
|
|
6077
|
+
const truncated = rows.length > maxRows ? `
|
|
6078
|
+
[showing ${maxRows} of ${rows.length} rows]` : "";
|
|
6079
|
+
return {
|
|
6080
|
+
success: true,
|
|
6081
|
+
output: `CSV: ${rows.length} rows, ${Object.keys(rows[0] ?? {}).length} columns
|
|
6082
|
+
${JSON.stringify(limited, null, 2)}${truncated}`,
|
|
6083
|
+
durationMs: performance.now() - start
|
|
6084
|
+
};
|
|
6085
|
+
}
|
|
6086
|
+
case "tsv": {
|
|
6087
|
+
const rows = parseCSV(text, " ");
|
|
6088
|
+
const limited = rows.slice(0, maxRows);
|
|
6089
|
+
const truncated = rows.length > maxRows ? `
|
|
6090
|
+
[showing ${maxRows} of ${rows.length} rows]` : "";
|
|
6091
|
+
return {
|
|
6092
|
+
success: true,
|
|
6093
|
+
output: `TSV: ${rows.length} rows, ${Object.keys(rows[0] ?? {}).length} columns
|
|
6094
|
+
${JSON.stringify(limited, null, 2)}${truncated}`,
|
|
6095
|
+
durationMs: performance.now() - start
|
|
6096
|
+
};
|
|
6097
|
+
}
|
|
6098
|
+
case "json": {
|
|
6099
|
+
const parsed = JSON.parse(text);
|
|
6100
|
+
const isArray = Array.isArray(parsed);
|
|
6101
|
+
const count = isArray ? parsed.length : Object.keys(parsed).length;
|
|
6102
|
+
let display;
|
|
6103
|
+
if (isArray && parsed.length > maxRows) {
|
|
6104
|
+
display = parsed.slice(0, maxRows);
|
|
6105
|
+
return {
|
|
6106
|
+
success: true,
|
|
6107
|
+
output: `JSON array: ${parsed.length} items
|
|
6108
|
+
${JSON.stringify(display, null, 2)}
|
|
6109
|
+
[showing ${maxRows} of ${parsed.length} items]`,
|
|
6110
|
+
durationMs: performance.now() - start
|
|
6111
|
+
};
|
|
6112
|
+
}
|
|
6113
|
+
return {
|
|
6114
|
+
success: true,
|
|
6115
|
+
output: `JSON ${isArray ? "array" : "object"}: ${count} ${isArray ? "items" : "keys"}
|
|
6116
|
+
${JSON.stringify(parsed, null, 2)}`,
|
|
6117
|
+
durationMs: performance.now() - start
|
|
6118
|
+
};
|
|
6119
|
+
}
|
|
6120
|
+
case "markdown": {
|
|
6121
|
+
const tables = parseMarkdownTables(text);
|
|
6122
|
+
if (tables.length === 0) {
|
|
6123
|
+
return {
|
|
6124
|
+
success: true,
|
|
6125
|
+
output: `Markdown file (no tables found). Content:
|
|
6126
|
+
${text.slice(0, 5e3)}${text.length > 5e3 ? "\n[truncated]" : ""}`,
|
|
6127
|
+
durationMs: performance.now() - start
|
|
6128
|
+
};
|
|
6129
|
+
}
|
|
6130
|
+
const parts = [];
|
|
6131
|
+
for (const table of tables) {
|
|
6132
|
+
const heading = table.heading ? `Table: ${table.heading}` : "Table";
|
|
6133
|
+
const limited = table.rows.slice(0, maxRows);
|
|
6134
|
+
parts.push(`${heading} (${table.rows.length} rows)
|
|
6135
|
+
${JSON.stringify(limited, null, 2)}`);
|
|
6136
|
+
}
|
|
6137
|
+
return {
|
|
6138
|
+
success: true,
|
|
6139
|
+
output: `Markdown: ${tables.length} table(s)
|
|
6140
|
+
|
|
6141
|
+
${parts.join("\n\n")}`,
|
|
6142
|
+
durationMs: performance.now() - start
|
|
6143
|
+
};
|
|
6144
|
+
}
|
|
6145
|
+
default:
|
|
6146
|
+
return {
|
|
6147
|
+
success: false,
|
|
6148
|
+
output: "",
|
|
6149
|
+
error: `Unsupported format: ${format}`,
|
|
6150
|
+
durationMs: performance.now() - start
|
|
6151
|
+
};
|
|
6152
|
+
}
|
|
6153
|
+
} catch (error) {
|
|
6154
|
+
return {
|
|
6155
|
+
success: false,
|
|
6156
|
+
output: "",
|
|
6157
|
+
error: error instanceof Error ? error.message : String(error),
|
|
5244
6158
|
durationMs: performance.now() - start
|
|
5245
6159
|
};
|
|
5246
6160
|
}
|
|
@@ -5353,6 +6267,9 @@ var init_dist2 = __esm({
|
|
|
5353
6267
|
init_tool_creator();
|
|
5354
6268
|
init_skill_tools();
|
|
5355
6269
|
init_transcribe_tool();
|
|
6270
|
+
init_structured_file();
|
|
6271
|
+
init_code_sandbox();
|
|
6272
|
+
init_structured_read();
|
|
5356
6273
|
init_shellRunner();
|
|
5357
6274
|
init_gitWorktree();
|
|
5358
6275
|
init_patchApplier();
|
|
@@ -6467,8 +7384,8 @@ var init_code_retriever = __esm({
|
|
|
6467
7384
|
});
|
|
6468
7385
|
}
|
|
6469
7386
|
async getFileContent(filePath, startLine, endLine) {
|
|
6470
|
-
const { readFile:
|
|
6471
|
-
const content = await
|
|
7387
|
+
const { readFile: readFile11 } = await import("node:fs/promises");
|
|
7388
|
+
const content = await readFile11(filePath, "utf-8");
|
|
6472
7389
|
if (startLine === void 0)
|
|
6473
7390
|
return content;
|
|
6474
7391
|
const lines = content.split("\n");
|
|
@@ -6483,8 +7400,8 @@ var init_code_retriever = __esm({
|
|
|
6483
7400
|
// packages/retrieval/dist/lexicalSearch.js
|
|
6484
7401
|
import { execFile as execFile4 } from "node:child_process";
|
|
6485
7402
|
import { promisify as promisify4 } from "node:util";
|
|
6486
|
-
import { readFile as
|
|
6487
|
-
import { join as
|
|
7403
|
+
import { readFile as readFile8, readdir as readdir2, stat as stat3 } from "node:fs/promises";
|
|
7404
|
+
import { join as join15, extname as extname6 } from "node:path";
|
|
6488
7405
|
async function searchByPath(pathPattern, options) {
|
|
6489
7406
|
const allFiles = await collectFiles(options.rootDir, options.includeGlobs ?? DEFAULT_INCLUDE_GLOBS, options.excludeGlobs ?? DEFAULT_EXCLUDE_GLOBS);
|
|
6490
7407
|
const pattern = options.caseInsensitive ? pathPattern.toLowerCase() : pathPattern;
|
|
@@ -6589,7 +7506,7 @@ async function searchWithNodeFallback(pattern, kind, options) {
|
|
|
6589
7506
|
if (results.length >= maxMatches)
|
|
6590
7507
|
break;
|
|
6591
7508
|
try {
|
|
6592
|
-
const content = await
|
|
7509
|
+
const content = await readFile8(filePath, "utf-8");
|
|
6593
7510
|
const contentLines = content.split("\n");
|
|
6594
7511
|
for (let i = 0; i < contentLines.length; i++) {
|
|
6595
7512
|
if (results.length >= maxMatches)
|
|
@@ -6617,7 +7534,7 @@ async function collectFiles(rootDir, includeGlobs, excludeGlobs) {
|
|
|
6617
7534
|
async function walkForFiles(rootDir, dir, excludeGlobs, results) {
|
|
6618
7535
|
let entries;
|
|
6619
7536
|
try {
|
|
6620
|
-
entries = await
|
|
7537
|
+
entries = await readdir2(dir, { withFileTypes: true, encoding: "utf-8" });
|
|
6621
7538
|
} catch {
|
|
6622
7539
|
return;
|
|
6623
7540
|
}
|
|
@@ -6626,16 +7543,16 @@ async function walkForFiles(rootDir, dir, excludeGlobs, results) {
|
|
|
6626
7543
|
continue;
|
|
6627
7544
|
if (excludeGlobs.some((g) => entry.name === g || matchesGlob(entry.name, g)))
|
|
6628
7545
|
continue;
|
|
6629
|
-
const absPath =
|
|
7546
|
+
const absPath = join15(dir, entry.name);
|
|
6630
7547
|
if (entry.isDirectory()) {
|
|
6631
7548
|
await walkForFiles(rootDir, absPath, excludeGlobs, results);
|
|
6632
7549
|
} else if (entry.isFile()) {
|
|
6633
|
-
const ext =
|
|
7550
|
+
const ext = extname6(entry.name);
|
|
6634
7551
|
if (!ALL_CODE_EXTS.has(ext))
|
|
6635
7552
|
continue;
|
|
6636
7553
|
const relativePath = absPath.startsWith(rootDir) ? absPath.slice(rootDir.length).replace(/^\//, "") : absPath;
|
|
6637
7554
|
try {
|
|
6638
|
-
const s = await
|
|
7555
|
+
const s = await stat3(absPath);
|
|
6639
7556
|
if (s.size > 2e6)
|
|
6640
7557
|
continue;
|
|
6641
7558
|
} catch {
|
|
@@ -6800,8 +7717,8 @@ var init_graphExpand = __esm({
|
|
|
6800
7717
|
});
|
|
6801
7718
|
|
|
6802
7719
|
// packages/retrieval/dist/snippetPacker.js
|
|
6803
|
-
import { readFile as
|
|
6804
|
-
import { join as
|
|
7720
|
+
import { readFile as readFile9 } from "node:fs/promises";
|
|
7721
|
+
import { join as join16 } from "node:path";
|
|
6805
7722
|
async function packSnippets(requests, opts = {}) {
|
|
6806
7723
|
const maxTokens = opts.maxTokens ?? DEFAULT_MAX_TOKENS;
|
|
6807
7724
|
const contextLines = opts.contextLines ?? DEFAULT_CONTEXT_LINES;
|
|
@@ -6827,10 +7744,10 @@ async function packSnippets(requests, opts = {}) {
|
|
|
6827
7744
|
return { packed, dropped, totalTokens };
|
|
6828
7745
|
}
|
|
6829
7746
|
async function extractSnippet(req, repoRoot, contextLines = DEFAULT_CONTEXT_LINES) {
|
|
6830
|
-
const absPath = req.filePath.startsWith("/") ? req.filePath :
|
|
7747
|
+
const absPath = req.filePath.startsWith("/") ? req.filePath : join16(repoRoot, req.filePath);
|
|
6831
7748
|
let content;
|
|
6832
7749
|
try {
|
|
6833
|
-
content = await
|
|
7750
|
+
content = await readFile9(absPath, "utf-8");
|
|
6834
7751
|
} catch {
|
|
6835
7752
|
return null;
|
|
6836
7753
|
}
|
|
@@ -8697,14 +9614,14 @@ ${result.output}`;
|
|
|
8697
9614
|
waitForSudoPassword(timeoutMs = 12e4) {
|
|
8698
9615
|
if (this._sudoPassword)
|
|
8699
9616
|
return Promise.resolve(this._sudoPassword);
|
|
8700
|
-
return new Promise((
|
|
9617
|
+
return new Promise((resolve18) => {
|
|
8701
9618
|
const timer = setTimeout(() => {
|
|
8702
9619
|
this._sudoResolve = null;
|
|
8703
|
-
|
|
9620
|
+
resolve18(null);
|
|
8704
9621
|
}, timeoutMs);
|
|
8705
9622
|
this._sudoResolve = (pw) => {
|
|
8706
9623
|
clearTimeout(timer);
|
|
8707
|
-
|
|
9624
|
+
resolve18(pw);
|
|
8708
9625
|
};
|
|
8709
9626
|
});
|
|
8710
9627
|
}
|
|
@@ -9332,6 +10249,489 @@ ${newerSummary}` : newerSummary;
|
|
|
9332
10249
|
}
|
|
9333
10250
|
});
|
|
9334
10251
|
|
|
10252
|
+
// packages/orchestrator/dist/costTracker.js
|
|
10253
|
+
var DEFAULT_PRICING, CostTracker;
|
|
10254
|
+
var init_costTracker = __esm({
|
|
10255
|
+
"packages/orchestrator/dist/costTracker.js"() {
|
|
10256
|
+
"use strict";
|
|
10257
|
+
DEFAULT_PRICING = [
|
|
10258
|
+
// Cloud providers — typical pricing tiers
|
|
10259
|
+
{ providerId: "openai", label: "OpenAI", inputPer1M: 2.5, outputPer1M: 10 },
|
|
10260
|
+
{ providerId: "together", label: "Together AI", inputPer1M: 0.8, outputPer1M: 0.8 },
|
|
10261
|
+
{ providerId: "groq", label: "Groq", inputPer1M: 0.05, outputPer1M: 0.1 },
|
|
10262
|
+
{ providerId: "openrouter", label: "OpenRouter", inputPer1M: 1, outputPer1M: 2 },
|
|
10263
|
+
{ providerId: "fireworks", label: "Fireworks AI", inputPer1M: 0.2, outputPer1M: 0.8 },
|
|
10264
|
+
{ providerId: "deepinfra", label: "DeepInfra", inputPer1M: 0.1, outputPer1M: 0.4 },
|
|
10265
|
+
{ providerId: "mistral", label: "Mistral AI", inputPer1M: 0.5, outputPer1M: 1.5 },
|
|
10266
|
+
{ providerId: "chutes", label: "Chutes AI", inputPer1M: 0.2, outputPer1M: 0.8 },
|
|
10267
|
+
{ providerId: "cerebras", label: "Cerebras", inputPer1M: 0.1, outputPer1M: 0.1 },
|
|
10268
|
+
{ providerId: "sambanova", label: "SambaNova", inputPer1M: 0.1, outputPer1M: 0.4 },
|
|
10269
|
+
{ providerId: "nvidia", label: "NVIDIA NIM", inputPer1M: 0.3, outputPer1M: 1.2 },
|
|
10270
|
+
{ providerId: "hyperbolic", label: "Hyperbolic", inputPer1M: 0.1, outputPer1M: 0.3 },
|
|
10271
|
+
// Local providers — free (no token cost)
|
|
10272
|
+
{ providerId: "ollama", label: "Ollama (local)", inputPer1M: 0, outputPer1M: 0 },
|
|
10273
|
+
{ providerId: "lmstudio", label: "LM Studio (local)", inputPer1M: 0, outputPer1M: 0 },
|
|
10274
|
+
{ providerId: "vllm", label: "vLLM (local)", inputPer1M: 0, outputPer1M: 0 }
|
|
10275
|
+
];
|
|
10276
|
+
CostTracker = class {
|
|
10277
|
+
pricing;
|
|
10278
|
+
tasks = [];
|
|
10279
|
+
sessionStartedAt;
|
|
10280
|
+
// Running totals
|
|
10281
|
+
_totalInputTokens = 0;
|
|
10282
|
+
_totalOutputTokens = 0;
|
|
10283
|
+
_totalEstimatedCost = 0;
|
|
10284
|
+
// Current task accumulator
|
|
10285
|
+
_currentTask = null;
|
|
10286
|
+
_currentInputTokens = 0;
|
|
10287
|
+
_currentOutputTokens = 0;
|
|
10288
|
+
_currentStartedAt = "";
|
|
10289
|
+
_currentStartMs = 0;
|
|
10290
|
+
constructor(providerId, customPricing) {
|
|
10291
|
+
this.sessionStartedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
10292
|
+
this.pricing = customPricing ?? DEFAULT_PRICING.find((p) => p.providerId === providerId) ?? { providerId: providerId ?? "unknown", label: "Unknown", inputPer1M: 0, outputPer1M: 0 };
|
|
10293
|
+
}
|
|
10294
|
+
/** Get the current provider pricing */
|
|
10295
|
+
get provider() {
|
|
10296
|
+
return this.pricing;
|
|
10297
|
+
}
|
|
10298
|
+
/** Update provider (e.g., when user switches endpoint) */
|
|
10299
|
+
setProvider(providerId, customPricing) {
|
|
10300
|
+
this.pricing = customPricing ?? DEFAULT_PRICING.find((p) => p.providerId === providerId) ?? { providerId, label: "Unknown", inputPer1M: 0, outputPer1M: 0 };
|
|
10301
|
+
}
|
|
10302
|
+
/** Start tracking a new task */
|
|
10303
|
+
startTask(taskDescription) {
|
|
10304
|
+
if (this._currentTask) {
|
|
10305
|
+
this.endTask();
|
|
10306
|
+
}
|
|
10307
|
+
this._currentTask = taskDescription;
|
|
10308
|
+
this._currentInputTokens = 0;
|
|
10309
|
+
this._currentOutputTokens = 0;
|
|
10310
|
+
this._currentStartedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
10311
|
+
this._currentStartMs = Date.now();
|
|
10312
|
+
}
|
|
10313
|
+
/** Record token usage from an API response */
|
|
10314
|
+
trackTokens(inputTokens, outputTokens) {
|
|
10315
|
+
this._currentInputTokens += inputTokens;
|
|
10316
|
+
this._currentOutputTokens += outputTokens;
|
|
10317
|
+
this._totalInputTokens += inputTokens;
|
|
10318
|
+
this._totalOutputTokens += outputTokens;
|
|
10319
|
+
const cost = this.calculateCost(inputTokens, outputTokens);
|
|
10320
|
+
this._totalEstimatedCost += cost;
|
|
10321
|
+
}
|
|
10322
|
+
/** End current task and record it */
|
|
10323
|
+
endTask() {
|
|
10324
|
+
if (!this._currentTask)
|
|
10325
|
+
return null;
|
|
10326
|
+
const cost = this.calculateCost(this._currentInputTokens, this._currentOutputTokens);
|
|
10327
|
+
const record = {
|
|
10328
|
+
task: this._currentTask,
|
|
10329
|
+
inputTokens: this._currentInputTokens,
|
|
10330
|
+
outputTokens: this._currentOutputTokens,
|
|
10331
|
+
estimatedCost: cost,
|
|
10332
|
+
durationMs: Date.now() - this._currentStartMs,
|
|
10333
|
+
startedAt: this._currentStartedAt
|
|
10334
|
+
};
|
|
10335
|
+
this.tasks.push(record);
|
|
10336
|
+
this._currentTask = null;
|
|
10337
|
+
return record;
|
|
10338
|
+
}
|
|
10339
|
+
/** Calculate cost for a given token usage */
|
|
10340
|
+
calculateCost(inputTokens, outputTokens) {
|
|
10341
|
+
return inputTokens / 1e6 * this.pricing.inputPer1M + outputTokens / 1e6 * this.pricing.outputPer1M;
|
|
10342
|
+
}
|
|
10343
|
+
/** Get current running cost estimate */
|
|
10344
|
+
get currentCost() {
|
|
10345
|
+
return this._totalEstimatedCost;
|
|
10346
|
+
}
|
|
10347
|
+
/** Get total input tokens */
|
|
10348
|
+
get totalInputTokens() {
|
|
10349
|
+
return this._totalInputTokens;
|
|
10350
|
+
}
|
|
10351
|
+
/** Get total output tokens */
|
|
10352
|
+
get totalOutputTokens() {
|
|
10353
|
+
return this._totalOutputTokens;
|
|
10354
|
+
}
|
|
10355
|
+
/** Whether this provider has non-zero pricing */
|
|
10356
|
+
get hasPricing() {
|
|
10357
|
+
return this.pricing.inputPer1M > 0 || this.pricing.outputPer1M > 0;
|
|
10358
|
+
}
|
|
10359
|
+
/** Format cost as a readable string */
|
|
10360
|
+
formatCost(cost) {
|
|
10361
|
+
const c3 = cost ?? this._totalEstimatedCost;
|
|
10362
|
+
if (c3 < 0.01)
|
|
10363
|
+
return `$${c3.toFixed(4)}`;
|
|
10364
|
+
if (c3 < 1)
|
|
10365
|
+
return `$${c3.toFixed(3)}`;
|
|
10366
|
+
return `$${c3.toFixed(2)}`;
|
|
10367
|
+
}
|
|
10368
|
+
/** Get full session summary */
|
|
10369
|
+
getSummary() {
|
|
10370
|
+
const pendingRecord = this._currentTask ? {
|
|
10371
|
+
task: this._currentTask,
|
|
10372
|
+
inputTokens: this._currentInputTokens,
|
|
10373
|
+
outputTokens: this._currentOutputTokens,
|
|
10374
|
+
estimatedCost: this.calculateCost(this._currentInputTokens, this._currentOutputTokens),
|
|
10375
|
+
durationMs: Date.now() - this._currentStartMs,
|
|
10376
|
+
startedAt: this._currentStartedAt
|
|
10377
|
+
} : null;
|
|
10378
|
+
const allTasks = pendingRecord ? [...this.tasks, pendingRecord] : [...this.tasks];
|
|
10379
|
+
return {
|
|
10380
|
+
totalInputTokens: this._totalInputTokens,
|
|
10381
|
+
totalOutputTokens: this._totalOutputTokens,
|
|
10382
|
+
totalEstimatedCost: this._totalEstimatedCost,
|
|
10383
|
+
taskCount: allTasks.length,
|
|
10384
|
+
tasks: allTasks,
|
|
10385
|
+
provider: this.pricing.label,
|
|
10386
|
+
sessionStartedAt: this.sessionStartedAt,
|
|
10387
|
+
sessionDurationMs: Date.now() - new Date(this.sessionStartedAt).getTime()
|
|
10388
|
+
};
|
|
10389
|
+
}
|
|
10390
|
+
/** Reset all tracking (e.g., new session) */
|
|
10391
|
+
reset() {
|
|
10392
|
+
this.tasks = [];
|
|
10393
|
+
this._totalInputTokens = 0;
|
|
10394
|
+
this._totalOutputTokens = 0;
|
|
10395
|
+
this._totalEstimatedCost = 0;
|
|
10396
|
+
this._currentTask = null;
|
|
10397
|
+
this.sessionStartedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
10398
|
+
}
|
|
10399
|
+
};
|
|
10400
|
+
}
|
|
10401
|
+
});
|
|
10402
|
+
|
|
10403
|
+
// packages/orchestrator/dist/workEvaluator.js
|
|
10404
|
+
function detectTaskType(taskDescription) {
|
|
10405
|
+
let bestType = "general";
|
|
10406
|
+
let bestScore = 0;
|
|
10407
|
+
for (const { type, patterns } of TASK_TYPE_PATTERNS) {
|
|
10408
|
+
let score = 0;
|
|
10409
|
+
for (const p of patterns) {
|
|
10410
|
+
if (p.test(taskDescription))
|
|
10411
|
+
score++;
|
|
10412
|
+
}
|
|
10413
|
+
if (score > bestScore) {
|
|
10414
|
+
bestScore = score;
|
|
10415
|
+
bestType = type;
|
|
10416
|
+
}
|
|
10417
|
+
}
|
|
10418
|
+
return bestType;
|
|
10419
|
+
}
|
|
10420
|
+
function getRubric(taskType) {
|
|
10421
|
+
return RUBRICS[taskType];
|
|
10422
|
+
}
|
|
10423
|
+
function buildEvaluationPrompt(task, summary, rubric) {
|
|
10424
|
+
const dimensionList = rubric.dimensions.map((d, i) => `${i + 1}. **${d.name}** (${Math.round(d.weight * 100)}%): ${d.criteria}`).join("\n");
|
|
10425
|
+
return `You are a quality evaluator. Score the following completed work on these dimensions.
|
|
10426
|
+
|
|
10427
|
+
## Task
|
|
10428
|
+
${task}
|
|
10429
|
+
|
|
10430
|
+
## Completed Work Summary
|
|
10431
|
+
${summary}
|
|
10432
|
+
|
|
10433
|
+
## Scoring Dimensions (${rubric.label} task)
|
|
10434
|
+
${dimensionList}
|
|
10435
|
+
|
|
10436
|
+
## Instructions
|
|
10437
|
+
For each dimension, provide:
|
|
10438
|
+
1. A score from 0-10 (0 = completely missing, 5 = adequate, 10 = exceptional)
|
|
10439
|
+
2. A brief explanation (1-2 sentences)
|
|
10440
|
+
|
|
10441
|
+
Then provide an overall summary of the work quality.
|
|
10442
|
+
|
|
10443
|
+
Respond in EXACTLY this JSON format:
|
|
10444
|
+
{
|
|
10445
|
+
"dimensions": [
|
|
10446
|
+
{"name": "${rubric.dimensions[0].name}", "score": <0-10>, "feedback": "<explanation>"},
|
|
10447
|
+
{"name": "${rubric.dimensions[1].name}", "score": <0-10>, "feedback": "<explanation>"},
|
|
10448
|
+
{"name": "${rubric.dimensions[2].name}", "score": <0-10>, "feedback": "<explanation>"},
|
|
10449
|
+
{"name": "${rubric.dimensions[3].name}", "score": <0-10>, "feedback": "<explanation>"}
|
|
10450
|
+
],
|
|
10451
|
+
"summary": "<2-3 sentence overall assessment>"
|
|
10452
|
+
}
|
|
10453
|
+
|
|
10454
|
+
Respond with ONLY the JSON object, no other text.`;
|
|
10455
|
+
}
|
|
10456
|
+
var RUBRICS, TASK_TYPE_PATTERNS, WorkEvaluator;
|
|
10457
|
+
var init_workEvaluator = __esm({
|
|
10458
|
+
"packages/orchestrator/dist/workEvaluator.js"() {
|
|
10459
|
+
"use strict";
|
|
10460
|
+
RUBRICS = {
|
|
10461
|
+
code: {
|
|
10462
|
+
type: "code",
|
|
10463
|
+
label: "Code",
|
|
10464
|
+
dimensions: [
|
|
10465
|
+
{ name: "Completeness", weight: 0.4, criteria: "All requested features implemented. Tests written if applicable. No missing edge cases." },
|
|
10466
|
+
{ name: "Correctness", weight: 0.3, criteria: "Code compiles/runs without errors. Tests pass. Logic is sound. No bugs or regressions." },
|
|
10467
|
+
{ name: "Quality", weight: 0.2, criteria: "Clean, readable code. Follows existing conventions. Appropriate naming. No unnecessary complexity." },
|
|
10468
|
+
{ name: "Domain", weight: 0.1, criteria: "Follows language/framework best practices. Proper error handling. Security considerations." }
|
|
10469
|
+
]
|
|
10470
|
+
},
|
|
10471
|
+
document: {
|
|
10472
|
+
type: "document",
|
|
10473
|
+
label: "Document",
|
|
10474
|
+
dimensions: [
|
|
10475
|
+
{ name: "Completeness", weight: 0.4, criteria: "All required sections present. Covers the full scope. No gaps in coverage." },
|
|
10476
|
+
{ name: "Correctness", weight: 0.3, criteria: "Factually accurate. No fabrications. Sources cited where applicable." },
|
|
10477
|
+
{ name: "Quality", weight: 0.2, criteria: "Well-structured. Clear writing. Professional formatting. Good flow." },
|
|
10478
|
+
{ name: "Domain", weight: 0.1, criteria: "Follows document type conventions. Appropriate tone and terminology." }
|
|
10479
|
+
]
|
|
10480
|
+
},
|
|
10481
|
+
analysis: {
|
|
10482
|
+
type: "analysis",
|
|
10483
|
+
label: "Analysis",
|
|
10484
|
+
dimensions: [
|
|
10485
|
+
{ name: "Completeness", weight: 0.4, criteria: "All data considered. Methodology explained. Conclusions cover key findings." },
|
|
10486
|
+
{ name: "Correctness", weight: 0.3, criteria: "Calculations accurate. Logic sound. No errors in reasoning or data interpretation." },
|
|
10487
|
+
{ name: "Quality", weight: 0.2, criteria: "Clear presentation. Data visualized where helpful. Executive summary included." },
|
|
10488
|
+
{ name: "Domain", weight: 0.1, criteria: "Follows analytical best practices. Appropriate statistical methods. Caveats noted." }
|
|
10489
|
+
]
|
|
10490
|
+
},
|
|
10491
|
+
plan: {
|
|
10492
|
+
type: "plan",
|
|
10493
|
+
label: "Plan",
|
|
10494
|
+
dimensions: [
|
|
10495
|
+
{ name: "Completeness", weight: 0.4, criteria: "All phases covered. Timeline realistic. Resources identified. Risks addressed." },
|
|
10496
|
+
{ name: "Correctness", weight: 0.3, criteria: "Dependencies accurate. Estimates reasonable. Constraints respected." },
|
|
10497
|
+
{ name: "Quality", weight: 0.2, criteria: "Actionable steps. Clear ownership. Measurable milestones. Well-organized." },
|
|
10498
|
+
{ name: "Domain", weight: 0.1, criteria: "Follows project management best practices. Appropriate methodology for scope." }
|
|
10499
|
+
]
|
|
10500
|
+
},
|
|
10501
|
+
general: {
|
|
10502
|
+
type: "general",
|
|
10503
|
+
label: "General",
|
|
10504
|
+
dimensions: [
|
|
10505
|
+
{ name: "Completeness", weight: 0.4, criteria: "All aspects of the request addressed. Nothing missing or incomplete." },
|
|
10506
|
+
{ name: "Correctness", weight: 0.3, criteria: "Accurate and factual. No errors or inconsistencies." },
|
|
10507
|
+
{ name: "Quality", weight: 0.2, criteria: "Well-structured. Clear communication. Professional output." },
|
|
10508
|
+
{ name: "Domain", weight: 0.1, criteria: "Appropriate for the context. Follows relevant conventions." }
|
|
10509
|
+
]
|
|
10510
|
+
}
|
|
10511
|
+
};
|
|
10512
|
+
TASK_TYPE_PATTERNS = [
|
|
10513
|
+
{
|
|
10514
|
+
type: "code",
|
|
10515
|
+
patterns: [
|
|
10516
|
+
/\b(fix|implement|refactor|debug|test|code|function|class|module|api|bug|feature|PR|commit|build|compile|lint)\b/i,
|
|
10517
|
+
/\.(ts|js|py|rs|go|java|cpp|rb|php|swift)\b/i
|
|
10518
|
+
]
|
|
10519
|
+
},
|
|
10520
|
+
{
|
|
10521
|
+
type: "document",
|
|
10522
|
+
patterns: [
|
|
10523
|
+
/\b(write|draft|document|report|article|blog|readme|guide|manual|specification|proposal|email|letter)\b/i,
|
|
10524
|
+
/\.(md|doc|docx|pdf|txt)\b/i
|
|
10525
|
+
]
|
|
10526
|
+
},
|
|
10527
|
+
{
|
|
10528
|
+
type: "analysis",
|
|
10529
|
+
patterns: [
|
|
10530
|
+
/\b(analyze|research|evaluate|compare|assess|review|audit|benchmark|metric|data|statistic|trend)\b/i
|
|
10531
|
+
]
|
|
10532
|
+
},
|
|
10533
|
+
{
|
|
10534
|
+
type: "plan",
|
|
10535
|
+
patterns: [
|
|
10536
|
+
/\b(plan|schedule|roadmap|strategy|design|architect|timeline|milestone|sprint|backlog|estimate)\b/i
|
|
10537
|
+
]
|
|
10538
|
+
}
|
|
10539
|
+
];
|
|
10540
|
+
WorkEvaluator = class {
|
|
10541
|
+
backend;
|
|
10542
|
+
constructor(backend) {
|
|
10543
|
+
this.backend = backend ?? null;
|
|
10544
|
+
}
|
|
10545
|
+
/** Set or update the evaluation backend */
|
|
10546
|
+
setBackend(backend) {
|
|
10547
|
+
this.backend = backend;
|
|
10548
|
+
}
|
|
10549
|
+
/** Evaluate completed work */
|
|
10550
|
+
async evaluate(task, summary, taskType) {
|
|
10551
|
+
if (!this.backend) {
|
|
10552
|
+
return {
|
|
10553
|
+
overallScore: 0,
|
|
10554
|
+
dimensions: [],
|
|
10555
|
+
feedback: "No evaluation backend configured.",
|
|
10556
|
+
taskType: taskType ?? "general",
|
|
10557
|
+
success: false,
|
|
10558
|
+
error: "No evaluation backend configured"
|
|
10559
|
+
};
|
|
10560
|
+
}
|
|
10561
|
+
const detectedType = taskType ?? detectTaskType(task);
|
|
10562
|
+
const rubric = getRubric(detectedType);
|
|
10563
|
+
const prompt = buildEvaluationPrompt(task, summary, rubric);
|
|
10564
|
+
try {
|
|
10565
|
+
const response = await this.backend.evaluate(prompt);
|
|
10566
|
+
return this.parseResponse(response, rubric, detectedType);
|
|
10567
|
+
} catch (err) {
|
|
10568
|
+
return {
|
|
10569
|
+
overallScore: 0,
|
|
10570
|
+
dimensions: [],
|
|
10571
|
+
feedback: `Evaluation failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
10572
|
+
taskType: detectedType,
|
|
10573
|
+
success: false,
|
|
10574
|
+
error: err instanceof Error ? err.message : String(err)
|
|
10575
|
+
};
|
|
10576
|
+
}
|
|
10577
|
+
}
|
|
10578
|
+
/** Parse the LLM's JSON response into an EvaluationResult */
|
|
10579
|
+
parseResponse(response, rubric, taskType) {
|
|
10580
|
+
try {
|
|
10581
|
+
let jsonStr = response.trim();
|
|
10582
|
+
const jsonMatch = jsonStr.match(/```(?:json)?\s*([\s\S]*?)```/);
|
|
10583
|
+
if (jsonMatch) {
|
|
10584
|
+
jsonStr = jsonMatch[1].trim();
|
|
10585
|
+
}
|
|
10586
|
+
if (!jsonStr.startsWith("{")) {
|
|
10587
|
+
const braceMatch = jsonStr.match(/\{[\s\S]*\}/);
|
|
10588
|
+
if (braceMatch)
|
|
10589
|
+
jsonStr = braceMatch[0];
|
|
10590
|
+
}
|
|
10591
|
+
const parsed = JSON.parse(jsonStr);
|
|
10592
|
+
if (!parsed.dimensions || !Array.isArray(parsed.dimensions)) {
|
|
10593
|
+
throw new Error("Missing dimensions array in response");
|
|
10594
|
+
}
|
|
10595
|
+
const dimensions = rubric.dimensions.map((rd, i) => {
|
|
10596
|
+
const pd = parsed.dimensions[i];
|
|
10597
|
+
const score = Math.max(0, Math.min(10, pd?.score ?? 0));
|
|
10598
|
+
return {
|
|
10599
|
+
name: rd.name,
|
|
10600
|
+
weight: rd.weight,
|
|
10601
|
+
score,
|
|
10602
|
+
feedback: pd?.feedback ?? ""
|
|
10603
|
+
};
|
|
10604
|
+
});
|
|
10605
|
+
const overallScore = dimensions.reduce((sum, d) => sum + d.score / 10 * d.weight, 0);
|
|
10606
|
+
return {
|
|
10607
|
+
overallScore,
|
|
10608
|
+
dimensions,
|
|
10609
|
+
feedback: parsed.summary ?? "",
|
|
10610
|
+
taskType,
|
|
10611
|
+
success: true
|
|
10612
|
+
};
|
|
10613
|
+
} catch (err) {
|
|
10614
|
+
return {
|
|
10615
|
+
overallScore: 0,
|
|
10616
|
+
dimensions: [],
|
|
10617
|
+
feedback: `Failed to parse evaluation response: ${err instanceof Error ? err.message : String(err)}`,
|
|
10618
|
+
taskType,
|
|
10619
|
+
success: false,
|
|
10620
|
+
error: `Parse error: ${err instanceof Error ? err.message : String(err)}`
|
|
10621
|
+
};
|
|
10622
|
+
}
|
|
10623
|
+
}
|
|
10624
|
+
};
|
|
10625
|
+
}
|
|
10626
|
+
});
|
|
10627
|
+
|
|
10628
|
+
// packages/orchestrator/dist/sessionMetrics.js
|
|
10629
|
+
var SessionMetrics;
|
|
10630
|
+
var init_sessionMetrics = __esm({
|
|
10631
|
+
"packages/orchestrator/dist/sessionMetrics.js"() {
|
|
10632
|
+
"use strict";
|
|
10633
|
+
SessionMetrics = class {
|
|
10634
|
+
sessionStart;
|
|
10635
|
+
turns = 0;
|
|
10636
|
+
toolCalls = 0;
|
|
10637
|
+
toolCallsByName = {};
|
|
10638
|
+
inputTokens = 0;
|
|
10639
|
+
outputTokens = 0;
|
|
10640
|
+
filesModified = /* @__PURE__ */ new Set();
|
|
10641
|
+
tasks = [];
|
|
10642
|
+
currentTask = null;
|
|
10643
|
+
constructor() {
|
|
10644
|
+
this.sessionStart = Date.now();
|
|
10645
|
+
}
|
|
10646
|
+
/** Record a new turn (assistant response). */
|
|
10647
|
+
recordTurn() {
|
|
10648
|
+
this.turns++;
|
|
10649
|
+
}
|
|
10650
|
+
/** Record a tool call. */
|
|
10651
|
+
recordToolCall(toolName) {
|
|
10652
|
+
this.toolCalls++;
|
|
10653
|
+
this.toolCallsByName[toolName] = (this.toolCallsByName[toolName] ?? 0) + 1;
|
|
10654
|
+
if (this.currentTask) {
|
|
10655
|
+
this.currentTask.toolCalls++;
|
|
10656
|
+
}
|
|
10657
|
+
}
|
|
10658
|
+
/** Record token usage. */
|
|
10659
|
+
recordTokenUsage(inputTokens, outputTokens) {
|
|
10660
|
+
this.inputTokens += inputTokens;
|
|
10661
|
+
this.outputTokens += outputTokens;
|
|
10662
|
+
}
|
|
10663
|
+
/** Record a file modification. */
|
|
10664
|
+
recordFileModified(filePath) {
|
|
10665
|
+
this.filesModified.add(filePath);
|
|
10666
|
+
}
|
|
10667
|
+
/** Start tracking a new task. */
|
|
10668
|
+
startTask(description) {
|
|
10669
|
+
this.currentTask = {
|
|
10670
|
+
description,
|
|
10671
|
+
startTime: Date.now(),
|
|
10672
|
+
toolCalls: 0
|
|
10673
|
+
};
|
|
10674
|
+
}
|
|
10675
|
+
/** End the current task with optional evaluation score. */
|
|
10676
|
+
endTask(evaluationScore) {
|
|
10677
|
+
if (this.currentTask) {
|
|
10678
|
+
this.currentTask.endTime = Date.now();
|
|
10679
|
+
this.currentTask.durationMs = this.currentTask.endTime - this.currentTask.startTime;
|
|
10680
|
+
if (evaluationScore !== void 0) {
|
|
10681
|
+
this.currentTask.evaluationScore = evaluationScore;
|
|
10682
|
+
}
|
|
10683
|
+
this.tasks.push(this.currentTask);
|
|
10684
|
+
this.currentTask = null;
|
|
10685
|
+
}
|
|
10686
|
+
}
|
|
10687
|
+
/** Get current session summary. */
|
|
10688
|
+
getSummary() {
|
|
10689
|
+
const now = Date.now();
|
|
10690
|
+
const evalScores = this.tasks.filter((t) => t.evaluationScore !== void 0).map((t) => t.evaluationScore);
|
|
10691
|
+
return {
|
|
10692
|
+
sessionStartTime: this.sessionStart,
|
|
10693
|
+
sessionDurationMs: now - this.sessionStart,
|
|
10694
|
+
totalTurns: this.turns,
|
|
10695
|
+
totalToolCalls: this.toolCalls,
|
|
10696
|
+
toolCallsByName: { ...this.toolCallsByName },
|
|
10697
|
+
totalInputTokens: this.inputTokens,
|
|
10698
|
+
totalOutputTokens: this.outputTokens,
|
|
10699
|
+
filesModified: [...this.filesModified],
|
|
10700
|
+
tasksCompleted: this.tasks.length,
|
|
10701
|
+
tasks: [...this.tasks],
|
|
10702
|
+
averageEvalScore: evalScores.length > 0 ? evalScores.reduce((a, b) => a + b, 0) / evalScores.length : void 0
|
|
10703
|
+
};
|
|
10704
|
+
}
|
|
10705
|
+
/** Get the most-used tools (sorted by count). */
|
|
10706
|
+
getTopTools(limit = 5) {
|
|
10707
|
+
return Object.entries(this.toolCallsByName).sort((a, b) => b[1] - a[1]).slice(0, limit).map(([name, count]) => ({ name, count }));
|
|
10708
|
+
}
|
|
10709
|
+
/** Format duration in human-readable form. */
|
|
10710
|
+
static formatDuration(ms) {
|
|
10711
|
+
if (ms < 1e3)
|
|
10712
|
+
return `${ms}ms`;
|
|
10713
|
+
const seconds = Math.floor(ms / 1e3);
|
|
10714
|
+
if (seconds < 60)
|
|
10715
|
+
return `${seconds}s`;
|
|
10716
|
+
const minutes = Math.floor(seconds / 60);
|
|
10717
|
+
const remainingSecs = seconds % 60;
|
|
10718
|
+
if (minutes < 60)
|
|
10719
|
+
return `${minutes}m ${remainingSecs}s`;
|
|
10720
|
+
const hours = Math.floor(minutes / 60);
|
|
10721
|
+
const remainingMins = minutes % 60;
|
|
10722
|
+
return `${hours}h ${remainingMins}m`;
|
|
10723
|
+
}
|
|
10724
|
+
};
|
|
10725
|
+
}
|
|
10726
|
+
});
|
|
10727
|
+
|
|
10728
|
+
// packages/orchestrator/dist/taskLearning.js
|
|
10729
|
+
var init_taskLearning = __esm({
|
|
10730
|
+
"packages/orchestrator/dist/taskLearning.js"() {
|
|
10731
|
+
"use strict";
|
|
10732
|
+
}
|
|
10733
|
+
});
|
|
10734
|
+
|
|
9335
10735
|
// packages/orchestrator/dist/index.js
|
|
9336
10736
|
var init_dist5 = __esm({
|
|
9337
10737
|
"packages/orchestrator/dist/index.js"() {
|
|
@@ -9347,13 +10747,17 @@ var init_dist5 = __esm({
|
|
|
9347
10747
|
init_mergeRunner();
|
|
9348
10748
|
init_retryController();
|
|
9349
10749
|
init_agenticRunner();
|
|
10750
|
+
init_costTracker();
|
|
10751
|
+
init_workEvaluator();
|
|
10752
|
+
init_sessionMetrics();
|
|
10753
|
+
init_taskLearning();
|
|
9350
10754
|
}
|
|
9351
10755
|
});
|
|
9352
10756
|
|
|
9353
10757
|
// packages/cli/dist/tui/listen.js
|
|
9354
|
-
import { spawn as
|
|
10758
|
+
import { spawn as spawn6, execSync as execSync9 } from "node:child_process";
|
|
9355
10759
|
import { existsSync as existsSync11, mkdirSync as mkdirSync5, writeFileSync as writeFileSync5 } from "node:fs";
|
|
9356
|
-
import { join as
|
|
10760
|
+
import { join as join17 } from "node:path";
|
|
9357
10761
|
import { homedir as homedir6 } from "node:os";
|
|
9358
10762
|
import { EventEmitter } from "node:events";
|
|
9359
10763
|
function isAudioPath(path) {
|
|
@@ -9444,16 +10848,16 @@ function ensureTranscribeCliBackground() {
|
|
|
9444
10848
|
timeout: 5e3,
|
|
9445
10849
|
stdio: ["pipe", "pipe", "pipe"]
|
|
9446
10850
|
}).trim();
|
|
9447
|
-
if (existsSync11(
|
|
10851
|
+
if (existsSync11(join17(globalRoot, "transcribe-cli", "dist", "index.js"))) {
|
|
9448
10852
|
return true;
|
|
9449
10853
|
}
|
|
9450
10854
|
} catch {
|
|
9451
10855
|
}
|
|
9452
10856
|
try {
|
|
9453
10857
|
const { exec } = await import("node:child_process");
|
|
9454
|
-
return new Promise((
|
|
10858
|
+
return new Promise((resolve18) => {
|
|
9455
10859
|
exec("npm i -g transcribe-cli", { timeout: 18e4 }, (err) => {
|
|
9456
|
-
|
|
10860
|
+
resolve18(!err);
|
|
9457
10861
|
});
|
|
9458
10862
|
});
|
|
9459
10863
|
} catch {
|
|
@@ -9568,24 +10972,24 @@ var init_listen = __esm({
|
|
|
9568
10972
|
timeout: 5e3,
|
|
9569
10973
|
stdio: ["pipe", "pipe", "pipe"]
|
|
9570
10974
|
}).trim();
|
|
9571
|
-
const tcPath =
|
|
9572
|
-
if (existsSync11(
|
|
10975
|
+
const tcPath = join17(globalRoot, "transcribe-cli");
|
|
10976
|
+
if (existsSync11(join17(tcPath, "dist", "index.js"))) {
|
|
9573
10977
|
const { createRequire: createRequire4 } = await import("node:module");
|
|
9574
10978
|
const req = createRequire4(import.meta.url);
|
|
9575
|
-
return req(
|
|
10979
|
+
return req(join17(tcPath, "dist", "index.js"));
|
|
9576
10980
|
}
|
|
9577
10981
|
} catch {
|
|
9578
10982
|
}
|
|
9579
|
-
const nvmBase =
|
|
10983
|
+
const nvmBase = join17(homedir6(), ".nvm", "versions", "node");
|
|
9580
10984
|
if (existsSync11(nvmBase)) {
|
|
9581
10985
|
try {
|
|
9582
10986
|
const { readdirSync: readdirSync9 } = await import("node:fs");
|
|
9583
10987
|
for (const ver of readdirSync9(nvmBase)) {
|
|
9584
|
-
const tcPath =
|
|
9585
|
-
if (existsSync11(
|
|
10988
|
+
const tcPath = join17(nvmBase, ver, "lib", "node_modules", "transcribe-cli");
|
|
10989
|
+
if (existsSync11(join17(tcPath, "dist", "index.js"))) {
|
|
9586
10990
|
const { createRequire: createRequire4 } = await import("node:module");
|
|
9587
10991
|
const req = createRequire4(import.meta.url);
|
|
9588
|
-
return req(
|
|
10992
|
+
return req(join17(tcPath, "dist", "index.js"));
|
|
9589
10993
|
}
|
|
9590
10994
|
}
|
|
9591
10995
|
} catch {
|
|
@@ -9646,18 +11050,18 @@ var init_listen = __esm({
|
|
|
9646
11050
|
this.liveTranscriber.on("error", (err) => {
|
|
9647
11051
|
this.emit("error", err);
|
|
9648
11052
|
});
|
|
9649
|
-
await new Promise((
|
|
11053
|
+
await new Promise((resolve18, reject) => {
|
|
9650
11054
|
const timeout = setTimeout(() => reject(new Error("Model load timeout (60s)")), 6e4);
|
|
9651
11055
|
this.liveTranscriber.on("ready", () => {
|
|
9652
11056
|
clearTimeout(timeout);
|
|
9653
|
-
|
|
11057
|
+
resolve18();
|
|
9654
11058
|
});
|
|
9655
11059
|
this.liveTranscriber.on("error", (err) => {
|
|
9656
11060
|
clearTimeout(timeout);
|
|
9657
11061
|
reject(err);
|
|
9658
11062
|
});
|
|
9659
11063
|
});
|
|
9660
|
-
this.micProcess =
|
|
11064
|
+
this.micProcess = spawn6(micCmd.cmd, micCmd.args, {
|
|
9661
11065
|
stdio: ["pipe", "pipe", "pipe"],
|
|
9662
11066
|
env: { ...process.env }
|
|
9663
11067
|
});
|
|
@@ -9768,9 +11172,9 @@ var init_listen = __esm({
|
|
|
9768
11172
|
});
|
|
9769
11173
|
if (outputDir) {
|
|
9770
11174
|
const { basename: basename8 } = await import("node:path");
|
|
9771
|
-
const transcriptDir =
|
|
11175
|
+
const transcriptDir = join17(outputDir, ".oa", "transcripts");
|
|
9772
11176
|
mkdirSync5(transcriptDir, { recursive: true });
|
|
9773
|
-
const outFile =
|
|
11177
|
+
const outFile = join17(transcriptDir, `${basename8(filePath)}.txt`);
|
|
9774
11178
|
writeFileSync5(outFile, result.text, "utf-8");
|
|
9775
11179
|
}
|
|
9776
11180
|
return {
|
|
@@ -9835,6 +11239,53 @@ async function fetchOllamaModels(baseUrl) {
|
|
|
9835
11239
|
parameterSize: m.details?.parameter_size
|
|
9836
11240
|
})).sort((a, b) => b.sizeBytes - a.sizeBytes);
|
|
9837
11241
|
}
|
|
11242
|
+
async function fetchOpenAIModels(baseUrl, apiKey) {
|
|
11243
|
+
const normalized = normalizeBaseUrl(baseUrl);
|
|
11244
|
+
const url = `${normalized}/v1/models`;
|
|
11245
|
+
const headers = {};
|
|
11246
|
+
if (apiKey) {
|
|
11247
|
+
headers["Authorization"] = `Bearer ${apiKey}`;
|
|
11248
|
+
}
|
|
11249
|
+
const resp = await fetch(url, {
|
|
11250
|
+
headers,
|
|
11251
|
+
signal: AbortSignal.timeout(1e4)
|
|
11252
|
+
});
|
|
11253
|
+
if (!resp.ok) {
|
|
11254
|
+
throw new Error(`Failed to fetch models: HTTP ${resp.status}`);
|
|
11255
|
+
}
|
|
11256
|
+
const data = await resp.json();
|
|
11257
|
+
const models = data.data ?? [];
|
|
11258
|
+
return models.map((m) => ({
|
|
11259
|
+
name: m.id,
|
|
11260
|
+
size: m.context_length ? `${Math.round(m.context_length / 1024)}K ctx` : m.max_model_len ? `${Math.round(m.max_model_len / 1024)}K ctx` : "",
|
|
11261
|
+
sizeBytes: 0,
|
|
11262
|
+
modified: m.created ? formatRelativeTime(new Date(m.created * 1e3).toISOString()) : "",
|
|
11263
|
+
parameterSize: m.owned_by ?? void 0
|
|
11264
|
+
})).sort((a, b) => a.name.localeCompare(b.name));
|
|
11265
|
+
}
|
|
11266
|
+
async function fetchModels(baseUrl, apiKey) {
|
|
11267
|
+
const provider = detectProvider(baseUrl);
|
|
11268
|
+
if (provider.id === "ollama") {
|
|
11269
|
+
try {
|
|
11270
|
+
return await fetchOllamaModels(baseUrl);
|
|
11271
|
+
} catch {
|
|
11272
|
+
try {
|
|
11273
|
+
return await fetchOpenAIModels(baseUrl, apiKey);
|
|
11274
|
+
} catch {
|
|
11275
|
+
throw new Error("Cannot reach Ollama at " + baseUrl);
|
|
11276
|
+
}
|
|
11277
|
+
}
|
|
11278
|
+
}
|
|
11279
|
+
try {
|
|
11280
|
+
return await fetchOpenAIModels(baseUrl, apiKey);
|
|
11281
|
+
} catch {
|
|
11282
|
+
try {
|
|
11283
|
+
return await fetchOllamaModels(baseUrl);
|
|
11284
|
+
} catch {
|
|
11285
|
+
throw new Error(`Cannot fetch models from ${provider.label} at ${baseUrl}`);
|
|
11286
|
+
}
|
|
11287
|
+
}
|
|
11288
|
+
}
|
|
9838
11289
|
function findModel(models, query) {
|
|
9839
11290
|
const exact = models.find((m) => m.name === query);
|
|
9840
11291
|
if (exact)
|
|
@@ -10330,6 +11781,10 @@ function renderSlashHelp() {
|
|
|
10330
11781
|
["/listen confirm", "Require Enter to submit transcription"],
|
|
10331
11782
|
["/listen auto", "Auto-submit after 3s silence (blinking \u25CF indicator)"],
|
|
10332
11783
|
["/listen stop", "Stop listening"],
|
|
11784
|
+
["/cost", "Show session token cost breakdown"],
|
|
11785
|
+
["/evaluate", "Evaluate last completed task (LLM quality scoring)"],
|
|
11786
|
+
["/task-type", "Set task type (code, document, analysis, plan, general, auto)"],
|
|
11787
|
+
["/stats", "Show session dashboard (metrics, tool usage, task history)"],
|
|
10333
11788
|
["/bruteforce", "Toggle brute-force mode (auto re-engage on turn limit)"],
|
|
10334
11789
|
["/tools", "List agent-created custom tools"],
|
|
10335
11790
|
["/skills", "List available AIWG skills"],
|
|
@@ -10708,22 +12163,215 @@ var init_render = __esm({
|
|
|
10708
12163
|
}
|
|
10709
12164
|
});
|
|
10710
12165
|
|
|
12166
|
+
// packages/prompts/dist/loader.js
|
|
12167
|
+
var init_loader = __esm({
|
|
12168
|
+
"packages/prompts/dist/loader.js"() {
|
|
12169
|
+
"use strict";
|
|
12170
|
+
}
|
|
12171
|
+
});
|
|
12172
|
+
|
|
12173
|
+
// packages/prompts/dist/render.js
|
|
12174
|
+
var init_render2 = __esm({
|
|
12175
|
+
"packages/prompts/dist/render.js"() {
|
|
12176
|
+
"use strict";
|
|
12177
|
+
}
|
|
12178
|
+
});
|
|
12179
|
+
|
|
12180
|
+
// packages/prompts/dist/task-templates.js
|
|
12181
|
+
function getTaskTemplate(type) {
|
|
12182
|
+
return TEMPLATES[type];
|
|
12183
|
+
}
|
|
12184
|
+
function getTaskTypes() {
|
|
12185
|
+
return Object.keys(TEMPLATES);
|
|
12186
|
+
}
|
|
12187
|
+
function buildTaskContext(type) {
|
|
12188
|
+
const template = TEMPLATES[type];
|
|
12189
|
+
return `${template.systemPromptAddition}
|
|
12190
|
+
|
|
12191
|
+
### Output Guidance
|
|
12192
|
+
${template.outputGuidance}`;
|
|
12193
|
+
}
|
|
12194
|
+
var TEMPLATES;
|
|
12195
|
+
var init_task_templates = __esm({
|
|
12196
|
+
"packages/prompts/dist/task-templates.js"() {
|
|
12197
|
+
"use strict";
|
|
12198
|
+
TEMPLATES = {
|
|
12199
|
+
code: {
|
|
12200
|
+
type: "code",
|
|
12201
|
+
label: "Software Development",
|
|
12202
|
+
description: "Writing, debugging, refactoring, or reviewing code.",
|
|
12203
|
+
systemPromptAddition: `
|
|
12204
|
+
## Task Context: Software Development
|
|
12205
|
+
|
|
12206
|
+
You are working on a software development task. Follow these principles:
|
|
12207
|
+
|
|
12208
|
+
- **Read before writing**: Always read the existing code and understand the context before making changes.
|
|
12209
|
+
- **Test-driven approach**: Run existing tests first, make changes, then verify tests still pass.
|
|
12210
|
+
- **Minimal changes**: Make the smallest change that solves the problem. Avoid refactoring unrelated code.
|
|
12211
|
+
- **Convention adherence**: Match the existing code style, naming conventions, and patterns in the project.
|
|
12212
|
+
- **Error handling**: Ensure proper error handling and edge case coverage.
|
|
12213
|
+
- **File organization**: Follow the existing project structure when adding new files.
|
|
12214
|
+
|
|
12215
|
+
When the task is complete, verify by running tests and/or type-checking where available.`,
|
|
12216
|
+
recommendedTools: [
|
|
12217
|
+
"file_read",
|
|
12218
|
+
"file_write",
|
|
12219
|
+
"file_edit",
|
|
12220
|
+
"shell",
|
|
12221
|
+
"grep_search",
|
|
12222
|
+
"glob_find",
|
|
12223
|
+
"git_info",
|
|
12224
|
+
"codebase_map"
|
|
12225
|
+
],
|
|
12226
|
+
outputGuidance: "Deliver working code with tests passing. Summarize what was changed and why."
|
|
12227
|
+
},
|
|
12228
|
+
document: {
|
|
12229
|
+
type: "document",
|
|
12230
|
+
label: "Document Drafting",
|
|
12231
|
+
description: "Creating reports, specifications, guides, proposals, or other professional documents.",
|
|
12232
|
+
systemPromptAddition: `
|
|
12233
|
+
## Task Context: Document Drafting
|
|
12234
|
+
|
|
12235
|
+
You are working on a professional document. Follow these principles:
|
|
12236
|
+
|
|
12237
|
+
- **Audience awareness**: Tailor language, depth, and terminology to the intended audience.
|
|
12238
|
+
- **Structure first**: Create a clear outline before filling in content. Use headings, sections, and lists.
|
|
12239
|
+
- **Completeness**: Cover all aspects the user requested. Flag any areas where you need clarification.
|
|
12240
|
+
- **Clarity**: Use clear, concise language. Avoid jargon unless appropriate for the audience.
|
|
12241
|
+
- **Formatting**: Use appropriate markdown formatting \u2014 tables for data, code blocks for technical content, lists for enumerations.
|
|
12242
|
+
- **Citations**: When referencing external information, note sources or indicate where citations are needed.
|
|
12243
|
+
|
|
12244
|
+
Use the create_structured_file tool for spreadsheets, CSV, or formatted output. Use file_write for documents.`,
|
|
12245
|
+
recommendedTools: [
|
|
12246
|
+
"file_read",
|
|
12247
|
+
"file_write",
|
|
12248
|
+
"web_search",
|
|
12249
|
+
"web_fetch",
|
|
12250
|
+
"create_structured_file",
|
|
12251
|
+
"memory_read"
|
|
12252
|
+
],
|
|
12253
|
+
outputGuidance: "Deliver a complete, well-structured document. Specify the output format (Markdown, PDF, etc.)."
|
|
12254
|
+
},
|
|
12255
|
+
analysis: {
|
|
12256
|
+
type: "analysis",
|
|
12257
|
+
label: "Analysis & Research",
|
|
12258
|
+
description: "Analyzing data, evaluating options, conducting research, or producing insights.",
|
|
12259
|
+
systemPromptAddition: `
|
|
12260
|
+
## Task Context: Analysis & Research
|
|
12261
|
+
|
|
12262
|
+
You are working on an analytical task. Follow these principles:
|
|
12263
|
+
|
|
12264
|
+
- **Evidence-based**: Ground conclusions in data, code, or verifiable sources. Avoid speculation.
|
|
12265
|
+
- **Methodology**: State your analytical approach clearly. When comparing options, define criteria upfront.
|
|
12266
|
+
- **Quantify**: Use numbers, metrics, and measurements wherever possible. Avoid vague qualifiers.
|
|
12267
|
+
- **Visualization**: Present data in tables or structured formats for clarity.
|
|
12268
|
+
- **Limitations**: Acknowledge limitations in your analysis \u2014 data gaps, assumptions, scope boundaries.
|
|
12269
|
+
- **Actionable conclusions**: End with clear recommendations or next steps.
|
|
12270
|
+
|
|
12271
|
+
Use web_search for external research. Use grep_search and codebase_map for codebase analysis.
|
|
12272
|
+
Use create_structured_file to output data as CSV, JSON, or markdown tables.`,
|
|
12273
|
+
recommendedTools: [
|
|
12274
|
+
"file_read",
|
|
12275
|
+
"grep_search",
|
|
12276
|
+
"glob_find",
|
|
12277
|
+
"web_search",
|
|
12278
|
+
"web_fetch",
|
|
12279
|
+
"codebase_map",
|
|
12280
|
+
"create_structured_file",
|
|
12281
|
+
"shell"
|
|
12282
|
+
],
|
|
12283
|
+
outputGuidance: "Deliver a structured analysis with findings, data tables, and actionable recommendations."
|
|
12284
|
+
},
|
|
12285
|
+
plan: {
|
|
12286
|
+
type: "plan",
|
|
12287
|
+
label: "Planning & Design",
|
|
12288
|
+
description: "Creating project plans, system designs, architecture proposals, or roadmaps.",
|
|
12289
|
+
systemPromptAddition: `
|
|
12290
|
+
## Task Context: Planning & Design
|
|
12291
|
+
|
|
12292
|
+
You are working on a planning or design task. Follow these principles:
|
|
12293
|
+
|
|
12294
|
+
- **Scope clarity**: Define what is in-scope and out-of-scope explicitly.
|
|
12295
|
+
- **Phased approach**: Break work into phases or milestones with clear dependencies.
|
|
12296
|
+
- **Risk identification**: Identify key risks, assumptions, and dependencies for each phase.
|
|
12297
|
+
- **Resource awareness**: Consider team size, skill requirements, and tool/infrastructure needs.
|
|
12298
|
+
- **Alternatives**: When making design decisions, briefly note alternatives considered and why the chosen approach is preferred.
|
|
12299
|
+
- **Actionable items**: Every section should include concrete next steps or action items.
|
|
12300
|
+
- **Traceability**: Link plan items to requirements or goals where applicable.
|
|
12301
|
+
|
|
12302
|
+
Use codebase_map and grep_search to understand existing architecture.
|
|
12303
|
+
Use create_structured_file for timeline/schedule output.`,
|
|
12304
|
+
recommendedTools: [
|
|
12305
|
+
"file_read",
|
|
12306
|
+
"grep_search",
|
|
12307
|
+
"glob_find",
|
|
12308
|
+
"codebase_map",
|
|
12309
|
+
"web_search",
|
|
12310
|
+
"create_structured_file",
|
|
12311
|
+
"file_write",
|
|
12312
|
+
"git_info"
|
|
12313
|
+
],
|
|
12314
|
+
outputGuidance: "Deliver a structured plan with phases, milestones, risks, and action items."
|
|
12315
|
+
},
|
|
12316
|
+
general: {
|
|
12317
|
+
type: "general",
|
|
12318
|
+
label: "General Task",
|
|
12319
|
+
description: "Tasks that don't clearly fit another category.",
|
|
12320
|
+
systemPromptAddition: `
|
|
12321
|
+
## Task Context: General
|
|
12322
|
+
|
|
12323
|
+
Approach this task thoughtfully:
|
|
12324
|
+
|
|
12325
|
+
- **Clarify intent**: If the task is ambiguous, use available tools to gather context before proceeding.
|
|
12326
|
+
- **Appropriate tools**: Select the right tools for the job \u2014 file tools for file work, search for research, shell for commands.
|
|
12327
|
+
- **Quality output**: Regardless of task type, produce clear, complete, and well-organized output.
|
|
12328
|
+
- **Verify results**: After completing work, verify the results are correct and complete.`,
|
|
12329
|
+
recommendedTools: [
|
|
12330
|
+
"file_read",
|
|
12331
|
+
"file_write",
|
|
12332
|
+
"shell",
|
|
12333
|
+
"grep_search",
|
|
12334
|
+
"web_search",
|
|
12335
|
+
"memory_read"
|
|
12336
|
+
],
|
|
12337
|
+
outputGuidance: "Deliver complete results with a clear summary of what was done."
|
|
12338
|
+
}
|
|
12339
|
+
};
|
|
12340
|
+
}
|
|
12341
|
+
});
|
|
12342
|
+
|
|
12343
|
+
// packages/prompts/dist/index.js
|
|
12344
|
+
import { join as join18, dirname as dirname4 } from "node:path";
|
|
12345
|
+
import { fileURLToPath } from "node:url";
|
|
12346
|
+
var _dir, _packageRoot;
|
|
12347
|
+
var init_dist6 = __esm({
|
|
12348
|
+
"packages/prompts/dist/index.js"() {
|
|
12349
|
+
"use strict";
|
|
12350
|
+
init_loader();
|
|
12351
|
+
init_render2();
|
|
12352
|
+
init_task_templates();
|
|
12353
|
+
init_render2();
|
|
12354
|
+
_dir = dirname4(fileURLToPath(import.meta.url));
|
|
12355
|
+
_packageRoot = join18(_dir, "..");
|
|
12356
|
+
}
|
|
12357
|
+
});
|
|
12358
|
+
|
|
10711
12359
|
// packages/cli/dist/tui/oa-directory.js
|
|
10712
12360
|
import { existsSync as existsSync12, mkdirSync as mkdirSync6, readFileSync as readFileSync10, writeFileSync as writeFileSync6, readdirSync as readdirSync6, statSync as statSync5, unlinkSync as unlinkSync2 } from "node:fs";
|
|
10713
|
-
import { join as
|
|
12361
|
+
import { join as join19, relative as relative2, basename as basename4, extname as extname7 } from "node:path";
|
|
10714
12362
|
import { homedir as homedir7 } from "node:os";
|
|
10715
12363
|
function initOaDirectory(repoRoot) {
|
|
10716
|
-
const oaPath =
|
|
12364
|
+
const oaPath = join19(repoRoot, OA_DIR);
|
|
10717
12365
|
for (const sub of SUBDIRS) {
|
|
10718
|
-
mkdirSync6(
|
|
12366
|
+
mkdirSync6(join19(oaPath, sub), { recursive: true });
|
|
10719
12367
|
}
|
|
10720
12368
|
return oaPath;
|
|
10721
12369
|
}
|
|
10722
12370
|
function hasOaDirectory(repoRoot) {
|
|
10723
|
-
return existsSync12(
|
|
12371
|
+
return existsSync12(join19(repoRoot, OA_DIR, "index"));
|
|
10724
12372
|
}
|
|
10725
12373
|
function loadProjectSettings(repoRoot) {
|
|
10726
|
-
const settingsPath =
|
|
12374
|
+
const settingsPath = join19(repoRoot, OA_DIR, "settings.json");
|
|
10727
12375
|
try {
|
|
10728
12376
|
if (existsSync12(settingsPath)) {
|
|
10729
12377
|
return JSON.parse(readFileSync10(settingsPath, "utf-8"));
|
|
@@ -10733,14 +12381,14 @@ function loadProjectSettings(repoRoot) {
|
|
|
10733
12381
|
return {};
|
|
10734
12382
|
}
|
|
10735
12383
|
function saveProjectSettings(repoRoot, settings) {
|
|
10736
|
-
const oaPath =
|
|
12384
|
+
const oaPath = join19(repoRoot, OA_DIR);
|
|
10737
12385
|
mkdirSync6(oaPath, { recursive: true });
|
|
10738
12386
|
const existing = loadProjectSettings(repoRoot);
|
|
10739
12387
|
const merged = { ...existing, ...settings };
|
|
10740
|
-
writeFileSync6(
|
|
12388
|
+
writeFileSync6(join19(oaPath, "settings.json"), JSON.stringify(merged, null, 2) + "\n", "utf-8");
|
|
10741
12389
|
}
|
|
10742
12390
|
function loadGlobalSettings() {
|
|
10743
|
-
const settingsPath =
|
|
12391
|
+
const settingsPath = join19(homedir7(), ".open-agents", "settings.json");
|
|
10744
12392
|
try {
|
|
10745
12393
|
if (existsSync12(settingsPath)) {
|
|
10746
12394
|
return JSON.parse(readFileSync10(settingsPath, "utf-8"));
|
|
@@ -10750,11 +12398,11 @@ function loadGlobalSettings() {
|
|
|
10750
12398
|
return {};
|
|
10751
12399
|
}
|
|
10752
12400
|
function saveGlobalSettings(settings) {
|
|
10753
|
-
const dir =
|
|
12401
|
+
const dir = join19(homedir7(), ".open-agents");
|
|
10754
12402
|
mkdirSync6(dir, { recursive: true });
|
|
10755
12403
|
const existing = loadGlobalSettings();
|
|
10756
12404
|
const merged = { ...existing, ...settings };
|
|
10757
|
-
writeFileSync6(
|
|
12405
|
+
writeFileSync6(join19(dir, "settings.json"), JSON.stringify(merged, null, 2) + "\n", "utf-8");
|
|
10758
12406
|
}
|
|
10759
12407
|
function resolveSettings(repoRoot) {
|
|
10760
12408
|
const global = loadGlobalSettings();
|
|
@@ -10769,7 +12417,7 @@ function discoverContextFiles(repoRoot, maxContentLen = 8e3) {
|
|
|
10769
12417
|
while (dir && !visited.has(dir)) {
|
|
10770
12418
|
visited.add(dir);
|
|
10771
12419
|
for (const name of CONTEXT_FILES) {
|
|
10772
|
-
const filePath =
|
|
12420
|
+
const filePath = join19(dir, name);
|
|
10773
12421
|
const normalizedName = name.toLowerCase();
|
|
10774
12422
|
if (existsSync12(filePath) && !seen.has(filePath)) {
|
|
10775
12423
|
seen.add(filePath);
|
|
@@ -10788,7 +12436,7 @@ function discoverContextFiles(repoRoot, maxContentLen = 8e3) {
|
|
|
10788
12436
|
}
|
|
10789
12437
|
}
|
|
10790
12438
|
}
|
|
10791
|
-
const projectMap =
|
|
12439
|
+
const projectMap = join19(dir, OA_DIR, "context", "project-map.md");
|
|
10792
12440
|
if (existsSync12(projectMap) && !seen.has(projectMap)) {
|
|
10793
12441
|
seen.add(projectMap);
|
|
10794
12442
|
try {
|
|
@@ -10804,7 +12452,7 @@ function discoverContextFiles(repoRoot, maxContentLen = 8e3) {
|
|
|
10804
12452
|
} catch {
|
|
10805
12453
|
}
|
|
10806
12454
|
}
|
|
10807
|
-
const parent =
|
|
12455
|
+
const parent = join19(dir, "..");
|
|
10808
12456
|
if (parent === dir)
|
|
10809
12457
|
break;
|
|
10810
12458
|
dir = parent;
|
|
@@ -10822,7 +12470,7 @@ function discoverContextFiles(repoRoot, maxContentLen = 8e3) {
|
|
|
10822
12470
|
return found;
|
|
10823
12471
|
}
|
|
10824
12472
|
function readIndexMeta(repoRoot) {
|
|
10825
|
-
const metaPath =
|
|
12473
|
+
const metaPath = join19(repoRoot, OA_DIR, "index", "meta.json");
|
|
10826
12474
|
try {
|
|
10827
12475
|
return JSON.parse(readFileSync10(metaPath, "utf-8"));
|
|
10828
12476
|
} catch {
|
|
@@ -10875,28 +12523,28 @@ ${tree}\`\`\`
|
|
|
10875
12523
|
sections.push("");
|
|
10876
12524
|
}
|
|
10877
12525
|
const content = sections.join("\n");
|
|
10878
|
-
const contextDir =
|
|
12526
|
+
const contextDir = join19(repoRoot, OA_DIR, "context");
|
|
10879
12527
|
mkdirSync6(contextDir, { recursive: true });
|
|
10880
|
-
writeFileSync6(
|
|
12528
|
+
writeFileSync6(join19(contextDir, "project-map.md"), content, "utf-8");
|
|
10881
12529
|
return content;
|
|
10882
12530
|
}
|
|
10883
12531
|
function saveSession(repoRoot, session) {
|
|
10884
|
-
const historyDir =
|
|
12532
|
+
const historyDir = join19(repoRoot, OA_DIR, "history");
|
|
10885
12533
|
mkdirSync6(historyDir, { recursive: true });
|
|
10886
|
-
writeFileSync6(
|
|
12534
|
+
writeFileSync6(join19(historyDir, `${session.id}.json`), JSON.stringify(session, null, 2), "utf-8");
|
|
10887
12535
|
}
|
|
10888
12536
|
function loadRecentSessions(repoRoot, limit = 5) {
|
|
10889
|
-
const historyDir =
|
|
12537
|
+
const historyDir = join19(repoRoot, OA_DIR, "history");
|
|
10890
12538
|
if (!existsSync12(historyDir))
|
|
10891
12539
|
return [];
|
|
10892
12540
|
try {
|
|
10893
12541
|
const files = readdirSync6(historyDir).filter((f) => f.endsWith(".json")).map((f) => {
|
|
10894
|
-
const
|
|
10895
|
-
return { file: f, mtime:
|
|
12542
|
+
const stat5 = statSync5(join19(historyDir, f));
|
|
12543
|
+
return { file: f, mtime: stat5.mtimeMs };
|
|
10896
12544
|
}).sort((a, b) => b.mtime - a.mtime).slice(0, limit);
|
|
10897
12545
|
return files.map((f) => {
|
|
10898
12546
|
try {
|
|
10899
|
-
return JSON.parse(readFileSync10(
|
|
12547
|
+
return JSON.parse(readFileSync10(join19(historyDir, f.file), "utf-8"));
|
|
10900
12548
|
} catch {
|
|
10901
12549
|
return null;
|
|
10902
12550
|
}
|
|
@@ -10906,12 +12554,12 @@ function loadRecentSessions(repoRoot, limit = 5) {
|
|
|
10906
12554
|
}
|
|
10907
12555
|
}
|
|
10908
12556
|
function savePendingTask(repoRoot, task) {
|
|
10909
|
-
const historyDir =
|
|
12557
|
+
const historyDir = join19(repoRoot, OA_DIR, "history");
|
|
10910
12558
|
mkdirSync6(historyDir, { recursive: true });
|
|
10911
|
-
writeFileSync6(
|
|
12559
|
+
writeFileSync6(join19(historyDir, PENDING_TASK_FILE), JSON.stringify(task, null, 2) + "\n", "utf-8");
|
|
10912
12560
|
}
|
|
10913
12561
|
function loadPendingTask(repoRoot) {
|
|
10914
|
-
const filePath =
|
|
12562
|
+
const filePath = join19(repoRoot, OA_DIR, "history", PENDING_TASK_FILE);
|
|
10915
12563
|
try {
|
|
10916
12564
|
if (!existsSync12(filePath))
|
|
10917
12565
|
return null;
|
|
@@ -10943,7 +12591,7 @@ function detectManifests(repoRoot) {
|
|
|
10943
12591
|
{ file: "docker-compose.yaml", type: "Docker Compose" }
|
|
10944
12592
|
];
|
|
10945
12593
|
for (const check of checks) {
|
|
10946
|
-
const filePath =
|
|
12594
|
+
const filePath = join19(repoRoot, check.file);
|
|
10947
12595
|
if (existsSync12(filePath)) {
|
|
10948
12596
|
let name;
|
|
10949
12597
|
if (check.nameField) {
|
|
@@ -10977,7 +12625,7 @@ function findKeyFiles(repoRoot) {
|
|
|
10977
12625
|
{ pattern: "CLAUDE.md", description: "Claude Code context" }
|
|
10978
12626
|
];
|
|
10979
12627
|
for (const check of checks) {
|
|
10980
|
-
if (existsSync12(
|
|
12628
|
+
if (existsSync12(join19(repoRoot, check.pattern))) {
|
|
10981
12629
|
keyFiles.push({ path: check.pattern, description: check.description });
|
|
10982
12630
|
}
|
|
10983
12631
|
}
|
|
@@ -11003,12 +12651,12 @@ function buildDirTree(root, maxDepth, prefix = "", depth = 0) {
|
|
|
11003
12651
|
if (entry.isDirectory()) {
|
|
11004
12652
|
let fileCount = 0;
|
|
11005
12653
|
try {
|
|
11006
|
-
fileCount = readdirSync6(
|
|
12654
|
+
fileCount = readdirSync6(join19(root, entry.name)).filter((f) => !f.startsWith(".")).length;
|
|
11007
12655
|
} catch {
|
|
11008
12656
|
}
|
|
11009
12657
|
result += `${prefix}${connector}${entry.name}/ (${fileCount})
|
|
11010
12658
|
`;
|
|
11011
|
-
result += buildDirTree(
|
|
12659
|
+
result += buildDirTree(join19(root, entry.name), maxDepth, childPrefix, depth + 1);
|
|
11012
12660
|
} else if (depth < maxDepth) {
|
|
11013
12661
|
result += `${prefix}${connector}${entry.name}
|
|
11014
12662
|
`;
|
|
@@ -11061,7 +12709,7 @@ var init_oa_directory = __esm({
|
|
|
11061
12709
|
import * as readline from "node:readline";
|
|
11062
12710
|
import { execSync as execSync10 } from "node:child_process";
|
|
11063
12711
|
import { existsSync as existsSync13, writeFileSync as writeFileSync7, mkdirSync as mkdirSync7 } from "node:fs";
|
|
11064
|
-
import { join as
|
|
12712
|
+
import { join as join20 } from "node:path";
|
|
11065
12713
|
import { homedir as homedir8 } from "node:os";
|
|
11066
12714
|
function detectSystemSpecs() {
|
|
11067
12715
|
let totalRamGB = 0;
|
|
@@ -11145,8 +12793,8 @@ function modelSupportsToolCalling(modelName) {
|
|
|
11145
12793
|
return false;
|
|
11146
12794
|
}
|
|
11147
12795
|
function ask(rl, question) {
|
|
11148
|
-
return new Promise((
|
|
11149
|
-
rl.question(question, (answer) =>
|
|
12796
|
+
return new Promise((resolve18) => {
|
|
12797
|
+
rl.question(question, (answer) => resolve18(answer.trim()));
|
|
11150
12798
|
});
|
|
11151
12799
|
}
|
|
11152
12800
|
function pullModelWithAutoUpdate(tag) {
|
|
@@ -11495,9 +13143,9 @@ async function doSetup(config, rl) {
|
|
|
11495
13143
|
`PARAMETER num_predict 16384`,
|
|
11496
13144
|
`PARAMETER stop "<|endoftext|>"`
|
|
11497
13145
|
].join("\n");
|
|
11498
|
-
const modelDir2 =
|
|
13146
|
+
const modelDir2 = join20(homedir8(), ".open-agents", "models");
|
|
11499
13147
|
mkdirSync7(modelDir2, { recursive: true });
|
|
11500
|
-
const modelfilePath =
|
|
13148
|
+
const modelfilePath = join20(modelDir2, `Modelfile.${customName}`);
|
|
11501
13149
|
writeFileSync7(modelfilePath, modelfileContent + "\n", "utf8");
|
|
11502
13150
|
process.stdout.write(` ${c2.dim("Creating model...")} `);
|
|
11503
13151
|
execSync10(`ollama create ${customName} -f ${modelfilePath}`, {
|
|
@@ -11535,7 +13183,7 @@ async function doSetup(config, rl) {
|
|
|
11535
13183
|
}
|
|
11536
13184
|
async function isModelAvailable(config) {
|
|
11537
13185
|
try {
|
|
11538
|
-
const models = await
|
|
13186
|
+
const models = await fetchModels(config.backendUrl, config.apiKey);
|
|
11539
13187
|
return !!findModel(models, config.model);
|
|
11540
13188
|
} catch {
|
|
11541
13189
|
return false;
|
|
@@ -11543,7 +13191,7 @@ async function isModelAvailable(config) {
|
|
|
11543
13191
|
}
|
|
11544
13192
|
function isFirstRun() {
|
|
11545
13193
|
try {
|
|
11546
|
-
return !existsSync13(
|
|
13194
|
+
return !existsSync13(join20(homedir8(), ".open-agents", "config.json"));
|
|
11547
13195
|
} catch {
|
|
11548
13196
|
return true;
|
|
11549
13197
|
}
|
|
@@ -11581,9 +13229,9 @@ function createExpandedVariant(baseModel, specs, sizeGB) {
|
|
|
11581
13229
|
`PARAMETER num_predict 16384`,
|
|
11582
13230
|
`PARAMETER stop "<|endoftext|>"`
|
|
11583
13231
|
].join("\n");
|
|
11584
|
-
const modelDir2 =
|
|
13232
|
+
const modelDir2 = join20(homedir8(), ".open-agents", "models");
|
|
11585
13233
|
mkdirSync7(modelDir2, { recursive: true });
|
|
11586
|
-
const modelfilePath =
|
|
13234
|
+
const modelfilePath = join20(modelDir2, `Modelfile.${customName}`);
|
|
11587
13235
|
writeFileSync7(modelfilePath, modelfileContent + "\n", "utf8");
|
|
11588
13236
|
execSync10(`ollama create ${customName} -f ${modelfilePath}`, {
|
|
11589
13237
|
stdio: "pipe",
|
|
@@ -11712,6 +13360,174 @@ async function handleSlashCommand(input, ctx) {
|
|
|
11712
13360
|
dryRun: String(ctx.config.dryRun)
|
|
11713
13361
|
});
|
|
11714
13362
|
return "handled";
|
|
13363
|
+
case "cost":
|
|
13364
|
+
case "costs":
|
|
13365
|
+
if (ctx.costTracker) {
|
|
13366
|
+
const summary = ctx.costTracker.getSummary();
|
|
13367
|
+
const lines = [];
|
|
13368
|
+
lines.push(c2.bold(` Session Cost Summary (${summary.provider})`));
|
|
13369
|
+
lines.push("");
|
|
13370
|
+
lines.push(` Input tokens: ${c2.bold(summary.totalInputTokens.toLocaleString())}`);
|
|
13371
|
+
lines.push(` Output tokens: ${c2.bold(summary.totalOutputTokens.toLocaleString())}`);
|
|
13372
|
+
if (ctx.costTracker.hasPricing) {
|
|
13373
|
+
lines.push(` Estimated cost: ${c2.bold(c2.yellow(ctx.costTracker.formatCost()))}`);
|
|
13374
|
+
lines.push(` Pricing: $${ctx.costTracker.provider.inputPer1M}/1M in, $${ctx.costTracker.provider.outputPer1M}/1M out`);
|
|
13375
|
+
} else {
|
|
13376
|
+
lines.push(` Cost: ${c2.dim("free (local provider)")}`);
|
|
13377
|
+
}
|
|
13378
|
+
if (summary.taskCount > 0) {
|
|
13379
|
+
lines.push("");
|
|
13380
|
+
lines.push(` Tasks: ${summary.taskCount}`);
|
|
13381
|
+
for (const t of summary.tasks.slice(-5)) {
|
|
13382
|
+
const costStr = ctx.costTracker.hasPricing ? ` ${ctx.costTracker.formatCost(t.estimatedCost)}` : "";
|
|
13383
|
+
const dur = (t.durationMs / 1e3).toFixed(1);
|
|
13384
|
+
lines.push(` ${c2.dim("\u2022")} ${t.task.slice(0, 50)}${t.task.length > 50 ? "..." : ""} \u2014 ${dur}s${costStr}`);
|
|
13385
|
+
}
|
|
13386
|
+
if (summary.taskCount > 5) {
|
|
13387
|
+
lines.push(` ${c2.dim(`... and ${summary.taskCount - 5} more`)}`);
|
|
13388
|
+
}
|
|
13389
|
+
}
|
|
13390
|
+
lines.push("");
|
|
13391
|
+
console.log(lines.join("\n"));
|
|
13392
|
+
} else {
|
|
13393
|
+
renderInfo("Cost tracking not available.");
|
|
13394
|
+
}
|
|
13395
|
+
return "handled";
|
|
13396
|
+
case "evaluate":
|
|
13397
|
+
case "eval":
|
|
13398
|
+
if (ctx.workEvaluator && ctx.lastTask && ctx.lastSummary) {
|
|
13399
|
+
renderInfo("Evaluating last completed task...");
|
|
13400
|
+
try {
|
|
13401
|
+
const evalResult = await ctx.workEvaluator.evaluate(ctx.lastTask, ctx.lastSummary);
|
|
13402
|
+
if (evalResult.success) {
|
|
13403
|
+
const lines = [];
|
|
13404
|
+
const pct = Math.round(evalResult.overallScore * 100);
|
|
13405
|
+
const scoreColor = pct >= 80 ? c2.green : pct >= 60 ? c2.yellow : c2.red;
|
|
13406
|
+
lines.push(`
|
|
13407
|
+
${c2.bold("Task Evaluation")} (${evalResult.taskType})`);
|
|
13408
|
+
lines.push(` Overall: ${scoreColor(c2.bold(`${pct}%`))}`);
|
|
13409
|
+
lines.push("");
|
|
13410
|
+
for (const d of evalResult.dimensions) {
|
|
13411
|
+
const bar = "\u2588".repeat(d.score) + "\u2591".repeat(10 - d.score);
|
|
13412
|
+
const dPct = Math.round(d.score / 10 * 100);
|
|
13413
|
+
const dColor = dPct >= 80 ? c2.green : dPct >= 60 ? c2.yellow : c2.red;
|
|
13414
|
+
lines.push(` ${d.name.padEnd(14)} ${dColor(bar)} ${dColor(`${d.score}/10`)} ${c2.dim(`(${Math.round(d.weight * 100)}%)`)}`);
|
|
13415
|
+
if (d.feedback)
|
|
13416
|
+
lines.push(` ${c2.dim(" " + d.feedback)}`);
|
|
13417
|
+
}
|
|
13418
|
+
if (evalResult.feedback) {
|
|
13419
|
+
lines.push("");
|
|
13420
|
+
lines.push(` ${c2.dim(evalResult.feedback)}`);
|
|
13421
|
+
}
|
|
13422
|
+
lines.push("");
|
|
13423
|
+
console.log(lines.join("\n"));
|
|
13424
|
+
} else {
|
|
13425
|
+
renderError(`Evaluation failed: ${evalResult.error}`);
|
|
13426
|
+
}
|
|
13427
|
+
} catch (err) {
|
|
13428
|
+
renderError(`Evaluation error: ${err instanceof Error ? err.message : String(err)}`);
|
|
13429
|
+
}
|
|
13430
|
+
} else if (!ctx.lastTask) {
|
|
13431
|
+
renderWarning("No completed task to evaluate. Complete a task first.");
|
|
13432
|
+
} else {
|
|
13433
|
+
renderWarning("Evaluation backend not configured.");
|
|
13434
|
+
}
|
|
13435
|
+
return "handled";
|
|
13436
|
+
case "task-type":
|
|
13437
|
+
case "tasktype":
|
|
13438
|
+
case "tt": {
|
|
13439
|
+
const validTypes = getTaskTypes();
|
|
13440
|
+
if (arg === "auto" || arg === "clear" || arg === "reset") {
|
|
13441
|
+
ctx.setTaskType?.(void 0);
|
|
13442
|
+
renderInfo("Task type set to auto-detect.");
|
|
13443
|
+
} else if (arg && validTypes.includes(arg)) {
|
|
13444
|
+
const type = arg;
|
|
13445
|
+
const template = getTaskTemplate(type);
|
|
13446
|
+
ctx.setTaskType?.(type);
|
|
13447
|
+
renderInfo(`Task type: ${c2.bold(template.label)} (${type})`);
|
|
13448
|
+
console.log(` ${c2.dim(template.description)}`);
|
|
13449
|
+
console.log(` ${c2.dim("Recommended tools:")} ${template.recommendedTools.slice(0, 5).join(", ")}`);
|
|
13450
|
+
console.log("");
|
|
13451
|
+
} else {
|
|
13452
|
+
const lines = [];
|
|
13453
|
+
lines.push(`
|
|
13454
|
+
${c2.bold("Available Task Types")}
|
|
13455
|
+
`);
|
|
13456
|
+
for (const t of validTypes) {
|
|
13457
|
+
const tmpl = getTaskTemplate(t);
|
|
13458
|
+
const active = ctx.taskType === t ? c2.green(" \u2190 active") : "";
|
|
13459
|
+
lines.push(` ${c2.bold(t.padEnd(10))} ${tmpl.label}${active}`);
|
|
13460
|
+
lines.push(` ${c2.dim(" " + tmpl.description)}`);
|
|
13461
|
+
}
|
|
13462
|
+
if (!ctx.taskType) {
|
|
13463
|
+
lines.push(`
|
|
13464
|
+
${c2.dim("Current: auto-detect")}`);
|
|
13465
|
+
}
|
|
13466
|
+
lines.push(`
|
|
13467
|
+
${c2.dim("Usage: /task-type <type> or /task-type auto")}`);
|
|
13468
|
+
lines.push("");
|
|
13469
|
+
console.log(lines.join("\n"));
|
|
13470
|
+
}
|
|
13471
|
+
return "handled";
|
|
13472
|
+
}
|
|
13473
|
+
case "stats":
|
|
13474
|
+
case "metrics":
|
|
13475
|
+
case "dashboard": {
|
|
13476
|
+
if (!ctx.sessionMetrics) {
|
|
13477
|
+
renderInfo("Session metrics not available.");
|
|
13478
|
+
return "handled";
|
|
13479
|
+
}
|
|
13480
|
+
const summary = ctx.sessionMetrics.getSummary();
|
|
13481
|
+
const dur = SessionMetrics.formatDuration(summary.sessionDurationMs);
|
|
13482
|
+
const lines = [];
|
|
13483
|
+
lines.push(`
|
|
13484
|
+
${c2.bold("Session Dashboard")}
|
|
13485
|
+
`);
|
|
13486
|
+
lines.push(` Duration: ${c2.bold(dur)}`);
|
|
13487
|
+
lines.push(` Tasks completed: ${c2.bold(String(summary.tasksCompleted))}`);
|
|
13488
|
+
lines.push(` Turns: ${c2.bold(String(summary.totalTurns))}`);
|
|
13489
|
+
lines.push(` Tool calls: ${c2.bold(String(summary.totalToolCalls))}`);
|
|
13490
|
+
lines.push(` Input tokens: ${c2.bold(summary.totalInputTokens.toLocaleString())}`);
|
|
13491
|
+
lines.push(` Output tokens: ${c2.bold(summary.totalOutputTokens.toLocaleString())}`);
|
|
13492
|
+
if (ctx.costTracker?.hasPricing) {
|
|
13493
|
+
lines.push(` Estimated cost: ${c2.bold(c2.yellow(ctx.costTracker.formatCost()))}`);
|
|
13494
|
+
}
|
|
13495
|
+
const topTools = ctx.sessionMetrics.getTopTools(5);
|
|
13496
|
+
if (topTools.length > 0) {
|
|
13497
|
+
lines.push(`
|
|
13498
|
+
${c2.bold("Top Tools")}`);
|
|
13499
|
+
for (const t of topTools) {
|
|
13500
|
+
const bar = "\u2588".repeat(Math.min(t.count, 30));
|
|
13501
|
+
lines.push(` ${t.name.padEnd(20)} ${c2.dim(bar)} ${t.count}`);
|
|
13502
|
+
}
|
|
13503
|
+
}
|
|
13504
|
+
if (summary.filesModified.length > 0) {
|
|
13505
|
+
lines.push(`
|
|
13506
|
+
${c2.bold("Files Modified")} (${summary.filesModified.length})`);
|
|
13507
|
+
for (const f of summary.filesModified.slice(0, 10)) {
|
|
13508
|
+
lines.push(` ${c2.dim("\u2022")} ${f}`);
|
|
13509
|
+
}
|
|
13510
|
+
if (summary.filesModified.length > 10) {
|
|
13511
|
+
lines.push(` ${c2.dim(`... and ${summary.filesModified.length - 10} more`)}`);
|
|
13512
|
+
}
|
|
13513
|
+
}
|
|
13514
|
+
if (summary.tasks.length > 0) {
|
|
13515
|
+
lines.push(`
|
|
13516
|
+
${c2.bold("Task History")}`);
|
|
13517
|
+
for (const task of summary.tasks.slice(-5)) {
|
|
13518
|
+
const taskDur = task.durationMs ? SessionMetrics.formatDuration(task.durationMs) : "?";
|
|
13519
|
+
const score = task.evaluationScore !== void 0 ? ` ${c2.dim(`(${Math.round(task.evaluationScore * 100)}%)`)}` : "";
|
|
13520
|
+
lines.push(` ${c2.dim("\u2022")} ${task.description.slice(0, 50)}${task.description.length > 50 ? "..." : ""} \u2014 ${taskDur}${score}`);
|
|
13521
|
+
}
|
|
13522
|
+
}
|
|
13523
|
+
if (summary.averageEvalScore !== void 0) {
|
|
13524
|
+
lines.push(`
|
|
13525
|
+
Avg eval score: ${c2.bold(`${Math.round(summary.averageEvalScore * 100)}%`)}`);
|
|
13526
|
+
}
|
|
13527
|
+
lines.push("");
|
|
13528
|
+
console.log(lines.join("\n"));
|
|
13529
|
+
return "handled";
|
|
13530
|
+
}
|
|
11715
13531
|
case "model":
|
|
11716
13532
|
if (arg) {
|
|
11717
13533
|
await switchModel(arg, ctx, hasLocal);
|
|
@@ -11910,7 +13726,7 @@ async function handleSlashCommand(input, ctx) {
|
|
|
11910
13726
|
}
|
|
11911
13727
|
async function listModels(ctx) {
|
|
11912
13728
|
try {
|
|
11913
|
-
const models = await
|
|
13729
|
+
const models = await fetchModels(ctx.config.backendUrl, ctx.config.apiKey);
|
|
11914
13730
|
renderModelList(models.map((m) => ({ name: m.name, size: m.size, modified: m.modified })), ctx.config.model);
|
|
11915
13731
|
} catch (err) {
|
|
11916
13732
|
renderError(`Failed to fetch models: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -11918,9 +13734,9 @@ async function listModels(ctx) {
|
|
|
11918
13734
|
}
|
|
11919
13735
|
async function showModelPicker(ctx) {
|
|
11920
13736
|
try {
|
|
11921
|
-
const models = await
|
|
13737
|
+
const models = await fetchModels(ctx.config.backendUrl, ctx.config.apiKey);
|
|
11922
13738
|
if (models.length === 0) {
|
|
11923
|
-
renderWarning("No models found.
|
|
13739
|
+
renderWarning("No models found.");
|
|
11924
13740
|
return;
|
|
11925
13741
|
}
|
|
11926
13742
|
renderModelList(models.map((m) => ({ name: m.name, size: m.size, modified: m.modified })), ctx.config.model);
|
|
@@ -12051,15 +13867,15 @@ async function handleUpdate(subcommand, ctx) {
|
|
|
12051
13867
|
let currentVersion = "0.0.0";
|
|
12052
13868
|
try {
|
|
12053
13869
|
const { createRequire: createRequire4 } = await import("node:module");
|
|
12054
|
-
const { fileURLToPath:
|
|
12055
|
-
const { dirname:
|
|
13870
|
+
const { fileURLToPath: fileURLToPath4 } = await import("node:url");
|
|
13871
|
+
const { dirname: dirname7, join: join30 } = await import("node:path");
|
|
12056
13872
|
const { existsSync: existsSync19 } = await import("node:fs");
|
|
12057
13873
|
const req = createRequire4(import.meta.url);
|
|
12058
|
-
const thisDir =
|
|
13874
|
+
const thisDir = dirname7(fileURLToPath4(import.meta.url));
|
|
12059
13875
|
const candidates = [
|
|
12060
|
-
|
|
12061
|
-
|
|
12062
|
-
|
|
13876
|
+
join30(thisDir, "..", "package.json"),
|
|
13877
|
+
join30(thisDir, "..", "..", "package.json"),
|
|
13878
|
+
join30(thisDir, "..", "..", "..", "package.json")
|
|
12063
13879
|
];
|
|
12064
13880
|
for (const pkgPath of candidates) {
|
|
12065
13881
|
if (existsSync19(pkgPath)) {
|
|
@@ -12114,7 +13930,7 @@ async function handleUpdate(subcommand, ctx) {
|
|
|
12114
13930
|
}
|
|
12115
13931
|
async function switchModel(query, ctx, local = false) {
|
|
12116
13932
|
try {
|
|
12117
|
-
const models = await
|
|
13933
|
+
const models = await fetchModels(ctx.config.backendUrl, ctx.config.apiKey);
|
|
12118
13934
|
const match = findModel(models, query);
|
|
12119
13935
|
if (!match) {
|
|
12120
13936
|
renderError(`Model not found: "${query}"`);
|
|
@@ -12157,6 +13973,8 @@ var init_commands = __esm({
|
|
|
12157
13973
|
init_render();
|
|
12158
13974
|
init_dist2();
|
|
12159
13975
|
init_config();
|
|
13976
|
+
init_dist5();
|
|
13977
|
+
init_dist6();
|
|
12160
13978
|
init_updater();
|
|
12161
13979
|
init_oa_directory();
|
|
12162
13980
|
init_setup();
|
|
@@ -12166,7 +13984,7 @@ var init_commands = __esm({
|
|
|
12166
13984
|
|
|
12167
13985
|
// packages/cli/dist/tui/project-context.js
|
|
12168
13986
|
import { existsSync as existsSync14, readFileSync as readFileSync11, readdirSync as readdirSync7 } from "node:fs";
|
|
12169
|
-
import { join as
|
|
13987
|
+
import { join as join21, basename as basename5 } from "node:path";
|
|
12170
13988
|
import { execSync as execSync11 } from "node:child_process";
|
|
12171
13989
|
import { homedir as homedir9, platform, release } from "node:os";
|
|
12172
13990
|
function loadProjectFiles(repoRoot) {
|
|
@@ -12186,7 +14004,7 @@ function loadProjectMap(repoRoot) {
|
|
|
12186
14004
|
if (!hasOaDirectory(repoRoot)) {
|
|
12187
14005
|
initOaDirectory(repoRoot);
|
|
12188
14006
|
}
|
|
12189
|
-
const mapPath =
|
|
14007
|
+
const mapPath = join21(repoRoot, OA_DIR, "context", "project-map.md");
|
|
12190
14008
|
if (existsSync14(mapPath)) {
|
|
12191
14009
|
try {
|
|
12192
14010
|
const content = readFileSync11(mapPath, "utf-8");
|
|
@@ -12230,17 +14048,17 @@ ${log}`);
|
|
|
12230
14048
|
}
|
|
12231
14049
|
function loadMemoryContext(repoRoot) {
|
|
12232
14050
|
const sections = [];
|
|
12233
|
-
const oaMemDir =
|
|
14051
|
+
const oaMemDir = join21(repoRoot, OA_DIR, "memory");
|
|
12234
14052
|
const oaEntries = loadMemoryDir(oaMemDir, "project");
|
|
12235
14053
|
if (oaEntries)
|
|
12236
14054
|
sections.push(oaEntries);
|
|
12237
|
-
const legacyMemDir =
|
|
14055
|
+
const legacyMemDir = join21(repoRoot, ".open-agents", "memory");
|
|
12238
14056
|
if (legacyMemDir !== oaMemDir && existsSync14(legacyMemDir)) {
|
|
12239
14057
|
const legacyEntries = loadMemoryDir(legacyMemDir, "project/legacy");
|
|
12240
14058
|
if (legacyEntries)
|
|
12241
14059
|
sections.push(legacyEntries);
|
|
12242
14060
|
}
|
|
12243
|
-
const globalMemDir =
|
|
14061
|
+
const globalMemDir = join21(homedir9(), ".open-agents", "memory");
|
|
12244
14062
|
const globalEntries = loadMemoryDir(globalMemDir, "global");
|
|
12245
14063
|
if (globalEntries)
|
|
12246
14064
|
sections.push(globalEntries);
|
|
@@ -12254,7 +14072,7 @@ function loadMemoryDir(memDir, scope) {
|
|
|
12254
14072
|
const files = readdirSync7(memDir).filter((f) => f.endsWith(".json"));
|
|
12255
14073
|
for (const file of files.slice(0, 10)) {
|
|
12256
14074
|
try {
|
|
12257
|
-
const raw = readFileSync11(
|
|
14075
|
+
const raw = readFileSync11(join21(memDir, file), "utf-8");
|
|
12258
14076
|
const entries = JSON.parse(raw);
|
|
12259
14077
|
const topic = basename5(file, ".json");
|
|
12260
14078
|
const keys = Object.keys(entries);
|
|
@@ -12967,7 +14785,7 @@ var init_toolPatternStore = __esm({
|
|
|
12967
14785
|
});
|
|
12968
14786
|
|
|
12969
14787
|
// packages/memory/dist/index.js
|
|
12970
|
-
var
|
|
14788
|
+
var init_dist7 = __esm({
|
|
12971
14789
|
"packages/memory/dist/index.js"() {
|
|
12972
14790
|
"use strict";
|
|
12973
14791
|
init_db();
|
|
@@ -13266,24 +15084,24 @@ var init_carousel = __esm({
|
|
|
13266
15084
|
|
|
13267
15085
|
// packages/cli/dist/tui/voice.js
|
|
13268
15086
|
import { existsSync as existsSync15, mkdirSync as mkdirSync8, writeFileSync as writeFileSync8, readFileSync as readFileSync12, unlinkSync as unlinkSync3 } from "node:fs";
|
|
13269
|
-
import { join as
|
|
13270
|
-
import { homedir as homedir10, tmpdir as
|
|
15087
|
+
import { join as join22 } from "node:path";
|
|
15088
|
+
import { homedir as homedir10, tmpdir as tmpdir3, platform as platform2 } from "node:os";
|
|
13271
15089
|
import { execSync as execSync12, spawn as nodeSpawn } from "node:child_process";
|
|
13272
15090
|
import { createRequire } from "node:module";
|
|
13273
15091
|
function voiceDir() {
|
|
13274
|
-
return
|
|
15092
|
+
return join22(homedir10(), ".open-agents", "voice");
|
|
13275
15093
|
}
|
|
13276
15094
|
function modelsDir() {
|
|
13277
|
-
return
|
|
15095
|
+
return join22(voiceDir(), "models");
|
|
13278
15096
|
}
|
|
13279
15097
|
function modelDir(id) {
|
|
13280
|
-
return
|
|
15098
|
+
return join22(modelsDir(), id);
|
|
13281
15099
|
}
|
|
13282
15100
|
function modelOnnxPath(id) {
|
|
13283
|
-
return
|
|
15101
|
+
return join22(modelDir(id), "model.onnx");
|
|
13284
15102
|
}
|
|
13285
15103
|
function modelConfigPath(id) {
|
|
13286
|
-
return
|
|
15104
|
+
return join22(modelDir(id), "config.json");
|
|
13287
15105
|
}
|
|
13288
15106
|
function describeToolCall(toolName, args) {
|
|
13289
15107
|
const path = args["path"];
|
|
@@ -13556,7 +15374,7 @@ var init_voice = __esm({
|
|
|
13556
15374
|
const audioData = result["output"].data;
|
|
13557
15375
|
if (audioData.length === 0)
|
|
13558
15376
|
return;
|
|
13559
|
-
const wavPath =
|
|
15377
|
+
const wavPath = join22(tmpdir3(), `oa-voice-${Date.now()}.wav`);
|
|
13560
15378
|
this.writeWav(audioData, this.config.audio.sample_rate, wavPath);
|
|
13561
15379
|
await this.playWav(wavPath);
|
|
13562
15380
|
try {
|
|
@@ -13645,7 +15463,7 @@ var init_voice = __esm({
|
|
|
13645
15463
|
const cmd = this.getPlayCommand(path);
|
|
13646
15464
|
if (!cmd)
|
|
13647
15465
|
return;
|
|
13648
|
-
return new Promise((
|
|
15466
|
+
return new Promise((resolve18) => {
|
|
13649
15467
|
const child = nodeSpawn(cmd[0], cmd.slice(1), {
|
|
13650
15468
|
stdio: "ignore",
|
|
13651
15469
|
detached: false
|
|
@@ -13654,12 +15472,12 @@ var init_voice = __esm({
|
|
|
13654
15472
|
child.on("close", () => {
|
|
13655
15473
|
if (this.currentPlayback === child)
|
|
13656
15474
|
this.currentPlayback = null;
|
|
13657
|
-
|
|
15475
|
+
resolve18();
|
|
13658
15476
|
});
|
|
13659
15477
|
child.on("error", () => {
|
|
13660
15478
|
if (this.currentPlayback === child)
|
|
13661
15479
|
this.currentPlayback = null;
|
|
13662
|
-
|
|
15480
|
+
resolve18();
|
|
13663
15481
|
});
|
|
13664
15482
|
setTimeout(() => {
|
|
13665
15483
|
if (this.currentPlayback === child) {
|
|
@@ -13669,7 +15487,7 @@ var init_voice = __esm({
|
|
|
13669
15487
|
}
|
|
13670
15488
|
this.currentPlayback = null;
|
|
13671
15489
|
}
|
|
13672
|
-
|
|
15490
|
+
resolve18();
|
|
13673
15491
|
}, 15e3);
|
|
13674
15492
|
});
|
|
13675
15493
|
}
|
|
@@ -13709,7 +15527,7 @@ var init_voice = __esm({
|
|
|
13709
15527
|
if (this.ort)
|
|
13710
15528
|
return;
|
|
13711
15529
|
mkdirSync8(voiceDir(), { recursive: true });
|
|
13712
|
-
const pkgPath =
|
|
15530
|
+
const pkgPath = join22(voiceDir(), "package.json");
|
|
13713
15531
|
const expectedDeps = {
|
|
13714
15532
|
"onnxruntime-node": "^1.21.0",
|
|
13715
15533
|
"phonemizer": "^1.2.1"
|
|
@@ -13731,7 +15549,7 @@ var init_voice = __esm({
|
|
|
13731
15549
|
dependencies: expectedDeps
|
|
13732
15550
|
}, null, 2));
|
|
13733
15551
|
}
|
|
13734
|
-
const voiceRequire = createRequire(
|
|
15552
|
+
const voiceRequire = createRequire(join22(voiceDir(), "index.js"));
|
|
13735
15553
|
try {
|
|
13736
15554
|
this.ort = voiceRequire("onnxruntime-node");
|
|
13737
15555
|
} catch {
|
|
@@ -14328,10 +16146,10 @@ var init_stream_renderer = __esm({
|
|
|
14328
16146
|
|
|
14329
16147
|
// packages/cli/dist/tui/edit-history.js
|
|
14330
16148
|
import { appendFileSync, mkdirSync as mkdirSync9 } from "node:fs";
|
|
14331
|
-
import { join as
|
|
16149
|
+
import { join as join23 } from "node:path";
|
|
14332
16150
|
function createEditHistoryLogger(repoRoot, sessionId) {
|
|
14333
|
-
const historyDir =
|
|
14334
|
-
const logPath =
|
|
16151
|
+
const historyDir = join23(repoRoot, ".oa", "history");
|
|
16152
|
+
const logPath = join23(historyDir, "edits.jsonl");
|
|
14335
16153
|
try {
|
|
14336
16154
|
mkdirSync9(historyDir, { recursive: true });
|
|
14337
16155
|
} catch {
|
|
@@ -14443,7 +16261,7 @@ var init_edit_history = __esm({
|
|
|
14443
16261
|
|
|
14444
16262
|
// packages/cli/dist/tui/dream-engine.js
|
|
14445
16263
|
import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync9, readFileSync as readFileSync13, existsSync as existsSync16, cpSync, rmSync, readdirSync as readdirSync8 } from "node:fs";
|
|
14446
|
-
import { join as
|
|
16264
|
+
import { join as join24, basename as basename6 } from "node:path";
|
|
14447
16265
|
import { execSync as execSync13 } from "node:child_process";
|
|
14448
16266
|
function adaptTool(tool) {
|
|
14449
16267
|
return {
|
|
@@ -14618,12 +16436,12 @@ var init_dream_engine = __esm({
|
|
|
14618
16436
|
const content = String(args["content"] ?? "");
|
|
14619
16437
|
if (!rawPath)
|
|
14620
16438
|
return { success: false, output: "", error: "path is required", durationMs: Date.now() - start };
|
|
14621
|
-
const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ?
|
|
16439
|
+
const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ? join24(this.dreamsDir, basename6(rawPath)) : join24(this.dreamsDir, rawPath);
|
|
14622
16440
|
if (!targetPath.startsWith(this.dreamsDir)) {
|
|
14623
16441
|
return { success: false, output: "", error: "Dream mode: writes are confined to .oa/dreams/", durationMs: Date.now() - start };
|
|
14624
16442
|
}
|
|
14625
16443
|
try {
|
|
14626
|
-
const dir =
|
|
16444
|
+
const dir = join24(targetPath, "..");
|
|
14627
16445
|
mkdirSync10(dir, { recursive: true });
|
|
14628
16446
|
writeFileSync9(targetPath, content, "utf-8");
|
|
14629
16447
|
return { success: true, output: `Wrote ${content.length} bytes to ${rawPath}`, durationMs: Date.now() - start };
|
|
@@ -14653,7 +16471,7 @@ var init_dream_engine = __esm({
|
|
|
14653
16471
|
const rawPath = String(args["path"] ?? "");
|
|
14654
16472
|
const oldStr = String(args["old_string"] ?? "");
|
|
14655
16473
|
const newStr = String(args["new_string"] ?? "");
|
|
14656
|
-
const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ?
|
|
16474
|
+
const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ? join24(this.dreamsDir, basename6(rawPath)) : join24(this.dreamsDir, rawPath);
|
|
14657
16475
|
if (!targetPath.startsWith(this.dreamsDir)) {
|
|
14658
16476
|
return { success: false, output: "", error: "Dream mode: edits are confined to .oa/dreams/", durationMs: Date.now() - start };
|
|
14659
16477
|
}
|
|
@@ -14720,7 +16538,7 @@ var init_dream_engine = __esm({
|
|
|
14720
16538
|
constructor(config, repoRoot) {
|
|
14721
16539
|
this.config = config;
|
|
14722
16540
|
this.repoRoot = repoRoot;
|
|
14723
|
-
this.dreamsDir =
|
|
16541
|
+
this.dreamsDir = join24(repoRoot, ".oa", "dreams");
|
|
14724
16542
|
this.state = {
|
|
14725
16543
|
mode: "default",
|
|
14726
16544
|
active: false,
|
|
@@ -14792,7 +16610,7 @@ ${result.summary}`;
|
|
|
14792
16610
|
if (mode !== "default" || cycle === totalCycles) {
|
|
14793
16611
|
renderDreamContraction(cycle);
|
|
14794
16612
|
const cycleSummary = this.buildCycleSummary(cycle, previousFindings);
|
|
14795
|
-
const summaryPath =
|
|
16613
|
+
const summaryPath = join24(this.dreamsDir, `cycle-${cycle}-summary.md`);
|
|
14796
16614
|
writeFileSync9(summaryPath, cycleSummary, "utf-8");
|
|
14797
16615
|
}
|
|
14798
16616
|
if (mode === "lucid" && !this.abortController.signal.aborted) {
|
|
@@ -14913,7 +16731,7 @@ Dreams directory: ${this.dreamsDir}`);
|
|
|
14913
16731
|
}
|
|
14914
16732
|
/** Save workspace backup for lucid mode */
|
|
14915
16733
|
saveVersionCheckpoint(cycle) {
|
|
14916
|
-
const checkpointDir =
|
|
16734
|
+
const checkpointDir = join24(this.dreamsDir, "checkpoints", `cycle-${cycle}`);
|
|
14917
16735
|
try {
|
|
14918
16736
|
mkdirSync10(checkpointDir, { recursive: true });
|
|
14919
16737
|
try {
|
|
@@ -14932,10 +16750,10 @@ Dreams directory: ${this.dreamsDir}`);
|
|
|
14932
16750
|
encoding: "utf-8",
|
|
14933
16751
|
timeout: 5e3
|
|
14934
16752
|
}).trim();
|
|
14935
|
-
writeFileSync9(
|
|
14936
|
-
writeFileSync9(
|
|
14937
|
-
writeFileSync9(
|
|
14938
|
-
writeFileSync9(
|
|
16753
|
+
writeFileSync9(join24(checkpointDir, "git-status.txt"), gitStatus, "utf-8");
|
|
16754
|
+
writeFileSync9(join24(checkpointDir, "git-diff.patch"), gitDiff, "utf-8");
|
|
16755
|
+
writeFileSync9(join24(checkpointDir, "git-hash.txt"), gitHash, "utf-8");
|
|
16756
|
+
writeFileSync9(join24(checkpointDir, "checkpoint.json"), JSON.stringify({
|
|
14939
16757
|
cycle,
|
|
14940
16758
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
14941
16759
|
gitHash,
|
|
@@ -14943,7 +16761,7 @@ Dreams directory: ${this.dreamsDir}`);
|
|
|
14943
16761
|
}, null, 2), "utf-8");
|
|
14944
16762
|
renderInfo(`Checkpoint saved: cycle ${cycle} (${gitHash.slice(0, 8)})`);
|
|
14945
16763
|
} catch {
|
|
14946
|
-
writeFileSync9(
|
|
16764
|
+
writeFileSync9(join24(checkpointDir, "checkpoint.json"), JSON.stringify({ cycle, timestamp: (/* @__PURE__ */ new Date()).toISOString(), mode: this.state.mode }, null, 2), "utf-8");
|
|
14947
16765
|
renderInfo(`Checkpoint saved: cycle ${cycle} (no git)`);
|
|
14948
16766
|
}
|
|
14949
16767
|
} catch (err) {
|
|
@@ -15001,14 +16819,14 @@ ${files.map((f) => `- [\`${f}\`](./${f})`).join("\n")}
|
|
|
15001
16819
|
---
|
|
15002
16820
|
*Auto-generated by open-agents dream engine*
|
|
15003
16821
|
`;
|
|
15004
|
-
writeFileSync9(
|
|
16822
|
+
writeFileSync9(join24(this.dreamsDir, "PROPOSAL-INDEX.md"), index, "utf-8");
|
|
15005
16823
|
} catch {
|
|
15006
16824
|
}
|
|
15007
16825
|
}
|
|
15008
16826
|
/** Save dream state for resume/inspection */
|
|
15009
16827
|
saveDreamState() {
|
|
15010
16828
|
try {
|
|
15011
|
-
writeFileSync9(
|
|
16829
|
+
writeFileSync9(join24(this.dreamsDir, "dream-state.json"), JSON.stringify(this.state, null, 2) + "\n", "utf-8");
|
|
15012
16830
|
} catch {
|
|
15013
16831
|
}
|
|
15014
16832
|
}
|
|
@@ -15244,13 +17062,18 @@ var init_status_bar = __esm({
|
|
|
15244
17062
|
const ctxPct = ctxTotal > 0 ? Math.max(0, Math.min(100, Math.round((1 - ctxUsed / ctxTotal) * 100))) : 100;
|
|
15245
17063
|
const ctxColor = ctxPct > 50 ? c2.green : ctxPct > 20 ? c2.yellow : c2.red;
|
|
15246
17064
|
const ctxLabel = pastel2(153, "Ctx: ") + c2.bold(`${ctxUsed.toLocaleString()}/${ctxTotal.toLocaleString()}`) + ` ${ctxColor(`${ctxPct}%`)}`;
|
|
17065
|
+
let costLabel = "";
|
|
17066
|
+
if (m.hasPricing && m.estimatedCost !== void 0) {
|
|
17067
|
+
const costStr = m.estimatedCost < 0.01 ? `$${m.estimatedCost.toFixed(4)}` : m.estimatedCost < 1 ? `$${m.estimatedCost.toFixed(3)}` : `$${m.estimatedCost.toFixed(2)}`;
|
|
17068
|
+
costLabel = pipe + pastel2(222, "Cost: ") + c2.bold(costStr);
|
|
17069
|
+
}
|
|
15247
17070
|
let recordingLabel = "";
|
|
15248
17071
|
if (this._recording) {
|
|
15249
17072
|
const dot = this._recBlink ? pastel2(210, "\u25CF") : " ";
|
|
15250
17073
|
const countdown = this._countdown > 0 ? c2.dim(` ${this._countdown}s`) : "";
|
|
15251
17074
|
recordingLabel = pipe + dot + pastel2(210, " REC") + countdown;
|
|
15252
17075
|
}
|
|
15253
|
-
return ` ${tokInLabel}${pipe}${tokOutLabel}${pipe}${ctxLabel}${recordingLabel}`;
|
|
17076
|
+
return ` ${tokInLabel}${pipe}${tokOutLabel}${pipe}${ctxLabel}${costLabel}${recordingLabel}`;
|
|
15254
17077
|
}
|
|
15255
17078
|
// -------------------------------------------------------------------------
|
|
15256
17079
|
// Private
|
|
@@ -15377,19 +17200,19 @@ var init_status_bar = __esm({
|
|
|
15377
17200
|
import * as readline2 from "node:readline";
|
|
15378
17201
|
import { Writable } from "node:stream";
|
|
15379
17202
|
import { cwd } from "node:process";
|
|
15380
|
-
import { resolve as
|
|
17203
|
+
import { resolve as resolve15, join as join25, dirname as dirname5, extname as extname8 } from "node:path";
|
|
15381
17204
|
import { createRequire as createRequire2 } from "node:module";
|
|
15382
|
-
import { fileURLToPath } from "node:url";
|
|
17205
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
15383
17206
|
import { readFileSync as readFileSync14 } from "node:fs";
|
|
15384
17207
|
import { existsSync as existsSync17 } from "node:fs";
|
|
15385
17208
|
function getVersion() {
|
|
15386
17209
|
try {
|
|
15387
17210
|
const require2 = createRequire2(import.meta.url);
|
|
15388
|
-
const thisDir =
|
|
17211
|
+
const thisDir = dirname5(fileURLToPath2(import.meta.url));
|
|
15389
17212
|
const candidates = [
|
|
15390
|
-
|
|
15391
|
-
|
|
15392
|
-
|
|
17213
|
+
join25(thisDir, "..", "package.json"),
|
|
17214
|
+
join25(thisDir, "..", "..", "package.json"),
|
|
17215
|
+
join25(thisDir, "..", "..", "..", "package.json")
|
|
15393
17216
|
];
|
|
15394
17217
|
for (const pkgPath of candidates) {
|
|
15395
17218
|
if (existsSync17(pkgPath)) {
|
|
@@ -15472,7 +17295,13 @@ function buildTools(repoRoot, config) {
|
|
|
15472
17295
|
new SkillExecuteTool(repoRoot),
|
|
15473
17296
|
// Transcription tools (transcribe-cli / faster-whisper)
|
|
15474
17297
|
new TranscribeFileTool(repoRoot),
|
|
15475
|
-
new TranscribeUrlTool(repoRoot)
|
|
17298
|
+
new TranscribeUrlTool(repoRoot),
|
|
17299
|
+
// Structured file generation (CSV, JSON, Markdown, Excel-compatible)
|
|
17300
|
+
new StructuredFileTool(repoRoot),
|
|
17301
|
+
// Code sandbox (isolated code execution)
|
|
17302
|
+
new CodeSandboxTool(repoRoot),
|
|
17303
|
+
// Structured file reading (CSV, JSON, Markdown, binary detection)
|
|
17304
|
+
new StructuredReadTool(repoRoot)
|
|
15476
17305
|
];
|
|
15477
17306
|
return [
|
|
15478
17307
|
...executionTools.map(adaptTool2),
|
|
@@ -15552,9 +17381,12 @@ Use task_status("${taskId}") or task_output("${taskId}") to check progress.`
|
|
|
15552
17381
|
}
|
|
15553
17382
|
};
|
|
15554
17383
|
}
|
|
15555
|
-
function startTask(task, config, repoRoot, voice, stream, taskStores, bruteForce, statusBar, sudoCallback) {
|
|
17384
|
+
function startTask(task, config, repoRoot, voice, stream, taskStores, bruteForce, statusBar, sudoCallback, costTracker, onComplete, taskType) {
|
|
15556
17385
|
const projectCtx = buildProjectContext(repoRoot, taskStores?.contextStores);
|
|
15557
|
-
|
|
17386
|
+
let dynamicContext = formatContextForPrompt(projectCtx);
|
|
17387
|
+
if (taskType) {
|
|
17388
|
+
dynamicContext += "\n\n" + buildTaskContext(taskType);
|
|
17389
|
+
}
|
|
15558
17390
|
const backend = new OllamaAgenticBackend(config.backendUrl, config.model, config.apiKey);
|
|
15559
17391
|
const runner = new AgenticRunner(backend, {
|
|
15560
17392
|
maxTurns: 60,
|
|
@@ -15658,7 +17490,14 @@ function startTask(task, config, repoRoot, voice, stream, taskStores, bruteForce
|
|
|
15658
17490
|
break;
|
|
15659
17491
|
case "token_usage":
|
|
15660
17492
|
if (statusBar && event.tokenUsage) {
|
|
15661
|
-
|
|
17493
|
+
if (costTracker && event.tokenUsage.promptTokens > 0) {
|
|
17494
|
+
costTracker.trackTokens(event.tokenUsage.promptTokens, event.tokenUsage.completionTokens);
|
|
17495
|
+
}
|
|
17496
|
+
statusBar.updateMetrics({
|
|
17497
|
+
...event.tokenUsage,
|
|
17498
|
+
estimatedCost: costTracker?.currentCost,
|
|
17499
|
+
hasPricing: costTracker?.hasPricing
|
|
17500
|
+
});
|
|
15662
17501
|
}
|
|
15663
17502
|
break;
|
|
15664
17503
|
case "sudo_request":
|
|
@@ -15677,6 +17516,8 @@ function startTask(task, config, repoRoot, voice, stream, taskStores, bruteForce
|
|
|
15677
17516
|
contentWrite(() => {
|
|
15678
17517
|
if (result.completed) {
|
|
15679
17518
|
renderTaskComplete(result.summary, result.turns, result.toolCalls, result.durationMs, tokens);
|
|
17519
|
+
if (onComplete)
|
|
17520
|
+
onComplete(result.summary);
|
|
15680
17521
|
if (voice?.enabled && result.summary) {
|
|
15681
17522
|
const ttsText = result.summary.length > 300 ? result.summary.slice(0, 300) + "..." : result.summary;
|
|
15682
17523
|
voice.speak(`Task complete. ${ttsText}`);
|
|
@@ -15734,7 +17575,7 @@ function startTask(task, config, repoRoot, voice, stream, taskStores, bruteForce
|
|
|
15734
17575
|
} };
|
|
15735
17576
|
}
|
|
15736
17577
|
async function startInteractive(config, repoPath) {
|
|
15737
|
-
const repoRoot =
|
|
17578
|
+
const repoRoot = resolve15(repoPath ?? cwd());
|
|
15738
17579
|
const isResumed = !!process.env.__OA_RESUMED;
|
|
15739
17580
|
if (isResumed) {
|
|
15740
17581
|
delete process.env.__OA_RESUMED;
|
|
@@ -15803,8 +17644,8 @@ async function startInteractive(config, repoPath) {
|
|
|
15803
17644
|
if (!isResumed) {
|
|
15804
17645
|
try {
|
|
15805
17646
|
const baseUrl = normalizeBaseUrl(config.backendUrl);
|
|
15806
|
-
const
|
|
15807
|
-
const healthUrl = `${baseUrl}${
|
|
17647
|
+
const provider2 = detectProvider(config.backendUrl);
|
|
17648
|
+
const healthUrl = `${baseUrl}${provider2.modelsPath}`;
|
|
15808
17649
|
const headers = {};
|
|
15809
17650
|
if (config.apiKey) {
|
|
15810
17651
|
headers["Authorization"] = `Bearer ${config.apiKey}`;
|
|
@@ -15813,9 +17654,9 @@ async function startInteractive(config, repoPath) {
|
|
|
15813
17654
|
if (!resp.ok)
|
|
15814
17655
|
throw new Error(`HTTP ${resp.status}`);
|
|
15815
17656
|
} catch {
|
|
15816
|
-
const
|
|
15817
|
-
renderWarning(`Cannot reach ${
|
|
15818
|
-
if (
|
|
17657
|
+
const provider2 = detectProvider(config.backendUrl);
|
|
17658
|
+
renderWarning(`Cannot reach ${provider2.label} at ${config.backendUrl}`);
|
|
17659
|
+
if (provider2.id === "ollama") {
|
|
15819
17660
|
renderInfo("Start Ollama with: ollama serve");
|
|
15820
17661
|
}
|
|
15821
17662
|
renderInfo("Use /endpoint to configure a different backend. Starting anyway...");
|
|
@@ -15846,6 +17687,10 @@ async function startInteractive(config, repoPath) {
|
|
|
15846
17687
|
end: () => statusBar.endContentWrite()
|
|
15847
17688
|
});
|
|
15848
17689
|
}
|
|
17690
|
+
const provider = detectProvider(config.backendUrl);
|
|
17691
|
+
const costTracker = new CostTracker(provider.id);
|
|
17692
|
+
const sessionMetrics = new SessionMetrics();
|
|
17693
|
+
const workEvaluator = new WorkEvaluator();
|
|
15849
17694
|
ensureTranscribeCliBackground();
|
|
15850
17695
|
const voiceEngine = new VoiceEngine();
|
|
15851
17696
|
const streamRenderer = new StreamRenderer();
|
|
@@ -15863,6 +17708,8 @@ async function startInteractive(config, repoPath) {
|
|
|
15863
17708
|
let messageQueue = [];
|
|
15864
17709
|
let carouselRetired = isResumed;
|
|
15865
17710
|
let lastSubmittedPrompt = "";
|
|
17711
|
+
let lastCompletedSummary = "";
|
|
17712
|
+
let currentTaskType;
|
|
15866
17713
|
let sessionFilesTouched = [];
|
|
15867
17714
|
let sessionToolCallCount = 0;
|
|
15868
17715
|
let sessionSudoPassword = null;
|
|
@@ -15930,11 +17777,43 @@ async function startInteractive(config, repoPath) {
|
|
|
15930
17777
|
const sudoPromptStr = ` ${c2.bold(c2.yellow("\u{1F511} Password:"))} `;
|
|
15931
17778
|
process.stdout.write(sudoPromptStr);
|
|
15932
17779
|
}
|
|
17780
|
+
const evalBackend = {
|
|
17781
|
+
async evaluate(prompt) {
|
|
17782
|
+
const backend = new OllamaAgenticBackend(currentConfig.backendUrl, currentConfig.model, currentConfig.apiKey);
|
|
17783
|
+
const result = await backend.chatCompletion({
|
|
17784
|
+
messages: [
|
|
17785
|
+
{ role: "system", content: "You are a quality evaluator. Respond with JSON only." },
|
|
17786
|
+
{ role: "user", content: prompt }
|
|
17787
|
+
],
|
|
17788
|
+
tools: [],
|
|
17789
|
+
temperature: 0,
|
|
17790
|
+
maxTokens: 2048,
|
|
17791
|
+
timeoutMs: currentConfig.timeoutMs
|
|
17792
|
+
});
|
|
17793
|
+
return result.choices[0]?.message?.content ?? "";
|
|
17794
|
+
}
|
|
17795
|
+
};
|
|
17796
|
+
workEvaluator.setBackend(evalBackend);
|
|
15933
17797
|
const commandCtx = {
|
|
15934
17798
|
get config() {
|
|
15935
17799
|
return currentConfig;
|
|
15936
17800
|
},
|
|
15937
17801
|
repoRoot,
|
|
17802
|
+
costTracker,
|
|
17803
|
+
workEvaluator,
|
|
17804
|
+
get lastTask() {
|
|
17805
|
+
return lastSubmittedPrompt;
|
|
17806
|
+
},
|
|
17807
|
+
get lastSummary() {
|
|
17808
|
+
return lastCompletedSummary;
|
|
17809
|
+
},
|
|
17810
|
+
get taskType() {
|
|
17811
|
+
return currentTaskType;
|
|
17812
|
+
},
|
|
17813
|
+
setTaskType(type) {
|
|
17814
|
+
currentTaskType = type;
|
|
17815
|
+
},
|
|
17816
|
+
sessionMetrics,
|
|
15938
17817
|
setModel(model) {
|
|
15939
17818
|
currentConfig = { ...currentConfig, model };
|
|
15940
17819
|
},
|
|
@@ -15948,6 +17827,8 @@ async function startInteractive(config, repoPath) {
|
|
|
15948
17827
|
backendType,
|
|
15949
17828
|
...apiKey !== void 0 ? { apiKey } : {}
|
|
15950
17829
|
};
|
|
17830
|
+
const newProvider = detectProvider(url);
|
|
17831
|
+
costTracker.setProvider(newProvider.id);
|
|
15951
17832
|
},
|
|
15952
17833
|
clearScreen() {
|
|
15953
17834
|
process.stdout.write("\x1B[2J\x1B[H");
|
|
@@ -16223,7 +18104,9 @@ Execute this skill now. Follow the behavioral guidance above.`;
|
|
|
16223
18104
|
taskMemoryStore: taskMemoryStore ?? void 0,
|
|
16224
18105
|
failureStore: failureStore ?? void 0,
|
|
16225
18106
|
toolPatternStore: toolPatternStore ?? void 0
|
|
16226
|
-
}, bruteForceEnabled, statusBar, handleSudoRequest)
|
|
18107
|
+
}, bruteForceEnabled, statusBar, handleSudoRequest, costTracker, (summary) => {
|
|
18108
|
+
lastCompletedSummary = summary;
|
|
18109
|
+
}, currentTaskType);
|
|
16227
18110
|
activeTask = task;
|
|
16228
18111
|
showPrompt();
|
|
16229
18112
|
await task.promise;
|
|
@@ -16237,15 +18120,15 @@ Execute this skill now. Follow the behavioral guidance above.`;
|
|
|
16237
18120
|
}
|
|
16238
18121
|
}
|
|
16239
18122
|
const cleanPath = input.replace(/^['"]|['"]$/g, "").trim();
|
|
16240
|
-
const isImage = isImagePath(cleanPath) && existsSync17(
|
|
16241
|
-
const isMedia = !isImage && isTranscribablePath(cleanPath) && existsSync17(
|
|
18123
|
+
const isImage = isImagePath(cleanPath) && existsSync17(resolve15(repoRoot, cleanPath));
|
|
18124
|
+
const isMedia = !isImage && isTranscribablePath(cleanPath) && existsSync17(resolve15(repoRoot, cleanPath));
|
|
16242
18125
|
if (activeTask) {
|
|
16243
18126
|
if (isImage) {
|
|
16244
18127
|
try {
|
|
16245
|
-
const imgPath =
|
|
18128
|
+
const imgPath = resolve15(repoRoot, cleanPath);
|
|
16246
18129
|
const imgBuffer = readFileSync14(imgPath);
|
|
16247
18130
|
const base64 = imgBuffer.toString("base64");
|
|
16248
|
-
const ext =
|
|
18131
|
+
const ext = extname8(cleanPath).toLowerCase();
|
|
16249
18132
|
const mime = ext === ".png" ? "image/png" : ext === ".gif" ? "image/gif" : ext === ".webp" ? "image/webp" : "image/jpeg";
|
|
16250
18133
|
activeTask.runner.injectImage(base64, mime, `User shared image: ${cleanPath}`);
|
|
16251
18134
|
writeContent(() => renderUserInterrupt(`[Image: ${cleanPath}]`));
|
|
@@ -16256,7 +18139,7 @@ Execute this skill now. Follow the behavioral guidance above.`;
|
|
|
16256
18139
|
} else if (isMedia) {
|
|
16257
18140
|
writeContent(() => renderInfo(`Transcribing: ${cleanPath}...`));
|
|
16258
18141
|
const engine = getListenEngine();
|
|
16259
|
-
const result = await engine.transcribeFile(
|
|
18142
|
+
const result = await engine.transcribeFile(resolve15(repoRoot, cleanPath), repoRoot);
|
|
16260
18143
|
if (result) {
|
|
16261
18144
|
const transcript = `[Transcription of ${cleanPath}]
|
|
16262
18145
|
${result.text}`;
|
|
@@ -16289,7 +18172,7 @@ ${result.text}`;
|
|
|
16289
18172
|
if (isMedia && fullInput === input) {
|
|
16290
18173
|
writeContent(() => renderInfo(`Transcribing: ${cleanPath}...`));
|
|
16291
18174
|
const engine = getListenEngine();
|
|
16292
|
-
const result = await engine.transcribeFile(
|
|
18175
|
+
const result = await engine.transcribeFile(resolve15(repoRoot, cleanPath), repoRoot);
|
|
16293
18176
|
if (result) {
|
|
16294
18177
|
fullInput = `The user has provided an audio/video file: ${cleanPath}.
|
|
16295
18178
|
|
|
@@ -16321,7 +18204,9 @@ Summarize or analyze this transcription as appropriate.`;
|
|
|
16321
18204
|
taskMemoryStore: taskMemoryStore ?? void 0,
|
|
16322
18205
|
failureStore: failureStore ?? void 0,
|
|
16323
18206
|
toolPatternStore: toolPatternStore ?? void 0
|
|
16324
|
-
}, bruteForceEnabled, statusBar, handleSudoRequest)
|
|
18207
|
+
}, bruteForceEnabled, statusBar, handleSudoRequest, costTracker, (summary) => {
|
|
18208
|
+
lastCompletedSummary = summary;
|
|
18209
|
+
}, currentTaskType);
|
|
16325
18210
|
activeTask = task;
|
|
16326
18211
|
showPrompt();
|
|
16327
18212
|
await task.promise;
|
|
@@ -16405,7 +18290,7 @@ ${c2.dim("(Use /quit to exit)")}
|
|
|
16405
18290
|
});
|
|
16406
18291
|
}
|
|
16407
18292
|
async function runWithTUI(task, config, repoPath) {
|
|
16408
|
-
const repoRoot =
|
|
18293
|
+
const repoRoot = resolve15(repoPath ?? cwd());
|
|
16409
18294
|
const needsSetup = isFirstRun() || !await isModelAvailable(config);
|
|
16410
18295
|
if (needsSetup && config.backendType === "ollama") {
|
|
16411
18296
|
const setupModel = await runSetupWizard(config);
|
|
@@ -16463,7 +18348,7 @@ var init_interactive = __esm({
|
|
|
16463
18348
|
init_commands();
|
|
16464
18349
|
init_setup();
|
|
16465
18350
|
init_project_context();
|
|
16466
|
-
|
|
18351
|
+
init_dist7();
|
|
16467
18352
|
init_oa_directory();
|
|
16468
18353
|
init_render();
|
|
16469
18354
|
init_carousel();
|
|
@@ -16472,6 +18357,7 @@ var init_interactive = __esm({
|
|
|
16472
18357
|
init_edit_history();
|
|
16473
18358
|
init_dream_engine();
|
|
16474
18359
|
init_status_bar();
|
|
18360
|
+
init_dist6();
|
|
16475
18361
|
taskManager = new BackgroundTaskManager();
|
|
16476
18362
|
}
|
|
16477
18363
|
});
|
|
@@ -16505,9 +18391,9 @@ var init_run = __esm({
|
|
|
16505
18391
|
// packages/indexer/dist/codebase-indexer.js
|
|
16506
18392
|
import { glob } from "glob";
|
|
16507
18393
|
import ignore from "ignore";
|
|
16508
|
-
import { readFile as
|
|
18394
|
+
import { readFile as readFile10, stat as stat4 } from "node:fs/promises";
|
|
16509
18395
|
import { createHash } from "node:crypto";
|
|
16510
|
-
import { join as
|
|
18396
|
+
import { join as join26, relative as relative3, extname as extname9, basename as basename7 } from "node:path";
|
|
16511
18397
|
var DEFAULT_EXCLUDE, LANGUAGE_MAP, CodebaseIndexer;
|
|
16512
18398
|
var init_codebase_indexer = __esm({
|
|
16513
18399
|
"packages/indexer/dist/codebase-indexer.js"() {
|
|
@@ -16551,7 +18437,7 @@ var init_codebase_indexer = __esm({
|
|
|
16551
18437
|
const ig = ignore.default();
|
|
16552
18438
|
if (this.config.respectGitignore) {
|
|
16553
18439
|
try {
|
|
16554
|
-
const gitignoreContent = await
|
|
18440
|
+
const gitignoreContent = await readFile10(join26(this.config.rootDir, ".gitignore"), "utf-8");
|
|
16555
18441
|
ig.add(gitignoreContent);
|
|
16556
18442
|
} catch {
|
|
16557
18443
|
}
|
|
@@ -16566,14 +18452,14 @@ var init_codebase_indexer = __esm({
|
|
|
16566
18452
|
for (const relativePath of files) {
|
|
16567
18453
|
if (ig.ignores(relativePath))
|
|
16568
18454
|
continue;
|
|
16569
|
-
const fullPath =
|
|
18455
|
+
const fullPath = join26(this.config.rootDir, relativePath);
|
|
16570
18456
|
try {
|
|
16571
|
-
const fileStat = await
|
|
18457
|
+
const fileStat = await stat4(fullPath);
|
|
16572
18458
|
if (fileStat.size > this.config.maxFileSize)
|
|
16573
18459
|
continue;
|
|
16574
|
-
const content = await
|
|
18460
|
+
const content = await readFile10(fullPath);
|
|
16575
18461
|
const hash = createHash("sha256").update(content).digest("hex");
|
|
16576
|
-
const ext =
|
|
18462
|
+
const ext = extname9(relativePath);
|
|
16577
18463
|
indexed.push({
|
|
16578
18464
|
path: fullPath,
|
|
16579
18465
|
relativePath,
|
|
@@ -16612,7 +18498,7 @@ var init_codebase_indexer = __esm({
|
|
|
16612
18498
|
if (!child) {
|
|
16613
18499
|
child = {
|
|
16614
18500
|
name: part,
|
|
16615
|
-
path:
|
|
18501
|
+
path: join26(current.path, part),
|
|
16616
18502
|
type: "directory",
|
|
16617
18503
|
children: []
|
|
16618
18504
|
};
|
|
@@ -16669,7 +18555,7 @@ var init_embeddings = __esm({
|
|
|
16669
18555
|
});
|
|
16670
18556
|
|
|
16671
18557
|
// packages/indexer/dist/index.js
|
|
16672
|
-
var
|
|
18558
|
+
var init_dist8 = __esm({
|
|
16673
18559
|
"packages/indexer/dist/index.js"() {
|
|
16674
18560
|
"use strict";
|
|
16675
18561
|
init_codebase_indexer();
|
|
@@ -16686,19 +18572,19 @@ var index_repo_exports = {};
|
|
|
16686
18572
|
__export(index_repo_exports, {
|
|
16687
18573
|
indexRepoCommand: () => indexRepoCommand
|
|
16688
18574
|
});
|
|
16689
|
-
import { resolve as
|
|
18575
|
+
import { resolve as resolve16 } from "node:path";
|
|
16690
18576
|
import { existsSync as existsSync18, statSync as statSync6 } from "node:fs";
|
|
16691
18577
|
import { cwd as cwd2 } from "node:process";
|
|
16692
18578
|
async function indexRepoCommand(opts, _config) {
|
|
16693
|
-
const repoRoot =
|
|
18579
|
+
const repoRoot = resolve16(opts.repoPath ?? cwd2());
|
|
16694
18580
|
printHeader("Index Repository");
|
|
16695
18581
|
printInfo(`Indexing: ${repoRoot}`);
|
|
16696
18582
|
if (!existsSync18(repoRoot)) {
|
|
16697
18583
|
printError(`Path does not exist: ${repoRoot}`);
|
|
16698
18584
|
process.exit(1);
|
|
16699
18585
|
}
|
|
16700
|
-
const
|
|
16701
|
-
if (!
|
|
18586
|
+
const stat5 = statSync6(repoRoot);
|
|
18587
|
+
if (!stat5.isDirectory()) {
|
|
16702
18588
|
printError(`Path is not a directory: ${repoRoot}`);
|
|
16703
18589
|
process.exit(1);
|
|
16704
18590
|
}
|
|
@@ -16776,7 +18662,7 @@ async function indexRepoCommand(opts, _config) {
|
|
|
16776
18662
|
var init_index_repo = __esm({
|
|
16777
18663
|
"packages/cli/dist/commands/index-repo.js"() {
|
|
16778
18664
|
"use strict";
|
|
16779
|
-
|
|
18665
|
+
init_dist8();
|
|
16780
18666
|
init_spinner();
|
|
16781
18667
|
init_output();
|
|
16782
18668
|
}
|
|
@@ -16939,7 +18825,7 @@ var config_exports = {};
|
|
|
16939
18825
|
__export(config_exports, {
|
|
16940
18826
|
configCommand: () => configCommand
|
|
16941
18827
|
});
|
|
16942
|
-
import { join as
|
|
18828
|
+
import { join as join27, resolve as resolve17 } from "node:path";
|
|
16943
18829
|
import { homedir as homedir11 } from "node:os";
|
|
16944
18830
|
import { cwd as cwd3 } from "node:process";
|
|
16945
18831
|
function coerceForSettings(key, value) {
|
|
@@ -16960,7 +18846,7 @@ async function configCommand(opts, config) {
|
|
|
16960
18846
|
return handleShow(opts, config);
|
|
16961
18847
|
}
|
|
16962
18848
|
function handleShow(opts, config) {
|
|
16963
|
-
const repoRoot =
|
|
18849
|
+
const repoRoot = resolve17(opts.repoPath ?? cwd3());
|
|
16964
18850
|
printHeader("Configuration");
|
|
16965
18851
|
printSection("Active Settings (merged)");
|
|
16966
18852
|
printKeyValue("backendUrl", config.backendUrl, 2);
|
|
@@ -16992,7 +18878,7 @@ function handleShow(opts, config) {
|
|
|
16992
18878
|
}
|
|
16993
18879
|
}
|
|
16994
18880
|
printSection("Config File");
|
|
16995
|
-
printInfo(`~/.open-agents/config.json (${
|
|
18881
|
+
printInfo(`~/.open-agents/config.json (${join27(homedir11(), ".open-agents", "config.json")})`);
|
|
16996
18882
|
printSection("Priority Chain");
|
|
16997
18883
|
printInfo(" 1. CLI flags (--model, --backend-url, etc.)");
|
|
16998
18884
|
printInfo(" 2. Project .oa/settings.json (--local)");
|
|
@@ -17025,13 +18911,13 @@ function handleSet(opts, _config) {
|
|
|
17025
18911
|
process.exit(1);
|
|
17026
18912
|
}
|
|
17027
18913
|
if (opts.local) {
|
|
17028
|
-
const repoRoot =
|
|
18914
|
+
const repoRoot = resolve17(opts.repoPath ?? cwd3());
|
|
17029
18915
|
try {
|
|
17030
18916
|
initOaDirectory(repoRoot);
|
|
17031
18917
|
const coerced = coerceForSettings(key, value);
|
|
17032
18918
|
saveProjectSettings(repoRoot, { [key]: coerced });
|
|
17033
18919
|
printSuccess(`Project override set: ${key} = ${value}`);
|
|
17034
|
-
printInfo(`Saved to ${
|
|
18920
|
+
printInfo(`Saved to ${join27(repoRoot, ".oa", "settings.json")}`);
|
|
17035
18921
|
printInfo("This override applies only when running in this workspace.");
|
|
17036
18922
|
} catch (err) {
|
|
17037
18923
|
printError(`Failed to save: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -17091,7 +18977,7 @@ var serve_exports = {};
|
|
|
17091
18977
|
__export(serve_exports, {
|
|
17092
18978
|
serveCommand: () => serveCommand
|
|
17093
18979
|
});
|
|
17094
|
-
import { spawn as
|
|
18980
|
+
import { spawn as spawn7 } from "node:child_process";
|
|
17095
18981
|
async function serveCommand(opts, config) {
|
|
17096
18982
|
const backendType = config.backendType;
|
|
17097
18983
|
if (backendType === "ollama") {
|
|
@@ -17183,8 +19069,8 @@ async function serveVllm(opts, config) {
|
|
|
17183
19069
|
await runVllmServer(args, opts.verbose ?? false);
|
|
17184
19070
|
}
|
|
17185
19071
|
async function runVllmServer(args, verbose) {
|
|
17186
|
-
return new Promise((
|
|
17187
|
-
const child =
|
|
19072
|
+
return new Promise((resolve18, reject) => {
|
|
19073
|
+
const child = spawn7("python", args, {
|
|
17188
19074
|
stdio: verbose ? "inherit" : ["ignore", "pipe", "pipe"],
|
|
17189
19075
|
env: { ...process.env }
|
|
17190
19076
|
});
|
|
@@ -17218,10 +19104,10 @@ async function runVllmServer(args, verbose) {
|
|
|
17218
19104
|
child.once("exit", (code, signal) => {
|
|
17219
19105
|
if (signal) {
|
|
17220
19106
|
printInfo(`vLLM server stopped by signal ${signal}`);
|
|
17221
|
-
|
|
19107
|
+
resolve18();
|
|
17222
19108
|
} else if (code === 0) {
|
|
17223
19109
|
printSuccess("vLLM server exited cleanly");
|
|
17224
|
-
|
|
19110
|
+
resolve18();
|
|
17225
19111
|
} else {
|
|
17226
19112
|
printError(`vLLM server exited with code ${code}`);
|
|
17227
19113
|
reject(new Error(`vLLM exited with code ${code}`));
|
|
@@ -17248,9 +19134,9 @@ var eval_exports = {};
|
|
|
17248
19134
|
__export(eval_exports, {
|
|
17249
19135
|
evalCommand: () => evalCommand
|
|
17250
19136
|
});
|
|
17251
|
-
import { tmpdir as
|
|
19137
|
+
import { tmpdir as tmpdir4 } from "node:os";
|
|
17252
19138
|
import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync10 } from "node:fs";
|
|
17253
|
-
import { join as
|
|
19139
|
+
import { join as join28 } from "node:path";
|
|
17254
19140
|
async function evalCommand(opts, config) {
|
|
17255
19141
|
const suiteName = opts.suite ?? "basic";
|
|
17256
19142
|
const suite = SUITES[suiteName];
|
|
@@ -17371,9 +19257,9 @@ async function evalCommand(opts, config) {
|
|
|
17371
19257
|
process.exit(failed > 0 ? 1 : 0);
|
|
17372
19258
|
}
|
|
17373
19259
|
function createTempEvalRepo() {
|
|
17374
|
-
const dir =
|
|
19260
|
+
const dir = join28(tmpdir4(), `open-agents-eval-${Date.now()}`);
|
|
17375
19261
|
mkdirSync11(dir, { recursive: true });
|
|
17376
|
-
writeFileSync10(
|
|
19262
|
+
writeFileSync10(join28(dir, "package.json"), JSON.stringify({ name: "eval-repo", version: "0.0.0" }, null, 2) + "\n", "utf8");
|
|
17377
19263
|
return dir;
|
|
17378
19264
|
}
|
|
17379
19265
|
var BASIC_SUITE, FULL_SUITE, SUITES;
|
|
@@ -17432,8 +19318,8 @@ init_output();
|
|
|
17432
19318
|
init_updater();
|
|
17433
19319
|
import { parseArgs as nodeParseArgs2 } from "node:util";
|
|
17434
19320
|
import { createRequire as createRequire3 } from "node:module";
|
|
17435
|
-
import { fileURLToPath as
|
|
17436
|
-
import { dirname as
|
|
19321
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
19322
|
+
import { dirname as dirname6, join as join29 } from "node:path";
|
|
17437
19323
|
|
|
17438
19324
|
// packages/cli/dist/cli.js
|
|
17439
19325
|
import { createInterface } from "node:readline";
|
|
@@ -17540,7 +19426,7 @@ init_output();
|
|
|
17540
19426
|
function getVersion2() {
|
|
17541
19427
|
try {
|
|
17542
19428
|
const require2 = createRequire3(import.meta.url);
|
|
17543
|
-
const pkgPath =
|
|
19429
|
+
const pkgPath = join29(dirname6(fileURLToPath3(import.meta.url)), "..", "package.json");
|
|
17544
19430
|
const pkg = require2(pkgPath);
|
|
17545
19431
|
return pkg.version;
|
|
17546
19432
|
} catch {
|