oasis_test 0.1.81 → 0.1.83

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 CHANGED
@@ -1794,9 +1794,9 @@ function resolveNodeRef(ref2, candidates) {
1794
1794
  const hit = candidates.find((n) => n.id === r);
1795
1795
  return hit ? { ok: true, id: hit.id } : { ok: false, reason: "not_found" };
1796
1796
  }
1797
- const sep3 = r.indexOf(":");
1798
- const type = (sep3 >= 0 ? r.slice(0, sep3) : r).trim().toLowerCase();
1799
- const title = sep3 >= 0 ? r.slice(sep3 + 1).trim().toLowerCase() : null;
1797
+ const sep4 = r.indexOf(":");
1798
+ const type = (sep4 >= 0 ? r.slice(0, sep4) : r).trim().toLowerCase();
1799
+ const title = sep4 >= 0 ? r.slice(sep4 + 1).trim().toLowerCase() : null;
1800
1800
  const matches = candidates.filter((n) => n.type.toLowerCase() === type && (title === null || (n.title ?? "").toLowerCase() === title));
1801
1801
  if (matches.length === 0) return { ok: false, reason: "not_found" };
1802
1802
  if (matches.length === 1) return { ok: true, id: matches[0].id };
@@ -2243,61 +2243,181 @@ var init_collab_view = __esm({
2243
2243
  });
2244
2244
 
2245
2245
  // ../contract/src/evaluation.ts
2246
- function calculateSpecialtyScore(dimensions) {
2247
- if (dimensions.length !== 5 || dimensions.some((dimension) => dimension.score === null)) {
2248
- return null;
2249
- }
2250
- const scores = dimensions.map((dimension) => dimension.score);
2251
- if (scores.some((score2) => score2 < 1 || score2 > 5)) {
2252
- throw new Error("S \u4E13\u9879\u7EF4\u5EA6\u5206\u5FC5\u987B\u5728 1-5 \u4E4B\u95F4");
2253
- }
2254
- const score = scores.reduce((sum, value2) => sum + value2, 0) / scores.length;
2255
- return { score, score100: score * 20 };
2256
- }
2257
2246
  function assertScore(value2, min2, max, label, nullable2 = false) {
2258
2247
  if (nullable2 && value2 === null) return;
2259
2248
  if (typeof value2 !== "number" || !Number.isFinite(value2) || value2 < min2 || value2 > max) {
2260
2249
  throw new Error(`${label} \u5FC5\u987B\u5728 ${min2}-${max} \u4E4B\u95F4${nullable2 ? "\u6216\u4E3A null" : ""}`);
2261
2250
  }
2262
2251
  }
