open-agents-ai 0.185.72 → 0.185.73
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +831 -261
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -13782,9 +13782,9 @@ print("${sentinel}")
|
|
|
13782
13782
|
if (!this.proc || this.proc.killed) {
|
|
13783
13783
|
return { success: false, path: "" };
|
|
13784
13784
|
}
|
|
13785
|
-
const { mkdirSync:
|
|
13785
|
+
const { mkdirSync: mkdirSync32, writeFileSync: writeFileSync30 } = await import("node:fs");
|
|
13786
13786
|
const sessionDir = join22(this.cwd, ".oa", "rlm");
|
|
13787
|
-
|
|
13787
|
+
mkdirSync32(sessionDir, { recursive: true });
|
|
13788
13788
|
const sessionPath = join22(sessionDir, "session.json");
|
|
13789
13789
|
try {
|
|
13790
13790
|
const inspectCode = `
|
|
@@ -13820,11 +13820,11 @@ print("__SESSION__" + json.dumps(_session) + "__SESSION__")
|
|
|
13820
13820
|
* what was previously computed. */
|
|
13821
13821
|
async loadSessionInfo() {
|
|
13822
13822
|
try {
|
|
13823
|
-
const { readFileSync:
|
|
13823
|
+
const { readFileSync: readFileSync46, existsSync: existsSync58 } = await import("node:fs");
|
|
13824
13824
|
const sessionPath = join22(this.cwd, ".oa", "rlm", "session.json");
|
|
13825
|
-
if (!
|
|
13825
|
+
if (!existsSync58(sessionPath))
|
|
13826
13826
|
return null;
|
|
13827
|
-
return JSON.parse(
|
|
13827
|
+
return JSON.parse(readFileSync46(sessionPath, "utf8"));
|
|
13828
13828
|
} catch {
|
|
13829
13829
|
return null;
|
|
13830
13830
|
}
|
|
@@ -14001,10 +14001,10 @@ var init_memory_metabolism = __esm({
|
|
|
14001
14001
|
const trajDir = join23(this.cwd, ".oa", "rlm-trajectories");
|
|
14002
14002
|
let lessons = [];
|
|
14003
14003
|
try {
|
|
14004
|
-
const { readdirSync: readdirSync24, readFileSync:
|
|
14004
|
+
const { readdirSync: readdirSync24, readFileSync: readFileSync46 } = await import("node:fs");
|
|
14005
14005
|
const files = readdirSync24(trajDir).filter((f) => f.endsWith(".jsonl")).sort().reverse().slice(0, 3);
|
|
14006
14006
|
for (const file of files) {
|
|
14007
|
-
const lines =
|
|
14007
|
+
const lines = readFileSync46(join23(trajDir, file), "utf8").split("\n").filter((l) => l.trim());
|
|
14008
14008
|
for (const line of lines) {
|
|
14009
14009
|
try {
|
|
14010
14010
|
const entry = JSON.parse(line);
|
|
@@ -14388,14 +14388,14 @@ ${issues.map((i) => ` - ${i}`).join("\n")}` : " No issues found."),
|
|
|
14388
14388
|
* Optionally filter by task type for phase-aware context (FSM paper insight).
|
|
14389
14389
|
*/
|
|
14390
14390
|
getTopMemoriesSync(k = 5, taskType) {
|
|
14391
|
-
const { readFileSync:
|
|
14391
|
+
const { readFileSync: readFileSync46, existsSync: existsSync58 } = __require("node:fs");
|
|
14392
14392
|
const metaDir = join23(this.cwd, ".oa", "memory", "metabolism");
|
|
14393
14393
|
const storeFile = join23(metaDir, "store.json");
|
|
14394
|
-
if (!
|
|
14394
|
+
if (!existsSync58(storeFile))
|
|
14395
14395
|
return "";
|
|
14396
14396
|
let store = [];
|
|
14397
14397
|
try {
|
|
14398
|
-
store = JSON.parse(
|
|
14398
|
+
store = JSON.parse(readFileSync46(storeFile, "utf8"));
|
|
14399
14399
|
} catch {
|
|
14400
14400
|
return "";
|
|
14401
14401
|
}
|
|
@@ -14417,14 +14417,14 @@ ${issues.map((i) => ` - ${i}`).join("\n")}` : " No issues found."),
|
|
|
14417
14417
|
/** Update memory scores based on task outcome. Called after task completion.
|
|
14418
14418
|
* Memories used in successful tasks get boosted. Memories present during failures get decayed. */
|
|
14419
14419
|
updateFromOutcomeSync(surfacedMemoryText, succeeded) {
|
|
14420
|
-
const { readFileSync:
|
|
14420
|
+
const { readFileSync: readFileSync46, writeFileSync: writeFileSync30, existsSync: existsSync58, mkdirSync: mkdirSync32 } = __require("node:fs");
|
|
14421
14421
|
const metaDir = join23(this.cwd, ".oa", "memory", "metabolism");
|
|
14422
14422
|
const storeFile = join23(metaDir, "store.json");
|
|
14423
|
-
if (!
|
|
14423
|
+
if (!existsSync58(storeFile))
|
|
14424
14424
|
return;
|
|
14425
14425
|
let store = [];
|
|
14426
14426
|
try {
|
|
14427
|
-
store = JSON.parse(
|
|
14427
|
+
store = JSON.parse(readFileSync46(storeFile, "utf8"));
|
|
14428
14428
|
} catch {
|
|
14429
14429
|
return;
|
|
14430
14430
|
}
|
|
@@ -14448,7 +14448,7 @@ ${issues.map((i) => ` - ${i}`).join("\n")}` : " No issues found."),
|
|
|
14448
14448
|
updated = true;
|
|
14449
14449
|
}
|
|
14450
14450
|
if (updated) {
|
|
14451
|
-
|
|
14451
|
+
mkdirSync32(metaDir, { recursive: true });
|
|
14452
14452
|
writeFileSync30(storeFile, JSON.stringify(store, null, 2));
|
|
14453
14453
|
}
|
|
14454
14454
|
}
|
|
@@ -14871,13 +14871,13 @@ Recommendation: Strategy ${scored[0].index + 1} scores highest.`;
|
|
|
14871
14871
|
// Per EvoSkill (arXiv:2603.02766): retrieve relevant strategies from archive.
|
|
14872
14872
|
/** Retrieve top-K strategies for context injection. Returns "" if none. */
|
|
14873
14873
|
getRelevantStrategiesSync(k = 3, taskType) {
|
|
14874
|
-
const { readFileSync:
|
|
14874
|
+
const { readFileSync: readFileSync46, existsSync: existsSync58 } = __require("node:fs");
|
|
14875
14875
|
const archiveFile = join25(this.cwd, ".oa", "arche", "variants.json");
|
|
14876
|
-
if (!
|
|
14876
|
+
if (!existsSync58(archiveFile))
|
|
14877
14877
|
return "";
|
|
14878
14878
|
let variants = [];
|
|
14879
14879
|
try {
|
|
14880
|
-
variants = JSON.parse(
|
|
14880
|
+
variants = JSON.parse(readFileSync46(archiveFile, "utf8"));
|
|
14881
14881
|
} catch {
|
|
14882
14882
|
return "";
|
|
14883
14883
|
}
|
|
@@ -14895,13 +14895,13 @@ Recommendation: Strategy ${scored[0].index + 1} scores highest.`;
|
|
|
14895
14895
|
}
|
|
14896
14896
|
/** Archive a strategy variant synchronously (for task completion path) */
|
|
14897
14897
|
archiveVariantSync(strategy, outcome, tags = []) {
|
|
14898
|
-
const { readFileSync:
|
|
14898
|
+
const { readFileSync: readFileSync46, writeFileSync: writeFileSync30, existsSync: existsSync58, mkdirSync: mkdirSync32 } = __require("node:fs");
|
|
14899
14899
|
const dir = join25(this.cwd, ".oa", "arche");
|
|
14900
14900
|
const archiveFile = join25(dir, "variants.json");
|
|
14901
14901
|
let variants = [];
|
|
14902
14902
|
try {
|
|
14903
|
-
if (
|
|
14904
|
-
variants = JSON.parse(
|
|
14903
|
+
if (existsSync58(archiveFile))
|
|
14904
|
+
variants = JSON.parse(readFileSync46(archiveFile, "utf8"));
|
|
14905
14905
|
} catch {
|
|
14906
14906
|
}
|
|
14907
14907
|
variants.push({
|
|
@@ -14916,7 +14916,7 @@ Recommendation: Strategy ${scored[0].index + 1} scores highest.`;
|
|
|
14916
14916
|
});
|
|
14917
14917
|
if (variants.length > 50)
|
|
14918
14918
|
variants = variants.slice(-50);
|
|
14919
|
-
|
|
14919
|
+
mkdirSync32(dir, { recursive: true });
|
|
14920
14920
|
writeFileSync30(archiveFile, JSON.stringify(variants, null, 2));
|
|
14921
14921
|
}
|
|
14922
14922
|
async saveArchive(variants) {
|
|
@@ -27422,10 +27422,10 @@ ${marker}` : marker);
|
|
|
27422
27422
|
if (!this._workingDirectory)
|
|
27423
27423
|
return;
|
|
27424
27424
|
try {
|
|
27425
|
-
const { mkdirSync:
|
|
27426
|
-
const { join:
|
|
27427
|
-
const sessionDir =
|
|
27428
|
-
|
|
27425
|
+
const { mkdirSync: mkdirSync32, writeFileSync: writeFileSync30 } = __require("node:fs");
|
|
27426
|
+
const { join: join78 } = __require("node:path");
|
|
27427
|
+
const sessionDir = join78(this._workingDirectory, ".oa", "session", this._sessionId);
|
|
27428
|
+
mkdirSync32(sessionDir, { recursive: true });
|
|
27429
27429
|
const checkpoint = {
|
|
27430
27430
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
27431
27431
|
sessionId: this._sessionId,
|
|
@@ -27437,7 +27437,7 @@ ${marker}` : marker);
|
|
|
27437
27437
|
memexEntryCount: this._memexArchive.size,
|
|
27438
27438
|
fileRegistrySize: this._fileRegistry.size
|
|
27439
27439
|
};
|
|
27440
|
-
writeFileSync30(
|
|
27440
|
+
writeFileSync30(join78(sessionDir, "checkpoint.json"), JSON.stringify(checkpoint, null, 2));
|
|
27441
27441
|
} catch {
|
|
27442
27442
|
}
|
|
27443
27443
|
}
|
|
@@ -28575,17 +28575,17 @@ ${transcript}`
|
|
|
28575
28575
|
let resizedBase64 = null;
|
|
28576
28576
|
try {
|
|
28577
28577
|
const { execSync: execSync36 } = await import("node:child_process");
|
|
28578
|
-
const { writeFileSync: writeFileSync30, readFileSync:
|
|
28579
|
-
const { join:
|
|
28578
|
+
const { writeFileSync: writeFileSync30, readFileSync: readFileSync46, unlinkSync: unlinkSync13 } = await import("node:fs");
|
|
28579
|
+
const { join: join78 } = await import("node:path");
|
|
28580
28580
|
const { tmpdir: tmpdir11 } = await import("node:os");
|
|
28581
|
-
const tmpIn =
|
|
28582
|
-
const tmpOut =
|
|
28581
|
+
const tmpIn = join78(tmpdir11(), `oa_img_in_${Date.now()}.png`);
|
|
28582
|
+
const tmpOut = join78(tmpdir11(), `oa_img_out_${Date.now()}.jpg`);
|
|
28583
28583
|
writeFileSync30(tmpIn, buffer);
|
|
28584
28584
|
const pyBin = process.platform === "win32" ? "python" : "python3";
|
|
28585
28585
|
const escapedIn = tmpIn.replace(/\\/g, "\\\\");
|
|
28586
28586
|
const escapedOut = tmpOut.replace(/\\/g, "\\\\");
|
|
28587
28587
|
execSync36(`${pyBin} -c "from PIL import Image; img = Image.open('${escapedIn}'); img.thumbnail((512, 512), Image.LANCZOS); img = img.convert('RGB'); img.save('${escapedOut}', 'JPEG', quality=75)"`, { timeout: 1e4, stdio: "pipe" });
|
|
28588
|
-
const resizedBuf =
|
|
28588
|
+
const resizedBuf = readFileSync46(tmpOut);
|
|
28589
28589
|
resizedBase64 = `data:image/jpeg;base64,${resizedBuf.toString("base64")}`;
|
|
28590
28590
|
try {
|
|
28591
28591
|
unlinkSync13(tmpIn);
|
|
@@ -39557,26 +39557,26 @@ async function fetchOpenAIModels(baseUrl, apiKey) {
|
|
|
39557
39557
|
async function fetchPeerModels(peerId, authKey) {
|
|
39558
39558
|
try {
|
|
39559
39559
|
const { NexusTool: NexusTool2 } = await Promise.resolve().then(() => (init_dist2(), dist_exports));
|
|
39560
|
-
const { existsSync:
|
|
39561
|
-
const { join:
|
|
39560
|
+
const { existsSync: existsSync58, readFileSync: readFileSync46 } = await import("node:fs");
|
|
39561
|
+
const { join: join78 } = await import("node:path");
|
|
39562
39562
|
const cwd4 = process.cwd();
|
|
39563
39563
|
const nexusTool = new NexusTool2(cwd4);
|
|
39564
39564
|
const nexusDir = nexusTool.getNexusDir();
|
|
39565
39565
|
let isLocalPeer = false;
|
|
39566
39566
|
try {
|
|
39567
|
-
const statusPath =
|
|
39568
|
-
if (
|
|
39569
|
-
const status = JSON.parse(
|
|
39567
|
+
const statusPath = join78(nexusDir, "status.json");
|
|
39568
|
+
if (existsSync58(statusPath)) {
|
|
39569
|
+
const status = JSON.parse(readFileSync46(statusPath, "utf8"));
|
|
39570
39570
|
if (status.peerId === peerId)
|
|
39571
39571
|
isLocalPeer = true;
|
|
39572
39572
|
}
|
|
39573
39573
|
} catch {
|
|
39574
39574
|
}
|
|
39575
39575
|
if (isLocalPeer) {
|
|
39576
|
-
const pricingPath =
|
|
39577
|
-
if (
|
|
39576
|
+
const pricingPath = join78(nexusDir, "pricing.json");
|
|
39577
|
+
if (existsSync58(pricingPath)) {
|
|
39578
39578
|
try {
|
|
39579
|
-
const pricing = JSON.parse(
|
|
39579
|
+
const pricing = JSON.parse(readFileSync46(pricingPath, "utf8"));
|
|
39580
39580
|
const localModels = (pricing.models || []).map((m) => ({
|
|
39581
39581
|
name: m.model || "unknown",
|
|
39582
39582
|
size: m.parameterSize || "",
|
|
@@ -39590,10 +39590,10 @@ async function fetchPeerModels(peerId, authKey) {
|
|
|
39590
39590
|
}
|
|
39591
39591
|
}
|
|
39592
39592
|
}
|
|
39593
|
-
const cachePath =
|
|
39594
|
-
if (
|
|
39593
|
+
const cachePath = join78(nexusDir, "peer-models-cache.json");
|
|
39594
|
+
if (existsSync58(cachePath)) {
|
|
39595
39595
|
try {
|
|
39596
|
-
const cache4 = JSON.parse(
|
|
39596
|
+
const cache4 = JSON.parse(readFileSync46(cachePath, "utf8"));
|
|
39597
39597
|
if (cache4.peerId === peerId && cache4.models?.length > 0) {
|
|
39598
39598
|
const age = Date.now() - new Date(cache4.cachedAt).getTime();
|
|
39599
39599
|
if (age < 5 * 60 * 1e3) {
|
|
@@ -39708,10 +39708,10 @@ async function fetchPeerModels(peerId, authKey) {
|
|
|
39708
39708
|
} catch {
|
|
39709
39709
|
}
|
|
39710
39710
|
if (isLocalPeer) {
|
|
39711
|
-
const pricingPath =
|
|
39712
|
-
if (
|
|
39711
|
+
const pricingPath = join78(nexusDir, "pricing.json");
|
|
39712
|
+
if (existsSync58(pricingPath)) {
|
|
39713
39713
|
try {
|
|
39714
|
-
const pricing = JSON.parse(
|
|
39714
|
+
const pricing = JSON.parse(readFileSync46(pricingPath, "utf8"));
|
|
39715
39715
|
return (pricing.models || []).map((m) => ({
|
|
39716
39716
|
name: m.model || "unknown",
|
|
39717
39717
|
size: m.parameterSize || "",
|
|
@@ -52121,12 +52121,12 @@ async function handleVoiceMenu(ctx, save, hasLocal) {
|
|
|
52121
52121
|
continue;
|
|
52122
52122
|
}
|
|
52123
52123
|
const { basename: basename18, join: pathJoin } = await import("node:path");
|
|
52124
|
-
const { copyFileSync: copyFileSync3, mkdirSync:
|
|
52124
|
+
const { copyFileSync: copyFileSync3, mkdirSync: mkdirSync32, existsSync: exists } = await import("node:fs");
|
|
52125
52125
|
const { homedir: homedir21 } = await import("node:os");
|
|
52126
52126
|
const modelName = basename18(onnxDrop.path, ".onnx").replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
52127
52127
|
const destDir = pathJoin(homedir21(), ".open-agents", "voice", "models", modelName);
|
|
52128
52128
|
if (!exists(destDir))
|
|
52129
|
-
|
|
52129
|
+
mkdirSync32(destDir, { recursive: true });
|
|
52130
52130
|
copyFileSync3(onnxDrop.path, pathJoin(destDir, "model.onnx"));
|
|
52131
52131
|
copyFileSync3(jsonDrop.path, pathJoin(destDir, "config.json"));
|
|
52132
52132
|
const { registerCustomOnnxModel: registerCustomOnnxModel2 } = await Promise.resolve().then(() => (init_voice(), voice_exports));
|
|
@@ -52965,10 +52965,10 @@ async function handlePeerEndpoint(peerId, authKey, ctx, local) {
|
|
|
52965
52965
|
const models = await fetchModels(peerUrl, authKey);
|
|
52966
52966
|
if (models.length > 0) {
|
|
52967
52967
|
try {
|
|
52968
|
-
const { writeFileSync: writeFileSync30, mkdirSync:
|
|
52969
|
-
const { join:
|
|
52970
|
-
const cachePath =
|
|
52971
|
-
|
|
52968
|
+
const { writeFileSync: writeFileSync30, mkdirSync: mkdirSync32 } = await import("node:fs");
|
|
52969
|
+
const { join: join78, dirname: dirname24 } = await import("node:path");
|
|
52970
|
+
const cachePath = join78(ctx.repoRoot || process.cwd(), ".oa", "nexus", "peer-models-cache.json");
|
|
52971
|
+
mkdirSync32(dirname24(cachePath), { recursive: true });
|
|
52972
52972
|
writeFileSync30(cachePath, JSON.stringify({
|
|
52973
52973
|
peerId,
|
|
52974
52974
|
cachedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -53168,17 +53168,17 @@ async function handleUpdate(subcommand, ctx) {
|
|
|
53168
53168
|
try {
|
|
53169
53169
|
const { createRequire: createRequire6 } = await import("node:module");
|
|
53170
53170
|
const { fileURLToPath: fileURLToPath16 } = await import("node:url");
|
|
53171
|
-
const { dirname: dirname24, join:
|
|
53172
|
-
const { existsSync:
|
|
53171
|
+
const { dirname: dirname24, join: join78 } = await import("node:path");
|
|
53172
|
+
const { existsSync: existsSync58 } = await import("node:fs");
|
|
53173
53173
|
const req = createRequire6(import.meta.url);
|
|
53174
53174
|
const thisDir = dirname24(fileURLToPath16(import.meta.url));
|
|
53175
53175
|
const candidates = [
|
|
53176
|
-
|
|
53177
|
-
|
|
53178
|
-
|
|
53176
|
+
join78(thisDir, "..", "package.json"),
|
|
53177
|
+
join78(thisDir, "..", "..", "package.json"),
|
|
53178
|
+
join78(thisDir, "..", "..", "..", "package.json")
|
|
53179
53179
|
];
|
|
53180
53180
|
for (const pkgPath of candidates) {
|
|
53181
|
-
if (
|
|
53181
|
+
if (existsSync58(pkgPath)) {
|
|
53182
53182
|
const pkg = req(pkgPath);
|
|
53183
53183
|
if (pkg.name === "open-agents-ai" || pkg.name === "@open-agents/cli") {
|
|
53184
53184
|
currentVersion = pkg.version ?? "0.0.0";
|
|
@@ -65238,25 +65238,561 @@ var init_direct_input = __esm({
|
|
|
65238
65238
|
}
|
|
65239
65239
|
});
|
|
65240
65240
|
|
|
65241
|
-
// packages/cli/dist/api/
|
|
65242
|
-
import {
|
|
65241
|
+
// packages/cli/dist/api/audit-log.js
|
|
65242
|
+
import { mkdirSync as mkdirSync26, appendFileSync as appendFileSync4, readFileSync as readFileSync41, existsSync as existsSync52 } from "node:fs";
|
|
65243
65243
|
import { join as join69 } from "node:path";
|
|
65244
|
+
function initAuditLog(oaDir) {
|
|
65245
|
+
auditDir = join69(oaDir, "audit");
|
|
65246
|
+
auditFile = join69(auditDir, "audit.jsonl");
|
|
65247
|
+
try {
|
|
65248
|
+
mkdirSync26(auditDir, { recursive: true });
|
|
65249
|
+
initialized = true;
|
|
65250
|
+
} catch {
|
|
65251
|
+
}
|
|
65252
|
+
}
|
|
65253
|
+
function recordAudit(record) {
|
|
65254
|
+
if (!initialized)
|
|
65255
|
+
return;
|
|
65256
|
+
try {
|
|
65257
|
+
const line = JSON.stringify(record) + "\n";
|
|
65258
|
+
appendFileSync4(auditFile, line, "utf-8");
|
|
65259
|
+
} catch {
|
|
65260
|
+
}
|
|
65261
|
+
}
|
|
65262
|
+
function queryAudit(opts) {
|
|
65263
|
+
if (!initialized || !existsSync52(auditFile))
|
|
65264
|
+
return [];
|
|
65265
|
+
try {
|
|
65266
|
+
const raw = readFileSync41(auditFile, "utf-8");
|
|
65267
|
+
const lines = raw.split("\n").filter(Boolean);
|
|
65268
|
+
let records = lines.map((l) => {
|
|
65269
|
+
try {
|
|
65270
|
+
return JSON.parse(l);
|
|
65271
|
+
} catch {
|
|
65272
|
+
return null;
|
|
65273
|
+
}
|
|
65274
|
+
}).filter(Boolean);
|
|
65275
|
+
if (opts.since) {
|
|
65276
|
+
const sinceTs = new Date(opts.since).getTime();
|
|
65277
|
+
records = records.filter((r) => new Date(r.ts).getTime() >= sinceTs);
|
|
65278
|
+
}
|
|
65279
|
+
if (opts.user) {
|
|
65280
|
+
records = records.filter((r) => r.user === opts.user);
|
|
65281
|
+
}
|
|
65282
|
+
records.reverse();
|
|
65283
|
+
if (opts.limit && opts.limit > 0) {
|
|
65284
|
+
records = records.slice(0, opts.limit);
|
|
65285
|
+
}
|
|
65286
|
+
return records;
|
|
65287
|
+
} catch {
|
|
65288
|
+
return [];
|
|
65289
|
+
}
|
|
65290
|
+
}
|
|
65291
|
+
var auditDir, auditFile, initialized;
|
|
65292
|
+
var init_audit_log = __esm({
|
|
65293
|
+
"packages/cli/dist/api/audit-log.js"() {
|
|
65294
|
+
"use strict";
|
|
65295
|
+
auditDir = "";
|
|
65296
|
+
auditFile = "";
|
|
65297
|
+
initialized = false;
|
|
65298
|
+
}
|
|
65299
|
+
});
|
|
65300
|
+
|
|
65301
|
+
// packages/cli/dist/api/web-ui.js
|
|
65302
|
+
function getWebUI() {
|
|
65303
|
+
return `<!DOCTYPE html>
|
|
65304
|
+
<html lang="en">
|
|
65305
|
+
<head>
|
|
65306
|
+
<meta charset="UTF-8">
|
|
65307
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
65308
|
+
<title>Open Agents</title>
|
|
65309
|
+
<style>
|
|
65310
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
65311
|
+
body {
|
|
65312
|
+
font-family: 'SF Mono', 'Cascadia Code', 'Fira Code', monospace;
|
|
65313
|
+
background: #1a1a1e;
|
|
65314
|
+
color: #b0b0b0;
|
|
65315
|
+
display: flex;
|
|
65316
|
+
flex-direction: column;
|
|
65317
|
+
height: 100vh;
|
|
65318
|
+
overflow: hidden;
|
|
65319
|
+
}
|
|
65320
|
+
#header {
|
|
65321
|
+
display: flex;
|
|
65322
|
+
align-items: center;
|
|
65323
|
+
gap: 12px;
|
|
65324
|
+
padding: 8px 16px;
|
|
65325
|
+
background: #1e1e22;
|
|
65326
|
+
border-bottom: 1px solid #2a2a30;
|
|
65327
|
+
flex-shrink: 0;
|
|
65328
|
+
}
|
|
65329
|
+
#header .accent { color: #b2920a; font-weight: bold; font-size: 0.8rem; }
|
|
65330
|
+
#header .status { font-size: 0.7rem; color: #555; }
|
|
65331
|
+
#header .status.live { color: #b2920a; }
|
|
65332
|
+
#header select {
|
|
65333
|
+
background: #2a2a30;
|
|
65334
|
+
border: 1px solid #3a3a42;
|
|
65335
|
+
color: #b0b0b0;
|
|
65336
|
+
padding: 4px 8px;
|
|
65337
|
+
border-radius: 3px;
|
|
65338
|
+
font-family: inherit;
|
|
65339
|
+
font-size: 0.7rem;
|
|
65340
|
+
margin-left: auto;
|
|
65341
|
+
}
|
|
65342
|
+
#header .key-btn {
|
|
65343
|
+
background: #2a2a30;
|
|
65344
|
+
border: 1px solid #3a3a42;
|
|
65345
|
+
color: #b2920a;
|
|
65346
|
+
padding: 4px 10px;
|
|
65347
|
+
border-radius: 3px;
|
|
65348
|
+
font-family: inherit;
|
|
65349
|
+
font-size: 0.7rem;
|
|
65350
|
+
cursor: pointer;
|
|
65351
|
+
transition: background 0.15s;
|
|
65352
|
+
}
|
|
65353
|
+
#header .key-btn:hover { background: #3a3a42; }
|
|
65354
|
+
#conversation {
|
|
65355
|
+
flex: 1;
|
|
65356
|
+
overflow-y: auto;
|
|
65357
|
+
padding: 12px 16px;
|
|
65358
|
+
display: flex;
|
|
65359
|
+
flex-direction: column;
|
|
65360
|
+
gap: 4px;
|
|
65361
|
+
}
|
|
65362
|
+
.msg { padding: 6px 0; font-size: 0.82rem; line-height: 1.5; white-space: pre-wrap; word-break: break-word; }
|
|
65363
|
+
.msg.user { color: #888; }
|
|
65364
|
+
.msg.user::before { content: '\\25B8 '; color: #555; }
|
|
65365
|
+
.msg.assistant { color: #b2920a; }
|
|
65366
|
+
.msg.assistant::before { content: '\\25B9 '; color: #b2920a; }
|
|
65367
|
+
.msg.system { color: #555; font-size: 0.7rem; }
|
|
65368
|
+
.msg code {
|
|
65369
|
+
background: #2a2a30;
|
|
65370
|
+
padding: 1px 4px;
|
|
65371
|
+
border-radius: 2px;
|
|
65372
|
+
font-size: 0.78rem;
|
|
65373
|
+
}
|
|
65374
|
+
.msg pre {
|
|
65375
|
+
background: #1e1e22;
|
|
65376
|
+
border: 1px solid #2a2a30;
|
|
65377
|
+
border-radius: 3px;
|
|
65378
|
+
padding: 8px 12px;
|
|
65379
|
+
margin: 6px 0;
|
|
65380
|
+
overflow-x: auto;
|
|
65381
|
+
font-size: 0.78rem;
|
|
65382
|
+
line-height: 1.4;
|
|
65383
|
+
position: relative;
|
|
65384
|
+
}
|
|
65385
|
+
.msg pre .copy-btn {
|
|
65386
|
+
position: absolute;
|
|
65387
|
+
top: 4px;
|
|
65388
|
+
right: 4px;
|
|
65389
|
+
background: #2a2a30;
|
|
65390
|
+
border: 1px solid #3a3a42;
|
|
65391
|
+
color: #b2920a;
|
|
65392
|
+
padding: 2px 8px;
|
|
65393
|
+
border-radius: 2px;
|
|
65394
|
+
font-family: inherit;
|
|
65395
|
+
font-size: 0.6rem;
|
|
65396
|
+
cursor: pointer;
|
|
65397
|
+
opacity: 0.5;
|
|
65398
|
+
transition: opacity 0.15s;
|
|
65399
|
+
}
|
|
65400
|
+
.msg pre:hover .copy-btn { opacity: 1; }
|
|
65401
|
+
.msg-actions {
|
|
65402
|
+
display: flex;
|
|
65403
|
+
gap: 8px;
|
|
65404
|
+
margin-top: 2px;
|
|
65405
|
+
}
|
|
65406
|
+
.msg-actions button {
|
|
65407
|
+
background: none;
|
|
65408
|
+
border: none;
|
|
65409
|
+
color: #555;
|
|
65410
|
+
font-family: inherit;
|
|
65411
|
+
font-size: 0.6rem;
|
|
65412
|
+
cursor: pointer;
|
|
65413
|
+
padding: 0;
|
|
65414
|
+
}
|
|
65415
|
+
.msg-actions button:hover { color: #b2920a; }
|
|
65416
|
+
#footer {
|
|
65417
|
+
display: flex;
|
|
65418
|
+
align-items: flex-end;
|
|
65419
|
+
gap: 10px;
|
|
65420
|
+
padding: 8px 16px;
|
|
65421
|
+
background: #1e1e22;
|
|
65422
|
+
border-top: 1px solid #2a2a30;
|
|
65423
|
+
flex-shrink: 0;
|
|
65424
|
+
}
|
|
65425
|
+
#input-area {
|
|
65426
|
+
flex: 1;
|
|
65427
|
+
background: #2a2a30;
|
|
65428
|
+
border: 1px solid #3a3a42;
|
|
65429
|
+
border-radius: 3px;
|
|
65430
|
+
padding: 8px 12px;
|
|
65431
|
+
color: #b0b0b0;
|
|
65432
|
+
font-family: inherit;
|
|
65433
|
+
font-size: 0.82rem;
|
|
65434
|
+
resize: none;
|
|
65435
|
+
min-height: 36px;
|
|
65436
|
+
max-height: 120px;
|
|
65437
|
+
line-height: 1.4;
|
|
65438
|
+
outline: none;
|
|
65439
|
+
}
|
|
65440
|
+
#input-area:focus { border-color: #b2920a; }
|
|
65441
|
+
#send-btn {
|
|
65442
|
+
background: #2a2a30;
|
|
65443
|
+
border: 1px solid #3a3a42;
|
|
65444
|
+
color: #b2920a;
|
|
65445
|
+
padding: 8px 16px;
|
|
65446
|
+
border-radius: 3px;
|
|
65447
|
+
font-family: inherit;
|
|
65448
|
+
font-size: 0.75rem;
|
|
65449
|
+
cursor: pointer;
|
|
65450
|
+
transition: background 0.15s;
|
|
65451
|
+
flex-shrink: 0;
|
|
65452
|
+
}
|
|
65453
|
+
#send-btn:hover { background: #3a3a42; }
|
|
65454
|
+
#send-btn:disabled { opacity: 0.3; cursor: default; }
|
|
65455
|
+
#system-prompt-toggle {
|
|
65456
|
+
font-size: 0.65rem;
|
|
65457
|
+
color: #444;
|
|
65458
|
+
cursor: pointer;
|
|
65459
|
+
padding: 4px 0;
|
|
65460
|
+
}
|
|
65461
|
+
#system-prompt-toggle:hover { color: #b2920a; }
|
|
65462
|
+
#system-prompt-area {
|
|
65463
|
+
display: none;
|
|
65464
|
+
padding: 0 16px 8px;
|
|
65465
|
+
background: #1e1e22;
|
|
65466
|
+
}
|
|
65467
|
+
#system-prompt-area textarea {
|
|
65468
|
+
width: 100%;
|
|
65469
|
+
background: #2a2a30;
|
|
65470
|
+
border: 1px solid #3a3a42;
|
|
65471
|
+
border-radius: 3px;
|
|
65472
|
+
padding: 6px 10px;
|
|
65473
|
+
color: #b0b0b0;
|
|
65474
|
+
font-family: inherit;
|
|
65475
|
+
font-size: 0.7rem;
|
|
65476
|
+
resize: vertical;
|
|
65477
|
+
min-height: 48px;
|
|
65478
|
+
outline: none;
|
|
65479
|
+
}
|
|
65480
|
+
#key-modal {
|
|
65481
|
+
display: none;
|
|
65482
|
+
position: fixed;
|
|
65483
|
+
top: 0; left: 0; right: 0; bottom: 0;
|
|
65484
|
+
background: rgba(0,0,0,0.7);
|
|
65485
|
+
z-index: 100;
|
|
65486
|
+
align-items: center;
|
|
65487
|
+
justify-content: center;
|
|
65488
|
+
}
|
|
65489
|
+
#key-modal.visible { display: flex; }
|
|
65490
|
+
#key-modal .modal {
|
|
65491
|
+
background: #1e1e22;
|
|
65492
|
+
border: 1px solid #2a2a30;
|
|
65493
|
+
border-radius: 6px;
|
|
65494
|
+
padding: 20px;
|
|
65495
|
+
width: 360px;
|
|
65496
|
+
max-width: 90vw;
|
|
65497
|
+
}
|
|
65498
|
+
#key-modal .modal h3 { color: #b2920a; font-size: 0.8rem; margin-bottom: 12px; }
|
|
65499
|
+
#key-modal .modal input {
|
|
65500
|
+
width: 100%;
|
|
65501
|
+
background: #2a2a30;
|
|
65502
|
+
border: 1px solid #3a3a42;
|
|
65503
|
+
border-radius: 3px;
|
|
65504
|
+
padding: 8px 10px;
|
|
65505
|
+
color: #b0b0b0;
|
|
65506
|
+
font-family: inherit;
|
|
65507
|
+
font-size: 0.75rem;
|
|
65508
|
+
outline: none;
|
|
65509
|
+
margin-bottom: 12px;
|
|
65510
|
+
}
|
|
65511
|
+
#key-modal .modal button {
|
|
65512
|
+
background: #2a2a30;
|
|
65513
|
+
border: 1px solid #b2920a;
|
|
65514
|
+
color: #b2920a;
|
|
65515
|
+
padding: 6px 16px;
|
|
65516
|
+
border-radius: 3px;
|
|
65517
|
+
font-family: inherit;
|
|
65518
|
+
font-size: 0.75rem;
|
|
65519
|
+
cursor: pointer;
|
|
65520
|
+
margin-right: 8px;
|
|
65521
|
+
}
|
|
65522
|
+
</style>
|
|
65523
|
+
</head>
|
|
65524
|
+
<body>
|
|
65525
|
+
|
|
65526
|
+
<div id="header">
|
|
65527
|
+
<span class="accent">OA</span>
|
|
65528
|
+
<span class="status" id="status">connecting...</span>
|
|
65529
|
+
<select id="model-select"><option>loading...</option></select>
|
|
65530
|
+
<button class="key-btn" id="key-btn" title="Set API key">key</button>
|
|
65531
|
+
</div>
|
|
65532
|
+
|
|
65533
|
+
<div id="system-prompt-area">
|
|
65534
|
+
<textarea id="system-prompt" placeholder="System prompt (optional)"></textarea>
|
|
65535
|
+
</div>
|
|
65536
|
+
|
|
65537
|
+
<div id="conversation"></div>
|
|
65538
|
+
|
|
65539
|
+
<div id="footer">
|
|
65540
|
+
<span id="system-prompt-toggle" onclick="toggleSystemPrompt()">sys</span>
|
|
65541
|
+
<textarea id="input-area" placeholder="Type a message..." rows="1"></textarea>
|
|
65542
|
+
<button id="send-btn" onclick="sendMessage()">send</button>
|
|
65543
|
+
</div>
|
|
65544
|
+
|
|
65545
|
+
<div id="key-modal">
|
|
65546
|
+
<div class="modal">
|
|
65547
|
+
<h3>API Key</h3>
|
|
65548
|
+
<input id="key-input" type="password" placeholder="Bearer token (leave empty if auth disabled)">
|
|
65549
|
+
<div>
|
|
65550
|
+
<button onclick="saveKey()">save</button>
|
|
65551
|
+
<button onclick="clearKey()">clear</button>
|
|
65552
|
+
<button onclick="closeKeyModal()">cancel</button>
|
|
65553
|
+
</div>
|
|
65554
|
+
</div>
|
|
65555
|
+
</div>
|
|
65556
|
+
|
|
65557
|
+
<script>
|
|
65558
|
+
const conv = document.getElementById('conversation');
|
|
65559
|
+
const input = document.getElementById('input-area');
|
|
65560
|
+
const sendBtn = document.getElementById('send-btn');
|
|
65561
|
+
const modelSelect = document.getElementById('model-select');
|
|
65562
|
+
const statusEl = document.getElementById('status');
|
|
65563
|
+
let apiKey = localStorage.getItem('oa-api-key') || '';
|
|
65564
|
+
let streaming = false;
|
|
65565
|
+
let messages = [];
|
|
65566
|
+
|
|
65567
|
+
// Auto-resize textarea
|
|
65568
|
+
input.addEventListener('input', () => {
|
|
65569
|
+
input.style.height = 'auto';
|
|
65570
|
+
input.style.height = Math.min(input.scrollHeight, 120) + 'px';
|
|
65571
|
+
});
|
|
65572
|
+
input.addEventListener('keydown', (e) => {
|
|
65573
|
+
if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); sendMessage(); }
|
|
65574
|
+
});
|
|
65575
|
+
|
|
65576
|
+
function headers() {
|
|
65577
|
+
const h = { 'Content-Type': 'application/json' };
|
|
65578
|
+
if (apiKey) h['Authorization'] = 'Bearer ' + apiKey;
|
|
65579
|
+
return h;
|
|
65580
|
+
}
|
|
65581
|
+
|
|
65582
|
+
// Health check
|
|
65583
|
+
async function checkHealth() {
|
|
65584
|
+
try {
|
|
65585
|
+
const r = await fetch('/health');
|
|
65586
|
+
const d = await r.json();
|
|
65587
|
+
statusEl.textContent = 'connected (' + d.version + ')';
|
|
65588
|
+
statusEl.className = 'status live';
|
|
65589
|
+
} catch {
|
|
65590
|
+
statusEl.textContent = 'disconnected';
|
|
65591
|
+
statusEl.className = 'status';
|
|
65592
|
+
}
|
|
65593
|
+
}
|
|
65594
|
+
|
|
65595
|
+
// Load models
|
|
65596
|
+
async function loadModels() {
|
|
65597
|
+
try {
|
|
65598
|
+
const r = await fetch('/v1/models', { headers: headers() });
|
|
65599
|
+
const d = await r.json();
|
|
65600
|
+
modelSelect.innerHTML = '';
|
|
65601
|
+
for (const m of (d.data || [])) {
|
|
65602
|
+
const opt = document.createElement('option');
|
|
65603
|
+
// Strip "local/" prefix for cleaner display
|
|
65604
|
+
opt.value = m.id.replace(/^local\\//, '');
|
|
65605
|
+
opt.textContent = m.id.replace(/^local\\//, '');
|
|
65606
|
+
modelSelect.appendChild(opt);
|
|
65607
|
+
}
|
|
65608
|
+
// Default to first model with "9b" in name, or first overall
|
|
65609
|
+
const preferred = Array.from(modelSelect.options).find(o => /9b/i.test(o.value));
|
|
65610
|
+
if (preferred) modelSelect.value = preferred.value;
|
|
65611
|
+
} catch { modelSelect.innerHTML = '<option>error loading models</option>'; }
|
|
65612
|
+
}
|
|
65613
|
+
|
|
65614
|
+
function addMessage(role, content) {
|
|
65615
|
+
const div = document.createElement('div');
|
|
65616
|
+
div.className = 'msg ' + role;
|
|
65617
|
+
div.innerHTML = renderMarkdown(content);
|
|
65618
|
+
// Copy button
|
|
65619
|
+
if (role === 'assistant') {
|
|
65620
|
+
const actions = document.createElement('div');
|
|
65621
|
+
actions.className = 'msg-actions';
|
|
65622
|
+
const copyBtn = document.createElement('button');
|
|
65623
|
+
copyBtn.textContent = 'copy';
|
|
65624
|
+
copyBtn.onclick = () => { navigator.clipboard.writeText(content); copyBtn.textContent = 'copied'; setTimeout(() => copyBtn.textContent = 'copy', 1500); };
|
|
65625
|
+
actions.appendChild(copyBtn);
|
|
65626
|
+
div.appendChild(actions);
|
|
65627
|
+
}
|
|
65628
|
+
conv.appendChild(div);
|
|
65629
|
+
conv.scrollTop = conv.scrollHeight;
|
|
65630
|
+
return div;
|
|
65631
|
+
}
|
|
65632
|
+
|
|
65633
|
+
function renderMarkdown(text) {
|
|
65634
|
+
// Code blocks
|
|
65635
|
+
text = text.replace(/\`\`\`(\\w*)\\n([\\s\\S]*?)\`\`\`/g, (_, lang, code) => {
|
|
65636
|
+
const id = 'cb' + Math.random().toString(36).slice(2,8);
|
|
65637
|
+
return '<pre><button class="copy-btn" onclick="navigator.clipboard.writeText(document.getElementById(\\'' + id + '\\').textContent);this.textContent=\\'copied\\';setTimeout(()=>this.textContent=\\'copy\\',1500)">copy</button><code id="' + id + '">' + escHtml(code) + '</code></pre>';
|
|
65638
|
+
});
|
|
65639
|
+
// Inline code
|
|
65640
|
+
text = text.replace(/\`([^\`]+)\`/g, '<code>$1</code>');
|
|
65641
|
+
// Bold
|
|
65642
|
+
text = text.replace(/\\*\\*(.+?)\\*\\*/g, '<strong>$1</strong>');
|
|
65643
|
+
return text;
|
|
65644
|
+
}
|
|
65645
|
+
|
|
65646
|
+
function escHtml(s) {
|
|
65647
|
+
return s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
|
|
65648
|
+
}
|
|
65649
|
+
|
|
65650
|
+
async function sendMessage() {
|
|
65651
|
+
const text = input.value.trim();
|
|
65652
|
+
if (!text || streaming) return;
|
|
65653
|
+
input.value = '';
|
|
65654
|
+
input.style.height = 'auto';
|
|
65655
|
+
|
|
65656
|
+
// Add user message
|
|
65657
|
+
messages.push({ role: 'user', content: text });
|
|
65658
|
+
addMessage('user', text);
|
|
65659
|
+
|
|
65660
|
+
// System prompt
|
|
65661
|
+
const sysPrompt = document.getElementById('system-prompt').value.trim();
|
|
65662
|
+
|
|
65663
|
+
streaming = true;
|
|
65664
|
+
sendBtn.disabled = true;
|
|
65665
|
+
sendBtn.textContent = '...';
|
|
65666
|
+
|
|
65667
|
+
const msgDiv = addMessage('assistant', '');
|
|
65668
|
+
let fullContent = '';
|
|
65669
|
+
|
|
65670
|
+
try {
|
|
65671
|
+
const body = {
|
|
65672
|
+
model: modelSelect.value,
|
|
65673
|
+
messages: [
|
|
65674
|
+
...(sysPrompt ? [{ role: 'system', content: sysPrompt }] : []),
|
|
65675
|
+
...messages,
|
|
65676
|
+
],
|
|
65677
|
+
stream: true,
|
|
65678
|
+
max_tokens: 4096,
|
|
65679
|
+
};
|
|
65680
|
+
|
|
65681
|
+
const response = await fetch('/v1/chat/completions', {
|
|
65682
|
+
method: 'POST',
|
|
65683
|
+
headers: headers(),
|
|
65684
|
+
body: JSON.stringify(body),
|
|
65685
|
+
});
|
|
65686
|
+
|
|
65687
|
+
const reader = response.body.getReader();
|
|
65688
|
+
const decoder = new TextDecoder();
|
|
65689
|
+
let buffer = '';
|
|
65690
|
+
|
|
65691
|
+
while (true) {
|
|
65692
|
+
const { done, value } = await reader.read();
|
|
65693
|
+
if (done) break;
|
|
65694
|
+
buffer += decoder.decode(value, { stream: true });
|
|
65695
|
+
|
|
65696
|
+
const lines = buffer.split('\\n');
|
|
65697
|
+
buffer = lines.pop() || '';
|
|
65698
|
+
|
|
65699
|
+
for (const line of lines) {
|
|
65700
|
+
if (!line.startsWith('data: ')) continue;
|
|
65701
|
+
const data = line.slice(6);
|
|
65702
|
+
if (data === '[DONE]') continue;
|
|
65703
|
+
try {
|
|
65704
|
+
const chunk = JSON.parse(data);
|
|
65705
|
+
const delta = chunk.choices?.[0]?.delta?.content || '';
|
|
65706
|
+
if (delta) {
|
|
65707
|
+
fullContent += delta;
|
|
65708
|
+
msgDiv.innerHTML = renderMarkdown(fullContent);
|
|
65709
|
+
conv.scrollTop = conv.scrollHeight;
|
|
65710
|
+
}
|
|
65711
|
+
} catch {}
|
|
65712
|
+
}
|
|
65713
|
+
}
|
|
65714
|
+
|
|
65715
|
+
messages.push({ role: 'assistant', content: fullContent });
|
|
65716
|
+
// Re-render with copy button
|
|
65717
|
+
msgDiv.innerHTML = renderMarkdown(fullContent);
|
|
65718
|
+
const actions = document.createElement('div');
|
|
65719
|
+
actions.className = 'msg-actions';
|
|
65720
|
+
const copyBtn = document.createElement('button');
|
|
65721
|
+
copyBtn.textContent = 'copy';
|
|
65722
|
+
copyBtn.onclick = () => { navigator.clipboard.writeText(fullContent); copyBtn.textContent = 'copied'; setTimeout(() => copyBtn.textContent = 'copy', 1500); };
|
|
65723
|
+
actions.appendChild(copyBtn);
|
|
65724
|
+
msgDiv.appendChild(actions);
|
|
65725
|
+
} catch (err) {
|
|
65726
|
+
msgDiv.innerHTML = '<span style="color:#ff4444">Error: ' + escHtml(err.message) + '</span>';
|
|
65727
|
+
}
|
|
65728
|
+
|
|
65729
|
+
streaming = false;
|
|
65730
|
+
sendBtn.disabled = false;
|
|
65731
|
+
sendBtn.textContent = 'send';
|
|
65732
|
+
conv.scrollTop = conv.scrollHeight;
|
|
65733
|
+
}
|
|
65734
|
+
|
|
65735
|
+
function toggleSystemPrompt() {
|
|
65736
|
+
const area = document.getElementById('system-prompt-area');
|
|
65737
|
+
area.style.display = area.style.display === 'none' ? 'block' : 'none';
|
|
65738
|
+
}
|
|
65739
|
+
|
|
65740
|
+
// Key modal
|
|
65741
|
+
document.getElementById('key-btn').onclick = () => {
|
|
65742
|
+
document.getElementById('key-modal').classList.add('visible');
|
|
65743
|
+
document.getElementById('key-input').value = apiKey;
|
|
65744
|
+
};
|
|
65745
|
+
function saveKey() {
|
|
65746
|
+
apiKey = document.getElementById('key-input').value;
|
|
65747
|
+
localStorage.setItem('oa-api-key', apiKey);
|
|
65748
|
+
closeKeyModal();
|
|
65749
|
+
loadModels();
|
|
65750
|
+
}
|
|
65751
|
+
function clearKey() {
|
|
65752
|
+
apiKey = '';
|
|
65753
|
+
localStorage.removeItem('oa-api-key');
|
|
65754
|
+
document.getElementById('key-input').value = '';
|
|
65755
|
+
closeKeyModal();
|
|
65756
|
+
loadModels();
|
|
65757
|
+
}
|
|
65758
|
+
function closeKeyModal() {
|
|
65759
|
+
document.getElementById('key-modal').classList.remove('visible');
|
|
65760
|
+
}
|
|
65761
|
+
|
|
65762
|
+
// Init
|
|
65763
|
+
checkHealth();
|
|
65764
|
+
loadModels();
|
|
65765
|
+
setInterval(checkHealth, 30000);
|
|
65766
|
+
input.focus();
|
|
65767
|
+
</script>
|
|
65768
|
+
</body>
|
|
65769
|
+
</html>`;
|
|
65770
|
+
}
|
|
65771
|
+
var init_web_ui = __esm({
|
|
65772
|
+
"packages/cli/dist/api/web-ui.js"() {
|
|
65773
|
+
"use strict";
|
|
65774
|
+
}
|
|
65775
|
+
});
|
|
65776
|
+
|
|
65777
|
+
// packages/cli/dist/api/profiles.js
|
|
65778
|
+
import { existsSync as existsSync53, readFileSync as readFileSync42, writeFileSync as writeFileSync25, mkdirSync as mkdirSync27, readdirSync as readdirSync20, unlinkSync as unlinkSync12 } from "node:fs";
|
|
65779
|
+
import { join as join70 } from "node:path";
|
|
65244
65780
|
import { homedir as homedir18 } from "node:os";
|
|
65245
65781
|
import { createCipheriv as createCipheriv3, createDecipheriv as createDecipheriv3, randomBytes as randomBytes15, scryptSync as scryptSync3, createHash as createHash5 } from "node:crypto";
|
|
65246
65782
|
function globalProfileDir() {
|
|
65247
|
-
return
|
|
65783
|
+
return join70(homedir18(), ".open-agents", "profiles");
|
|
65248
65784
|
}
|
|
65249
65785
|
function projectProfileDir(projectDir) {
|
|
65250
|
-
return
|
|
65786
|
+
return join70(projectDir || process.cwd(), ".oa", "profiles");
|
|
65251
65787
|
}
|
|
65252
65788
|
function listProfiles(projectDir) {
|
|
65253
65789
|
const result = [];
|
|
65254
65790
|
const seen = /* @__PURE__ */ new Set();
|
|
65255
65791
|
const projDir = projectProfileDir(projectDir);
|
|
65256
|
-
if (
|
|
65792
|
+
if (existsSync53(projDir)) {
|
|
65257
65793
|
for (const f of readdirSync20(projDir).filter((f2) => f2.endsWith(".json"))) {
|
|
65258
65794
|
try {
|
|
65259
|
-
const raw = JSON.parse(
|
|
65795
|
+
const raw = JSON.parse(readFileSync42(join70(projDir, f), "utf8"));
|
|
65260
65796
|
const name = f.replace(".json", "");
|
|
65261
65797
|
seen.add(name);
|
|
65262
65798
|
result.push({
|
|
@@ -65270,13 +65806,13 @@ function listProfiles(projectDir) {
|
|
|
65270
65806
|
}
|
|
65271
65807
|
}
|
|
65272
65808
|
const globDir = globalProfileDir();
|
|
65273
|
-
if (
|
|
65809
|
+
if (existsSync53(globDir)) {
|
|
65274
65810
|
for (const f of readdirSync20(globDir).filter((f2) => f2.endsWith(".json"))) {
|
|
65275
65811
|
const name = f.replace(".json", "");
|
|
65276
65812
|
if (seen.has(name))
|
|
65277
65813
|
continue;
|
|
65278
65814
|
try {
|
|
65279
|
-
const raw = JSON.parse(
|
|
65815
|
+
const raw = JSON.parse(readFileSync42(join70(globDir, f), "utf8"));
|
|
65280
65816
|
result.push({
|
|
65281
65817
|
name,
|
|
65282
65818
|
description: raw.description || "",
|
|
@@ -65291,12 +65827,12 @@ function listProfiles(projectDir) {
|
|
|
65291
65827
|
}
|
|
65292
65828
|
function loadProfile(name, password, projectDir) {
|
|
65293
65829
|
const sanitized = name.replace(/[^a-zA-Z0-9_-]/g, "");
|
|
65294
|
-
const projPath =
|
|
65295
|
-
const globPath =
|
|
65296
|
-
const filePath =
|
|
65830
|
+
const projPath = join70(projectProfileDir(projectDir), `${sanitized}.json`);
|
|
65831
|
+
const globPath = join70(globalProfileDir(), `${sanitized}.json`);
|
|
65832
|
+
const filePath = existsSync53(projPath) ? projPath : existsSync53(globPath) ? globPath : null;
|
|
65297
65833
|
if (!filePath)
|
|
65298
65834
|
return null;
|
|
65299
|
-
const raw = JSON.parse(
|
|
65835
|
+
const raw = JSON.parse(readFileSync42(filePath, "utf8"));
|
|
65300
65836
|
if (raw.encrypted === true) {
|
|
65301
65837
|
if (!password)
|
|
65302
65838
|
return null;
|
|
@@ -65306,9 +65842,9 @@ function loadProfile(name, password, projectDir) {
|
|
|
65306
65842
|
}
|
|
65307
65843
|
function saveProfile(profile, password, scope = "global", projectDir) {
|
|
65308
65844
|
const dir = scope === "project" ? projectProfileDir(projectDir) : globalProfileDir();
|
|
65309
|
-
|
|
65845
|
+
mkdirSync27(dir, { recursive: true });
|
|
65310
65846
|
const sanitized = profile.name.replace(/[^a-zA-Z0-9_-]/g, "");
|
|
65311
|
-
const filePath =
|
|
65847
|
+
const filePath = join70(dir, `${sanitized}.json`);
|
|
65312
65848
|
profile.modified = (/* @__PURE__ */ new Date()).toISOString();
|
|
65313
65849
|
if (password) {
|
|
65314
65850
|
const encrypted = encryptProfile(profile, password);
|
|
@@ -65321,8 +65857,8 @@ function saveProfile(profile, password, scope = "global", projectDir) {
|
|
|
65321
65857
|
function deleteProfile(name, scope = "global", projectDir) {
|
|
65322
65858
|
const sanitized = name.replace(/[^a-zA-Z0-9_-]/g, "");
|
|
65323
65859
|
const dir = scope === "project" ? projectProfileDir(projectDir) : globalProfileDir();
|
|
65324
|
-
const filePath =
|
|
65325
|
-
if (
|
|
65860
|
+
const filePath = join70(dir, `${sanitized}.json`);
|
|
65861
|
+
if (existsSync53(filePath)) {
|
|
65326
65862
|
unlinkSync12(filePath);
|
|
65327
65863
|
return true;
|
|
65328
65864
|
}
|
|
@@ -65415,22 +65951,22 @@ import * as http from "node:http";
|
|
|
65415
65951
|
import * as https from "node:https";
|
|
65416
65952
|
import { createRequire as createRequire3 } from "node:module";
|
|
65417
65953
|
import { fileURLToPath as fileURLToPath13 } from "node:url";
|
|
65418
|
-
import { dirname as dirname21, join as
|
|
65954
|
+
import { dirname as dirname21, join as join71, resolve as resolve31 } from "node:path";
|
|
65419
65955
|
import { spawn as spawn21 } from "node:child_process";
|
|
65420
|
-
import { mkdirSync as
|
|
65421
|
-
import { randomBytes as randomBytes16 } from "node:crypto";
|
|
65956
|
+
import { mkdirSync as mkdirSync28, writeFileSync as writeFileSync26, readFileSync as readFileSync43, readdirSync as readdirSync21, existsSync as existsSync54 } from "node:fs";
|
|
65957
|
+
import { randomBytes as randomBytes16, randomUUID as randomUUID4 } from "node:crypto";
|
|
65422
65958
|
function getVersion3() {
|
|
65423
65959
|
try {
|
|
65424
65960
|
const require2 = createRequire3(import.meta.url);
|
|
65425
65961
|
const thisDir = dirname21(fileURLToPath13(import.meta.url));
|
|
65426
65962
|
const candidates = [
|
|
65427
|
-
|
|
65428
|
-
|
|
65429
|
-
|
|
65963
|
+
join71(thisDir, "..", "package.json"),
|
|
65964
|
+
join71(thisDir, "..", "..", "package.json"),
|
|
65965
|
+
join71(thisDir, "..", "..", "..", "package.json")
|
|
65430
65966
|
];
|
|
65431
65967
|
for (const pkgPath of candidates) {
|
|
65432
65968
|
try {
|
|
65433
|
-
if (!
|
|
65969
|
+
if (!existsSync54(pkgPath))
|
|
65434
65970
|
continue;
|
|
65435
65971
|
const pkg = require2(pkgPath);
|
|
65436
65972
|
if (pkg.name === "open-agents-ai" || pkg.name === "@open-agents/cli" || pkg.name === "@open-agents/monorepo") {
|
|
@@ -65613,27 +66149,33 @@ function formatMetrics() {
|
|
|
65613
66149
|
}
|
|
65614
66150
|
function jsonResponse(res, status, body) {
|
|
65615
66151
|
const payload = JSON.stringify(body);
|
|
65616
|
-
res.writeHead(status, {
|
|
65617
|
-
"Content-Type": "application/json",
|
|
65618
|
-
"Access-Control-Allow-Origin": "*",
|
|
65619
|
-
"Access-Control-Allow-Methods": "GET, POST, PUT, PATCH, DELETE, OPTIONS",
|
|
65620
|
-
"Access-Control-Allow-Headers": "Content-Type, Authorization"
|
|
65621
|
-
});
|
|
66152
|
+
res.writeHead(status, { "Content-Type": "application/json" });
|
|
65622
66153
|
res.end(payload);
|
|
65623
66154
|
}
|
|
65624
66155
|
function textResponse(res, status, body, contentType = "text/plain") {
|
|
65625
|
-
res.writeHead(status, {
|
|
65626
|
-
"Content-Type": contentType,
|
|
65627
|
-
"Access-Control-Allow-Origin": "*",
|
|
65628
|
-
"Access-Control-Allow-Methods": "GET, POST, PUT, PATCH, DELETE, OPTIONS",
|
|
65629
|
-
"Access-Control-Allow-Headers": "Content-Type, Authorization"
|
|
65630
|
-
});
|
|
66156
|
+
res.writeHead(status, { "Content-Type": contentType });
|
|
65631
66157
|
res.end(body);
|
|
65632
66158
|
}
|
|
65633
|
-
function
|
|
65634
|
-
|
|
66159
|
+
function isOriginAllowed(origin) {
|
|
66160
|
+
if (!origin)
|
|
66161
|
+
return true;
|
|
66162
|
+
if (_corsOrigins.includes("*"))
|
|
66163
|
+
return true;
|
|
66164
|
+
if (_corsLocalOnly)
|
|
66165
|
+
return /^https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?$/.test(origin);
|
|
66166
|
+
return _corsOrigins.some((p) => origin === p || p.includes("*") && new RegExp("^" + p.replace(/\*/g, ".*") + "$").test(origin));
|
|
66167
|
+
}
|
|
66168
|
+
function corsHeaders(req, res) {
|
|
66169
|
+
const origin = req.headers["origin"];
|
|
66170
|
+
if (!isOriginAllowed(origin)) {
|
|
66171
|
+
res.writeHead(403, { "Content-Type": "application/json" });
|
|
66172
|
+
res.end(JSON.stringify({ error: "Forbidden", message: `Origin '${origin}' not allowed. Set OA_CORS_ORIGINS to allow.` }));
|
|
66173
|
+
return false;
|
|
66174
|
+
}
|
|
66175
|
+
res.setHeader("Access-Control-Allow-Origin", origin || "*");
|
|
65635
66176
|
res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS");
|
|
65636
|
-
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
|
|
66177
|
+
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Request-ID, X-Working-Directory, X-Tool-Profile, X-Profile-Password");
|
|
66178
|
+
return true;
|
|
65637
66179
|
}
|
|
65638
66180
|
function readBody(req) {
|
|
65639
66181
|
return new Promise((resolve36, reject) => {
|
|
@@ -65725,29 +66267,29 @@ function ollamaStream(ollamaUrl, path, method, body, onData, onEnd, onError) {
|
|
|
65725
66267
|
}
|
|
65726
66268
|
function jobsDir() {
|
|
65727
66269
|
const root = resolve31(process.cwd());
|
|
65728
|
-
const dir =
|
|
65729
|
-
|
|
66270
|
+
const dir = join71(root, ".oa", "jobs");
|
|
66271
|
+
mkdirSync28(dir, { recursive: true });
|
|
65730
66272
|
return dir;
|
|
65731
66273
|
}
|
|
65732
66274
|
function loadJob(id) {
|
|
65733
|
-
const file =
|
|
65734
|
-
if (!
|
|
66275
|
+
const file = join71(jobsDir(), `${id}.json`);
|
|
66276
|
+
if (!existsSync54(file))
|
|
65735
66277
|
return null;
|
|
65736
66278
|
try {
|
|
65737
|
-
return JSON.parse(
|
|
66279
|
+
return JSON.parse(readFileSync43(file, "utf-8"));
|
|
65738
66280
|
} catch {
|
|
65739
66281
|
return null;
|
|
65740
66282
|
}
|
|
65741
66283
|
}
|
|
65742
66284
|
function listJobs() {
|
|
65743
66285
|
const dir = jobsDir();
|
|
65744
|
-
if (!
|
|
66286
|
+
if (!existsSync54(dir))
|
|
65745
66287
|
return [];
|
|
65746
66288
|
const files = readdirSync21(dir).filter((f) => f.endsWith(".json")).sort();
|
|
65747
66289
|
const jobs = [];
|
|
65748
66290
|
for (const file of files) {
|
|
65749
66291
|
try {
|
|
65750
|
-
jobs.push(JSON.parse(
|
|
66292
|
+
jobs.push(JSON.parse(readFileSync43(join71(dir, file), "utf-8")));
|
|
65751
66293
|
} catch {
|
|
65752
66294
|
}
|
|
65753
66295
|
}
|
|
@@ -65874,10 +66416,7 @@ async function handleV1ChatCompletions(req, res, ollamaUrl) {
|
|
|
65874
66416
|
res.writeHead(200, {
|
|
65875
66417
|
"Content-Type": "text/event-stream",
|
|
65876
66418
|
"Cache-Control": "no-cache",
|
|
65877
|
-
"Connection": "keep-alive"
|
|
65878
|
-
"Access-Control-Allow-Origin": "*",
|
|
65879
|
-
"Access-Control-Allow-Methods": "GET, POST, PUT, PATCH, DELETE, OPTIONS",
|
|
65880
|
-
"Access-Control-Allow-Headers": "Content-Type, Authorization"
|
|
66419
|
+
"Connection": "keep-alive"
|
|
65881
66420
|
});
|
|
65882
66421
|
ollamaStream(targetUrl, "/v1/chat/completions", "POST", payload, (chunk) => {
|
|
65883
66422
|
res.write(chunk);
|
|
@@ -65923,10 +66462,7 @@ async function handleV1ChatCompletions(req, res, ollamaUrl) {
|
|
|
65923
66462
|
res.writeHead(200, {
|
|
65924
66463
|
"Content-Type": "text/event-stream",
|
|
65925
66464
|
"Cache-Control": "no-cache",
|
|
65926
|
-
"Connection": "keep-alive"
|
|
65927
|
-
"Access-Control-Allow-Origin": "*",
|
|
65928
|
-
"Access-Control-Allow-Methods": "GET, POST, PUT, PATCH, DELETE, OPTIONS",
|
|
65929
|
-
"Access-Control-Allow-Headers": "Content-Type, Authorization"
|
|
66465
|
+
"Connection": "keep-alive"
|
|
65930
66466
|
});
|
|
65931
66467
|
const chatId = `chatcmpl-${randomBytes16(12).toString("hex")}`;
|
|
65932
66468
|
let buffer = "";
|
|
@@ -66140,8 +66676,8 @@ async function handleV1Run(req, res) {
|
|
|
66140
66676
|
if (workingDir) {
|
|
66141
66677
|
cwd4 = resolve31(workingDir);
|
|
66142
66678
|
} else if (isolate) {
|
|
66143
|
-
const wsDir =
|
|
66144
|
-
|
|
66679
|
+
const wsDir = join71(dir, "..", "workspaces", id);
|
|
66680
|
+
mkdirSync28(wsDir, { recursive: true });
|
|
66145
66681
|
cwd4 = wsDir;
|
|
66146
66682
|
} else {
|
|
66147
66683
|
cwd4 = resolve31(process.cwd());
|
|
@@ -66213,16 +66749,13 @@ async function handleV1Run(req, res) {
|
|
|
66213
66749
|
});
|
|
66214
66750
|
child.unref();
|
|
66215
66751
|
job.pid = child.pid ?? 0;
|
|
66216
|
-
writeFileSync26(
|
|
66752
|
+
writeFileSync26(join71(dir, `${id}.json`), JSON.stringify(job, null, 2));
|
|
66217
66753
|
runningProcesses.set(id, child);
|
|
66218
66754
|
if (streamMode) {
|
|
66219
66755
|
res.writeHead(200, {
|
|
66220
66756
|
"Content-Type": "text/event-stream",
|
|
66221
66757
|
"Cache-Control": "no-cache",
|
|
66222
|
-
"Connection": "keep-alive"
|
|
66223
|
-
"Access-Control-Allow-Origin": "*",
|
|
66224
|
-
"Access-Control-Allow-Methods": "GET, POST, PUT, PATCH, DELETE, OPTIONS",
|
|
66225
|
-
"Access-Control-Allow-Headers": "Content-Type, Authorization"
|
|
66758
|
+
"Connection": "keep-alive"
|
|
66226
66759
|
});
|
|
66227
66760
|
res.write(`data: ${JSON.stringify({ type: "run_started", run_id: id, pid: job.pid })}
|
|
66228
66761
|
|
|
@@ -66243,7 +66776,7 @@ async function handleV1Run(req, res) {
|
|
|
66243
66776
|
job.status = code === 0 ? "completed" : "failed";
|
|
66244
66777
|
job.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
66245
66778
|
try {
|
|
66246
|
-
writeFileSync26(
|
|
66779
|
+
writeFileSync26(join71(dir, `${id}.json`), JSON.stringify(job, null, 2));
|
|
66247
66780
|
} catch {
|
|
66248
66781
|
}
|
|
66249
66782
|
runningProcesses.delete(id);
|
|
@@ -66274,7 +66807,7 @@ async function handleV1Run(req, res) {
|
|
|
66274
66807
|
job.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
66275
66808
|
}
|
|
66276
66809
|
try {
|
|
66277
|
-
writeFileSync26(
|
|
66810
|
+
writeFileSync26(join71(dir, `${id}.json`), JSON.stringify(job, null, 2));
|
|
66278
66811
|
} catch {
|
|
66279
66812
|
}
|
|
66280
66813
|
runningProcesses.delete(id);
|
|
@@ -66315,7 +66848,7 @@ function handleV1RunsDelete(res, id) {
|
|
|
66315
66848
|
job.error = "Aborted via API";
|
|
66316
66849
|
const dir = jobsDir();
|
|
66317
66850
|
try {
|
|
66318
|
-
writeFileSync26(
|
|
66851
|
+
writeFileSync26(join71(dir, `${id}.json`), JSON.stringify(job, null, 2));
|
|
66319
66852
|
} catch {
|
|
66320
66853
|
}
|
|
66321
66854
|
runningProcesses.delete(id);
|
|
@@ -66459,17 +66992,23 @@ async function handleRequest(req, res, ollamaUrl, verbose) {
|
|
|
66459
66992
|
const method = req.method ?? "GET";
|
|
66460
66993
|
const urlObj = new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`);
|
|
66461
66994
|
const pathname = urlObj.pathname;
|
|
66995
|
+
const startMs = performance.now();
|
|
66996
|
+
const requestId = req.headers["x-request-id"] || randomUUID4();
|
|
66997
|
+
res.setHeader("X-Request-ID", requestId);
|
|
66462
66998
|
if (verbose) {
|
|
66463
66999
|
const ts = (/* @__PURE__ */ new Date()).toISOString().split("T")[1]?.slice(0, 8) ?? "";
|
|
66464
|
-
process.stderr.write(`[${ts}] ${method} ${pathname}
|
|
67000
|
+
process.stderr.write(`[${ts}] ${requestId.slice(0, 8)} ${method} ${pathname}
|
|
66465
67001
|
`);
|
|
66466
67002
|
}
|
|
66467
67003
|
if (method === "OPTIONS") {
|
|
66468
|
-
corsHeaders(res)
|
|
67004
|
+
if (!corsHeaders(req, res))
|
|
67005
|
+
return;
|
|
66469
67006
|
res.writeHead(204);
|
|
66470
67007
|
res.end();
|
|
66471
67008
|
return;
|
|
66472
67009
|
}
|
|
67010
|
+
if (!corsHeaders(req, res))
|
|
67011
|
+
return;
|
|
66473
67012
|
let status = 200;
|
|
66474
67013
|
try {
|
|
66475
67014
|
if (pathname === "/health" && method === "GET") {
|
|
@@ -66492,6 +67031,11 @@ async function handleRequest(req, res, ollamaUrl, verbose) {
|
|
|
66492
67031
|
handleMetrics(res);
|
|
66493
67032
|
return;
|
|
66494
67033
|
}
|
|
67034
|
+
if (pathname === "/" && method === "GET" && req.headers.accept?.includes("text/html")) {
|
|
67035
|
+
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
67036
|
+
res.end(getWebUI());
|
|
67037
|
+
return;
|
|
67038
|
+
}
|
|
66495
67039
|
if (pathname.startsWith("/v1/")) {
|
|
66496
67040
|
const isWrite = method === "POST" || method === "PUT" || method === "PATCH" || method === "DELETE";
|
|
66497
67041
|
const isRun = pathname === "/v1/run" || pathname.startsWith("/v1/runs");
|
|
@@ -66650,6 +67194,15 @@ async function handleRequest(req, res, ollamaUrl, verbose) {
|
|
|
66650
67194
|
jsonResponse(res, deleted ? 200 : 404, deleted ? { status: "deleted", name } : { error: "Profile not found", name });
|
|
66651
67195
|
return;
|
|
66652
67196
|
}
|
|
67197
|
+
if (pathname === "/v1/audit" && method === "GET") {
|
|
67198
|
+
if (!checkAuth(req, res, "read"))
|
|
67199
|
+
return;
|
|
67200
|
+
const since = urlObj.searchParams.get("since") ?? void 0;
|
|
67201
|
+
const user = urlObj.searchParams.get("user") ?? void 0;
|
|
67202
|
+
const limit = parseInt(urlObj.searchParams.get("limit") ?? "100", 10);
|
|
67203
|
+
jsonResponse(res, 200, { records: queryAudit({ since, user, limit }) });
|
|
67204
|
+
return;
|
|
67205
|
+
}
|
|
66653
67206
|
status = 404;
|
|
66654
67207
|
jsonResponse(res, 404, { error: "Not found", path: pathname });
|
|
66655
67208
|
} catch (err) {
|
|
@@ -66661,6 +67214,17 @@ async function handleRequest(req, res, ollamaUrl, verbose) {
|
|
|
66661
67214
|
});
|
|
66662
67215
|
} finally {
|
|
66663
67216
|
recordMetric(method, pathname, status);
|
|
67217
|
+
recordAudit({
|
|
67218
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
67219
|
+
requestId,
|
|
67220
|
+
method,
|
|
67221
|
+
path: pathname,
|
|
67222
|
+
status,
|
|
67223
|
+
user: req._authUser ?? "anonymous",
|
|
67224
|
+
scope: req._authScope ?? "none",
|
|
67225
|
+
latencyMs: Math.round(performance.now() - startMs),
|
|
67226
|
+
ip: req.socket?.remoteAddress ?? ""
|
|
67227
|
+
});
|
|
66664
67228
|
}
|
|
66665
67229
|
}
|
|
66666
67230
|
function startApiServer(options = {}) {
|
|
@@ -66687,6 +67251,8 @@ function startApiServer(options = {}) {
|
|
|
66687
67251
|
const verbose = options.verbose ?? false;
|
|
66688
67252
|
const config = loadConfig();
|
|
66689
67253
|
const ollamaUrl = options.ollamaUrl ?? config.backendUrl;
|
|
67254
|
+
const cwd4 = process.cwd();
|
|
67255
|
+
initAuditLog(join71(cwd4, ".oa"));
|
|
66690
67256
|
const server = http.createServer((req, res) => {
|
|
66691
67257
|
handleRequest(req, res, ollamaUrl, verbose).catch((err) => {
|
|
66692
67258
|
metrics.totalErrors++;
|
|
@@ -66816,11 +67382,13 @@ async function apiServeCommand(opts, config) {
|
|
|
66816
67382
|
server.on("close", resolve36);
|
|
66817
67383
|
});
|
|
66818
67384
|
}
|
|
66819
|
-
var endpointRegistry, modelRouteMap, endpointUsage, metrics, startedAt, runningProcesses;
|
|
67385
|
+
var endpointRegistry, modelRouteMap, endpointUsage, metrics, startedAt, _corsOrigins, _corsLocalOnly, runningProcesses;
|
|
66820
67386
|
var init_serve = __esm({
|
|
66821
67387
|
"packages/cli/dist/api/serve.js"() {
|
|
66822
67388
|
"use strict";
|
|
66823
67389
|
init_config();
|
|
67390
|
+
init_audit_log();
|
|
67391
|
+
init_web_ui();
|
|
66824
67392
|
init_oa_directory();
|
|
66825
67393
|
init_render();
|
|
66826
67394
|
init_profiles();
|
|
@@ -66834,17 +67402,19 @@ var init_serve = __esm({
|
|
|
66834
67402
|
totalErrors: 0
|
|
66835
67403
|
};
|
|
66836
67404
|
startedAt = Date.now();
|
|
67405
|
+
_corsOrigins = (process.env["OA_CORS_ORIGINS"] || "").split(",").filter(Boolean);
|
|
67406
|
+
_corsLocalOnly = _corsOrigins.length === 0;
|
|
66837
67407
|
runningProcesses = /* @__PURE__ */ new Map();
|
|
66838
67408
|
}
|
|
66839
67409
|
});
|
|
66840
67410
|
|
|
66841
67411
|
// packages/cli/dist/tui/interactive.js
|
|
66842
67412
|
import { cwd } from "node:process";
|
|
66843
|
-
import { resolve as resolve32, join as
|
|
67413
|
+
import { resolve as resolve32, join as join72, dirname as dirname22, extname as extname11 } from "node:path";
|
|
66844
67414
|
import { createRequire as createRequire4 } from "node:module";
|
|
66845
67415
|
import { fileURLToPath as fileURLToPath14 } from "node:url";
|
|
66846
|
-
import { readFileSync as
|
|
66847
|
-
import { existsSync as
|
|
67416
|
+
import { readFileSync as readFileSync44, writeFileSync as writeFileSync27, appendFileSync as appendFileSync5, rmSync as rmSync3, readdirSync as readdirSync22, mkdirSync as mkdirSync29 } from "node:fs";
|
|
67417
|
+
import { existsSync as existsSync55 } from "node:fs";
|
|
66848
67418
|
import { execSync as execSync35 } from "node:child_process";
|
|
66849
67419
|
import { homedir as homedir19 } from "node:os";
|
|
66850
67420
|
function formatTimeAgo(date) {
|
|
@@ -66865,12 +67435,12 @@ function getVersion4() {
|
|
|
66865
67435
|
const require2 = createRequire4(import.meta.url);
|
|
66866
67436
|
const thisDir = dirname22(fileURLToPath14(import.meta.url));
|
|
66867
67437
|
const candidates = [
|
|
66868
|
-
|
|
66869
|
-
|
|
66870
|
-
|
|
67438
|
+
join72(thisDir, "..", "package.json"),
|
|
67439
|
+
join72(thisDir, "..", "..", "package.json"),
|
|
67440
|
+
join72(thisDir, "..", "..", "..", "package.json")
|
|
66871
67441
|
];
|
|
66872
67442
|
for (const pkgPath of candidates) {
|
|
66873
|
-
if (
|
|
67443
|
+
if (existsSync55(pkgPath)) {
|
|
66874
67444
|
const pkg = require2(pkgPath);
|
|
66875
67445
|
if (pkg.name === "open-agents-ai" || pkg.name === "@open-agents/cli" || pkg.name === "@open-agents/monorepo") {
|
|
66876
67446
|
return pkg.version ?? "0.0.0";
|
|
@@ -67109,15 +67679,15 @@ Use task_status("${taskId}") or task_output("${taskId}") to check progress.`
|
|
|
67109
67679
|
function gatherMemorySnippets(root) {
|
|
67110
67680
|
const snippets = [];
|
|
67111
67681
|
const dirs = [
|
|
67112
|
-
|
|
67113
|
-
|
|
67682
|
+
join72(root, ".oa", "memory"),
|
|
67683
|
+
join72(root, ".open-agents", "memory")
|
|
67114
67684
|
];
|
|
67115
67685
|
for (const dir of dirs) {
|
|
67116
|
-
if (!
|
|
67686
|
+
if (!existsSync55(dir))
|
|
67117
67687
|
continue;
|
|
67118
67688
|
try {
|
|
67119
67689
|
for (const f of readdirSync22(dir).filter((f2) => f2.endsWith(".json"))) {
|
|
67120
|
-
const data = JSON.parse(
|
|
67690
|
+
const data = JSON.parse(readFileSync44(join72(dir, f), "utf-8"));
|
|
67121
67691
|
for (const val of Object.values(data)) {
|
|
67122
67692
|
const v = typeof val === "object" && val !== null && "value" in val ? String(val.value) : String(val);
|
|
67123
67693
|
if (v.length > 10)
|
|
@@ -67274,9 +67844,9 @@ ${metabolismMemories}
|
|
|
67274
67844
|
} catch {
|
|
67275
67845
|
}
|
|
67276
67846
|
try {
|
|
67277
|
-
const archeFile =
|
|
67278
|
-
if (
|
|
67279
|
-
const variants = JSON.parse(
|
|
67847
|
+
const archeFile = join72(repoRoot, ".oa", "arche", "variants.json");
|
|
67848
|
+
if (existsSync55(archeFile)) {
|
|
67849
|
+
const variants = JSON.parse(readFileSync44(archeFile, "utf8"));
|
|
67280
67850
|
if (variants.length > 0) {
|
|
67281
67851
|
let filtered = variants;
|
|
67282
67852
|
if (taskType) {
|
|
@@ -67445,9 +68015,9 @@ RULES:
|
|
|
67445
68015
|
const compactionThreshold = modelTier === "small" ? 12e3 : modelTier === "medium" ? 24e3 : 4e4;
|
|
67446
68016
|
let identityInjection = "";
|
|
67447
68017
|
try {
|
|
67448
|
-
const ikStateFile =
|
|
67449
|
-
if (
|
|
67450
|
-
const selfState = JSON.parse(
|
|
68018
|
+
const ikStateFile = join72(repoRoot, ".oa", "identity", "self-state.json");
|
|
68019
|
+
if (existsSync55(ikStateFile)) {
|
|
68020
|
+
const selfState = JSON.parse(readFileSync44(ikStateFile, "utf8"));
|
|
67451
68021
|
const lines = [
|
|
67452
68022
|
`[Identity State v${selfState.version}]`,
|
|
67453
68023
|
`Self: ${selfState.narrative_summary}`,
|
|
@@ -68091,13 +68661,13 @@ When done, either call task_complete with your answer, or use FINAL_VAR(variable
|
|
|
68091
68661
|
});
|
|
68092
68662
|
}
|
|
68093
68663
|
try {
|
|
68094
|
-
const ikDir =
|
|
68095
|
-
const ikFile =
|
|
68664
|
+
const ikDir = join72(repoRoot, ".oa", "identity");
|
|
68665
|
+
const ikFile = join72(ikDir, "self-state.json");
|
|
68096
68666
|
let ikState;
|
|
68097
|
-
if (
|
|
68098
|
-
ikState = JSON.parse(
|
|
68667
|
+
if (existsSync55(ikFile)) {
|
|
68668
|
+
ikState = JSON.parse(readFileSync44(ikFile, "utf8"));
|
|
68099
68669
|
} else {
|
|
68100
|
-
|
|
68670
|
+
mkdirSync29(ikDir, { recursive: true });
|
|
68101
68671
|
const machineId = Date.now().toString(36) + Math.random().toString(36).slice(2, 8);
|
|
68102
68672
|
ikState = {
|
|
68103
68673
|
self_id: `oa-${machineId}`,
|
|
@@ -68138,9 +68708,9 @@ When done, either call task_complete with your answer, or use FINAL_VAR(variable
|
|
|
68138
68708
|
} else {
|
|
68139
68709
|
renderTaskIncomplete(result.turns, result.toolCalls, result.durationMs, tokens);
|
|
68140
68710
|
try {
|
|
68141
|
-
const ikFile =
|
|
68142
|
-
if (
|
|
68143
|
-
const ikState = JSON.parse(
|
|
68711
|
+
const ikFile = join72(repoRoot, ".oa", "identity", "self-state.json");
|
|
68712
|
+
if (existsSync55(ikFile)) {
|
|
68713
|
+
const ikState = JSON.parse(readFileSync44(ikFile, "utf8"));
|
|
68144
68714
|
ikState.homeostasis.uncertainty = Math.min(1, ikState.homeostasis.uncertainty + 0.1);
|
|
68145
68715
|
ikState.homeostasis.coherence = Math.max(0, ikState.homeostasis.coherence - 0.05);
|
|
68146
68716
|
ikState.session_count = (ikState.session_count || 0) + 1;
|
|
@@ -68242,10 +68812,10 @@ async function startInteractive(config, repoPath) {
|
|
|
68242
68812
|
process.stdin.pause();
|
|
68243
68813
|
}
|
|
68244
68814
|
try {
|
|
68245
|
-
const oaDir =
|
|
68246
|
-
const nexusPidFile =
|
|
68247
|
-
if (
|
|
68248
|
-
const pid = parseInt(
|
|
68815
|
+
const oaDir = join72(repoRoot, ".oa");
|
|
68816
|
+
const nexusPidFile = join72(oaDir, "nexus", "daemon.pid");
|
|
68817
|
+
if (existsSync55(nexusPidFile)) {
|
|
68818
|
+
const pid = parseInt(readFileSync44(nexusPidFile, "utf8").trim(), 10);
|
|
68249
68819
|
if (pid > 0) {
|
|
68250
68820
|
try {
|
|
68251
68821
|
process.kill(pid, 0);
|
|
@@ -68582,7 +69152,7 @@ Review its full output in the [${id}] tab or via full_sub_agent(action='output',
|
|
|
68582
69152
|
let p2pGateway = null;
|
|
68583
69153
|
let peerMesh = null;
|
|
68584
69154
|
let inferenceRouter = null;
|
|
68585
|
-
const secretVault = new SecretVault(
|
|
69155
|
+
const secretVault = new SecretVault(join72(repoRoot, ".oa", "vault.enc"));
|
|
68586
69156
|
let adminSessionKey = null;
|
|
68587
69157
|
const callSubAgents = /* @__PURE__ */ new Map();
|
|
68588
69158
|
const streamRenderer = new StreamRenderer();
|
|
@@ -68805,13 +69375,13 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
68805
69375
|
const hits = allCompletions.filter((c3) => c3.toLowerCase().startsWith(lower));
|
|
68806
69376
|
return [hits, line];
|
|
68807
69377
|
}
|
|
68808
|
-
const HISTORY_DIR =
|
|
68809
|
-
const HISTORY_FILE =
|
|
69378
|
+
const HISTORY_DIR = join72(homedir19(), ".open-agents");
|
|
69379
|
+
const HISTORY_FILE = join72(HISTORY_DIR, "repl-history");
|
|
68810
69380
|
const MAX_HISTORY_LINES = 500;
|
|
68811
69381
|
let savedHistory = [];
|
|
68812
69382
|
try {
|
|
68813
|
-
if (
|
|
68814
|
-
const raw =
|
|
69383
|
+
if (existsSync55(HISTORY_FILE)) {
|
|
69384
|
+
const raw = readFileSync44(HISTORY_FILE, "utf8").trim();
|
|
68815
69385
|
if (raw)
|
|
68816
69386
|
savedHistory = raw.split("\n").reverse();
|
|
68817
69387
|
}
|
|
@@ -68914,10 +69484,10 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
68914
69484
|
if (!line.trim())
|
|
68915
69485
|
return;
|
|
68916
69486
|
try {
|
|
68917
|
-
|
|
68918
|
-
|
|
69487
|
+
mkdirSync29(HISTORY_DIR, { recursive: true });
|
|
69488
|
+
appendFileSync5(HISTORY_FILE, line + "\n", "utf8");
|
|
68919
69489
|
if (Math.random() < 0.02) {
|
|
68920
|
-
const all =
|
|
69490
|
+
const all = readFileSync44(HISTORY_FILE, "utf8").trim().split("\n");
|
|
68921
69491
|
if (all.length > MAX_HISTORY_LINES) {
|
|
68922
69492
|
writeFileSync27(HISTORY_FILE, all.slice(-MAX_HISTORY_LINES).join("\n") + "\n", "utf8");
|
|
68923
69493
|
}
|
|
@@ -69103,7 +69673,7 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
69103
69673
|
} catch {
|
|
69104
69674
|
}
|
|
69105
69675
|
try {
|
|
69106
|
-
const oaDir =
|
|
69676
|
+
const oaDir = join72(repoRoot, ".oa");
|
|
69107
69677
|
const reconnected = await ExposeGateway.checkAndReconnect(oaDir, {
|
|
69108
69678
|
onInfo: (msg) => writeContent(() => renderInfo(msg)),
|
|
69109
69679
|
onError: (msg) => writeContent(() => renderWarning(msg))
|
|
@@ -69135,7 +69705,7 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
69135
69705
|
} catch {
|
|
69136
69706
|
}
|
|
69137
69707
|
try {
|
|
69138
|
-
const oaDir =
|
|
69708
|
+
const oaDir = join72(repoRoot, ".oa");
|
|
69139
69709
|
const reconnectedP2P = await ExposeP2PGateway.checkAndReconnect(oaDir, new NexusTool(repoRoot), {
|
|
69140
69710
|
onInfo: (msg) => writeContent(() => renderInfo(msg)),
|
|
69141
69711
|
onError: (msg) => writeContent(() => renderWarning(msg))
|
|
@@ -69176,11 +69746,11 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
69176
69746
|
}
|
|
69177
69747
|
try {
|
|
69178
69748
|
const { homedir: _hd, hostname: _hn, userInfo: _ui } = await import("node:os");
|
|
69179
|
-
const globalNamePath =
|
|
69749
|
+
const globalNamePath = join72(_hd(), ".open-agents", "agent-name");
|
|
69180
69750
|
let agName = "";
|
|
69181
69751
|
try {
|
|
69182
|
-
if (
|
|
69183
|
-
agName =
|
|
69752
|
+
if (existsSync55(globalNamePath))
|
|
69753
|
+
agName = readFileSync44(globalNamePath, "utf8").trim();
|
|
69184
69754
|
} catch {
|
|
69185
69755
|
}
|
|
69186
69756
|
if (!agName) {
|
|
@@ -70156,7 +70726,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
70156
70726
|
kind,
|
|
70157
70727
|
targetUrl,
|
|
70158
70728
|
authKey,
|
|
70159
|
-
stateDir:
|
|
70729
|
+
stateDir: join72(repoRoot, ".oa"),
|
|
70160
70730
|
passthrough: passthrough ?? false,
|
|
70161
70731
|
loadbalance: loadbalance ?? false,
|
|
70162
70732
|
endpointAuth: passthrough ? currentConfig.apiKey : void 0,
|
|
@@ -70202,7 +70772,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
70202
70772
|
await tunnelGateway.stop();
|
|
70203
70773
|
tunnelGateway = null;
|
|
70204
70774
|
}
|
|
70205
|
-
const newTunnel = new ExposeGateway({ kind, targetUrl, authKey, fullAccess, stateDir:
|
|
70775
|
+
const newTunnel = new ExposeGateway({ kind, targetUrl, authKey, fullAccess, stateDir: join72(repoRoot, ".oa") });
|
|
70206
70776
|
newTunnel.on("stats", (stats) => {
|
|
70207
70777
|
statusBar.setExposeStatus({
|
|
70208
70778
|
status: stats.status,
|
|
@@ -70291,9 +70861,9 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
70291
70861
|
if (!result.success)
|
|
70292
70862
|
throw new Error(result.error || "Connect failed");
|
|
70293
70863
|
try {
|
|
70294
|
-
const nexusPidFile =
|
|
70295
|
-
if (
|
|
70296
|
-
const pid = parseInt(
|
|
70864
|
+
const nexusPidFile = join72(repoRoot, ".oa", "nexus", "daemon.pid");
|
|
70865
|
+
if (existsSync55(nexusPidFile)) {
|
|
70866
|
+
const pid = parseInt(readFileSync44(nexusPidFile, "utf8").trim(), 10);
|
|
70297
70867
|
if (pid > 0) {
|
|
70298
70868
|
registry.register({
|
|
70299
70869
|
name: "Nexus",
|
|
@@ -70489,10 +71059,10 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
70489
71059
|
writeContent(() => renderInfo(`Killed ${bgKilled} background task(s).`));
|
|
70490
71060
|
}
|
|
70491
71061
|
try {
|
|
70492
|
-
const nexusDir =
|
|
70493
|
-
const pidFile =
|
|
70494
|
-
if (
|
|
70495
|
-
const pid = parseInt(
|
|
71062
|
+
const nexusDir = join72(repoRoot, OA_DIR, "nexus");
|
|
71063
|
+
const pidFile = join72(nexusDir, "daemon.pid");
|
|
71064
|
+
if (existsSync55(pidFile)) {
|
|
71065
|
+
const pid = parseInt(readFileSync44(pidFile, "utf8").trim(), 10);
|
|
70496
71066
|
if (pid > 0) {
|
|
70497
71067
|
try {
|
|
70498
71068
|
if (process.platform === "win32") {
|
|
@@ -70514,13 +71084,13 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
70514
71084
|
} catch {
|
|
70515
71085
|
}
|
|
70516
71086
|
try {
|
|
70517
|
-
const voiceDir2 =
|
|
71087
|
+
const voiceDir2 = join72(homedir19(), ".open-agents", "voice");
|
|
70518
71088
|
const voicePidFiles = ["luxtts-daemon.pid", "piper-daemon.pid"];
|
|
70519
71089
|
for (const pf of voicePidFiles) {
|
|
70520
|
-
const pidPath =
|
|
70521
|
-
if (
|
|
71090
|
+
const pidPath = join72(voiceDir2, pf);
|
|
71091
|
+
if (existsSync55(pidPath)) {
|
|
70522
71092
|
try {
|
|
70523
|
-
const pid = parseInt(
|
|
71093
|
+
const pid = parseInt(readFileSync44(pidPath, "utf8").trim(), 10);
|
|
70524
71094
|
if (pid > 0) {
|
|
70525
71095
|
if (process.platform === "win32") {
|
|
70526
71096
|
try {
|
|
@@ -70544,8 +71114,8 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
70544
71114
|
execSync35(process.platform === "win32" ? "timeout /t 1 /nobreak >nul" : "sleep 0.5", { timeout: 3e3, stdio: "ignore" });
|
|
70545
71115
|
} catch {
|
|
70546
71116
|
}
|
|
70547
|
-
const oaPath =
|
|
70548
|
-
if (
|
|
71117
|
+
const oaPath = join72(repoRoot, OA_DIR);
|
|
71118
|
+
if (existsSync55(oaPath)) {
|
|
70549
71119
|
let deleted = false;
|
|
70550
71120
|
for (let attempt = 0; attempt < 3; attempt++) {
|
|
70551
71121
|
try {
|
|
@@ -70628,19 +71198,19 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
70628
71198
|
try {
|
|
70629
71199
|
const { isPersonaPlexRunning: isPersonaPlexRunning2 } = await Promise.resolve().then(() => (init_personaplex(), personaplex_exports));
|
|
70630
71200
|
if (isPersonaPlexRunning2()) {
|
|
70631
|
-
const ppPidFile =
|
|
70632
|
-
const ppPortFile =
|
|
70633
|
-
if (
|
|
70634
|
-
const ppPid = parseInt(
|
|
70635
|
-
const ppPort =
|
|
71201
|
+
const ppPidFile = join72(homedir19(), ".open-agents", "voice", "personaplex", "daemon.pid");
|
|
71202
|
+
const ppPortFile = join72(homedir19(), ".open-agents", "voice", "personaplex", "daemon.port");
|
|
71203
|
+
if (existsSync55(ppPidFile)) {
|
|
71204
|
+
const ppPid = parseInt(readFileSync44(ppPidFile, "utf8").trim(), 10);
|
|
71205
|
+
const ppPort = existsSync55(ppPortFile) ? parseInt(readFileSync44(ppPortFile, "utf8").trim(), 10) : void 0;
|
|
70636
71206
|
if (ppPid > 0 && !registry.daemons.has("PersonaPlex")) {
|
|
70637
71207
|
registry.register({ name: "PersonaPlex", pid: ppPid, port: ppPort, startedAt: Date.now(), status: "running" });
|
|
70638
71208
|
}
|
|
70639
71209
|
}
|
|
70640
71210
|
}
|
|
70641
|
-
const nexusPidFile =
|
|
70642
|
-
if (
|
|
70643
|
-
const nPid = parseInt(
|
|
71211
|
+
const nexusPidFile = join72(repoRoot, ".oa", "nexus", "daemon.pid");
|
|
71212
|
+
if (existsSync55(nexusPidFile)) {
|
|
71213
|
+
const nPid = parseInt(readFileSync44(nexusPidFile, "utf8").trim(), 10);
|
|
70644
71214
|
if (nPid > 0 && !registry.daemons.has("Nexus")) {
|
|
70645
71215
|
try {
|
|
70646
71216
|
process.kill(nPid, 0);
|
|
@@ -70982,8 +71552,8 @@ Execute this skill now. Follow the behavioral guidance above.`;
|
|
|
70982
71552
|
}
|
|
70983
71553
|
}
|
|
70984
71554
|
const cleanPath = input.replace(/^['"]|['"]$/g, "").trim();
|
|
70985
|
-
const isImage = isImagePath(cleanPath) &&
|
|
70986
|
-
const isMedia = !isImage && isTranscribablePath(cleanPath) &&
|
|
71555
|
+
const isImage = isImagePath(cleanPath) && existsSync55(resolve32(repoRoot, cleanPath));
|
|
71556
|
+
const isMedia = !isImage && isTranscribablePath(cleanPath) && existsSync55(resolve32(repoRoot, cleanPath));
|
|
70987
71557
|
if (activeTask) {
|
|
70988
71558
|
if (activeTask.runner.isPaused) {
|
|
70989
71559
|
activeTask.runner.resume();
|
|
@@ -70992,7 +71562,7 @@ Execute this skill now. Follow the behavioral guidance above.`;
|
|
|
70992
71562
|
if (isImage) {
|
|
70993
71563
|
try {
|
|
70994
71564
|
const imgPath = resolve32(repoRoot, cleanPath);
|
|
70995
|
-
const imgBuffer =
|
|
71565
|
+
const imgBuffer = readFileSync44(imgPath);
|
|
70996
71566
|
const base64 = imgBuffer.toString("base64");
|
|
70997
71567
|
const ext = extname11(cleanPath).toLowerCase();
|
|
70998
71568
|
const mime = ext === ".png" ? "image/png" : ext === ".gif" ? "image/gif" : ext === ".webp" ? "image/webp" : "image/jpeg";
|
|
@@ -71207,7 +71777,7 @@ Summarize or analyze this transcription as appropriate.`;
|
|
|
71207
71777
|
|
|
71208
71778
|
NEW TASK: ${fullInput}`;
|
|
71209
71779
|
restoredSessionContext = null;
|
|
71210
|
-
} else if (
|
|
71780
|
+
} else if (existsSync55(join72(repoRoot, ".oa", "context", "session-diary.md"))) {
|
|
71211
71781
|
taskInput = `[Previous sessions exist \u2014 file_read(".oa/context/session-diary.md") to recall]
|
|
71212
71782
|
|
|
71213
71783
|
${fullInput}`;
|
|
@@ -71524,13 +72094,13 @@ async function runWithTUI(task, config, repoPath) {
|
|
|
71524
72094
|
const handle = startTask(task, config, repoRoot);
|
|
71525
72095
|
await handle.promise;
|
|
71526
72096
|
try {
|
|
71527
|
-
const ikDir =
|
|
71528
|
-
const ikFile =
|
|
72097
|
+
const ikDir = join72(repoRoot, ".oa", "identity");
|
|
72098
|
+
const ikFile = join72(ikDir, "self-state.json");
|
|
71529
72099
|
let ikState;
|
|
71530
|
-
if (
|
|
71531
|
-
ikState = JSON.parse(
|
|
72100
|
+
if (existsSync55(ikFile)) {
|
|
72101
|
+
ikState = JSON.parse(readFileSync44(ikFile, "utf8"));
|
|
71532
72102
|
} else {
|
|
71533
|
-
|
|
72103
|
+
mkdirSync29(ikDir, { recursive: true });
|
|
71534
72104
|
ikState = {
|
|
71535
72105
|
self_id: `oa-${Date.now().toString(36)}`,
|
|
71536
72106
|
version: 1,
|
|
@@ -71561,12 +72131,12 @@ async function runWithTUI(task, config, repoPath) {
|
|
|
71561
72131
|
ec.archiveVariantSync(`Task: ${task.slice(0, 200)}`, "success \u2014 completed", ["general"]);
|
|
71562
72132
|
} catch {
|
|
71563
72133
|
try {
|
|
71564
|
-
const archeDir =
|
|
71565
|
-
const archeFile =
|
|
72134
|
+
const archeDir = join72(repoRoot, ".oa", "arche");
|
|
72135
|
+
const archeFile = join72(archeDir, "variants.json");
|
|
71566
72136
|
let variants = [];
|
|
71567
72137
|
try {
|
|
71568
|
-
if (
|
|
71569
|
-
variants = JSON.parse(
|
|
72138
|
+
if (existsSync55(archeFile))
|
|
72139
|
+
variants = JSON.parse(readFileSync44(archeFile, "utf8"));
|
|
71570
72140
|
} catch {
|
|
71571
72141
|
}
|
|
71572
72142
|
variants.push({
|
|
@@ -71581,15 +72151,15 @@ async function runWithTUI(task, config, repoPath) {
|
|
|
71581
72151
|
});
|
|
71582
72152
|
if (variants.length > 50)
|
|
71583
72153
|
variants = variants.slice(-50);
|
|
71584
|
-
|
|
72154
|
+
mkdirSync29(archeDir, { recursive: true });
|
|
71585
72155
|
writeFileSync27(archeFile, JSON.stringify(variants, null, 2));
|
|
71586
72156
|
} catch {
|
|
71587
72157
|
}
|
|
71588
72158
|
}
|
|
71589
72159
|
try {
|
|
71590
|
-
const metaFile =
|
|
71591
|
-
if (
|
|
71592
|
-
const store = JSON.parse(
|
|
72160
|
+
const metaFile = join72(repoRoot, ".oa", "memory", "metabolism", "store.json");
|
|
72161
|
+
if (existsSync55(metaFile)) {
|
|
72162
|
+
const store = JSON.parse(readFileSync44(metaFile, "utf8"));
|
|
71593
72163
|
const surfaced = store.filter((m) => m.type !== "quarantine" && m.scores?.confidence > 0.15).sort((a, b) => b.scores.utility * b.scores.confidence - a.scores.utility * a.scores.confidence).slice(0, 5);
|
|
71594
72164
|
let updated = false;
|
|
71595
72165
|
for (const item of surfaced) {
|
|
@@ -71653,9 +72223,9 @@ Rules:
|
|
|
71653
72223
|
try {
|
|
71654
72224
|
const { initDb: initDb2 } = __require("@open-agents/memory");
|
|
71655
72225
|
const { ProceduralMemoryStore: ProceduralMemoryStore2 } = __require("@open-agents/memory");
|
|
71656
|
-
const dbDir =
|
|
71657
|
-
|
|
71658
|
-
const db = initDb2(
|
|
72226
|
+
const dbDir = join72(repoRoot, ".oa", "memory");
|
|
72227
|
+
mkdirSync29(dbDir, { recursive: true });
|
|
72228
|
+
const db = initDb2(join72(dbDir, "structured.db"));
|
|
71659
72229
|
const memStore = new ProceduralMemoryStore2(db);
|
|
71660
72230
|
memStore.createWithEmbedding({
|
|
71661
72231
|
content: content.slice(0, 600),
|
|
@@ -71670,12 +72240,12 @@ Rules:
|
|
|
71670
72240
|
db.close();
|
|
71671
72241
|
} catch {
|
|
71672
72242
|
}
|
|
71673
|
-
const metaDir =
|
|
71674
|
-
const storeFile =
|
|
72243
|
+
const metaDir = join72(repoRoot, ".oa", "memory", "metabolism");
|
|
72244
|
+
const storeFile = join72(metaDir, "store.json");
|
|
71675
72245
|
let store = [];
|
|
71676
72246
|
try {
|
|
71677
|
-
if (
|
|
71678
|
-
store = JSON.parse(
|
|
72247
|
+
if (existsSync55(storeFile))
|
|
72248
|
+
store = JSON.parse(readFileSync44(storeFile, "utf8"));
|
|
71679
72249
|
} catch {
|
|
71680
72250
|
}
|
|
71681
72251
|
store.push({
|
|
@@ -71691,26 +72261,26 @@ Rules:
|
|
|
71691
72261
|
});
|
|
71692
72262
|
if (store.length > 100)
|
|
71693
72263
|
store = store.slice(-100);
|
|
71694
|
-
|
|
72264
|
+
mkdirSync29(metaDir, { recursive: true });
|
|
71695
72265
|
writeFileSync27(storeFile, JSON.stringify(store, null, 2));
|
|
71696
72266
|
}
|
|
71697
72267
|
}
|
|
71698
72268
|
} catch {
|
|
71699
72269
|
}
|
|
71700
72270
|
try {
|
|
71701
|
-
const cohereSettingsFile =
|
|
72271
|
+
const cohereSettingsFile = join72(repoRoot, ".oa", "settings.json");
|
|
71702
72272
|
let cohereActive = false;
|
|
71703
72273
|
try {
|
|
71704
|
-
if (
|
|
71705
|
-
const settings = JSON.parse(
|
|
72274
|
+
if (existsSync55(cohereSettingsFile)) {
|
|
72275
|
+
const settings = JSON.parse(readFileSync44(cohereSettingsFile, "utf8"));
|
|
71706
72276
|
cohereActive = settings.cohere === true;
|
|
71707
72277
|
}
|
|
71708
72278
|
} catch {
|
|
71709
72279
|
}
|
|
71710
72280
|
if (cohereActive) {
|
|
71711
|
-
const metaFile =
|
|
71712
|
-
if (
|
|
71713
|
-
const store = JSON.parse(
|
|
72281
|
+
const metaFile = join72(repoRoot, ".oa", "memory", "metabolism", "store.json");
|
|
72282
|
+
if (existsSync55(metaFile)) {
|
|
72283
|
+
const store = JSON.parse(readFileSync44(metaFile, "utf8"));
|
|
71714
72284
|
const latest = store.filter((m) => m.sourceTrace === "trajectory-extraction" || m.sourceTrace === "llm-trajectory-extraction").slice(-1)[0];
|
|
71715
72285
|
if (latest && latest.scores?.confidence >= 0.6) {
|
|
71716
72286
|
try {
|
|
@@ -71735,18 +72305,18 @@ Rules:
|
|
|
71735
72305
|
}
|
|
71736
72306
|
} catch (err) {
|
|
71737
72307
|
try {
|
|
71738
|
-
const ikFile =
|
|
71739
|
-
if (
|
|
71740
|
-
const ikState = JSON.parse(
|
|
72308
|
+
const ikFile = join72(repoRoot, ".oa", "identity", "self-state.json");
|
|
72309
|
+
if (existsSync55(ikFile)) {
|
|
72310
|
+
const ikState = JSON.parse(readFileSync44(ikFile, "utf8"));
|
|
71741
72311
|
ikState.homeostasis.uncertainty = Math.min(1, ikState.homeostasis.uncertainty + 0.1);
|
|
71742
72312
|
ikState.homeostasis.coherence = Math.max(0, ikState.homeostasis.coherence - 0.05);
|
|
71743
72313
|
ikState.session_count = (ikState.session_count || 0) + 1;
|
|
71744
72314
|
ikState.updated_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
71745
72315
|
writeFileSync27(ikFile, JSON.stringify(ikState, null, 2));
|
|
71746
72316
|
}
|
|
71747
|
-
const metaFile =
|
|
71748
|
-
if (
|
|
71749
|
-
const store = JSON.parse(
|
|
72317
|
+
const metaFile = join72(repoRoot, ".oa", "memory", "metabolism", "store.json");
|
|
72318
|
+
if (existsSync55(metaFile)) {
|
|
72319
|
+
const store = JSON.parse(readFileSync44(metaFile, "utf8"));
|
|
71750
72320
|
const surfaced = store.filter((m) => m.type !== "quarantine" && m.scores?.confidence > 0.15).sort((a, b) => b.scores.utility * b.scores.confidence - a.scores.utility * a.scores.confidence).slice(0, 5);
|
|
71751
72321
|
for (const item of surfaced) {
|
|
71752
72322
|
item.accessCount = (item.accessCount || 0) + 1;
|
|
@@ -71757,12 +72327,12 @@ Rules:
|
|
|
71757
72327
|
writeFileSync27(metaFile, JSON.stringify(store, null, 2));
|
|
71758
72328
|
}
|
|
71759
72329
|
try {
|
|
71760
|
-
const archeDir =
|
|
71761
|
-
const archeFile =
|
|
72330
|
+
const archeDir = join72(repoRoot, ".oa", "arche");
|
|
72331
|
+
const archeFile = join72(archeDir, "variants.json");
|
|
71762
72332
|
let variants = [];
|
|
71763
72333
|
try {
|
|
71764
|
-
if (
|
|
71765
|
-
variants = JSON.parse(
|
|
72334
|
+
if (existsSync55(archeFile))
|
|
72335
|
+
variants = JSON.parse(readFileSync44(archeFile, "utf8"));
|
|
71766
72336
|
} catch {
|
|
71767
72337
|
}
|
|
71768
72338
|
variants.push({
|
|
@@ -71777,7 +72347,7 @@ Rules:
|
|
|
71777
72347
|
});
|
|
71778
72348
|
if (variants.length > 50)
|
|
71779
72349
|
variants = variants.slice(-50);
|
|
71780
|
-
|
|
72350
|
+
mkdirSync29(archeDir, { recursive: true });
|
|
71781
72351
|
writeFileSync27(archeFile, JSON.stringify(variants, null, 2));
|
|
71782
72352
|
} catch {
|
|
71783
72353
|
}
|
|
@@ -71848,13 +72418,13 @@ __export(run_exports, {
|
|
|
71848
72418
|
});
|
|
71849
72419
|
import { resolve as resolve33 } from "node:path";
|
|
71850
72420
|
import { spawn as spawn22 } from "node:child_process";
|
|
71851
|
-
import { mkdirSync as
|
|
72421
|
+
import { mkdirSync as mkdirSync30, writeFileSync as writeFileSync28, readFileSync as readFileSync45, readdirSync as readdirSync23, existsSync as existsSync56 } from "node:fs";
|
|
71852
72422
|
import { randomBytes as randomBytes17 } from "node:crypto";
|
|
71853
|
-
import { join as
|
|
72423
|
+
import { join as join73 } from "node:path";
|
|
71854
72424
|
function jobsDir2(repoPath) {
|
|
71855
72425
|
const root = resolve33(repoPath ?? process.cwd());
|
|
71856
|
-
const dir =
|
|
71857
|
-
|
|
72426
|
+
const dir = join73(root, ".oa", "jobs");
|
|
72427
|
+
mkdirSync30(dir, { recursive: true });
|
|
71858
72428
|
return dir;
|
|
71859
72429
|
}
|
|
71860
72430
|
async function runCommand(opts, config) {
|
|
@@ -71939,7 +72509,7 @@ async function runBackground(task, config, opts) {
|
|
|
71939
72509
|
});
|
|
71940
72510
|
child.unref();
|
|
71941
72511
|
job.pid = child.pid ?? 0;
|
|
71942
|
-
writeFileSync28(
|
|
72512
|
+
writeFileSync28(join73(dir, `${id}.json`), JSON.stringify(job, null, 2));
|
|
71943
72513
|
let output = "";
|
|
71944
72514
|
child.stdout?.on("data", (chunk) => {
|
|
71945
72515
|
output += chunk.toString();
|
|
@@ -71955,7 +72525,7 @@ async function runBackground(task, config, opts) {
|
|
|
71955
72525
|
job.summary = result.summary;
|
|
71956
72526
|
job.durationMs = result.durationMs;
|
|
71957
72527
|
job.error = result.error;
|
|
71958
|
-
writeFileSync28(
|
|
72528
|
+
writeFileSync28(join73(dir, `${id}.json`), JSON.stringify(job, null, 2));
|
|
71959
72529
|
} catch {
|
|
71960
72530
|
}
|
|
71961
72531
|
});
|
|
@@ -71971,13 +72541,13 @@ async function runBackground(task, config, opts) {
|
|
|
71971
72541
|
}
|
|
71972
72542
|
function statusCommand(jobId, repoPath) {
|
|
71973
72543
|
const dir = jobsDir2(repoPath);
|
|
71974
|
-
const file =
|
|
71975
|
-
if (!
|
|
72544
|
+
const file = join73(dir, `${jobId}.json`);
|
|
72545
|
+
if (!existsSync56(file)) {
|
|
71976
72546
|
console.error(`Job not found: ${jobId}`);
|
|
71977
72547
|
console.log(`Available jobs: oa jobs`);
|
|
71978
72548
|
process.exit(1);
|
|
71979
72549
|
}
|
|
71980
|
-
const job = JSON.parse(
|
|
72550
|
+
const job = JSON.parse(readFileSync45(file, "utf-8"));
|
|
71981
72551
|
const runtime = job.completedAt ? `${((new Date(job.completedAt).getTime() - new Date(job.startedAt).getTime()) / 1e3).toFixed(0)}s` : `${((Date.now() - new Date(job.startedAt).getTime()) / 1e3).toFixed(0)}s`;
|
|
71982
72552
|
const icon = job.status === "completed" ? "\u2713" : job.status === "failed" ? "\u2717" : "\u25CF";
|
|
71983
72553
|
console.log(`${icon} ${job.id} [${job.status}] ${runtime}`);
|
|
@@ -72000,7 +72570,7 @@ function jobsCommand(repoPath) {
|
|
|
72000
72570
|
console.log("Jobs:");
|
|
72001
72571
|
for (const file of files) {
|
|
72002
72572
|
try {
|
|
72003
|
-
const job = JSON.parse(
|
|
72573
|
+
const job = JSON.parse(readFileSync45(join73(dir, file), "utf-8"));
|
|
72004
72574
|
const icon = job.status === "completed" ? "\u2713" : job.status === "failed" ? "\u2717" : "\u25CF";
|
|
72005
72575
|
const runtime = job.completedAt ? `${((new Date(job.completedAt).getTime() - new Date(job.startedAt).getTime()) / 1e3).toFixed(0)}s` : `${((Date.now() - new Date(job.startedAt).getTime()) / 1e3).toFixed(0)}s`;
|
|
72006
72576
|
console.log(` ${icon} ${job.id} [${job.status}] ${runtime} \u2014 ${job.task.slice(0, 60)}`);
|
|
@@ -72020,7 +72590,7 @@ import { glob } from "glob";
|
|
|
72020
72590
|
import ignore from "ignore";
|
|
72021
72591
|
import { readFile as readFile23, stat as stat4 } from "node:fs/promises";
|
|
72022
72592
|
import { createHash as createHash6 } from "node:crypto";
|
|
72023
|
-
import { join as
|
|
72593
|
+
import { join as join74, relative as relative4, extname as extname12, basename as basename17 } from "node:path";
|
|
72024
72594
|
var DEFAULT_EXCLUDE, LANGUAGE_MAP, CodebaseIndexer;
|
|
72025
72595
|
var init_codebase_indexer = __esm({
|
|
72026
72596
|
"packages/indexer/dist/codebase-indexer.js"() {
|
|
@@ -72064,7 +72634,7 @@ var init_codebase_indexer = __esm({
|
|
|
72064
72634
|
const ig = ignore.default();
|
|
72065
72635
|
if (this.config.respectGitignore) {
|
|
72066
72636
|
try {
|
|
72067
|
-
const gitignoreContent = await readFile23(
|
|
72637
|
+
const gitignoreContent = await readFile23(join74(this.config.rootDir, ".gitignore"), "utf-8");
|
|
72068
72638
|
ig.add(gitignoreContent);
|
|
72069
72639
|
} catch {
|
|
72070
72640
|
}
|
|
@@ -72079,7 +72649,7 @@ var init_codebase_indexer = __esm({
|
|
|
72079
72649
|
for (const relativePath of files) {
|
|
72080
72650
|
if (ig.ignores(relativePath))
|
|
72081
72651
|
continue;
|
|
72082
|
-
const fullPath =
|
|
72652
|
+
const fullPath = join74(this.config.rootDir, relativePath);
|
|
72083
72653
|
try {
|
|
72084
72654
|
const fileStat = await stat4(fullPath);
|
|
72085
72655
|
if (fileStat.size > this.config.maxFileSize)
|
|
@@ -72125,7 +72695,7 @@ var init_codebase_indexer = __esm({
|
|
|
72125
72695
|
if (!child) {
|
|
72126
72696
|
child = {
|
|
72127
72697
|
name: part,
|
|
72128
|
-
path:
|
|
72698
|
+
path: join74(current.path, part),
|
|
72129
72699
|
type: "directory",
|
|
72130
72700
|
children: []
|
|
72131
72701
|
};
|
|
@@ -72208,13 +72778,13 @@ __export(index_repo_exports, {
|
|
|
72208
72778
|
indexRepoCommand: () => indexRepoCommand
|
|
72209
72779
|
});
|
|
72210
72780
|
import { resolve as resolve34 } from "node:path";
|
|
72211
|
-
import { existsSync as
|
|
72781
|
+
import { existsSync as existsSync57, statSync as statSync17 } from "node:fs";
|
|
72212
72782
|
import { cwd as cwd2 } from "node:process";
|
|
72213
72783
|
async function indexRepoCommand(opts, _config) {
|
|
72214
72784
|
const repoRoot = resolve34(opts.repoPath ?? cwd2());
|
|
72215
72785
|
printHeader("Index Repository");
|
|
72216
72786
|
printInfo(`Indexing: ${repoRoot}`);
|
|
72217
|
-
if (!
|
|
72787
|
+
if (!existsSync57(repoRoot)) {
|
|
72218
72788
|
printError(`Path does not exist: ${repoRoot}`);
|
|
72219
72789
|
process.exit(1);
|
|
72220
72790
|
}
|
|
@@ -72466,7 +73036,7 @@ var config_exports2 = {};
|
|
|
72466
73036
|
__export(config_exports2, {
|
|
72467
73037
|
configCommand: () => configCommand
|
|
72468
73038
|
});
|
|
72469
|
-
import { join as
|
|
73039
|
+
import { join as join75, resolve as resolve35 } from "node:path";
|
|
72470
73040
|
import { homedir as homedir20 } from "node:os";
|
|
72471
73041
|
import { cwd as cwd3 } from "node:process";
|
|
72472
73042
|
function redactIfSensitive(key, value) {
|
|
@@ -72549,7 +73119,7 @@ function handleShow(opts, config) {
|
|
|
72549
73119
|
}
|
|
72550
73120
|
}
|
|
72551
73121
|
printSection("Config File");
|
|
72552
|
-
printInfo(`~/.open-agents/config.json (${
|
|
73122
|
+
printInfo(`~/.open-agents/config.json (${join75(homedir20(), ".open-agents", "config.json")})`);
|
|
72553
73123
|
printSection("Priority Chain");
|
|
72554
73124
|
printInfo(" 1. CLI flags (--model, --backend-url, etc.)");
|
|
72555
73125
|
printInfo(" 2. Project .oa/settings.json (--local)");
|
|
@@ -72588,7 +73158,7 @@ function handleSet(opts, _config) {
|
|
|
72588
73158
|
const coerced = coerceForSettings(key, value);
|
|
72589
73159
|
saveProjectSettings(repoRoot, { [key]: coerced });
|
|
72590
73160
|
printSuccess(`Project override set: ${key} = ${redactIfSensitive(key, value)}`);
|
|
72591
|
-
printInfo(`Saved to ${
|
|
73161
|
+
printInfo(`Saved to ${join75(repoRoot, ".oa", "settings.json")}`);
|
|
72592
73162
|
printInfo("This override applies only when running in this workspace.");
|
|
72593
73163
|
} catch (err) {
|
|
72594
73164
|
printError(`Failed to save: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -72731,8 +73301,8 @@ __export(eval_exports, {
|
|
|
72731
73301
|
evalCommand: () => evalCommand
|
|
72732
73302
|
});
|
|
72733
73303
|
import { tmpdir as tmpdir10 } from "node:os";
|
|
72734
|
-
import { mkdirSync as
|
|
72735
|
-
import { join as
|
|
73304
|
+
import { mkdirSync as mkdirSync31, writeFileSync as writeFileSync29 } from "node:fs";
|
|
73305
|
+
import { join as join76 } from "node:path";
|
|
72736
73306
|
async function evalCommand(opts, config) {
|
|
72737
73307
|
const suiteName = opts.suite ?? "basic";
|
|
72738
73308
|
const suite = SUITES[suiteName];
|
|
@@ -72857,9 +73427,9 @@ async function evalCommand(opts, config) {
|
|
|
72857
73427
|
process.exit(failed > 0 ? 1 : 0);
|
|
72858
73428
|
}
|
|
72859
73429
|
function createTempEvalRepo() {
|
|
72860
|
-
const dir =
|
|
72861
|
-
|
|
72862
|
-
writeFileSync29(
|
|
73430
|
+
const dir = join76(tmpdir10(), `open-agents-eval-${Date.now()}`);
|
|
73431
|
+
mkdirSync31(dir, { recursive: true });
|
|
73432
|
+
writeFileSync29(join76(dir, "package.json"), JSON.stringify({ name: "eval-repo", version: "0.0.0" }, null, 2) + "\n", "utf8");
|
|
72863
73433
|
return dir;
|
|
72864
73434
|
}
|
|
72865
73435
|
var BASIC_SUITE, FULL_SUITE, SUITES;
|
|
@@ -72919,7 +73489,7 @@ init_updater();
|
|
|
72919
73489
|
import { parseArgs as nodeParseArgs2 } from "node:util";
|
|
72920
73490
|
import { createRequire as createRequire5 } from "node:module";
|
|
72921
73491
|
import { fileURLToPath as fileURLToPath15 } from "node:url";
|
|
72922
|
-
import { dirname as dirname23, join as
|
|
73492
|
+
import { dirname as dirname23, join as join77 } from "node:path";
|
|
72923
73493
|
|
|
72924
73494
|
// packages/cli/dist/cli.js
|
|
72925
73495
|
import { createInterface } from "node:readline";
|
|
@@ -73026,7 +73596,7 @@ init_output();
|
|
|
73026
73596
|
function getVersion5() {
|
|
73027
73597
|
try {
|
|
73028
73598
|
const require2 = createRequire5(import.meta.url);
|
|
73029
|
-
const pkgPath =
|
|
73599
|
+
const pkgPath = join77(dirname23(fileURLToPath15(import.meta.url)), "..", "package.json");
|
|
73030
73600
|
const pkg = require2(pkgPath);
|
|
73031
73601
|
return pkg.version;
|
|
73032
73602
|
} catch {
|
|
@@ -73301,12 +73871,12 @@ function crashLog(label, err) {
|
|
|
73301
73871
|
const logLine = `[${timestamp}] ${label}: ${msg}
|
|
73302
73872
|
`;
|
|
73303
73873
|
try {
|
|
73304
|
-
const { appendFileSync:
|
|
73305
|
-
const { join:
|
|
73874
|
+
const { appendFileSync: appendFileSync6, mkdirSync: mkdirSync32 } = __require("node:fs");
|
|
73875
|
+
const { join: join78 } = __require("node:path");
|
|
73306
73876
|
const { homedir: homedir21 } = __require("node:os");
|
|
73307
|
-
const logDir =
|
|
73308
|
-
|
|
73309
|
-
|
|
73877
|
+
const logDir = join78(homedir21(), ".open-agents");
|
|
73878
|
+
mkdirSync32(logDir, { recursive: true });
|
|
73879
|
+
appendFileSync6(join78(logDir, "crash.log"), logLine);
|
|
73310
73880
|
} catch {
|
|
73311
73881
|
}
|
|
73312
73882
|
try {
|