oasis_test 0.1.54 → 0.1.56
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 +276 -35
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4014,7 +4014,10 @@ function computeReviewJobs(model) {
|
|
|
4014
4014
|
}
|
|
4015
4015
|
return out;
|
|
4016
4016
|
}
|
|
4017
|
-
|
|
4017
|
+
function isSelfHealingExit(reason) {
|
|
4018
|
+
return reason !== void 0 && SELF_HEALING_EXITS.has(reason);
|
|
4019
|
+
}
|
|
4020
|
+
var import_node_crypto2, DEFAULT_PREDISPATCH_TIMEOUT_MS, SpawnAttemptStale, SEED_ROOT_SUCCESSFUL_PRODUCE_LIMIT, SELF_HEALING_EXITS, CANVAS_RUNTIME_KIND, NON_PRODUCE_FALLBACK_RUNTIME_KIND, Dispatcher;
|
|
4018
4021
|
var init_dispatcher = __esm({
|
|
4019
4022
|
"../core/src/dispatcher.ts"() {
|
|
4020
4023
|
"use strict";
|
|
@@ -4032,6 +4035,7 @@ var init_dispatcher = __esm({
|
|
|
4032
4035
|
}
|
|
4033
4036
|
};
|
|
4034
4037
|
SEED_ROOT_SUCCESSFUL_PRODUCE_LIMIT = 5;
|
|
4038
|
+
SELF_HEALING_EXITS = /* @__PURE__ */ new Set(["rate-limit"]);
|
|
4035
4039
|
CANVAS_RUNTIME_KIND = "open-design";
|
|
4036
4040
|
NON_PRODUCE_FALLBACK_RUNTIME_KIND = "claude-code";
|
|
4037
4041
|
Dispatcher = class {
|
|
@@ -4076,6 +4080,20 @@ var init_dispatcher = __esm({
|
|
|
4076
4080
|
fusedAt: st.fusedAt
|
|
4077
4081
|
}));
|
|
4078
4082
|
}
|
|
4083
|
+
/**
|
|
4084
|
+
* 长期饥饿的自愈类 job(rate-limit 持续退避超 starvationMs 仍未恢复):自愈类从不熔断、进不了 fusedJobs,
|
|
4085
|
+
* 若配额**长期**不足就成了静默卡死——本访问器供 SLA 扫描把它升级为**算力缺口**(提案"长期不足才=算力缺口")。
|
|
4086
|
+
*/
|
|
4087
|
+
starvingJobs(starvationMs, now) {
|
|
4088
|
+
const out = [];
|
|
4089
|
+
for (const [jobKey, st] of this.strikes) {
|
|
4090
|
+
if (st.fused || !isSelfHealingExit(st.lastReason) || !st.firstFailedAt) continue;
|
|
4091
|
+
const sinceMs = now - Date.parse(st.firstFailedAt);
|
|
4092
|
+
if (sinceMs <= starvationMs) continue;
|
|
4093
|
+
out.push({ jobKey, artifactId: st.artifactId, actor: st.actor, action: st.action, consecutiveFailures: st.count, lastReason: st.lastReason, sinceMs });
|
|
4094
|
+
}
|
|
4095
|
+
return out;
|
|
4096
|
+
}
|
|
4079
4097
|
/** v1 调度准入:当前被并发上限挡下、等待重评的 produce 会话数(/api/view dispatches 表面化)。 */
|
|
4080
4098
|
queuedCount() {
|
|
4081
4099
|
return this.queued.size;
|
|
@@ -4315,19 +4333,22 @@ var init_dispatcher = __esm({
|
|
|
4315
4333
|
}
|
|
4316
4334
|
recordSpawnFailure(jobKey, spec, reason) {
|
|
4317
4335
|
const seqAtVerdict = this.opts.kernel.model.lastSeq.get(spec.artifactId) ?? 0;
|
|
4318
|
-
const
|
|
4336
|
+
const prev = this.strikes.get(jobKey);
|
|
4337
|
+
const consecutive = (prev?.count ?? 0) + 1;
|
|
4319
4338
|
const max = this.opts.backoff?.maxConsecutiveFailures ?? 3;
|
|
4320
4339
|
const base = this.opts.backoff?.baseMs ?? 3e4;
|
|
4321
|
-
const
|
|
4340
|
+
const cap = this.opts.backoff?.maxBackoffMs ?? 30 * 6e4;
|
|
4341
|
+
const fused = consecutive >= max && !isSelfHealingExit(reason);
|
|
4322
4342
|
this.strikes.set(jobKey, {
|
|
4323
4343
|
artifactId: spec.artifactId,
|
|
4324
4344
|
actor: spec.actor,
|
|
4325
4345
|
action: spec.action,
|
|
4326
4346
|
count: consecutive,
|
|
4327
|
-
nextEligibleAt: Date.now() + base * 2 ** (consecutive - 1),
|
|
4347
|
+
nextEligibleAt: Date.now() + Math.min(base * 2 ** (consecutive - 1), cap),
|
|
4328
4348
|
fused,
|
|
4329
4349
|
...fused ? { fusedAt: (/* @__PURE__ */ new Date()).toISOString() } : {},
|
|
4330
4350
|
seqAtVerdict,
|
|
4351
|
+
firstFailedAt: prev?.firstFailedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
4331
4352
|
lastReason: reason
|
|
4332
4353
|
});
|
|
4333
4354
|
if (fused) {
|
|
@@ -4401,7 +4422,7 @@ var init_dispatcher = __esm({
|
|
|
4401
4422
|
}
|
|
4402
4423
|
}
|
|
4403
4424
|
const retry = this.strikes.get(jobKey);
|
|
4404
|
-
const lastFailure = retry && retry.count > 0 && retry.lastReason ? { reason: retry.lastReason } : void 0;
|
|
4425
|
+
const lastFailure = retry && retry.count > 0 && retry.lastReason && !isSelfHealingExit(retry.lastReason) ? { reason: retry.lastReason } : void 0;
|
|
4405
4426
|
const ws = kernel.model.artifacts.get(spec.artifactId)?.workspace;
|
|
4406
4427
|
const codeRepo = ws ? await this.opts.resolveCodeRepo?.(ws) ?? null : null;
|
|
4407
4428
|
this.assertSpawnAttemptCurrent(jobKey, attempt);
|
|
@@ -4588,19 +4609,23 @@ var init_dispatcher = __esm({
|
|
|
4588
4609
|
if (progressed) {
|
|
4589
4610
|
this.strikes.delete(jobKey);
|
|
4590
4611
|
} else {
|
|
4591
|
-
|
|
4612
|
+
const prev = this.strikes.get(jobKey);
|
|
4613
|
+
consecutive = (prev?.count ?? 0) + 1;
|
|
4592
4614
|
const max = this.opts.backoff?.maxConsecutiveFailures ?? 3;
|
|
4593
4615
|
const base = this.opts.backoff?.baseMs ?? 3e4;
|
|
4594
|
-
const
|
|
4616
|
+
const cap = this.opts.backoff?.maxBackoffMs ?? 30 * 6e4;
|
|
4617
|
+
const fused = consecutive >= max && !isSelfHealingExit(info.reason);
|
|
4595
4618
|
this.strikes.set(jobKey, {
|
|
4596
4619
|
artifactId: spec.artifactId,
|
|
4597
4620
|
actor: spec.actor,
|
|
4598
4621
|
action: spec.action,
|
|
4599
4622
|
count: consecutive,
|
|
4600
|
-
|
|
4623
|
+
// 退避封顶(maxBackoffMs,默认 30min):自愈类不熔断→consecutive 可无界增长,不封顶则间隔爆炸。
|
|
4624
|
+
nextEligibleAt: Date.now() + Math.min(base * 2 ** (consecutive - 1), cap),
|
|
4601
4625
|
fused,
|
|
4602
4626
|
...fused ? { fusedAt: (/* @__PURE__ */ new Date()).toISOString() } : {},
|
|
4603
4627
|
seqAtVerdict: seqAtExit,
|
|
4628
|
+
firstFailedAt: prev?.firstFailedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
4604
4629
|
...info.reason ? { lastReason: info.reason } : {}
|
|
4605
4630
|
});
|
|
4606
4631
|
if (fused) {
|
|
@@ -22454,6 +22479,82 @@ var init_node_state = __esm({
|
|
|
22454
22479
|
}
|
|
22455
22480
|
});
|
|
22456
22481
|
|
|
22482
|
+
// ../server/src/domains/collab/stall.ts
|
|
22483
|
+
function shortId(id) {
|
|
22484
|
+
return id.length > 22 ? `${id.slice(0, 14)}\u2026` : id;
|
|
22485
|
+
}
|
|
22486
|
+
function stallOf(model, id, runtime) {
|
|
22487
|
+
const a = model.artifacts.get(id);
|
|
22488
|
+
if (!a) return null;
|
|
22489
|
+
const ownerIsAgent = a.owner.startsWith("actor:agent:");
|
|
22490
|
+
if (runtime?.status === "running") {
|
|
22491
|
+
return { kind: "running", detail: `${runtime.action ?? "produce"} \u5728\u8DD1`, ...runtime.startedAt ? { since: runtime.startedAt } : {} };
|
|
22492
|
+
}
|
|
22493
|
+
if (isHeld(model, id)) {
|
|
22494
|
+
const h = holdOf(model, id);
|
|
22495
|
+
return { kind: "held", action: "resume", detail: `\u5DF2\u6682\u505C\u6D3E\u53D1${h?.reason ? `\uFF1A${h.reason}` : ""}\u2014\u2014\u5F85\u6062\u590D`, ...h?.at ? { since: h.at } : {} };
|
|
22496
|
+
}
|
|
22497
|
+
if (runtime && (runtime.status === "failed" || runtime.status === "fused" || runtime.status === "escalated")) {
|
|
22498
|
+
const label = runtime.status === "escalated" ? "\u5DF2\u5347\u7EA7\u3001\u5F85\u4EBA\u4ECB\u5165" : runtime.status === "fused" ? "\u8FDE\u8D25\u7194\u65AD\u3001\u505C\u6D3E\u5F85\u5904\u7406" : "\u8FD0\u884C\u51FA\u9519";
|
|
22499
|
+
return {
|
|
22500
|
+
kind: "failed",
|
|
22501
|
+
detail: `${label}${runtime.reason ? `\uFF08${runtime.reason}\uFF09` : ""}`,
|
|
22502
|
+
...runtime.reason ? { reason: runtime.reason } : {},
|
|
22503
|
+
...runtime.finishedAt ? { since: runtime.finishedAt } : {}
|
|
22504
|
+
};
|
|
22505
|
+
}
|
|
22506
|
+
const head = queueOf(model, id)[0];
|
|
22507
|
+
if (head) {
|
|
22508
|
+
const authors = declaredHumanAuthorsOf(model, head);
|
|
22509
|
+
if (authors.size > 0) {
|
|
22510
|
+
const approved = new Set((model.reviews.get(head.id) ?? []).filter((v2) => v2.verdict === "approve").map((v2) => v2.author));
|
|
22511
|
+
const missing = [...authors].filter((x2) => !approved.has(x2));
|
|
22512
|
+
if (missing.length > 0) {
|
|
22513
|
+
return {
|
|
22514
|
+
kind: "waiting_human",
|
|
22515
|
+
action: "accept",
|
|
22516
|
+
actorId: missing[0],
|
|
22517
|
+
ref: head.id,
|
|
22518
|
+
detail: `\u7B49 ${shortId(missing[0])} \u9A8C\u6536 ${shortId(head.id)} \u7248${missing.length > 1 ? `\uFF08\u5171 ${missing.length} \u4EBA\uFF09` : ""}`,
|
|
22519
|
+
since: head.createdAt
|
|
22520
|
+
};
|
|
22521
|
+
}
|
|
22522
|
+
}
|
|
22523
|
+
}
|
|
22524
|
+
const gate = pendingConcludeAttempt(model, id);
|
|
22525
|
+
if (gate?.gate) {
|
|
22526
|
+
const votedBy = new Set((model.reviews.get(gate.head) ?? []).map((v2) => v2.author));
|
|
22527
|
+
const humanEligible = gate.gate.eligible.filter((r) => r.startsWith("actor:human:") && !votedBy.has(r));
|
|
22528
|
+
if (humanEligible.length > 0) {
|
|
22529
|
+
return { kind: "waiting_human", action: "review", actorId: humanEligible[0], detail: `\u7B49 ${shortId(humanEligible[0])} \u5BA1\u6279\uFF08quorum=${gate.gate.quorum}\uFF09`, since: gate.at };
|
|
22530
|
+
}
|
|
22531
|
+
}
|
|
22532
|
+
if (hasOpenHumanChangeRequest(model, id) || headRejected(model, id)) {
|
|
22533
|
+
return ownerIsAgent ? { kind: "waiting_agent", action: "rework", actorId: a.owner, detail: "\u6709\u672A\u5904\u7406\u7684\u53D8\u66F4\u8BF7\u6C42\uFF0C\u5F85\u8FD4\u5DE5" } : { kind: "waiting_human", action: "rework", actorId: a.owner, detail: "\u6709\u672A\u5904\u7406\u7684\u53D8\u66F4\u8BF7\u6C42\uFF0C\u5F85\u4F60\u8FD4\u5DE5" };
|
|
22534
|
+
}
|
|
22535
|
+
const escs = unresolvedEscalationsOf(model, id);
|
|
22536
|
+
if (escs.length > 0) {
|
|
22537
|
+
return { kind: "waiting_human", action: "discuss", ref: id, detail: `\u5DF2\u4E0A\u62A5\u5F85\u4EBA\u4ECB\u5165\uFF1A${escs.at(-1).reason.slice(0, 60)}`, since: escs.at(-1).at };
|
|
22538
|
+
}
|
|
22539
|
+
const gaps = unresolvedGapsOf(model, id);
|
|
22540
|
+
if (gaps.length > 0) {
|
|
22541
|
+
return { kind: "waiting_human", action: "resolve_gap", detail: `\u5361\u5728\u7F3A\u53E3\u4E0A\u5F85\u4EBA\u8865\uFF1A${gaps[0].description.slice(0, 60)}` };
|
|
22542
|
+
}
|
|
22543
|
+
const b2 = blockedOf(model, id);
|
|
22544
|
+
if (b2.blocked) {
|
|
22545
|
+
const dep = a.inputs.find((e) => e.required && !isConcluded(model, e.to));
|
|
22546
|
+
if (dep) return { kind: "waiting_system", ref: dep.to, detail: `\u7B49\u4E0A\u6E38\u6536\u53E3\uFF1A${shortId(dep.to)}` };
|
|
22547
|
+
return { kind: "waiting_system", detail: `\u963B\u585E\u4E2D\uFF1A${b2.reasons[0] ?? "\u5F85\u524D\u7F6E\u5C31\u7EEA"}` };
|
|
22548
|
+
}
|
|
22549
|
+
return null;
|
|
22550
|
+
}
|
|
22551
|
+
var init_stall = __esm({
|
|
22552
|
+
"../server/src/domains/collab/stall.ts"() {
|
|
22553
|
+
"use strict";
|
|
22554
|
+
init_src2();
|
|
22555
|
+
}
|
|
22556
|
+
});
|
|
22557
|
+
|
|
22457
22558
|
// ../server/src/coordinator/identity.ts
|
|
22458
22559
|
function isCoordinatorAgentName(name) {
|
|
22459
22560
|
return COORDINATOR_NAME_RE.test(name);
|
|
@@ -23105,6 +23206,11 @@ function buildWorkorderDetail(model, workspaceId, resolveActor, resolveProject,
|
|
|
23105
23206
|
...e.upstreamCancelled ? { upstreamCancelled: true } : {}
|
|
23106
23207
|
})) : [];
|
|
23107
23208
|
const pv = reviewerPreview?.(a.id);
|
|
23209
|
+
const stallRaw = stallOf(model, a.id, runtime);
|
|
23210
|
+
const stall = stallRaw ? (() => {
|
|
23211
|
+
const { actorId, ...rest } = stallRaw;
|
|
23212
|
+
return { ...rest, ...actorId ? { actor: ref(actorId) } : {} };
|
|
23213
|
+
})() : void 0;
|
|
23108
23214
|
return {
|
|
23109
23215
|
id: a.id,
|
|
23110
23216
|
type: a.type,
|
|
@@ -23119,12 +23225,35 @@ function buildWorkorderDetail(model, workspaceId, resolveActor, resolveProject,
|
|
|
23119
23225
|
...runtime ? { runtime } : {},
|
|
23120
23226
|
...pv ? { reviewers: pv.reviewers.map((r) => ({ actor: ref(r.actor), source: r.source })), quorum: pv.quorum, typeName: pv.typeName } : {},
|
|
23121
23227
|
// 过期事实(提案 rework-cascade-rollout):无条件透出,前端 DAG 挂「上游已更新」徽标。
|
|
23122
|
-
...outdated.length > 0 ? { outdated } : {}
|
|
23228
|
+
...outdated.length > 0 ? { outdated } : {},
|
|
23229
|
+
// 停滞四态(看得清):为什么不动 + 谁欠什么 + 去处理锚;null 时不带。
|
|
23230
|
+
...stall ? { stall } : {}
|
|
23123
23231
|
};
|
|
23124
23232
|
});
|
|
23125
23233
|
const edges = arts.flatMap(
|
|
23126
23234
|
(a) => a.inputs.map((e) => ({ from: a.id, to: e.to, pinned: e.pinned, required: e.required }))
|
|
23127
23235
|
);
|
|
23236
|
+
const stallSummary = (() => {
|
|
23237
|
+
const counts = { running: 0, held: 0, failed: 0, waitingHuman: 0, waitingAgent: 0, waitingSystem: 0 };
|
|
23238
|
+
const sev = { failed: 5, held: 4, waiting_human: 3, waiting_agent: 2, waiting_system: 1, running: 0 };
|
|
23239
|
+
const stuck = [];
|
|
23240
|
+
for (const n of nodes) {
|
|
23241
|
+
const st = n.stall;
|
|
23242
|
+
if (!st) continue;
|
|
23243
|
+
if (st.kind === "running") counts.running++;
|
|
23244
|
+
else if (st.kind === "held") counts.held++;
|
|
23245
|
+
else if (st.kind === "failed") counts.failed++;
|
|
23246
|
+
else if (st.kind === "waiting_human") counts.waitingHuman++;
|
|
23247
|
+
else if (st.kind === "waiting_agent") counts.waitingAgent++;
|
|
23248
|
+
else counts.waitingSystem++;
|
|
23249
|
+
if (st.kind !== "running") {
|
|
23250
|
+
stuck.push({ id: n.id, label: n.label, kind: st.kind, ...st.action ? { action: st.action } : {}, ...st.ref ? { ref: st.ref } : {}, detail: st.detail, ...st.actor ? { actor: st.actor } : {} });
|
|
23251
|
+
}
|
|
23252
|
+
}
|
|
23253
|
+
stuck.sort((a, b2) => sev[b2.kind] - sev[a.kind]);
|
|
23254
|
+
const total = counts.running + counts.held + counts.failed + counts.waitingHuman + counts.waitingAgent + counts.waitingSystem;
|
|
23255
|
+
return total > 0 ? { counts, stuck } : void 0;
|
|
23256
|
+
})();
|
|
23128
23257
|
const activity = buildActivity(model, arts, ref);
|
|
23129
23258
|
const coordinatorActivity = buildCoordinatorActivity(arts, ops, ref);
|
|
23130
23259
|
const acceptance = buildAcceptance(model, arts);
|
|
@@ -23140,6 +23269,7 @@ function buildWorkorderDetail(model, workspaceId, resolveActor, resolveProject,
|
|
|
23140
23269
|
acceptance,
|
|
23141
23270
|
...managerActorId ? { managerActorId } : {},
|
|
23142
23271
|
...spec?.acceptanceCriteria ? { acceptanceCriteria: spec.acceptanceCriteria } : {},
|
|
23272
|
+
...stallSummary ? { stallSummary } : {},
|
|
23143
23273
|
planning
|
|
23144
23274
|
};
|
|
23145
23275
|
}
|
|
@@ -23435,6 +23565,7 @@ var init_workorder_detail = __esm({
|
|
|
23435
23565
|
"use strict";
|
|
23436
23566
|
init_src2();
|
|
23437
23567
|
init_node_state();
|
|
23568
|
+
init_stall();
|
|
23438
23569
|
init_workorders();
|
|
23439
23570
|
ACTIVITY_NOTE_MAX_CHARS = 500;
|
|
23440
23571
|
COORDINATOR_EDIT_KINDS = /* @__PURE__ */ new Set([
|
|
@@ -26795,7 +26926,7 @@ var init_memory_trace_store = __esm({
|
|
|
26795
26926
|
return { items: page.map((r) => this.decorate(structuredClone(r))), nextCursor };
|
|
26796
26927
|
}
|
|
26797
26928
|
async listUsageRuns(filter) {
|
|
26798
|
-
return [...this.runs.values()].filter((run) => run.usage
|
|
26929
|
+
return [...this.runs.values()].filter((run) => run.usage != null && run.startedAt >= filter.from && run.startedAt <= filter.to).map((run) => ({
|
|
26799
26930
|
actorId: run.actorId,
|
|
26800
26931
|
artifactId: run.artifactId,
|
|
26801
26932
|
startedAt: run.startedAt,
|
|
@@ -33839,6 +33970,10 @@ var init_daemon_hub = __esm({
|
|
|
33839
33970
|
connectedDaemons() {
|
|
33840
33971
|
return [...this.daemons.values()];
|
|
33841
33972
|
}
|
|
33973
|
+
/** 最近一帧(含 pong 心跳)的时刻(ms)——节点心跳时钟,供节点健康派生判"心跳新鲜"。缺 = 未连接/已清。 */
|
|
33974
|
+
lastSeenAt(daemonId) {
|
|
33975
|
+
return this.lastSeen.get(daemonId);
|
|
33976
|
+
}
|
|
33842
33977
|
/** Nodes that disconnected within the last GHOST_TTL_MS ms. */
|
|
33843
33978
|
recentlyDisconnected() {
|
|
33844
33979
|
const cutoff = Date.now() - _DaemonHub.GHOST_TTL_MS;
|
|
@@ -35528,6 +35663,7 @@ function actorsDomain(opts) {
|
|
|
35528
35663
|
status: "active",
|
|
35529
35664
|
...b2.email !== void 0 ? { email: b2.email } : {},
|
|
35530
35665
|
...b2.teamId !== void 0 ? { teamId: b2.teamId } : {},
|
|
35666
|
+
...b2.reportsTo ? { reportsTo: b2.reportsTo } : {},
|
|
35531
35667
|
...avatar !== void 0 ? { avatar } : {},
|
|
35532
35668
|
...positions !== void 0 ? { roles: positions } : {}
|
|
35533
35669
|
},
|
|
@@ -35542,10 +35678,12 @@ function actorsDomain(opts) {
|
|
|
35542
35678
|
const b2 = req.body ?? {};
|
|
35543
35679
|
const positions = positionsFromPayload(b2);
|
|
35544
35680
|
const avatar = avatarRefFromPayload(b2);
|
|
35545
|
-
const { positions: _positions, id: _id, kind: _kind, avatar: _avatar, ...patch } = b2;
|
|
35681
|
+
const { positions: _positions, id: _id, kind: _kind, avatar: _avatar, reportsTo: _reportsTo, ...patch } = b2;
|
|
35546
35682
|
const actor = await service.upsertActor({
|
|
35547
35683
|
...existing,
|
|
35548
35684
|
...patch,
|
|
35685
|
+
// 汇报人:显式给(含清空)——传空串/null 归一为 undefined(写库落 null);未传则保留原值
|
|
35686
|
+
...b2.reportsTo !== void 0 ? { reportsTo: b2.reportsTo || void 0 } : {},
|
|
35549
35687
|
...avatar !== void 0 ? { avatar } : {},
|
|
35550
35688
|
...positions !== void 0 ? { roles: positions } : {},
|
|
35551
35689
|
id: existing.id,
|
|
@@ -36380,12 +36518,12 @@ function parseAcceptanceCriteria(body) {
|
|
|
36380
36518
|
}
|
|
36381
36519
|
function parseReviewActor(req) {
|
|
36382
36520
|
const actor = String(req.auth.actor);
|
|
36383
|
-
const
|
|
36521
|
+
const shortId2 = actor.split(":").slice(2).join(":") || actor;
|
|
36384
36522
|
const b2 = req.body ?? {};
|
|
36385
36523
|
return {
|
|
36386
36524
|
actorKind: actor.includes(":agent:") ? "agent" : "human",
|
|
36387
36525
|
actorId: actor,
|
|
36388
|
-
...b2.actor_name !== void 0 || b2.actorName !== void 0 ? { actorName: b2.actor_name ?? b2.actorName } : { actorName:
|
|
36526
|
+
...b2.actor_name !== void 0 || b2.actorName !== void 0 ? { actorName: b2.actor_name ?? b2.actorName } : { actorName: shortId2 }
|
|
36389
36527
|
};
|
|
36390
36528
|
}
|
|
36391
36529
|
function parseAnnotationActor(req) {
|
|
@@ -41403,6 +41541,63 @@ var init_connect_script = __esm({
|
|
|
41403
41541
|
}
|
|
41404
41542
|
});
|
|
41405
41543
|
|
|
41544
|
+
// ../server/src/node-health.ts
|
|
41545
|
+
function deriveNodeHealth(input) {
|
|
41546
|
+
const staleMs = input.staleMs ?? 9e4;
|
|
41547
|
+
const maxFail = input.maxConsecutiveFailures ?? 3;
|
|
41548
|
+
const cf = input.snapshot?.consecutiveFailures ?? 0;
|
|
41549
|
+
const heartbeatFresh = input.lastHeartbeatMs !== void 0 && input.now - input.lastHeartbeatMs < staleMs;
|
|
41550
|
+
const healthy = input.online && heartbeatFresh && cf < maxFail;
|
|
41551
|
+
return {
|
|
41552
|
+
healthy,
|
|
41553
|
+
online: input.online,
|
|
41554
|
+
...input.lastHeartbeatMs !== void 0 ? { lastHeartbeatAt: new Date(input.lastHeartbeatMs).toISOString() } : {},
|
|
41555
|
+
activeRunCount: input.activeRunCount,
|
|
41556
|
+
consecutiveFailures: cf,
|
|
41557
|
+
...input.snapshot?.lastSuccessfulDispatchAt ? { lastSuccessfulDispatchAt: input.snapshot.lastSuccessfulDispatchAt } : {},
|
|
41558
|
+
...input.snapshot?.lastFailureAt ? { lastFailureAt: input.snapshot.lastFailureAt } : {},
|
|
41559
|
+
...input.snapshot?.lastFailureReason ? { lastFailureReason: input.snapshot.lastFailureReason } : {}
|
|
41560
|
+
};
|
|
41561
|
+
}
|
|
41562
|
+
var NodeHealthTracker;
|
|
41563
|
+
var init_node_health = __esm({
|
|
41564
|
+
"../server/src/node-health.ts"() {
|
|
41565
|
+
"use strict";
|
|
41566
|
+
NodeHealthTracker = class {
|
|
41567
|
+
byNode = /* @__PURE__ */ new Map();
|
|
41568
|
+
ensure(nodeId) {
|
|
41569
|
+
let s2 = this.byNode.get(nodeId);
|
|
41570
|
+
if (!s2) {
|
|
41571
|
+
s2 = { consecutiveFailures: 0 };
|
|
41572
|
+
this.byNode.set(nodeId, s2);
|
|
41573
|
+
}
|
|
41574
|
+
return s2;
|
|
41575
|
+
}
|
|
41576
|
+
/** 节点交付了一次会话(可达):清零连败、记成功时刻。 */
|
|
41577
|
+
recordReachable(nodeId, nowIso = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
41578
|
+
const s2 = this.ensure(nodeId);
|
|
41579
|
+
s2.consecutiveFailures = 0;
|
|
41580
|
+
s2.lastSuccessfulDispatchAt = nowIso;
|
|
41581
|
+
}
|
|
41582
|
+
/** 节点级失败(server-unreachable/失联/派发丢失):连败 +1、记失败时刻与归因。 */
|
|
41583
|
+
recordUnreachable(nodeId, reason, nowIso = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
41584
|
+
const s2 = this.ensure(nodeId);
|
|
41585
|
+
s2.consecutiveFailures += 1;
|
|
41586
|
+
s2.lastFailureAt = nowIso;
|
|
41587
|
+
if (reason !== void 0) s2.lastFailureReason = reason;
|
|
41588
|
+
}
|
|
41589
|
+
snapshot(nodeId) {
|
|
41590
|
+
const s2 = this.byNode.get(nodeId);
|
|
41591
|
+
return s2 ? { ...s2 } : void 0;
|
|
41592
|
+
}
|
|
41593
|
+
/** 节点被删除/换机时清账(可选调用)。 */
|
|
41594
|
+
forget(nodeId) {
|
|
41595
|
+
this.byNode.delete(nodeId);
|
|
41596
|
+
}
|
|
41597
|
+
};
|
|
41598
|
+
}
|
|
41599
|
+
});
|
|
41600
|
+
|
|
41406
41601
|
// ../server/src/domains/nodes/routes.ts
|
|
41407
41602
|
function nodesDomain(deps) {
|
|
41408
41603
|
let hubWired = false;
|
|
@@ -41486,6 +41681,8 @@ function nodesDomain(deps) {
|
|
|
41486
41681
|
}
|
|
41487
41682
|
const daemonVersionById = new Map((hub?.connectedDaemons() ?? []).map((d) => [d.daemonId, d.meta.daemonVersion]));
|
|
41488
41683
|
const connectionById = new Map((hub?.recentConnectionChanges() ?? []).map((d) => [d.daemonId, d]));
|
|
41684
|
+
const onlineIds = new Set((hub?.connectedDaemons() ?? []).map((d) => d.daemonId));
|
|
41685
|
+
const healthNow = Date.now();
|
|
41489
41686
|
const nodes = await deps.nodeStore.listNodes();
|
|
41490
41687
|
const items = await Promise.all(nodes.map(async (n) => {
|
|
41491
41688
|
const rts = await deps.nodeStore.listRuntimes(n.id);
|
|
@@ -41514,6 +41711,15 @@ function nodesDomain(deps) {
|
|
|
41514
41711
|
...connection.lastDisconnectedAt ? { lastDisconnectedAt: new Date(connection.lastDisconnectedAt).toISOString() } : {},
|
|
41515
41712
|
...connection.lastReconnectedAt ? { lastReconnectedAt: new Date(connection.lastReconnectedAt).toISOString() } : {}
|
|
41516
41713
|
}
|
|
41714
|
+
} : {},
|
|
41715
|
+
...deps.nodeHealth ? {
|
|
41716
|
+
health: deriveNodeHealth({
|
|
41717
|
+
online: onlineIds.has(n.id),
|
|
41718
|
+
...hub?.lastSeenAt(n.id) !== void 0 ? { lastHeartbeatMs: hub.lastSeenAt(n.id) } : {},
|
|
41719
|
+
activeRunCount: deps.activeRunCountOf?.(n.id) ?? 0,
|
|
41720
|
+
...deps.nodeHealth.snapshot(n.id) ? { snapshot: deps.nodeHealth.snapshot(n.id) } : {},
|
|
41721
|
+
now: healthNow
|
|
41722
|
+
})
|
|
41517
41723
|
} : {}
|
|
41518
41724
|
};
|
|
41519
41725
|
}));
|
|
@@ -41712,6 +41918,7 @@ var init_routes4 = __esm({
|
|
|
41712
41918
|
import_node_path2 = require("node:path");
|
|
41713
41919
|
init_src4();
|
|
41714
41920
|
init_connect_script();
|
|
41921
|
+
init_node_health();
|
|
41715
41922
|
}
|
|
41716
41923
|
});
|
|
41717
41924
|
|
|
@@ -43123,7 +43330,7 @@ var init_service4 = __esm({
|
|
|
43123
43330
|
/** 组织汇总专用瘦读:只取归属、时间和 usage,并统一补齐展示成本。 */
|
|
43124
43331
|
async listUsageRuns(filter) {
|
|
43125
43332
|
const rows = await this.store.listUsageRuns(filter);
|
|
43126
|
-
return rows.map((row) => ({
|
|
43333
|
+
return rows.filter((row) => row.usage != null).map((row) => ({
|
|
43127
43334
|
...row,
|
|
43128
43335
|
usage: {
|
|
43129
43336
|
...row.usage,
|
|
@@ -45205,6 +45412,7 @@ var init_daemon_adapter = __esm({
|
|
|
45205
45412
|
this.nodeLostGraceMs = opts.nodeLostGraceMs ?? graceFromEnv(12e4);
|
|
45206
45413
|
this.ackTimeoutMs = opts.ackTimeoutMs ?? ackMsFromEnv(15e3);
|
|
45207
45414
|
this.log = opts.log ?? ((m2) => console.warn(m2));
|
|
45415
|
+
this.health = opts.health;
|
|
45208
45416
|
hub.addMessageListener((_daemonId, msg) => this.onDaemonMessage(msg));
|
|
45209
45417
|
hub.addDisconnectListener((daemonId) => this.onNodeDown(daemonId));
|
|
45210
45418
|
hub.addConnectListener((daemon) => this.onNodeUp(daemon.daemonId));
|
|
@@ -45213,6 +45421,7 @@ var init_daemon_adapter = __esm({
|
|
|
45213
45421
|
nodeLostGraceMs;
|
|
45214
45422
|
ackTimeoutMs;
|
|
45215
45423
|
log;
|
|
45424
|
+
health;
|
|
45216
45425
|
/** 断联节点 → 收割定时器。重连取消;到期收割。 */
|
|
45217
45426
|
reapTimers = /* @__PURE__ */ new Map();
|
|
45218
45427
|
/** 统一结算一次会话退出:清 ack 定时器、置 exited、触发回调、从 pending 摘除。幂等(已退出即跳过)。 */
|
|
@@ -45224,9 +45433,17 @@ var init_daemon_adapter = __esm({
|
|
|
45224
45433
|
entry.ackTimer = void 0;
|
|
45225
45434
|
}
|
|
45226
45435
|
entry.exited = info;
|
|
45436
|
+
if (info.reason === "server-unreachable") this.health?.recordUnreachable(entry.nodeId, info.reason);
|
|
45437
|
+
else this.health?.recordReachable(entry.nodeId);
|
|
45227
45438
|
for (const cb of entry.exitCbs.splice(0)) cb(info);
|
|
45228
45439
|
this.pending.delete(dispatchId);
|
|
45229
45440
|
}
|
|
45441
|
+
/** 该节点当前在途(未退出)会话数——节点健康的 activeRunCount。 */
|
|
45442
|
+
activeRunCount(nodeId) {
|
|
45443
|
+
let n = 0;
|
|
45444
|
+
for (const e of this.pending.values()) if (e.nodeId === nodeId && !e.exited) n++;
|
|
45445
|
+
return n;
|
|
45446
|
+
}
|
|
45230
45447
|
/** 收到任何回帧(started/event/output/exited)即视为派发已达,取消 ack 超时。 */
|
|
45231
45448
|
cancelAck(dispatchId) {
|
|
45232
45449
|
const entry = this.pending.get(dispatchId);
|
|
@@ -45269,6 +45486,8 @@ var init_daemon_adapter = __esm({
|
|
|
45269
45486
|
onDaemonMessage(msg) {
|
|
45270
45487
|
if (msg.type === "session_started") {
|
|
45271
45488
|
this.cancelAck(msg.dispatchId);
|
|
45489
|
+
const entry = this.pending.get(msg.dispatchId);
|
|
45490
|
+
if (entry) this.health?.recordReachable(entry.nodeId);
|
|
45272
45491
|
} else if (msg.type === "session_exited") {
|
|
45273
45492
|
const info = msg.info.reason || msg.info.code !== null ? msg.info : { ...msg.info, reason: "error" };
|
|
45274
45493
|
this.settle(msg.dispatchId, info);
|
|
@@ -45769,6 +45988,12 @@ var init_ci_gate = __esm({
|
|
|
45769
45988
|
const statuses = [];
|
|
45770
45989
|
const repoViews = [];
|
|
45771
45990
|
for (const unit of units) {
|
|
45991
|
+
if (await ci.isMerged({ repo: unit.repo, sha: unit.sha })) {
|
|
45992
|
+
const status2 = { state: "success", summary: `${unit.repo.id}@${unit.sha.slice(0, 8)}: \u5185\u5BB9\u5DF2\u5728 ${unit.repo.develop}\uFF08\u4E0A\u8F6E\u5DF2\u5408\uFF09\uFF0CCI \u514D\u68C0` };
|
|
45993
|
+
statuses.push({ unit, status: status2 });
|
|
45994
|
+
repoViews.push({ repoId: unit.repo.id, sha: unit.sha.slice(0, 8), state: "success", summary: status2.summary });
|
|
45995
|
+
continue;
|
|
45996
|
+
}
|
|
45772
45997
|
const pr = await ci.ensurePr(
|
|
45773
45998
|
{ repo: unit.repo, branch: unit.branch, sha: unit.sha },
|
|
45774
45999
|
{ title: `[oasis-ci] ${artifactId} \u2192 ${unit.repo.develop}`, body: `CI gate for artifact ${artifactId} @ ${unit.sha}` }
|
|
@@ -46558,6 +46783,7 @@ var init_src5 = __esm({
|
|
|
46558
46783
|
init_playbooks2();
|
|
46559
46784
|
init_scheduler();
|
|
46560
46785
|
init_daemon_adapter();
|
|
46786
|
+
init_node_health();
|
|
46561
46787
|
init_side_map();
|
|
46562
46788
|
init_engine();
|
|
46563
46789
|
init_fs_state();
|
|
@@ -52908,6 +53134,7 @@ var PostgresRegistryStore = class _PostgresRegistryStore {
|
|
|
52908
53134
|
name text NOT NULL,
|
|
52909
53135
|
email text,
|
|
52910
53136
|
team_id text,
|
|
53137
|
+
reports_to text, -- \u6C47\u62A5\u4EBA\uFF08\u8D1F\u8D23\u4EBA\uFF09\uFF1A\u53E6\u4E00\u4E2A actor id\uFF0C\u53EF\u7A7A
|
|
52911
53138
|
status text NOT NULL, -- active | disabled\uFF08\u5220\u9664\u5373\u505C\u7528\uFF09
|
|
52912
53139
|
roles jsonb NOT NULL DEFAULT '[]'::jsonb, -- spec \xA76.2 \u540D\u518C\u89D2\u8272\uFF08\u4EFB\u52A1 2.0\uFF09
|
|
52913
53140
|
avatar text, -- "blob:<hash>"\uFF0C\u7A7A=\u9ED8\u8BA4\u751F\u6210
|
|
@@ -52933,6 +53160,7 @@ var PostgresRegistryStore = class _PostgresRegistryStore {
|
|
|
52933
53160
|
await pool.query(`ALTER TABLE "${s2}".actor_configs ADD COLUMN IF NOT EXISTS max_concurrent integer NOT NULL DEFAULT 4`);
|
|
52934
53161
|
await pool.query(`ALTER TABLE "${s2}".actor_configs ADD COLUMN IF NOT EXISTS reviewer_ids jsonb NOT NULL DEFAULT '[]'::jsonb`);
|
|
52935
53162
|
await pool.query(`ALTER TABLE "${s2}".actor_configs ADD COLUMN IF NOT EXISTS batched_continuation boolean NOT NULL DEFAULT false`);
|
|
53163
|
+
await pool.query(`ALTER TABLE "${s2}".actors ADD COLUMN IF NOT EXISTS reports_to text`);
|
|
52936
53164
|
await pool.query(`
|
|
52937
53165
|
CREATE TABLE IF NOT EXISTS "${s2}".teams (
|
|
52938
53166
|
id text PRIMARY KEY,
|
|
@@ -53036,10 +53264,10 @@ var PostgresRegistryStore = class _PostgresRegistryStore {
|
|
|
53036
53264
|
/* ---------- 员工 ---------- */
|
|
53037
53265
|
async upsertActor(a) {
|
|
53038
53266
|
await this.pool.query(
|
|
53039
|
-
`INSERT INTO ${this.s}.actors (id, kind, name, email, team_id, status, roles, avatar, created_at)
|
|
53040
|
-
VALUES ($1,$2,$3,$4,$5,$6,$7::jsonb,$8,$9)
|
|
53041
|
-
ON CONFLICT (id) DO UPDATE SET kind=$2, name=$3, email=$4, team_id=$5, status=$6, roles=$7::jsonb, avatar=$8`,
|
|
53042
|
-
[a.id, a.kind, a.name, a.email ?? null, a.teamId ?? null, a.status, JSON.stringify(a.roles), a.avatar ?? null, a.createdAt]
|
|
53267
|
+
`INSERT INTO ${this.s}.actors (id, kind, name, email, team_id, status, roles, avatar, created_at, reports_to)
|
|
53268
|
+
VALUES ($1,$2,$3,$4,$5,$6,$7::jsonb,$8,$9,$10)
|
|
53269
|
+
ON CONFLICT (id) DO UPDATE SET kind=$2, name=$3, email=$4, team_id=$5, status=$6, roles=$7::jsonb, avatar=$8, reports_to=$10`,
|
|
53270
|
+
[a.id, a.kind, a.name, a.email ?? null, a.teamId ?? null, a.status, JSON.stringify(a.roles), a.avatar ?? null, a.createdAt, a.reportsTo ?? null]
|
|
53043
53271
|
);
|
|
53044
53272
|
}
|
|
53045
53273
|
async getActor(id) {
|
|
@@ -53398,6 +53626,7 @@ var rowToActor = (row) => ({
|
|
|
53398
53626
|
name: row.name,
|
|
53399
53627
|
...row.email !== null ? { email: row.email } : {},
|
|
53400
53628
|
...row.team_id !== null ? { teamId: row.team_id } : {},
|
|
53629
|
+
...row.reports_to !== null && row.reports_to !== void 0 ? { reportsTo: row.reports_to } : {},
|
|
53401
53630
|
status: row.status,
|
|
53402
53631
|
roles: row.roles ?? [],
|
|
53403
53632
|
...row.avatar !== null && row.avatar !== void 0 ? { avatar: row.avatar } : {},
|
|
@@ -54884,7 +55113,7 @@ var PostgresTraceStore = class _PostgresTraceStore {
|
|
|
54884
55113
|
const r = await this.pool.query(
|
|
54885
55114
|
`SELECT actor_id, artifact_id, started_at, effective_model, usage
|
|
54886
55115
|
FROM ${this.s}.agent_runs
|
|
54887
|
-
WHERE usage
|
|
55116
|
+
WHERE jsonb_typeof(usage) = 'object' AND started_at >= $1 AND started_at <= $2
|
|
54888
55117
|
ORDER BY started_at`,
|
|
54889
55118
|
[filter.from, filter.to]
|
|
54890
55119
|
);
|
|
@@ -56668,6 +56897,8 @@ async function startServe(opts) {
|
|
|
56668
56897
|
let hub = null;
|
|
56669
56898
|
let chatRemoteAdapter = null;
|
|
56670
56899
|
let dispatchRemoteAdapter = null;
|
|
56900
|
+
const nodeHealth = new NodeHealthTracker();
|
|
56901
|
+
const activeRunCountOf = (nodeId) => (chatRemoteAdapter?.activeRunCount(nodeId) ?? 0) + (dispatchRemoteAdapter?.activeRunCount(nodeId) ?? 0);
|
|
56671
56902
|
let localUrl = "";
|
|
56672
56903
|
const chatLiveSessions = /* @__PURE__ */ new Map();
|
|
56673
56904
|
const remoteApiUrl = opts.publicUrl ? normalizeHttpBaseUrl(opts.publicUrl) : apiUrlFromGatewayUrl(opts.gatewayUrl);
|
|
@@ -56809,7 +57040,9 @@ async function startServe(opts) {
|
|
|
56809
57040
|
nodeStore,
|
|
56810
57041
|
registry: registryStore,
|
|
56811
57042
|
gatewayUrl: opts.gatewayUrl ?? `ws://127.0.0.1:${opts.port ?? 7320}/node-gateway`,
|
|
56812
|
-
repoRemote: opts.nodeRepoRemote ?? "git@github.com:open-friday/oasis-core.git"
|
|
57043
|
+
repoRemote: opts.nodeRepoRemote ?? "git@github.com:open-friday/oasis-core.git",
|
|
57044
|
+
nodeHealth,
|
|
57045
|
+
activeRunCountOf
|
|
56813
57046
|
}),
|
|
56814
57047
|
collabDomain({
|
|
56815
57048
|
kernel,
|
|
@@ -57178,7 +57411,7 @@ ${detail}` : genericLine));
|
|
|
57178
57411
|
}
|
|
57179
57412
|
});
|
|
57180
57413
|
hub = new DaemonHub(server.httpServer, "/node-gateway", (t) => nodeTokens.resolve(t));
|
|
57181
|
-
const hubAdapterOpts = { log: (m2) => console.warn(m2) };
|
|
57414
|
+
const hubAdapterOpts = { log: (m2) => console.warn(m2), health: nodeHealth };
|
|
57182
57415
|
chatRemoteAdapter = new DaemonHubAdapter(hub, hubAdapterOpts);
|
|
57183
57416
|
dispatchRemoteAdapter = new DaemonHubAdapter(hub, hubAdapterOpts);
|
|
57184
57417
|
const port = new URL(server.baseUrl).port;
|
|
@@ -57413,6 +57646,7 @@ ${detail}` : genericLine));
|
|
|
57413
57646
|
}
|
|
57414
57647
|
const humanMs = opts.sla?.humanMs ?? 24 * 36e5;
|
|
57415
57648
|
const agentMs = opts.sla?.agentMs ?? 10 * 6e4;
|
|
57649
|
+
const quotaStarvationMs = opts.sla?.quotaStarvationMs ?? 6 * 36e5;
|
|
57416
57650
|
const initiatorCache = /* @__PURE__ */ new Map();
|
|
57417
57651
|
const initiatorOf = async (workspace) => {
|
|
57418
57652
|
if (initiatorCache.has(workspace)) return initiatorCache.get(workspace);
|
|
@@ -57485,22 +57719,29 @@ ${detail}` : genericLine));
|
|
|
57485
57719
|
await escalate(a.id, a.owner, `human \u6301\u6709 ${Math.round(humanMs / 6e4)} \u5206\u949F\u672A\u52A8\u5DE5`);
|
|
57486
57720
|
}
|
|
57487
57721
|
}
|
|
57488
|
-
|
|
57489
|
-
if (
|
|
57490
|
-
|
|
57491
|
-
|
|
57492
|
-
if (now - Date.parse(f2.fusedAt) <= agentMs) continue;
|
|
57493
|
-
if (unresolvedEscalationsOf(kernel.model, f2.artifactId).length > 0) continue;
|
|
57494
|
-
if (isHeld(kernel.model, f2.artifactId)) continue;
|
|
57495
|
-
const reason = `agent \u8FDE\u8D25\u7194\u65AD\u540E ${Math.round(agentMs / 6e4)} \u5206\u949F\u65E0\u4EBA\u5904\u7406\uFF08\u8FDE\u8D25 ${f2.consecutiveFailures} \u6B21\uFF09`;
|
|
57722
|
+
const escalateHold = async (artifactId, reason, kind) => {
|
|
57723
|
+
if (unresolvedEscalationsOf(kernel.model, artifactId).length > 0) return;
|
|
57724
|
+
if (isHeld(kernel.model, artifactId)) return;
|
|
57725
|
+
const owner = kernel.model.artifacts.get(artifactId)?.owner ?? "";
|
|
57496
57726
|
try {
|
|
57497
|
-
await kernel.escalate({ artifactId
|
|
57498
|
-
await kernel.hold({ artifactId
|
|
57499
|
-
journal({ kind: "escalated", at: (/* @__PURE__ */ new Date()).toISOString(), artifactId
|
|
57500
|
-
console.log(`[sla] ${
|
|
57727
|
+
await kernel.escalate({ artifactId, actor: SYSTEM_ACTOR, reason });
|
|
57728
|
+
await kernel.hold({ artifactId, actor: SYSTEM_ACTOR, source: "sla", reason });
|
|
57729
|
+
journal({ kind: "escalated", at: (/* @__PURE__ */ new Date()).toISOString(), artifactId, from: owner, to: owner, reason });
|
|
57730
|
+
console.log(`[sla] ${artifactId} ${kind}\uFF1A\u843D escalate + hold\uFF08owner \u4FDD\u6301 ${owner}\uFF0C\u4E0D\u593A\uFF09`);
|
|
57501
57731
|
} catch (err) {
|
|
57502
|
-
console.error(`[sla] \
|
|
57732
|
+
console.error(`[sla] ${kind}\u5931\u8D25 ${artifactId}: ${String(err)}`);
|
|
57503
57733
|
}
|
|
57734
|
+
};
|
|
57735
|
+
for (const f2 of allDispatchers().flatMap((d) => d.fusedJobs())) {
|
|
57736
|
+
if (f2.action !== "produce") continue;
|
|
57737
|
+
if (!kernel.model.artifacts.get(f2.artifactId)) continue;
|
|
57738
|
+
if (now - Date.parse(f2.fusedAt) <= agentMs) continue;
|
|
57739
|
+
await escalateHold(f2.artifactId, `agent \u8FDE\u8D25\u7194\u65AD\u540E ${Math.round(agentMs / 6e4)} \u5206\u949F\u65E0\u4EBA\u5904\u7406\uFF08\u8FDE\u8D25 ${f2.consecutiveFailures} \u6B21\uFF09`, "\u7194\u65AD\u5347\u7EA7");
|
|
57740
|
+
}
|
|
57741
|
+
for (const s2 of allDispatchers().flatMap((d) => d.starvingJobs(quotaStarvationMs, now))) {
|
|
57742
|
+
if (s2.action !== "produce") continue;
|
|
57743
|
+
if (!kernel.model.artifacts.get(s2.artifactId)) continue;
|
|
57744
|
+
await escalateHold(s2.artifactId, `\u914D\u989D\u957F\u671F\u4E0D\u8DB3\uFF1A\u7ED1\u5B9A\u8D26\u53F7\u5DF2\u9650\u6D41 ${Math.round(s2.sinceMs / 36e5)} \u5C0F\u65F6\u4ECD\u672A\u6062\u590D\uFF08\u7591\u4F3C\u7B97\u529B\u7F3A\u53E3\uFF0C\u9700\u52A0\u989D\u5EA6/\u6362\u7ED1\u5B9A/\u51CF\u5E76\u53D1\uFF09`, "\u914D\u989D\u9965\u997F\u5347\u7EA7");
|
|
57504
57745
|
}
|
|
57505
57746
|
})().catch((err) => console.error(`[sla] \u626B\u63CF\u5931\u8D25: ${String(err)}`));
|
|
57506
57747
|
}, opts.sla?.scanMs ?? 6e4);
|
|
@@ -59756,7 +59997,7 @@ ${res.warning}`);
|
|
|
59756
59997
|
}
|
|
59757
59998
|
|
|
59758
59999
|
// src/index.ts
|
|
59759
|
-
var PKG_VERSION = true ? "0.1.
|
|
60000
|
+
var PKG_VERSION = true ? "0.1.56" : "dev";
|
|
59760
60001
|
var OASIS_DIR = path18.join(os9.homedir(), ".oasis");
|
|
59761
60002
|
var CONFIG_FILE = path18.join(OASIS_DIR, "node-config.json");
|
|
59762
60003
|
var PID_FILE = path18.join(OASIS_DIR, "node.pid");
|