open-agents-ai 0.187.533 → 0.187.535
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 +1632 -410
- package/npm-shrinkwrap.json +11 -11
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7783,11 +7783,41 @@ async function handleCmd(cmd) {
|
|
|
7783
7783
|
const capability = args.capability || 'text-generation';
|
|
7784
7784
|
const input = args.input || {};
|
|
7785
7785
|
if (!peerId) { writeResp(id, { ok: false, output: 'target_peer is required' }); return; }
|
|
7786
|
-
|
|
7786
|
+
// Streaming mode: when stream_file is supplied, tee invoke events
|
|
7787
|
+
// to the file as JSONL so the caller can tail them in real time.
|
|
7788
|
+
const icStreamFile = typeof args.stream_file === 'string' ? args.stream_file : '';
|
|
7789
|
+
const icUseStream = !!icStreamFile;
|
|
7790
|
+
dlog('invoke_capability: peer=' + peerId.slice(0, 20) + ' cap=' + capability + (icUseStream ? ' [stream]' : ''));
|
|
7787
7791
|
try {
|
|
7788
|
-
// Race libp2p + NATS in parallel — whichever route works first wins
|
|
7789
7792
|
const INVOKE_TIMEOUT = 300_000;
|
|
7790
7793
|
const invokeInput = typeof input === 'string' ? { prompt: input } : input;
|
|
7794
|
+
if (icUseStream) {
|
|
7795
|
+
// Stream-mode: get an AsyncGenerator and tee each event to the file.
|
|
7796
|
+
var icStreamGen;
|
|
7797
|
+
try {
|
|
7798
|
+
icStreamGen = await nexus.invokeCapability(peerId, capability, invokeInput, { stream: true, maxDurationMs: 240000 });
|
|
7799
|
+
} catch (invokeStartErr) {
|
|
7800
|
+
writeResp(id, { ok: false, output: 'Invoke start failed: ' + (invokeStartErr.message || invokeStartErr) });
|
|
7801
|
+
break;
|
|
7802
|
+
}
|
|
7803
|
+
// Signal the caller that streaming has begun.
|
|
7804
|
+
writeResp(id, { ok: true, output: JSON.stringify({ streaming: true, stream_file: icStreamFile }) });
|
|
7805
|
+
try {
|
|
7806
|
+
for await (var icEvt of icStreamGen) {
|
|
7807
|
+
appendFileSync(icStreamFile, JSON.stringify({ type: 'event', event: icEvt.event || '', seq: icEvt.seq || 0, data: icEvt.data }) + '
|
|
7808
|
+
');
|
|
7809
|
+
}
|
|
7810
|
+
appendFileSync(icStreamFile, JSON.stringify({ type: 'done' }) + '
|
|
7811
|
+
');
|
|
7812
|
+
dlog('invoke_capability: stream complete');
|
|
7813
|
+
} catch (icStreamErr) {
|
|
7814
|
+
appendFileSync(icStreamFile, JSON.stringify({ type: 'error', error: String(icStreamErr.message || icStreamErr) }) + '
|
|
7815
|
+
');
|
|
7816
|
+
dlog('invoke_capability: stream error: ' + (icStreamErr.message || icStreamErr));
|
|
7817
|
+
}
|
|
7818
|
+
break;
|
|
7819
|
+
}
|
|
7820
|
+
// Non-stream mode: race libp2p + NATS in parallel.
|
|
7791
7821
|
const invokePromise = nexus.invokeCapability(peerId, capability, invokeInput, { stream: false, maxDurationMs: 240000 });
|
|
7792
7822
|
const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error('invoke_capability timed out after ' + (INVOKE_TIMEOUT / 1000) + 's')), INVOKE_TIMEOUT));
|
|
7793
7823
|
|
|
@@ -9427,6 +9457,119 @@ process.on('unhandledRejection', (reason) => {
|
|
|
9427
9457
|
}
|
|
9428
9458
|
connected = true;
|
|
9429
9459
|
|
|
9460
|
+
// http_tunnel capability — proxies HTTP requests from remote peers
|
|
9461
|
+
// to the local OA API daemon. Auth is delegated to the API key store
|
|
9462
|
+
// (remote sends share key in Authorization header). SSE streams are
|
|
9463
|
+
// forwarded chunk-by-chunk over libp2p invoke. The local API port is
|
|
9464
|
+
// read from nexusDir/api-port.json which oa serve writes on startup.
|
|
9465
|
+
if (typeof nexus.registerCapability === 'function') {
|
|
9466
|
+
var nodePathMod = require('node:path');
|
|
9467
|
+
var apiPortHintPath = nodePathMod.join(nexusDir, 'api-port.json');
|
|
9468
|
+
nexus.registerCapability('http_tunnel', async (request, stream) => {
|
|
9469
|
+
var htClosed = false;
|
|
9470
|
+
async function htWrite(msg) {
|
|
9471
|
+
if (htClosed) return;
|
|
9472
|
+
try { await stream.write(msg); } catch { htClosed = true; }
|
|
9473
|
+
}
|
|
9474
|
+
var htChunks = [];
|
|
9475
|
+
var htInputDone = false;
|
|
9476
|
+
stream.onData(function(msg) {
|
|
9477
|
+
if (msg.type === 'invoke.chunk') {
|
|
9478
|
+
htChunks.push(typeof msg.data === 'string' ? msg.data : JSON.stringify(msg.data));
|
|
9479
|
+
}
|
|
9480
|
+
if (msg.type === 'invoke.done' || msg.type === 'invoke.end') htInputDone = true;
|
|
9481
|
+
});
|
|
9482
|
+
await htWrite({ type: 'invoke.accept', version: 1, requestId: request.requestId, accepted: true });
|
|
9483
|
+
var htWait = 0;
|
|
9484
|
+
while (!htInputDone && htWait < 5000) {
|
|
9485
|
+
await new Promise(function(r) { setTimeout(r, 20); });
|
|
9486
|
+
htWait += 20;
|
|
9487
|
+
}
|
|
9488
|
+
var htReq;
|
|
9489
|
+
try {
|
|
9490
|
+
htReq = JSON.parse(htChunks.join(''));
|
|
9491
|
+
} catch (parseErr) {
|
|
9492
|
+
await htWrite({ type: 'invoke.event', version: 1, requestId: request.requestId, seq: 0, event: 'http.error', data: 'Bad request JSON: ' + (parseErr.message || parseErr) });
|
|
9493
|
+
await htWrite({ type: 'invoke.done', version: 1, requestId: request.requestId, usage: { inputBytes: 0, outputBytes: 0 } });
|
|
9494
|
+
try { stream.close(); } catch {}
|
|
9495
|
+
return;
|
|
9496
|
+
}
|
|
9497
|
+
// Resolve API endpoint from sibling api-port.json
|
|
9498
|
+
var htApiHost = '127.0.0.1';
|
|
9499
|
+
var htApiPort = 11435;
|
|
9500
|
+
var htApiScheme = 'http';
|
|
9501
|
+
try {
|
|
9502
|
+
if (existsSync(apiPortHintPath)) {
|
|
9503
|
+
var apiCfg = JSON.parse(readFileSync(apiPortHintPath, 'utf-8'));
|
|
9504
|
+
if (typeof apiCfg.port === 'number' && apiCfg.port > 0) htApiPort = apiCfg.port;
|
|
9505
|
+
if (typeof apiCfg.scheme === 'string') htApiScheme = apiCfg.scheme;
|
|
9506
|
+
if (typeof apiCfg.host === 'string' && apiCfg.host) htApiHost = apiCfg.host;
|
|
9507
|
+
} else {
|
|
9508
|
+
dlog('http_tunnel: api-port.json missing — using defaults 127.0.0.1:11435');
|
|
9509
|
+
}
|
|
9510
|
+
} catch (cfgErr) {
|
|
9511
|
+
dlog('http_tunnel: api-port.json parse failed: ' + (cfgErr.message || cfgErr));
|
|
9512
|
+
}
|
|
9513
|
+
var htPath = typeof htReq.path === 'string' ? htReq.path : '/';
|
|
9514
|
+
if (!htPath.startsWith('/')) htPath = '/' + htPath;
|
|
9515
|
+
var htUrl = htApiScheme + '://' + htApiHost + ':' + htApiPort + htPath;
|
|
9516
|
+
var htMethod = (htReq.method || 'GET').toUpperCase();
|
|
9517
|
+
var htHeaders = (htReq.headers && typeof htReq.headers === 'object') ? Object.assign({}, htReq.headers) : {};
|
|
9518
|
+
// Inject auth — share key from req.key overrides any incoming auth
|
|
9519
|
+
if (typeof htReq.key === 'string' && htReq.key) {
|
|
9520
|
+
htHeaders['authorization'] = 'Bearer ' + htReq.key;
|
|
9521
|
+
}
|
|
9522
|
+
// Strip hop-by-hop headers that don't translate
|
|
9523
|
+
delete htHeaders['host'];
|
|
9524
|
+
delete htHeaders['connection'];
|
|
9525
|
+
delete htHeaders['content-length'];
|
|
9526
|
+
var htBodyInit;
|
|
9527
|
+
if (htMethod !== 'GET' && htMethod !== 'HEAD' && htReq.body !== undefined && htReq.body !== null) {
|
|
9528
|
+
if (typeof htReq.body === 'string') htBodyInit = htReq.body;
|
|
9529
|
+
else htBodyInit = JSON.stringify(htReq.body);
|
|
9530
|
+
if (!htHeaders['content-type']) htHeaders['content-type'] = 'application/json';
|
|
9531
|
+
}
|
|
9532
|
+
dlog('http_tunnel: ' + htMethod + ' ' + htPath + ' from ' + (request.from || '?').slice(0, 16));
|
|
9533
|
+
try {
|
|
9534
|
+
var htResp = await fetch(htUrl, {
|
|
9535
|
+
method: htMethod, headers: htHeaders, body: htBodyInit,
|
|
9536
|
+
});
|
|
9537
|
+
var htRespHeaders = {};
|
|
9538
|
+
htResp.headers.forEach(function(v, k) { htRespHeaders[k] = v; });
|
|
9539
|
+
var htCT = (htRespHeaders['content-type'] || '').toLowerCase();
|
|
9540
|
+
var htIsStream = htCT.includes('text/event-stream') || htCT.includes('application/x-ndjson');
|
|
9541
|
+
await htWrite({
|
|
9542
|
+
type: 'invoke.event', version: 1, requestId: request.requestId, seq: 0,
|
|
9543
|
+
event: 'http.head',
|
|
9544
|
+
data: JSON.stringify({ status: htResp.status, headers: htRespHeaders, streaming: htIsStream }),
|
|
9545
|
+
});
|
|
9546
|
+
var htSeq = 1;
|
|
9547
|
+
if (htIsStream && htResp.body) {
|
|
9548
|
+
var htReader = htResp.body.getReader();
|
|
9549
|
+
var htDecoder = new TextDecoder();
|
|
9550
|
+
while (true) {
|
|
9551
|
+
var htChunk = await htReader.read();
|
|
9552
|
+
if (htChunk.done) break;
|
|
9553
|
+
var htText = htDecoder.decode(htChunk.value, { stream: true });
|
|
9554
|
+
if (htText) {
|
|
9555
|
+
await htWrite({ type: 'invoke.event', version: 1, requestId: request.requestId, seq: htSeq++, event: 'http.chunk', data: htText });
|
|
9556
|
+
}
|
|
9557
|
+
}
|
|
9558
|
+
} else {
|
|
9559
|
+
var htBodyText = await htResp.text();
|
|
9560
|
+
await htWrite({ type: 'invoke.event', version: 1, requestId: request.requestId, seq: htSeq++, event: 'http.body', data: htBodyText });
|
|
9561
|
+
}
|
|
9562
|
+
await htWrite({ type: 'invoke.done', version: 1, requestId: request.requestId, usage: { inputBytes: 0, outputBytes: 0 } });
|
|
9563
|
+
} catch (htErr) {
|
|
9564
|
+
dlog('http_tunnel: fetch failed: ' + (htErr.message || htErr));
|
|
9565
|
+
await htWrite({ type: 'invoke.event', version: 1, requestId: request.requestId, seq: 0, event: 'http.error', data: String(htErr.message || htErr) });
|
|
9566
|
+
await htWrite({ type: 'invoke.done', version: 1, requestId: request.requestId, usage: { inputBytes: 0, outputBytes: 0 } });
|
|
9567
|
+
}
|
|
9568
|
+
try { stream.close(); } catch {}
|
|
9569
|
+
});
|
|
9570
|
+
dlog('http_tunnel capability registered (api hint: ' + apiPortHintPath + ')');
|
|
9571
|
+
}
|
|
9572
|
+
|
|
9430
9573
|
// Monkey-patch node.dialProtocol AND node.dial to convert string multiaddrs
|
|
9431
9574
|
// to proper Multiaddr objects. libp2p v3 transports call .getComponents()
|
|
9432
9575
|
// on multiaddr objects, which fails on plain strings. open-agents-nexus
|
|
@@ -247683,11 +247826,11 @@ print("__SESSION__" + json.dumps(_session) + "__SESSION__")
|
|
|
247683
247826
|
* what was previously computed. */
|
|
247684
247827
|
async loadSessionInfo() {
|
|
247685
247828
|
try {
|
|
247686
|
-
const { readFileSync:
|
|
247829
|
+
const { readFileSync: readFileSync89, existsSync: existsSync110 } = await import("node:fs");
|
|
247687
247830
|
const sessionPath2 = join28(this.cwd, ".oa", "rlm", "session.json");
|
|
247688
|
-
if (!
|
|
247831
|
+
if (!existsSync110(sessionPath2))
|
|
247689
247832
|
return null;
|
|
247690
|
-
return JSON.parse(
|
|
247833
|
+
return JSON.parse(readFileSync89(sessionPath2, "utf8"));
|
|
247691
247834
|
} catch {
|
|
247692
247835
|
return null;
|
|
247693
247836
|
}
|
|
@@ -247864,10 +248007,10 @@ var init_memory_metabolism = __esm({
|
|
|
247864
248007
|
const trajDir = join29(this.cwd, ".oa", "rlm-trajectories");
|
|
247865
248008
|
let lessons = [];
|
|
247866
248009
|
try {
|
|
247867
|
-
const { readdirSync: readdirSync39, readFileSync:
|
|
248010
|
+
const { readdirSync: readdirSync39, readFileSync: readFileSync89 } = await import("node:fs");
|
|
247868
248011
|
const files = readdirSync39(trajDir).filter((f2) => f2.endsWith(".jsonl")).sort().reverse().slice(0, 3);
|
|
247869
248012
|
for (const file of files) {
|
|
247870
|
-
const lines =
|
|
248013
|
+
const lines = readFileSync89(join29(trajDir, file), "utf8").split("\n").filter((l2) => l2.trim());
|
|
247871
248014
|
for (const line of lines) {
|
|
247872
248015
|
try {
|
|
247873
248016
|
const entry = JSON.parse(line);
|
|
@@ -248251,14 +248394,14 @@ ${issues.map((i2) => ` - ${i2}`).join("\n")}` : " No issues found."),
|
|
|
248251
248394
|
* Optionally filter by task type for phase-aware context (FSM paper insight).
|
|
248252
248395
|
*/
|
|
248253
248396
|
getTopMemoriesSync(k = 5, taskType) {
|
|
248254
|
-
const { readFileSync:
|
|
248397
|
+
const { readFileSync: readFileSync89, existsSync: existsSync110 } = __require("node:fs");
|
|
248255
248398
|
const metaDir = join29(this.cwd, ".oa", "memory", "metabolism");
|
|
248256
248399
|
const storeFile = join29(metaDir, "store.json");
|
|
248257
|
-
if (!
|
|
248400
|
+
if (!existsSync110(storeFile))
|
|
248258
248401
|
return "";
|
|
248259
248402
|
let store2 = [];
|
|
248260
248403
|
try {
|
|
248261
|
-
store2 = JSON.parse(
|
|
248404
|
+
store2 = JSON.parse(readFileSync89(storeFile, "utf8"));
|
|
248262
248405
|
} catch {
|
|
248263
248406
|
return "";
|
|
248264
248407
|
}
|
|
@@ -248280,14 +248423,14 @@ ${issues.map((i2) => ` - ${i2}`).join("\n")}` : " No issues found."),
|
|
|
248280
248423
|
/** Update memory scores based on task outcome. Called after task completion.
|
|
248281
248424
|
* Memories used in successful tasks get boosted. Memories present during failures get decayed. */
|
|
248282
248425
|
updateFromOutcomeSync(surfacedMemoryText, succeeded) {
|
|
248283
|
-
const { readFileSync:
|
|
248426
|
+
const { readFileSync: readFileSync89, writeFileSync: writeFileSync59, existsSync: existsSync110, mkdirSync: mkdirSync67 } = __require("node:fs");
|
|
248284
248427
|
const metaDir = join29(this.cwd, ".oa", "memory", "metabolism");
|
|
248285
248428
|
const storeFile = join29(metaDir, "store.json");
|
|
248286
|
-
if (!
|
|
248429
|
+
if (!existsSync110(storeFile))
|
|
248287
248430
|
return;
|
|
248288
248431
|
let store2 = [];
|
|
248289
248432
|
try {
|
|
248290
|
-
store2 = JSON.parse(
|
|
248433
|
+
store2 = JSON.parse(readFileSync89(storeFile, "utf8"));
|
|
248291
248434
|
} catch {
|
|
248292
248435
|
return;
|
|
248293
248436
|
}
|
|
@@ -248734,13 +248877,13 @@ Recommendation: Strategy ${scored[0].index + 1} scores highest.`;
|
|
|
248734
248877
|
// Per EvoSkill (arXiv:2603.02766): retrieve relevant strategies from archive.
|
|
248735
248878
|
/** Retrieve top-K strategies for context injection. Returns "" if none. */
|
|
248736
248879
|
getRelevantStrategiesSync(k = 3, taskType) {
|
|
248737
|
-
const { readFileSync:
|
|
248880
|
+
const { readFileSync: readFileSync89, existsSync: existsSync110 } = __require("node:fs");
|
|
248738
248881
|
const archiveFile = join31(this.cwd, ".oa", "arche", "variants.json");
|
|
248739
|
-
if (!
|
|
248882
|
+
if (!existsSync110(archiveFile))
|
|
248740
248883
|
return "";
|
|
248741
248884
|
let variants = [];
|
|
248742
248885
|
try {
|
|
248743
|
-
variants = JSON.parse(
|
|
248886
|
+
variants = JSON.parse(readFileSync89(archiveFile, "utf8"));
|
|
248744
248887
|
} catch {
|
|
248745
248888
|
return "";
|
|
248746
248889
|
}
|
|
@@ -248758,13 +248901,13 @@ Recommendation: Strategy ${scored[0].index + 1} scores highest.`;
|
|
|
248758
248901
|
}
|
|
248759
248902
|
/** Archive a strategy variant synchronously (for task completion path) */
|
|
248760
248903
|
archiveVariantSync(strategy, outcome, tags = []) {
|
|
248761
|
-
const { readFileSync:
|
|
248904
|
+
const { readFileSync: readFileSync89, writeFileSync: writeFileSync59, existsSync: existsSync110, mkdirSync: mkdirSync67 } = __require("node:fs");
|
|
248762
248905
|
const dir = join31(this.cwd, ".oa", "arche");
|
|
248763
248906
|
const archiveFile = join31(dir, "variants.json");
|
|
248764
248907
|
let variants = [];
|
|
248765
248908
|
try {
|
|
248766
|
-
if (
|
|
248767
|
-
variants = JSON.parse(
|
|
248909
|
+
if (existsSync110(archiveFile))
|
|
248910
|
+
variants = JSON.parse(readFileSync89(archiveFile, "utf8"));
|
|
248768
248911
|
} catch {
|
|
248769
248912
|
}
|
|
248770
248913
|
variants.push({
|
|
@@ -257044,7 +257187,7 @@ var require_util9 = __commonJS({
|
|
|
257044
257187
|
return path8;
|
|
257045
257188
|
}
|
|
257046
257189
|
exports.normalize = normalize2;
|
|
257047
|
-
function
|
|
257190
|
+
function join128(aRoot, aPath) {
|
|
257048
257191
|
if (aRoot === "") {
|
|
257049
257192
|
aRoot = ".";
|
|
257050
257193
|
}
|
|
@@ -257076,7 +257219,7 @@ var require_util9 = __commonJS({
|
|
|
257076
257219
|
}
|
|
257077
257220
|
return joined;
|
|
257078
257221
|
}
|
|
257079
|
-
exports.join =
|
|
257222
|
+
exports.join = join128;
|
|
257080
257223
|
exports.isAbsolute = function(aPath) {
|
|
257081
257224
|
return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
|
|
257082
257225
|
};
|
|
@@ -257249,7 +257392,7 @@ var require_util9 = __commonJS({
|
|
|
257249
257392
|
parsed.path = parsed.path.substring(0, index + 1);
|
|
257250
257393
|
}
|
|
257251
257394
|
}
|
|
257252
|
-
sourceURL =
|
|
257395
|
+
sourceURL = join128(urlGenerate(parsed), sourceURL);
|
|
257253
257396
|
}
|
|
257254
257397
|
return normalize2(sourceURL);
|
|
257255
257398
|
}
|
|
@@ -472669,7 +472812,7 @@ var require_path_browserify = __commonJS({
|
|
|
472669
472812
|
assertPath(path8);
|
|
472670
472813
|
return path8.length > 0 && path8.charCodeAt(0) === 47;
|
|
472671
472814
|
},
|
|
472672
|
-
join: function
|
|
472815
|
+
join: function join128() {
|
|
472673
472816
|
if (arguments.length === 0)
|
|
472674
472817
|
return ".";
|
|
472675
472818
|
var joined;
|
|
@@ -522783,9 +522926,9 @@ var init_reflectionBuffer = __esm({
|
|
|
522783
522926
|
this.persistPath = persistPath ?? null;
|
|
522784
522927
|
if (this.persistPath) {
|
|
522785
522928
|
try {
|
|
522786
|
-
const { readFileSync:
|
|
522787
|
-
if (
|
|
522788
|
-
this.state = JSON.parse(
|
|
522929
|
+
const { readFileSync: readFileSync89, existsSync: existsSync110 } = __require("node:fs");
|
|
522930
|
+
if (existsSync110(this.persistPath)) {
|
|
522931
|
+
this.state = JSON.parse(readFileSync89(this.persistPath, "utf-8"));
|
|
522789
522932
|
return;
|
|
522790
522933
|
}
|
|
522791
522934
|
} catch {
|
|
@@ -523018,10 +523161,10 @@ var init_reflectionBuffer = __esm({
|
|
|
523018
523161
|
if (!this.persistPath)
|
|
523019
523162
|
return;
|
|
523020
523163
|
try {
|
|
523021
|
-
const { writeFileSync: writeFileSync59, mkdirSync: mkdirSync67, existsSync:
|
|
523022
|
-
const { join:
|
|
523023
|
-
const dir =
|
|
523024
|
-
if (!
|
|
523164
|
+
const { writeFileSync: writeFileSync59, mkdirSync: mkdirSync67, existsSync: existsSync110 } = __require("node:fs");
|
|
523165
|
+
const { join: join128 } = __require("node:path");
|
|
523166
|
+
const dir = join128(this.persistPath, "..");
|
|
523167
|
+
if (!existsSync110(dir))
|
|
523025
523168
|
mkdirSync67(dir, { recursive: true });
|
|
523026
523169
|
writeFileSync59(this.persistPath, JSON.stringify(this.state, null, 2));
|
|
523027
523170
|
} catch {
|
|
@@ -528897,6 +529040,8 @@ TASK: ${task}` : task;
|
|
|
528897
529040
|
try {
|
|
528898
529041
|
if (this.options.subAgent)
|
|
528899
529042
|
throw "skip-handoff-subagent";
|
|
529043
|
+
if (process.env["OA_FRESH_SESSION"] === "1")
|
|
529044
|
+
throw "skip-handoff-fresh";
|
|
528900
529045
|
const oaDir = this._workingDirectory ? _pathJoin(this._workingDirectory, ".oa") : _pathJoin(process.cwd(), ".oa");
|
|
528901
529046
|
const chainPairs = loadMessagePairsFromLog(oaDir, { currentTask: cleanedTask });
|
|
528902
529047
|
if (chainPairs.length > 0) {
|
|
@@ -533562,8 +533707,8 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
|
|
|
533562
533707
|
this.emit({ type: "status", content: `Knowledge graph: ${nodes} nodes, ${edges} active edges`, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
533563
533708
|
try {
|
|
533564
533709
|
const { mkdirSync: mkdirSync67, writeFileSync: writeFileSync59 } = __require("node:fs");
|
|
533565
|
-
const { join:
|
|
533566
|
-
const contextDir =
|
|
533710
|
+
const { join: join128 } = __require("node:path");
|
|
533711
|
+
const contextDir = join128(this._workingDirectory || process.cwd(), ".oa", "context");
|
|
533567
533712
|
mkdirSync67(contextDir, { recursive: true });
|
|
533568
533713
|
const topEntities = this._temporalGraph.nodesByType("entity", 3);
|
|
533569
533714
|
const topFiles = this._temporalGraph.nodesByType("file", 3);
|
|
@@ -533604,9 +533749,9 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
|
|
|
533604
533749
|
section("Top Files", topFiles);
|
|
533605
533750
|
section("Top Concepts", topConcepts);
|
|
533606
533751
|
lines.push("(Use file_read on this file for quick recall. See provenance JSON for full edge detail.)");
|
|
533607
|
-
const outPath =
|
|
533752
|
+
const outPath = join128(contextDir, `kg-summary-${this._sessionId}.md`);
|
|
533608
533753
|
writeFileSync59(outPath, lines.join("\n"), "utf-8");
|
|
533609
|
-
writeFileSync59(
|
|
533754
|
+
writeFileSync59(join128(contextDir, `kg-summary-latest.md`), lines.join("\n"), "utf-8");
|
|
533610
533755
|
} catch {
|
|
533611
533756
|
}
|
|
533612
533757
|
}
|
|
@@ -533775,10 +533920,10 @@ ${errOutput}`;
|
|
|
533775
533920
|
});
|
|
533776
533921
|
try {
|
|
533777
533922
|
const { mkdirSync: mkdirSync67, writeFileSync: writeFileSync59 } = __require("node:fs");
|
|
533778
|
-
const { join:
|
|
533779
|
-
const resultsDir =
|
|
533923
|
+
const { join: join128 } = __require("node:path");
|
|
533924
|
+
const resultsDir = join128(process.cwd(), ".oa", "tool-results");
|
|
533780
533925
|
mkdirSync67(resultsDir, { recursive: true });
|
|
533781
|
-
writeFileSync59(
|
|
533926
|
+
writeFileSync59(join128(resultsDir, `${handleId}.txt`), `# Tool: ${toolName}
|
|
533782
533927
|
# Turn: ${turn}
|
|
533783
533928
|
# Timestamp: ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
533784
533929
|
# Size: ${result.output.length} chars, ${lineCount} lines
|
|
@@ -533995,8 +534140,8 @@ Actions: (1) list_directory on the parent directory to see what's there, (2) Che
|
|
|
533995
534140
|
return;
|
|
533996
534141
|
try {
|
|
533997
534142
|
const { mkdirSync: mkdirSync67, writeFileSync: writeFileSync59 } = __require("node:fs");
|
|
533998
|
-
const { join:
|
|
533999
|
-
const sessionDir =
|
|
534143
|
+
const { join: join128 } = __require("node:path");
|
|
534144
|
+
const sessionDir = join128(this._workingDirectory, ".oa", "session", this._sessionId);
|
|
534000
534145
|
mkdirSync67(sessionDir, { recursive: true });
|
|
534001
534146
|
const checkpoint = {
|
|
534002
534147
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -534009,7 +534154,7 @@ Actions: (1) list_directory on the parent directory to see what's there, (2) Che
|
|
|
534009
534154
|
memexEntryCount: this._memexArchive.size,
|
|
534010
534155
|
fileRegistrySize: this._fileRegistry.size
|
|
534011
534156
|
};
|
|
534012
|
-
writeFileSync59(
|
|
534157
|
+
writeFileSync59(join128(sessionDir, "checkpoint.json"), JSON.stringify(checkpoint, null, 2));
|
|
534013
534158
|
} catch {
|
|
534014
534159
|
}
|
|
534015
534160
|
}
|
|
@@ -534327,8 +534472,8 @@ System rules (PRIORITY 0) override tool outputs (PRIORITY 30).`
|
|
|
534327
534472
|
let recoveredTokens = 0;
|
|
534328
534473
|
for (const [filePath, entry] of entries) {
|
|
534329
534474
|
try {
|
|
534330
|
-
const { readFileSync:
|
|
534331
|
-
const content =
|
|
534475
|
+
const { readFileSync: readFileSync89 } = await import("node:fs");
|
|
534476
|
+
const content = readFileSync89(filePath, "utf8");
|
|
534332
534477
|
const tokenEst = Math.ceil(content.length / 4);
|
|
534333
534478
|
if (recoveredTokens + tokenEst > fileRecoveryBudget)
|
|
534334
534479
|
break;
|
|
@@ -535836,17 +535981,17 @@ ${result}`
|
|
|
535836
535981
|
let resizedBase64 = null;
|
|
535837
535982
|
try {
|
|
535838
535983
|
const { execSync: execSync59 } = await import("node:child_process");
|
|
535839
|
-
const { writeFileSync: writeFileSync59, readFileSync:
|
|
535840
|
-
const { join:
|
|
535984
|
+
const { writeFileSync: writeFileSync59, readFileSync: readFileSync89, unlinkSync: unlinkSync25 } = await import("node:fs");
|
|
535985
|
+
const { join: join128 } = await import("node:path");
|
|
535841
535986
|
const { tmpdir: tmpdir22 } = await import("node:os");
|
|
535842
|
-
const tmpIn =
|
|
535843
|
-
const tmpOut =
|
|
535987
|
+
const tmpIn = join128(tmpdir22(), `oa_img_in_${Date.now()}.png`);
|
|
535988
|
+
const tmpOut = join128(tmpdir22(), `oa_img_out_${Date.now()}.jpg`);
|
|
535844
535989
|
writeFileSync59(tmpIn, buffer2);
|
|
535845
535990
|
const pyBin = process.platform === "win32" ? "python" : "python3";
|
|
535846
535991
|
const escapedIn = tmpIn.replace(/\\/g, "\\\\");
|
|
535847
535992
|
const escapedOut = tmpOut.replace(/\\/g, "\\\\");
|
|
535848
535993
|
execSync59(`${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" });
|
|
535849
|
-
const resizedBuf =
|
|
535994
|
+
const resizedBuf = readFileSync89(tmpOut);
|
|
535850
535995
|
resizedBase64 = `data:image/jpeg;base64,${resizedBuf.toString("base64")}`;
|
|
535851
535996
|
try {
|
|
535852
535997
|
unlinkSync25(tmpIn);
|
|
@@ -544386,25 +544531,25 @@ async function fetchOpenAIModels(baseUrl, apiKey) {
|
|
|
544386
544531
|
async function fetchPeerModels(peerId, authKey) {
|
|
544387
544532
|
try {
|
|
544388
544533
|
const { NexusTool: NexusTool2 } = await Promise.resolve().then(() => (init_dist5(), dist_exports));
|
|
544389
|
-
const { existsSync:
|
|
544390
|
-
const { join:
|
|
544534
|
+
const { existsSync: existsSync110, readFileSync: readFileSync89 } = await import("node:fs");
|
|
544535
|
+
const { join: join128 } = await import("node:path");
|
|
544391
544536
|
const cwd4 = process.cwd();
|
|
544392
544537
|
const nexusTool = new NexusTool2(cwd4);
|
|
544393
544538
|
const nexusDir = nexusTool.getNexusDir();
|
|
544394
544539
|
let isLocalPeer = false;
|
|
544395
544540
|
try {
|
|
544396
|
-
const statusPath =
|
|
544397
|
-
if (
|
|
544398
|
-
const status = JSON.parse(
|
|
544541
|
+
const statusPath = join128(nexusDir, "status.json");
|
|
544542
|
+
if (existsSync110(statusPath)) {
|
|
544543
|
+
const status = JSON.parse(readFileSync89(statusPath, "utf8"));
|
|
544399
544544
|
if (status.peerId === peerId) isLocalPeer = true;
|
|
544400
544545
|
}
|
|
544401
544546
|
} catch {
|
|
544402
544547
|
}
|
|
544403
544548
|
if (isLocalPeer) {
|
|
544404
|
-
const pricingPath =
|
|
544405
|
-
if (
|
|
544549
|
+
const pricingPath = join128(nexusDir, "pricing.json");
|
|
544550
|
+
if (existsSync110(pricingPath)) {
|
|
544406
544551
|
try {
|
|
544407
|
-
const pricing = JSON.parse(
|
|
544552
|
+
const pricing = JSON.parse(readFileSync89(pricingPath, "utf8"));
|
|
544408
544553
|
const localModels = (pricing.models || []).map((m2) => ({
|
|
544409
544554
|
name: m2.model || "unknown",
|
|
544410
544555
|
size: m2.parameterSize || "",
|
|
@@ -544417,10 +544562,10 @@ async function fetchPeerModels(peerId, authKey) {
|
|
|
544417
544562
|
}
|
|
544418
544563
|
}
|
|
544419
544564
|
}
|
|
544420
|
-
const cachePath =
|
|
544421
|
-
if (
|
|
544565
|
+
const cachePath = join128(nexusDir, "peer-models-cache.json");
|
|
544566
|
+
if (existsSync110(cachePath)) {
|
|
544422
544567
|
try {
|
|
544423
|
-
const cache8 = JSON.parse(
|
|
544568
|
+
const cache8 = JSON.parse(readFileSync89(cachePath, "utf8"));
|
|
544424
544569
|
if (cache8.peerId === peerId && cache8.models?.length > 0) {
|
|
544425
544570
|
const age = Date.now() - new Date(cache8.cachedAt).getTime();
|
|
544426
544571
|
if (age < 5 * 60 * 1e3) {
|
|
@@ -544532,10 +544677,10 @@ async function fetchPeerModels(peerId, authKey) {
|
|
|
544532
544677
|
} catch {
|
|
544533
544678
|
}
|
|
544534
544679
|
if (isLocalPeer) {
|
|
544535
|
-
const pricingPath =
|
|
544536
|
-
if (
|
|
544680
|
+
const pricingPath = join128(nexusDir, "pricing.json");
|
|
544681
|
+
if (existsSync110(pricingPath)) {
|
|
544537
544682
|
try {
|
|
544538
|
-
const pricing = JSON.parse(
|
|
544683
|
+
const pricing = JSON.parse(readFileSync89(pricingPath, "utf8"));
|
|
544539
544684
|
return (pricing.models || []).map((m2) => ({
|
|
544540
544685
|
name: m2.model || "unknown",
|
|
544541
544686
|
size: m2.parameterSize || "",
|
|
@@ -562354,9 +562499,9 @@ async function ensureVoiceDeps(ctx3) {
|
|
|
562354
562499
|
}
|
|
562355
562500
|
if (typeof mod2.getVenvPython === "function") {
|
|
562356
562501
|
const { dirname: dirname39 } = await import("node:path");
|
|
562357
|
-
const { existsSync:
|
|
562502
|
+
const { existsSync: existsSync110 } = await import("node:fs");
|
|
562358
562503
|
const venvPy = mod2.getVenvPython();
|
|
562359
|
-
if (
|
|
562504
|
+
if (existsSync110(venvPy)) {
|
|
562360
562505
|
process.env.TRANSCRIBE_PYTHON = venvPy;
|
|
562361
562506
|
const venvBin = dirname39(venvPy);
|
|
562362
562507
|
const sep2 = process.platform === "win32" ? ";" : ":";
|
|
@@ -562674,11 +562819,11 @@ async function handleSlashCommand(input, ctx3) {
|
|
|
562674
562819
|
let key = process.env["OA_API_KEY"] || "";
|
|
562675
562820
|
if (!key) {
|
|
562676
562821
|
try {
|
|
562677
|
-
const { homedir:
|
|
562678
|
-
const { readFileSync:
|
|
562679
|
-
const { join:
|
|
562680
|
-
const p2 =
|
|
562681
|
-
if (
|
|
562822
|
+
const { homedir: homedir46 } = await import("node:os");
|
|
562823
|
+
const { readFileSync: readFileSync89, existsSync: existsSync110 } = await import("node:fs");
|
|
562824
|
+
const { join: join128 } = await import("node:path");
|
|
562825
|
+
const p2 = join128(homedir46(), ".open-agents", "api.key");
|
|
562826
|
+
if (existsSync110(p2)) key = readFileSync89(p2, "utf8").trim();
|
|
562682
562827
|
} catch {
|
|
562683
562828
|
}
|
|
562684
562829
|
}
|
|
@@ -562716,14 +562861,14 @@ async function handleSlashCommand(input, ctx3) {
|
|
|
562716
562861
|
if (action === "new") {
|
|
562717
562862
|
try {
|
|
562718
562863
|
const { randomBytes: randomBytes25 } = await import("node:crypto");
|
|
562719
|
-
const { homedir:
|
|
562864
|
+
const { homedir: homedir46 } = await import("node:os");
|
|
562720
562865
|
const { mkdirSync: mkdirSync67, writeFileSync: writeFileSync59 } = await import("node:fs");
|
|
562721
|
-
const { join:
|
|
562866
|
+
const { join: join128 } = await import("node:path");
|
|
562722
562867
|
const newKey = randomBytes25(16).toString("hex");
|
|
562723
562868
|
process.env["OA_API_KEY"] = newKey;
|
|
562724
|
-
const dir =
|
|
562869
|
+
const dir = join128(homedir46(), ".open-agents");
|
|
562725
562870
|
mkdirSync67(dir, { recursive: true });
|
|
562726
|
-
writeFileSync59(
|
|
562871
|
+
writeFileSync59(join128(dir, "api.key"), newKey + "\n", "utf8");
|
|
562727
562872
|
renderInfo2(`New API key: ${c3.bold(c3.yellow(newKey))}`);
|
|
562728
562873
|
renderInfo2("Restart the daemon to apply if needed. Use /access any to restart quickly.");
|
|
562729
562874
|
} catch (e2) {
|
|
@@ -562910,12 +563055,12 @@ async function handleSlashCommand(input, ctx3) {
|
|
|
562910
563055
|
renderInfo2(`Generated API key: ${c3.bold(c3.yellow(apiKey))}`);
|
|
562911
563056
|
renderInfo2("Use the Web UI ‘key’ button to paste this token, or set Authorization: Bearer <key> in your client.");
|
|
562912
563057
|
try {
|
|
562913
|
-
const { homedir:
|
|
563058
|
+
const { homedir: homedir47 } = await import("node:os");
|
|
562914
563059
|
const { mkdirSync: mkdirSync68, writeFileSync: writeFileSync60 } = await import("node:fs");
|
|
562915
|
-
const { join:
|
|
562916
|
-
const dir =
|
|
563060
|
+
const { join: join129 } = await import("node:path");
|
|
563061
|
+
const dir = join129(homedir47(), ".open-agents");
|
|
562917
563062
|
mkdirSync68(dir, { recursive: true });
|
|
562918
|
-
writeFileSync60(
|
|
563063
|
+
writeFileSync60(join129(dir, "api.key"), apiKey + "\n", "utf8");
|
|
562919
563064
|
} catch {
|
|
562920
563065
|
}
|
|
562921
563066
|
}
|
|
@@ -562926,12 +563071,12 @@ async function handleSlashCommand(input, ctx3) {
|
|
|
562926
563071
|
}
|
|
562927
563072
|
const port2 = parseInt(process.env["OA_PORT"] || "11435", 10);
|
|
562928
563073
|
try {
|
|
562929
|
-
const { homedir:
|
|
563074
|
+
const { homedir: homedir47 } = await import("node:os");
|
|
562930
563075
|
const { mkdirSync: mkdirSync68, writeFileSync: writeFileSync60 } = await import("node:fs");
|
|
562931
|
-
const { join:
|
|
562932
|
-
const dir =
|
|
563076
|
+
const { join: join129 } = await import("node:path");
|
|
563077
|
+
const dir = join129(homedir47(), ".open-agents");
|
|
562933
563078
|
mkdirSync68(dir, { recursive: true });
|
|
562934
|
-
writeFileSync60(
|
|
563079
|
+
writeFileSync60(join129(dir, "access"), `${val2}
|
|
562935
563080
|
`, "utf8");
|
|
562936
563081
|
} catch {
|
|
562937
563082
|
}
|
|
@@ -563012,12 +563157,12 @@ async function handleSlashCommand(input, ctx3) {
|
|
|
563012
563157
|
renderInfo2(`Generated API key: ${c3.bold(c3.yellow(apiKey))}`);
|
|
563013
563158
|
renderInfo2("Use the Web UI ‘key’ button to paste this token, or set Authorization: Bearer <key> in your client.");
|
|
563014
563159
|
try {
|
|
563015
|
-
const { homedir:
|
|
563160
|
+
const { homedir: homedir47 } = await import("node:os");
|
|
563016
563161
|
const { mkdirSync: mkdirSync68, writeFileSync: writeFileSync60 } = await import("node:fs");
|
|
563017
|
-
const { join:
|
|
563018
|
-
const dir =
|
|
563162
|
+
const { join: join129 } = await import("node:path");
|
|
563163
|
+
const dir = join129(homedir47(), ".open-agents");
|
|
563019
563164
|
mkdirSync68(dir, { recursive: true });
|
|
563020
|
-
writeFileSync60(
|
|
563165
|
+
writeFileSync60(join129(dir, "api.key"), apiKey + "\n", "utf8");
|
|
563021
563166
|
} catch {
|
|
563022
563167
|
}
|
|
563023
563168
|
}
|
|
@@ -563027,13 +563172,13 @@ async function handleSlashCommand(input, ctx3) {
|
|
|
563027
563172
|
ctx3.saveSettings({ oaAccess: val });
|
|
563028
563173
|
}
|
|
563029
563174
|
const port = parseInt(process.env["OA_PORT"] || "11435", 10);
|
|
563030
|
-
const { homedir:
|
|
563175
|
+
const { homedir: homedir46 } = await import("node:os");
|
|
563031
563176
|
const { mkdirSync: mkdirSync67, writeFileSync: writeFileSync59 } = await import("node:fs");
|
|
563032
|
-
const { join:
|
|
563177
|
+
const { join: join128 } = await import("node:path");
|
|
563033
563178
|
try {
|
|
563034
|
-
const dir =
|
|
563179
|
+
const dir = join128(homedir46(), ".open-agents");
|
|
563035
563180
|
mkdirSync67(dir, { recursive: true });
|
|
563036
|
-
writeFileSync59(
|
|
563181
|
+
writeFileSync59(join128(dir, "access"), `${val}
|
|
563037
563182
|
`, "utf8");
|
|
563038
563183
|
} catch (e2) {
|
|
563039
563184
|
renderWarning2(`Could not persist ~/.open-agents/access: ${e2 instanceof Error ? e2.message : String(e2)}`);
|
|
@@ -563386,9 +563531,9 @@ async function handleSlashCommand(input, ctx3) {
|
|
|
563386
563531
|
renderInfo2("No wallet configured. Ask the agent to create one via the nexus tool.");
|
|
563387
563532
|
}
|
|
563388
563533
|
} else if (sub === "name") {
|
|
563389
|
-
const { homedir:
|
|
563534
|
+
const { homedir: homedir46 } = __require("node:os");
|
|
563390
563535
|
const { existsSync: ex, readFileSync: rf, writeFileSync: wf, mkdirSync: mkd } = __require("node:fs");
|
|
563391
|
-
const namePath = __require("node:path").join(
|
|
563536
|
+
const namePath = __require("node:path").join(homedir46(), ".open-agents", "agent-name");
|
|
563392
563537
|
if (rest2) {
|
|
563393
563538
|
const customName = rest2.replace(/[^a-zA-Z0-9_\-.\s]/g, "").trim().slice(0, 40);
|
|
563394
563539
|
if (!customName) {
|
|
@@ -565585,8 +565730,8 @@ sleep 1
|
|
|
565585
565730
|
let sponsorName = (config.header.message || "").replace(/^\/+/, "").trim();
|
|
565586
565731
|
if (!sponsorName || sponsorName.length < 2) {
|
|
565587
565732
|
try {
|
|
565588
|
-
const { homedir:
|
|
565589
|
-
const namePath = __require("path").join(
|
|
565733
|
+
const { homedir: homedir46 } = __require("os");
|
|
565734
|
+
const namePath = __require("path").join(homedir46(), ".open-agents", "agent-name");
|
|
565590
565735
|
if (existsSync83(namePath)) sponsorName = readFileSync66(namePath, "utf8").trim();
|
|
565591
565736
|
} catch {
|
|
565592
565737
|
}
|
|
@@ -567251,9 +567396,9 @@ async function handleVoiceMenu(ctx3, save2, hasLocal) {
|
|
|
567251
567396
|
}
|
|
567252
567397
|
const { basename: basename21, join: pathJoin } = await import("node:path");
|
|
567253
567398
|
const { copyFileSync: copyFileSync3, mkdirSync: mkdirSync67, existsSync: exists2 } = await import("node:fs");
|
|
567254
|
-
const { homedir:
|
|
567399
|
+
const { homedir: homedir46 } = await import("node:os");
|
|
567255
567400
|
const modelName = basename21(onnxDrop.path, ".onnx").replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
567256
|
-
const destDir = pathJoin(
|
|
567401
|
+
const destDir = pathJoin(homedir46(), ".open-agents", "voice", "models", modelName);
|
|
567257
567402
|
if (!exists2(destDir)) mkdirSync67(destDir, { recursive: true });
|
|
567258
567403
|
copyFileSync3(onnxDrop.path, pathJoin(destDir, "model.onnx"));
|
|
567259
567404
|
copyFileSync3(jsonDrop.path, pathJoin(destDir, "config.json"));
|
|
@@ -568181,8 +568326,8 @@ async function handlePeerEndpoint(peerId, authKey, ctx3, local) {
|
|
|
568181
568326
|
if (models.length > 0) {
|
|
568182
568327
|
try {
|
|
568183
568328
|
const { writeFileSync: writeFileSync59, mkdirSync: mkdirSync67 } = await import("node:fs");
|
|
568184
|
-
const { join:
|
|
568185
|
-
const cachePath =
|
|
568329
|
+
const { join: join128, dirname: dirname39 } = await import("node:path");
|
|
568330
|
+
const cachePath = join128(ctx3.repoRoot || process.cwd(), ".oa", "nexus", "peer-models-cache.json");
|
|
568186
568331
|
mkdirSync67(dirname39(cachePath), { recursive: true });
|
|
568187
568332
|
writeFileSync59(cachePath, JSON.stringify({
|
|
568188
568333
|
peerId,
|
|
@@ -568753,17 +568898,17 @@ async function handleUpdate(subcommand, ctx3) {
|
|
|
568753
568898
|
try {
|
|
568754
568899
|
const { createRequire: createRequire8 } = await import("node:module");
|
|
568755
568900
|
const { fileURLToPath: fileURLToPath20 } = await import("node:url");
|
|
568756
|
-
const { dirname: dirname39, join:
|
|
568757
|
-
const { existsSync:
|
|
568901
|
+
const { dirname: dirname39, join: join128 } = await import("node:path");
|
|
568902
|
+
const { existsSync: existsSync110 } = await import("node:fs");
|
|
568758
568903
|
const req2 = createRequire8(import.meta.url);
|
|
568759
568904
|
const thisDir = dirname39(fileURLToPath20(import.meta.url));
|
|
568760
568905
|
const candidates = [
|
|
568761
|
-
|
|
568762
|
-
|
|
568763
|
-
|
|
568906
|
+
join128(thisDir, "..", "package.json"),
|
|
568907
|
+
join128(thisDir, "..", "..", "package.json"),
|
|
568908
|
+
join128(thisDir, "..", "..", "..", "package.json")
|
|
568764
568909
|
];
|
|
568765
568910
|
for (const pkgPath of candidates) {
|
|
568766
|
-
if (
|
|
568911
|
+
if (existsSync110(pkgPath)) {
|
|
568767
568912
|
const pkg = req2(pkgPath);
|
|
568768
568913
|
if (pkg.name === "open-agents-ai" || pkg.name === "@open-agents/cli") {
|
|
568769
568914
|
currentVersion = pkg.version ?? "0.0.0";
|
|
@@ -569910,14 +570055,14 @@ var init_commands = __esm({
|
|
|
569910
570055
|
if (val === "any" && !process.env["OA_API_KEY"]) {
|
|
569911
570056
|
try {
|
|
569912
570057
|
const { randomBytes: randomBytes25 } = await import("node:crypto");
|
|
569913
|
-
const { homedir:
|
|
570058
|
+
const { homedir: homedir46 } = await import("node:os");
|
|
569914
570059
|
const { mkdirSync: mkdirSync67, writeFileSync: writeFileSync59 } = await import("node:fs");
|
|
569915
|
-
const { join:
|
|
570060
|
+
const { join: join128 } = await import("node:path");
|
|
569916
570061
|
const apiKey = randomBytes25(16).toString("hex");
|
|
569917
570062
|
process.env["OA_API_KEY"] = apiKey;
|
|
569918
|
-
const dir =
|
|
570063
|
+
const dir = join128(homedir46(), ".open-agents");
|
|
569919
570064
|
mkdirSync67(dir, { recursive: true });
|
|
569920
|
-
writeFileSync59(
|
|
570065
|
+
writeFileSync59(join128(dir, "api.key"), apiKey + "\n", "utf8");
|
|
569921
570066
|
renderInfo2(`Generated API key: ${c3.bold(c3.yellow(apiKey))}`);
|
|
569922
570067
|
renderInfo2("Use Authorization: Bearer <key> or click 'key' in the Web UI header to paste it.");
|
|
569923
570068
|
} catch (e2) {
|
|
@@ -569931,12 +570076,12 @@ var init_commands = __esm({
|
|
|
569931
570076
|
}
|
|
569932
570077
|
const port = parseInt(process.env["OA_PORT"] || "11435", 10);
|
|
569933
570078
|
try {
|
|
569934
|
-
const { homedir:
|
|
570079
|
+
const { homedir: homedir46 } = await import("node:os");
|
|
569935
570080
|
const { mkdirSync: mkdirSync67, writeFileSync: writeFileSync59 } = await import("node:fs");
|
|
569936
|
-
const { join:
|
|
569937
|
-
const dir =
|
|
570081
|
+
const { join: join128 } = await import("node:path");
|
|
570082
|
+
const dir = join128(homedir46(), ".open-agents");
|
|
569938
570083
|
mkdirSync67(dir, { recursive: true });
|
|
569939
|
-
writeFileSync59(
|
|
570084
|
+
writeFileSync59(join128(dir, "access"), `${val}
|
|
569940
570085
|
`, "utf8");
|
|
569941
570086
|
} catch {
|
|
569942
570087
|
}
|
|
@@ -585469,10 +585614,168 @@ var init_runtime_keys = __esm({
|
|
|
585469
585614
|
}
|
|
585470
585615
|
});
|
|
585471
585616
|
|
|
585472
|
-
// packages/cli/src/api/
|
|
585473
|
-
|
|
585474
|
-
|
|
585617
|
+
// packages/cli/src/api/tor-fallback.ts
|
|
585618
|
+
var tor_fallback_exports = {};
|
|
585619
|
+
__export(tor_fallback_exports, {
|
|
585620
|
+
getLocalOnion: () => getLocalOnion,
|
|
585621
|
+
torIsReachable: () => torIsReachable,
|
|
585622
|
+
tunnelViaTor: () => tunnelViaTor
|
|
585623
|
+
});
|
|
585624
|
+
import { existsSync as existsSync101, readFileSync as readFileSync82 } from "node:fs";
|
|
585475
585625
|
import { homedir as homedir39 } from "node:os";
|
|
585626
|
+
import { join as join117 } from "node:path";
|
|
585627
|
+
import { createConnection as createConnection3 } from "node:net";
|
|
585628
|
+
function getLocalOnion() {
|
|
585629
|
+
const candidates = [
|
|
585630
|
+
join117(homedir39(), "hidden_service_hostname"),
|
|
585631
|
+
join117(homedir39(), ".oa", "tor", "hostname"),
|
|
585632
|
+
"/var/lib/tor/hidden_service/hostname"
|
|
585633
|
+
];
|
|
585634
|
+
for (const p2 of candidates) {
|
|
585635
|
+
try {
|
|
585636
|
+
if (existsSync101(p2)) {
|
|
585637
|
+
const v = readFileSync82(p2, "utf-8").trim();
|
|
585638
|
+
if (v && v.endsWith(".onion")) return v;
|
|
585639
|
+
}
|
|
585640
|
+
} catch {
|
|
585641
|
+
}
|
|
585642
|
+
}
|
|
585643
|
+
return null;
|
|
585644
|
+
}
|
|
585645
|
+
async function torIsReachable() {
|
|
585646
|
+
return new Promise((resolve43) => {
|
|
585647
|
+
const sock = createConnection3({ host: DEFAULT_SOCKS_HOST, port: DEFAULT_SOCKS_PORT });
|
|
585648
|
+
let done = false;
|
|
585649
|
+
const finish = (ok2) => {
|
|
585650
|
+
if (done) return;
|
|
585651
|
+
done = true;
|
|
585652
|
+
try {
|
|
585653
|
+
sock.destroy();
|
|
585654
|
+
} catch {
|
|
585655
|
+
}
|
|
585656
|
+
resolve43(ok2);
|
|
585657
|
+
};
|
|
585658
|
+
sock.once("connect", () => finish(true));
|
|
585659
|
+
sock.once("error", () => finish(false));
|
|
585660
|
+
setTimeout(() => finish(false), 500);
|
|
585661
|
+
});
|
|
585662
|
+
}
|
|
585663
|
+
async function tunnelViaTor(req2) {
|
|
585664
|
+
const headers = { ...req2.headers || {} };
|
|
585665
|
+
if (req2.shareKey) headers["authorization"] = `Bearer ${req2.shareKey}`;
|
|
585666
|
+
if (!headers["host"]) headers["host"] = req2.onion;
|
|
585667
|
+
if (req2.body && !headers["content-length"]) headers["content-length"] = String(Buffer.byteLength(req2.body, "utf-8"));
|
|
585668
|
+
if (!headers["connection"]) headers["connection"] = "close";
|
|
585669
|
+
const lines = [`${req2.method.toUpperCase()} ${req2.path} HTTP/1.1`];
|
|
585670
|
+
for (const [k, v] of Object.entries(headers)) lines.push(`${k}: ${v}`);
|
|
585671
|
+
lines.push("");
|
|
585672
|
+
lines.push("");
|
|
585673
|
+
const reqBuf = Buffer.from(lines.join("\r\n") + (req2.body ?? ""), "utf-8");
|
|
585674
|
+
const socksSock = await openSocks5(req2.onion, 80, req2.timeoutMs ?? 6e4);
|
|
585675
|
+
socksSock.write(reqBuf);
|
|
585676
|
+
const chunks = [];
|
|
585677
|
+
for await (const ch of socksSock) chunks.push(ch);
|
|
585678
|
+
const raw = Buffer.concat(chunks).toString("utf-8");
|
|
585679
|
+
const headerEnd = raw.indexOf("\r\n\r\n");
|
|
585680
|
+
if (headerEnd < 0) throw new Error("Tor: malformed response (no header terminator)");
|
|
585681
|
+
const headBlock = raw.slice(0, headerEnd);
|
|
585682
|
+
const bodyText = raw.slice(headerEnd + 4);
|
|
585683
|
+
const headLines = headBlock.split("\r\n");
|
|
585684
|
+
const statusLine = headLines.shift() ?? "";
|
|
585685
|
+
const m2 = statusLine.match(/^HTTP\/[\d.]+ (\d+)/);
|
|
585686
|
+
const status = m2 ? parseInt(m2[1], 10) : 0;
|
|
585687
|
+
const respHeaders = {};
|
|
585688
|
+
for (const ln of headLines) {
|
|
585689
|
+
const idx = ln.indexOf(":");
|
|
585690
|
+
if (idx <= 0) continue;
|
|
585691
|
+
respHeaders[ln.slice(0, idx).toLowerCase()] = ln.slice(idx + 1).trim();
|
|
585692
|
+
}
|
|
585693
|
+
const ct = (respHeaders["content-type"] || "").toLowerCase();
|
|
585694
|
+
const streaming = ct.includes("text/event-stream") || ct.includes("application/x-ndjson");
|
|
585695
|
+
return { status, headers: respHeaders, body: bodyText, streaming };
|
|
585696
|
+
}
|
|
585697
|
+
function openSocks5(targetHost, targetPort, timeoutMs) {
|
|
585698
|
+
return new Promise((resolve43, reject) => {
|
|
585699
|
+
const sock = createConnection3({ host: DEFAULT_SOCKS_HOST, port: DEFAULT_SOCKS_PORT });
|
|
585700
|
+
let stage = "greet";
|
|
585701
|
+
const timer = setTimeout(() => {
|
|
585702
|
+
try {
|
|
585703
|
+
sock.destroy(new Error(`Tor SOCKS5 timeout (${timeoutMs}ms)`));
|
|
585704
|
+
} catch {
|
|
585705
|
+
}
|
|
585706
|
+
reject(new Error(`Tor SOCKS5 timeout (${timeoutMs}ms)`));
|
|
585707
|
+
}, timeoutMs);
|
|
585708
|
+
sock.on("error", (e2) => {
|
|
585709
|
+
clearTimeout(timer);
|
|
585710
|
+
reject(e2);
|
|
585711
|
+
});
|
|
585712
|
+
sock.on("connect", () => {
|
|
585713
|
+
sock.write(Buffer.from([5, 1, 0]));
|
|
585714
|
+
});
|
|
585715
|
+
sock.on("data", (chunk) => {
|
|
585716
|
+
if (stage === "greet") {
|
|
585717
|
+
if (chunk.length < 2 || chunk[0] !== 5 || chunk[1] !== 0) {
|
|
585718
|
+
clearTimeout(timer);
|
|
585719
|
+
reject(new Error("Tor SOCKS5: greeting rejected (auth required?)"));
|
|
585720
|
+
try {
|
|
585721
|
+
sock.destroy();
|
|
585722
|
+
} catch {
|
|
585723
|
+
}
|
|
585724
|
+
return;
|
|
585725
|
+
}
|
|
585726
|
+
const hostBuf = Buffer.from(targetHost, "ascii");
|
|
585727
|
+
const buf = Buffer.alloc(7 + hostBuf.length);
|
|
585728
|
+
buf[0] = 5;
|
|
585729
|
+
buf[1] = 1;
|
|
585730
|
+
buf[2] = 0;
|
|
585731
|
+
buf[3] = 3;
|
|
585732
|
+
buf[4] = hostBuf.length;
|
|
585733
|
+
hostBuf.copy(buf, 5);
|
|
585734
|
+
buf.writeUInt16BE(targetPort, 5 + hostBuf.length);
|
|
585735
|
+
sock.write(buf);
|
|
585736
|
+
stage = "connect";
|
|
585737
|
+
return;
|
|
585738
|
+
}
|
|
585739
|
+
if (stage === "connect") {
|
|
585740
|
+
if (chunk.length < 2 || chunk[0] !== 5) {
|
|
585741
|
+
clearTimeout(timer);
|
|
585742
|
+
reject(new Error("Tor SOCKS5: malformed CONNECT reply"));
|
|
585743
|
+
try {
|
|
585744
|
+
sock.destroy();
|
|
585745
|
+
} catch {
|
|
585746
|
+
}
|
|
585747
|
+
return;
|
|
585748
|
+
}
|
|
585749
|
+
if (chunk[1] !== 0) {
|
|
585750
|
+
const code8 = chunk[1];
|
|
585751
|
+
clearTimeout(timer);
|
|
585752
|
+
reject(new Error(`Tor SOCKS5: CONNECT failed (code ${code8})`));
|
|
585753
|
+
try {
|
|
585754
|
+
sock.destroy();
|
|
585755
|
+
} catch {
|
|
585756
|
+
}
|
|
585757
|
+
return;
|
|
585758
|
+
}
|
|
585759
|
+
clearTimeout(timer);
|
|
585760
|
+
stage = "ready";
|
|
585761
|
+
resolve43(sock);
|
|
585762
|
+
}
|
|
585763
|
+
});
|
|
585764
|
+
});
|
|
585765
|
+
}
|
|
585766
|
+
var DEFAULT_SOCKS_PORT, DEFAULT_SOCKS_HOST;
|
|
585767
|
+
var init_tor_fallback = __esm({
|
|
585768
|
+
"packages/cli/src/api/tor-fallback.ts"() {
|
|
585769
|
+
"use strict";
|
|
585770
|
+
DEFAULT_SOCKS_PORT = parseInt(process.env["OA_TOR_SOCKS_PORT"] || "9050", 10);
|
|
585771
|
+
DEFAULT_SOCKS_HOST = process.env["OA_TOR_SOCKS_HOST"] || "127.0.0.1";
|
|
585772
|
+
}
|
|
585773
|
+
});
|
|
585774
|
+
|
|
585775
|
+
// packages/cli/src/api/routes-v1.ts
|
|
585776
|
+
import { existsSync as existsSync102, readFileSync as readFileSync83, readdirSync as readdirSync34, statSync as statSync34 } from "node:fs";
|
|
585777
|
+
import { join as join118, resolve as pathResolve2 } from "node:path";
|
|
585778
|
+
import { homedir as homedir40 } from "node:os";
|
|
585476
585779
|
async function tryRouteV1(ctx3) {
|
|
585477
585780
|
const { pathname, method } = ctx3;
|
|
585478
585781
|
if (pathname === "/v1/skills" && method === "GET") {
|
|
@@ -585554,6 +585857,8 @@ async function tryRouteV1(ctx3) {
|
|
|
585554
585857
|
const m2 = /^\/v1\/keys\/([^/]+)$/.exec(pathname);
|
|
585555
585858
|
if (m2 && method === "DELETE") return handleRevokeKey(ctx3, decodeURIComponent(m2[1]));
|
|
585556
585859
|
}
|
|
585860
|
+
if (pathname === "/v1/share/generate" && method === "POST") return handleGenerateShare(ctx3);
|
|
585861
|
+
if (pathname === "/v1/remote-proxy" && method === "POST") return handleRemoteProxy(ctx3);
|
|
585557
585862
|
if (pathname === "/v1/tools" && method === "GET") {
|
|
585558
585863
|
return handleListTools(ctx3);
|
|
585559
585864
|
}
|
|
@@ -585700,11 +586005,11 @@ async function handleGetSkill(ctx3, name10) {
|
|
|
585700
586005
|
async function fallbackDiscoverSkills() {
|
|
585701
586006
|
return (_root) => {
|
|
585702
586007
|
const roots = [
|
|
585703
|
-
|
|
586008
|
+
join118(homedir40(), ".local", "share", "ai-writing-guide")
|
|
585704
586009
|
];
|
|
585705
586010
|
const out = [];
|
|
585706
586011
|
for (const root of roots) {
|
|
585707
|
-
if (!
|
|
586012
|
+
if (!existsSync102(root)) continue;
|
|
585708
586013
|
walkForSkills(root, out, 0);
|
|
585709
586014
|
}
|
|
585710
586015
|
return out;
|
|
@@ -585715,12 +586020,12 @@ function walkForSkills(dir, out, depth) {
|
|
|
585715
586020
|
try {
|
|
585716
586021
|
for (const e2 of readdirSync34(dir, { withFileTypes: true })) {
|
|
585717
586022
|
if (e2.name.startsWith(".") || e2.name === "node_modules") continue;
|
|
585718
|
-
const p2 =
|
|
586023
|
+
const p2 = join118(dir, e2.name);
|
|
585719
586024
|
if (e2.isDirectory()) {
|
|
585720
586025
|
walkForSkills(p2, out, depth + 1);
|
|
585721
586026
|
} else if (e2.isFile() && e2.name === "SKILL.md") {
|
|
585722
586027
|
try {
|
|
585723
|
-
const content =
|
|
586028
|
+
const content = readFileSync83(p2, "utf-8").slice(0, 2e3);
|
|
585724
586029
|
const nameMatch = content.match(/^name:\s*(.+)$/m);
|
|
585725
586030
|
const descMatch = content.match(/^description:\s*(.+)$/m);
|
|
585726
586031
|
out.push({
|
|
@@ -585904,7 +586209,7 @@ async function getMemoryStores() {
|
|
|
585904
586209
|
if (memoryInitTried) return null;
|
|
585905
586210
|
memoryInitTried = true;
|
|
585906
586211
|
try {
|
|
585907
|
-
const dbPath =
|
|
586212
|
+
const dbPath = join118(homedir40(), ".open-agents", "memory.db");
|
|
585908
586213
|
const sharedDb = initDb(dbPath);
|
|
585909
586214
|
memoryStoresCache = {
|
|
585910
586215
|
episode: new EpisodeStore(dbPath),
|
|
@@ -586162,7 +586467,7 @@ async function handleFilesRead(ctx3) {
|
|
|
586162
586467
|
}));
|
|
586163
586468
|
return true;
|
|
586164
586469
|
}
|
|
586165
|
-
if (!
|
|
586470
|
+
if (!existsSync102(resolved)) {
|
|
586166
586471
|
sendProblem(res, problemDetails({
|
|
586167
586472
|
type: P.notFound,
|
|
586168
586473
|
status: 404,
|
|
@@ -586194,7 +586499,7 @@ async function handleFilesRead(ctx3) {
|
|
|
586194
586499
|
}));
|
|
586195
586500
|
return true;
|
|
586196
586501
|
}
|
|
586197
|
-
const content =
|
|
586502
|
+
const content = readFileSync83(resolved, "utf-8");
|
|
586198
586503
|
const offset = typeof body.offset === "number" && body.offset >= 0 ? body.offset : 0;
|
|
586199
586504
|
const limit = typeof body.limit === "number" && body.limit > 0 ? body.limit : content.length;
|
|
586200
586505
|
const slice2 = content.slice(offset, offset + limit);
|
|
@@ -586427,14 +586732,14 @@ async function handleNexusStatus(ctx3) {
|
|
|
586427
586732
|
const { res, requestId } = ctx3;
|
|
586428
586733
|
try {
|
|
586429
586734
|
const statePaths = [
|
|
586430
|
-
|
|
586431
|
-
|
|
586735
|
+
join118(process.cwd(), ".oa", "nexus-peer-state.json"),
|
|
586736
|
+
join118(homedir40(), ".open-agents", "nexus-peer-cache.json")
|
|
586432
586737
|
];
|
|
586433
586738
|
const states = [];
|
|
586434
586739
|
for (const p2 of statePaths) {
|
|
586435
|
-
if (!
|
|
586740
|
+
if (!existsSync102(p2)) continue;
|
|
586436
586741
|
try {
|
|
586437
|
-
const raw =
|
|
586742
|
+
const raw = readFileSync83(p2, "utf-8");
|
|
586438
586743
|
states.push({ source: p2, data: JSON.parse(raw) });
|
|
586439
586744
|
} catch (e2) {
|
|
586440
586745
|
states.push({ source: p2, error: String(e2) });
|
|
@@ -586461,8 +586766,8 @@ async function handleNexusStatus(ctx3) {
|
|
|
586461
586766
|
}
|
|
586462
586767
|
function loadAgentName() {
|
|
586463
586768
|
try {
|
|
586464
|
-
const p2 =
|
|
586465
|
-
if (
|
|
586769
|
+
const p2 = join118(homedir40(), ".open-agents", "agent-name");
|
|
586770
|
+
if (existsSync102(p2)) return readFileSync83(p2, "utf-8").trim();
|
|
586466
586771
|
} catch {
|
|
586467
586772
|
}
|
|
586468
586773
|
return null;
|
|
@@ -586471,14 +586776,14 @@ async function handleSponsors(ctx3) {
|
|
|
586471
586776
|
const { req: req2, res, url, requestId } = ctx3;
|
|
586472
586777
|
try {
|
|
586473
586778
|
const candidates = [
|
|
586474
|
-
|
|
586475
|
-
|
|
586779
|
+
join118(homedir40(), ".open-agents", "sponsor-cache.json"),
|
|
586780
|
+
join118(homedir40(), ".open-agents", "sponsors.json")
|
|
586476
586781
|
];
|
|
586477
586782
|
let sponsors = [];
|
|
586478
586783
|
for (const p2 of candidates) {
|
|
586479
|
-
if (!
|
|
586784
|
+
if (!existsSync102(p2)) continue;
|
|
586480
586785
|
try {
|
|
586481
|
-
const raw = JSON.parse(
|
|
586786
|
+
const raw = JSON.parse(readFileSync83(p2, "utf-8"));
|
|
586482
586787
|
if (Array.isArray(raw)) {
|
|
586483
586788
|
sponsors = raw;
|
|
586484
586789
|
break;
|
|
@@ -586547,8 +586852,8 @@ async function handleEvaluate(ctx3) {
|
|
|
586547
586852
|
}));
|
|
586548
586853
|
return true;
|
|
586549
586854
|
}
|
|
586550
|
-
const jobPath =
|
|
586551
|
-
if (!
|
|
586855
|
+
const jobPath = join118(process.cwd(), ".oa", "jobs", `${runId}.json`);
|
|
586856
|
+
if (!existsSync102(jobPath)) {
|
|
586552
586857
|
sendProblem(res, problemDetails({
|
|
586553
586858
|
type: P.notFound,
|
|
586554
586859
|
status: 404,
|
|
@@ -586558,7 +586863,7 @@ async function handleEvaluate(ctx3) {
|
|
|
586558
586863
|
}));
|
|
586559
586864
|
return true;
|
|
586560
586865
|
}
|
|
586561
|
-
const job = JSON.parse(
|
|
586866
|
+
const job = JSON.parse(readFileSync83(jobPath, "utf-8"));
|
|
586562
586867
|
sendJson(res, 200, {
|
|
586563
586868
|
run_id: runId,
|
|
586564
586869
|
task: job.task,
|
|
@@ -586695,6 +587000,358 @@ async function handleMintKey(ctx3) {
|
|
|
586695
587000
|
}
|
|
586696
587001
|
return true;
|
|
586697
587002
|
}
|
|
587003
|
+
function resolveLocalPeerId() {
|
|
587004
|
+
const candidates = [
|
|
587005
|
+
join118(process.cwd(), ".oa", "nexus", "status.json"),
|
|
587006
|
+
join118(homedir40(), ".oa", "nexus", "status.json"),
|
|
587007
|
+
join118(homedir40(), ".open-agents", "nexus", "status.json")
|
|
587008
|
+
];
|
|
587009
|
+
for (const p2 of candidates) {
|
|
587010
|
+
if (!existsSync102(p2)) continue;
|
|
587011
|
+
try {
|
|
587012
|
+
const data = JSON.parse(readFileSync83(p2, "utf-8"));
|
|
587013
|
+
if (data?.connected && typeof data.peerId === "string" && data.peerId.length > 10) {
|
|
587014
|
+
return { peerId: data.peerId, agentName: typeof data.agentName === "string" ? data.agentName : null, source: p2 };
|
|
587015
|
+
}
|
|
587016
|
+
} catch {
|
|
587017
|
+
}
|
|
587018
|
+
}
|
|
587019
|
+
return null;
|
|
587020
|
+
}
|
|
587021
|
+
async function handleGenerateShare(ctx3) {
|
|
587022
|
+
const { req: req2, res, requestId } = ctx3;
|
|
587023
|
+
const reqAuth = req2;
|
|
587024
|
+
if (reqAuth._authScope !== "admin") {
|
|
587025
|
+
sendProblem(res, problemDetails({
|
|
587026
|
+
type: P.forbidden,
|
|
587027
|
+
status: 403,
|
|
587028
|
+
title: "Admin scope required",
|
|
587029
|
+
detail: "Generating a share URL mints a runtime key, which requires 'admin' scope.",
|
|
587030
|
+
instance: requestId
|
|
587031
|
+
}));
|
|
587032
|
+
return true;
|
|
587033
|
+
}
|
|
587034
|
+
try {
|
|
587035
|
+
const body = await parseJsonBodyStrict(req2).catch(() => null) ?? {};
|
|
587036
|
+
const label = typeof body["label"] === "string" && body["label"] ? String(body["label"]).slice(0, 100) : `share-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}`;
|
|
587037
|
+
const scope = typeof body["scope"] === "string" && ["read", "run", "admin"].includes(body["scope"]) ? body["scope"] : "run";
|
|
587038
|
+
const owner = `share:${label}`;
|
|
587039
|
+
const { mintKey: mintKey2 } = await Promise.resolve().then(() => (init_runtime_keys(), runtime_keys_exports));
|
|
587040
|
+
const rec = mintKey2({
|
|
587041
|
+
scope,
|
|
587042
|
+
owner,
|
|
587043
|
+
profile: null
|
|
587044
|
+
});
|
|
587045
|
+
const hostHeader = String(req2.headers["host"] || "").trim();
|
|
587046
|
+
const fallbackHost = process.env["OA_HOST"] || "127.0.0.1:11435";
|
|
587047
|
+
let hostPort = hostHeader || fallbackHost;
|
|
587048
|
+
hostPort = hostPort.replace(/^https?:\/\//i, "");
|
|
587049
|
+
const colonIdx = hostPort.lastIndexOf(":");
|
|
587050
|
+
const host = colonIdx > 0 ? hostPort.slice(0, colonIdx) : hostPort;
|
|
587051
|
+
const portStr = colonIdx > 0 ? hostPort.slice(colonIdx + 1) : "11435";
|
|
587052
|
+
const port = parseInt(portStr, 10) || 11435;
|
|
587053
|
+
const fullKey = rec.key || "";
|
|
587054
|
+
const keyPrefix2 = fullKey.slice(0, 12);
|
|
587055
|
+
if (!fullKey) {
|
|
587056
|
+
sendProblem(res, problemDetails({
|
|
587057
|
+
type: P.internalError,
|
|
587058
|
+
status: 500,
|
|
587059
|
+
title: "Key generation succeeded but no secret returned",
|
|
587060
|
+
detail: "mintKey() did not include the full secret in its response.",
|
|
587061
|
+
instance: requestId
|
|
587062
|
+
}));
|
|
587063
|
+
return true;
|
|
587064
|
+
}
|
|
587065
|
+
const directOnly = body["direct"] === true;
|
|
587066
|
+
const peerInfo = directOnly ? null : resolveLocalPeerId();
|
|
587067
|
+
const scheme = String(req2.headers["x-forwarded-proto"] || (req2.socket?.encrypted ? "https" : "http"));
|
|
587068
|
+
const { getLocalOnion: getLocalOnion2 } = await Promise.resolve().then(() => (init_tor_fallback(), tor_fallback_exports));
|
|
587069
|
+
const onion = getLocalOnion2();
|
|
587070
|
+
let shareUrl;
|
|
587071
|
+
let mode;
|
|
587072
|
+
if (peerInfo && hostHeader) {
|
|
587073
|
+
shareUrl = `oa-share://${peerInfo.peerId}@${hostPort}#${fullKey}`;
|
|
587074
|
+
mode = "libp2p+lan";
|
|
587075
|
+
} else if (peerInfo) {
|
|
587076
|
+
shareUrl = `oa-share://${peerInfo.peerId}#${fullKey}`;
|
|
587077
|
+
mode = "libp2p";
|
|
587078
|
+
} else {
|
|
587079
|
+
shareUrl = `oa-share://${hostPort}#${fullKey}`;
|
|
587080
|
+
mode = "direct";
|
|
587081
|
+
}
|
|
587082
|
+
const plainParams = [];
|
|
587083
|
+
if (peerInfo) plainParams.push(`oa-share-peer=${encodeURIComponent(peerInfo.peerId)}`);
|
|
587084
|
+
plainParams.push(`oa-key=${encodeURIComponent(fullKey)}`);
|
|
587085
|
+
if (onion) plainParams.push(`oa-onion=${encodeURIComponent(onion)}`);
|
|
587086
|
+
plainParams.push(`oa-share-label=${encodeURIComponent(label)}`);
|
|
587087
|
+
const plainUrl = `${scheme}://${hostPort}/?${plainParams.join("&")}`;
|
|
587088
|
+
sendJson(res, 201, {
|
|
587089
|
+
shareUrl,
|
|
587090
|
+
plainUrl,
|
|
587091
|
+
mode,
|
|
587092
|
+
peerId: peerInfo?.peerId || null,
|
|
587093
|
+
onion: onion || null,
|
|
587094
|
+
agentName: peerInfo?.agentName || null,
|
|
587095
|
+
host,
|
|
587096
|
+
port,
|
|
587097
|
+
key: fullKey,
|
|
587098
|
+
keyPrefix: keyPrefix2,
|
|
587099
|
+
label,
|
|
587100
|
+
issuedAt: rec.created || (/* @__PURE__ */ new Date()).toISOString(),
|
|
587101
|
+
reach: {
|
|
587102
|
+
libp2p: !!peerInfo,
|
|
587103
|
+
tor: !!onion,
|
|
587104
|
+
direct: !peerInfo
|
|
587105
|
+
},
|
|
587106
|
+
_note: peerInfo && onion ? "Globally reachable via libp2p (primary) and Tor (.onion fallback)." : peerInfo ? "Globally reachable via libp2p. For maximum reach add Tor: see scripts/tor/tor_setup.sh." : "Nexus daemon offline — URL is direct-HTTP only (LAN/VPN reach). Start nexus for global reach."
|
|
587107
|
+
});
|
|
587108
|
+
} catch (err) {
|
|
587109
|
+
sendProblem(res, problemDetails({
|
|
587110
|
+
type: P.internalError,
|
|
587111
|
+
status: 500,
|
|
587112
|
+
title: "Share URL generation failed",
|
|
587113
|
+
detail: err instanceof Error ? err.message : String(err),
|
|
587114
|
+
instance: requestId
|
|
587115
|
+
}));
|
|
587116
|
+
}
|
|
587117
|
+
return true;
|
|
587118
|
+
}
|
|
587119
|
+
async function handleRemoteProxy(ctx3) {
|
|
587120
|
+
const { req: req2, res, requestId } = ctx3;
|
|
587121
|
+
const reqAuth = req2;
|
|
587122
|
+
if (reqAuth._authScope !== "admin" && reqAuth._authScope !== "run") {
|
|
587123
|
+
sendProblem(res, problemDetails({
|
|
587124
|
+
type: P.forbidden,
|
|
587125
|
+
status: 403,
|
|
587126
|
+
title: "Auth required",
|
|
587127
|
+
detail: "Remote proxy requires 'run' or 'admin' scope on the LOCAL daemon.",
|
|
587128
|
+
instance: requestId
|
|
587129
|
+
}));
|
|
587130
|
+
return true;
|
|
587131
|
+
}
|
|
587132
|
+
let body;
|
|
587133
|
+
try {
|
|
587134
|
+
body = await parseJsonBodyStrict(req2);
|
|
587135
|
+
} catch {
|
|
587136
|
+
sendProblem(res, problemDetails({
|
|
587137
|
+
type: P.invalidRequest,
|
|
587138
|
+
status: 400,
|
|
587139
|
+
title: "Invalid JSON body",
|
|
587140
|
+
detail: "Body must be JSON object with peerId, key, method, path.",
|
|
587141
|
+
instance: requestId
|
|
587142
|
+
}));
|
|
587143
|
+
return true;
|
|
587144
|
+
}
|
|
587145
|
+
const peerId = String(body?.peerId || "").trim();
|
|
587146
|
+
const onionHint = typeof body?.onion === "string" && body.onion.endsWith(".onion") ? body.onion : null;
|
|
587147
|
+
const shareKey = String(body?.key || "").trim();
|
|
587148
|
+
const method = String(body?.method || "GET").toUpperCase();
|
|
587149
|
+
const path8 = String(body?.path || "/").trim();
|
|
587150
|
+
const headers = body?.headers && typeof body.headers === "object" ? body.headers : {};
|
|
587151
|
+
const useStream = body?.stream === true;
|
|
587152
|
+
const timeoutMs = typeof body?.timeoutMs === "number" ? body.timeoutMs : 6e4;
|
|
587153
|
+
if (!peerId && !onionHint || !shareKey) {
|
|
587154
|
+
sendProblem(res, problemDetails({
|
|
587155
|
+
type: P.invalidRequest,
|
|
587156
|
+
status: 400,
|
|
587157
|
+
title: "key + (peerId or onion) required",
|
|
587158
|
+
detail: "Provide a share key and at least one of peerId (libp2p) or onion (Tor).",
|
|
587159
|
+
instance: requestId
|
|
587160
|
+
}));
|
|
587161
|
+
return true;
|
|
587162
|
+
}
|
|
587163
|
+
const nexusCandidates = [
|
|
587164
|
+
join118(process.cwd(), ".oa", "nexus"),
|
|
587165
|
+
join118(homedir40(), ".oa", "nexus"),
|
|
587166
|
+
join118(homedir40(), ".open-agents", "nexus")
|
|
587167
|
+
];
|
|
587168
|
+
let nexusDirPath = null;
|
|
587169
|
+
for (const p2 of nexusCandidates) {
|
|
587170
|
+
if (existsSync102(join118(p2, "status.json"))) {
|
|
587171
|
+
nexusDirPath = p2;
|
|
587172
|
+
break;
|
|
587173
|
+
}
|
|
587174
|
+
}
|
|
587175
|
+
let tool = null;
|
|
587176
|
+
if (peerId && nexusDirPath) {
|
|
587177
|
+
const { NexusTool: NexusTool2 } = await Promise.resolve().then(() => (init_dist5(), dist_exports));
|
|
587178
|
+
const nexusToolRepoRoot = nexusDirPath.replace(/[\\/]\.oa[\\/]nexus$/, "");
|
|
587179
|
+
tool = new NexusTool2(nexusToolRepoRoot);
|
|
587180
|
+
}
|
|
587181
|
+
const tunnelInput = {
|
|
587182
|
+
method,
|
|
587183
|
+
path: path8,
|
|
587184
|
+
headers,
|
|
587185
|
+
body: body?.body,
|
|
587186
|
+
key: shareKey
|
|
587187
|
+
};
|
|
587188
|
+
function torEnvelope(t2) {
|
|
587189
|
+
return {
|
|
587190
|
+
event: "http.head",
|
|
587191
|
+
data: JSON.stringify({ status: t2.status, headers: t2.headers, streaming: t2.streaming }),
|
|
587192
|
+
// The browser fetch interceptor reads either `event: http.head + data` (with embedded
|
|
587193
|
+
// status/headers) or falls back to `raw`. We pass both.
|
|
587194
|
+
raw: t2.body,
|
|
587195
|
+
transport: "tor"
|
|
587196
|
+
};
|
|
587197
|
+
}
|
|
587198
|
+
if (!useStream) {
|
|
587199
|
+
let libp2pErr = null;
|
|
587200
|
+
if (tool) {
|
|
587201
|
+
try {
|
|
587202
|
+
const raw = await tool.sendCommand("invoke_capability", {
|
|
587203
|
+
target_peer: peerId,
|
|
587204
|
+
capability: "http_tunnel",
|
|
587205
|
+
input: JSON.stringify(tunnelInput)
|
|
587206
|
+
}, timeoutMs);
|
|
587207
|
+
let parsed = null;
|
|
587208
|
+
try {
|
|
587209
|
+
parsed = JSON.parse(raw);
|
|
587210
|
+
} catch {
|
|
587211
|
+
parsed = { raw };
|
|
587212
|
+
}
|
|
587213
|
+
if (parsed && typeof parsed === "object") parsed.transport = "libp2p";
|
|
587214
|
+
sendJson(res, 200, parsed);
|
|
587215
|
+
return true;
|
|
587216
|
+
} catch (e2) {
|
|
587217
|
+
libp2pErr = e2;
|
|
587218
|
+
}
|
|
587219
|
+
}
|
|
587220
|
+
if (onionHint) {
|
|
587221
|
+
try {
|
|
587222
|
+
const { tunnelViaTor: tunnelViaTor2, torIsReachable: torIsReachable2 } = await Promise.resolve().then(() => (init_tor_fallback(), tor_fallback_exports));
|
|
587223
|
+
if (await torIsReachable2()) {
|
|
587224
|
+
const t2 = await tunnelViaTor2({
|
|
587225
|
+
onion: onionHint,
|
|
587226
|
+
method,
|
|
587227
|
+
path: path8,
|
|
587228
|
+
headers,
|
|
587229
|
+
body: typeof body?.body === "string" ? body.body : body?.body !== void 0 ? JSON.stringify(body.body) : void 0,
|
|
587230
|
+
shareKey,
|
|
587231
|
+
timeoutMs
|
|
587232
|
+
});
|
|
587233
|
+
sendJson(res, 200, torEnvelope(t2));
|
|
587234
|
+
return true;
|
|
587235
|
+
}
|
|
587236
|
+
} catch (torErr) {
|
|
587237
|
+
sendProblem(res, problemDetails({
|
|
587238
|
+
type: P.internalError,
|
|
587239
|
+
status: 502,
|
|
587240
|
+
title: "Both libp2p and Tor transports failed",
|
|
587241
|
+
detail: `libp2p: ${libp2pErr instanceof Error ? libp2pErr.message : String(libp2pErr || "n/a")}; tor: ${torErr instanceof Error ? torErr.message : String(torErr)}`,
|
|
587242
|
+
instance: requestId
|
|
587243
|
+
}));
|
|
587244
|
+
return true;
|
|
587245
|
+
}
|
|
587246
|
+
}
|
|
587247
|
+
sendProblem(res, problemDetails({
|
|
587248
|
+
type: P.internalError,
|
|
587249
|
+
status: 502,
|
|
587250
|
+
title: "No transport reached the remote",
|
|
587251
|
+
detail: tool ? `libp2p invoke failed: ${libp2pErr instanceof Error ? libp2pErr.message : String(libp2pErr)}${onionHint ? "; Tor SOCKS5 not reachable on 127.0.0.1:9050" : "; no .onion fallback available"}` : "Local nexus daemon is offline and no .onion fallback was provided. Start nexus with `oa connect` or include onion in the request.",
|
|
587252
|
+
instance: requestId
|
|
587253
|
+
}));
|
|
587254
|
+
return true;
|
|
587255
|
+
}
|
|
587256
|
+
if (!tool) {
|
|
587257
|
+
sendProblem(res, problemDetails({
|
|
587258
|
+
type: P.internalError,
|
|
587259
|
+
status: 503,
|
|
587260
|
+
title: "Streaming requires libp2p (nexus not running)",
|
|
587261
|
+
detail: "SSE/streaming proxy requires the local nexus daemon. Start it with `oa connect`, or use a non-streaming endpoint with the Tor fallback.",
|
|
587262
|
+
instance: requestId
|
|
587263
|
+
}));
|
|
587264
|
+
return true;
|
|
587265
|
+
}
|
|
587266
|
+
const streamFile = join118(nexusDirPath, `tunnel-${requestId}-${Date.now()}.jsonl`);
|
|
587267
|
+
try {
|
|
587268
|
+
const { writeFileSync: _wfs } = await import("node:fs");
|
|
587269
|
+
_wfs(streamFile, "");
|
|
587270
|
+
} catch {
|
|
587271
|
+
}
|
|
587272
|
+
res.statusCode = 200;
|
|
587273
|
+
res.setHeader("content-type", "text/event-stream");
|
|
587274
|
+
res.setHeader("cache-control", "no-cache");
|
|
587275
|
+
res.setHeader("x-accel-buffering", "no");
|
|
587276
|
+
res.flushHeaders?.();
|
|
587277
|
+
let stopped = false;
|
|
587278
|
+
const stop2 = () => {
|
|
587279
|
+
stopped = true;
|
|
587280
|
+
};
|
|
587281
|
+
req2.on("close", stop2);
|
|
587282
|
+
req2.on("aborted", stop2);
|
|
587283
|
+
const invokeP = tool.sendCommand("invoke_capability", {
|
|
587284
|
+
target_peer: peerId,
|
|
587285
|
+
capability: "http_tunnel",
|
|
587286
|
+
input: JSON.stringify(tunnelInput),
|
|
587287
|
+
stream_file: streamFile
|
|
587288
|
+
}, timeoutMs).catch((err) => {
|
|
587289
|
+
if (!stopped) {
|
|
587290
|
+
try {
|
|
587291
|
+
res.write(`event: error
|
|
587292
|
+
data: ${JSON.stringify({ error: err instanceof Error ? err.message : String(err) })}
|
|
587293
|
+
|
|
587294
|
+
`);
|
|
587295
|
+
} catch {
|
|
587296
|
+
}
|
|
587297
|
+
}
|
|
587298
|
+
});
|
|
587299
|
+
const { readFileSync: _rfs, existsSync: _exists } = await import("node:fs");
|
|
587300
|
+
let lastSize = 0;
|
|
587301
|
+
let leftover = "";
|
|
587302
|
+
while (!stopped) {
|
|
587303
|
+
try {
|
|
587304
|
+
if (_exists(streamFile)) {
|
|
587305
|
+
const stat5 = (await import("node:fs")).statSync(streamFile);
|
|
587306
|
+
if (stat5.size > lastSize) {
|
|
587307
|
+
const fd = (await import("node:fs")).openSync(streamFile, "r");
|
|
587308
|
+
const len = stat5.size - lastSize;
|
|
587309
|
+
const buf = Buffer.alloc(len);
|
|
587310
|
+
(await import("node:fs")).readSync(fd, buf, 0, len, lastSize);
|
|
587311
|
+
(await import("node:fs")).closeSync(fd);
|
|
587312
|
+
lastSize = stat5.size;
|
|
587313
|
+
const txt = leftover + buf.toString("utf-8");
|
|
587314
|
+
const parts = txt.split("\n");
|
|
587315
|
+
leftover = parts.pop() ?? "";
|
|
587316
|
+
for (const ln of parts) {
|
|
587317
|
+
if (!ln.trim()) continue;
|
|
587318
|
+
let parsed;
|
|
587319
|
+
try {
|
|
587320
|
+
parsed = JSON.parse(ln);
|
|
587321
|
+
} catch {
|
|
587322
|
+
continue;
|
|
587323
|
+
}
|
|
587324
|
+
const eventName = parsed.type === "event" ? parsed.event || "data" : parsed.type;
|
|
587325
|
+
res.write(`event: ${eventName}
|
|
587326
|
+
`);
|
|
587327
|
+
res.write(`data: ${JSON.stringify(parsed)}
|
|
587328
|
+
|
|
587329
|
+
`);
|
|
587330
|
+
if (parsed.type === "done" || parsed.type === "error") {
|
|
587331
|
+
stopped = true;
|
|
587332
|
+
break;
|
|
587333
|
+
}
|
|
587334
|
+
}
|
|
587335
|
+
}
|
|
587336
|
+
}
|
|
587337
|
+
} catch {
|
|
587338
|
+
}
|
|
587339
|
+
if (stopped) break;
|
|
587340
|
+
await new Promise((r2) => setTimeout(r2, 30));
|
|
587341
|
+
}
|
|
587342
|
+
await invokeP.catch(() => {
|
|
587343
|
+
});
|
|
587344
|
+
try {
|
|
587345
|
+
res.end();
|
|
587346
|
+
} catch {
|
|
587347
|
+
}
|
|
587348
|
+
try {
|
|
587349
|
+
const { unlinkSync: _unl } = await import("node:fs");
|
|
587350
|
+
_unl(streamFile);
|
|
587351
|
+
} catch {
|
|
587352
|
+
}
|
|
587353
|
+
return true;
|
|
587354
|
+
}
|
|
586698
587355
|
async function handleRevokeKey(ctx3, prefix) {
|
|
586699
587356
|
const { req: req2, res, requestId } = ctx3;
|
|
586700
587357
|
const reqAuth = req2;
|
|
@@ -587046,17 +587703,17 @@ async function handleListAgentTypes(ctx3) {
|
|
|
587046
587703
|
}
|
|
587047
587704
|
async function handleListEngines(ctx3) {
|
|
587048
587705
|
const { res } = ctx3;
|
|
587049
|
-
const home =
|
|
587706
|
+
const home = homedir40();
|
|
587050
587707
|
sendJson(res, 200, {
|
|
587051
587708
|
engines: [
|
|
587052
|
-
{ name: "dream", state_file:
|
|
587053
|
-
{ name: "bless", state_file:
|
|
587054
|
-
{ name: "call", state_file:
|
|
587055
|
-
{ name: "listen", state_file:
|
|
587056
|
-
{ name: "telegram", state_file:
|
|
587057
|
-
{ name: "expose", state_file:
|
|
587058
|
-
{ name: "nexus", state_file:
|
|
587059
|
-
{ name: "ipfs", state_file:
|
|
587709
|
+
{ name: "dream", state_file: join118(process.cwd(), ".oa", "dreams"), controllable_via: "SSE + slash commands" },
|
|
587710
|
+
{ name: "bless", state_file: join118(process.cwd(), ".oa", "bless-state.json"), controllable_via: "slash commands" },
|
|
587711
|
+
{ name: "call", state_file: join118(process.cwd(), ".oa", "call-state.json"), controllable_via: "slash commands" },
|
|
587712
|
+
{ name: "listen", state_file: join118(process.cwd(), ".oa", "listen-state.json"), controllable_via: "slash commands" },
|
|
587713
|
+
{ name: "telegram", state_file: join118(home, ".open-agents", "telegram-state.json"), controllable_via: "slash commands" },
|
|
587714
|
+
{ name: "expose", state_file: join118(process.cwd(), ".oa", "expose-state.json"), controllable_via: "/expose commands" },
|
|
587715
|
+
{ name: "nexus", state_file: join118(home, ".open-agents", "nexus-peer-cache.json"), controllable_via: "/nexus commands" },
|
|
587716
|
+
{ name: "ipfs", state_file: join118(process.cwd(), ".oa", "ipfs"), controllable_via: "slash commands" }
|
|
587060
587717
|
],
|
|
587061
587718
|
note: "Engine instrumentation lives in the running TUI process. Full status + control requires the daemon↔TUI bridge (PT-07). See parity audit WO-PARITY-04."
|
|
587062
587719
|
});
|
|
@@ -587139,12 +587796,12 @@ async function tryAimsRoute(ctx3) {
|
|
|
587139
587796
|
return false;
|
|
587140
587797
|
}
|
|
587141
587798
|
function aimsDir() {
|
|
587142
|
-
return
|
|
587799
|
+
return join118(homedir40(), ".open-agents", "aims");
|
|
587143
587800
|
}
|
|
587144
587801
|
function readAimsFile(name10, fallback) {
|
|
587145
587802
|
try {
|
|
587146
|
-
const p2 =
|
|
587147
|
-
if (
|
|
587803
|
+
const p2 = join118(aimsDir(), name10);
|
|
587804
|
+
if (existsSync102(p2)) return JSON.parse(readFileSync83(p2, "utf-8"));
|
|
587148
587805
|
} catch {
|
|
587149
587806
|
}
|
|
587150
587807
|
return fallback;
|
|
@@ -587153,7 +587810,7 @@ function writeAimsFile(name10, data) {
|
|
|
587153
587810
|
const dir = aimsDir();
|
|
587154
587811
|
const { mkdirSync: mkdirSync67, writeFileSync: wf, renameSync: rn } = __require("node:fs");
|
|
587155
587812
|
mkdirSync67(dir, { recursive: true });
|
|
587156
|
-
const finalPath =
|
|
587813
|
+
const finalPath = join118(dir, name10);
|
|
587157
587814
|
const tmpPath = `${finalPath}.tmp.${process.pid}.${Date.now()}`;
|
|
587158
587815
|
try {
|
|
587159
587816
|
wf(tmpPath, JSON.stringify(data, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
|
|
@@ -587483,12 +588140,12 @@ async function handleAimsSuppliers(ctx3) {
|
|
|
587483
588140
|
}
|
|
587484
588141
|
];
|
|
587485
588142
|
const sponsorPaths = [
|
|
587486
|
-
|
|
588143
|
+
join118(homedir40(), ".open-agents", "sponsor-cache.json")
|
|
587487
588144
|
];
|
|
587488
588145
|
for (const p2 of sponsorPaths) {
|
|
587489
|
-
if (!
|
|
588146
|
+
if (!existsSync102(p2)) continue;
|
|
587490
588147
|
try {
|
|
587491
|
-
const raw = JSON.parse(
|
|
588148
|
+
const raw = JSON.parse(readFileSync83(p2, "utf-8"));
|
|
587492
588149
|
const list = Array.isArray(raw) ? raw : raw?.sponsors ?? [];
|
|
587493
588150
|
for (const s2 of list) {
|
|
587494
588151
|
suppliers.push({
|
|
@@ -589011,7 +589668,7 @@ body { display:flex; flex-direction:column; height:100vh; margin:0; overflow:hid
|
|
|
589011
589668
|
<span id="sidebar-status-dot" style="width:8px;height:8px;border-radius:50%;background:var(--color-fg-faint);flex-shrink:0" title="Backend connection"></span>
|
|
589012
589669
|
<span id="sidebar-status-text" style="flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis">connecting...</span>
|
|
589013
589670
|
<button id="sidebar-update-btn" onclick="doUpdate()" style="display:none;background:var(--color-warning);border:none;color:#000;padding:2px 6px;border-radius:var(--radius-sm);font-size:0.6rem;cursor:pointer;font-weight:600">update</button>
|
|
589014
|
-
<button id="sidebar-key-btn" onclick="
|
|
589671
|
+
<button id="sidebar-key-btn" onclick="openKeyModal()" title="Set API key / share access" style="background:transparent;border:1px solid var(--color-border);color:var(--color-fg-muted);padding:2px 6px;border-radius:var(--radius-sm);font-size:0.6rem;cursor:pointer">key</button>
|
|
589015
589672
|
</div>
|
|
589016
589673
|
|
|
589017
589674
|
<!-- Resize handle -->
|
|
@@ -589343,14 +590000,21 @@ body { display:flex; flex-direction:column; height:100vh; margin:0; overflow:hid
|
|
|
589343
590000
|
</div>
|
|
589344
590001
|
|
|
589345
590002
|
<div id="key-modal">
|
|
589346
|
-
<form class="modal" onsubmit="event.preventDefault(); saveKey();" autocomplete="off">
|
|
589347
|
-
<h3>API Key</h3>
|
|
589348
|
-
<
|
|
589349
|
-
|
|
590003
|
+
<form class="modal" onsubmit="event.preventDefault(); saveKey();" autocomplete="off" style="min-width:480px">
|
|
590004
|
+
<h3>API Key & Sharing</h3>
|
|
590005
|
+
<div style="position:relative">
|
|
590006
|
+
<input id="key-input" type="password" placeholder="Bearer token (leave empty if auth disabled, or paste an oa-share:// URL to connect remote)" autocomplete="new-password" oninput="onKeyInputChange(this.value)" onfocus="showRecentKeysDropdown()" onblur="setTimeout(hideRecentKeysDropdown, 150)">
|
|
590007
|
+
<div id="key-recent-dropdown" style="display:none;position:absolute;top:100%;left:0;right:0;background:var(--color-bg-elevated);border:1px solid var(--color-border);border-radius:var(--radius-sm);max-height:180px;overflow-y:auto;z-index:10;font-size:0.78rem;margin-top:2px"></div>
|
|
590008
|
+
</div>
|
|
590009
|
+
<p id="key-input-hint" style="font-size:0.7rem;color:var(--color-fg-muted);margin:4px 0 8px">Tip: paste an <code>oa-share://host:port#key</code> URL or <code>http://host:port/?oa-key=…</code> to connect to a remote OA instance.</p>
|
|
590010
|
+
<div style="display:flex;gap:6px;flex-wrap:wrap">
|
|
589350
590011
|
<button type="submit">save</button>
|
|
589351
590012
|
<button type="button" onclick="clearKey()">clear</button>
|
|
590013
|
+
<button type="button" onclick="generateShareUrl()" title="Generate a share URL that lets a remote OA instance connect to this one">share access</button>
|
|
589352
590014
|
<button type="button" onclick="closeKeyModal()">cancel</button>
|
|
589353
590015
|
</div>
|
|
590016
|
+
<div id="share-result" style="display:none;margin-top:14px;padding:10px;background:var(--color-bg-elevated);border:1px solid var(--color-border);border-radius:var(--radius-sm);font-size:0.78rem"></div>
|
|
590017
|
+
<div id="remote-state" style="display:none;margin-top:14px;padding:10px;background:var(--color-bg-elevated);border:1px solid var(--color-accent);border-radius:var(--radius-sm);font-size:0.78rem"></div>
|
|
589354
590018
|
</form>
|
|
589355
590019
|
</div>
|
|
589356
590020
|
|
|
@@ -590472,6 +591136,15 @@ async function sendMessage() {
|
|
|
590472
591136
|
messageWithContext = filesBlock + text;
|
|
590473
591137
|
}
|
|
590474
591138
|
|
|
591139
|
+
// FRESH-SESSION: pull the one-shot fresh flag the newChatSession()
|
|
591140
|
+
// handler set. Consumed (cleared) here so subsequent sends within
|
|
591141
|
+
// this same session don't keep claiming "fresh" and miss legitimate
|
|
591142
|
+
// mid-session handoff.
|
|
591143
|
+
let _freshPending = false;
|
|
591144
|
+
try {
|
|
591145
|
+
_freshPending = localStorage.getItem('oa.freshSessionPending') === '1';
|
|
591146
|
+
if (_freshPending) localStorage.removeItem('oa.freshSessionPending');
|
|
591147
|
+
} catch {}
|
|
590475
591148
|
const body = {
|
|
590476
591149
|
session_id: chatSessionId,
|
|
590477
591150
|
model: modelSelect.value,
|
|
@@ -590481,6 +591154,10 @@ async function sendMessage() {
|
|
|
590481
591154
|
// Pass the user-selected workspace as working_directory so the
|
|
590482
591155
|
// agent subprocess operates in the right cwd.
|
|
590483
591156
|
...(chatWorkingDir ? { working_directory: chatWorkingDir } : {}),
|
|
591157
|
+
// FRESH-SESSION: tell the daemon to skip cross-task handoff
|
|
591158
|
+
// injection on this turn. Daemon plumbs it to OA_FRESH_SESSION=1
|
|
591159
|
+
// for the agent subprocess; runner's handoff block respects it.
|
|
591160
|
+
...(_freshPending ? { fresh: true } : {}),
|
|
590484
591161
|
};
|
|
590485
591162
|
|
|
590486
591163
|
const response = await fetch('/v1/chat', {
|
|
@@ -590788,11 +591465,174 @@ document.getElementById('key-btn').onclick = () => {
|
|
|
590788
591465
|
document.getElementById('key-input').value = apiKey;
|
|
590789
591466
|
};
|
|
590790
591467
|
function saveKey() {
|
|
590791
|
-
|
|
591468
|
+
const raw = document.getElementById('key-input').value || '';
|
|
591469
|
+
const parsed = parseShareInput(raw);
|
|
591470
|
+
if (parsed) {
|
|
591471
|
+
// Save into recent-keys for autocomplete
|
|
591472
|
+
const recLabel = parsed.label || (parsed.peerId
|
|
591473
|
+
? ('remote ' + (parsed.peerId.slice(0, 12) + '…'))
|
|
591474
|
+
: ('remote ' + parsed.host));
|
|
591475
|
+
saveRecentKey({
|
|
591476
|
+
key: parsed.key, peerId: parsed.peerId, onion: parsed.onion || null,
|
|
591477
|
+
host: parsed.host, label: recLabel,
|
|
591478
|
+
});
|
|
591479
|
+
if (parsed.peerId || parsed.onion) {
|
|
591480
|
+
// ─── REMOTE MODE: libp2p (primary) + Tor (fallback) ──────────────
|
|
591481
|
+
// Stay on this page; route /v1/... calls through this daemon's
|
|
591482
|
+
// /v1/remote-proxy. The local daemon will try libp2p invoke first
|
|
591483
|
+
// (when peerId is set); if that fails (or peerId missing) it
|
|
591484
|
+
// falls back to Tor SOCKS5 → onion (when onion is set).
|
|
591485
|
+
try {
|
|
591486
|
+
localStorage.setItem('oa.activeRemoteShare', JSON.stringify({
|
|
591487
|
+
peerId: parsed.peerId,
|
|
591488
|
+
onion: parsed.onion || null,
|
|
591489
|
+
key: parsed.key,
|
|
591490
|
+
host: parsed.host || null,
|
|
591491
|
+
label: recLabel,
|
|
591492
|
+
activatedAt: new Date().toISOString(),
|
|
591493
|
+
}));
|
|
591494
|
+
} catch {}
|
|
591495
|
+
installRemoteFetchProxy();
|
|
591496
|
+
closeKeyModal();
|
|
591497
|
+
try { location.reload(); } catch { loadModels(); }
|
|
591498
|
+
return;
|
|
591499
|
+
}
|
|
591500
|
+
if (parsed.host) {
|
|
591501
|
+
// Legacy direct-HTTP — open the remote origin in a new tab.
|
|
591502
|
+
const remoteUrl = (parsed.scheme || 'http') + '://' + parsed.host + '/?oa-key=' + encodeURIComponent(parsed.key) + '&oa-share-label=' + encodeURIComponent(parsed.label || '');
|
|
591503
|
+
window.open(remoteUrl, '_blank');
|
|
591504
|
+
closeKeyModal();
|
|
591505
|
+
return;
|
|
591506
|
+
}
|
|
591507
|
+
}
|
|
591508
|
+
apiKey = raw;
|
|
590792
591509
|
localStorage.setItem('oa-api-key', apiKey);
|
|
591510
|
+
if (apiKey) {
|
|
591511
|
+
saveRecentKey({ key: apiKey, host: location.host, label: 'local ' + location.host });
|
|
591512
|
+
}
|
|
590793
591513
|
closeKeyModal();
|
|
590794
591514
|
loadModels();
|
|
590795
591515
|
}
|
|
591516
|
+
|
|
591517
|
+
// ─── Remote-mode fetch proxy ─────────────────────────────────────────────
|
|
591518
|
+
// When 'oa.activeRemoteShare' is set, intercept window.fetch so any
|
|
591519
|
+
// /v1/... call gets re-routed via POST /v1/remote-proxy to be tunneled
|
|
591520
|
+
// through libp2p to the remote peer. SSE streams keep their text/event-
|
|
591521
|
+
// stream shape end-to-end.
|
|
591522
|
+
let _oaRemoteFetchInstalled = false;
|
|
591523
|
+
function getActiveRemoteShare() {
|
|
591524
|
+
try {
|
|
591525
|
+
const raw = localStorage.getItem('oa.activeRemoteShare');
|
|
591526
|
+
if (!raw) return null;
|
|
591527
|
+
const obj = JSON.parse(raw);
|
|
591528
|
+
if (!obj || !obj.peerId || !obj.key) return null;
|
|
591529
|
+
return obj;
|
|
591530
|
+
} catch { return null; }
|
|
591531
|
+
}
|
|
591532
|
+
function clearActiveRemoteShare() {
|
|
591533
|
+
try { localStorage.removeItem('oa.activeRemoteShare'); } catch {}
|
|
591534
|
+
}
|
|
591535
|
+
function installRemoteFetchProxy() {
|
|
591536
|
+
if (_oaRemoteFetchInstalled) return;
|
|
591537
|
+
_oaRemoteFetchInstalled = true;
|
|
591538
|
+
const _origFetch = window.fetch.bind(window);
|
|
591539
|
+
window.fetch = async function(input, init) {
|
|
591540
|
+
const share = getActiveRemoteShare();
|
|
591541
|
+
if (!share) return _origFetch(input, init);
|
|
591542
|
+
let urlStr = '';
|
|
591543
|
+
if (typeof input === 'string') urlStr = input;
|
|
591544
|
+
else if (input && input.url) urlStr = input.url;
|
|
591545
|
+
else return _origFetch(input, init);
|
|
591546
|
+
let pathOnly;
|
|
591547
|
+
try {
|
|
591548
|
+
const u = new URL(urlStr, location.href);
|
|
591549
|
+
// Don't proxy:
|
|
591550
|
+
// - cross-origin (already remote)
|
|
591551
|
+
// - the proxy endpoint itself (infinite loop)
|
|
591552
|
+
// - non-/v1/* routes (e.g. /assets, /openapi.json)
|
|
591553
|
+
if (u.origin !== location.origin) return _origFetch(input, init);
|
|
591554
|
+
if (u.pathname === '/v1/remote-proxy') return _origFetch(input, init);
|
|
591555
|
+
if (!u.pathname.startsWith('/v1/')) return _origFetch(input, init);
|
|
591556
|
+
pathOnly = u.pathname + u.search;
|
|
591557
|
+
} catch { return _origFetch(input, init); }
|
|
591558
|
+
|
|
591559
|
+
const method = ((init && init.method) || (input && input.method) || 'GET').toUpperCase();
|
|
591560
|
+
const headersIn = {};
|
|
591561
|
+
if (init && init.headers) {
|
|
591562
|
+
const h = init.headers;
|
|
591563
|
+
if (h instanceof Headers) h.forEach((v, k) => { headersIn[k] = v; });
|
|
591564
|
+
else if (Array.isArray(h)) h.forEach(([k, v]) => { headersIn[k] = v; });
|
|
591565
|
+
else Object.assign(headersIn, h);
|
|
591566
|
+
}
|
|
591567
|
+
let bodyOut;
|
|
591568
|
+
if (init && init.body !== undefined && init.body !== null) {
|
|
591569
|
+
if (typeof init.body === 'string') bodyOut = init.body;
|
|
591570
|
+
else if (init.body instanceof FormData) {
|
|
591571
|
+
const obj = {}; init.body.forEach((v, k) => { obj[k] = v; });
|
|
591572
|
+
bodyOut = obj;
|
|
591573
|
+
} else bodyOut = init.body;
|
|
591574
|
+
}
|
|
591575
|
+
// Heuristic: SSE if Accept includes text/event-stream OR the path is
|
|
591576
|
+
// a known streaming endpoint. We open the proxy in stream mode and
|
|
591577
|
+
// surface a Response with text/event-stream.
|
|
591578
|
+
const acceptHdr = (headersIn['accept'] || headersIn['Accept'] || '').toLowerCase();
|
|
591579
|
+
const wantsStream = acceptHdr.includes('text/event-stream')
|
|
591580
|
+
|| pathOnly.includes('/v1/chat/completions')
|
|
591581
|
+
|| pathOnly.includes('/v1/events');
|
|
591582
|
+
|
|
591583
|
+
const proxyBody = JSON.stringify({
|
|
591584
|
+
peerId: share.peerId || null,
|
|
591585
|
+
onion: share.onion || null,
|
|
591586
|
+
key: share.key,
|
|
591587
|
+
method, path: pathOnly, headers: headersIn, body: bodyOut,
|
|
591588
|
+
stream: wantsStream, timeoutMs: 120000,
|
|
591589
|
+
});
|
|
591590
|
+
if (wantsStream) {
|
|
591591
|
+
// Pass through as-is — receiver returns text/event-stream.
|
|
591592
|
+
return _origFetch('/v1/remote-proxy', {
|
|
591593
|
+
method: 'POST',
|
|
591594
|
+
headers: { 'content-type': 'application/json', 'accept': 'text/event-stream' },
|
|
591595
|
+
body: proxyBody,
|
|
591596
|
+
});
|
|
591597
|
+
}
|
|
591598
|
+
// Non-stream: receiver returns a JSON envelope { status, headers, body }.
|
|
591599
|
+
// Synthesize a Response that mimics the original remote response.
|
|
591600
|
+
const proxyResp = await _origFetch('/v1/remote-proxy', {
|
|
591601
|
+
method: 'POST',
|
|
591602
|
+
headers: { 'content-type': 'application/json' },
|
|
591603
|
+
body: proxyBody,
|
|
591604
|
+
});
|
|
591605
|
+
if (!proxyResp.ok) return proxyResp;
|
|
591606
|
+
let env = null;
|
|
591607
|
+
try { env = await proxyResp.json(); } catch {}
|
|
591608
|
+
if (!env || typeof env !== 'object') {
|
|
591609
|
+
return new Response('', { status: 502, statusText: 'Empty proxy response' });
|
|
591610
|
+
}
|
|
591611
|
+
// The non-stream envelope is the http_tunnel handler last event,
|
|
591612
|
+
// with its body JSON-stringified inside the data field. Unwrap it.
|
|
591613
|
+
let status = 200;
|
|
591614
|
+
let headersOut = new Headers();
|
|
591615
|
+
let bodyText = '';
|
|
591616
|
+
if (typeof env.raw === 'string') {
|
|
591617
|
+
// Single-shot result from the http_tunnel head+body events combined
|
|
591618
|
+
bodyText = env.raw;
|
|
591619
|
+
} else if (env.event === 'http.body' || env.event === 'http.head') {
|
|
591620
|
+
try {
|
|
591621
|
+
const inner = JSON.parse(env.data);
|
|
591622
|
+
if (inner.status) status = inner.status;
|
|
591623
|
+
if (inner.headers) Object.entries(inner.headers).forEach(([k, v]) => headersOut.set(k, String(v)));
|
|
591624
|
+
} catch {}
|
|
591625
|
+
bodyText = String(env.data || '');
|
|
591626
|
+
} else {
|
|
591627
|
+
bodyText = JSON.stringify(env);
|
|
591628
|
+
}
|
|
591629
|
+
return new Response(bodyText, { status, headers: headersOut });
|
|
591630
|
+
};
|
|
591631
|
+
}
|
|
591632
|
+
// Auto-install on every load if a remote share is active.
|
|
591633
|
+
try {
|
|
591634
|
+
if (getActiveRemoteShare()) installRemoteFetchProxy();
|
|
591635
|
+
} catch {}
|
|
590796
591636
|
function clearKey() {
|
|
590797
591637
|
apiKey = '';
|
|
590798
591638
|
localStorage.removeItem('oa-api-key');
|
|
@@ -590802,7 +591642,351 @@ function clearKey() {
|
|
|
590802
591642
|
}
|
|
590803
591643
|
function closeKeyModal() {
|
|
590804
591644
|
document.getElementById('key-modal').classList.remove('visible');
|
|
591645
|
+
const sr = document.getElementById('share-result'); if (sr) sr.style.display = 'none';
|
|
590805
591646
|
}
|
|
591647
|
+
function openKeyModal() {
|
|
591648
|
+
document.getElementById('key-modal').classList.add('visible');
|
|
591649
|
+
document.getElementById('key-input').value = apiKey;
|
|
591650
|
+
// Refresh the remote-state hint based on current localStorage.
|
|
591651
|
+
refreshKeyModalRemoteState();
|
|
591652
|
+
}
|
|
591653
|
+
window.openKeyModal = openKeyModal;
|
|
591654
|
+
|
|
591655
|
+
// ─── Share URL parsing ─────────────────────────────────────────────────
|
|
591656
|
+
// Accepts:
|
|
591657
|
+
// oa-share://<peerId>#<key> (libp2p, global)
|
|
591658
|
+
// oa-share://<peerId>@<host:port>#<key> (libp2p w/ LAN hint)
|
|
591659
|
+
// oa-share://<host:port>#<key> (legacy direct-HTTP)
|
|
591660
|
+
// http(s)://host:port/?oa-key=KEY[&oa-share-peer=PID&oa-share-label=L]
|
|
591661
|
+
// Returns { peerId?, host?, key, scheme?, label? } or null when the input
|
|
591662
|
+
// is a plain key. peerId is a libp2p PeerID (starts with 12D3KooW or Qm).
|
|
591663
|
+
function _looksLikePeerId(s) {
|
|
591664
|
+
if (!s || typeof s !== 'string') return false;
|
|
591665
|
+
// libp2p PeerIDs are base58-encoded multihashes, typically starting with
|
|
591666
|
+
// 12D3KooW (Ed25519) or Qm (RSA). Length ~46-52 chars, no dots or colons.
|
|
591667
|
+
return /^(12D3KooW|Qm)[1-9A-HJ-NP-Za-km-z]{30,}$/.test(s);
|
|
591668
|
+
}
|
|
591669
|
+
function parseShareInput(raw) {
|
|
591670
|
+
const v = String(raw || '').trim();
|
|
591671
|
+
if (!v) return null;
|
|
591672
|
+
// oa-share scheme — custom parser since URL() doesn't always honor it.
|
|
591673
|
+
if (v.toLowerCase().startsWith('oa-share://')) {
|
|
591674
|
+
const after = v.slice('oa-share://'.length);
|
|
591675
|
+
const hashIdx = after.indexOf('#');
|
|
591676
|
+
if (hashIdx < 0) return null;
|
|
591677
|
+
const hostPart = after.slice(0, hashIdx);
|
|
591678
|
+
const key = after.slice(hashIdx + 1);
|
|
591679
|
+
if (!hostPart || !key) return null;
|
|
591680
|
+
// Three shapes:
|
|
591681
|
+
// peerId@host:port → libp2p+LAN
|
|
591682
|
+
// peerId → libp2p only (no host)
|
|
591683
|
+
// host:port → legacy direct
|
|
591684
|
+
const atIdx = hostPart.indexOf('@');
|
|
591685
|
+
if (atIdx >= 0) {
|
|
591686
|
+
const peerId = hostPart.slice(0, atIdx);
|
|
591687
|
+
const host = hostPart.slice(atIdx + 1);
|
|
591688
|
+
return { peerId: _looksLikePeerId(peerId) ? peerId : null, host, key, scheme: 'http' };
|
|
591689
|
+
}
|
|
591690
|
+
if (_looksLikePeerId(hostPart)) {
|
|
591691
|
+
return { peerId: hostPart, host: null, key, scheme: 'libp2p' };
|
|
591692
|
+
}
|
|
591693
|
+
return { peerId: null, host: hostPart, key, scheme: 'http' };
|
|
591694
|
+
}
|
|
591695
|
+
// http(s) URL with ?oa-key=, optional ?oa-share-peer=, optional ?oa-onion=
|
|
591696
|
+
if (/^https?:\\/\\//i.test(v)) {
|
|
591697
|
+
try {
|
|
591698
|
+
const u = new URL(v);
|
|
591699
|
+
const k = u.searchParams.get('oa-key');
|
|
591700
|
+
if (!k) return null;
|
|
591701
|
+
const peerIdQ = u.searchParams.get('oa-share-peer') || null;
|
|
591702
|
+
const onionQ = u.searchParams.get('oa-onion') || null;
|
|
591703
|
+
const label = u.searchParams.get('oa-share-label') || '';
|
|
591704
|
+
return {
|
|
591705
|
+
peerId: _looksLikePeerId(peerIdQ) ? peerIdQ : null,
|
|
591706
|
+
onion: (onionQ && onionQ.endsWith('.onion')) ? onionQ : null,
|
|
591707
|
+
host: u.host, key: k,
|
|
591708
|
+
scheme: u.protocol.replace(':', ''), label,
|
|
591709
|
+
};
|
|
591710
|
+
} catch { return null; }
|
|
591711
|
+
}
|
|
591712
|
+
return null;
|
|
591713
|
+
}
|
|
591714
|
+
|
|
591715
|
+
function onKeyInputChange(v) {
|
|
591716
|
+
const hint = document.getElementById('key-input-hint');
|
|
591717
|
+
if (!hint) return;
|
|
591718
|
+
const parsed = parseShareInput(v);
|
|
591719
|
+
if (parsed) {
|
|
591720
|
+
hint.innerHTML = '✓ detected share URL — host <code>' + escapeHtml(parsed.host) + '</code>; clicking save will open the remote UI with this key';
|
|
591721
|
+
hint.style.color = 'var(--color-success)';
|
|
591722
|
+
} else {
|
|
591723
|
+
hint.innerHTML = 'Tip: paste an <code>oa-share://host:port#key</code> URL or <code>http://host:port/?oa-key=…</code> to connect to a remote OA instance.';
|
|
591724
|
+
hint.style.color = 'var(--color-fg-muted)';
|
|
591725
|
+
}
|
|
591726
|
+
showRecentKeysDropdown();
|
|
591727
|
+
}
|
|
591728
|
+
|
|
591729
|
+
// Tiny HTML escape — same as the one used in connections settings.
|
|
591730
|
+
function escapeHtml(s) {
|
|
591731
|
+
return String(s || '').replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, ''');
|
|
591732
|
+
}
|
|
591733
|
+
|
|
591734
|
+
// ─── Recent keys (localStorage history with autocomplete dropdown) ──
|
|
591735
|
+
const _OA_RECENT_KEYS_LS = 'oa.recentKeys';
|
|
591736
|
+
const _OA_RECENT_KEYS_MAX = 10;
|
|
591737
|
+
function loadRecentKeys() {
|
|
591738
|
+
try {
|
|
591739
|
+
const raw = localStorage.getItem(_OA_RECENT_KEYS_LS);
|
|
591740
|
+
if (!raw) return [];
|
|
591741
|
+
const parsed = JSON.parse(raw);
|
|
591742
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
591743
|
+
} catch { return []; }
|
|
591744
|
+
}
|
|
591745
|
+
function saveRecentKey(rec) {
|
|
591746
|
+
if (!rec || !rec.key) return;
|
|
591747
|
+
let list = loadRecentKeys();
|
|
591748
|
+
// Move existing entry with same key to top; otherwise prepend.
|
|
591749
|
+
list = list.filter(r => r.key !== rec.key);
|
|
591750
|
+
list.unshift({ ...rec, lastUsed: new Date().toISOString() });
|
|
591751
|
+
if (list.length > _OA_RECENT_KEYS_MAX) list = list.slice(0, _OA_RECENT_KEYS_MAX);
|
|
591752
|
+
try { localStorage.setItem(_OA_RECENT_KEYS_LS, JSON.stringify(list)); } catch {}
|
|
591753
|
+
}
|
|
591754
|
+
function deleteRecentKey(key) {
|
|
591755
|
+
let list = loadRecentKeys().filter(r => r.key !== key);
|
|
591756
|
+
try { localStorage.setItem(_OA_RECENT_KEYS_LS, JSON.stringify(list)); } catch {}
|
|
591757
|
+
showRecentKeysDropdown();
|
|
591758
|
+
}
|
|
591759
|
+
window.deleteRecentKey = deleteRecentKey;
|
|
591760
|
+
|
|
591761
|
+
function showRecentKeysDropdown() {
|
|
591762
|
+
const dd = document.getElementById('key-recent-dropdown');
|
|
591763
|
+
if (!dd) return;
|
|
591764
|
+
const recents = loadRecentKeys();
|
|
591765
|
+
const inp = document.getElementById('key-input');
|
|
591766
|
+
const filter = (inp && inp.value || '').toLowerCase();
|
|
591767
|
+
const matches = recents.filter(r => {
|
|
591768
|
+
if (!filter) return true;
|
|
591769
|
+
return (r.key || '').toLowerCase().includes(filter)
|
|
591770
|
+
|| (r.host || '').toLowerCase().includes(filter)
|
|
591771
|
+
|| (r.label || '').toLowerCase().includes(filter);
|
|
591772
|
+
});
|
|
591773
|
+
if (matches.length === 0) { dd.style.display = 'none'; return; }
|
|
591774
|
+
dd.innerHTML = matches.map(r => {
|
|
591775
|
+
const k = String(r.key || '');
|
|
591776
|
+
const masked = k.length > 12 ? k.slice(0, 4) + '…' + k.slice(-4) : k;
|
|
591777
|
+
const host = escapeHtml(r.host || '');
|
|
591778
|
+
const label = escapeHtml(r.label || '');
|
|
591779
|
+
const keySafe = k.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, "\\\\'");
|
|
591780
|
+
return '<div class="oa-rec-key" style="display:flex;align-items:center;gap:8px;padding:6px 10px;cursor:pointer;border-bottom:1px solid var(--color-border)" '
|
|
591781
|
+
+ 'onclick="useRecentKey(\\'' + keySafe + '\\')" '
|
|
591782
|
+
+ 'onmouseover="this.style.background=\\'var(--color-bg-hover)\\'" '
|
|
591783
|
+
+ 'onmouseout="this.style.background=\\'transparent\\'">'
|
|
591784
|
+
+ '<span style="flex:1;font-family:var(--font-mono);font-size:0.78rem"><span style="color:var(--color-fg-muted)">' + (host || 'local') + '</span> · <code>' + masked + '</code></span>'
|
|
591785
|
+
+ '<span style="font-size:0.7rem;color:var(--color-fg-muted)">' + label + '</span>'
|
|
591786
|
+
+ '<button type="button" onclick="event.stopPropagation();deleteRecentKey(\\'' + keySafe + '\\')" '
|
|
591787
|
+
+ 'title="Forget this key" '
|
|
591788
|
+
+ 'style="background:transparent;border:none;color:var(--color-fg-muted);cursor:pointer;font-size:1rem;padding:0 4px">×</button>'
|
|
591789
|
+
+ '</div>';
|
|
591790
|
+
}).join('');
|
|
591791
|
+
dd.style.display = 'block';
|
|
591792
|
+
}
|
|
591793
|
+
function hideRecentKeysDropdown() {
|
|
591794
|
+
const dd = document.getElementById('key-recent-dropdown');
|
|
591795
|
+
if (dd) dd.style.display = 'none';
|
|
591796
|
+
}
|
|
591797
|
+
function useRecentKey(k) {
|
|
591798
|
+
const inp = document.getElementById('key-input');
|
|
591799
|
+
if (inp) {
|
|
591800
|
+
inp.value = k;
|
|
591801
|
+
inp.focus();
|
|
591802
|
+
onKeyInputChange(k);
|
|
591803
|
+
}
|
|
591804
|
+
hideRecentKeysDropdown();
|
|
591805
|
+
}
|
|
591806
|
+
window.useRecentKey = useRecentKey;
|
|
591807
|
+
|
|
591808
|
+
// ─── Generate share URL ────────────────────────────────────────────────
|
|
591809
|
+
async function generateShareUrl() {
|
|
591810
|
+
const out = document.getElementById('share-result');
|
|
591811
|
+
if (!out) return;
|
|
591812
|
+
out.style.display = 'block';
|
|
591813
|
+
out.innerHTML = '<div style="color:var(--color-fg-muted)">generating…</div>';
|
|
591814
|
+
try {
|
|
591815
|
+
const r = await fetch('/v1/share/generate', {
|
|
591816
|
+
method: 'POST',
|
|
591817
|
+
headers: { ...headers(), 'Content-Type': 'application/json' },
|
|
591818
|
+
body: JSON.stringify({ scope: 'run' }),
|
|
591819
|
+
});
|
|
591820
|
+
if (r.status === 403) {
|
|
591821
|
+
out.innerHTML = '<div style="color:var(--color-error)">✗ admin scope required — your current key does not have permission to mint share URLs. Set an admin-scope key first.</div>';
|
|
591822
|
+
return;
|
|
591823
|
+
}
|
|
591824
|
+
if (r.status >= 400) {
|
|
591825
|
+
const err = await r.json().catch(() => ({}));
|
|
591826
|
+
out.innerHTML = '<div style="color:var(--color-error)">✗ HTTP ' + r.status + (err.detail ? ' — ' + escapeHtml(err.detail) : '') + '</div>';
|
|
591827
|
+
return;
|
|
591828
|
+
}
|
|
591829
|
+
const j = await r.json();
|
|
591830
|
+
const safeShare = escapeHtml(j.shareUrl || '');
|
|
591831
|
+
const safePlain = escapeHtml(j.plainUrl || '');
|
|
591832
|
+
out.innerHTML =
|
|
591833
|
+
'<div style="font-weight:500;margin-bottom:6px;color:var(--color-success)">✓ Share URL generated — hand off to remote</div>' +
|
|
591834
|
+
'<div style="margin:6px 0">' +
|
|
591835
|
+
'<label style="display:block;font-size:0.7rem;color:var(--color-fg-muted);margin-bottom:2px">oa-share URL (compact, recommended for OA-to-OA)</label>' +
|
|
591836
|
+
'<div style="display:flex;gap:6px;align-items:center">' +
|
|
591837
|
+
'<input readonly value="' + safeShare + '" style="flex:1;background:var(--color-bg-input);border:1px solid var(--color-border);color:var(--color-fg);padding:5px 8px;border-radius:var(--radius-sm);font-family:var(--font-mono);font-size:0.74rem">' +
|
|
591838
|
+
'<button type="button" onclick="copyShareUrl(\\'oa-share\\')" style="font-size:0.74rem">copy</button>' +
|
|
591839
|
+
'</div>' +
|
|
591840
|
+
'</div>' +
|
|
591841
|
+
'<div style="margin:6px 0">' +
|
|
591842
|
+
'<label style="display:block;font-size:0.7rem;color:var(--color-fg-muted);margin-bottom:2px">plain URL (works in any browser, no scheme handler needed)</label>' +
|
|
591843
|
+
'<div style="display:flex;gap:6px;align-items:center">' +
|
|
591844
|
+
'<input readonly value="' + safePlain + '" style="flex:1;background:var(--color-bg-input);border:1px solid var(--color-border);color:var(--color-fg);padding:5px 8px;border-radius:var(--radius-sm);font-family:var(--font-mono);font-size:0.74rem">' +
|
|
591845
|
+
'<button type="button" onclick="copyShareUrl(\\'plain\\')" style="font-size:0.74rem">copy</button>' +
|
|
591846
|
+
'</div>' +
|
|
591847
|
+
'</div>' +
|
|
591848
|
+
'<p style="font-size:0.68rem;color:var(--color-fg-muted);margin:6px 0 0">Note: this URL contains the full secret. Anyone with it can use this OA. To revoke: open Advanced settings → keys → revoke the prefix <code>' + escapeHtml(j.keyPrefix || '') + '</code>.</p>';
|
|
591849
|
+
// Stash for the copy buttons + add to recent.
|
|
591850
|
+
window.__oaLastShareUrl = j.shareUrl;
|
|
591851
|
+
window.__oaLastPlainUrl = j.plainUrl;
|
|
591852
|
+
saveRecentKey({ key: j.key, host: j.host + ':' + j.port, label: j.label || ('shared ' + j.host) });
|
|
591853
|
+
} catch (e) {
|
|
591854
|
+
out.innerHTML = '<div style="color:var(--color-error)">✗ ' + escapeHtml(e && e.message ? e.message : String(e)) + '</div>';
|
|
591855
|
+
}
|
|
591856
|
+
}
|
|
591857
|
+
function copyShareUrl(which) {
|
|
591858
|
+
const v = which === 'plain' ? window.__oaLastPlainUrl : window.__oaLastShareUrl;
|
|
591859
|
+
if (!v) return;
|
|
591860
|
+
if (navigator.clipboard && navigator.clipboard.writeText) {
|
|
591861
|
+
navigator.clipboard.writeText(v).then(
|
|
591862
|
+
() => { /* ok */ },
|
|
591863
|
+
() => { fallbackCopy(v); }
|
|
591864
|
+
);
|
|
591865
|
+
} else {
|
|
591866
|
+
fallbackCopy(v);
|
|
591867
|
+
}
|
|
591868
|
+
}
|
|
591869
|
+
function fallbackCopy(v) {
|
|
591870
|
+
const ta = document.createElement('textarea');
|
|
591871
|
+
ta.value = v; document.body.appendChild(ta); ta.select();
|
|
591872
|
+
try { document.execCommand('copy'); } catch {}
|
|
591873
|
+
document.body.removeChild(ta);
|
|
591874
|
+
}
|
|
591875
|
+
window.generateShareUrl = generateShareUrl;
|
|
591876
|
+
window.copyShareUrl = copyShareUrl;
|
|
591877
|
+
|
|
591878
|
+
// ─── Remote-state helpers (visual indicator on the key button) ───────
|
|
591879
|
+
// When localStorage carries oa.remoteHost we are in REMOTE mode: the
|
|
591880
|
+
// key was loaded from an oa-share URL or via on-load ?oa-key=. The key
|
|
591881
|
+
// button shows a "remote" badge and clicking expands to show host+key
|
|
591882
|
+
// inline with a "close connection" button that severs and shuffles the
|
|
591883
|
+
// key into recents.
|
|
591884
|
+
function refreshKeyModalRemoteState() {
|
|
591885
|
+
// Two remote modes coexist:
|
|
591886
|
+
// 1. libp2p — oa.activeRemoteShare = {peerId, key, host?, label}
|
|
591887
|
+
// 2. direct — oa.remoteHost (legacy, set by ?oa-key= pickup)
|
|
591888
|
+
const active = getActiveRemoteShare();
|
|
591889
|
+
const directHost = (function() {
|
|
591890
|
+
try { return localStorage.getItem('oa.remoteHost') || ''; } catch { return ''; }
|
|
591891
|
+
})();
|
|
591892
|
+
const isRemote = !!active || !!directHost;
|
|
591893
|
+
let remoteLabel;
|
|
591894
|
+
if (active) {
|
|
591895
|
+
const parts = [];
|
|
591896
|
+
if (active.peerId) parts.push('libp2p ' + active.peerId.slice(0, 12) + '…');
|
|
591897
|
+
if (active.onion) parts.push('tor ' + active.onion.slice(0, 16) + '…');
|
|
591898
|
+
if (active.host) parts.push(active.host);
|
|
591899
|
+
remoteLabel = parts.join(' / ') || 'remote';
|
|
591900
|
+
} else {
|
|
591901
|
+
remoteLabel = directHost;
|
|
591902
|
+
}
|
|
591903
|
+
const stateBox = document.getElementById('remote-state');
|
|
591904
|
+
const btn = document.getElementById('sidebar-key-btn');
|
|
591905
|
+
if (isRemote && btn) {
|
|
591906
|
+
btn.textContent = 'remote';
|
|
591907
|
+
btn.style.background = 'var(--color-accent)';
|
|
591908
|
+
btn.style.color = '#fff';
|
|
591909
|
+
btn.style.borderColor = 'var(--color-accent)';
|
|
591910
|
+
btn.title = 'connected to ' + remoteLabel + ' — click to view / disconnect';
|
|
591911
|
+
} else if (btn) {
|
|
591912
|
+
btn.textContent = 'key';
|
|
591913
|
+
btn.style.background = 'transparent';
|
|
591914
|
+
btn.style.color = 'var(--color-fg-muted)';
|
|
591915
|
+
btn.style.borderColor = 'var(--color-border)';
|
|
591916
|
+
btn.title = 'set API key / share access';
|
|
591917
|
+
}
|
|
591918
|
+
if (!stateBox) return;
|
|
591919
|
+
if (isRemote) {
|
|
591920
|
+
const safe = escapeHtml(remoteLabel);
|
|
591921
|
+
let mode;
|
|
591922
|
+
if (active) {
|
|
591923
|
+
const tiers = [];
|
|
591924
|
+
if (active.peerId) tiers.push('libp2p');
|
|
591925
|
+
if (active.onion) tiers.push('tor');
|
|
591926
|
+
mode = tiers.join(' + ') + ' (global)';
|
|
591927
|
+
} else {
|
|
591928
|
+
mode = 'direct (LAN/VPN)';
|
|
591929
|
+
}
|
|
591930
|
+
stateBox.style.display = 'block';
|
|
591931
|
+
stateBox.innerHTML =
|
|
591932
|
+
'<div style="font-weight:500;color:var(--color-accent)">REMOTE connection active</div>' +
|
|
591933
|
+
'<div style="margin-top:4px;font-size:0.74rem">mode <code>' + escapeHtml(mode) + '</code></div>' +
|
|
591934
|
+
'<div style="margin-top:2px;font-size:0.74rem">target <code>' + safe + '</code></div>' +
|
|
591935
|
+
'<div style="margin-top:8px"><button type="button" onclick="closeRemoteConnection()" style="background:var(--color-error);color:#fff;border:none;padding:4px 10px;border-radius:var(--radius-sm);cursor:pointer;font-size:0.74rem">close connection</button></div>';
|
|
591936
|
+
} else {
|
|
591937
|
+
stateBox.style.display = 'none';
|
|
591938
|
+
}
|
|
591939
|
+
}
|
|
591940
|
+
function closeRemoteConnection() {
|
|
591941
|
+
// Save the active remote into recents before clearing.
|
|
591942
|
+
const active = getActiveRemoteShare();
|
|
591943
|
+
if (active) {
|
|
591944
|
+
saveRecentKey({
|
|
591945
|
+
key: active.key, peerId: active.peerId, host: active.host,
|
|
591946
|
+
label: 'recent ' + (active.label || ('remote ' + (active.peerId || '').slice(0, 12) + '…')),
|
|
591947
|
+
});
|
|
591948
|
+
clearActiveRemoteShare();
|
|
591949
|
+
} else {
|
|
591950
|
+
let savedKey = ''; let savedHost = '';
|
|
591951
|
+
try {
|
|
591952
|
+
savedKey = localStorage.getItem('oa-api-key') || '';
|
|
591953
|
+
savedHost = localStorage.getItem('oa.remoteHost') || '';
|
|
591954
|
+
} catch {}
|
|
591955
|
+
if (savedKey) saveRecentKey({ key: savedKey, host: savedHost, label: 'recent remote ' + savedHost });
|
|
591956
|
+
}
|
|
591957
|
+
try {
|
|
591958
|
+
localStorage.removeItem('oa.remoteHost');
|
|
591959
|
+
localStorage.removeItem('oa.remoteScheme');
|
|
591960
|
+
localStorage.removeItem('oa-api-key');
|
|
591961
|
+
} catch {}
|
|
591962
|
+
apiKey = '';
|
|
591963
|
+
refreshKeyModalRemoteState();
|
|
591964
|
+
location.reload();
|
|
591965
|
+
}
|
|
591966
|
+
window.closeRemoteConnection = closeRemoteConnection;
|
|
591967
|
+
|
|
591968
|
+
// ─── On-load: ?oa-key=... pickup ───────────────────────────────────────
|
|
591969
|
+
// When the page loads with an oa-key query param (i.e. someone clicked
|
|
591970
|
+
// a share URL), capture the key into localStorage, mark this as a
|
|
591971
|
+
// remote session (host = this origin), and clean the URL.
|
|
591972
|
+
(function pickupShareKeyFromUrl() {
|
|
591973
|
+
try {
|
|
591974
|
+
const u = new URL(location.href);
|
|
591975
|
+
const k = u.searchParams.get('oa-key');
|
|
591976
|
+
if (!k) return;
|
|
591977
|
+
const label = u.searchParams.get('oa-share-label') || '';
|
|
591978
|
+
localStorage.setItem('oa-api-key', k);
|
|
591979
|
+
// Origin-based remote: when the page loaded from a different host
|
|
591980
|
+
// than the user's "home" OA, that's a remote session by definition.
|
|
591981
|
+
localStorage.setItem('oa.remoteHost', location.host);
|
|
591982
|
+
localStorage.setItem('oa.remoteScheme', location.protocol.replace(':', ''));
|
|
591983
|
+
saveRecentKey({ key: k, host: location.host, label: label || ('remote ' + location.host) });
|
|
591984
|
+
// Strip the key from the URL so it isn't visible / browser-history'd.
|
|
591985
|
+
u.searchParams.delete('oa-key');
|
|
591986
|
+
u.searchParams.delete('oa-share-label');
|
|
591987
|
+
history.replaceState({}, '', u.pathname + (u.search || '') + (u.hash || ''));
|
|
591988
|
+
} catch {}
|
|
591989
|
+
})();
|
|
590806
591990
|
|
|
590807
591991
|
// Tab switching
|
|
590808
591992
|
const allPanels = ['chat-container','agent-panel','jobs-panel','config-panel','activity-panel','projects-panel','voice-panel'];
|
|
@@ -591536,6 +592720,11 @@ function newChatSession() {
|
|
|
591536
592720
|
switchSession('');
|
|
591537
592721
|
const sel = document.getElementById('chat-session-select');
|
|
591538
592722
|
if (sel) sel.value = '';
|
|
592723
|
+
// FRESH-SESSION: mark the next chat send as fresh so the daemon skips
|
|
592724
|
+
// cross-task handoff injection (which previously bled prior session
|
|
592725
|
+
// context into the new chat regardless of the browser's reset).
|
|
592726
|
+
// Cleared inside the chat send handler after one use.
|
|
592727
|
+
try { localStorage.setItem('oa.freshSessionPending', '1'); } catch {}
|
|
591539
592728
|
}
|
|
591540
592729
|
function deleteChatSession() {
|
|
591541
592730
|
if (!chatSessionId) return;
|
|
@@ -592399,6 +593588,7 @@ async function doUpdate() {
|
|
|
592399
593588
|
try { pollMetrics(); } catch {}
|
|
592400
593589
|
try { loadScheduled(); } catch {}
|
|
592401
593590
|
try { loadServices(); } catch {}
|
|
593591
|
+
try { refreshKeyModalRemoteState(); } catch {}
|
|
592402
593592
|
|
|
592403
593593
|
btn.textContent = 'updated v' + newVersion;
|
|
592404
593594
|
btn.style.background = '#1a3a1a';
|
|
@@ -593383,6 +594573,7 @@ $currentProject.subscribe((proj) => {
|
|
|
593383
594573
|
try { if (typeof updateSessionSelect === 'function') updateSessionSelect(); } catch {}
|
|
593384
594574
|
try { if (typeof updateAgentRunSelect === 'function') updateAgentRunSelect(); } catch {}
|
|
593385
594575
|
try { if (typeof restoreChatSession === 'function') restoreChatSession(); } catch {}
|
|
594576
|
+
try { if (typeof refreshKeyModalRemoteState === 'function') refreshKeyModalRemoteState(); } catch {}
|
|
593386
594577
|
});
|
|
593387
594578
|
|
|
593388
594579
|
// $selectedModel changes update the visible <select> if it's not
|
|
@@ -595561,15 +596752,15 @@ var init_auth_oidc = __esm({
|
|
|
595561
596752
|
});
|
|
595562
596753
|
|
|
595563
596754
|
// packages/cli/src/api/usage-tracker.ts
|
|
595564
|
-
import { mkdirSync as mkdirSync60, readFileSync as
|
|
595565
|
-
import { join as
|
|
596755
|
+
import { mkdirSync as mkdirSync60, readFileSync as readFileSync84, writeFileSync as writeFileSync52, existsSync as existsSync103 } from "node:fs";
|
|
596756
|
+
import { join as join119 } from "node:path";
|
|
595566
596757
|
function initUsageTracker(oaDir) {
|
|
595567
|
-
const dir =
|
|
596758
|
+
const dir = join119(oaDir, "usage");
|
|
595568
596759
|
mkdirSync60(dir, { recursive: true });
|
|
595569
|
-
usageFile =
|
|
596760
|
+
usageFile = join119(dir, "token-usage.json");
|
|
595570
596761
|
try {
|
|
595571
|
-
if (
|
|
595572
|
-
store = JSON.parse(
|
|
596762
|
+
if (existsSync103(usageFile)) {
|
|
596763
|
+
store = JSON.parse(readFileSync84(usageFile, "utf-8"));
|
|
595573
596764
|
}
|
|
595574
596765
|
} catch {
|
|
595575
596766
|
store = { providers: {}, lastSaved: "" };
|
|
@@ -595633,24 +596824,24 @@ var init_usage_tracker = __esm({
|
|
|
595633
596824
|
});
|
|
595634
596825
|
|
|
595635
596826
|
// packages/cli/src/api/profiles.ts
|
|
595636
|
-
import { existsSync as
|
|
595637
|
-
import { join as
|
|
595638
|
-
import { homedir as
|
|
596827
|
+
import { existsSync as existsSync104, readFileSync as readFileSync85, writeFileSync as writeFileSync53, mkdirSync as mkdirSync61, readdirSync as readdirSync35, unlinkSync as unlinkSync23 } from "node:fs";
|
|
596828
|
+
import { join as join120 } from "node:path";
|
|
596829
|
+
import { homedir as homedir41 } from "node:os";
|
|
595639
596830
|
import { createCipheriv as createCipheriv4, createDecipheriv as createDecipheriv4, randomBytes as randomBytes22, scryptSync as scryptSync3 } from "node:crypto";
|
|
595640
596831
|
function globalProfileDir() {
|
|
595641
|
-
return
|
|
596832
|
+
return join120(homedir41(), ".open-agents", "profiles");
|
|
595642
596833
|
}
|
|
595643
596834
|
function projectProfileDir(projectDir2) {
|
|
595644
|
-
return
|
|
596835
|
+
return join120(projectDir2 || process.cwd(), ".oa", "profiles");
|
|
595645
596836
|
}
|
|
595646
596837
|
function listProfiles(projectDir2) {
|
|
595647
596838
|
const result = [];
|
|
595648
596839
|
const seen = /* @__PURE__ */ new Set();
|
|
595649
596840
|
const projDir = projectProfileDir(projectDir2);
|
|
595650
|
-
if (
|
|
596841
|
+
if (existsSync104(projDir)) {
|
|
595651
596842
|
for (const f2 of readdirSync35(projDir).filter((f3) => f3.endsWith(".json"))) {
|
|
595652
596843
|
try {
|
|
595653
|
-
const raw = JSON.parse(
|
|
596844
|
+
const raw = JSON.parse(readFileSync85(join120(projDir, f2), "utf8"));
|
|
595654
596845
|
const name10 = f2.replace(".json", "");
|
|
595655
596846
|
seen.add(name10);
|
|
595656
596847
|
result.push({
|
|
@@ -595664,12 +596855,12 @@ function listProfiles(projectDir2) {
|
|
|
595664
596855
|
}
|
|
595665
596856
|
}
|
|
595666
596857
|
const globDir = globalProfileDir();
|
|
595667
|
-
if (
|
|
596858
|
+
if (existsSync104(globDir)) {
|
|
595668
596859
|
for (const f2 of readdirSync35(globDir).filter((f3) => f3.endsWith(".json"))) {
|
|
595669
596860
|
const name10 = f2.replace(".json", "");
|
|
595670
596861
|
if (seen.has(name10)) continue;
|
|
595671
596862
|
try {
|
|
595672
|
-
const raw = JSON.parse(
|
|
596863
|
+
const raw = JSON.parse(readFileSync85(join120(globDir, f2), "utf8"));
|
|
595673
596864
|
result.push({
|
|
595674
596865
|
name: name10,
|
|
595675
596866
|
description: raw.description || "",
|
|
@@ -595684,11 +596875,11 @@ function listProfiles(projectDir2) {
|
|
|
595684
596875
|
}
|
|
595685
596876
|
function loadProfile(name10, password, projectDir2) {
|
|
595686
596877
|
const sanitized = name10.replace(/[^a-zA-Z0-9_-]/g, "");
|
|
595687
|
-
const projPath =
|
|
595688
|
-
const globPath =
|
|
595689
|
-
const filePath =
|
|
596878
|
+
const projPath = join120(projectProfileDir(projectDir2), `${sanitized}.json`);
|
|
596879
|
+
const globPath = join120(globalProfileDir(), `${sanitized}.json`);
|
|
596880
|
+
const filePath = existsSync104(projPath) ? projPath : existsSync104(globPath) ? globPath : null;
|
|
595690
596881
|
if (!filePath) return null;
|
|
595691
|
-
const raw = JSON.parse(
|
|
596882
|
+
const raw = JSON.parse(readFileSync85(filePath, "utf8"));
|
|
595692
596883
|
if (raw.encrypted === true) {
|
|
595693
596884
|
if (!password) return null;
|
|
595694
596885
|
return decryptProfile(raw, password);
|
|
@@ -595699,7 +596890,7 @@ function saveProfile(profile, password, scope = "global", projectDir2) {
|
|
|
595699
596890
|
const dir = scope === "project" ? projectProfileDir(projectDir2) : globalProfileDir();
|
|
595700
596891
|
mkdirSync61(dir, { recursive: true });
|
|
595701
596892
|
const sanitized = profile.name.replace(/[^a-zA-Z0-9_-]/g, "");
|
|
595702
|
-
const filePath =
|
|
596893
|
+
const filePath = join120(dir, `${sanitized}.json`);
|
|
595703
596894
|
profile.modified = (/* @__PURE__ */ new Date()).toISOString();
|
|
595704
596895
|
if (password) {
|
|
595705
596896
|
const encrypted = encryptProfile(profile, password);
|
|
@@ -595712,8 +596903,8 @@ function saveProfile(profile, password, scope = "global", projectDir2) {
|
|
|
595712
596903
|
function deleteProfile(name10, scope = "global", projectDir2) {
|
|
595713
596904
|
const sanitized = name10.replace(/[^a-zA-Z0-9_-]/g, "");
|
|
595714
596905
|
const dir = scope === "project" ? projectProfileDir(projectDir2) : globalProfileDir();
|
|
595715
|
-
const filePath =
|
|
595716
|
-
if (
|
|
596906
|
+
const filePath = join120(dir, `${sanitized}.json`);
|
|
596907
|
+
if (existsSync104(filePath)) {
|
|
595717
596908
|
unlinkSync23(filePath);
|
|
595718
596909
|
return true;
|
|
595719
596910
|
}
|
|
@@ -595828,23 +597019,23 @@ var init_profiles = __esm({
|
|
|
595828
597019
|
|
|
595829
597020
|
// packages/cli/src/docker.ts
|
|
595830
597021
|
import { execSync as execSync56, spawn as spawn24 } from "node:child_process";
|
|
595831
|
-
import { existsSync as
|
|
595832
|
-
import { join as
|
|
595833
|
-
import { homedir as
|
|
597022
|
+
import { existsSync as existsSync105, mkdirSync as mkdirSync62, writeFileSync as writeFileSync54 } from "node:fs";
|
|
597023
|
+
import { join as join121, resolve as resolve37, dirname as dirname35 } from "node:path";
|
|
597024
|
+
import { homedir as homedir42 } from "node:os";
|
|
595834
597025
|
import { fileURLToPath as fileURLToPath16 } from "node:url";
|
|
595835
597026
|
function getDockerDir() {
|
|
595836
597027
|
try {
|
|
595837
597028
|
if (typeof __dirname !== "undefined") {
|
|
595838
|
-
return
|
|
597029
|
+
return join121(__dirname, "..", "..", "..", "docker");
|
|
595839
597030
|
}
|
|
595840
597031
|
} catch {
|
|
595841
597032
|
}
|
|
595842
597033
|
try {
|
|
595843
597034
|
const thisDir = dirname35(fileURLToPath16(import.meta.url));
|
|
595844
|
-
return
|
|
597035
|
+
return join121(thisDir, "..", "..", "..", "docker");
|
|
595845
597036
|
} catch {
|
|
595846
597037
|
}
|
|
595847
|
-
return
|
|
597038
|
+
return join121(process.cwd(), "docker");
|
|
595848
597039
|
}
|
|
595849
597040
|
function isDockerAvailable() {
|
|
595850
597041
|
try {
|
|
@@ -595975,10 +597166,10 @@ async function ensureOaImage(force = false) {
|
|
|
595975
597166
|
}
|
|
595976
597167
|
let buildContext;
|
|
595977
597168
|
const dockerDir = getDockerDir();
|
|
595978
|
-
if (
|
|
597169
|
+
if (existsSync105(join121(dockerDir, "Dockerfile"))) {
|
|
595979
597170
|
buildContext = dockerDir;
|
|
595980
597171
|
} else {
|
|
595981
|
-
buildContext =
|
|
597172
|
+
buildContext = join121(homedir42(), ".oa", "docker-build");
|
|
595982
597173
|
mkdirSync62(buildContext, { recursive: true });
|
|
595983
597174
|
writeDockerfiles(buildContext);
|
|
595984
597175
|
}
|
|
@@ -596053,8 +597244,8 @@ chown -R node:node /workspace /home/node/.oa /home/node/.open-agents 2>/dev/null
|
|
|
596053
597244
|
if [ "$1" = "oa" ]; then shift; exec su - node -c "cd /workspace && oa $*"; fi
|
|
596054
597245
|
exec "$@"
|
|
596055
597246
|
`;
|
|
596056
|
-
writeFileSync54(
|
|
596057
|
-
writeFileSync54(
|
|
597247
|
+
writeFileSync54(join121(dir, "Dockerfile"), dockerfile);
|
|
597248
|
+
writeFileSync54(join121(dir, "docker-entrypoint.sh"), entrypoint, { mode: 493 });
|
|
596058
597249
|
}
|
|
596059
597250
|
function hasNvidiaGpu() {
|
|
596060
597251
|
try {
|
|
@@ -596307,23 +597498,23 @@ import * as http5 from "node:http";
|
|
|
596307
597498
|
import * as https3 from "node:https";
|
|
596308
597499
|
import { createRequire as createRequire5 } from "node:module";
|
|
596309
597500
|
import { fileURLToPath as fileURLToPath17 } from "node:url";
|
|
596310
|
-
import { dirname as dirname36, join as
|
|
596311
|
-
import { homedir as
|
|
597501
|
+
import { dirname as dirname36, join as join122, resolve as resolve38 } from "node:path";
|
|
597502
|
+
import { homedir as homedir43 } from "node:os";
|
|
596312
597503
|
import { spawn as spawn25, execSync as execSync57 } from "node:child_process";
|
|
596313
|
-
import { mkdirSync as mkdirSync63, writeFileSync as writeFileSync55, readFileSync as
|
|
597504
|
+
import { mkdirSync as mkdirSync63, writeFileSync as writeFileSync55, readFileSync as readFileSync86, readdirSync as readdirSync36, existsSync as existsSync106, watch as fsWatch3, renameSync as renameSync8, unlinkSync as unlinkSync24 } from "node:fs";
|
|
596314
597505
|
import { randomBytes as randomBytes23, randomUUID as randomUUID16 } from "node:crypto";
|
|
596315
597506
|
import { createHash as createHash19 } from "node:crypto";
|
|
596316
597507
|
function getVersion3() {
|
|
596317
597508
|
try {
|
|
596318
597509
|
const thisDir = dirname36(fileURLToPath17(import.meta.url));
|
|
596319
597510
|
const candidates = [
|
|
596320
|
-
|
|
596321
|
-
|
|
596322
|
-
|
|
597511
|
+
join122(thisDir, "..", "package.json"),
|
|
597512
|
+
join122(thisDir, "..", "..", "package.json"),
|
|
597513
|
+
join122(thisDir, "..", "..", "..", "package.json")
|
|
596323
597514
|
];
|
|
596324
597515
|
for (const pkgPath of candidates) {
|
|
596325
597516
|
try {
|
|
596326
|
-
if (!
|
|
597517
|
+
if (!existsSync106(pkgPath)) continue;
|
|
596327
597518
|
const pkg = require3(pkgPath);
|
|
596328
597519
|
if (pkg.name === "open-agents-ai" || pkg.name === "@open-agents/cli" || pkg.name === "@open-agents/monorepo") {
|
|
596329
597520
|
return pkg.version ?? "0.0.0";
|
|
@@ -596525,9 +597716,9 @@ function isOriginAllowed(origin) {
|
|
|
596525
597716
|
if (!origin) return true;
|
|
596526
597717
|
let accessMode = (process.env["OA_ACCESS"] || "").toLowerCase().trim();
|
|
596527
597718
|
try {
|
|
596528
|
-
const accessFile =
|
|
596529
|
-
if (
|
|
596530
|
-
const persisted =
|
|
597719
|
+
const accessFile = join122(homedir43(), ".open-agents", "access");
|
|
597720
|
+
if (existsSync106(accessFile)) {
|
|
597721
|
+
const persisted = readFileSync86(accessFile, "utf8").trim().toLowerCase();
|
|
596531
597722
|
if (persisted === "any" || persisted === "lan" || persisted === "loopback") {
|
|
596532
597723
|
accessMode = persisted;
|
|
596533
597724
|
}
|
|
@@ -596587,7 +597778,7 @@ async function retrieveMemoryContext(userMessage, sessionId, maxEpisodes = 5) {
|
|
|
596587
597778
|
if (!memMod || !memMod.EpisodeStore) {
|
|
596588
597779
|
return { contextBlock: "", retrieved: [] };
|
|
596589
597780
|
}
|
|
596590
|
-
const dbPath =
|
|
597781
|
+
const dbPath = join122(homedir43(), ".open-agents", "memory.db");
|
|
596591
597782
|
const store2 = new memMod.EpisodeStore(dbPath);
|
|
596592
597783
|
const recent = store2.search({ limit: 30, sessionId: void 0 }) ?? [];
|
|
596593
597784
|
const qLower = userMessage.toLowerCase();
|
|
@@ -596630,7 +597821,7 @@ async function writeMemoryEpisodes(sessionId, userMessage, assistantContent, too
|
|
|
596630
597821
|
try {
|
|
596631
597822
|
const memMod = await Promise.resolve().then(() => (init_dist7(), dist_exports2)).catch(() => null);
|
|
596632
597823
|
if (!memMod || !memMod.EpisodeStore) return 0;
|
|
596633
|
-
const dbPath =
|
|
597824
|
+
const dbPath = join122(homedir43(), ".open-agents", "memory.db");
|
|
596634
597825
|
const store2 = new memMod.EpisodeStore(dbPath);
|
|
596635
597826
|
let written = 0;
|
|
596636
597827
|
try {
|
|
@@ -596952,27 +598143,27 @@ function ollamaStream(ollamaUrl, path8, method, body, onData, onEnd, onError, ti
|
|
|
596952
598143
|
}
|
|
596953
598144
|
function jobsDir() {
|
|
596954
598145
|
const root = resolve38(process.cwd());
|
|
596955
|
-
const dir =
|
|
598146
|
+
const dir = join122(root, ".oa", "jobs");
|
|
596956
598147
|
mkdirSync63(dir, { recursive: true });
|
|
596957
598148
|
return dir;
|
|
596958
598149
|
}
|
|
596959
598150
|
function loadJob(id) {
|
|
596960
|
-
const file =
|
|
596961
|
-
if (!
|
|
598151
|
+
const file = join122(jobsDir(), `${id}.json`);
|
|
598152
|
+
if (!existsSync106(file)) return null;
|
|
596962
598153
|
try {
|
|
596963
|
-
return JSON.parse(
|
|
598154
|
+
return JSON.parse(readFileSync86(file, "utf-8"));
|
|
596964
598155
|
} catch {
|
|
596965
598156
|
return null;
|
|
596966
598157
|
}
|
|
596967
598158
|
}
|
|
596968
598159
|
function listJobs() {
|
|
596969
598160
|
const dir = jobsDir();
|
|
596970
|
-
if (!
|
|
598161
|
+
if (!existsSync106(dir)) return [];
|
|
596971
598162
|
const files = readdirSync36(dir).filter((f2) => f2.endsWith(".json")).sort();
|
|
596972
598163
|
const jobs = [];
|
|
596973
598164
|
for (const file of files) {
|
|
596974
598165
|
try {
|
|
596975
|
-
jobs.push(JSON.parse(
|
|
598166
|
+
jobs.push(JSON.parse(readFileSync86(join122(dir, file), "utf-8")));
|
|
596976
598167
|
} catch {
|
|
596977
598168
|
}
|
|
596978
598169
|
}
|
|
@@ -596982,14 +598173,14 @@ function pruneOldJobs() {
|
|
|
596982
598173
|
const retentionH = parseFloat(process.env["OA_RUN_RETENTION_H"] || "24");
|
|
596983
598174
|
const cutoffMs = Date.now() - (Number.isFinite(retentionH) && retentionH > 0 ? retentionH : 24) * 36e5;
|
|
596984
598175
|
const dir = jobsDir();
|
|
596985
|
-
if (!
|
|
598176
|
+
if (!existsSync106(dir)) return { pruned: 0, kept: 0 };
|
|
596986
598177
|
let pruned = 0;
|
|
596987
598178
|
let kept = 0;
|
|
596988
598179
|
for (const file of readdirSync36(dir)) {
|
|
596989
598180
|
if (!file.endsWith(".json")) continue;
|
|
596990
|
-
const path8 =
|
|
598181
|
+
const path8 = join122(dir, file);
|
|
596991
598182
|
try {
|
|
596992
|
-
const job = JSON.parse(
|
|
598183
|
+
const job = JSON.parse(readFileSync86(path8, "utf-8"));
|
|
596993
598184
|
if (job.status === "running") {
|
|
596994
598185
|
kept++;
|
|
596995
598186
|
continue;
|
|
@@ -597002,7 +598193,7 @@ function pruneOldJobs() {
|
|
|
597002
598193
|
} catch {
|
|
597003
598194
|
}
|
|
597004
598195
|
const outFile = path8.replace(/\.json$/, ".output");
|
|
597005
|
-
if (
|
|
598196
|
+
if (existsSync106(outFile)) {
|
|
597006
598197
|
try {
|
|
597007
598198
|
unlinkSync24(outFile);
|
|
597008
598199
|
} catch {
|
|
@@ -597295,7 +598486,7 @@ function autoSeedTodosFromPrompt(prompt) {
|
|
|
597295
598486
|
return [];
|
|
597296
598487
|
}
|
|
597297
598488
|
function atomicJobWrite(dir, id, job) {
|
|
597298
|
-
const finalPath =
|
|
598489
|
+
const finalPath = join122(dir, `${id}.json`);
|
|
597299
598490
|
const tmpPath = `${finalPath}.tmp.${process.pid}.${Date.now()}`;
|
|
597300
598491
|
try {
|
|
597301
598492
|
writeFileSync55(tmpPath, JSON.stringify(job, null, 2), "utf-8");
|
|
@@ -598721,23 +599912,23 @@ ${task}` : task;
|
|
|
598721
599912
|
});
|
|
598722
599913
|
}
|
|
598723
599914
|
function updateStateFile() {
|
|
598724
|
-
return
|
|
599915
|
+
return join122(homedir43(), ".open-agents", "update-state.json");
|
|
598725
599916
|
}
|
|
598726
599917
|
function updateLogPath() {
|
|
598727
|
-
return
|
|
599918
|
+
return join122(homedir43(), ".open-agents", "update.log");
|
|
598728
599919
|
}
|
|
598729
599920
|
function readUpdateState() {
|
|
598730
599921
|
try {
|
|
598731
599922
|
const p2 = updateStateFile();
|
|
598732
|
-
if (!
|
|
598733
|
-
return JSON.parse(
|
|
599923
|
+
if (!existsSync106(p2)) return null;
|
|
599924
|
+
return JSON.parse(readFileSync86(p2, "utf-8"));
|
|
598734
599925
|
} catch {
|
|
598735
599926
|
return null;
|
|
598736
599927
|
}
|
|
598737
599928
|
}
|
|
598738
599929
|
function writeUpdateState(state) {
|
|
598739
599930
|
try {
|
|
598740
|
-
const dir =
|
|
599931
|
+
const dir = join122(homedir43(), ".open-agents");
|
|
598741
599932
|
mkdirSync63(dir, { recursive: true });
|
|
598742
599933
|
const finalPath = updateStateFile();
|
|
598743
599934
|
const tmpPath = `${finalPath}.tmp.${process.pid}`;
|
|
@@ -598785,15 +599976,15 @@ async function handleV1Update(req2, res, requestId) {
|
|
|
598785
599976
|
const { execSync: es } = require3("node:child_process");
|
|
598786
599977
|
const isWin2 = process.platform === "win32";
|
|
598787
599978
|
let npmBin = "";
|
|
598788
|
-
for (const candidate of isWin2 ? [
|
|
598789
|
-
if (
|
|
599979
|
+
for (const candidate of isWin2 ? [join122(nodeDir, "npm.cmd"), join122(nodeDir, "npm")] : [join122(nodeDir, "npm"), "/usr/local/bin/npm", "/usr/bin/npm"]) {
|
|
599980
|
+
if (existsSync106(candidate)) {
|
|
598790
599981
|
npmBin = candidate;
|
|
598791
599982
|
break;
|
|
598792
599983
|
}
|
|
598793
599984
|
}
|
|
598794
599985
|
if (!npmBin) npmBin = isWin2 ? "npm.cmd" : "npm";
|
|
598795
599986
|
const pkgSpec = `open-agents-ai@${targetVersion}`;
|
|
598796
|
-
const dir =
|
|
599987
|
+
const dir = join122(homedir43(), ".open-agents");
|
|
598797
599988
|
fs7.mkdirSync(dir, { recursive: true });
|
|
598798
599989
|
const logFd = fs7.openSync(logPath3, "w");
|
|
598799
599990
|
const npmPrefix = dirname36(nodeDir);
|
|
@@ -598803,13 +599994,13 @@ async function handleV1Update(req2, res, requestId) {
|
|
|
598803
599994
|
globalBinDir = es(`${npmBin} bin -g`, { encoding: "utf8", timeout: 5e3, stdio: "pipe" }).trim();
|
|
598804
599995
|
} else {
|
|
598805
599996
|
const npmCliCandidates = [
|
|
598806
|
-
|
|
598807
|
-
|
|
599997
|
+
join122(nodeDir, "..", "lib", "node_modules", "npm", "bin", "npm-cli.js"),
|
|
599998
|
+
join122(npmBin, "..", "..", "lib", "node_modules", "npm", "bin", "npm-cli.js")
|
|
598808
599999
|
];
|
|
598809
600000
|
let npmCli = "";
|
|
598810
600001
|
for (const c9 of npmCliCandidates) {
|
|
598811
600002
|
try {
|
|
598812
|
-
if (
|
|
600003
|
+
if (existsSync106(c9)) {
|
|
598813
600004
|
npmCli = c9;
|
|
598814
600005
|
break;
|
|
598815
600006
|
}
|
|
@@ -598841,13 +600032,13 @@ async function handleV1Update(req2, res, requestId) {
|
|
|
598841
600032
|
});
|
|
598842
600033
|
} else {
|
|
598843
600034
|
const npmCliCandidates = [
|
|
598844
|
-
|
|
598845
|
-
|
|
600035
|
+
join122(nodeDir, "..", "lib", "node_modules", "npm", "bin", "npm-cli.js"),
|
|
600036
|
+
join122(npmBin, "..", "..", "lib", "node_modules", "npm", "bin", "npm-cli.js")
|
|
598846
600037
|
];
|
|
598847
600038
|
let npmCli = "";
|
|
598848
600039
|
for (const c9 of npmCliCandidates) {
|
|
598849
600040
|
try {
|
|
598850
|
-
if (
|
|
600041
|
+
if (existsSync106(c9)) {
|
|
598851
600042
|
npmCli = c9;
|
|
598852
600043
|
break;
|
|
598853
600044
|
}
|
|
@@ -598944,8 +600135,8 @@ function handleV1UpdateStatus(res) {
|
|
|
598944
600135
|
let logTail = "";
|
|
598945
600136
|
let exitCode = null;
|
|
598946
600137
|
try {
|
|
598947
|
-
if (
|
|
598948
|
-
const raw =
|
|
600138
|
+
if (existsSync106(logPath3)) {
|
|
600139
|
+
const raw = readFileSync86(logPath3, "utf-8");
|
|
598949
600140
|
const m2 = raw.match(/__EXIT_CODE=(\d+)/);
|
|
598950
600141
|
if (m2) exitCode = parseInt(m2[1], 10);
|
|
598951
600142
|
logTail = raw.slice(-2e3);
|
|
@@ -599041,7 +600232,7 @@ async function handleV1Run(req2, res) {
|
|
|
599041
600232
|
if (workingDir) {
|
|
599042
600233
|
cwd4 = resolve38(workingDir);
|
|
599043
600234
|
} else if (isolate) {
|
|
599044
|
-
const wsDir =
|
|
600235
|
+
const wsDir = join122(dir, "..", "workspaces", id);
|
|
599045
600236
|
mkdirSync63(wsDir, { recursive: true });
|
|
599046
600237
|
cwd4 = wsDir;
|
|
599047
600238
|
} else {
|
|
@@ -599228,7 +600419,7 @@ async function handleV1Run(req2, res) {
|
|
|
599228
600419
|
let output = "";
|
|
599229
600420
|
let tailBytes = 0;
|
|
599230
600421
|
const TAIL_BUDGET = 1048576;
|
|
599231
|
-
const outputWriter = new DiskTaskOutput(
|
|
600422
|
+
const outputWriter = new DiskTaskOutput(join122(dir, `${id}.output`));
|
|
599232
600423
|
job.outputFile = outputWriter.path;
|
|
599233
600424
|
atomicJobWrite(dir, id, job);
|
|
599234
600425
|
child.stdout?.on("data", (chunk) => {
|
|
@@ -600994,6 +602185,9 @@ ${historyLines}
|
|
|
600994
602185
|
runEnv["OA_RUN_USER"] = req2._authUser || "anonymous";
|
|
600995
602186
|
runEnv["OA_RUN_SCOPE"] = req2._authScope || "admin";
|
|
600996
602187
|
runEnv["OA_SESSION_ID"] = session.id;
|
|
602188
|
+
if (chatBody["fresh"] === true) {
|
|
602189
|
+
runEnv["OA_FRESH_SESSION"] = "1";
|
|
602190
|
+
}
|
|
600997
602191
|
runEnv["OLLAMA_HOST"] = currentCfg.backendUrl || process.env["OLLAMA_HOST"] || "http://127.0.0.1:11434";
|
|
600998
602192
|
if (currentCfg.apiKey) runEnv["OA_API_KEY_INHERIT"] = currentCfg.apiKey;
|
|
600999
602193
|
const child = spawn25(process.execPath, [oaBin, ...args], {
|
|
@@ -601799,7 +602993,7 @@ ${steering}`;
|
|
|
601799
602993
|
function getScheduleRoots() {
|
|
601800
602994
|
const rootsEnv = process.env["OA_SCHEDULE_ROOTS"] || "";
|
|
601801
602995
|
const roots = rootsEnv.split(rootsEnv.includes(";") ? ";" : ":").filter(Boolean);
|
|
601802
|
-
const defaults3 = [process.cwd(),
|
|
602996
|
+
const defaults3 = [process.cwd(), join122(homedir43(), "Documents")];
|
|
601803
602997
|
const set = /* @__PURE__ */ new Set([...defaults3, ...roots]);
|
|
601804
602998
|
return [...set];
|
|
601805
602999
|
}
|
|
@@ -601811,10 +603005,10 @@ function listScheduledTasks() {
|
|
|
601811
603005
|
for (const root of roots) {
|
|
601812
603006
|
try {
|
|
601813
603007
|
walk(root, 0, (dir) => {
|
|
601814
|
-
if (dir.endsWith(`${
|
|
601815
|
-
const file =
|
|
603008
|
+
if (dir.endsWith(`${join122(".oa", "scheduled")}`) || dir.includes(`${join122(".oa", "scheduled")}`)) {
|
|
603009
|
+
const file = join122(dir, "tasks.json");
|
|
601816
603010
|
try {
|
|
601817
|
-
const raw =
|
|
603011
|
+
const raw = readFileSync86(file, "utf-8");
|
|
601818
603012
|
const json = JSON.parse(raw);
|
|
601819
603013
|
const tasks = Array.isArray(json?.tasks) ? json.tasks : Array.isArray(json) ? json : [];
|
|
601820
603014
|
tasks.forEach((t2, i2) => {
|
|
@@ -601879,7 +603073,7 @@ function walk(dir, depth, onDir, maxDepth) {
|
|
|
601879
603073
|
if (e2.name === "node_modules" || e2.name.startsWith(".")) {
|
|
601880
603074
|
if (e2.name !== ".oa") continue;
|
|
601881
603075
|
}
|
|
601882
|
-
const child =
|
|
603076
|
+
const child = join122(dir, e2.name);
|
|
601883
603077
|
walk(child, depth + 1, onDir, maxDepth);
|
|
601884
603078
|
}
|
|
601885
603079
|
}
|
|
@@ -601888,7 +603082,7 @@ function setScheduledEnabled(id, enabled2) {
|
|
|
601888
603082
|
const target = tasks.find((t2) => t2.id === id);
|
|
601889
603083
|
if (!target) return false;
|
|
601890
603084
|
try {
|
|
601891
|
-
const raw =
|
|
603085
|
+
const raw = readFileSync86(target.file, "utf-8");
|
|
601892
603086
|
const json = JSON.parse(raw);
|
|
601893
603087
|
const arr = Array.isArray(json?.tasks) ? json.tasks : Array.isArray(json) ? json : [];
|
|
601894
603088
|
if (!arr[target.index]) return false;
|
|
@@ -601921,7 +603115,7 @@ function deleteScheduledById(id) {
|
|
|
601921
603115
|
const target = tasks.find((t2) => t2.id === id);
|
|
601922
603116
|
if (!target) return false;
|
|
601923
603117
|
try {
|
|
601924
|
-
const raw =
|
|
603118
|
+
const raw = readFileSync86(target.file, "utf-8");
|
|
601925
603119
|
const json = JSON.parse(raw);
|
|
601926
603120
|
const arr = Array.isArray(json?.tasks) ? json.tasks : Array.isArray(json) ? json : [];
|
|
601927
603121
|
if (!arr[target.index]) return false;
|
|
@@ -602186,11 +603380,11 @@ function reconcileScheduledTasks(apply) {
|
|
|
602186
603380
|
const errors = [];
|
|
602187
603381
|
for (const f2 of found) {
|
|
602188
603382
|
const wdir = f2.workingDir || process.cwd();
|
|
602189
|
-
const file =
|
|
603383
|
+
const file = join122(wdir, ".oa", "scheduled", "tasks.json");
|
|
602190
603384
|
try {
|
|
602191
603385
|
let json = { tasks: [] };
|
|
602192
603386
|
try {
|
|
602193
|
-
const raw =
|
|
603387
|
+
const raw = readFileSync86(file, "utf-8");
|
|
602194
603388
|
json = JSON.parse(raw);
|
|
602195
603389
|
} catch {
|
|
602196
603390
|
}
|
|
@@ -602201,8 +603395,8 @@ function reconcileScheduledTasks(apply) {
|
|
|
602201
603395
|
const entry = { task: f2.task || `legacy ${f2.id}`, schedule: f2.cron, enabled: true };
|
|
602202
603396
|
arr.push(entry);
|
|
602203
603397
|
const toWrite = Array.isArray(json?.tasks) ? { ...json, tasks: arr } : Array.isArray(json) ? arr : { tasks: arr };
|
|
602204
|
-
mkdirSync63(
|
|
602205
|
-
mkdirSync63(
|
|
603398
|
+
mkdirSync63(join122(wdir, ".oa", "scheduled"), { recursive: true });
|
|
603399
|
+
mkdirSync63(join122(wdir, ".oa", "scheduled", "logs"), { recursive: true });
|
|
602206
603400
|
writeFileSync55(file, JSON.stringify(toWrite, null, 2));
|
|
602207
603401
|
adopted.push({ file, index: arr.length - 1 });
|
|
602208
603402
|
}
|
|
@@ -602247,32 +603441,32 @@ function writeCrontabLines(lines) {
|
|
|
602247
603441
|
}
|
|
602248
603442
|
function canonicalCronLine(rec) {
|
|
602249
603443
|
const oaBin = findOaBinary4();
|
|
602250
|
-
const logDir =
|
|
602251
|
-
const logFile =
|
|
602252
|
-
const storeFile =
|
|
603444
|
+
const logDir = join122(rec.workingDir, ".oa", "scheduled", "logs");
|
|
603445
|
+
const logFile = join122(logDir, `${rec.id}.log`);
|
|
603446
|
+
const storeFile = join122(rec.workingDir, ".oa", "scheduled", "tasks.json");
|
|
602253
603447
|
const taskEsc = rec.task.replace(/'/g, "'\\''");
|
|
602254
|
-
const lockDir =
|
|
602255
|
-
const lockPath =
|
|
603448
|
+
const lockDir = join122(rec.workingDir, ".oa", "run");
|
|
603449
|
+
const lockPath = join122(lockDir, `${rec.id}.lock`);
|
|
602256
603450
|
const wrapper = [
|
|
602257
603451
|
`cd ${JSON.stringify(rec.workingDir)}`,
|
|
602258
603452
|
`mkdir -p ${JSON.stringify(logDir)}`,
|
|
602259
603453
|
`mkdir -p ${JSON.stringify(lockDir)}`,
|
|
602260
603454
|
`if mkdir ${JSON.stringify(lockPath)} 2>/dev/null; then`,
|
|
602261
|
-
` echo $$ > ${JSON.stringify(
|
|
603455
|
+
` echo $$ > ${JSON.stringify(join122(lockPath, "pid"))}`,
|
|
602262
603456
|
` trap 'rm -rf ${lockPath}' EXIT`,
|
|
602263
603457
|
`else`,
|
|
602264
|
-
` if [ -f ${JSON.stringify(
|
|
602265
|
-
` oldpid=$(cat ${JSON.stringify(
|
|
603458
|
+
` if [ -f ${JSON.stringify(join122(lockPath, "pid"))} ]; then`,
|
|
603459
|
+
` oldpid=$(cat ${JSON.stringify(join122(lockPath, "pid"))} 2>/dev/null || echo)`,
|
|
602266
603460
|
` if [ -n "$oldpid" ] && kill -0 "$oldpid" 2>/dev/null; then`,
|
|
602267
603461
|
` echo "[oa-scheduler] ${rec.id} already running as PID $oldpid; skipping" >> ${JSON.stringify(logFile)}`,
|
|
602268
603462
|
` exit 0`,
|
|
602269
603463
|
` else`,
|
|
602270
603464
|
` rm -rf ${JSON.stringify(lockPath)} 2>/dev/null || true`,
|
|
602271
|
-
` mkdir -p ${JSON.stringify(lockPath)} && echo $$ > ${JSON.stringify(
|
|
603465
|
+
` mkdir -p ${JSON.stringify(lockPath)} && echo $$ > ${JSON.stringify(join122(lockPath, "pid"))} && trap 'rm -rf ${lockPath}' EXIT`,
|
|
602272
603466
|
` fi`,
|
|
602273
603467
|
` else`,
|
|
602274
603468
|
` rm -rf ${JSON.stringify(lockPath)} 2>/dev/null || true`,
|
|
602275
|
-
` mkdir -p ${JSON.stringify(lockPath)} && echo $$ > ${JSON.stringify(
|
|
603469
|
+
` mkdir -p ${JSON.stringify(lockPath)} && echo $$ > ${JSON.stringify(join122(lockPath, "pid"))} && trap 'rm -rf ${lockPath}' EXIT`,
|
|
602276
603470
|
` fi`,
|
|
602277
603471
|
`fi`,
|
|
602278
603472
|
`${oaBin} '${taskEsc}' >> ${JSON.stringify(logFile)} 2>&1; _oa_exit=$?`,
|
|
@@ -602304,9 +603498,9 @@ function fixupOrMigrateScheduled(mode, dryRun) {
|
|
|
602304
603498
|
try {
|
|
602305
603499
|
if (!f2.workingDir || !f2.task) continue;
|
|
602306
603500
|
const unitBase = `oa-${f2.id}`;
|
|
602307
|
-
const unitDir =
|
|
602308
|
-
const svc =
|
|
602309
|
-
const tim =
|
|
603501
|
+
const unitDir = join122(homedir43(), ".config", "systemd", "user");
|
|
603502
|
+
const svc = join122(unitDir, `${unitBase}.service`);
|
|
603503
|
+
const tim = join122(unitDir, `${unitBase}.timer`);
|
|
602310
603504
|
const oaBin = findOaBinary4();
|
|
602311
603505
|
const rec = { id: f2.id, cron: f2.cron, workingDir: f2.workingDir, task: f2.task };
|
|
602312
603506
|
const cmd = canonicalCronLine(rec).split(" ").slice(5).join(" ");
|
|
@@ -602432,8 +603626,8 @@ function startApiServer(options2 = {}) {
|
|
|
602432
603626
|
const config = loadConfig();
|
|
602433
603627
|
const ollamaUrl = options2.ollamaUrl ?? config.backendUrl;
|
|
602434
603628
|
const cwd4 = process.cwd();
|
|
602435
|
-
initAuditLog(
|
|
602436
|
-
initUsageTracker(
|
|
603629
|
+
initAuditLog(join122(cwd4, ".oa"));
|
|
603630
|
+
initUsageTracker(join122(cwd4, ".oa"));
|
|
602437
603631
|
try {
|
|
602438
603632
|
const taskMgr = getSharedTaskManager();
|
|
602439
603633
|
taskMgr.setEventPublisher((type, data, opts) => {
|
|
@@ -602484,7 +603678,7 @@ function startApiServer(options2 = {}) {
|
|
|
602484
603678
|
if (!f2.endsWith(".json") || f2.includes(".tmp.")) continue;
|
|
602485
603679
|
const sid = f2.replace(/\.json$/, "");
|
|
602486
603680
|
try {
|
|
602487
|
-
const items = JSON.parse(
|
|
603681
|
+
const items = JSON.parse(readFileSync86(join122(dir, f2), "utf-8"));
|
|
602488
603682
|
if (Array.isArray(items)) {
|
|
602489
603683
|
cache8.set(sid, new Map(items.map((t2) => [t2.id, t2])));
|
|
602490
603684
|
}
|
|
@@ -602496,10 +603690,10 @@ function startApiServer(options2 = {}) {
|
|
|
602496
603690
|
const watcher = fsWatch3(dir, (_evt, fname) => {
|
|
602497
603691
|
if (!fname || !fname.endsWith(".json") || fname.includes(".tmp.")) return;
|
|
602498
603692
|
const sid = fname.replace(/\.json$/, "");
|
|
602499
|
-
const fp =
|
|
603693
|
+
const fp = join122(dir, fname);
|
|
602500
603694
|
let next = [];
|
|
602501
603695
|
try {
|
|
602502
|
-
if (!
|
|
603696
|
+
if (!existsSync106(fp)) {
|
|
602503
603697
|
const old = cache8.get(sid);
|
|
602504
603698
|
if (old) {
|
|
602505
603699
|
for (const t2 of old.values()) {
|
|
@@ -602512,7 +603706,7 @@ function startApiServer(options2 = {}) {
|
|
|
602512
603706
|
}
|
|
602513
603707
|
return;
|
|
602514
603708
|
}
|
|
602515
|
-
next = JSON.parse(
|
|
603709
|
+
next = JSON.parse(readFileSync86(fp, "utf-8"));
|
|
602516
603710
|
if (!Array.isArray(next)) return;
|
|
602517
603711
|
} catch {
|
|
602518
603712
|
return;
|
|
@@ -602551,14 +603745,14 @@ function startApiServer(options2 = {}) {
|
|
|
602551
603745
|
const retentionDays = parseInt(process.env["OA_JOB_RETENTION_DAYS"] ?? "30", 10);
|
|
602552
603746
|
if (retentionDays > 0) {
|
|
602553
603747
|
try {
|
|
602554
|
-
const jobsDir3 =
|
|
602555
|
-
if (
|
|
603748
|
+
const jobsDir3 = join122(cwd4, ".oa", "jobs");
|
|
603749
|
+
if (existsSync106(jobsDir3)) {
|
|
602556
603750
|
const cutoff = Date.now() - retentionDays * 864e5;
|
|
602557
603751
|
for (const f2 of readdirSync36(jobsDir3)) {
|
|
602558
603752
|
if (!f2.endsWith(".json")) continue;
|
|
602559
603753
|
try {
|
|
602560
|
-
const jobPath =
|
|
602561
|
-
const job = JSON.parse(
|
|
603754
|
+
const jobPath = join122(jobsDir3, f2);
|
|
603755
|
+
const job = JSON.parse(readFileSync86(jobPath, "utf-8"));
|
|
602562
603756
|
const jobTime = new Date(job.startedAt ?? job.completedAt ?? 0).getTime();
|
|
602563
603757
|
if (jobTime > 0 && jobTime < cutoff && job.status !== "running") {
|
|
602564
603758
|
const { unlinkSync: unlinkSync25 } = require3("node:fs");
|
|
@@ -602578,8 +603772,8 @@ function startApiServer(options2 = {}) {
|
|
|
602578
603772
|
if (useTls) {
|
|
602579
603773
|
try {
|
|
602580
603774
|
tlsOpts = {
|
|
602581
|
-
cert:
|
|
602582
|
-
key:
|
|
603775
|
+
cert: readFileSync86(resolve38(tlsCert)),
|
|
603776
|
+
key: readFileSync86(resolve38(tlsKey))
|
|
602583
603777
|
};
|
|
602584
603778
|
} catch (e2) {
|
|
602585
603779
|
log22(`
|
|
@@ -602590,9 +603784,9 @@ function startApiServer(options2 = {}) {
|
|
|
602590
603784
|
}
|
|
602591
603785
|
let runtimeAccessMode = resolveAccessMode(process.env["OA_ACCESS"], host);
|
|
602592
603786
|
try {
|
|
602593
|
-
const accessFile =
|
|
602594
|
-
if (
|
|
602595
|
-
const persisted =
|
|
603787
|
+
const accessFile = join122(homedir43(), ".open-agents", "access");
|
|
603788
|
+
if (existsSync106(accessFile)) {
|
|
603789
|
+
const persisted = readFileSync86(accessFile, "utf8").trim();
|
|
602596
603790
|
const resolved = resolveAccessMode(persisted, host);
|
|
602597
603791
|
if (resolved) runtimeAccessMode = resolved;
|
|
602598
603792
|
}
|
|
@@ -602645,9 +603839,9 @@ function startApiServer(options2 = {}) {
|
|
|
602645
603839
|
const previous = runtimeAccessMode;
|
|
602646
603840
|
runtimeAccessMode = requested;
|
|
602647
603841
|
try {
|
|
602648
|
-
const dir =
|
|
603842
|
+
const dir = join122(homedir43(), ".open-agents");
|
|
602649
603843
|
mkdirSync63(dir, { recursive: true });
|
|
602650
|
-
writeFileSync55(
|
|
603844
|
+
writeFileSync55(join122(dir, "access"), `${runtimeAccessMode}
|
|
602651
603845
|
`, "utf8");
|
|
602652
603846
|
} catch {
|
|
602653
603847
|
}
|
|
@@ -602860,9 +604054,9 @@ function startApiServer(options2 = {}) {
|
|
|
602860
604054
|
try {
|
|
602861
604055
|
const { startEmbeddingWorkers: startEmbeddingWorkers2 } = await Promise.resolve().then(() => (init_embedding_workers(), embedding_workers_exports));
|
|
602862
604056
|
const { ensureEmbedDeps: ensureEmbedDeps2, runEmbedImage: runEmbedImage2, runEmbedAudio: runEmbedAudio2 } = await Promise.resolve().then(() => (init_py_embed(), py_embed_exports));
|
|
602863
|
-
const dbBase =
|
|
602864
|
-
const epStore = new mem.EpisodeStore(
|
|
602865
|
-
const kg = new mem.TemporalGraph(
|
|
604057
|
+
const dbBase = join122(cwd4, ".oa");
|
|
604058
|
+
const epStore = new mem.EpisodeStore(join122(dbBase, "memory.db"));
|
|
604059
|
+
const kg = new mem.TemporalGraph(join122(dbBase, "kg.db"));
|
|
602866
604060
|
try {
|
|
602867
604061
|
ensureEmbedDeps2();
|
|
602868
604062
|
} catch {
|
|
@@ -602939,6 +604133,34 @@ function startApiServer(options2 = {}) {
|
|
|
602939
604133
|
`);
|
|
602940
604134
|
log22(` Primary: ${config.backendUrl} (${config.backendType || "ollama"})
|
|
602941
604135
|
`);
|
|
604136
|
+
try {
|
|
604137
|
+
const { writeFileSync: writeFileSync59, mkdirSync: mkdirSync67, existsSync: _exists } = require3("node:fs");
|
|
604138
|
+
const { join: _join } = require3("node:path");
|
|
604139
|
+
const { homedir: _homedir } = require3("node:os");
|
|
604140
|
+
const apiHint = JSON.stringify({
|
|
604141
|
+
port,
|
|
604142
|
+
host: host === "0.0.0.0" ? "127.0.0.1" : host,
|
|
604143
|
+
scheme: proto,
|
|
604144
|
+
pid: process.pid,
|
|
604145
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
604146
|
+
version: version4
|
|
604147
|
+
}, null, 2);
|
|
604148
|
+
const candidates = [
|
|
604149
|
+
_join(process.cwd(), ".oa", "nexus"),
|
|
604150
|
+
_join(_homedir(), ".oa", "nexus"),
|
|
604151
|
+
_join(_homedir(), ".open-agents", "nexus")
|
|
604152
|
+
];
|
|
604153
|
+
for (const dir of candidates) {
|
|
604154
|
+
try {
|
|
604155
|
+
if (!_exists(dir)) mkdirSync67(dir, { recursive: true });
|
|
604156
|
+
writeFileSync59(_join(dir, "api-port.json"), apiHint);
|
|
604157
|
+
} catch {
|
|
604158
|
+
}
|
|
604159
|
+
}
|
|
604160
|
+
} catch (e2) {
|
|
604161
|
+
log22(` WARN: api-port hint write failed: ${e2.message}
|
|
604162
|
+
`);
|
|
604163
|
+
}
|
|
602942
604164
|
try {
|
|
602943
604165
|
adoptHandoffRuns();
|
|
602944
604166
|
} catch (e2) {
|
|
@@ -603172,10 +604394,10 @@ async function handleMemoryIngest(req2, res, ollamaUrl) {
|
|
|
603172
604394
|
const labels = Array.isArray(b.labels) ? b.labels : [];
|
|
603173
604395
|
const mediaPath = typeof b.media_path === "string" ? b.media_path : void 0;
|
|
603174
604396
|
const cwd4 = process.cwd();
|
|
603175
|
-
const dbBase =
|
|
604397
|
+
const dbBase = join122(cwd4, ".oa");
|
|
603176
604398
|
const { EpisodeStore: EpisodeStore3, TemporalGraph: TemporalGraph3 } = await Promise.resolve().then(() => (init_dist7(), dist_exports2));
|
|
603177
|
-
const epStore = new EpisodeStore3(
|
|
603178
|
-
const kg = new TemporalGraph3(
|
|
604399
|
+
const epStore = new EpisodeStore3(join122(dbBase, "memory.db"));
|
|
604400
|
+
const kg = new TemporalGraph3(join122(dbBase, "kg.db"));
|
|
603179
604401
|
const meta = {};
|
|
603180
604402
|
if (mediaPath) meta.media_path = mediaPath;
|
|
603181
604403
|
const epId = epStore.insert({ modality, content: content || (mediaPath || ""), metadata: meta, toolName: "memory_ingest" });
|
|
@@ -603242,7 +604464,7 @@ async function handleEntitiesList(req2, res) {
|
|
|
603242
604464
|
const type = url.searchParams.get("type") || "person";
|
|
603243
604465
|
const limit = Math.max(1, Math.min(1e3, parseInt(url.searchParams.get("limit") || "100", 10)));
|
|
603244
604466
|
const { TemporalGraph: TemporalGraph3 } = await Promise.resolve().then(() => (init_dist7(), dist_exports2));
|
|
603245
|
-
const kg = new TemporalGraph3(
|
|
604467
|
+
const kg = new TemporalGraph3(join122(process.cwd(), ".oa", "kg.db"));
|
|
603246
604468
|
const nodes = kg.nodesByType(type, limit).map((n2) => ({ id: n2.id, text: n2.text, mentionCount: n2.mentionCount, firstSeen: n2.firstSeen, lastSeen: n2.lastSeen }));
|
|
603247
604469
|
jsonResponse(res, 200, { object: "list", data: nodes });
|
|
603248
604470
|
} catch (err) {
|
|
@@ -603264,7 +604486,7 @@ async function handleMemorySearch2(req2, res) {
|
|
|
603264
604486
|
const wLex = typeof b.lexical_weight === "number" ? b.lexical_weight : 1;
|
|
603265
604487
|
const wEmb = typeof b.embedding_weight === "number" ? b.embedding_weight : 1;
|
|
603266
604488
|
const { EpisodeStore: EpisodeStore3 } = await Promise.resolve().then(() => (init_dist7(), dist_exports2));
|
|
603267
|
-
const epStore = new EpisodeStore3(
|
|
604489
|
+
const epStore = new EpisodeStore3(join122(process.cwd(), ".oa", "memory.db"));
|
|
603268
604490
|
const results = epStore.search({ query, modality, limit }, { queryEmbedding: qEmb, lexicalWeight: wLex, embeddingWeight: wEmb });
|
|
603269
604491
|
jsonResponse(res, 200, { object: "list", data: results.map((e2) => ({ id: e2.id, modality: e2.modality, content: e2.content, timestamp: e2.timestamp })) });
|
|
603270
604492
|
} catch (err) {
|
|
@@ -603381,13 +604603,13 @@ var init_serve = __esm({
|
|
|
603381
604603
|
|
|
603382
604604
|
// packages/cli/src/tui/interactive.ts
|
|
603383
604605
|
import { cwd } from "node:process";
|
|
603384
|
-
import { resolve as resolve39, join as
|
|
604606
|
+
import { resolve as resolve39, join as join123, dirname as dirname37, extname as extname12 } from "node:path";
|
|
603385
604607
|
import { createRequire as createRequire6 } from "node:module";
|
|
603386
604608
|
import { fileURLToPath as fileURLToPath18 } from "node:url";
|
|
603387
|
-
import { readFileSync as
|
|
603388
|
-
import { existsSync as
|
|
604609
|
+
import { readFileSync as readFileSync87, writeFileSync as writeFileSync56, appendFileSync as appendFileSync8, rmSync as rmSync5, readdirSync as readdirSync37, mkdirSync as mkdirSync64 } from "node:fs";
|
|
604610
|
+
import { existsSync as existsSync107 } from "node:fs";
|
|
603389
604611
|
import { execSync as execSync58 } from "node:child_process";
|
|
603390
|
-
import { homedir as
|
|
604612
|
+
import { homedir as homedir44 } from "node:os";
|
|
603391
604613
|
function formatTimeAgo2(date) {
|
|
603392
604614
|
const seconds = Math.floor((Date.now() - date.getTime()) / 1e3);
|
|
603393
604615
|
if (seconds < 60) return "just now";
|
|
@@ -603403,12 +604625,12 @@ function getVersion4() {
|
|
|
603403
604625
|
const require4 = createRequire6(import.meta.url);
|
|
603404
604626
|
const thisDir = dirname37(fileURLToPath18(import.meta.url));
|
|
603405
604627
|
const candidates = [
|
|
603406
|
-
|
|
603407
|
-
|
|
603408
|
-
|
|
604628
|
+
join123(thisDir, "..", "package.json"),
|
|
604629
|
+
join123(thisDir, "..", "..", "package.json"),
|
|
604630
|
+
join123(thisDir, "..", "..", "..", "package.json")
|
|
603409
604631
|
];
|
|
603410
604632
|
for (const pkgPath of candidates) {
|
|
603411
|
-
if (
|
|
604633
|
+
if (existsSync107(pkgPath)) {
|
|
603412
604634
|
const pkg = require4(pkgPath);
|
|
603413
604635
|
if (pkg.name === "open-agents-ai" || pkg.name === "@open-agents/cli" || pkg.name === "@open-agents/monorepo") {
|
|
603414
604636
|
return pkg.version ?? "0.0.0";
|
|
@@ -604214,14 +605436,14 @@ Meta-critique: quality ${meta.quality}/5, thorough: ${meta.thorough}`;
|
|
|
604214
605436
|
function gatherMemorySnippets(root) {
|
|
604215
605437
|
const snippets = [];
|
|
604216
605438
|
const dirs = [
|
|
604217
|
-
|
|
604218
|
-
|
|
605439
|
+
join123(root, ".oa", "memory"),
|
|
605440
|
+
join123(root, ".open-agents", "memory")
|
|
604219
605441
|
];
|
|
604220
605442
|
for (const dir of dirs) {
|
|
604221
|
-
if (!
|
|
605443
|
+
if (!existsSync107(dir)) continue;
|
|
604222
605444
|
try {
|
|
604223
605445
|
for (const f2 of readdirSync37(dir).filter((f3) => f3.endsWith(".json"))) {
|
|
604224
|
-
const data = JSON.parse(
|
|
605446
|
+
const data = JSON.parse(readFileSync87(join123(dir, f2), "utf-8"));
|
|
604225
605447
|
for (const val of Object.values(data)) {
|
|
604226
605448
|
const v = typeof val === "object" && val !== null && "value" in val ? String(val.value) : String(val);
|
|
604227
605449
|
if (v.length > 10) snippets.push(v);
|
|
@@ -604375,9 +605597,9 @@ ${metabolismMemories}
|
|
|
604375
605597
|
} catch {
|
|
604376
605598
|
}
|
|
604377
605599
|
try {
|
|
604378
|
-
const archeFile =
|
|
604379
|
-
if (
|
|
604380
|
-
const variants = JSON.parse(
|
|
605600
|
+
const archeFile = join123(repoRoot, ".oa", "arche", "variants.json");
|
|
605601
|
+
if (existsSync107(archeFile)) {
|
|
605602
|
+
const variants = JSON.parse(readFileSync87(archeFile, "utf8"));
|
|
604381
605603
|
if (variants.length > 0) {
|
|
604382
605604
|
let filtered = variants;
|
|
604383
605605
|
if (taskType) {
|
|
@@ -604549,9 +605771,9 @@ RULES:
|
|
|
604549
605771
|
const compactionThreshold = Number.isFinite(envOverride) && envOverride > 0 ? envOverride : modelTier === "small" ? 12e3 : modelTier === "medium" ? 24e3 : 4e4;
|
|
604550
605772
|
let identityInjection = "";
|
|
604551
605773
|
try {
|
|
604552
|
-
const ikStateFile =
|
|
604553
|
-
if (
|
|
604554
|
-
const selfState = JSON.parse(
|
|
605774
|
+
const ikStateFile = join123(repoRoot, ".oa", "identity", "self-state.json");
|
|
605775
|
+
if (existsSync107(ikStateFile)) {
|
|
605776
|
+
const selfState = JSON.parse(readFileSync87(ikStateFile, "utf8"));
|
|
604555
605777
|
const lines = [
|
|
604556
605778
|
`[Identity State v${selfState.version}]`,
|
|
604557
605779
|
`Self: ${selfState.narrative_summary}`,
|
|
@@ -605413,11 +606635,11 @@ When done, either call task_complete with your answer, or use FINAL_VAR(variable
|
|
|
605413
606635
|
});
|
|
605414
606636
|
}
|
|
605415
606637
|
try {
|
|
605416
|
-
const ikDir =
|
|
605417
|
-
const ikFile =
|
|
606638
|
+
const ikDir = join123(repoRoot, ".oa", "identity");
|
|
606639
|
+
const ikFile = join123(ikDir, "self-state.json");
|
|
605418
606640
|
let ikState;
|
|
605419
|
-
if (
|
|
605420
|
-
ikState = JSON.parse(
|
|
606641
|
+
if (existsSync107(ikFile)) {
|
|
606642
|
+
ikState = JSON.parse(readFileSync87(ikFile, "utf8"));
|
|
605421
606643
|
} else {
|
|
605422
606644
|
mkdirSync64(ikDir, { recursive: true });
|
|
605423
606645
|
const machineId = Date.now().toString(36) + Math.random().toString(36).slice(2, 8);
|
|
@@ -605494,9 +606716,9 @@ When done, either call task_complete with your answer, or use FINAL_VAR(variable
|
|
|
605494
606716
|
} else {
|
|
605495
606717
|
renderTaskIncomplete(result.turns, result.toolCalls, result.durationMs, tokens);
|
|
605496
606718
|
try {
|
|
605497
|
-
const ikFile =
|
|
605498
|
-
if (
|
|
605499
|
-
const ikState = JSON.parse(
|
|
606719
|
+
const ikFile = join123(repoRoot, ".oa", "identity", "self-state.json");
|
|
606720
|
+
if (existsSync107(ikFile)) {
|
|
606721
|
+
const ikState = JSON.parse(readFileSync87(ikFile, "utf8"));
|
|
605500
606722
|
if (!ikState.stats) ikState.stats = { queries_served: 0 };
|
|
605501
606723
|
ikState.stats.queries_served = (ikState.stats.queries_served || 0) + 1;
|
|
605502
606724
|
ikState.homeostasis.uncertainty = Math.min(1, ikState.homeostasis.uncertainty + 0.03);
|
|
@@ -605752,10 +606974,10 @@ async function startInteractive(config, repoPath) {
|
|
|
605752
606974
|
process.stdin.pause();
|
|
605753
606975
|
}
|
|
605754
606976
|
try {
|
|
605755
|
-
const oaDir =
|
|
605756
|
-
const nexusPidFile =
|
|
605757
|
-
if (
|
|
605758
|
-
const pid = parseInt(
|
|
606977
|
+
const oaDir = join123(repoRoot, ".oa");
|
|
606978
|
+
const nexusPidFile = join123(oaDir, "nexus", "daemon.pid");
|
|
606979
|
+
if (existsSync107(nexusPidFile)) {
|
|
606980
|
+
const pid = parseInt(readFileSync87(nexusPidFile, "utf8").trim(), 10);
|
|
605759
606981
|
if (pid > 0) {
|
|
605760
606982
|
try {
|
|
605761
606983
|
process.kill(pid, 0);
|
|
@@ -606415,7 +607637,7 @@ ${result.summary}`
|
|
|
606415
607637
|
let p2pGateway = null;
|
|
606416
607638
|
let peerMesh = null;
|
|
606417
607639
|
let inferenceRouter = null;
|
|
606418
|
-
const secretVault = new SecretVault(
|
|
607640
|
+
const secretVault = new SecretVault(join123(repoRoot, ".oa", "vault.enc"));
|
|
606419
607641
|
let adminSessionKey = null;
|
|
606420
607642
|
const callSubAgents = /* @__PURE__ */ new Map();
|
|
606421
607643
|
const streamRenderer = new StreamRenderer();
|
|
@@ -606646,13 +607868,13 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
606646
607868
|
const hits = allCompletions.filter((c9) => c9.toLowerCase().startsWith(lower));
|
|
606647
607869
|
return [hits, line];
|
|
606648
607870
|
}
|
|
606649
|
-
const HISTORY_DIR =
|
|
606650
|
-
const HISTORY_FILE =
|
|
607871
|
+
const HISTORY_DIR = join123(homedir44(), ".open-agents");
|
|
607872
|
+
const HISTORY_FILE = join123(HISTORY_DIR, "repl-history");
|
|
606651
607873
|
const MAX_HISTORY_LINES = 500;
|
|
606652
607874
|
let savedHistory = [];
|
|
606653
607875
|
try {
|
|
606654
|
-
if (
|
|
606655
|
-
const raw =
|
|
607876
|
+
if (existsSync107(HISTORY_FILE)) {
|
|
607877
|
+
const raw = readFileSync87(HISTORY_FILE, "utf8").trim();
|
|
606656
607878
|
if (raw) savedHistory = raw.split("\n").reverse();
|
|
606657
607879
|
}
|
|
606658
607880
|
} catch {
|
|
@@ -606802,7 +608024,7 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
606802
608024
|
mkdirSync64(HISTORY_DIR, { recursive: true });
|
|
606803
608025
|
appendFileSync8(HISTORY_FILE, line + "\n", "utf8");
|
|
606804
608026
|
if (Math.random() < 0.02) {
|
|
606805
|
-
const all2 =
|
|
608027
|
+
const all2 = readFileSync87(HISTORY_FILE, "utf8").trim().split("\n");
|
|
606806
608028
|
if (all2.length > MAX_HISTORY_LINES) {
|
|
606807
608029
|
writeFileSync56(HISTORY_FILE, all2.slice(-MAX_HISTORY_LINES).join("\n") + "\n", "utf8");
|
|
606808
608030
|
}
|
|
@@ -606989,10 +608211,10 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
606989
608211
|
const { unlinkSync: _rmStale } = await import("node:fs");
|
|
606990
608212
|
const { homedir: _hdir } = await import("node:os");
|
|
606991
608213
|
for (const dp of [
|
|
606992
|
-
|
|
606993
|
-
|
|
608214
|
+
join123(repoRoot, ".oa", "nexus", "nexus-daemon.mjs"),
|
|
608215
|
+
join123(_hdir(), ".open-agents", ".oa", "nexus", "nexus-daemon.mjs")
|
|
606994
608216
|
]) {
|
|
606995
|
-
if (
|
|
608217
|
+
if (existsSync107(dp)) try {
|
|
606996
608218
|
_rmStale(dp);
|
|
606997
608219
|
} catch {
|
|
606998
608220
|
}
|
|
@@ -607003,9 +608225,9 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
607003
608225
|
const autoNexus = new NexusTool(repoRoot);
|
|
607004
608226
|
const _registerNexusDaemon = () => {
|
|
607005
608227
|
try {
|
|
607006
|
-
const nexusPidFile =
|
|
607007
|
-
if (
|
|
607008
|
-
const nPid = parseInt(
|
|
608228
|
+
const nexusPidFile = join123(repoRoot, ".oa", "nexus", "daemon.pid");
|
|
608229
|
+
if (existsSync107(nexusPidFile)) {
|
|
608230
|
+
const nPid = parseInt(readFileSync87(nexusPidFile, "utf8").trim(), 10);
|
|
607009
608231
|
if (nPid > 0 && !registry2.daemons.has("Nexus")) {
|
|
607010
608232
|
registry2.register({ name: "Nexus", pid: nPid, startedAt: Date.now(), status: "running" });
|
|
607011
608233
|
statusBar.ensureMonitorTimer();
|
|
@@ -607062,7 +608284,7 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
607062
608284
|
} catch {
|
|
607063
608285
|
}
|
|
607064
608286
|
try {
|
|
607065
|
-
const oaDir =
|
|
608287
|
+
const oaDir = join123(repoRoot, ".oa");
|
|
607066
608288
|
const reconnected = await ExposeGateway.checkAndReconnect(oaDir, {
|
|
607067
608289
|
onInfo: (msg) => writeContent(() => renderInfo2(msg)),
|
|
607068
608290
|
onError: (msg) => writeContent(() => renderWarning2(msg))
|
|
@@ -607094,7 +608316,7 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
607094
608316
|
} catch {
|
|
607095
608317
|
}
|
|
607096
608318
|
try {
|
|
607097
|
-
const oaDir =
|
|
608319
|
+
const oaDir = join123(repoRoot, ".oa");
|
|
607098
608320
|
const reconnectedP2P = await ExposeP2PGateway.checkAndReconnect(oaDir, new NexusTool(repoRoot), {
|
|
607099
608321
|
onInfo: (msg) => writeContent(() => renderInfo2(msg)),
|
|
607100
608322
|
onError: (msg) => writeContent(() => renderWarning2(msg))
|
|
@@ -607135,10 +608357,10 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
607135
608357
|
}
|
|
607136
608358
|
try {
|
|
607137
608359
|
const { homedir: _hd, hostname: _hn, userInfo: _ui } = await import("node:os");
|
|
607138
|
-
const globalNamePath =
|
|
608360
|
+
const globalNamePath = join123(_hd(), ".open-agents", "agent-name");
|
|
607139
608361
|
let agName = "";
|
|
607140
608362
|
try {
|
|
607141
|
-
if (
|
|
608363
|
+
if (existsSync107(globalNamePath)) agName = readFileSync87(globalNamePath, "utf8").trim();
|
|
607142
608364
|
} catch {
|
|
607143
608365
|
}
|
|
607144
608366
|
if (!agName) {
|
|
@@ -607167,11 +608389,11 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
607167
608389
|
}
|
|
607168
608390
|
if (!ollamaAlive) {
|
|
607169
608391
|
try {
|
|
607170
|
-
const savedSponsorsPath =
|
|
608392
|
+
const savedSponsorsPath = join123(repoRoot, ".oa", "sponsor", "known-sponsors.json");
|
|
607171
608393
|
let savedSponsors = [];
|
|
607172
608394
|
try {
|
|
607173
|
-
if (
|
|
607174
|
-
savedSponsors = JSON.parse(
|
|
608395
|
+
if (existsSync107(savedSponsorsPath)) {
|
|
608396
|
+
savedSponsors = JSON.parse(readFileSync87(savedSponsorsPath, "utf8"));
|
|
607175
608397
|
const oneHourAgo = Date.now() - 36e5;
|
|
607176
608398
|
savedSponsors = savedSponsors.filter((s2) => (s2.lastVerified || 0) > oneHourAgo);
|
|
607177
608399
|
}
|
|
@@ -608263,10 +609485,10 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
608263
609485
|
if (name10 === "voice_list_files") {
|
|
608264
609486
|
const baseDir = String(args?.dir ?? ".");
|
|
608265
609487
|
const { readdirSync: readdirSync39, statSync: statSync36 } = __require("node:fs");
|
|
608266
|
-
const { join:
|
|
608267
|
-
const base3 = baseDir.startsWith("/") ? baseDir : resolve43(
|
|
609488
|
+
const { join: join128, resolve: resolve43 } = __require("node:path");
|
|
609489
|
+
const base3 = baseDir.startsWith("/") ? baseDir : resolve43(join128(repoRoot, baseDir));
|
|
608268
609490
|
const items = readdirSync39(base3).slice(0, 200).map((f2) => {
|
|
608269
|
-
const s2 = statSync36(
|
|
609491
|
+
const s2 = statSync36(join128(base3, f2));
|
|
608270
609492
|
return { name: f2, dir: s2.isDirectory(), size: s2.size };
|
|
608271
609493
|
});
|
|
608272
609494
|
return JSON.stringify({ dir: base3, items }, null, 2);
|
|
@@ -608354,7 +609576,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
608354
609576
|
kind,
|
|
608355
609577
|
targetUrl,
|
|
608356
609578
|
authKey,
|
|
608357
|
-
stateDir:
|
|
609579
|
+
stateDir: join123(repoRoot, ".oa"),
|
|
608358
609580
|
passthrough: passthrough ?? false,
|
|
608359
609581
|
loadbalance: loadbalance ?? false,
|
|
608360
609582
|
endpointAuth: passthrough ? currentConfig.apiKey : void 0,
|
|
@@ -608400,7 +609622,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
608400
609622
|
await tunnelGateway.stop();
|
|
608401
609623
|
tunnelGateway = null;
|
|
608402
609624
|
}
|
|
608403
|
-
const newTunnel = new ExposeGateway({ kind, targetUrl, authKey, fullAccess, stateDir:
|
|
609625
|
+
const newTunnel = new ExposeGateway({ kind, targetUrl, authKey, fullAccess, stateDir: join123(repoRoot, ".oa") });
|
|
608404
609626
|
newTunnel.on("stats", (stats) => {
|
|
608405
609627
|
statusBar.setExposeStatus({
|
|
608406
609628
|
status: stats.status,
|
|
@@ -608487,9 +609709,9 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
608487
609709
|
});
|
|
608488
609710
|
if (!result.success) throw new Error(result.error || "Connect failed");
|
|
608489
609711
|
try {
|
|
608490
|
-
const nexusPidFile =
|
|
608491
|
-
if (
|
|
608492
|
-
const pid = parseInt(
|
|
609712
|
+
const nexusPidFile = join123(repoRoot, ".oa", "nexus", "daemon.pid");
|
|
609713
|
+
if (existsSync107(nexusPidFile)) {
|
|
609714
|
+
const pid = parseInt(readFileSync87(nexusPidFile, "utf8").trim(), 10);
|
|
608493
609715
|
if (pid > 0) {
|
|
608494
609716
|
registry2.register({
|
|
608495
609717
|
name: "Nexus",
|
|
@@ -608677,10 +609899,10 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
608677
609899
|
writeContent(() => renderInfo2(`Killed ${bgKilled} background task(s).`));
|
|
608678
609900
|
}
|
|
608679
609901
|
try {
|
|
608680
|
-
const nexusDir =
|
|
608681
|
-
const pidFile =
|
|
608682
|
-
if (
|
|
608683
|
-
const pid = parseInt(
|
|
609902
|
+
const nexusDir = join123(repoRoot, OA_DIR, "nexus");
|
|
609903
|
+
const pidFile = join123(nexusDir, "daemon.pid");
|
|
609904
|
+
if (existsSync107(pidFile)) {
|
|
609905
|
+
const pid = parseInt(readFileSync87(pidFile, "utf8").trim(), 10);
|
|
608684
609906
|
if (pid > 0) {
|
|
608685
609907
|
try {
|
|
608686
609908
|
if (process.platform === "win32") {
|
|
@@ -608702,13 +609924,13 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
608702
609924
|
} catch {
|
|
608703
609925
|
}
|
|
608704
609926
|
try {
|
|
608705
|
-
const voiceDir2 =
|
|
609927
|
+
const voiceDir2 = join123(homedir44(), ".open-agents", "voice");
|
|
608706
609928
|
const voicePidFiles = ["luxtts-daemon.pid", "piper-daemon.pid"];
|
|
608707
609929
|
for (const pf of voicePidFiles) {
|
|
608708
|
-
const pidPath =
|
|
608709
|
-
if (
|
|
609930
|
+
const pidPath = join123(voiceDir2, pf);
|
|
609931
|
+
if (existsSync107(pidPath)) {
|
|
608710
609932
|
try {
|
|
608711
|
-
const pid = parseInt(
|
|
609933
|
+
const pid = parseInt(readFileSync87(pidPath, "utf8").trim(), 10);
|
|
608712
609934
|
if (pid > 0) {
|
|
608713
609935
|
if (process.platform === "win32") {
|
|
608714
609936
|
try {
|
|
@@ -608732,8 +609954,8 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
608732
609954
|
execSync58(process.platform === "win32" ? "timeout /t 1 /nobreak >nul" : "sleep 0.5", { timeout: 3e3, stdio: "ignore" });
|
|
608733
609955
|
} catch {
|
|
608734
609956
|
}
|
|
608735
|
-
const oaPath =
|
|
608736
|
-
if (
|
|
609957
|
+
const oaPath = join123(repoRoot, OA_DIR);
|
|
609958
|
+
if (existsSync107(oaPath)) {
|
|
608737
609959
|
let deleted = false;
|
|
608738
609960
|
for (let attempt = 0; attempt < 3; attempt++) {
|
|
608739
609961
|
try {
|
|
@@ -608817,19 +610039,19 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
608817
610039
|
try {
|
|
608818
610040
|
const { isPersonaPlexRunning: isPersonaPlexRunning2 } = await Promise.resolve().then(() => (init_personaplex(), personaplex_exports));
|
|
608819
610041
|
if (isPersonaPlexRunning2()) {
|
|
608820
|
-
const ppPidFile =
|
|
608821
|
-
const ppPortFile =
|
|
608822
|
-
if (
|
|
608823
|
-
const ppPid = parseInt(
|
|
608824
|
-
const ppPort =
|
|
610042
|
+
const ppPidFile = join123(homedir44(), ".open-agents", "voice", "personaplex", "daemon.pid");
|
|
610043
|
+
const ppPortFile = join123(homedir44(), ".open-agents", "voice", "personaplex", "daemon.port");
|
|
610044
|
+
if (existsSync107(ppPidFile)) {
|
|
610045
|
+
const ppPid = parseInt(readFileSync87(ppPidFile, "utf8").trim(), 10);
|
|
610046
|
+
const ppPort = existsSync107(ppPortFile) ? parseInt(readFileSync87(ppPortFile, "utf8").trim(), 10) : void 0;
|
|
608825
610047
|
if (ppPid > 0 && !registry2.daemons.has("PersonaPlex")) {
|
|
608826
610048
|
registry2.register({ name: "PersonaPlex", pid: ppPid, port: ppPort, startedAt: Date.now(), status: "running" });
|
|
608827
610049
|
}
|
|
608828
610050
|
}
|
|
608829
610051
|
}
|
|
608830
|
-
const nexusPidFile =
|
|
608831
|
-
if (
|
|
608832
|
-
const nPid = parseInt(
|
|
610052
|
+
const nexusPidFile = join123(repoRoot, ".oa", "nexus", "daemon.pid");
|
|
610053
|
+
if (existsSync107(nexusPidFile)) {
|
|
610054
|
+
const nPid = parseInt(readFileSync87(nexusPidFile, "utf8").trim(), 10);
|
|
608833
610055
|
if (nPid > 0 && !registry2.daemons.has("Nexus")) {
|
|
608834
610056
|
try {
|
|
608835
610057
|
process.kill(nPid, 0);
|
|
@@ -609196,9 +610418,9 @@ Execute this skill now. Follow the behavioral guidance above.`;
|
|
|
609196
610418
|
}
|
|
609197
610419
|
}
|
|
609198
610420
|
const cleanPath = input.replace(/^['"]|['"]$/g, "").trim();
|
|
609199
|
-
const isImage = isImagePath(cleanPath) &&
|
|
609200
|
-
const isMedia = !isImage && isTranscribablePath(cleanPath) &&
|
|
609201
|
-
const isMarkdown = !isImage && !isMedia && /\.(md|markdown)$/i.test(cleanPath) &&
|
|
610421
|
+
const isImage = isImagePath(cleanPath) && existsSync107(resolve39(repoRoot, cleanPath));
|
|
610422
|
+
const isMedia = !isImage && isTranscribablePath(cleanPath) && existsSync107(resolve39(repoRoot, cleanPath));
|
|
610423
|
+
const isMarkdown = !isImage && !isMedia && /\.(md|markdown)$/i.test(cleanPath) && existsSync107(resolve39(repoRoot, cleanPath));
|
|
609202
610424
|
if (activeTask) {
|
|
609203
610425
|
if (activeTask.runner.isPaused) {
|
|
609204
610426
|
activeTask.runner.resume();
|
|
@@ -609207,7 +610429,7 @@ Execute this skill now. Follow the behavioral guidance above.`;
|
|
|
609207
610429
|
if (isImage) {
|
|
609208
610430
|
try {
|
|
609209
610431
|
const imgPath = resolve39(repoRoot, cleanPath);
|
|
609210
|
-
const imgBuffer =
|
|
610432
|
+
const imgBuffer = readFileSync87(imgPath);
|
|
609211
610433
|
const base642 = imgBuffer.toString("base64");
|
|
609212
610434
|
const ext = extname12(cleanPath).toLowerCase();
|
|
609213
610435
|
const mime = ext === ".png" ? "image/png" : ext === ".gif" ? "image/gif" : ext === ".webp" ? "image/webp" : "image/jpeg";
|
|
@@ -609363,7 +610585,7 @@ ${result.text}`;
|
|
|
609363
610585
|
if (isMarkdown && fullInput === input) {
|
|
609364
610586
|
try {
|
|
609365
610587
|
const mdPath = resolve39(repoRoot, cleanPath);
|
|
609366
|
-
const mdContent =
|
|
610588
|
+
const mdContent = readFileSync87(mdPath, "utf8");
|
|
609367
610589
|
const { parseMcpMarkdown: parseMcpMarkdown2 } = await Promise.resolve().then(() => (init_dist5(), dist_exports));
|
|
609368
610590
|
const result = parseMcpMarkdown2(mdContent);
|
|
609369
610591
|
if (result.servers.length > 0) {
|
|
@@ -609785,11 +611007,11 @@ async function runWithTUI(task, config, repoPath, callbacks) {
|
|
|
609785
611007
|
const handle2 = startTask(task, config, repoRoot);
|
|
609786
611008
|
await handle2.promise;
|
|
609787
611009
|
try {
|
|
609788
|
-
const ikDir =
|
|
609789
|
-
const ikFile =
|
|
611010
|
+
const ikDir = join123(repoRoot, ".oa", "identity");
|
|
611011
|
+
const ikFile = join123(ikDir, "self-state.json");
|
|
609790
611012
|
let ikState;
|
|
609791
|
-
if (
|
|
609792
|
-
ikState = JSON.parse(
|
|
611013
|
+
if (existsSync107(ikFile)) {
|
|
611014
|
+
ikState = JSON.parse(readFileSync87(ikFile, "utf8"));
|
|
609793
611015
|
} else {
|
|
609794
611016
|
mkdirSync64(ikDir, { recursive: true });
|
|
609795
611017
|
ikState = {
|
|
@@ -609826,11 +611048,11 @@ async function runWithTUI(task, config, repoPath, callbacks) {
|
|
|
609826
611048
|
);
|
|
609827
611049
|
} catch {
|
|
609828
611050
|
try {
|
|
609829
|
-
const archeDir =
|
|
609830
|
-
const archeFile =
|
|
611051
|
+
const archeDir = join123(repoRoot, ".oa", "arche");
|
|
611052
|
+
const archeFile = join123(archeDir, "variants.json");
|
|
609831
611053
|
let variants = [];
|
|
609832
611054
|
try {
|
|
609833
|
-
if (
|
|
611055
|
+
if (existsSync107(archeFile)) variants = JSON.parse(readFileSync87(archeFile, "utf8"));
|
|
609834
611056
|
} catch {
|
|
609835
611057
|
}
|
|
609836
611058
|
variants.push({
|
|
@@ -609850,9 +611072,9 @@ async function runWithTUI(task, config, repoPath, callbacks) {
|
|
|
609850
611072
|
}
|
|
609851
611073
|
}
|
|
609852
611074
|
try {
|
|
609853
|
-
const metaFile =
|
|
609854
|
-
if (
|
|
609855
|
-
const store2 = JSON.parse(
|
|
611075
|
+
const metaFile = join123(repoRoot, ".oa", "memory", "metabolism", "store.json");
|
|
611076
|
+
if (existsSync107(metaFile)) {
|
|
611077
|
+
const store2 = JSON.parse(readFileSync87(metaFile, "utf8"));
|
|
609856
611078
|
const surfaced = store2.filter((m2) => m2.type !== "quarantine" && m2.scores?.confidence > 0.15).sort((a2, b) => b.scores.utility * b.scores.confidence - a2.scores.utility * a2.scores.confidence).slice(0, 5);
|
|
609857
611079
|
let updated = false;
|
|
609858
611080
|
for (const item of surfaced) {
|
|
@@ -609916,9 +611138,9 @@ Rules:
|
|
|
609916
611138
|
try {
|
|
609917
611139
|
const { initDb: initDb2 } = __require("@open-agents/memory");
|
|
609918
611140
|
const { ProceduralMemoryStore: ProceduralMemoryStore2 } = __require("@open-agents/memory");
|
|
609919
|
-
const dbDir =
|
|
611141
|
+
const dbDir = join123(repoRoot, ".oa", "memory");
|
|
609920
611142
|
mkdirSync64(dbDir, { recursive: true });
|
|
609921
|
-
const db = initDb2(
|
|
611143
|
+
const db = initDb2(join123(dbDir, "structured.db"));
|
|
609922
611144
|
const memStore = new ProceduralMemoryStore2(db);
|
|
609923
611145
|
memStore.createWithEmbedding({
|
|
609924
611146
|
content: content.slice(0, 600),
|
|
@@ -609933,11 +611155,11 @@ Rules:
|
|
|
609933
611155
|
db.close();
|
|
609934
611156
|
} catch {
|
|
609935
611157
|
}
|
|
609936
|
-
const metaDir =
|
|
609937
|
-
const storeFile =
|
|
611158
|
+
const metaDir = join123(repoRoot, ".oa", "memory", "metabolism");
|
|
611159
|
+
const storeFile = join123(metaDir, "store.json");
|
|
609938
611160
|
let store2 = [];
|
|
609939
611161
|
try {
|
|
609940
|
-
if (
|
|
611162
|
+
if (existsSync107(storeFile)) store2 = JSON.parse(readFileSync87(storeFile, "utf8"));
|
|
609941
611163
|
} catch {
|
|
609942
611164
|
}
|
|
609943
611165
|
store2.push({
|
|
@@ -609959,19 +611181,19 @@ Rules:
|
|
|
609959
611181
|
} catch {
|
|
609960
611182
|
}
|
|
609961
611183
|
try {
|
|
609962
|
-
const cohereSettingsFile =
|
|
611184
|
+
const cohereSettingsFile = join123(repoRoot, ".oa", "settings.json");
|
|
609963
611185
|
let cohereActive = false;
|
|
609964
611186
|
try {
|
|
609965
|
-
if (
|
|
609966
|
-
const settings = JSON.parse(
|
|
611187
|
+
if (existsSync107(cohereSettingsFile)) {
|
|
611188
|
+
const settings = JSON.parse(readFileSync87(cohereSettingsFile, "utf8"));
|
|
609967
611189
|
cohereActive = settings.cohere === true;
|
|
609968
611190
|
}
|
|
609969
611191
|
} catch {
|
|
609970
611192
|
}
|
|
609971
611193
|
if (cohereActive) {
|
|
609972
|
-
const metaFile =
|
|
609973
|
-
if (
|
|
609974
|
-
const store2 = JSON.parse(
|
|
611194
|
+
const metaFile = join123(repoRoot, ".oa", "memory", "metabolism", "store.json");
|
|
611195
|
+
if (existsSync107(metaFile)) {
|
|
611196
|
+
const store2 = JSON.parse(readFileSync87(metaFile, "utf8"));
|
|
609975
611197
|
const latest = store2.filter((m2) => m2.sourceTrace === "trajectory-extraction" || m2.sourceTrace === "llm-trajectory-extraction").slice(-1)[0];
|
|
609976
611198
|
if (latest && latest.scores?.confidence >= 0.6) {
|
|
609977
611199
|
try {
|
|
@@ -609996,18 +611218,18 @@ Rules:
|
|
|
609996
611218
|
}
|
|
609997
611219
|
} catch (err) {
|
|
609998
611220
|
try {
|
|
609999
|
-
const ikFile =
|
|
610000
|
-
if (
|
|
610001
|
-
const ikState = JSON.parse(
|
|
611221
|
+
const ikFile = join123(repoRoot, ".oa", "identity", "self-state.json");
|
|
611222
|
+
if (existsSync107(ikFile)) {
|
|
611223
|
+
const ikState = JSON.parse(readFileSync87(ikFile, "utf8"));
|
|
610002
611224
|
ikState.homeostasis.uncertainty = Math.min(1, ikState.homeostasis.uncertainty + 0.1);
|
|
610003
611225
|
ikState.homeostasis.coherence = Math.max(0, ikState.homeostasis.coherence - 0.05);
|
|
610004
611226
|
ikState.session_count = (ikState.session_count || 0) + 1;
|
|
610005
611227
|
ikState.updated_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
610006
611228
|
writeFileSync56(ikFile, JSON.stringify(ikState, null, 2));
|
|
610007
611229
|
}
|
|
610008
|
-
const metaFile =
|
|
610009
|
-
if (
|
|
610010
|
-
const store2 = JSON.parse(
|
|
611230
|
+
const metaFile = join123(repoRoot, ".oa", "memory", "metabolism", "store.json");
|
|
611231
|
+
if (existsSync107(metaFile)) {
|
|
611232
|
+
const store2 = JSON.parse(readFileSync87(metaFile, "utf8"));
|
|
610011
611233
|
const surfaced = store2.filter((m2) => m2.type !== "quarantine" && m2.scores?.confidence > 0.15).sort((a2, b) => b.scores.utility * b.scores.confidence - a2.scores.utility * a2.scores.confidence).slice(0, 5);
|
|
610012
611234
|
for (const item of surfaced) {
|
|
610013
611235
|
item.accessCount = (item.accessCount || 0) + 1;
|
|
@@ -610018,11 +611240,11 @@ Rules:
|
|
|
610018
611240
|
writeFileSync56(metaFile, JSON.stringify(store2, null, 2));
|
|
610019
611241
|
}
|
|
610020
611242
|
try {
|
|
610021
|
-
const archeDir =
|
|
610022
|
-
const archeFile =
|
|
611243
|
+
const archeDir = join123(repoRoot, ".oa", "arche");
|
|
611244
|
+
const archeFile = join123(archeDir, "variants.json");
|
|
610023
611245
|
let variants = [];
|
|
610024
611246
|
try {
|
|
610025
|
-
if (
|
|
611247
|
+
if (existsSync107(archeFile)) variants = JSON.parse(readFileSync87(archeFile, "utf8"));
|
|
610026
611248
|
} catch {
|
|
610027
611249
|
}
|
|
610028
611250
|
variants.push({
|
|
@@ -610126,12 +611348,12 @@ __export(run_exports, {
|
|
|
610126
611348
|
});
|
|
610127
611349
|
import { resolve as resolve40 } from "node:path";
|
|
610128
611350
|
import { spawn as spawn26 } from "node:child_process";
|
|
610129
|
-
import { mkdirSync as mkdirSync65, writeFileSync as writeFileSync57, readFileSync as
|
|
611351
|
+
import { mkdirSync as mkdirSync65, writeFileSync as writeFileSync57, readFileSync as readFileSync88, readdirSync as readdirSync38, existsSync as existsSync108 } from "node:fs";
|
|
610130
611352
|
import { randomBytes as randomBytes24 } from "node:crypto";
|
|
610131
|
-
import { join as
|
|
611353
|
+
import { join as join124 } from "node:path";
|
|
610132
611354
|
function jobsDir2(repoPath) {
|
|
610133
611355
|
const root = resolve40(repoPath ?? process.cwd());
|
|
610134
|
-
const dir =
|
|
611356
|
+
const dir = join124(root, ".oa", "jobs");
|
|
610135
611357
|
mkdirSync65(dir, { recursive: true });
|
|
610136
611358
|
return dir;
|
|
610137
611359
|
}
|
|
@@ -610254,7 +611476,7 @@ async function runBackground(task, config, opts) {
|
|
|
610254
611476
|
}
|
|
610255
611477
|
});
|
|
610256
611478
|
job.pid = child.pid ?? 0;
|
|
610257
|
-
writeFileSync57(
|
|
611479
|
+
writeFileSync57(join124(dir, `${id}.json`), JSON.stringify(job, null, 2));
|
|
610258
611480
|
let output = "";
|
|
610259
611481
|
child.stdout?.on("data", (chunk) => {
|
|
610260
611482
|
output += chunk.toString();
|
|
@@ -610270,7 +611492,7 @@ async function runBackground(task, config, opts) {
|
|
|
610270
611492
|
job.summary = result.summary;
|
|
610271
611493
|
job.durationMs = result.durationMs;
|
|
610272
611494
|
job.error = result.error;
|
|
610273
|
-
writeFileSync57(
|
|
611495
|
+
writeFileSync57(join124(dir, `${id}.json`), JSON.stringify(job, null, 2));
|
|
610274
611496
|
} catch {
|
|
610275
611497
|
}
|
|
610276
611498
|
});
|
|
@@ -610286,13 +611508,13 @@ async function runBackground(task, config, opts) {
|
|
|
610286
611508
|
}
|
|
610287
611509
|
function statusCommand(jobId, repoPath) {
|
|
610288
611510
|
const dir = jobsDir2(repoPath);
|
|
610289
|
-
const file =
|
|
610290
|
-
if (!
|
|
611511
|
+
const file = join124(dir, `${jobId}.json`);
|
|
611512
|
+
if (!existsSync108(file)) {
|
|
610291
611513
|
console.error(`Job not found: ${jobId}`);
|
|
610292
611514
|
console.log(`Available jobs: oa jobs`);
|
|
610293
611515
|
process.exit(1);
|
|
610294
611516
|
}
|
|
610295
|
-
const job = JSON.parse(
|
|
611517
|
+
const job = JSON.parse(readFileSync88(file, "utf-8"));
|
|
610296
611518
|
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`;
|
|
610297
611519
|
const icon = job.status === "completed" ? "✓" : job.status === "failed" ? "✗" : "●";
|
|
610298
611520
|
console.log(`${icon} ${job.id} [${job.status}] ${runtime}`);
|
|
@@ -610313,7 +611535,7 @@ function jobsCommand(repoPath) {
|
|
|
610313
611535
|
console.log("Jobs:");
|
|
610314
611536
|
for (const file of files) {
|
|
610315
611537
|
try {
|
|
610316
|
-
const job = JSON.parse(
|
|
611538
|
+
const job = JSON.parse(readFileSync88(join124(dir, file), "utf-8"));
|
|
610317
611539
|
const icon = job.status === "completed" ? "✓" : job.status === "failed" ? "✗" : "●";
|
|
610318
611540
|
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`;
|
|
610319
611541
|
const cleanListTask = cleanForStorage(job.task) || job.task;
|
|
@@ -610337,13 +611559,13 @@ __export(index_repo_exports, {
|
|
|
610337
611559
|
indexRepoCommand: () => indexRepoCommand
|
|
610338
611560
|
});
|
|
610339
611561
|
import { resolve as resolve41 } from "node:path";
|
|
610340
|
-
import { existsSync as
|
|
611562
|
+
import { existsSync as existsSync109, statSync as statSync35 } from "node:fs";
|
|
610341
611563
|
import { cwd as cwd2 } from "node:process";
|
|
610342
611564
|
async function indexRepoCommand(opts, _config3) {
|
|
610343
611565
|
const repoRoot = resolve41(opts.repoPath ?? cwd2());
|
|
610344
611566
|
printHeader("Index Repository");
|
|
610345
611567
|
printInfo(`Indexing: ${repoRoot}`);
|
|
610346
|
-
if (!
|
|
611568
|
+
if (!existsSync109(repoRoot)) {
|
|
610347
611569
|
printError(`Path does not exist: ${repoRoot}`);
|
|
610348
611570
|
process.exit(1);
|
|
610349
611571
|
}
|
|
@@ -610595,8 +611817,8 @@ var config_exports2 = {};
|
|
|
610595
611817
|
__export(config_exports2, {
|
|
610596
611818
|
configCommand: () => configCommand
|
|
610597
611819
|
});
|
|
610598
|
-
import { join as
|
|
610599
|
-
import { homedir as
|
|
611820
|
+
import { join as join125, resolve as resolve42 } from "node:path";
|
|
611821
|
+
import { homedir as homedir45 } from "node:os";
|
|
610600
611822
|
import { cwd as cwd3 } from "node:process";
|
|
610601
611823
|
function redactIfSensitive(key, value2) {
|
|
610602
611824
|
if (SENSITIVE_KEYS.has(key) && typeof value2 === "string" && value2.length > 0) {
|
|
@@ -610677,7 +611899,7 @@ function handleShow(opts, config) {
|
|
|
610677
611899
|
}
|
|
610678
611900
|
}
|
|
610679
611901
|
printSection("Config File");
|
|
610680
|
-
printInfo(`~/.open-agents/config.json (${
|
|
611902
|
+
printInfo(`~/.open-agents/config.json (${join125(homedir45(), ".open-agents", "config.json")})`);
|
|
610681
611903
|
printSection("Priority Chain");
|
|
610682
611904
|
printInfo(" 1. CLI flags (--model, --backend-url, etc.)");
|
|
610683
611905
|
printInfo(" 2. Project .oa/settings.json (--local)");
|
|
@@ -610716,7 +611938,7 @@ function handleSet(opts, _config3) {
|
|
|
610716
611938
|
const coerced = coerceForSettings(key, value2);
|
|
610717
611939
|
saveProjectSettings(repoRoot, { [key]: coerced });
|
|
610718
611940
|
printSuccess(`Project override set: ${key} = ${redactIfSensitive(key, value2)}`);
|
|
610719
|
-
printInfo(`Saved to ${
|
|
611941
|
+
printInfo(`Saved to ${join125(repoRoot, ".oa", "settings.json")}`);
|
|
610720
611942
|
printInfo("This override applies only when running in this workspace.");
|
|
610721
611943
|
} catch (err) {
|
|
610722
611944
|
printError(`Failed to save: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -610901,7 +612123,7 @@ __export(eval_exports, {
|
|
|
610901
612123
|
});
|
|
610902
612124
|
import { tmpdir as tmpdir21 } from "node:os";
|
|
610903
612125
|
import { mkdirSync as mkdirSync66, writeFileSync as writeFileSync58 } from "node:fs";
|
|
610904
|
-
import { join as
|
|
612126
|
+
import { join as join126 } from "node:path";
|
|
610905
612127
|
async function evalCommand(opts, config) {
|
|
610906
612128
|
const suiteName = opts.suite ?? "basic";
|
|
610907
612129
|
const suite = SUITES[suiteName];
|
|
@@ -611030,10 +612252,10 @@ async function evalCommand(opts, config) {
|
|
|
611030
612252
|
process.exit(failed > 0 ? 1 : 0);
|
|
611031
612253
|
}
|
|
611032
612254
|
function createTempEvalRepo() {
|
|
611033
|
-
const dir =
|
|
612255
|
+
const dir = join126(tmpdir21(), `open-agents-eval-${Date.now()}`);
|
|
611034
612256
|
mkdirSync66(dir, { recursive: true });
|
|
611035
612257
|
writeFileSync58(
|
|
611036
|
-
|
|
612258
|
+
join126(dir, "package.json"),
|
|
611037
612259
|
JSON.stringify({ name: "eval-repo", version: "0.0.0" }, null, 2) + "\n",
|
|
611038
612260
|
"utf8"
|
|
611039
612261
|
);
|
|
@@ -611097,7 +612319,7 @@ init_typed_node_events();
|
|
|
611097
612319
|
import { parseArgs as nodeParseArgs2 } from "node:util";
|
|
611098
612320
|
import { createRequire as createRequire7 } from "node:module";
|
|
611099
612321
|
import { fileURLToPath as fileURLToPath19 } from "node:url";
|
|
611100
|
-
import { dirname as dirname38, join as
|
|
612322
|
+
import { dirname as dirname38, join as join127 } from "node:path";
|
|
611101
612323
|
|
|
611102
612324
|
// packages/cli/src/cli.ts
|
|
611103
612325
|
init_typed_node_events();
|
|
@@ -611237,7 +612459,7 @@ init_output();
|
|
|
611237
612459
|
function getVersion5() {
|
|
611238
612460
|
try {
|
|
611239
612461
|
const require4 = createRequire7(import.meta.url);
|
|
611240
|
-
const pkgPath =
|
|
612462
|
+
const pkgPath = join127(dirname38(fileURLToPath19(import.meta.url)), "..", "package.json");
|
|
611241
612463
|
const pkg = require4(pkgPath);
|
|
611242
612464
|
return pkg.version;
|
|
611243
612465
|
} catch {
|
|
@@ -611552,11 +612774,11 @@ function crashLog(label, err) {
|
|
|
611552
612774
|
`;
|
|
611553
612775
|
try {
|
|
611554
612776
|
const { appendFileSync: appendFileSync9, mkdirSync: mkdirSync67 } = __require("node:fs");
|
|
611555
|
-
const { join:
|
|
611556
|
-
const { homedir:
|
|
611557
|
-
const logDir =
|
|
612777
|
+
const { join: join128 } = __require("node:path");
|
|
612778
|
+
const { homedir: homedir46 } = __require("node:os");
|
|
612779
|
+
const logDir = join128(homedir46(), ".open-agents");
|
|
611558
612780
|
mkdirSync67(logDir, { recursive: true });
|
|
611559
|
-
appendFileSync9(
|
|
612781
|
+
appendFileSync9(join128(logDir, "crash.log"), logLine);
|
|
611560
612782
|
} catch {
|
|
611561
612783
|
}
|
|
611562
612784
|
try {
|