open-agents-ai 0.35.2 → 0.37.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/README.md +86 -1
- package/dist/index.js +1648 -331
- package/dist/scripts/web_scrape.py +1273 -0
- package/package.json +4 -2
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((resolve26) => {
|
|
1289
1289
|
const child = spawn("bash", ["-c", command], {
|
|
1290
1290
|
cwd: this.workingDir,
|
|
1291
1291
|
env: {
|
|
@@ -1313,7 +1313,7 @@ ${stdinInput ?? ""}`);
|
|
|
1313
1313
|
clearTimeout(timer);
|
|
1314
1314
|
if (exitFlushTimer)
|
|
1315
1315
|
clearTimeout(exitFlushTimer);
|
|
1316
|
-
|
|
1316
|
+
resolve26(result);
|
|
1317
1317
|
};
|
|
1318
1318
|
const timer = setTimeout(() => {
|
|
1319
1319
|
killed = true;
|
|
@@ -2317,7 +2317,7 @@ Meta: ${metaKeys.map((k) => `${k}="${meta[k]?.slice(0, 80)}"`).join(", ")}`);
|
|
|
2317
2317
|
return null;
|
|
2318
2318
|
}
|
|
2319
2319
|
runProcess(cmd, args, timeoutMs) {
|
|
2320
|
-
return new Promise((
|
|
2320
|
+
return new Promise((resolve26, reject) => {
|
|
2321
2321
|
const proc = execFile3(cmd, args, {
|
|
2322
2322
|
timeout: timeoutMs,
|
|
2323
2323
|
maxBuffer: 10 * 1024 * 1024,
|
|
@@ -2327,7 +2327,7 @@ Meta: ${metaKeys.map((k) => `${k}="${meta[k]?.slice(0, 80)}"`).join(", ")}`);
|
|
|
2327
2327
|
reject(new Error(`Process timeout after ${timeoutMs}ms`));
|
|
2328
2328
|
return;
|
|
2329
2329
|
}
|
|
2330
|
-
|
|
2330
|
+
resolve26({
|
|
2331
2331
|
stdout: String(stdout),
|
|
2332
2332
|
stderr: String(stderr),
|
|
2333
2333
|
exitCode: error ? error.code ?? 1 : 0
|
|
@@ -2906,6 +2906,10 @@ var init_explore_tools = __esm({
|
|
|
2906
2906
|
code_sandbox: "Run code in an isolated sandbox",
|
|
2907
2907
|
structured_read: "Read structured data files (CSV, JSON)",
|
|
2908
2908
|
sub_agent: "Delegate a subtask to a new agent instance",
|
|
2909
|
+
browser_action: "Automate headless Chrome: navigate, click, type, screenshot, read DOM",
|
|
2910
|
+
scheduler: "Schedule tasks for automatic future execution via OS cron",
|
|
2911
|
+
reminder: "Set reminders that surface at future agent startups",
|
|
2912
|
+
agenda: "View all pending reminders, scheduled tasks, and attention items",
|
|
2909
2913
|
background_run: "Run a shell command in the background",
|
|
2910
2914
|
task_status: "Check status of background tasks",
|
|
2911
2915
|
task_output: "Read output from a background task",
|
|
@@ -5357,7 +5361,7 @@ var init_custom_tool = __esm({
|
|
|
5357
5361
|
}
|
|
5358
5362
|
/** Execute a single shell command and return output */
|
|
5359
5363
|
runCommand(command) {
|
|
5360
|
-
return new Promise((
|
|
5364
|
+
return new Promise((resolve26) => {
|
|
5361
5365
|
const child = spawn3("bash", ["-c", command], {
|
|
5362
5366
|
cwd: this.workingDir,
|
|
5363
5367
|
env: { ...process.env, CI: "true", NO_COLOR: "1" },
|
|
@@ -5382,11 +5386,11 @@ var init_custom_tool = __esm({
|
|
|
5382
5386
|
child.kill("SIGTERM");
|
|
5383
5387
|
} catch {
|
|
5384
5388
|
}
|
|
5385
|
-
|
|
5389
|
+
resolve26({ success: false, output: stdout, error: "Command timed out after 60s" });
|
|
5386
5390
|
}, 6e4);
|
|
5387
5391
|
child.on("close", (code) => {
|
|
5388
5392
|
clearTimeout(timer);
|
|
5389
|
-
|
|
5393
|
+
resolve26({
|
|
5390
5394
|
success: code === 0,
|
|
5391
5395
|
output: stdout + (stderr && code === 0 ? `
|
|
5392
5396
|
STDERR:
|
|
@@ -5396,7 +5400,7 @@ ${stderr}` : ""),
|
|
|
5396
5400
|
});
|
|
5397
5401
|
child.on("error", (err) => {
|
|
5398
5402
|
clearTimeout(timer);
|
|
5399
|
-
|
|
5403
|
+
resolve26({ success: false, output: stdout, error: err.message });
|
|
5400
5404
|
});
|
|
5401
5405
|
});
|
|
5402
5406
|
}
|
|
@@ -6578,7 +6582,7 @@ import { writeFile as writeFile7, mkdtemp, rm, readdir as readdir2, stat } from
|
|
|
6578
6582
|
import { join as join16 } from "node:path";
|
|
6579
6583
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
6580
6584
|
function runProcess(cmd, args, options) {
|
|
6581
|
-
return new Promise((
|
|
6585
|
+
return new Promise((resolve26) => {
|
|
6582
6586
|
const proc = spawn5(cmd, args, {
|
|
6583
6587
|
cwd: options.cwd,
|
|
6584
6588
|
timeout: options.timeout,
|
|
@@ -6608,7 +6612,7 @@ function runProcess(cmd, args, options) {
|
|
|
6608
6612
|
}
|
|
6609
6613
|
});
|
|
6610
6614
|
proc.on("error", (err) => {
|
|
6611
|
-
|
|
6615
|
+
resolve26({
|
|
6612
6616
|
stdout,
|
|
6613
6617
|
stderr: stderr || err.message,
|
|
6614
6618
|
exitCode: 1,
|
|
@@ -6620,7 +6624,7 @@ function runProcess(cmd, args, options) {
|
|
|
6620
6624
|
if (signal === "SIGTERM" || signal === "SIGKILL") {
|
|
6621
6625
|
timedOut = true;
|
|
6622
6626
|
}
|
|
6623
|
-
|
|
6627
|
+
resolve26({
|
|
6624
6628
|
stdout,
|
|
6625
6629
|
stderr,
|
|
6626
6630
|
exitCode: code ?? (timedOut ? 124 : 1),
|
|
@@ -8650,6 +8654,1248 @@ Note: Advanced Python pipeline not available \u2014 install pytesseract, opencv-
|
|
|
8650
8654
|
}
|
|
8651
8655
|
});
|
|
8652
8656
|
|
|
8657
|
+
// packages/execution/dist/tools/browser-action.js
|
|
8658
|
+
import { execSync as execSync15, spawn as spawn7 } from "node:child_process";
|
|
8659
|
+
import { existsSync as existsSync18, readFileSync as readFileSync13 } from "node:fs";
|
|
8660
|
+
import { join as join21, dirname as dirname8 } from "node:path";
|
|
8661
|
+
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
8662
|
+
async function probeService() {
|
|
8663
|
+
try {
|
|
8664
|
+
const controller = new AbortController();
|
|
8665
|
+
const timeout = setTimeout(() => controller.abort(), 3e3);
|
|
8666
|
+
const res = await fetch(`${BASE_URL}/health`, { signal: controller.signal });
|
|
8667
|
+
clearTimeout(timeout);
|
|
8668
|
+
return res.ok;
|
|
8669
|
+
} catch {
|
|
8670
|
+
return false;
|
|
8671
|
+
}
|
|
8672
|
+
}
|
|
8673
|
+
function findPython2() {
|
|
8674
|
+
for (const cmd of ["python3", "python"]) {
|
|
8675
|
+
try {
|
|
8676
|
+
const ver = execSync15(`${cmd} --version 2>&1`, { stdio: "pipe", timeout: 5e3 }).toString().trim();
|
|
8677
|
+
if (ver.includes("Python 3"))
|
|
8678
|
+
return cmd;
|
|
8679
|
+
} catch {
|
|
8680
|
+
}
|
|
8681
|
+
}
|
|
8682
|
+
return null;
|
|
8683
|
+
}
|
|
8684
|
+
async function launchService() {
|
|
8685
|
+
if (await probeService())
|
|
8686
|
+
return null;
|
|
8687
|
+
const python = findPython2();
|
|
8688
|
+
if (!python)
|
|
8689
|
+
return "Python 3 not found. Install Python 3.9+ to use browser automation.";
|
|
8690
|
+
if (!existsSync18(SCRAPE_SCRIPT)) {
|
|
8691
|
+
return `Scrape service script not found at ${SCRAPE_SCRIPT}`;
|
|
8692
|
+
}
|
|
8693
|
+
serviceProcess = spawn7(python, [SCRAPE_SCRIPT], {
|
|
8694
|
+
stdio: "ignore",
|
|
8695
|
+
detached: true,
|
|
8696
|
+
env: {
|
|
8697
|
+
...process.env,
|
|
8698
|
+
SCRAPE_PORT: String(DEFAULT_PORT),
|
|
8699
|
+
SCRAPE_HEADLESS_DEFAULT: "1",
|
|
8700
|
+
SCRAPE_REQUIRE_AUTH: "0"
|
|
8701
|
+
}
|
|
8702
|
+
});
|
|
8703
|
+
serviceProcess.unref();
|
|
8704
|
+
for (let i = 0; i < 120; i++) {
|
|
8705
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
8706
|
+
if (await probeService())
|
|
8707
|
+
return null;
|
|
8708
|
+
}
|
|
8709
|
+
return "Scrape service failed to start within 60s. Check Chrome/Chromium installation.";
|
|
8710
|
+
}
|
|
8711
|
+
async function ensureSession() {
|
|
8712
|
+
if (activeSessionId) {
|
|
8713
|
+
try {
|
|
8714
|
+
const res2 = await fetch(`${BASE_URL}/health`);
|
|
8715
|
+
if (res2.ok)
|
|
8716
|
+
return { sessionId: activeSessionId };
|
|
8717
|
+
} catch {
|
|
8718
|
+
}
|
|
8719
|
+
activeSessionId = null;
|
|
8720
|
+
}
|
|
8721
|
+
const res = await fetch(`${BASE_URL}/session/start`, {
|
|
8722
|
+
method: "POST",
|
|
8723
|
+
headers: { "Content-Type": "application/json" },
|
|
8724
|
+
body: JSON.stringify({ headless: true })
|
|
8725
|
+
});
|
|
8726
|
+
const data = await res.json();
|
|
8727
|
+
if (!data.ok)
|
|
8728
|
+
return { error: String(data.message ?? "Failed to start browser session"), sessionId: "" };
|
|
8729
|
+
activeSessionId = data.session_id;
|
|
8730
|
+
return { sessionId: activeSessionId };
|
|
8731
|
+
}
|
|
8732
|
+
async function apiCall(endpoint, method = "POST", body) {
|
|
8733
|
+
const options = {
|
|
8734
|
+
method,
|
|
8735
|
+
headers: { "Content-Type": "application/json" }
|
|
8736
|
+
};
|
|
8737
|
+
if (body && method === "POST") {
|
|
8738
|
+
options.body = JSON.stringify({ sid: activeSessionId, ...body });
|
|
8739
|
+
}
|
|
8740
|
+
let url = `${BASE_URL}${endpoint}`;
|
|
8741
|
+
if (method === "GET" && activeSessionId) {
|
|
8742
|
+
url += `?sid=${encodeURIComponent(activeSessionId)}`;
|
|
8743
|
+
}
|
|
8744
|
+
const res = await fetch(url, options);
|
|
8745
|
+
return await res.json();
|
|
8746
|
+
}
|
|
8747
|
+
var __dirname2, SCRAPE_SCRIPT, DEFAULT_PORT, BASE_URL, serviceProcess, activeSessionId, BrowserActionTool;
|
|
8748
|
+
var init_browser_action = __esm({
|
|
8749
|
+
"packages/execution/dist/tools/browser-action.js"() {
|
|
8750
|
+
"use strict";
|
|
8751
|
+
__dirname2 = dirname8(fileURLToPath5(import.meta.url));
|
|
8752
|
+
SCRAPE_SCRIPT = join21(__dirname2, "..", "..", "scripts", "web_scrape.py");
|
|
8753
|
+
DEFAULT_PORT = 8130;
|
|
8754
|
+
BASE_URL = `http://localhost:${DEFAULT_PORT}`;
|
|
8755
|
+
serviceProcess = null;
|
|
8756
|
+
activeSessionId = null;
|
|
8757
|
+
BrowserActionTool = class {
|
|
8758
|
+
name = "browser_action";
|
|
8759
|
+
description = "Automate a headless Chrome browser: navigate to URLs, click elements, type text, take screenshots, read DOM content, scroll, and navigate history. Uses a local Selenium-based service that auto-starts on first use. Better than xdotool for web automation \u2014 works headlessly without a display server. Actions: navigate, click, click_xy, type, screenshot, dom, scroll, back, forward, close.";
|
|
8760
|
+
parameters = {
|
|
8761
|
+
type: "object",
|
|
8762
|
+
properties: {
|
|
8763
|
+
action: {
|
|
8764
|
+
type: "string",
|
|
8765
|
+
enum: ["navigate", "click", "click_xy", "type", "screenshot", "dom", "scroll", "scroll_up", "scroll_down", "back", "forward", "close"],
|
|
8766
|
+
description: "Browser action to perform"
|
|
8767
|
+
},
|
|
8768
|
+
url: {
|
|
8769
|
+
type: "string",
|
|
8770
|
+
description: "URL to navigate to (for 'navigate' action)"
|
|
8771
|
+
},
|
|
8772
|
+
selector: {
|
|
8773
|
+
type: "string",
|
|
8774
|
+
description: "CSS selector of element to interact with (for 'click' and 'type' actions)"
|
|
8775
|
+
},
|
|
8776
|
+
text: {
|
|
8777
|
+
type: "string",
|
|
8778
|
+
description: "Text to type into the selected element (for 'type' action)"
|
|
8779
|
+
},
|
|
8780
|
+
x: {
|
|
8781
|
+
type: "number",
|
|
8782
|
+
description: "X coordinate for click_xy action (viewport pixels)"
|
|
8783
|
+
},
|
|
8784
|
+
y: {
|
|
8785
|
+
type: "number",
|
|
8786
|
+
description: "Y coordinate for click_xy action (viewport pixels)"
|
|
8787
|
+
},
|
|
8788
|
+
amount: {
|
|
8789
|
+
type: "number",
|
|
8790
|
+
description: "Scroll amount in pixels (for 'scroll' action, default 600)"
|
|
8791
|
+
}
|
|
8792
|
+
},
|
|
8793
|
+
required: ["action"]
|
|
8794
|
+
};
|
|
8795
|
+
async execute(args) {
|
|
8796
|
+
const start = Date.now();
|
|
8797
|
+
const action = args.action;
|
|
8798
|
+
const launchErr = await launchService();
|
|
8799
|
+
if (launchErr) {
|
|
8800
|
+
return { success: false, output: "", error: launchErr, durationMs: Date.now() - start };
|
|
8801
|
+
}
|
|
8802
|
+
if (action === "close") {
|
|
8803
|
+
if (activeSessionId) {
|
|
8804
|
+
try {
|
|
8805
|
+
await apiCall("/session/close");
|
|
8806
|
+
} catch {
|
|
8807
|
+
}
|
|
8808
|
+
activeSessionId = null;
|
|
8809
|
+
}
|
|
8810
|
+
return { success: true, output: "Browser session closed.", durationMs: Date.now() - start };
|
|
8811
|
+
}
|
|
8812
|
+
const session = await ensureSession();
|
|
8813
|
+
if (session.error) {
|
|
8814
|
+
return { success: false, output: "", error: session.error, durationMs: Date.now() - start };
|
|
8815
|
+
}
|
|
8816
|
+
try {
|
|
8817
|
+
let result;
|
|
8818
|
+
switch (action) {
|
|
8819
|
+
case "navigate":
|
|
8820
|
+
if (!args.url)
|
|
8821
|
+
return { success: false, output: "", error: "url is required for navigate action", durationMs: Date.now() - start };
|
|
8822
|
+
result = await apiCall("/navigate", "POST", { url: args.url });
|
|
8823
|
+
return {
|
|
8824
|
+
success: !!result.ok,
|
|
8825
|
+
output: result.ok ? `Navigated to ${args.url}` : String(result.message ?? "Navigation failed"),
|
|
8826
|
+
durationMs: Date.now() - start
|
|
8827
|
+
};
|
|
8828
|
+
case "click":
|
|
8829
|
+
if (!args.selector)
|
|
8830
|
+
return { success: false, output: "", error: "selector is required for click action", durationMs: Date.now() - start };
|
|
8831
|
+
result = await apiCall("/click", "POST", { selector: args.selector });
|
|
8832
|
+
return {
|
|
8833
|
+
success: !!result.ok,
|
|
8834
|
+
output: result.ok ? `Clicked element: ${args.selector}` : String(result.message ?? "Click failed"),
|
|
8835
|
+
durationMs: Date.now() - start
|
|
8836
|
+
};
|
|
8837
|
+
case "click_xy":
|
|
8838
|
+
if (args.x == null || args.y == null)
|
|
8839
|
+
return { success: false, output: "", error: "x and y are required for click_xy action", durationMs: Date.now() - start };
|
|
8840
|
+
result = await apiCall("/click_xy", "POST", { x: args.x, y: args.y });
|
|
8841
|
+
return {
|
|
8842
|
+
success: !!result.ok,
|
|
8843
|
+
output: result.ok ? `Clicked at (${args.x}, ${args.y})` : String(result.message ?? "Click failed"),
|
|
8844
|
+
durationMs: Date.now() - start
|
|
8845
|
+
};
|
|
8846
|
+
case "type":
|
|
8847
|
+
if (!args.selector || !args.text)
|
|
8848
|
+
return { success: false, output: "", error: "selector and text are required for type action", durationMs: Date.now() - start };
|
|
8849
|
+
result = await apiCall("/type", "POST", { selector: args.selector, text: args.text });
|
|
8850
|
+
return {
|
|
8851
|
+
success: !!result.ok,
|
|
8852
|
+
output: result.ok ? `Typed "${args.text.slice(0, 50)}" into ${args.selector}` : String(result.message ?? "Type failed"),
|
|
8853
|
+
durationMs: Date.now() - start
|
|
8854
|
+
};
|
|
8855
|
+
case "screenshot": {
|
|
8856
|
+
result = await apiCall("/screenshot", "GET");
|
|
8857
|
+
const b64 = result.b64;
|
|
8858
|
+
const width = result.width;
|
|
8859
|
+
const height = result.height;
|
|
8860
|
+
if (b64) {
|
|
8861
|
+
return {
|
|
8862
|
+
success: true,
|
|
8863
|
+
output: `Screenshot captured (${width}x${height}). Base64 length: ${b64.length} chars.
|
|
8864
|
+
[IMAGE_BASE64:image/png:${b64.slice(0, 200)}...]`,
|
|
8865
|
+
durationMs: Date.now() - start
|
|
8866
|
+
};
|
|
8867
|
+
}
|
|
8868
|
+
return { success: false, output: "", error: "Screenshot failed", durationMs: Date.now() - start };
|
|
8869
|
+
}
|
|
8870
|
+
case "dom": {
|
|
8871
|
+
result = await apiCall("/dom", "GET");
|
|
8872
|
+
const dom = result.dom;
|
|
8873
|
+
if (dom) {
|
|
8874
|
+
const truncated = dom.length > 5e4 ? dom.slice(0, 5e4) + "\n... (truncated)" : dom;
|
|
8875
|
+
return { success: true, output: truncated, durationMs: Date.now() - start };
|
|
8876
|
+
}
|
|
8877
|
+
return { success: false, output: "", error: "DOM capture failed", durationMs: Date.now() - start };
|
|
8878
|
+
}
|
|
8879
|
+
case "scroll":
|
|
8880
|
+
result = await apiCall("/scroll", "POST", { amount: args.amount ?? 600 });
|
|
8881
|
+
return { success: !!result.ok, output: `Scrolled ${args.amount ?? 600}px`, durationMs: Date.now() - start };
|
|
8882
|
+
case "scroll_up":
|
|
8883
|
+
result = await apiCall("/scroll/up", "POST");
|
|
8884
|
+
return { success: !!result.ok, output: "Scrolled up", durationMs: Date.now() - start };
|
|
8885
|
+
case "scroll_down":
|
|
8886
|
+
result = await apiCall("/scroll/down", "POST");
|
|
8887
|
+
return { success: !!result.ok, output: "Scrolled down", durationMs: Date.now() - start };
|
|
8888
|
+
case "back":
|
|
8889
|
+
result = await apiCall("/history/back", "POST");
|
|
8890
|
+
return { success: !!result.ok, output: "Navigated back", durationMs: Date.now() - start };
|
|
8891
|
+
case "forward":
|
|
8892
|
+
result = await apiCall("/history/forward", "POST");
|
|
8893
|
+
return { success: !!result.ok, output: "Navigated forward", durationMs: Date.now() - start };
|
|
8894
|
+
default:
|
|
8895
|
+
return { success: false, output: "", error: `Unknown action: ${action}. Available: navigate, click, click_xy, type, screenshot, dom, scroll, scroll_up, scroll_down, back, forward, close`, durationMs: Date.now() - start };
|
|
8896
|
+
}
|
|
8897
|
+
} catch (err) {
|
|
8898
|
+
return {
|
|
8899
|
+
success: false,
|
|
8900
|
+
output: "",
|
|
8901
|
+
error: `Browser action failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
8902
|
+
durationMs: Date.now() - start
|
|
8903
|
+
};
|
|
8904
|
+
}
|
|
8905
|
+
}
|
|
8906
|
+
};
|
|
8907
|
+
}
|
|
8908
|
+
});
|
|
8909
|
+
|
|
8910
|
+
// packages/execution/dist/tools/scheduler.js
|
|
8911
|
+
import { execSync as execSync16, exec as execCb } from "node:child_process";
|
|
8912
|
+
import { readFile as readFile9, writeFile as writeFile8, mkdir as mkdir4 } from "node:fs/promises";
|
|
8913
|
+
import { resolve as resolve20, join as join22 } from "node:path";
|
|
8914
|
+
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
8915
|
+
function isValidCron(expr) {
|
|
8916
|
+
const parts = expr.trim().split(/\s+/);
|
|
8917
|
+
if (parts.length !== 5)
|
|
8918
|
+
return false;
|
|
8919
|
+
return parts.every((p) => /^[\d*,\-/]+$/.test(p));
|
|
8920
|
+
}
|
|
8921
|
+
function resolveSchedule(schedule) {
|
|
8922
|
+
const lower = schedule.toLowerCase().trim();
|
|
8923
|
+
if (SCHEDULE_PRESETS[lower])
|
|
8924
|
+
return SCHEDULE_PRESETS[lower];
|
|
8925
|
+
const inMatch = lower.match(/^in\s+(\d+)\s*(m|min|mins|minutes?|h|hr|hrs|hours?|d|days?)$/);
|
|
8926
|
+
if (inMatch) {
|
|
8927
|
+
const amount = parseInt(inMatch[1], 10);
|
|
8928
|
+
const unit = inMatch[2].charAt(0);
|
|
8929
|
+
const now = /* @__PURE__ */ new Date();
|
|
8930
|
+
if (unit === "m")
|
|
8931
|
+
now.setMinutes(now.getMinutes() + amount);
|
|
8932
|
+
else if (unit === "h")
|
|
8933
|
+
now.setHours(now.getHours() + amount);
|
|
8934
|
+
else if (unit === "d")
|
|
8935
|
+
now.setDate(now.getDate() + amount);
|
|
8936
|
+
return `${now.getMinutes()} ${now.getHours()} ${now.getDate()} ${now.getMonth() + 1} *`;
|
|
8937
|
+
}
|
|
8938
|
+
const atMatch = lower.match(/^at\s+(\d{1,2}):(\d{2})$/);
|
|
8939
|
+
if (atMatch) {
|
|
8940
|
+
const hour = parseInt(atMatch[1], 10);
|
|
8941
|
+
const minute = parseInt(atMatch[2], 10);
|
|
8942
|
+
if (hour >= 0 && hour <= 23 && minute >= 0 && minute <= 59) {
|
|
8943
|
+
return `${minute} ${hour} * * *`;
|
|
8944
|
+
}
|
|
8945
|
+
}
|
|
8946
|
+
if (isValidCron(schedule))
|
|
8947
|
+
return schedule.trim();
|
|
8948
|
+
return null;
|
|
8949
|
+
}
|
|
8950
|
+
function describeCron(expr) {
|
|
8951
|
+
const parts = expr.split(/\s+/);
|
|
8952
|
+
if (parts.length !== 5)
|
|
8953
|
+
return expr;
|
|
8954
|
+
const [min, hour, dom, mon, dow] = parts;
|
|
8955
|
+
if (expr === "* * * * *")
|
|
8956
|
+
return "every minute";
|
|
8957
|
+
if (min?.startsWith("*/") && hour === "*")
|
|
8958
|
+
return `every ${min.slice(2)} minutes`;
|
|
8959
|
+
if (min === "0" && hour?.startsWith("*/"))
|
|
8960
|
+
return `every ${hour.slice(2)} hours`;
|
|
8961
|
+
if (min === "0" && hour !== "*" && dom === "*" && mon === "*" && dow === "*")
|
|
8962
|
+
return `daily at ${hour}:00`;
|
|
8963
|
+
if (min !== "*" && hour !== "*" && dom === "*" && mon === "*" && dow === "*")
|
|
8964
|
+
return `daily at ${hour}:${min?.padStart(2, "0")}`;
|
|
8965
|
+
if (dow !== "*" && dom === "*")
|
|
8966
|
+
return `weekly on day ${dow} at ${hour}:${min?.padStart(2, "0")}`;
|
|
8967
|
+
if (dom !== "*" && mon === "*")
|
|
8968
|
+
return `monthly on day ${dom} at ${hour}:${min?.padStart(2, "0")}`;
|
|
8969
|
+
return expr;
|
|
8970
|
+
}
|
|
8971
|
+
function getCurrentCrontab() {
|
|
8972
|
+
try {
|
|
8973
|
+
return execSync16("crontab -l 2>/dev/null", { stdio: "pipe" }).toString().split("\n");
|
|
8974
|
+
} catch {
|
|
8975
|
+
return [];
|
|
8976
|
+
}
|
|
8977
|
+
}
|
|
8978
|
+
function writeCrontab(lines) {
|
|
8979
|
+
const content = lines.join("\n") + "\n";
|
|
8980
|
+
execSync16(`echo ${JSON.stringify(content)} | crontab -`, { stdio: "pipe" });
|
|
8981
|
+
}
|
|
8982
|
+
function findOaBinary() {
|
|
8983
|
+
for (const cmd of ["oa", "open-agents"]) {
|
|
8984
|
+
try {
|
|
8985
|
+
const path = execSync16(`which ${cmd} 2>/dev/null`, { stdio: "pipe" }).toString().trim();
|
|
8986
|
+
if (path)
|
|
8987
|
+
return path;
|
|
8988
|
+
} catch {
|
|
8989
|
+
}
|
|
8990
|
+
}
|
|
8991
|
+
return "npx open-agents-ai";
|
|
8992
|
+
}
|
|
8993
|
+
function installCronJob(task, workingDir) {
|
|
8994
|
+
const lines = getCurrentCrontab();
|
|
8995
|
+
const oaBin = findOaBinary();
|
|
8996
|
+
const logDir = resolve20(workingDir, ".oa", "scheduled", "logs");
|
|
8997
|
+
const logFile = join22(logDir, `${task.id}.log`);
|
|
8998
|
+
const cronLine = `${task.schedule} cd ${JSON.stringify(workingDir)} && ${oaBin} ${JSON.stringify(task.task)} >> ${JSON.stringify(logFile)} 2>&1 ${CRON_MARKER}${task.id}`;
|
|
8999
|
+
const filtered = lines.filter((l) => !l.includes(`${CRON_MARKER}${task.id}`));
|
|
9000
|
+
filtered.push(cronLine);
|
|
9001
|
+
writeCrontab(filtered);
|
|
9002
|
+
}
|
|
9003
|
+
function removeCronJob(taskId) {
|
|
9004
|
+
const lines = getCurrentCrontab();
|
|
9005
|
+
const filtered = lines.filter((l) => !l.includes(`${CRON_MARKER}${taskId}`));
|
|
9006
|
+
if (filtered.length !== lines.length) {
|
|
9007
|
+
writeCrontab(filtered);
|
|
9008
|
+
}
|
|
9009
|
+
}
|
|
9010
|
+
function listCronJobs() {
|
|
9011
|
+
return getCurrentCrontab().filter((l) => l.includes(CRON_MARKER)).map((l) => {
|
|
9012
|
+
const idMatch = l.match(new RegExp(`${CRON_MARKER.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(\\S+)`));
|
|
9013
|
+
return { id: idMatch?.[1] ?? "unknown", line: l };
|
|
9014
|
+
});
|
|
9015
|
+
}
|
|
9016
|
+
async function loadStore(workingDir) {
|
|
9017
|
+
const storePath = resolve20(workingDir, ".oa", "scheduled", "tasks.json");
|
|
9018
|
+
try {
|
|
9019
|
+
const raw = await readFile9(storePath, "utf-8");
|
|
9020
|
+
return JSON.parse(raw);
|
|
9021
|
+
} catch {
|
|
9022
|
+
return { tasks: [], updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
9023
|
+
}
|
|
9024
|
+
}
|
|
9025
|
+
async function saveStore(workingDir, store) {
|
|
9026
|
+
const dir = resolve20(workingDir, ".oa", "scheduled");
|
|
9027
|
+
await mkdir4(dir, { recursive: true });
|
|
9028
|
+
await mkdir4(join22(dir, "logs"), { recursive: true });
|
|
9029
|
+
store.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
9030
|
+
await writeFile8(join22(dir, "tasks.json"), JSON.stringify(store, null, 2), "utf-8");
|
|
9031
|
+
}
|
|
9032
|
+
var SCHEDULE_PRESETS, CRON_MARKER, SchedulerTool;
|
|
9033
|
+
var init_scheduler = __esm({
|
|
9034
|
+
"packages/execution/dist/tools/scheduler.js"() {
|
|
9035
|
+
"use strict";
|
|
9036
|
+
SCHEDULE_PRESETS = {
|
|
9037
|
+
"every minute": "* * * * *",
|
|
9038
|
+
"every 5 minutes": "*/5 * * * *",
|
|
9039
|
+
"every 15 minutes": "*/15 * * * *",
|
|
9040
|
+
"every 30 minutes": "*/30 * * * *",
|
|
9041
|
+
"every hour": "0 * * * *",
|
|
9042
|
+
"every 2 hours": "0 */2 * * *",
|
|
9043
|
+
"every 6 hours": "0 */6 * * *",
|
|
9044
|
+
"every 12 hours": "0 */12 * * *",
|
|
9045
|
+
"daily": "0 9 * * *",
|
|
9046
|
+
"daily morning": "0 9 * * *",
|
|
9047
|
+
"daily evening": "0 18 * * *",
|
|
9048
|
+
"weekly": "0 9 * * 1",
|
|
9049
|
+
"monthly": "0 9 1 * *",
|
|
9050
|
+
"hourly": "0 * * * *"
|
|
9051
|
+
};
|
|
9052
|
+
CRON_MARKER = "# OPEN-AGENTS-SCHEDULED:";
|
|
9053
|
+
SchedulerTool = class {
|
|
9054
|
+
name = "scheduler";
|
|
9055
|
+
description = "Schedule tasks for automatic future execution using OS-level cron. Actions: 'create' a new scheduled task, 'list' all scheduled tasks, 'cancel' a task by ID, 'pause'/'resume' a task. Schedules: use presets ('daily', 'every 5 minutes', 'hourly', 'weekly'), natural language ('in 30m', 'at 14:30'), or raw cron expressions ('0 */2 * * *'). Tasks launch the agent automatically at the scheduled time.";
|
|
9056
|
+
parameters = {
|
|
9057
|
+
type: "object",
|
|
9058
|
+
properties: {
|
|
9059
|
+
action: {
|
|
9060
|
+
type: "string",
|
|
9061
|
+
enum: ["create", "list", "cancel", "pause", "resume", "logs"],
|
|
9062
|
+
description: "Scheduler action to perform"
|
|
9063
|
+
},
|
|
9064
|
+
task: {
|
|
9065
|
+
type: "string",
|
|
9066
|
+
description: "The task/prompt the agent should execute (for 'create')"
|
|
9067
|
+
},
|
|
9068
|
+
schedule: {
|
|
9069
|
+
type: "string",
|
|
9070
|
+
description: "When to run: preset ('daily', 'every 5 minutes'), natural ('in 30m', 'at 14:30'), or cron ('0 */2 * * *')"
|
|
9071
|
+
},
|
|
9072
|
+
id: {
|
|
9073
|
+
type: "string",
|
|
9074
|
+
description: "Task ID (for 'cancel', 'pause', 'resume', 'logs')"
|
|
9075
|
+
},
|
|
9076
|
+
max_runs: {
|
|
9077
|
+
type: "number",
|
|
9078
|
+
description: "Auto-disable after N executions (omit for unlimited)"
|
|
9079
|
+
},
|
|
9080
|
+
one_shot: {
|
|
9081
|
+
type: "boolean",
|
|
9082
|
+
description: "If true, task auto-removes after first execution"
|
|
9083
|
+
}
|
|
9084
|
+
},
|
|
9085
|
+
required: ["action"]
|
|
9086
|
+
};
|
|
9087
|
+
workingDir;
|
|
9088
|
+
constructor(workingDir) {
|
|
9089
|
+
this.workingDir = workingDir;
|
|
9090
|
+
}
|
|
9091
|
+
async execute(args) {
|
|
9092
|
+
const start = performance.now();
|
|
9093
|
+
const action = String(args["action"] ?? "list");
|
|
9094
|
+
try {
|
|
9095
|
+
switch (action) {
|
|
9096
|
+
case "create":
|
|
9097
|
+
return await this.createTask(args, start);
|
|
9098
|
+
case "list":
|
|
9099
|
+
return await this.listTasks(start);
|
|
9100
|
+
case "cancel":
|
|
9101
|
+
return await this.cancelTask(args, start);
|
|
9102
|
+
case "pause":
|
|
9103
|
+
return await this.toggleTask(args, false, start);
|
|
9104
|
+
case "resume":
|
|
9105
|
+
return await this.toggleTask(args, true, start);
|
|
9106
|
+
case "logs":
|
|
9107
|
+
return await this.viewLogs(args, start);
|
|
9108
|
+
default:
|
|
9109
|
+
return {
|
|
9110
|
+
success: false,
|
|
9111
|
+
output: "",
|
|
9112
|
+
error: `Unknown action '${action}'. Use: create, list, cancel, pause, resume, logs`,
|
|
9113
|
+
durationMs: performance.now() - start
|
|
9114
|
+
};
|
|
9115
|
+
}
|
|
9116
|
+
} catch (err) {
|
|
9117
|
+
return {
|
|
9118
|
+
success: false,
|
|
9119
|
+
output: "",
|
|
9120
|
+
error: `Scheduler error: ${err instanceof Error ? err.message : String(err)}`,
|
|
9121
|
+
durationMs: performance.now() - start
|
|
9122
|
+
};
|
|
9123
|
+
}
|
|
9124
|
+
}
|
|
9125
|
+
async createTask(args, start) {
|
|
9126
|
+
const task = String(args["task"] ?? "");
|
|
9127
|
+
const schedule = String(args["schedule"] ?? "");
|
|
9128
|
+
if (!task)
|
|
9129
|
+
return { success: false, output: "", error: "task is required for create action", durationMs: performance.now() - start };
|
|
9130
|
+
if (!schedule)
|
|
9131
|
+
return { success: false, output: "", error: "schedule is required for create action", durationMs: performance.now() - start };
|
|
9132
|
+
const cronExpr = resolveSchedule(schedule);
|
|
9133
|
+
if (!cronExpr) {
|
|
9134
|
+
return {
|
|
9135
|
+
success: false,
|
|
9136
|
+
output: "",
|
|
9137
|
+
error: `Cannot parse schedule '${schedule}'. Use presets (daily, hourly, every 5 minutes), natural (in 30m, at 14:30), or cron (0 */2 * * *). Available presets: ${Object.keys(SCHEDULE_PRESETS).join(", ")}`,
|
|
9138
|
+
durationMs: performance.now() - start
|
|
9139
|
+
};
|
|
9140
|
+
}
|
|
9141
|
+
const id = `sched-${randomBytes2(4).toString("hex")}`;
|
|
9142
|
+
const oneShot = Boolean(args["one_shot"]);
|
|
9143
|
+
const maxRuns = typeof args["max_runs"] === "number" ? args["max_runs"] : void 0;
|
|
9144
|
+
const newTask = {
|
|
9145
|
+
id,
|
|
9146
|
+
task,
|
|
9147
|
+
schedule: cronExpr,
|
|
9148
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9149
|
+
nextRunDescription: describeCron(cronExpr),
|
|
9150
|
+
enabled: true,
|
|
9151
|
+
runCount: 0,
|
|
9152
|
+
maxRuns,
|
|
9153
|
+
oneShot: oneShot || void 0
|
|
9154
|
+
};
|
|
9155
|
+
const store = await loadStore(this.workingDir);
|
|
9156
|
+
store.tasks.push(newTask);
|
|
9157
|
+
await saveStore(this.workingDir, store);
|
|
9158
|
+
installCronJob(newTask, this.workingDir);
|
|
9159
|
+
return {
|
|
9160
|
+
success: true,
|
|
9161
|
+
output: [
|
|
9162
|
+
`Scheduled task created:`,
|
|
9163
|
+
` ID: ${id}`,
|
|
9164
|
+
` Task: ${task}`,
|
|
9165
|
+
` Schedule: ${describeCron(cronExpr)} (${cronExpr})`,
|
|
9166
|
+
oneShot ? ` Mode: one-shot (auto-removes after first run)` : "",
|
|
9167
|
+
maxRuns ? ` Max runs: ${maxRuns}` : "",
|
|
9168
|
+
` Status: enabled`,
|
|
9169
|
+
``,
|
|
9170
|
+
`The agent will launch automatically at the scheduled time.`,
|
|
9171
|
+
`Use scheduler(action='logs', id='${id}') to check execution history.`
|
|
9172
|
+
].filter(Boolean).join("\n"),
|
|
9173
|
+
durationMs: performance.now() - start
|
|
9174
|
+
};
|
|
9175
|
+
}
|
|
9176
|
+
async listTasks(start) {
|
|
9177
|
+
const store = await loadStore(this.workingDir);
|
|
9178
|
+
const cronJobs = listCronJobs();
|
|
9179
|
+
if (store.tasks.length === 0) {
|
|
9180
|
+
return {
|
|
9181
|
+
success: true,
|
|
9182
|
+
output: "No scheduled tasks. Use scheduler(action='create', task='...', schedule='daily') to create one.",
|
|
9183
|
+
durationMs: performance.now() - start
|
|
9184
|
+
};
|
|
9185
|
+
}
|
|
9186
|
+
const lines = [`Scheduled Tasks (${store.tasks.length}):
|
|
9187
|
+
`];
|
|
9188
|
+
for (const t of store.tasks) {
|
|
9189
|
+
const status = t.enabled ? "enabled" : "PAUSED";
|
|
9190
|
+
const cronInstalled = cronJobs.some((j) => j.id === t.id);
|
|
9191
|
+
const cronStatus = cronInstalled ? "" : " [cron not installed]";
|
|
9192
|
+
lines.push(` [${t.id}] ${status}${cronStatus}`);
|
|
9193
|
+
lines.push(` Task: ${t.task.slice(0, 100)}${t.task.length > 100 ? "..." : ""}`);
|
|
9194
|
+
lines.push(` Schedule: ${t.nextRunDescription} (${t.schedule})`);
|
|
9195
|
+
lines.push(` Runs: ${t.runCount}${t.maxRuns ? `/${t.maxRuns}` : ""}${t.oneShot ? " (one-shot)" : ""}`);
|
|
9196
|
+
if (t.lastRun)
|
|
9197
|
+
lines.push(` Last run: ${t.lastRun}`);
|
|
9198
|
+
lines.push("");
|
|
9199
|
+
}
|
|
9200
|
+
return {
|
|
9201
|
+
success: true,
|
|
9202
|
+
output: lines.join("\n"),
|
|
9203
|
+
durationMs: performance.now() - start
|
|
9204
|
+
};
|
|
9205
|
+
}
|
|
9206
|
+
async cancelTask(args, start) {
|
|
9207
|
+
const id = String(args["id"] ?? "");
|
|
9208
|
+
if (!id)
|
|
9209
|
+
return { success: false, output: "", error: "id is required for cancel action", durationMs: performance.now() - start };
|
|
9210
|
+
const store = await loadStore(this.workingDir);
|
|
9211
|
+
const idx = store.tasks.findIndex((t) => t.id === id);
|
|
9212
|
+
if (idx === -1)
|
|
9213
|
+
return { success: false, output: "", error: `No task found with ID '${id}'`, durationMs: performance.now() - start };
|
|
9214
|
+
const removed = store.tasks.splice(idx, 1)[0];
|
|
9215
|
+
await saveStore(this.workingDir, store);
|
|
9216
|
+
removeCronJob(id);
|
|
9217
|
+
return {
|
|
9218
|
+
success: true,
|
|
9219
|
+
output: `Cancelled and removed scheduled task '${id}': ${removed.task.slice(0, 80)}`,
|
|
9220
|
+
durationMs: performance.now() - start
|
|
9221
|
+
};
|
|
9222
|
+
}
|
|
9223
|
+
async toggleTask(args, enable, start) {
|
|
9224
|
+
const id = String(args["id"] ?? "");
|
|
9225
|
+
if (!id)
|
|
9226
|
+
return { success: false, output: "", error: "id is required", durationMs: performance.now() - start };
|
|
9227
|
+
const store = await loadStore(this.workingDir);
|
|
9228
|
+
const task = store.tasks.find((t) => t.id === id);
|
|
9229
|
+
if (!task)
|
|
9230
|
+
return { success: false, output: "", error: `No task found with ID '${id}'`, durationMs: performance.now() - start };
|
|
9231
|
+
task.enabled = enable;
|
|
9232
|
+
await saveStore(this.workingDir, store);
|
|
9233
|
+
if (enable) {
|
|
9234
|
+
installCronJob(task, this.workingDir);
|
|
9235
|
+
} else {
|
|
9236
|
+
removeCronJob(id);
|
|
9237
|
+
}
|
|
9238
|
+
return {
|
|
9239
|
+
success: true,
|
|
9240
|
+
output: `Task '${id}' ${enable ? "resumed" : "paused"}: ${task.task.slice(0, 80)}`,
|
|
9241
|
+
durationMs: performance.now() - start
|
|
9242
|
+
};
|
|
9243
|
+
}
|
|
9244
|
+
async viewLogs(args, start) {
|
|
9245
|
+
const id = String(args["id"] ?? "");
|
|
9246
|
+
if (!id)
|
|
9247
|
+
return { success: false, output: "", error: "id is required for logs action", durationMs: performance.now() - start };
|
|
9248
|
+
const logFile = resolve20(this.workingDir, ".oa", "scheduled", "logs", `${id}.log`);
|
|
9249
|
+
try {
|
|
9250
|
+
const raw = await readFile9(logFile, "utf-8");
|
|
9251
|
+
const truncated = raw.length > 1e4 ? "...(truncated)\n" + raw.slice(-1e4) : raw;
|
|
9252
|
+
return { success: true, output: `Logs for ${id}:
|
|
9253
|
+
${truncated}`, durationMs: performance.now() - start };
|
|
9254
|
+
} catch {
|
|
9255
|
+
return { success: true, output: `No logs yet for task '${id}'.`, durationMs: performance.now() - start };
|
|
9256
|
+
}
|
|
9257
|
+
}
|
|
9258
|
+
};
|
|
9259
|
+
}
|
|
9260
|
+
});
|
|
9261
|
+
|
|
9262
|
+
// packages/execution/dist/tools/reminder.js
|
|
9263
|
+
import { readFile as readFile10, writeFile as writeFile9, mkdir as mkdir5 } from "node:fs/promises";
|
|
9264
|
+
import { resolve as resolve21, join as join23 } from "node:path";
|
|
9265
|
+
import { randomBytes as randomBytes3 } from "node:crypto";
|
|
9266
|
+
function parseDueTime(due) {
|
|
9267
|
+
const lower = due.toLowerCase().trim();
|
|
9268
|
+
const now = /* @__PURE__ */ new Date();
|
|
9269
|
+
const inMatch = lower.match(/^in\s+(\d+)\s*(m|min|mins|minutes?|h|hr|hrs|hours?|d|days?|w|weeks?)$/);
|
|
9270
|
+
if (inMatch) {
|
|
9271
|
+
const amount = parseInt(inMatch[1], 10);
|
|
9272
|
+
const unit = inMatch[2].charAt(0);
|
|
9273
|
+
const target = new Date(now);
|
|
9274
|
+
if (unit === "m")
|
|
9275
|
+
target.setMinutes(target.getMinutes() + amount);
|
|
9276
|
+
else if (unit === "h")
|
|
9277
|
+
target.setHours(target.getHours() + amount);
|
|
9278
|
+
else if (unit === "d")
|
|
9279
|
+
target.setDate(target.getDate() + amount);
|
|
9280
|
+
else if (unit === "w")
|
|
9281
|
+
target.setDate(target.getDate() + amount * 7);
|
|
9282
|
+
return { isoDate: target.toISOString(), description: `in ${amount}${unit}` };
|
|
9283
|
+
}
|
|
9284
|
+
if (lower === "tomorrow") {
|
|
9285
|
+
const target = new Date(now);
|
|
9286
|
+
target.setDate(target.getDate() + 1);
|
|
9287
|
+
target.setHours(9, 0, 0, 0);
|
|
9288
|
+
return { isoDate: target.toISOString(), description: "tomorrow morning" };
|
|
9289
|
+
}
|
|
9290
|
+
if (lower === "next week") {
|
|
9291
|
+
const target = new Date(now);
|
|
9292
|
+
target.setDate(target.getDate() + 7);
|
|
9293
|
+
target.setHours(9, 0, 0, 0);
|
|
9294
|
+
return { isoDate: target.toISOString(), description: "next week" };
|
|
9295
|
+
}
|
|
9296
|
+
const todayMatch = lower.match(/^(?:today\s+)?at\s+(\d{1,2}):(\d{2})$/);
|
|
9297
|
+
if (todayMatch) {
|
|
9298
|
+
const target = new Date(now);
|
|
9299
|
+
target.setHours(parseInt(todayMatch[1], 10), parseInt(todayMatch[2], 10), 0, 0);
|
|
9300
|
+
if (target <= now)
|
|
9301
|
+
target.setDate(target.getDate() + 1);
|
|
9302
|
+
return { isoDate: target.toISOString(), description: `at ${todayMatch[1]}:${todayMatch[2]}` };
|
|
9303
|
+
}
|
|
9304
|
+
if (lower === "now" || lower === "next startup" || lower === "startup") {
|
|
9305
|
+
return { isoDate: now.toISOString(), description: "next startup" };
|
|
9306
|
+
}
|
|
9307
|
+
const parsed = new Date(due);
|
|
9308
|
+
if (!isNaN(parsed.getTime())) {
|
|
9309
|
+
return { isoDate: parsed.toISOString(), description: parsed.toLocaleDateString() };
|
|
9310
|
+
}
|
|
9311
|
+
return null;
|
|
9312
|
+
}
|
|
9313
|
+
async function getStorePath(workingDir) {
|
|
9314
|
+
const dir = resolve21(workingDir, ".oa", "scheduled");
|
|
9315
|
+
await mkdir5(dir, { recursive: true });
|
|
9316
|
+
return join23(dir, STORE_FILE);
|
|
9317
|
+
}
|
|
9318
|
+
async function loadReminderStore(workingDir) {
|
|
9319
|
+
const storePath = await getStorePath(workingDir);
|
|
9320
|
+
try {
|
|
9321
|
+
const raw = await readFile10(storePath, "utf-8");
|
|
9322
|
+
return JSON.parse(raw);
|
|
9323
|
+
} catch {
|
|
9324
|
+
return { reminders: [], updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
9325
|
+
}
|
|
9326
|
+
}
|
|
9327
|
+
async function saveReminderStore(workingDir, store) {
|
|
9328
|
+
const storePath = await getStorePath(workingDir);
|
|
9329
|
+
store.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
9330
|
+
await writeFile9(storePath, JSON.stringify(store, null, 2), "utf-8");
|
|
9331
|
+
}
|
|
9332
|
+
async function getDueReminders(workingDir) {
|
|
9333
|
+
const store = await loadReminderStore(workingDir);
|
|
9334
|
+
const now = /* @__PURE__ */ new Date();
|
|
9335
|
+
return store.reminders.filter((r) => {
|
|
9336
|
+
if (r.status !== "pending")
|
|
9337
|
+
return false;
|
|
9338
|
+
if (!r.dueAt)
|
|
9339
|
+
return true;
|
|
9340
|
+
return new Date(r.dueAt) <= now;
|
|
9341
|
+
});
|
|
9342
|
+
}
|
|
9343
|
+
async function markRemindersSeen(workingDir, ids) {
|
|
9344
|
+
const store = await loadReminderStore(workingDir);
|
|
9345
|
+
const idSet = new Set(ids);
|
|
9346
|
+
for (const r of store.reminders) {
|
|
9347
|
+
if (idSet.has(r.id) && r.status === "pending") {
|
|
9348
|
+
r.status = "seen";
|
|
9349
|
+
r.seenAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
9350
|
+
}
|
|
9351
|
+
}
|
|
9352
|
+
await saveReminderStore(workingDir, store);
|
|
9353
|
+
}
|
|
9354
|
+
var STORE_FILE, ReminderTool;
|
|
9355
|
+
var init_reminder = __esm({
|
|
9356
|
+
"packages/execution/dist/tools/reminder.js"() {
|
|
9357
|
+
"use strict";
|
|
9358
|
+
STORE_FILE = "reminders.json";
|
|
9359
|
+
ReminderTool = class {
|
|
9360
|
+
name = "reminder";
|
|
9361
|
+
description = "Set reminders that surface at future agent startups. Leave instructions for your future self across sessions. Actions: 'set' a new reminder, 'list' all reminders, 'complete' or 'dismiss' a reminder, 'snooze' to postpone. Reminders appear automatically when the agent starts and can have due dates, priority levels, and tags for filtering.";
|
|
9362
|
+
parameters = {
|
|
9363
|
+
type: "object",
|
|
9364
|
+
properties: {
|
|
9365
|
+
action: {
|
|
9366
|
+
type: "string",
|
|
9367
|
+
enum: ["set", "list", "complete", "dismiss", "snooze"],
|
|
9368
|
+
description: "Reminder action to perform"
|
|
9369
|
+
},
|
|
9370
|
+
message: {
|
|
9371
|
+
type: "string",
|
|
9372
|
+
description: "The reminder message (for 'set')"
|
|
9373
|
+
},
|
|
9374
|
+
due: {
|
|
9375
|
+
type: "string",
|
|
9376
|
+
description: "When the reminder should surface: 'in 30m', 'tomorrow', 'at 14:30', 'next startup', 'in 2d' (for 'set' and 'snooze')"
|
|
9377
|
+
},
|
|
9378
|
+
priority: {
|
|
9379
|
+
type: "string",
|
|
9380
|
+
enum: ["low", "normal", "high", "critical"],
|
|
9381
|
+
description: "Priority level (default: normal)"
|
|
9382
|
+
},
|
|
9383
|
+
tags: {
|
|
9384
|
+
type: "string",
|
|
9385
|
+
description: "Comma-separated tags for categorization (e.g. 'deploy,auth,urgent')"
|
|
9386
|
+
},
|
|
9387
|
+
context: {
|
|
9388
|
+
type: "string",
|
|
9389
|
+
description: "Additional context: file paths, task details, debugging notes"
|
|
9390
|
+
},
|
|
9391
|
+
id: {
|
|
9392
|
+
type: "string",
|
|
9393
|
+
description: "Reminder ID (for 'complete', 'dismiss', 'snooze')"
|
|
9394
|
+
},
|
|
9395
|
+
filter: {
|
|
9396
|
+
type: "string",
|
|
9397
|
+
description: "Filter by status: 'pending', 'seen', 'all' (for 'list', default: 'pending')"
|
|
9398
|
+
}
|
|
9399
|
+
},
|
|
9400
|
+
required: ["action"]
|
|
9401
|
+
};
|
|
9402
|
+
workingDir;
|
|
9403
|
+
constructor(workingDir) {
|
|
9404
|
+
this.workingDir = workingDir;
|
|
9405
|
+
}
|
|
9406
|
+
async execute(args) {
|
|
9407
|
+
const start = performance.now();
|
|
9408
|
+
const action = String(args["action"] ?? "list");
|
|
9409
|
+
try {
|
|
9410
|
+
switch (action) {
|
|
9411
|
+
case "set":
|
|
9412
|
+
return await this.setReminder(args, start);
|
|
9413
|
+
case "list":
|
|
9414
|
+
return await this.listReminders(args, start);
|
|
9415
|
+
case "complete":
|
|
9416
|
+
return await this.updateStatus(args, "completed", start);
|
|
9417
|
+
case "dismiss":
|
|
9418
|
+
return await this.updateStatus(args, "dismissed", start);
|
|
9419
|
+
case "snooze":
|
|
9420
|
+
return await this.snoozeReminder(args, start);
|
|
9421
|
+
default:
|
|
9422
|
+
return {
|
|
9423
|
+
success: false,
|
|
9424
|
+
output: "",
|
|
9425
|
+
error: `Unknown action '${action}'. Use: set, list, complete, dismiss, snooze`,
|
|
9426
|
+
durationMs: performance.now() - start
|
|
9427
|
+
};
|
|
9428
|
+
}
|
|
9429
|
+
} catch (err) {
|
|
9430
|
+
return {
|
|
9431
|
+
success: false,
|
|
9432
|
+
output: "",
|
|
9433
|
+
error: `Reminder error: ${err instanceof Error ? err.message : String(err)}`,
|
|
9434
|
+
durationMs: performance.now() - start
|
|
9435
|
+
};
|
|
9436
|
+
}
|
|
9437
|
+
}
|
|
9438
|
+
async setReminder(args, start) {
|
|
9439
|
+
const message = String(args["message"] ?? "");
|
|
9440
|
+
if (!message)
|
|
9441
|
+
return { success: false, output: "", error: "message is required for set action", durationMs: performance.now() - start };
|
|
9442
|
+
const priority = args["priority"] ?? "normal";
|
|
9443
|
+
const tagsStr = args["tags"] ?? "";
|
|
9444
|
+
const tags = tagsStr ? tagsStr.split(",").map((t) => t.trim()).filter(Boolean) : [];
|
|
9445
|
+
const context = args["context"] ?? void 0;
|
|
9446
|
+
const dueStr = args["due"] ?? "";
|
|
9447
|
+
let dueAt;
|
|
9448
|
+
let dueDescription;
|
|
9449
|
+
if (dueStr) {
|
|
9450
|
+
const parsed = parseDueTime(dueStr);
|
|
9451
|
+
if (!parsed) {
|
|
9452
|
+
return {
|
|
9453
|
+
success: false,
|
|
9454
|
+
output: "",
|
|
9455
|
+
error: `Cannot parse due time '${dueStr}'. Try: 'in 30m', 'tomorrow', 'at 14:30', 'next startup', 'in 2d'`,
|
|
9456
|
+
durationMs: performance.now() - start
|
|
9457
|
+
};
|
|
9458
|
+
}
|
|
9459
|
+
dueAt = parsed.isoDate;
|
|
9460
|
+
dueDescription = parsed.description;
|
|
9461
|
+
}
|
|
9462
|
+
const id = `rem-${randomBytes3(4).toString("hex")}`;
|
|
9463
|
+
const entry = {
|
|
9464
|
+
id,
|
|
9465
|
+
message,
|
|
9466
|
+
priority,
|
|
9467
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9468
|
+
dueAt,
|
|
9469
|
+
dueDescription,
|
|
9470
|
+
tags,
|
|
9471
|
+
status: "pending",
|
|
9472
|
+
context,
|
|
9473
|
+
source: "agent"
|
|
9474
|
+
};
|
|
9475
|
+
const store = await loadReminderStore(this.workingDir);
|
|
9476
|
+
store.reminders.push(entry);
|
|
9477
|
+
await saveReminderStore(this.workingDir, store);
|
|
9478
|
+
return {
|
|
9479
|
+
success: true,
|
|
9480
|
+
output: [
|
|
9481
|
+
`Reminder set:`,
|
|
9482
|
+
` ID: ${id}`,
|
|
9483
|
+
` Message: ${message}`,
|
|
9484
|
+
` Priority: ${priority}`,
|
|
9485
|
+
dueDescription ? ` Due: ${dueDescription}` : ` Due: next startup`,
|
|
9486
|
+
tags.length > 0 ? ` Tags: ${tags.join(", ")}` : "",
|
|
9487
|
+
context ? ` Context: ${context.slice(0, 100)}` : "",
|
|
9488
|
+
``,
|
|
9489
|
+
`This reminder will surface when the agent next starts${dueDescription ? ` (after ${dueDescription})` : ""}.`
|
|
9490
|
+
].filter(Boolean).join("\n"),
|
|
9491
|
+
durationMs: performance.now() - start
|
|
9492
|
+
};
|
|
9493
|
+
}
|
|
9494
|
+
async listReminders(args, start) {
|
|
9495
|
+
const store = await loadReminderStore(this.workingDir);
|
|
9496
|
+
const filter = String(args["filter"] ?? "pending");
|
|
9497
|
+
let filtered = store.reminders;
|
|
9498
|
+
if (filter === "pending")
|
|
9499
|
+
filtered = filtered.filter((r) => r.status === "pending" || r.status === "seen");
|
|
9500
|
+
else if (filter !== "all")
|
|
9501
|
+
filtered = filtered.filter((r) => r.status === filter);
|
|
9502
|
+
if (filtered.length === 0) {
|
|
9503
|
+
return {
|
|
9504
|
+
success: true,
|
|
9505
|
+
output: filter === "all" ? "No reminders set. Use reminder(action='set', message='...') to create one." : `No ${filter} reminders. Use reminder(action='list', filter='all') to see all.`,
|
|
9506
|
+
durationMs: performance.now() - start
|
|
9507
|
+
};
|
|
9508
|
+
}
|
|
9509
|
+
const priorityOrder = { critical: 0, high: 1, normal: 2, low: 3 };
|
|
9510
|
+
filtered.sort((a, b) => (priorityOrder[a.priority] ?? 2) - (priorityOrder[b.priority] ?? 2));
|
|
9511
|
+
const lines = [`Reminders (${filtered.length} ${filter}):
|
|
9512
|
+
`];
|
|
9513
|
+
for (const r of filtered) {
|
|
9514
|
+
const priorityIcon = r.priority === "critical" ? "[!!!]" : r.priority === "high" ? "[!!]" : r.priority === "low" ? "[.]" : "[*]";
|
|
9515
|
+
const statusLabel = r.status === "seen" ? " (seen)" : r.status === "completed" ? " (done)" : r.status === "dismissed" ? " (dismissed)" : "";
|
|
9516
|
+
lines.push(` ${priorityIcon} [${r.id}]${statusLabel}`);
|
|
9517
|
+
lines.push(` ${r.message}`);
|
|
9518
|
+
if (r.dueDescription)
|
|
9519
|
+
lines.push(` Due: ${r.dueDescription}`);
|
|
9520
|
+
if (r.tags.length > 0)
|
|
9521
|
+
lines.push(` Tags: ${r.tags.join(", ")}`);
|
|
9522
|
+
if (r.context)
|
|
9523
|
+
lines.push(` Context: ${r.context.slice(0, 80)}${r.context.length > 80 ? "..." : ""}`);
|
|
9524
|
+
lines.push("");
|
|
9525
|
+
}
|
|
9526
|
+
return {
|
|
9527
|
+
success: true,
|
|
9528
|
+
output: lines.join("\n"),
|
|
9529
|
+
durationMs: performance.now() - start
|
|
9530
|
+
};
|
|
9531
|
+
}
|
|
9532
|
+
async updateStatus(args, status, start) {
|
|
9533
|
+
const id = String(args["id"] ?? "");
|
|
9534
|
+
if (!id)
|
|
9535
|
+
return { success: false, output: "", error: "id is required", durationMs: performance.now() - start };
|
|
9536
|
+
const store = await loadReminderStore(this.workingDir);
|
|
9537
|
+
const reminder = store.reminders.find((r) => r.id === id);
|
|
9538
|
+
if (!reminder)
|
|
9539
|
+
return { success: false, output: "", error: `No reminder found with ID '${id}'`, durationMs: performance.now() - start };
|
|
9540
|
+
reminder.status = status;
|
|
9541
|
+
await saveReminderStore(this.workingDir, store);
|
|
9542
|
+
return {
|
|
9543
|
+
success: true,
|
|
9544
|
+
output: `Reminder '${id}' marked as ${status}: ${reminder.message.slice(0, 80)}`,
|
|
9545
|
+
durationMs: performance.now() - start
|
|
9546
|
+
};
|
|
9547
|
+
}
|
|
9548
|
+
async snoozeReminder(args, start) {
|
|
9549
|
+
const id = String(args["id"] ?? "");
|
|
9550
|
+
const due = String(args["due"] ?? "in 1h");
|
|
9551
|
+
if (!id)
|
|
9552
|
+
return { success: false, output: "", error: "id is required for snooze", durationMs: performance.now() - start };
|
|
9553
|
+
const parsed = parseDueTime(due);
|
|
9554
|
+
if (!parsed)
|
|
9555
|
+
return { success: false, output: "", error: `Cannot parse due time '${due}'`, durationMs: performance.now() - start };
|
|
9556
|
+
const store = await loadReminderStore(this.workingDir);
|
|
9557
|
+
const reminder = store.reminders.find((r) => r.id === id);
|
|
9558
|
+
if (!reminder)
|
|
9559
|
+
return { success: false, output: "", error: `No reminder found with ID '${id}'`, durationMs: performance.now() - start };
|
|
9560
|
+
reminder.status = "pending";
|
|
9561
|
+
reminder.dueAt = parsed.isoDate;
|
|
9562
|
+
reminder.dueDescription = parsed.description;
|
|
9563
|
+
reminder.seenAt = void 0;
|
|
9564
|
+
await saveReminderStore(this.workingDir, store);
|
|
9565
|
+
return {
|
|
9566
|
+
success: true,
|
|
9567
|
+
output: `Reminder '${id}' snoozed until ${parsed.description}: ${reminder.message.slice(0, 80)}`,
|
|
9568
|
+
durationMs: performance.now() - start
|
|
9569
|
+
};
|
|
9570
|
+
}
|
|
9571
|
+
};
|
|
9572
|
+
}
|
|
9573
|
+
});
|
|
9574
|
+
|
|
9575
|
+
// packages/execution/dist/tools/agenda.js
|
|
9576
|
+
import { readFile as readFile11, writeFile as writeFile10, mkdir as mkdir6 } from "node:fs/promises";
|
|
9577
|
+
import { resolve as resolve22, join as join24 } from "node:path";
|
|
9578
|
+
import { randomBytes as randomBytes4 } from "node:crypto";
|
|
9579
|
+
async function loadAttentionStore(workingDir) {
|
|
9580
|
+
const storePath = resolve22(workingDir, ".oa", "scheduled", "attention.json");
|
|
9581
|
+
try {
|
|
9582
|
+
const raw = await readFile11(storePath, "utf-8");
|
|
9583
|
+
return JSON.parse(raw);
|
|
9584
|
+
} catch {
|
|
9585
|
+
return { items: [], updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
9586
|
+
}
|
|
9587
|
+
}
|
|
9588
|
+
async function saveAttentionStore(workingDir, store) {
|
|
9589
|
+
const dir = resolve22(workingDir, ".oa", "scheduled");
|
|
9590
|
+
await mkdir6(dir, { recursive: true });
|
|
9591
|
+
store.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
9592
|
+
await writeFile10(join24(dir, "attention.json"), JSON.stringify(store, null, 2), "utf-8");
|
|
9593
|
+
}
|
|
9594
|
+
async function getActiveAttentionItems(workingDir) {
|
|
9595
|
+
const store = await loadAttentionStore(workingDir);
|
|
9596
|
+
const now = /* @__PURE__ */ new Date();
|
|
9597
|
+
let changed = false;
|
|
9598
|
+
for (const item of store.items) {
|
|
9599
|
+
if (item.status === "active" && item.expiresAt && new Date(item.expiresAt) <= now) {
|
|
9600
|
+
item.status = "expired";
|
|
9601
|
+
changed = true;
|
|
9602
|
+
}
|
|
9603
|
+
}
|
|
9604
|
+
if (changed)
|
|
9605
|
+
await saveAttentionStore(workingDir, store);
|
|
9606
|
+
return store.items.filter((i) => i.status === "active");
|
|
9607
|
+
}
|
|
9608
|
+
var AgendaTool;
|
|
9609
|
+
var init_agenda = __esm({
|
|
9610
|
+
"packages/execution/dist/tools/agenda.js"() {
|
|
9611
|
+
"use strict";
|
|
9612
|
+
init_reminder();
|
|
9613
|
+
AgendaTool = class {
|
|
9614
|
+
name = "agenda";
|
|
9615
|
+
description = "View and manage the agent's temporal awareness: pending reminders, scheduled tasks, and attention items. Actions: 'view' the full agenda (default), 'flag' an item for attention, 'resolve' an attention item, 'startup_brief' to see what surfaces at next startup. Categories: followup (check back on something), review (code/PR review needed), monitor (watch for changes), investigate (dig deeper), decision (needs a call).";
|
|
9616
|
+
parameters = {
|
|
9617
|
+
type: "object",
|
|
9618
|
+
properties: {
|
|
9619
|
+
action: {
|
|
9620
|
+
type: "string",
|
|
9621
|
+
enum: ["view", "flag", "resolve", "startup_brief"],
|
|
9622
|
+
description: "Agenda action (default: view)"
|
|
9623
|
+
},
|
|
9624
|
+
title: {
|
|
9625
|
+
type: "string",
|
|
9626
|
+
description: "Title for the attention item (for 'flag')"
|
|
9627
|
+
},
|
|
9628
|
+
description: {
|
|
9629
|
+
type: "string",
|
|
9630
|
+
description: "Detailed description (for 'flag')"
|
|
9631
|
+
},
|
|
9632
|
+
category: {
|
|
9633
|
+
type: "string",
|
|
9634
|
+
enum: ["followup", "review", "monitor", "investigate", "decision"],
|
|
9635
|
+
description: "Category of attention item (for 'flag')"
|
|
9636
|
+
},
|
|
9637
|
+
priority: {
|
|
9638
|
+
type: "string",
|
|
9639
|
+
enum: ["low", "normal", "high", "critical"],
|
|
9640
|
+
description: "Priority level (for 'flag', default: normal)"
|
|
9641
|
+
},
|
|
9642
|
+
expires_in: {
|
|
9643
|
+
type: "string",
|
|
9644
|
+
description: "Auto-dismiss after duration: 'in 1h', 'in 7d', 'in 30d' (for 'flag')"
|
|
9645
|
+
},
|
|
9646
|
+
related_files: {
|
|
9647
|
+
type: "string",
|
|
9648
|
+
description: "Comma-separated related file paths (for 'flag')"
|
|
9649
|
+
},
|
|
9650
|
+
notes: {
|
|
9651
|
+
type: "string",
|
|
9652
|
+
description: "Working notes or context (for 'flag')"
|
|
9653
|
+
},
|
|
9654
|
+
id: {
|
|
9655
|
+
type: "string",
|
|
9656
|
+
description: "Item ID (for 'resolve')"
|
|
9657
|
+
}
|
|
9658
|
+
},
|
|
9659
|
+
required: []
|
|
9660
|
+
};
|
|
9661
|
+
workingDir;
|
|
9662
|
+
constructor(workingDir) {
|
|
9663
|
+
this.workingDir = workingDir;
|
|
9664
|
+
}
|
|
9665
|
+
async execute(args) {
|
|
9666
|
+
const start = performance.now();
|
|
9667
|
+
const action = String(args["action"] ?? "view");
|
|
9668
|
+
try {
|
|
9669
|
+
switch (action) {
|
|
9670
|
+
case "view":
|
|
9671
|
+
return await this.viewAgenda(start);
|
|
9672
|
+
case "flag":
|
|
9673
|
+
return await this.flagAttention(args, start);
|
|
9674
|
+
case "resolve":
|
|
9675
|
+
return await this.resolveItem(args, start);
|
|
9676
|
+
case "startup_brief":
|
|
9677
|
+
return await this.startupBrief(start);
|
|
9678
|
+
default:
|
|
9679
|
+
return {
|
|
9680
|
+
success: false,
|
|
9681
|
+
output: "",
|
|
9682
|
+
error: `Unknown action '${action}'. Use: view, flag, resolve, startup_brief`,
|
|
9683
|
+
durationMs: performance.now() - start
|
|
9684
|
+
};
|
|
9685
|
+
}
|
|
9686
|
+
} catch (err) {
|
|
9687
|
+
return {
|
|
9688
|
+
success: false,
|
|
9689
|
+
output: "",
|
|
9690
|
+
error: `Agenda error: ${err instanceof Error ? err.message : String(err)}`,
|
|
9691
|
+
durationMs: performance.now() - start
|
|
9692
|
+
};
|
|
9693
|
+
}
|
|
9694
|
+
}
|
|
9695
|
+
async viewAgenda(start) {
|
|
9696
|
+
const [dueReminders, activeAttention, schedStore] = await Promise.all([
|
|
9697
|
+
getDueReminders(this.workingDir),
|
|
9698
|
+
getActiveAttentionItems(this.workingDir),
|
|
9699
|
+
this.loadScheduleStore()
|
|
9700
|
+
]);
|
|
9701
|
+
const sections = [];
|
|
9702
|
+
if (dueReminders.length > 0) {
|
|
9703
|
+
sections.push(`REMINDERS DUE (${dueReminders.length}):`);
|
|
9704
|
+
for (const r of dueReminders) {
|
|
9705
|
+
const icon = r.priority === "critical" ? "[!!!]" : r.priority === "high" ? "[!!]" : "[*]";
|
|
9706
|
+
sections.push(` ${icon} [${r.id}] ${r.message}`);
|
|
9707
|
+
if (r.context)
|
|
9708
|
+
sections.push(` Context: ${r.context.slice(0, 80)}`);
|
|
9709
|
+
}
|
|
9710
|
+
sections.push("");
|
|
9711
|
+
}
|
|
9712
|
+
if (activeAttention.length > 0) {
|
|
9713
|
+
sections.push(`ATTENTION ITEMS (${activeAttention.length}):`);
|
|
9714
|
+
const priorityOrder = { critical: 0, high: 1, normal: 2, low: 3 };
|
|
9715
|
+
activeAttention.sort((a, b) => (priorityOrder[a.priority] ?? 2) - (priorityOrder[b.priority] ?? 2));
|
|
9716
|
+
for (const item of activeAttention) {
|
|
9717
|
+
const icon = item.priority === "critical" ? "[!!!]" : item.priority === "high" ? "[!!]" : "[*]";
|
|
9718
|
+
sections.push(` ${icon} [${item.id}] (${item.category}) ${item.title}`);
|
|
9719
|
+
if (item.description)
|
|
9720
|
+
sections.push(` ${item.description.slice(0, 100)}`);
|
|
9721
|
+
if (item.relatedFiles?.length)
|
|
9722
|
+
sections.push(` Files: ${item.relatedFiles.join(", ")}`);
|
|
9723
|
+
if (item.expiresAt)
|
|
9724
|
+
sections.push(` Expires: ${new Date(item.expiresAt).toLocaleString()}`);
|
|
9725
|
+
}
|
|
9726
|
+
sections.push("");
|
|
9727
|
+
}
|
|
9728
|
+
const enabledTasks = schedStore.filter((t) => t.enabled);
|
|
9729
|
+
if (enabledTasks.length > 0) {
|
|
9730
|
+
sections.push(`SCHEDULED TASKS (${enabledTasks.length} active):`);
|
|
9731
|
+
for (const t of enabledTasks) {
|
|
9732
|
+
sections.push(` [${t.id}] ${t.nextRunDescription}: ${t.task.slice(0, 80)}`);
|
|
9733
|
+
}
|
|
9734
|
+
sections.push("");
|
|
9735
|
+
}
|
|
9736
|
+
if (sections.length === 0) {
|
|
9737
|
+
return {
|
|
9738
|
+
success: true,
|
|
9739
|
+
output: "Agenda is clear. No pending reminders, attention items, or scheduled tasks.",
|
|
9740
|
+
durationMs: performance.now() - start
|
|
9741
|
+
};
|
|
9742
|
+
}
|
|
9743
|
+
return {
|
|
9744
|
+
success: true,
|
|
9745
|
+
output: `AGENT AGENDA
|
|
9746
|
+
${"\u2500".repeat(50)}
|
|
9747
|
+
|
|
9748
|
+
${sections.join("\n")}`,
|
|
9749
|
+
durationMs: performance.now() - start
|
|
9750
|
+
};
|
|
9751
|
+
}
|
|
9752
|
+
async flagAttention(args, start) {
|
|
9753
|
+
const title = String(args["title"] ?? "");
|
|
9754
|
+
if (!title)
|
|
9755
|
+
return { success: false, output: "", error: "title is required for flag action", durationMs: performance.now() - start };
|
|
9756
|
+
const description = String(args["description"] ?? "");
|
|
9757
|
+
const category = args["category"] ?? "followup";
|
|
9758
|
+
const priority = args["priority"] ?? "normal";
|
|
9759
|
+
const notes = args["notes"] ?? void 0;
|
|
9760
|
+
const relatedFilesStr = args["related_files"] ?? "";
|
|
9761
|
+
const relatedFiles = relatedFilesStr ? relatedFilesStr.split(",").map((f) => f.trim()).filter(Boolean) : void 0;
|
|
9762
|
+
let expiresAt;
|
|
9763
|
+
const expiresIn = args["expires_in"] ?? "";
|
|
9764
|
+
if (expiresIn) {
|
|
9765
|
+
const match = expiresIn.match(/^(?:in\s+)?(\d+)\s*(m|h|d|w)/);
|
|
9766
|
+
if (match) {
|
|
9767
|
+
const target = /* @__PURE__ */ new Date();
|
|
9768
|
+
const amount = parseInt(match[1], 10);
|
|
9769
|
+
const unit = match[2];
|
|
9770
|
+
if (unit === "m")
|
|
9771
|
+
target.setMinutes(target.getMinutes() + amount);
|
|
9772
|
+
else if (unit === "h")
|
|
9773
|
+
target.setHours(target.getHours() + amount);
|
|
9774
|
+
else if (unit === "d")
|
|
9775
|
+
target.setDate(target.getDate() + amount);
|
|
9776
|
+
else if (unit === "w")
|
|
9777
|
+
target.setDate(target.getDate() + amount * 7);
|
|
9778
|
+
expiresAt = target.toISOString();
|
|
9779
|
+
}
|
|
9780
|
+
}
|
|
9781
|
+
const id = `attn-${randomBytes4(4).toString("hex")}`;
|
|
9782
|
+
const item = {
|
|
9783
|
+
id,
|
|
9784
|
+
title,
|
|
9785
|
+
description,
|
|
9786
|
+
category,
|
|
9787
|
+
priority,
|
|
9788
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9789
|
+
expiresAt,
|
|
9790
|
+
relatedFiles,
|
|
9791
|
+
status: "active",
|
|
9792
|
+
notes
|
|
9793
|
+
};
|
|
9794
|
+
const store = await loadAttentionStore(this.workingDir);
|
|
9795
|
+
store.items.push(item);
|
|
9796
|
+
await saveAttentionStore(this.workingDir, store);
|
|
9797
|
+
return {
|
|
9798
|
+
success: true,
|
|
9799
|
+
output: [
|
|
9800
|
+
`Attention item flagged:`,
|
|
9801
|
+
` ID: ${id}`,
|
|
9802
|
+
` Title: ${title}`,
|
|
9803
|
+
` Category: ${category}`,
|
|
9804
|
+
` Priority: ${priority}`,
|
|
9805
|
+
expiresAt ? ` Expires: ${new Date(expiresAt).toLocaleString()}` : "",
|
|
9806
|
+
relatedFiles ? ` Files: ${relatedFiles.join(", ")}` : "",
|
|
9807
|
+
``,
|
|
9808
|
+
`This item will appear in the agent's agenda until resolved or expired.`
|
|
9809
|
+
].filter(Boolean).join("\n"),
|
|
9810
|
+
durationMs: performance.now() - start
|
|
9811
|
+
};
|
|
9812
|
+
}
|
|
9813
|
+
async resolveItem(args, start) {
|
|
9814
|
+
const id = String(args["id"] ?? "");
|
|
9815
|
+
if (!id)
|
|
9816
|
+
return { success: false, output: "", error: "id is required for resolve", durationMs: performance.now() - start };
|
|
9817
|
+
const store = await loadAttentionStore(this.workingDir);
|
|
9818
|
+
const item = store.items.find((i) => i.id === id);
|
|
9819
|
+
if (!item)
|
|
9820
|
+
return { success: false, output: "", error: `No attention item found with ID '${id}'`, durationMs: performance.now() - start };
|
|
9821
|
+
item.status = "resolved";
|
|
9822
|
+
item.resolvedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
9823
|
+
await saveAttentionStore(this.workingDir, store);
|
|
9824
|
+
return {
|
|
9825
|
+
success: true,
|
|
9826
|
+
output: `Attention item '${id}' resolved: ${item.title}`,
|
|
9827
|
+
durationMs: performance.now() - start
|
|
9828
|
+
};
|
|
9829
|
+
}
|
|
9830
|
+
async startupBrief(start) {
|
|
9831
|
+
const [dueReminders, activeAttention] = await Promise.all([
|
|
9832
|
+
getDueReminders(this.workingDir),
|
|
9833
|
+
getActiveAttentionItems(this.workingDir)
|
|
9834
|
+
]);
|
|
9835
|
+
const criticalReminders = dueReminders.filter((r) => r.priority === "critical" || r.priority === "high");
|
|
9836
|
+
const criticalAttention = activeAttention.filter((a) => a.priority === "critical" || a.priority === "high");
|
|
9837
|
+
const lines = [];
|
|
9838
|
+
if (criticalReminders.length > 0 || criticalAttention.length > 0) {
|
|
9839
|
+
lines.push(`URGENT ITEMS REQUIRING IMMEDIATE ATTENTION:
|
|
9840
|
+
`);
|
|
9841
|
+
for (const r of criticalReminders) {
|
|
9842
|
+
lines.push(` [REMINDER] ${r.message}`);
|
|
9843
|
+
if (r.context)
|
|
9844
|
+
lines.push(` Context: ${r.context}`);
|
|
9845
|
+
}
|
|
9846
|
+
for (const a of criticalAttention) {
|
|
9847
|
+
lines.push(` [${a.category.toUpperCase()}] ${a.title}: ${a.description}`);
|
|
9848
|
+
if (a.relatedFiles?.length)
|
|
9849
|
+
lines.push(` Files: ${a.relatedFiles.join(", ")}`);
|
|
9850
|
+
}
|
|
9851
|
+
lines.push("");
|
|
9852
|
+
}
|
|
9853
|
+
const normalReminders = dueReminders.filter((r) => r.priority !== "critical" && r.priority !== "high");
|
|
9854
|
+
const normalAttention = activeAttention.filter((a) => a.priority !== "critical" && a.priority !== "high");
|
|
9855
|
+
if (normalReminders.length > 0) {
|
|
9856
|
+
lines.push(`Pending reminders: ${normalReminders.length}`);
|
|
9857
|
+
for (const r of normalReminders.slice(0, 5)) {
|
|
9858
|
+
lines.push(` - ${r.message}`);
|
|
9859
|
+
}
|
|
9860
|
+
if (normalReminders.length > 5)
|
|
9861
|
+
lines.push(` ... and ${normalReminders.length - 5} more`);
|
|
9862
|
+
lines.push("");
|
|
9863
|
+
}
|
|
9864
|
+
if (normalAttention.length > 0) {
|
|
9865
|
+
lines.push(`Active attention items: ${normalAttention.length}`);
|
|
9866
|
+
for (const a of normalAttention.slice(0, 5)) {
|
|
9867
|
+
lines.push(` - (${a.category}) ${a.title}`);
|
|
9868
|
+
}
|
|
9869
|
+
if (normalAttention.length > 5)
|
|
9870
|
+
lines.push(` ... and ${normalAttention.length - 5} more`);
|
|
9871
|
+
}
|
|
9872
|
+
if (lines.length === 0) {
|
|
9873
|
+
return {
|
|
9874
|
+
success: true,
|
|
9875
|
+
output: "No pending items for this startup. Agenda is clear.",
|
|
9876
|
+
durationMs: performance.now() - start
|
|
9877
|
+
};
|
|
9878
|
+
}
|
|
9879
|
+
return {
|
|
9880
|
+
success: true,
|
|
9881
|
+
output: lines.join("\n"),
|
|
9882
|
+
durationMs: performance.now() - start
|
|
9883
|
+
};
|
|
9884
|
+
}
|
|
9885
|
+
async loadScheduleStore() {
|
|
9886
|
+
try {
|
|
9887
|
+
const storePath = resolve22(this.workingDir, ".oa", "scheduled", "tasks.json");
|
|
9888
|
+
const raw = await readFile11(storePath, "utf-8");
|
|
9889
|
+
const store = JSON.parse(raw);
|
|
9890
|
+
return store.tasks ?? [];
|
|
9891
|
+
} catch {
|
|
9892
|
+
return [];
|
|
9893
|
+
}
|
|
9894
|
+
}
|
|
9895
|
+
};
|
|
9896
|
+
}
|
|
9897
|
+
});
|
|
9898
|
+
|
|
8653
9899
|
// packages/execution/dist/shellRunner.js
|
|
8654
9900
|
var init_shellRunner = __esm({
|
|
8655
9901
|
"packages/execution/dist/shellRunner.js"() {
|
|
@@ -8765,6 +10011,10 @@ var init_dist2 = __esm({
|
|
|
8765
10011
|
init_ocr_pdf();
|
|
8766
10012
|
init_pdf_to_text();
|
|
8767
10013
|
init_ocr_image_advanced();
|
|
10014
|
+
init_browser_action();
|
|
10015
|
+
init_scheduler();
|
|
10016
|
+
init_reminder();
|
|
10017
|
+
init_agenda();
|
|
8768
10018
|
init_system_deps();
|
|
8769
10019
|
init_shellRunner();
|
|
8770
10020
|
init_gitWorktree();
|
|
@@ -9880,8 +11130,8 @@ var init_code_retriever = __esm({
|
|
|
9880
11130
|
});
|
|
9881
11131
|
}
|
|
9882
11132
|
async getFileContent(filePath, startLine, endLine) {
|
|
9883
|
-
const { readFile:
|
|
9884
|
-
const content = await
|
|
11133
|
+
const { readFile: readFile15 } = await import("node:fs/promises");
|
|
11134
|
+
const content = await readFile15(filePath, "utf-8");
|
|
9885
11135
|
if (startLine === void 0)
|
|
9886
11136
|
return content;
|
|
9887
11137
|
const lines = content.split("\n");
|
|
@@ -9896,8 +11146,8 @@ var init_code_retriever = __esm({
|
|
|
9896
11146
|
// packages/retrieval/dist/lexicalSearch.js
|
|
9897
11147
|
import { execFile as execFile5 } from "node:child_process";
|
|
9898
11148
|
import { promisify as promisify4 } from "node:util";
|
|
9899
|
-
import { readFile as
|
|
9900
|
-
import { join as
|
|
11149
|
+
import { readFile as readFile12, readdir as readdir3, stat as stat3 } from "node:fs/promises";
|
|
11150
|
+
import { join as join25, extname as extname7 } from "node:path";
|
|
9901
11151
|
async function searchByPath(pathPattern, options) {
|
|
9902
11152
|
const allFiles = await collectFiles(options.rootDir, options.includeGlobs ?? DEFAULT_INCLUDE_GLOBS, options.excludeGlobs ?? DEFAULT_EXCLUDE_GLOBS);
|
|
9903
11153
|
const pattern = options.caseInsensitive ? pathPattern.toLowerCase() : pathPattern;
|
|
@@ -10002,7 +11252,7 @@ async function searchWithNodeFallback(pattern, kind, options) {
|
|
|
10002
11252
|
if (results.length >= maxMatches)
|
|
10003
11253
|
break;
|
|
10004
11254
|
try {
|
|
10005
|
-
const content = await
|
|
11255
|
+
const content = await readFile12(filePath, "utf-8");
|
|
10006
11256
|
const contentLines = content.split("\n");
|
|
10007
11257
|
for (let i = 0; i < contentLines.length; i++) {
|
|
10008
11258
|
if (results.length >= maxMatches)
|
|
@@ -10039,7 +11289,7 @@ async function walkForFiles(rootDir, dir, excludeGlobs, results) {
|
|
|
10039
11289
|
continue;
|
|
10040
11290
|
if (excludeGlobs.some((g) => entry.name === g || matchesGlob(entry.name, g)))
|
|
10041
11291
|
continue;
|
|
10042
|
-
const absPath =
|
|
11292
|
+
const absPath = join25(dir, entry.name);
|
|
10043
11293
|
if (entry.isDirectory()) {
|
|
10044
11294
|
await walkForFiles(rootDir, absPath, excludeGlobs, results);
|
|
10045
11295
|
} else if (entry.isFile()) {
|
|
@@ -10345,8 +11595,8 @@ var init_graphExpand = __esm({
|
|
|
10345
11595
|
});
|
|
10346
11596
|
|
|
10347
11597
|
// packages/retrieval/dist/snippetPacker.js
|
|
10348
|
-
import { readFile as
|
|
10349
|
-
import { join as
|
|
11598
|
+
import { readFile as readFile13 } from "node:fs/promises";
|
|
11599
|
+
import { join as join26 } from "node:path";
|
|
10350
11600
|
async function packSnippets(requests, opts = {}) {
|
|
10351
11601
|
const maxTokens = opts.maxTokens ?? DEFAULT_MAX_TOKENS;
|
|
10352
11602
|
const contextLines = opts.contextLines ?? DEFAULT_CONTEXT_LINES;
|
|
@@ -10372,10 +11622,10 @@ async function packSnippets(requests, opts = {}) {
|
|
|
10372
11622
|
return { packed, dropped, totalTokens };
|
|
10373
11623
|
}
|
|
10374
11624
|
async function extractSnippet(req, repoRoot, contextLines = DEFAULT_CONTEXT_LINES) {
|
|
10375
|
-
const absPath = req.filePath.startsWith("/") ? req.filePath :
|
|
11625
|
+
const absPath = req.filePath.startsWith("/") ? req.filePath : join26(repoRoot, req.filePath);
|
|
10376
11626
|
let content;
|
|
10377
11627
|
try {
|
|
10378
|
-
content = await
|
|
11628
|
+
content = await readFile13(absPath, "utf-8");
|
|
10379
11629
|
} catch {
|
|
10380
11630
|
return null;
|
|
10381
11631
|
}
|
|
@@ -12079,8 +13329,8 @@ Rules:
|
|
|
12079
13329
|
async waitIfPaused() {
|
|
12080
13330
|
if (!this._paused)
|
|
12081
13331
|
return true;
|
|
12082
|
-
await new Promise((
|
|
12083
|
-
this._pauseResolve =
|
|
13332
|
+
await new Promise((resolve26) => {
|
|
13333
|
+
this._pauseResolve = resolve26;
|
|
12084
13334
|
});
|
|
12085
13335
|
return !this.aborted;
|
|
12086
13336
|
}
|
|
@@ -12298,7 +13548,8 @@ Integrate this guidance into your current approach. Continue working on the task
|
|
|
12298
13548
|
"task_output",
|
|
12299
13549
|
"image_read",
|
|
12300
13550
|
"screenshot",
|
|
12301
|
-
"ocr"
|
|
13551
|
+
"ocr",
|
|
13552
|
+
"browser_action"
|
|
12302
13553
|
]);
|
|
12303
13554
|
const executeSingle = async (tc) => {
|
|
12304
13555
|
if (this.aborted)
|
|
@@ -12659,14 +13910,14 @@ ${result.output}`;
|
|
|
12659
13910
|
waitForSudoPassword(timeoutMs = 12e4) {
|
|
12660
13911
|
if (this._sudoPassword)
|
|
12661
13912
|
return Promise.resolve(this._sudoPassword);
|
|
12662
|
-
return new Promise((
|
|
13913
|
+
return new Promise((resolve26) => {
|
|
12663
13914
|
const timer = setTimeout(() => {
|
|
12664
13915
|
this._sudoResolve = null;
|
|
12665
|
-
|
|
13916
|
+
resolve26(null);
|
|
12666
13917
|
}, timeoutMs);
|
|
12667
13918
|
this._sudoResolve = (pw) => {
|
|
12668
13919
|
clearTimeout(timer);
|
|
12669
|
-
|
|
13920
|
+
resolve26(pw);
|
|
12670
13921
|
};
|
|
12671
13922
|
});
|
|
12672
13923
|
}
|
|
@@ -12789,8 +14040,8 @@ ${marker}` : marker);
|
|
|
12789
14040
|
return;
|
|
12790
14041
|
try {
|
|
12791
14042
|
const { mkdirSync: mkdirSync13, writeFileSync: writeFileSync12 } = __require("node:fs");
|
|
12792
|
-
const { join:
|
|
12793
|
-
const sessionDir =
|
|
14043
|
+
const { join: join41 } = __require("node:path");
|
|
14044
|
+
const sessionDir = join41(this._workingDirectory, ".oa", "session", this._sessionId);
|
|
12794
14045
|
mkdirSync13(sessionDir, { recursive: true });
|
|
12795
14046
|
const checkpoint = {
|
|
12796
14047
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -12803,7 +14054,7 @@ ${marker}` : marker);
|
|
|
12803
14054
|
memexEntryCount: this._memexArchive.size,
|
|
12804
14055
|
fileRegistrySize: this._fileRegistry.size
|
|
12805
14056
|
};
|
|
12806
|
-
writeFileSync12(
|
|
14057
|
+
writeFileSync12(join41(sessionDir, "checkpoint.json"), JSON.stringify(checkpoint, null, 2));
|
|
12807
14058
|
} catch {
|
|
12808
14059
|
}
|
|
12809
14060
|
}
|
|
@@ -13759,6 +15010,7 @@ ${transcript}`
|
|
|
13759
15010
|
temperature: request.temperature,
|
|
13760
15011
|
max_tokens: request.maxTokens,
|
|
13761
15012
|
stream: true,
|
|
15013
|
+
stream_options: { include_usage: true },
|
|
13762
15014
|
think: true
|
|
13763
15015
|
};
|
|
13764
15016
|
const resp = await fetch(`${this.baseUrl}/v1/chat/completions`, {
|
|
@@ -14340,11 +15592,11 @@ var init_dist5 = __esm({
|
|
|
14340
15592
|
});
|
|
14341
15593
|
|
|
14342
15594
|
// packages/cli/dist/tui/listen.js
|
|
14343
|
-
import { spawn as
|
|
14344
|
-
import { existsSync as
|
|
14345
|
-
import { join as
|
|
15595
|
+
import { spawn as spawn8, execSync as execSync17 } from "node:child_process";
|
|
15596
|
+
import { existsSync as existsSync19, mkdirSync as mkdirSync5, writeFileSync as writeFileSync5, readdirSync as readdirSync6 } from "node:fs";
|
|
15597
|
+
import { join as join27, dirname as dirname9 } from "node:path";
|
|
14346
15598
|
import { homedir as homedir8 } from "node:os";
|
|
14347
|
-
import { fileURLToPath as
|
|
15599
|
+
import { fileURLToPath as fileURLToPath6 } from "node:url";
|
|
14348
15600
|
import { EventEmitter } from "node:events";
|
|
14349
15601
|
import { createInterface as createInterface2 } from "node:readline";
|
|
14350
15602
|
function isAudioPath(path) {
|
|
@@ -14362,7 +15614,7 @@ function findMicCaptureCommand() {
|
|
|
14362
15614
|
const platform4 = process.platform;
|
|
14363
15615
|
if (platform4 === "linux") {
|
|
14364
15616
|
try {
|
|
14365
|
-
|
|
15617
|
+
execSync17("which arecord", { stdio: "pipe" });
|
|
14366
15618
|
return {
|
|
14367
15619
|
cmd: "arecord",
|
|
14368
15620
|
args: ["-f", "S16_LE", "-r", "16000", "-c", "1", "-t", "raw", "-q", "-"]
|
|
@@ -14372,7 +15624,7 @@ function findMicCaptureCommand() {
|
|
|
14372
15624
|
}
|
|
14373
15625
|
if (platform4 === "darwin") {
|
|
14374
15626
|
try {
|
|
14375
|
-
|
|
15627
|
+
execSync17("which sox", { stdio: "pipe" });
|
|
14376
15628
|
return {
|
|
14377
15629
|
cmd: "sox",
|
|
14378
15630
|
args: ["-d", "-t", "raw", "-r", "16000", "-c", "1", "-b", "16", "-e", "signed-integer", "-"]
|
|
@@ -14381,7 +15633,7 @@ function findMicCaptureCommand() {
|
|
|
14381
15633
|
}
|
|
14382
15634
|
}
|
|
14383
15635
|
try {
|
|
14384
|
-
|
|
15636
|
+
execSync17("which ffmpeg", { stdio: "pipe" });
|
|
14385
15637
|
if (platform4 === "linux") {
|
|
14386
15638
|
return {
|
|
14387
15639
|
cmd: "ffmpeg",
|
|
@@ -14426,41 +15678,41 @@ function findMicCaptureCommand() {
|
|
|
14426
15678
|
return null;
|
|
14427
15679
|
}
|
|
14428
15680
|
function findLiveWhisperScript() {
|
|
14429
|
-
const thisDir =
|
|
15681
|
+
const thisDir = dirname9(fileURLToPath6(import.meta.url));
|
|
14430
15682
|
const candidates = [
|
|
14431
|
-
|
|
14432
|
-
|
|
14433
|
-
|
|
15683
|
+
join27(thisDir, "../../../../packages/execution/scripts/live-whisper.py"),
|
|
15684
|
+
join27(thisDir, "../../../packages/execution/scripts/live-whisper.py"),
|
|
15685
|
+
join27(thisDir, "../../execution/scripts/live-whisper.py"),
|
|
14434
15686
|
// npm install layout — scripts bundled alongside dist
|
|
14435
|
-
|
|
14436
|
-
|
|
15687
|
+
join27(thisDir, "../scripts/live-whisper.py"),
|
|
15688
|
+
join27(thisDir, "../../scripts/live-whisper.py")
|
|
14437
15689
|
];
|
|
14438
15690
|
for (const p of candidates) {
|
|
14439
|
-
if (
|
|
15691
|
+
if (existsSync19(p))
|
|
14440
15692
|
return p;
|
|
14441
15693
|
}
|
|
14442
15694
|
try {
|
|
14443
|
-
const globalRoot =
|
|
15695
|
+
const globalRoot = execSync17("npm root -g", {
|
|
14444
15696
|
encoding: "utf-8",
|
|
14445
15697
|
timeout: 5e3,
|
|
14446
15698
|
stdio: ["pipe", "pipe", "pipe"]
|
|
14447
15699
|
}).trim();
|
|
14448
15700
|
const candidates2 = [
|
|
14449
|
-
|
|
14450
|
-
|
|
15701
|
+
join27(globalRoot, "open-agents-ai", "dist", "scripts", "live-whisper.py"),
|
|
15702
|
+
join27(globalRoot, "open-agents-ai", "scripts", "live-whisper.py")
|
|
14451
15703
|
];
|
|
14452
15704
|
for (const p of candidates2) {
|
|
14453
|
-
if (
|
|
15705
|
+
if (existsSync19(p))
|
|
14454
15706
|
return p;
|
|
14455
15707
|
}
|
|
14456
15708
|
} catch {
|
|
14457
15709
|
}
|
|
14458
|
-
const nvmBase =
|
|
14459
|
-
if (
|
|
15710
|
+
const nvmBase = join27(homedir8(), ".nvm", "versions", "node");
|
|
15711
|
+
if (existsSync19(nvmBase)) {
|
|
14460
15712
|
try {
|
|
14461
15713
|
for (const ver of readdirSync6(nvmBase)) {
|
|
14462
|
-
const p =
|
|
14463
|
-
if (
|
|
15714
|
+
const p = join27(nvmBase, ver, "lib", "node_modules", "open-agents-ai", "dist", "scripts", "live-whisper.py");
|
|
15715
|
+
if (existsSync19(p))
|
|
14464
15716
|
return p;
|
|
14465
15717
|
}
|
|
14466
15718
|
} catch {
|
|
@@ -14473,21 +15725,21 @@ function ensureTranscribeCliBackground() {
|
|
|
14473
15725
|
return;
|
|
14474
15726
|
_bgInstallPromise = (async () => {
|
|
14475
15727
|
try {
|
|
14476
|
-
const globalRoot =
|
|
15728
|
+
const globalRoot = execSync17("npm root -g", {
|
|
14477
15729
|
encoding: "utf-8",
|
|
14478
15730
|
timeout: 5e3,
|
|
14479
15731
|
stdio: ["pipe", "pipe", "pipe"]
|
|
14480
15732
|
}).trim();
|
|
14481
|
-
if (
|
|
15733
|
+
if (existsSync19(join27(globalRoot, "transcribe-cli", "dist", "index.js"))) {
|
|
14482
15734
|
return true;
|
|
14483
15735
|
}
|
|
14484
15736
|
} catch {
|
|
14485
15737
|
}
|
|
14486
15738
|
try {
|
|
14487
15739
|
const { exec } = await import("node:child_process");
|
|
14488
|
-
return new Promise((
|
|
15740
|
+
return new Promise((resolve26) => {
|
|
14489
15741
|
exec("npm i -g transcribe-cli", { timeout: 18e4 }, (err) => {
|
|
14490
|
-
|
|
15742
|
+
resolve26(!err);
|
|
14491
15743
|
});
|
|
14492
15744
|
});
|
|
14493
15745
|
} catch {
|
|
@@ -14540,11 +15792,11 @@ var init_listen = __esm({
|
|
|
14540
15792
|
return this._ready;
|
|
14541
15793
|
}
|
|
14542
15794
|
async start() {
|
|
14543
|
-
return new Promise((
|
|
15795
|
+
return new Promise((resolve26, reject) => {
|
|
14544
15796
|
const timeout = setTimeout(() => {
|
|
14545
15797
|
reject(new Error("Whisper fallback: model load timeout (5 min). First run downloads the model."));
|
|
14546
15798
|
}, 3e5);
|
|
14547
|
-
this.process =
|
|
15799
|
+
this.process = spawn8("python3", [
|
|
14548
15800
|
this.scriptPath,
|
|
14549
15801
|
"--model",
|
|
14550
15802
|
this.model,
|
|
@@ -14568,7 +15820,7 @@ var init_listen = __esm({
|
|
|
14568
15820
|
this._ready = true;
|
|
14569
15821
|
clearTimeout(timeout);
|
|
14570
15822
|
this.emit("ready");
|
|
14571
|
-
|
|
15823
|
+
resolve26();
|
|
14572
15824
|
break;
|
|
14573
15825
|
case "transcript":
|
|
14574
15826
|
this.emit("transcript", {
|
|
@@ -14673,7 +15925,7 @@ var init_listen = __esm({
|
|
|
14673
15925
|
}
|
|
14674
15926
|
if (!this.transcribeCliAvailable) {
|
|
14675
15927
|
try {
|
|
14676
|
-
|
|
15928
|
+
execSync17("which transcribe-cli", { stdio: "pipe" });
|
|
14677
15929
|
this.transcribeCliAvailable = true;
|
|
14678
15930
|
} catch {
|
|
14679
15931
|
this.transcribeCliAvailable = false;
|
|
@@ -14690,29 +15942,29 @@ var init_listen = __esm({
|
|
|
14690
15942
|
} catch {
|
|
14691
15943
|
}
|
|
14692
15944
|
try {
|
|
14693
|
-
const globalRoot =
|
|
15945
|
+
const globalRoot = execSync17("npm root -g", {
|
|
14694
15946
|
encoding: "utf-8",
|
|
14695
15947
|
timeout: 5e3,
|
|
14696
15948
|
stdio: ["pipe", "pipe", "pipe"]
|
|
14697
15949
|
}).trim();
|
|
14698
|
-
const tcPath =
|
|
14699
|
-
if (
|
|
15950
|
+
const tcPath = join27(globalRoot, "transcribe-cli");
|
|
15951
|
+
if (existsSync19(join27(tcPath, "dist", "index.js"))) {
|
|
14700
15952
|
const { createRequire: createRequire4 } = await import("node:module");
|
|
14701
15953
|
const req = createRequire4(import.meta.url);
|
|
14702
|
-
return req(
|
|
15954
|
+
return req(join27(tcPath, "dist", "index.js"));
|
|
14703
15955
|
}
|
|
14704
15956
|
} catch {
|
|
14705
15957
|
}
|
|
14706
|
-
const nvmBase =
|
|
14707
|
-
if (
|
|
15958
|
+
const nvmBase = join27(homedir8(), ".nvm", "versions", "node");
|
|
15959
|
+
if (existsSync19(nvmBase)) {
|
|
14708
15960
|
try {
|
|
14709
15961
|
const { readdirSync: readdirSync11 } = await import("node:fs");
|
|
14710
15962
|
for (const ver of readdirSync11(nvmBase)) {
|
|
14711
|
-
const tcPath =
|
|
14712
|
-
if (
|
|
15963
|
+
const tcPath = join27(nvmBase, ver, "lib", "node_modules", "transcribe-cli");
|
|
15964
|
+
if (existsSync19(join27(tcPath, "dist", "index.js"))) {
|
|
14713
15965
|
const { createRequire: createRequire4 } = await import("node:module");
|
|
14714
15966
|
const req = createRequire4(import.meta.url);
|
|
14715
|
-
return req(
|
|
15967
|
+
return req(join27(tcPath, "dist", "index.js"));
|
|
14716
15968
|
}
|
|
14717
15969
|
}
|
|
14718
15970
|
} catch {
|
|
@@ -14740,7 +15992,7 @@ var init_listen = __esm({
|
|
|
14740
15992
|
}
|
|
14741
15993
|
if (!tc) {
|
|
14742
15994
|
try {
|
|
14743
|
-
|
|
15995
|
+
execSync17("npm i -g transcribe-cli", { stdio: "pipe", timeout: 18e4 });
|
|
14744
15996
|
this.transcribeCliAvailable = null;
|
|
14745
15997
|
tc = await this.loadTranscribeCli();
|
|
14746
15998
|
} catch {
|
|
@@ -14772,11 +16024,11 @@ var init_listen = __esm({
|
|
|
14772
16024
|
this.liveTranscriber.on("error", (err) => {
|
|
14773
16025
|
this.emit("error", err);
|
|
14774
16026
|
});
|
|
14775
|
-
await new Promise((
|
|
16027
|
+
await new Promise((resolve26, reject) => {
|
|
14776
16028
|
const timeout = setTimeout(() => reject(new Error("Model load timeout (60s)")), 6e4);
|
|
14777
16029
|
this.liveTranscriber.on("ready", () => {
|
|
14778
16030
|
clearTimeout(timeout);
|
|
14779
|
-
|
|
16031
|
+
resolve26();
|
|
14780
16032
|
});
|
|
14781
16033
|
this.liveTranscriber.on("error", (err) => {
|
|
14782
16034
|
clearTimeout(timeout);
|
|
@@ -14826,7 +16078,7 @@ transcribe-cli error: ${transcribeCliError}` : "";
|
|
|
14826
16078
|
return `Failed to start live transcription: ${msg}${tcHint}`;
|
|
14827
16079
|
}
|
|
14828
16080
|
}
|
|
14829
|
-
this.micProcess =
|
|
16081
|
+
this.micProcess = spawn8(micCmd.cmd, micCmd.args, {
|
|
14830
16082
|
stdio: ["pipe", "pipe", "pipe"],
|
|
14831
16083
|
env: { ...process.env }
|
|
14832
16084
|
});
|
|
@@ -14921,7 +16173,7 @@ transcribe-cli error: ${transcribeCliError}` : "";
|
|
|
14921
16173
|
}
|
|
14922
16174
|
if (!tc) {
|
|
14923
16175
|
try {
|
|
14924
|
-
|
|
16176
|
+
execSync17("npm i -g transcribe-cli", { stdio: "pipe", timeout: 18e4 });
|
|
14925
16177
|
this.transcribeCliAvailable = null;
|
|
14926
16178
|
tc = await this.loadTranscribeCli();
|
|
14927
16179
|
} catch {
|
|
@@ -14938,9 +16190,9 @@ transcribe-cli error: ${transcribeCliError}` : "";
|
|
|
14938
16190
|
});
|
|
14939
16191
|
if (outputDir) {
|
|
14940
16192
|
const { basename: basename14 } = await import("node:path");
|
|
14941
|
-
const transcriptDir =
|
|
16193
|
+
const transcriptDir = join27(outputDir, ".oa", "transcripts");
|
|
14942
16194
|
mkdirSync5(transcriptDir, { recursive: true });
|
|
14943
|
-
const outFile =
|
|
16195
|
+
const outFile = join27(transcriptDir, `${basename14(filePath)}.txt`);
|
|
14944
16196
|
writeFileSync5(outFile, result.text, "utf-8");
|
|
14945
16197
|
}
|
|
14946
16198
|
return {
|
|
@@ -16220,8 +17472,8 @@ Approach this task thoughtfully:
|
|
|
16220
17472
|
});
|
|
16221
17473
|
|
|
16222
17474
|
// packages/prompts/dist/index.js
|
|
16223
|
-
import { join as
|
|
16224
|
-
import { fileURLToPath as
|
|
17475
|
+
import { join as join28, dirname as dirname10 } from "node:path";
|
|
17476
|
+
import { fileURLToPath as fileURLToPath7 } from "node:url";
|
|
16225
17477
|
var _dir, _packageRoot;
|
|
16226
17478
|
var init_dist6 = __esm({
|
|
16227
17479
|
"packages/prompts/dist/index.js"() {
|
|
@@ -16230,25 +17482,25 @@ var init_dist6 = __esm({
|
|
|
16230
17482
|
init_render2();
|
|
16231
17483
|
init_task_templates();
|
|
16232
17484
|
init_render2();
|
|
16233
|
-
_dir =
|
|
16234
|
-
_packageRoot =
|
|
17485
|
+
_dir = dirname10(fileURLToPath7(import.meta.url));
|
|
17486
|
+
_packageRoot = join28(_dir, "..");
|
|
16235
17487
|
}
|
|
16236
17488
|
});
|
|
16237
17489
|
|
|
16238
17490
|
// packages/cli/dist/tui/oa-directory.js
|
|
16239
|
-
import { existsSync as
|
|
16240
|
-
import { join as
|
|
17491
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync6, readFileSync as readFileSync14, writeFileSync as writeFileSync6, readdirSync as readdirSync7, statSync as statSync9, unlinkSync as unlinkSync3 } from "node:fs";
|
|
17492
|
+
import { join as join29, relative as relative2, basename as basename9, extname as extname8 } from "node:path";
|
|
16241
17493
|
import { homedir as homedir9 } from "node:os";
|
|
16242
17494
|
function initOaDirectory(repoRoot) {
|
|
16243
|
-
const oaPath =
|
|
17495
|
+
const oaPath = join29(repoRoot, OA_DIR);
|
|
16244
17496
|
for (const sub of SUBDIRS) {
|
|
16245
|
-
mkdirSync6(
|
|
17497
|
+
mkdirSync6(join29(oaPath, sub), { recursive: true });
|
|
16246
17498
|
}
|
|
16247
17499
|
try {
|
|
16248
|
-
const gitignorePath =
|
|
17500
|
+
const gitignorePath = join29(repoRoot, ".gitignore");
|
|
16249
17501
|
const settingsPattern = ".oa/settings.json";
|
|
16250
|
-
if (
|
|
16251
|
-
const content =
|
|
17502
|
+
if (existsSync20(gitignorePath)) {
|
|
17503
|
+
const content = readFileSync14(gitignorePath, "utf-8");
|
|
16252
17504
|
if (!content.includes(settingsPattern)) {
|
|
16253
17505
|
writeFileSync6(gitignorePath, content.trimEnd() + "\n" + settingsPattern + "\n", "utf-8");
|
|
16254
17506
|
}
|
|
@@ -16258,41 +17510,41 @@ function initOaDirectory(repoRoot) {
|
|
|
16258
17510
|
return oaPath;
|
|
16259
17511
|
}
|
|
16260
17512
|
function hasOaDirectory(repoRoot) {
|
|
16261
|
-
return
|
|
17513
|
+
return existsSync20(join29(repoRoot, OA_DIR, "index"));
|
|
16262
17514
|
}
|
|
16263
17515
|
function loadProjectSettings(repoRoot) {
|
|
16264
|
-
const settingsPath =
|
|
17516
|
+
const settingsPath = join29(repoRoot, OA_DIR, "settings.json");
|
|
16265
17517
|
try {
|
|
16266
|
-
if (
|
|
16267
|
-
return JSON.parse(
|
|
17518
|
+
if (existsSync20(settingsPath)) {
|
|
17519
|
+
return JSON.parse(readFileSync14(settingsPath, "utf-8"));
|
|
16268
17520
|
}
|
|
16269
17521
|
} catch {
|
|
16270
17522
|
}
|
|
16271
17523
|
return {};
|
|
16272
17524
|
}
|
|
16273
17525
|
function saveProjectSettings(repoRoot, settings) {
|
|
16274
|
-
const oaPath =
|
|
17526
|
+
const oaPath = join29(repoRoot, OA_DIR);
|
|
16275
17527
|
mkdirSync6(oaPath, { recursive: true });
|
|
16276
17528
|
const existing = loadProjectSettings(repoRoot);
|
|
16277
17529
|
const merged = { ...existing, ...settings };
|
|
16278
|
-
writeFileSync6(
|
|
17530
|
+
writeFileSync6(join29(oaPath, "settings.json"), JSON.stringify(merged, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
|
|
16279
17531
|
}
|
|
16280
17532
|
function loadGlobalSettings() {
|
|
16281
|
-
const settingsPath =
|
|
17533
|
+
const settingsPath = join29(homedir9(), ".open-agents", "settings.json");
|
|
16282
17534
|
try {
|
|
16283
|
-
if (
|
|
16284
|
-
return JSON.parse(
|
|
17535
|
+
if (existsSync20(settingsPath)) {
|
|
17536
|
+
return JSON.parse(readFileSync14(settingsPath, "utf-8"));
|
|
16285
17537
|
}
|
|
16286
17538
|
} catch {
|
|
16287
17539
|
}
|
|
16288
17540
|
return {};
|
|
16289
17541
|
}
|
|
16290
17542
|
function saveGlobalSettings(settings) {
|
|
16291
|
-
const dir =
|
|
17543
|
+
const dir = join29(homedir9(), ".open-agents");
|
|
16292
17544
|
mkdirSync6(dir, { recursive: true });
|
|
16293
17545
|
const existing = loadGlobalSettings();
|
|
16294
17546
|
const merged = { ...existing, ...settings };
|
|
16295
|
-
writeFileSync6(
|
|
17547
|
+
writeFileSync6(join29(dir, "settings.json"), JSON.stringify(merged, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
|
|
16296
17548
|
}
|
|
16297
17549
|
function resolveSettings(repoRoot) {
|
|
16298
17550
|
const global = loadGlobalSettings();
|
|
@@ -16307,12 +17559,12 @@ function discoverContextFiles(repoRoot, maxContentLen = 8e3) {
|
|
|
16307
17559
|
while (dir && !visited.has(dir)) {
|
|
16308
17560
|
visited.add(dir);
|
|
16309
17561
|
for (const name of CONTEXT_FILES) {
|
|
16310
|
-
const filePath =
|
|
17562
|
+
const filePath = join29(dir, name);
|
|
16311
17563
|
const normalizedName = name.toLowerCase();
|
|
16312
|
-
if (
|
|
17564
|
+
if (existsSync20(filePath) && !seen.has(filePath)) {
|
|
16313
17565
|
seen.add(filePath);
|
|
16314
17566
|
try {
|
|
16315
|
-
let content =
|
|
17567
|
+
let content = readFileSync14(filePath, "utf-8");
|
|
16316
17568
|
if (content.length > maxContentLen) {
|
|
16317
17569
|
content = content.slice(0, maxContentLen) + "\n\n...(truncated)";
|
|
16318
17570
|
}
|
|
@@ -16326,11 +17578,11 @@ function discoverContextFiles(repoRoot, maxContentLen = 8e3) {
|
|
|
16326
17578
|
}
|
|
16327
17579
|
}
|
|
16328
17580
|
}
|
|
16329
|
-
const projectMap =
|
|
16330
|
-
if (
|
|
17581
|
+
const projectMap = join29(dir, OA_DIR, "context", "project-map.md");
|
|
17582
|
+
if (existsSync20(projectMap) && !seen.has(projectMap)) {
|
|
16331
17583
|
seen.add(projectMap);
|
|
16332
17584
|
try {
|
|
16333
|
-
let content =
|
|
17585
|
+
let content = readFileSync14(projectMap, "utf-8");
|
|
16334
17586
|
if (content.length > maxContentLen) {
|
|
16335
17587
|
content = content.slice(0, maxContentLen) + "\n\n...(truncated)";
|
|
16336
17588
|
}
|
|
@@ -16342,7 +17594,7 @@ function discoverContextFiles(repoRoot, maxContentLen = 8e3) {
|
|
|
16342
17594
|
} catch {
|
|
16343
17595
|
}
|
|
16344
17596
|
}
|
|
16345
|
-
const parent =
|
|
17597
|
+
const parent = join29(dir, "..");
|
|
16346
17598
|
if (parent === dir)
|
|
16347
17599
|
break;
|
|
16348
17600
|
dir = parent;
|
|
@@ -16360,9 +17612,9 @@ function discoverContextFiles(repoRoot, maxContentLen = 8e3) {
|
|
|
16360
17612
|
return found;
|
|
16361
17613
|
}
|
|
16362
17614
|
function readIndexMeta(repoRoot) {
|
|
16363
|
-
const metaPath =
|
|
17615
|
+
const metaPath = join29(repoRoot, OA_DIR, "index", "meta.json");
|
|
16364
17616
|
try {
|
|
16365
|
-
return JSON.parse(
|
|
17617
|
+
return JSON.parse(readFileSync14(metaPath, "utf-8"));
|
|
16366
17618
|
} catch {
|
|
16367
17619
|
return null;
|
|
16368
17620
|
}
|
|
@@ -16413,28 +17665,28 @@ ${tree}\`\`\`
|
|
|
16413
17665
|
sections.push("");
|
|
16414
17666
|
}
|
|
16415
17667
|
const content = sections.join("\n");
|
|
16416
|
-
const contextDir =
|
|
17668
|
+
const contextDir = join29(repoRoot, OA_DIR, "context");
|
|
16417
17669
|
mkdirSync6(contextDir, { recursive: true });
|
|
16418
|
-
writeFileSync6(
|
|
17670
|
+
writeFileSync6(join29(contextDir, "project-map.md"), content, "utf-8");
|
|
16419
17671
|
return content;
|
|
16420
17672
|
}
|
|
16421
17673
|
function saveSession(repoRoot, session) {
|
|
16422
|
-
const historyDir =
|
|
17674
|
+
const historyDir = join29(repoRoot, OA_DIR, "history");
|
|
16423
17675
|
mkdirSync6(historyDir, { recursive: true });
|
|
16424
|
-
writeFileSync6(
|
|
17676
|
+
writeFileSync6(join29(historyDir, `${session.id}.json`), JSON.stringify(session, null, 2), "utf-8");
|
|
16425
17677
|
}
|
|
16426
17678
|
function loadRecentSessions(repoRoot, limit = 5) {
|
|
16427
|
-
const historyDir =
|
|
16428
|
-
if (!
|
|
17679
|
+
const historyDir = join29(repoRoot, OA_DIR, "history");
|
|
17680
|
+
if (!existsSync20(historyDir))
|
|
16429
17681
|
return [];
|
|
16430
17682
|
try {
|
|
16431
17683
|
const files = readdirSync7(historyDir).filter((f) => f.endsWith(".json") && f !== "pending-task.json").map((f) => {
|
|
16432
|
-
const stat5 = statSync9(
|
|
17684
|
+
const stat5 = statSync9(join29(historyDir, f));
|
|
16433
17685
|
return { file: f, mtime: stat5.mtimeMs };
|
|
16434
17686
|
}).sort((a, b) => b.mtime - a.mtime).slice(0, limit);
|
|
16435
17687
|
return files.map((f) => {
|
|
16436
17688
|
try {
|
|
16437
|
-
return JSON.parse(
|
|
17689
|
+
return JSON.parse(readFileSync14(join29(historyDir, f.file), "utf-8"));
|
|
16438
17690
|
} catch {
|
|
16439
17691
|
return null;
|
|
16440
17692
|
}
|
|
@@ -16444,16 +17696,16 @@ function loadRecentSessions(repoRoot, limit = 5) {
|
|
|
16444
17696
|
}
|
|
16445
17697
|
}
|
|
16446
17698
|
function savePendingTask(repoRoot, task) {
|
|
16447
|
-
const historyDir =
|
|
17699
|
+
const historyDir = join29(repoRoot, OA_DIR, "history");
|
|
16448
17700
|
mkdirSync6(historyDir, { recursive: true });
|
|
16449
|
-
writeFileSync6(
|
|
17701
|
+
writeFileSync6(join29(historyDir, PENDING_TASK_FILE), JSON.stringify(task, null, 2) + "\n", "utf-8");
|
|
16450
17702
|
}
|
|
16451
17703
|
function loadPendingTask(repoRoot) {
|
|
16452
|
-
const filePath =
|
|
17704
|
+
const filePath = join29(repoRoot, OA_DIR, "history", PENDING_TASK_FILE);
|
|
16453
17705
|
try {
|
|
16454
|
-
if (!
|
|
17706
|
+
if (!existsSync20(filePath))
|
|
16455
17707
|
return null;
|
|
16456
|
-
const data = JSON.parse(
|
|
17708
|
+
const data = JSON.parse(readFileSync14(filePath, "utf-8"));
|
|
16457
17709
|
try {
|
|
16458
17710
|
unlinkSync3(filePath);
|
|
16459
17711
|
} catch {
|
|
@@ -16464,13 +17716,13 @@ function loadPendingTask(repoRoot) {
|
|
|
16464
17716
|
}
|
|
16465
17717
|
}
|
|
16466
17718
|
function saveSessionContext(repoRoot, entry) {
|
|
16467
|
-
const contextDir =
|
|
17719
|
+
const contextDir = join29(repoRoot, OA_DIR, "context");
|
|
16468
17720
|
mkdirSync6(contextDir, { recursive: true });
|
|
16469
|
-
const filePath =
|
|
17721
|
+
const filePath = join29(contextDir, CONTEXT_SAVE_FILE);
|
|
16470
17722
|
let ctx;
|
|
16471
17723
|
try {
|
|
16472
|
-
if (
|
|
16473
|
-
ctx = JSON.parse(
|
|
17724
|
+
if (existsSync20(filePath)) {
|
|
17725
|
+
ctx = JSON.parse(readFileSync14(filePath, "utf-8"));
|
|
16474
17726
|
} else {
|
|
16475
17727
|
ctx = { entries: [], maxEntries: MAX_CONTEXT_ENTRIES, updatedAt: "" };
|
|
16476
17728
|
}
|
|
@@ -16485,11 +17737,11 @@ function saveSessionContext(repoRoot, entry) {
|
|
|
16485
17737
|
writeFileSync6(filePath, JSON.stringify(ctx, null, 2) + "\n", "utf-8");
|
|
16486
17738
|
}
|
|
16487
17739
|
function loadSessionContext(repoRoot) {
|
|
16488
|
-
const filePath =
|
|
17740
|
+
const filePath = join29(repoRoot, OA_DIR, "context", CONTEXT_SAVE_FILE);
|
|
16489
17741
|
try {
|
|
16490
|
-
if (!
|
|
17742
|
+
if (!existsSync20(filePath))
|
|
16491
17743
|
return null;
|
|
16492
|
-
return JSON.parse(
|
|
17744
|
+
return JSON.parse(readFileSync14(filePath, "utf-8"));
|
|
16493
17745
|
} catch {
|
|
16494
17746
|
return null;
|
|
16495
17747
|
}
|
|
@@ -16536,12 +17788,12 @@ function detectManifests(repoRoot) {
|
|
|
16536
17788
|
{ file: "docker-compose.yaml", type: "Docker Compose" }
|
|
16537
17789
|
];
|
|
16538
17790
|
for (const check of checks) {
|
|
16539
|
-
const filePath =
|
|
16540
|
-
if (
|
|
17791
|
+
const filePath = join29(repoRoot, check.file);
|
|
17792
|
+
if (existsSync20(filePath)) {
|
|
16541
17793
|
let name;
|
|
16542
17794
|
if (check.nameField) {
|
|
16543
17795
|
try {
|
|
16544
|
-
const data = JSON.parse(
|
|
17796
|
+
const data = JSON.parse(readFileSync14(filePath, "utf-8"));
|
|
16545
17797
|
name = data[check.nameField];
|
|
16546
17798
|
} catch {
|
|
16547
17799
|
}
|
|
@@ -16570,7 +17822,7 @@ function findKeyFiles(repoRoot) {
|
|
|
16570
17822
|
{ pattern: "CLAUDE.md", description: "Claude Code context" }
|
|
16571
17823
|
];
|
|
16572
17824
|
for (const check of checks) {
|
|
16573
|
-
if (
|
|
17825
|
+
if (existsSync20(join29(repoRoot, check.pattern))) {
|
|
16574
17826
|
keyFiles.push({ path: check.pattern, description: check.description });
|
|
16575
17827
|
}
|
|
16576
17828
|
}
|
|
@@ -16596,12 +17848,12 @@ function buildDirTree(root, maxDepth, prefix = "", depth = 0) {
|
|
|
16596
17848
|
if (entry.isDirectory()) {
|
|
16597
17849
|
let fileCount = 0;
|
|
16598
17850
|
try {
|
|
16599
|
-
fileCount = readdirSync7(
|
|
17851
|
+
fileCount = readdirSync7(join29(root, entry.name)).filter((f) => !f.startsWith(".")).length;
|
|
16600
17852
|
} catch {
|
|
16601
17853
|
}
|
|
16602
17854
|
result += `${prefix}${connector}${entry.name}/ (${fileCount})
|
|
16603
17855
|
`;
|
|
16604
|
-
result += buildDirTree(
|
|
17856
|
+
result += buildDirTree(join29(root, entry.name), maxDepth, childPrefix, depth + 1);
|
|
16605
17857
|
} else if (depth < maxDepth) {
|
|
16606
17858
|
result += `${prefix}${connector}${entry.name}
|
|
16607
17859
|
`;
|
|
@@ -16654,9 +17906,9 @@ var init_oa_directory = __esm({
|
|
|
16654
17906
|
|
|
16655
17907
|
// packages/cli/dist/tui/setup.js
|
|
16656
17908
|
import * as readline from "node:readline";
|
|
16657
|
-
import { execSync as
|
|
16658
|
-
import { existsSync as
|
|
16659
|
-
import { join as
|
|
17909
|
+
import { execSync as execSync18, spawn as spawn9 } from "node:child_process";
|
|
17910
|
+
import { existsSync as existsSync21, writeFileSync as writeFileSync7, mkdirSync as mkdirSync7 } from "node:fs";
|
|
17911
|
+
import { join as join30 } from "node:path";
|
|
16660
17912
|
import { homedir as homedir10, platform } from "node:os";
|
|
16661
17913
|
function detectSystemSpecs() {
|
|
16662
17914
|
let totalRamGB = 0;
|
|
@@ -16664,7 +17916,7 @@ function detectSystemSpecs() {
|
|
|
16664
17916
|
let gpuVramGB = 0;
|
|
16665
17917
|
let gpuName = "";
|
|
16666
17918
|
try {
|
|
16667
|
-
const memInfo =
|
|
17919
|
+
const memInfo = execSync18("free -b 2>/dev/null || sysctl -n hw.memsize 2>/dev/null", {
|
|
16668
17920
|
encoding: "utf8",
|
|
16669
17921
|
timeout: 5e3
|
|
16670
17922
|
});
|
|
@@ -16684,7 +17936,7 @@ function detectSystemSpecs() {
|
|
|
16684
17936
|
} catch {
|
|
16685
17937
|
}
|
|
16686
17938
|
try {
|
|
16687
|
-
const nvidiaSmi =
|
|
17939
|
+
const nvidiaSmi = execSync18("nvidia-smi --query-gpu=memory.total,name --format=csv,noheader,nounits 2>/dev/null", { encoding: "utf8", timeout: 5e3 });
|
|
16688
17940
|
const lines = nvidiaSmi.trim().split("\n");
|
|
16689
17941
|
if (lines.length > 0) {
|
|
16690
17942
|
for (const line of lines) {
|
|
@@ -16740,12 +17992,12 @@ function modelSupportsToolCalling(modelName) {
|
|
|
16740
17992
|
return false;
|
|
16741
17993
|
}
|
|
16742
17994
|
function ask(rl, question) {
|
|
16743
|
-
return new Promise((
|
|
16744
|
-
rl.question(question, (answer) =>
|
|
17995
|
+
return new Promise((resolve26) => {
|
|
17996
|
+
rl.question(question, (answer) => resolve26(answer.trim()));
|
|
16745
17997
|
});
|
|
16746
17998
|
}
|
|
16747
17999
|
function askSecret(rl, question) {
|
|
16748
|
-
return new Promise((
|
|
18000
|
+
return new Promise((resolve26) => {
|
|
16749
18001
|
process.stdout.write(question);
|
|
16750
18002
|
let secret = "";
|
|
16751
18003
|
const stdin = process.stdin;
|
|
@@ -16763,7 +18015,7 @@ function askSecret(rl, question) {
|
|
|
16763
18015
|
stdin.setRawMode(hadRawMode ?? false);
|
|
16764
18016
|
}
|
|
16765
18017
|
process.stdout.write("\n");
|
|
16766
|
-
|
|
18018
|
+
resolve26(secret.trim());
|
|
16767
18019
|
return;
|
|
16768
18020
|
} else if (c3 === "") {
|
|
16769
18021
|
stdin.removeListener("data", onData);
|
|
@@ -16771,7 +18023,7 @@ function askSecret(rl, question) {
|
|
|
16771
18023
|
stdin.setRawMode(hadRawMode ?? false);
|
|
16772
18024
|
}
|
|
16773
18025
|
process.stdout.write("\n");
|
|
16774
|
-
|
|
18026
|
+
resolve26("");
|
|
16775
18027
|
return;
|
|
16776
18028
|
} else if (c3 === "\x7F" || c3 === "\b") {
|
|
16777
18029
|
if (secret.length > 0) {
|
|
@@ -16809,7 +18061,7 @@ function installOllamaLinux() {
|
|
|
16809
18061
|
|
|
16810
18062
|
`);
|
|
16811
18063
|
try {
|
|
16812
|
-
|
|
18064
|
+
execSync18("curl -fsSL https://ollama.com/install.sh | sh", {
|
|
16813
18065
|
stdio: "inherit",
|
|
16814
18066
|
timeout: 3e5
|
|
16815
18067
|
});
|
|
@@ -16848,10 +18100,10 @@ async function installOllamaMac(rl) {
|
|
|
16848
18100
|
|
|
16849
18101
|
`);
|
|
16850
18102
|
try {
|
|
16851
|
-
|
|
18103
|
+
execSync18('/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"', { stdio: "inherit", timeout: 6e5 });
|
|
16852
18104
|
if (!hasCmd("brew")) {
|
|
16853
18105
|
try {
|
|
16854
|
-
const brewPrefix =
|
|
18106
|
+
const brewPrefix = existsSync21("/opt/homebrew/bin/brew") ? "/opt/homebrew" : "/usr/local";
|
|
16855
18107
|
process.env["PATH"] = `${brewPrefix}/bin:${process.env["PATH"]}`;
|
|
16856
18108
|
} catch {
|
|
16857
18109
|
}
|
|
@@ -16881,7 +18133,7 @@ async function installOllamaMac(rl) {
|
|
|
16881
18133
|
|
|
16882
18134
|
`);
|
|
16883
18135
|
try {
|
|
16884
|
-
|
|
18136
|
+
execSync18("brew install ollama", {
|
|
16885
18137
|
stdio: "inherit",
|
|
16886
18138
|
timeout: 3e5
|
|
16887
18139
|
});
|
|
@@ -16908,7 +18160,7 @@ function installOllamaWindows() {
|
|
|
16908
18160
|
|
|
16909
18161
|
`);
|
|
16910
18162
|
try {
|
|
16911
|
-
|
|
18163
|
+
execSync18('powershell -Command "irm https://ollama.com/install.ps1 | iex"', {
|
|
16912
18164
|
stdio: "inherit",
|
|
16913
18165
|
timeout: 3e5
|
|
16914
18166
|
});
|
|
@@ -16931,7 +18183,7 @@ function installOllamaWindows() {
|
|
|
16931
18183
|
}
|
|
16932
18184
|
function pullModelWithAutoUpdate(tag) {
|
|
16933
18185
|
try {
|
|
16934
|
-
|
|
18186
|
+
execSync18(`ollama pull ${tag}`, {
|
|
16935
18187
|
stdio: "inherit",
|
|
16936
18188
|
timeout: 36e5
|
|
16937
18189
|
// 1 hour max
|
|
@@ -16948,7 +18200,7 @@ function pullModelWithAutoUpdate(tag) {
|
|
|
16948
18200
|
|
|
16949
18201
|
`);
|
|
16950
18202
|
try {
|
|
16951
|
-
|
|
18203
|
+
execSync18("curl -fsSL https://ollama.com/install.sh | sh", {
|
|
16952
18204
|
stdio: "inherit",
|
|
16953
18205
|
timeout: 3e5
|
|
16954
18206
|
// 5 min max for install
|
|
@@ -16959,7 +18211,7 @@ function pullModelWithAutoUpdate(tag) {
|
|
|
16959
18211
|
process.stdout.write(` ${c2.cyan("\u25CF")} Retrying pull of ${c2.bold(tag)}...
|
|
16960
18212
|
|
|
16961
18213
|
`);
|
|
16962
|
-
|
|
18214
|
+
execSync18(`ollama pull ${tag}`, {
|
|
16963
18215
|
stdio: "inherit",
|
|
16964
18216
|
timeout: 36e5
|
|
16965
18217
|
});
|
|
@@ -17140,9 +18392,9 @@ async function doSetup(config, rl) {
|
|
|
17140
18392
|
${c2.cyan("\u25CF")} Starting ollama serve in background...
|
|
17141
18393
|
`);
|
|
17142
18394
|
try {
|
|
17143
|
-
const child =
|
|
18395
|
+
const child = spawn9("ollama", ["serve"], { stdio: "ignore", detached: true });
|
|
17144
18396
|
child.unref();
|
|
17145
|
-
await new Promise((
|
|
18397
|
+
await new Promise((resolve26) => setTimeout(resolve26, 3e3));
|
|
17146
18398
|
try {
|
|
17147
18399
|
models = await fetchOllamaModels(config.backendUrl);
|
|
17148
18400
|
process.stdout.write(` ${c2.green("\u2714")} Ollama is running.
|
|
@@ -17168,9 +18420,9 @@ async function doSetup(config, rl) {
|
|
|
17168
18420
|
${c2.cyan("\u25CF")} Starting ollama serve...
|
|
17169
18421
|
`);
|
|
17170
18422
|
try {
|
|
17171
|
-
const child =
|
|
18423
|
+
const child = spawn9("ollama", ["serve"], { stdio: "ignore", detached: true });
|
|
17172
18424
|
child.unref();
|
|
17173
|
-
await new Promise((
|
|
18425
|
+
await new Promise((resolve26) => setTimeout(resolve26, 3e3));
|
|
17174
18426
|
try {
|
|
17175
18427
|
models = await fetchOllamaModels(config.backendUrl);
|
|
17176
18428
|
process.stdout.write(` ${c2.green("\u2714")} Ollama is running.
|
|
@@ -17325,12 +18577,12 @@ async function doSetup(config, rl) {
|
|
|
17325
18577
|
`PARAMETER num_predict ${numPredict}`,
|
|
17326
18578
|
`PARAMETER stop "<|endoftext|>"`
|
|
17327
18579
|
].join("\n");
|
|
17328
|
-
const modelDir2 =
|
|
18580
|
+
const modelDir2 = join30(homedir10(), ".open-agents", "models");
|
|
17329
18581
|
mkdirSync7(modelDir2, { recursive: true });
|
|
17330
|
-
const modelfilePath =
|
|
18582
|
+
const modelfilePath = join30(modelDir2, `Modelfile.${customName}`);
|
|
17331
18583
|
writeFileSync7(modelfilePath, modelfileContent + "\n", "utf8");
|
|
17332
18584
|
process.stdout.write(` ${c2.dim("Creating model...")} `);
|
|
17333
|
-
|
|
18585
|
+
execSync18(`ollama create ${customName} -f ${modelfilePath}`, {
|
|
17334
18586
|
stdio: "pipe",
|
|
17335
18587
|
timeout: 12e4
|
|
17336
18588
|
});
|
|
@@ -17373,7 +18625,7 @@ async function isModelAvailable(config) {
|
|
|
17373
18625
|
}
|
|
17374
18626
|
function isFirstRun() {
|
|
17375
18627
|
try {
|
|
17376
|
-
return !
|
|
18628
|
+
return !existsSync21(join30(homedir10(), ".open-agents", "config.json"));
|
|
17377
18629
|
} catch {
|
|
17378
18630
|
return true;
|
|
17379
18631
|
}
|
|
@@ -17381,7 +18633,7 @@ function isFirstRun() {
|
|
|
17381
18633
|
function hasCmd(cmd) {
|
|
17382
18634
|
try {
|
|
17383
18635
|
const whichCmd = process.platform === "win32" ? `where ${cmd}` : `which ${cmd}`;
|
|
17384
|
-
|
|
18636
|
+
execSync18(whichCmd, { stdio: "pipe", timeout: 3e3 });
|
|
17385
18637
|
return true;
|
|
17386
18638
|
} catch {
|
|
17387
18639
|
return false;
|
|
@@ -17410,11 +18662,11 @@ function detectPkgManager() {
|
|
|
17410
18662
|
return null;
|
|
17411
18663
|
}
|
|
17412
18664
|
function getVenvDir() {
|
|
17413
|
-
return
|
|
18665
|
+
return join30(homedir10(), ".open-agents", "venv");
|
|
17414
18666
|
}
|
|
17415
18667
|
function hasVenvModule() {
|
|
17416
18668
|
try {
|
|
17417
|
-
|
|
18669
|
+
execSync18("python3 -m venv --help", { stdio: "pipe", timeout: 5e3 });
|
|
17418
18670
|
return true;
|
|
17419
18671
|
} catch {
|
|
17420
18672
|
return false;
|
|
@@ -17422,8 +18674,8 @@ function hasVenvModule() {
|
|
|
17422
18674
|
}
|
|
17423
18675
|
function ensureVenv(log) {
|
|
17424
18676
|
const venvDir = getVenvDir();
|
|
17425
|
-
const venvPip =
|
|
17426
|
-
if (
|
|
18677
|
+
const venvPip = join30(venvDir, "bin", "pip");
|
|
18678
|
+
if (existsSync21(venvPip))
|
|
17427
18679
|
return venvDir;
|
|
17428
18680
|
log("Creating Python venv for vision deps...");
|
|
17429
18681
|
if (!hasCmd("python3")) {
|
|
@@ -17435,9 +18687,9 @@ function ensureVenv(log) {
|
|
|
17435
18687
|
return null;
|
|
17436
18688
|
}
|
|
17437
18689
|
try {
|
|
17438
|
-
mkdirSync7(
|
|
17439
|
-
|
|
17440
|
-
|
|
18690
|
+
mkdirSync7(join30(homedir10(), ".open-agents"), { recursive: true });
|
|
18691
|
+
execSync18(`python3 -m venv "${venvDir}"`, { stdio: "pipe", timeout: 3e4 });
|
|
18692
|
+
execSync18(`"${join30(venvDir, "bin", "pip")}" install --upgrade pip`, {
|
|
17441
18693
|
stdio: "pipe",
|
|
17442
18694
|
timeout: 6e4
|
|
17443
18695
|
});
|
|
@@ -17450,7 +18702,7 @@ function ensureVenv(log) {
|
|
|
17450
18702
|
}
|
|
17451
18703
|
function trySudoPasswordless(cmd, timeoutMs = 12e4) {
|
|
17452
18704
|
try {
|
|
17453
|
-
|
|
18705
|
+
execSync18(`sudo -n ${cmd}`, {
|
|
17454
18706
|
stdio: "pipe",
|
|
17455
18707
|
timeout: timeoutMs,
|
|
17456
18708
|
env: { ...process.env, DEBIAN_FRONTEND: "noninteractive" }
|
|
@@ -17462,7 +18714,7 @@ function trySudoPasswordless(cmd, timeoutMs = 12e4) {
|
|
|
17462
18714
|
}
|
|
17463
18715
|
function runWithSudo(cmd, password, timeoutMs = 12e4) {
|
|
17464
18716
|
try {
|
|
17465
|
-
|
|
18717
|
+
execSync18(`sudo -S ${cmd}`, {
|
|
17466
18718
|
input: password + "\n",
|
|
17467
18719
|
stdio: ["pipe", "pipe", "pipe"],
|
|
17468
18720
|
timeout: timeoutMs,
|
|
@@ -17522,7 +18774,7 @@ async function ensureVisionDeps(onInfo, getSudoPassword) {
|
|
|
17522
18774
|
} else {
|
|
17523
18775
|
log("Installing tesseract-ocr...");
|
|
17524
18776
|
try {
|
|
17525
|
-
|
|
18777
|
+
execSync18(pkg.cmd, { stdio: "pipe", timeout: 12e4 });
|
|
17526
18778
|
if (hasCmd("tesseract")) {
|
|
17527
18779
|
log("tesseract-ocr installed successfully.");
|
|
17528
18780
|
} else {
|
|
@@ -17594,7 +18846,7 @@ async function ensureVisionDeps(onInfo, getSudoPassword) {
|
|
|
17594
18846
|
} else {
|
|
17595
18847
|
log(`Installing ${dep.label}...`);
|
|
17596
18848
|
try {
|
|
17597
|
-
|
|
18849
|
+
execSync18(pkg.cmd, { stdio: "pipe", timeout: 12e4 });
|
|
17598
18850
|
if (hasCmd(dep.binary)) {
|
|
17599
18851
|
log(`${dep.label} installed successfully.`);
|
|
17600
18852
|
} else {
|
|
@@ -17625,7 +18877,7 @@ async function ensureVisionDeps(onInfo, getSudoPassword) {
|
|
|
17625
18877
|
const venvCmds = {
|
|
17626
18878
|
apt: () => {
|
|
17627
18879
|
try {
|
|
17628
|
-
const pyVer =
|
|
18880
|
+
const pyVer = execSync18(`python3 -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')"`, { encoding: "utf8", stdio: "pipe", timeout: 5e3 }).trim();
|
|
17629
18881
|
return `apt-get install -y python3-venv python${pyVer}-venv`;
|
|
17630
18882
|
} catch {
|
|
17631
18883
|
return "apt-get install -y python3-venv";
|
|
@@ -17646,19 +18898,19 @@ async function ensureVisionDeps(onInfo, getSudoPassword) {
|
|
|
17646
18898
|
}
|
|
17647
18899
|
}
|
|
17648
18900
|
const venvDir = getVenvDir();
|
|
17649
|
-
const venvBin =
|
|
17650
|
-
const venvMoondream =
|
|
18901
|
+
const venvBin = join30(venvDir, "bin");
|
|
18902
|
+
const venvMoondream = join30(venvBin, "moondream-station");
|
|
17651
18903
|
const venv = ensureVenv(log);
|
|
17652
|
-
if (venv && !hasCmd("moondream-station") && !
|
|
17653
|
-
const venvPip =
|
|
18904
|
+
if (venv && !hasCmd("moondream-station") && !existsSync21(venvMoondream)) {
|
|
18905
|
+
const venvPip = join30(venvBin, "pip");
|
|
17654
18906
|
log("Installing moondream-station in ~/.open-agents/venv...");
|
|
17655
18907
|
try {
|
|
17656
|
-
|
|
17657
|
-
if (
|
|
18908
|
+
execSync18(`"${venvPip}" install moondream-station`, { stdio: "pipe", timeout: 3e5 });
|
|
18909
|
+
if (existsSync21(venvMoondream)) {
|
|
17658
18910
|
log("moondream-station installed successfully.");
|
|
17659
18911
|
} else {
|
|
17660
18912
|
try {
|
|
17661
|
-
const check =
|
|
18913
|
+
const check = execSync18(`"${venvPip}" show moondream-station`, { encoding: "utf8", stdio: "pipe", timeout: 5e3 });
|
|
17662
18914
|
if (check.includes("moondream")) {
|
|
17663
18915
|
log("moondream-station package installed.");
|
|
17664
18916
|
}
|
|
@@ -17671,11 +18923,11 @@ async function ensureVisionDeps(onInfo, getSudoPassword) {
|
|
|
17671
18923
|
}
|
|
17672
18924
|
}
|
|
17673
18925
|
if (venv) {
|
|
17674
|
-
const venvPython =
|
|
17675
|
-
const venvPip2 =
|
|
18926
|
+
const venvPython = join30(venvBin, "python");
|
|
18927
|
+
const venvPip2 = join30(venvBin, "pip");
|
|
17676
18928
|
let ocrStackInstalled = false;
|
|
17677
18929
|
try {
|
|
17678
|
-
|
|
18930
|
+
execSync18(`"${venvPython}" -c "import cv2, pytesseract, numpy, PIL"`, { stdio: "pipe", timeout: 1e4 });
|
|
17679
18931
|
ocrStackInstalled = true;
|
|
17680
18932
|
} catch {
|
|
17681
18933
|
}
|
|
@@ -17683,9 +18935,9 @@ async function ensureVisionDeps(onInfo, getSudoPassword) {
|
|
|
17683
18935
|
const ocrPackages = "pytesseract Pillow opencv-python-headless numpy";
|
|
17684
18936
|
log("Installing OCR Python stack (pytesseract, OpenCV, Pillow, numpy)...");
|
|
17685
18937
|
try {
|
|
17686
|
-
|
|
18938
|
+
execSync18(`"${venvPip2}" install ${ocrPackages}`, { stdio: "pipe", timeout: 3e5 });
|
|
17687
18939
|
try {
|
|
17688
|
-
|
|
18940
|
+
execSync18(`"${venvPython}" -c "import cv2, pytesseract, numpy, PIL"`, { stdio: "pipe", timeout: 1e4 });
|
|
17689
18941
|
log("OCR Python stack installed successfully.");
|
|
17690
18942
|
} catch {
|
|
17691
18943
|
log("OCR Python stack install completed but import verification failed.");
|
|
@@ -17732,11 +18984,11 @@ function createExpandedVariant(baseModel, specs, sizeGB) {
|
|
|
17732
18984
|
`PARAMETER num_predict ${numPredict}`,
|
|
17733
18985
|
`PARAMETER stop "<|endoftext|>"`
|
|
17734
18986
|
].join("\n");
|
|
17735
|
-
const modelDir2 =
|
|
18987
|
+
const modelDir2 = join30(homedir10(), ".open-agents", "models");
|
|
17736
18988
|
mkdirSync7(modelDir2, { recursive: true });
|
|
17737
|
-
const modelfilePath =
|
|
18989
|
+
const modelfilePath = join30(modelDir2, `Modelfile.${customName}`);
|
|
17738
18990
|
writeFileSync7(modelfilePath, modelfileContent + "\n", "utf8");
|
|
17739
|
-
|
|
18991
|
+
execSync18(`ollama create ${customName} -f ${modelfilePath}`, {
|
|
17740
18992
|
stdio: "pipe",
|
|
17741
18993
|
timeout: 12e4
|
|
17742
18994
|
});
|
|
@@ -18522,18 +19774,18 @@ async function handleUpdate(subcommand, ctx) {
|
|
|
18522
19774
|
let currentVersion = "0.0.0";
|
|
18523
19775
|
try {
|
|
18524
19776
|
const { createRequire: createRequire4 } = await import("node:module");
|
|
18525
|
-
const { fileURLToPath:
|
|
18526
|
-
const { dirname:
|
|
18527
|
-
const { existsSync:
|
|
19777
|
+
const { fileURLToPath: fileURLToPath10 } = await import("node:url");
|
|
19778
|
+
const { dirname: dirname13, join: join41 } = await import("node:path");
|
|
19779
|
+
const { existsSync: existsSync28 } = await import("node:fs");
|
|
18528
19780
|
const req = createRequire4(import.meta.url);
|
|
18529
|
-
const thisDir =
|
|
19781
|
+
const thisDir = dirname13(fileURLToPath10(import.meta.url));
|
|
18530
19782
|
const candidates = [
|
|
18531
|
-
|
|
18532
|
-
|
|
18533
|
-
|
|
19783
|
+
join41(thisDir, "..", "package.json"),
|
|
19784
|
+
join41(thisDir, "..", "..", "package.json"),
|
|
19785
|
+
join41(thisDir, "..", "..", "..", "package.json")
|
|
18534
19786
|
];
|
|
18535
19787
|
for (const pkgPath of candidates) {
|
|
18536
|
-
if (
|
|
19788
|
+
if (existsSync28(pkgPath)) {
|
|
18537
19789
|
const pkg = req(pkgPath);
|
|
18538
19790
|
if (pkg.name === "open-agents-ai" || pkg.name === "@open-agents/cli") {
|
|
18539
19791
|
currentVersion = pkg.version ?? "0.0.0";
|
|
@@ -18571,8 +19823,8 @@ async function handleUpdate(subcommand, ctx) {
|
|
|
18571
19823
|
checkSpinner.stop(`Update available: v${info.currentVersion} \u2192 v${c2.bold(c2.green(info.latestVersion))}`);
|
|
18572
19824
|
const installSpinner = startInlineSpinner("Installing update");
|
|
18573
19825
|
const { exec } = await import("node:child_process");
|
|
18574
|
-
const installOk = await new Promise((
|
|
18575
|
-
const child = exec(`npm cache clean --force open-agents-ai 2>/dev/null; npm install -g open-agents-ai@latest --force`, { timeout: 18e4 }, (err) =>
|
|
19826
|
+
const installOk = await new Promise((resolve26) => {
|
|
19827
|
+
const child = exec(`npm cache clean --force open-agents-ai 2>/dev/null; npm install -g open-agents-ai@latest --force`, { timeout: 18e4 }, (err) => resolve26(!err));
|
|
18576
19828
|
child.stdout?.resume();
|
|
18577
19829
|
child.stderr?.resume();
|
|
18578
19830
|
});
|
|
@@ -18665,9 +19917,9 @@ var init_commands = __esm({
|
|
|
18665
19917
|
});
|
|
18666
19918
|
|
|
18667
19919
|
// packages/cli/dist/tui/project-context.js
|
|
18668
|
-
import { existsSync as
|
|
18669
|
-
import { join as
|
|
18670
|
-
import { execSync as
|
|
19920
|
+
import { existsSync as existsSync22, readFileSync as readFileSync15, readdirSync as readdirSync8 } from "node:fs";
|
|
19921
|
+
import { join as join31, basename as basename10 } from "node:path";
|
|
19922
|
+
import { execSync as execSync19 } from "node:child_process";
|
|
18671
19923
|
import { homedir as homedir11, platform as platform2, release } from "node:os";
|
|
18672
19924
|
function getModelTier(modelName) {
|
|
18673
19925
|
const m = modelName.toLowerCase();
|
|
@@ -18701,10 +19953,10 @@ function loadProjectMap(repoRoot) {
|
|
|
18701
19953
|
if (!hasOaDirectory(repoRoot)) {
|
|
18702
19954
|
initOaDirectory(repoRoot);
|
|
18703
19955
|
}
|
|
18704
|
-
const mapPath =
|
|
18705
|
-
if (
|
|
19956
|
+
const mapPath = join31(repoRoot, OA_DIR, "context", "project-map.md");
|
|
19957
|
+
if (existsSync22(mapPath)) {
|
|
18706
19958
|
try {
|
|
18707
|
-
const content =
|
|
19959
|
+
const content = readFileSync15(mapPath, "utf-8");
|
|
18708
19960
|
return content;
|
|
18709
19961
|
} catch {
|
|
18710
19962
|
}
|
|
@@ -18713,19 +19965,19 @@ function loadProjectMap(repoRoot) {
|
|
|
18713
19965
|
}
|
|
18714
19966
|
function getGitInfo(repoRoot) {
|
|
18715
19967
|
try {
|
|
18716
|
-
|
|
19968
|
+
execSync19("git rev-parse --is-inside-work-tree", { cwd: repoRoot, stdio: "pipe" });
|
|
18717
19969
|
} catch {
|
|
18718
19970
|
return "";
|
|
18719
19971
|
}
|
|
18720
19972
|
const lines = [];
|
|
18721
19973
|
try {
|
|
18722
|
-
const branch =
|
|
19974
|
+
const branch = execSync19("git branch --show-current", { cwd: repoRoot, encoding: "utf-8", stdio: "pipe" }).trim();
|
|
18723
19975
|
if (branch)
|
|
18724
19976
|
lines.push(`Branch: ${branch}`);
|
|
18725
19977
|
} catch {
|
|
18726
19978
|
}
|
|
18727
19979
|
try {
|
|
18728
|
-
const status =
|
|
19980
|
+
const status = execSync19("git status --porcelain", { cwd: repoRoot, encoding: "utf-8", stdio: "pipe" }).trim();
|
|
18729
19981
|
if (status) {
|
|
18730
19982
|
const changed = status.split("\n").length;
|
|
18731
19983
|
lines.push(`Working tree: ${changed} changed file(s)`);
|
|
@@ -18735,7 +19987,7 @@ function getGitInfo(repoRoot) {
|
|
|
18735
19987
|
} catch {
|
|
18736
19988
|
}
|
|
18737
19989
|
try {
|
|
18738
|
-
const log =
|
|
19990
|
+
const log = execSync19("git log --oneline -5 --no-decorate", { cwd: repoRoot, encoding: "utf-8", stdio: "pipe" }).trim();
|
|
18739
19991
|
if (log)
|
|
18740
19992
|
lines.push(`Recent commits:
|
|
18741
19993
|
${log}`);
|
|
@@ -18745,31 +19997,31 @@ ${log}`);
|
|
|
18745
19997
|
}
|
|
18746
19998
|
function loadMemoryContext(repoRoot) {
|
|
18747
19999
|
const sections = [];
|
|
18748
|
-
const oaMemDir =
|
|
20000
|
+
const oaMemDir = join31(repoRoot, OA_DIR, "memory");
|
|
18749
20001
|
const oaEntries = loadMemoryDir(oaMemDir, "project");
|
|
18750
20002
|
if (oaEntries)
|
|
18751
20003
|
sections.push(oaEntries);
|
|
18752
|
-
const legacyMemDir =
|
|
18753
|
-
if (legacyMemDir !== oaMemDir &&
|
|
20004
|
+
const legacyMemDir = join31(repoRoot, ".open-agents", "memory");
|
|
20005
|
+
if (legacyMemDir !== oaMemDir && existsSync22(legacyMemDir)) {
|
|
18754
20006
|
const legacyEntries = loadMemoryDir(legacyMemDir, "project/legacy");
|
|
18755
20007
|
if (legacyEntries)
|
|
18756
20008
|
sections.push(legacyEntries);
|
|
18757
20009
|
}
|
|
18758
|
-
const globalMemDir =
|
|
20010
|
+
const globalMemDir = join31(homedir11(), ".open-agents", "memory");
|
|
18759
20011
|
const globalEntries = loadMemoryDir(globalMemDir, "global");
|
|
18760
20012
|
if (globalEntries)
|
|
18761
20013
|
sections.push(globalEntries);
|
|
18762
20014
|
return sections.join("\n\n");
|
|
18763
20015
|
}
|
|
18764
20016
|
function loadMemoryDir(memDir, scope) {
|
|
18765
|
-
if (!
|
|
20017
|
+
if (!existsSync22(memDir))
|
|
18766
20018
|
return "";
|
|
18767
20019
|
const lines = [];
|
|
18768
20020
|
try {
|
|
18769
20021
|
const files = readdirSync8(memDir).filter((f) => f.endsWith(".json"));
|
|
18770
20022
|
for (const file of files.slice(0, 10)) {
|
|
18771
20023
|
try {
|
|
18772
|
-
const raw =
|
|
20024
|
+
const raw = readFileSync15(join31(memDir, file), "utf-8");
|
|
18773
20025
|
const entries = JSON.parse(raw);
|
|
18774
20026
|
const topic = basename10(file, ".json");
|
|
18775
20027
|
const keys = Object.keys(entries);
|
|
@@ -19796,22 +21048,22 @@ var init_carousel = __esm({
|
|
|
19796
21048
|
});
|
|
19797
21049
|
|
|
19798
21050
|
// packages/cli/dist/tui/carousel-descriptors.js
|
|
19799
|
-
import { existsSync as
|
|
19800
|
-
import { join as
|
|
21051
|
+
import { existsSync as existsSync23, readFileSync as readFileSync16, writeFileSync as writeFileSync8, mkdirSync as mkdirSync8, readdirSync as readdirSync9 } from "node:fs";
|
|
21052
|
+
import { join as join32, basename as basename11 } from "node:path";
|
|
19801
21053
|
function loadToolProfile(repoRoot) {
|
|
19802
|
-
const filePath =
|
|
21054
|
+
const filePath = join32(repoRoot, OA_DIR, "context", TOOL_PROFILE_FILE);
|
|
19803
21055
|
try {
|
|
19804
|
-
if (!
|
|
21056
|
+
if (!existsSync23(filePath))
|
|
19805
21057
|
return null;
|
|
19806
|
-
return JSON.parse(
|
|
21058
|
+
return JSON.parse(readFileSync16(filePath, "utf-8"));
|
|
19807
21059
|
} catch {
|
|
19808
21060
|
return null;
|
|
19809
21061
|
}
|
|
19810
21062
|
}
|
|
19811
21063
|
function saveToolProfile(repoRoot, profile) {
|
|
19812
|
-
const contextDir =
|
|
21064
|
+
const contextDir = join32(repoRoot, OA_DIR, "context");
|
|
19813
21065
|
mkdirSync8(contextDir, { recursive: true });
|
|
19814
|
-
writeFileSync8(
|
|
21066
|
+
writeFileSync8(join32(contextDir, TOOL_PROFILE_FILE), JSON.stringify(profile, null, 2), "utf-8");
|
|
19815
21067
|
}
|
|
19816
21068
|
function categorizeToolCall(toolName) {
|
|
19817
21069
|
for (const cat of TOOL_CATEGORIES) {
|
|
@@ -19869,25 +21121,25 @@ function weightedColor(profile) {
|
|
|
19869
21121
|
return selectedCat.colors[Math.floor(Math.random() * selectedCat.colors.length)];
|
|
19870
21122
|
}
|
|
19871
21123
|
function loadCachedDescriptors(repoRoot) {
|
|
19872
|
-
const filePath =
|
|
21124
|
+
const filePath = join32(repoRoot, OA_DIR, "context", DESCRIPTOR_FILE);
|
|
19873
21125
|
try {
|
|
19874
|
-
if (!
|
|
21126
|
+
if (!existsSync23(filePath))
|
|
19875
21127
|
return null;
|
|
19876
|
-
const cached = JSON.parse(
|
|
21128
|
+
const cached = JSON.parse(readFileSync16(filePath, "utf-8"));
|
|
19877
21129
|
return cached.phrases.length > 0 ? cached.phrases : null;
|
|
19878
21130
|
} catch {
|
|
19879
21131
|
return null;
|
|
19880
21132
|
}
|
|
19881
21133
|
}
|
|
19882
21134
|
function saveCachedDescriptors(repoRoot, phrases, sourceHash) {
|
|
19883
|
-
const contextDir =
|
|
21135
|
+
const contextDir = join32(repoRoot, OA_DIR, "context");
|
|
19884
21136
|
mkdirSync8(contextDir, { recursive: true });
|
|
19885
21137
|
const cached = {
|
|
19886
21138
|
phrases,
|
|
19887
21139
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
19888
21140
|
sourceHash
|
|
19889
21141
|
};
|
|
19890
|
-
writeFileSync8(
|
|
21142
|
+
writeFileSync8(join32(contextDir, DESCRIPTOR_FILE), JSON.stringify(cached, null, 2), "utf-8");
|
|
19891
21143
|
}
|
|
19892
21144
|
function generateDescriptors(repoRoot) {
|
|
19893
21145
|
const profile = loadToolProfile(repoRoot);
|
|
@@ -19935,11 +21187,11 @@ function generateDescriptors(repoRoot) {
|
|
|
19935
21187
|
return phrases;
|
|
19936
21188
|
}
|
|
19937
21189
|
function extractFromPackageJson(repoRoot, tags) {
|
|
19938
|
-
const pkgPath =
|
|
21190
|
+
const pkgPath = join32(repoRoot, "package.json");
|
|
19939
21191
|
try {
|
|
19940
|
-
if (!
|
|
21192
|
+
if (!existsSync23(pkgPath))
|
|
19941
21193
|
return;
|
|
19942
|
-
const pkg = JSON.parse(
|
|
21194
|
+
const pkg = JSON.parse(readFileSync16(pkgPath, "utf-8"));
|
|
19943
21195
|
if (pkg.name && typeof pkg.name === "string") {
|
|
19944
21196
|
const parts = pkg.name.replace(/^@/, "").split("/");
|
|
19945
21197
|
for (const p of parts)
|
|
@@ -19983,7 +21235,7 @@ function extractFromManifests(repoRoot, tags) {
|
|
|
19983
21235
|
{ file: ".github/workflows", tag: "ci/cd" }
|
|
19984
21236
|
];
|
|
19985
21237
|
for (const check of manifestChecks) {
|
|
19986
|
-
if (
|
|
21238
|
+
if (existsSync23(join32(repoRoot, check.file))) {
|
|
19987
21239
|
tags.push(check.tag);
|
|
19988
21240
|
}
|
|
19989
21241
|
}
|
|
@@ -20005,16 +21257,16 @@ function extractFromSessions(repoRoot, tags) {
|
|
|
20005
21257
|
}
|
|
20006
21258
|
}
|
|
20007
21259
|
function extractFromMemory(repoRoot, tags) {
|
|
20008
|
-
const memoryDir =
|
|
21260
|
+
const memoryDir = join32(repoRoot, OA_DIR, "memory");
|
|
20009
21261
|
try {
|
|
20010
|
-
if (!
|
|
21262
|
+
if (!existsSync23(memoryDir))
|
|
20011
21263
|
return;
|
|
20012
21264
|
const files = readdirSync9(memoryDir).filter((f) => f.endsWith(".json"));
|
|
20013
21265
|
for (const file of files) {
|
|
20014
21266
|
const topic = file.replace(/\.json$/, "").replace(/[-_]/g, " ");
|
|
20015
21267
|
tags.push(topic);
|
|
20016
21268
|
try {
|
|
20017
|
-
const data = JSON.parse(
|
|
21269
|
+
const data = JSON.parse(readFileSync16(join32(memoryDir, file), "utf-8"));
|
|
20018
21270
|
if (data && typeof data === "object") {
|
|
20019
21271
|
const keys = Object.keys(data).slice(0, 3);
|
|
20020
21272
|
for (const key of keys) {
|
|
@@ -20149,25 +21401,25 @@ var init_carousel_descriptors = __esm({
|
|
|
20149
21401
|
});
|
|
20150
21402
|
|
|
20151
21403
|
// packages/cli/dist/tui/voice.js
|
|
20152
|
-
import { existsSync as
|
|
20153
|
-
import { join as
|
|
21404
|
+
import { existsSync as existsSync24, mkdirSync as mkdirSync9, writeFileSync as writeFileSync9, readFileSync as readFileSync17, unlinkSync as unlinkSync4 } from "node:fs";
|
|
21405
|
+
import { join as join33 } from "node:path";
|
|
20154
21406
|
import { homedir as homedir12, tmpdir as tmpdir6, platform as platform3 } from "node:os";
|
|
20155
|
-
import { execSync as
|
|
21407
|
+
import { execSync as execSync20, spawn as nodeSpawn } from "node:child_process";
|
|
20156
21408
|
import { createRequire } from "node:module";
|
|
20157
21409
|
function voiceDir() {
|
|
20158
|
-
return
|
|
21410
|
+
return join33(homedir12(), ".open-agents", "voice");
|
|
20159
21411
|
}
|
|
20160
21412
|
function modelsDir() {
|
|
20161
|
-
return
|
|
21413
|
+
return join33(voiceDir(), "models");
|
|
20162
21414
|
}
|
|
20163
21415
|
function modelDir(id) {
|
|
20164
|
-
return
|
|
21416
|
+
return join33(modelsDir(), id);
|
|
20165
21417
|
}
|
|
20166
21418
|
function modelOnnxPath(id) {
|
|
20167
|
-
return
|
|
21419
|
+
return join33(modelDir(id), "model.onnx");
|
|
20168
21420
|
}
|
|
20169
21421
|
function modelConfigPath(id) {
|
|
20170
|
-
return
|
|
21422
|
+
return join33(modelDir(id), "config.json");
|
|
20171
21423
|
}
|
|
20172
21424
|
function describeToolCall(toolName, args, personality = 2) {
|
|
20173
21425
|
const path = args["path"];
|
|
@@ -20242,6 +21494,14 @@ function describeToolCallTerse(toolName, args, file) {
|
|
|
20242
21494
|
return `Creating custom tool`;
|
|
20243
21495
|
case "manage_tools":
|
|
20244
21496
|
return `Managing custom tools`;
|
|
21497
|
+
case "browser_action":
|
|
21498
|
+
return `Browser ${args["action"] ?? "action"}`;
|
|
21499
|
+
case "scheduler":
|
|
21500
|
+
return `${args["action"] === "create" ? "Scheduling task" : "Checking scheduler"}`;
|
|
21501
|
+
case "reminder":
|
|
21502
|
+
return `${args["action"] === "set" ? "Setting reminder" : "Checking reminders"}`;
|
|
21503
|
+
case "agenda":
|
|
21504
|
+
return `Checking agenda`;
|
|
20245
21505
|
default:
|
|
20246
21506
|
return `Using ${toolName}`;
|
|
20247
21507
|
}
|
|
@@ -20288,6 +21548,14 @@ function describeToolCallConversational(toolName, args, file) {
|
|
|
20288
21548
|
return `Taking a look at that image`;
|
|
20289
21549
|
case "screenshot":
|
|
20290
21550
|
return `Grabbing a screenshot`;
|
|
21551
|
+
case "browser_action":
|
|
21552
|
+
return `Let me ${args["action"] === "navigate" ? "open that page" : args["action"] === "screenshot" ? "grab a screenshot of the browser" : `do a browser ${args["action"] ?? "action"}`}`;
|
|
21553
|
+
case "scheduler":
|
|
21554
|
+
return `${args["action"] === "create" ? "Setting up a scheduled task" : "Checking the schedule"}`;
|
|
21555
|
+
case "reminder":
|
|
21556
|
+
return `${args["action"] === "set" ? "Making a note for next time" : "Looking at reminders"}`;
|
|
21557
|
+
case "agenda":
|
|
21558
|
+
return `Let me check what's on the agenda`;
|
|
20291
21559
|
default:
|
|
20292
21560
|
return `Working with ${toolName}`;
|
|
20293
21561
|
}
|
|
@@ -20334,6 +21602,14 @@ function describeToolCallChatty(toolName, args, file) {
|
|
|
20334
21602
|
return `Let me get a good look at that image`;
|
|
20335
21603
|
case "screenshot":
|
|
20336
21604
|
return `Snapping a screenshot to see what's happening`;
|
|
21605
|
+
case "browser_action":
|
|
21606
|
+
return `Firing up the browser, let's ${args["action"] === "navigate" ? "see what's on that page" : args["action"] === "screenshot" ? "get a visual" : `${args["action"] ?? "do this"}`}`;
|
|
21607
|
+
case "scheduler":
|
|
21608
|
+
return `${args["action"] === "create" ? "Alright, let me set up a recurring task for you" : "Let me pull up the schedule and see what's coming up"}`;
|
|
21609
|
+
case "reminder":
|
|
21610
|
+
return `${args["action"] === "set" ? "Leaving myself a note for future me, don't let me forget" : "Let me check if past me left any reminders"}`;
|
|
21611
|
+
case "agenda":
|
|
21612
|
+
return `Let me see the full picture of what needs doing`;
|
|
20337
21613
|
default:
|
|
20338
21614
|
return `Pulling in ${toolName}, hang tight`;
|
|
20339
21615
|
}
|
|
@@ -20589,7 +21865,7 @@ var init_voice = __esm({
|
|
|
20589
21865
|
const audioData = result["output"].data;
|
|
20590
21866
|
if (audioData.length === 0)
|
|
20591
21867
|
return;
|
|
20592
|
-
const wavPath =
|
|
21868
|
+
const wavPath = join33(tmpdir6(), `oa-voice-${Date.now()}.wav`);
|
|
20593
21869
|
this.writeWav(audioData, this.config.audio.sample_rate, wavPath);
|
|
20594
21870
|
await this.playWav(wavPath);
|
|
20595
21871
|
try {
|
|
@@ -20678,7 +21954,7 @@ var init_voice = __esm({
|
|
|
20678
21954
|
const cmd = this.getPlayCommand(path);
|
|
20679
21955
|
if (!cmd)
|
|
20680
21956
|
return;
|
|
20681
|
-
return new Promise((
|
|
21957
|
+
return new Promise((resolve26) => {
|
|
20682
21958
|
const child = nodeSpawn(cmd[0], cmd.slice(1), {
|
|
20683
21959
|
stdio: "ignore",
|
|
20684
21960
|
detached: false
|
|
@@ -20687,12 +21963,12 @@ var init_voice = __esm({
|
|
|
20687
21963
|
child.on("close", () => {
|
|
20688
21964
|
if (this.currentPlayback === child)
|
|
20689
21965
|
this.currentPlayback = null;
|
|
20690
|
-
|
|
21966
|
+
resolve26();
|
|
20691
21967
|
});
|
|
20692
21968
|
child.on("error", () => {
|
|
20693
21969
|
if (this.currentPlayback === child)
|
|
20694
21970
|
this.currentPlayback = null;
|
|
20695
|
-
|
|
21971
|
+
resolve26();
|
|
20696
21972
|
});
|
|
20697
21973
|
setTimeout(() => {
|
|
20698
21974
|
if (this.currentPlayback === child) {
|
|
@@ -20702,7 +21978,7 @@ var init_voice = __esm({
|
|
|
20702
21978
|
}
|
|
20703
21979
|
this.currentPlayback = null;
|
|
20704
21980
|
}
|
|
20705
|
-
|
|
21981
|
+
resolve26();
|
|
20706
21982
|
}, 15e3);
|
|
20707
21983
|
});
|
|
20708
21984
|
}
|
|
@@ -20719,7 +21995,7 @@ var init_voice = __esm({
|
|
|
20719
21995
|
}
|
|
20720
21996
|
for (const player of ["paplay", "pw-play", "aplay"]) {
|
|
20721
21997
|
try {
|
|
20722
|
-
|
|
21998
|
+
execSync20(`which ${player}`, { stdio: "pipe" });
|
|
20723
21999
|
return [player, path];
|
|
20724
22000
|
} catch {
|
|
20725
22001
|
}
|
|
@@ -20744,14 +22020,14 @@ var init_voice = __esm({
|
|
|
20744
22020
|
const arch = process.arch;
|
|
20745
22021
|
const isArmLinux = (arch === "arm64" || arch === "arm") && process.platform === "linux";
|
|
20746
22022
|
mkdirSync9(voiceDir(), { recursive: true });
|
|
20747
|
-
const pkgPath =
|
|
22023
|
+
const pkgPath = join33(voiceDir(), "package.json");
|
|
20748
22024
|
const expectedDeps = {
|
|
20749
22025
|
"onnxruntime-node": "^1.21.0",
|
|
20750
22026
|
"phonemizer": "^1.2.1"
|
|
20751
22027
|
};
|
|
20752
|
-
if (
|
|
22028
|
+
if (existsSync24(pkgPath)) {
|
|
20753
22029
|
try {
|
|
20754
|
-
const existing = JSON.parse(
|
|
22030
|
+
const existing = JSON.parse(readFileSync17(pkgPath, "utf8"));
|
|
20755
22031
|
if (!existing.dependencies?.["phonemizer"]) {
|
|
20756
22032
|
existing.dependencies = { ...existing.dependencies, ...expectedDeps };
|
|
20757
22033
|
writeFileSync9(pkgPath, JSON.stringify(existing, null, 2));
|
|
@@ -20759,14 +22035,14 @@ var init_voice = __esm({
|
|
|
20759
22035
|
} catch {
|
|
20760
22036
|
}
|
|
20761
22037
|
}
|
|
20762
|
-
if (!
|
|
22038
|
+
if (!existsSync24(pkgPath)) {
|
|
20763
22039
|
writeFileSync9(pkgPath, JSON.stringify({
|
|
20764
22040
|
name: "open-agents-voice",
|
|
20765
22041
|
private: true,
|
|
20766
22042
|
dependencies: expectedDeps
|
|
20767
22043
|
}, null, 2));
|
|
20768
22044
|
}
|
|
20769
|
-
const voiceRequire = createRequire(
|
|
22045
|
+
const voiceRequire = createRequire(join33(voiceDir(), "index.js"));
|
|
20770
22046
|
try {
|
|
20771
22047
|
this.ort = voiceRequire("onnxruntime-node");
|
|
20772
22048
|
} catch {
|
|
@@ -20775,7 +22051,7 @@ var init_voice = __esm({
|
|
|
20775
22051
|
}
|
|
20776
22052
|
renderInfo("Installing ONNX runtime for voice synthesis...");
|
|
20777
22053
|
try {
|
|
20778
|
-
|
|
22054
|
+
execSync20("npm install --no-audit --no-fund", {
|
|
20779
22055
|
cwd: voiceDir(),
|
|
20780
22056
|
stdio: "pipe",
|
|
20781
22057
|
timeout: 12e4
|
|
@@ -20796,7 +22072,7 @@ Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
|
20796
22072
|
}
|
|
20797
22073
|
renderInfo("Installing phonemizer for voice synthesis...");
|
|
20798
22074
|
try {
|
|
20799
|
-
|
|
22075
|
+
execSync20("npm install --no-audit --no-fund", {
|
|
20800
22076
|
cwd: voiceDir(),
|
|
20801
22077
|
stdio: "pipe",
|
|
20802
22078
|
timeout: 12e4
|
|
@@ -20820,10 +22096,10 @@ Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
|
20820
22096
|
const dir = modelDir(id);
|
|
20821
22097
|
const onnxPath = modelOnnxPath(id);
|
|
20822
22098
|
const configPath = modelConfigPath(id);
|
|
20823
|
-
if (
|
|
22099
|
+
if (existsSync24(onnxPath) && existsSync24(configPath))
|
|
20824
22100
|
return;
|
|
20825
22101
|
mkdirSync9(dir, { recursive: true });
|
|
20826
|
-
if (!
|
|
22102
|
+
if (!existsSync24(configPath)) {
|
|
20827
22103
|
renderInfo(`Downloading ${model.label} voice config...`);
|
|
20828
22104
|
const configResp = await fetch(model.configUrl);
|
|
20829
22105
|
if (!configResp.ok)
|
|
@@ -20831,7 +22107,7 @@ Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
|
20831
22107
|
const configText = await configResp.text();
|
|
20832
22108
|
writeFileSync9(configPath, configText);
|
|
20833
22109
|
}
|
|
20834
|
-
if (!
|
|
22110
|
+
if (!existsSync24(onnxPath)) {
|
|
20835
22111
|
renderInfo(`Downloading ${model.label} voice model (this may take a minute)...`);
|
|
20836
22112
|
const onnxResp = await fetch(model.onnxUrl);
|
|
20837
22113
|
if (!onnxResp.ok)
|
|
@@ -20867,10 +22143,10 @@ Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
|
20867
22143
|
throw new Error("ONNX runtime not loaded");
|
|
20868
22144
|
const onnxPath = modelOnnxPath(this.modelId);
|
|
20869
22145
|
const configPath = modelConfigPath(this.modelId);
|
|
20870
|
-
if (!
|
|
22146
|
+
if (!existsSync24(onnxPath) || !existsSync24(configPath)) {
|
|
20871
22147
|
throw new Error(`Model files not found for ${this.modelId}`);
|
|
20872
22148
|
}
|
|
20873
|
-
this.config = JSON.parse(
|
|
22149
|
+
this.config = JSON.parse(readFileSync17(configPath, "utf8"));
|
|
20874
22150
|
renderInfo("Loading voice model...");
|
|
20875
22151
|
this.session = await this.ort.InferenceSession.create(onnxPath, {
|
|
20876
22152
|
executionProviders: ["cpu"],
|
|
@@ -21371,10 +22647,10 @@ var init_stream_renderer = __esm({
|
|
|
21371
22647
|
|
|
21372
22648
|
// packages/cli/dist/tui/edit-history.js
|
|
21373
22649
|
import { appendFileSync, mkdirSync as mkdirSync10 } from "node:fs";
|
|
21374
|
-
import { join as
|
|
22650
|
+
import { join as join34 } from "node:path";
|
|
21375
22651
|
function createEditHistoryLogger(repoRoot, sessionId) {
|
|
21376
|
-
const historyDir =
|
|
21377
|
-
const logPath =
|
|
22652
|
+
const historyDir = join34(repoRoot, ".oa", "history");
|
|
22653
|
+
const logPath = join34(historyDir, "edits.jsonl");
|
|
21378
22654
|
try {
|
|
21379
22655
|
mkdirSync10(historyDir, { recursive: true });
|
|
21380
22656
|
} catch {
|
|
@@ -21485,9 +22761,9 @@ var init_edit_history = __esm({
|
|
|
21485
22761
|
});
|
|
21486
22762
|
|
|
21487
22763
|
// packages/cli/dist/tui/dream-engine.js
|
|
21488
|
-
import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync10, readFileSync as
|
|
21489
|
-
import { join as
|
|
21490
|
-
import { execSync as
|
|
22764
|
+
import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync10, readFileSync as readFileSync18, existsSync as existsSync25, cpSync, rmSync, readdirSync as readdirSync10 } from "node:fs";
|
|
22765
|
+
import { join as join35, basename as basename12 } from "node:path";
|
|
22766
|
+
import { execSync as execSync21 } from "node:child_process";
|
|
21491
22767
|
function adaptTool(tool) {
|
|
21492
22768
|
return {
|
|
21493
22769
|
name: tool.name,
|
|
@@ -21661,12 +22937,12 @@ var init_dream_engine = __esm({
|
|
|
21661
22937
|
const content = String(args["content"] ?? "");
|
|
21662
22938
|
if (!rawPath)
|
|
21663
22939
|
return { success: false, output: "", error: "path is required", durationMs: Date.now() - start };
|
|
21664
|
-
const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ?
|
|
22940
|
+
const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ? join35(this.dreamsDir, basename12(rawPath)) : join35(this.dreamsDir, rawPath);
|
|
21665
22941
|
if (!targetPath.startsWith(this.dreamsDir)) {
|
|
21666
22942
|
return { success: false, output: "", error: "Dream mode: writes are confined to .oa/dreams/", durationMs: Date.now() - start };
|
|
21667
22943
|
}
|
|
21668
22944
|
try {
|
|
21669
|
-
const dir =
|
|
22945
|
+
const dir = join35(targetPath, "..");
|
|
21670
22946
|
mkdirSync11(dir, { recursive: true });
|
|
21671
22947
|
writeFileSync10(targetPath, content, "utf-8");
|
|
21672
22948
|
return { success: true, output: `Wrote ${content.length} bytes to ${rawPath}`, durationMs: Date.now() - start };
|
|
@@ -21696,15 +22972,15 @@ var init_dream_engine = __esm({
|
|
|
21696
22972
|
const rawPath = String(args["path"] ?? "");
|
|
21697
22973
|
const oldStr = String(args["old_string"] ?? "");
|
|
21698
22974
|
const newStr = String(args["new_string"] ?? "");
|
|
21699
|
-
const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ?
|
|
22975
|
+
const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ? join35(this.dreamsDir, basename12(rawPath)) : join35(this.dreamsDir, rawPath);
|
|
21700
22976
|
if (!targetPath.startsWith(this.dreamsDir)) {
|
|
21701
22977
|
return { success: false, output: "", error: "Dream mode: edits are confined to .oa/dreams/", durationMs: Date.now() - start };
|
|
21702
22978
|
}
|
|
21703
22979
|
try {
|
|
21704
|
-
if (!
|
|
22980
|
+
if (!existsSync25(targetPath)) {
|
|
21705
22981
|
return { success: false, output: "", error: `File not found: ${rawPath}`, durationMs: Date.now() - start };
|
|
21706
22982
|
}
|
|
21707
|
-
let content =
|
|
22983
|
+
let content = readFileSync18(targetPath, "utf-8");
|
|
21708
22984
|
if (!content.includes(oldStr)) {
|
|
21709
22985
|
return { success: false, output: "", error: "old_string not found in file", durationMs: Date.now() - start };
|
|
21710
22986
|
}
|
|
@@ -21740,7 +23016,7 @@ var init_dream_engine = __esm({
|
|
|
21740
23016
|
}
|
|
21741
23017
|
}
|
|
21742
23018
|
try {
|
|
21743
|
-
const output =
|
|
23019
|
+
const output = execSync21(cmd, {
|
|
21744
23020
|
cwd: this.repoRoot,
|
|
21745
23021
|
timeout: 3e4,
|
|
21746
23022
|
encoding: "utf-8",
|
|
@@ -21763,7 +23039,7 @@ var init_dream_engine = __esm({
|
|
|
21763
23039
|
constructor(config, repoRoot) {
|
|
21764
23040
|
this.config = config;
|
|
21765
23041
|
this.repoRoot = repoRoot;
|
|
21766
|
-
this.dreamsDir =
|
|
23042
|
+
this.dreamsDir = join35(repoRoot, ".oa", "dreams");
|
|
21767
23043
|
this.state = {
|
|
21768
23044
|
mode: "default",
|
|
21769
23045
|
active: false,
|
|
@@ -21835,7 +23111,7 @@ ${result.summary}`;
|
|
|
21835
23111
|
if (mode !== "default" || cycle === totalCycles) {
|
|
21836
23112
|
renderDreamContraction(cycle);
|
|
21837
23113
|
const cycleSummary = this.buildCycleSummary(cycle, previousFindings);
|
|
21838
|
-
const summaryPath =
|
|
23114
|
+
const summaryPath = join35(this.dreamsDir, `cycle-${cycle}-summary.md`);
|
|
21839
23115
|
writeFileSync10(summaryPath, cycleSummary, "utf-8");
|
|
21840
23116
|
}
|
|
21841
23117
|
if (mode === "lucid" && !this.abortController.signal.aborted) {
|
|
@@ -21958,29 +23234,29 @@ Dreams directory: ${this.dreamsDir}`);
|
|
|
21958
23234
|
}
|
|
21959
23235
|
/** Save workspace backup for lucid mode */
|
|
21960
23236
|
saveVersionCheckpoint(cycle) {
|
|
21961
|
-
const checkpointDir =
|
|
23237
|
+
const checkpointDir = join35(this.dreamsDir, "checkpoints", `cycle-${cycle}`);
|
|
21962
23238
|
try {
|
|
21963
23239
|
mkdirSync11(checkpointDir, { recursive: true });
|
|
21964
23240
|
try {
|
|
21965
|
-
const gitStatus =
|
|
23241
|
+
const gitStatus = execSync21("git status --porcelain", {
|
|
21966
23242
|
cwd: this.repoRoot,
|
|
21967
23243
|
encoding: "utf-8",
|
|
21968
23244
|
timeout: 1e4
|
|
21969
23245
|
});
|
|
21970
|
-
const gitDiff =
|
|
23246
|
+
const gitDiff = execSync21("git diff", {
|
|
21971
23247
|
cwd: this.repoRoot,
|
|
21972
23248
|
encoding: "utf-8",
|
|
21973
23249
|
timeout: 1e4
|
|
21974
23250
|
});
|
|
21975
|
-
const gitHash =
|
|
23251
|
+
const gitHash = execSync21("git rev-parse HEAD 2>/dev/null || echo 'no-git'", {
|
|
21976
23252
|
cwd: this.repoRoot,
|
|
21977
23253
|
encoding: "utf-8",
|
|
21978
23254
|
timeout: 5e3
|
|
21979
23255
|
}).trim();
|
|
21980
|
-
writeFileSync10(
|
|
21981
|
-
writeFileSync10(
|
|
21982
|
-
writeFileSync10(
|
|
21983
|
-
writeFileSync10(
|
|
23256
|
+
writeFileSync10(join35(checkpointDir, "git-status.txt"), gitStatus, "utf-8");
|
|
23257
|
+
writeFileSync10(join35(checkpointDir, "git-diff.patch"), gitDiff, "utf-8");
|
|
23258
|
+
writeFileSync10(join35(checkpointDir, "git-hash.txt"), gitHash, "utf-8");
|
|
23259
|
+
writeFileSync10(join35(checkpointDir, "checkpoint.json"), JSON.stringify({
|
|
21984
23260
|
cycle,
|
|
21985
23261
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
21986
23262
|
gitHash,
|
|
@@ -21988,7 +23264,7 @@ Dreams directory: ${this.dreamsDir}`);
|
|
|
21988
23264
|
}, null, 2), "utf-8");
|
|
21989
23265
|
renderInfo(`Checkpoint saved: cycle ${cycle} (${gitHash.slice(0, 8)})`);
|
|
21990
23266
|
} catch {
|
|
21991
|
-
writeFileSync10(
|
|
23267
|
+
writeFileSync10(join35(checkpointDir, "checkpoint.json"), JSON.stringify({ cycle, timestamp: (/* @__PURE__ */ new Date()).toISOString(), mode: this.state.mode }, null, 2), "utf-8");
|
|
21992
23268
|
renderInfo(`Checkpoint saved: cycle ${cycle} (no git)`);
|
|
21993
23269
|
}
|
|
21994
23270
|
} catch (err) {
|
|
@@ -22046,14 +23322,14 @@ ${files.map((f) => `- [\`${f}\`](./${f})`).join("\n")}
|
|
|
22046
23322
|
---
|
|
22047
23323
|
*Auto-generated by open-agents dream engine*
|
|
22048
23324
|
`;
|
|
22049
|
-
writeFileSync10(
|
|
23325
|
+
writeFileSync10(join35(this.dreamsDir, "PROPOSAL-INDEX.md"), index, "utf-8");
|
|
22050
23326
|
} catch {
|
|
22051
23327
|
}
|
|
22052
23328
|
}
|
|
22053
23329
|
/** Save dream state for resume/inspection */
|
|
22054
23330
|
saveDreamState() {
|
|
22055
23331
|
try {
|
|
22056
|
-
writeFileSync10(
|
|
23332
|
+
writeFileSync10(join35(this.dreamsDir, "dream-state.json"), JSON.stringify(this.state, null, 2) + "\n", "utf-8");
|
|
22057
23333
|
} catch {
|
|
22058
23334
|
}
|
|
22059
23335
|
}
|
|
@@ -23109,11 +24385,11 @@ var init_status_bar = __esm({
|
|
|
23109
24385
|
import * as readline2 from "node:readline";
|
|
23110
24386
|
import { Writable } from "node:stream";
|
|
23111
24387
|
import { cwd } from "node:process";
|
|
23112
|
-
import { resolve as
|
|
24388
|
+
import { resolve as resolve23, join as join36, dirname as dirname11, extname as extname9 } from "node:path";
|
|
23113
24389
|
import { createRequire as createRequire2 } from "node:module";
|
|
23114
|
-
import { fileURLToPath as
|
|
23115
|
-
import { readFileSync as
|
|
23116
|
-
import { existsSync as
|
|
24390
|
+
import { fileURLToPath as fileURLToPath8 } from "node:url";
|
|
24391
|
+
import { readFileSync as readFileSync19, rmSync as rmSync2 } from "node:fs";
|
|
24392
|
+
import { existsSync as existsSync26 } from "node:fs";
|
|
23117
24393
|
function formatTimeAgo(date) {
|
|
23118
24394
|
const seconds = Math.floor((Date.now() - date.getTime()) / 1e3);
|
|
23119
24395
|
if (seconds < 60)
|
|
@@ -23130,14 +24406,14 @@ function formatTimeAgo(date) {
|
|
|
23130
24406
|
function getVersion() {
|
|
23131
24407
|
try {
|
|
23132
24408
|
const require2 = createRequire2(import.meta.url);
|
|
23133
|
-
const thisDir =
|
|
24409
|
+
const thisDir = dirname11(fileURLToPath8(import.meta.url));
|
|
23134
24410
|
const candidates = [
|
|
23135
|
-
|
|
23136
|
-
|
|
23137
|
-
|
|
24411
|
+
join36(thisDir, "..", "package.json"),
|
|
24412
|
+
join36(thisDir, "..", "..", "package.json"),
|
|
24413
|
+
join36(thisDir, "..", "..", "..", "package.json")
|
|
23138
24414
|
];
|
|
23139
24415
|
for (const pkgPath of candidates) {
|
|
23140
|
-
if (
|
|
24416
|
+
if (existsSync26(pkgPath)) {
|
|
23141
24417
|
const pkg = require2(pkgPath);
|
|
23142
24418
|
if (pkg.name === "open-agents-ai" || pkg.name === "@open-agents/cli") {
|
|
23143
24419
|
return pkg.version ?? "0.0.0";
|
|
@@ -23235,7 +24511,13 @@ function buildTools(repoRoot, config, contextWindowSize) {
|
|
|
23235
24511
|
new OcrPdfTool(repoRoot),
|
|
23236
24512
|
new PdfToTextTool(repoRoot),
|
|
23237
24513
|
// Advanced image OCR (multi-variant preprocessing pipeline)
|
|
23238
|
-
new OcrImageAdvancedTool(repoRoot)
|
|
24514
|
+
new OcrImageAdvancedTool(repoRoot),
|
|
24515
|
+
// Browser automation (headless Chrome via Hydra scrape service)
|
|
24516
|
+
new BrowserActionTool(),
|
|
24517
|
+
// Temporal agency (scheduling, reminders, attention steering)
|
|
24518
|
+
new SchedulerTool(repoRoot),
|
|
24519
|
+
new ReminderTool(repoRoot),
|
|
24520
|
+
new AgendaTool(repoRoot)
|
|
23239
24521
|
];
|
|
23240
24522
|
return [
|
|
23241
24523
|
...executionTools.map(adaptTool2),
|
|
@@ -23648,7 +24930,7 @@ ${entry.fullContent}`
|
|
|
23648
24930
|
} };
|
|
23649
24931
|
}
|
|
23650
24932
|
async function startInteractive(config, repoPath) {
|
|
23651
|
-
const repoRoot =
|
|
24933
|
+
const repoRoot = resolve23(repoPath ?? cwd());
|
|
23652
24934
|
const resumeFlag = process.env.__OA_RESUMED ?? "";
|
|
23653
24935
|
const isResumed = resumeFlag !== "";
|
|
23654
24936
|
const hasTaskToResume = resumeFlag === "1";
|
|
@@ -23801,14 +25083,14 @@ async function startInteractive(config, repoPath) {
|
|
|
23801
25083
|
renderInfo(msg);
|
|
23802
25084
|
statusBar.endContentWrite();
|
|
23803
25085
|
}
|
|
23804
|
-
}, () => new Promise((
|
|
25086
|
+
}, () => new Promise((resolve26) => {
|
|
23805
25087
|
depSudoPromptPending = true;
|
|
23806
25088
|
depSudoResolver = (pw) => {
|
|
23807
25089
|
depSudoPromptPending = false;
|
|
23808
25090
|
depSudoResolver = null;
|
|
23809
25091
|
if (pw)
|
|
23810
25092
|
sessionSudoPassword = pw;
|
|
23811
|
-
|
|
25093
|
+
resolve26(pw);
|
|
23812
25094
|
};
|
|
23813
25095
|
if (statusBar?.isActive) {
|
|
23814
25096
|
statusBar.beginContentWrite();
|
|
@@ -24230,8 +25512,8 @@ async function startInteractive(config, repoPath) {
|
|
|
24230
25512
|
return true;
|
|
24231
25513
|
},
|
|
24232
25514
|
destroyProject() {
|
|
24233
|
-
const oaPath =
|
|
24234
|
-
if (
|
|
25515
|
+
const oaPath = join36(repoRoot, OA_DIR);
|
|
25516
|
+
if (existsSync26(oaPath)) {
|
|
24235
25517
|
try {
|
|
24236
25518
|
rmSync2(oaPath, { recursive: true, force: true });
|
|
24237
25519
|
writeContent(() => renderInfo(`Removed ${OA_DIR}/ directory.`));
|
|
@@ -24293,6 +25575,41 @@ async function startInteractive(config, repoPath) {
|
|
|
24293
25575
|
}, 150);
|
|
24294
25576
|
}
|
|
24295
25577
|
}
|
|
25578
|
+
if (!isResumed) {
|
|
25579
|
+
(async () => {
|
|
25580
|
+
try {
|
|
25581
|
+
const [dueReminders, activeAttention] = await Promise.all([
|
|
25582
|
+
getDueReminders(repoRoot),
|
|
25583
|
+
getActiveAttentionItems(repoRoot)
|
|
25584
|
+
]);
|
|
25585
|
+
const criticalReminders = dueReminders.filter((r) => r.priority === "critical" || r.priority === "high");
|
|
25586
|
+
const criticalAttention = activeAttention.filter((a) => a.priority === "critical" || a.priority === "high");
|
|
25587
|
+
const totalDue = dueReminders.length + activeAttention.length;
|
|
25588
|
+
if (totalDue > 0) {
|
|
25589
|
+
setTimeout(() => {
|
|
25590
|
+
writeContent(() => {
|
|
25591
|
+
if (criticalReminders.length > 0 || criticalAttention.length > 0) {
|
|
25592
|
+
renderWarning(`${criticalReminders.length + criticalAttention.length} urgent item(s) need attention`);
|
|
25593
|
+
for (const r of criticalReminders)
|
|
25594
|
+
renderWarning(` Reminder: ${r.message.slice(0, 80)}`);
|
|
25595
|
+
for (const a of criticalAttention)
|
|
25596
|
+
renderWarning(` ${a.category}: ${a.title}`);
|
|
25597
|
+
}
|
|
25598
|
+
if (totalDue > criticalReminders.length + criticalAttention.length) {
|
|
25599
|
+
const normalCount = totalDue - criticalReminders.length - criticalAttention.length;
|
|
25600
|
+
renderInfo(`${normalCount} pending agenda item(s). Use agenda() to view.`);
|
|
25601
|
+
}
|
|
25602
|
+
});
|
|
25603
|
+
showPrompt();
|
|
25604
|
+
}, 300);
|
|
25605
|
+
if (dueReminders.length > 0) {
|
|
25606
|
+
await markRemindersSeen(repoRoot, dueReminders.map((r) => r.id));
|
|
25607
|
+
}
|
|
25608
|
+
}
|
|
25609
|
+
} catch {
|
|
25610
|
+
}
|
|
25611
|
+
})();
|
|
25612
|
+
}
|
|
24296
25613
|
if (hasTaskToResume) {
|
|
24297
25614
|
const pendingTask = loadPendingTask(repoRoot);
|
|
24298
25615
|
if (pendingTask) {
|
|
@@ -24463,13 +25780,13 @@ Execute this skill now. Follow the behavioral guidance above.`;
|
|
|
24463
25780
|
}
|
|
24464
25781
|
}
|
|
24465
25782
|
const cleanPath = input.replace(/^['"]|['"]$/g, "").trim();
|
|
24466
|
-
const isImage = isImagePath(cleanPath) &&
|
|
24467
|
-
const isMedia = !isImage && isTranscribablePath(cleanPath) &&
|
|
25783
|
+
const isImage = isImagePath(cleanPath) && existsSync26(resolve23(repoRoot, cleanPath));
|
|
25784
|
+
const isMedia = !isImage && isTranscribablePath(cleanPath) && existsSync26(resolve23(repoRoot, cleanPath));
|
|
24468
25785
|
if (activeTask) {
|
|
24469
25786
|
if (isImage) {
|
|
24470
25787
|
try {
|
|
24471
|
-
const imgPath =
|
|
24472
|
-
const imgBuffer =
|
|
25788
|
+
const imgPath = resolve23(repoRoot, cleanPath);
|
|
25789
|
+
const imgBuffer = readFileSync19(imgPath);
|
|
24473
25790
|
const base64 = imgBuffer.toString("base64");
|
|
24474
25791
|
const ext = extname9(cleanPath).toLowerCase();
|
|
24475
25792
|
const mime = ext === ".png" ? "image/png" : ext === ".gif" ? "image/gif" : ext === ".webp" ? "image/webp" : "image/jpeg";
|
|
@@ -24482,7 +25799,7 @@ Execute this skill now. Follow the behavioral guidance above.`;
|
|
|
24482
25799
|
} else if (isMedia) {
|
|
24483
25800
|
writeContent(() => renderInfo(`Transcribing: ${cleanPath}...`));
|
|
24484
25801
|
const engine = getListenEngine();
|
|
24485
|
-
const result = await engine.transcribeFile(
|
|
25802
|
+
const result = await engine.transcribeFile(resolve23(repoRoot, cleanPath), repoRoot);
|
|
24486
25803
|
if (result) {
|
|
24487
25804
|
const transcript = `[Transcription of ${cleanPath}]
|
|
24488
25805
|
${result.text}`;
|
|
@@ -24515,7 +25832,7 @@ ${result.text}`;
|
|
|
24515
25832
|
if (isMedia && fullInput === input) {
|
|
24516
25833
|
writeContent(() => renderInfo(`Transcribing: ${cleanPath}...`));
|
|
24517
25834
|
const engine = getListenEngine();
|
|
24518
|
-
const result = await engine.transcribeFile(
|
|
25835
|
+
const result = await engine.transcribeFile(resolve23(repoRoot, cleanPath), repoRoot);
|
|
24519
25836
|
if (result) {
|
|
24520
25837
|
fullInput = `The user has provided an audio/video file: ${cleanPath}.
|
|
24521
25838
|
|
|
@@ -24646,7 +25963,7 @@ ${c2.dim("(Use /quit to exit)")}
|
|
|
24646
25963
|
});
|
|
24647
25964
|
}
|
|
24648
25965
|
async function runWithTUI(task, config, repoPath) {
|
|
24649
|
-
const repoRoot =
|
|
25966
|
+
const repoRoot = resolve23(repoPath ?? cwd());
|
|
24650
25967
|
const needsSetup = isFirstRun() || !await isModelAvailable(config);
|
|
24651
25968
|
if (needsSetup && config.backendType === "ollama") {
|
|
24652
25969
|
const setupModel = await runSetupWizard(config);
|
|
@@ -24750,9 +26067,9 @@ var init_run = __esm({
|
|
|
24750
26067
|
// packages/indexer/dist/codebase-indexer.js
|
|
24751
26068
|
import { glob } from "glob";
|
|
24752
26069
|
import ignore from "ignore";
|
|
24753
|
-
import { readFile as
|
|
26070
|
+
import { readFile as readFile14, stat as stat4 } from "node:fs/promises";
|
|
24754
26071
|
import { createHash } from "node:crypto";
|
|
24755
|
-
import { join as
|
|
26072
|
+
import { join as join37, relative as relative3, extname as extname10, basename as basename13 } from "node:path";
|
|
24756
26073
|
var DEFAULT_EXCLUDE, LANGUAGE_MAP, CodebaseIndexer;
|
|
24757
26074
|
var init_codebase_indexer = __esm({
|
|
24758
26075
|
"packages/indexer/dist/codebase-indexer.js"() {
|
|
@@ -24796,7 +26113,7 @@ var init_codebase_indexer = __esm({
|
|
|
24796
26113
|
const ig = ignore.default();
|
|
24797
26114
|
if (this.config.respectGitignore) {
|
|
24798
26115
|
try {
|
|
24799
|
-
const gitignoreContent = await
|
|
26116
|
+
const gitignoreContent = await readFile14(join37(this.config.rootDir, ".gitignore"), "utf-8");
|
|
24800
26117
|
ig.add(gitignoreContent);
|
|
24801
26118
|
} catch {
|
|
24802
26119
|
}
|
|
@@ -24811,12 +26128,12 @@ var init_codebase_indexer = __esm({
|
|
|
24811
26128
|
for (const relativePath of files) {
|
|
24812
26129
|
if (ig.ignores(relativePath))
|
|
24813
26130
|
continue;
|
|
24814
|
-
const fullPath =
|
|
26131
|
+
const fullPath = join37(this.config.rootDir, relativePath);
|
|
24815
26132
|
try {
|
|
24816
26133
|
const fileStat = await stat4(fullPath);
|
|
24817
26134
|
if (fileStat.size > this.config.maxFileSize)
|
|
24818
26135
|
continue;
|
|
24819
|
-
const content = await
|
|
26136
|
+
const content = await readFile14(fullPath);
|
|
24820
26137
|
const hash = createHash("sha256").update(content).digest("hex");
|
|
24821
26138
|
const ext = extname10(relativePath);
|
|
24822
26139
|
indexed.push({
|
|
@@ -24857,7 +26174,7 @@ var init_codebase_indexer = __esm({
|
|
|
24857
26174
|
if (!child) {
|
|
24858
26175
|
child = {
|
|
24859
26176
|
name: part,
|
|
24860
|
-
path:
|
|
26177
|
+
path: join37(current.path, part),
|
|
24861
26178
|
type: "directory",
|
|
24862
26179
|
children: []
|
|
24863
26180
|
};
|
|
@@ -24939,14 +26256,14 @@ var index_repo_exports = {};
|
|
|
24939
26256
|
__export(index_repo_exports, {
|
|
24940
26257
|
indexRepoCommand: () => indexRepoCommand
|
|
24941
26258
|
});
|
|
24942
|
-
import { resolve as
|
|
24943
|
-
import { existsSync as
|
|
26259
|
+
import { resolve as resolve24 } from "node:path";
|
|
26260
|
+
import { existsSync as existsSync27, statSync as statSync10 } from "node:fs";
|
|
24944
26261
|
import { cwd as cwd2 } from "node:process";
|
|
24945
26262
|
async function indexRepoCommand(opts, _config) {
|
|
24946
|
-
const repoRoot =
|
|
26263
|
+
const repoRoot = resolve24(opts.repoPath ?? cwd2());
|
|
24947
26264
|
printHeader("Index Repository");
|
|
24948
26265
|
printInfo(`Indexing: ${repoRoot}`);
|
|
24949
|
-
if (!
|
|
26266
|
+
if (!existsSync27(repoRoot)) {
|
|
24950
26267
|
printError(`Path does not exist: ${repoRoot}`);
|
|
24951
26268
|
process.exit(1);
|
|
24952
26269
|
}
|
|
@@ -25198,7 +26515,7 @@ var config_exports = {};
|
|
|
25198
26515
|
__export(config_exports, {
|
|
25199
26516
|
configCommand: () => configCommand
|
|
25200
26517
|
});
|
|
25201
|
-
import { join as
|
|
26518
|
+
import { join as join38, resolve as resolve25 } from "node:path";
|
|
25202
26519
|
import { homedir as homedir13 } from "node:os";
|
|
25203
26520
|
import { cwd as cwd3 } from "node:process";
|
|
25204
26521
|
function redactIfSensitive(key, value) {
|
|
@@ -25225,7 +26542,7 @@ async function configCommand(opts, config) {
|
|
|
25225
26542
|
return handleShow(opts, config);
|
|
25226
26543
|
}
|
|
25227
26544
|
function handleShow(opts, config) {
|
|
25228
|
-
const repoRoot =
|
|
26545
|
+
const repoRoot = resolve25(opts.repoPath ?? cwd3());
|
|
25229
26546
|
printHeader("Configuration");
|
|
25230
26547
|
printSection("Active Settings (merged)");
|
|
25231
26548
|
printKeyValue("backendUrl", config.backendUrl, 2);
|
|
@@ -25257,7 +26574,7 @@ function handleShow(opts, config) {
|
|
|
25257
26574
|
}
|
|
25258
26575
|
}
|
|
25259
26576
|
printSection("Config File");
|
|
25260
|
-
printInfo(`~/.open-agents/config.json (${
|
|
26577
|
+
printInfo(`~/.open-agents/config.json (${join38(homedir13(), ".open-agents", "config.json")})`);
|
|
25261
26578
|
printSection("Priority Chain");
|
|
25262
26579
|
printInfo(" 1. CLI flags (--model, --backend-url, etc.)");
|
|
25263
26580
|
printInfo(" 2. Project .oa/settings.json (--local)");
|
|
@@ -25290,13 +26607,13 @@ function handleSet(opts, _config) {
|
|
|
25290
26607
|
process.exit(1);
|
|
25291
26608
|
}
|
|
25292
26609
|
if (opts.local) {
|
|
25293
|
-
const repoRoot =
|
|
26610
|
+
const repoRoot = resolve25(opts.repoPath ?? cwd3());
|
|
25294
26611
|
try {
|
|
25295
26612
|
initOaDirectory(repoRoot);
|
|
25296
26613
|
const coerced = coerceForSettings(key, value);
|
|
25297
26614
|
saveProjectSettings(repoRoot, { [key]: coerced });
|
|
25298
26615
|
printSuccess(`Project override set: ${key} = ${redactIfSensitive(key, value)}`);
|
|
25299
|
-
printInfo(`Saved to ${
|
|
26616
|
+
printInfo(`Saved to ${join38(repoRoot, ".oa", "settings.json")}`);
|
|
25300
26617
|
printInfo("This override applies only when running in this workspace.");
|
|
25301
26618
|
} catch (err) {
|
|
25302
26619
|
printError(`Failed to save: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -25357,7 +26674,7 @@ var serve_exports = {};
|
|
|
25357
26674
|
__export(serve_exports, {
|
|
25358
26675
|
serveCommand: () => serveCommand
|
|
25359
26676
|
});
|
|
25360
|
-
import { spawn as
|
|
26677
|
+
import { spawn as spawn10 } from "node:child_process";
|
|
25361
26678
|
async function serveCommand(opts, config) {
|
|
25362
26679
|
const backendType = config.backendType;
|
|
25363
26680
|
if (backendType === "ollama") {
|
|
@@ -25449,8 +26766,8 @@ async function serveVllm(opts, config) {
|
|
|
25449
26766
|
await runVllmServer(args, opts.verbose ?? false);
|
|
25450
26767
|
}
|
|
25451
26768
|
async function runVllmServer(args, verbose) {
|
|
25452
|
-
return new Promise((
|
|
25453
|
-
const child =
|
|
26769
|
+
return new Promise((resolve26, reject) => {
|
|
26770
|
+
const child = spawn10("python", args, {
|
|
25454
26771
|
stdio: verbose ? "inherit" : ["ignore", "pipe", "pipe"],
|
|
25455
26772
|
env: { ...process.env }
|
|
25456
26773
|
});
|
|
@@ -25484,10 +26801,10 @@ async function runVllmServer(args, verbose) {
|
|
|
25484
26801
|
child.once("exit", (code, signal) => {
|
|
25485
26802
|
if (signal) {
|
|
25486
26803
|
printInfo(`vLLM server stopped by signal ${signal}`);
|
|
25487
|
-
|
|
26804
|
+
resolve26();
|
|
25488
26805
|
} else if (code === 0) {
|
|
25489
26806
|
printSuccess("vLLM server exited cleanly");
|
|
25490
|
-
|
|
26807
|
+
resolve26();
|
|
25491
26808
|
} else {
|
|
25492
26809
|
printError(`vLLM server exited with code ${code}`);
|
|
25493
26810
|
reject(new Error(`vLLM exited with code ${code}`));
|
|
@@ -25516,7 +26833,7 @@ __export(eval_exports, {
|
|
|
25516
26833
|
});
|
|
25517
26834
|
import { tmpdir as tmpdir7 } from "node:os";
|
|
25518
26835
|
import { mkdirSync as mkdirSync12, writeFileSync as writeFileSync11 } from "node:fs";
|
|
25519
|
-
import { join as
|
|
26836
|
+
import { join as join39 } from "node:path";
|
|
25520
26837
|
async function evalCommand(opts, config) {
|
|
25521
26838
|
const suiteName = opts.suite ?? "basic";
|
|
25522
26839
|
const suite = SUITES[suiteName];
|
|
@@ -25637,9 +26954,9 @@ async function evalCommand(opts, config) {
|
|
|
25637
26954
|
process.exit(failed > 0 ? 1 : 0);
|
|
25638
26955
|
}
|
|
25639
26956
|
function createTempEvalRepo() {
|
|
25640
|
-
const dir =
|
|
26957
|
+
const dir = join39(tmpdir7(), `open-agents-eval-${Date.now()}`);
|
|
25641
26958
|
mkdirSync12(dir, { recursive: true });
|
|
25642
|
-
writeFileSync11(
|
|
26959
|
+
writeFileSync11(join39(dir, "package.json"), JSON.stringify({ name: "eval-repo", version: "0.0.0" }, null, 2) + "\n", "utf8");
|
|
25643
26960
|
return dir;
|
|
25644
26961
|
}
|
|
25645
26962
|
var BASIC_SUITE, FULL_SUITE, SUITES;
|
|
@@ -25698,8 +27015,8 @@ init_output();
|
|
|
25698
27015
|
init_updater();
|
|
25699
27016
|
import { parseArgs as nodeParseArgs2 } from "node:util";
|
|
25700
27017
|
import { createRequire as createRequire3 } from "node:module";
|
|
25701
|
-
import { fileURLToPath as
|
|
25702
|
-
import { dirname as
|
|
27018
|
+
import { fileURLToPath as fileURLToPath9 } from "node:url";
|
|
27019
|
+
import { dirname as dirname12, join as join40 } from "node:path";
|
|
25703
27020
|
|
|
25704
27021
|
// packages/cli/dist/cli.js
|
|
25705
27022
|
import { createInterface } from "node:readline";
|
|
@@ -25806,7 +27123,7 @@ init_output();
|
|
|
25806
27123
|
function getVersion2() {
|
|
25807
27124
|
try {
|
|
25808
27125
|
const require2 = createRequire3(import.meta.url);
|
|
25809
|
-
const pkgPath =
|
|
27126
|
+
const pkgPath = join40(dirname12(fileURLToPath9(import.meta.url)), "..", "package.json");
|
|
25810
27127
|
const pkg = require2(pkgPath);
|
|
25811
27128
|
return pkg.version;
|
|
25812
27129
|
} catch {
|