oasis_test 0.1.54 → 0.1.57
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 +1008 -319
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -911,8 +911,8 @@ function deriveArtifactId(type, workspace, title, usedIds) {
|
|
|
911
911
|
usedIds.add(id);
|
|
912
912
|
return id;
|
|
913
913
|
}
|
|
914
|
-
function resolveNodeRef(
|
|
915
|
-
const r =
|
|
914
|
+
function resolveNodeRef(ref2, candidates) {
|
|
915
|
+
const r = ref2.trim();
|
|
916
916
|
if (r.startsWith("artifact:")) {
|
|
917
917
|
const hit = candidates.find((n) => n.id === r);
|
|
918
918
|
return hit ? { ok: true, id: hit.id } : { ok: false, reason: "not_found" };
|
|
@@ -1068,16 +1068,16 @@ var init_content_type_handler = __esm({
|
|
|
1068
1068
|
const short = (s2) => s2.slice(0, 12);
|
|
1069
1069
|
const versionLine = (() => {
|
|
1070
1070
|
if (!(ctx.hasHead && ctx.headExternalRef)) return [];
|
|
1071
|
-
const
|
|
1072
|
-
if (
|
|
1071
|
+
const ref2 = ctx.headExternalRef;
|
|
1072
|
+
if (ref2.trim().startsWith("{")) {
|
|
1073
1073
|
try {
|
|
1074
|
-
const m2 = JSON.parse(
|
|
1074
|
+
const m2 = JSON.parse(ref2);
|
|
1075
1075
|
const parts = Object.entries(m2).map(([id, sha2]) => `\`${id}\` @ \`${short(sha2)}\``);
|
|
1076
1076
|
return [`> **\u5F53\u524D\u7248\u672C**\uFF08\u4F60\u4E0A\u4E00\u7248\uFF0C\u5DF2\u5E76\u5165\u5404\u4ED3\u4E3B\u5E72\uFF09\uFF1A${parts.join("\uFF0C")}\u2014\u2014clone \u4E3B\u5E72\u5373\u5728\u5B83\u4E4B\u4E0A\u6539\uFF0C\u522B\u4ECE\u5934\u5199\u3002`];
|
|
1077
1077
|
} catch {
|
|
1078
1078
|
}
|
|
1079
1079
|
}
|
|
1080
|
-
return [`> **\u5F53\u524D\u7248\u672C**\uFF08\u4F60\u4E0A\u4E00\u7248\uFF0C\u5DF2\u5E76\u5165\u4E3B\u5E72\uFF09\uFF1A\`${repos[0]?.id ?? "<\u4E3B\u4ED3>"}\` @ \`${short(
|
|
1080
|
+
return [`> **\u5F53\u524D\u7248\u672C**\uFF08\u4F60\u4E0A\u4E00\u7248\uFF0C\u5DF2\u5E76\u5165\u4E3B\u5E72\uFF09\uFF1A\`${repos[0]?.id ?? "<\u4E3B\u4ED3>"}\` @ \`${short(ref2)}\`\u2014\u2014clone \u4E3B\u5E72\u5373\u5728\u5B83\u4E4B\u4E0A\u6539\uFF0C\u522B\u4ECE\u5934\u5199\u3002`];
|
|
1081
1081
|
})();
|
|
1082
1082
|
return [
|
|
1083
1083
|
`\u4F60\u4EA7\u51FA\u7684\u662F\u9879\u76EE **${ctx.projectName ?? "?"}** \u7684\u4EE3\u7801\u2014\u2014**\u5185\u5BB9\u76F4\u63A5\u6D3B\u5728 git \u4ED3\u5E93\u91CC**\uFF0C\u4F60\u50CF\u5F00\u53D1\u8005\u4E00\u6837\u5728 git \u91CC\u5E72\uFF0C\u4EA7\u7269\u4E0D\u8FDB Oasis \u6863\u6848\u67DC\u3002`,
|
|
@@ -1405,6 +1405,68 @@ var init_collab_view = __esm({
|
|
|
1405
1405
|
}
|
|
1406
1406
|
});
|
|
1407
1407
|
|
|
1408
|
+
// ../contract/src/workorder-quality.ts
|
|
1409
|
+
function record(value) {
|
|
1410
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
1411
|
+
}
|
|
1412
|
+
function requiredString(value, field) {
|
|
1413
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
1414
|
+
throw new Error(`invalid qa_quality_metrics payload: ${field} must be a non-empty string`);
|
|
1415
|
+
}
|
|
1416
|
+
return value.trim();
|
|
1417
|
+
}
|
|
1418
|
+
function count(value, field) {
|
|
1419
|
+
if (!Number.isInteger(value) || value < 0) {
|
|
1420
|
+
throw new Error(`invalid qa_quality_metrics payload: ${field} must be a non-negative integer`);
|
|
1421
|
+
}
|
|
1422
|
+
return value;
|
|
1423
|
+
}
|
|
1424
|
+
function counts(value, field) {
|
|
1425
|
+
const input = record(value);
|
|
1426
|
+
if (!input) throw new Error(`invalid qa_quality_metrics payload: ${field} must be an object`);
|
|
1427
|
+
const passed = count(input["passed"], `${field}.passed`);
|
|
1428
|
+
const total = count(input["total"], `${field}.total`);
|
|
1429
|
+
if (passed > total) throw new Error(`invalid qa_quality_metrics payload: ${field}.passed cannot exceed total`);
|
|
1430
|
+
return { passed, total };
|
|
1431
|
+
}
|
|
1432
|
+
function testCounts(value, field) {
|
|
1433
|
+
const input = record(value);
|
|
1434
|
+
if (!input) throw new Error(`invalid qa_quality_metrics payload: ${field} must be an object`);
|
|
1435
|
+
const base = counts(input, field);
|
|
1436
|
+
const failed = count(input["failed"] ?? 0, `${field}.failed`);
|
|
1437
|
+
const blocked = count(input["blocked"] ?? 0, `${field}.blocked`);
|
|
1438
|
+
if (base.passed + failed + blocked > base.total) {
|
|
1439
|
+
throw new Error(`invalid qa_quality_metrics payload: ${field} passed + failed + blocked cannot exceed total`);
|
|
1440
|
+
}
|
|
1441
|
+
return { ...base, failed, blocked };
|
|
1442
|
+
}
|
|
1443
|
+
function parseWorkorderQualityMetricsPayload(value) {
|
|
1444
|
+
const input = record(value);
|
|
1445
|
+
if (!input || input["kind"] !== "qa_quality_metrics") return null;
|
|
1446
|
+
const schemaVersion = input["schema_version"] ?? input["schemaVersion"];
|
|
1447
|
+
if (schemaVersion !== 1) {
|
|
1448
|
+
throw new Error("invalid qa_quality_metrics payload: schema_version must be 1");
|
|
1449
|
+
}
|
|
1450
|
+
const checklistRefRaw = input["checklist_ref"] ?? input["checklistRef"];
|
|
1451
|
+
if (checklistRefRaw !== void 0 && (typeof checklistRefRaw !== "string" || !checklistRefRaw.trim())) {
|
|
1452
|
+
throw new Error("invalid qa_quality_metrics payload: checklist_ref must be a non-empty string when provided");
|
|
1453
|
+
}
|
|
1454
|
+
return {
|
|
1455
|
+
kind: "qa_quality_metrics",
|
|
1456
|
+
schemaVersion: 1,
|
|
1457
|
+
suiteRunId: requiredString(input["suite_run_id"] ?? input["suiteRunId"], "suite_run_id"),
|
|
1458
|
+
...typeof checklistRefRaw === "string" ? { checklistRef: checklistRefRaw.trim() } : {},
|
|
1459
|
+
functionalCoverage: counts(input["functional_coverage"] ?? input["functionalCoverage"], "functional_coverage"),
|
|
1460
|
+
p0Tests: testCounts(input["p0_tests"] ?? input["p0Tests"], "p0_tests"),
|
|
1461
|
+
p1Tests: testCounts(input["p1_tests"] ?? input["p1Tests"], "p1_tests")
|
|
1462
|
+
};
|
|
1463
|
+
}
|
|
1464
|
+
var init_workorder_quality = __esm({
|
|
1465
|
+
"../contract/src/workorder-quality.ts"() {
|
|
1466
|
+
"use strict";
|
|
1467
|
+
}
|
|
1468
|
+
});
|
|
1469
|
+
|
|
1408
1470
|
// ../contract/src/schema.ts
|
|
1409
1471
|
var init_schema = __esm({
|
|
1410
1472
|
"../contract/src/schema.ts"() {
|
|
@@ -1462,9 +1524,9 @@ var init_storage = __esm({
|
|
|
1462
1524
|
});
|
|
1463
1525
|
|
|
1464
1526
|
// ../contract/src/avatar.ts
|
|
1465
|
-
function isAgentAvatarPresetRef(
|
|
1466
|
-
if (typeof
|
|
1467
|
-
const id =
|
|
1527
|
+
function isAgentAvatarPresetRef(ref2) {
|
|
1528
|
+
if (typeof ref2 !== "string" || !ref2.startsWith(AGENT_AVATAR_PRESET_PREFIX)) return false;
|
|
1529
|
+
const id = ref2.slice(AGENT_AVATAR_PRESET_PREFIX.length);
|
|
1468
1530
|
return AGENT_AVATAR_PRESET_IDS.includes(id);
|
|
1469
1531
|
}
|
|
1470
1532
|
var AGENT_AVATAR_PRESET_PREFIX, AGENT_AVATAR_PRESET_IDS;
|
|
@@ -1576,6 +1638,7 @@ var init_src = __esm({
|
|
|
1576
1638
|
init_company();
|
|
1577
1639
|
init_annotation();
|
|
1578
1640
|
init_collab_view();
|
|
1641
|
+
init_workorder_quality();
|
|
1579
1642
|
init_schema();
|
|
1580
1643
|
init_errors();
|
|
1581
1644
|
init_storage();
|
|
@@ -1636,13 +1699,13 @@ async function reachableBlobs(oplog, blobs) {
|
|
|
1636
1699
|
const reachable = /* @__PURE__ */ new Set();
|
|
1637
1700
|
for await (const { op } of oplog.readAll()) {
|
|
1638
1701
|
const payload = op.payload;
|
|
1639
|
-
const
|
|
1640
|
-
if (typeof
|
|
1702
|
+
const ref2 = payload.contentRef;
|
|
1703
|
+
if (typeof ref2 !== "string") continue;
|
|
1641
1704
|
if (payload.contentKind === "external-pin") continue;
|
|
1642
1705
|
if (payload.contentKind === "manifest") {
|
|
1643
|
-
for (const h of await manifestRefs(blobs,
|
|
1706
|
+
for (const h of await manifestRefs(blobs, ref2)) reachable.add(h);
|
|
1644
1707
|
} else {
|
|
1645
|
-
reachable.add(
|
|
1708
|
+
reachable.add(ref2);
|
|
1646
1709
|
}
|
|
1647
1710
|
}
|
|
1648
1711
|
return reachable;
|
|
@@ -1664,10 +1727,10 @@ async function checkCitationExists(input) {
|
|
|
1664
1727
|
if (input.revision.contentKind && input.revision.contentKind !== "inline-blob") return [];
|
|
1665
1728
|
const text = new TextDecoder().decode(await input.blobs.get(input.revision.contentRef));
|
|
1666
1729
|
const findings = [];
|
|
1667
|
-
for (const
|
|
1668
|
-
const exists =
|
|
1730
|
+
for (const ref2 of new Set(text.match(CITATION_RE) ?? [])) {
|
|
1731
|
+
const exists = ref2.startsWith("artifact:") ? input.model.artifacts.has(ref2) : input.model.revisions.has(ref2);
|
|
1669
1732
|
if (!exists) {
|
|
1670
|
-
findings.push({ check: "citation_exists", detail: `\u51ED\u7A7A/\u60AC\u7A7A\u5F15\u7528\uFF1A${
|
|
1733
|
+
findings.push({ check: "citation_exists", detail: `\u51ED\u7A7A/\u60AC\u7A7A\u5F15\u7528\uFF1A${ref2}` });
|
|
1671
1734
|
}
|
|
1672
1735
|
}
|
|
1673
1736
|
return findings;
|
|
@@ -2802,7 +2865,7 @@ var init_kernel = __esm({
|
|
|
2802
2865
|
return id;
|
|
2803
2866
|
});
|
|
2804
2867
|
const candidates = [...existing, ...batch];
|
|
2805
|
-
const
|
|
2868
|
+
const ref2 = (r, what) => {
|
|
2806
2869
|
if (r === void 0) return void 0;
|
|
2807
2870
|
if (!ws) return r;
|
|
2808
2871
|
const res = resolveNodeRef(r, candidates);
|
|
@@ -2815,15 +2878,15 @@ ${res.candidates.map((c) => ` - ${c.type}:${c.title ?? "(\u65E0title)"} \u2192
|
|
|
2815
2878
|
const ops = plan.ops.map((op, i) => {
|
|
2816
2879
|
switch (op.action) {
|
|
2817
2880
|
case "spawn":
|
|
2818
|
-
return { ...op, id: spawnIds[i], ...op.workspace === void 0 && ws ? { workspace: ws } : {}, ...op.inputs ? { inputs: op.inputs.map((e) => ({ to:
|
|
2881
|
+
return { ...op, id: spawnIds[i], ...op.workspace === void 0 && ws ? { workspace: ws } : {}, ...op.inputs ? { inputs: op.inputs.map((e) => ({ to: ref2(e.to, "spawn \u4F9D\u8D56"), ...e.required !== void 0 ? { required: e.required } : {} })) } : {} };
|
|
2819
2882
|
case "link":
|
|
2820
2883
|
case "unlink":
|
|
2821
2884
|
case "pin":
|
|
2822
|
-
return { ...op, artifactId:
|
|
2885
|
+
return { ...op, artifactId: ref2(op.artifactId, op.action), to: ref2(op.to, `${op.action} \u4E0A\u6E38`) };
|
|
2823
2886
|
case "annotate":
|
|
2824
|
-
return { ...op, artifactId:
|
|
2887
|
+
return { ...op, artifactId: ref2(op.artifactId, "annotate"), ...op.raisedFrom ? { raisedFrom: ref2(op.raisedFrom, "annotate raisedFrom") } : {} };
|
|
2825
2888
|
default:
|
|
2826
|
-
return { ...op, artifactId:
|
|
2889
|
+
return { ...op, artifactId: ref2(op.artifactId, op.action) };
|
|
2827
2890
|
}
|
|
2828
2891
|
});
|
|
2829
2892
|
return { ...plan, ops };
|
|
@@ -4014,7 +4077,10 @@ function computeReviewJobs(model) {
|
|
|
4014
4077
|
}
|
|
4015
4078
|
return out;
|
|
4016
4079
|
}
|
|
4017
|
-
|
|
4080
|
+
function isSelfHealingExit(reason) {
|
|
4081
|
+
return reason !== void 0 && SELF_HEALING_EXITS.has(reason);
|
|
4082
|
+
}
|
|
4083
|
+
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
4084
|
var init_dispatcher = __esm({
|
|
4019
4085
|
"../core/src/dispatcher.ts"() {
|
|
4020
4086
|
"use strict";
|
|
@@ -4032,6 +4098,7 @@ var init_dispatcher = __esm({
|
|
|
4032
4098
|
}
|
|
4033
4099
|
};
|
|
4034
4100
|
SEED_ROOT_SUCCESSFUL_PRODUCE_LIMIT = 5;
|
|
4101
|
+
SELF_HEALING_EXITS = /* @__PURE__ */ new Set(["rate-limit"]);
|
|
4035
4102
|
CANVAS_RUNTIME_KIND = "open-design";
|
|
4036
4103
|
NON_PRODUCE_FALLBACK_RUNTIME_KIND = "claude-code";
|
|
4037
4104
|
Dispatcher = class {
|
|
@@ -4065,7 +4132,7 @@ var init_dispatcher = __esm({
|
|
|
4065
4132
|
} catch {
|
|
4066
4133
|
}
|
|
4067
4134
|
}
|
|
4068
|
-
/** 熔断中的 job(B3 表面化:/api/view dispatches 的 fused
|
|
4135
|
+
/** 熔断中的 job(B3 表面化:/api/view dispatches 的 fused 区;lastReason 供自动分诊做诊断上下文) */
|
|
4069
4136
|
fusedJobs() {
|
|
4070
4137
|
return [...this.strikes.entries()].filter(([, st]) => st.fused).map(([jobKey, st]) => ({
|
|
4071
4138
|
jobKey,
|
|
@@ -4073,9 +4140,24 @@ var init_dispatcher = __esm({
|
|
|
4073
4140
|
actor: st.actor,
|
|
4074
4141
|
action: st.action,
|
|
4075
4142
|
consecutiveFailures: st.count,
|
|
4076
|
-
fusedAt: st.fusedAt
|
|
4143
|
+
fusedAt: st.fusedAt,
|
|
4144
|
+
...st.lastReason ? { lastReason: st.lastReason } : {}
|
|
4077
4145
|
}));
|
|
4078
4146
|
}
|
|
4147
|
+
/**
|
|
4148
|
+
* 长期饥饿的自愈类 job(rate-limit 持续退避超 starvationMs 仍未恢复):自愈类从不熔断、进不了 fusedJobs,
|
|
4149
|
+
* 若配额**长期**不足就成了静默卡死——本访问器供 SLA 扫描把它升级为**算力缺口**(提案"长期不足才=算力缺口")。
|
|
4150
|
+
*/
|
|
4151
|
+
starvingJobs(starvationMs, now) {
|
|
4152
|
+
const out = [];
|
|
4153
|
+
for (const [jobKey, st] of this.strikes) {
|
|
4154
|
+
if (st.fused || !isSelfHealingExit(st.lastReason) || !st.firstFailedAt) continue;
|
|
4155
|
+
const sinceMs = now - Date.parse(st.firstFailedAt);
|
|
4156
|
+
if (sinceMs <= starvationMs) continue;
|
|
4157
|
+
out.push({ jobKey, artifactId: st.artifactId, actor: st.actor, action: st.action, consecutiveFailures: st.count, lastReason: st.lastReason, sinceMs });
|
|
4158
|
+
}
|
|
4159
|
+
return out;
|
|
4160
|
+
}
|
|
4079
4161
|
/** v1 调度准入:当前被并发上限挡下、等待重评的 produce 会话数(/api/view dispatches 表面化)。 */
|
|
4080
4162
|
queuedCount() {
|
|
4081
4163
|
return this.queued.size;
|
|
@@ -4315,19 +4397,22 @@ var init_dispatcher = __esm({
|
|
|
4315
4397
|
}
|
|
4316
4398
|
recordSpawnFailure(jobKey, spec, reason) {
|
|
4317
4399
|
const seqAtVerdict = this.opts.kernel.model.lastSeq.get(spec.artifactId) ?? 0;
|
|
4318
|
-
const
|
|
4400
|
+
const prev = this.strikes.get(jobKey);
|
|
4401
|
+
const consecutive = (prev?.count ?? 0) + 1;
|
|
4319
4402
|
const max = this.opts.backoff?.maxConsecutiveFailures ?? 3;
|
|
4320
4403
|
const base = this.opts.backoff?.baseMs ?? 3e4;
|
|
4321
|
-
const
|
|
4404
|
+
const cap = this.opts.backoff?.maxBackoffMs ?? 30 * 6e4;
|
|
4405
|
+
const fused = consecutive >= max && !isSelfHealingExit(reason);
|
|
4322
4406
|
this.strikes.set(jobKey, {
|
|
4323
4407
|
artifactId: spec.artifactId,
|
|
4324
4408
|
actor: spec.actor,
|
|
4325
4409
|
action: spec.action,
|
|
4326
4410
|
count: consecutive,
|
|
4327
|
-
nextEligibleAt: Date.now() + base * 2 ** (consecutive - 1),
|
|
4411
|
+
nextEligibleAt: Date.now() + Math.min(base * 2 ** (consecutive - 1), cap),
|
|
4328
4412
|
fused,
|
|
4329
4413
|
...fused ? { fusedAt: (/* @__PURE__ */ new Date()).toISOString() } : {},
|
|
4330
4414
|
seqAtVerdict,
|
|
4415
|
+
firstFailedAt: prev?.firstFailedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
4331
4416
|
lastReason: reason
|
|
4332
4417
|
});
|
|
4333
4418
|
if (fused) {
|
|
@@ -4401,7 +4486,7 @@ var init_dispatcher = __esm({
|
|
|
4401
4486
|
}
|
|
4402
4487
|
}
|
|
4403
4488
|
const retry = this.strikes.get(jobKey);
|
|
4404
|
-
const lastFailure = retry && retry.count > 0 && retry.lastReason ? { reason: retry.lastReason } : void 0;
|
|
4489
|
+
const lastFailure = retry && retry.count > 0 && retry.lastReason && !isSelfHealingExit(retry.lastReason) ? { reason: retry.lastReason } : void 0;
|
|
4405
4490
|
const ws = kernel.model.artifacts.get(spec.artifactId)?.workspace;
|
|
4406
4491
|
const codeRepo = ws ? await this.opts.resolveCodeRepo?.(ws) ?? null : null;
|
|
4407
4492
|
this.assertSpawnAttemptCurrent(jobKey, attempt);
|
|
@@ -4588,19 +4673,23 @@ var init_dispatcher = __esm({
|
|
|
4588
4673
|
if (progressed) {
|
|
4589
4674
|
this.strikes.delete(jobKey);
|
|
4590
4675
|
} else {
|
|
4591
|
-
|
|
4676
|
+
const prev = this.strikes.get(jobKey);
|
|
4677
|
+
consecutive = (prev?.count ?? 0) + 1;
|
|
4592
4678
|
const max = this.opts.backoff?.maxConsecutiveFailures ?? 3;
|
|
4593
4679
|
const base = this.opts.backoff?.baseMs ?? 3e4;
|
|
4594
|
-
const
|
|
4680
|
+
const cap = this.opts.backoff?.maxBackoffMs ?? 30 * 6e4;
|
|
4681
|
+
const fused = consecutive >= max && !isSelfHealingExit(info.reason);
|
|
4595
4682
|
this.strikes.set(jobKey, {
|
|
4596
4683
|
artifactId: spec.artifactId,
|
|
4597
4684
|
actor: spec.actor,
|
|
4598
4685
|
action: spec.action,
|
|
4599
4686
|
count: consecutive,
|
|
4600
|
-
|
|
4687
|
+
// 退避封顶(maxBackoffMs,默认 30min):自愈类不熔断→consecutive 可无界增长,不封顶则间隔爆炸。
|
|
4688
|
+
nextEligibleAt: Date.now() + Math.min(base * 2 ** (consecutive - 1), cap),
|
|
4601
4689
|
fused,
|
|
4602
4690
|
...fused ? { fusedAt: (/* @__PURE__ */ new Date()).toISOString() } : {},
|
|
4603
4691
|
seqAtVerdict: seqAtExit,
|
|
4692
|
+
firstFailedAt: prev?.firstFailedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
4604
4693
|
...info.reason ? { lastReason: info.reason } : {}
|
|
4605
4694
|
});
|
|
4606
4695
|
if (fused) {
|
|
@@ -4981,22 +5070,22 @@ var init_ci_provider = __esm({
|
|
|
4981
5070
|
const { stdout } = await execFile("git", args, { cwd: this.repoDir(repo), env: process.env });
|
|
4982
5071
|
return stdout.trim();
|
|
4983
5072
|
}
|
|
4984
|
-
async ensurePr(
|
|
4985
|
-
if (!
|
|
4986
|
-
await this.git(
|
|
4987
|
-
await this.git(
|
|
4988
|
-
const existing = await this.gh(
|
|
5073
|
+
async ensurePr(ref2, meta) {
|
|
5074
|
+
if (!ref2.repo.remote) throw new Error(`repo ${ref2.repo.id} \u65E0 remote\uFF0C\u65E0\u6CD5\u5F00 PR`);
|
|
5075
|
+
await this.git(ref2.repo, ["fetch", "--quiet", "--prune", "origin"]);
|
|
5076
|
+
await this.git(ref2.repo, ["push", "--quiet", "--force-with-lease", "origin", `${ref2.sha}:refs/heads/${ref2.branch}`]);
|
|
5077
|
+
const existing = await this.gh(ref2.repo, ["pr", "list", "--head", ref2.branch, "--base", ref2.repo.develop, "--state", "open", "--json", "number,url"]);
|
|
4989
5078
|
const list = JSON.parse(existing || "[]");
|
|
4990
5079
|
if (list[0]) return list[0];
|
|
4991
|
-
const url = await this.gh(
|
|
4992
|
-
const created = JSON.parse(await this.gh(
|
|
4993
|
-
this.opts.log?.(`[ci] opened PR ${created.url} (${
|
|
5080
|
+
const url = await this.gh(ref2.repo, ["pr", "create", "--base", ref2.repo.develop, "--head", ref2.branch, "--title", meta.title, "--body", meta.body]);
|
|
5081
|
+
const created = JSON.parse(await this.gh(ref2.repo, ["pr", "view", ref2.branch, "--json", "number,url"]));
|
|
5082
|
+
this.opts.log?.(`[ci] opened PR ${created.url} (${ref2.branch} \u2192 ${ref2.repo.develop})`);
|
|
4994
5083
|
return created.url ? created : { number: created.number, url };
|
|
4995
5084
|
}
|
|
4996
|
-
async status(
|
|
5085
|
+
async status(ref2) {
|
|
4997
5086
|
let raw;
|
|
4998
5087
|
try {
|
|
4999
|
-
raw = await this.gh(
|
|
5088
|
+
raw = await this.gh(ref2.repo, ["pr", "view", ref2.branch, "--json", "statusCheckRollup,createdAt"]);
|
|
5000
5089
|
} catch (e) {
|
|
5001
5090
|
return { state: "pending", summary: `\u8BFB PR \u72B6\u6001\u5931\u8D25\uFF08\u4E0B\u8F6E\u91CD\u8BD5\uFF09\uFF1A${String(e)}` };
|
|
5002
5091
|
}
|
|
@@ -5007,7 +5096,7 @@ var init_ci_provider = __esm({
|
|
|
5007
5096
|
const ageMs = parsed.createdAt ? Date.now() - Date.parse(parsed.createdAt) : Infinity;
|
|
5008
5097
|
if (ageMs < grace) return { state: "pending" };
|
|
5009
5098
|
if (this.opts.failClosedWhenNoChecks) return { state: "failure", summary: "\u8BE5\u4ED3\u672A\u914D\u4EFB\u4F55 Actions check\uFF08fail-closed\uFF09\u2014\u2014\u8BF7\u8865 CI \u6216\u6539\u914D\u7F6E" };
|
|
5010
|
-
this.opts.log?.(`[ci] ${
|
|
5099
|
+
this.opts.log?.(`[ci] ${ref2.repo.id} PR ${ref2.branch} \u5F00\u4E86 ${Math.round(ageMs / 1e3)}s \u4ECD\u65E0 check\uFF0C\u5224\u65E0 CI\u3001\u95F8\u7A7A\u8FC7\uFF08\u544A\u8B66\uFF09`);
|
|
5011
5100
|
return { state: "success", summary: "\u65E0 CI check\uFF0C\u95F8\u7A7A\u8FC7" };
|
|
5012
5101
|
}
|
|
5013
5102
|
const failed = [];
|
|
@@ -5029,7 +5118,7 @@ var init_ci_provider = __esm({
|
|
|
5029
5118
|
const url = c.detailsUrl ?? c.targetUrl ?? "";
|
|
5030
5119
|
let block = ` - ${name} \u2192 ${concl}${url ? `
|
|
5031
5120
|
${url}` : ""}`;
|
|
5032
|
-
const tail = await this.failedLogTail(
|
|
5121
|
+
const tail = await this.failedLogTail(ref2.repo, url);
|
|
5033
5122
|
if (tail) block += `
|
|
5034
5123
|
\u5931\u8D25\u65E5\u5FD7\uFF08\u672B\u5C3E\uFF09\uFF1A
|
|
5035
5124
|
${tail.split("\n").map((l) => " " + l).join("\n")}`;
|
|
@@ -5052,20 +5141,20 @@ ${blocks.join("\n")}` };
|
|
|
5052
5141
|
return "";
|
|
5053
5142
|
}
|
|
5054
5143
|
}
|
|
5055
|
-
async merge(
|
|
5144
|
+
async merge(ref2) {
|
|
5056
5145
|
try {
|
|
5057
|
-
await this.gh(
|
|
5058
|
-
this.opts.log?.(`[ci] merged PR ${
|
|
5146
|
+
await this.gh(ref2.repo, ["pr", "merge", ref2.branch, "--merge", "--delete-branch"]);
|
|
5147
|
+
this.opts.log?.(`[ci] merged PR ${ref2.branch} \u2192 ${ref2.repo.develop}`);
|
|
5059
5148
|
return { merged: true };
|
|
5060
5149
|
} catch (e) {
|
|
5061
5150
|
return { merged: false, reason: String(e) };
|
|
5062
5151
|
}
|
|
5063
5152
|
}
|
|
5064
|
-
async isMerged(
|
|
5065
|
-
if (!
|
|
5153
|
+
async isMerged(ref2) {
|
|
5154
|
+
if (!ref2.repo.remote) return false;
|
|
5066
5155
|
try {
|
|
5067
|
-
await this.git(
|
|
5068
|
-
await this.git(
|
|
5156
|
+
await this.git(ref2.repo, ["fetch", "--quiet", "origin", ref2.repo.develop]);
|
|
5157
|
+
await this.git(ref2.repo, ["merge-base", "--is-ancestor", ref2.sha, `origin/${ref2.repo.develop}`]);
|
|
5069
5158
|
return true;
|
|
5070
5159
|
} catch {
|
|
5071
5160
|
return false;
|
|
@@ -5092,8 +5181,8 @@ function collectUmbrellaCommits(repos, featBranch, env) {
|
|
|
5092
5181
|
const refs = /* @__PURE__ */ new Map();
|
|
5093
5182
|
for (const line of ls.trim().split("\n")) {
|
|
5094
5183
|
if (!line) continue;
|
|
5095
|
-
const [sha2,
|
|
5096
|
-
if (sha2 &&
|
|
5184
|
+
const [sha2, ref2] = line.split(" ");
|
|
5185
|
+
if (sha2 && ref2) refs.set(ref2, sha2);
|
|
5097
5186
|
}
|
|
5098
5187
|
const featSha = refs.get(`refs/heads/${featBranch}`);
|
|
5099
5188
|
const devSha = refs.get(`refs/heads/${r.develop}`);
|
|
@@ -5168,9 +5257,9 @@ function autoMergeWorkIntoFeat(args) {
|
|
|
5168
5257
|
}
|
|
5169
5258
|
}
|
|
5170
5259
|
}
|
|
5171
|
-
const has = (
|
|
5260
|
+
const has = (ref2) => {
|
|
5172
5261
|
try {
|
|
5173
|
-
git(["rev-parse", "--verify", "--quiet",
|
|
5262
|
+
git(["rev-parse", "--verify", "--quiet", ref2]);
|
|
5174
5263
|
return true;
|
|
5175
5264
|
} catch {
|
|
5176
5265
|
return false;
|
|
@@ -12662,7 +12751,7 @@ function intersection(left, right) {
|
|
|
12662
12751
|
right
|
|
12663
12752
|
});
|
|
12664
12753
|
}
|
|
12665
|
-
function
|
|
12754
|
+
function record2(keyType, valueType, params) {
|
|
12666
12755
|
return new ZodRecord2({
|
|
12667
12756
|
type: "record",
|
|
12668
12757
|
keyType,
|
|
@@ -13471,7 +13560,7 @@ var init_types2 = __esm({
|
|
|
13471
13560
|
});
|
|
13472
13561
|
FormElicitationCapabilitySchema = intersection(object({
|
|
13473
13562
|
applyDefaults: boolean2().optional()
|
|
13474
|
-
}),
|
|
13563
|
+
}), record2(string2(), unknown()));
|
|
13475
13564
|
ElicitationCapabilitySchema = preprocess((value) => {
|
|
13476
13565
|
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
13477
13566
|
if (Object.keys(value).length === 0) {
|
|
@@ -13482,7 +13571,7 @@ var init_types2 = __esm({
|
|
|
13482
13571
|
}, intersection(object({
|
|
13483
13572
|
form: FormElicitationCapabilitySchema.optional(),
|
|
13484
13573
|
url: AssertObjectSchema.optional()
|
|
13485
|
-
}),
|
|
13574
|
+
}), record2(string2(), unknown()).optional()));
|
|
13486
13575
|
ClientTasksCapabilitySchema = looseObject({
|
|
13487
13576
|
/**
|
|
13488
13577
|
* Present if the client supports listing tasks.
|
|
@@ -13535,7 +13624,7 @@ var init_types2 = __esm({
|
|
|
13535
13624
|
/**
|
|
13536
13625
|
* Experimental, non-standard capabilities that the client supports.
|
|
13537
13626
|
*/
|
|
13538
|
-
experimental:
|
|
13627
|
+
experimental: record2(string2(), AssertObjectSchema).optional(),
|
|
13539
13628
|
/**
|
|
13540
13629
|
* Present if the client supports sampling from an LLM.
|
|
13541
13630
|
*/
|
|
@@ -13570,7 +13659,7 @@ var init_types2 = __esm({
|
|
|
13570
13659
|
/**
|
|
13571
13660
|
* Extensions that the client supports. Keys are extension identifiers (vendor-prefix/extension-name).
|
|
13572
13661
|
*/
|
|
13573
|
-
extensions:
|
|
13662
|
+
extensions: record2(string2(), AssertObjectSchema).optional()
|
|
13574
13663
|
});
|
|
13575
13664
|
InitializeRequestParamsSchema = BaseRequestParamsSchema.extend({
|
|
13576
13665
|
/**
|
|
@@ -13588,7 +13677,7 @@ var init_types2 = __esm({
|
|
|
13588
13677
|
/**
|
|
13589
13678
|
* Experimental, non-standard capabilities that the server supports.
|
|
13590
13679
|
*/
|
|
13591
|
-
experimental:
|
|
13680
|
+
experimental: record2(string2(), AssertObjectSchema).optional(),
|
|
13592
13681
|
/**
|
|
13593
13682
|
* Present if the server supports sending log messages to the client.
|
|
13594
13683
|
*/
|
|
@@ -13635,7 +13724,7 @@ var init_types2 = __esm({
|
|
|
13635
13724
|
/**
|
|
13636
13725
|
* Extensions that the server supports. Keys are extension identifiers (vendor-prefix/extension-name).
|
|
13637
13726
|
*/
|
|
13638
|
-
extensions:
|
|
13727
|
+
extensions: record2(string2(), AssertObjectSchema).optional()
|
|
13639
13728
|
});
|
|
13640
13729
|
InitializeResultSchema = ResultSchema.extend({
|
|
13641
13730
|
/**
|
|
@@ -13773,7 +13862,7 @@ var init_types2 = __esm({
|
|
|
13773
13862
|
* See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields)
|
|
13774
13863
|
* for notes on _meta usage.
|
|
13775
13864
|
*/
|
|
13776
|
-
_meta:
|
|
13865
|
+
_meta: record2(string2(), unknown()).optional()
|
|
13777
13866
|
});
|
|
13778
13867
|
TextResourceContentsSchema = ResourceContentsSchema.extend({
|
|
13779
13868
|
/**
|
|
@@ -13967,7 +14056,7 @@ var init_types2 = __esm({
|
|
|
13967
14056
|
/**
|
|
13968
14057
|
* Arguments to use for templating the prompt.
|
|
13969
14058
|
*/
|
|
13970
|
-
arguments:
|
|
14059
|
+
arguments: record2(string2(), string2()).optional()
|
|
13971
14060
|
});
|
|
13972
14061
|
GetPromptRequestSchema = RequestSchema.extend({
|
|
13973
14062
|
method: literal("prompts/get"),
|
|
@@ -13987,7 +14076,7 @@ var init_types2 = __esm({
|
|
|
13987
14076
|
* See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields)
|
|
13988
14077
|
* for notes on _meta usage.
|
|
13989
14078
|
*/
|
|
13990
|
-
_meta:
|
|
14079
|
+
_meta: record2(string2(), unknown()).optional()
|
|
13991
14080
|
});
|
|
13992
14081
|
ImageContentSchema = object({
|
|
13993
14082
|
type: literal("image"),
|
|
@@ -14007,7 +14096,7 @@ var init_types2 = __esm({
|
|
|
14007
14096
|
* See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields)
|
|
14008
14097
|
* for notes on _meta usage.
|
|
14009
14098
|
*/
|
|
14010
|
-
_meta:
|
|
14099
|
+
_meta: record2(string2(), unknown()).optional()
|
|
14011
14100
|
});
|
|
14012
14101
|
AudioContentSchema = object({
|
|
14013
14102
|
type: literal("audio"),
|
|
@@ -14027,7 +14116,7 @@ var init_types2 = __esm({
|
|
|
14027
14116
|
* See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields)
|
|
14028
14117
|
* for notes on _meta usage.
|
|
14029
14118
|
*/
|
|
14030
|
-
_meta:
|
|
14119
|
+
_meta: record2(string2(), unknown()).optional()
|
|
14031
14120
|
});
|
|
14032
14121
|
ToolUseContentSchema = object({
|
|
14033
14122
|
type: literal("tool_use"),
|
|
@@ -14045,12 +14134,12 @@ var init_types2 = __esm({
|
|
|
14045
14134
|
* Arguments to pass to the tool.
|
|
14046
14135
|
* Must conform to the tool's inputSchema.
|
|
14047
14136
|
*/
|
|
14048
|
-
input:
|
|
14137
|
+
input: record2(string2(), unknown()),
|
|
14049
14138
|
/**
|
|
14050
14139
|
* See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields)
|
|
14051
14140
|
* for notes on _meta usage.
|
|
14052
14141
|
*/
|
|
14053
|
-
_meta:
|
|
14142
|
+
_meta: record2(string2(), unknown()).optional()
|
|
14054
14143
|
});
|
|
14055
14144
|
EmbeddedResourceSchema = object({
|
|
14056
14145
|
type: literal("resource"),
|
|
@@ -14063,7 +14152,7 @@ var init_types2 = __esm({
|
|
|
14063
14152
|
* See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields)
|
|
14064
14153
|
* for notes on _meta usage.
|
|
14065
14154
|
*/
|
|
14066
|
-
_meta:
|
|
14155
|
+
_meta: record2(string2(), unknown()).optional()
|
|
14067
14156
|
});
|
|
14068
14157
|
ResourceLinkSchema = ResourceSchema.extend({
|
|
14069
14158
|
type: literal("resource_link")
|
|
@@ -14153,7 +14242,7 @@ var init_types2 = __esm({
|
|
|
14153
14242
|
*/
|
|
14154
14243
|
inputSchema: object({
|
|
14155
14244
|
type: literal("object"),
|
|
14156
|
-
properties:
|
|
14245
|
+
properties: record2(string2(), AssertObjectSchema).optional(),
|
|
14157
14246
|
required: array(string2()).optional()
|
|
14158
14247
|
}).catchall(unknown()),
|
|
14159
14248
|
/**
|
|
@@ -14163,7 +14252,7 @@ var init_types2 = __esm({
|
|
|
14163
14252
|
*/
|
|
14164
14253
|
outputSchema: object({
|
|
14165
14254
|
type: literal("object"),
|
|
14166
|
-
properties:
|
|
14255
|
+
properties: record2(string2(), AssertObjectSchema).optional(),
|
|
14167
14256
|
required: array(string2()).optional()
|
|
14168
14257
|
}).catchall(unknown()).optional(),
|
|
14169
14258
|
/**
|
|
@@ -14178,7 +14267,7 @@ var init_types2 = __esm({
|
|
|
14178
14267
|
* See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields)
|
|
14179
14268
|
* for notes on _meta usage.
|
|
14180
14269
|
*/
|
|
14181
|
-
_meta:
|
|
14270
|
+
_meta: record2(string2(), unknown()).optional()
|
|
14182
14271
|
});
|
|
14183
14272
|
ListToolsRequestSchema = PaginatedRequestSchema.extend({
|
|
14184
14273
|
method: literal("tools/list")
|
|
@@ -14199,7 +14288,7 @@ var init_types2 = __esm({
|
|
|
14199
14288
|
*
|
|
14200
14289
|
* If the Tool defines an outputSchema, this field MUST be present in the result, and contain a JSON object that matches the schema.
|
|
14201
14290
|
*/
|
|
14202
|
-
structuredContent:
|
|
14291
|
+
structuredContent: record2(string2(), unknown()).optional(),
|
|
14203
14292
|
/**
|
|
14204
14293
|
* Whether the tool call ended in an error.
|
|
14205
14294
|
*
|
|
@@ -14227,7 +14316,7 @@ var init_types2 = __esm({
|
|
|
14227
14316
|
/**
|
|
14228
14317
|
* Arguments to pass to the tool.
|
|
14229
14318
|
*/
|
|
14230
|
-
arguments:
|
|
14319
|
+
arguments: record2(string2(), unknown()).optional()
|
|
14231
14320
|
});
|
|
14232
14321
|
CallToolRequestSchema = RequestSchema.extend({
|
|
14233
14322
|
method: literal("tools/call"),
|
|
@@ -14329,7 +14418,7 @@ var init_types2 = __esm({
|
|
|
14329
14418
|
* See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields)
|
|
14330
14419
|
* for notes on _meta usage.
|
|
14331
14420
|
*/
|
|
14332
|
-
_meta:
|
|
14421
|
+
_meta: record2(string2(), unknown()).optional()
|
|
14333
14422
|
});
|
|
14334
14423
|
SamplingContentSchema = discriminatedUnion("type", [TextContentSchema, ImageContentSchema, AudioContentSchema]);
|
|
14335
14424
|
SamplingMessageContentBlockSchema = discriminatedUnion("type", [
|
|
@@ -14346,7 +14435,7 @@ var init_types2 = __esm({
|
|
|
14346
14435
|
* See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields)
|
|
14347
14436
|
* for notes on _meta usage.
|
|
14348
14437
|
*/
|
|
14349
|
-
_meta:
|
|
14438
|
+
_meta: record2(string2(), unknown()).optional()
|
|
14350
14439
|
});
|
|
14351
14440
|
CreateMessageRequestParamsSchema = TaskAugmentedRequestParamsSchema.extend({
|
|
14352
14441
|
messages: array(SamplingMessageSchema),
|
|
@@ -14534,7 +14623,7 @@ var init_types2 = __esm({
|
|
|
14534
14623
|
*/
|
|
14535
14624
|
requestedSchema: object({
|
|
14536
14625
|
type: literal("object"),
|
|
14537
|
-
properties:
|
|
14626
|
+
properties: record2(string2(), PrimitiveSchemaDefinitionSchema),
|
|
14538
14627
|
required: array(string2()).optional()
|
|
14539
14628
|
})
|
|
14540
14629
|
});
|
|
@@ -14586,7 +14675,7 @@ var init_types2 = __esm({
|
|
|
14586
14675
|
* Per MCP spec, content is "typically omitted" for decline/cancel actions.
|
|
14587
14676
|
* We normalize null to undefined for leniency while maintaining type compatibility.
|
|
14588
14677
|
*/
|
|
14589
|
-
content: preprocess((val) => val === null ? void 0 : val,
|
|
14678
|
+
content: preprocess((val) => val === null ? void 0 : val, record2(string2(), union([string2(), number2(), boolean2(), array(string2())])).optional())
|
|
14590
14679
|
});
|
|
14591
14680
|
ResourceTemplateReferenceSchema = object({
|
|
14592
14681
|
type: literal("ref/resource"),
|
|
@@ -14621,7 +14710,7 @@ var init_types2 = __esm({
|
|
|
14621
14710
|
/**
|
|
14622
14711
|
* Previously-resolved variables in a URI template or prompt.
|
|
14623
14712
|
*/
|
|
14624
|
-
arguments:
|
|
14713
|
+
arguments: record2(string2(), string2()).optional()
|
|
14625
14714
|
}).optional()
|
|
14626
14715
|
});
|
|
14627
14716
|
CompleteRequestSchema = RequestSchema.extend({
|
|
@@ -14657,7 +14746,7 @@ var init_types2 = __esm({
|
|
|
14657
14746
|
* See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields)
|
|
14658
14747
|
* for notes on _meta usage.
|
|
14659
14748
|
*/
|
|
14660
|
-
_meta:
|
|
14749
|
+
_meta: record2(string2(), unknown()).optional()
|
|
14661
14750
|
});
|
|
14662
14751
|
ListRootsRequestSchema = RequestSchema.extend({
|
|
14663
14752
|
method: literal("roots/list"),
|
|
@@ -17306,20 +17395,20 @@ var require_resolve = __commonJS({
|
|
|
17306
17395
|
return false;
|
|
17307
17396
|
}
|
|
17308
17397
|
function countKeys(schema) {
|
|
17309
|
-
let
|
|
17398
|
+
let count2 = 0;
|
|
17310
17399
|
for (const key in schema) {
|
|
17311
17400
|
if (key === "$ref")
|
|
17312
17401
|
return Infinity;
|
|
17313
|
-
|
|
17402
|
+
count2++;
|
|
17314
17403
|
if (SIMPLE_INLINED.has(key))
|
|
17315
17404
|
continue;
|
|
17316
17405
|
if (typeof schema[key] == "object") {
|
|
17317
|
-
(0, util_1.eachItem)(schema[key], (sch) =>
|
|
17406
|
+
(0, util_1.eachItem)(schema[key], (sch) => count2 += countKeys(sch));
|
|
17318
17407
|
}
|
|
17319
|
-
if (
|
|
17408
|
+
if (count2 === Infinity)
|
|
17320
17409
|
return Infinity;
|
|
17321
17410
|
}
|
|
17322
|
-
return
|
|
17411
|
+
return count2;
|
|
17323
17412
|
}
|
|
17324
17413
|
function getFullPath(resolver, id = "", normalize) {
|
|
17325
17414
|
if (normalize !== false)
|
|
@@ -17363,26 +17452,26 @@ var require_resolve = __commonJS({
|
|
|
17363
17452
|
addAnchor.call(this, sch.$anchor);
|
|
17364
17453
|
addAnchor.call(this, sch.$dynamicAnchor);
|
|
17365
17454
|
baseIds[jsonPtr] = innerBaseId;
|
|
17366
|
-
function addRef(
|
|
17455
|
+
function addRef(ref2) {
|
|
17367
17456
|
const _resolve = this.opts.uriResolver.resolve;
|
|
17368
|
-
|
|
17369
|
-
if (schemaRefs.has(
|
|
17370
|
-
throw ambiguos(
|
|
17371
|
-
schemaRefs.add(
|
|
17372
|
-
let schOrRef = this.refs[
|
|
17457
|
+
ref2 = normalizeId(innerBaseId ? _resolve(innerBaseId, ref2) : ref2);
|
|
17458
|
+
if (schemaRefs.has(ref2))
|
|
17459
|
+
throw ambiguos(ref2);
|
|
17460
|
+
schemaRefs.add(ref2);
|
|
17461
|
+
let schOrRef = this.refs[ref2];
|
|
17373
17462
|
if (typeof schOrRef == "string")
|
|
17374
17463
|
schOrRef = this.refs[schOrRef];
|
|
17375
17464
|
if (typeof schOrRef == "object") {
|
|
17376
|
-
checkAmbiguosRef(sch, schOrRef.schema,
|
|
17377
|
-
} else if (
|
|
17378
|
-
if (
|
|
17379
|
-
checkAmbiguosRef(sch, localRefs[
|
|
17380
|
-
localRefs[
|
|
17465
|
+
checkAmbiguosRef(sch, schOrRef.schema, ref2);
|
|
17466
|
+
} else if (ref2 !== normalizeId(fullPath)) {
|
|
17467
|
+
if (ref2[0] === "#") {
|
|
17468
|
+
checkAmbiguosRef(sch, localRefs[ref2], ref2);
|
|
17469
|
+
localRefs[ref2] = sch;
|
|
17381
17470
|
} else {
|
|
17382
|
-
this.refs[
|
|
17471
|
+
this.refs[ref2] = fullPath;
|
|
17383
17472
|
}
|
|
17384
17473
|
}
|
|
17385
|
-
return
|
|
17474
|
+
return ref2;
|
|
17386
17475
|
}
|
|
17387
17476
|
function addAnchor(anchor) {
|
|
17388
17477
|
if (typeof anchor == "string") {
|
|
@@ -17393,12 +17482,12 @@ var require_resolve = __commonJS({
|
|
|
17393
17482
|
}
|
|
17394
17483
|
});
|
|
17395
17484
|
return localRefs;
|
|
17396
|
-
function checkAmbiguosRef(sch1, sch2,
|
|
17485
|
+
function checkAmbiguosRef(sch1, sch2, ref2) {
|
|
17397
17486
|
if (sch2 !== void 0 && !equal(sch1, sch2))
|
|
17398
|
-
throw ambiguos(
|
|
17487
|
+
throw ambiguos(ref2);
|
|
17399
17488
|
}
|
|
17400
|
-
function ambiguos(
|
|
17401
|
-
return new Error(`reference "${
|
|
17489
|
+
function ambiguos(ref2) {
|
|
17490
|
+
return new Error(`reference "${ref2}" resolves to more than one schema`);
|
|
17402
17491
|
}
|
|
17403
17492
|
}
|
|
17404
17493
|
exports2.getSchemaRefs = getSchemaRefs;
|
|
@@ -17936,9 +18025,9 @@ var require_ref_error = __commonJS({
|
|
|
17936
18025
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
17937
18026
|
var resolve_1 = require_resolve();
|
|
17938
18027
|
var MissingRefError = class extends Error {
|
|
17939
|
-
constructor(resolver, baseId,
|
|
17940
|
-
super(msg || `can't resolve reference ${
|
|
17941
|
-
this.missingRef = (0, resolve_1.resolveUrl)(resolver, baseId,
|
|
18028
|
+
constructor(resolver, baseId, ref2, msg) {
|
|
18029
|
+
super(msg || `can't resolve reference ${ref2} from id ${baseId}`);
|
|
18030
|
+
this.missingRef = (0, resolve_1.resolveUrl)(resolver, baseId, ref2);
|
|
17942
18031
|
this.missingSchema = (0, resolve_1.normalizeId)((0, resolve_1.getFullPath)(resolver, this.missingRef));
|
|
17943
18032
|
}
|
|
17944
18033
|
};
|
|
@@ -18064,22 +18153,22 @@ var require_compile = __commonJS({
|
|
|
18064
18153
|
}
|
|
18065
18154
|
}
|
|
18066
18155
|
exports2.compileSchema = compileSchema;
|
|
18067
|
-
function resolveRef2(root, baseId,
|
|
18156
|
+
function resolveRef2(root, baseId, ref2) {
|
|
18068
18157
|
var _a;
|
|
18069
|
-
|
|
18070
|
-
const schOrFunc = root.refs[
|
|
18158
|
+
ref2 = (0, resolve_1.resolveUrl)(this.opts.uriResolver, baseId, ref2);
|
|
18159
|
+
const schOrFunc = root.refs[ref2];
|
|
18071
18160
|
if (schOrFunc)
|
|
18072
18161
|
return schOrFunc;
|
|
18073
|
-
let _sch = resolve5.call(this, root,
|
|
18162
|
+
let _sch = resolve5.call(this, root, ref2);
|
|
18074
18163
|
if (_sch === void 0) {
|
|
18075
|
-
const schema = (_a = root.localRefs) === null || _a === void 0 ? void 0 : _a[
|
|
18164
|
+
const schema = (_a = root.localRefs) === null || _a === void 0 ? void 0 : _a[ref2];
|
|
18076
18165
|
const { schemaId } = this.opts;
|
|
18077
18166
|
if (schema)
|
|
18078
18167
|
_sch = new SchemaEnv({ schema, schemaId, root, baseId });
|
|
18079
18168
|
}
|
|
18080
18169
|
if (_sch === void 0)
|
|
18081
18170
|
return;
|
|
18082
|
-
return root.refs[
|
|
18171
|
+
return root.refs[ref2] = inlineOrCompile.call(this, _sch);
|
|
18083
18172
|
}
|
|
18084
18173
|
exports2.resolveRef = resolveRef2;
|
|
18085
18174
|
function inlineOrCompile(sch) {
|
|
@@ -18097,14 +18186,14 @@ var require_compile = __commonJS({
|
|
|
18097
18186
|
function sameSchemaEnv(s1, s2) {
|
|
18098
18187
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
18099
18188
|
}
|
|
18100
|
-
function resolve5(root,
|
|
18189
|
+
function resolve5(root, ref2) {
|
|
18101
18190
|
let sch;
|
|
18102
|
-
while (typeof (sch = this.refs[
|
|
18103
|
-
|
|
18104
|
-
return sch || this.schemas[
|
|
18191
|
+
while (typeof (sch = this.refs[ref2]) == "string")
|
|
18192
|
+
ref2 = sch;
|
|
18193
|
+
return sch || this.schemas[ref2] || resolveSchema.call(this, root, ref2);
|
|
18105
18194
|
}
|
|
18106
|
-
function resolveSchema(root,
|
|
18107
|
-
const p2 = this.opts.uriResolver.parse(
|
|
18195
|
+
function resolveSchema(root, ref2) {
|
|
18196
|
+
const p2 = this.opts.uriResolver.parse(ref2);
|
|
18108
18197
|
const refPath = (0, resolve_1._getFullPath)(this.opts.uriResolver, p2);
|
|
18109
18198
|
let baseId = (0, resolve_1.getFullPath)(this.opts.uriResolver, root.baseId, void 0);
|
|
18110
18199
|
if (Object.keys(root.schema).length > 0 && refPath === baseId) {
|
|
@@ -18122,7 +18211,7 @@ var require_compile = __commonJS({
|
|
|
18122
18211
|
return;
|
|
18123
18212
|
if (!schOrRef.validate)
|
|
18124
18213
|
compileSchema.call(this, schOrRef);
|
|
18125
|
-
if (id === (0, resolve_1.normalizeId)(
|
|
18214
|
+
if (id === (0, resolve_1.normalizeId)(ref2)) {
|
|
18126
18215
|
const { schema } = schOrRef;
|
|
18127
18216
|
const { schemaId } = this.opts;
|
|
18128
18217
|
const schId = schema[schemaId];
|
|
@@ -19209,26 +19298,26 @@ var require_core = __commonJS({
|
|
|
19209
19298
|
return _compileAsync.call(this, sch);
|
|
19210
19299
|
}
|
|
19211
19300
|
}
|
|
19212
|
-
function checkLoaded({ missingSchema:
|
|
19213
|
-
if (this.refs[
|
|
19214
|
-
throw new Error(`AnySchema ${
|
|
19301
|
+
function checkLoaded({ missingSchema: ref2, missingRef }) {
|
|
19302
|
+
if (this.refs[ref2]) {
|
|
19303
|
+
throw new Error(`AnySchema ${ref2} is loaded but ${missingRef} cannot be resolved`);
|
|
19215
19304
|
}
|
|
19216
19305
|
}
|
|
19217
|
-
async function loadMissingSchema(
|
|
19218
|
-
const _schema = await _loadSchema.call(this,
|
|
19219
|
-
if (!this.refs[
|
|
19306
|
+
async function loadMissingSchema(ref2) {
|
|
19307
|
+
const _schema = await _loadSchema.call(this, ref2);
|
|
19308
|
+
if (!this.refs[ref2])
|
|
19220
19309
|
await loadMetaSchema.call(this, _schema.$schema);
|
|
19221
|
-
if (!this.refs[
|
|
19222
|
-
this.addSchema(_schema,
|
|
19310
|
+
if (!this.refs[ref2])
|
|
19311
|
+
this.addSchema(_schema, ref2, meta);
|
|
19223
19312
|
}
|
|
19224
|
-
async function _loadSchema(
|
|
19225
|
-
const p2 = this._loading[
|
|
19313
|
+
async function _loadSchema(ref2) {
|
|
19314
|
+
const p2 = this._loading[ref2];
|
|
19226
19315
|
if (p2)
|
|
19227
19316
|
return p2;
|
|
19228
19317
|
try {
|
|
19229
|
-
return await (this._loading[
|
|
19318
|
+
return await (this._loading[ref2] = loadSchema(ref2));
|
|
19230
19319
|
} finally {
|
|
19231
|
-
delete this._loading[
|
|
19320
|
+
delete this._loading[ref2];
|
|
19232
19321
|
}
|
|
19233
19322
|
}
|
|
19234
19323
|
}
|
|
@@ -20491,8 +20580,8 @@ var require_contains = __commonJS({
|
|
|
20491
20580
|
cxt.result(valid, () => cxt.reset());
|
|
20492
20581
|
function validateItemsWithCount() {
|
|
20493
20582
|
const schValid = gen.name("_valid");
|
|
20494
|
-
const
|
|
20495
|
-
validateItems(schValid, () => gen.if(schValid, () => checkLimits(
|
|
20583
|
+
const count2 = gen.let("count", 0);
|
|
20584
|
+
validateItems(schValid, () => gen.if(schValid, () => checkLimits(count2)));
|
|
20496
20585
|
}
|
|
20497
20586
|
function validateItems(_valid, block) {
|
|
20498
20587
|
gen.forRange("i", 0, len, (i) => {
|
|
@@ -20505,16 +20594,16 @@ var require_contains = __commonJS({
|
|
|
20505
20594
|
block();
|
|
20506
20595
|
});
|
|
20507
20596
|
}
|
|
20508
|
-
function checkLimits(
|
|
20509
|
-
gen.code((0, codegen_1._)`${
|
|
20597
|
+
function checkLimits(count2) {
|
|
20598
|
+
gen.code((0, codegen_1._)`${count2}++`);
|
|
20510
20599
|
if (max === void 0) {
|
|
20511
|
-
gen.if((0, codegen_1._)`${
|
|
20600
|
+
gen.if((0, codegen_1._)`${count2} >= ${min2}`, () => gen.assign(valid, true).break());
|
|
20512
20601
|
} else {
|
|
20513
|
-
gen.if((0, codegen_1._)`${
|
|
20602
|
+
gen.if((0, codegen_1._)`${count2} > ${max}`, () => gen.assign(valid, false).break());
|
|
20514
20603
|
if (min2 === 1)
|
|
20515
20604
|
gen.assign(valid, true);
|
|
20516
20605
|
else
|
|
20517
|
-
gen.if((0, codegen_1._)`${
|
|
20606
|
+
gen.if((0, codegen_1._)`${count2} >= ${min2}`, () => gen.assign(valid, true));
|
|
20518
20607
|
}
|
|
20519
20608
|
}
|
|
20520
20609
|
}
|
|
@@ -21387,12 +21476,12 @@ var require_discriminator = __commonJS({
|
|
|
21387
21476
|
for (let i = 0; i < oneOf.length; i++) {
|
|
21388
21477
|
let sch = oneOf[i];
|
|
21389
21478
|
if ((sch === null || sch === void 0 ? void 0 : sch.$ref) && !(0, util_1.schemaHasRulesButRef)(sch, it.self.RULES)) {
|
|
21390
|
-
const
|
|
21391
|
-
sch = compile_1.resolveRef.call(it.self, it.schemaEnv.root, it.baseId,
|
|
21479
|
+
const ref2 = sch.$ref;
|
|
21480
|
+
sch = compile_1.resolveRef.call(it.self, it.schemaEnv.root, it.baseId, ref2);
|
|
21392
21481
|
if (sch instanceof compile_1.SchemaEnv)
|
|
21393
21482
|
sch = sch.schema;
|
|
21394
21483
|
if (sch === void 0)
|
|
21395
|
-
throw new ref_error_1.default(it.opts.uriResolver, it.baseId,
|
|
21484
|
+
throw new ref_error_1.default(it.opts.uriResolver, it.baseId, ref2);
|
|
21396
21485
|
}
|
|
21397
21486
|
const propSch = (_a = sch === null || sch === void 0 ? void 0 : sch.properties) === null || _a === void 0 ? void 0 : _a[tagName];
|
|
21398
21487
|
if (typeof propSch != "object") {
|
|
@@ -22316,12 +22405,12 @@ var init_workorder_drafts = __esm({
|
|
|
22316
22405
|
});
|
|
22317
22406
|
|
|
22318
22407
|
// ../server/src/governance/draft-edit.ts
|
|
22319
|
-
function resolveRef(
|
|
22320
|
-
const res = resolveNodeRef(
|
|
22408
|
+
function resolveRef(ref2, draft) {
|
|
22409
|
+
const res = resolveNodeRef(ref2, candidatesOf(draft));
|
|
22321
22410
|
if (res.ok) return res.id;
|
|
22322
22411
|
if (res.reason === "ambiguous")
|
|
22323
|
-
throw new Error(`\u300C${
|
|
22324
|
-
throw new Error(`\u300C${
|
|
22412
|
+
throw new Error(`\u300C${ref2}\u300D\u5728\u672C\u8349\u6848\u5339\u914D\u5230\u591A\u4E2A\u8282\u70B9\uFF0C\u8BF7\u66F4\u5177\u4F53\uFF08type:title \u6216 id\uFF09\uFF1A${res.candidates.map((c) => `${c.type}:${c.title ?? "?"}`).join("\u3001")}`);
|
|
22413
|
+
throw new Error(`\u300C${ref2}\u300D\u5728\u672C\u8349\u6848\u91CC\u627E\u4E0D\u5230\u5BF9\u5E94\u8282\u70B9\uFF08\u53EF\u7528 type / type:title / id\uFF09`);
|
|
22325
22414
|
}
|
|
22326
22415
|
function editDraftPlan(draft, op) {
|
|
22327
22416
|
switch (op.action) {
|
|
@@ -22454,6 +22543,82 @@ var init_node_state = __esm({
|
|
|
22454
22543
|
}
|
|
22455
22544
|
});
|
|
22456
22545
|
|
|
22546
|
+
// ../server/src/domains/collab/stall.ts
|
|
22547
|
+
function shortId(id) {
|
|
22548
|
+
return id.length > 22 ? `${id.slice(0, 14)}\u2026` : id;
|
|
22549
|
+
}
|
|
22550
|
+
function stallOf(model, id, runtime) {
|
|
22551
|
+
const a = model.artifacts.get(id);
|
|
22552
|
+
if (!a) return null;
|
|
22553
|
+
const ownerIsAgent = a.owner.startsWith("actor:agent:");
|
|
22554
|
+
if (runtime?.status === "running") {
|
|
22555
|
+
return { kind: "running", detail: `${runtime.action ?? "produce"} \u5728\u8DD1`, ...runtime.startedAt ? { since: runtime.startedAt } : {} };
|
|
22556
|
+
}
|
|
22557
|
+
if (isHeld(model, id)) {
|
|
22558
|
+
const h = holdOf(model, id);
|
|
22559
|
+
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 } : {} };
|
|
22560
|
+
}
|
|
22561
|
+
if (runtime && (runtime.status === "failed" || runtime.status === "fused" || runtime.status === "escalated")) {
|
|
22562
|
+
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";
|
|
22563
|
+
return {
|
|
22564
|
+
kind: "failed",
|
|
22565
|
+
detail: `${label}${runtime.reason ? `\uFF08${runtime.reason}\uFF09` : ""}`,
|
|
22566
|
+
...runtime.reason ? { reason: runtime.reason } : {},
|
|
22567
|
+
...runtime.finishedAt ? { since: runtime.finishedAt } : {}
|
|
22568
|
+
};
|
|
22569
|
+
}
|
|
22570
|
+
const head = queueOf(model, id)[0];
|
|
22571
|
+
if (head) {
|
|
22572
|
+
const authors = declaredHumanAuthorsOf(model, head);
|
|
22573
|
+
if (authors.size > 0) {
|
|
22574
|
+
const approved = new Set((model.reviews.get(head.id) ?? []).filter((v2) => v2.verdict === "approve").map((v2) => v2.author));
|
|
22575
|
+
const missing = [...authors].filter((x2) => !approved.has(x2));
|
|
22576
|
+
if (missing.length > 0) {
|
|
22577
|
+
return {
|
|
22578
|
+
kind: "waiting_human",
|
|
22579
|
+
action: "accept",
|
|
22580
|
+
actorId: missing[0],
|
|
22581
|
+
ref: head.id,
|
|
22582
|
+
detail: `\u7B49 ${shortId(missing[0])} \u9A8C\u6536 ${shortId(head.id)} \u7248${missing.length > 1 ? `\uFF08\u5171 ${missing.length} \u4EBA\uFF09` : ""}`,
|
|
22583
|
+
since: head.createdAt
|
|
22584
|
+
};
|
|
22585
|
+
}
|
|
22586
|
+
}
|
|
22587
|
+
}
|
|
22588
|
+
const gate = pendingConcludeAttempt(model, id);
|
|
22589
|
+
if (gate?.gate) {
|
|
22590
|
+
const votedBy = new Set((model.reviews.get(gate.head) ?? []).map((v2) => v2.author));
|
|
22591
|
+
const humanEligible = gate.gate.eligible.filter((r) => r.startsWith("actor:human:") && !votedBy.has(r));
|
|
22592
|
+
if (humanEligible.length > 0) {
|
|
22593
|
+
return { kind: "waiting_human", action: "review", actorId: humanEligible[0], detail: `\u7B49 ${shortId(humanEligible[0])} \u5BA1\u6279\uFF08quorum=${gate.gate.quorum}\uFF09`, since: gate.at };
|
|
22594
|
+
}
|
|
22595
|
+
}
|
|
22596
|
+
if (hasOpenHumanChangeRequest(model, id) || headRejected(model, id)) {
|
|
22597
|
+
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" };
|
|
22598
|
+
}
|
|
22599
|
+
const escs = unresolvedEscalationsOf(model, id);
|
|
22600
|
+
if (escs.length > 0) {
|
|
22601
|
+
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 };
|
|
22602
|
+
}
|
|
22603
|
+
const gaps = unresolvedGapsOf(model, id);
|
|
22604
|
+
if (gaps.length > 0) {
|
|
22605
|
+
return { kind: "waiting_human", action: "resolve_gap", detail: `\u5361\u5728\u7F3A\u53E3\u4E0A\u5F85\u4EBA\u8865\uFF1A${gaps[0].description.slice(0, 60)}` };
|
|
22606
|
+
}
|
|
22607
|
+
const b2 = blockedOf(model, id);
|
|
22608
|
+
if (b2.blocked) {
|
|
22609
|
+
const dep = a.inputs.find((e) => e.required && !isConcluded(model, e.to));
|
|
22610
|
+
if (dep) return { kind: "waiting_system", ref: dep.to, detail: `\u7B49\u4E0A\u6E38\u6536\u53E3\uFF1A${shortId(dep.to)}` };
|
|
22611
|
+
return { kind: "waiting_system", detail: `\u963B\u585E\u4E2D\uFF1A${b2.reasons[0] ?? "\u5F85\u524D\u7F6E\u5C31\u7EEA"}` };
|
|
22612
|
+
}
|
|
22613
|
+
return null;
|
|
22614
|
+
}
|
|
22615
|
+
var init_stall = __esm({
|
|
22616
|
+
"../server/src/domains/collab/stall.ts"() {
|
|
22617
|
+
"use strict";
|
|
22618
|
+
init_src2();
|
|
22619
|
+
}
|
|
22620
|
+
});
|
|
22621
|
+
|
|
22457
22622
|
// ../server/src/coordinator/identity.ts
|
|
22458
22623
|
function isCoordinatorAgentName(name) {
|
|
22459
22624
|
return COORDINATOR_NAME_RE.test(name);
|
|
@@ -22990,7 +23155,7 @@ function buildWorkorderSummaries(model, resolveActor, resolveProject, dispatchPa
|
|
|
22990
23155
|
arr.push(a);
|
|
22991
23156
|
byWorkspace.set(a.workspace, arr);
|
|
22992
23157
|
}
|
|
22993
|
-
const
|
|
23158
|
+
const ref2 = (id) => {
|
|
22994
23159
|
const extra = resolveActor?.(id);
|
|
22995
23160
|
return {
|
|
22996
23161
|
id,
|
|
@@ -23018,8 +23183,8 @@ function buildWorkorderSummaries(model, resolveActor, resolveProject, dispatchPa
|
|
|
23018
23183
|
// 一句话目标:优先取结构化 spec.goal;缺省时前端回退 description 首段(投影不替前端做回退,只给真值)
|
|
23019
23184
|
...spec?.goal ? { goal: spec.goal } : {},
|
|
23020
23185
|
stage,
|
|
23021
|
-
owner:
|
|
23022
|
-
participants: participantIds.map(
|
|
23186
|
+
owner: ref2(seed.owner),
|
|
23187
|
+
participants: participantIds.map(ref2),
|
|
23023
23188
|
artifactCount: arts.length,
|
|
23024
23189
|
progress: { concluded, total: arts.length },
|
|
23025
23190
|
updatedAt: lastOps[lastOps.length - 1] ?? "",
|
|
@@ -23081,7 +23246,7 @@ function buildWorkorderDetail(model, workspaceId, resolveActor, resolveProject,
|
|
|
23081
23246
|
if (arts.length === 0) return null;
|
|
23082
23247
|
const summary = buildWorkorderSummaries(model, resolveActor, resolveProject, dispatchPausedOf).find((w2) => w2.id === workspaceId);
|
|
23083
23248
|
if (!summary) return null;
|
|
23084
|
-
const
|
|
23249
|
+
const ref2 = (id) => {
|
|
23085
23250
|
const extra = resolveActor?.(id);
|
|
23086
23251
|
return {
|
|
23087
23252
|
id,
|
|
@@ -23090,7 +23255,7 @@ function buildWorkorderDetail(model, workspaceId, resolveActor, resolveProject,
|
|
|
23090
23255
|
...extra?.avatar ? { avatar: extra.avatar } : {}
|
|
23091
23256
|
};
|
|
23092
23257
|
};
|
|
23093
|
-
const runtimeByArtifact = buildRuntimeByArtifact(dispatchJournal,
|
|
23258
|
+
const runtimeByArtifact = buildRuntimeByArtifact(dispatchJournal, ref2);
|
|
23094
23259
|
const nodes = arts.map((a) => {
|
|
23095
23260
|
const info = nodeInfo(model, a);
|
|
23096
23261
|
const observedRuntime = runtimeByArtifact.get(a.id);
|
|
@@ -23105,6 +23270,11 @@ function buildWorkorderDetail(model, workspaceId, resolveActor, resolveProject,
|
|
|
23105
23270
|
...e.upstreamCancelled ? { upstreamCancelled: true } : {}
|
|
23106
23271
|
})) : [];
|
|
23107
23272
|
const pv = reviewerPreview?.(a.id);
|
|
23273
|
+
const stallRaw = stallOf(model, a.id, runtime);
|
|
23274
|
+
const stall = stallRaw ? (() => {
|
|
23275
|
+
const { actorId, ...rest } = stallRaw;
|
|
23276
|
+
return { ...rest, ...actorId ? { actor: ref2(actorId) } : {} };
|
|
23277
|
+
})() : void 0;
|
|
23108
23278
|
return {
|
|
23109
23279
|
id: a.id,
|
|
23110
23280
|
type: a.type,
|
|
@@ -23113,20 +23283,43 @@ function buildWorkorderDetail(model, workspaceId, resolveActor, resolveProject,
|
|
|
23113
23283
|
currentRev: a.currentRev,
|
|
23114
23284
|
queue: info.queueLen,
|
|
23115
23285
|
blocked: blockedOf(model, a.id).blocked,
|
|
23116
|
-
owner:
|
|
23286
|
+
owner: ref2(a.owner),
|
|
23117
23287
|
// 封存原因透出:stage 只到 "sealed" 粒度,原因(accepted/cancelled/frozen)另给,供前端区分展示。
|
|
23118
23288
|
...lifecycle !== "active" ? { sealedReason: lifecycle.slice("sealed:".length) } : {},
|
|
23119
23289
|
...runtime ? { runtime } : {},
|
|
23120
|
-
...pv ? { reviewers: pv.reviewers.map((r) => ({ actor:
|
|
23290
|
+
...pv ? { reviewers: pv.reviewers.map((r) => ({ actor: ref2(r.actor), source: r.source })), quorum: pv.quorum, typeName: pv.typeName } : {},
|
|
23121
23291
|
// 过期事实(提案 rework-cascade-rollout):无条件透出,前端 DAG 挂「上游已更新」徽标。
|
|
23122
|
-
...outdated.length > 0 ? { outdated } : {}
|
|
23292
|
+
...outdated.length > 0 ? { outdated } : {},
|
|
23293
|
+
// 停滞四态(看得清):为什么不动 + 谁欠什么 + 去处理锚;null 时不带。
|
|
23294
|
+
...stall ? { stall } : {}
|
|
23123
23295
|
};
|
|
23124
23296
|
});
|
|
23125
23297
|
const edges = arts.flatMap(
|
|
23126
23298
|
(a) => a.inputs.map((e) => ({ from: a.id, to: e.to, pinned: e.pinned, required: e.required }))
|
|
23127
23299
|
);
|
|
23128
|
-
const
|
|
23129
|
-
|
|
23300
|
+
const stallSummary = (() => {
|
|
23301
|
+
const counts2 = { running: 0, held: 0, failed: 0, waitingHuman: 0, waitingAgent: 0, waitingSystem: 0 };
|
|
23302
|
+
const sev = { failed: 5, held: 4, waiting_human: 3, waiting_agent: 2, waiting_system: 1, running: 0 };
|
|
23303
|
+
const stuck = [];
|
|
23304
|
+
for (const n of nodes) {
|
|
23305
|
+
const st = n.stall;
|
|
23306
|
+
if (!st) continue;
|
|
23307
|
+
if (st.kind === "running") counts2.running++;
|
|
23308
|
+
else if (st.kind === "held") counts2.held++;
|
|
23309
|
+
else if (st.kind === "failed") counts2.failed++;
|
|
23310
|
+
else if (st.kind === "waiting_human") counts2.waitingHuman++;
|
|
23311
|
+
else if (st.kind === "waiting_agent") counts2.waitingAgent++;
|
|
23312
|
+
else counts2.waitingSystem++;
|
|
23313
|
+
if (st.kind !== "running") {
|
|
23314
|
+
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 } : {} });
|
|
23315
|
+
}
|
|
23316
|
+
}
|
|
23317
|
+
stuck.sort((a, b2) => sev[b2.kind] - sev[a.kind]);
|
|
23318
|
+
const total = counts2.running + counts2.held + counts2.failed + counts2.waitingHuman + counts2.waitingAgent + counts2.waitingSystem;
|
|
23319
|
+
return total > 0 ? { counts: counts2, stuck } : void 0;
|
|
23320
|
+
})();
|
|
23321
|
+
const activity = buildActivity(model, arts, ref2);
|
|
23322
|
+
const coordinatorActivity = buildCoordinatorActivity(arts, ops, ref2);
|
|
23130
23323
|
const acceptance = buildAcceptance(model, arts);
|
|
23131
23324
|
const planning = planningStatusOf(model, arts);
|
|
23132
23325
|
const spec = workorderSpecOf(model, arts);
|
|
@@ -23140,11 +23333,12 @@ function buildWorkorderDetail(model, workspaceId, resolveActor, resolveProject,
|
|
|
23140
23333
|
acceptance,
|
|
23141
23334
|
...managerActorId ? { managerActorId } : {},
|
|
23142
23335
|
...spec?.acceptanceCriteria ? { acceptanceCriteria: spec.acceptanceCriteria } : {},
|
|
23336
|
+
...stallSummary ? { stallSummary } : {},
|
|
23143
23337
|
planning
|
|
23144
23338
|
};
|
|
23145
23339
|
}
|
|
23146
23340
|
function buildWorkorderDraftDetail(draft, resolveActor) {
|
|
23147
|
-
const
|
|
23341
|
+
const ref2 = (id) => {
|
|
23148
23342
|
const extra = resolveActor?.(id);
|
|
23149
23343
|
return { id, ...extra?.name ? { name: extra.name } : {}, ...extra?.role ? { role: extra.role } : {}, ...extra?.avatar ? { avatar: extra.avatar } : {} };
|
|
23150
23344
|
};
|
|
@@ -23157,7 +23351,7 @@ function buildWorkorderDraftDetail(draft, resolveActor) {
|
|
|
23157
23351
|
currentRev: null,
|
|
23158
23352
|
queue: 0,
|
|
23159
23353
|
blocked: false,
|
|
23160
|
-
owner:
|
|
23354
|
+
owner: ref2(op.owner ?? draft.draftedBy)
|
|
23161
23355
|
}));
|
|
23162
23356
|
const edges = [
|
|
23163
23357
|
...spawns.flatMap((op) => (op.inputs ?? []).map((inp) => ({ from: op.id, to: inp.to, pinned: null, required: inp.required ?? true }))),
|
|
@@ -23172,8 +23366,8 @@ function buildWorkorderDraftDetail(draft, resolveActor) {
|
|
|
23172
23366
|
...draft.seed.brief && draft.seed.brief !== title ? { description: draft.seed.brief } : {},
|
|
23173
23367
|
...draft.seed.goal ? { goal: draft.seed.goal } : {},
|
|
23174
23368
|
stage: "draft",
|
|
23175
|
-
owner:
|
|
23176
|
-
participants: participantIds.map((id) =>
|
|
23369
|
+
owner: ref2(draft.draftedBy),
|
|
23370
|
+
participants: participantIds.map((id) => ref2(id)),
|
|
23177
23371
|
artifactCount: nodes.length,
|
|
23178
23372
|
progress: { concluded: 0, total: nodes.length },
|
|
23179
23373
|
updatedAt: draft.at,
|
|
@@ -23221,7 +23415,7 @@ function withRuntimeActivity(model, artifactId, runtime) {
|
|
|
23221
23415
|
);
|
|
23222
23416
|
return lastActivityAt ? { ...runtime, lastActivityAt } : runtime;
|
|
23223
23417
|
}
|
|
23224
|
-
function buildRuntimeByArtifact(entries,
|
|
23418
|
+
function buildRuntimeByArtifact(entries, ref2) {
|
|
23225
23419
|
const byJob = /* @__PURE__ */ new Map();
|
|
23226
23420
|
for (const entry of entries) {
|
|
23227
23421
|
if (entry.kind === "dispatched") {
|
|
@@ -23229,7 +23423,7 @@ function buildRuntimeByArtifact(entries, ref) {
|
|
|
23229
23423
|
artifactId: entry.artifactId,
|
|
23230
23424
|
status: "running",
|
|
23231
23425
|
action: entry.action,
|
|
23232
|
-
actor:
|
|
23426
|
+
actor: ref2(entry.actor),
|
|
23233
23427
|
startedAt: entry.at,
|
|
23234
23428
|
at: entry.at
|
|
23235
23429
|
});
|
|
@@ -23239,7 +23433,7 @@ function buildRuntimeByArtifact(entries, ref) {
|
|
|
23239
23433
|
artifactId: entry.artifactId,
|
|
23240
23434
|
status: "running",
|
|
23241
23435
|
action: entry.action,
|
|
23242
|
-
actor:
|
|
23436
|
+
actor: ref2(entry.actor),
|
|
23243
23437
|
startedAt: prev?.startedAt ?? entry.at,
|
|
23244
23438
|
...entry.interruptedAt ? { interruptedAt: entry.interruptedAt } : {},
|
|
23245
23439
|
recoveredAt: entry.recoveredAt,
|
|
@@ -23251,7 +23445,7 @@ function buildRuntimeByArtifact(entries, ref) {
|
|
|
23251
23445
|
artifactId: entry.artifactId,
|
|
23252
23446
|
status: entry.progressed ? "completed" : "failed",
|
|
23253
23447
|
action: entry.action,
|
|
23254
|
-
actor:
|
|
23448
|
+
actor: ref2(entry.actor),
|
|
23255
23449
|
finishedAt: entry.at,
|
|
23256
23450
|
durationMs: entry.durationMs,
|
|
23257
23451
|
...entry.reason ? { reason: entry.reason } : {},
|
|
@@ -23263,7 +23457,7 @@ function buildRuntimeByArtifact(entries, ref) {
|
|
|
23263
23457
|
artifactId: entry.artifactId,
|
|
23264
23458
|
status: "fused",
|
|
23265
23459
|
action: entry.action,
|
|
23266
|
-
actor:
|
|
23460
|
+
actor: ref2(entry.actor),
|
|
23267
23461
|
finishedAt: entry.at,
|
|
23268
23462
|
consecutiveFailures: entry.consecutiveFailures,
|
|
23269
23463
|
at: entry.at
|
|
@@ -23272,7 +23466,7 @@ function buildRuntimeByArtifact(entries, ref) {
|
|
|
23272
23466
|
byJob.set(`escalated::${entry.artifactId}`, {
|
|
23273
23467
|
artifactId: entry.artifactId,
|
|
23274
23468
|
status: "escalated",
|
|
23275
|
-
actor:
|
|
23469
|
+
actor: ref2(entry.to),
|
|
23276
23470
|
finishedAt: entry.at,
|
|
23277
23471
|
reason: entry.reason,
|
|
23278
23472
|
at: entry.at
|
|
@@ -23301,7 +23495,7 @@ function buildRuntimeByArtifact(entries, ref) {
|
|
|
23301
23495
|
function activitySummaryNote(note) {
|
|
23302
23496
|
return note.length <= ACTIVITY_NOTE_MAX_CHARS ? note : `${note.slice(0, ACTIVITY_NOTE_MAX_CHARS)}\u2026\uFF08\u5DF2\u622A\u65AD\uFF0C\u539F\u6587 ${note.length} \u5B57\uFF0C\u5168\u6587\u89C1 oplog\uFF09`;
|
|
23303
23497
|
}
|
|
23304
|
-
function buildActivity(model, arts,
|
|
23498
|
+
function buildActivity(model, arts, ref2) {
|
|
23305
23499
|
const events = [];
|
|
23306
23500
|
for (const a of arts) {
|
|
23307
23501
|
for (const r of revisionsOf(model, a.id)) {
|
|
@@ -23309,7 +23503,7 @@ function buildActivity(model, arts, ref) {
|
|
|
23309
23503
|
events.push({
|
|
23310
23504
|
seq: model.proposeSeq.get(r.id) ?? 0,
|
|
23311
23505
|
at: r.createdAt,
|
|
23312
|
-
actor:
|
|
23506
|
+
actor: ref2(r.author),
|
|
23313
23507
|
kind: "propose",
|
|
23314
23508
|
artifactId: a.id,
|
|
23315
23509
|
revisionId: r.id,
|
|
@@ -23322,7 +23516,7 @@ function buildActivity(model, arts, ref) {
|
|
|
23322
23516
|
events.push({
|
|
23323
23517
|
seq: vote.seq,
|
|
23324
23518
|
at: vote.at,
|
|
23325
|
-
actor:
|
|
23519
|
+
actor: ref2(vote.author),
|
|
23326
23520
|
kind: vote.verdict === "approve" ? "review-approve" : "review-request-changes",
|
|
23327
23521
|
artifactId: a.id,
|
|
23328
23522
|
revisionId: r.id,
|
|
@@ -23334,7 +23528,7 @@ function buildActivity(model, arts, ref) {
|
|
|
23334
23528
|
events.push({
|
|
23335
23529
|
seq: m2.seq,
|
|
23336
23530
|
at: m2.at,
|
|
23337
|
-
actor:
|
|
23531
|
+
actor: ref2(m2.forced?.by ?? a.owner),
|
|
23338
23532
|
kind: "conclude",
|
|
23339
23533
|
artifactId: a.id,
|
|
23340
23534
|
revisionId: m2.head,
|
|
@@ -23345,7 +23539,7 @@ function buildActivity(model, arts, ref) {
|
|
|
23345
23539
|
events.push({
|
|
23346
23540
|
seq: 0,
|
|
23347
23541
|
at: annotation.thread[0]?.ts ?? "",
|
|
23348
|
-
actor:
|
|
23542
|
+
actor: ref2(annotation.author),
|
|
23349
23543
|
kind: "annotate",
|
|
23350
23544
|
artifactId: a.id,
|
|
23351
23545
|
summary: annotation.body.split("\n").find((line) => line.trim() && !line.startsWith("OASIS_PLANNING_ISSUES ")) ?? "\u6279\u6CE8"
|
|
@@ -23354,7 +23548,7 @@ function buildActivity(model, arts, ref) {
|
|
|
23354
23548
|
}
|
|
23355
23549
|
return events.sort((x2, y) => x2.at < y.at ? -1 : x2.at > y.at ? 1 : x2.seq - y.seq);
|
|
23356
23550
|
}
|
|
23357
|
-
function buildCoordinatorActivity(arts, ops,
|
|
23551
|
+
function buildCoordinatorActivity(arts, ops, ref2) {
|
|
23358
23552
|
const inWorkspace = new Set(arts.map((a) => a.id));
|
|
23359
23553
|
const managerRaw = arts.find((a) => a.type === "brief")?.fields?.["manager"];
|
|
23360
23554
|
const managerActor = typeof managerRaw === "string" ? managerRaw : null;
|
|
@@ -23369,11 +23563,11 @@ function buildCoordinatorActivity(arts, ops, ref) {
|
|
|
23369
23563
|
if ((kind === "spawn_artifact" || kind === "link_input") && (!firstRevisionAt || op.timestamp < firstRevisionAt)) {
|
|
23370
23564
|
continue;
|
|
23371
23565
|
}
|
|
23372
|
-
const detail = coordinatorEditDetail(kind, op.payload,
|
|
23566
|
+
const detail = coordinatorEditDetail(kind, op.payload, ref2);
|
|
23373
23567
|
edits.push({
|
|
23374
23568
|
seq: op.seq,
|
|
23375
23569
|
at: op.timestamp,
|
|
23376
|
-
actor:
|
|
23570
|
+
actor: ref2(op.actor),
|
|
23377
23571
|
kind,
|
|
23378
23572
|
artifactId: op.artifactId,
|
|
23379
23573
|
label: COORDINATOR_EDIT_LABEL[kind],
|
|
@@ -23382,7 +23576,7 @@ function buildCoordinatorActivity(arts, ops, ref) {
|
|
|
23382
23576
|
}
|
|
23383
23577
|
return edits.sort((x2, y) => x2.at < y.at ? -1 : x2.at > y.at ? 1 : x2.seq - y.seq);
|
|
23384
23578
|
}
|
|
23385
|
-
function coordinatorEditDetail(kind, payload,
|
|
23579
|
+
function coordinatorEditDetail(kind, payload, ref2) {
|
|
23386
23580
|
const str2 = (v2) => typeof v2 === "string" && v2.trim() ? v2 : void 0;
|
|
23387
23581
|
switch (kind) {
|
|
23388
23582
|
case "link_input":
|
|
@@ -23392,7 +23586,7 @@ function coordinatorEditDetail(kind, payload, ref) {
|
|
|
23392
23586
|
return str2(payload.title) ?? str2(payload.type);
|
|
23393
23587
|
case "assign_owner": {
|
|
23394
23588
|
const owner = str2(payload.owner);
|
|
23395
|
-
return owner ?
|
|
23589
|
+
return owner ? ref2(owner).name ?? owner : void 0;
|
|
23396
23590
|
}
|
|
23397
23591
|
case "bump_pin": {
|
|
23398
23592
|
const to = str2(payload.to);
|
|
@@ -23435,6 +23629,7 @@ var init_workorder_detail = __esm({
|
|
|
23435
23629
|
"use strict";
|
|
23436
23630
|
init_src2();
|
|
23437
23631
|
init_node_state();
|
|
23632
|
+
init_stall();
|
|
23438
23633
|
init_workorders();
|
|
23439
23634
|
ACTIVITY_NOTE_MAX_CHARS = 500;
|
|
23440
23635
|
COORDINATOR_EDIT_KINDS = /* @__PURE__ */ new Set([
|
|
@@ -25177,7 +25372,7 @@ async function startOasisServer(opts) {
|
|
|
25177
25372
|
const chatStore = opts.chatSession;
|
|
25178
25373
|
const ws = review.workspace ?? engine.kernel.model.artifacts.get(review.anchor)?.workspace ?? null;
|
|
25179
25374
|
let target = review.origin ?? discussSessions.get(`draft:${review.draftId}`) ?? void 0;
|
|
25180
|
-
let
|
|
25375
|
+
let record6 = target && chatStore ? await chatStore.getSession(target).catch(() => null) : null;
|
|
25181
25376
|
if (!target && chatStore && ws) {
|
|
25182
25377
|
const brief = [...engine.kernel.model.artifacts.values()].find((x2) => x2.type === "brief" && x2.workspace === ws);
|
|
25183
25378
|
if (brief) {
|
|
@@ -25186,7 +25381,7 @@ async function startOasisServer(opts) {
|
|
|
25186
25381
|
const wos = await chatStore.listWorkOrdersForSession(s2.id).catch(() => []);
|
|
25187
25382
|
if (wos.includes(ws)) {
|
|
25188
25383
|
target = s2.id;
|
|
25189
|
-
|
|
25384
|
+
record6 = s2;
|
|
25190
25385
|
break;
|
|
25191
25386
|
}
|
|
25192
25387
|
}
|
|
@@ -25197,7 +25392,7 @@ async function startOasisServer(opts) {
|
|
|
25197
25392
|
if (chatStore) {
|
|
25198
25393
|
await chatStore.appendMessage({ id: randomUUID18(), sessionId: target, role: "user", content: message, createdAt: (/* @__PURE__ */ new Date()).toISOString() }).catch(() => void 0);
|
|
25199
25394
|
}
|
|
25200
|
-
const rt =
|
|
25395
|
+
const rt = record6?.runtimeSessionId ?? opts.retainedSession?.({ draftId: review.draftId });
|
|
25201
25396
|
const session = await opts.dispatchChat({
|
|
25202
25397
|
actorId: review.proposedBy,
|
|
25203
25398
|
message,
|
|
@@ -25380,9 +25575,9 @@ async function startOasisServer(opts) {
|
|
|
25380
25575
|
if (opts.workorderDrafts) {
|
|
25381
25576
|
let ws = typeof workspace === "string" && workspace.trim() ? workspace.trim() : void 0;
|
|
25382
25577
|
if (!ws) {
|
|
25383
|
-
const
|
|
25384
|
-
if (typeof
|
|
25385
|
-
ws = opts.workorderDrafts.list().find((d) => d.plan.ops.some((o) => o.action === "spawn" && o.id ===
|
|
25578
|
+
const ref2 = op.artifactId;
|
|
25579
|
+
if (typeof ref2 === "string" && ref2.startsWith("artifact:"))
|
|
25580
|
+
ws = opts.workorderDrafts.list().find((d) => d.plan.ops.some((o) => o.action === "spawn" && o.id === ref2))?.workspace;
|
|
25386
25581
|
}
|
|
25387
25582
|
const draft = ws ? opts.workorderDrafts.forWorkspace(ws) : void 0;
|
|
25388
25583
|
if (draft) {
|
|
@@ -26443,14 +26638,14 @@ var init_tokens = __esm({
|
|
|
26443
26638
|
};
|
|
26444
26639
|
isTokenClaims = (value) => {
|
|
26445
26640
|
if (value === null || typeof value !== "object") return false;
|
|
26446
|
-
const
|
|
26447
|
-
if (typeof
|
|
26448
|
-
if (typeof
|
|
26449
|
-
if (
|
|
26450
|
-
if (
|
|
26451
|
-
if (
|
|
26641
|
+
const record6 = value;
|
|
26642
|
+
if (typeof record6["actor"] !== "string" || !record6["actor"].startsWith("actor:")) return false;
|
|
26643
|
+
if (typeof record6["issuedAt"] !== "number" || !Number.isFinite(record6["issuedAt"])) return false;
|
|
26644
|
+
if (record6["expiresAt"] !== void 0 && (typeof record6["expiresAt"] !== "number" || !Number.isFinite(record6["expiresAt"]))) return false;
|
|
26645
|
+
if (record6["dispatchSeq"] !== void 0 && (typeof record6["dispatchSeq"] !== "number" || !Number.isFinite(record6["dispatchSeq"]))) return false;
|
|
26646
|
+
if (record6["scopes"] !== void 0 && (!Array.isArray(record6["scopes"]) || record6["scopes"].some((scope) => typeof scope !== "string"))) return false;
|
|
26452
26647
|
for (const key of ["sessionId", "artifactId", "action", "nodeId", "runtimeKind", "companyId", "chatSessionId"]) {
|
|
26453
|
-
if (
|
|
26648
|
+
if (record6[key] !== void 0 && typeof record6[key] !== "string") return false;
|
|
26454
26649
|
}
|
|
26455
26650
|
return true;
|
|
26456
26651
|
};
|
|
@@ -26795,7 +26990,7 @@ var init_memory_trace_store = __esm({
|
|
|
26795
26990
|
return { items: page.map((r) => this.decorate(structuredClone(r))), nextCursor };
|
|
26796
26991
|
}
|
|
26797
26992
|
async listUsageRuns(filter) {
|
|
26798
|
-
return [...this.runs.values()].filter((run) => run.usage
|
|
26993
|
+
return [...this.runs.values()].filter((run) => run.usage != null && run.startedAt >= filter.from && run.startedAt <= filter.to).map((run) => ({
|
|
26799
26994
|
actorId: run.actorId,
|
|
26800
26995
|
artifactId: run.artifactId,
|
|
26801
26996
|
startedAt: run.startedAt,
|
|
@@ -27044,14 +27239,14 @@ var init_memory_trace_store = __esm({
|
|
|
27044
27239
|
this.usageAggregates.delete(key);
|
|
27045
27240
|
}
|
|
27046
27241
|
}
|
|
27047
|
-
let
|
|
27242
|
+
let count2 = 0;
|
|
27048
27243
|
for (const run of this.runs.values()) {
|
|
27049
27244
|
if (run.usage == null) continue;
|
|
27050
27245
|
if (run.startedAt < from || run.startedAt >= to) continue;
|
|
27051
27246
|
await this.updateUsageAggregates(run);
|
|
27052
|
-
|
|
27247
|
+
count2++;
|
|
27053
27248
|
}
|
|
27054
|
-
return
|
|
27249
|
+
return count2;
|
|
27055
27250
|
}
|
|
27056
27251
|
/** day 滚动:把 hourly 聚合(已存在)按日再汇总——内存版直接从 hourly 行重算 day 行。 */
|
|
27057
27252
|
async rollupHourlyToDaily(day) {
|
|
@@ -27424,6 +27619,19 @@ var init_src3 = __esm({
|
|
|
27424
27619
|
}
|
|
27425
27620
|
});
|
|
27426
27621
|
|
|
27622
|
+
// ../contract/src/chat-session.ts
|
|
27623
|
+
function deriveLastTurnQuality(lastAssistant) {
|
|
27624
|
+
const status = lastAssistant?.status;
|
|
27625
|
+
if (status === void 0 || status === "running") return void 0;
|
|
27626
|
+
if (status === "error") return "abnormal";
|
|
27627
|
+
return lastAssistant && lastAssistant.content.trim().length > 0 ? "clean" : "abnormal";
|
|
27628
|
+
}
|
|
27629
|
+
var init_chat_session = __esm({
|
|
27630
|
+
"../contract/src/chat-session.ts"() {
|
|
27631
|
+
"use strict";
|
|
27632
|
+
}
|
|
27633
|
+
});
|
|
27634
|
+
|
|
27427
27635
|
// ../server/src/domains/projects/projection.ts
|
|
27428
27636
|
function decodeDocumentDescription(description) {
|
|
27429
27637
|
if (description === void 0) return {};
|
|
@@ -27998,6 +28206,7 @@ var DEFAULT_AGENT_ACTOR, MemoryProjectStateStore, MemoryArtifactStateStore, Memo
|
|
|
27998
28206
|
var init_service = __esm({
|
|
27999
28207
|
"../server/src/domains/projects/service.ts"() {
|
|
28000
28208
|
"use strict";
|
|
28209
|
+
init_src();
|
|
28001
28210
|
init_src2();
|
|
28002
28211
|
init_projection();
|
|
28003
28212
|
init_workorders();
|
|
@@ -28661,9 +28870,9 @@ var init_service = __esm({
|
|
|
28661
28870
|
...input.revision.continuation ? { continuation: input.revision.continuation } : {}
|
|
28662
28871
|
});
|
|
28663
28872
|
await this.syncProjection();
|
|
28664
|
-
const
|
|
28665
|
-
if (!
|
|
28666
|
-
return
|
|
28873
|
+
const record6 = await this.artifacts.getRevision(kernelRevision.id);
|
|
28874
|
+
if (!record6) throw new Error(`revision projection missing after register: ${kernelRevision.id}`);
|
|
28875
|
+
return record6;
|
|
28667
28876
|
}
|
|
28668
28877
|
async approveArtifactRevision(input) {
|
|
28669
28878
|
if (input.actorKind !== "human") throw namedError("AgentReviewForbidden", "agents cannot approve artifact revisions");
|
|
@@ -28766,9 +28975,9 @@ var init_service = __esm({
|
|
|
28766
28975
|
...input.revisionId ? { revisionId: input.revisionId } : {}
|
|
28767
28976
|
});
|
|
28768
28977
|
await this.syncProjection();
|
|
28769
|
-
const
|
|
28770
|
-
if (!
|
|
28771
|
-
return
|
|
28978
|
+
const record6 = await this.artifacts.getAnnotation(kernelAnnotation.id);
|
|
28979
|
+
if (!record6) throw new Error(`annotation projection missing after create: ${kernelAnnotation.id}`);
|
|
28980
|
+
return record6;
|
|
28772
28981
|
}
|
|
28773
28982
|
async resolveArtifactAnnotation(input) {
|
|
28774
28983
|
const artifact = await this.artifacts.getArtifact(input.artifactId);
|
|
@@ -28784,11 +28993,16 @@ var init_service = __esm({
|
|
|
28784
28993
|
...input.comment?.trim() ? { note: input.comment.trim() } : {}
|
|
28785
28994
|
});
|
|
28786
28995
|
await this.syncProjection();
|
|
28787
|
-
const
|
|
28788
|
-
if (!
|
|
28789
|
-
return
|
|
28996
|
+
const record6 = await this.artifacts.getAnnotation(input.annotationId);
|
|
28997
|
+
if (!record6) throw new Error(`annotation projection missing after resolve: ${input.annotationId}`);
|
|
28998
|
+
return record6;
|
|
28790
28999
|
}
|
|
28791
29000
|
async registerNodeOutput(input) {
|
|
29001
|
+
const status = input.status ?? "completed";
|
|
29002
|
+
const qualityMetrics = parseWorkorderQualityMetricsPayload(input.payload);
|
|
29003
|
+
if (qualityMetrics && status !== "completed") {
|
|
29004
|
+
throw new Error("invalid qa_quality_metrics payload: quality metrics require status=completed");
|
|
29005
|
+
}
|
|
28792
29006
|
await this.assertProjectExecutable(input.projectId);
|
|
28793
29007
|
if (!input.outputId.trim()) throw new Error("output_id is required");
|
|
28794
29008
|
if (!input.workOrderId.trim()) throw new Error("work_order_id is required");
|
|
@@ -28802,7 +29016,7 @@ var init_service = __esm({
|
|
|
28802
29016
|
workOrderId: input.workOrderId,
|
|
28803
29017
|
nodeId: input.nodeId,
|
|
28804
29018
|
projectId: input.projectId,
|
|
28805
|
-
status
|
|
29019
|
+
status,
|
|
28806
29020
|
documents,
|
|
28807
29021
|
...input.error ? { error: input.error } : {},
|
|
28808
29022
|
payload: { ...input.payload ?? {} },
|
|
@@ -29024,6 +29238,7 @@ var init_dev_store = __esm({
|
|
|
29024
29238
|
path4 = __toESM(require("node:path"), 1);
|
|
29025
29239
|
init_src();
|
|
29026
29240
|
init_src3();
|
|
29241
|
+
init_chat_session();
|
|
29027
29242
|
init_src3();
|
|
29028
29243
|
init_service();
|
|
29029
29244
|
NdjsonOplogStore = class _NdjsonOplogStore {
|
|
@@ -29446,7 +29661,13 @@ var init_dev_store = __esm({
|
|
|
29446
29661
|
this.sessions.set(s2.id, s2);
|
|
29447
29662
|
}
|
|
29448
29663
|
async listSessions(humanActorId) {
|
|
29449
|
-
return [...this.sessions.values()].filter((s2) => s2.humanActorId === humanActorId).sort((a, b2) => b2.touchedAt.localeCompare(a.touchedAt))
|
|
29664
|
+
return [...this.sessions.values()].filter((s2) => s2.humanActorId === humanActorId).sort((a, b2) => b2.touchedAt.localeCompare(a.touchedAt)).map((s2) => {
|
|
29665
|
+
const msgs = this.messages.get(s2.id) ?? [];
|
|
29666
|
+
let lastAssistant;
|
|
29667
|
+
for (const m2 of msgs) if (m2.role === "assistant" && (!lastAssistant || m2.seq > lastAssistant.seq)) lastAssistant = m2;
|
|
29668
|
+
const quality = deriveLastTurnQuality(lastAssistant);
|
|
29669
|
+
return quality ? { ...s2, lastTurnQuality: quality } : s2;
|
|
29670
|
+
});
|
|
29450
29671
|
}
|
|
29451
29672
|
async getSession(id) {
|
|
29452
29673
|
return this.sessions.get(id) ?? null;
|
|
@@ -29463,10 +29684,10 @@ var init_dev_store = __esm({
|
|
|
29463
29684
|
async appendMessage(m2) {
|
|
29464
29685
|
const list = this.messages.get(m2.sessionId) ?? [];
|
|
29465
29686
|
const seq = (list.length ? Math.max(...list.map((x2) => x2.seq)) : 0) + 1;
|
|
29466
|
-
const
|
|
29467
|
-
list.push(
|
|
29687
|
+
const record6 = { ...m2, seq };
|
|
29688
|
+
list.push(record6);
|
|
29468
29689
|
this.messages.set(m2.sessionId, list);
|
|
29469
|
-
return
|
|
29690
|
+
return record6;
|
|
29470
29691
|
}
|
|
29471
29692
|
async updateMessage(id, patch) {
|
|
29472
29693
|
for (const list of this.messages.values()) {
|
|
@@ -29524,9 +29745,9 @@ var init_dev_store = __esm({
|
|
|
29524
29745
|
this.save();
|
|
29525
29746
|
}
|
|
29526
29747
|
async appendMessage(m2) {
|
|
29527
|
-
const
|
|
29748
|
+
const record6 = await super.appendMessage(m2);
|
|
29528
29749
|
this.save();
|
|
29529
|
-
return
|
|
29750
|
+
return record6;
|
|
29530
29751
|
}
|
|
29531
29752
|
async updateMessage(id, patch) {
|
|
29532
29753
|
await super.updateMessage(id, patch);
|
|
@@ -33839,6 +34060,10 @@ var init_daemon_hub = __esm({
|
|
|
33839
34060
|
connectedDaemons() {
|
|
33840
34061
|
return [...this.daemons.values()];
|
|
33841
34062
|
}
|
|
34063
|
+
/** 最近一帧(含 pong 心跳)的时刻(ms)——节点心跳时钟,供节点健康派生判"心跳新鲜"。缺 = 未连接/已清。 */
|
|
34064
|
+
lastSeenAt(daemonId) {
|
|
34065
|
+
return this.lastSeen.get(daemonId);
|
|
34066
|
+
}
|
|
33842
34067
|
/** Nodes that disconnected within the last GHOST_TTL_MS ms. */
|
|
33843
34068
|
recentlyDisconnected() {
|
|
33844
34069
|
const cutoff = Date.now() - _DaemonHub.GHOST_TTL_MS;
|
|
@@ -34213,19 +34438,19 @@ var init_service2 = __esm({
|
|
|
34213
34438
|
async upsertActor(a, by) {
|
|
34214
34439
|
const existing = await this.opts.store.getActor(a.id);
|
|
34215
34440
|
const roles = a.roles ?? existing?.roles ?? [];
|
|
34216
|
-
const
|
|
34217
|
-
if (isActiveCoordinatorAgent(
|
|
34218
|
-
const existingCoordinator = (await this.opts.store.listActors({ kind: "agent", status: "active" })).find((actor) => actor.id !==
|
|
34441
|
+
const record6 = { ...a, roles, createdAt: existing?.createdAt ?? a.createdAt ?? this.now() };
|
|
34442
|
+
if (isActiveCoordinatorAgent(record6)) {
|
|
34443
|
+
const existingCoordinator = (await this.opts.store.listActors({ kind: "agent", status: "active" })).find((actor) => actor.id !== record6.id && isActiveCoordinatorAgent(actor));
|
|
34219
34444
|
if (existingCoordinator) {
|
|
34220
34445
|
throw new Error(
|
|
34221
|
-
`\u7CFB\u7EDF\u53EA\u80FD\u6709\u4E00\u4E2A\u534F\u8C03\u8005\u667A\u80FD\u4F53\uFF1A\u5DF2\u5B58\u5728 ${existingCoordinator.name}\uFF08${existingCoordinator.id}\uFF09\uFF0C\u4E0D\u80FD\u518D\u521B\u5EFA\u6216\u542F\u7528 ${
|
|
34446
|
+
`\u7CFB\u7EDF\u53EA\u80FD\u6709\u4E00\u4E2A\u534F\u8C03\u8005\u667A\u80FD\u4F53\uFF1A\u5DF2\u5B58\u5728 ${existingCoordinator.name}\uFF08${existingCoordinator.id}\uFF09\uFF0C\u4E0D\u80FD\u518D\u521B\u5EFA\u6216\u542F\u7528 ${record6.name}\uFF08${record6.id}\uFF09\u3002`
|
|
34222
34447
|
);
|
|
34223
34448
|
}
|
|
34224
34449
|
}
|
|
34225
|
-
await this.opts.store.upsertActor(
|
|
34226
|
-
this.opts.onRolesChanged?.(
|
|
34450
|
+
await this.opts.store.upsertActor(record6);
|
|
34451
|
+
this.opts.onRolesChanged?.(record6.id, record6.status === "active" ? roles : []);
|
|
34227
34452
|
await this.audit({ kind: "actor_upsert", actorId: a.id, by, at: this.now(), detail: { status: a.status, roles } });
|
|
34228
|
-
return
|
|
34453
|
+
return record6;
|
|
34229
34454
|
}
|
|
34230
34455
|
/** 删除即停用(2.1 完成标准) */
|
|
34231
34456
|
async disableActor(id, by) {
|
|
@@ -34237,21 +34462,21 @@ var init_service2 = __esm({
|
|
|
34237
34462
|
return this.opts.store.getActor(id);
|
|
34238
34463
|
}
|
|
34239
34464
|
/** 设置/清除头像引用("blob:<哈希>";null = 回到默认生成的插画头像) */
|
|
34240
|
-
async setActorAvatar(id,
|
|
34465
|
+
async setActorAvatar(id, ref2, by) {
|
|
34241
34466
|
const a = await this.opts.store.getActor(id);
|
|
34242
34467
|
if (!a) throw new Error(`actor not found: ${id}`);
|
|
34243
34468
|
const { avatar: _drop, ...rest } = a;
|
|
34244
|
-
const
|
|
34245
|
-
await this.opts.store.upsertActor(
|
|
34246
|
-
await this.audit({ kind: "actor_upsert", actorId: id, by, at: this.now(), detail: { avatar:
|
|
34247
|
-
return
|
|
34469
|
+
const record6 = ref2 === null ? rest : { ...rest, avatar: ref2 };
|
|
34470
|
+
await this.opts.store.upsertActor(record6);
|
|
34471
|
+
await this.audit({ kind: "actor_upsert", actorId: id, by, at: this.now(), detail: { avatar: ref2 ?? "cleared" } });
|
|
34472
|
+
return record6;
|
|
34248
34473
|
}
|
|
34249
34474
|
/** 设置/清除团队图标引用(同头像约定;不接受 emoji,只接受 blob 引用) */
|
|
34250
|
-
async setTeamIcon(teamId,
|
|
34475
|
+
async setTeamIcon(teamId, ref2) {
|
|
34251
34476
|
const t = (await this.opts.store.listTeams()).find((x2) => x2.id === teamId);
|
|
34252
34477
|
if (!t) throw new Error(`team not found: ${teamId}`);
|
|
34253
34478
|
const { icon: _drop, ...rest } = t;
|
|
34254
|
-
await this.opts.store.upsertTeam(
|
|
34479
|
+
await this.opts.store.upsertTeam(ref2 === null ? rest : { ...rest, icon: ref2 });
|
|
34255
34480
|
}
|
|
34256
34481
|
listActors(filter) {
|
|
34257
34482
|
return this.opts.store.listActors(filter);
|
|
@@ -34657,13 +34882,13 @@ ${input.description}
|
|
|
34657
34882
|
this.opts.store.listConnectors()
|
|
34658
34883
|
]);
|
|
34659
34884
|
const globalConnected = new Set(connectors.filter((c) => c.status === "connected").map((c) => c.id));
|
|
34660
|
-
const
|
|
34885
|
+
const record6 = new Map(connections.map((c) => [c.connectorId, c.enabled]));
|
|
34661
34886
|
const legacy = new Set(config2?.connectorIds ?? []);
|
|
34662
|
-
const ids = /* @__PURE__ */ new Set([...
|
|
34887
|
+
const ids = /* @__PURE__ */ new Set([...record6.keys(), ...legacy, ...globalConnected]);
|
|
34663
34888
|
const effective = /* @__PURE__ */ new Set();
|
|
34664
34889
|
for (const id of ids) {
|
|
34665
|
-
if (
|
|
34666
|
-
if (
|
|
34890
|
+
if (record6.has(id)) {
|
|
34891
|
+
if (record6.get(id)) effective.add(id);
|
|
34667
34892
|
} else if (legacy.has(id)) effective.add(id);
|
|
34668
34893
|
else if (globalConnected.has(id)) effective.add(id);
|
|
34669
34894
|
}
|
|
@@ -35528,6 +35753,7 @@ function actorsDomain(opts) {
|
|
|
35528
35753
|
status: "active",
|
|
35529
35754
|
...b2.email !== void 0 ? { email: b2.email } : {},
|
|
35530
35755
|
...b2.teamId !== void 0 ? { teamId: b2.teamId } : {},
|
|
35756
|
+
...b2.reportsTo ? { reportsTo: b2.reportsTo } : {},
|
|
35531
35757
|
...avatar !== void 0 ? { avatar } : {},
|
|
35532
35758
|
...positions !== void 0 ? { roles: positions } : {}
|
|
35533
35759
|
},
|
|
@@ -35542,10 +35768,12 @@ function actorsDomain(opts) {
|
|
|
35542
35768
|
const b2 = req.body ?? {};
|
|
35543
35769
|
const positions = positionsFromPayload(b2);
|
|
35544
35770
|
const avatar = avatarRefFromPayload(b2);
|
|
35545
|
-
const { positions: _positions, id: _id, kind: _kind, avatar: _avatar, ...patch } = b2;
|
|
35771
|
+
const { positions: _positions, id: _id, kind: _kind, avatar: _avatar, reportsTo: _reportsTo, ...patch } = b2;
|
|
35546
35772
|
const actor = await service.upsertActor({
|
|
35547
35773
|
...existing,
|
|
35548
35774
|
...patch,
|
|
35775
|
+
// 汇报人:显式给(含清空)——传空串/null 归一为 undefined(写库落 null);未传则保留原值
|
|
35776
|
+
...b2.reportsTo !== void 0 ? { reportsTo: b2.reportsTo || void 0 } : {},
|
|
35549
35777
|
...avatar !== void 0 ? { avatar } : {},
|
|
35550
35778
|
...positions !== void 0 ? { roles: positions } : {},
|
|
35551
35779
|
id: existing.id,
|
|
@@ -35561,8 +35789,8 @@ function actorsDomain(opts) {
|
|
|
35561
35789
|
router.post("/api/actors/:id/avatar", async (req) => {
|
|
35562
35790
|
const { service, blobs } = await resolveCtx(req.auth.companyId);
|
|
35563
35791
|
if (!blobs) throw new ApiError(501, "NOT_IMPLEMENTED", "blob \u5B58\u50A8\u672A\u63A5\u5165");
|
|
35564
|
-
const
|
|
35565
|
-
const actor = await service.setActorAvatar(req.params.id,
|
|
35792
|
+
const ref2 = await storeImageBlob(blobs, req.body?.data);
|
|
35793
|
+
const actor = await service.setActorAvatar(req.params.id, ref2, req.auth.actor);
|
|
35566
35794
|
return { status: 201, body: { avatar: actor.avatar } };
|
|
35567
35795
|
});
|
|
35568
35796
|
router.delete("/api/actors/:id/avatar", async (req) => {
|
|
@@ -35573,9 +35801,9 @@ function actorsDomain(opts) {
|
|
|
35573
35801
|
router.post("/api/teams/:id/icon", async (req) => {
|
|
35574
35802
|
const { service, blobs } = await resolveCtx(req.auth.companyId);
|
|
35575
35803
|
if (!blobs) throw new ApiError(501, "NOT_IMPLEMENTED", "blob \u5B58\u50A8\u672A\u63A5\u5165");
|
|
35576
|
-
const
|
|
35577
|
-
await service.setTeamIcon(req.params.id,
|
|
35578
|
-
return { status: 201, body: { icon:
|
|
35804
|
+
const ref2 = await storeImageBlob(blobs, req.body?.data);
|
|
35805
|
+
await service.setTeamIcon(req.params.id, ref2);
|
|
35806
|
+
return { status: 201, body: { icon: ref2 } };
|
|
35579
35807
|
});
|
|
35580
35808
|
router.delete("/api/teams/:id/icon", async (req) => {
|
|
35581
35809
|
const { service } = await resolveCtx(req.auth.companyId);
|
|
@@ -36380,12 +36608,12 @@ function parseAcceptanceCriteria(body) {
|
|
|
36380
36608
|
}
|
|
36381
36609
|
function parseReviewActor(req) {
|
|
36382
36610
|
const actor = String(req.auth.actor);
|
|
36383
|
-
const
|
|
36611
|
+
const shortId2 = actor.split(":").slice(2).join(":") || actor;
|
|
36384
36612
|
const b2 = req.body ?? {};
|
|
36385
36613
|
return {
|
|
36386
36614
|
actorKind: actor.includes(":agent:") ? "agent" : "human",
|
|
36387
36615
|
actorId: actor,
|
|
36388
|
-
...b2.actor_name !== void 0 || b2.actorName !== void 0 ? { actorName: b2.actor_name ?? b2.actorName } : { actorName:
|
|
36616
|
+
...b2.actor_name !== void 0 || b2.actorName !== void 0 ? { actorName: b2.actor_name ?? b2.actorName } : { actorName: shortId2 }
|
|
36389
36617
|
};
|
|
36390
36618
|
}
|
|
36391
36619
|
function parseAnnotationActor(req) {
|
|
@@ -36429,6 +36657,9 @@ function parseResolveArtifactAnnotation(req) {
|
|
|
36429
36657
|
};
|
|
36430
36658
|
}
|
|
36431
36659
|
function mapProjectError(err) {
|
|
36660
|
+
if (err instanceof Error && err.message.startsWith("invalid qa_quality_metrics payload:")) {
|
|
36661
|
+
return new ApiError(400, "INVALID_QA_QUALITY_METRICS", err.message);
|
|
36662
|
+
}
|
|
36432
36663
|
if (err instanceof Error && err.name === "ProjectDocumentSystemNotReady") {
|
|
36433
36664
|
return new ApiError(409, "PROJECT_DOCUMENT_SYSTEM_NOT_READY", err.message);
|
|
36434
36665
|
}
|
|
@@ -36873,10 +37104,10 @@ var init_service3 = __esm({
|
|
|
36873
37104
|
return this.store.getCompany(id);
|
|
36874
37105
|
}
|
|
36875
37106
|
/** 设置/清除公司头像引用("blob:<哈希>";null = 回到默认首字母标识)。 */
|
|
36876
|
-
async setAvatar(id,
|
|
37107
|
+
async setAvatar(id, ref2) {
|
|
36877
37108
|
const company = await this.requireCompany(id);
|
|
36878
|
-
await this.store.updateCompany(id, { avatar:
|
|
36879
|
-
const next =
|
|
37109
|
+
await this.store.updateCompany(id, { avatar: ref2 });
|
|
37110
|
+
const next = ref2 === null ? (({ avatar: _drop, ...rest }) => rest)(company) : { ...company, avatar: ref2 };
|
|
36880
37111
|
return next;
|
|
36881
37112
|
}
|
|
36882
37113
|
/**
|
|
@@ -37114,8 +37345,8 @@ function companiesDomain(opts) {
|
|
|
37114
37345
|
});
|
|
37115
37346
|
router.post("/api/companies/:id/avatar", async (req) => {
|
|
37116
37347
|
if (!blobs) throw new ApiError(501, "NOT_IMPLEMENTED", "blob \u5B58\u50A8\u672A\u63A5\u5165");
|
|
37117
|
-
const
|
|
37118
|
-
const company = await service.setAvatar(req.params.id,
|
|
37348
|
+
const ref2 = await storeImageBlob(blobs, req.body?.data);
|
|
37349
|
+
const company = await service.setAvatar(req.params.id, ref2).catch(mapErr);
|
|
37119
37350
|
return { status: 201, body: { avatar: company.avatar } };
|
|
37120
37351
|
});
|
|
37121
37352
|
router.delete("/api/companies/:id/avatar", async (req) => {
|
|
@@ -38912,13 +39143,13 @@ function scanCodexTelemetry(workdir, sinceMs, sessionsRoot = codexSessionsRoot()
|
|
|
38912
39143
|
function createCodexNormalizeState() {
|
|
38913
39144
|
return { toolUseIds: /* @__PURE__ */ new Set(), previousAgentMessage: false, lastAgentMessageEndedWithNewline: false };
|
|
38914
39145
|
}
|
|
38915
|
-
function
|
|
39146
|
+
function record3(value) {
|
|
38916
39147
|
return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
38917
39148
|
}
|
|
38918
39149
|
function textOf3(value) {
|
|
38919
39150
|
if (typeof value === "string") return value;
|
|
38920
39151
|
if (Array.isArray(value)) return value.map(textOf3).filter(Boolean).join("\n");
|
|
38921
|
-
const obj =
|
|
39152
|
+
const obj = record3(value);
|
|
38922
39153
|
if (!obj) return void 0;
|
|
38923
39154
|
if (typeof obj.text === "string") return obj.text;
|
|
38924
39155
|
if (typeof obj.content === "string") return obj.content;
|
|
@@ -38982,7 +39213,7 @@ ${text}` : text;
|
|
|
38982
39213
|
resetAgentMessageBoundary(state);
|
|
38983
39214
|
const id = item.id;
|
|
38984
39215
|
const name = typeof item.name === "string" ? item.name : "mcp_tool_call";
|
|
38985
|
-
const input =
|
|
39216
|
+
const input = record3(item.arguments) ?? record3(item.input) ?? {};
|
|
38986
39217
|
const events = toolUseOnce(state, id, name, input);
|
|
38987
39218
|
if (phase === "completed" || phase === "direct") {
|
|
38988
39219
|
events.push({
|
|
@@ -39027,7 +39258,7 @@ function normalizeCodexStreamLine(line, state = createCodexNormalizeState()) {
|
|
|
39027
39258
|
} catch {
|
|
39028
39259
|
return line ? [{ kind: "message", payload: { text: line }, outputText: line }] : [];
|
|
39029
39260
|
}
|
|
39030
|
-
const item =
|
|
39261
|
+
const item = record3(obj.item);
|
|
39031
39262
|
if (obj.type === "item.started" && item) return normalizeCodexItem(item, "started", state);
|
|
39032
39263
|
if (obj.type === "item.completed" && item) return normalizeCodexItem(item, "completed", state);
|
|
39033
39264
|
if (typeof obj.type === "string") return normalizeCodexItem(obj, "direct", state);
|
|
@@ -39286,7 +39517,7 @@ function addToken(acc, value, field) {
|
|
|
39286
39517
|
acc[field] += value;
|
|
39287
39518
|
}
|
|
39288
39519
|
}
|
|
39289
|
-
function
|
|
39520
|
+
function record4(value) {
|
|
39290
39521
|
return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
39291
39522
|
}
|
|
39292
39523
|
function firstNumber(src, keys) {
|
|
@@ -39348,23 +39579,23 @@ function accumulateTokenFields(acc, src) {
|
|
|
39348
39579
|
"cache_write_tokens",
|
|
39349
39580
|
"cacheWriteTokens"
|
|
39350
39581
|
], "cacheCreationTokens") || changed;
|
|
39351
|
-
const promptDetails =
|
|
39582
|
+
const promptDetails = record4(src["prompt_tokens_details"]) ?? record4(src["promptTokensDetails"]);
|
|
39352
39583
|
if (promptDetails) {
|
|
39353
39584
|
changed = addFirstToken(acc, promptDetails, ["cached_tokens", "cachedTokens"], "cacheReadTokens") || changed;
|
|
39354
39585
|
}
|
|
39355
39586
|
return changed;
|
|
39356
39587
|
}
|
|
39357
39588
|
function accumulateUsage(acc, value) {
|
|
39358
|
-
const root =
|
|
39589
|
+
const root = record4(value);
|
|
39359
39590
|
if (!root) return false;
|
|
39360
39591
|
const candidates = [
|
|
39361
39592
|
root,
|
|
39362
|
-
|
|
39363
|
-
|
|
39364
|
-
|
|
39365
|
-
|
|
39366
|
-
|
|
39367
|
-
|
|
39593
|
+
record4(root["usage"]),
|
|
39594
|
+
record4(root["token_usage"]),
|
|
39595
|
+
record4(root["tokenUsage"]),
|
|
39596
|
+
record4(root["tokens"]),
|
|
39597
|
+
record4(root["usageMetadata"]),
|
|
39598
|
+
record4(root["usage_metadata"])
|
|
39368
39599
|
];
|
|
39369
39600
|
const seen = /* @__PURE__ */ new Set();
|
|
39370
39601
|
let changed = false;
|
|
@@ -39556,7 +39787,7 @@ var init_pricing = __esm({
|
|
|
39556
39787
|
});
|
|
39557
39788
|
|
|
39558
39789
|
// ../adapters/src/_core/acp.ts
|
|
39559
|
-
function
|
|
39790
|
+
function record5(value) {
|
|
39560
39791
|
return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
39561
39792
|
}
|
|
39562
39793
|
function firstString(...values) {
|
|
@@ -39571,11 +39802,11 @@ function textFromUnknown(value) {
|
|
|
39571
39802
|
const parts = value.map(textFromUnknown).filter((x2) => Boolean(x2));
|
|
39572
39803
|
return parts.length ? parts.join("") : void 0;
|
|
39573
39804
|
}
|
|
39574
|
-
const obj =
|
|
39805
|
+
const obj = record5(value);
|
|
39575
39806
|
if (!obj) return void 0;
|
|
39576
|
-
const direct = firstString(obj["text"], obj["delta"], obj["message"],
|
|
39807
|
+
const direct = firstString(obj["text"], obj["delta"], obj["message"], record5(obj["error"])?.["message"]);
|
|
39577
39808
|
if (direct) return direct;
|
|
39578
|
-
return textFromUnknown(obj["content"]) ?? textFromUnknown(
|
|
39809
|
+
return textFromUnknown(obj["content"]) ?? textFromUnknown(record5(obj["result"])?.["content"]) ?? textFromUnknown(obj["result"]);
|
|
39579
39810
|
}
|
|
39580
39811
|
function jsonLike(value) {
|
|
39581
39812
|
if (typeof value !== "string") return value;
|
|
@@ -39590,15 +39821,15 @@ function jsonLike(value) {
|
|
|
39590
39821
|
return { text: value };
|
|
39591
39822
|
}
|
|
39592
39823
|
function toolPayload(data) {
|
|
39593
|
-
const d =
|
|
39594
|
-
const nested =
|
|
39824
|
+
const d = record5(data) ?? {};
|
|
39825
|
+
const nested = record5(d["toolCall"]) ?? record5(d["tool_call"]) ?? record5(d["call"]) ?? record5(d["tool"]) ?? record5(d["data"]) ?? {};
|
|
39595
39826
|
return { ...nested, ...d };
|
|
39596
39827
|
}
|
|
39597
39828
|
function toolCallIdOf(d) {
|
|
39598
39829
|
return firstString(d["toolCallId"], d["tool_call_id"], d["callId"], d["call_id"], d["id"]);
|
|
39599
39830
|
}
|
|
39600
39831
|
function toolNameOf(d) {
|
|
39601
|
-
return firstString(d["name"], d["toolName"], d["tool_name"],
|
|
39832
|
+
return firstString(d["name"], d["toolName"], d["tool_name"], record5(d["tool"])?.["name"]) ?? toolNameFromTitle(firstString(d["title"]) ?? "", firstString(d["kind"]) ?? "");
|
|
39602
39833
|
}
|
|
39603
39834
|
function inputFromTitle(title, toolName) {
|
|
39604
39835
|
const colon = title.indexOf(":");
|
|
@@ -39640,7 +39871,7 @@ function argsTextOf(d) {
|
|
|
39640
39871
|
return typeof value === "string" ? value : void 0;
|
|
39641
39872
|
}
|
|
39642
39873
|
function toolOutputOf(d) {
|
|
39643
|
-
const error2 =
|
|
39874
|
+
const error2 = record5(d["error"]);
|
|
39644
39875
|
if (error2) return error2["message"] ?? error2;
|
|
39645
39876
|
const raw = d["rawOutput"] ?? d["raw_output"] ?? d["output"] ?? d["result"] ?? d["results"] ?? d["response"] ?? d["data"] ?? d["content"];
|
|
39646
39877
|
const stream = compactRecord({
|
|
@@ -39678,7 +39909,7 @@ function parseJsonString(value) {
|
|
|
39678
39909
|
function locationsOf(d) {
|
|
39679
39910
|
const locations = d["locations"];
|
|
39680
39911
|
if (!Array.isArray(locations)) return void 0;
|
|
39681
|
-
const out = locations.filter((item) => Boolean(
|
|
39912
|
+
const out = locations.filter((item) => Boolean(record5(item)));
|
|
39682
39913
|
return out.length ? out : void 0;
|
|
39683
39914
|
}
|
|
39684
39915
|
function statusOf(d) {
|
|
@@ -39783,8 +40014,8 @@ function extractSessionID(result) {
|
|
|
39783
40014
|
return result?.sessionId ?? "";
|
|
39784
40015
|
}
|
|
39785
40016
|
function extractCurrentModelID(result) {
|
|
39786
|
-
const r =
|
|
39787
|
-
const models =
|
|
40017
|
+
const r = record5(result);
|
|
40018
|
+
const models = record5(r?.["models"]);
|
|
39788
40019
|
return firstString(
|
|
39789
40020
|
models?.["currentModelId"],
|
|
39790
40021
|
models?.["current_model_id"],
|
|
@@ -40242,11 +40473,11 @@ var init_acp = __esm({
|
|
|
40242
40473
|
this.flushTextBuffer("message");
|
|
40243
40474
|
}
|
|
40244
40475
|
handleAgentMessage(data) {
|
|
40245
|
-
const text = textFromUnknown(
|
|
40476
|
+
const text = textFromUnknown(record5(data)?.["content"] ?? data);
|
|
40246
40477
|
if (text) this.appendText("message", text);
|
|
40247
40478
|
}
|
|
40248
40479
|
handleAgentThought(data) {
|
|
40249
|
-
const text = textFromUnknown(
|
|
40480
|
+
const text = textFromUnknown(record5(data)?.["content"] ?? data);
|
|
40250
40481
|
if (text) this.appendText("thought", text);
|
|
40251
40482
|
}
|
|
40252
40483
|
handleToolCallStart(data) {
|
|
@@ -41403,6 +41634,63 @@ var init_connect_script = __esm({
|
|
|
41403
41634
|
}
|
|
41404
41635
|
});
|
|
41405
41636
|
|
|
41637
|
+
// ../server/src/node-health.ts
|
|
41638
|
+
function deriveNodeHealth(input) {
|
|
41639
|
+
const staleMs = input.staleMs ?? 9e4;
|
|
41640
|
+
const maxFail = input.maxConsecutiveFailures ?? 3;
|
|
41641
|
+
const cf = input.snapshot?.consecutiveFailures ?? 0;
|
|
41642
|
+
const heartbeatFresh = input.lastHeartbeatMs !== void 0 && input.now - input.lastHeartbeatMs < staleMs;
|
|
41643
|
+
const healthy = input.online && heartbeatFresh && cf < maxFail;
|
|
41644
|
+
return {
|
|
41645
|
+
healthy,
|
|
41646
|
+
online: input.online,
|
|
41647
|
+
...input.lastHeartbeatMs !== void 0 ? { lastHeartbeatAt: new Date(input.lastHeartbeatMs).toISOString() } : {},
|
|
41648
|
+
activeRunCount: input.activeRunCount,
|
|
41649
|
+
consecutiveFailures: cf,
|
|
41650
|
+
...input.snapshot?.lastSuccessfulDispatchAt ? { lastSuccessfulDispatchAt: input.snapshot.lastSuccessfulDispatchAt } : {},
|
|
41651
|
+
...input.snapshot?.lastFailureAt ? { lastFailureAt: input.snapshot.lastFailureAt } : {},
|
|
41652
|
+
...input.snapshot?.lastFailureReason ? { lastFailureReason: input.snapshot.lastFailureReason } : {}
|
|
41653
|
+
};
|
|
41654
|
+
}
|
|
41655
|
+
var NodeHealthTracker;
|
|
41656
|
+
var init_node_health = __esm({
|
|
41657
|
+
"../server/src/node-health.ts"() {
|
|
41658
|
+
"use strict";
|
|
41659
|
+
NodeHealthTracker = class {
|
|
41660
|
+
byNode = /* @__PURE__ */ new Map();
|
|
41661
|
+
ensure(nodeId) {
|
|
41662
|
+
let s2 = this.byNode.get(nodeId);
|
|
41663
|
+
if (!s2) {
|
|
41664
|
+
s2 = { consecutiveFailures: 0 };
|
|
41665
|
+
this.byNode.set(nodeId, s2);
|
|
41666
|
+
}
|
|
41667
|
+
return s2;
|
|
41668
|
+
}
|
|
41669
|
+
/** 节点交付了一次会话(可达):清零连败、记成功时刻。 */
|
|
41670
|
+
recordReachable(nodeId, nowIso = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
41671
|
+
const s2 = this.ensure(nodeId);
|
|
41672
|
+
s2.consecutiveFailures = 0;
|
|
41673
|
+
s2.lastSuccessfulDispatchAt = nowIso;
|
|
41674
|
+
}
|
|
41675
|
+
/** 节点级失败(server-unreachable/失联/派发丢失):连败 +1、记失败时刻与归因。 */
|
|
41676
|
+
recordUnreachable(nodeId, reason, nowIso = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
41677
|
+
const s2 = this.ensure(nodeId);
|
|
41678
|
+
s2.consecutiveFailures += 1;
|
|
41679
|
+
s2.lastFailureAt = nowIso;
|
|
41680
|
+
if (reason !== void 0) s2.lastFailureReason = reason;
|
|
41681
|
+
}
|
|
41682
|
+
snapshot(nodeId) {
|
|
41683
|
+
const s2 = this.byNode.get(nodeId);
|
|
41684
|
+
return s2 ? { ...s2 } : void 0;
|
|
41685
|
+
}
|
|
41686
|
+
/** 节点被删除/换机时清账(可选调用)。 */
|
|
41687
|
+
forget(nodeId) {
|
|
41688
|
+
this.byNode.delete(nodeId);
|
|
41689
|
+
}
|
|
41690
|
+
};
|
|
41691
|
+
}
|
|
41692
|
+
});
|
|
41693
|
+
|
|
41406
41694
|
// ../server/src/domains/nodes/routes.ts
|
|
41407
41695
|
function nodesDomain(deps) {
|
|
41408
41696
|
let hubWired = false;
|
|
@@ -41486,6 +41774,8 @@ function nodesDomain(deps) {
|
|
|
41486
41774
|
}
|
|
41487
41775
|
const daemonVersionById = new Map((hub?.connectedDaemons() ?? []).map((d) => [d.daemonId, d.meta.daemonVersion]));
|
|
41488
41776
|
const connectionById = new Map((hub?.recentConnectionChanges() ?? []).map((d) => [d.daemonId, d]));
|
|
41777
|
+
const onlineIds = new Set((hub?.connectedDaemons() ?? []).map((d) => d.daemonId));
|
|
41778
|
+
const healthNow = Date.now();
|
|
41489
41779
|
const nodes = await deps.nodeStore.listNodes();
|
|
41490
41780
|
const items = await Promise.all(nodes.map(async (n) => {
|
|
41491
41781
|
const rts = await deps.nodeStore.listRuntimes(n.id);
|
|
@@ -41514,6 +41804,15 @@ function nodesDomain(deps) {
|
|
|
41514
41804
|
...connection.lastDisconnectedAt ? { lastDisconnectedAt: new Date(connection.lastDisconnectedAt).toISOString() } : {},
|
|
41515
41805
|
...connection.lastReconnectedAt ? { lastReconnectedAt: new Date(connection.lastReconnectedAt).toISOString() } : {}
|
|
41516
41806
|
}
|
|
41807
|
+
} : {},
|
|
41808
|
+
...deps.nodeHealth ? {
|
|
41809
|
+
health: deriveNodeHealth({
|
|
41810
|
+
online: onlineIds.has(n.id),
|
|
41811
|
+
...hub?.lastSeenAt(n.id) !== void 0 ? { lastHeartbeatMs: hub.lastSeenAt(n.id) } : {},
|
|
41812
|
+
activeRunCount: deps.activeRunCountOf?.(n.id) ?? 0,
|
|
41813
|
+
...deps.nodeHealth.snapshot(n.id) ? { snapshot: deps.nodeHealth.snapshot(n.id) } : {},
|
|
41814
|
+
now: healthNow
|
|
41815
|
+
})
|
|
41517
41816
|
} : {}
|
|
41518
41817
|
};
|
|
41519
41818
|
}));
|
|
@@ -41712,6 +42011,7 @@ var init_routes4 = __esm({
|
|
|
41712
42011
|
import_node_path2 = require("node:path");
|
|
41713
42012
|
init_src4();
|
|
41714
42013
|
init_connect_script();
|
|
42014
|
+
init_node_health();
|
|
41715
42015
|
}
|
|
41716
42016
|
});
|
|
41717
42017
|
|
|
@@ -42220,6 +42520,207 @@ var init_dashboard = __esm({
|
|
|
42220
42520
|
}
|
|
42221
42521
|
});
|
|
42222
42522
|
|
|
42523
|
+
// ../server/src/domains/collab/workorder-metrics.ts
|
|
42524
|
+
function rate(passed, total, source) {
|
|
42525
|
+
return { passed, total, rate: total > 0 ? passed / total : null, source };
|
|
42526
|
+
}
|
|
42527
|
+
function ref(actorId, resolveActor) {
|
|
42528
|
+
const extra = resolveActor?.(actorId);
|
|
42529
|
+
return {
|
|
42530
|
+
id: actorId,
|
|
42531
|
+
...extra?.name ? { name: extra.name } : {},
|
|
42532
|
+
...extra?.role ? { role: extra.role } : {},
|
|
42533
|
+
...extra?.avatar ? { avatar: extra.avatar } : {}
|
|
42534
|
+
};
|
|
42535
|
+
}
|
|
42536
|
+
function firstReviewPassRate(model, artifactIds) {
|
|
42537
|
+
let passed = 0;
|
|
42538
|
+
let total = 0;
|
|
42539
|
+
for (const artifactId of artifactIds) {
|
|
42540
|
+
const first = (model.concludeAttempts.get(artifactId) ?? []).find((attempt) => attempt.gate !== null);
|
|
42541
|
+
if (!first) continue;
|
|
42542
|
+
total += 1;
|
|
42543
|
+
if (attemptStatus(model, first) === "satisfied") passed += 1;
|
|
42544
|
+
}
|
|
42545
|
+
return rate(passed, total, "oplog");
|
|
42546
|
+
}
|
|
42547
|
+
function qualitySnapshot(outputs) {
|
|
42548
|
+
const completed = outputs.filter((output) => output.status === "completed").sort((a, b2) => b2.updatedAt.localeCompare(a.updatedAt) || b2.outputId.localeCompare(a.outputId));
|
|
42549
|
+
for (const output of completed) {
|
|
42550
|
+
try {
|
|
42551
|
+
const payload = parseWorkorderQualityMetricsPayload(output.payload);
|
|
42552
|
+
if (!payload) continue;
|
|
42553
|
+
return {
|
|
42554
|
+
source: "qa",
|
|
42555
|
+
schemaVersion: 1,
|
|
42556
|
+
suiteRunId: payload.suiteRunId,
|
|
42557
|
+
...payload.checklistRef ? { checklistRef: payload.checklistRef } : {},
|
|
42558
|
+
reportedAt: output.updatedAt,
|
|
42559
|
+
functionalCoverage: rate(payload.functionalCoverage.passed, payload.functionalCoverage.total, "qa"),
|
|
42560
|
+
p0Tests: {
|
|
42561
|
+
...rate(payload.p0Tests.passed, payload.p0Tests.total, "qa"),
|
|
42562
|
+
failed: payload.p0Tests.failed,
|
|
42563
|
+
blocked: payload.p0Tests.blocked
|
|
42564
|
+
},
|
|
42565
|
+
p1Tests: {
|
|
42566
|
+
...rate(payload.p1Tests.passed, payload.p1Tests.total, "qa"),
|
|
42567
|
+
failed: payload.p1Tests.failed,
|
|
42568
|
+
blocked: payload.p1Tests.blocked
|
|
42569
|
+
}
|
|
42570
|
+
};
|
|
42571
|
+
} catch {
|
|
42572
|
+
}
|
|
42573
|
+
}
|
|
42574
|
+
return null;
|
|
42575
|
+
}
|
|
42576
|
+
function earliestIso(values) {
|
|
42577
|
+
let earliest = null;
|
|
42578
|
+
for (const raw of values) {
|
|
42579
|
+
if (!raw) continue;
|
|
42580
|
+
const time3 = Date.parse(raw);
|
|
42581
|
+
if (!Number.isFinite(time3)) continue;
|
|
42582
|
+
if (!earliest || time3 < earliest.time) earliest = { raw, time: time3 };
|
|
42583
|
+
}
|
|
42584
|
+
return earliest?.raw ?? null;
|
|
42585
|
+
}
|
|
42586
|
+
function latestIso(values) {
|
|
42587
|
+
let latest = null;
|
|
42588
|
+
for (const raw of values) {
|
|
42589
|
+
if (!raw) continue;
|
|
42590
|
+
const time3 = Date.parse(raw);
|
|
42591
|
+
if (!Number.isFinite(time3)) continue;
|
|
42592
|
+
if (!latest || time3 > latest.time) latest = { raw, time: time3 };
|
|
42593
|
+
}
|
|
42594
|
+
return latest?.raw ?? null;
|
|
42595
|
+
}
|
|
42596
|
+
function journalIdentity(entry) {
|
|
42597
|
+
return entry.sessionId ?? entry.dispatchId;
|
|
42598
|
+
}
|
|
42599
|
+
function executionMetrics(journal, artifactIds, resolveActor, nowMs) {
|
|
42600
|
+
const sessions = /* @__PURE__ */ new Map();
|
|
42601
|
+
const activeByJob = /* @__PURE__ */ new Map();
|
|
42602
|
+
let fallbackSeq = 0;
|
|
42603
|
+
for (const entry of journal) {
|
|
42604
|
+
if (!("artifactId" in entry) || !artifactIds.has(entry.artifactId)) continue;
|
|
42605
|
+
if (entry.kind !== "dispatched" && entry.kind !== "recovered" && entry.kind !== "exited") continue;
|
|
42606
|
+
const identity = journalIdentity(entry);
|
|
42607
|
+
const active = activeByJob.get(entry.jobKey);
|
|
42608
|
+
const key = (identity && sessions.has(identity) ? identity : active) ?? identity ?? `${entry.jobKey}#${fallbackSeq++}`;
|
|
42609
|
+
const previous = sessions.get(key);
|
|
42610
|
+
if (entry.kind === "dispatched") {
|
|
42611
|
+
sessions.set(key, {
|
|
42612
|
+
key,
|
|
42613
|
+
artifactId: entry.artifactId,
|
|
42614
|
+
actor: entry.actor,
|
|
42615
|
+
startedAt: entry.at,
|
|
42616
|
+
failed: false
|
|
42617
|
+
});
|
|
42618
|
+
activeByJob.set(entry.jobKey, key);
|
|
42619
|
+
} else if (entry.kind === "recovered") {
|
|
42620
|
+
sessions.set(key, {
|
|
42621
|
+
key,
|
|
42622
|
+
artifactId: entry.artifactId,
|
|
42623
|
+
actor: entry.actor,
|
|
42624
|
+
startedAt: previous?.startedAt ?? entry.at,
|
|
42625
|
+
durationMs: previous?.durationMs,
|
|
42626
|
+
failed: previous?.failed ?? false
|
|
42627
|
+
});
|
|
42628
|
+
activeByJob.set(entry.jobKey, key);
|
|
42629
|
+
} else {
|
|
42630
|
+
sessions.set(key, {
|
|
42631
|
+
key,
|
|
42632
|
+
artifactId: entry.artifactId,
|
|
42633
|
+
actor: entry.actor,
|
|
42634
|
+
startedAt: previous?.startedAt,
|
|
42635
|
+
durationMs: entry.durationMs,
|
|
42636
|
+
failed: !entry.progressed
|
|
42637
|
+
});
|
|
42638
|
+
activeByJob.delete(entry.jobKey);
|
|
42639
|
+
}
|
|
42640
|
+
}
|
|
42641
|
+
const actorTotals = /* @__PURE__ */ new Map();
|
|
42642
|
+
let executionDurationMs = 0;
|
|
42643
|
+
let executionFailures = 0;
|
|
42644
|
+
for (const session of sessions.values()) {
|
|
42645
|
+
const started = session.startedAt ? Date.parse(session.startedAt) : Number.NaN;
|
|
42646
|
+
const duration3 = session.durationMs ?? (Number.isFinite(started) ? Math.max(0, nowMs - started) : 0);
|
|
42647
|
+
executionDurationMs += duration3;
|
|
42648
|
+
if (session.failed) executionFailures += 1;
|
|
42649
|
+
const current = actorTotals.get(session.actor) ?? { sessionCount: 0, executionDurationMs: 0 };
|
|
42650
|
+
current.sessionCount += 1;
|
|
42651
|
+
current.executionDurationMs += duration3;
|
|
42652
|
+
actorTotals.set(session.actor, current);
|
|
42653
|
+
}
|
|
42654
|
+
const byActor = [...actorTotals.entries()].map(([actor, totals]) => ({ actor: ref(actor, resolveActor), ...totals })).sort((a, b2) => b2.executionDurationMs - a.executionDurationMs || a.actor.id.localeCompare(b2.actor.id));
|
|
42655
|
+
return { sessionCount: sessions.size, executionDurationMs, byActor, executionFailures };
|
|
42656
|
+
}
|
|
42657
|
+
function workorderDuration(ops, journal, artifactIds) {
|
|
42658
|
+
const createdAt = earliestIso(
|
|
42659
|
+
ops.filter((op) => op.kind === "spawn_artifact" && artifactIds.has(op.artifactId)).map((op) => op.timestamp)
|
|
42660
|
+
);
|
|
42661
|
+
const latestExecutionFinishedAt = latestIso(
|
|
42662
|
+
journal.filter((entry) => entry.kind === "exited" && artifactIds.has(entry.artifactId)).map((entry) => entry.at)
|
|
42663
|
+
);
|
|
42664
|
+
const createdMs = createdAt ? Date.parse(createdAt) : Number.NaN;
|
|
42665
|
+
const finishedMs = latestExecutionFinishedAt ? Date.parse(latestExecutionFinishedAt) : Number.NaN;
|
|
42666
|
+
return {
|
|
42667
|
+
createdAt,
|
|
42668
|
+
latestExecutionFinishedAt,
|
|
42669
|
+
durationMs: Number.isFinite(createdMs) && Number.isFinite(finishedMs) ? Math.max(0, finishedMs - createdMs) : null
|
|
42670
|
+
};
|
|
42671
|
+
}
|
|
42672
|
+
function downstreamAnnotationCount(model, artifactIds) {
|
|
42673
|
+
let total = 0;
|
|
42674
|
+
for (const annotation of model.annotations.values()) {
|
|
42675
|
+
if (!annotation.raisedFrom || !artifactIds.has(annotation.raisedFrom)) continue;
|
|
42676
|
+
const target = annotation.anchor.target;
|
|
42677
|
+
const targetArtifact = model.artifacts.has(target) ? target : model.revisions.get(target)?.artifactId;
|
|
42678
|
+
if (targetArtifact && artifactIds.has(targetArtifact)) total += 1;
|
|
42679
|
+
}
|
|
42680
|
+
return total;
|
|
42681
|
+
}
|
|
42682
|
+
function reportedGapCount(model, artifactIds) {
|
|
42683
|
+
let total = 0;
|
|
42684
|
+
for (const artifactId of artifactIds) total += (model.gaps.get(artifactId) ?? []).length;
|
|
42685
|
+
return total;
|
|
42686
|
+
}
|
|
42687
|
+
function buildWorkorderMetrics(input) {
|
|
42688
|
+
const nowMs = input.nowMs ?? Date.now();
|
|
42689
|
+
return input.workorders.map((workorder) => {
|
|
42690
|
+
const artifactIds = new Set(
|
|
42691
|
+
[...input.model.artifacts.values()].filter((artifact) => artifact.workspace === workorder.id).map((artifact) => artifact.id)
|
|
42692
|
+
);
|
|
42693
|
+
const execution = executionMetrics(input.dispatchJournal, artifactIds, input.resolveActor, nowMs);
|
|
42694
|
+
const reportedGaps = reportedGapCount(input.model, artifactIds);
|
|
42695
|
+
return {
|
|
42696
|
+
workorder,
|
|
42697
|
+
sessionCount: execution.sessionCount,
|
|
42698
|
+
executionDurationMs: execution.executionDurationMs,
|
|
42699
|
+
workorderDuration: workorderDuration(
|
|
42700
|
+
input.opsByWorkorder?.get(workorder.id) ?? [],
|
|
42701
|
+
input.dispatchJournal,
|
|
42702
|
+
artifactIds
|
|
42703
|
+
),
|
|
42704
|
+
byActor: execution.byActor,
|
|
42705
|
+
firstReviewPassRate: firstReviewPassRate(input.model, artifactIds),
|
|
42706
|
+
qualityMetrics: qualitySnapshot(input.nodeOutputsByWorkorder?.get(workorder.id) ?? []),
|
|
42707
|
+
annotationCount: downstreamAnnotationCount(input.model, artifactIds),
|
|
42708
|
+
blockage: {
|
|
42709
|
+
total: execution.executionFailures + reportedGaps,
|
|
42710
|
+
executionFailures: execution.executionFailures,
|
|
42711
|
+
reportedGaps
|
|
42712
|
+
}
|
|
42713
|
+
};
|
|
42714
|
+
});
|
|
42715
|
+
}
|
|
42716
|
+
var init_workorder_metrics = __esm({
|
|
42717
|
+
"../server/src/domains/collab/workorder-metrics.ts"() {
|
|
42718
|
+
"use strict";
|
|
42719
|
+
init_src2();
|
|
42720
|
+
init_src();
|
|
42721
|
+
}
|
|
42722
|
+
});
|
|
42723
|
+
|
|
42223
42724
|
// ../server/src/domains/collab/organization-usage.ts
|
|
42224
42725
|
function emptyUsage() {
|
|
42225
42726
|
return {
|
|
@@ -42465,6 +42966,43 @@ function collabDomain(opts) {
|
|
|
42465
42966
|
const dispatchPausedOf = await buildDispatchPausedResolver(artifacts);
|
|
42466
42967
|
return { status: 200, body: { items: buildWorkorderSummaries(kernel.model, resolve5, resolveProject, dispatchPausedOf) } };
|
|
42467
42968
|
});
|
|
42969
|
+
router.get("/api/workorder-metrics", async (req) => {
|
|
42970
|
+
const { kernel, oplog, registry: registry2, artifacts } = await resolveCtx(req.auth.companyId);
|
|
42971
|
+
const resolve5 = await buildResolver(registry2);
|
|
42972
|
+
const resolveProject = await buildProjectResolver(artifacts);
|
|
42973
|
+
const dispatchPausedOf = await buildDispatchPausedResolver(artifacts);
|
|
42974
|
+
const workorders = buildWorkorderSummaries(kernel.model, resolve5, resolveProject, dispatchPausedOf);
|
|
42975
|
+
const nodeOutputsByWorkorder = /* @__PURE__ */ new Map();
|
|
42976
|
+
const artifactIdsByWorkorder = /* @__PURE__ */ new Map();
|
|
42977
|
+
for (const artifact of kernel.model.artifacts.values()) {
|
|
42978
|
+
const ids = artifactIdsByWorkorder.get(artifact.workspace) ?? [];
|
|
42979
|
+
ids.push(artifact.id);
|
|
42980
|
+
artifactIdsByWorkorder.set(artifact.workspace, ids);
|
|
42981
|
+
}
|
|
42982
|
+
const opsByWorkorder = /* @__PURE__ */ new Map();
|
|
42983
|
+
await Promise.all(workorders.map(async (workorder) => {
|
|
42984
|
+
const artifactIds = artifactIdsByWorkorder.get(workorder.id) ?? [];
|
|
42985
|
+
const [nodeOutputs, opGroups] = await Promise.all([
|
|
42986
|
+
artifacts ? artifacts.listNodeOutputs({ workOrderId: workorder.id }) : Promise.resolve([]),
|
|
42987
|
+
Promise.all(artifactIds.map((artifactId) => oplog.read(artifactId)))
|
|
42988
|
+
]);
|
|
42989
|
+
nodeOutputsByWorkorder.set(workorder.id, nodeOutputs);
|
|
42990
|
+
opsByWorkorder.set(workorder.id, opGroups.flat());
|
|
42991
|
+
}));
|
|
42992
|
+
return {
|
|
42993
|
+
status: 200,
|
|
42994
|
+
body: {
|
|
42995
|
+
items: buildWorkorderMetrics({
|
|
42996
|
+
model: kernel.model,
|
|
42997
|
+
workorders,
|
|
42998
|
+
dispatchJournal: opts.metricsDispatchJournal?.() ?? opts.dispatchJournal?.() ?? [],
|
|
42999
|
+
opsByWorkorder,
|
|
43000
|
+
nodeOutputsByWorkorder,
|
|
43001
|
+
...resolve5 ? { resolveActor: resolve5 } : {}
|
|
43002
|
+
})
|
|
43003
|
+
}
|
|
43004
|
+
};
|
|
43005
|
+
});
|
|
42468
43006
|
router.get("/api/workorders/:id", async (req) => {
|
|
42469
43007
|
const { kernel, oplog, registry: registry2, artifacts } = await resolveCtx(req.auth.companyId);
|
|
42470
43008
|
const resolve5 = await buildResolver(registry2);
|
|
@@ -42592,10 +43130,12 @@ var init_collab = __esm({
|
|
|
42592
43130
|
init_inbox();
|
|
42593
43131
|
init_audit();
|
|
42594
43132
|
init_dashboard();
|
|
43133
|
+
init_workorder_metrics();
|
|
42595
43134
|
init_organization_usage();
|
|
42596
43135
|
init_node_state();
|
|
42597
43136
|
init_workorders();
|
|
42598
43137
|
init_workorder_detail();
|
|
43138
|
+
init_workorder_metrics();
|
|
42599
43139
|
init_inbox();
|
|
42600
43140
|
init_audit();
|
|
42601
43141
|
init_dashboard();
|
|
@@ -42632,8 +43172,8 @@ function makeSeededWorkorderCreator(deps) {
|
|
|
42632
43172
|
await deps.kernel.applyIntervention(planned.plan, preview2.baseSeqs, input.actor);
|
|
42633
43173
|
const briefId = planned.rootArtifactId;
|
|
42634
43174
|
if (input.brief.trim()) {
|
|
42635
|
-
const
|
|
42636
|
-
await deps.kernel.proposeRevision({ artifactId: briefId, actor: input.actor, contentRef:
|
|
43175
|
+
const ref2 = await deps.blobs.put(enc2(input.brief));
|
|
43176
|
+
await deps.kernel.proposeRevision({ artifactId: briefId, actor: input.actor, contentRef: ref2, reason: "\u5267\u672C\u5EFA\u5355\uFF1A\u843D\u5B9A brief \u9996\u7248" });
|
|
42637
43177
|
await deps.kernel.advanceQueue(briefId, input.actor);
|
|
42638
43178
|
await deps.kernel.conclude({ artifactId: briefId, actor: input.actor, note: "\u5267\u672C\u5EFA\u5355\u65F6\u5B9A\u7A3F" });
|
|
42639
43179
|
}
|
|
@@ -42932,18 +43472,18 @@ var init_sink = __esm({
|
|
|
42932
43472
|
end(sessionId, update) {
|
|
42933
43473
|
const captured = this.sessions.get(sessionId);
|
|
42934
43474
|
this.enqueue(sessionId, async (st) => {
|
|
42935
|
-
for (const
|
|
43475
|
+
for (const ref2 of update.opRefs) {
|
|
42936
43476
|
await this.store.appendEvents(st.runId, [{
|
|
42937
43477
|
seq: ++st.seq,
|
|
42938
43478
|
eventType: "oplog.appended",
|
|
42939
43479
|
stream: "oasis",
|
|
42940
|
-
message:
|
|
42941
|
-
payload: { opId:
|
|
43480
|
+
message: ref2.kind,
|
|
43481
|
+
payload: { opId: ref2.id, kind: ref2.kind, target: ref2.target, oplogSeq: ref2.seq }
|
|
42942
43482
|
}]);
|
|
42943
43483
|
await this.store.putRunLink({
|
|
42944
43484
|
runId: st.runId,
|
|
42945
43485
|
refType: "op",
|
|
42946
|
-
refId:
|
|
43486
|
+
refId: ref2.id,
|
|
42947
43487
|
relation: "produced",
|
|
42948
43488
|
createdAt: update.exit.at
|
|
42949
43489
|
});
|
|
@@ -43123,7 +43663,7 @@ var init_service4 = __esm({
|
|
|
43123
43663
|
/** 组织汇总专用瘦读:只取归属、时间和 usage,并统一补齐展示成本。 */
|
|
43124
43664
|
async listUsageRuns(filter) {
|
|
43125
43665
|
const rows = await this.store.listUsageRuns(filter);
|
|
43126
|
-
return rows.map((row) => ({
|
|
43666
|
+
return rows.filter((row) => row.usage != null).map((row) => ({
|
|
43127
43667
|
...row,
|
|
43128
43668
|
usage: {
|
|
43129
43669
|
...row.usage,
|
|
@@ -43240,8 +43780,8 @@ var init_service4 = __esm({
|
|
|
43240
43780
|
totalRuns: items.length,
|
|
43241
43781
|
runningRuns: byStatus.get("running") ?? 0,
|
|
43242
43782
|
failedRuns: (byStatus.get("failed") ?? 0) + (byStatus.get("timeout") ?? 0) + (byStatus.get("killed") ?? 0) + (byStatus.get("orphaned") ?? 0),
|
|
43243
|
-
byStatus: [...byStatus].map(([status,
|
|
43244
|
-
byRuntimeKind: [...byKind].map(([runtimeKind,
|
|
43783
|
+
byStatus: [...byStatus].map(([status, count2]) => ({ status, count: count2 })),
|
|
43784
|
+
byRuntimeKind: [...byKind].map(([runtimeKind, count2]) => ({ runtimeKind, count: count2 }))
|
|
43245
43785
|
};
|
|
43246
43786
|
}
|
|
43247
43787
|
};
|
|
@@ -43836,18 +44376,18 @@ var init_chat_sessions = __esm({
|
|
|
43836
44376
|
});
|
|
43837
44377
|
|
|
43838
44378
|
// ../server/src/domains/automations/playbooks.ts
|
|
43839
|
-
function isKnownPlaybook(
|
|
43840
|
-
return
|
|
44379
|
+
function isKnownPlaybook(ref2) {
|
|
44380
|
+
return ref2 in BUILTIN;
|
|
43841
44381
|
}
|
|
43842
|
-
function resolvePlaybook(
|
|
43843
|
-
const def = BUILTIN[
|
|
44382
|
+
function resolvePlaybook(ref2, ctx) {
|
|
44383
|
+
const def = BUILTIN[ref2];
|
|
43844
44384
|
if (def) {
|
|
43845
44385
|
return { artifactType: def.artifactType, title: def.title(ctx), brief: def.brief(ctx) };
|
|
43846
44386
|
}
|
|
43847
44387
|
return {
|
|
43848
44388
|
artifactType: "document",
|
|
43849
44389
|
title: `\u81EA\u52A8\u5316\u7ACB\u9879\uFF1A${ctx.automation.name}\uFF08${isoDate(ctx.now)}\uFF09`,
|
|
43850
|
-
brief: `\u7531\u81EA\u52A8\u5316\u300C${ctx.automation.name}\u300D\uFF08\u5267\u672C ${
|
|
44390
|
+
brief: `\u7531\u81EA\u52A8\u5316\u300C${ctx.automation.name}\u300D\uFF08\u5267\u672C ${ref2}\uFF09\u53D1\u8D77\u7684\u534F\u4F5C\u3002`
|
|
43851
44391
|
};
|
|
43852
44392
|
}
|
|
43853
44393
|
var isoDate, BUILTIN, BUILTIN_PLAYBOOK_REFS;
|
|
@@ -45036,8 +45576,8 @@ ${body || "\uFF08\u672A\u586B\u5199\uFF09"}`;
|
|
|
45036
45576
|
plan
|
|
45037
45577
|
};
|
|
45038
45578
|
}
|
|
45039
|
-
function isKnownPlaybook2(
|
|
45040
|
-
return
|
|
45579
|
+
function isKnownPlaybook2(ref2) {
|
|
45580
|
+
return ref2 in BUILTIN2;
|
|
45041
45581
|
}
|
|
45042
45582
|
function listPlaybooks() {
|
|
45043
45583
|
return Object.values(BUILTIN2).map((d) => ({
|
|
@@ -45049,8 +45589,8 @@ function listPlaybooks() {
|
|
|
45049
45589
|
...d.graph ? { graph: d.graph } : {}
|
|
45050
45590
|
}));
|
|
45051
45591
|
}
|
|
45052
|
-
function resolvePlaybook2(
|
|
45053
|
-
const def = BUILTIN2[
|
|
45592
|
+
function resolvePlaybook2(ref2, ctx) {
|
|
45593
|
+
const def = BUILTIN2[ref2];
|
|
45054
45594
|
return def ? def.resolve(ctx) : null;
|
|
45055
45595
|
}
|
|
45056
45596
|
var BUG_FIX_INPUTS, BUG_FIX_STRUCTURE, BUILTIN2, PLAYBOOK_REFS;
|
|
@@ -45120,15 +45660,15 @@ function playbooksDomain(opts) {
|
|
|
45120
45660
|
return { status: 200, body };
|
|
45121
45661
|
});
|
|
45122
45662
|
router.post("/api/playbooks/:ref/run", async (req) => {
|
|
45123
|
-
const
|
|
45124
|
-
if (!
|
|
45125
|
-
throw new ApiError(400, "UNKNOWN_PLAYBOOK", `\u672A\u77E5\u5267\u672C ${
|
|
45663
|
+
const ref2 = req.params.ref;
|
|
45664
|
+
if (!ref2 || !isKnownPlaybook2(ref2)) {
|
|
45665
|
+
throw new ApiError(400, "UNKNOWN_PLAYBOOK", `\u672A\u77E5\u5267\u672C ${ref2}\uFF08\u5185\u7F6E\uFF1A${PLAYBOOK_REFS.join(", ")}\uFF09`);
|
|
45126
45666
|
}
|
|
45127
45667
|
const payload = (req.body ?? null)?.payload ?? null;
|
|
45128
|
-
const resolved = resolvePlaybook2(
|
|
45129
|
-
if (!resolved) throw new ApiError(400, "UNKNOWN_PLAYBOOK", `\u672A\u77E5\u5267\u672C ${
|
|
45668
|
+
const resolved = resolvePlaybook2(ref2, { now: now(), ...payload !== null ? { payload } : {} });
|
|
45669
|
+
if (!resolved) throw new ApiError(400, "UNKNOWN_PLAYBOOK", `\u672A\u77E5\u5267\u672C ${ref2}`);
|
|
45130
45670
|
if (resolved.produces !== "workorder" || !resolved.plan) {
|
|
45131
|
-
throw new ApiError(400, "PLAYBOOK_NOT_RUNNABLE", `\u5267\u672C ${
|
|
45671
|
+
throw new ApiError(400, "PLAYBOOK_NOT_RUNNABLE", `\u5267\u672C ${ref2} \u6682\u4E0D\u652F\u6301\u76F4\u63A5\u8FD0\u884C\u5EFA\u5355`);
|
|
45132
45672
|
}
|
|
45133
45673
|
const projectId = readProjectId(payload);
|
|
45134
45674
|
if (projectId && opts.projectExists && !await opts.projectExists(projectId)) {
|
|
@@ -45144,7 +45684,7 @@ function playbooksDomain(opts) {
|
|
|
45144
45684
|
actor: req.auth.actor
|
|
45145
45685
|
});
|
|
45146
45686
|
const body = {
|
|
45147
|
-
playbookRef:
|
|
45687
|
+
playbookRef: ref2,
|
|
45148
45688
|
produces: resolved.produces,
|
|
45149
45689
|
workspaceId: result.workspace,
|
|
45150
45690
|
rootArtifactId: result.rootArtifactId,
|
|
@@ -45205,6 +45745,7 @@ var init_daemon_adapter = __esm({
|
|
|
45205
45745
|
this.nodeLostGraceMs = opts.nodeLostGraceMs ?? graceFromEnv(12e4);
|
|
45206
45746
|
this.ackTimeoutMs = opts.ackTimeoutMs ?? ackMsFromEnv(15e3);
|
|
45207
45747
|
this.log = opts.log ?? ((m2) => console.warn(m2));
|
|
45748
|
+
this.health = opts.health;
|
|
45208
45749
|
hub.addMessageListener((_daemonId, msg) => this.onDaemonMessage(msg));
|
|
45209
45750
|
hub.addDisconnectListener((daemonId) => this.onNodeDown(daemonId));
|
|
45210
45751
|
hub.addConnectListener((daemon) => this.onNodeUp(daemon.daemonId));
|
|
@@ -45213,6 +45754,7 @@ var init_daemon_adapter = __esm({
|
|
|
45213
45754
|
nodeLostGraceMs;
|
|
45214
45755
|
ackTimeoutMs;
|
|
45215
45756
|
log;
|
|
45757
|
+
health;
|
|
45216
45758
|
/** 断联节点 → 收割定时器。重连取消;到期收割。 */
|
|
45217
45759
|
reapTimers = /* @__PURE__ */ new Map();
|
|
45218
45760
|
/** 统一结算一次会话退出:清 ack 定时器、置 exited、触发回调、从 pending 摘除。幂等(已退出即跳过)。 */
|
|
@@ -45224,9 +45766,17 @@ var init_daemon_adapter = __esm({
|
|
|
45224
45766
|
entry.ackTimer = void 0;
|
|
45225
45767
|
}
|
|
45226
45768
|
entry.exited = info;
|
|
45769
|
+
if (info.reason === "server-unreachable") this.health?.recordUnreachable(entry.nodeId, info.reason);
|
|
45770
|
+
else this.health?.recordReachable(entry.nodeId);
|
|
45227
45771
|
for (const cb of entry.exitCbs.splice(0)) cb(info);
|
|
45228
45772
|
this.pending.delete(dispatchId);
|
|
45229
45773
|
}
|
|
45774
|
+
/** 该节点当前在途(未退出)会话数——节点健康的 activeRunCount。 */
|
|
45775
|
+
activeRunCount(nodeId) {
|
|
45776
|
+
let n = 0;
|
|
45777
|
+
for (const e of this.pending.values()) if (e.nodeId === nodeId && !e.exited) n++;
|
|
45778
|
+
return n;
|
|
45779
|
+
}
|
|
45230
45780
|
/** 收到任何回帧(started/event/output/exited)即视为派发已达,取消 ack 超时。 */
|
|
45231
45781
|
cancelAck(dispatchId) {
|
|
45232
45782
|
const entry = this.pending.get(dispatchId);
|
|
@@ -45269,6 +45819,8 @@ var init_daemon_adapter = __esm({
|
|
|
45269
45819
|
onDaemonMessage(msg) {
|
|
45270
45820
|
if (msg.type === "session_started") {
|
|
45271
45821
|
this.cancelAck(msg.dispatchId);
|
|
45822
|
+
const entry = this.pending.get(msg.dispatchId);
|
|
45823
|
+
if (entry) this.health?.recordReachable(entry.nodeId);
|
|
45272
45824
|
} else if (msg.type === "session_exited") {
|
|
45273
45825
|
const info = msg.info.reason || msg.info.code !== null ? msg.info : { ...msg.info, reason: "error" };
|
|
45274
45826
|
this.settle(msg.dispatchId, info);
|
|
@@ -45769,6 +46321,12 @@ var init_ci_gate = __esm({
|
|
|
45769
46321
|
const statuses = [];
|
|
45770
46322
|
const repoViews = [];
|
|
45771
46323
|
for (const unit of units) {
|
|
46324
|
+
if (await ci.isMerged({ repo: unit.repo, sha: unit.sha })) {
|
|
46325
|
+
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` };
|
|
46326
|
+
statuses.push({ unit, status: status2 });
|
|
46327
|
+
repoViews.push({ repoId: unit.repo.id, sha: unit.sha.slice(0, 8), state: "success", summary: status2.summary });
|
|
46328
|
+
continue;
|
|
46329
|
+
}
|
|
45772
46330
|
const pr = await ci.ensurePr(
|
|
45773
46331
|
{ repo: unit.repo, branch: unit.branch, sha: unit.sha },
|
|
45774
46332
|
{ title: `[oasis-ci] ${artifactId} \u2192 ${unit.repo.develop}`, body: `CI gate for artifact ${artifactId} @ ${unit.sha}` }
|
|
@@ -45947,7 +46505,7 @@ var init_resolve = __esm({
|
|
|
45947
46505
|
});
|
|
45948
46506
|
|
|
45949
46507
|
// ../server/src/coordinator/worker.ts
|
|
45950
|
-
var import_node_crypto21, AUTONOMOUS_ETHOS, CONVERSATIONAL_ETHOS, SHARED_GRAPH_BODY, COORDINATOR_SYSTEM_PROMPT, CONVERSATIONAL_MANAGER_BODY, CoordinatorWorker;
|
|
46508
|
+
var import_node_crypto21, AUTONOMOUS_ETHOS, CONVERSATIONAL_ETHOS, SHARED_GRAPH_BODY, COORDINATOR_SYSTEM_PROMPT, CONVERSATIONAL_RECOVERY_TOOLS, CONVERSATIONAL_MANAGER_BODY, CoordinatorWorker;
|
|
45951
46509
|
var init_worker = __esm({
|
|
45952
46510
|
"../server/src/coordinator/worker.ts"() {
|
|
45953
46511
|
"use strict";
|
|
@@ -46001,9 +46559,15 @@ var init_worker = __esm({
|
|
|
46001
46559
|
COORDINATOR_SYSTEM_PROMPT = `${AUTONOMOUS_ETHOS}
|
|
46002
46560
|
|
|
46003
46561
|
${SHARED_GRAPH_BODY}`;
|
|
46562
|
+
CONVERSATIONAL_RECOVERY_TOOLS = `\u3010\u6062\u590D\u52A8\u4F5C\uFF08\u5BF9\u8BDD\u4E13\u5C5E\uFF0C\u4EBA\u5728\u573A\u65F6\u624D\u7528\uFF09\uFF1A\u6682\u505C / \u6062\u590D\u8282\u70B9\u6D3E\u53D1\u2014\u2014\u53EA\u6321 agent \u6D3E\u53D1\u3001\u4E0D\u9501\u5185\u5BB9\uFF08\u2260 freeze/cancel\uFF09\uFF0C\u5373\u65F6\u751F\u6548\u3001\u4E0D\u8FDB\u6539\u56FE\u7F13\u51B2\u3011\uFF1A
|
|
46563
|
+
- \`oasis hold <id> --reason "<\u4E3A\u4EC0\u4E48\u5148\u51BB>"\` \u2014\u2014 \u6682\u505C\u8BE5\u8282\u70B9\u7684 agent \u6D3E\u53D1\u3002\u53CD\u590D\u5931\u8D25\u3001\u6216\u4EBA\u8981\u5148\u67E5/\u5148\u624B\u52A8\u6539\u73AF\u5883\uFF08\u6362 runtime\u3001\u8865\u51ED\u8BC1\uFF09\u65F6\uFF0C\u5148\u628A\u5B83\u51BB\u4F4F\u522B\u518D\u7A7A\u8F6C\u91CD\u6D3E\uFF1Bowner \u4E0D\u53D8\u3001\u5185\u5BB9\u4ECD\u53EF\u6539\u3002
|
|
46564
|
+
- \`oasis release <id>\` \u2014\u2014 \u6062\u590D\u6D3E\u53D1\uFF1A\u89E3\u963B\u540E\u7CFB\u7EDF\u91CD\u63A8\u8BE5\u8282\u70B9**\u5F53\u4E0B\u771F\u6B63\u6B20\u7684\u6D3B**\uFF08\u5BF9\u88AB\u5347\u7EA7\u51BB\u7ED3\u7684\u8282\u70B9\uFF0C\u8FD9\u5C31\u662F"\u8BA9\u5B83\u91CD\u65B0\u8DD1"\uFF09\u3002**\u53EA\u5728\u786E\u8BA4\u6839\u56E0\u5DF2\u5904\u7406\u540E\u624D\u653E**\uFF08\u4EBA\u5DF2\u6362 runtime / \u8865\u4E86\u51ED\u8BC1 / \u6539\u4E86\u4EFB\u52A1\u4E66\uFF09\uFF0C\u5426\u5219\u4E00\u653E\u53C8\u683D\u540C\u4E00\u4E2A\u5751\u3002
|
|
46565
|
+
\u5224\u65AD\u8FB9\u754C\uFF1A\u8FD9\u4FE9\u662F"\u6709\u4EE3\u4EF7\u3001\u9700\u5224\u65AD"\u7684\u52A8\u4F5C\u2014\u2014**\u4EBA\u6279\u51C6\u4E86\u518D\u505A**\uFF0C\u522B\u81EA\u4F5C\u4E3B\u5F20\u628A\u4EBA\u6B63\u5728\u67E5\u7684\u8282\u70B9\u653E\u51FA\u53BB\u3002`;
|
|
46004
46566
|
CONVERSATIONAL_MANAGER_BODY = `${CONVERSATIONAL_ETHOS}
|
|
46005
46567
|
|
|
46006
|
-
${SHARED_GRAPH_BODY}
|
|
46568
|
+
${SHARED_GRAPH_BODY}
|
|
46569
|
+
|
|
46570
|
+
${CONVERSATIONAL_RECOVERY_TOOLS}`;
|
|
46007
46571
|
CoordinatorWorker = class {
|
|
46008
46572
|
constructor(deps) {
|
|
46009
46573
|
this.deps = deps;
|
|
@@ -46334,6 +46898,69 @@ ${SHARED_GRAPH_BODY}`;
|
|
|
46334
46898
|
].join("\n");
|
|
46335
46899
|
await this.runCoordinator(p2.id, task, `\u6B7B\u9501\u8BC4\u4F30 ${p2.id}\uFF08\u963B\u585E ${mins}min\uFF09`);
|
|
46336
46900
|
}
|
|
46901
|
+
/**
|
|
46902
|
+
* ADR-0048 自动分诊:结构性运行时故障(连不上 / 挂死超时 / 缺凭证 / 配额打满)熔断升级前,**先跑一次本工单管理者
|
|
46903
|
+
* 产出诊断**——人点开 inbox 卡时看到的是"管理者已诊断 + 给了处置建议",而非冷启动的系统通用占位。
|
|
46904
|
+
*
|
|
46905
|
+
* 由 SLA 扫描 **fire-and-forget** 调用(内部 await 管理者会话跑完,但不阻塞扫描线程)。调用前 SLA 扫描已把节点
|
|
46906
|
+
* **冻结**(hold source:sla),所以这里管理者用自主 prompt(COORDINATOR_SYSTEM_PROMPT,**不含 hold/release**)——
|
|
46907
|
+
* 它能做的只有"诊断 + escalate"(运行时故障它多半解不了),**不会**误把刚冻的节点放出去。
|
|
46908
|
+
*
|
|
46909
|
+
* 兜底(保证 inbox 一定有卡):无可用管理者(run=null)/ 管理者跑完仍没 escalate(空手)→ 系统落一条通用 escalate。
|
|
46910
|
+
*/
|
|
46911
|
+
async triageFailure(artifactId, ctx) {
|
|
46912
|
+
if (unresolvedEscalationsOf(this.deps.kernel.model, artifactId).length > 0) return;
|
|
46913
|
+
const task = this.buildTriageTask(artifactId, ctx);
|
|
46914
|
+
const run = await this.runCoordinator(
|
|
46915
|
+
artifactId,
|
|
46916
|
+
task,
|
|
46917
|
+
`\u5931\u8D25\u5206\u8BCA ${artifactId}\uFF08\u8FDE\u8D25 ${ctx.consecutiveFailures}${ctx.lastReason ? `\uFF0C\u672B\u6B21 ${ctx.lastReason}` : ""}\uFF09`
|
|
46918
|
+
);
|
|
46919
|
+
if (unresolvedEscalationsOf(this.deps.kernel.model, artifactId).length > 0) {
|
|
46920
|
+
this.deps.log?.(`[coordinator] ${artifactId} \u81EA\u52A8\u5206\u8BCA\u5B8C\u6210\uFF1A\u7BA1\u7406\u8005\u5DF2\u4EA7\u51FA\u8BCA\u65AD\u5E76 escalate`);
|
|
46921
|
+
return;
|
|
46922
|
+
}
|
|
46923
|
+
const failLine = `agent \u8FDE\u8D25\u7194\u65AD\uFF08\u8FDE\u8D25 ${ctx.consecutiveFailures} \u6B21${ctx.lastReason ? `\uFF0C\u672B\u6B21\u5931\u8D25\uFF1A${ctx.lastReason}` : ""}\uFF09`;
|
|
46924
|
+
await this.deps.kernel.escalate({
|
|
46925
|
+
artifactId,
|
|
46926
|
+
actor: SYSTEM_ACTOR,
|
|
46927
|
+
reason: run ? `\u81EA\u52A8\u5206\u8BCA\u672A\u6536\u53E3\uFF08\u7BA1\u7406\u8005\u88AB\u5524\u8D77\u5374\u6CA1\u4E0A\u62A5\u8BCA\u65AD\uFF09\u2014\u2014\u7CFB\u7EDF\u515C\u5E95\u5347\u7EA7\uFF1A${failLine}\uFF0C\u8BF7\u4EBA\u5DE5\u6392\u67E5\u6839\u56E0\uFF08\u8FDE\u4E0D\u4E0A/\u6302\u6B7B/\u7F3A\u51ED\u8BC1/\u914D\u989D\uFF09\u3002` : `\u672C\u5DE5\u5355\u65E0\u53EF\u7528\u7BA1\u7406\u8005\u3001\u65E0\u6CD5\u81EA\u52A8\u5206\u8BCA\u2014\u2014\u7CFB\u7EDF\u5347\u7EA7\uFF1A${failLine}\uFF0C\u8BF7\u4EBA\u5DE5\u6392\u67E5\u6839\u56E0\uFF08\u8FDE\u4E0D\u4E0A/\u6302\u6B7B/\u7F3A\u51ED\u8BC1/\u914D\u989D\uFF09\u3002`
|
|
46928
|
+
}).catch((e) => this.deps.log?.(`[coordinator] ${artifactId} \u5206\u8BCA\u515C\u5E95 escalate \u5931\u8D25\uFF1A${String(e)}`));
|
|
46929
|
+
this.deps.log?.(`[coordinator] ${artifactId} \u81EA\u52A8\u5206\u8BCA\u515C\u5E95\uFF1A\u7CFB\u7EDF\u843D\u901A\u7528 escalate\uFF08\u7BA1\u7406\u8005${run ? "\u7A7A\u624B" : "\u4E0D\u53EF\u7528"}\uFF09`);
|
|
46930
|
+
}
|
|
46931
|
+
/** 失败分诊的 TASK.md:把已知失败事实喂给管理者,让它归因 + 给处置建议 + escalate(唯一收尾)。 */
|
|
46932
|
+
buildTriageTask(artifactId, ctx) {
|
|
46933
|
+
const m2 = this.deps.kernel.model;
|
|
46934
|
+
const node = m2.artifacts.get(artifactId);
|
|
46935
|
+
const brief = node?.title ?? node?.description ?? "";
|
|
46936
|
+
const downstreams = consumersOf(m2, artifactId).map((a) => a.id);
|
|
46937
|
+
return [
|
|
46938
|
+
`## \u672C\u6B21\u4E3A\u4EC0\u4E48\u5524\u8D77\u4F60`,
|
|
46939
|
+
`\u8282\u70B9 **${artifactId}**${brief ? `\uFF08\u5B83\u662F\uFF1A${brief}\uFF09` : ""} \u7684 agent **\u53CD\u590D\u5931\u8D25\u3001\u5DF2\u88AB\u7194\u65AD**\u2014\u2014\u8FDE\u8D25 **${ctx.consecutiveFailures}** \u6B21\u3002`,
|
|
46940
|
+
ctx.lastReason ? `> \u672B\u6B21\u5931\u8D25\u539F\u56E0\uFF08\u8FD0\u884C\u65F6\u7ED9\u7684\uFF09\uFF1A\`${ctx.lastReason}\`` : `> \u672B\u6B21\u5931\u8D25\u539F\u56E0\uFF1A\u672A\u77E5\uFF08\u8FD0\u884C\u65F6\u672A\u7ED9\u7ED3\u6784\u5316\u539F\u56E0\uFF09\u3002`,
|
|
46941
|
+
`\u7CFB\u7EDF\u5DF2\u628A\u5B83**\u51BB\u7ED3**\uFF08\u9632\u6B62\u5B83\u7A7A\u8F6C\u53CD\u590D\u91CD\u8DD1\uFF09\u3002**\u4F60\u7684\u4EFB\u52A1\u662F\u8BCA\u65AD + \u4E0A\u62A5\uFF0C\u4E0D\u662F\u8BA9\u5B83\u590D\u5DE5**\u2014\u2014\u6839\u56E0\u6CA1\u9664\u5C31\u653E\u51FA\u53BB\u53EA\u4F1A\u518D\u683D\u4E00\u6B21\u3002`,
|
|
46942
|
+
downstreams.length ? `\u8FD9\u6761\u7EBF\u5361\u7740\u3001\u4E0B\u6E38\u8DDF\u7740\u505C\uFF1A${downstreams.map((d) => `\`${d}\``).join("\u3001")}\u3002` : ``,
|
|
46943
|
+
``,
|
|
46944
|
+
`## \u8FD9\u591A\u534A\u662F\u8FD0\u884C\u65F6 / \u8D44\u6E90\u7C7B\u6545\u969C\uFF08\u4E0D\u662F\u56FE\u75C5\uFF09`,
|
|
46945
|
+
`\u7194\u65AD = agent \u8FDE\u7740\u8DD1\u4E0D\u8D77\u6765\u6216\u8DD1\u4E0D\u5B8C\uFF0C\u5E38\u89C1\u51E0\u7C7B\uFF0C\u4F60\u636E\u672B\u6B21\u539F\u56E0\u5224\u65AD\u843D\u5728\u54EA\u7C7B\uFF1A`,
|
|
46946
|
+
`- **\u7ED1\u5B9A\u8D26\u53F7\u914D\u989D\u6253\u6EE1**\uFF08\u5982 429 / \u4F7F\u7528\u4E0A\u9650\uFF09\u2014\u2014\u8981\u4EBA\u52A0\u989D\u5EA6 / \u6362\u7ED1\u5B9A\u5230\u6709\u989D\u5EA6\u7684\u8D26\u53F7 / \u51CF\u5E76\u53D1\u3002`,
|
|
46947
|
+
`- **\u7F3A\u51ED\u8BC1 / \u5BC6\u94A5**\uFF08\u5982\u67D0\u4ED3\u5E93\u3001\u67D0 API \u6CA1\u6388\u6743\uFF09\u2014\u2014\u8981\u4EBA\u8865\u51ED\u8BC1\u3002`,
|
|
46948
|
+
`- **runtime \u8FDE\u4E0D\u4E0A / \u4F1A\u8BDD\u6302\u6B7B\u8D85\u65F6**\uFF08\u8282\u70B9\u6389\u7EBF\u3001\u8FDB\u7A0B\u5361\u6B7B\uFF09\u2014\u2014\u8981\u4EBA\u6362 runtime / \u91CD\u542F\u8282\u70B9\u3002`,
|
|
46949
|
+
`- **\u4EFB\u52A1\u672C\u8EAB\u8BA9 agent \u53CD\u590D\u4EA7\u4E0D\u51FA**\uFF08\u4EFB\u52A1\u4E66\u6709\u786C\u4F24 / \u7F3A\u5173\u952E\u8F93\u5165\uFF09\u2014\u2014\u8981\u4EBA\u6539\u4EFB\u52A1\u4E66\u6216\u8865\u8F93\u5165\u3002`,
|
|
46950
|
+
`\u8FD9\u4E9B\u4F60**\u591A\u534A\u72EC\u7ACB\u89E3\u4E0D\u4E86**\uFF08\u6362\u989D\u5EA6\u3001\u6362\u673A\u5668\u3001\u8865\u51ED\u8BC1\u90FD\u8981\u4EBA\uFF09\uFF0C\u6240\u4EE5\u6838\u5FC3\u4EA7\u51FA\u662F**\u4E00\u4EFD\u8BA9\u4EBA\u4E00\u773C\u770B\u61C2\u8BE5\u600E\u4E48\u4FEE\u7684\u8BCA\u65AD**\u3002`,
|
|
46951
|
+
``,
|
|
46952
|
+
`## \u73B0\u6709\u4EA7\u7269\uFF08\u90BB\u57DF\u4E0A\u4E0B\u6587\uFF0C\u5E2E\u4F60\u5224\u65AD\u5F71\u54CD\u9762\uFF09`,
|
|
46953
|
+
this.structDigest(artifactId),
|
|
46954
|
+
``,
|
|
46955
|
+
`## \u4F60\u7684\u52A8\u4F5C\u2014\u2014**\u53EA\u6709\u4E00\u4E2A\u6536\u5C3E\uFF1Aescalate**`,
|
|
46956
|
+
`\`oasis escalate ${artifactId} --reason "<\u4F60\u5224\u65AD\u7684\u6839\u56E0\u7C7B\u522B + \u5EFA\u8BAE\u4EBA\u5177\u4F53\u505A\u4EC0\u4E48>"\``,
|
|
46957
|
+
`- reason \u5199\u4EBA\u8BDD\uFF1A\u5148\u8BF4\u6839\u56E0\uFF08\u5982"\u7ED1\u5B9A\u8D26\u53F7\u914D\u989D\u6253\u6EE1\uFF0C\u672B\u6B21\u62A5 429 \u4F7F\u7528\u4E0A\u9650"\uFF09\uFF0C\u518D\u8BF4\u5EFA\u8BAE\uFF08\u5982"\u6362\u7ED1\u5B9A\u5230\u6709\u989D\u5EA6\u8D26\u53F7 / \u52A0\u989D\u5EA6 / \u51CF\u5E76\u53D1"\uFF09\u3002\u4EBA\u5728 inbox \u91CC\u76F4\u63A5\u770B\u8FD9\u6BB5\u3002`,
|
|
46958
|
+
`- **\u522B\u6539\u56FE**\uFF08link/spawn/cancel\uFF09\u2014\u2014\u8FD9\u4E0D\u662F\u7F3A\u4E0A\u6E38 / \u56FE\u75C5\uFF0C\u4E71\u6539\u56FE\u4F1A\u63A9\u76D6\u771F\u95EE\u9898\u3002`,
|
|
46959
|
+
`- **\u522B resolve-gap**\u2014\u2014\u8FD9\u91CC\u6CA1\u6709 gap\u3002`,
|
|
46960
|
+
`- **\u522B\u8BD5\u56FE\u8BA9\u5B83\u590D\u5DE5 / \u522B\u50AC\u91CD\u8DD1**\u2014\u2014\u5B83\u88AB\u51BB\u7740\u662F\u5BF9\u7684\uFF0C\u6839\u56E0\u6CA1\u9664\u653E\u51FA\u53BB\u5FC5\u518D\u683D\u3002`,
|
|
46961
|
+
`- **\u7EDD\u4E0D\u7A7A\u624B\u9000\u51FA**\uFF1A\u4E0D escalate = \u4EBA\u62FF\u5230\u7684\u8FD8\u662F\u7CFB\u7EDF\u7684\u901A\u7528\u5360\u4F4D\u3001\u8FD9\u6B21\u5206\u8BCA\u767D\u8DD1\u3002\u5224\u65AD\u4E0D\u4E86\u6839\u56E0\uFF0C\u4E5F\u628A"\u6211\u770B\u5230\u7684\u73B0\u8C61 + \u9700\u8981\u4EBA\u67E5\u4EC0\u4E48"escalate \u4E0A\u53BB\u3002`
|
|
46962
|
+
].filter(Boolean).join("\n");
|
|
46963
|
+
}
|
|
46337
46964
|
/**
|
|
46338
46965
|
* 决策 0026:解析某节点所属**工单**的管理者——读该 workspace 根 brief 的 `fields.manager`(陪发起人聊出此单的
|
|
46339
46966
|
* AI 实例),再经 `resolveManager` 拿它的 active record + binding。无 manager 字段 / 解析不到(非 active / 无绑定)
|
|
@@ -46558,6 +47185,7 @@ var init_src5 = __esm({
|
|
|
46558
47185
|
init_playbooks2();
|
|
46559
47186
|
init_scheduler();
|
|
46560
47187
|
init_daemon_adapter();
|
|
47188
|
+
init_node_health();
|
|
46561
47189
|
init_side_map();
|
|
46562
47190
|
init_engine();
|
|
46563
47191
|
init_fs_state();
|
|
@@ -47354,11 +47982,11 @@ var require_binaryParsers = __commonJS({
|
|
|
47354
47982
|
var array2 = [];
|
|
47355
47983
|
var i2;
|
|
47356
47984
|
if (dimension.length > 1) {
|
|
47357
|
-
var
|
|
47358
|
-
for (i2 = 0; i2 <
|
|
47985
|
+
var count2 = dimension.shift();
|
|
47986
|
+
for (i2 = 0; i2 < count2; i2++) {
|
|
47359
47987
|
array2[i2] = parse2(dimension, elementType2);
|
|
47360
47988
|
}
|
|
47361
|
-
dimension.unshift(
|
|
47989
|
+
dimension.unshift(count2);
|
|
47362
47990
|
} else {
|
|
47363
47991
|
for (i2 = 0; i2 < dimension[0]; i2++) {
|
|
47364
47992
|
array2[i2] = parseElement(elementType2);
|
|
@@ -52699,8 +53327,8 @@ function renderIndexYaml2(index) {
|
|
|
52699
53327
|
function renderProgressJsonl(progress) {
|
|
52700
53328
|
return "```json\n" + progress.map((p2) => JSON.stringify(p2)).join("\n") + "\n```";
|
|
52701
53329
|
}
|
|
52702
|
-
function parseDocRef(
|
|
52703
|
-
return
|
|
53330
|
+
function parseDocRef(ref2) {
|
|
53331
|
+
return ref2.startsWith(DOC_REF_PREFIX) ? ref2.slice(DOC_REF_PREFIX.length) : null;
|
|
52704
53332
|
}
|
|
52705
53333
|
function runStateKey2(workOrderId, nodeId) {
|
|
52706
53334
|
return `${workOrderId ?? ""}::${nodeId ?? ""}`;
|
|
@@ -52908,6 +53536,7 @@ var PostgresRegistryStore = class _PostgresRegistryStore {
|
|
|
52908
53536
|
name text NOT NULL,
|
|
52909
53537
|
email text,
|
|
52910
53538
|
team_id text,
|
|
53539
|
+
reports_to text, -- \u6C47\u62A5\u4EBA\uFF08\u8D1F\u8D23\u4EBA\uFF09\uFF1A\u53E6\u4E00\u4E2A actor id\uFF0C\u53EF\u7A7A
|
|
52911
53540
|
status text NOT NULL, -- active | disabled\uFF08\u5220\u9664\u5373\u505C\u7528\uFF09
|
|
52912
53541
|
roles jsonb NOT NULL DEFAULT '[]'::jsonb, -- spec \xA76.2 \u540D\u518C\u89D2\u8272\uFF08\u4EFB\u52A1 2.0\uFF09
|
|
52913
53542
|
avatar text, -- "blob:<hash>"\uFF0C\u7A7A=\u9ED8\u8BA4\u751F\u6210
|
|
@@ -52933,6 +53562,7 @@ var PostgresRegistryStore = class _PostgresRegistryStore {
|
|
|
52933
53562
|
await pool.query(`ALTER TABLE "${s2}".actor_configs ADD COLUMN IF NOT EXISTS max_concurrent integer NOT NULL DEFAULT 4`);
|
|
52934
53563
|
await pool.query(`ALTER TABLE "${s2}".actor_configs ADD COLUMN IF NOT EXISTS reviewer_ids jsonb NOT NULL DEFAULT '[]'::jsonb`);
|
|
52935
53564
|
await pool.query(`ALTER TABLE "${s2}".actor_configs ADD COLUMN IF NOT EXISTS batched_continuation boolean NOT NULL DEFAULT false`);
|
|
53565
|
+
await pool.query(`ALTER TABLE "${s2}".actors ADD COLUMN IF NOT EXISTS reports_to text`);
|
|
52936
53566
|
await pool.query(`
|
|
52937
53567
|
CREATE TABLE IF NOT EXISTS "${s2}".teams (
|
|
52938
53568
|
id text PRIMARY KEY,
|
|
@@ -53036,10 +53666,10 @@ var PostgresRegistryStore = class _PostgresRegistryStore {
|
|
|
53036
53666
|
/* ---------- 员工 ---------- */
|
|
53037
53667
|
async upsertActor(a) {
|
|
53038
53668
|
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]
|
|
53669
|
+
`INSERT INTO ${this.s}.actors (id, kind, name, email, team_id, status, roles, avatar, created_at, reports_to)
|
|
53670
|
+
VALUES ($1,$2,$3,$4,$5,$6,$7::jsonb,$8,$9,$10)
|
|
53671
|
+
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`,
|
|
53672
|
+
[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
53673
|
);
|
|
53044
53674
|
}
|
|
53045
53675
|
async getActor(id) {
|
|
@@ -53398,6 +54028,7 @@ var rowToActor = (row) => ({
|
|
|
53398
54028
|
name: row.name,
|
|
53399
54029
|
...row.email !== null ? { email: row.email } : {},
|
|
53400
54030
|
...row.team_id !== null ? { teamId: row.team_id } : {},
|
|
54031
|
+
...row.reports_to !== null && row.reports_to !== void 0 ? { reportsTo: row.reports_to } : {},
|
|
53401
54032
|
status: row.status,
|
|
53402
54033
|
roles: row.roles ?? [],
|
|
53403
54034
|
...row.avatar !== null && row.avatar !== void 0 ? { avatar: row.avatar } : {},
|
|
@@ -54884,7 +55515,7 @@ var PostgresTraceStore = class _PostgresTraceStore {
|
|
|
54884
55515
|
const r = await this.pool.query(
|
|
54885
55516
|
`SELECT actor_id, artifact_id, started_at, effective_model, usage
|
|
54886
55517
|
FROM ${this.s}.agent_runs
|
|
54887
|
-
WHERE usage
|
|
55518
|
+
WHERE jsonb_typeof(usage) = 'object' AND started_at >= $1 AND started_at <= $2
|
|
54888
55519
|
ORDER BY started_at`,
|
|
54889
55520
|
[filter.from, filter.to]
|
|
54890
55521
|
);
|
|
@@ -55690,6 +56321,7 @@ var rowToRun2 = (row) => ({
|
|
|
55690
56321
|
});
|
|
55691
56322
|
|
|
55692
56323
|
// ../storage/src/postgres-chat-sessions.ts
|
|
56324
|
+
init_chat_session();
|
|
55693
56325
|
var ident7 = (s2) => {
|
|
55694
56326
|
if (!/^[a-z_][a-z0-9_]*$/.test(s2)) throw new Error(`invalid schema name: ${s2}`);
|
|
55695
56327
|
return s2;
|
|
@@ -55757,10 +56389,24 @@ var PostgresChatSessionStore = class _PostgresChatSessionStore {
|
|
|
55757
56389
|
}
|
|
55758
56390
|
async listSessions(humanActorId) {
|
|
55759
56391
|
const r = await this.pool.query(
|
|
55760
|
-
`SELECT
|
|
56392
|
+
`SELECT s.*, lm.status AS last_assistant_status, lm.content AS last_assistant_content
|
|
56393
|
+
FROM ${this.s}.chat_sessions s
|
|
56394
|
+
LEFT JOIN LATERAL (
|
|
56395
|
+
SELECT status, content FROM ${this.s}.chat_messages
|
|
56396
|
+
WHERE session_id = s.id AND role = 'assistant'
|
|
56397
|
+
ORDER BY seq DESC LIMIT 1
|
|
56398
|
+
) lm ON TRUE
|
|
56399
|
+
WHERE s.human_actor_id = $1
|
|
56400
|
+
ORDER BY s.touched_at DESC`,
|
|
55761
56401
|
[humanActorId]
|
|
55762
56402
|
);
|
|
55763
|
-
return r.rows.map(
|
|
56403
|
+
return r.rows.map((row) => {
|
|
56404
|
+
const quality = deriveLastTurnQuality({
|
|
56405
|
+
status: row.last_assistant_status ?? void 0,
|
|
56406
|
+
content: row.last_assistant_content ?? ""
|
|
56407
|
+
});
|
|
56408
|
+
return { ...rowToSession(row), ...quality ? { lastTurnQuality: quality } : {} };
|
|
56409
|
+
});
|
|
55764
56410
|
}
|
|
55765
56411
|
async getSession(id) {
|
|
55766
56412
|
const r = await this.pool.query(`SELECT * FROM ${this.s}.chat_sessions WHERE id = $1`, [id]);
|
|
@@ -56401,10 +57047,10 @@ async function startServe(opts) {
|
|
|
56401
57047
|
let nodeStore = await FileNodeStore.open(path16.join(opts.dir, "nodes.json"));
|
|
56402
57048
|
const registryAuditFile = path16.join(opts.dir, "registry-audit.ndjson");
|
|
56403
57049
|
const registryListeners = /* @__PURE__ */ new Set();
|
|
56404
|
-
const registryAudit = (
|
|
56405
|
-
fs18.appendFile(registryAuditFile, JSON.stringify(
|
|
57050
|
+
const registryAudit = (record6) => {
|
|
57051
|
+
fs18.appendFile(registryAuditFile, JSON.stringify(record6) + "\n", () => {
|
|
56406
57052
|
});
|
|
56407
|
-
for (const l of registryListeners) l({ kind:
|
|
57053
|
+
for (const l of registryListeners) l({ kind: record6.kind, actor: record6.actor, target: record6.target, timestamp: record6.timestamp });
|
|
56408
57054
|
};
|
|
56409
57055
|
await syncRegistryRolesToKernel(registryStore, kernel);
|
|
56410
57056
|
let builtinSkills = [];
|
|
@@ -56627,6 +57273,20 @@ async function startServe(opts) {
|
|
|
56627
57273
|
fs18.appendFile(journalFile, JSON.stringify(entry) + "\n", () => {
|
|
56628
57274
|
});
|
|
56629
57275
|
};
|
|
57276
|
+
const readMetricJournal = () => {
|
|
57277
|
+
if (!fs18.existsSync(journalFile)) return [...journalRing];
|
|
57278
|
+
try {
|
|
57279
|
+
return fs18.readFileSync(journalFile, "utf8").split(/\r?\n/).filter(Boolean).flatMap((line) => {
|
|
57280
|
+
try {
|
|
57281
|
+
return [JSON.parse(line)];
|
|
57282
|
+
} catch {
|
|
57283
|
+
return [];
|
|
57284
|
+
}
|
|
57285
|
+
});
|
|
57286
|
+
} catch {
|
|
57287
|
+
return [...journalRing];
|
|
57288
|
+
}
|
|
57289
|
+
};
|
|
56630
57290
|
const closeOrphanedDispatches = () => {
|
|
56631
57291
|
const open2 = /* @__PURE__ */ new Map();
|
|
56632
57292
|
for (const entry of journalRing) {
|
|
@@ -56668,6 +57328,8 @@ async function startServe(opts) {
|
|
|
56668
57328
|
let hub = null;
|
|
56669
57329
|
let chatRemoteAdapter = null;
|
|
56670
57330
|
let dispatchRemoteAdapter = null;
|
|
57331
|
+
const nodeHealth = new NodeHealthTracker();
|
|
57332
|
+
const activeRunCountOf = (nodeId) => (chatRemoteAdapter?.activeRunCount(nodeId) ?? 0) + (dispatchRemoteAdapter?.activeRunCount(nodeId) ?? 0);
|
|
56671
57333
|
let localUrl = "";
|
|
56672
57334
|
const chatLiveSessions = /* @__PURE__ */ new Map();
|
|
56673
57335
|
const remoteApiUrl = opts.publicUrl ? normalizeHttpBaseUrl(opts.publicUrl) : apiUrlFromGatewayUrl(opts.gatewayUrl);
|
|
@@ -56809,7 +57471,9 @@ async function startServe(opts) {
|
|
|
56809
57471
|
nodeStore,
|
|
56810
57472
|
registry: registryStore,
|
|
56811
57473
|
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"
|
|
57474
|
+
repoRemote: opts.nodeRepoRemote ?? "git@github.com:open-friday/oasis-core.git",
|
|
57475
|
+
nodeHealth,
|
|
57476
|
+
activeRunCountOf
|
|
56813
57477
|
}),
|
|
56814
57478
|
collabDomain({
|
|
56815
57479
|
kernel,
|
|
@@ -56818,6 +57482,7 @@ async function startServe(opts) {
|
|
|
56818
57482
|
registry: registryStore,
|
|
56819
57483
|
artifacts: artifactStateStore,
|
|
56820
57484
|
dispatchJournal: () => journalRing.slice(-200),
|
|
57485
|
+
metricsDispatchJournal: readMetricJournal,
|
|
56821
57486
|
workorderDrafts,
|
|
56822
57487
|
// 活工单查不到时回退查建单草案(status="draft")
|
|
56823
57488
|
...opts.sla ? { sla: opts.sla } : {},
|
|
@@ -57178,7 +57843,7 @@ ${detail}` : genericLine));
|
|
|
57178
57843
|
}
|
|
57179
57844
|
});
|
|
57180
57845
|
hub = new DaemonHub(server.httpServer, "/node-gateway", (t) => nodeTokens.resolve(t));
|
|
57181
|
-
const hubAdapterOpts = { log: (m2) => console.warn(m2) };
|
|
57846
|
+
const hubAdapterOpts = { log: (m2) => console.warn(m2), health: nodeHealth };
|
|
57182
57847
|
chatRemoteAdapter = new DaemonHubAdapter(hub, hubAdapterOpts);
|
|
57183
57848
|
dispatchRemoteAdapter = new DaemonHubAdapter(hub, hubAdapterOpts);
|
|
57184
57849
|
const port = new URL(server.baseUrl).port;
|
|
@@ -57413,6 +58078,8 @@ ${detail}` : genericLine));
|
|
|
57413
58078
|
}
|
|
57414
58079
|
const humanMs = opts.sla?.humanMs ?? 24 * 36e5;
|
|
57415
58080
|
const agentMs = opts.sla?.agentMs ?? 10 * 6e4;
|
|
58081
|
+
const quotaStarvationMs = opts.sla?.quotaStarvationMs ?? 6 * 36e5;
|
|
58082
|
+
let triageFailure;
|
|
57416
58083
|
const initiatorCache = /* @__PURE__ */ new Map();
|
|
57417
58084
|
const initiatorOf = async (workspace) => {
|
|
57418
58085
|
if (initiatorCache.has(workspace)) return initiatorCache.get(workspace);
|
|
@@ -57485,23 +58152,44 @@ ${detail}` : genericLine));
|
|
|
57485
58152
|
await escalate(a.id, a.owner, `human \u6301\u6709 ${Math.round(humanMs / 6e4)} \u5206\u949F\u672A\u52A8\u5DE5`);
|
|
57486
58153
|
}
|
|
57487
58154
|
}
|
|
58155
|
+
const escalateHold = async (artifactId, reason, kind) => {
|
|
58156
|
+
if (unresolvedEscalationsOf(kernel.model, artifactId).length > 0) return;
|
|
58157
|
+
if (isHeld(kernel.model, artifactId)) return;
|
|
58158
|
+
const owner = kernel.model.artifacts.get(artifactId)?.owner ?? "";
|
|
58159
|
+
try {
|
|
58160
|
+
await kernel.escalate({ artifactId, actor: SYSTEM_ACTOR, reason });
|
|
58161
|
+
await kernel.hold({ artifactId, actor: SYSTEM_ACTOR, source: "sla", reason });
|
|
58162
|
+
journal({ kind: "escalated", at: (/* @__PURE__ */ new Date()).toISOString(), artifactId, from: owner, to: owner, reason });
|
|
58163
|
+
console.log(`[sla] ${artifactId} ${kind}\uFF1A\u843D escalate + hold\uFF08owner \u4FDD\u6301 ${owner}\uFF0C\u4E0D\u593A\uFF09`);
|
|
58164
|
+
} catch (err) {
|
|
58165
|
+
console.error(`[sla] ${kind}\u5931\u8D25 ${artifactId}: ${String(err)}`);
|
|
58166
|
+
}
|
|
58167
|
+
};
|
|
57488
58168
|
for (const f2 of allDispatchers().flatMap((d) => d.fusedJobs())) {
|
|
57489
58169
|
if (f2.action !== "produce") continue;
|
|
57490
|
-
|
|
57491
|
-
if (!cur) continue;
|
|
58170
|
+
if (!kernel.model.artifacts.get(f2.artifactId)) continue;
|
|
57492
58171
|
if (now - Date.parse(f2.fusedAt) <= agentMs) continue;
|
|
57493
58172
|
if (unresolvedEscalationsOf(kernel.model, f2.artifactId).length > 0) continue;
|
|
57494
58173
|
if (isHeld(kernel.model, f2.artifactId)) continue;
|
|
57495
|
-
const
|
|
57496
|
-
|
|
57497
|
-
|
|
57498
|
-
|
|
57499
|
-
|
|
57500
|
-
|
|
57501
|
-
|
|
57502
|
-
|
|
58174
|
+
const failReason = `agent \u8FDE\u8D25\u7194\u65AD\u540E ${Math.round(agentMs / 6e4)} \u5206\u949F\u65E0\u4EBA\u5904\u7406\uFF08\u8FDE\u8D25 ${f2.consecutiveFailures} \u6B21\uFF09`;
|
|
58175
|
+
if (triageFailure) {
|
|
58176
|
+
const owner = kernel.model.artifacts.get(f2.artifactId)?.owner ?? "";
|
|
58177
|
+
try {
|
|
58178
|
+
await kernel.hold({ artifactId: f2.artifactId, actor: SYSTEM_ACTOR, source: "sla", reason: failReason });
|
|
58179
|
+
console.log(`[sla] ${f2.artifactId} \u7194\u65AD\u5347\u7EA7\uFF1A\u51BB\u7ED3 + \u89E6\u53D1\u81EA\u52A8\u5206\u8BCA\uFF08owner \u4FDD\u6301 ${owner}\uFF0C\u4E0D\u593A\uFF09`);
|
|
58180
|
+
void triageFailure(f2.artifactId, { consecutiveFailures: f2.consecutiveFailures, ...f2.lastReason ? { lastReason: f2.lastReason } : {} });
|
|
58181
|
+
} catch (err) {
|
|
58182
|
+
console.error(`[sla] \u7194\u65AD\u5347\u7EA7\u51BB\u7ED3\u5931\u8D25 ${f2.artifactId}: ${String(err)}`);
|
|
58183
|
+
}
|
|
58184
|
+
} else {
|
|
58185
|
+
await escalateHold(f2.artifactId, failReason, "\u7194\u65AD\u5347\u7EA7");
|
|
57503
58186
|
}
|
|
57504
58187
|
}
|
|
58188
|
+
for (const s2 of allDispatchers().flatMap((d) => d.starvingJobs(quotaStarvationMs, now))) {
|
|
58189
|
+
if (s2.action !== "produce") continue;
|
|
58190
|
+
if (!kernel.model.artifacts.get(s2.artifactId)) continue;
|
|
58191
|
+
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");
|
|
58192
|
+
}
|
|
57505
58193
|
})().catch((err) => console.error(`[sla] \u626B\u63CF\u5931\u8D25: ${String(err)}`));
|
|
57506
58194
|
}, opts.sla?.scanMs ?? 6e4);
|
|
57507
58195
|
let mirrorTimer;
|
|
@@ -57594,6 +58282,7 @@ ${detail}` : genericLine));
|
|
|
57594
58282
|
// 0030 D7 落盘
|
|
57595
58283
|
});
|
|
57596
58284
|
coordinatorRef = coordinator;
|
|
58285
|
+
triageFailure = (artifactId, ctx) => coordinator.triageFailure(artifactId, ctx);
|
|
57597
58286
|
coordTimer = setInterval(() => {
|
|
57598
58287
|
void coordinator.tick().catch((err) => console.error(`[coordinator] tick \u5931\u8D25: ${String(err)}`));
|
|
57599
58288
|
}, 15e3);
|
|
@@ -59756,7 +60445,7 @@ ${res.warning}`);
|
|
|
59756
60445
|
}
|
|
59757
60446
|
|
|
59758
60447
|
// src/index.ts
|
|
59759
|
-
var PKG_VERSION = true ? "0.1.
|
|
60448
|
+
var PKG_VERSION = true ? "0.1.57" : "dev";
|
|
59760
60449
|
var OASIS_DIR = path18.join(os9.homedir(), ".oasis");
|
|
59761
60450
|
var CONFIG_FILE = path18.join(OASIS_DIR, "node-config.json");
|
|
59762
60451
|
var PID_FILE = path18.join(OASIS_DIR, "node.pid");
|