2263
- function validateEvaluationResult(value2) {
2264
- if (!value2 || typeof value2 !== "object") throw new Error("\u8BC4\u5206\u7ED3\u679C\u5FC5\u987B\u662F\u5BF9\u8C61");
2265
- const result = value2;
2266
- if (!Array.isArray(result.common?.dimensions) || result.common.dimensions.length !== 7) {
2267
- throw new Error("\u901A\u7528\u80FD\u529B\u5FC5\u987B\u5305\u542B G1-G7 \u4E03\u4E2A\u7EF4\u5EA6");
2268
- }
2269
- const commonIds = result.common.dimensions.map((dimension) => dimension.id);
2270
- for (const id of ["G1", "G2", "G3", "G4", "G5", "G6", "G7"]) {
2271
- if (!commonIds.includes(id)) throw new Error(`\u901A\u7528\u80FD\u529B\u7F3A\u5C11 ${id}`);
2252
+ function validateSection(result, spec) {
2253
+ const section = sectionOf(result, spec.sectionKey);
2254
+ if (!section) throw new Error(`\u7F3A\u5C11\u8BC4\u5206\u6BB5 ${spec.sectionKey}`);
2255
+ if (!spec.dimensions.length) {
2256
+ if (!Array.isArray(section["items"])) throw new Error(`\u8BC4\u5206\u6BB5 ${spec.sectionKey} \u7F3A\u5C11\u8BC4\u5206\u9879`);
2257
+ return;
2272
2258
  }
2273
- for (const dimension of result.common.dimensions) {
2274
- assertScore(dimension.score, 1, 5, dimension.id, dimension.id === "G6");
2259
+ const dimensions = section["dimensions"];
2260
+ if (!Array.isArray(dimensions) || dimensions.length !== spec.dimensions.length) {
2261
+ throw new Error(`\u8BC4\u5206\u6BB5 ${spec.sectionKey} \u5FC5\u987B\u5305\u542B ${spec.dimensions.length} \u4E2A\u7EF4\u5EA6`);
2275
2262
  }
2276
- if (!Array.isArray(result.specialty?.dimensions)) throw new Error("\u7F3A\u5C11 S \u4E13\u9879\u7EF4\u5EA6");
2277
- if (result.specialty.dimensions.length !== 5) throw new Error("S \u4E13\u9879\u5FC5\u987B\u5305\u542B\u4E94\u4E2A\u7EF4\u5EA6");
2278
- const calculated = calculateSpecialtyScore(result.specialty.dimensions);
2279
- if (calculated) {
2280
- if (Math.abs((result.specialty.score ?? Number.NaN) - calculated.score) > 1e-9) {
2281
- throw new Error("S \u4E13\u9879\u5E73\u5747\u5206\u4E0E\u4E94\u4E2A\u7EF4\u5EA6\u4E0D\u4E00\u81F4");
2263
+ const byId = new Map(
2264
+ dimensions.map((dimension) => [dimension?.id, dimension])
2265
+ );
2266
+ spec.dimensions.forEach((expected, index) => {
2267
+ const dimension = spec.strictIds === false ? dimensions[index] : byId.get(expected.id);
2268
+ if (!dimension) throw new Error(`\u8BC4\u5206\u6BB5 ${spec.sectionKey} \u7F3A\u5C11 ${expected.id}`);
2269
+ assertScore(dimension.score, expected.min, expected.max, expected.id, expected.nullable === true);
2270
+ });
2271
+ if (spec.aggregation !== "mean") return;
2272
+ const scores = dimensions.map((dimension) => dimension.score);
2273
+ const complete = scores.every((value2) => typeof value2 === "number");
2274
+ const score = section["score"];
2275
+ const score100 = section["score100"];
2276
+ if (complete) {
2277
+ const mean = scores.reduce((sum, value2) => sum + value2, 0) / scores.length;
2278
+ const max = spec.dimensions[0]?.max ?? 5;
2279
+ if (Math.abs((typeof score === "number" ? score : Number.NaN) - mean) > 1e-9) {
2280
+ throw new Error(`\u8BC4\u5206\u6BB5 ${spec.sectionKey} \u7684\u5E73\u5747\u5206\u4E0E\u7EF4\u5EA6\u4E0D\u4E00\u81F4`);
2282
2281
  }
2283
- if (Math.abs((result.specialty.score100 ?? Number.NaN) - calculated.score100) > 1e-9) {
2284
- throw new Error("S \u4E13\u9879\u767E\u5206\u5236\u5206\u6570\u4E0E\u4E94\u4E2A\u7EF4\u5EA6\u4E0D\u4E00\u81F4");
2282
+ if (Math.abs((typeof score100 === "number" ? score100 : Number.NaN) - mean * (100 / max)) > 1e-9) {
2283
+ throw new Error(`\u8BC4\u5206\u6BB5 ${spec.sectionKey} \u7684\u767E\u5206\u5236\u5206\u6570\u4E0E\u7EF4\u5EA6\u4E0D\u4E00\u81F4`);
2285
2284
  }
2286
- } else if (result.specialty.score !== null || result.specialty.score100 !== null) {
2287
- throw new Error("S \u4E13\u9879\u7EF4\u5EA6\u4E0D\u5B8C\u6574\u65F6\u4E0D\u80FD\u751F\u6210\u4E13\u9879\u5206");
2285
+ } else if (score !== null || score100 !== null) {
2286
+ throw new Error(`\u8BC4\u5206\u6BB5 ${spec.sectionKey} \u7EF4\u5EA6\u4E0D\u5B8C\u6574\u65F6\u4E0D\u80FD\u751F\u6210\u6BB5\u5206`);
2288
2287
  }
2289
- if (!Array.isArray(result.caseSpecial?.items)) throw new Error("\u7F3A\u5C11 Case Special \u8BC4\u5206\u9879");
2290
- assertScore(result.caseSpecial.score100, 0, 100, "Case Special", true);
2291
- if (!result.runtimeMetrics || typeof result.runtimeMetrics !== "object") {
2288
+ }
2289
+ function validateEvaluationResult(value2, specs = BUILTIN_OUTPUT_SPECS) {
2290
+ if (!value2 || typeof value2 !== "object") throw new Error("\u8BC4\u5206\u7ED3\u679C\u5FC5\u987B\u662F\u5BF9\u8C61");
2291
+ const result = value2;
2292
+ for (const spec of specs.length ? specs : BUILTIN_OUTPUT_SPECS) validateSection(result, spec);
2293
+ const caseSpecial = sectionOf(result, "caseSpecial");
2294
+ if (caseSpecial) assertScore(caseSpecial["score100"], 0, 100, "Case Special", true);
2295
+ if (!result["runtimeMetrics"] || typeof result["runtimeMetrics"] !== "object") {
2292
2296
  throw new Error("\u7F3A\u5C11\u8FD0\u884C\u6307\u6807");
2293
2297
  }
2294
2298
  return structuredClone(result);
2295
2299
  }
2296
- var isEvaluationEligibleWorkorder;
2300
+ var isEvaluationEligibleWorkorder, BUILTIN_COMMON_OUTPUT_SPEC, BUILTIN_SPECIALTY_OUTPUT_SPEC, BUILTIN_CASE_SPECIAL_OUTPUT_SPEC, BUILTIN_OUTPUT_SPECS, sectionOf;
2297
2301
  var init_evaluation = __esm({
2298
2302
  "../contract/src/evaluation.ts"() {
2299
2303
  "use strict";
2300
2304
  isEvaluationEligibleWorkorder = (workorder) => workorder.stage === "concluded";
2305
+ BUILTIN_COMMON_OUTPUT_SPEC = {
2306
+ sectionKey: "common",
2307
+ aggregation: "none",
2308
+ dimensions: [
2309
+ { id: "G1", label: "G1", min: 1, max: 5 },
2310
+ { id: "G2", label: "G2", min: 1, max: 5 },
2311
+ { id: "G3", label: "G3", min: 1, max: 5 },
2312
+ { id: "G4", label: "G4", min: 1, max: 5 },
2313
+ { id: "G5", label: "G5", min: 1, max: 5 },
2314
+ { id: "G6", label: "G6", min: 1, max: 5, nullable: true },
2315
+ { id: "G7", label: "G7", min: 1, max: 5 }
2316
+ ]
2317
+ };
2318
+ BUILTIN_SPECIALTY_OUTPUT_SPEC = {
2319
+ sectionKey: "specialty",
2320
+ aggregation: "mean",
2321
+ // strictIds=false:五项的 id 由各 S 类标准自己定,历史校验也只数个数不认 id。
2322
+ strictIds: false,
2323
+ // nullable:S 专项允许整段不评分(没有可读专业产物时五项全 null,段分随之为 null)——
2324
+ // 这是既有语义,见 enforceSpecialtyArtifactBoundary。段分一致性由 aggregation 那条兜住。
2325
+ dimensions: Array.from({ length: 5 }, (_unused, index) => ({
2326
+ id: `S${index + 1}`,
2327
+ label: `S${index + 1}`,
2328
+ min: 1,
2329
+ max: 5,
2330
+ nullable: true
2331
+ }))
2332
+ };
2333
+ BUILTIN_CASE_SPECIAL_OUTPUT_SPEC = {
2334
+ sectionKey: "caseSpecial",
2335
+ aggregation: "none",
2336
+ dimensions: []
2337
+ };
2338
+ BUILTIN_OUTPUT_SPECS = [
2339
+ BUILTIN_COMMON_OUTPUT_SPEC,
2340
+ BUILTIN_SPECIALTY_OUTPUT_SPEC,
2341
+ BUILTIN_CASE_SPECIAL_OUTPUT_SPEC
2342
+ ];
2343
+ sectionOf = (result, key) => {
2344
+ const section = result[key];
2345
+ return section && typeof section === "object" && !Array.isArray(section) ? section : void 0;
2346
+ };
2347
+ }
2348
+ });
2349
+
2350
+ // ../contract/src/evaluation-rubric.ts
2351
+ function validateEvaluationRubricOutputSpec(value2) {
2352
+ if (!value2 || typeof value2 !== "object") throw new Error("\u8F93\u51FA\u5951\u7EA6\u5FC5\u987B\u662F\u5BF9\u8C61");
2353
+ const spec = value2;
2354
+ if (typeof spec.sectionKey !== "string" || !spec.sectionKey.trim()) {
2355
+ throw new Error("\u8F93\u51FA\u5951\u7EA6\u7F3A\u5C11 sectionKey");
2356
+ }
2357
+ if (spec.aggregation !== "none" && spec.aggregation !== "mean") {
2358
+ throw new Error("aggregation \u53EA\u80FD\u662F none \u6216 mean");
2359
+ }
2360
+ if (!Array.isArray(spec.dimensions)) throw new Error("dimensions \u5FC5\u987B\u662F\u6570\u7EC4");
2361
+ const seen = /* @__PURE__ */ new Set();
2362
+ for (const dimension of spec.dimensions) {
2363
+ if (!dimension || typeof dimension !== "object") throw new Error("\u7EF4\u5EA6\u5FC5\u987B\u662F\u5BF9\u8C61");
2364
+ if (typeof dimension.id !== "string" || !DIMENSION_ID.test(dimension.id)) {
2365
+ throw new Error(`\u7EF4\u5EA6 id \u975E\u6CD5\uFF1A${String(dimension.id)}`);
2366
+ }
2367
+ if (seen.has(dimension.id)) throw new Error(`\u7EF4\u5EA6 id \u91CD\u590D\uFF1A${dimension.id}`);
2368
+ seen.add(dimension.id);
2369
+ if (typeof dimension.label !== "string" || !dimension.label.trim()) {
2370
+ throw new Error(`\u7EF4\u5EA6 ${dimension.id} \u7F3A\u5C11 label`);
2371
+ }
2372
+ if (typeof dimension.min !== "number" || typeof dimension.max !== "number" || !Number.isFinite(dimension.min) || !Number.isFinite(dimension.max) || dimension.min >= dimension.max) {
2373
+ throw new Error(`\u7EF4\u5EA6 ${dimension.id} \u7684\u5206\u503C\u533A\u95F4\u975E\u6CD5`);
2374
+ }
2375
+ }
2376
+ return {
2377
+ sectionKey: spec.sectionKey.trim(),
2378
+ aggregation: spec.aggregation,
2379
+ ...spec.strictIds === false ? { strictIds: false } : {},
2380
+ dimensions: spec.dimensions.map((dimension) => ({
2381
+ id: dimension.id,
2382
+ label: dimension.label,
2383
+ min: dimension.min,
2384
+ max: dimension.max,
2385
+ ...dimension.nullable ? { nullable: true } : {}
2386
+ }))
2387
+ };
2388
+ }
2389
+ function validateUpsertEvaluationRubricInput(value2) {
2390
+ if (!value2 || typeof value2 !== "object") throw new Error("\u8BC4\u5206\u6807\u51C6\u5FC5\u987B\u662F\u5BF9\u8C61");
2391
+ const input = value2;
2392
+ if (typeof input.name !== "string" || !input.name.trim()) throw new Error("\u8BC4\u5206\u6807\u51C6\u7F3A\u5C11\u540D\u79F0");
2393
+ if (input.kind !== "common" && input.kind !== "specialty" && input.kind !== "case_special") {
2394
+ throw new Error("kind \u53EA\u80FD\u662F common / specialty / case_special");
2395
+ }
2396
+ if (typeof input.promptSection !== "string" || !input.promptSection.trim()) {
2397
+ throw new Error("\u8BC4\u5206\u6807\u51C6\u6B63\u6587\u4E0D\u80FD\u4E3A\u7A7A");
2398
+ }
2399
+ if (input.status !== void 0 && input.status !== "active" && input.status !== "archived") {
2400
+ throw new Error("status \u53EA\u80FD\u662F active \u6216 archived");
2401
+ }
2402
+ return {
2403
+ ...typeof input.rubricId === "string" && input.rubricId ? { rubricId: input.rubricId } : {},
2404
+ name: input.name.trim(),
2405
+ kind: input.kind,
2406
+ ...typeof input.description === "string" && input.description.trim() ? { description: input.description.trim() } : {},
2407
+ promptSection: input.promptSection,
2408
+ outputSpec: validateEvaluationRubricOutputSpec(input.outputSpec),
2409
+ ...input.status ? { status: input.status } : {}
2410
+ };
2411
+ }
2412
+ function rubricVersionOf(rubrics, fallback) {
2413
+ if (!rubrics.length) return fallback;
2414
+ return rubrics.map((rubric) => `${rubric.rubricId}@${rubric.version}`).join("+");
2415
+ }
2416
+ var DIMENSION_ID;
2417
+ var init_evaluation_rubric = __esm({
2418
+ "../contract/src/evaluation-rubric.ts"() {
2419
+ "use strict";
2420
+ DIMENSION_ID = /^[A-Za-z][A-Za-z0-9_.-]{0,31}$/;
2301
2421
  }
2302
2422
  });
2303
2423
 
@@ -2615,6 +2735,7 @@ var init_src = __esm({
2615
2735
  init_annotation();
2616
2736
  init_collab_view();
2617
2737
  init_evaluation();
2738
+ init_evaluation_rubric();
2618
2739
  init_inbox_read();
2619
2740
  init_workorder_quality();
2620
2741
  init_workorder_attachments();
@@ -6441,8 +6562,8 @@ var init_dispatcher = __esm({
6441
6562
  /** 从 produce jobKey 解析 artifactId:`produce::<artifactId>` 或 `produce::<artifactId>::<part>`。 */
6442
6563
  artifactIdFromJobKey(jobKey) {
6443
6564
  const rest = jobKey.slice(jobKey.indexOf("::") + 2);
6444
- const sep3 = rest.indexOf("::");
6445
- return sep3 >= 0 ? rest.slice(0, sep3) : rest;
6565
+ const sep4 = rest.indexOf("::");
6566
+ return sep4 >= 0 ? rest.slice(0, sep4) : rest;
6446
6567
  }
6447
6568
  /**
6448
6569
  * 某节点的派发器运行时信号(stuckDiagnosis 的非 oplog 那半;proposal 协调者阻塞诊断 D1)。
@@ -7541,11 +7662,88 @@ var init_store = __esm({
7541
7662
  }
7542
7663
  });
7543
7664
 
7665
+ // ../core/src/evaluation/rubric-store.ts
7666
+ var import_node_crypto4, bindingKey, MemoryEvaluationRubricStore;
7667
+ var init_rubric_store = __esm({
7668
+ "../core/src/evaluation/rubric-store.ts"() {
7669
+ "use strict";
7670
+ import_node_crypto4 = require("node:crypto");
7671
+ bindingKey = (companyId, caseId) => JSON.stringify([companyId, caseId]);
7672
+ MemoryEvaluationRubricStore = class {
7673
+ rubrics = /* @__PURE__ */ new Map();
7674
+ bindings = /* @__PURE__ */ new Map();
7675
+ async listRubrics(companyId) {
7676
+ return [...this.rubrics.values()].filter((rubric) => rubric.companyId === companyId).sort((left, right) => left.name.localeCompare(right.name)).map((rubric) => structuredClone(rubric));
7677
+ }
7678
+ async getRubric(rubricId) {
7679
+ const rubric = this.rubrics.get(rubricId);
7680
+ return rubric ? structuredClone(rubric) : null;
7681
+ }
7682
+ async upsertRubric(input, at) {
7683
+ const existing = input.rubricId ? this.rubrics.get(input.rubricId) : void 0;
7684
+ if (existing && existing.companyId !== input.companyId) {
7685
+ throw new Error(`\u8BC4\u5206\u6807\u51C6 ${input.rubricId} \u4E0D\u5C5E\u4E8E\u5F53\u524D\u516C\u53F8`);
7686
+ }
7687
+ const rubric = {
7688
+ rubricId: existing?.rubricId ?? input.rubricId ?? (0, import_node_crypto4.randomUUID)(),
7689
+ companyId: input.companyId,
7690
+ name: input.name,
7691
+ kind: input.kind,
7692
+ ...input.description ? { description: input.description } : {},
7693
+ promptSection: input.promptSection,
7694
+ outputSpec: structuredClone(input.outputSpec),
7695
+ // 版本随每次保存自增:判分记录靠 rubricId@version 复现「当时用的是哪一版标准」。
7696
+ version: (existing?.version ?? 0) + 1,
7697
+ status: input.status ?? existing?.status ?? "active",
7698
+ createdBy: existing?.createdBy ?? input.actor,
7699
+ createdAt: existing?.createdAt ?? at,
7700
+ updatedBy: input.actor,
7701
+ updatedAt: at
7702
+ };
7703
+ this.rubrics.set(rubric.rubricId, rubric);
7704
+ return structuredClone(rubric);
7705
+ }
7706
+ async deleteRubric(rubricId, companyId) {
7707
+ const rubric = this.rubrics.get(rubricId);
7708
+ if (!rubric || rubric.companyId !== companyId) return;
7709
+ this.rubrics.delete(rubricId);
7710
+ for (const [key, binding] of this.bindings) {
7711
+ if (binding.companyId !== companyId || !binding.rubricIds.includes(rubricId)) continue;
7712
+ this.bindings.set(key, {
7713
+ ...binding,
7714
+ rubricIds: binding.rubricIds.filter((id) => id !== rubricId)
7715
+ });
7716
+ }
7717
+ }
7718
+ async listBindings(companyId) {
7719
+ return [...this.bindings.values()].filter((binding) => binding.companyId === companyId).map((binding) => structuredClone(binding));
7720
+ }
7721
+ async getBinding(companyId, caseId) {
7722
+ const binding = this.bindings.get(bindingKey(companyId, caseId));
7723
+ return binding ? structuredClone(binding) : null;
7724
+ }
7725
+ async putBinding(input, at) {
7726
+ const binding = {
7727
+ companyId: input.companyId,
7728
+ caseId: input.caseId,
7729
+ rubricIds: [...input.rubricIds],
7730
+ judgeActorId: input.judgeActorId,
7731
+ updatedBy: input.actor,
7732
+ updatedAt: at
7733
+ };
7734
+ this.bindings.set(bindingKey(input.companyId, input.caseId), binding);
7735
+ return structuredClone(binding);
7736
+ }
7737
+ };
7738
+ }
7739
+ });
7740
+
7544
7741
  // ../core/src/evaluation/index.ts
7545
7742
  var init_evaluation2 = __esm({
7546
7743
  "../core/src/evaluation/index.ts"() {
7547
7744
  "use strict";
7548
7745
  init_store();
7746
+ init_rubric_store();
7549
7747
  }
7550
7748
  });
7551
7749
 
@@ -7845,11 +8043,11 @@ var init_parse = __esm({
7845
8043
 
7846
8044
  // ../channels/src/feishu/crypto.ts
7847
8045
  function decryptFeishu(encrypt, encryptKey) {
7848
- const key = (0, import_node_crypto4.createHash)("sha256").update(encryptKey).digest();
8046
+ const key = (0, import_node_crypto5.createHash)("sha256").update(encryptKey).digest();
7849
8047
  const data = Buffer.from(encrypt, "base64");
7850
8048
  const iv = data.subarray(0, 16);
7851
8049
  const ciphertext = data.subarray(16);
7852
- const decipher = (0, import_node_crypto4.createDecipheriv)("aes-256-cbc", key, iv);
8050
+ const decipher = (0, import_node_crypto5.createDecipheriv)("aes-256-cbc", key, iv);
7853
8051
  decipher.setAutoPadding(true);
7854
8052
  return Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString("utf8");
7855
8053
  }
@@ -7883,11 +8081,11 @@ function verifyToken(decoded, expected) {
7883
8081
  const token = headerToken ?? decoded["token"];
7884
8082
  return token === expected;
7885
8083
  }
7886
- var import_node_crypto4;
8084
+ var import_node_crypto5;
7887
8085
  var init_crypto = __esm({
7888
8086
  "../channels/src/feishu/crypto.ts"() {
7889
8087
  "use strict";
7890
- import_node_crypto4 = require("node:crypto");
8088
+ import_node_crypto5 = require("node:crypto");
7891
8089
  }
7892
8090
  });
7893
8091
 
@@ -8023,11 +8221,11 @@ var init_src3 = __esm({
8023
8221
  function errMsg(e) {
8024
8222
  return e instanceof Error ? e.message : String(e);
8025
8223
  }
8026
- var import_node_crypto5, FEISHU, ChannelService, CardStreamer;
8224
+ var import_node_crypto6, FEISHU, ChannelService, CardStreamer;
8027
8225
  var init_service = __esm({
8028
8226
  "../server/src/channels/service.ts"() {
8029
8227
  "use strict";
8030
- import_node_crypto5 = require("node:crypto");
8228
+ import_node_crypto6 = require("node:crypto");
8031
8229
  init_src3();
8032
8230
  FEISHU = "feishu";
8033
8231
  ChannelService = class {
@@ -8107,7 +8305,7 @@ var init_service = __esm({
8107
8305
  return existing.chatSessionId;
8108
8306
  }
8109
8307
  }
8110
- const id = (0, import_node_crypto5.randomUUID)();
8308
+ const id = (0, import_node_crypto6.randomUUID)();
8111
8309
  const now = this.now();
8112
8310
  if (cs) {
8113
8311
  const rt = await this.deps.resolveRuntime?.(a.aiActorId).catch(() => null);
@@ -8143,7 +8341,7 @@ var init_service = __esm({
8143
8341
  if (cs) {
8144
8342
  const sess = await cs.getSession(intent.chatSessionId).catch(() => null);
8145
8343
  resumeRt = sess?.runtimeSessionId ?? void 0;
8146
- await cs.appendMessage({ id: (0, import_node_crypto5.randomUUID)(), sessionId: intent.chatSessionId, role: "user", content: intent.message, createdAt: this.now() }).catch(() => void 0);
8344
+ await cs.appendMessage({ id: (0, import_node_crypto6.randomUUID)(), sessionId: intent.chatSessionId, role: "user", content: intent.message, createdAt: this.now() }).catch(() => void 0);
8147
8345
  }
8148
8346
  let session;
8149
8347
  try {
@@ -8165,7 +8363,7 @@ var init_service = __esm({
8165
8363
  const reply = streamer.text();
8166
8364
  if (reply || session.runId) {
8167
8365
  await cs.appendMessage({
8168
- id: (0, import_node_crypto5.randomUUID)(),
8366
+ id: (0, import_node_crypto6.randomUUID)(),
8169
8367
  sessionId: intent.chatSessionId,
8170
8368
  role: "assistant",
8171
8369
  content: reply,
@@ -137636,7 +137834,7 @@ var init_live_chat = __esm({
137636
137834
  }
137637
137835
  if (!res.accepted) return say(res, { from: "runtime" });
137638
137836
  if (this.turns.get(chatSessionId) !== turn || turn.status !== "running") {
137639
- return say({ accepted: true, reason: "turn-finished" }, { turnStatus: turn.status, replaced: this.turns.get(chatSessionId) !== turn });
137837
+ return say({ accepted: false, reason: "turn-finished" }, { turnStatus: turn.status, replaced: this.turns.get(chatSessionId) !== turn });
137640
137838
  }
137641
137839
  const withSeq = { type: "user", text: text2, seq: ++turn.seq };
137642
137840
  turn.buffer.push(withSeq);
@@ -138196,7 +138394,7 @@ function slug4(name) {
138196
138394
  return s2 || "user";
138197
138395
  }
138198
138396
  function short6() {
138199
- return (0, import_node_crypto6.randomBytes)(4).toString("hex").slice(0, 6);
138397
+ return (0, import_node_crypto7.randomBytes)(4).toString("hex").slice(0, 6);
138200
138398
  }
138201
138399
  async function assertBindingWritePermission(caller, targetHumanId, deps) {
138202
138400
  if (caller === targetHumanId) return true;
@@ -138261,11 +138459,11 @@ async function resolveWorkorderPrincipals(caller, cliOverrides, deps) {
138261
138459
  }
138262
138460
  return { error: "UNBOUND_AGENT_NO_OWNER", message: `owner \u65E0\u6CD5\u89E3\u6790\uFF1A\u8C03\u7528\u65B9 ${caller} \u65E2\u975E\u5728\u5C97\u771F\u4EBA\u4E5F\u975E\u5DF2\u7ED1\u52A9\u7406` };
138263
138461
  }
138264
- var import_node_crypto6, DEFAULT_ASSISTANT_PROMPT, DEFAULT_ASSISTANT_SKILLS, DEFAULT_ASSISTANT_RUNTIME_KIND, ASSISTANT_ARCHIVED_CODE, AssistantLazyCreateError, AssistantsService;
138462
+ var import_node_crypto7, DEFAULT_ASSISTANT_PROMPT, DEFAULT_ASSISTANT_SKILLS, DEFAULT_ASSISTANT_RUNTIME_KIND, ASSISTANT_ARCHIVED_CODE, AssistantLazyCreateError, AssistantsService;
138265
138463
  var init_assistants = __esm({
138266
138464
  "../server/src/domains/actors/assistants.ts"() {
138267
138465
  "use strict";
138268
- import_node_crypto6 = require("node:crypto");
138466
+ import_node_crypto7 = require("node:crypto");
138269
138467
  init_src();
138270
138468
  DEFAULT_ASSISTANT_PROMPT = "\u4F60\u662F\u8FD9\u540D\u771F\u4EBA\u5458\u5DE5\u7684\u4E13\u5C5E\u4E2A\u4EBA\u52A9\u7406\u3002\u4F60\u4EE5\u5176\u300C\u5DE5\u5355\u7BA1\u7406\u8005\u300D\u8EAB\u4EFD\u4EE3\u8DD1\uFF0C\u9075\u5FAA\u4E09\u6863\u6743\u9650\u6A21\u578B\uFF1A\u6863 A\uFF08\u52A0\u8FB9\u3001\u65B0\u5EFA\u8282\u70B9\u3001\u6539\u6807\u9898\u4E0E brief\u3001\u5E38\u89C4\u8BC4\u8BBA\u7B54\u7591\u3001\u63A8\u8FDB\u81EA\u5DF1\u63A5\u7684\u6D3B\uFF09\u53EF\u9006\u6539\u52A8\u76F4\u63A5\u751F\u6548\uFF1B\u6863 B\uFF08\u65AD\u8FB9\u3001\u5E9F\u8282\u70B9\u3001\u6539\u6D3E\u3001\u64A4\u90E8\u4EF6\uFF09\u9500\u6BC1\u6027\u6539\u52A8\u81EA\u52A8\u6253\u5305\u6210\u5F85\u786E\u8BA4\u63D0\u6848\uFF0C\u4EA4\u7531\u672C\u4EBA\u786E\u8BA4\u540E\u751F\u6548\uFF1B\u6863 C\uFF08force-conclude\u3001promote \u7B49\u6CBB\u7406\u547D\u4EE4\uFF09\u8D70\u4EBA\u5DE5\u6388\u6743\u5361\u3002\u4F60\u4E0D\u627F\u62C5\u4E1A\u52A1\u4E13\u4E1A\u5C97\u4F4D\u804C\u8D23\uFF0C\u53EA\u5728\u5176\u6388\u6743\u8303\u56F4\u5185\u534F\u52A9\u5EFA\u5355\u3001\u8DDF\u8FDB\u4E0E\u6C9F\u901A\u3002";
138271
138469
  DEFAULT_ASSISTANT_SKILLS = [];
@@ -139226,9 +139424,9 @@ function agentEdgesFor(dependsOn, nodes, briefId, issues) {
139226
139424
  edges.add(briefId);
139227
139425
  continue;
139228
139426
  }
139229
- const sep3 = d.indexOf(":");
139230
- const depType = (sep3 >= 0 ? d.slice(0, sep3) : d).trim().toLowerCase();
139231
- const depTitle = sep3 >= 0 ? d.slice(sep3 + 1).trim().toLowerCase() : null;
139427
+ const sep4 = d.indexOf(":");
139428
+ const depType = (sep4 >= 0 ? d.slice(0, sep4) : d).trim().toLowerCase();
139429
+ const depTitle = sep4 >= 0 ? d.slice(sep4 + 1).trim().toLowerCase() : null;
139232
139430
  const match = nodes.find((n) => n.type === depType && (depTitle === null || (n.title ?? "").toLowerCase() === depTitle));
139233
139431
  if (match) edges.add(match.id);
139234
139432
  else issues.push({ code: "planner_invalid", severity: "warning", message: `\u8282\u70B9\u4F9D\u8D56\u300C${dep}\u300D\u627E\u4E0D\u5230\u5BF9\u5E94\u4E0A\u6E38\uFF08\u6309 type:title \u5339\u914D\uFF09\uFF0C\u5DF2\u5FFD\u7565\u8FD9\u6761\u8FB9\u3002` });
@@ -140566,6 +140764,13 @@ function resolveWrapperScript(wrapperDir, slug6) {
140566
140764
  }
140567
140765
  return null;
140568
140766
  }
140767
+ function isOasisWrapperPath(p2) {
140768
+ try {
140769
+ return (0, import_node_fs2.realpathSync)(p2).endsWith(`${import_node_path.sep}wrapper.sh`);
140770
+ } catch {
140771
+ return false;
140772
+ }
140773
+ }
140569
140774
  function wrapperCandidates(wrapperDir, slug6) {
140570
140775
  const override = process.env[ASSETS_DIR_ENV];
140571
140776
  if (override) return [(0, import_node_path.resolve)(override, slug6, "wrapper.sh")];
@@ -140863,13 +141068,27 @@ var init_cli_connector = __esm({
140863
141068
  }
140864
141069
  }
140865
141070
  /**
140866
- * 用 `which` 解析真实二进制的绝对路径;找不到就原样返回命令名。
140867
- * 必须在**跑 agent 的那台机器**上解析——server 侧算出的路径在远程节点上并不存在。
141071
+ * 用 `which -a` 解析真实二进制的绝对路径,**跳过 oasis 自己 stage 出来的 wrapper**;
141072
+ * 一个都没有就原样返回命令名。必须在**跑 agent 的那台机器**上解析——server 侧算出的
141073
+ * 路径在远程节点上并不存在。
141074
+ *
141075
+ * 为什么要跳过 wrapper(2026-08-03 实测踩到):`which` 吃的是**本进程的 PATH**,而
141076
+ * daemon 的 PATH 可能被 agent 会话的 wrapper 目录污染(`oasis daemon start` 把当时
141077
+ * shell 的 PATH 固化进 systemd unit——在 agent 会话里触发更新就会带进 /tmp/oasis-conn-*)。
141078
+ * 裸 `which gh` 于是解析到 wrapper 自己,注入的 GH_BIN 指回 wrapper,wrapper 再 exec
141079
+ * 它 → 无限递归。节点侧已在 daemon 启动时清洗 PATH,这里是第二道闸:
141080
+ * **解析结果一旦是我们自己的 wrapper 就继续往后找。**
140868
141081
  */
140869
141082
  async resolveRealBin(name) {
140870
141083
  try {
140871
- const { stdout } = await execFile3("which", [name]);
140872
- return stdout.trim();
141084
+ const { stdout } = await execFile3("which", ["-a", name]);
141085
+ for (const line of stdout.split("\n")) {
141086
+ const candidate = line.trim();
141087
+ if (!candidate) continue;
141088
+ if (isOasisWrapperPath(candidate)) continue;
141089
+ return candidate;
141090
+ }
141091
+ return name;
140873
141092
  } catch {
140874
141093
  return name;
140875
141094
  }
@@ -141420,7 +141639,10 @@ var init_github = __esm({
141420
141639
  "GIT_AUTHOR_EMAIL",
141421
141640
  "GIT_COMMITTER_NAME",
141422
141641
  "GIT_COMMITTER_EMAIL",
141423
- "EMAIL"
141642
+ "EMAIL",
141643
+ "GIT_CONFIG_COUNT",
141644
+ "GIT_CONFIG_KEY_0",
141645
+ "GIT_CONFIG_VALUE_0"
141424
141646
  ];
141425
141647
  /** 自检:问 GitHub「我是谁」——这是唯一能戳穿「静默用成宿主机身份」的检查。 */
141426
141648
  verifyArgs = ["api", "user", "--jq", ".login"];
@@ -141460,6 +141682,9 @@ var init_github = __esm({
141460
141682
  sessionEnv.set("GIT_COMMITTER_NAME", name);
141461
141683
  sessionEnv.set("GIT_COMMITTER_EMAIL", "");
141462
141684
  sessionEnv.set("EMAIL", "");
141685
+ sessionEnv.set("GIT_CONFIG_COUNT", "1");
141686
+ sessionEnv.set("GIT_CONFIG_KEY_0", "credential.https://github.com.helper");
141687
+ sessionEnv.set("GIT_CONFIG_VALUE_0", "!gh auth git-credential");
141463
141688
  }
141464
141689
  };
141465
141690
  }
@@ -141643,7 +141868,7 @@ var init_prepare_job = __esm({
141643
141868
  function deriveBoardKey(artifactId) {
141644
141869
  const tail = artifactId.split(":").pop() ?? artifactId;
141645
141870
  const ascii = tail.replace(/[^a-zA-Z0-9-]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").slice(0, 24);
141646
- const sha8 = (0, import_node_crypto7.createHash)("sha256").update(artifactId).digest("hex").slice(0, 8);
141871
+ const sha8 = (0, import_node_crypto8.createHash)("sha256").update(artifactId).digest("hex").slice(0, 8);
141647
141872
  return ascii ? `od-${ascii}-${sha8}` : `od-${sha8}`;
141648
141873
  }
141649
141874
  async function odApi(base, fetchImpl, method, p2, body) {
@@ -141686,7 +141911,7 @@ function materializeContext(resolvedDir, files) {
141686
141911
  }
141687
141912
  }
141688
141913
  async function putVisibleUserTurn(base, fetchImpl, args) {
141689
- const messageId = (0, import_node_crypto7.randomUUID)();
141914
+ const messageId = (0, import_node_crypto8.randomUUID)();
141690
141915
  await odApi(
141691
141916
  base,
141692
141917
  fetchImpl,
@@ -141701,8 +141926,8 @@ async function startDesignRun(base, fetchImpl, args) {
141701
141926
  agentId: args.agentId,
141702
141927
  projectId: args.boardKey,
141703
141928
  conversationId: args.conversationId,
141704
- assistantMessageId: (0, import_node_crypto7.randomUUID)(),
141705
- clientRequestId: (0, import_node_crypto7.randomUUID)(),
141929
+ assistantMessageId: (0, import_node_crypto8.randomUUID)(),
141930
+ clientRequestId: (0, import_node_crypto8.randomUUID)(),
141706
141931
  message: args.message,
141707
141932
  // 提案 design-conversational-driving 坑②:systemPrompt 从写死改为可选——缺省用引擎侧默认,
141708
141933
  // 让设计意图由驱动方每轮的话(message)表达,而非焊死一句。
@@ -141883,11 +142108,11 @@ async function runDesignChatTurn(opts) {
141883
142108
  const { artifacts, fileCount } = await fetchResultPackage(opts.base, fetchImpl, runId);
141884
142109
  return { boardKey, conversationId, runId, userMessageId, artifacts, fileCount };
141885
142110
  }
141886
- var import_node_crypto7, fs5, os, path4;
142111
+ var import_node_crypto8, fs5, os, path4;
141887
142112
  var init_driver = __esm({
141888
142113
  "../adapters/src/open-design/driver.ts"() {
141889
142114
  "use strict";
141890
- import_node_crypto7 = require("node:crypto");
142115
+ import_node_crypto8 = require("node:crypto");
141891
142116
  fs5 = __toESM(require("node:fs"), 1);
141892
142117
  os = __toESM(require("node:os"), 1);
141893
142118
  path4 = __toESM(require("node:path"), 1);
@@ -141998,7 +142223,7 @@ function resolveWorkRoots(workRoot) {
141998
142223
  }
141999
142224
  function slug5(workdirKey) {
142000
142225
  const safe = workdirKey.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 48);
142001
- const h = (0, import_node_crypto8.createHash)("sha256").update(workdirKey).digest("hex").slice(0, 8);
142226
+ const h = (0, import_node_crypto9.createHash)("sha256").update(workdirKey).digest("hex").slice(0, 8);
142002
142227
  return `${safe}-${h}`;
142003
142228
  }
142004
142229
  function sessionDirFor(workRoot, runtimeKind, workdirKey) {
@@ -142130,11 +142355,11 @@ function prepareWorkdir(args) {
142130
142355
  function legacyChatSessionDir(workRoot, rtId) {
142131
142356
  return import_node_path8.default.join(resolveLegacyWorkRoot(workRoot), "oasis-chat-sessions", rtId.replace(/[^a-zA-Z0-9_-]+/g, "_"));
142132
142357
  }
142133
- var import_node_crypto8, import_node_fs6, import_node_os4, import_node_path8, META_FILE, LOCK_FILE, NEW_WORK_ROOT, LEGACY_ROOTS, LEGACY_ONESHOT_PREFIX;
142358
+ var import_node_crypto9, import_node_fs6, import_node_os4, import_node_path8, META_FILE, LOCK_FILE, NEW_WORK_ROOT, LEGACY_ROOTS, LEGACY_ONESHOT_PREFIX;
142134
142359
  var init_session_paths = __esm({
142135
142360
  "../adapters/src/_core/session-paths.ts"() {
142136
142361
  "use strict";
142137
- import_node_crypto8 = require("node:crypto");
142362
+ import_node_crypto9 = require("node:crypto");
142138
142363
  import_node_fs6 = __toESM(require("node:fs"), 1);
142139
142364
  import_node_os4 = __toESM(require("node:os"), 1);
142140
142365
  import_node_path8 = __toESM(require("node:path"), 1);
@@ -142337,12 +142562,12 @@ function classifyExit(result) {
142337
142562
  if (status === 429 || status === 529) return "rate-limit";
142338
142563
  return "error";
142339
142564
  }
142340
- var import_node_child_process8, import_node_crypto9, fs9, path7, readline, ONE_SHOT_UNSAFE_TOOLS, ClaudeCodeAdapter;
142565
+ var import_node_child_process8, import_node_crypto10, fs9, path7, readline, ONE_SHOT_UNSAFE_TOOLS, ClaudeCodeAdapter;
142341
142566
  var init_claude_code = __esm({
142342
142567
  "../adapters/src/claude-code/index.ts"() {
142343
142568
  "use strict";
142344
142569
  import_node_child_process8 = require("node:child_process");
142345
- import_node_crypto9 = require("node:crypto");
142570
+ import_node_crypto10 = require("node:crypto");
142346
142571
  fs9 = __toESM(require("node:fs"), 1);
142347
142572
  path7 = __toESM(require("node:path"), 1);
142348
142573
  readline = __toESM(require("node:readline"), 1);
@@ -142383,7 +142608,7 @@ var init_claude_code = __esm({
142383
142608
  }
142384
142609
  async spawn(job) {
142385
142610
  const slug6 = job.artifactId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 32);
142386
- const id = `claude-${slug6}-${(0, import_node_crypto9.randomUUID)().slice(0, 8)}`;
142611
+ const id = `claude-${slug6}-${(0, import_node_crypto10.randomUUID)().slice(0, 8)}`;
142387
142612
  const dir = job.workdirKey ? prepareWorkdir({
142388
142613
  workRoot: this.opts.workRoot,
142389
142614
  runtimeKind: "claude",
@@ -143749,12 +143974,12 @@ function normalizeCodexConsoleLine(line, state = createCodexNormalizeState()) {
143749
143974
  tool.output.push(line);
143750
143975
  return [];
143751
143976
  }
143752
- var import_node_child_process10, import_node_crypto10, fs10, os4, path9, readline2, CODEX_ARGV_PROMPT_MAX_BYTES, CodexAdapter;
143977
+ var import_node_child_process10, import_node_crypto11, fs10, os4, path9, readline2, CODEX_ARGV_PROMPT_MAX_BYTES, CodexAdapter;
143753
143978
  var init_codex = __esm({
143754
143979
  "../adapters/src/codex/index.ts"() {
143755
143980
  "use strict";
143756
143981
  import_node_child_process10 = require("node:child_process");
143757
- import_node_crypto10 = require("node:crypto");
143982
+ import_node_crypto11 = require("node:crypto");
143758
143983
  fs10 = __toESM(require("node:fs"), 1);
143759
143984
  os4 = __toESM(require("node:os"), 1);
143760
143985
  path9 = __toESM(require("node:path"), 1);
@@ -143781,7 +144006,7 @@ var init_codex = __esm({
143781
144006
  capabilities = { appendInput: false };
143782
144007
  async spawn(job) {
143783
144008
  const slug6 = job.artifactId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 32);
143784
- const id = `codex-${slug6}-${(0, import_node_crypto10.randomUUID)().slice(0, 8)}`;
144009
+ const id = `codex-${slug6}-${(0, import_node_crypto11.randomUUID)().slice(0, 8)}`;
143785
144010
  const startedAtMs = Date.now();
143786
144011
  const dir = job.workdirKey ? prepareWorkdir({
143787
144012
  workRoot: this.opts.workRoot,
@@ -144528,7 +144753,7 @@ function buildReportedUsage(acc, model, inputTokensIncludeCacheRead) {
144528
144753
  async function runACPSession(job, cfg) {
144529
144754
  const slug6 = job.artifactId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 32);
144530
144755
  const binTag = path10.basename(cfg.bin).replace(/[^a-zA-Z0-9]/g, "").slice(0, 12) || "acp";
144531
- const id = `${binTag}-${slug6}-${(0, import_node_crypto11.randomUUID)().slice(0, 8)}`;
144756
+ const id = `${binTag}-${slug6}-${(0, import_node_crypto12.randomUUID)().slice(0, 8)}`;
144532
144757
  const dir = job.workdirKey ? prepareWorkdir({
144533
144758
  workRoot: cfg.workRoot,
144534
144759
  runtimeKind: cfg.runtimeKind ?? "subprocess",
@@ -144832,12 +145057,12 @@ ${task2}` : task2;
144832
145057
  }
144833
145058
  };
144834
145059
  }
144835
- var import_node_child_process11, import_node_crypto11, fs11, path10, readline3, ACPClient;
145060
+ var import_node_child_process11, import_node_crypto12, fs11, path10, readline3, ACPClient;
144836
145061
  var init_acp = __esm({
144837
145062
  "../adapters/src/_core/acp.ts"() {
144838
145063
  "use strict";
144839
145064
  import_node_child_process11 = require("node:child_process");
144840
- import_node_crypto11 = require("node:crypto");
145065
+ import_node_crypto12 = require("node:crypto");
144841
145066
  fs11 = __toESM(require("node:fs"), 1);
144842
145067
  path10 = __toESM(require("node:path"), 1);
144843
145068
  readline3 = __toESM(require("node:readline"), 1);
@@ -145189,7 +145414,7 @@ var init_kiro = __esm({
145189
145414
  // ../adapters/src/_core/subprocess.ts
145190
145415
  async function materialize(job, cfg) {
145191
145416
  const slug6 = job.artifactId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 32);
145192
- const id = `${slug6}-${(0, import_node_crypto12.randomUUID)().slice(0, 8)}`;
145417
+ const id = `${slug6}-${(0, import_node_crypto13.randomUUID)().slice(0, 8)}`;
145193
145418
  const dir = job.workdirKey ? prepareWorkdir({
145194
145419
  workRoot: cfg.workRoot,
145195
145420
  runtimeKind: cfg.runtimeKind ?? "subprocess",
@@ -145411,12 +145636,12 @@ async function runOneShotText(job, cfg) {
145411
145636
  }
145412
145637
  });
145413
145638
  }
145414
- var import_node_child_process12, import_node_crypto12, fs12, path11, readline4;
145639
+ var import_node_child_process12, import_node_crypto13, fs12, path11, readline4;
145415
145640
  var init_subprocess = __esm({
145416
145641
  "../adapters/src/_core/subprocess.ts"() {
145417
145642
  "use strict";
145418
145643
  import_node_child_process12 = require("node:child_process");
145419
- import_node_crypto12 = require("node:crypto");
145644
+ import_node_crypto13 = require("node:crypto");
145420
145645
  fs12 = __toESM(require("node:fs"), 1);
145421
145646
  path11 = __toESM(require("node:path"), 1);
145422
145647
  readline4 = __toESM(require("node:readline"), 1);
@@ -145830,11 +146055,11 @@ function normalizeOpenClaw(line) {
145830
146055
  }
145831
146056
  return [];
145832
146057
  }
145833
- var import_node_crypto13, OpenClawAdapter;
146058
+ var import_node_crypto14, OpenClawAdapter;
145834
146059
  var init_openclaw = __esm({
145835
146060
  "../adapters/src/openclaw/index.ts"() {
145836
146061
  "use strict";
145837
- import_node_crypto13 = require("node:crypto");
146062
+ import_node_crypto14 = require("node:crypto");
145838
146063
  init_subprocess();
145839
146064
  OpenClawAdapter = class {
145840
146065
  constructor(opts = {}) {
@@ -145852,7 +146077,7 @@ var init_openclaw = __esm({
145852
146077
  ---
145853
146078
 
145854
146079
  ${task2}` : task2;
145855
- const sessionId = job2.runtimeSessionId ?? `oasis-${(0, import_node_crypto13.randomUUID)().slice(0, 8)}`;
146080
+ const sessionId = job2.runtimeSessionId ?? `oasis-${(0, import_node_crypto14.randomUUID)().slice(0, 8)}`;
145856
146081
  return [
145857
146082
  "agent",
145858
146083
  ...opts.mode !== "gateway" ? ["--local"] : [],
@@ -147591,12 +147816,12 @@ async function startOasisServer(opts) {
147591
147816
  if (!store || !dispatch) return;
147592
147817
  const session = await store.getSession(origin).catch(() => null);
147593
147818
  if (!session) return;
147594
- const { randomUUID: randomUUID29 } = await import("node:crypto");
147819
+ const { randomUUID: randomUUID31 } = await import("node:crypto");
147595
147820
  const approved = resolution.status === "approved";
147596
147821
  const by = ctx.authorizedBy ?? "\u7BA1\u7406\u8005";
147597
147822
  const label = ctx.effectLabel || ctx.command || "";
147598
147823
  const statusText = approved ? `\u547D\u4EE4\u5DF2\u7531 ${by} \u6279\u51C6\u5E76\u4EE5\u5176\u540D\u4E49\u6267\u884C${label ? `\uFF1A${label}` : ""}\u3002` : `\u547D\u4EE4\u5DF2\u88AB ${by} \u9A73\u56DE${ctx.reason ? `\uFF1A${ctx.reason}` : ""}\u3002`;
147599
- await store.appendMessage({ id: randomUUID29(), sessionId: origin, role: "system", content: statusText, createdAt: (/* @__PURE__ */ new Date()).toISOString() }).catch(() => void 0);
147824
+ await store.appendMessage({ id: randomUUID31(), sessionId: origin, role: "system", content: statusText, createdAt: (/* @__PURE__ */ new Date()).toISOString() }).catch(() => void 0);
147600
147825
  if (liveChat.isRunning(origin)) return;
147601
147826
  const prompt = approved ? `\u4E0A\u4E00\u6761\u5F85\u6388\u6743\u547D\u4EE4\u5DF2\u88AB ${by} \u6279\u51C6\u5E76\u4EE5\u5176\u540D\u4E49\u6267\u884C\uFF08\u547D\u4EE4\uFF1A${label}\uFF09\u3002\u8BF7\u7EE7\u7EED\u539F\u4EFB\u52A1\u3002` : `\u4E0A\u4E00\u6761\u5F85\u6388\u6743\u547D\u4EE4\u5DF2\u88AB ${by} \u9A73\u56DE${ctx.reason ? `\uFF08\u7406\u7531\uFF1A${ctx.reason}\uFF09` : ""}\u3002\u522B\u91CD\u8BD5\u540C\u4E00\u6761\u2014\u2014\u8BF7\u6539\u65B9\u6848\u6216\u5148\u5411\u53D1\u8D77\u4EBA\u95EE\u6E05\u695A\u3002`;
147602
147827
  let dispatched;
@@ -147617,7 +147842,7 @@ async function startOasisServer(opts) {
147617
147842
  void dispatched.done.then(async () => {
147618
147843
  if (text2 || dispatched.runId) {
147619
147844
  await store.appendMessage({
147620
- id: randomUUID29(),
147845
+ id: randomUUID31(),
147621
147846
  sessionId: origin,
147622
147847
  role: "assistant",
147623
147848
  content: text2,
@@ -148268,11 +148493,11 @@ async function startOasisServer(opts) {
148268
148493
  const itemKey = `${baseItemKey}:${ctx.ownerId}`;
148269
148494
  let chatSessionId;
148270
148495
  if (chatStore) {
148271
- const { randomUUID: randomUUID29 } = await import("node:crypto");
148496
+ const { randomUUID: randomUUID31 } = await import("node:crypto");
148272
148497
  const known = discussSessions.get(itemKey);
148273
148498
  if (known && await chatStore.getSession(known).catch(() => null)) chatSessionId = known;
148274
148499
  if (!chatSessionId) {
148275
- chatSessionId = randomUUID29();
148500
+ chatSessionId = randomUUID31();
148276
148501
  const now = (/* @__PURE__ */ new Date()).toISOString();
148277
148502
  const title = `\u89E3\u51B3\uFF1A${ctx.seed.slice(ctx.seed.indexOf("\uFF1A") + 1, ctx.seed.indexOf("\uFF1A") + 25) || "\u5DE5\u5355\u5361\u70B9"}`;
148278
148503
  const reg0 = (await resolveEngine(currentCompanyId).catch(() => null))?.registry ?? opts.registry;
@@ -148722,14 +148947,14 @@ async function startOasisServer(opts) {
148722
148947
  runtimeSessionId: session.nativeSessionId ?? session.id
148723
148948
  }).catch(() => void 0);
148724
148949
  }
148725
- const { randomUUID: randomUUID30 } = await import("node:crypto");
148950
+ const { randomUUID: randomUUID32 } = await import("node:crypto");
148726
148951
  const persistAttachments = attachments.map((a) => ({
148727
148952
  name: a.name,
148728
148953
  ...a.blobRef !== void 0 ? { blobRef: a.blobRef } : {},
148729
148954
  ...a.contentType !== void 0 ? { contentType: a.contentType } : {}
148730
148955
  }));
148731
148956
  await chatStore.appendMessage({
148732
- id: randomUUID30(),
148957
+ id: randomUUID32(),
148733
148958
  sessionId: persistTarget.id,
148734
148959
  role: "user",
148735
148960
  content: persistedUserMessage,
@@ -148739,8 +148964,8 @@ async function startOasisServer(opts) {
148739
148964
  }
148740
148965
  let assistantMsgId;
148741
148966
  if (chatStore && persistTarget) {
148742
- const { randomUUID: randomUUID30 } = await import("node:crypto");
148743
- const id = randomUUID30();
148967
+ const { randomUUID: randomUUID32 } = await import("node:crypto");
148968
+ const id = randomUUID32();
148744
148969
  await chatStore.appendMessage({
148745
148970
  id,
148746
148971
  sessionId: persistTarget.id,
@@ -148776,9 +149001,9 @@ async function startOasisServer(opts) {
148776
149001
  }).catch(() => void 0);
148777
149002
  } else {
148778
149003
  if (!assistantText && !session.runId && parts.length === 0) return;
148779
- const { randomUUID: randomUUID30 } = await import("node:crypto");
149004
+ const { randomUUID: randomUUID32 } = await import("node:crypto");
148780
149005
  await chatStore.appendMessage({
148781
- id: randomUUID30(),
149006
+ id: randomUUID32(),
148782
149007
  sessionId: persistTarget.id,
148783
149008
  role: "assistant",
148784
149009
  content: assistantText,
@@ -149011,8 +149236,8 @@ async function startOasisServer(opts) {
149011
149236
  }
149012
149237
  }
149013
149238
  const { spawn: spawn7 } = await import("node:child_process");
149014
- const { randomUUID: randomUUID29 } = await import("node:crypto");
149015
- const sessionId = body.sessionId ?? randomUUID29();
149239
+ const { randomUUID: randomUUID31 } = await import("node:crypto");
149240
+ const sessionId = body.sessionId ?? randomUUID31();
149016
149241
  const args = [
149017
149242
  "-p",
149018
149243
  body.message,
@@ -149513,10 +149738,10 @@ function createTokenIssuer(opts = {}) {
149513
149738
  if (revoked.has(token)) return null;
149514
149739
  if (!token.startsWith(SESSION_TOKEN_PREFIX)) return null;
149515
149740
  const encoded = token.slice(SESSION_TOKEN_PREFIX.length);
149516
- const sep3 = encoded.indexOf(".");
149517
- if (sep3 <= 0) return null;
149518
- const payload = encoded.slice(0, sep3);
149519
- const actualSig = encoded.slice(sep3 + 1);
149741
+ const sep4 = encoded.indexOf(".");
149742
+ if (sep4 <= 0) return null;
149743
+ const payload = encoded.slice(0, sep4);
149744
+ const actualSig = encoded.slice(sep4 + 1);
149520
149745
  const expectedSig = sign(secret, payload);
149521
149746
  if (!signatureMatches(actualSig, expectedSig)) return null;
149522
149747
  let claims;
@@ -149574,7 +149799,7 @@ function createNodeTokenStore(file) {
149574
149799
  return {
149575
149800
  issue(nodeId) {
149576
149801
  const table = read();
149577
- const token = `ont_${(0, import_node_crypto14.randomBytes)(24).toString("base64url")}`;
149802
+ const token = `ont_${(0, import_node_crypto15.randomBytes)(24).toString("base64url")}`;
149578
149803
  table[token] = nodeId;
149579
149804
  write(table);
149580
149805
  return token;
@@ -149616,7 +149841,7 @@ function createEnrollTokenStore(defaultTtlMs = 30 * 60 * 1e3, file) {
149616
149841
  return {
149617
149842
  issue(name, ttlMs = defaultTtlMs) {
149618
149843
  const m2 = prune();
149619
- const token = `ent_${(0, import_node_crypto14.randomBytes)(24).toString("base64url")}`;
149844
+ const token = `ent_${(0, import_node_crypto15.randomBytes)(24).toString("base64url")}`;
149620
149845
  const expiresAt = Date.now() + ttlMs;
149621
149846
  m2.set(token, { name, expiresAt });
149622
149847
  write(m2);
@@ -149646,33 +149871,33 @@ function createEnrollTokenStore(defaultTtlMs = 30 * 60 * 1e3, file) {
149646
149871
  }
149647
149872
  };
149648
149873
  }
149649
- var import_node_crypto14, fs14, path13, SESSION_TOKEN_PREFIX, b64url, fromB64url, readOrCreateSecret, sign, signatureMatches, isTokenClaims;
149874
+ var import_node_crypto15, fs14, path13, SESSION_TOKEN_PREFIX, b64url, fromB64url, readOrCreateSecret, sign, signatureMatches, isTokenClaims;
149650
149875
  var init_tokens = __esm({
149651
149876
  "../server/src/tokens.ts"() {
149652
149877
  "use strict";
149653
- import_node_crypto14 = require("node:crypto");
149878
+ import_node_crypto15 = require("node:crypto");
149654
149879
  fs14 = __toESM(require("node:fs"), 1);
149655
149880
  path13 = __toESM(require("node:path"), 1);
149656
149881
  SESSION_TOKEN_PREFIX = "oat_v2_";
149657
149882
  b64url = (value2) => Buffer.from(value2).toString("base64url");
149658
149883
  fromB64url = (value2) => Buffer.from(value2, "base64url").toString("utf8");
149659
149884
  readOrCreateSecret = (file) => {
149660
- if (!file) return (0, import_node_crypto14.randomBytes)(32);
149885
+ if (!file) return (0, import_node_crypto15.randomBytes)(32);
149661
149886
  try {
149662
149887
  const raw = fs14.readFileSync(file, "utf8").trim();
149663
149888
  if (raw) return Buffer.from(raw, "base64url");
149664
149889
  } catch {
149665
149890
  }
149666
- const secret = (0, import_node_crypto14.randomBytes)(32);
149891
+ const secret = (0, import_node_crypto15.randomBytes)(32);
149667
149892
  fs14.mkdirSync(path13.dirname(file), { recursive: true });
149668
149893
  fs14.writeFileSync(file, secret.toString("base64url"), { mode: 384 });
149669
149894
  return secret;
149670
149895
  };
149671
- sign = (secret, payload) => (0, import_node_crypto14.createHmac)("sha256", secret).update(payload).digest("base64url");
149896
+ sign = (secret, payload) => (0, import_node_crypto15.createHmac)("sha256", secret).update(payload).digest("base64url");
149672
149897
  signatureMatches = (actual, expected) => {
149673
149898
  const a = Buffer.from(actual);
149674
149899
  const b2 = Buffer.from(expected);
149675
- return a.length === b2.length && (0, import_node_crypto14.timingSafeEqual)(a, b2);
149900
+ return a.length === b2.length && (0, import_node_crypto15.timingSafeEqual)(a, b2);
149676
149901
  };
149677
149902
  isTokenClaims = (value2) => {
149678
149903
  if (value2 === null || typeof value2 !== "object") return false;
@@ -150889,11 +151114,11 @@ function onlyHits(pool, q) {
150889
151114
  if (!q.requireMatch || q.keywords.length === 0) return [...pool];
150890
151115
  return pool.filter((r) => memoryMatchScore(r, q.keywords) > 0);
150891
151116
  }
150892
- var import_node_crypto15, MemoryActorMemoryStore, toIndexEntry;
151117
+ var import_node_crypto16, MemoryActorMemoryStore, toIndexEntry;
150893
151118
  var init_memory_actor_memory_store = __esm({
150894
151119
  "../testkit/src/memory-actor-memory-store.ts"() {
150895
151120
  "use strict";
150896
- import_node_crypto15 = require("node:crypto");
151121
+ import_node_crypto16 = require("node:crypto");
150897
151122
  init_src();
150898
151123
  MemoryActorMemoryStore = class {
150899
151124
  rows = /* @__PURE__ */ new Map();
@@ -150947,7 +151172,7 @@ var init_memory_actor_memory_store = __esm({
150947
151172
  async write(input, now) {
150948
151173
  if (input.memId === void 0) {
150949
151174
  const rec = {
150950
- memId: `mem:${(0, import_node_crypto15.randomUUID)()}`,
151175
+ memId: `mem:${(0, import_node_crypto16.randomUUID)()}`,
150951
151176
  actorId: input.actorId,
150952
151177
  projectId: input.projectId,
150953
151178
  keywords: [...input.keywords],
@@ -152662,11 +152887,11 @@ var init_service2 = __esm({
152662
152887
  });
152663
152888
 
152664
152889
  // ../server/src/dev-store.ts
152665
- var import_node_crypto16, fs15, path14, NdjsonOplogStore, DirBlobStore, MUTATORS, FileTypeRegistryStore, FileRoleRegistryStore, FileRegistryStore, FileAssistantBindStore, FileHumanPrefsStore, FileProjectStateStore, FileProjectDocumentStore, FileArtifactStateStore, FileTraceStore, MemoryChatSessionStore, FileChatSessionStore, MemoryReadMarkerStore, FileReadMarkerStore;
152890
+ var import_node_crypto17, fs15, path14, NdjsonOplogStore, DirBlobStore, MUTATORS, FileTypeRegistryStore, FileRoleRegistryStore, FileRegistryStore, FileAssistantBindStore, FileHumanPrefsStore, FileProjectStateStore, FileProjectDocumentStore, FileArtifactStateStore, FileTraceStore, MemoryChatSessionStore, FileChatSessionStore, MemoryReadMarkerStore, FileReadMarkerStore;
152666
152891
  var init_dev_store = __esm({
152667
152892
  "../server/src/dev-store.ts"() {
152668
152893
  "use strict";
152669
- import_node_crypto16 = require("node:crypto");
152894
+ import_node_crypto17 = require("node:crypto");
152670
152895
  fs15 = __toESM(require("node:fs"), 1);
152671
152896
  path14 = __toESM(require("node:path"), 1);
152672
152897
  init_src();
@@ -152720,7 +152945,7 @@ var init_dev_store = __esm({
152720
152945
  return path14.join(this.dir, hash);
152721
152946
  }
152722
152947
  async put(bytes) {
152723
- const hash = (0, import_node_crypto16.createHash)("sha256").update(bytes).digest("hex");
152948
+ const hash = (0, import_node_crypto17.createHash)("sha256").update(bytes).digest("hex");
152724
152949
  const file = this.fileOf(hash);
152725
152950
  if (!fs15.existsSync(file)) fs15.writeFileSync(file, bytes);
152726
152951
  return hash;
@@ -153457,11 +153682,11 @@ function typeDefError(def, mode) {
153457
153682
  }
153458
153683
  return null;
153459
153684
  }
153460
- var import_node_crypto17, RESERVED_FIELD_NAMES, ARTIFACT_TYPE_ACCENTS, TYPE_DEF_SCHEMA, TypesAdminService;
153685
+ var import_node_crypto18, RESERVED_FIELD_NAMES, ARTIFACT_TYPE_ACCENTS, TYPE_DEF_SCHEMA, TypesAdminService;
153461
153686
  var init_types_admin = __esm({
153462
153687
  "../server/src/types-admin.ts"() {
153463
153688
  "use strict";
153464
- import_node_crypto17 = require("node:crypto");
153689
+ import_node_crypto18 = require("node:crypto");
153465
153690
  init_zod();
153466
153691
  init_src2();
153467
153692
  init_config_audit();
@@ -153578,7 +153803,7 @@ var init_types_admin = __esm({
153578
153803
  async trace(change, target, by, detail) {
153579
153804
  try {
153580
153805
  await this.audit?.({
153581
- id: `reg_${(0, import_node_crypto17.randomUUID)()}`,
153806
+ id: `reg_${(0, import_node_crypto18.randomUUID)()}`,
153582
153807
  actor: by ?? SYSTEM_CONFIG_ACTOR,
153583
153808
  kind: "registry_change",
153584
153809
  target,
@@ -153726,11 +153951,11 @@ function roleDefError(def, mode) {
153726
153951
  }
153727
153952
  return null;
153728
153953
  }
153729
- var import_node_crypto18, ACCENTS, ROLE_DEF_SCHEMA, RolesAdminService;
153954
+ var import_node_crypto19, ACCENTS, ROLE_DEF_SCHEMA, RolesAdminService;
153730
153955
  var init_roles_admin = __esm({
153731
153956
  "../server/src/roles-admin.ts"() {
153732
153957
  "use strict";
153733
- import_node_crypto18 = require("node:crypto");
153958
+ import_node_crypto19 = require("node:crypto");
153734
153959
  init_zod();
153735
153960
  init_src2();
153736
153961
  init_config_audit();
@@ -153755,7 +153980,7 @@ var init_roles_admin = __esm({
153755
153980
  async trace(change, target, by, detail) {
153756
153981
  try {
153757
153982
  await this.deps.audit?.({
153758
- id: `reg_${(0, import_node_crypto18.randomUUID)()}`,
153983
+ id: `reg_${(0, import_node_crypto19.randomUUID)()}`,
153759
153984
  actor: by ?? SYSTEM_CONFIG_ACTOR,
153760
153985
  kind: "registry_change",
153761
153986
  target,
@@ -155113,6 +155338,7 @@ async function planChatTurnRecovery(deps) {
155113
155338
  assistantMsgId: row.id,
155114
155339
  runId: run.id,
155115
155340
  artifactId: run.artifactId,
155341
+ actor: run.actorId,
155116
155342
  ...run.runtimeKind ? { runtimeKind: run.runtimeKind } : {},
155117
155343
  ...runtimeSessionId ? { runtimeSessionId } : {},
155118
155344
  startedAt: run.startedAt,
@@ -155210,7 +155436,7 @@ function wireRecoveredChatTurn(deps) {
155210
155436
  const segText = assistantText;
155211
155437
  const segParts = collectedParts();
155212
155438
  const closingId = currentMsgId;
155213
- const nextId = (0, import_node_crypto19.randomUUID)();
155439
+ const nextId = (0, import_node_crypto20.randomUUID)();
155214
155440
  assistantText = "";
155215
155441
  currentMsgId = nextId;
155216
155442
  segmentBaseSeq = live.bufferedParts().reduce((max, p2) => p2.seq > max ? p2.seq : max, 0);
@@ -155223,7 +155449,7 @@ function wireRecoveredChatTurn(deps) {
155223
155449
  ...segParts.length ? { parts: segParts } : {}
155224
155450
  }).catch(() => void 0);
155225
155451
  await store.appendMessage({
155226
- id: (0, import_node_crypto19.randomUUID)(),
155452
+ id: (0, import_node_crypto20.randomUUID)(),
155227
155453
  sessionId: plan.chatSessionId,
155228
155454
  role: "user",
155229
155455
  content: text2,
@@ -155403,11 +155629,11 @@ async function reconcileChatExitFrame(deps) {
155403
155629
  }
155404
155630
  return false;
155405
155631
  }
155406
- var import_node_crypto19, asObj3, partsOf, maxPartSeq, exitFailed, exitErrorText, runTerminalPatch;
155632
+ var import_node_crypto20, asObj3, partsOf, maxPartSeq, exitFailed, exitErrorText, runTerminalPatch;
155407
155633
  var init_chat_recovery = __esm({
155408
155634
  "../server/src/chat-recovery.ts"() {
155409
155635
  "use strict";
155410
- import_node_crypto19 = require("node:crypto");
155636
+ import_node_crypto20 = require("node:crypto");
155411
155637
  init_chat_parts();
155412
155638
  init_sink();
155413
155639
  asObj3 = (v2) => v2 && typeof v2 === "object" && !Array.isArray(v2) ? v2 : void 0;
@@ -155432,8 +155658,8 @@ var init_chat_recovery = __esm({
155432
155658
 
155433
155659
  // ../server/src/auth/crypto.ts
155434
155660
  function hashPassword(password) {
155435
- const salt = (0, import_node_crypto20.randomBytes)(16);
155436
- const dk = (0, import_node_crypto20.scryptSync)(password, salt, SCRYPT_KEYLEN, { N: SCRYPT_N, maxmem: 64 * 1024 * 1024 });
155661
+ const salt = (0, import_node_crypto21.randomBytes)(16);
155662
+ const dk = (0, import_node_crypto21.scryptSync)(password, salt, SCRYPT_KEYLEN, { N: SCRYPT_N, maxmem: 64 * 1024 * 1024 });
155437
155663
  return `scrypt$${SCRYPT_N}$${salt.toString("base64url")}$${dk.toString("base64url")}`;
155438
155664
  }
155439
155665
  function verifyPassword(password, stored) {
@@ -155450,8 +155676,8 @@ function verifyPassword(password, stored) {
155450
155676
  return false;
155451
155677
  }
155452
155678
  if (expected.length === 0) return false;
155453
- const dk = (0, import_node_crypto20.scryptSync)(password, salt, expected.length, { N, maxmem: 64 * 1024 * 1024 });
155454
- return dk.length === expected.length && (0, import_node_crypto20.timingSafeEqual)(dk, expected);
155679
+ const dk = (0, import_node_crypto21.scryptSync)(password, salt, expected.length, { N, maxmem: 64 * 1024 * 1024 });
155680
+ return dk.length === expected.length && (0, import_node_crypto21.timingSafeEqual)(dk, expected);
155455
155681
  }
155456
155682
  function b64urlJson(value2) {
155457
155683
  return Buffer.from(JSON.stringify(value2)).toString("base64url");
@@ -155459,17 +155685,17 @@ function b64urlJson(value2) {
155459
155685
  function signSession(claims, secret) {
155460
155686
  const head = b64urlJson({ alg: "HS256", typ: "JWT" });
155461
155687
  const body = b64urlJson(claims);
155462
- const sig = (0, import_node_crypto20.createHmac)("sha256", secret).update(`${head}.${body}`).digest("base64url");
155688
+ const sig = (0, import_node_crypto21.createHmac)("sha256", secret).update(`${head}.${body}`).digest("base64url");
155463
155689
  return `${head}.${body}.${sig}`;
155464
155690
  }
155465
155691
  function verifySession(token, secret, nowMs) {
155466
155692
  const parts = token.split(".");
155467
155693
  if (parts.length !== 3) return null;
155468
155694
  const [head, body, sig] = parts;
155469
- const expected = (0, import_node_crypto20.createHmac)("sha256", secret).update(`${head}.${body}`).digest("base64url");
155695
+ const expected = (0, import_node_crypto21.createHmac)("sha256", secret).update(`${head}.${body}`).digest("base64url");
155470
155696
  const got = Buffer.from(sig);
155471
155697
  const exp = Buffer.from(expected);
155472
- if (got.length !== exp.length || !(0, import_node_crypto20.timingSafeEqual)(got, exp)) return null;
155698
+ if (got.length !== exp.length || !(0, import_node_crypto21.timingSafeEqual)(got, exp)) return null;
155473
155699
  let claims;
155474
155700
  try {
155475
155701
  claims = JSON.parse(Buffer.from(body, "base64url").toString("utf8"));
@@ -155481,21 +155707,21 @@ function verifySession(token, secret, nowMs) {
155481
155707
  return claims;
155482
155708
  }
155483
155709
  function generateCode() {
155484
- return String((0, import_node_crypto20.randomInt)(0, 1e6)).padStart(6, "0");
155710
+ return String((0, import_node_crypto21.randomInt)(0, 1e6)).padStart(6, "0");
155485
155711
  }
155486
155712
  function hashCode(code, secret) {
155487
- return (0, import_node_crypto20.createHmac)("sha256", secret).update(`code:${code}`).digest("base64url");
155713
+ return (0, import_node_crypto21.createHmac)("sha256", secret).update(`code:${code}`).digest("base64url");
155488
155714
  }
155489
155715
  function safeEqualHash(a, b2) {
155490
155716
  const ba = Buffer.from(a);
155491
155717
  const bb = Buffer.from(b2);
155492
- return ba.length === bb.length && (0, import_node_crypto20.timingSafeEqual)(ba, bb);
155718
+ return ba.length === bb.length && (0, import_node_crypto21.timingSafeEqual)(ba, bb);
155493
155719
  }
155494
- var import_node_crypto20, SCRYPT_N, SCRYPT_KEYLEN;
155720
+ var import_node_crypto21, SCRYPT_N, SCRYPT_KEYLEN;
155495
155721
  var init_crypto2 = __esm({
155496
155722
  "../server/src/auth/crypto.ts"() {
155497
155723
  "use strict";
155498
- import_node_crypto20 = require("node:crypto");
155724
+ import_node_crypto21 = require("node:crypto");
155499
155725
  SCRYPT_N = 16384;
155500
155726
  SCRYPT_KEYLEN = 32;
155501
155727
  }
@@ -156024,13 +156250,13 @@ function variableKeyFromEnv(env = process.env) {
156024
156250
  return buf;
156025
156251
  }
156026
156252
  if (env.NODE_ENV === "production") throw new Error("OASIS_VAR_KEY is required in production");
156027
- return (0, import_node_crypto21.createHash)("sha256").update("oasis-dev-only-variable-key").digest();
156253
+ return (0, import_node_crypto22.createHash)("sha256").update("oasis-dev-only-variable-key").digest();
156028
156254
  }
156029
- var import_node_crypto21, REDACTED_MARKER, ActorsService, mask, changedKeys;
156255
+ var import_node_crypto22, REDACTED_MARKER, ActorsService, mask, changedKeys;
156030
156256
  var init_service3 = __esm({
156031
156257
  "../server/src/domains/actors/service.ts"() {
156032
156258
  "use strict";
156033
- import_node_crypto21 = require("node:crypto");
156259
+ import_node_crypto22 = require("node:crypto");
156034
156260
  init_skill_fetcher();
156035
156261
  init_identity();
156036
156262
  init_src5();
@@ -156424,7 +156650,7 @@ ${input.description}
156424
156650
  */
156425
156651
  buildSkillFile(skillId, path30, content, now) {
156426
156652
  const bytes = new TextEncoder().encode(content);
156427
- const blobHash = (0, import_node_crypto21.createHash)("sha256").update(bytes).digest("hex");
156653
+ const blobHash = (0, import_node_crypto22.createHash)("sha256").update(bytes).digest("hex");
156428
156654
  return { skillId, path: path30, content, blobHash, size: bytes.length, updatedAt: now };
156429
156655
  }
156430
156656
  /**
@@ -156779,15 +157005,15 @@ ${input.description}
156779
157005
  return env;
156780
157006
  }
156781
157007
  encrypt(plain) {
156782
- const iv = (0, import_node_crypto21.randomBytes)(12);
156783
- const cipher = (0, import_node_crypto21.createCipheriv)("aes-256-gcm", this.opts.variableKey, iv);
157008
+ const iv = (0, import_node_crypto22.randomBytes)(12);
157009
+ const cipher = (0, import_node_crypto22.createCipheriv)("aes-256-gcm", this.opts.variableKey, iv);
156784
157010
  const enc4 = Buffer.concat([cipher.update(plain, "utf8"), cipher.final()]);
156785
157011
  return [iv.toString("base64"), cipher.getAuthTag().toString("base64"), enc4.toString("base64")].join(".");
156786
157012
  }
156787
157013
  decrypt(packed) {
156788
157014
  const [iv, tag, data] = packed.split(".");
156789
157015
  if (!iv || !tag || typeof data !== "string") throw new Error("malformed ciphertext");
156790
- const decipher = (0, import_node_crypto21.createDecipheriv)("aes-256-gcm", this.opts.variableKey, Buffer.from(iv, "base64"));
157016
+ const decipher = (0, import_node_crypto22.createDecipheriv)("aes-256-gcm", this.opts.variableKey, Buffer.from(iv, "base64"));
156791
157017
  decipher.setAuthTag(Buffer.from(tag, "base64"));
156792
157018
  return Buffer.concat([decipher.update(Buffer.from(data, "base64")), decipher.final()]).toString("utf8");
156793
157019
  }
@@ -157628,7 +157854,7 @@ async function listSkillMetadataForActor(args) {
157628
157854
  usedDirs.add(dir);
157629
157855
  const sorted = [...metas].sort((a, b2) => a.path.localeCompare(b2.path));
157630
157856
  let latest = "1970-01-01T00:00:00.000Z";
157631
- const hasher = (0, import_node_crypto22.createHash)("sha256");
157857
+ const hasher = (0, import_node_crypto23.createHash)("sha256");
157632
157858
  for (const m2 of sorted) {
157633
157859
  if (m2.updatedAt > latest) latest = m2.updatedAt;
157634
157860
  hasher.update(m2.path);
@@ -157653,11 +157879,11 @@ async function listSkillMetadataForActor(args) {
157653
157879
  const dir = sanitizeSkillDir(c.name, c.slug);
157654
157880
  if (usedDirs.has(dir)) continue;
157655
157881
  usedDirs.add(dir);
157656
- const hasher = (0, import_node_crypto22.createHash)("sha256");
157882
+ const hasher = (0, import_node_crypto23.createHash)("sha256");
157657
157883
  for (const p2 of paths) {
157658
157884
  hasher.update(p2);
157659
157885
  hasher.update("\0");
157660
- hasher.update((0, import_node_crypto22.createHash)("sha256").update(c.files[p2]).digest("hex"));
157886
+ hasher.update((0, import_node_crypto23.createHash)("sha256").update(c.files[p2]).digest("hex"));
157661
157887
  hasher.update("\0");
157662
157888
  }
157663
157889
  out.push({
@@ -157678,11 +157904,11 @@ async function listSkillMetadataForActor(args) {
157678
157904
  const dir = sanitizeSkillDir(b2.name, b2.id);
157679
157905
  if (usedDirs.has(dir)) continue;
157680
157906
  usedDirs.add(dir);
157681
- const hasher = (0, import_node_crypto22.createHash)("sha256");
157907
+ const hasher = (0, import_node_crypto23.createHash)("sha256");
157682
157908
  for (const p2 of paths) {
157683
157909
  hasher.update(p2);
157684
157910
  hasher.update("\0");
157685
- hasher.update((0, import_node_crypto22.createHash)("sha256").update(b2.files[p2]).digest("hex"));
157911
+ hasher.update((0, import_node_crypto23.createHash)("sha256").update(b2.files[p2]).digest("hex"));
157686
157912
  hasher.update("\0");
157687
157913
  }
157688
157914
  out.push({
@@ -157702,7 +157928,7 @@ function builtinSkillToFiles(b2) {
157702
157928
  skillId: `builtin:${b2.id}`,
157703
157929
  path: path30,
157704
157930
  content,
157705
- blobHash: (0, import_node_crypto22.createHash)("sha256").update(content).digest("hex"),
157931
+ blobHash: (0, import_node_crypto23.createHash)("sha256").update(content).digest("hex"),
157706
157932
  size: Buffer.byteLength(content, "utf8"),
157707
157933
  updatedAt: "1970-01-01T00:00:00.000Z"
157708
157934
  }));
@@ -157726,7 +157952,7 @@ function sanitizeSkillDir(name, fallbackId) {
157726
157952
  if (byName) return byName;
157727
157953
  const byId = fallbackId ? fold2(fallbackId) : "";
157728
157954
  if (byId) return byId;
157729
- return `skill-${(0, import_node_crypto22.createHash)("sha256").update(name).digest("hex").slice(0, 8)}`;
157955
+ return `skill-${(0, import_node_crypto23.createHash)("sha256").update(name).digest("hex").slice(0, 8)}`;
157730
157956
  }
157731
157957
  async function materializeSkillFiles(args) {
157732
157958
  const skills = await args.service.listInstalledSkillsForActor(args.actorId);
@@ -157759,7 +157985,7 @@ function connectorSkillToFiles(c) {
157759
157985
  skillId: c.id,
157760
157986
  path: path30,
157761
157987
  content,
157762
- blobHash: (0, import_node_crypto22.createHash)("sha256").update(content).digest("hex"),
157988
+ blobHash: (0, import_node_crypto23.createHash)("sha256").update(content).digest("hex"),
157763
157989
  size: Buffer.byteLength(content, "utf8"),
157764
157990
  updatedAt: "1970-01-01T00:00:00.000Z"
157765
157991
  }));
@@ -157776,11 +158002,11 @@ function connectorSkillDisplayRows(connectorSkills, enabledConnectors) {
157776
158002
  ...s2.version !== void 0 ? { version: s2.version } : {}
157777
158003
  }));
157778
158004
  }
157779
- var import_node_crypto22;
158005
+ var import_node_crypto23;
157780
158006
  var init_skill_materializer = __esm({
157781
158007
  "../server/src/domains/actors/skill-materializer.ts"() {
157782
158008
  "use strict";
157783
- import_node_crypto22 = require("node:crypto");
158009
+ import_node_crypto23 = require("node:crypto");
157784
158010
  }
157785
158011
  });
157786
158012
 
@@ -158719,7 +158945,7 @@ function createActorsDomain(opts) {
158719
158945
  ...kernel !== void 0 ? { onRolesChanged: (a, r) => kernel.setActorRoles(a, r) } : {},
158720
158946
  audit: async (entry) => {
158721
158947
  await opts.audit?.({
158722
- id: `reg_${(0, import_node_crypto23.randomUUID)()}`,
158948
+ id: `reg_${(0, import_node_crypto24.randomUUID)()}`,
158723
158949
  actor: entry.by,
158724
158950
  kind: "registry_change",
158725
158951
  target: entry.actorId,
@@ -158754,11 +158980,11 @@ function createActorsDomain(opts) {
158754
158980
  register: actorsDomain({ resolveCtx, ...opts.trace ? { trace: opts.trace } : {}, ...opts.listBuiltinSkills ? { listBuiltinSkills: opts.listBuiltinSkills } : {}, ...opts.getBuiltinSkills ? { getBuiltinSkills: opts.getBuiltinSkills } : {}, ...opts.getConnectorSkills ? { getConnectorSkills: opts.getConnectorSkills } : {}, ...opts.refreshConnectorSkills ? { refreshConnectorSkills: opts.refreshConnectorSkills } : {}, ...opts.memory ? { memory: opts.memory } : {} })
158755
158981
  };
158756
158982
  }
158757
- var import_node_crypto23;
158983
+ var import_node_crypto24;
158758
158984
  var init_actors = __esm({
158759
158985
  "../server/src/domains/actors/index.ts"() {
158760
158986
  "use strict";
158761
- import_node_crypto23 = require("node:crypto");
158987
+ import_node_crypto24 = require("node:crypto");
158762
158988
  init_service3();
158763
158989
  init_routes();
158764
158990
  init_service3();
@@ -159814,11 +160040,11 @@ var init_projects = __esm({
159814
160040
  });
159815
160041
 
159816
160042
  // ../server/src/domains/companies/service.ts
159817
- var import_node_crypto24, ROLES, INVITABLE_ROLES, INVITATION_TTL_MS, SLUG_RE, CompanyError, CompaniesService;
160043
+ var import_node_crypto25, ROLES, INVITABLE_ROLES, INVITATION_TTL_MS, SLUG_RE, CompanyError, CompaniesService;
159818
160044
  var init_service4 = __esm({
159819
160045
  "../server/src/domains/companies/service.ts"() {
159820
160046
  "use strict";
159821
- import_node_crypto24 = require("node:crypto");
160047
+ import_node_crypto25 = require("node:crypto");
159822
160048
  ROLES = ["owner", "admin", "member"];
159823
160049
  INVITABLE_ROLES = ["admin", "member"];
159824
160050
  INVITATION_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
@@ -159866,7 +160092,7 @@ var init_service4 = __esm({
159866
160092
  const existing = await this.store.getAccountByEmail(normalized);
159867
160093
  if (existing) return existing;
159868
160094
  const account = {
159869
- id: `actor:human:${(0, import_node_crypto24.randomUUID)()}`,
160095
+ id: `actor:human:${(0, import_node_crypto25.randomUUID)()}`,
159870
160096
  email: normalized,
159871
160097
  name: name ?? normalized,
159872
160098
  status: "active"
@@ -160026,7 +160252,7 @@ var init_service4 = __esm({
160026
160252
  }
160027
160253
  const nowMs = Date.parse(this.now());
160028
160254
  const invitation = {
160029
- id: `invitation:${(0, import_node_crypto24.randomUUID)()}`,
160255
+ id: `invitation:${(0, import_node_crypto25.randomUUID)()}`,
160030
160256
  companyId,
160031
160257
  email: mail,
160032
160258
  role,
@@ -161062,6 +161288,23 @@ function daemonVersionLess(a, b2) {
161062
161288
  function nodesDomain(deps) {
161063
161289
  const UPDATE_TIMEOUT_MS = 15e4;
161064
161290
  const nodeUpdates = /* @__PURE__ */ new Map();
161291
+ function runtimeInfoOf(r) {
161292
+ const activeRunCount = deps.activeRunCountOf?.(r.nodeId, r.kind) ?? 0;
161293
+ const activeRuns = deps.activeRunsOf?.(r.nodeId, r.kind);
161294
+ return {
161295
+ id: r.id,
161296
+ nodeId: r.nodeId,
161297
+ hostname: r.hostname,
161298
+ kind: r.kind,
161299
+ ...r.binary ? { binary: r.binary } : {},
161300
+ ...r.version ? { version: r.version } : {},
161301
+ status: r.status,
161302
+ busy: activeRunCount > 0,
161303
+ activeRunCount,
161304
+ ...activeRuns ? { activeRuns } : {},
161305
+ lastReportAt: r.lastSeenAt
161306
+ };
161307
+ }
161065
161308
  const publicUpdateStatus = (entry, activeRunCount) => ({
161066
161309
  state: entry.state,
161067
161310
  requestedAt: new Date(entry.requestedAtMs).toISOString(),
@@ -161211,21 +161454,7 @@ function nodesDomain(deps) {
161211
161454
  id: n.id,
161212
161455
  hostname: n.hostname,
161213
161456
  adapters: rts.map((r) => r.kind),
161214
- runtimes: rts.map((r) => {
161215
- const runtimeActiveRunCount = deps.activeRunCountOf?.(r.nodeId, r.kind) ?? 0;
161216
- return {
161217
- id: r.id,
161218
- nodeId: r.nodeId,
161219
- hostname: r.hostname,
161220
- kind: r.kind,
161221
- ...r.binary ? { binary: r.binary } : {},
161222
- ...r.version ? { version: r.version } : {},
161223
- status: r.status,
161224
- busy: runtimeActiveRunCount > 0,
161225
- activeRunCount: runtimeActiveRunCount,
161226
- lastReportAt: r.lastSeenAt
161227
- };
161228
- }),
161457
+ runtimes: rts.map(runtimeInfoOf),
161229
161458
  nodeVersion: n.nodeVersion,
161230
161459
  ...daemonVersion ? { daemonVersion } : {},
161231
161460
  ...n.name ? { name: n.name } : {},
@@ -161258,38 +161487,10 @@ function nodesDomain(deps) {
161258
161487
  const stale = [...new Set(rts.filter((r) => onlineIds.has(r.nodeId) && r.status !== "online").map((r) => r.nodeId))];
161259
161488
  if (stale.length > 0) {
161260
161489
  await Promise.all(stale.map((id) => syncConnectedDaemon(id, hub)));
161261
- return { status: 200, body: { items: (await deps.nodeStore.listRuntimes()).map((r) => {
161262
- const activeRunCount = deps.activeRunCountOf?.(r.nodeId, r.kind) ?? 0;
161263
- return {
161264
- id: r.id,
161265
- nodeId: r.nodeId,
161266
- hostname: r.hostname,
161267
- kind: r.kind,
161268
- ...r.binary ? { binary: r.binary } : {},
161269
- ...r.version ? { version: r.version } : {},
161270
- status: r.status,
161271
- busy: activeRunCount > 0,
161272
- activeRunCount,
161273
- lastReportAt: r.lastSeenAt
161274
- };
161275
- }) } };
161490
+ return { status: 200, body: { items: (await deps.nodeStore.listRuntimes()).map(runtimeInfoOf) } };
161276
161491
  }
161277
161492
  }
161278
- const items = rts.map((r) => {
161279
- const activeRunCount = deps.activeRunCountOf?.(r.nodeId, r.kind) ?? 0;
161280
- return {
161281
- id: r.id,
161282
- nodeId: r.nodeId,
161283
- hostname: r.hostname,
161284
- kind: r.kind,
161285
- ...r.binary ? { binary: r.binary } : {},
161286
- ...r.version ? { version: r.version } : {},
161287
- status: r.status,
161288
- busy: activeRunCount > 0,
161289
- activeRunCount,
161290
- lastReportAt: r.lastSeenAt
161291
- };
161292
- });
161493
+ const items = rts.map(runtimeInfoOf);
161293
161494
  return { status: 200, body: { items } };
161294
161495
  });
161295
161496
  router.post("/api/nodes/enroll", async (req) => {
@@ -161315,7 +161516,7 @@ function nodesDomain(deps) {
161315
161516
  nodeId = incomingNodeId;
161316
161517
  deps.enrollTokens.setIssuedNodeId(enrollToken, nodeId);
161317
161518
  } else {
161318
- nodeId = `node-${(0, import_node_crypto25.randomUUID)().slice(0, 8)}`;
161519
+ nodeId = `node-${(0, import_node_crypto26.randomUUID)().slice(0, 8)}`;
161319
161520
  deps.enrollTokens.setIssuedNodeId(enrollToken, nodeId);
161320
161521
  }
161321
161522
  const existingNode = await deps.nodeStore.getNode(nodeId);
@@ -161453,11 +161654,11 @@ function nodesDomain(deps) {
161453
161654
  });
161454
161655
  };
161455
161656
  }
161456
- var import_node_crypto25, import_node_fs11, import_node_url4, import_node_path13;
161657
+ var import_node_crypto26, import_node_fs11, import_node_url4, import_node_path13;
161457
161658
  var init_routes5 = __esm({
161458
161659
  "../server/src/domains/nodes/routes.ts"() {
161459
161660
  "use strict";
161460
- import_node_crypto25 = require("node:crypto");
161661
+ import_node_crypto26 = require("node:crypto");
161461
161662
  import_node_fs11 = require("node:fs");
161462
161663
  import_node_url4 = require("node:url");
161463
161664
  import_node_path13 = require("node:path");
@@ -162655,13 +162856,13 @@ function nameKey(name) {
162655
162856
  function cleanName(name) {
162656
162857
  return name.trim().replace(/\s+/g, " ");
162657
162858
  }
162658
- var import_node_fs12, import_node_path14, import_node_crypto26, SEP, keyOf, prefixOf, MemoryWorkorderTagStore, FileWorkorderTagStore;
162859
+ var import_node_fs12, import_node_path14, import_node_crypto27, SEP, keyOf, prefixOf, MemoryWorkorderTagStore, FileWorkorderTagStore;
162659
162860
  var init_tags = __esm({
162660
162861
  "../server/src/domains/collab/tags.ts"() {
162661
162862
  "use strict";
162662
162863
  import_node_fs12 = __toESM(require("node:fs"), 1);
162663
162864
  import_node_path14 = __toESM(require("node:path"), 1);
162664
- import_node_crypto26 = __toESM(require("node:crypto"), 1);
162865
+ import_node_crypto27 = __toESM(require("node:crypto"), 1);
162665
162866
  SEP = "::";
162666
162867
  keyOf = (companyId, id) => `${companyId}${SEP}${id}`;
162667
162868
  prefixOf = (companyId) => `${companyId}${SEP}`;
@@ -162679,7 +162880,7 @@ var init_tags = __esm({
162679
162880
  if (!name) return null;
162680
162881
  if (this.entries(companyId).some((t) => nameKey(t.name) === nameKey(name))) return null;
162681
162882
  const tag = {
162682
- id: `tag-${import_node_crypto26.default.randomBytes(6).toString("hex")}`,
162883
+ id: `tag-${import_node_crypto27.default.randomBytes(6).toString("hex")}`,
162683
162884
  name,
162684
162885
  ...input.color?.trim() ? { color: input.color.trim() } : {},
162685
162886
  ...input.description?.trim() ? { description: input.description.trim() } : {}
@@ -163274,7 +163475,7 @@ var init_collab = __esm({
163274
163475
 
163275
163476
  // ../server/src/domains/collab/create-seeded-workorder.ts
163276
163477
  function makeSeededWorkorderCreator(deps) {
163277
- const genWorkspace = deps.genWorkspace ?? (() => `ws:wo-${(0, import_node_crypto27.randomUUID)().slice(0, 8)}`);
163478
+ const genWorkspace = deps.genWorkspace ?? (() => `ws:wo-${(0, import_node_crypto28.randomUUID)().slice(0, 8)}`);
163278
163479
  return async (input) => {
163279
163480
  const workspace = genWorkspace();
163280
163481
  if (deps.artifactState && (input.projectId || deps.createProject)) {
@@ -163354,11 +163555,11 @@ function makeSeededWorkorderCreator(deps) {
163354
163555
  return { workspace, rootArtifactId: briefId, spawned: planned.spawned };
163355
163556
  };
163356
163557
  }
163357
- var import_node_crypto27, enc2;
163558
+ var import_node_crypto28, enc2;
163358
163559
  var init_create_seeded_workorder = __esm({
163359
163560
  "../server/src/domains/collab/create-seeded-workorder.ts"() {
163360
163561
  "use strict";
163361
- import_node_crypto27 = require("node:crypto");
163562
+ import_node_crypto28 = require("node:crypto");
163362
163563
  init_ephemeral_project();
163363
163564
  init_planner();
163364
163565
  enc2 = (s2) => new TextEncoder().encode(s2);
@@ -164212,7 +164413,7 @@ function createChatSessionsDomain(opts) {
164212
164413
  const runtimeId = await currentRuntimeId(body.aiActorId) ?? "unknown";
164213
164414
  const now = (/* @__PURE__ */ new Date()).toISOString();
164214
164415
  const session = {
164215
- id: (0, import_node_crypto28.randomUUID)(),
164416
+ id: (0, import_node_crypto29.randomUUID)(),
164216
164417
  humanActorId: req.auth.actor,
164217
164418
  aiActorId: body.aiActorId,
164218
164419
  runtimeId,
@@ -164285,7 +164486,7 @@ function createChatSessionsDomain(opts) {
164285
164486
  if (body.role !== "user" && body.role !== "assistant") throw new ApiError(400, "BAD_REQUEST", "role must be user or assistant");
164286
164487
  const role = body.role;
164287
164488
  const msg = await store.appendMessage({
164288
- id: (0, import_node_crypto28.randomUUID)(),
164489
+ id: (0, import_node_crypto29.randomUUID)(),
164289
164490
  sessionId: req.params.id,
164290
164491
  role,
164291
164492
  content: role === "user" ? stripInjectedChatContext(body.content) : body.content,
@@ -164377,11 +164578,11 @@ function createChatSessionsDomain(opts) {
164377
164578
  });
164378
164579
  };
164379
164580
  }
164380
- var import_node_crypto28, WORKDIR_READ_MAX_BYTES;
164581
+ var import_node_crypto29, WORKDIR_READ_MAX_BYTES;
164381
164582
  var init_chat_sessions = __esm({
164382
164583
  "../server/src/domains/chat-sessions/index.ts"() {
164383
164584
  "use strict";
164384
- import_node_crypto28 = require("node:crypto");
164585
+ import_node_crypto29 = require("node:crypto");
164385
164586
  init_chat_session();
164386
164587
  init_router();
164387
164588
  init_workorders();
@@ -165592,14 +165793,294 @@ var init_project_binding = __esm({
165592
165793
  }
165593
165794
  });
165594
165795
 
165796
+ // ../server/src/domains/evaluation/judge-prompt.ts
165797
+ function builtinRubricsForCase(evaluationCase) {
165798
+ const at = "1970-01-01T00:00:00.000Z";
165799
+ const base = {
165800
+ companyId: "",
165801
+ version: 0,
165802
+ status: "active",
165803
+ createdBy: "system",
165804
+ createdAt: at,
165805
+ updatedBy: "system",
165806
+ updatedAt: at
165807
+ };
165808
+ return [
165809
+ {
165810
+ ...base,
165811
+ rubricId: "builtin:common",
165812
+ name: "\u901A\u7528\u80FD\u529B\u6807\u51C6\uFF08Case \u81EA\u5E26\uFF09",
165813
+ kind: "common",
165814
+ promptSection: evaluationCase.commonRubric,
165815
+ outputSpec: BUILTIN_COMMON_OUTPUT_SPEC
165816
+ },
165817
+ {
165818
+ ...base,
165819
+ rubricId: "builtin:specialty",
165820
+ name: `S \u4E13\u9879\u6807\u51C6\uFF08${evaluationCase.scopeType}\uFF0CCase \u81EA\u5E26\uFF09`,
165821
+ kind: "specialty",
165822
+ // 「只看可读专业产物」这条约束原先写在硬编码提示词里、不在 bench 的专项标准正文里。
165823
+ // 搬到这里而不是丢掉——它同时还有代码侧的事后守卫(enforceSpecialtyArtifactBoundary),
165824
+ // 两边必须说同一件事,否则模型评了分又被守卫抹掉,白跑一轮还看不懂为什么。
165825
+ promptSection: [
165826
+ "S \u4E13\u9879\u53EA\u80FD\u4F9D\u636E artifacts \u4E2D\u53EF\u8BFB\u7684\u4E13\u4E1A\u4EA7\u7269\u6B63\u6587\u5224\u65AD\u3002Trace\u3001\u8282\u70B9\u6458\u8981\u548C Brief \u4E0D\u80FD\u66FF\u4EE3\u4E13\u4E1A\u4EA7\u7269\u3002",
165827
+ "\u6CA1\u6709\u53EF\u8BFB\u4E13\u4E1A\u4EA7\u7269\u65F6\uFF0C\u4E94\u9879 score\u3001specialty.score \u548C specialty.score100 \u5FC5\u987B\u5168\u90E8\u4E3A null\u3002",
165828
+ "",
165829
+ evaluationCase.specialtyRubric
165830
+ ].join("\n"),
165831
+ outputSpec: BUILTIN_SPECIALTY_OUTPUT_SPEC
165832
+ },
165833
+ {
165834
+ ...base,
165835
+ rubricId: "builtin:case_special",
165836
+ name: "Case \u4E13\u9879\u6807\u51C6\uFF08Case \u81EA\u5E26\uFF09",
165837
+ kind: "case_special",
165838
+ promptSection: [
165839
+ "\u53EA\u4F9D\u636E\u6700\u7EC8\u4EA7\u7269\u53CA evaluator \u7ED3\u679C\u7ED9\u5206\u3002",
165840
+ "evaluator.type=native \u7684\u9879\u76EE\u53EA\u80FD\u8BFB\u53D6\u771F\u5B9E native evaluator \u8F93\u51FA\uFF1B\u5F53\u524D\u8BC1\u636E\u6CA1\u6709\u8BE5\u8F93\u51FA\u65F6\u5FC5\u987B\u8FD4\u56DE",
165841
+ "status=evaluator_failed\uFF0C\u7981\u6B62\u7531 LLM \u4EE3\u6253\u5B98\u65B9\u5206\u6570\u3002"
165842
+ ].join("\n"),
165843
+ outputSpec: BUILTIN_CASE_SPECIAL_OUTPUT_SPEC
165844
+ }
165845
+ ];
165846
+ }
165847
+ function caseSpecialItemDefinitions(evaluationCase) {
165848
+ const items = Array.isArray(evaluationCase.caseSpecial["items"]) ? evaluationCase.caseSpecial["items"] : [];
165849
+ return items.flatMap((raw) => {
165850
+ const item = asRecord2(raw);
165851
+ if (!item || typeof item["id"] !== "string") return [];
165852
+ const evaluator = asRecord2(item["evaluator"]);
165853
+ return [{
165854
+ id: item["id"],
165855
+ label: typeof item["label"] === "string" ? item["label"] : typeof item["description"] === "string" ? item["description"] : item["id"],
165856
+ maxScore: typeof item["max_score"] === "number" ? item["max_score"] : null,
165857
+ evaluatorType: typeof evaluator?.["type"] === "string" ? evaluator["type"] : null
165858
+ }];
165859
+ });
165860
+ }
165861
+ function sectionSkeleton(spec, caseSpecialItems) {
165862
+ if (spec.dimensions.length) {
165863
+ const rows2 = spec.dimensions.map((dimension) => ` - ${dimension.id}\uFF08${dimension.label}\uFF09\uFF1A${dimension.min}-${dimension.max} \u5206${dimension.nullable ? "\uFF0C\u786E\u5B9E\u4E0D\u9002\u7528\u65F6\u53EF\u4E3A null" : "\uFF0C\u4E0D\u5F97\u4E3A null"}`);
165864
+ const aggregation = spec.aggregation === "mean" ? `
165865
+ \u6BB5\u5185\u8FD8\u9700\u7ED9\u51FA score\uFF08\u5404\u7EF4\u5EA6\u5747\u503C\uFF09\u4E0E score100\uFF08\u5747\u503C\u6362\u7B97\u767E\u5206\u5236\uFF09\uFF0C\u7EF4\u5EA6\u4E0D\u5168\u65F6\u4E24\u8005\u90FD\u4E3A null\u3002` : "";
165866
+ return ` "${spec.sectionKey}".dimensions \u5FC5\u987B\u6070\u597D ${spec.dimensions.length} \u9879\uFF1A
165867
+ ${rows2.join("\n")}${aggregation}`;
165868
+ }
165869
+ if (!caseSpecialItems.length) {
165870
+ return ` "${spec.sectionKey}".items \u4E3A\u6570\u7EC4\uFF1B\u672C Case \u6CA1\u6709\u5B9A\u4E49\u8BC4\u5206\u9879\u65F6\u7ED9\u7A7A\u6570\u7EC4 []\uFF0C\u4E0D\u8981\u7701\u7565\u8BE5\u5B57\u6BB5\u3002`;
165871
+ }
165872
+ const rows = caseSpecialItems.map((item) => ` - id="${item.id}"\uFF08${item.label}\uFF09${item.maxScore === null ? "" : `\uFF0C\u6EE1\u5206 ${item.maxScore}`}${item.evaluatorType ? `\uFF0Cevaluator=${item.evaluatorType}` : ""}`);
165873
+ return [
165874
+ ` "${spec.sectionKey}".items \u5FC5\u987B\u9010\u9879\u8986\u76D6\u4E0B\u9762 ${caseSpecialItems.length} \u4E2A id\uFF0C\u4E00\u4E2A\u90FD\u4E0D\u80FD\u5C11\uFF1A`,
165875
+ ...rows,
165876
+ ` \u6BCF\u9879\u542B id / label / score / maxScore / status / reasoning\uFF1B`,
165877
+ ` status \u2208 scored | not_applicable | evaluator_failed\uFF1B\u62FF\u4E0D\u5230 evaluator \u8F93\u51FA\u5C31\u586B evaluator_failed \u4E14 score=null\u3002`
165878
+ ].join("\n");
165879
+ }
165880
+ function caseContextForPrompt(evaluationCase) {
165881
+ const {
165882
+ commonRubric: _commonRubric,
165883
+ specialtyRubric: _specialtyRubric,
165884
+ caseSpecial: _caseSpecial,
165885
+ ...rest
165886
+ } = evaluationCase;
165887
+ return rest;
165888
+ }
165889
+ function buildJudgePrompt(input) {
165890
+ const items = caseSpecialItemDefinitions(input.evaluationCase);
165891
+ const specs = input.rubrics.map((rubric) => rubric.outputSpec);
165892
+ const sections = input.rubrics.map((rubric, index) => [
165893
+ `### \u6807\u51C6 ${index + 1}\uFF0F${input.rubrics.length}\uFF1A${rubric.name}`,
165894
+ `- \u7C7B\u578B\uFF1A${rubric.kind}\uFF1B\u8F93\u51FA\u5230\u7ED3\u679C JSON \u7684 "${rubric.outputSpec.sectionKey}" \u6BB5` + (rubric.version ? `\uFF1B\u7248\u672C ${rubric.rubricId}@${rubric.version}` : ""),
165895
+ ...rubric.description ? [`- \u8BF4\u660E\uFF1A${rubric.description}`] : [],
165896
+ "",
165897
+ rubric.promptSection.trim()
165898
+ ].join("\n"));
165899
+ return [
165900
+ "\u4F60\u662F Oasis Benchmark \u7684\u8BC4\u5206\u5458\u5DE5\u3002\u672C\u6B21\u4EFB\u52A1\u53EA\u505A\u8BC4\u6D4B\uFF0C\u4E0D\u4FEE\u6539\u88AB\u6D4B\u5DE5\u5355\u3002",
165901
+ `evaluation_id: ${input.evaluationId}`,
165902
+ "",
165903
+ "## \u8BC4\u5206\u6807\u51C6\uFF08\u9010\u6761\u9002\u7528\uFF0C\u7F3A\u4E00\u4E0D\u53EF\uFF09",
165904
+ "",
165905
+ sections.join("\n\n"),
165906
+ "",
165907
+ "## \u8F93\u51FA\u8981\u6C42",
165908
+ "",
165909
+ "\u53EA\u8FD4\u56DE\u4E00\u4E2A JSON \u5BF9\u8C61\uFF0C\u4E0D\u8981\u8FD4\u56DE Markdown \u89E3\u91CA\u3001\u4E0D\u8981\u52A0\u4EE3\u7801\u5757\u4EE5\u5916\u7684\u6B63\u6587\u3002\u5BF9\u8C61\u5FC5\u987B\u540C\u65F6\u5305\u542B\u4E0B\u5217\u5404\u6BB5\uFF1A",
165910
+ specs.map((spec) => sectionSkeleton(spec, items)).join("\n"),
165911
+ ' "runtimeMetrics"\uFF1A\u539F\u6837\u4FDD\u7559\u8BC1\u636E\u4E2D\u7684\u8FD0\u884C\u6307\u6807\uFF0C\u4E0D\u8FDB\u5165\u8D28\u91CF\u5206\u3002',
165912
+ "",
165913
+ "\u7981\u6B62\u751F\u6210\u8DE8\u6BB5\u7684\u603B\u4F53\u603B\u5206\u3002\u6BCF\u4E2A\u7EF4\u5EA6\u90FD\u8981\u7ED9 reasoning\uFF0C\u5E76\u5C3D\u91CF\u5E26 evidenceRefs\u3002",
165914
+ "",
165915
+ "## CASE",
165916
+ JSON.stringify(caseContextForPrompt(input.evaluationCase)),
165917
+ "",
165918
+ "## EVIDENCE SNAPSHOT",
165919
+ input.evidenceJson
165920
+ ].join("\n");
165921
+ }
165922
+ var asRecord2;
165923
+ var init_judge_prompt = __esm({
165924
+ "../server/src/domains/evaluation/judge-prompt.ts"() {
165925
+ "use strict";
165926
+ init_src();
165927
+ asRecord2 = (value2) => value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
165928
+ }
165929
+ });
165930
+
165931
+ // ../server/src/domains/evaluation/scoring.ts
165932
+ var ScoringConfigError, EvaluationScoringService;
165933
+ var init_scoring = __esm({
165934
+ "../server/src/domains/evaluation/scoring.ts"() {
165935
+ "use strict";
165936
+ init_src();
165937
+ init_judge_prompt();
165938
+ ScoringConfigError = class extends Error {
165939
+ constructor(statusCode, code, message) {
165940
+ super(message);
165941
+ this.statusCode = statusCode;
165942
+ this.code = code;
165943
+ this.name = "ScoringConfigError";
165944
+ }
165945
+ };
165946
+ EvaluationScoringService = class {
165947
+ constructor(options) {
165948
+ this.options = options;
165949
+ }
165950
+ at() {
165951
+ return (this.options.now ?? (() => /* @__PURE__ */ new Date()))().toISOString();
165952
+ }
165953
+ listRubrics(companyId) {
165954
+ return this.options.store.listRubrics(companyId);
165955
+ }
165956
+ async upsertRubric(body, companyId, actor) {
165957
+ const raw = body ?? {};
165958
+ const rubricId = typeof raw["rubricId"] === "string" && raw["rubricId"] ? raw["rubricId"] : void 0;
165959
+ let existing = null;
165960
+ if (rubricId) {
165961
+ existing = await this.options.store.getRubric(rubricId);
165962
+ if (existing && existing.companyId !== companyId) {
165963
+ throw new ScoringConfigError(404, "RUBRIC_NOT_FOUND", `\u8BC4\u5206\u6807\u51C6 ${rubricId} \u4E0D\u5B58\u5728`);
165964
+ }
165965
+ }
165966
+ const merged = existing ? {
165967
+ rubricId,
165968
+ name: raw["name"] ?? existing.name,
165969
+ kind: raw["kind"] ?? existing.kind,
165970
+ description: raw["description"] ?? existing.description,
165971
+ promptSection: raw["promptSection"] ?? existing.promptSection,
165972
+ outputSpec: raw["outputSpec"] ?? existing.outputSpec,
165973
+ status: raw["status"] ?? existing.status
165974
+ } : raw;
165975
+ let input;
165976
+ try {
165977
+ input = validateUpsertEvaluationRubricInput(merged);
165978
+ } catch (error2) {
165979
+ throw new ScoringConfigError(400, "BAD_REQUEST", error2 instanceof Error ? error2.message : String(error2));
165980
+ }
165981
+ return this.options.store.upsertRubric({ ...input, companyId, actor }, this.at());
165982
+ }
165983
+ async deleteRubric(rubricId, companyId) {
165984
+ const existing = await this.options.store.getRubric(rubricId);
165985
+ if (!existing || existing.companyId !== companyId) {
165986
+ throw new ScoringConfigError(404, "RUBRIC_NOT_FOUND", `\u8BC4\u5206\u6807\u51C6 ${rubricId} \u4E0D\u5B58\u5728`);
165987
+ }
165988
+ await this.options.store.deleteRubric(rubricId, companyId);
165989
+ }
165990
+ listBindings(companyId) {
165991
+ return this.options.store.listBindings(companyId);
165992
+ }
165993
+ async putBinding(caseId, body, companyId, actor) {
165994
+ const input = body ?? {};
165995
+ const rubricIds = Array.isArray(input.rubricIds) ? input.rubricIds.filter((id) => typeof id === "string" && id.length > 0) : [];
165996
+ if (new Set(rubricIds).size !== rubricIds.length) {
165997
+ throw new ScoringConfigError(400, "BAD_REQUEST", "\u540C\u4E00\u6761\u8BC4\u5206\u6807\u51C6\u4E0D\u80FD\u91CD\u590D\u6302\u8F7D");
165998
+ }
165999
+ const rubrics = [];
166000
+ for (const rubricId of rubricIds) {
166001
+ const rubric = await this.options.store.getRubric(rubricId);
166002
+ if (!rubric || rubric.companyId !== companyId) {
166003
+ throw new ScoringConfigError(400, "RUBRIC_NOT_FOUND", `\u8BC4\u5206\u6807\u51C6 ${rubricId} \u4E0D\u5B58\u5728`);
166004
+ }
166005
+ if (rubric.status !== "active") {
166006
+ throw new ScoringConfigError(400, "RUBRIC_ARCHIVED", `\u8BC4\u5206\u6807\u51C6\u300C${rubric.name}\u300D\u5DF2\u5F52\u6863\uFF0C\u4E0D\u80FD\u6302\u8F7D`);
166007
+ }
166008
+ rubrics.push(rubric);
166009
+ }
166010
+ const sections = rubrics.map((rubric) => rubric.outputSpec.sectionKey);
166011
+ if (new Set(sections).size !== sections.length) {
166012
+ throw new ScoringConfigError(
166013
+ 400,
166014
+ "RUBRIC_SECTION_CONFLICT",
166015
+ `\u6302\u8F7D\u7684\u6807\u51C6\u8F93\u51FA\u5230\u4E86\u540C\u4E00\u4E2A\u7ED3\u679C\u6BB5\uFF08${sections.join("\u3001")}\uFF09\uFF0C\u8BF7\u6539\u5176\u4E2D\u4E00\u6761\u7684 sectionKey`
166016
+ );
166017
+ }
166018
+ const judgeActorId = typeof input.judgeActorId === "string" && input.judgeActorId.trim() ? input.judgeActorId.trim() : null;
166019
+ if (judgeActorId && this.options.verifyJudgeActor && !await this.options.verifyJudgeActor(judgeActorId, companyId)) {
166020
+ throw new ScoringConfigError(400, "JUDGE_ACTOR_INVALID", `${judgeActorId} \u4E0D\u662F\u53EF\u7528\u7684\u5224\u5206\u5458\u5DE5`);
166021
+ }
166022
+ const binding = await this.options.store.putBinding(
166023
+ { companyId, caseId, rubricIds, judgeActorId, actor },
166024
+ this.at()
166025
+ );
166026
+ return {
166027
+ caseId,
166028
+ rubrics,
166029
+ judgeActorId: binding.judgeActorId,
166030
+ usesBuiltinFallback: rubrics.length === 0
166031
+ };
166032
+ }
166033
+ /** Case 当前装配的对外投影(挂载展开 + 是否还在吃回落)。 */
166034
+ async getCaseScoring(caseId, companyId) {
166035
+ const binding = await this.options.store.getBinding(companyId, caseId);
166036
+ const rubrics = await this.mountedRubrics(binding, companyId);
166037
+ return {
166038
+ caseId,
166039
+ rubrics,
166040
+ judgeActorId: binding?.judgeActorId ?? null,
166041
+ usesBuiltinFallback: rubrics.length === 0
166042
+ };
166043
+ }
166044
+ /** 判分前的最终解析:拿到本次真正要用的标准与判分员工。 */
166045
+ async resolveForRun(evaluationCase, companyId, requestedJudgeActorId) {
166046
+ const binding = await this.options.store.getBinding(companyId, evaluationCase.id);
166047
+ const mounted = await this.mountedRubrics(binding, companyId);
166048
+ const judgeActorId = requestedJudgeActorId?.trim() || binding?.judgeActorId || this.options.defaultJudgeActorId;
166049
+ if (!judgeActorId) {
166050
+ throw new ScoringConfigError(
166051
+ 409,
166052
+ "JUDGE_ACTOR_NOT_CONFIGURED",
166053
+ "\u6CA1\u6709\u53EF\u7528\u7684\u5224\u5206\u5458\u5DE5\uFF1A\u8BF7\u5728 Case \u8BC4\u5206\u88C5\u914D\u91CC\u6307\u5B9A\uFF0C\u6216\u914D\u7F6E OASIS_EVALUATION_SCORING_ACTOR_ID"
166054
+ );
166055
+ }
166056
+ return {
166057
+ rubrics: mounted.length ? mounted : builtinRubricsForCase(evaluationCase),
166058
+ judgeActorId,
166059
+ usesBuiltinFallback: mounted.length === 0
166060
+ };
166061
+ }
166062
+ async mountedRubrics(binding, companyId) {
166063
+ if (!binding?.rubricIds.length) return [];
166064
+ const rubrics = [];
166065
+ for (const rubricId of binding.rubricIds) {
166066
+ const rubric = await this.options.store.getRubric(rubricId);
166067
+ if (rubric && rubric.companyId === companyId && rubric.status === "active") rubrics.push(rubric);
166068
+ }
166069
+ return rubrics;
166070
+ }
166071
+ };
166072
+ }
166073
+ });
166074
+
165595
166075
  // ../server/src/domains/evaluation/service.ts
165596
- var import_node_crypto29, EvaluationError, EvaluationService;
166076
+ var import_node_crypto30, EvaluationError, EvaluationService;
165597
166077
  var init_service7 = __esm({
165598
166078
  "../server/src/domains/evaluation/service.ts"() {
165599
166079
  "use strict";
165600
- import_node_crypto29 = require("node:crypto");
166080
+ import_node_crypto30 = require("node:crypto");
165601
166081
  init_src();
165602
166082
  init_project_binding();
166083
+ init_scoring();
165603
166084
  EvaluationError = class extends Error {
165604
166085
  constructor(statusCode, code, message) {
165605
166086
  super(message);
@@ -165612,7 +166093,7 @@ var init_service7 = __esm({
165612
166093
  constructor(options) {
165613
166094
  this.options = options;
165614
166095
  this.now = options.now ?? (() => /* @__PURE__ */ new Date());
165615
- this.id = options.id ?? import_node_crypto29.randomUUID;
166096
+ this.id = options.id ?? import_node_crypto30.randomUUID;
165616
166097
  }
165617
166098
  now;
165618
166099
  id;
@@ -165715,10 +166196,17 @@ var init_service7 = __esm({
165715
166196
  createdBy: actor,
165716
166197
  createdAt: now
165717
166198
  });
165718
- const evaluation = await this.createEvaluation(run.runId, evaluationCase, actor, true);
166199
+ const evaluation = await this.createEvaluation(
166200
+ run.runId,
166201
+ evaluationCase,
166202
+ actor,
166203
+ companyId,
166204
+ input.judgeActorId,
166205
+ true
166206
+ );
165719
166207
  return { run, evaluation };
165720
166208
  }
165721
- async createRescore(runId, actor, companyId = "default") {
166209
+ async createRescore(runId, actor, companyId = "default", judgeActorId) {
165722
166210
  const run = await this.options.store.getRun(runId);
165723
166211
  if (!run || run.companyId !== companyId) {
165724
166212
  throw new EvaluationError(404, "RUN_NOT_FOUND", `Run ${runId} \u4E0D\u5B58\u5728`);
@@ -165728,7 +166216,7 @@ var init_service7 = __esm({
165728
166216
  if (!evaluationCase) {
165729
166217
  throw new EvaluationError(409, "CASE_VERSION_MISSING", `Case ${run.caseId}@${run.caseVersion} \u4E0D\u5B58\u5728`);
165730
166218
  }
165731
- return this.createEvaluation(runId, evaluationCase, actor);
166219
+ return this.createEvaluation(runId, evaluationCase, actor, companyId, judgeActorId);
165732
166220
  }
165733
166221
  async runEvaluation(evaluationId, companyId) {
165734
166222
  const current = await this.options.store.getEvaluation(evaluationId);
@@ -165752,11 +166240,18 @@ var init_service7 = __esm({
165752
166240
  };
165753
166241
  await this.options.store.updateEvaluation(started);
165754
166242
  try {
166243
+ const resolved = await this.options.scoring.resolveForRun(
166244
+ evaluationCase,
166245
+ run.companyId,
166246
+ current.judgeActorId
166247
+ );
165755
166248
  const judged = await this.options.judge.evaluate({
165756
166249
  ...companyId ? { companyId } : {},
165757
166250
  evaluationId,
165758
166251
  evaluationCase,
165759
- evidenceSnapshot: run.evidenceSnapshot
166252
+ evidenceSnapshot: run.evidenceSnapshot,
166253
+ rubrics: resolved.rubrics,
166254
+ judgeActorId: resolved.judgeActorId
165760
166255
  });
165761
166256
  const snapshotMetrics = run.evidenceSnapshot["runtimeMetrics"];
165762
166257
  const result = {
@@ -165828,15 +166323,20 @@ var init_service7 = __esm({
165828
166323
  benchmarkProjects
165829
166324
  };
165830
166325
  }
165831
- createEvaluation(runId, evaluationCase, actor, ifRunHasNone = false) {
166326
+ /**
166327
+ * 判分员工与 rubricVersion 在**建 Evaluation 时**定下并落库,不在跑的时候再算:
166328
+ * 队列里排到再解析的话,中途改了装配就说不清「这条分是按哪套标准、谁打的」。
166329
+ */
166330
+ async createEvaluation(runId, evaluationCase, actor, companyId, judgeActorId, ifRunHasNone = false) {
165832
166331
  const now = this.now().toISOString();
166332
+ const resolved = await this.options.scoring.resolveForRun(evaluationCase, companyId, judgeActorId);
165833
166333
  return this.options.store.createEvaluation({
165834
166334
  evaluationId: this.id(),
165835
166335
  runId,
165836
166336
  status: "queued",
165837
- judgeActorId: this.options.judgeActorId,
166337
+ judgeActorId: resolved.judgeActorId,
165838
166338
  judgeVersion: this.options.judgeVersion,
165839
- rubricVersion: evaluationCase.rubricVersion,
166339
+ rubricVersion: rubricVersionOf(resolved.rubrics, evaluationCase.rubricVersion),
165840
166340
  evaluatorVersion: evaluationCase.evaluatorVersion,
165841
166341
  createdBy: actor,
165842
166342
  createdAt: now
@@ -165850,6 +166350,7 @@ var init_service7 = __esm({
165850
166350
  function evaluationDomain(options) {
165851
166351
  const schedule = options.schedule ?? ((task2) => queueMicrotask(task2));
165852
166352
  const service = options.service;
166353
+ const scoring = options.scoring;
165853
166354
  return (router) => {
165854
166355
  router.get("/api/evaluations/workorders", async (req) => ({
165855
166356
  status: 200,
@@ -165877,7 +166378,8 @@ function evaluationDomain(options) {
165877
166378
  const created = await service.createRun({
165878
166379
  workOrderId: body.workOrderId,
165879
166380
  caseId: body.caseId,
165880
- ...body.caseVersion ? { caseVersion: body.caseVersion } : {}
166381
+ ...body.caseVersion ? { caseVersion: body.caseVersion } : {},
166382
+ judgeActorId: optionalActorId(body.judgeActorId)
165881
166383
  }, req.auth.actor, req.auth.companyId ?? "default");
165882
166384
  schedule(() => {
165883
166385
  void service.runEvaluation(created.evaluation.evaluationId, req.auth.companyId);
@@ -165892,7 +166394,8 @@ function evaluationDomain(options) {
165892
166394
  const evaluation = await service.createRescore(
165893
166395
  req.params.runId,
165894
166396
  req.auth.actor,
165895
- req.auth.companyId ?? "default"
166397
+ req.auth.companyId ?? "default",
166398
+ optionalActorId(req.body?.judgeActorId)
165896
166399
  );
165897
166400
  schedule(() => {
165898
166401
  void service.runEvaluation(evaluation.evaluationId, req.auth.companyId);
@@ -165902,20 +166405,87 @@ function evaluationDomain(options) {
165902
166405
  return mapError(error2);
165903
166406
  }
165904
166407
  });
166408
+ router.get("/api/evaluations/rubrics", async (req) => ({
166409
+ status: 200,
166410
+ body: { items: await scoring.listRubrics(req.auth.companyId ?? "default") }
166411
+ }));
166412
+ router.post("/api/evaluations/rubrics", async (req) => {
166413
+ try {
166414
+ return {
166415
+ status: 201,
166416
+ body: await scoring.upsertRubric(req.body, req.auth.companyId ?? "default", req.auth.actor)
166417
+ };
166418
+ } catch (error2) {
166419
+ return mapError(error2);
166420
+ }
166421
+ });
166422
+ router.put("/api/evaluations/rubrics/:rubricId", async (req) => {
166423
+ try {
166424
+ return {
166425
+ status: 200,
166426
+ body: await scoring.upsertRubric(
166427
+ { ...req.body, rubricId: req.params.rubricId },
166428
+ req.auth.companyId ?? "default",
166429
+ req.auth.actor
166430
+ )
166431
+ };
166432
+ } catch (error2) {
166433
+ return mapError(error2);
166434
+ }
166435
+ });
166436
+ router.delete("/api/evaluations/rubrics/:rubricId", async (req) => {
166437
+ try {
166438
+ await scoring.deleteRubric(req.params.rubricId, req.auth.companyId ?? "default");
166439
+ return { status: 200, body: { ok: true } };
166440
+ } catch (error2) {
166441
+ return mapError(error2);
166442
+ }
166443
+ });
166444
+ router.get("/api/evaluations/case-scoring", async (req) => ({
166445
+ status: 200,
166446
+ body: { items: await scoring.listBindings(req.auth.companyId ?? "default") }
166447
+ }));
166448
+ router.get("/api/evaluations/cases/:caseId/scoring", async (req) => ({
166449
+ status: 200,
166450
+ body: await scoring.getCaseScoring(req.params.caseId, req.auth.companyId ?? "default")
166451
+ }));
166452
+ router.put("/api/evaluations/cases/:caseId/scoring", async (req) => {
166453
+ try {
166454
+ return {
166455
+ status: 200,
166456
+ body: await scoring.putBinding(
166457
+ req.params.caseId,
166458
+ req.body,
166459
+ req.auth.companyId ?? "default",
166460
+ req.auth.actor
166461
+ )
166462
+ };
166463
+ } catch (error2) {
166464
+ return mapError(error2);
166465
+ }
166466
+ });
166467
+ router.get("/api/evaluations/judge-candidates", async (req) => ({
166468
+ status: 200,
166469
+ body: {
166470
+ items: options.listJudgeCandidates ? await options.listJudgeCandidates(req.auth.companyId ?? "default") : []
166471
+ }
166472
+ }));
165905
166473
  };
165906
166474
  }
165907
- var mapError;
166475
+ var mapError, optionalActorId;
165908
166476
  var init_routes8 = __esm({
165909
166477
  "../server/src/domains/evaluation/routes.ts"() {
165910
166478
  "use strict";
165911
166479
  init_router();
165912
166480
  init_service7();
166481
+ init_scoring();
165913
166482
  mapError = (error2) => {
165914
- if (error2 instanceof EvaluationError) {
166483
+ if (error2 instanceof EvaluationError || error2 instanceof ScoringConfigError) {
165915
166484
  throw new ApiError(error2.statusCode, error2.code, error2.message);
165916
166485
  }
165917
166486
  throw error2;
165918
166487
  };
166488
+ optionalActorId = (value2) => typeof value2 === "string" && value2.trim() ? value2.trim() : null;
165919
166489
  }
165920
166490
  });
165921
166491
 
@@ -169974,10 +170544,10 @@ var require_resolve_block_map = __commonJS({
169974
170544
  let offset = bm.offset;
169975
170545
  let commentEnd = null;
169976
170546
  for (const collItem of bm.items) {
169977
- const { start, key, sep: sep3, value: value2 } = collItem;
170547
+ const { start, key, sep: sep4, value: value2 } = collItem;
169978
170548
  const keyProps = resolveProps.resolveProps(start, {
169979
170549
  indicator: "explicit-key-ind",
169980
- next: key ?? sep3?.[0],
170550
+ next: key ?? sep4?.[0],
169981
170551
  offset,
169982
170552
  onError,
169983
170553
  parentIndent: bm.indent,
@@ -169991,7 +170561,7 @@ var require_resolve_block_map = __commonJS({
169991
170561
  else if ("indent" in key && key.indent !== bm.indent)
169992
170562
  onError(offset, "BAD_INDENT", startColMsg);
169993
170563
  }
169994
- if (!keyProps.anchor && !keyProps.tag && !sep3) {
170564
+ if (!keyProps.anchor && !keyProps.tag && !sep4) {
169995
170565
  commentEnd = keyProps.end;
169996
170566
  if (keyProps.comment) {
169997
170567
  if (map.comment)
@@ -170015,7 +170585,7 @@ var require_resolve_block_map = __commonJS({
170015
170585
  ctx.atKey = false;
170016
170586
  if (utilMapIncludes.mapIncludes(ctx, map.items, keyNode))
170017
170587
  onError(keyStart, "DUPLICATE_KEY", "Map keys must be unique");
170018
- const valueProps = resolveProps.resolveProps(sep3 ?? [], {
170588
+ const valueProps = resolveProps.resolveProps(sep4 ?? [], {
170019
170589
  indicator: "map-value-ind",
170020
170590
  next: value2,
170021
170591
  offset: keyNode.range[2],
@@ -170031,7 +170601,7 @@ var require_resolve_block_map = __commonJS({
170031
170601
  if (ctx.options.strict && keyProps.start < valueProps.found.offset - 1024)
170032
170602
  onError(keyNode.range, "KEY_OVER_1024_CHARS", "The : indicator must be at most 1024 chars after the start of an implicit block mapping key");
170033
170603
  }
170034
- const valueNode = value2 ? composeNode(ctx, value2, valueProps, onError) : composeEmptyNode(ctx, offset, sep3, null, valueProps, onError);
170604
+ const valueNode = value2 ? composeNode(ctx, value2, valueProps, onError) : composeEmptyNode(ctx, offset, sep4, null, valueProps, onError);
170035
170605
  if (ctx.schema.compat)
170036
170606
  utilFlowIndentCheck.flowIndentCheck(bm.indent, value2, onError);
170037
170607
  offset = valueNode.range[2];
@@ -170122,7 +170692,7 @@ var require_resolve_end = __commonJS({
170122
170692
  let comment = "";
170123
170693
  if (end) {
170124
170694
  let hasSpace = false;
170125
- let sep3 = "";
170695
+ let sep4 = "";
170126
170696
  for (const token of end) {
170127
170697
  const { source, type } = token;
170128
170698
  switch (type) {
@@ -170136,13 +170706,13 @@ var require_resolve_end = __commonJS({
170136
170706
  if (!comment)
170137
170707
  comment = cb;
170138
170708
  else
170139
- comment += sep3 + cb;
170140
- sep3 = "";
170709
+ comment += sep4 + cb;
170710
+ sep4 = "";
170141
170711
  break;
170142
170712
  }
170143
170713
  case "newline":
170144
170714
  if (comment)
170145
- sep3 += source;
170715
+ sep4 += source;
170146
170716
  hasSpace = true;
170147
170717
  break;
170148
170718
  default:
@@ -170185,18 +170755,18 @@ var require_resolve_flow_collection = __commonJS({
170185
170755
  let offset = fc.offset + fc.start.source.length;
170186
170756
  for (let i = 0; i < fc.items.length; ++i) {
170187
170757
  const collItem = fc.items[i];
170188
- const { start, key, sep: sep3, value: value2 } = collItem;
170758
+ const { start, key, sep: sep4, value: value2 } = collItem;
170189
170759
  const props = resolveProps.resolveProps(start, {
170190
170760
  flow: fcName,
170191
170761
  indicator: "explicit-key-ind",
170192
- next: key ?? sep3?.[0],
170762
+ next: key ?? sep4?.[0],
170193
170763
  offset,
170194
170764
  onError,
170195
170765
  parentIndent: fc.indent,
170196
170766
  startOnNewline: false
170197
170767
  });
170198
170768
  if (!props.found) {
170199
- if (!props.anchor && !props.tag && !sep3 && !value2) {
170769
+ if (!props.anchor && !props.tag && !sep4 && !value2) {
170200
170770
  if (i === 0 && props.comma)
170201
170771
  onError(props.comma, "UNEXPECTED_TOKEN", `Unexpected , in ${fcName}`);
170202
170772
  else if (i < fc.items.length - 1)
@@ -170250,8 +170820,8 @@ var require_resolve_flow_collection = __commonJS({
170250
170820
  }
170251
170821
  }
170252
170822
  }
170253
- if (!isMap && !sep3 && !props.found) {
170254
- const valueNode = value2 ? composeNode(ctx, value2, props, onError) : composeEmptyNode(ctx, props.end, sep3, null, props, onError);
170823
+ if (!isMap && !sep4 && !props.found) {
170824
+ const valueNode = value2 ? composeNode(ctx, value2, props, onError) : composeEmptyNode(ctx, props.end, sep4, null, props, onError);
170255
170825
  coll.items.push(valueNode);
170256
170826
  offset = valueNode.range[2];
170257
170827
  if (isBlock(value2))
@@ -170263,7 +170833,7 @@ var require_resolve_flow_collection = __commonJS({
170263
170833
  if (isBlock(key))
170264
170834
  onError(keyNode.range, "BLOCK_IN_FLOW", blockMsg);
170265
170835
  ctx.atKey = false;
170266
- const valueProps = resolveProps.resolveProps(sep3 ?? [], {
170836
+ const valueProps = resolveProps.resolveProps(sep4 ?? [], {
170267
170837
  flow: fcName,
170268
170838
  indicator: "map-value-ind",
170269
170839
  next: value2,
@@ -170274,8 +170844,8 @@ var require_resolve_flow_collection = __commonJS({
170274
170844
  });
170275
170845
  if (valueProps.found) {
170276
170846
  if (!isMap && !props.found && ctx.options.strict) {
170277
- if (sep3)
170278
- for (const st of sep3) {
170847
+ if (sep4)
170848
+ for (const st of sep4) {
170279
170849
  if (st === valueProps.found)
170280
170850
  break;
170281
170851
  if (st.type === "newline") {
@@ -170292,7 +170862,7 @@ var require_resolve_flow_collection = __commonJS({
170292
170862
  else
170293
170863
  onError(valueProps.start, "MISSING_CHAR", `Missing , or : between ${fcName} items`);
170294
170864
  }
170295
- const valueNode = value2 ? composeNode(ctx, value2, valueProps, onError) : valueProps.found ? composeEmptyNode(ctx, valueProps.end, sep3, null, valueProps, onError) : null;
170865
+ const valueNode = value2 ? composeNode(ctx, value2, valueProps, onError) : valueProps.found ? composeEmptyNode(ctx, valueProps.end, sep4, null, valueProps, onError) : null;
170296
170866
  if (valueNode) {
170297
170867
  if (isBlock(value2))
170298
170868
  onError(valueNode.range, "BLOCK_IN_FLOW", blockMsg);
@@ -170472,7 +171042,7 @@ var require_resolve_block_scalar = __commonJS({
170472
171042
  chompStart = i + 1;
170473
171043
  }
170474
171044
  let value2 = "";
170475
- let sep3 = "";
171045
+ let sep4 = "";
170476
171046
  let prevMoreIndented = false;
170477
171047
  for (let i = 0; i < contentStart; ++i)
170478
171048
  value2 += lines[i][0].slice(trimIndent) + "\n";
@@ -170489,24 +171059,24 @@ var require_resolve_block_scalar = __commonJS({
170489
171059
  indent = "";
170490
171060
  }
170491
171061
  if (type === Scalar.Scalar.BLOCK_LITERAL) {
170492
- value2 += sep3 + indent.slice(trimIndent) + content;
170493
- sep3 = "\n";
171062
+ value2 += sep4 + indent.slice(trimIndent) + content;
171063
+ sep4 = "\n";
170494
171064
  } else if (indent.length > trimIndent || content[0] === " ") {
170495
- if (sep3 === " ")
170496
- sep3 = "\n";
170497
- else if (!prevMoreIndented && sep3 === "\n")
170498
- sep3 = "\n\n";
170499
- value2 += sep3 + indent.slice(trimIndent) + content;
170500
- sep3 = "\n";
171065
+ if (sep4 === " ")
171066
+ sep4 = "\n";
171067
+ else if (!prevMoreIndented && sep4 === "\n")
171068
+ sep4 = "\n\n";
171069
+ value2 += sep4 + indent.slice(trimIndent) + content;
171070
+ sep4 = "\n";
170501
171071
  prevMoreIndented = true;
170502
171072
  } else if (content === "") {
170503
- if (sep3 === "\n")
171073
+ if (sep4 === "\n")
170504
171074
  value2 += "\n";
170505
171075
  else
170506
- sep3 = "\n";
171076
+ sep4 = "\n";
170507
171077
  } else {
170508
- value2 += sep3 + content;
170509
- sep3 = " ";
171078
+ value2 += sep4 + content;
171079
+ sep4 = " ";
170510
171080
  prevMoreIndented = false;
170511
171081
  }
170512
171082
  }
@@ -170688,25 +171258,25 @@ var require_resolve_flow_scalar = __commonJS({
170688
171258
  if (!match)
170689
171259
  return source;
170690
171260
  let res = match[1];
170691
- let sep3 = " ";
171261
+ let sep4 = " ";
170692
171262
  let pos = first.lastIndex;
170693
171263
  line.lastIndex = pos;
170694
171264
  while (match = line.exec(source)) {
170695
171265
  if (match[1] === "") {
170696
- if (sep3 === "\n")
170697
- res += sep3;
171266
+ if (sep4 === "\n")
171267
+ res += sep4;
170698
171268
  else
170699
- sep3 = "\n";
171269
+ sep4 = "\n";
170700
171270
  } else {
170701
- res += sep3 + match[1];
170702
- sep3 = " ";
171271
+ res += sep4 + match[1];
171272
+ sep4 = " ";
170703
171273
  }
170704
171274
  pos = line.lastIndex;
170705
171275
  }
170706
171276
  const last = /[ \t]*(.*)/sy;
170707
171277
  last.lastIndex = pos;
170708
171278
  match = last.exec(source);
170709
- return res + sep3 + (match?.[1] ?? "");
171279
+ return res + sep4 + (match?.[1] ?? "");
170710
171280
  }
170711
171281
  function doubleQuotedValue(source, onError) {
170712
171282
  let res = "";
@@ -171516,14 +172086,14 @@ var require_cst_stringify = __commonJS({
171516
172086
  }
171517
172087
  }
171518
172088
  }
171519
- function stringifyItem({ start, key, sep: sep3, value: value2 }) {
172089
+ function stringifyItem({ start, key, sep: sep4, value: value2 }) {
171520
172090
  let res = "";
171521
172091
  for (const st of start)
171522
172092
  res += st.source;
171523
172093
  if (key)
171524
172094
  res += stringifyToken(key);
171525
- if (sep3)
171526
- for (const st of sep3)
172095
+ if (sep4)
172096
+ for (const st of sep4)
171527
172097
  res += st.source;
171528
172098
  if (value2)
171529
172099
  res += stringifyToken(value2);
@@ -172690,18 +173260,18 @@ var require_parser = __commonJS({
172690
173260
  if (this.type === "map-value-ind") {
172691
173261
  const prev = getPrevProps(this.peek(2));
172692
173262
  const start = getFirstKeyStartProps(prev);
172693
- let sep3;
173263
+ let sep4;
172694
173264
  if (scalar.end) {
172695
- sep3 = scalar.end;
172696
- sep3.push(this.sourceToken);
173265
+ sep4 = scalar.end;
173266
+ sep4.push(this.sourceToken);
172697
173267
  delete scalar.end;
172698
173268
  } else
172699
- sep3 = [this.sourceToken];
173269
+ sep4 = [this.sourceToken];
172700
173270
  const map = {
172701
173271
  type: "block-map",
172702
173272
  offset: scalar.offset,
172703
173273
  indent: scalar.indent,
172704
- items: [{ start, key: scalar, sep: sep3 }]
173274
+ items: [{ start, key: scalar, sep: sep4 }]
172705
173275
  };
172706
173276
  this.onKeyLine = true;
172707
173277
  this.stack[this.stack.length - 1] = map;
@@ -172854,15 +173424,15 @@ var require_parser = __commonJS({
172854
173424
  } else if (isFlowToken(it.key) && !includesToken(it.sep, "newline")) {
172855
173425
  const start2 = getFirstKeyStartProps(it.start);
172856
173426
  const key = it.key;
172857
- const sep3 = it.sep;
172858
- sep3.push(this.sourceToken);
173427
+ const sep4 = it.sep;
173428
+ sep4.push(this.sourceToken);
172859
173429
  delete it.key;
172860
173430
  delete it.sep;
172861
173431
  this.stack.push({
172862
173432
  type: "block-map",
172863
173433
  offset: this.offset,
172864
173434
  indent: this.indent,
172865
- items: [{ start: start2, key, sep: sep3 }]
173435
+ items: [{ start: start2, key, sep: sep4 }]
172866
173436
  });
172867
173437
  } else if (start.length > 0) {
172868
173438
  it.sep = it.sep.concat(start, this.sourceToken);
@@ -173056,13 +173626,13 @@ var require_parser = __commonJS({
173056
173626
  const prev = getPrevProps(parent);
173057
173627
  const start = getFirstKeyStartProps(prev);
173058
173628
  fixFlowSeqItems(fc);
173059
- const sep3 = fc.end.splice(1, fc.end.length);
173060
- sep3.push(this.sourceToken);
173629
+ const sep4 = fc.end.splice(1, fc.end.length);
173630
+ sep4.push(this.sourceToken);
173061
173631
  const map = {
173062
173632
  type: "block-map",
173063
173633
  offset: fc.offset,
173064
173634
  indent: fc.indent,
173065
- items: [{ start, key: fc, sep: sep3 }]
173635
+ items: [{ start, key: fc, sep: sep4 }]
173066
173636
  };
173067
173637
  this.onKeyLine = true;
173068
173638
  this.stack[this.stack.length - 1] = map;
@@ -173614,27 +174184,12 @@ function evidenceForJudge(snapshot) {
173614
174184
  };
173615
174185
  }
173616
174186
  function judgePrompt(input) {
173617
- return [
173618
- "\u4F60\u662F Oasis Benchmark \u7684\u8BC4\u5206\u5458\u5DE5\u3002\u672C\u6B21\u4EFB\u52A1\u53EA\u505A\u8BC4\u6D4B\uFF0C\u4E0D\u4FEE\u6539\u88AB\u6D4B\u5DE5\u5355\u3002",
173619
- `evaluation_id: ${input.evaluationId}`,
173620
- "",
173621
- "\u5FC5\u987B\u5206\u522B\u8F93\u51FA\u56DB\u7EC4\u7ED3\u679C\uFF0C\u7981\u6B62\u751F\u6210\u603B\u4F53\u603B\u5206\uFF1A",
173622
- "1. common.dimensions\uFF1AG1-G7 \u4E03\u9879\uFF0C1-5 \u5206\uFF1B\u53EA\u6709 G6 \u53EF\u5728\u786E\u5B9E\u4E0D\u9002\u7528\u65F6\u4E3A null\u3002",
173623
- "2. specialty.dimensions\uFF1A\u4E25\u683C\u4E94\u9879\u3001\u6BCF\u9879 1-5 \u5206\uFF1Bscore \u4E3A\u4E94\u9879\u5E73\u5747\uFF0Cscore100=score*20\u3002",
173624
- " S \u4E13\u9879\u53EA\u80FD\u4F9D\u636E artifacts \u4E2D\u53EF\u8BFB\u7684\u4E13\u4E1A\u4EA7\u7269\u6B63\u6587\u5224\u65AD\u3002Trace\u3001\u8282\u70B9\u6458\u8981\u548C Brief \u4E0D\u80FD\u66FF\u4EE3\u4E13\u4E1A\u4EA7\u7269\u3002",
173625
- " \u6CA1\u6709\u53EF\u8BFB\u4E13\u4E1A\u4EA7\u7269\u65F6\uFF0C\u4E94\u9879 score\u3001specialty.score \u548C specialty.score100 \u5FC5\u987B\u5168\u90E8\u4E3A null\u3002",
173626
- "3. caseSpecial\uFF1A\u53EA\u4F9D\u636E\u6700\u7EC8\u4EA7\u7269\u53CA evaluator \u7ED3\u679C\u3002",
173627
- " evaluator.type=native \u7684\u9879\u76EE\u53EA\u80FD\u8BFB\u53D6\u771F\u5B9E native evaluator \u8F93\u51FA\uFF1B\u5F53\u524D\u8BC1\u636E\u6CA1\u6709\u8BE5\u8F93\u51FA\u65F6\u5FC5\u987B\u8FD4\u56DE evaluator_failed\uFF0C\u7981\u6B62\u7531 LLM \u4EE3\u6253\u5B98\u65B9\u5206\u6570\u3002",
173628
- "4. runtimeMetrics\uFF1A\u539F\u6837\u4FDD\u7559\u8BC1\u636E\u4E2D\u7684\u8FD0\u884C\u6307\u6807\uFF0C\u4E0D\u8FDB\u5165\u8D28\u91CF\u5206\u3002",
173629
- "",
173630
- "\u53EA\u8FD4\u56DE\u4E00\u4E2A JSON \u5BF9\u8C61\uFF0C\u4E0D\u8981\u8FD4\u56DE Markdown \u89E3\u91CA\u3002",
173631
- "",
173632
- "CASE:",
173633
- JSON.stringify(input.evaluationCase),
173634
- "",
173635
- "EVIDENCE SNAPSHOT:",
173636
- JSON.stringify(evidenceForJudge(input.evidenceSnapshot))
173637
- ].join("\n");
174187
+ return buildJudgePrompt({
174188
+ evaluationId: input.evaluationId,
174189
+ evaluationCase: input.evaluationCase,
174190
+ rubrics: input.rubrics,
174191
+ evidenceJson: JSON.stringify(evidenceForJudge(input.evidenceSnapshot))
174192
+ });
173638
174193
  }
173639
174194
  function record7(value2) {
173640
174195
  return value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
@@ -173673,19 +174228,20 @@ function normalizeDimensions(value2, expectedIds) {
173673
174228
  if (!dimensions) return value2;
173674
174229
  return Object.entries(dimensions).map(([id, raw]) => normalizeDimensionItem(raw, id, expectedIds));
173675
174230
  }
173676
- function normalizeJudgeOutput(value2, evaluationCase) {
174231
+ function normalizeJudgeOutput(value2, evaluationCase, rubrics) {
173677
174232
  const source = record7(value2);
173678
174233
  if (!source) return value2;
173679
174234
  const result = structuredClone(source);
173680
- const common = record7(result["common"]);
173681
- if (common) {
173682
- common["dimensions"] = normalizeDimensions(
173683
- common["dimensions"],
173684
- ["G1", "G2", "G3", "G4", "G5", "G6", "G7"]
174235
+ for (const rubric of rubrics) {
174236
+ const spec = rubric.outputSpec;
174237
+ if (!spec.dimensions.length) continue;
174238
+ const section = record7(result[spec.sectionKey]);
174239
+ if (!section) continue;
174240
+ section["dimensions"] = normalizeDimensions(
174241
+ section["dimensions"],
174242
+ spec.dimensions.map((dimension) => dimension.id)
173685
174243
  );
173686
174244
  }
173687
- const specialty = record7(result["specialty"]);
173688
- if (specialty) specialty["dimensions"] = normalizeDimensions(specialty["dimensions"]);
173689
174245
  const caseSpecial = record7(result["caseSpecial"]);
173690
174246
  if (caseSpecial && Array.isArray(caseSpecial["items"])) {
173691
174247
  const definitions = Array.isArray(evaluationCase.caseSpecial["items"]) ? evaluationCase.caseSpecial["items"] : [];
@@ -173711,6 +174267,30 @@ function normalizeJudgeOutput(value2, evaluationCase) {
173711
174267
  }
173712
174268
  return result;
173713
174269
  }
174270
+ function fillMissingItemSections(value2, evaluationCase, rubrics) {
174271
+ const result = record7(value2);
174272
+ if (!result) return value2;
174273
+ const filled = structuredClone(result);
174274
+ const definitions = caseSpecialItemDefinitions(evaluationCase);
174275
+ for (const rubric of rubrics) {
174276
+ const spec = rubric.outputSpec;
174277
+ if (spec.dimensions.length) continue;
174278
+ const section = record7(filled[spec.sectionKey]);
174279
+ if (section && Array.isArray(section["items"])) continue;
174280
+ filled[spec.sectionKey] = {
174281
+ score100: null,
174282
+ items: definitions.map((definition) => ({
174283
+ id: definition.id,
174284
+ label: definition.label,
174285
+ score: null,
174286
+ maxScore: definition.maxScore,
174287
+ status: "evaluator_failed",
174288
+ reasoning: `\u8BC4\u5206\u5458\u5DE5\u672A\u8FD4\u56DE ${spec.sectionKey} \u6BB5\uFF0C\u672C\u9879\u6309\u672A\u8BC4\u5206\u8BB0\u5F55\uFF08\u6807\u51C6\uFF1A${rubric.name}\uFF09\u3002`
174289
+ }))
174290
+ };
174291
+ }
174292
+ return filled;
174293
+ }
173714
174294
  function enforceEvaluatorBoundaries(value2, evaluationCase) {
173715
174295
  if (!value2 || typeof value2 !== "object") return value2;
173716
174296
  const result = structuredClone(value2);
@@ -173776,17 +174356,22 @@ var init_judge = __esm({
173776
174356
  "../server/src/domains/evaluation/judge.ts"() {
173777
174357
  "use strict";
173778
174358
  init_src();
174359
+ init_judge_prompt();
173779
174360
  TRACE_STRING_LIMIT = 200;
173780
174361
  TRACE_ARRAY_LIMIT = 20;
173781
174362
  ChatEvaluationJudge = class {
173782
174363
  constructor(options) {
173783
174364
  this.options = options;
174365
+ this.attempts = Math.max(1, options.attempts ?? 2);
173784
174366
  }
174367
+ attempts;
173785
174368
  async evaluate(input) {
173786
- const message = judgePrompt(input);
173787
- for (let attempt = 0; attempt < 2; attempt += 1) {
174369
+ if (!input.judgeActorId) throw new Error("\u672A\u6307\u5B9A\u5224\u5206\u5458\u5DE5");
174370
+ const rubrics = input.rubrics?.length ? input.rubrics : builtinRubricsForCase(input.evaluationCase);
174371
+ const message = judgePrompt({ ...input, rubrics });
174372
+ for (let attempt = 0; attempt < this.attempts; attempt += 1) {
173788
174373
  const session = await this.options.dispatchChat({
173789
- actorId: this.options.actorId,
174374
+ actorId: input.judgeActorId,
173790
174375
  message,
173791
174376
  ...input.companyId ? { companyId: input.companyId } : {}
173792
174377
  });
@@ -173797,7 +174382,7 @@ var init_judge = __esm({
173797
174382
  try {
173798
174383
  await session.done;
173799
174384
  } catch (error2) {
173800
- if (attempt === 0 && isRetryableRuntimeExit(error2, output)) continue;
174385
+ if (attempt + 1 < this.attempts && isRetryableRuntimeExit(error2, output)) continue;
173801
174386
  if (error2 instanceof Error && session.runId) {
173802
174387
  Object.assign(error2, { judgeRunId: session.runId });
173803
174388
  }
@@ -173806,13 +174391,20 @@ var init_judge = __esm({
173806
174391
  return {
173807
174392
  judgeRunId: session.runId ?? null,
173808
174393
  judgeVersion: this.options.judgeVersion,
173809
- result: validateEvaluationResult(enforceEvaluatorBoundaries(
173810
- enforceSpecialtyArtifactBoundary(
173811
- normalizeJudgeOutput(extractJson2(output), input.evaluationCase),
173812
- input.evidenceSnapshot
174394
+ result: validateEvaluationResult(
174395
+ enforceEvaluatorBoundaries(
174396
+ enforceSpecialtyArtifactBoundary(
174397
+ fillMissingItemSections(
174398
+ normalizeJudgeOutput(extractJson2(output), input.evaluationCase, rubrics),
174399
+ input.evaluationCase,
174400
+ rubrics
174401
+ ),
174402
+ input.evidenceSnapshot
174403
+ ),
174404
+ input.evaluationCase
173813
174405
  ),
173814
- input.evaluationCase
173815
- ))
174406
+ rubrics.map((rubric) => rubric.outputSpec)
174407
+ )
173816
174408
  };
173817
174409
  }
173818
174410
  throw new Error("\u8BC4\u5206\u5458\u5DE5\u91CD\u8BD5\u6D41\u7A0B\u5F02\u5E38\u7ED3\u675F");
@@ -173880,6 +174472,8 @@ var init_evaluation3 = __esm({
173880
174472
  init_evidence();
173881
174473
  init_filesystem_catalog();
173882
174474
  init_judge();
174475
+ init_judge_prompt();
174476
+ init_scoring();
173883
174477
  init_project_binding();
173884
174478
  init_runtime_metrics();
173885
174479
  init_routes8();
@@ -174479,7 +175073,7 @@ function playbooksDomain(opts) {
174479
175073
  opts.overrides.set(companyOf(req), ref2, nodeKey, nextOverride);
174480
175074
  try {
174481
175075
  await opts.audit?.({
174482
- id: `reg_${(0, import_node_crypto30.randomUUID)()}`,
175076
+ id: `reg_${(0, import_node_crypto31.randomUUID)()}`,
174483
175077
  actor: req.auth.actor,
174484
175078
  kind: "registry_change",
174485
175079
  target: `playbook:${ref2}#${nodeKey}`,
@@ -174496,11 +175090,11 @@ function playbooksDomain(opts) {
174496
175090
  });
174497
175091
  };
174498
175092
  }
174499
- var import_node_crypto30;
175093
+ var import_node_crypto31;
174500
175094
  var init_routes9 = __esm({
174501
175095
  "../server/src/domains/playbooks/routes.ts"() {
174502
175096
  "use strict";
174503
- import_node_crypto30 = require("node:crypto");
175097
+ import_node_crypto31 = require("node:crypto");
174504
175098
  init_router();
174505
175099
  init_registry3();
174506
175100
  init_planner();
@@ -174633,11 +175227,11 @@ function remoteAppendInput(hub, nodeId, dispatchId, entry, input, timeoutMs) {
174633
175227
  entry.appendWaiters.push({ resolve: resolve9, timer });
174634
175228
  });
174635
175229
  }
174636
- var import_node_crypto31, STASH_TTL_MS, STASH_MAX_FRAMES_PER_ID, STASH_MAX_IDS, DaemonHubAdapter, BindingRouterAdapter, WorkdirBridge;
175230
+ var import_node_crypto32, STASH_TTL_MS, STASH_MAX_FRAMES_PER_ID, STASH_MAX_IDS, DaemonHubAdapter, BindingRouterAdapter, WorkdirBridge;
174637
175231
  var init_daemon_adapter = __esm({
174638
175232
  "../server/src/daemon-adapter.ts"() {
174639
175233
  "use strict";
174640
- import_node_crypto31 = require("node:crypto");
175234
+ import_node_crypto32 = require("node:crypto");
174641
175235
  STASH_TTL_MS = 5 * 6e4;
174642
175236
  STASH_MAX_FRAMES_PER_ID = 500;
174643
175237
  STASH_MAX_IDS = 50;
@@ -174723,6 +175317,21 @@ var init_daemon_adapter = __esm({
174723
175317
  }
174724
175318
  return n;
174725
175319
  }
175320
+ /**
175321
+ * 当前在途会话的**按员工分布**:`activeRunCount` 的同源摊开(同一张 pending 表、同一组过滤条件),
175322
+ * 故 `sum(count) === activeRunCount(nodeId, runtimeKind)` 恒成立。
175323
+ * 重挂路没带 actor 的会话归到 `actorId: ""`——不丢计数、也不猜身份。
175324
+ */
175325
+ activeRunsByActor(nodeId, runtimeKind) {
175326
+ const byActor = /* @__PURE__ */ new Map();
175327
+ for (const e of this.pending.values()) {
175328
+ if (e.nodeId !== nodeId || e.exited) continue;
175329
+ if (runtimeKind !== void 0 && e.runtimeKind !== runtimeKind) continue;
175330
+ const key = e.actorId ?? "";
175331
+ byActor.set(key, (byActor.get(key) ?? 0) + 1);
175332
+ }
175333
+ return byActor;
175334
+ }
174726
175335
  /** 收到任何回帧(started/event/output/exited)即视为派发已达,取消 ack 超时。 */
174727
175336
  cancelAck(dispatchId) {
174728
175337
  const entry = this.pending.get(dispatchId);
@@ -174793,10 +175402,11 @@ var init_daemon_adapter = __esm({
174793
175402
  async spawn(job) {
174794
175403
  const nodeId = job.binding?.nodeId;
174795
175404
  if (!nodeId) throw new Error("DaemonHubAdapter \u9700\u8981 job.binding.nodeId\uFF08\u8DEF\u7531\u9519\u8BEF\uFF09");
174796
- const dispatchId = job.dispatchId ?? `dispatch:${(0, import_node_crypto31.randomUUID)()}`;
175405
+ const dispatchId = job.dispatchId ?? `dispatch:${(0, import_node_crypto32.randomUUID)()}`;
174797
175406
  const entry = {
174798
175407
  nodeId,
174799
175408
  ...job.binding?.runtimeKind ? { runtimeKind: job.binding.runtimeKind } : {},
175409
+ ...job.actor ? { actorId: job.actor } : {},
174800
175410
  exitCbs: [],
174801
175411
  telemetryCbs: [],
174802
175412
  outputCbs: [],
@@ -174840,13 +175450,14 @@ var init_daemon_adapter = __esm({
174840
175450
  appendInput: (input) => remoteAppendInput(hub, nodeId, dispatchId, entry, input, appendTimeoutMs)
174841
175451
  };
174842
175452
  }
174843
- recover(dispatchId, nodeId, runtimeKind) {
175453
+ recover(dispatchId, nodeId, runtimeKind, actorId) {
174844
175454
  const stashed = this.drainStash(dispatchId);
174845
175455
  let entry = this.pending.get(dispatchId);
174846
175456
  if (!entry) {
174847
175457
  entry = {
174848
175458
  nodeId,
174849
175459
  ...runtimeKind ? { runtimeKind } : {},
175460
+ ...actorId ? { actorId } : {},
174850
175461
  exitCbs: [],
174851
175462
  telemetryCbs: [],
174852
175463
  outputCbs: [],
@@ -174954,7 +175565,7 @@ var init_daemon_adapter = __esm({
174954
175565
  }));
174955
175566
  }
174956
175567
  request(nodeId, buildFrame) {
174957
- const requestId = (0, import_node_crypto31.randomUUID)();
175568
+ const requestId = (0, import_node_crypto32.randomUUID)();
174958
175569
  const sent = this.hub.dispatch(nodeId, buildFrame(requestId));
174959
175570
  if (!sent) return Promise.resolve({ ok: false, code: "NODE_OFFLINE" });
174960
175571
  return new Promise((resolve9) => {
@@ -175037,13 +175648,13 @@ function classifyPage(page, lastPushedHash, serviceAccount) {
175037
175648
  if (sha(body) === lastPushedHash) return { kind: "echo" };
175038
175649
  return { kind: "human-edit", content: body, updatedBy: page.updatedBy };
175039
175650
  }
175040
- var import_node_crypto32, sha, enc3, dec, MirrorEngine, MapMirrorIdentities;
175651
+ var import_node_crypto33, sha, enc3, dec, MirrorEngine, MapMirrorIdentities;
175041
175652
  var init_engine = __esm({
175042
175653
  "../server/src/mirror/engine.ts"() {
175043
175654
  "use strict";
175044
- import_node_crypto32 = require("node:crypto");
175655
+ import_node_crypto33 = require("node:crypto");
175045
175656
  init_src();
175046
- sha = (s2) => (0, import_node_crypto32.createHash)("sha256").update(s2, "utf8").digest("hex");
175657
+ sha = (s2) => (0, import_node_crypto33.createHash)("sha256").update(s2, "utf8").digest("hex");
175047
175658
  enc3 = (s2) => new TextEncoder().encode(s2);
175048
175659
  dec = (b2) => new TextDecoder().decode(b2);
175049
175660
  MirrorEngine = class {
@@ -175795,11 +176406,11 @@ function humanExitCause(exit) {
175795
176406
  const base = (exit.reason ? label[exit.reason] : void 0) ?? `\u4F1A\u8BDD\u5F02\u5E38\u7ED3\u675F\uFF08${exit.reason ?? "\u65E0\u9000\u51FA\u4FE1\u606F"}\uFF09`;
175796
176407
  return exit.errorMessage ? `${base}\uFF1A${exit.errorMessage.slice(0, 200)}` : base;
175797
176408
  }
175798
- var import_node_crypto33, AUTONOMOUS_ETHOS, CONVERSATIONAL_ETHOS, SHARED_GRAPH_BODY, AUTONOMOUS_RECOVERY_TOOLS, HIGH_RISK_COMMANDS, COORDINATOR_SYSTEM_PROMPT, CONVERSATIONAL_RECOVERY_TOOLS, CONVERSATIONAL_MANAGER_BODY, MACHINE_EXIT_CODES, CoordinatorWorker;
176409
+ var import_node_crypto34, AUTONOMOUS_ETHOS, CONVERSATIONAL_ETHOS, SHARED_GRAPH_BODY, AUTONOMOUS_RECOVERY_TOOLS, HIGH_RISK_COMMANDS, COORDINATOR_SYSTEM_PROMPT, CONVERSATIONAL_RECOVERY_TOOLS, CONVERSATIONAL_MANAGER_BODY, MACHINE_EXIT_CODES, CoordinatorWorker;
175799
176410
  var init_worker = __esm({
175800
176411
  "../server/src/coordinator/worker.ts"() {
175801
176412
  "use strict";
175802
- import_node_crypto33 = require("node:crypto");
176413
+ import_node_crypto34 = require("node:crypto");
175803
176414
  init_src2();
175804
176415
  init_identity();
175805
176416
  AUTONOMOUS_ETHOS = `\u4F60\u662F\u8FD9\u4E2A\u5DE5\u5355\u7684**\u7BA1\u7406\u8005**\u2014\u2014\u804C\u8D23\u662F\u8BA9\u5B83\u987A\u7545\u8DD1\u5B8C\u3002\u7CFB\u7EDF\u5728\u67D0\u4E2A\u8282\u70B9\u5361\u4F4F\u3001\u673A\u68B0\u5206\u8BCA\u786E\u8BA4"\u9700\u8981\u4F60"\u65F6\u5524\u8D77\u4F60\uFF08\u65E0\u4EBA\u5728\u573A\uFF0C\u4F60\u8FD9\u4E00\u8F6E\u628A\u80FD\u505A\u7684\u505A\u6389\uFF09\u3002\u4F60\u7684\u624B\u6BB5\u5F88\u5BBD\uFF1A
@@ -176038,7 +176649,7 @@ ${HIGH_RISK_COMMANDS}`;
176038
176649
  return this.deps.kernel.model.lastSeq.get(artifactId) ?? 0;
176039
176650
  }
176040
176651
  evaluationKey(kind, artifactId, evidence) {
176041
- const fingerprint = (0, import_node_crypto33.createHash)("sha256").update(JSON.stringify(evidence)).digest("hex");
176652
+ const fingerprint = (0, import_node_crypto34.createHash)("sha256").update(JSON.stringify(evidence)).digest("hex");
176042
176653
  return `${kind}:${artifactId}:${fingerprint}`;
176043
176654
  }
176044
176655
  artifactEvidence(id) {
@@ -176403,7 +177014,7 @@ ${ctx.nodeFault}
176403
177014
  const token = this.deps.tokenFor(actorId, ctx);
176404
177015
  const serverUrl = this.deps.serverUrlFor ? await this.deps.serverUrlFor(ctx) : this.deps.serverUrl;
176405
177016
  const workspace = this.deps.kernel.model.artifacts.get(artifactId)?.workspace;
176406
- const runtimeSessionId = opts?.resumeSessionId ?? (0, import_node_crypto33.randomUUID)();
177017
+ const runtimeSessionId = opts?.resumeSessionId ?? (0, import_node_crypto34.randomUUID)();
176407
177018
  const job = {
176408
177019
  actor: actorId,
176409
177020
  actorToken: token,
@@ -181812,11 +182423,11 @@ var init_esm2 = __esm({
181812
182423
  });
181813
182424
 
181814
182425
  // ../storage/src/postgres.ts
181815
- var import_node_crypto34, ident3, isUniqueViolation, PostgresOplogStore, PostgresBlobStore;
182426
+ var import_node_crypto35, ident3, isUniqueViolation, PostgresOplogStore, PostgresBlobStore;
181816
182427
  var init_postgres = __esm({
181817
182428
  "../storage/src/postgres.ts"() {
181818
182429
  "use strict";
181819
- import_node_crypto34 = require("node:crypto");
182430
+ import_node_crypto35 = require("node:crypto");
181820
182431
  init_esm2();
181821
182432
  init_src();
181822
182433
  ident3 = (s2) => {
@@ -181969,7 +182580,7 @@ var init_postgres = __esm({
181969
182580
  return new _PostgresBlobStore(pool, schema);
181970
182581
  }
181971
182582
  async put(bytes) {
181972
- const hash = (0, import_node_crypto34.createHash)("sha256").update(bytes).digest("hex");
182583
+ const hash = (0, import_node_crypto35.createHash)("sha256").update(bytes).digest("hex");
181973
182584
  await this.pool.query(
181974
182585
  `INSERT INTO ${this.t} (hash, bytes, size, content_type) VALUES ($1, $2, $3, $4) ON CONFLICT (hash) DO NOTHING`,
181975
182586
  [hash, Buffer.from(bytes), bytes.byteLength, sniffContentType(bytes) ?? null]
@@ -185849,11 +186460,11 @@ var init_postgres_chat_sessions = __esm({
185849
186460
  });
185850
186461
 
185851
186462
  // ../storage/src/postgres-nodes.ts
185852
- var import_node_crypto35, ident12, PostgresNodeStore, PostgresNodeTokenStore, rowToNode, rowToRuntime;
186463
+ var import_node_crypto36, ident12, PostgresNodeStore, PostgresNodeTokenStore, rowToNode, rowToRuntime;
185853
186464
  var init_postgres_nodes = __esm({
185854
186465
  "../storage/src/postgres-nodes.ts"() {
185855
186466
  "use strict";
185856
- import_node_crypto35 = require("node:crypto");
186467
+ import_node_crypto36 = require("node:crypto");
185857
186468
  init_esm2();
185858
186469
  ident12 = (s2) => {
185859
186470
  if (!/^[a-z_][a-z0-9_]*$/.test(s2)) throw new Error(`invalid schema name: ${s2}`);
@@ -185992,7 +186603,7 @@ var init_postgres_nodes = __esm({
185992
186603
  return store;
185993
186604
  }
185994
186605
  issue(nodeId) {
185995
- const token = `ont_${(0, import_node_crypto35.randomBytes)(24).toString("base64url")}`;
186606
+ const token = `ont_${(0, import_node_crypto36.randomBytes)(24).toString("base64url")}`;
185996
186607
  this.cache.set(token, nodeId);
185997
186608
  void this.pool.query(`INSERT INTO ${this.s}.node_tokens (token,node_id) VALUES ($1,$2)`, [token, nodeId]);
185998
186609
  return token;
@@ -186203,11 +186814,11 @@ var init_postgres_type_registry = __esm({
186203
186814
  });
186204
186815
 
186205
186816
  // ../storage/src/postgres-actor-memory.ts
186206
- var import_node_crypto36, matchClause, ident15, PostgresActorMemoryStore, rowToIndexEntry, rowToRecord;
186817
+ var import_node_crypto37, matchClause, ident15, PostgresActorMemoryStore, rowToIndexEntry, rowToRecord;
186207
186818
  var init_postgres_actor_memory = __esm({
186208
186819
  "../storage/src/postgres-actor-memory.ts"() {
186209
186820
  "use strict";
186210
- import_node_crypto36 = require("node:crypto");
186821
+ import_node_crypto37 = require("node:crypto");
186211
186822
  init_src();
186212
186823
  matchClause = (q) => q.requireMatch && q.keywords.length > 0 ? " WHERE m > 0" : "";
186213
186824
  ident15 = (s2) => {
@@ -186412,7 +187023,7 @@ var init_postgres_actor_memory = __esm({
186412
187023
  }
186413
187024
  async write(input, now) {
186414
187025
  if (input.memId === void 0) {
186415
- const memId = `mem:${(0, import_node_crypto36.randomUUID)()}`;
187026
+ const memId = `mem:${(0, import_node_crypto37.randomUUID)()}`;
186416
187027
  const r2 = await this.pool.query(
186417
187028
  `INSERT INTO ${this.s}.actor_memories
186418
187029
  (mem_id, actor_id, project_id, keywords, content, version, created_at, updated_at, accessed_at, source_artifact_id, source_session_id)
@@ -186605,6 +187216,20 @@ function benchmarkSchemaSql(schema) {
186605
187216
  ON ${s2}.benchmark_runs (case_id, attempt_no DESC);
186606
187217
  CREATE INDEX IF NOT EXISTS benchmark_evaluations_run_idx
186607
187218
  ON ${s2}.benchmark_evaluations (run_id, evaluation_no DESC);
187219
+ CREATE TABLE IF NOT EXISTS ${s2}.benchmark_rubrics (
187220
+ rubric_id text PRIMARY KEY, company_id text NOT NULL, name text NOT NULL, kind text NOT NULL,
187221
+ description text, prompt_section text NOT NULL, output_spec jsonb NOT NULL,
187222
+ version integer NOT NULL, status text NOT NULL,
187223
+ created_by text NOT NULL, created_at timestamptz NOT NULL,
187224
+ updated_by text NOT NULL, updated_at timestamptz NOT NULL
187225
+ );
187226
+ CREATE TABLE IF NOT EXISTS ${s2}.benchmark_case_scoring (
187227
+ company_id text NOT NULL, case_id text NOT NULL, rubric_ids jsonb NOT NULL,
187228
+ judge_actor_id text, updated_by text NOT NULL, updated_at timestamptz NOT NULL,
187229
+ PRIMARY KEY (company_id, case_id)
187230
+ );
187231
+ CREATE INDEX IF NOT EXISTS benchmark_rubrics_company_idx
187232
+ ON ${s2}.benchmark_rubrics (company_id, name);
186608
187233
  `;
186609
187234
  }
186610
187235
  function benchmarkAttemptLockKey(companyId, caseId) {
@@ -186648,10 +187273,38 @@ function toEvaluation(row) {
186648
187273
  completedAt: nullableIso(row.completed_at)
186649
187274
  };
186650
187275
  }
186651
- var ident17, iso2, nullableIso, nullableText, PostgresEvaluationStore;
187276
+ function toRubric(row) {
187277
+ return {
187278
+ rubricId: String(row.rubric_id),
187279
+ companyId: String(row.company_id),
187280
+ name: String(row.name),
187281
+ kind: String(row.kind),
187282
+ ...row.description == null ? {} : { description: String(row.description) },
187283
+ promptSection: String(row.prompt_section),
187284
+ outputSpec: structuredClone(row.output_spec),
187285
+ version: Number(row.version),
187286
+ status: String(row.status),
187287
+ createdBy: String(row.created_by),
187288
+ createdAt: iso2(row.created_at),
187289
+ updatedBy: String(row.updated_by),
187290
+ updatedAt: iso2(row.updated_at)
187291
+ };
187292
+ }
187293
+ function toBinding(row) {
187294
+ return {
187295
+ companyId: String(row.company_id),
187296
+ caseId: String(row.case_id),
187297
+ rubricIds: Array.isArray(row.rubric_ids) ? row.rubric_ids.map(String) : [],
187298
+ judgeActorId: nullableText(row.judge_actor_id),
187299
+ updatedBy: String(row.updated_by),
187300
+ updatedAt: iso2(row.updated_at)
187301
+ };
187302
+ }
187303
+ var import_node_crypto38, ident17, iso2, nullableIso, nullableText, PostgresEvaluationStore, PostgresEvaluationRubricStore;
186652
187304
  var init_postgres_evaluation = __esm({
186653
187305
  "../storage/src/postgres-evaluation.ts"() {
186654
187306
  "use strict";
187307
+ import_node_crypto38 = require("node:crypto");
186655
187308
  init_esm2();
186656
187309
  ident17 = (value2) => {
186657
187310
  if (!/^[a-z_][a-z0-9_]*$/.test(value2)) throw new Error(`invalid schema name: ${value2}`);
@@ -186838,6 +187491,147 @@ var init_postgres_evaluation = __esm({
186838
187491
  if (result.rowCount !== 1) throw new Error(`Evaluation ${evaluation.evaluationId} \u4E0D\u5B58\u5728`);
186839
187492
  }
186840
187493
  };
187494
+ PostgresEvaluationRubricStore = class _PostgresEvaluationRubricStore {
187495
+ constructor(pool, schema) {
187496
+ this.pool = pool;
187497
+ this.s = `"${ident17(schema)}"`;
187498
+ }
187499
+ s;
187500
+ static async open(pool, schema = "public") {
187501
+ const safe = ident17(schema);
187502
+ await pool.query(`CREATE SCHEMA IF NOT EXISTS "${safe}"`);
187503
+ await pool.query(benchmarkSchemaSql(safe));
187504
+ return new _PostgresEvaluationRubricStore(pool, safe);
187505
+ }
187506
+ async listRubrics(companyId) {
187507
+ const result = await this.pool.query(
187508
+ `SELECT * FROM ${this.s}.benchmark_rubrics WHERE company_id=$1 ORDER BY name ASC`,
187509
+ [companyId]
187510
+ );
187511
+ return result.rows.map((row) => toRubric(row));
187512
+ }
187513
+ async getRubric(rubricId) {
187514
+ const result = await this.pool.query(
187515
+ `SELECT * FROM ${this.s}.benchmark_rubrics WHERE rubric_id=$1`,
187516
+ [rubricId]
187517
+ );
187518
+ return result.rows[0] ? toRubric(result.rows[0]) : null;
187519
+ }
187520
+ async upsertRubric(input, at) {
187521
+ const client = await this.pool.connect();
187522
+ try {
187523
+ await client.query("BEGIN");
187524
+ const existing = input.rubricId ? (await client.query(
187525
+ `SELECT * FROM ${this.s}.benchmark_rubrics WHERE rubric_id=$1 FOR UPDATE`,
187526
+ [input.rubricId]
187527
+ )).rows[0] : void 0;
187528
+ if (existing && String(existing.company_id) !== input.companyId) {
187529
+ throw new Error(`\u8BC4\u5206\u6807\u51C6 ${input.rubricId} \u4E0D\u5C5E\u4E8E\u5F53\u524D\u516C\u53F8`);
187530
+ }
187531
+ const rubricId = existing ? String(existing.rubric_id) : input.rubricId ?? (0, import_node_crypto38.randomUUID)();
187532
+ const version2 = existing ? Number(existing.version) + 1 : 1;
187533
+ const status = input.status ?? (existing ? String(existing.status) : "active");
187534
+ const createdBy = existing ? String(existing.created_by) : input.actor;
187535
+ const createdAt = existing ? iso2(existing.created_at) : at;
187536
+ await client.query(
187537
+ `INSERT INTO ${this.s}.benchmark_rubrics
187538
+ (rubric_id,company_id,name,kind,description,prompt_section,output_spec,version,status,
187539
+ created_by,created_at,updated_by,updated_at)
187540
+ VALUES ($1,$2,$3,$4,$5,$6,$7::jsonb,$8,$9,$10,$11,$12,$13)
187541
+ ON CONFLICT (rubric_id) DO UPDATE SET name=EXCLUDED.name,kind=EXCLUDED.kind,
187542
+ description=EXCLUDED.description,prompt_section=EXCLUDED.prompt_section,
187543
+ output_spec=EXCLUDED.output_spec,version=EXCLUDED.version,status=EXCLUDED.status,
187544
+ updated_by=EXCLUDED.updated_by,updated_at=EXCLUDED.updated_at`,
187545
+ [
187546
+ rubricId,
187547
+ input.companyId,
187548
+ input.name,
187549
+ input.kind,
187550
+ input.description ?? null,
187551
+ input.promptSection,
187552
+ JSON.stringify(input.outputSpec),
187553
+ version2,
187554
+ status,
187555
+ createdBy,
187556
+ createdAt,
187557
+ input.actor,
187558
+ at
187559
+ ]
187560
+ );
187561
+ await client.query("COMMIT");
187562
+ const saved = await this.getRubric(rubricId);
187563
+ if (!saved) throw new Error(`\u8BC4\u5206\u6807\u51C6 ${rubricId} \u4FDD\u5B58\u540E\u8BFB\u4E0D\u56DE`);
187564
+ return saved;
187565
+ } catch (error2) {
187566
+ await client.query("ROLLBACK").catch(() => {
187567
+ });
187568
+ throw error2;
187569
+ } finally {
187570
+ client.release();
187571
+ }
187572
+ }
187573
+ async deleteRubric(rubricId, companyId) {
187574
+ const client = await this.pool.connect();
187575
+ try {
187576
+ await client.query("BEGIN");
187577
+ await client.query(
187578
+ `DELETE FROM ${this.s}.benchmark_rubrics WHERE rubric_id=$1 AND company_id=$2`,
187579
+ [rubricId, companyId]
187580
+ );
187581
+ await client.query(
187582
+ `UPDATE ${this.s}.benchmark_case_scoring
187583
+ SET rubric_ids = COALESCE((
187584
+ SELECT jsonb_agg(value) FROM jsonb_array_elements_text(rubric_ids) AS value
187585
+ WHERE value <> $2
187586
+ ), '[]'::jsonb)
187587
+ WHERE company_id=$1 AND rubric_ids @> to_jsonb($2::text)`,
187588
+ [companyId, rubricId]
187589
+ );
187590
+ await client.query("COMMIT");
187591
+ } catch (error2) {
187592
+ await client.query("ROLLBACK").catch(() => {
187593
+ });
187594
+ throw error2;
187595
+ } finally {
187596
+ client.release();
187597
+ }
187598
+ }
187599
+ async listBindings(companyId) {
187600
+ const result = await this.pool.query(
187601
+ `SELECT * FROM ${this.s}.benchmark_case_scoring WHERE company_id=$1 ORDER BY case_id ASC`,
187602
+ [companyId]
187603
+ );
187604
+ return result.rows.map((row) => toBinding(row));
187605
+ }
187606
+ async getBinding(companyId, caseId) {
187607
+ const result = await this.pool.query(
187608
+ `SELECT * FROM ${this.s}.benchmark_case_scoring WHERE company_id=$1 AND case_id=$2`,
187609
+ [companyId, caseId]
187610
+ );
187611
+ return result.rows[0] ? toBinding(result.rows[0]) : null;
187612
+ }
187613
+ async putBinding(input, at) {
187614
+ await this.pool.query(
187615
+ `INSERT INTO ${this.s}.benchmark_case_scoring
187616
+ (company_id,case_id,rubric_ids,judge_actor_id,updated_by,updated_at)
187617
+ VALUES ($1,$2,$3::jsonb,$4,$5,$6)
187618
+ ON CONFLICT (company_id,case_id) DO UPDATE SET rubric_ids=EXCLUDED.rubric_ids,
187619
+ judge_actor_id=EXCLUDED.judge_actor_id,updated_by=EXCLUDED.updated_by,
187620
+ updated_at=EXCLUDED.updated_at`,
187621
+ [
187622
+ input.companyId,
187623
+ input.caseId,
187624
+ JSON.stringify(input.rubricIds),
187625
+ input.judgeActorId,
187626
+ input.actor,
187627
+ at
187628
+ ]
187629
+ );
187630
+ const saved = await this.getBinding(input.companyId, input.caseId);
187631
+ if (!saved) throw new Error(`Case ${input.caseId} \u88C5\u914D\u4FDD\u5B58\u540E\u8BFB\u4E0D\u56DE`);
187632
+ return saved;
187633
+ }
187634
+ };
186841
187635
  }
186842
187636
  });
186843
187637
 
@@ -186852,6 +187646,7 @@ __export(src_exports, {
186852
187646
  PostgresChannelStore: () => PostgresChannelStore,
186853
187647
  PostgresChatSessionStore: () => PostgresChatSessionStore,
186854
187648
  PostgresControlPlaneStore: () => PostgresControlPlaneStore,
187649
+ PostgresEvaluationRubricStore: () => PostgresEvaluationRubricStore,
186855
187650
  PostgresEvaluationStore: () => PostgresEvaluationStore,
186856
187651
  PostgresHumanPrefsStore: () => PostgresHumanPrefsStore,
186857
187652
  PostgresModelPriceStore: () => PostgresModelPriceStore,
@@ -187027,13 +187822,13 @@ var import_node_child_process17 = require("node:child_process");
187027
187822
  var fs33 = __toESM(require("node:fs"), 1);
187028
187823
  var os8 = __toESM(require("node:os"), 1);
187029
187824
  var path27 = __toESM(require("node:path"), 1);
187030
- var import_node_crypto40 = require("node:crypto");
187825
+ var import_node_crypto42 = require("node:crypto");
187031
187826
 
187032
187827
  // ../cli/src/serve.ts
187033
187828
  var fs29 = __toESM(require("node:fs"), 1);
187034
187829
  var os5 = __toESM(require("node:os"), 1);
187035
187830
  var path23 = __toESM(require("node:path"), 1);
187036
- var import_node_crypto37 = require("node:crypto");
187831
+ var import_node_crypto39 = require("node:crypto");
187037
187832
  var import_node_url5 = require("node:url");
187038
187833
  init_src2();
187039
187834
  init_src7();
@@ -187268,8 +188063,8 @@ exec ${JSON.stringify(tsx)} ${JSON.stringify(main)} "$@"
187268
188063
  return wrapper;
187269
188064
  }
187270
188065
  function splitIdentityFiles3(prompt) {
187271
- const sep3 = /<!-- FILE: (.+?) -->\n?/g;
187272
- const parts = prompt.split(sep3);
188066
+ const sep4 = /<!-- FILE: (.+?) -->\n?/g;
188067
+ const parts = prompt.split(sep4);
187273
188068
  if (parts.length === 1) return { "identity/AGENTS.md": prompt };
187274
188069
  const out = {};
187275
188070
  for (let i = 1; i < parts.length; i += 2) {
@@ -187923,6 +188718,16 @@ async function startServe(opts) {
187923
188718
  let workdirBridge = null;
187924
188719
  const nodeHealth = new NodeHealthTracker();
187925
188720
  const activeRunCountOf = (nodeId, runtimeKind) => (chatRemoteAdapter?.activeRunCount(nodeId, runtimeKind) ?? 0) + (dispatchRemoteAdapter?.activeRunCount(nodeId, runtimeKind) ?? 0);
188721
+ const activeRunsOf = (nodeId, runtimeKind) => {
188722
+ const byActor = /* @__PURE__ */ new Map();
188723
+ for (const adapter of [chatRemoteAdapter, dispatchRemoteAdapter]) {
188724
+ if (!adapter) continue;
188725
+ for (const [actorId, count2] of adapter.activeRunsByActor(nodeId, runtimeKind)) {
188726
+ byActor.set(actorId, (byActor.get(actorId) ?? 0) + count2);
188727
+ }
188728
+ }
188729
+ return [...byActor].map(([actorId, count2]) => ({ actorId, count: count2 })).sort((a, b2) => b2.count - a.count || a.actorId.localeCompare(b2.actorId));
188730
+ };
187926
188731
  let localUrl = "";
187927
188732
  const chatLiveSessions = /* @__PURE__ */ new Map();
187928
188733
  const remoteApiUrl = opts.publicUrl ? normalizeHttpBaseUrl(opts.publicUrl) : apiUrlFromGatewayUrl(opts.gatewayUrl);
@@ -187980,6 +188785,7 @@ async function startServe(opts) {
187980
188785
  const structuralBaselines = /* @__PURE__ */ new Map();
187981
188786
  const deployTargets = DeployTargetStore.open(path23.join(opts.dir, "deploy-targets.json"));
187982
188787
  const evaluationStore = pgPool ? await PostgresEvaluationStore.open(pgPool, pgSchema) : new MemoryEvaluationStore();
188788
+ const evaluationRubricStore = pgPool ? await PostgresEvaluationRubricStore.open(pgPool, pgSchema) : new MemoryEvaluationRubricStore();
187983
188789
  const evaluationBenchRoot = process.env["OASIS_EVALUATION_BENCH_ROOT"]?.trim() ?? "";
187984
188790
  const evaluationCatalog = evaluationBenchRoot ? await FilesystemEvaluationCaseCatalog.open(evaluationBenchRoot) : new StaticEvaluationCaseCatalog([]);
187985
188791
  console.log(`[serve] evaluation benchmark catalog=${evaluationBenchRoot || "empty (OASIS_EVALUATION_BENCH_ROOT unset)"}`);
@@ -188029,19 +188835,34 @@ async function startServe(opts) {
188029
188835
  return collector.freeze(workOrderId);
188030
188836
  };
188031
188837
  const evaluationJudge = new ChatEvaluationJudge({
188032
- actorId: evaluationScoringActorId,
188033
188838
  judgeVersion: evaluationJudgeVersion,
188034
188839
  dispatchChat: async (request) => {
188035
- if (!evaluationScoringActorId) {
188036
- throw new Error("OASIS_EVALUATION_SCORING_ACTOR_ID \u672A\u914D\u7F6E\uFF0C\u65E0\u6CD5\u8C03\u7528\u8BC4\u5206\u5458\u5DE5");
188037
- }
188038
188840
  if (!evaluationDispatchChat) {
188039
188841
  throw new Error("\u8BC4\u5206\u5458\u5DE5\u6D3E\u53D1\u94FE\u8DEF\u5C1A\u672A\u521D\u59CB\u5316");
188040
188842
  }
188041
188843
  return evaluationDispatchChat(request);
188042
188844
  }
188043
188845
  });
188846
+ const listJudgeCandidates = async (companyId) => {
188847
+ const actorCtx = await actors.resolveCtx(companyId);
188848
+ const [agents, resolveBinding] = await Promise.all([
188849
+ actorCtx.service.listActors({ kind: "agent", status: "active" }),
188850
+ actorCtx.service.resolveBinding()
188851
+ ]);
188852
+ const candidates = await Promise.all(agents.map(async (agent) => {
188853
+ const binding = await resolveBinding(agent.id).catch(() => null);
188854
+ return binding ? { actorId: agent.id, name: agent.name } : null;
188855
+ }));
188856
+ return candidates.filter((candidate) => candidate !== null);
188857
+ };
188858
+ const evaluationScoring = new EvaluationScoringService({
188859
+ store: evaluationRubricStore,
188860
+ defaultJudgeActorId: evaluationScoringActorId,
188861
+ verifyJudgeActor: async (actorId, companyId) => (await listJudgeCandidates(companyId)).some((candidate) => candidate.actorId === actorId)
188862
+ });
188044
188863
  const evaluations = createEvaluationDomain({
188864
+ scoring: evaluationScoring,
188865
+ listJudgeCandidates,
188045
188866
  service: new EvaluationService({
188046
188867
  store: evaluationStore,
188047
188868
  catalog: evaluationCatalog,
@@ -188051,7 +188872,7 @@ async function startServe(opts) {
188051
188872
  },
188052
188873
  freezeEvidence: async (runId, companyId) => structuredClone(await collectEvaluationEvidence(runId, companyId)),
188053
188874
  judge: evaluationJudge,
188054
- judgeActorId: evaluationScoringActorId,
188875
+ scoring: evaluationScoring,
188055
188876
  judgeVersion: evaluationJudgeVersion,
188056
188877
  resolveBenchmarkProjects: (evaluationCase) => resolveEvaluationBenchmarkProjects(evaluationCase, projectStateStore)
188057
188878
  })
@@ -188117,7 +188938,7 @@ async function startServe(opts) {
188117
188938
  }));
188118
188939
  }
188119
188940
  const limits = { wallClockMs: SESSION_WALL_CLOCK_MS.planner };
188120
- const artifactId = `artifact:planner:${(0, import_node_crypto37.randomUUID)()}`;
188941
+ const artifactId = `artifact:planner:${(0, import_node_crypto39.randomUUID)()}`;
188121
188942
  const handle = await chatRemoteAdapter.spawn({
188122
188943
  actor: planner.id,
188123
188944
  actorToken: issueSessionToken(planner.id, { artifactId, action: "plan-workorder", limits, binding }),
@@ -188164,6 +188985,7 @@ async function startServe(opts) {
188164
188985
  repoRemote: opts.nodeRepoRemote ?? "git@github.com:open-friday/oasis-core.git",
188165
188986
  nodeHealth,
188166
188987
  activeRunCountOf,
188988
+ activeRunsOf,
188167
188989
  fetchLatestNpmDaemonVersion
188168
188990
  }),
188169
188991
  evaluations.register,
@@ -188308,10 +189130,10 @@ async function startServe(opts) {
188308
189130
  { nodeId: priorChatSession?.runtimeId, runtimeKind: priorChatSession?.runtimeKind },
188309
189131
  { nodeId: binding.nodeId, runtimeKind: binding.runtimeKind }
188310
189132
  ) : false;
188311
- const runtimeSessionId = sessionId ?? (0, import_node_crypto37.randomUUID)();
189133
+ const runtimeSessionId = sessionId ?? (0, import_node_crypto39.randomUUID)();
188312
189134
  const resumeRuntimeSession = Boolean(sessionId);
188313
- const traceRunId = `chat-run:${(0, import_node_crypto37.randomUUID)()}`;
188314
- const artifactId = `artifact:chat:${(0, import_node_crypto37.randomUUID)()}`;
189135
+ const traceRunId = `chat-run:${(0, import_node_crypto39.randomUUID)()}`;
189136
+ const artifactId = `artifact:chat:${(0, import_node_crypto39.randomUUID)()}`;
188315
189137
  const traceStartedAt = (/* @__PURE__ */ new Date()).toISOString();
188316
189138
  let traceSeq = 0;
188317
189139
  let lastProgressTouchMs = 0;
@@ -188645,7 +189467,7 @@ async function startServe(opts) {
188645
189467
  isWired: (artifactId) => chatLiveSessions.has(`chat::${artifactId}`)
188646
189468
  });
188647
189469
  for (const plan of plans) {
188648
- const handle = chatRemoteAdapter.recover(plan.dispatchId, daemonId, plan.runtimeKind);
189470
+ const handle = chatRemoteAdapter.recover(plan.dispatchId, daemonId, plan.runtimeKind, plan.actor);
188649
189471
  const jobKey = `chat::${plan.artifactId}`;
188650
189472
  wireRecoveredChatTurn({
188651
189473
  plan,
@@ -189078,7 +189900,7 @@ async function startServe(opts) {
189078
189900
  ensureDispatcherForEngine?.(companyId, engine2);
189079
189901
  const slot = dispatchers.get(companyId);
189080
189902
  if (!slot) continue;
189081
- const session = dispatchRemoteAdapter.recover(plan.dispatchId, daemonId, plan.runtimeKind);
189903
+ const session = dispatchRemoteAdapter.recover(plan.dispatchId, daemonId, plan.runtimeKind, plan.actor);
189082
189904
  const recoveredAt = (/* @__PURE__ */ new Date()).toISOString();
189083
189905
  const interruptedAt = previousServerHeartbeatAt ?? serverStartedAt;
189084
189906
  const restored = slot.dispatcher.recoverInFlightSession({
@@ -189708,7 +190530,7 @@ var SessionManager = class {
189708
190530
  // ../cli/src/daemon/ws-client.ts
189709
190531
  init_wrapper();
189710
190532
  var import_node_os7 = require("node:os");
189711
- var import_node_crypto38 = require("node:crypto");
190533
+ var import_node_crypto40 = require("node:crypto");
189712
190534
  init_src5();
189713
190535
 
189714
190536
  // ../cli/src/daemon/detect-adapters.ts
@@ -190264,7 +191086,7 @@ var DaemonWsClient = class {
190264
191086
  */
190265
191087
  async queryArtifactStates(artifactIds, timeoutMs = 15e3) {
190266
191088
  if (artifactIds.length === 0) return {};
190267
- const requestId = (0, import_node_crypto38.randomUUID)();
191089
+ const requestId = (0, import_node_crypto40.randomUUID)();
190268
191090
  return new Promise((resolve9, reject) => {
190269
191091
  const timer = setTimeout(() => {
190270
191092
  this.gcPending.delete(requestId);
@@ -190483,7 +191305,7 @@ async function startNode(opts) {
190483
191305
  // ../cli/src/daemon/machine-id.ts
190484
191306
  var import_node_child_process16 = require("node:child_process");
190485
191307
  var import_node_fs18 = require("node:fs");
190486
- var import_node_crypto39 = require("node:crypto");
191308
+ var import_node_crypto41 = require("node:crypto");
190487
191309
  var import_node_os10 = require("node:os");
190488
191310
  function linuxMachineId() {
190489
191311
  for (const p2 of ["/etc/machine-id", "/var/lib/dbus/machine-id"]) {
@@ -190549,7 +191371,7 @@ var defaultSources = {
190549
191371
  function resolveNodeId(sources = {}) {
190550
191372
  const s2 = { ...defaultSources, ...sources };
190551
191373
  const material = `${s2.machineFingerprint()}:${s2.osUser()}`;
190552
- const digest = (0, import_node_crypto39.createHash)("sha256").update(material).digest("hex").slice(0, 12);
191374
+ const digest = (0, import_node_crypto41.createHash)("sha256").update(material).digest("hex").slice(0, 12);
190553
191375
  return `node-${digest}`;
190554
191376
  }
190555
191377
 
@@ -190720,6 +191542,24 @@ var USAGE = `oasis \u2014\u2014 artifact-centric \u534F\u4F5C\u5185\u6838 CLI\uF
190720
191542
  legacy-assistants list # \u5217\u5B58\u91CF\u53EF\u8BA4\u9886\u7684\u79C1\u4EBA agent\uFF08\u5019\u9009\u9762\uFF0C\u9644\u731C\u6D4B\u5F52\u5C5E\u4EBA\uFF0C\u4E0D\u9884\u586B\uFF09
190721
191543
  legacy-assistants claim <agentId> --human <humanId> [--keep-position] [--name <\u65B0\u540D>] # \u8BA4\u9886\u5E76\u6C38\u4E45\u9501\u5B9A\u7ED9\u8BE5\u771F\u4EBA
190722
191544
 
191545
+ \u6D4B\u8BC4\u4E0E\u8BC4\u5206\u88C5\u914D\uFF08\u4EBA\u548C agent \u540C\u4E00\u5957\u547D\u4EE4\uFF1B\u524D\u7AEF\u300C\u8BC4\u6D4B \u2192 \u8BC4\u5206\u88C5\u914D\u300D\u9875\u8D70\u540C\u4E00\u6279\u63A5\u53E3\uFF09
191546
+ cases # Benchmark Case \u6E05\u5355
191547
+ evaluations [--case <caseId>] # Run \u4E00\u89C8\uFF1A\u6700\u65B0\u8BC4\u5206\u72B6\u6001 / \u5224\u5206\u5458\u5DE5 / \u6807\u51C6\u7248\u672C
191548
+ evaluate <workOrderId> --case <caseId> [--judge <actorId>] [--case-version <v>] # \u5EFA Run \u5E76\u6392\u961F\u9996\u6B21\u8BC4\u5206
191549
+ rescore <runId> [--judge <actorId>] # \u53EA\u65B0\u589E\u4E00\u6B21\u8BC4\u5206\uFF0C\u4E0D\u52A8 Run \u5E8F\u53F7
191550
+ judges # \u53EF\u5F53\u5224\u5206\u5458\u5DE5\u7684 agent\uFF08\u53EA\u5217\u6709 active runtime \u7ED1\u5B9A\u7684\uFF09
191551
+ rubrics [--kind common|specialty|case_special] # \u8BC4\u5206\u6807\u51C6\u6E05\u5355\uFF08\u4E09\u79CD\u6807\u51C6\u662F\u540C\u4E00\u79CD\u5B9E\u4F53\uFF09
191552
+ rubric <rubricId> # \u770B\u4E00\u6761\u6807\u51C6\uFF1A\u8BF4\u660E + \u8F93\u51FA\u5951\u7EA6 + \u6CE8\u5165 prompt \u7684\u6B63\u6587\u5168\u6587
191553
+ rubric-save [--rubric-id <id>] --name <\u540D> --kind <k> (--prompt <\u6587\u672C>|--prompt-file <\u8DEF\u5F84>) [--spec-file <json>|--spec <json>] [--description \u2026] [--status active|archived]
191554
+ # \u4E0D\u5E26 --rubric-id \u662F\u65B0\u5EFA\uFF0C\u5E26\u4E0A\u662F\u6539\uFF08\u7248\u672C\u53F7\u81EA\u589E\uFF09\u3002--spec \u662F\u8F93\u51FA\u5951\u7EA6\uFF1A
191555
+ # { "sectionKey": "common", "aggregation": "none"|"mean", "strictIds": true, "dimensions": [{"id":"G1","label":"\u2026","min":1,"max":5,"nullable":false}] }
191556
+ # \u5B83\u540C\u65F6\u51B3\u5B9A\u300C\u5224\u5206\u5458\u5DE5\u8981\u8F93\u51FA\u4EC0\u4E48\u5F62\u72B6\u300D\u548C\u300C\u7ED3\u679C\u600E\u4E48\u6821\u9A8C\u300D\u2014\u2014\u4E0D\u518D\u5199\u6B7B G1-G7/\u4E94\u9879\u3002
191557
+ rubric-delete <rubricId> # \u5220\u6807\u51C6\uFF08\u6302\u8F7D\u4E86\u5B83\u7684 Case \u540C\u6B65\u6458\u5F15\u7528\uFF09
191558
+ case-scoring <caseId> # \u770B\u67D0 Case \u6302\u4E86\u54EA\u51E0\u5957\u6807\u51C6\u3001\u7531\u8C01\u6253\u5206\u3001\u662F\u5426\u8FD8\u5728\u5403\u56DE\u843D
191559
+ case-scoring-set <caseId> [--rubrics id1,id2] [--judge <actorId>|none]
191560
+ # \u53EA\u7ED9\u5176\u4E2D\u4E00\u4E2A flag \u5C31\u53EA\u6539\u90A3\u4E00\u9879\uFF08\u53E6\u4E00\u9879\u6CBF\u7528\u73B0\u503C\uFF0C\u4E0D\u4F1A\u88AB\u6E05\u7A7A\uFF09\u3002--judge none = \u56DE\u5230\u90E8\u7F72\u9ED8\u8BA4\u3002
191561
+ # \u4E00\u6761\u6807\u51C6\u90FD\u4E0D\u6302 = \u56DE\u843D\u5230 oasis-bench \u81EA\u5E26\u7684\u901A\u7528/\u4E13\u9879/Case \u4E13\u9879\u4E09\u4EFD\u6750\u6599\uFF0C\u884C\u4E3A\u4E0E\u914D\u7F6E\u5316\u4E4B\u524D\u4E00\u81F4\u3002
191562
+
190723
191563
  \u6CBB\u7406\uFF08\xA711\uFF09
190724
191564
  reopen <artifactId> [--note t] # \u89E3\u5C01\uFF08lifecycle \u2192 active\uFF09
190725
191565
  force-conclude <artifactId> --reason <t> # \u8C41\u514D gate\uFF1B\u673A\u68B0\u68C0\u67E5\u7167\u8DD1\u3001\u91CC\u7A0B\u7891\u5E26 forced \u6807\u8BB0
@@ -191069,7 +191909,7 @@ async function runCli(argv, println = console.log) {
191069
191909
  const store = createNodeTokenStore(path27.join(dir, "node-tokens.json"));
191070
191910
  const sub = positional[0];
191071
191911
  if (sub === "issue") {
191072
- const id = flags.get("id") ?? `node-${(0, import_node_crypto40.randomUUID)()}`;
191912
+ const id = flags.get("id") ?? `node-${(0, import_node_crypto42.randomUUID)()}`;
191073
191913
  const token2 = store.issue(id);
191074
191914
  println(token2);
191075
191915
  process.stderr.write(
@@ -192687,6 +193527,151 @@ ${res.warning}`);
192687
193527
  else if (!wsFilter && rows.length > 30) println(`\u2014\u2014 \u5171 ${rows.length} \u4E2A\u4EA7\u7269\uFF08\u5168\u5E93\u62C9\u5E73\uFF09\u3002\u6309\u5DE5\u5355\u770B\u7528 \`oasis ls --workspace <ws:id>\`\uFF0C\u5DE5\u5355\u6E05\u5355\u7528 \`oasis workorders\`\u3002`);
192688
193528
  break;
192689
193529
  }
193530
+ /**
193531
+ * 评测评分装配(人和 agent 同一套命令)。
193532
+ *
193533
+ * 三种评分标准(通用 / S 专项 / Case 专项)在系统里是**同一种实体**,统一经 prompt 注入判分员工;
193534
+ * 一条标准可挂到多个 Case,一个 Case 可挂多条;判分员工按「本次指定 → Case 装配 → 部署默认」解析。
193535
+ * 前端「评测 → 评分装配」页走的是同一批接口,两边不会各算各的。
193536
+ */
193537
+ case "rubrics": {
193538
+ const kind = flags.get("kind");
193539
+ const res = await api.request("GET", "/api/evaluations/rubrics");
193540
+ const items = kind ? res.items.filter((r) => r.kind === kind) : res.items;
193541
+ println(`\u8BC4\u5206\u6807\u51C6(${items.length}${kind ? ` / kind=${kind}` : ""})\u2014\u2014\u6302\u5230 Case \u7528 \`oasis case-scoring-set\`:`);
193542
+ for (const r of items) {
193543
+ println(`- ${r.rubricId} ${r.name} [${r.kind}] v${r.version}${r.status === "archived" ? " [\u5DF2\u5F52\u6863]" : ""}`);
193544
+ println(` \u8F93\u51FA\u6BB5=${r.outputSpec.sectionKey} \u7EF4\u5EA6=${r.outputSpec.dimensions.length || "\u7531 Case \u5B9A\u4E49"}${r.description ? ` ${r.description}` : ""}`);
193545
+ }
193546
+ if (items.length === 0) println("\uFF08\u65E0\u3002\u4E00\u6761\u90FD\u6CA1\u6709\u65F6 Case \u4F1A\u56DE\u843D\u5230 oasis-bench \u81EA\u5E26\u7684\u4E09\u4EFD\u6750\u6599\uFF09");
193547
+ break;
193548
+ }
193549
+ case "rubric": {
193550
+ const rubricId = needPos(positional, 0, "oasis rubric <rubricId>");
193551
+ const res = await api.request("GET", "/api/evaluations/rubrics");
193552
+ const rubric = res.items.find((r) => r.rubricId === rubricId);
193553
+ if (!rubric) throw new Error(`\u8BC4\u5206\u6807\u51C6 ${rubricId} \u4E0D\u5B58\u5728`);
193554
+ println(`${rubric.name} [${rubric.kind}] v${rubric.version} ${rubric.status}`);
193555
+ if (rubric.description) println(`\u8BF4\u660E: ${rubric.description}`);
193556
+ println(`\u8F93\u51FA\u5951\u7EA6: ${JSON.stringify(rubric.outputSpec, null, 2)}`);
193557
+ println("--- \u6CE8\u5165\u5224\u5206 prompt \u7684\u6B63\u6587 ---");
193558
+ println(rubric.promptSection);
193559
+ break;
193560
+ }
193561
+ case "rubric-save": {
193562
+ const rubricId = flags.get("rubric-id");
193563
+ const promptSection = flags.get("prompt-file") !== void 0 ? readFileArg(flags.get("prompt-file")) : flags.get("prompt");
193564
+ if (!promptSection) {
193565
+ throw new Error("\u7F3A\u5C11\u6807\u51C6\u6B63\u6587\uFF1A\u7ED9 --prompt <\u6587\u672C> \u6216 --prompt-file <\u8DEF\u5F84>");
193566
+ }
193567
+ const outputSpec = flags.get("spec-file") !== void 0 ? JSON.parse(readFileArg(flags.get("spec-file"))) : flags.get("spec") !== void 0 ? JSON.parse(flags.get("spec")) : void 0;
193568
+ const body = { promptSection };
193569
+ if (flags.get("name") !== void 0) body["name"] = flags.get("name");
193570
+ if (flags.get("kind") !== void 0) body["kind"] = flags.get("kind");
193571
+ if (flags.get("description") !== void 0) body["description"] = flags.get("description");
193572
+ if (flags.get("status") !== void 0) body["status"] = flags.get("status");
193573
+ if (outputSpec !== void 0) body["outputSpec"] = outputSpec;
193574
+ const saved = rubricId ? await api.request("PUT", `/api/evaluations/rubrics/${encodeURIComponent(rubricId)}`, body) : await api.request("POST", "/api/evaluations/rubrics", body);
193575
+ println(`\u5DF2\u4FDD\u5B58 ${saved.rubricId} ${saved.name} [${saved.kind}] v${saved.version}`);
193576
+ println(`\u6302\u5230 Case: oasis case-scoring-set <caseId> --rubrics ${saved.rubricId}`);
193577
+ break;
193578
+ }
193579
+ case "rubric-delete": {
193580
+ const rubricId = needPos(positional, 0, "oasis rubric-delete <rubricId>");
193581
+ await api.request("DELETE", `/api/evaluations/rubrics/${encodeURIComponent(rubricId)}`);
193582
+ println(`\u5DF2\u5220\u9664 ${rubricId}\uFF08\u6302\u8F7D\u4E86\u5B83\u7684 Case \u4F1A\u540C\u6B65\u6458\u6389\u5F15\u7528\uFF09`);
193583
+ break;
193584
+ }
193585
+ case "case-scoring": {
193586
+ const caseId = needPos(positional, 0, "oasis case-scoring <caseId>");
193587
+ const res = await api.request(
193588
+ "GET",
193589
+ `/api/evaluations/cases/${encodeURIComponent(caseId)}/scoring`
193590
+ );
193591
+ println(`Case ${res.caseId} \u8BC4\u5206\u88C5\u914D:`);
193592
+ println(` \u5224\u5206\u5458\u5DE5: ${res.judgeActorId ?? "\uFF08\u7528\u90E8\u7F72\u9ED8\u8BA4\uFF09"}`);
193593
+ if (res.usesBuiltinFallback) {
193594
+ println(" \u8BC4\u5206\u6807\u51C6: \uFF08\u672A\u6302\u8F7D\uFF0C\u56DE\u843D\u5230 oasis-bench \u81EA\u5E26\u7684\u901A\u7528 / \u4E13\u9879 / Case \u4E13\u9879\u4E09\u4EFD\u6750\u6599\uFF09");
193595
+ } else {
193596
+ for (const r of res.rubrics) {
193597
+ println(` - ${r.rubricId} ${r.name} [${r.kind}] v${r.version} \u2192 \u8F93\u51FA\u6BB5 ${r.outputSpec.sectionKey}`);
193598
+ }
193599
+ }
193600
+ break;
193601
+ }
193602
+ case "case-scoring-set": {
193603
+ const caseId = needPos(positional, 0, "oasis case-scoring-set <caseId> [--rubrics id1,id2] [--judge <actorId>|none]");
193604
+ const current = await api.request(
193605
+ "GET",
193606
+ `/api/evaluations/cases/${encodeURIComponent(caseId)}/scoring`
193607
+ );
193608
+ const rubricIds = flags.get("rubrics") !== void 0 ? flags.get("rubrics").split(",").map((v2) => v2.trim()).filter(Boolean) : current.rubrics.map((r) => r.rubricId);
193609
+ const judgeFlag = flags.get("judge");
193610
+ const judgeActorId = judgeFlag === void 0 ? current.judgeActorId : judgeFlag === "none" || judgeFlag === "" ? null : judgeFlag;
193611
+ const saved = await api.request(
193612
+ "PUT",
193613
+ `/api/evaluations/cases/${encodeURIComponent(caseId)}/scoring`,
193614
+ { rubricIds, judgeActorId }
193615
+ );
193616
+ println(`\u5DF2\u66F4\u65B0 Case ${saved.caseId} \u7684\u8BC4\u5206\u88C5\u914D\uFF1A\u6807\u51C6 ${saved.rubrics.length} \u5957\uFF0C\u5224\u5206\u5458\u5DE5 ${saved.judgeActorId ?? "\u90E8\u7F72\u9ED8\u8BA4"}`);
193617
+ if (saved.usesBuiltinFallback) println("\uFF08\u4E00\u6761\u90FD\u6CA1\u6302 = \u4ECD\u8D70 oasis-bench \u56DE\u843D\uFF09");
193618
+ break;
193619
+ }
193620
+ case "judges": {
193621
+ const res = await api.request(
193622
+ "GET",
193623
+ "/api/evaluations/judge-candidates"
193624
+ );
193625
+ println(`\u53EF\u9009\u5224\u5206\u5458\u5DE5(${res.items.length}):`);
193626
+ for (const j of res.items) println(`- ${j.actorId} ${j.name}`);
193627
+ if (res.items.length === 0) println("\uFF08\u65E0\uFF1A\u6CA1\u6709 agent \u914D\u4E86 active runtime \u7ED1\u5B9A\uFF09");
193628
+ break;
193629
+ }
193630
+ case "evaluations": {
193631
+ const res = await api.request("GET", "/api/evaluations/runs");
193632
+ const caseId = flags.get("case");
193633
+ const items = caseId ? res.items.filter((i) => i.run.caseId === caseId) : res.items;
193634
+ println(`Benchmark Runs(${items.length}):`);
193635
+ for (const item of items) {
193636
+ const e = item.latestEvaluation;
193637
+ println(`- ${item.run.runId} ${item.run.workOrderName} case=${item.run.caseId}#${item.run.attemptNo}`);
193638
+ println(` \u8BC4\u5206=${e ? `${e.status}${e.errorMessage ? ` (${e.errorMessage})` : ""}` : "\u5C1A\u672A\u8BC4\u5206"} \u5224\u5206\u5458\u5DE5=${e?.judgeActorId ?? "-"} \u6807\u51C6\u7248\u672C=${e?.rubricVersion ?? "-"}`);
193639
+ }
193640
+ break;
193641
+ }
193642
+ case "evaluate": {
193643
+ const workOrderId = needPos(positional, 0, "oasis evaluate <workOrderId> --case <caseId> [--judge <actorId>]");
193644
+ const caseId = flags.get("case");
193645
+ if (!caseId) throw new Error("\u7F3A\u5C11 --case <caseId>\uFF08\u53EF\u7528 oasis cases \u770B\u6E05\u5355\uFF09");
193646
+ const r = await api.request(
193647
+ "POST",
193648
+ "/api/evaluations/runs",
193649
+ { workOrderId, caseId, ...flags.get("case-version") ? { caseVersion: flags.get("case-version") } : {}, ...flags.get("judge") ? { judgeActorId: flags.get("judge") } : {} }
193650
+ );
193651
+ println(`\u5DF2\u5EFA Run ${r.run.runId}\uFF0C\u8BC4\u5206 ${r.evaluation.evaluationId} \u5DF2\u6392\u961F\uFF08\u5224\u5206\u5458\u5DE5 ${r.evaluation.judgeActorId}\uFF09`);
193652
+ break;
193653
+ }
193654
+ case "rescore": {
193655
+ const runId = needPos(positional, 0, "oasis rescore <runId> [--judge <actorId>]");
193656
+ const r = await api.request(
193657
+ "POST",
193658
+ `/api/evaluations/runs/${encodeURIComponent(runId)}/rescore`,
193659
+ flags.get("judge") ? { judgeActorId: flags.get("judge") } : {}
193660
+ );
193661
+ println(`\u5DF2\u6392\u961F\u7B2C ${r.evaluationNo} \u6B21\u8BC4\u5206 ${r.evaluationId}\uFF08\u5224\u5206\u5458\u5DE5 ${r.judgeActorId}\uFF09`);
193662
+ break;
193663
+ }
193664
+ case "cases": {
193665
+ const res = await api.request(
193666
+ "GET",
193667
+ "/api/evaluations/cases"
193668
+ );
193669
+ println(`Benchmark Cases(${res.items.length}):`);
193670
+ for (const c of res.items) {
193671
+ println(`- ${c.id} ${c.title} [${c.scopeType}/${c.difficultyLevel}] ${c.status}`);
193672
+ }
193673
+ break;
193674
+ }
192690
193675
  case "artifact-types": {
192691
193676
  const sub = positional[0] ?? "list";
192692
193677
  const typeBodyFromFlags = () => {
@@ -192849,6 +193834,14 @@ init_src5();
192849
193834
  var fs34 = __toESM(require("node:fs"));
192850
193835
  var path28 = __toESM(require("node:path"));
192851
193836
  var ASSET_EXT = ".sh";
193837
+ var SESSION_SCOPED_PREFIXES = ["oasis-conn-", "oasis-wrappers-", "oasis-cli-"];
193838
+ function sanitizeDaemonPath(rawPath) {
193839
+ return (rawPath ?? "").split(":").filter((dir) => {
193840
+ if (!dir) return false;
193841
+ const base = path28.basename(dir);
193842
+ return !SESSION_SCOPED_PREFIXES.some((p2) => base.startsWith(p2));
193843
+ }).join(":");
193844
+ }
192852
193845
  function installRuntimeAssets(srcRoot, binDir) {
192853
193846
  if (path28.resolve(srcRoot) === path28.resolve(binDir)) return 0;
192854
193847
  let copied = 0;
@@ -192889,7 +193882,7 @@ function syncRuntimeAssets(candidateRoots, binDir) {
192889
193882
  }
192890
193883
 
192891
193884
  // src/index.ts
192892
- var PKG_VERSION = true ? "0.1.81" : "dev";
193885
+ var PKG_VERSION = true ? "0.1.83" : "dev";
192893
193886
  var OASIS_DIR = path29.join(os9.homedir(), ".oasis");
192894
193887
  var CONFIG_FILE = path29.join(OASIS_DIR, "node-config.json");
192895
193888
  var PID_FILE = path29.join(OASIS_DIR, "node.pid");
@@ -192967,7 +193960,7 @@ function setupAutostart() {
192967
193960
  path29.join(home, ".local", "bin"),
192968
193961
  "/usr/local/bin"
192969
193962
  ];
192970
- const daemonPath = [process.env["PATH"] ?? "", ...extraBins].filter(Boolean).join(":");
193963
+ const daemonPath = sanitizeDaemonPath([process.env["PATH"] ?? "", ...extraBins].filter(Boolean).join(":"));
192971
193964
  if (process.platform === "linux") {
192972
193965
  const unitDir = path29.join(os9.homedir(), ".config", "systemd", "user");
192973
193966
  fs35.mkdirSync(unitDir, { recursive: true });
@@ -193113,6 +194106,11 @@ void (async () => {
193113
194106
  cleanup();
193114
194107
  process.exit(0);
193115
194108
  });
194109
+ const cleanPath = sanitizeDaemonPath(process.env["PATH"]);
194110
+ if (cleanPath !== process.env["PATH"]) {
194111
+ console.error(`[oasis] daemon PATH \u5DF2\u6E05\u6D17\uFF1A\u5254\u9664 agent \u4F1A\u8BDD\u4E34\u65F6 wrapper \u76EE\u5F55 ${(process.env["PATH"] ?? "").split(":").length - cleanPath.split(":").length} \u6761`);
194112
+ process.env["PATH"] = cleanPath;
194113
+ }
193116
194114
  try {
193117
194115
  ensureRuntimeAssets();
193118
194116
  } catch (e) {