oasis_test 0.1.1 → 0.1.2
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 +438 -78
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -9092,7 +9092,7 @@ var require_compile = __commonJS({
|
|
|
9092
9092
|
const schOrFunc = root.refs[ref];
|
|
9093
9093
|
if (schOrFunc)
|
|
9094
9094
|
return schOrFunc;
|
|
9095
|
-
let _sch =
|
|
9095
|
+
let _sch = resolve.call(this, root, ref);
|
|
9096
9096
|
if (_sch === void 0) {
|
|
9097
9097
|
const schema = (_a = root.localRefs) === null || _a === void 0 ? void 0 : _a[ref];
|
|
9098
9098
|
const { schemaId } = this.opts;
|
|
@@ -9119,7 +9119,7 @@ var require_compile = __commonJS({
|
|
|
9119
9119
|
function sameSchemaEnv(s1, s2) {
|
|
9120
9120
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
9121
9121
|
}
|
|
9122
|
-
function
|
|
9122
|
+
function resolve(root, ref) {
|
|
9123
9123
|
let sch;
|
|
9124
9124
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
9125
9125
|
ref = sch;
|
|
@@ -9750,7 +9750,7 @@ var require_fast_uri = __commonJS({
|
|
|
9750
9750
|
}
|
|
9751
9751
|
return uri;
|
|
9752
9752
|
}
|
|
9753
|
-
function
|
|
9753
|
+
function resolve(baseURI, relativeURI, options) {
|
|
9754
9754
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
9755
9755
|
const resolved = resolveComponent(parse2(baseURI, schemelessOptions), parse2(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
9756
9756
|
schemelessOptions.skipEscape = true;
|
|
@@ -10008,7 +10008,7 @@ var require_fast_uri = __commonJS({
|
|
|
10008
10008
|
var fastUri = {
|
|
10009
10009
|
SCHEMES,
|
|
10010
10010
|
normalize,
|
|
10011
|
-
resolve
|
|
10011
|
+
resolve,
|
|
10012
10012
|
resolveComponent,
|
|
10013
10013
|
equal,
|
|
10014
10014
|
serialize,
|
|
@@ -16948,10 +16948,117 @@ var init_wrapper = __esm({
|
|
|
16948
16948
|
});
|
|
16949
16949
|
|
|
16950
16950
|
// ../server/src/daemon-hub.ts
|
|
16951
|
+
var DaemonHub;
|
|
16951
16952
|
var init_daemon_hub = __esm({
|
|
16952
16953
|
"../server/src/daemon-hub.ts"() {
|
|
16953
16954
|
"use strict";
|
|
16954
16955
|
init_wrapper();
|
|
16956
|
+
DaemonHub = class _DaemonHub {
|
|
16957
|
+
daemons = /* @__PURE__ */ new Map();
|
|
16958
|
+
wss;
|
|
16959
|
+
ghosts = /* @__PURE__ */ new Map();
|
|
16960
|
+
static GHOST_TTL_MS = 5 * 60 * 1e3;
|
|
16961
|
+
/** 外部可订阅的事件回调 */
|
|
16962
|
+
onDaemonConnected;
|
|
16963
|
+
onDaemonDisconnected;
|
|
16964
|
+
onMessage;
|
|
16965
|
+
messageListeners = /* @__PURE__ */ new Set();
|
|
16966
|
+
/** 多路消息订阅(onMessage 单槽之外的加法;DaemonHubAdapter 等用) */
|
|
16967
|
+
addMessageListener(cb) {
|
|
16968
|
+
this.messageListeners.add(cb);
|
|
16969
|
+
return () => this.messageListeners.delete(cb);
|
|
16970
|
+
}
|
|
16971
|
+
constructor(server, path6 = "/daemon/ws", resolveNode) {
|
|
16972
|
+
this.wss = new import_websocket_server.default({
|
|
16973
|
+
server,
|
|
16974
|
+
path: path6,
|
|
16975
|
+
...resolveNode ? {
|
|
16976
|
+
verifyClient: (info, cb) => {
|
|
16977
|
+
const authHeader = info.req.headers.authorization ?? "";
|
|
16978
|
+
const token2 = authHeader.startsWith("Bearer ") ? authHeader.slice("Bearer ".length) : "";
|
|
16979
|
+
const nodeId2 = token2 ? resolveNode(token2) : null;
|
|
16980
|
+
if (!nodeId2) {
|
|
16981
|
+
cb(false, 401, "invalid node token");
|
|
16982
|
+
return;
|
|
16983
|
+
}
|
|
16984
|
+
info.req.oasisNodeId = nodeId2;
|
|
16985
|
+
cb(true);
|
|
16986
|
+
}
|
|
16987
|
+
} : {}
|
|
16988
|
+
});
|
|
16989
|
+
this.wss.on("connection", (ws, req) => this.handleConnection(ws, req));
|
|
16990
|
+
}
|
|
16991
|
+
dispatch(daemonId, msg) {
|
|
16992
|
+
const daemon = this.daemons.get(daemonId);
|
|
16993
|
+
if (!daemon) return false;
|
|
16994
|
+
daemon.send(msg);
|
|
16995
|
+
return true;
|
|
16996
|
+
}
|
|
16997
|
+
broadcast(msg) {
|
|
16998
|
+
for (const daemon of this.daemons.values()) daemon.send(msg);
|
|
16999
|
+
}
|
|
17000
|
+
connectedDaemons() {
|
|
17001
|
+
return [...this.daemons.values()];
|
|
17002
|
+
}
|
|
17003
|
+
/** Nodes that disconnected within the last GHOST_TTL_MS ms. */
|
|
17004
|
+
recentlyDisconnected() {
|
|
17005
|
+
const cutoff = Date.now() - _DaemonHub.GHOST_TTL_MS;
|
|
17006
|
+
const result = [];
|
|
17007
|
+
for (const [id, g] of this.ghosts) {
|
|
17008
|
+
if (g.disconnectedAt < cutoff) {
|
|
17009
|
+
this.ghosts.delete(id);
|
|
17010
|
+
continue;
|
|
17011
|
+
}
|
|
17012
|
+
result.push({ daemonId: id, meta: g.meta, disconnectedAt: g.disconnectedAt });
|
|
17013
|
+
}
|
|
17014
|
+
return result;
|
|
17015
|
+
}
|
|
17016
|
+
evictGhost(daemonId) {
|
|
17017
|
+
this.ghosts.delete(daemonId);
|
|
17018
|
+
}
|
|
17019
|
+
handleConnection(ws, req) {
|
|
17020
|
+
const verifiedId = req.oasisNodeId;
|
|
17021
|
+
const daemonId = verifiedId ?? req.headers["x-daemon-id"] ?? `anon-${Date.now()}`;
|
|
17022
|
+
let registered = false;
|
|
17023
|
+
const daemon = {
|
|
17024
|
+
daemonId,
|
|
17025
|
+
meta: { hostname: "unknown", adapters: [], nodeVersion: "unknown" },
|
|
17026
|
+
send: (msg) => {
|
|
17027
|
+
if (ws.readyState === import_websocket.default.OPEN) ws.send(JSON.stringify(msg));
|
|
17028
|
+
},
|
|
17029
|
+
close: () => ws.close()
|
|
17030
|
+
};
|
|
17031
|
+
ws.on("message", (raw) => {
|
|
17032
|
+
let msg;
|
|
17033
|
+
try {
|
|
17034
|
+
msg = JSON.parse(raw.toString());
|
|
17035
|
+
} catch {
|
|
17036
|
+
return;
|
|
17037
|
+
}
|
|
17038
|
+
if (msg.type === "hello") {
|
|
17039
|
+
this.ghosts.delete(daemonId);
|
|
17040
|
+
Object.assign(daemon.meta, msg.meta);
|
|
17041
|
+
if (!registered) {
|
|
17042
|
+
registered = true;
|
|
17043
|
+
this.daemons.set(daemonId, daemon);
|
|
17044
|
+
this.onDaemonConnected?.(daemon);
|
|
17045
|
+
}
|
|
17046
|
+
}
|
|
17047
|
+
this.onMessage?.(daemonId, msg);
|
|
17048
|
+
for (const listener of this.messageListeners) listener(daemonId, msg);
|
|
17049
|
+
});
|
|
17050
|
+
ws.on("close", () => {
|
|
17051
|
+
const d = this.daemons.get(daemonId);
|
|
17052
|
+
if (d) this.ghosts.set(daemonId, { meta: { ...d.meta }, disconnectedAt: Date.now() });
|
|
17053
|
+
this.daemons.delete(daemonId);
|
|
17054
|
+
this.onDaemonDisconnected?.(daemonId);
|
|
17055
|
+
});
|
|
17056
|
+
ws.on("error", (err) => {
|
|
17057
|
+
console.error(`[hub] daemon ${daemonId} error:`, err.message);
|
|
17058
|
+
});
|
|
17059
|
+
daemon.send({ type: "ping" });
|
|
17060
|
+
}
|
|
17061
|
+
};
|
|
16955
17062
|
}
|
|
16956
17063
|
});
|
|
16957
17064
|
|
|
@@ -17178,6 +17285,35 @@ var init_collab = __esm({
|
|
|
17178
17285
|
var init_service4 = __esm({
|
|
17179
17286
|
"../server/src/domains/trace/service.ts"() {
|
|
17180
17287
|
"use strict";
|
|
17288
|
+
init_src();
|
|
17289
|
+
}
|
|
17290
|
+
});
|
|
17291
|
+
|
|
17292
|
+
// ../server/src/domains/trace/otlp/redact.ts
|
|
17293
|
+
var MASK, TEXT_PATTERNS;
|
|
17294
|
+
var init_redact = __esm({
|
|
17295
|
+
"../server/src/domains/trace/otlp/redact.ts"() {
|
|
17296
|
+
"use strict";
|
|
17297
|
+
MASK = "***";
|
|
17298
|
+
TEXT_PATTERNS = [
|
|
17299
|
+
[/\bBearer\s+[A-Za-z0-9._\-]+/gi, "Bearer " + MASK],
|
|
17300
|
+
[/\b(sk|pk)-[A-Za-z0-9]{8,}\b/g, MASK],
|
|
17301
|
+
// OpenAI 风格
|
|
17302
|
+
[/\bgh[pousr]_[A-Za-z0-9]{20,}\b/g, MASK],
|
|
17303
|
+
// GitHub token
|
|
17304
|
+
[/\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g, MASK],
|
|
17305
|
+
// Slack token
|
|
17306
|
+
// key=value / key: "value"(键名敏感时遮值)
|
|
17307
|
+
[/\b(api[_-]?key|secret|password|passwd|token|authorization|access[_-]?token|refresh[_-]?token)(["']?\s*[:=]\s*["']?)([^\s"',}]{6,})/gi, `$1$2${MASK}`]
|
|
17308
|
+
];
|
|
17309
|
+
}
|
|
17310
|
+
});
|
|
17311
|
+
|
|
17312
|
+
// ../server/src/domains/trace/otlp/map.ts
|
|
17313
|
+
var init_map2 = __esm({
|
|
17314
|
+
"../server/src/domains/trace/otlp/map.ts"() {
|
|
17315
|
+
"use strict";
|
|
17316
|
+
init_redact();
|
|
17181
17317
|
}
|
|
17182
17318
|
});
|
|
17183
17319
|
|
|
@@ -17187,6 +17323,7 @@ var init_routes5 = __esm({
|
|
|
17187
17323
|
"use strict";
|
|
17188
17324
|
init_src();
|
|
17189
17325
|
init_router();
|
|
17326
|
+
init_map2();
|
|
17190
17327
|
}
|
|
17191
17328
|
});
|
|
17192
17329
|
|
|
@@ -20286,7 +20423,7 @@ var require_dist2 = __commonJS({
|
|
|
20286
20423
|
function parse2(stream, callback) {
|
|
20287
20424
|
const parser = new parser_1.Parser();
|
|
20288
20425
|
stream.on("data", (buffer) => parser.parse(buffer, callback));
|
|
20289
|
-
return new Promise((
|
|
20426
|
+
return new Promise((resolve) => stream.on("end", () => resolve()));
|
|
20290
20427
|
}
|
|
20291
20428
|
exports2.parse = parse2;
|
|
20292
20429
|
}
|
|
@@ -21029,12 +21166,12 @@ var require_client = __commonJS({
|
|
|
21029
21166
|
this._connect(callback);
|
|
21030
21167
|
return;
|
|
21031
21168
|
}
|
|
21032
|
-
return new this._Promise((
|
|
21169
|
+
return new this._Promise((resolve, reject) => {
|
|
21033
21170
|
this._connect((error2) => {
|
|
21034
21171
|
if (error2) {
|
|
21035
21172
|
reject(error2);
|
|
21036
21173
|
} else {
|
|
21037
|
-
|
|
21174
|
+
resolve(this);
|
|
21038
21175
|
}
|
|
21039
21176
|
});
|
|
21040
21177
|
});
|
|
@@ -21381,8 +21518,8 @@ var require_client = __commonJS({
|
|
|
21381
21518
|
} else {
|
|
21382
21519
|
query = new Query2(config2, values, callback);
|
|
21383
21520
|
if (!query.callback) {
|
|
21384
|
-
result = new this._Promise((
|
|
21385
|
-
query.callback = (err, res) => err ? reject(err) :
|
|
21521
|
+
result = new this._Promise((resolve, reject) => {
|
|
21522
|
+
query.callback = (err, res) => err ? reject(err) : resolve(res);
|
|
21386
21523
|
}).catch((err) => {
|
|
21387
21524
|
Error.captureStackTrace(err);
|
|
21388
21525
|
throw err;
|
|
@@ -21466,8 +21603,8 @@ var require_client = __commonJS({
|
|
|
21466
21603
|
if (cb) {
|
|
21467
21604
|
this.connection.once("end", cb);
|
|
21468
21605
|
} else {
|
|
21469
|
-
return new this._Promise((
|
|
21470
|
-
this.connection.once("end",
|
|
21606
|
+
return new this._Promise((resolve) => {
|
|
21607
|
+
this.connection.once("end", resolve);
|
|
21471
21608
|
});
|
|
21472
21609
|
}
|
|
21473
21610
|
}
|
|
@@ -21516,8 +21653,8 @@ var require_pg_pool = __commonJS({
|
|
|
21516
21653
|
const cb = function(err, client) {
|
|
21517
21654
|
err ? rej(err) : res(client);
|
|
21518
21655
|
};
|
|
21519
|
-
const result = new Promise2(function(
|
|
21520
|
-
res =
|
|
21656
|
+
const result = new Promise2(function(resolve, reject) {
|
|
21657
|
+
res = resolve;
|
|
21521
21658
|
rej = reject;
|
|
21522
21659
|
}).catch((err) => {
|
|
21523
21660
|
Error.captureStackTrace(err);
|
|
@@ -21578,7 +21715,7 @@ var require_pg_pool = __commonJS({
|
|
|
21578
21715
|
if (typeof Promise2.try === "function") {
|
|
21579
21716
|
return Promise2.try(f);
|
|
21580
21717
|
}
|
|
21581
|
-
return new Promise2((
|
|
21718
|
+
return new Promise2((resolve) => resolve(f()));
|
|
21582
21719
|
}
|
|
21583
21720
|
_isFull() {
|
|
21584
21721
|
return this._clients.length >= this.options.max;
|
|
@@ -21971,8 +22108,8 @@ var require_query2 = __commonJS({
|
|
|
21971
22108
|
NativeQuery.prototype._getPromise = function() {
|
|
21972
22109
|
if (this._promise) return this._promise;
|
|
21973
22110
|
this._promise = new Promise(
|
|
21974
|
-
function(
|
|
21975
|
-
this._once("end",
|
|
22111
|
+
function(resolve, reject) {
|
|
22112
|
+
this._once("end", resolve);
|
|
21976
22113
|
this._once("error", reject);
|
|
21977
22114
|
}.bind(this)
|
|
21978
22115
|
);
|
|
@@ -22149,12 +22286,12 @@ var require_client2 = __commonJS({
|
|
|
22149
22286
|
this._connect(callback);
|
|
22150
22287
|
return;
|
|
22151
22288
|
}
|
|
22152
|
-
return new this._Promise((
|
|
22289
|
+
return new this._Promise((resolve, reject) => {
|
|
22153
22290
|
this._connect((error2) => {
|
|
22154
22291
|
if (error2) {
|
|
22155
22292
|
reject(error2);
|
|
22156
22293
|
} else {
|
|
22157
|
-
|
|
22294
|
+
resolve(this);
|
|
22158
22295
|
}
|
|
22159
22296
|
});
|
|
22160
22297
|
});
|
|
@@ -22178,8 +22315,8 @@ var require_client2 = __commonJS({
|
|
|
22178
22315
|
query = new NativeQuery(config2, values, callback);
|
|
22179
22316
|
if (!query.callback) {
|
|
22180
22317
|
let resolveOut, rejectOut;
|
|
22181
|
-
result = new this._Promise((
|
|
22182
|
-
resolveOut =
|
|
22318
|
+
result = new this._Promise((resolve, reject) => {
|
|
22319
|
+
resolveOut = resolve;
|
|
22183
22320
|
rejectOut = reject;
|
|
22184
22321
|
}).catch((err) => {
|
|
22185
22322
|
Error.captureStackTrace(err);
|
|
@@ -22242,8 +22379,8 @@ var require_client2 = __commonJS({
|
|
|
22242
22379
|
}
|
|
22243
22380
|
let result;
|
|
22244
22381
|
if (!cb) {
|
|
22245
|
-
result = new this._Promise(function(
|
|
22246
|
-
cb = (err) => err ? reject(err) :
|
|
22382
|
+
result = new this._Promise(function(resolve, reject) {
|
|
22383
|
+
cb = (err) => err ? reject(err) : resolve();
|
|
22247
22384
|
});
|
|
22248
22385
|
}
|
|
22249
22386
|
this.native.end(function() {
|
|
@@ -22393,6 +22530,7 @@ var init_trajectory = __esm({
|
|
|
22393
22530
|
// src/index.ts
|
|
22394
22531
|
var import_node_crypto7 = require("node:crypto");
|
|
22395
22532
|
var fs5 = __toESM(require("node:fs"));
|
|
22533
|
+
var os5 = __toESM(require("node:os"));
|
|
22396
22534
|
var path5 = __toESM(require("node:path"));
|
|
22397
22535
|
|
|
22398
22536
|
// ../cli/src/serve.ts
|
|
@@ -22459,6 +22597,43 @@ function normalizeClaudeStreamLine(line) {
|
|
|
22459
22597
|
}
|
|
22460
22598
|
return [];
|
|
22461
22599
|
}
|
|
22600
|
+
function asNum(v) {
|
|
22601
|
+
return typeof v === "number" && Number.isFinite(v) ? v : 0;
|
|
22602
|
+
}
|
|
22603
|
+
function newClaudeUsageAcc() {
|
|
22604
|
+
return { input: 0, output: 0, cacheRead: 0, cacheCreation: 0, costUsd: null, saw: false };
|
|
22605
|
+
}
|
|
22606
|
+
function accumulateClaudeUsage(acc, p) {
|
|
22607
|
+
const type = p["type"];
|
|
22608
|
+
if (type === "assistant") {
|
|
22609
|
+
const msg = p["message"];
|
|
22610
|
+
const u = msg?.usage;
|
|
22611
|
+
if (u && typeof u === "object") {
|
|
22612
|
+
acc.input += asNum(u["input_tokens"]);
|
|
22613
|
+
acc.output += asNum(u["output_tokens"]);
|
|
22614
|
+
acc.cacheRead += asNum(u["cache_read_input_tokens"]);
|
|
22615
|
+
acc.cacheCreation += asNum(u["cache_creation_input_tokens"]);
|
|
22616
|
+
acc.saw = true;
|
|
22617
|
+
}
|
|
22618
|
+
} else if (type === "result") {
|
|
22619
|
+
const c = p["total_cost_usd"];
|
|
22620
|
+
if (typeof c === "number" && Number.isFinite(c)) {
|
|
22621
|
+
acc.costUsd = c;
|
|
22622
|
+
acc.saw = true;
|
|
22623
|
+
}
|
|
22624
|
+
}
|
|
22625
|
+
}
|
|
22626
|
+
function buildClaudeUsage(acc) {
|
|
22627
|
+
if (!acc.saw) return void 0;
|
|
22628
|
+
return {
|
|
22629
|
+
inputTokens: acc.input,
|
|
22630
|
+
outputTokens: acc.output,
|
|
22631
|
+
totalTokens: acc.input + acc.output,
|
|
22632
|
+
cacheReadTokens: acc.cacheRead,
|
|
22633
|
+
cacheCreationTokens: acc.cacheCreation,
|
|
22634
|
+
costUsdMicros: acc.costUsd != null ? Math.round(acc.costUsd * 1e6) : null
|
|
22635
|
+
};
|
|
22636
|
+
}
|
|
22462
22637
|
function scrubLeakyEnv(env) {
|
|
22463
22638
|
const LEAKY = /^npm_|^PNPM_|^INIT_CWD$|^OLDPWD$/;
|
|
22464
22639
|
return Object.fromEntries(Object.entries(env).filter(([k]) => !LEAKY.test(k)));
|
|
@@ -22476,14 +22651,35 @@ var ClaudeCodeAdapter = class {
|
|
|
22476
22651
|
constructor(opts = {}) {
|
|
22477
22652
|
this.opts = opts;
|
|
22478
22653
|
}
|
|
22654
|
+
/**
|
|
22655
|
+
* OTel 接线开关:opts.otel 优先,否则回落环境变量(OASIS_OTEL_ENDPOINT 设了即开)。
|
|
22656
|
+
* 关时返回 {}(无任何 OTEL_* 注入,行为与未接入前一致)。
|
|
22657
|
+
* runId 等进 OTEL_RESOURCE_ATTRIBUTES,让 Claude Code 自带 OTel 的上报归位到本次 run。
|
|
22658
|
+
*/
|
|
22659
|
+
resolveOtelEnv(job, runId) {
|
|
22660
|
+
const endpoint = this.opts.otel?.endpoint ?? process.env["OASIS_OTEL_ENDPOINT"];
|
|
22661
|
+
if (!endpoint) return {};
|
|
22662
|
+
const protocol = this.opts.otel?.protocol ?? process.env["OASIS_OTEL_PROTOCOL"] ?? "http/protobuf";
|
|
22663
|
+
const logs = this.opts.otel?.logs ?? process.env["OASIS_OTEL_LOGS"] === "1";
|
|
22664
|
+
return {
|
|
22665
|
+
CLAUDE_CODE_ENABLE_TELEMETRY: "1",
|
|
22666
|
+
OTEL_METRICS_EXPORTER: "otlp",
|
|
22667
|
+
...logs ? { OTEL_LOGS_EXPORTER: "otlp" } : {},
|
|
22668
|
+
OTEL_EXPORTER_OTLP_PROTOCOL: protocol,
|
|
22669
|
+
OTEL_EXPORTER_OTLP_ENDPOINT: endpoint,
|
|
22670
|
+
// 复用 agent 自己的 bearer 作上报鉴权(与 /api/traces/otlp 的 Bearer 门一致)。
|
|
22671
|
+
OTEL_EXPORTER_OTLP_HEADERS: `Authorization=Bearer ${job.actorToken}`,
|
|
22672
|
+
OTEL_RESOURCE_ATTRIBUTES: `oasis.run_id=${runId},oasis.actor_id=${job.actor},oasis.artifact_id=${job.artifactId}`
|
|
22673
|
+
};
|
|
22674
|
+
}
|
|
22479
22675
|
async spawn(job) {
|
|
22480
22676
|
const slug = job.artifactId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 32);
|
|
22481
22677
|
const id = `claude-${slug}-${(0, import_node_crypto2.randomUUID)().slice(0, 8)}`;
|
|
22482
|
-
const
|
|
22678
|
+
const dir = fs.mkdtempSync(
|
|
22483
22679
|
path.join(this.opts.workRoot ?? os.tmpdir(), "oasis-session-")
|
|
22484
22680
|
);
|
|
22485
22681
|
for (const [rel, content] of Object.entries(job.bundle.files)) {
|
|
22486
|
-
const file = path.join(
|
|
22682
|
+
const file = path.join(dir, rel);
|
|
22487
22683
|
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
22488
22684
|
fs.writeFileSync(file, content);
|
|
22489
22685
|
}
|
|
@@ -22501,8 +22697,9 @@ var ClaudeCodeAdapter = class {
|
|
|
22501
22697
|
...this.opts.model ? ["--model", this.opts.model] : [],
|
|
22502
22698
|
...this.opts.extraArgs ?? []
|
|
22503
22699
|
];
|
|
22700
|
+
const otelEnv = this.resolveOtelEnv(job, id);
|
|
22504
22701
|
const child = (0, import_node_child_process3.spawn)(this.opts.claudeBin ?? "claude", args, {
|
|
22505
|
-
cwd:
|
|
22702
|
+
cwd: dir,
|
|
22506
22703
|
env: {
|
|
22507
22704
|
// 凭证泄漏防护:剔除 pnpm/npm 脚本注入的变量——npm_lifecycle_script 等会把 serve 的启动命令
|
|
22508
22705
|
// (含 `--dir <数据目录>`,即 operator-token 所在)泄给 agent,它据此用 operator 凭证冒充人。
|
|
@@ -22514,15 +22711,18 @@ var ClaudeCodeAdapter = class {
|
|
|
22514
22711
|
...this.opts.maxOutputTokens ? { CLAUDE_CODE_MAX_OUTPUT_TOKENS: String(this.opts.maxOutputTokens) } : {},
|
|
22515
22712
|
...job.wrapperPaths?.length ? { PATH: `${job.wrapperPaths.map((p) => path.dirname(p)).join(path.delimiter)}${path.delimiter}${job.env?.["PATH"] ?? process.env["PATH"] ?? ""}` } : {},
|
|
22516
22713
|
OASIS_SERVER: job.server.url,
|
|
22517
|
-
OASIS_TOKEN: job.actorToken
|
|
22714
|
+
OASIS_TOKEN: job.actorToken,
|
|
22715
|
+
// OTel 遥测(默认关;resolveOtelEnv 决定开不开,runId 进 resource 属性自然归位到本次 run)。
|
|
22716
|
+
...otelEnv
|
|
22518
22717
|
},
|
|
22519
22718
|
stdio: ["ignore", "pipe", "pipe"]
|
|
22520
22719
|
});
|
|
22521
|
-
let transcriptRef = path.join(
|
|
22720
|
+
let transcriptRef = path.join(dir, "transcript.txt");
|
|
22522
22721
|
const out = fs.createWriteStream(transcriptRef);
|
|
22523
22722
|
const telemetryCbs = [];
|
|
22524
22723
|
let eventSeq = 0;
|
|
22525
22724
|
let lastResult;
|
|
22725
|
+
const usageAcc = newClaudeUsageAcc();
|
|
22526
22726
|
const outputCbs = [];
|
|
22527
22727
|
if (this.opts.streamJson) {
|
|
22528
22728
|
const rl = readline.createInterface({ input: child.stdout });
|
|
@@ -22531,6 +22731,7 @@ var ClaudeCodeAdapter = class {
|
|
|
22531
22731
|
try {
|
|
22532
22732
|
const p = JSON.parse(line);
|
|
22533
22733
|
if (p["type"] === "result") lastResult = p;
|
|
22734
|
+
accumulateClaudeUsage(usageAcc, p);
|
|
22534
22735
|
if (p["type"] === "stream_event") {
|
|
22535
22736
|
const evt = p["event"];
|
|
22536
22737
|
if (evt?.type === "content_block_delta" && evt.delta?.type === "text_delta" && typeof evt.delta.text === "string") {
|
|
@@ -22586,7 +22787,7 @@ var ClaudeCodeAdapter = class {
|
|
|
22586
22787
|
out.end(() => {
|
|
22587
22788
|
try {
|
|
22588
22789
|
fs.renameSync(src, kept);
|
|
22589
|
-
fs.rmSync(
|
|
22790
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
22590
22791
|
} catch {
|
|
22591
22792
|
}
|
|
22592
22793
|
});
|
|
@@ -22594,7 +22795,8 @@ var ClaudeCodeAdapter = class {
|
|
|
22594
22795
|
} catch {
|
|
22595
22796
|
}
|
|
22596
22797
|
}
|
|
22597
|
-
|
|
22798
|
+
const usage = buildClaudeUsage(usageAcc);
|
|
22799
|
+
exited = { code: killedByUs ? null : code, ...reason ? { reason } : {}, transcriptRef, ...usage ? { usage } : {} };
|
|
22598
22800
|
for (const cb of callbacks.splice(0)) cb(exited);
|
|
22599
22801
|
});
|
|
22600
22802
|
return {
|
|
@@ -22624,6 +22826,102 @@ var fs2 = __toESM(require("node:fs"), 1);
|
|
|
22624
22826
|
var os2 = __toESM(require("node:os"), 1);
|
|
22625
22827
|
var path2 = __toESM(require("node:path"), 1);
|
|
22626
22828
|
var readline2 = __toESM(require("node:readline"), 1);
|
|
22829
|
+
function codexNum(v) {
|
|
22830
|
+
return typeof v === "number" && Number.isFinite(v) ? v : 0;
|
|
22831
|
+
}
|
|
22832
|
+
function parseCodexTokenUsage(lines) {
|
|
22833
|
+
let last;
|
|
22834
|
+
for (const line of lines) {
|
|
22835
|
+
if (!line || line.indexOf("token_count") === -1) continue;
|
|
22836
|
+
let o;
|
|
22837
|
+
try {
|
|
22838
|
+
o = JSON.parse(line);
|
|
22839
|
+
} catch {
|
|
22840
|
+
continue;
|
|
22841
|
+
}
|
|
22842
|
+
if (o?.type === "event_msg" && o.payload?.type === "token_count" && o.payload.info?.total_token_usage) {
|
|
22843
|
+
last = o.payload.info.total_token_usage;
|
|
22844
|
+
}
|
|
22845
|
+
}
|
|
22846
|
+
if (!last) return void 0;
|
|
22847
|
+
const cacheRead = codexNum(last["cached_input_tokens"]) || codexNum(last["cache_read_input_tokens"]);
|
|
22848
|
+
const inputFresh = Math.max(codexNum(last["input_tokens"]) - cacheRead, 0);
|
|
22849
|
+
const output = codexNum(last["output_tokens"]) + codexNum(last["reasoning_output_tokens"]);
|
|
22850
|
+
return {
|
|
22851
|
+
inputTokens: inputFresh,
|
|
22852
|
+
outputTokens: output,
|
|
22853
|
+
totalTokens: inputFresh + output,
|
|
22854
|
+
// = input+output(不含 cache,与 claude/OTLP 口径一致)
|
|
22855
|
+
cacheReadTokens: cacheRead,
|
|
22856
|
+
cacheCreationTokens: null,
|
|
22857
|
+
// codex 不报 cache 写入
|
|
22858
|
+
costUsdMicros: null
|
|
22859
|
+
// codex rollout 无成本
|
|
22860
|
+
};
|
|
22861
|
+
}
|
|
22862
|
+
function codexSessionsRoot() {
|
|
22863
|
+
const candidates = [];
|
|
22864
|
+
const ch = process.env["CODEX_HOME"];
|
|
22865
|
+
if (ch) candidates.push(path2.join(ch, "sessions"));
|
|
22866
|
+
const home = process.env["HOME"] || os2.homedir();
|
|
22867
|
+
if (home) candidates.push(path2.join(home, ".codex", "sessions"));
|
|
22868
|
+
for (const c of candidates) {
|
|
22869
|
+
try {
|
|
22870
|
+
if (fs2.statSync(c).isDirectory()) return c;
|
|
22871
|
+
} catch {
|
|
22872
|
+
}
|
|
22873
|
+
}
|
|
22874
|
+
return "";
|
|
22875
|
+
}
|
|
22876
|
+
function listRecentRollouts(root, sinceMs) {
|
|
22877
|
+
const margin = sinceMs - 6e4;
|
|
22878
|
+
const found = [];
|
|
22879
|
+
const walk = (d) => {
|
|
22880
|
+
let ents;
|
|
22881
|
+
try {
|
|
22882
|
+
ents = fs2.readdirSync(d, { withFileTypes: true });
|
|
22883
|
+
} catch {
|
|
22884
|
+
return;
|
|
22885
|
+
}
|
|
22886
|
+
for (const ent of ents) {
|
|
22887
|
+
const p = path2.join(d, ent.name);
|
|
22888
|
+
if (ent.isDirectory()) walk(p);
|
|
22889
|
+
else if (ent.isFile() && ent.name.startsWith("rollout-") && ent.name.endsWith(".jsonl")) {
|
|
22890
|
+
let m = 0;
|
|
22891
|
+
try {
|
|
22892
|
+
m = fs2.statSync(p).mtimeMs;
|
|
22893
|
+
} catch {
|
|
22894
|
+
}
|
|
22895
|
+
if (m >= margin) found.push({ f: p, m });
|
|
22896
|
+
}
|
|
22897
|
+
}
|
|
22898
|
+
};
|
|
22899
|
+
walk(root);
|
|
22900
|
+
return found.sort((a, b) => b.m - a.m).map((x) => x.f);
|
|
22901
|
+
}
|
|
22902
|
+
function scanCodexUsage(workdir, sinceMs, sessionsRoot = codexSessionsRoot()) {
|
|
22903
|
+
try {
|
|
22904
|
+
for (const f of listRecentRollouts(sessionsRoot, sinceMs)) {
|
|
22905
|
+
let lines;
|
|
22906
|
+
try {
|
|
22907
|
+
lines = fs2.readFileSync(f, "utf8").split("\n");
|
|
22908
|
+
} catch {
|
|
22909
|
+
continue;
|
|
22910
|
+
}
|
|
22911
|
+
let meta;
|
|
22912
|
+
try {
|
|
22913
|
+
meta = JSON.parse(lines[0] ?? "");
|
|
22914
|
+
} catch {
|
|
22915
|
+
continue;
|
|
22916
|
+
}
|
|
22917
|
+
if (meta?.type === "session_meta" && meta.payload?.cwd === workdir) {
|
|
22918
|
+
return parseCodexTokenUsage(lines);
|
|
22919
|
+
}
|
|
22920
|
+
}
|
|
22921
|
+
} catch {
|
|
22922
|
+
}
|
|
22923
|
+
return void 0;
|
|
22924
|
+
}
|
|
22627
22925
|
function createCodexNormalizeState() {
|
|
22628
22926
|
return { toolUseIds: /* @__PURE__ */ new Set(), previousAgentMessage: false, lastAgentMessageEndedWithNewline: false };
|
|
22629
22927
|
}
|
|
@@ -22797,9 +23095,10 @@ var CodexAdapter = class {
|
|
|
22797
23095
|
async spawn(job) {
|
|
22798
23096
|
const slug = job.artifactId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 32);
|
|
22799
23097
|
const id = `codex-${slug}-${(0, import_node_crypto3.randomUUID)().slice(0, 8)}`;
|
|
22800
|
-
const
|
|
23098
|
+
const startedAtMs = Date.now();
|
|
23099
|
+
const dir = fs2.mkdtempSync(path2.join(this.opts.workRoot ?? os2.tmpdir(), "oasis-session-"));
|
|
22801
23100
|
for (const [rel, content] of Object.entries(job.bundle.files)) {
|
|
22802
|
-
const file = path2.join(
|
|
23101
|
+
const file = path2.join(dir, rel);
|
|
22803
23102
|
fs2.mkdirSync(path2.dirname(file), { recursive: true });
|
|
22804
23103
|
fs2.writeFileSync(file, content);
|
|
22805
23104
|
}
|
|
@@ -22812,13 +23111,13 @@ var CodexAdapter = class {
|
|
|
22812
23111
|
"--dangerously-bypass-approvals-and-sandbox",
|
|
22813
23112
|
"--skip-git-repo-check",
|
|
22814
23113
|
"-C",
|
|
22815
|
-
|
|
23114
|
+
dir,
|
|
22816
23115
|
...this.opts.model ? ["--model", this.opts.model] : [],
|
|
22817
23116
|
...this.opts.extraArgs ?? [],
|
|
22818
23117
|
prompt
|
|
22819
23118
|
];
|
|
22820
23119
|
const child = (0, import_node_child_process4.spawn)(this.opts.codexBin ?? "codex", args, {
|
|
22821
|
-
cwd:
|
|
23120
|
+
cwd: dir,
|
|
22822
23121
|
env: {
|
|
22823
23122
|
...scrubLeakyEnv(process.env),
|
|
22824
23123
|
...this.opts.env,
|
|
@@ -22829,7 +23128,7 @@ var CodexAdapter = class {
|
|
|
22829
23128
|
},
|
|
22830
23129
|
stdio: ["ignore", "pipe", "pipe"]
|
|
22831
23130
|
});
|
|
22832
|
-
let transcriptRef = path2.join(
|
|
23131
|
+
let transcriptRef = path2.join(dir, "transcript.txt");
|
|
22833
23132
|
const out = fs2.createWriteStream(transcriptRef);
|
|
22834
23133
|
const outputCbs = [];
|
|
22835
23134
|
const telemetryCbs = [];
|
|
@@ -22867,7 +23166,7 @@ var CodexAdapter = class {
|
|
|
22867
23166
|
out.end(() => {
|
|
22868
23167
|
try {
|
|
22869
23168
|
fs2.renameSync(src, kept);
|
|
22870
|
-
fs2.rmSync(
|
|
23169
|
+
fs2.rmSync(dir, { recursive: true, force: true });
|
|
22871
23170
|
} catch {
|
|
22872
23171
|
}
|
|
22873
23172
|
});
|
|
@@ -22889,10 +23188,12 @@ var CodexAdapter = class {
|
|
|
22889
23188
|
});
|
|
22890
23189
|
child.on("exit", (code) => {
|
|
22891
23190
|
clearTimeout(timer);
|
|
23191
|
+
const usage = scanCodexUsage(dir, startedAtMs);
|
|
22892
23192
|
finish({
|
|
22893
23193
|
code: killedByUs ? null : code,
|
|
22894
23194
|
reason: killedByUs ? "timeout" : code === 0 ? "clean" : "error",
|
|
22895
|
-
transcriptRef
|
|
23195
|
+
transcriptRef,
|
|
23196
|
+
...usage ? { usage } : {}
|
|
22896
23197
|
});
|
|
22897
23198
|
});
|
|
22898
23199
|
return {
|
|
@@ -22936,8 +23237,8 @@ var ACPClient = class {
|
|
|
22936
23237
|
seq = 0;
|
|
22937
23238
|
request(method, params) {
|
|
22938
23239
|
const id = this.nextId++;
|
|
22939
|
-
return new Promise((
|
|
22940
|
-
this.pending.set(id, { resolve
|
|
23240
|
+
return new Promise((resolve, reject) => {
|
|
23241
|
+
this.pending.set(id, { resolve, reject, method });
|
|
22941
23242
|
this.write(JSON.stringify({ jsonrpc: "2.0", id, method, params }) + "\n");
|
|
22942
23243
|
});
|
|
22943
23244
|
}
|
|
@@ -23124,16 +23425,16 @@ async function runACPSession(job, cfg) {
|
|
|
23124
23425
|
const slug = job.artifactId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 32);
|
|
23125
23426
|
const binTag = path3.basename(cfg.bin).replace(/[^a-zA-Z0-9]/g, "").slice(0, 12) || "acp";
|
|
23126
23427
|
const id = `${binTag}-${slug}-${(0, import_node_crypto4.randomUUID)().slice(0, 8)}`;
|
|
23127
|
-
const
|
|
23428
|
+
const dir = fs3.mkdtempSync(path3.join(cfg.workRoot ?? os3.tmpdir(), "oasis-session-"));
|
|
23128
23429
|
for (const [rel, content] of Object.entries(job.bundle.files)) {
|
|
23129
|
-
const file = path3.join(
|
|
23430
|
+
const file = path3.join(dir, rel);
|
|
23130
23431
|
fs3.mkdirSync(path3.dirname(file), { recursive: true });
|
|
23131
23432
|
fs3.writeFileSync(file, content);
|
|
23132
23433
|
}
|
|
23133
23434
|
const task = job.bundle.files["TASK.md"];
|
|
23134
23435
|
if (!task) throw new Error("bundle \u7F3A TASK.md\uFF08\u88C5\u914D\u5668\u5951\u7EA6\uFF09");
|
|
23135
23436
|
const child = (0, import_node_child_process5.spawn)(cfg.bin, [...cfg.args ?? [], ...cfg.extraArgs ?? []], {
|
|
23136
|
-
cwd:
|
|
23437
|
+
cwd: dir,
|
|
23137
23438
|
env: {
|
|
23138
23439
|
...scrubLeakyEnv(process.env),
|
|
23139
23440
|
...cfg.env,
|
|
@@ -23145,7 +23446,7 @@ async function runACPSession(job, cfg) {
|
|
|
23145
23446
|
},
|
|
23146
23447
|
stdio: ["pipe", "pipe", "pipe"]
|
|
23147
23448
|
});
|
|
23148
|
-
let transcriptRef = path3.join(
|
|
23449
|
+
let transcriptRef = path3.join(dir, "transcript.txt");
|
|
23149
23450
|
const transcriptOut = fs3.createWriteStream(transcriptRef);
|
|
23150
23451
|
const outputCbs = [];
|
|
23151
23452
|
const telemetryCbs = [];
|
|
@@ -23163,7 +23464,7 @@ async function runACPSession(job, cfg) {
|
|
|
23163
23464
|
transcriptOut.end(() => {
|
|
23164
23465
|
try {
|
|
23165
23466
|
fs3.renameSync(src, kept);
|
|
23166
|
-
fs3.rmSync(
|
|
23467
|
+
fs3.rmSync(dir, { recursive: true, force: true });
|
|
23167
23468
|
} catch {
|
|
23168
23469
|
}
|
|
23169
23470
|
});
|
|
@@ -23200,14 +23501,14 @@ async function runACPSession(job, cfg) {
|
|
|
23200
23501
|
() => streamingCurrentTurn
|
|
23201
23502
|
);
|
|
23202
23503
|
const rl = readline3.createInterface({ input: child.stdout });
|
|
23203
|
-
const readerDone = new Promise((
|
|
23504
|
+
const readerDone = new Promise((resolve) => {
|
|
23204
23505
|
rl.on("line", (line) => {
|
|
23205
23506
|
transcriptOut.write(line + "\n");
|
|
23206
23507
|
client.handleLine(line);
|
|
23207
23508
|
});
|
|
23208
23509
|
rl.on("close", () => {
|
|
23209
23510
|
client.closeAllPending(new Error("process exited"));
|
|
23210
|
-
|
|
23511
|
+
resolve();
|
|
23211
23512
|
});
|
|
23212
23513
|
});
|
|
23213
23514
|
child.on("error", () => {
|
|
@@ -23226,7 +23527,7 @@ async function runACPSession(job, cfg) {
|
|
|
23226
23527
|
clientCapabilities: {}
|
|
23227
23528
|
});
|
|
23228
23529
|
const sessionRes = await client.request("session/new", {
|
|
23229
|
-
cwd:
|
|
23530
|
+
cwd: dir,
|
|
23230
23531
|
mcpServers: [],
|
|
23231
23532
|
...cfg.model ? { model: cfg.model } : {}
|
|
23232
23533
|
});
|
|
@@ -23347,15 +23648,15 @@ var readline4 = __toESM(require("node:readline"), 1);
|
|
|
23347
23648
|
function materialize(job, workRoot) {
|
|
23348
23649
|
const slug = job.artifactId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 32);
|
|
23349
23650
|
const id = `${slug}-${(0, import_node_crypto5.randomUUID)().slice(0, 8)}`;
|
|
23350
|
-
const
|
|
23651
|
+
const dir = fs4.mkdtempSync(path4.join(workRoot ?? os4.tmpdir(), "oasis-session-"));
|
|
23351
23652
|
for (const [rel, content] of Object.entries(job.bundle.files)) {
|
|
23352
|
-
const file = path4.join(
|
|
23653
|
+
const file = path4.join(dir, rel);
|
|
23353
23654
|
fs4.mkdirSync(path4.dirname(file), { recursive: true });
|
|
23354
23655
|
fs4.writeFileSync(file, content);
|
|
23355
23656
|
}
|
|
23356
23657
|
const task = job.bundle.files["TASK.md"];
|
|
23357
23658
|
if (!task) throw new Error("bundle \u7F3A TASK.md\uFF08\u88C5\u914D\u5668\u5951\u7EA6\uFF09");
|
|
23358
|
-
return { id, dir
|
|
23659
|
+
return { id, dir, task };
|
|
23359
23660
|
}
|
|
23360
23661
|
function buildEnv(job, extra) {
|
|
23361
23662
|
return {
|
|
@@ -23367,7 +23668,7 @@ function buildEnv(job, extra) {
|
|
|
23367
23668
|
OASIS_TOKEN: job.actorToken
|
|
23368
23669
|
};
|
|
23369
23670
|
}
|
|
23370
|
-
function makeFinish(id, cfg, transcriptRefPtr, transcriptOut,
|
|
23671
|
+
function makeFinish(id, cfg, transcriptRefPtr, transcriptOut, dir, exitCbs) {
|
|
23371
23672
|
let exited;
|
|
23372
23673
|
const finish = (info) => {
|
|
23373
23674
|
if (exited) return;
|
|
@@ -23380,7 +23681,7 @@ function makeFinish(id, cfg, transcriptRefPtr, transcriptOut, dir2, exitCbs) {
|
|
|
23380
23681
|
transcriptOut.end(() => {
|
|
23381
23682
|
try {
|
|
23382
23683
|
fs4.renameSync(src, kept);
|
|
23383
|
-
fs4.rmSync(
|
|
23684
|
+
fs4.rmSync(dir, { recursive: true, force: true });
|
|
23384
23685
|
} catch {
|
|
23385
23686
|
}
|
|
23386
23687
|
});
|
|
@@ -23395,19 +23696,19 @@ function makeFinish(id, cfg, transcriptRefPtr, transcriptOut, dir2, exitCbs) {
|
|
|
23395
23696
|
return { finish, exited: () => exited };
|
|
23396
23697
|
}
|
|
23397
23698
|
function runStreamJson(job, cfg) {
|
|
23398
|
-
const { id, dir
|
|
23399
|
-
const args = [...cfg.buildArgs(job,
|
|
23699
|
+
const { id, dir, task: _task } = materialize(job, cfg.workRoot);
|
|
23700
|
+
const args = [...cfg.buildArgs(job, dir), ...cfg.extraArgs ?? []];
|
|
23400
23701
|
const child = (0, import_node_child_process6.spawn)(cfg.bin, args, {
|
|
23401
|
-
cwd:
|
|
23702
|
+
cwd: dir,
|
|
23402
23703
|
env: buildEnv(job, cfg.env),
|
|
23403
23704
|
stdio: ["ignore", "pipe", "pipe"]
|
|
23404
23705
|
});
|
|
23405
|
-
const transcriptRefPtr = { value: path4.join(
|
|
23706
|
+
const transcriptRefPtr = { value: path4.join(dir, "transcript.txt") };
|
|
23406
23707
|
const transcriptOut = fs4.createWriteStream(transcriptRefPtr.value);
|
|
23407
23708
|
const outputCbs = [];
|
|
23408
23709
|
const telemetryCbs = [];
|
|
23409
23710
|
const exitCbs = [];
|
|
23410
|
-
const { finish, exited } = makeFinish(id, cfg, transcriptRefPtr, transcriptOut,
|
|
23711
|
+
const { finish, exited } = makeFinish(id, cfg, transcriptRefPtr, transcriptOut, dir, exitCbs);
|
|
23411
23712
|
let killedByUs = false;
|
|
23412
23713
|
let seq = 0;
|
|
23413
23714
|
child.stderr.pipe(transcriptOut);
|
|
@@ -23453,18 +23754,18 @@ function runStreamJson(job, cfg) {
|
|
|
23453
23754
|
});
|
|
23454
23755
|
}
|
|
23455
23756
|
function runOneShotText(job, cfg) {
|
|
23456
|
-
const { id, dir
|
|
23457
|
-
const args = [...cfg.buildArgs(job,
|
|
23757
|
+
const { id, dir } = materialize(job, cfg.workRoot);
|
|
23758
|
+
const args = [...cfg.buildArgs(job, dir), ...cfg.extraArgs ?? []];
|
|
23458
23759
|
const child = (0, import_node_child_process6.spawn)(cfg.bin, args, {
|
|
23459
|
-
cwd:
|
|
23760
|
+
cwd: dir,
|
|
23460
23761
|
env: buildEnv(job, cfg.env),
|
|
23461
23762
|
stdio: ["ignore", "pipe", "pipe"]
|
|
23462
23763
|
});
|
|
23463
|
-
const transcriptRefPtr = { value: path4.join(
|
|
23764
|
+
const transcriptRefPtr = { value: path4.join(dir, "transcript.txt") };
|
|
23464
23765
|
const transcriptOut = fs4.createWriteStream(transcriptRefPtr.value);
|
|
23465
23766
|
const outputCbs = [];
|
|
23466
23767
|
const exitCbs = [];
|
|
23467
|
-
const { finish, exited } = makeFinish(id, cfg, transcriptRefPtr, transcriptOut,
|
|
23768
|
+
const { finish, exited } = makeFinish(id, cfg, transcriptRefPtr, transcriptOut, dir, exitCbs);
|
|
23468
23769
|
let killedByUs = false;
|
|
23469
23770
|
child.stdout.on("data", (chunk) => {
|
|
23470
23771
|
transcriptOut.write(chunk);
|
|
@@ -23551,14 +23852,14 @@ var CursorAdapter = class {
|
|
|
23551
23852
|
const opts = this.opts;
|
|
23552
23853
|
return runStreamJson(job, {
|
|
23553
23854
|
bin: opts.cursorBin ?? "cursor-agent",
|
|
23554
|
-
buildArgs(job2,
|
|
23855
|
+
buildArgs(job2, dir) {
|
|
23555
23856
|
const task = job2.bundle.files["TASK.md"] ?? "";
|
|
23556
23857
|
const prompt = job2.systemPrompt ? `${job2.systemPrompt}
|
|
23557
23858
|
|
|
23558
23859
|
---
|
|
23559
23860
|
|
|
23560
23861
|
${task}` : task;
|
|
23561
|
-
return ["-p", prompt, "--output-format", "stream-json", "--yolo", "--workspace",
|
|
23862
|
+
return ["-p", prompt, "--output-format", "stream-json", "--yolo", "--workspace", dir, ...opts.model ? ["--model", opts.model] : []];
|
|
23562
23863
|
},
|
|
23563
23864
|
createState: () => ({}),
|
|
23564
23865
|
normalizeStdout: (line) => normalizeCursor(line),
|
|
@@ -23693,14 +23994,14 @@ var OpenCodeAdapter = class {
|
|
|
23693
23994
|
const opts = this.opts;
|
|
23694
23995
|
return runStreamJson(job, {
|
|
23695
23996
|
bin: opts.openCodeBin ?? "opencode",
|
|
23696
|
-
buildArgs(_job,
|
|
23997
|
+
buildArgs(_job, dir) {
|
|
23697
23998
|
return [
|
|
23698
23999
|
"run",
|
|
23699
24000
|
"--format",
|
|
23700
24001
|
"json",
|
|
23701
24002
|
"--dangerously-skip-permissions",
|
|
23702
24003
|
"--dir",
|
|
23703
|
-
|
|
24004
|
+
dir,
|
|
23704
24005
|
...opts.model ? ["--model", opts.model] : []
|
|
23705
24006
|
];
|
|
23706
24007
|
},
|
|
@@ -24014,13 +24315,14 @@ function log2(tag, msg, extra) {
|
|
|
24014
24315
|
var RECONNECT_DELAY_MS = 3e3;
|
|
24015
24316
|
var PING_INTERVAL_MS = 2e4;
|
|
24016
24317
|
var DaemonWsClient = class {
|
|
24017
|
-
constructor(
|
|
24018
|
-
this.serverUrl =
|
|
24318
|
+
constructor(serverUrl2, daemonId, sessions, adapters = ["claude-code"], token2, runtimes = adapters.map((kind) => ({ kind })), nodeName2) {
|
|
24319
|
+
this.serverUrl = serverUrl2;
|
|
24019
24320
|
this.daemonId = daemonId;
|
|
24020
24321
|
this.sessions = sessions;
|
|
24021
24322
|
this.adapters = adapters;
|
|
24022
24323
|
this.token = token2;
|
|
24023
24324
|
this.runtimes = runtimes;
|
|
24325
|
+
this.nodeName = nodeName2;
|
|
24024
24326
|
}
|
|
24025
24327
|
ws = null;
|
|
24026
24328
|
pingTimer = null;
|
|
@@ -24107,7 +24409,7 @@ var DaemonWsClient = class {
|
|
|
24107
24409
|
if (this.ws?.readyState === import_websocket.default.OPEN) this.ws.send(JSON.stringify(msg));
|
|
24108
24410
|
}
|
|
24109
24411
|
buildMeta() {
|
|
24110
|
-
return { hostname: (0, import_node_os.hostname)(), adapters: this.adapters, runtimes: this.runtimes, nodeVersion: process.version };
|
|
24412
|
+
return { hostname: (0, import_node_os.hostname)(), adapters: this.adapters, runtimes: this.runtimes, nodeVersion: process.version, ...this.nodeName ? { nodeName: this.nodeName } : {} };
|
|
24111
24413
|
}
|
|
24112
24414
|
};
|
|
24113
24415
|
|
|
@@ -24209,17 +24511,17 @@ async function startNode(opts) {
|
|
|
24209
24511
|
claude
|
|
24210
24512
|
)
|
|
24211
24513
|
);
|
|
24212
|
-
const client = new DaemonWsClient(opts.serverUrl, opts.nodeId, sessions, adapters, opts.token, runtimes);
|
|
24514
|
+
const client = new DaemonWsClient(opts.serverUrl, opts.nodeId, sessions, adapters, opts.token, runtimes, opts.nodeName);
|
|
24213
24515
|
console.log(`[oasis node] ${opts.nodeId} \u2192 ${opts.serverUrl}`);
|
|
24214
24516
|
client.start();
|
|
24215
|
-
await new Promise((
|
|
24517
|
+
await new Promise((resolve) => {
|
|
24216
24518
|
process.on("SIGTERM", () => {
|
|
24217
24519
|
client.stop();
|
|
24218
|
-
|
|
24520
|
+
resolve();
|
|
24219
24521
|
});
|
|
24220
24522
|
process.on("SIGINT", () => {
|
|
24221
24523
|
client.stop();
|
|
24222
|
-
|
|
24524
|
+
resolve();
|
|
24223
24525
|
});
|
|
24224
24526
|
});
|
|
24225
24527
|
}
|
|
@@ -24234,14 +24536,72 @@ for (let i = 0; i < argv.length; i++) {
|
|
|
24234
24536
|
const a = argv[i];
|
|
24235
24537
|
if (a.startsWith("--")) flags.set(a.slice(2), argv[++i] ?? "");
|
|
24236
24538
|
}
|
|
24237
|
-
var
|
|
24238
|
-
var
|
|
24239
|
-
var
|
|
24539
|
+
var stateDir = path5.join(os5.homedir(), ".oasis");
|
|
24540
|
+
var stateFile = path5.join(stateDir, "node-state.json");
|
|
24541
|
+
var pidFile = path5.join(stateDir, "node.pid");
|
|
24542
|
+
function readState() {
|
|
24543
|
+
try {
|
|
24544
|
+
return JSON.parse(fs5.readFileSync(stateFile, "utf8"));
|
|
24545
|
+
} catch {
|
|
24546
|
+
return null;
|
|
24547
|
+
}
|
|
24548
|
+
}
|
|
24549
|
+
function saveState(s) {
|
|
24550
|
+
fs5.mkdirSync(stateDir, { recursive: true });
|
|
24551
|
+
fs5.writeFileSync(stateFile, JSON.stringify(s), { mode: 384 });
|
|
24552
|
+
}
|
|
24553
|
+
function checkPid() {
|
|
24554
|
+
try {
|
|
24555
|
+
const pid = parseInt(fs5.readFileSync(pidFile, "utf8").trim(), 10);
|
|
24556
|
+
if (!isNaN(pid)) {
|
|
24557
|
+
try {
|
|
24558
|
+
process.kill(pid, 0);
|
|
24559
|
+
console.error(`[oasis node] already running (PID ${pid})`);
|
|
24560
|
+
process.exit(0);
|
|
24561
|
+
} catch {
|
|
24562
|
+
}
|
|
24563
|
+
}
|
|
24564
|
+
} catch {
|
|
24565
|
+
}
|
|
24566
|
+
fs5.mkdirSync(stateDir, { recursive: true });
|
|
24567
|
+
fs5.writeFileSync(pidFile, String(process.pid));
|
|
24568
|
+
}
|
|
24569
|
+
function cleanup() {
|
|
24570
|
+
try {
|
|
24571
|
+
fs5.unlinkSync(pidFile);
|
|
24572
|
+
} catch {
|
|
24573
|
+
}
|
|
24574
|
+
}
|
|
24575
|
+
var serverUrl = flags.get("server-ws") ?? process.env["OASIS_SERVER_WS"] ?? "ws://127.0.0.1:7320/node-gateway";
|
|
24576
|
+
var token = flags.get("token") ?? process.env["OASIS_NODE_TOKEN"];
|
|
24577
|
+
if (!token) {
|
|
24578
|
+
const saved = readState();
|
|
24579
|
+
if (saved?.serverUrl === serverUrl) token = saved.token;
|
|
24580
|
+
}
|
|
24581
|
+
if (!token) {
|
|
24582
|
+
console.error("[oasis node] no token \u2014 generate one from the web UI and run with --token <token>");
|
|
24583
|
+
process.exit(1);
|
|
24584
|
+
}
|
|
24585
|
+
if (flags.has("token")) saveState({ serverUrl, token });
|
|
24586
|
+
checkPid();
|
|
24587
|
+
var nodeName = flags.get("name") ?? process.env["OASIS_NODE_NAME"];
|
|
24588
|
+
var nodeId = flags.get("id") ?? process.env["OASIS_NODE_ID"] ?? `node-${(0, import_node_crypto7.randomUUID)()}`;
|
|
24589
|
+
process.on("exit", cleanup);
|
|
24590
|
+
process.on("SIGTERM", () => {
|
|
24591
|
+
cleanup();
|
|
24592
|
+
process.exit(0);
|
|
24593
|
+
});
|
|
24594
|
+
process.on("SIGINT", () => {
|
|
24595
|
+
cleanup();
|
|
24596
|
+
process.exit(0);
|
|
24597
|
+
});
|
|
24240
24598
|
startNode({
|
|
24241
|
-
serverUrl
|
|
24242
|
-
nodeId
|
|
24243
|
-
|
|
24599
|
+
serverUrl,
|
|
24600
|
+
nodeId,
|
|
24601
|
+
token,
|
|
24602
|
+
...nodeName ? { nodeName } : {}
|
|
24244
24603
|
}).catch((err) => {
|
|
24245
24604
|
console.error(String(err instanceof Error ? err.message : err));
|
|
24605
|
+
cleanup();
|
|
24246
24606
|
process.exitCode = 1;
|
|
24247
24607
|
});
|
package/package.json
CHANGED