oasis_test_v2 2.2.124 → 2.2.126

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.
Files changed (2) hide show
  1. package/dist/index.js +796 -674
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -1674,10 +1674,14 @@ function overlapSimilarity(a5, b6) {
1674
1674
  return shared / Math.sqrt(a5.size * b6.size);
1675
1675
  }
1676
1676
  function overlapScore(query, title, body2) {
1677
- const byTitle = overlapSimilarity(query, overlapTokens(title));
1677
+ const titleTokens = overlapTokens(title);
1678
+ const byTitle = overlapSimilarity(query, titleTokens);
1678
1679
  const byAll = body2 ? overlapSimilarity(query, overlapTokens(`${title}
1679
1680
  ${body2}`)) : byTitle;
1680
- return Math.round(Math.max(byTitle, byAll) * 1e3) / 1e3;
1681
+ let shared = 0;
1682
+ for (const t of titleTokens) if (query.has(t)) shared++;
1683
+ const cover = shared >= COVER_MIN_SHARED ? COVER_WEIGHT * shared / titleTokens.size : 0;
1684
+ return Math.round(Math.max(byTitle, byAll, cover) * 1e3) / 1e3;
1681
1685
  }
1682
1686
  function monthDay(dayOrIso, timeZone) {
1683
1687
  let day = dayOrIso.slice(0, 10);
@@ -1721,7 +1725,7 @@ function formatOverlapLines(r5, timeZone) {
1721
1725
  if (all2.length === 0) return [];
1722
1726
  return [OVERLAP_HEADING, ...all2.map((c5) => formatOverlapCandidate(c5, timeZone)), OVERLAP_LOOKUP_HINT, OVERLAP_HANDLING_HINT];
1723
1727
  }
1724
- var OVERLAP_ACTIONS, STOP_TOKENS, isCjk, OVERLAP_HEADING, OVERLAP_LOOKUP_HINT, OVERLAP_HANDLING_HINT, who;
1728
+ var OVERLAP_ACTIONS, STOP_TOKENS, isCjk, COVER_MIN_SHARED, COVER_WEIGHT, OVERLAP_HEADING, OVERLAP_LOOKUP_HINT, OVERLAP_HANDLING_HINT, who;
1725
1729
  var init_overlap = __esm({
1726
1730
  "../contract/src/overlap.ts"() {
1727
1731
  "use strict";
@@ -1774,6 +1778,14 @@ var init_overlap = __esm({
1774
1778
  "\u4E4B\u540E",
1775
1779
  "\u4EE5\u524D",
1776
1780
  "\u622A\u6B62",
1781
+ // 任务书里的套话(v2 实测:两份毫不相干的委派因为都写了「交付一个 Markdown 文件 outputs/…」被比成相近)。
1782
+ "\u4EA4\u4ED8",
1783
+ "\u6587\u4EF6",
1784
+ "\u80CC\u666F",
1785
+ "\u7528\u6237",
1786
+ "\u660E\u786E",
1787
+ "\u64B0\u5199",
1788
+ "\u72EC\u7ACB",
1777
1789
  "the",
1778
1790
  "and",
1779
1791
  "for",
@@ -1783,9 +1795,14 @@ var init_overlap = __esm({
1783
1795
  "that",
1784
1796
  "into",
1785
1797
  "todo",
1786
- "task"
1798
+ "task",
1799
+ "markdown",
1800
+ "outputs",
1801
+ "md"
1787
1802
  ]);
1788
1803
  isCjk = (ch) => /[㐀-鿿豈-﫿]/u.test(ch);
1804
+ COVER_MIN_SHARED = 3;
1805
+ COVER_WEIGHT = 0.9;
1789
1806
  OVERLAP_HEADING = "\u76F8\u8FD1\u7684\u4E8B\u9879\uFF08\u7CFB\u7EDF\u7C97\u7B5B\uFF0C\u672A\u786E\u8BA4\uFF0C\u8BF7\u7528 id \u67E5\u8BE6\u60C5\u540E\u5224\u65AD\uFF09\uFF1A";
1790
1807
  OVERLAP_LOOKUP_HINT = "\u67E5\u8BE6\u60C5\uFF1A\u5F85\u529E oasis todo show <\u5F85\u529Eid>\uFF1B\u5DE5\u5355 oasis workorder <\u5DE5\u5355id>\uFF1B\u59D4\u6D3E oasis delegate --status <\u59D4\u6D3Eid>\uFF08\u522B\u4EBA\u5BF9\u8BDD\u91CC\u6D3E\u7684\u4E5F\u80FD\u67E5\u6458\u8981\uFF09";
1791
1808
  OVERLAP_HANDLING_HINT = "\u600E\u4E48\u7528\uFF1A\u9010\u6761\u67E5\u5B8C\u518D\u5224\u65AD\u662F\u4E0D\u662F\u540C\u4E00\u4EF6\u4E8B\uFF1B\u786E\u5B9E\u76F8\u5173\u624D\u544A\u8BC9\u7528\u6237\uFF0C\u4E0D\u76F8\u5173\u4E00\u4E2A\u5B57\u4E0D\u63D0\u3002\u5728\u505A\u7684\u5EFA\u8BAE\u7528\u6237\u5148\u95EE\u95EE\u5BF9\u65B9\uFF0C\u770B\u5408\u5E76\u8FD8\u662F\u5206\u5DE5\uFF1B\u505A\u5B8C\u7684\u628A\u7ED3\u679C\u7ED9\u7528\u6237\uFF0C\u95EE\u80FD\u4E0D\u80FD\u76F4\u63A5\u7528\u3002\u4E0D\u66FF\u7528\u6237\u5408\u5E76\u3001\u53D6\u6D88\u6216\u6539\u6D3E\u3002";
@@ -237384,6 +237401,16 @@ async function listSkillMetadataForActor(args) {
237384
237401
  }
237385
237402
  return out;
237386
237403
  }
237404
+ async function skillManifestForActor(args) {
237405
+ const enabledConnectors = args.connectorSkills.length > 0 ? await args.service.effectiveEnabledConnectors(args.actorId) : /* @__PURE__ */ new Set();
237406
+ return listSkillMetadataForActor({
237407
+ service: args.service,
237408
+ actorId: args.actorId,
237409
+ builtins: args.builtins,
237410
+ connectorSkills: args.connectorSkills,
237411
+ enabledConnectors
237412
+ });
237413
+ }
237387
237414
  function builtinSkillToFiles(b6) {
237388
237415
  return Object.entries(b6.files ?? {}).map(([path50, content3]) => ({
237389
237416
  skillId: `builtin:${b6.id}`,
@@ -238891,14 +238918,11 @@ function actorsDomain(opts) {
238891
238918
  const { service } = await resolveCtx(req.auth.companyId);
238892
238919
  const claim = req.auth.dispatch?.chatSessionId ? { chatSessionId: req.auth.dispatch.chatSessionId, companyId: req.auth.companyId } : void 0;
238893
238920
  const builtins = await opts.getBuiltinSkills?.(claim) ?? [];
238894
- const connectorSkills = opts.getConnectorSkills?.() ?? [];
238895
- const enabledConnectors = connectorSkills.length > 0 ? await service.effectiveEnabledConnectors(req.auth.actor) : /* @__PURE__ */ new Set();
238896
- const items = await listSkillMetadataForActor({
238921
+ const items = await skillManifestForActor({
238897
238922
  service,
238898
238923
  actorId: req.auth.actor,
238899
238924
  builtins,
238900
- connectorSkills,
238901
- enabledConnectors
238925
+ connectorSkills: opts.getConnectorSkills?.() ?? []
238902
238926
  });
238903
238927
  return { status: 200, body: { items } };
238904
238928
  });
@@ -255141,6 +255165,562 @@ var init_renderer = __esm({
255141
255165
  }
255142
255166
  });
255143
255167
 
255168
+ // ../server/src/domains/trace/unit-data.ts
255169
+ function keysetBefore(timeExpr, idExpr, before, push2) {
255170
+ return `(date_trunc('milliseconds', ${timeExpr}), ${idExpr}) < (${push2(before.at)}::timestamptz, ${push2(before.id)})`;
255171
+ }
255172
+ function quoteSchema(name) {
255173
+ if (!/^[A-Za-z0-9_][A-Za-z0-9_.-]*$/.test(name)) throw new Error(`invalid schema name: ${name}`);
255174
+ return `"${name}"`;
255175
+ }
255176
+ function dispatchSchemaIdent(name) {
255177
+ const s3 = name.replace(/[^a-zA-Z0-9_]/g, "");
255178
+ if (!s3) throw new Error(`invalid dispatch schema name: ${name}`);
255179
+ return `"${s3}"`;
255180
+ }
255181
+ function replyIssueIdFromWorkId(workId) {
255182
+ const m4 = /^wk:reply:(.+):\d+$/.exec(workId);
255183
+ return m4 ? m4[1] : null;
255184
+ }
255185
+ function toWork(r5) {
255186
+ return {
255187
+ id: String(r5["id"]),
255188
+ workorderId: String(r5["workorder_id"]),
255189
+ nodeId: String(r5["node_id"]),
255190
+ nodeType: str5(r5["node_type"]),
255191
+ nodeTitle: str5(r5["node_title"]),
255192
+ assigneeActorId: String(r5["assignee_actor_id"]),
255193
+ createdAt: isoReq(r5["created_at"]),
255194
+ startedAt: iso4(r5["started_at"]),
255195
+ endedAt: iso4(r5["ended_at"]),
255196
+ deadAt: iso4(r5["dead_at"]),
255197
+ status: str5(r5["status"]),
255198
+ outcome: str5(r5["outcome"]),
255199
+ // 存量 lane 为空时按 work id 前缀兜底(回信轮 id 恒为 `wk:reply:<issueId>:<n>`)。
255200
+ lane: r5["lane"] === "reply" || r5["lane"] == null && String(r5["id"]).startsWith("wk:reply:") ? "reply" : "main",
255201
+ replyIssueId: replyIssueIdFromWorkId(String(r5["id"])),
255202
+ continuesWorkId: str5(r5["continues_work_id"]),
255203
+ acceptanceState: str5(r5["acceptance_state"]) ?? null,
255204
+ acceptedAt: iso4(r5["accepted_at"]),
255205
+ rejectedReason: str5(r5["rejected_reason"]),
255206
+ overrideBy: str5(r5["override_by"]),
255207
+ overrideReason: str5(r5["override_reason"]),
255208
+ frozenIssueIds: strArr(r5["frozen_issue_ids"]),
255209
+ protocolRecovery: r5["protocol_recovery"] ?? null,
255210
+ killSource: str5(r5["kill_source"]),
255211
+ outputVersionNo: num3(r5["output_version_no"])
255212
+ };
255213
+ }
255214
+ function toReview(r5) {
255215
+ const verdict = str5(r5["verdict"]);
255216
+ let status = str5(r5["status"]);
255217
+ if (!status) {
255218
+ if (r5["retry_at"] != null) status = "retry";
255219
+ else if (r5["cancelled_at"] != null) status = "dead";
255220
+ else if (verdict === "approve" && r5["decided_at"] != null) status = "accept";
255221
+ else if (verdict === "request_changes" && r5["decided_at"] != null) status = "reject";
255222
+ else if (r5["ended_at"] != null) status = verdict ? verdict === "approve" ? "accept" : "reject" : "failed";
255223
+ else status = "running";
255224
+ }
255225
+ return {
255226
+ id: String(r5["id"]),
255227
+ workorderId: String(r5["workorder_id"]),
255228
+ nodeId: String(r5["node_id"]),
255229
+ nodeTitle: str5(r5["node_title"]),
255230
+ targetWorkId: String(r5["target_work_id"]),
255231
+ reviewerActorId: String(r5["reviewer_actor_id"]),
255232
+ reviewGroup: String(r5["review_group"] ?? ""),
255233
+ status,
255234
+ verdict: verdict ?? null,
255235
+ note: str5(r5["note"]),
255236
+ createdAt: isoReq(r5["created_at"]),
255237
+ startedAt: iso4(r5["started_at"]),
255238
+ endedAt: iso4(r5["ended_at"]),
255239
+ decidedAt: iso4(r5["decided_at"]),
255240
+ cancelledAt: iso4(r5["cancelled_at"]),
255241
+ killSource: str5(r5["kill_source"])
255242
+ };
255243
+ }
255244
+ function toIssue(r5) {
255245
+ return {
255246
+ id: String(r5["id"]),
255247
+ workorderId: String(r5["workorder_id"]),
255248
+ kind: String(r5["kind"]),
255249
+ body: String(r5["body"] ?? ""),
255250
+ aboutNodeId: str5(r5["about_node_id"]),
255251
+ aboutWorkId: str5(r5["about_work_id"]),
255252
+ raisedByNodeId: str5(r5["raised_by_node_id"]),
255253
+ authorActorId: String(r5["author_actor_id"]),
255254
+ resolvedAt: iso4(r5["resolved_at"]),
255255
+ createdAt: isoReq(r5["created_at"])
255256
+ };
255257
+ }
255258
+ function toDispatch(r5) {
255259
+ return {
255260
+ id: String(r5["id"]),
255261
+ targetKind: String(r5["target_kind"]),
255262
+ targetId: String(r5["target_id"]),
255263
+ actorId: str5(r5["actor_id"]),
255264
+ createdAt: isoReq(r5["created_at"]),
255265
+ startedAt: iso4(r5["started_at"]),
255266
+ endedAt: iso4(r5["ended_at"]),
255267
+ outcome: str5(r5["outcome"]),
255268
+ reason: str5(r5["reason"]),
255269
+ protocolRecoveryRound: num3(r5["protocol_recovery_round"])
255270
+ };
255271
+ }
255272
+ function toDelegation(r5) {
255273
+ return {
255274
+ id: String(r5["id"]),
255275
+ parentSessionId: String(r5["parent_session_id"]),
255276
+ parentMessageId: String(r5["parent_message_id"] ?? ""),
255277
+ childSessionId: String(r5["child_session_id"]),
255278
+ expertActorId: String(r5["expert_actor_id"]),
255279
+ state: String(r5["state"]),
255280
+ failureKind: str5(r5["failure_kind"]),
255281
+ failureReason: str5(r5["failure_reason"]),
255282
+ consecutiveFails: num3(r5["consecutive_fails"]) ?? 0,
255283
+ dispatchSeq: num3(r5["dispatch_seq"]),
255284
+ createdAt: isoReq(r5["created_at"]),
255285
+ settledAt: iso4(r5["settled_at"]),
255286
+ label: str5(r5["label"]),
255287
+ taskDigest: str5(r5["task_digest"])
255288
+ };
255289
+ }
255290
+ function toSession(r5) {
255291
+ return {
255292
+ id: String(r5["id"]),
255293
+ humanActorId: String(r5["human_actor_id"]),
255294
+ aiActorId: String(r5["ai_actor_id"]),
255295
+ title: str5(r5["title"]),
255296
+ analyzedRunId: str5(r5["analyzed_run_id"]),
255297
+ runtimeSessionId: str5(r5["runtime_session_id"]),
255298
+ touchedAt: isoReq(r5["touched_at"]),
255299
+ createdAt: isoReq(r5["created_at"])
255300
+ };
255301
+ }
255302
+ function toTurn(r5) {
255303
+ return {
255304
+ id: String(r5["id"]),
255305
+ chatSessionId: String(r5["chat_session_id"]),
255306
+ source: String(r5["source"]),
255307
+ status: String(r5["status"]),
255308
+ reservedAt: isoReq(r5["reserved_at"]),
255309
+ startedAt: iso4(r5["started_at"]),
255310
+ completedAt: iso4(r5["completed_at"]),
255311
+ cancelledBy: str5(r5["cancelled_by"]),
255312
+ dispatchId: str5(r5["dispatch_id"]),
255313
+ assistantRunId: str5(r5["assistant_run_id"])
255314
+ };
255315
+ }
255316
+ function toMessage(r5) {
255317
+ return {
255318
+ id: String(r5["id"]),
255319
+ sessionId: String(r5["session_id"]),
255320
+ role: String(r5["role"]),
255321
+ content: String(r5["content"] ?? ""),
255322
+ seq: Number(r5["seq"]),
255323
+ createdAt: isoReq(r5["created_at"]),
255324
+ runId: str5(r5["run_id"]),
255325
+ turnId: str5(r5["turn_id"]),
255326
+ source: str5(r5["source"])
255327
+ };
255328
+ }
255329
+ function toLink(r5) {
255330
+ return { sessionId: String(r5["session_id"]), workOrderId: String(r5["work_order_id"]), linkedAt: isoReq(r5["linked_at"]) };
255331
+ }
255332
+ var unitListKey, iso4, isoReq, str5, num3, strArr, WORK_COLS, REVIEW_COLS, MAX_IDS, capIds, PgUnitDataSource;
255333
+ var init_unit_data = __esm({
255334
+ "../server/src/domains/trace/unit-data.ts"() {
255335
+ "use strict";
255336
+ unitListKey = {
255337
+ work: (w2) => ({ at: w2.endedAt ?? w2.deadAt, id: w2.id }),
255338
+ review: (r5) => ({ at: r5.endedAt ?? r5.decidedAt ?? r5.cancelledAt ?? r5.createdAt, id: r5.id }),
255339
+ delegation: (d5) => ({ at: d5.settledAt ?? d5.createdAt, id: d5.id }),
255340
+ session: (s3) => ({ at: s3.touchedAt, id: s3.id })
255341
+ };
255342
+ iso4 = (v2) => v2 == null ? null : v2 instanceof Date ? v2.toISOString() : typeof v2 === "string" ? new Date(v2).toISOString() : null;
255343
+ isoReq = (v2) => iso4(v2) ?? (/* @__PURE__ */ new Date(0)).toISOString();
255344
+ str5 = (v2) => typeof v2 === "string" ? v2 : v2 == null ? null : String(v2);
255345
+ num3 = (v2) => v2 == null ? null : Number.isFinite(Number(v2)) ? Number(v2) : null;
255346
+ strArr = (v2) => Array.isArray(v2) ? v2.filter((x2) => typeof x2 === "string") : [];
255347
+ WORK_COLS = `w.id, w.workorder_id, w.node_id, n.type AS node_type, n.title AS node_title, w.assignee_actor_id,
255348
+ w.created_at, w.started_at, w.ended_at, w.dead_at, w.status, w.outcome, w.lane, w.continues_work_id,
255349
+ w.acceptance_state, w.accepted_at, w.rejected_reason, w.override_by, w.override_reason, w.frozen_issue_ids,
255350
+ w.protocol_recovery, w.kill_source, w.output_version_no`;
255351
+ REVIEW_COLS = `r.id, r.workorder_id, r.node_id, n.title AS node_title, r.target_work_id, r.reviewer_actor_id, r.review_group,
255352
+ r.status, r.verdict, r.note, r.created_at, r.started_at, r.ended_at, r.decided_at, r.cancelled_at, r.retry_at, r.kill_source`;
255353
+ MAX_IDS = 500;
255354
+ capIds = (ids2) => [...new Set(ids2)].slice(0, MAX_IDS);
255355
+ PgUnitDataSource = class {
255356
+ pool;
255357
+ /** 引擎 schema(works / reviews / issues / events / workflow_*)。 */
255358
+ e;
255359
+ /** chat 一族(chat_sessions / chat_messages / chat_session_turns / 委派);缺省与引擎同 schema。 */
255360
+ c;
255361
+ /** 派发台账 schema(按 dispatches store 的口径净化)。 */
255362
+ d;
255363
+ constructor(opts) {
255364
+ this.pool = opts.pool;
255365
+ this.e = quoteSchema(opts.engineSchema);
255366
+ this.c = quoteSchema(opts.chatSchema ?? opts.engineSchema);
255367
+ this.d = dispatchSchemaIdent(opts.dispatchSchema);
255368
+ }
255369
+ async q(text7, values = []) {
255370
+ return (await this.pool.query(text7, values)).rows;
255371
+ }
255372
+ /* ── work / review ── */
255373
+ async getWorks(ids2) {
255374
+ if (ids2.length === 0) return [];
255375
+ const rows = await this.q(
255376
+ `SELECT ${WORK_COLS} FROM ${this.e}.works w LEFT JOIN ${this.e}.workflow_nodes n ON n.id = w.node_id WHERE w.id = ANY($1)`,
255377
+ [capIds(ids2)]
255378
+ );
255379
+ return rows.map(toWork);
255380
+ }
255381
+ async getReview(id) {
255382
+ const rows = await this.q(
255383
+ `SELECT ${REVIEW_COLS} FROM ${this.e}.reviews r LEFT JOIN ${this.e}.workflow_nodes n ON n.id = r.node_id WHERE r.id = $1`,
255384
+ [id]
255385
+ );
255386
+ return rows[0] ? toReview(rows[0]) : null;
255387
+ }
255388
+ async reviewsOfWorks(workIds) {
255389
+ if (workIds.length === 0) return [];
255390
+ const rows = await this.q(
255391
+ `SELECT ${REVIEW_COLS} FROM ${this.e}.reviews r LEFT JOIN ${this.e}.workflow_nodes n ON n.id = r.node_id
255392
+ WHERE r.target_work_id = ANY($1) ORDER BY r.created_at ASC, r.id ASC LIMIT 500`,
255393
+ [capIds(workIds)]
255394
+ );
255395
+ return rows.map(toReview);
255396
+ }
255397
+ async worksOfNode(nodeId, limit) {
255398
+ const rows = await this.q(
255399
+ `SELECT ${WORK_COLS} FROM ${this.e}.works w LEFT JOIN ${this.e}.workflow_nodes n ON n.id = w.node_id
255400
+ WHERE w.node_id = $1 ORDER BY w.created_at DESC, w.id DESC LIMIT $2`,
255401
+ [nodeId, limit]
255402
+ );
255403
+ return rows.map(toWork);
255404
+ }
255405
+ async workInputsOf(workIds) {
255406
+ if (workIds.length === 0) return [];
255407
+ const rows = await this.q(
255408
+ `SELECT work_id, upstream_node_id, upstream_work_id FROM ${this.e}.work_inputs WHERE work_id = ANY($1) LIMIT 2000`,
255409
+ [capIds(workIds)]
255410
+ );
255411
+ return rows.map((r5) => ({
255412
+ workId: String(r5["work_id"]),
255413
+ upstreamNodeId: String(r5["upstream_node_id"]),
255414
+ upstreamWorkId: String(r5["upstream_work_id"])
255415
+ }));
255416
+ }
255417
+ async inputNodesOf(nodeId) {
255418
+ const rows = await this.q(
255419
+ `SELECT from_node_id FROM ${this.e}.workflow_edges WHERE to_node_id = $1 AND kind = 'data' ORDER BY from_node_id LIMIT 100`,
255420
+ [nodeId]
255421
+ );
255422
+ return rows.map((r5) => String(r5["from_node_id"]));
255423
+ }
255424
+ async outputNodesOf(nodeId) {
255425
+ const rows = await this.q(
255426
+ `SELECT to_node_id FROM ${this.e}.workflow_edges WHERE from_node_id = $1 AND kind = 'data' ORDER BY to_node_id LIMIT 100`,
255427
+ [nodeId]
255428
+ );
255429
+ return rows.map((r5) => String(r5["to_node_id"]));
255430
+ }
255431
+ async latestAcceptedWorkOfNodeBefore(nodeId, beforeIso) {
255432
+ const rows = await this.q(
255433
+ `SELECT ${WORK_COLS} FROM ${this.e}.works w LEFT JOIN ${this.e}.workflow_nodes n ON n.id = w.node_id
255434
+ WHERE w.node_id = $1 AND w.acceptance_state = 'accepted' AND w.accepted_at IS NOT NULL AND w.accepted_at <= $2
255435
+ ORDER BY w.accepted_at DESC, w.id DESC LIMIT 1`,
255436
+ [nodeId, beforeIso]
255437
+ );
255438
+ return rows[0] ? toWork(rows[0]) : null;
255439
+ }
255440
+ async worksAcceptedInWindow(nodeIds, fromIso, toIso2, limit) {
255441
+ if (nodeIds.length === 0) return [];
255442
+ const rows = await this.q(
255443
+ `SELECT ${WORK_COLS} FROM ${this.e}.works w LEFT JOIN ${this.e}.workflow_nodes n ON n.id = w.node_id
255444
+ WHERE w.node_id = ANY($1) AND w.acceptance_state = 'accepted' AND w.accepted_at >= $2 AND w.accepted_at <= $3
255445
+ ORDER BY w.accepted_at ASC, w.id ASC LIMIT $4`,
255446
+ [capIds(nodeIds), fromIso, toIso2, limit]
255447
+ );
255448
+ return rows.map(toWork);
255449
+ }
255450
+ async reworkSourcesOf(work) {
255451
+ const rows = await this.q(
255452
+ `SELECT DISTINCT x.reason->>'workId' AS src
255453
+ FROM (SELECT payload FROM ${this.e}.events
255454
+ WHERE node_id = $1 AND kind = 'work.create' AND payload->>'workId' = $2
255455
+ ORDER BY seq DESC LIMIT 20) ev,
255456
+ LATERAL jsonb_array_elements(COALESCE(ev.payload->'reasons', '[]'::jsonb)) AS x(reason)
255457
+ WHERE x.reason->>'kind' = 'rework' AND x.reason->>'workId' IS NOT NULL`,
255458
+ [work.nodeId, work.id]
255459
+ );
255460
+ return rows.map((r5) => String(r5["src"]));
255461
+ }
255462
+ async reworkedBy(work) {
255463
+ const viaCol = await this.q(
255464
+ `SELECT id FROM ${this.e}.works WHERE node_id = $1 AND continues_work_id = $2 AND id <> $2 ORDER BY created_at ASC LIMIT 50`,
255465
+ [work.nodeId, work.id]
255466
+ );
255467
+ const viaEvents = await this.q(
255468
+ `SELECT DISTINCT ev.payload->>'workId' AS wid
255469
+ FROM (SELECT payload FROM ${this.e}.events WHERE node_id = $1 AND kind = 'work.create' ORDER BY seq DESC LIMIT 200) ev,
255470
+ LATERAL jsonb_array_elements(COALESCE(ev.payload->'reasons', '[]'::jsonb)) AS x(reason)
255471
+ WHERE x.reason->>'kind' = 'rework' AND x.reason->>'workId' = $2`,
255472
+ [work.nodeId, work.id]
255473
+ );
255474
+ const out = /* @__PURE__ */ new Set();
255475
+ for (const r5 of viaCol) out.add(String(r5["id"]));
255476
+ for (const r5 of viaEvents) if (r5["wid"] != null && r5["wid"] !== work.id) out.add(String(r5["wid"]));
255477
+ return [...out];
255478
+ }
255479
+ async briefNodesOf(workorderId) {
255480
+ const rows = await this.q(
255481
+ `SELECT id FROM ${this.e}.workflow_nodes WHERE workorder_id = $1 AND type = 'brief' ORDER BY created_at ASC LIMIT 10`,
255482
+ [workorderId]
255483
+ );
255484
+ return rows.map((r5) => String(r5["id"]));
255485
+ }
255486
+ /* ── issue ── */
255487
+ async issuesByIds(ids2) {
255488
+ if (ids2.length === 0) return [];
255489
+ const rows = await this.q(`SELECT * FROM ${this.e}.issues WHERE id = ANY($1)`, [capIds(ids2)]);
255490
+ return rows.map(toIssue);
255491
+ }
255492
+ async issuesInWorkorder(workorderId, q4) {
255493
+ const args = [workorderId];
255494
+ const conds = ["workorder_id = $1"];
255495
+ const ors = [];
255496
+ const push2 = (v2) => {
255497
+ args.push(v2);
255498
+ return `$${args.length}`;
255499
+ };
255500
+ if (q4.aboutWorkIds?.length) ors.push(`about_work_id = ANY(${push2(capIds(q4.aboutWorkIds))})`);
255501
+ if (q4.aboutNodeIds?.length) ors.push(`about_node_id = ANY(${push2(capIds(q4.aboutNodeIds))})`);
255502
+ if (q4.raisedByNodeIds?.length) ors.push(`raised_by_node_id = ANY(${push2(capIds(q4.raisedByNodeIds))})`);
255503
+ if (ors.length) conds.push(`(${ors.join(" OR ")})`);
255504
+ if (q4.fromIso) conds.push(`created_at >= ${push2(q4.fromIso)}`);
255505
+ if (q4.toIso) conds.push(`created_at <= ${push2(q4.toIso)}`);
255506
+ const rows = await this.q(
255507
+ `SELECT * FROM ${this.e}.issues WHERE ${conds.join(" AND ")} ORDER BY created_at ASC, id ASC LIMIT ${push2(q4.limit)}`,
255508
+ args
255509
+ );
255510
+ return rows.map(toIssue);
255511
+ }
255512
+ async worksHandlingIssues(workorderId, issueIds, limit) {
255513
+ if (issueIds.length === 0) return [];
255514
+ const ids2 = capIds(issueIds);
255515
+ const rows = await this.q(
255516
+ `SELECT ${WORK_COLS} FROM ${this.e}.works w LEFT JOIN ${this.e}.workflow_nodes n ON n.id = w.node_id
255517
+ WHERE w.workorder_id = $1
255518
+ AND (w.id LIKE ANY($4::text[]) OR (jsonb_typeof(w.frozen_issue_ids) = 'array' AND w.frozen_issue_ids ?| $2))
255519
+ ORDER BY w.created_at ASC, w.id ASC LIMIT $3`,
255520
+ [workorderId, ids2, limit, ids2.map((i5) => `wk:reply:${i5.replace(/[\\%_]/g, (c5) => `\\${c5}`)}:%`)]
255521
+ );
255522
+ return rows.map(toWork);
255523
+ }
255524
+ /* ── dispatches ── */
255525
+ async dispatchesOf(kind, targetIds) {
255526
+ if (targetIds.length === 0) return [];
255527
+ const rows = await this.q(
255528
+ `SELECT id, target_kind, target_id, actor_id, created_at, started_at, ended_at, outcome, reason, protocol_recovery_round
255529
+ FROM ${this.d}.dispatches WHERE target_kind = $1 AND target_id = ANY($2) ORDER BY created_at ASC, id ASC LIMIT 1000`,
255530
+ [kind, capIds(targetIds)]
255531
+ );
255532
+ return rows.map(toDispatch);
255533
+ }
255534
+ async dispatchTargetOf(runId) {
255535
+ const rows = await this.q(`SELECT target_kind, target_id FROM ${this.d}.dispatches WHERE id = $1`, [runId]);
255536
+ const r5 = rows[0];
255537
+ return r5 ? { targetKind: String(r5["target_kind"]), targetId: String(r5["target_id"]) } : null;
255538
+ }
255539
+ /* ── 委派 ── */
255540
+ async getDelegation(id) {
255541
+ const rows = await this.q(`SELECT * FROM ${this.c}.chat_session_delegations WHERE id = $1`, [id]);
255542
+ return rows[0] ? toDelegation(rows[0]) : null;
255543
+ }
255544
+ async delegationByChildSession(childSessionId) {
255545
+ const rows = await this.q(`SELECT * FROM ${this.c}.chat_session_delegations WHERE child_session_id = $1`, [childSessionId]);
255546
+ return rows[0] ? toDelegation(rows[0]) : null;
255547
+ }
255548
+ async delegationsOfParent(parentSessionId, limit) {
255549
+ const rows = await this.q(
255550
+ `SELECT * FROM ${this.c}.chat_session_delegations WHERE parent_session_id = $1 ORDER BY created_at ASC, id ASC LIMIT $2`,
255551
+ [parentSessionId, limit]
255552
+ );
255553
+ return rows.map(toDelegation);
255554
+ }
255555
+ async touchesOf(delegationId) {
255556
+ const rows = await this.q(
255557
+ `SELECT delegation_id, message_id, kind, at FROM ${this.c}.chat_session_delegation_touches
255558
+ WHERE delegation_id = $1 ORDER BY at ASC LIMIT 500`,
255559
+ [delegationId]
255560
+ );
255561
+ return rows.map((r5) => ({
255562
+ delegationId: String(r5["delegation_id"]),
255563
+ messageId: String(r5["message_id"]),
255564
+ kind: String(r5["kind"]),
255565
+ at: isoReq(r5["at"])
255566
+ }));
255567
+ }
255568
+ /* ── 会话 / 轮次 / 消息 ── */
255569
+ async getSession(id) {
255570
+ const rows = await this.q(`SELECT * FROM ${this.c}.chat_sessions WHERE id = $1`, [id]);
255571
+ return rows[0] ? toSession(rows[0]) : null;
255572
+ }
255573
+ async getTurn(id) {
255574
+ const rows = await this.q(`SELECT * FROM ${this.c}.chat_session_turns WHERE id = $1`, [id]);
255575
+ return rows[0] ? toTurn(rows[0]) : null;
255576
+ }
255577
+ async turnsOfSession(sessionId, limit) {
255578
+ const rows = await this.q(
255579
+ `SELECT * FROM ${this.c}.chat_session_turns WHERE chat_session_id = $1 ORDER BY reserved_at DESC, id DESC LIMIT $2`,
255580
+ [sessionId, limit + 1]
255581
+ );
255582
+ const truncated = rows.length > limit;
255583
+ const turns = (truncated ? rows.slice(0, limit) : rows).map(toTurn).reverse();
255584
+ return { turns, truncated };
255585
+ }
255586
+ async getMessage(id) {
255587
+ const rows = await this.q(`SELECT * FROM ${this.c}.chat_messages WHERE id = $1`, [id]);
255588
+ return rows[0] ? toMessage(rows[0]) : null;
255589
+ }
255590
+ async messagesOf(sessionId, q4) {
255591
+ const args = [sessionId];
255592
+ const push2 = (v2) => {
255593
+ args.push(v2);
255594
+ return `$${args.length}`;
255595
+ };
255596
+ const conds = ["session_id = $1"];
255597
+ if (q4.turnIds) {
255598
+ const window3 = ["turn_id IS NULL"];
255599
+ if (q4.fromIso) window3.push(`created_at >= ${push2(q4.fromIso)}`);
255600
+ if (q4.toIso) window3.push(`created_at <= ${push2(q4.toIso)}`);
255601
+ conds.push(`(turn_id = ANY(${push2(capIds(q4.turnIds))}) OR (${window3.join(" AND ")}))`);
255602
+ } else {
255603
+ if (q4.fromIso) conds.push(`created_at >= ${push2(q4.fromIso)}`);
255604
+ if (q4.toIso) conds.push(`created_at <= ${push2(q4.toIso)}`);
255605
+ }
255606
+ if (q4.roles?.length) conds.push(`role = ANY(${push2(q4.roles)})`);
255607
+ const rows = await this.q(
255608
+ `SELECT id, session_id, role, content, seq, created_at, run_id, turn_id, source FROM ${this.c}.chat_messages
255609
+ WHERE ${conds.join(" AND ")} ORDER BY seq ASC LIMIT ${push2(q4.limit)}`,
255610
+ args
255611
+ );
255612
+ return rows.map(toMessage);
255613
+ }
255614
+ async pendingMessagesOf(sessionId, fromIso, toIso2, limit) {
255615
+ const rows = await this.q(
255616
+ `SELECT id, chat_session_id, text, created_at, state, flavour FROM ${this.c}.chat_pending_messages
255617
+ WHERE chat_session_id = $1 AND created_at >= $2 AND created_at <= $3 ORDER BY seq ASC LIMIT $4`,
255618
+ [sessionId, fromIso, toIso2, limit]
255619
+ );
255620
+ return rows.map((r5) => ({
255621
+ id: String(r5["id"]),
255622
+ chatSessionId: String(r5["chat_session_id"]),
255623
+ text: String(r5["text"] ?? ""),
255624
+ createdAt: isoReq(r5["created_at"]),
255625
+ state: str5(r5["state"]),
255626
+ flavour: str5(r5["flavour"])
255627
+ }));
255628
+ }
255629
+ async originLinksOfWorkorder(workorderId) {
255630
+ const rows = await this.q(
255631
+ `SELECT session_id, work_order_id, linked_at FROM ${this.c}.chat_session_work_orders
255632
+ WHERE work_order_id = $1 AND link_kind = 'origin' ORDER BY linked_at ASC LIMIT 20`,
255633
+ [workorderId]
255634
+ );
255635
+ return rows.map(toLink);
255636
+ }
255637
+ async originLinksOfSession(sessionId) {
255638
+ const rows = await this.q(
255639
+ `SELECT session_id, work_order_id, linked_at FROM ${this.c}.chat_session_work_orders
255640
+ WHERE session_id = $1 AND link_kind = 'origin' ORDER BY linked_at ASC LIMIT 200`,
255641
+ [sessionId]
255642
+ );
255643
+ return rows.map(toLink);
255644
+ }
255645
+ /* ── find / peers 候选 ── */
255646
+ async listEndedWorks(q4) {
255647
+ const args = [];
255648
+ const push2 = (v2) => {
255649
+ args.push(v2);
255650
+ return `$${args.length}`;
255651
+ };
255652
+ const conds = [`(w.ended_at IS NOT NULL OR w.dead_at IS NOT NULL)`, `w.acceptance_state IS DISTINCT FROM 'draft'`];
255653
+ if (q4.sinceIso) conds.push(`COALESCE(w.ended_at, w.dead_at) >= ${push2(q4.sinceIso)}`);
255654
+ if (q4.actorId) conds.push(`w.assignee_actor_id = ${push2(q4.actorId)}`);
255655
+ if (q4.nodeType) conds.push(`n.type = ${push2(q4.nodeType)}`);
255656
+ if (q4.lane) conds.push(`COALESCE(w.lane, CASE WHEN w.id LIKE 'wk:reply:%' THEN 'reply' ELSE 'main' END) = ${push2(q4.lane)}`);
255657
+ const endExpr = `COALESCE(w.ended_at, w.dead_at)`;
255658
+ if (q4.before) conds.push(keysetBefore(endExpr, "w.id", q4.before, push2));
255659
+ const rows = await this.q(
255660
+ `SELECT ${WORK_COLS} FROM ${this.e}.works w LEFT JOIN ${this.e}.workflow_nodes n ON n.id = w.node_id
255661
+ WHERE ${conds.join(" AND ")} ORDER BY date_trunc('milliseconds', ${endExpr}) DESC, w.id DESC LIMIT ${push2(q4.limit)}`,
255662
+ args
255663
+ );
255664
+ return rows.map(toWork);
255665
+ }
255666
+ async listEndedReviews(q4) {
255667
+ const args = [];
255668
+ const push2 = (v2) => {
255669
+ args.push(v2);
255670
+ return `$${args.length}`;
255671
+ };
255672
+ const endExpr = `COALESCE(r.ended_at, r.decided_at, r.cancelled_at, r.created_at)`;
255673
+ const conds = [`r.status IN ('accept','reject','failed','dead')`];
255674
+ if (q4.sinceIso) conds.push(`${endExpr} >= ${push2(q4.sinceIso)}`);
255675
+ if (q4.actorId) conds.push(`r.reviewer_actor_id = ${push2(q4.actorId)}`);
255676
+ if (q4.before) conds.push(keysetBefore(endExpr, "r.id", q4.before, push2));
255677
+ const rows = await this.q(
255678
+ `SELECT ${REVIEW_COLS} FROM ${this.e}.reviews r LEFT JOIN ${this.e}.workflow_nodes n ON n.id = r.node_id
255679
+ WHERE ${conds.join(" AND ")} ORDER BY date_trunc('milliseconds', ${endExpr}) DESC, r.id DESC LIMIT ${push2(q4.limit)}`,
255680
+ args
255681
+ );
255682
+ return rows.map(toReview);
255683
+ }
255684
+ async listEndedDelegations(q4) {
255685
+ const args = [];
255686
+ const push2 = (v2) => {
255687
+ args.push(v2);
255688
+ return `$${args.length}`;
255689
+ };
255690
+ const conds = [`state IN ('done','failed')`];
255691
+ if (q4.sinceIso) conds.push(`COALESCE(settled_at, created_at) >= ${push2(q4.sinceIso)}`);
255692
+ if (q4.actorId) conds.push(`expert_actor_id = ${push2(q4.actorId)}`);
255693
+ if (q4.before) conds.push(keysetBefore(`COALESCE(settled_at, created_at)`, "id", q4.before, push2));
255694
+ const rows = await this.q(
255695
+ `SELECT * FROM ${this.c}.chat_session_delegations WHERE ${conds.join(" AND ")}
255696
+ ORDER BY date_trunc('milliseconds', COALESCE(settled_at, created_at)) DESC, id DESC LIMIT ${push2(q4.limit)}`,
255697
+ args
255698
+ );
255699
+ return rows.map(toDelegation);
255700
+ }
255701
+ async listRecentSessions(q4) {
255702
+ const args = [];
255703
+ const push2 = (v2) => {
255704
+ args.push(v2);
255705
+ return `$${args.length}`;
255706
+ };
255707
+ const conds = [`NOT EXISTS (SELECT 1 FROM ${this.c}.chat_session_delegations d WHERE d.child_session_id = s.id)`];
255708
+ if (!q4.includeAnalysis) conds.push(`s.analyzed_run_id IS NULL`);
255709
+ if (q4.sinceIso) conds.push(`s.touched_at >= ${push2(q4.sinceIso)}`);
255710
+ if (q4.aiActorId) conds.push(`s.ai_actor_id = ${push2(q4.aiActorId)}`);
255711
+ if (q4.before) conds.push(keysetBefore("s.touched_at", "s.id", q4.before, push2));
255712
+ const rows = await this.q(
255713
+ `SELECT s.id, s.human_actor_id, s.ai_actor_id, s.title, s.analyzed_run_id, s.runtime_session_id, s.touched_at, s.created_at
255714
+ FROM ${this.c}.chat_sessions s WHERE ${conds.join(" AND ")}
255715
+ ORDER BY date_trunc('milliseconds', s.touched_at) DESC, s.id DESC LIMIT ${push2(q4.limit)}`,
255716
+ args
255717
+ );
255718
+ return rows.map(toSession);
255719
+ }
255720
+ };
255721
+ }
255722
+ });
255723
+
255144
255724
  // ../server/src/domains/trace/units.ts
255145
255725
  function splitSegments(turns, gapMs = SEGMENT_IDLE_GAP_MS) {
255146
255726
  const sorted = [...turns].sort((a5, b6) => {
@@ -255235,6 +255815,23 @@ function parseSince(since, nowMs) {
255235
255815
  if (!Number.isFinite(t)) throw new RangeError(`--since \u4E0D\u5408\u6CD5\uFF1A${since}\uFF08\u8981 ISO \u65F6\u95F4\u6216 7d / 12h / 30m\uFF09`);
255236
255816
  return new Date(t).toISOString();
255237
255817
  }
255818
+ function keysetSource(list3, keyOf4, batch, toCandidates) {
255819
+ let before;
255820
+ const src = {
255821
+ watermark: "",
255822
+ async next() {
255823
+ if (src.watermark === null) return [];
255824
+ const rows = await list3(before);
255825
+ const last = rows[rows.length - 1];
255826
+ if (last) before = keyOf4(last);
255827
+ src.watermark = rows.length < batch || !before ? null : before.at;
255828
+ const out = [];
255829
+ for (const r5 of rows) out.push(...await toCandidates(r5));
255830
+ return out;
255831
+ }
255832
+ };
255833
+ return src;
255834
+ }
255238
255835
  function memo(map3, key2, fn) {
255239
255836
  let p4 = map3.get(key2);
255240
255837
  if (!p4) {
@@ -255259,11 +255856,13 @@ function metaString(meta, key2) {
255259
255856
  }
255260
255857
  return null;
255261
255858
  }
255262
- var SEG_TURN_CAP, RUN_PAGE, RUN_CAP, NODE_WORK_CAP, MAX_CHAIN_NODES, MESSAGE_CAP, SIGNAL_TEXT_CAP, FIND_DEFAULT_LIMIT, FIND_MAX_LIMIT, RUN_ROW_CAP, TURN_TERMINAL, REVIEW_ENDED, DELEGATION_ENDED, SYSTEM_CANCEL_REASONS, EXOGENOUS_RUN_STATUS, UnitError, ms, turnStart, turnEnd, UnitService, unitTypeOf, segId, clip4, UnitReader;
255859
+ var SEG_TURN_CAP, RUN_PAGE, RUN_CAP, NODE_WORK_CAP, MAX_CHAIN_NODES, MESSAGE_CAP, SIGNAL_TEXT_CAP, EXOGENOUS_TEXT_CAP, FIND_DEFAULT_LIMIT, FIND_BATCH_MAX, FIND_MAX_LIMIT, RUN_ROW_CAP, TURN_TERMINAL, REVIEW_ENDED, DELEGATION_ENDED, SYSTEM_CANCEL_REASONS, EXOGENOUS_RUN_STATUS, UnitError, ms, turnStart, turnEnd, UnitService, unitTypeOf, segId, clipField, outcomeFetchCmd, exogenousFetchCmd, UnitReader;
255263
255860
  var init_units = __esm({
255264
255861
  "../server/src/domains/trace/units.ts"() {
255265
255862
  "use strict";
255266
255863
  init_src();
255864
+ init_unit_data();
255865
+ init_renderer();
255267
255866
  SEG_TURN_CAP = 2e3;
255268
255867
  RUN_PAGE = 200;
255269
255868
  RUN_CAP = 2e3;
@@ -255271,7 +255870,9 @@ var init_units = __esm({
255271
255870
  MAX_CHAIN_NODES = 200;
255272
255871
  MESSAGE_CAP = 1e3;
255273
255872
  SIGNAL_TEXT_CAP = 2e3;
255873
+ EXOGENOUS_TEXT_CAP = 500;
255274
255874
  FIND_DEFAULT_LIMIT = 20;
255875
+ FIND_BATCH_MAX = 200;
255275
255876
  FIND_MAX_LIMIT = 200;
255276
255877
  RUN_ROW_CAP = 50;
255277
255878
  TURN_TERMINAL = /* @__PURE__ */ new Set(["succeeded", "failed", "cancelled", "orphaned"]);
@@ -255320,11 +255921,12 @@ var init_units = __esm({
255320
255921
  async evidenceScope(unitId, maxHop) {
255321
255922
  return this.reader().evidenceScope(unitId, maxHop);
255322
255923
  }
255323
- async outcome(unitId) {
255324
- return this.reader().outcome(unitId);
255924
+ /** `full`:长文本不截(`oasis trace outcome <unit> --full`,即截断标记里给的取回命令)。 */
255925
+ async outcome(unitId, opts = {}) {
255926
+ return this.reader().outcome(unitId, opts);
255325
255927
  }
255326
- async exogenous(unitId) {
255327
- return this.reader().exogenous(unitId);
255928
+ async exogenous(unitId, opts = {}) {
255929
+ return this.reader().exogenous(unitId, opts);
255328
255930
  }
255329
255931
  async peers(unitId, limit) {
255330
255932
  return this.reader().peers(unitId, limit);
@@ -255335,7 +255937,9 @@ var init_units = __esm({
255335
255937
  };
255336
255938
  unitTypeOf = (u) => u.kind === "work" || u.kind === "review" ? "work" : u.kind === "delegation" ? "delegation" : "chat";
255337
255939
  segId = (sessionId, firstTurnId) => `seg:${sessionId}:${firstTurnId}`;
255338
- clip4 = (s3, n3 = SIGNAL_TEXT_CAP) => ({ text: s3.length > n3 ? s3.slice(0, n3) : s3, chars: s3.length, clipped: s3.length > n3 });
255940
+ clipField = (s3, fetchCmd, full, n3 = SIGNAL_TEXT_CAP) => full ? { text: s3, truncated: false, fullChars: s3.length, fetchCmd } : { ...truncateText(s3, n3, fetchCmd) };
255941
+ outcomeFetchCmd = (unitId) => `oasis trace outcome ${unitId} --full`;
255942
+ exogenousFetchCmd = (unitId) => `oasis trace exogenous ${unitId} --full`;
255339
255943
  UnitReader = class {
255340
255944
  constructor(deps) {
255341
255945
  this.deps = deps;
@@ -255584,7 +256188,7 @@ var init_units = __esm({
255584
256188
  const ended = reviewEnded(u.review);
255585
256189
  return {
255586
256190
  ended,
255587
- endedAt: ended ? u.review.endedAt ?? u.review.decidedAt ?? u.review.createdAt : null,
256191
+ endedAt: ended ? unitListKey.review(u.review).at : null,
255588
256192
  startedAt: u.review.startedAt ?? u.review.createdAt,
255589
256193
  actorId: u.review.reviewerActorId,
255590
256194
  cursor: u.unitId,
@@ -255640,14 +256244,16 @@ var init_units = __esm({
255640
256244
  async find(q4) {
255641
256245
  const limit = Math.max(1, Math.min(FIND_MAX_LIMIT, Math.floor(q4.limit ?? FIND_DEFAULT_LIMIT)));
255642
256246
  const sinceIso = parseSince(q4.since, this.nowMs);
255643
- const fetchN = limit * 3;
256247
+ const batch = Math.min(FIND_BATCH_MAX, limit * 3);
255644
256248
  const wants = (t) => !q4.type || q4.type === t;
255645
- const cands = [];
256249
+ const base = { ...sinceIso ? { sinceIso } : {}, ...q4.actor ? { actorId: q4.actor } : {} };
256250
+ const sources = [];
255646
256251
  if (wants("work")) {
255647
- const works = await this.data.listEndedWorks({ ...sinceIso ? { sinceIso } : {}, ...q4.actor ? { actorId: q4.actor } : {}, limit: fetchN });
255648
- for (const w2 of works) {
255649
- if (!workEnded(w2)) continue;
255650
- cands.push({
256252
+ sources.push(keysetSource(
256253
+ (before) => this.data.listEndedWorks({ ...base, ...before ? { before } : {}, limit: batch }),
256254
+ unitListKey.work,
256255
+ batch,
256256
+ async (w2) => workEnded(w2) ? [{
255651
256257
  unitId: w2.id,
255652
256258
  type: "work",
255653
256259
  endedAt: w2.endedAt ?? w2.deadAt,
@@ -255655,69 +256261,81 @@ var init_units = __esm({
255655
256261
  sessionId: null,
255656
256262
  cursor: w2.id,
255657
256263
  load: async () => this.cacheUnit({ kind: "work", unitId: w2.id, work: w2 })
255658
- });
255659
- }
255660
- const reviews = await this.data.listEndedReviews({ ...sinceIso ? { sinceIso } : {}, ...q4.actor ? { actorId: q4.actor } : {}, limit: fetchN });
255661
- for (const r5 of reviews) {
255662
- if (!reviewEnded(r5)) continue;
255663
- cands.push({
256264
+ }] : []
256265
+ ));
256266
+ sources.push(keysetSource(
256267
+ (before) => this.data.listEndedReviews({ ...base, ...before ? { before } : {}, limit: batch }),
256268
+ unitListKey.review,
256269
+ batch,
256270
+ async (r5) => reviewEnded(r5) ? [{
255664
256271
  unitId: r5.id,
255665
256272
  type: "work",
255666
- endedAt: r5.endedAt ?? r5.decidedAt ?? r5.createdAt,
256273
+ endedAt: unitListKey.review(r5).at,
255667
256274
  actorId: r5.reviewerActorId,
255668
256275
  sessionId: null,
255669
256276
  cursor: r5.id,
255670
256277
  load: async () => this.cacheUnit({ kind: "review", unitId: r5.id, review: r5 })
255671
- });
255672
- }
256278
+ }] : []
256279
+ ));
255673
256280
  }
255674
256281
  if (wants("delegation")) {
255675
- const dlgs = await this.data.listEndedDelegations({ ...sinceIso ? { sinceIso } : {}, ...q4.actor ? { actorId: q4.actor } : {}, limit: fetchN });
255676
- for (const d5 of dlgs) {
255677
- if (!delegationEnded(d5)) continue;
255678
- const unitId = `dlg:${d5.id}`;
255679
- cands.push({
255680
- unitId,
255681
- type: "delegation",
255682
- endedAt: d5.settledAt ?? d5.createdAt,
255683
- actorId: d5.expertActorId,
255684
- sessionId: null,
255685
- cursor: delegationCursor(d5),
255686
- load: async () => this.cacheUnit({ kind: "delegation", unitId, dlg: d5 })
255687
- });
255688
- }
256282
+ sources.push(keysetSource(
256283
+ (before) => this.data.listEndedDelegations({ ...base, ...before ? { before } : {}, limit: batch }),
256284
+ unitListKey.delegation,
256285
+ batch,
256286
+ async (d5) => {
256287
+ if (!delegationEnded(d5)) return [];
256288
+ const unitId = `dlg:${d5.id}`;
256289
+ return [{
256290
+ unitId,
256291
+ type: "delegation",
256292
+ endedAt: d5.settledAt ?? d5.createdAt,
256293
+ actorId: d5.expertActorId,
256294
+ sessionId: null,
256295
+ cursor: delegationCursor(d5),
256296
+ load: async () => this.cacheUnit({ kind: "delegation", unitId, dlg: d5 })
256297
+ }];
256298
+ }
256299
+ ));
255689
256300
  }
255690
256301
  if (wants("chat")) {
255691
256302
  const excluded = new Set(!q4.includeMeta && this.deps.reflectorSessionIds ? await this.deps.reflectorSessionIds() : []);
255692
- const sessions = await this.data.listRecentSessions({
255693
- ...sinceIso ? { sinceIso } : {},
255694
- ...q4.actor ? { aiActorId: q4.actor } : {},
255695
- includeAnalysis: q4.includeMeta === true,
255696
- limit: fetchN
255697
- });
255698
- for (const s3 of sessions) {
255699
- if (excluded.has(s3.id)) continue;
255700
- const ss = await this.sessionSegments(s3.id);
255701
- if (!ss) continue;
255702
- for (let i5 = 0; i5 < ss.segments.length; i5++) {
255703
- const seg = ss.segments[i5];
255704
- if (!segmentEnded(seg, i5 < ss.segments.length - 1, this.nowMs)) continue;
255705
- const endedAt = turnEnd(seg.turns[seg.turns.length - 1]);
255706
- if (sinceIso && ms(endedAt) < ms(sinceIso)) continue;
255707
- const idx = i5;
255708
- cands.push({
255709
- unitId: segId(s3.id, seg.firstTurnId),
255710
- type: "chat",
255711
- endedAt,
255712
- actorId: s3.aiActorId,
255713
- sessionId: s3.id,
255714
- cursor: seg.lastTurnId,
255715
- load: () => this.segmentUnit(ss, idx)
255716
- });
256303
+ sources.push(keysetSource(
256304
+ (before) => this.data.listRecentSessions({
256305
+ ...sinceIso ? { sinceIso } : {},
256306
+ ...q4.actor ? { aiActorId: q4.actor } : {},
256307
+ includeAnalysis: q4.includeMeta === true,
256308
+ ...before ? { before } : {},
256309
+ limit: batch
256310
+ }),
256311
+ unitListKey.session,
256312
+ batch,
256313
+ // 会话按 touched_at 取:段的结束时间不晚于它,水位照样成立。
256314
+ async (s3) => {
256315
+ if (excluded.has(s3.id)) return [];
256316
+ const ss = await this.sessionSegments(s3.id);
256317
+ if (!ss) return [];
256318
+ const segs = [];
256319
+ for (let i5 = 0; i5 < ss.segments.length; i5++) {
256320
+ const seg = ss.segments[i5];
256321
+ if (!segmentEnded(seg, i5 < ss.segments.length - 1, this.nowMs)) continue;
256322
+ const endedAt = turnEnd(seg.turns[seg.turns.length - 1]);
256323
+ if (sinceIso && ms(endedAt) < ms(sinceIso)) continue;
256324
+ const idx = i5;
256325
+ segs.push({
256326
+ unitId: segId(s3.id, seg.firstTurnId),
256327
+ type: "chat",
256328
+ endedAt,
256329
+ actorId: s3.aiActorId,
256330
+ sessionId: s3.id,
256331
+ cursor: seg.lastTurnId,
256332
+ load: () => this.segmentUnit(ss, idx)
256333
+ });
256334
+ }
256335
+ return segs;
255717
256336
  }
255718
- }
256337
+ ));
255719
256338
  }
255720
- cands.sort((a5, b6) => ms(b6.endedAt) - ms(a5.endedAt) || (a5.unitId < b6.unitId ? 1 : -1));
255721
256339
  const roleCache = /* @__PURE__ */ new Map();
255722
256340
  const roleOk = async (actorId) => {
255723
256341
  if (!q4.role) return true;
@@ -255726,22 +256344,34 @@ var init_units = __esm({
255726
256344
  const roles = await memo(roleCache, actorId, () => fn(actorId)) ?? "";
255727
256345
  return roles.split(",").map((r5) => r5.trim()).includes(q4.role);
255728
256346
  };
255729
- const reflected = this.deps.reflectedCursors ? await this.deps.reflectedCursors(cands.map((c5) => c5.unitId)) : /* @__PURE__ */ new Map();
255730
256347
  const out = [];
255731
- let built = 0;
255732
- for (const c5 of cands) {
255733
- if (out.length >= limit || built >= limit * 5) break;
255734
- if (!await roleOk(c5.actorId)) continue;
255735
- if (q4.unreflected && (reflected.get(c5.unitId) ?? []).some((r5) => cursorCovers(r5, c5.cursor, c5.type))) continue;
255736
- const u = await c5.load();
255737
- if (!u) continue;
255738
- built++;
255739
- const s3 = await this.summary(u, reflected);
255740
- if (!s3.ended) continue;
255741
- if (q4.outcome && s3.outcome !== q4.outcome) continue;
255742
- out.push(s3);
256348
+ const pending = [];
256349
+ for (const src of sources) pending.push(...await src.next());
256350
+ for (; ; ) {
256351
+ const open3 = sources.filter((src) => src.watermark !== null);
256352
+ const mark = open3.length ? Math.max(...open3.map((src) => ms(src.watermark))) : -Infinity;
256353
+ pending.sort((a5, b6) => ms(b6.endedAt) - ms(a5.endedAt) || (a5.unitId < b6.unitId ? 1 : -1));
256354
+ let ready = 0;
256355
+ while (ready < pending.length && ms(pending[ready].endedAt) > mark) ready++;
256356
+ const chunk = pending.splice(0, ready);
256357
+ if (chunk.length > 0) {
256358
+ const reflected = this.deps.reflectedCursors ? await this.deps.reflectedCursors(chunk.map((c5) => c5.unitId)) : /* @__PURE__ */ new Map();
256359
+ for (const c5 of chunk) {
256360
+ if (!await roleOk(c5.actorId)) continue;
256361
+ if (q4.unreflected && (reflected.get(c5.unitId) ?? []).some((r5) => cursorCovers(r5, c5.cursor, c5.type))) continue;
256362
+ const u = await c5.load();
256363
+ if (!u) continue;
256364
+ const s3 = await this.summary(u, reflected);
256365
+ if (!s3.ended) continue;
256366
+ if (q4.outcome && s3.outcome !== q4.outcome) continue;
256367
+ out.push(s3);
256368
+ if (out.length >= limit) return out;
256369
+ }
256370
+ }
256371
+ if (open3.length === 0) return out;
256372
+ const lead = open3.reduce((a5, b6) => ms(b6.watermark) > ms(a5.watermark) ? b6 : a5);
256373
+ pending.push(...await lead.next());
255743
256374
  }
255744
- return out;
255745
256375
  }
255746
256376
  cacheUnit(u) {
255747
256377
  if (!this.units.has(u.unitId)) this.units.set(u.unitId, Promise.resolve(u));
@@ -255942,9 +256572,10 @@ var init_units = __esm({
255942
256572
  return { runHop, nodes: nodes5 };
255943
256573
  }
255944
256574
  /* ── outcome ── */
255945
- async outcome(unitId) {
256575
+ async outcome(unitId, opts = {}) {
255946
256576
  const u = await this.mustLoad(unitId);
255947
256577
  const signals = {};
256578
+ const field = (s3) => clipField(s3, outcomeFetchCmd(u.unitId), opts.full === true);
255948
256579
  switch (u.kind) {
255949
256580
  case "work": {
255950
256581
  const w2 = u.work;
@@ -255971,8 +256602,7 @@ var init_units = __esm({
255971
256602
  decidedAt: r5.decidedAt
255972
256603
  }));
255973
256604
  signals["issues"] = (await this.data.issuesInWorkorder(w2.workorderId, { aboutWorkIds: [w2.id], limit: 100 })).map((i5) => {
255974
- const b6 = clip4(i5.body);
255975
- return { issueId: i5.id, kind: i5.kind, author: i5.authorActorId, resolved: i5.resolvedAt != null, createdAt: i5.createdAt, body: b6.text, bodyChars: b6.chars };
256605
+ return { issueId: i5.id, kind: i5.kind, author: i5.authorActorId, resolved: i5.resolvedAt != null, createdAt: i5.createdAt, body: field(i5.body) };
255976
256606
  });
255977
256607
  signals["reworkedBy"] = await this.data.reworkedBy(w2);
255978
256608
  break;
@@ -256018,16 +256648,16 @@ var init_units = __esm({
256018
256648
  const inter = await this.segmentInterjections(u);
256019
256649
  signals["interjections"] = [...inter].map(([turnId, msgs]) => ({
256020
256650
  turnId,
256021
- messages: msgs.map((m4) => {
256022
- const c5 = clip4(m4.content);
256023
- return { messageId: m4.id, at: m4.at, text: c5.text, chars: c5.chars };
256024
- })
256651
+ messages: msgs.map((m4) => ({ messageId: m4.id, at: m4.at, body: field(m4.content) }))
256025
256652
  }));
256026
256653
  const endIso = new Date(last.completedAt ? ms(last.completedAt) : this.nowMs).toISOString();
256027
- signals["pending"] = (await this.data.pendingMessagesOf(u.session.id, u.seg.turns[0].reservedAt, endIso, 200)).map((p4) => {
256028
- const c5 = clip4(p4.text);
256029
- return { id: p4.id, at: p4.createdAt, state: p4.state, flavour: p4.flavour, text: c5.text, chars: c5.chars };
256030
- });
256654
+ signals["pending"] = (await this.data.pendingMessagesOf(u.session.id, u.seg.turns[0].reservedAt, endIso, 200)).map((p4) => ({
256655
+ id: p4.id,
256656
+ at: p4.createdAt,
256657
+ state: p4.state,
256658
+ flavour: p4.flavour,
256659
+ body: field(p4.text)
256660
+ }));
256031
256661
  break;
256032
256662
  }
256033
256663
  }
@@ -256042,9 +256672,10 @@ var init_units = __esm({
256042
256672
  }
256043
256673
  return out;
256044
256674
  }
256045
- async exogenous(unitId) {
256675
+ async exogenous(unitId, opts = {}) {
256046
256676
  const u = await this.mustLoad(unitId);
256047
256677
  const facts = [];
256678
+ const field = (s3) => clipField(s3, exogenousFetchCmd(u.unitId), opts.full === true, EXOGENOUS_TEXT_CAP);
256048
256679
  const runs = await this.runRows(await this.runIdsOf(u));
256049
256680
  for (const r5 of runs) {
256050
256681
  const abnormal = EXOGENOUS_RUN_STATUS.has(r5.status);
@@ -256054,7 +256685,7 @@ var init_units = __esm({
256054
256685
  at: r5.endedAt ?? r5.startedAt,
256055
256686
  runId: r5.id,
256056
256687
  summary: `run ${r5.id} \u72B6\u6001 ${r5.status}${r5.exitReason ? `\uFF0Cexit_reason=${r5.exitReason}` : ""}${r5.errorCode ? `\uFF0Cerror_code=${r5.errorCode}` : ""}`,
256057
- detail: { status: r5.status, exitReason: r5.exitReason, errorCode: r5.errorCode, errorMessage: r5.errorMessage ? clip4(r5.errorMessage, 500).text : null }
256688
+ detail: { status: r5.status, exitReason: r5.exitReason, errorCode: r5.errorCode, errorMessage: r5.errorMessage ? field(r5.errorMessage) : null }
256058
256689
  });
256059
256690
  }
256060
256691
  const instances = [...new Set(runs.map((r5) => r5.runtimeInstanceId).filter((x2) => !!x2))];
@@ -256097,11 +256728,11 @@ var init_units = __esm({
256097
256728
  });
256098
256729
  }
256099
256730
  }
256100
- if (u.kind === "work") facts.push(...await this.upstreamFacts(u.work));
256731
+ if (u.kind === "work") facts.push(...await this.upstreamFacts(u.work, field));
256101
256732
  return facts;
256102
256733
  }
256103
256734
  /** 单元时间窗里上游(输入节点、brief)收到的 issue、出的新版本。 */
256104
- async upstreamFacts(w2) {
256735
+ async upstreamFacts(w2, field) {
256105
256736
  const out = [];
256106
256737
  const from = w2.startedAt ?? w2.createdAt;
256107
256738
  const to = w2.endedAt ?? w2.deadAt ?? new Date(this.nowMs).toISOString();
@@ -256113,13 +256744,13 @@ var init_units = __esm({
256113
256744
  if (nodes5.size === 0) return out;
256114
256745
  const nodeIds = [...nodes5];
256115
256746
  for (const i5 of await this.data.issuesInWorkorder(w2.workorderId, { aboutNodeIds: nodeIds, fromIso: from, toIso: to, limit: 50 })) {
256116
- const b6 = clip4(i5.body, 500);
256747
+ const b6 = field(i5.body);
256117
256748
  out.push({
256118
256749
  kind: "upstream-issue",
256119
256750
  at: i5.createdAt,
256120
256751
  runId: null,
256121
256752
  summary: `\u6267\u884C\u671F\u95F4\u4E0A\u6E38\u8282\u70B9 ${i5.aboutNodeId} \u6536\u5230 ${i5.kind}\uFF1A${b6.text.split("\n")[0]}`,
256122
- detail: { issueId: i5.id, kind: i5.kind, aboutNodeId: i5.aboutNodeId, author: i5.authorActorId, resolved: i5.resolvedAt != null, body: b6.text, bodyChars: b6.chars }
256753
+ detail: { issueId: i5.id, kind: i5.kind, aboutNodeId: i5.aboutNodeId, author: i5.authorActorId, resolved: i5.resolvedAt != null, body: b6 }
256123
256754
  });
256124
256755
  }
256125
256756
  for (const x2 of await this.data.worksAcceptedInWindow(nodeIds, from, to, 50)) {
@@ -256542,12 +257173,13 @@ function reflectionDomain(opts) {
256542
257173
  router.get("/api/traces/units/:unit/outcome", async (req) => {
256543
257174
  const d5 = await deps(req);
256544
257175
  const u = await requireUnit(d5, req.params.unit);
256545
- return { status: 200, body: await d5.units.outcome(u.summary.unitId).catch(unitErr) };
257176
+ return { status: 200, body: await d5.units.outcome(u.summary.unitId, { full: boolParam(req.query, "full") }).catch(unitErr) };
256546
257177
  });
256547
257178
  router.get("/api/traces/units/:unit/exogenous", async (req) => {
256548
257179
  const d5 = await deps(req);
256549
257180
  const u = await requireUnit(d5, req.params.unit);
256550
- return { status: 200, body: { unitId: u.summary.unitId, facts: await d5.units.exogenous(u.summary.unitId).catch(unitErr) } };
257181
+ const facts = await d5.units.exogenous(u.summary.unitId, { full: boolParam(req.query, "full") }).catch(unitErr);
257182
+ return { status: 200, body: { unitId: u.summary.unitId, facts } };
256551
257183
  });
256552
257184
  router.get("/api/traces/units/:unit/runs", async (req) => {
256553
257185
  const d5 = await deps(req);
@@ -257708,546 +258340,6 @@ var init_reflection_service = __esm({
257708
258340
  }
257709
258341
  });
257710
258342
 
257711
- // ../server/src/domains/trace/unit-data.ts
257712
- function quoteSchema(name) {
257713
- if (!/^[A-Za-z0-9_][A-Za-z0-9_.-]*$/.test(name)) throw new Error(`invalid schema name: ${name}`);
257714
- return `"${name}"`;
257715
- }
257716
- function dispatchSchemaIdent(name) {
257717
- const s3 = name.replace(/[^a-zA-Z0-9_]/g, "");
257718
- if (!s3) throw new Error(`invalid dispatch schema name: ${name}`);
257719
- return `"${s3}"`;
257720
- }
257721
- function replyIssueIdFromWorkId(workId) {
257722
- const m4 = /^wk:reply:(.+):\d+$/.exec(workId);
257723
- return m4 ? m4[1] : null;
257724
- }
257725
- function toWork(r5) {
257726
- return {
257727
- id: String(r5["id"]),
257728
- workorderId: String(r5["workorder_id"]),
257729
- nodeId: String(r5["node_id"]),
257730
- nodeType: str5(r5["node_type"]),
257731
- nodeTitle: str5(r5["node_title"]),
257732
- assigneeActorId: String(r5["assignee_actor_id"]),
257733
- createdAt: isoReq(r5["created_at"]),
257734
- startedAt: iso4(r5["started_at"]),
257735
- endedAt: iso4(r5["ended_at"]),
257736
- deadAt: iso4(r5["dead_at"]),
257737
- status: str5(r5["status"]),
257738
- outcome: str5(r5["outcome"]),
257739
- // 存量 lane 为空时按 work id 前缀兜底(回信轮 id 恒为 `wk:reply:<issueId>:<n>`)。
257740
- lane: r5["lane"] === "reply" || r5["lane"] == null && String(r5["id"]).startsWith("wk:reply:") ? "reply" : "main",
257741
- replyIssueId: replyIssueIdFromWorkId(String(r5["id"])),
257742
- continuesWorkId: str5(r5["continues_work_id"]),
257743
- acceptanceState: str5(r5["acceptance_state"]) ?? null,
257744
- acceptedAt: iso4(r5["accepted_at"]),
257745
- rejectedReason: str5(r5["rejected_reason"]),
257746
- overrideBy: str5(r5["override_by"]),
257747
- overrideReason: str5(r5["override_reason"]),
257748
- frozenIssueIds: strArr(r5["frozen_issue_ids"]),
257749
- protocolRecovery: r5["protocol_recovery"] ?? null,
257750
- killSource: str5(r5["kill_source"]),
257751
- outputVersionNo: num3(r5["output_version_no"])
257752
- };
257753
- }
257754
- function toReview(r5) {
257755
- const verdict = str5(r5["verdict"]);
257756
- let status = str5(r5["status"]);
257757
- if (!status) {
257758
- if (r5["retry_at"] != null) status = "retry";
257759
- else if (r5["cancelled_at"] != null) status = "dead";
257760
- else if (verdict === "approve" && r5["decided_at"] != null) status = "accept";
257761
- else if (verdict === "request_changes" && r5["decided_at"] != null) status = "reject";
257762
- else if (r5["ended_at"] != null) status = verdict ? verdict === "approve" ? "accept" : "reject" : "failed";
257763
- else status = "running";
257764
- }
257765
- return {
257766
- id: String(r5["id"]),
257767
- workorderId: String(r5["workorder_id"]),
257768
- nodeId: String(r5["node_id"]),
257769
- nodeTitle: str5(r5["node_title"]),
257770
- targetWorkId: String(r5["target_work_id"]),
257771
- reviewerActorId: String(r5["reviewer_actor_id"]),
257772
- reviewGroup: String(r5["review_group"] ?? ""),
257773
- status,
257774
- verdict: verdict ?? null,
257775
- note: str5(r5["note"]),
257776
- createdAt: isoReq(r5["created_at"]),
257777
- startedAt: iso4(r5["started_at"]),
257778
- endedAt: iso4(r5["ended_at"]),
257779
- decidedAt: iso4(r5["decided_at"]),
257780
- killSource: str5(r5["kill_source"])
257781
- };
257782
- }
257783
- function toIssue(r5) {
257784
- return {
257785
- id: String(r5["id"]),
257786
- workorderId: String(r5["workorder_id"]),
257787
- kind: String(r5["kind"]),
257788
- body: String(r5["body"] ?? ""),
257789
- aboutNodeId: str5(r5["about_node_id"]),
257790
- aboutWorkId: str5(r5["about_work_id"]),
257791
- raisedByNodeId: str5(r5["raised_by_node_id"]),
257792
- authorActorId: String(r5["author_actor_id"]),
257793
- resolvedAt: iso4(r5["resolved_at"]),
257794
- createdAt: isoReq(r5["created_at"])
257795
- };
257796
- }
257797
- function toDispatch(r5) {
257798
- return {
257799
- id: String(r5["id"]),
257800
- targetKind: String(r5["target_kind"]),
257801
- targetId: String(r5["target_id"]),
257802
- actorId: str5(r5["actor_id"]),
257803
- createdAt: isoReq(r5["created_at"]),
257804
- startedAt: iso4(r5["started_at"]),
257805
- endedAt: iso4(r5["ended_at"]),
257806
- outcome: str5(r5["outcome"]),
257807
- reason: str5(r5["reason"]),
257808
- protocolRecoveryRound: num3(r5["protocol_recovery_round"])
257809
- };
257810
- }
257811
- function toDelegation(r5) {
257812
- return {
257813
- id: String(r5["id"]),
257814
- parentSessionId: String(r5["parent_session_id"]),
257815
- parentMessageId: String(r5["parent_message_id"] ?? ""),
257816
- childSessionId: String(r5["child_session_id"]),
257817
- expertActorId: String(r5["expert_actor_id"]),
257818
- state: String(r5["state"]),
257819
- failureKind: str5(r5["failure_kind"]),
257820
- failureReason: str5(r5["failure_reason"]),
257821
- consecutiveFails: num3(r5["consecutive_fails"]) ?? 0,
257822
- dispatchSeq: num3(r5["dispatch_seq"]),
257823
- createdAt: isoReq(r5["created_at"]),
257824
- settledAt: iso4(r5["settled_at"]),
257825
- label: str5(r5["label"]),
257826
- taskDigest: str5(r5["task_digest"])
257827
- };
257828
- }
257829
- function toSession(r5) {
257830
- return {
257831
- id: String(r5["id"]),
257832
- humanActorId: String(r5["human_actor_id"]),
257833
- aiActorId: String(r5["ai_actor_id"]),
257834
- title: str5(r5["title"]),
257835
- analyzedRunId: str5(r5["analyzed_run_id"]),
257836
- runtimeSessionId: str5(r5["runtime_session_id"]),
257837
- touchedAt: isoReq(r5["touched_at"]),
257838
- createdAt: isoReq(r5["created_at"])
257839
- };
257840
- }
257841
- function toTurn(r5) {
257842
- return {
257843
- id: String(r5["id"]),
257844
- chatSessionId: String(r5["chat_session_id"]),
257845
- source: String(r5["source"]),
257846
- status: String(r5["status"]),
257847
- reservedAt: isoReq(r5["reserved_at"]),
257848
- startedAt: iso4(r5["started_at"]),
257849
- completedAt: iso4(r5["completed_at"]),
257850
- cancelledBy: str5(r5["cancelled_by"]),
257851
- dispatchId: str5(r5["dispatch_id"]),
257852
- assistantRunId: str5(r5["assistant_run_id"])
257853
- };
257854
- }
257855
- function toMessage(r5) {
257856
- return {
257857
- id: String(r5["id"]),
257858
- sessionId: String(r5["session_id"]),
257859
- role: String(r5["role"]),
257860
- content: String(r5["content"] ?? ""),
257861
- seq: Number(r5["seq"]),
257862
- createdAt: isoReq(r5["created_at"]),
257863
- runId: str5(r5["run_id"]),
257864
- turnId: str5(r5["turn_id"]),
257865
- source: str5(r5["source"])
257866
- };
257867
- }
257868
- function toLink(r5) {
257869
- return { sessionId: String(r5["session_id"]), workOrderId: String(r5["work_order_id"]), linkedAt: isoReq(r5["linked_at"]) };
257870
- }
257871
- var iso4, isoReq, str5, num3, strArr, WORK_COLS, REVIEW_COLS, MAX_IDS, capIds, PgUnitDataSource;
257872
- var init_unit_data = __esm({
257873
- "../server/src/domains/trace/unit-data.ts"() {
257874
- "use strict";
257875
- iso4 = (v2) => v2 == null ? null : v2 instanceof Date ? v2.toISOString() : typeof v2 === "string" ? new Date(v2).toISOString() : null;
257876
- isoReq = (v2) => iso4(v2) ?? (/* @__PURE__ */ new Date(0)).toISOString();
257877
- str5 = (v2) => typeof v2 === "string" ? v2 : v2 == null ? null : String(v2);
257878
- num3 = (v2) => v2 == null ? null : Number.isFinite(Number(v2)) ? Number(v2) : null;
257879
- strArr = (v2) => Array.isArray(v2) ? v2.filter((x2) => typeof x2 === "string") : [];
257880
- WORK_COLS = `w.id, w.workorder_id, w.node_id, n.type AS node_type, n.title AS node_title, w.assignee_actor_id,
257881
- w.created_at, w.started_at, w.ended_at, w.dead_at, w.status, w.outcome, w.lane, w.continues_work_id,
257882
- w.acceptance_state, w.accepted_at, w.rejected_reason, w.override_by, w.override_reason, w.frozen_issue_ids,
257883
- w.protocol_recovery, w.kill_source, w.output_version_no`;
257884
- REVIEW_COLS = `r.id, r.workorder_id, r.node_id, n.title AS node_title, r.target_work_id, r.reviewer_actor_id, r.review_group,
257885
- r.status, r.verdict, r.note, r.created_at, r.started_at, r.ended_at, r.decided_at, r.cancelled_at, r.retry_at, r.kill_source`;
257886
- MAX_IDS = 500;
257887
- capIds = (ids2) => [...new Set(ids2)].slice(0, MAX_IDS);
257888
- PgUnitDataSource = class {
257889
- pool;
257890
- /** 引擎 schema(works / reviews / issues / events / workflow_*)。 */
257891
- e;
257892
- /** chat 一族(chat_sessions / chat_messages / chat_session_turns / 委派);缺省与引擎同 schema。 */
257893
- c;
257894
- /** 派发台账 schema(按 dispatches store 的口径净化)。 */
257895
- d;
257896
- constructor(opts) {
257897
- this.pool = opts.pool;
257898
- this.e = quoteSchema(opts.engineSchema);
257899
- this.c = quoteSchema(opts.chatSchema ?? opts.engineSchema);
257900
- this.d = dispatchSchemaIdent(opts.dispatchSchema);
257901
- }
257902
- async q(text7, values = []) {
257903
- return (await this.pool.query(text7, values)).rows;
257904
- }
257905
- /* ── work / review ── */
257906
- async getWorks(ids2) {
257907
- if (ids2.length === 0) return [];
257908
- const rows = await this.q(
257909
- `SELECT ${WORK_COLS} FROM ${this.e}.works w LEFT JOIN ${this.e}.workflow_nodes n ON n.id = w.node_id WHERE w.id = ANY($1)`,
257910
- [capIds(ids2)]
257911
- );
257912
- return rows.map(toWork);
257913
- }
257914
- async getReview(id) {
257915
- const rows = await this.q(
257916
- `SELECT ${REVIEW_COLS} FROM ${this.e}.reviews r LEFT JOIN ${this.e}.workflow_nodes n ON n.id = r.node_id WHERE r.id = $1`,
257917
- [id]
257918
- );
257919
- return rows[0] ? toReview(rows[0]) : null;
257920
- }
257921
- async reviewsOfWorks(workIds) {
257922
- if (workIds.length === 0) return [];
257923
- const rows = await this.q(
257924
- `SELECT ${REVIEW_COLS} FROM ${this.e}.reviews r LEFT JOIN ${this.e}.workflow_nodes n ON n.id = r.node_id
257925
- WHERE r.target_work_id = ANY($1) ORDER BY r.created_at ASC, r.id ASC LIMIT 500`,
257926
- [capIds(workIds)]
257927
- );
257928
- return rows.map(toReview);
257929
- }
257930
- async worksOfNode(nodeId, limit) {
257931
- const rows = await this.q(
257932
- `SELECT ${WORK_COLS} FROM ${this.e}.works w LEFT JOIN ${this.e}.workflow_nodes n ON n.id = w.node_id
257933
- WHERE w.node_id = $1 ORDER BY w.created_at DESC, w.id DESC LIMIT $2`,
257934
- [nodeId, limit]
257935
- );
257936
- return rows.map(toWork);
257937
- }
257938
- async workInputsOf(workIds) {
257939
- if (workIds.length === 0) return [];
257940
- const rows = await this.q(
257941
- `SELECT work_id, upstream_node_id, upstream_work_id FROM ${this.e}.work_inputs WHERE work_id = ANY($1) LIMIT 2000`,
257942
- [capIds(workIds)]
257943
- );
257944
- return rows.map((r5) => ({
257945
- workId: String(r5["work_id"]),
257946
- upstreamNodeId: String(r5["upstream_node_id"]),
257947
- upstreamWorkId: String(r5["upstream_work_id"])
257948
- }));
257949
- }
257950
- async inputNodesOf(nodeId) {
257951
- const rows = await this.q(
257952
- `SELECT from_node_id FROM ${this.e}.workflow_edges WHERE to_node_id = $1 AND kind = 'data' ORDER BY from_node_id LIMIT 100`,
257953
- [nodeId]
257954
- );
257955
- return rows.map((r5) => String(r5["from_node_id"]));
257956
- }
257957
- async outputNodesOf(nodeId) {
257958
- const rows = await this.q(
257959
- `SELECT to_node_id FROM ${this.e}.workflow_edges WHERE from_node_id = $1 AND kind = 'data' ORDER BY to_node_id LIMIT 100`,
257960
- [nodeId]
257961
- );
257962
- return rows.map((r5) => String(r5["to_node_id"]));
257963
- }
257964
- async latestAcceptedWorkOfNodeBefore(nodeId, beforeIso) {
257965
- const rows = await this.q(
257966
- `SELECT ${WORK_COLS} FROM ${this.e}.works w LEFT JOIN ${this.e}.workflow_nodes n ON n.id = w.node_id
257967
- WHERE w.node_id = $1 AND w.acceptance_state = 'accepted' AND w.accepted_at IS NOT NULL AND w.accepted_at <= $2
257968
- ORDER BY w.accepted_at DESC, w.id DESC LIMIT 1`,
257969
- [nodeId, beforeIso]
257970
- );
257971
- return rows[0] ? toWork(rows[0]) : null;
257972
- }
257973
- async worksAcceptedInWindow(nodeIds, fromIso, toIso2, limit) {
257974
- if (nodeIds.length === 0) return [];
257975
- const rows = await this.q(
257976
- `SELECT ${WORK_COLS} FROM ${this.e}.works w LEFT JOIN ${this.e}.workflow_nodes n ON n.id = w.node_id
257977
- WHERE w.node_id = ANY($1) AND w.acceptance_state = 'accepted' AND w.accepted_at >= $2 AND w.accepted_at <= $3
257978
- ORDER BY w.accepted_at ASC, w.id ASC LIMIT $4`,
257979
- [capIds(nodeIds), fromIso, toIso2, limit]
257980
- );
257981
- return rows.map(toWork);
257982
- }
257983
- async reworkSourcesOf(work) {
257984
- const rows = await this.q(
257985
- `SELECT DISTINCT x.reason->>'workId' AS src
257986
- FROM (SELECT payload FROM ${this.e}.events
257987
- WHERE node_id = $1 AND kind = 'work.create' AND payload->>'workId' = $2
257988
- ORDER BY seq DESC LIMIT 20) ev,
257989
- LATERAL jsonb_array_elements(COALESCE(ev.payload->'reasons', '[]'::jsonb)) AS x(reason)
257990
- WHERE x.reason->>'kind' = 'rework' AND x.reason->>'workId' IS NOT NULL`,
257991
- [work.nodeId, work.id]
257992
- );
257993
- return rows.map((r5) => String(r5["src"]));
257994
- }
257995
- async reworkedBy(work) {
257996
- const viaCol = await this.q(
257997
- `SELECT id FROM ${this.e}.works WHERE node_id = $1 AND continues_work_id = $2 AND id <> $2 ORDER BY created_at ASC LIMIT 50`,
257998
- [work.nodeId, work.id]
257999
- );
258000
- const viaEvents = await this.q(
258001
- `SELECT DISTINCT ev.payload->>'workId' AS wid
258002
- FROM (SELECT payload FROM ${this.e}.events WHERE node_id = $1 AND kind = 'work.create' ORDER BY seq DESC LIMIT 200) ev,
258003
- LATERAL jsonb_array_elements(COALESCE(ev.payload->'reasons', '[]'::jsonb)) AS x(reason)
258004
- WHERE x.reason->>'kind' = 'rework' AND x.reason->>'workId' = $2`,
258005
- [work.nodeId, work.id]
258006
- );
258007
- const out = /* @__PURE__ */ new Set();
258008
- for (const r5 of viaCol) out.add(String(r5["id"]));
258009
- for (const r5 of viaEvents) if (r5["wid"] != null && r5["wid"] !== work.id) out.add(String(r5["wid"]));
258010
- return [...out];
258011
- }
258012
- async briefNodesOf(workorderId) {
258013
- const rows = await this.q(
258014
- `SELECT id FROM ${this.e}.workflow_nodes WHERE workorder_id = $1 AND type = 'brief' ORDER BY created_at ASC LIMIT 10`,
258015
- [workorderId]
258016
- );
258017
- return rows.map((r5) => String(r5["id"]));
258018
- }
258019
- /* ── issue ── */
258020
- async issuesByIds(ids2) {
258021
- if (ids2.length === 0) return [];
258022
- const rows = await this.q(`SELECT * FROM ${this.e}.issues WHERE id = ANY($1)`, [capIds(ids2)]);
258023
- return rows.map(toIssue);
258024
- }
258025
- async issuesInWorkorder(workorderId, q4) {
258026
- const args = [workorderId];
258027
- const conds = ["workorder_id = $1"];
258028
- const ors = [];
258029
- const push2 = (v2) => {
258030
- args.push(v2);
258031
- return `$${args.length}`;
258032
- };
258033
- if (q4.aboutWorkIds?.length) ors.push(`about_work_id = ANY(${push2(capIds(q4.aboutWorkIds))})`);
258034
- if (q4.aboutNodeIds?.length) ors.push(`about_node_id = ANY(${push2(capIds(q4.aboutNodeIds))})`);
258035
- if (q4.raisedByNodeIds?.length) ors.push(`raised_by_node_id = ANY(${push2(capIds(q4.raisedByNodeIds))})`);
258036
- if (ors.length) conds.push(`(${ors.join(" OR ")})`);
258037
- if (q4.fromIso) conds.push(`created_at >= ${push2(q4.fromIso)}`);
258038
- if (q4.toIso) conds.push(`created_at <= ${push2(q4.toIso)}`);
258039
- const rows = await this.q(
258040
- `SELECT * FROM ${this.e}.issues WHERE ${conds.join(" AND ")} ORDER BY created_at ASC, id ASC LIMIT ${push2(q4.limit)}`,
258041
- args
258042
- );
258043
- return rows.map(toIssue);
258044
- }
258045
- async worksHandlingIssues(workorderId, issueIds, limit) {
258046
- if (issueIds.length === 0) return [];
258047
- const ids2 = capIds(issueIds);
258048
- const rows = await this.q(
258049
- `SELECT ${WORK_COLS} FROM ${this.e}.works w LEFT JOIN ${this.e}.workflow_nodes n ON n.id = w.node_id
258050
- WHERE w.workorder_id = $1
258051
- AND (w.id LIKE ANY($4::text[]) OR (jsonb_typeof(w.frozen_issue_ids) = 'array' AND w.frozen_issue_ids ?| $2))
258052
- ORDER BY w.created_at ASC, w.id ASC LIMIT $3`,
258053
- [workorderId, ids2, limit, ids2.map((i5) => `wk:reply:${i5.replace(/[\\%_]/g, (c5) => `\\${c5}`)}:%`)]
258054
- );
258055
- return rows.map(toWork);
258056
- }
258057
- /* ── dispatches ── */
258058
- async dispatchesOf(kind, targetIds) {
258059
- if (targetIds.length === 0) return [];
258060
- const rows = await this.q(
258061
- `SELECT id, target_kind, target_id, actor_id, created_at, started_at, ended_at, outcome, reason, protocol_recovery_round
258062
- FROM ${this.d}.dispatches WHERE target_kind = $1 AND target_id = ANY($2) ORDER BY created_at ASC, id ASC LIMIT 1000`,
258063
- [kind, capIds(targetIds)]
258064
- );
258065
- return rows.map(toDispatch);
258066
- }
258067
- async dispatchTargetOf(runId) {
258068
- const rows = await this.q(`SELECT target_kind, target_id FROM ${this.d}.dispatches WHERE id = $1`, [runId]);
258069
- const r5 = rows[0];
258070
- return r5 ? { targetKind: String(r5["target_kind"]), targetId: String(r5["target_id"]) } : null;
258071
- }
258072
- /* ── 委派 ── */
258073
- async getDelegation(id) {
258074
- const rows = await this.q(`SELECT * FROM ${this.c}.chat_session_delegations WHERE id = $1`, [id]);
258075
- return rows[0] ? toDelegation(rows[0]) : null;
258076
- }
258077
- async delegationByChildSession(childSessionId) {
258078
- const rows = await this.q(`SELECT * FROM ${this.c}.chat_session_delegations WHERE child_session_id = $1`, [childSessionId]);
258079
- return rows[0] ? toDelegation(rows[0]) : null;
258080
- }
258081
- async delegationsOfParent(parentSessionId, limit) {
258082
- const rows = await this.q(
258083
- `SELECT * FROM ${this.c}.chat_session_delegations WHERE parent_session_id = $1 ORDER BY created_at ASC, id ASC LIMIT $2`,
258084
- [parentSessionId, limit]
258085
- );
258086
- return rows.map(toDelegation);
258087
- }
258088
- async touchesOf(delegationId) {
258089
- const rows = await this.q(
258090
- `SELECT delegation_id, message_id, kind, at FROM ${this.c}.chat_session_delegation_touches
258091
- WHERE delegation_id = $1 ORDER BY at ASC LIMIT 500`,
258092
- [delegationId]
258093
- );
258094
- return rows.map((r5) => ({
258095
- delegationId: String(r5["delegation_id"]),
258096
- messageId: String(r5["message_id"]),
258097
- kind: String(r5["kind"]),
258098
- at: isoReq(r5["at"])
258099
- }));
258100
- }
258101
- /* ── 会话 / 轮次 / 消息 ── */
258102
- async getSession(id) {
258103
- const rows = await this.q(`SELECT * FROM ${this.c}.chat_sessions WHERE id = $1`, [id]);
258104
- return rows[0] ? toSession(rows[0]) : null;
258105
- }
258106
- async getTurn(id) {
258107
- const rows = await this.q(`SELECT * FROM ${this.c}.chat_session_turns WHERE id = $1`, [id]);
258108
- return rows[0] ? toTurn(rows[0]) : null;
258109
- }
258110
- async turnsOfSession(sessionId, limit) {
258111
- const rows = await this.q(
258112
- `SELECT * FROM ${this.c}.chat_session_turns WHERE chat_session_id = $1 ORDER BY reserved_at DESC, id DESC LIMIT $2`,
258113
- [sessionId, limit + 1]
258114
- );
258115
- const truncated = rows.length > limit;
258116
- const turns = (truncated ? rows.slice(0, limit) : rows).map(toTurn).reverse();
258117
- return { turns, truncated };
258118
- }
258119
- async getMessage(id) {
258120
- const rows = await this.q(`SELECT * FROM ${this.c}.chat_messages WHERE id = $1`, [id]);
258121
- return rows[0] ? toMessage(rows[0]) : null;
258122
- }
258123
- async messagesOf(sessionId, q4) {
258124
- const args = [sessionId];
258125
- const push2 = (v2) => {
258126
- args.push(v2);
258127
- return `$${args.length}`;
258128
- };
258129
- const conds = ["session_id = $1"];
258130
- if (q4.turnIds) {
258131
- const window3 = ["turn_id IS NULL"];
258132
- if (q4.fromIso) window3.push(`created_at >= ${push2(q4.fromIso)}`);
258133
- if (q4.toIso) window3.push(`created_at <= ${push2(q4.toIso)}`);
258134
- conds.push(`(turn_id = ANY(${push2(capIds(q4.turnIds))}) OR (${window3.join(" AND ")}))`);
258135
- } else {
258136
- if (q4.fromIso) conds.push(`created_at >= ${push2(q4.fromIso)}`);
258137
- if (q4.toIso) conds.push(`created_at <= ${push2(q4.toIso)}`);
258138
- }
258139
- if (q4.roles?.length) conds.push(`role = ANY(${push2(q4.roles)})`);
258140
- const rows = await this.q(
258141
- `SELECT id, session_id, role, content, seq, created_at, run_id, turn_id, source FROM ${this.c}.chat_messages
258142
- WHERE ${conds.join(" AND ")} ORDER BY seq ASC LIMIT ${push2(q4.limit)}`,
258143
- args
258144
- );
258145
- return rows.map(toMessage);
258146
- }
258147
- async pendingMessagesOf(sessionId, fromIso, toIso2, limit) {
258148
- const rows = await this.q(
258149
- `SELECT id, chat_session_id, text, created_at, state, flavour FROM ${this.c}.chat_pending_messages
258150
- WHERE chat_session_id = $1 AND created_at >= $2 AND created_at <= $3 ORDER BY seq ASC LIMIT $4`,
258151
- [sessionId, fromIso, toIso2, limit]
258152
- );
258153
- return rows.map((r5) => ({
258154
- id: String(r5["id"]),
258155
- chatSessionId: String(r5["chat_session_id"]),
258156
- text: String(r5["text"] ?? ""),
258157
- createdAt: isoReq(r5["created_at"]),
258158
- state: str5(r5["state"]),
258159
- flavour: str5(r5["flavour"])
258160
- }));
258161
- }
258162
- async originLinksOfWorkorder(workorderId) {
258163
- const rows = await this.q(
258164
- `SELECT session_id, work_order_id, linked_at FROM ${this.c}.chat_session_work_orders
258165
- WHERE work_order_id = $1 AND link_kind = 'origin' ORDER BY linked_at ASC LIMIT 20`,
258166
- [workorderId]
258167
- );
258168
- return rows.map(toLink);
258169
- }
258170
- async originLinksOfSession(sessionId) {
258171
- const rows = await this.q(
258172
- `SELECT session_id, work_order_id, linked_at FROM ${this.c}.chat_session_work_orders
258173
- WHERE session_id = $1 AND link_kind = 'origin' ORDER BY linked_at ASC LIMIT 200`,
258174
- [sessionId]
258175
- );
258176
- return rows.map(toLink);
258177
- }
258178
- /* ── find / peers 候选 ── */
258179
- async listEndedWorks(q4) {
258180
- const args = [];
258181
- const push2 = (v2) => {
258182
- args.push(v2);
258183
- return `$${args.length}`;
258184
- };
258185
- const conds = [`(w.ended_at IS NOT NULL OR w.dead_at IS NOT NULL)`, `w.acceptance_state IS DISTINCT FROM 'draft'`];
258186
- if (q4.sinceIso) conds.push(`COALESCE(w.ended_at, w.dead_at) >= ${push2(q4.sinceIso)}`);
258187
- if (q4.actorId) conds.push(`w.assignee_actor_id = ${push2(q4.actorId)}`);
258188
- if (q4.nodeType) conds.push(`n.type = ${push2(q4.nodeType)}`);
258189
- if (q4.lane) conds.push(`COALESCE(w.lane, CASE WHEN w.id LIKE 'wk:reply:%' THEN 'reply' ELSE 'main' END) = ${push2(q4.lane)}`);
258190
- const rows = await this.q(
258191
- `SELECT ${WORK_COLS} FROM ${this.e}.works w LEFT JOIN ${this.e}.workflow_nodes n ON n.id = w.node_id
258192
- WHERE ${conds.join(" AND ")} ORDER BY COALESCE(w.ended_at, w.dead_at) DESC, w.id DESC LIMIT ${push2(q4.limit)}`,
258193
- args
258194
- );
258195
- return rows.map(toWork);
258196
- }
258197
- async listEndedReviews(q4) {
258198
- const args = [];
258199
- const push2 = (v2) => {
258200
- args.push(v2);
258201
- return `$${args.length}`;
258202
- };
258203
- const endExpr = `COALESCE(r.ended_at, r.decided_at, r.cancelled_at, r.created_at)`;
258204
- const conds = [`r.status IN ('accept','reject','failed','dead')`];
258205
- if (q4.sinceIso) conds.push(`${endExpr} >= ${push2(q4.sinceIso)}`);
258206
- if (q4.actorId) conds.push(`r.reviewer_actor_id = ${push2(q4.actorId)}`);
258207
- const rows = await this.q(
258208
- `SELECT ${REVIEW_COLS} FROM ${this.e}.reviews r LEFT JOIN ${this.e}.workflow_nodes n ON n.id = r.node_id
258209
- WHERE ${conds.join(" AND ")} ORDER BY ${endExpr} DESC, r.id DESC LIMIT ${push2(q4.limit)}`,
258210
- args
258211
- );
258212
- return rows.map(toReview);
258213
- }
258214
- async listEndedDelegations(q4) {
258215
- const args = [];
258216
- const push2 = (v2) => {
258217
- args.push(v2);
258218
- return `$${args.length}`;
258219
- };
258220
- const conds = [`state IN ('done','failed')`];
258221
- if (q4.sinceIso) conds.push(`COALESCE(settled_at, created_at) >= ${push2(q4.sinceIso)}`);
258222
- if (q4.actorId) conds.push(`expert_actor_id = ${push2(q4.actorId)}`);
258223
- const rows = await this.q(
258224
- `SELECT * FROM ${this.c}.chat_session_delegations WHERE ${conds.join(" AND ")}
258225
- ORDER BY COALESCE(settled_at, created_at) DESC, id DESC LIMIT ${push2(q4.limit)}`,
258226
- args
258227
- );
258228
- return rows.map(toDelegation);
258229
- }
258230
- async listRecentSessions(q4) {
258231
- const args = [];
258232
- const push2 = (v2) => {
258233
- args.push(v2);
258234
- return `$${args.length}`;
258235
- };
258236
- const conds = [`NOT EXISTS (SELECT 1 FROM ${this.c}.chat_session_delegations d WHERE d.child_session_id = s.id)`];
258237
- if (!q4.includeAnalysis) conds.push(`s.analyzed_run_id IS NULL`);
258238
- if (q4.sinceIso) conds.push(`s.touched_at >= ${push2(q4.sinceIso)}`);
258239
- if (q4.aiActorId) conds.push(`s.ai_actor_id = ${push2(q4.aiActorId)}`);
258240
- const rows = await this.q(
258241
- `SELECT s.id, s.human_actor_id, s.ai_actor_id, s.title, s.analyzed_run_id, s.runtime_session_id, s.touched_at, s.created_at
258242
- FROM ${this.c}.chat_sessions s WHERE ${conds.join(" AND ")} ORDER BY s.touched_at DESC, s.id DESC LIMIT ${push2(q4.limit)}`,
258243
- args
258244
- );
258245
- return rows.map(toSession);
258246
- }
258247
- };
258248
- }
258249
- });
258250
-
258251
258343
  // ../server/src/domains/trace/index.ts
258252
258344
  function createTraceDomain(opts) {
258253
258345
  const service = new TraceService({ store: opts.store });
@@ -261506,7 +261598,7 @@ function shown(field, v2, nameOf2) {
261506
261598
  if (v2 === void 0 || v2 === "") return "\uFF08\u7A7A\uFF09";
261507
261599
  if (field === "dueDate" || field === "startDate") return formatTodoDue(v2);
261508
261600
  if (field === "assignee") return nameOf2(v2);
261509
- return clip5(v2);
261601
+ return clip4(v2);
261510
261602
  }
261511
261603
  function assignedTitle(who2, todo) {
261512
261604
  return `${who2} \u6D3E\u7ED9\u4F60\uFF1A${todo.title}\uFF0C${formatTodoSpan(todo)}`;
@@ -261517,13 +261609,13 @@ function unseenTitle(assigneeName, todo) {
261517
261609
  function changedTitle(who2, todo, changes, nameOf2) {
261518
261610
  const parts = changes.map((c5) => `${FIELD_LABEL[c5.field] ?? c5.field} ${shown(c5.field, c5.oldValue, nameOf2)} \u2192 ${shown(c5.field, c5.newValue, nameOf2)}`);
261519
261611
  const reason2 = changes.find((c5) => c5.reason)?.reason;
261520
- return `${who2} \u6539\u4E86\u300C${todo.title}\u300D\uFF1A${parts.join("\uFF1B")}${reason2 ? `\uFF1B\u539F\u56E0\uFF1A${clip5(reason2)}` : ""}`;
261612
+ return `${who2} \u6539\u4E86\u300C${todo.title}\u300D\uFF1A${parts.join("\uFF1B")}${reason2 ? `\uFF1B\u539F\u56E0\uFF1A${clip4(reason2)}` : ""}`;
261521
261613
  }
261522
261614
  function statusTitle(who2, todo, kind, reason2, result) {
261523
261615
  const verb = kind === "todo-done" ? "\u5B8C\u6210\u4E86" : kind === "todo-reopened" ? "\u91CD\u65B0\u6253\u5F00\u4E86" : "\u53D6\u6D88\u4E86";
261524
- return `${who2} ${verb}\u300C${todo.title}\u300D${result ? `\uFF1B\u7ED3\u679C\uFF1A${clip5(result)}` : ""}${reason2 ? `\uFF1B\u539F\u56E0\uFF1A${clip5(reason2)}` : ""}`;
261616
+ return `${who2} ${verb}\u300C${todo.title}\u300D${result ? `\uFF1B\u7ED3\u679C\uFF1A${clip4(result)}` : ""}${reason2 ? `\uFF1B\u539F\u56E0\uFF1A${clip4(reason2)}` : ""}`;
261525
261617
  }
261526
- var VALUE_MAX, FIELD_LABEL, clip5, todoAssignedSourceKey, todoChangeSourceKey, todoUnseenSourceKey;
261618
+ var VALUE_MAX, FIELD_LABEL, clip4, todoAssignedSourceKey, todoChangeSourceKey, todoUnseenSourceKey;
261527
261619
  var init_notices = __esm({
261528
261620
  "../server/src/domains/todos/notices.ts"() {
261529
261621
  "use strict";
@@ -261540,7 +261632,7 @@ var init_notices = __esm({
261540
261632
  assignee: "\u627F\u63A5\u4EBA",
261541
261633
  result: "\u7ED3\u679C\u5728\u54EA"
261542
261634
  };
261543
- clip5 = (v2) => v2.length > VALUE_MAX ? `${v2.slice(0, VALUE_MAX)}\u2026` : v2;
261635
+ clip4 = (v2) => v2.length > VALUE_MAX ? `${v2.slice(0, VALUE_MAX)}\u2026` : v2;
261544
261636
  todoAssignedSourceKey = (todoId) => `todo:${todoId}@assigned`;
261545
261637
  todoChangeSourceKey = (todoId, changeId) => `todo:${todoId}@change:${changeId}`;
261546
261638
  todoUnseenSourceKey = (todo) => `todo:${todo.id}@unseen:${todo.dueDate}`;
@@ -327220,6 +327312,7 @@ __export(src_exports2, {
327220
327312
  shouldInjectResumePack: () => shouldInjectResumePack,
327221
327313
  shouldPush: () => shouldPush,
327222
327314
  singlePushPayload: () => singlePushPayload,
327315
+ skillManifestForActor: () => skillManifestForActor,
327223
327316
  skillsDirForRuntime: () => skillsDirForRuntime,
327224
327317
  splitKnowledgeChunks: () => splitKnowledgeChunks,
327225
327318
  stableChatTraceRunId: () => stableChatTraceRunId,
@@ -330036,6 +330129,7 @@ function createTodoRuntime(options) {
330036
330129
  value2 = options.store(id).then((store) => new TodoService({
330037
330130
  store,
330038
330131
  timeZone: () => options.timeZone(id),
330132
+ ...options.now ? { now: options.now } : {},
330039
330133
  ...options.people ? { people: () => options.people(id) } : {},
330040
330134
  ...options.runOf ? { runOf: options.runOf } : {},
330041
330135
  // 派给别人的待办的告知(ADR 0640):与到期提醒同一条路——直接 insert 进台账 `todo` 类,新写的推送 + 刷铃铛。
@@ -330334,7 +330428,7 @@ function createOverlapRuntime(options) {
330334
330428
  const people = await options.people(companyId).catch(() => []);
330335
330429
  for (const p4 of people) if (ids2.includes(p4.actorId)) out[p4.actorId] = p4.name;
330336
330430
  for (const id of ids2) {
330337
- if (out[id] || isHumanActorId(id)) continue;
330431
+ if (out[id]) continue;
330338
330432
  const name = await options.actorName(companyId, id).catch(() => void 0);
330339
330433
  if (name) out[id] = name;
330340
330434
  }
@@ -331022,6 +331116,18 @@ function skillContentHash(files) {
331022
331116
  }
331023
331117
  return `sha256:${h5.digest("hex")}`;
331024
331118
  }
331119
+ function inMemorySkillFiles(skillId, pools) {
331120
+ const toFiles = (files) => Object.entries(files).map(([path50, content3]) => ({ path: path50, content: content3 }));
331121
+ if (skillId.startsWith("builtin:")) {
331122
+ const b6 = pools.builtins.find((x2) => `builtin:${x2.id}` === skillId);
331123
+ return b6 ? toFiles(b6.files) : null;
331124
+ }
331125
+ if (skillId.startsWith("connector:")) {
331126
+ const c5 = pools.connectorSkills.find((x2) => x2.id === skillId);
331127
+ return c5 ? toFiles(c5.files) : null;
331128
+ }
331129
+ return void 0;
331130
+ }
331025
331131
  function scopedTrace(trace, scope2) {
331026
331132
  if (scope2.companyScoped) return trace;
331027
331133
  const allows = traceReadAllows(scope2);
@@ -331147,7 +331253,10 @@ ${f6.content}`).join("\n\n");
331147
331253
  const svc = await exposureServiceFor(cid, await deps.traceStoreFor(cid), reflection);
331148
331254
  await svc.recordDispatch({
331149
331255
  runId: input.runId,
331150
- skills: await deps.listSkills(cid, input.actorId, { builtins: input.builtins }),
331256
+ skills: await deps.listSkills(cid, input.actorId, {
331257
+ builtins: input.builtins,
331258
+ ...input.chatSessionId !== void 0 ? { chatSessionId: input.chatSessionId } : {}
331259
+ }),
331151
331260
  memories: input.memories ? input.memories.map((m4) => ({ memId: m4.memId, version: m4.version })) : null
331152
331261
  });
331153
331262
  })().catch((e5) => log3(`[reflection] ${cid} chat run ${input.runId} \u57CB\u70B9\u5931\u8D25\uFF08\u4E0D\u5F71\u54CD\u5BF9\u8BDD\uFF09\uFF1A${String(e5)}`));
@@ -334931,9 +335040,12 @@ async function startServe(opts) {
334931
335040
  traceReadScopeFor: (cid) => traceReadScopeFor(cid),
334932
335041
  blobStoreFor: (cid) => blobStoreFor(cid),
334933
335042
  readBundleFile: (id, rel) => trajReader.readBundleFile(id, rel),
335043
+ // 与 `GET /api/skill-cache/manifest` 同一个函数、同一组参数(ADR 0641 §3.3):内置按会话 claim 投影
335044
+ //(管理者会话不给委派变体),连接器技能按该员工启用的 connector 门禁——节点拿到什么就记什么。
334934
335045
  listSkills: async (cid, actorId, o3) => {
334935
335046
  const { service } = await actors.resolveCtx(cid);
334936
- return listSkillMetadataForActor({ service, actorId, ...o3.builtins ? { builtins: builtinSkills } : {} });
335047
+ const builtins = o3.builtins ? await chatBuiltinSkillsForClaim(o3.chatSessionId ? { chatSessionId: o3.chatSessionId, companyId: cid } : void 0) : [];
335048
+ return skillManifestForActor({ service, actorId, builtins, connectorSkills });
334937
335049
  },
334938
335050
  readMemories: async (cid, actorId, memIds) => {
334939
335051
  const svc = await actorMemoryFor(cid);
@@ -334950,11 +335062,8 @@ async function startServe(opts) {
334950
335062
  return cfg ? { prompt: cfg.prompt ?? "", version: cfg.version } : null;
334951
335063
  },
334952
335064
  readSkillFiles: async (cid, skillId) => {
334953
- if (skillId.startsWith("builtin:")) {
334954
- const b6 = builtinSkills.find((x2) => `builtin:${x2.id}` === skillId);
334955
- return b6 ? Object.entries(b6.files).map(([path50, content3]) => ({ path: path50, content: content3 })) : null;
334956
- }
334957
- if (skillId.startsWith("connector:")) return null;
335065
+ const mem = inMemorySkillFiles(skillId, { builtins: effectiveBuiltinSkills(), connectorSkills });
335066
+ if (mem !== void 0) return mem;
334958
335067
  const files = await (await actors.resolveCtx(cid)).service.listSkillFiles(skillId).catch(() => []);
334959
335068
  return files.length ? files.map((f6) => ({ path: f6.path, content: f6.content })) : null;
334960
335069
  },
@@ -336468,6 +336577,7 @@ async function startServe(opts) {
336468
336577
  actorId,
336469
336578
  turnId: chatTurnId,
336470
336579
  builtins: !isolatedBackground,
336580
+ ...chatSessionId !== void 0 ? { chatSessionId } : {},
336471
336581
  memories: chatInjectedMemories,
336472
336582
  files: { ...files },
336473
336583
  systemPromptFingerprint: null
@@ -342713,7 +342823,7 @@ var COMMAND_DECLS = {
342713
342823
  delegate: {
342714
342824
  group: "\u59D4\u6D3E\u4E13\u5BB6",
342715
342825
  usage: 'oasis delegate --to <role|actorId> --task "<\u4EFB\u52A1\u4E66>" [--as <\u77ED\u540D>] [--file <\u8DEF\u5F84>]... [--json true]\n oasis delegate --follow-up <\u5F15\u7528> --text "<...>" [--file <\u8DEF\u5F84>]...\n oasis delegate --status <\u5F15\u7528|\u59D4\u6D3Eid> [--json true]\n oasis delegate --list [--all] [--json true]',
342716
- description: "\u628A\u4E00\u4EF6\u4E8B\u4EA4\u7ED9\u7EC4\u7EC7\u91CC\u5BF9\u53E3\u7684\u4E13\u5BB6\u53BB\u505A\uFF08\u5F02\u6B65\uFF09\u3002\u547D\u4EE4\u7ACB\u5373\u8FD4\u56DE\uFF0C\u4E13\u5BB6\u5E72\u5B8C\u4E86\u7ED3\u679C\u81EA\u5DF1\u56DE\u5230\u8FD9\u6761\u5BF9\u8BDD\u2014\u2014**\u4E0D\u8981\u5728\u8FD9\u91CC\u7B49**\u3002\u6210\u529F\u540E\u5982\u679C\u672C\u516C\u53F8\u6709\u4EBA\u5728\u505A\u6216\u505A\u8FC7\u76F8\u8FD1\u7684\u4E8B\uFF0C\u8F93\u51FA\u672B\u5C3E\u4F1A\u591A\u4E00\u6BB5\u300C\u76F8\u8FD1\u7684\u4E8B\u9879\uFF08\u7CFB\u7EDF\u7C97\u7B5B\uFF0C\u672A\u786E\u8BA4\uFF0C\u8BF7\u7528 id \u67E5\u8BE6\u60C5\u540E\u5224\u65AD\uFF09\u300D\uFF0C\u6BCF\u6761\u5E26 id\uFF1A\u7528 id \u9010\u6761\u67E5\u8BE6\u60C5\uFF08\u5F85\u529E oasis todo show\u3001\u5DE5\u5355 oasis workorder\u3001\u59D4\u6D3E oasis delegate --status\uFF09\uFF0C\u5224\u65AD\u662F\u4E0D\u662F\u540C\u4E00\u4EF6\u4E8B\uFF1B\u786E\u5B9E\u76F8\u5173\u624D\u544A\u8BC9\u7528\u6237\uFF0C\u4E0D\u76F8\u5173\u4E00\u4E2A\u5B57\u90FD\u4E0D\u63D0\uFF1B\u5728\u505A\u7684\u5EFA\u8BAE\u7528\u6237\u5148\u95EE\u95EE\u5BF9\u65B9\uFF0C\u770B\u5408\u5E76\u8FD8\u662F\u5206\u5DE5\uFF1B\u505A\u5B8C\u7684\u628A\u7ED3\u679C\u7ED9\u7528\u6237\uFF0C\u95EE\u80FD\u4E0D\u80FD\u76F4\u63A5\u7528\uFF1B\u4E0D\u66FF\u7528\u6237\u505C\u6389\u8FD9\u6B21\u59D4\u6D3E\u3001\u5408\u5E76\u3001\u53D6\u6D88\u6216\u6539\u6D3E\u3002\u6CA1\u6709\u8FD9\u4E00\u6BB5\u5C31\u662F\u6CA1\u6BD4\u51FA\u6765\uFF0C\u6BD4\u5BF9\u51FA\u4E86\u95EE\u9898\u4E5F\u53EA\u662F\u6CA1\u6709\u8FD9\u4E00\u6BB5\uFF0C\u547D\u4EE4\u7167\u6837\u7B97\u6210\u529F\u3002",
342826
+ description: "\u628A\u4E00\u4EF6\u4E8B\u4EA4\u7ED9\u7EC4\u7EC7\u91CC\u5BF9\u53E3\u7684\u4E13\u5BB6\u53BB\u505A\uFF08\u5F02\u6B65\uFF09\u3002\u547D\u4EE4\u7ACB\u5373\u8FD4\u56DE\uFF0C\u4E13\u5BB6\u5E72\u5B8C\u4E86\u7ED3\u679C\u81EA\u5DF1\u56DE\u5230\u8FD9\u6761\u5BF9\u8BDD\u2014\u2014**\u4E0D\u8981\u5728\u8FD9\u91CC\u7B49**\u3002\u6210\u529F\u540E\u5982\u679C\u672C\u516C\u53F8\u6709\u4EBA\u5728\u505A\u6216\u505A\u8FC7\u76F8\u8FD1\u7684\u4E8B\uFF0C\u8F93\u51FA\u672B\u5C3E\u4F1A\u591A\u4E00\u6BB5\u300C\u76F8\u8FD1\u7684\u4E8B\u9879\uFF08\u7CFB\u7EDF\u7C97\u7B5B\uFF0C\u672A\u786E\u8BA4\uFF0C\u8BF7\u7528 id \u67E5\u8BE6\u60C5\u540E\u5224\u65AD\uFF09\u300D\uFF08--json \u65F6\u5728 overlap \u5B57\u6BB5\u91CC\uFF0C\u540C\u6837\u51E0\u884C\uFF09\uFF0C\u6BCF\u6761\u5E26 id\uFF1A\u7528 id \u9010\u6761\u67E5\u8BE6\u60C5\uFF08\u5F85\u529E oasis todo show\u3001\u5DE5\u5355 oasis workorder\u3001\u59D4\u6D3E oasis delegate --status\uFF09\uFF0C\u5224\u65AD\u662F\u4E0D\u662F\u540C\u4E00\u4EF6\u4E8B\uFF1B\u786E\u5B9E\u76F8\u5173\u624D\u544A\u8BC9\u7528\u6237\uFF0C\u4E0D\u76F8\u5173\u4E00\u4E2A\u5B57\u90FD\u4E0D\u63D0\uFF1B\u5728\u505A\u7684\u5EFA\u8BAE\u7528\u6237\u5148\u95EE\u95EE\u5BF9\u65B9\uFF0C\u770B\u5408\u5E76\u8FD8\u662F\u5206\u5DE5\uFF1B\u505A\u5B8C\u7684\u628A\u7ED3\u679C\u7ED9\u7528\u6237\uFF0C\u95EE\u80FD\u4E0D\u80FD\u76F4\u63A5\u7528\uFF1B\u4E0D\u66FF\u7528\u6237\u505C\u6389\u8FD9\u6B21\u59D4\u6D3E\u3001\u5408\u5E76\u3001\u53D6\u6D88\u6216\u6539\u6D3E\u3002\u6CA1\u6709\u8FD9\u4E00\u6BB5\u5C31\u662F\u6CA1\u6BD4\u51FA\u6765\uFF0C\u6BD4\u5BF9\u51FA\u4E86\u95EE\u9898\u4E5F\u53EA\u662F\u6CA1\u6709\u8FD9\u4E00\u6BB5\uFF0C\u547D\u4EE4\u7167\u6837\u7B97\u6210\u529F\u3002",
342717
342827
  flags: [
342718
342828
  { name: "to", desc: "\u6D3E\u7ED9\u8C01\uFF1A\u5C97\u4F4D\u540D\u6216 actorId\uFF08\u5C97\u4F4D 0 \u4EBA\u5728\u5C97 / \u7ED1\u5B9A\u4E0D\u53EF\u7528\u4F1A\u5F53\u573A\u62A5\u9519\uFF0C\u90A3\u65F6\u81EA\u5DF1\u505A\uFF09" },
342719
342829
  { name: "task", desc: "\u4EFB\u52A1\u4E66\u5168\u6587\u2014\u2014\u4E13\u5BB6**\u552F\u4E00**\u7684\u4E0A\u4E0B\u6587\u6765\u6E90\uFF0C\u5199\u5168\uFF1B\u4E0D\u8BBE\u957F\u5EA6\u4E0A\u9650\u3001\u4E0D\u622A\u65AD" },
@@ -343813,18 +343923,24 @@ var COMMAND_DECLS = {
343813
343923
  },
343814
343924
  "trace outcome": {
343815
343925
  group: "\u6267\u884C\u8BB0\u5F55\uFF08trace\uFF09",
343816
- usage: "oasis trace outcome <unit> [--json]",
343817
- description: "\u539F\u59CB\u7ED3\u679C\u4FE1\u53F7\uFF08\u72B6\u6001\u3001\u9A8C\u6536\u3001\u8BC4\u5BA1 verdict \u4E0E note\u3001issue\u3001\u8FD4\u5DE5\u3001\u5F3A\u5236\u901A\u8FC7\u3001\u53EB\u505C\u3001\u63D2\u8BDD\u3001\u8FFD\u95EE\u2026\u2026\uFF09\uFF0C\u5E73\u53F0\u4E0D\u4E0B\u7ED3\u8BBA\uFF0C\u6027\u8D28\u7531\u4F60\u5224\u65AD\u3002",
343926
+ usage: "oasis trace outcome <unit> [--full] [--json]",
343927
+ description: "\u539F\u59CB\u7ED3\u679C\u4FE1\u53F7\uFF08\u72B6\u6001\u3001\u9A8C\u6536\u3001\u8BC4\u5BA1 verdict \u4E0E note\u3001issue\u3001\u8FD4\u5DE5\u3001\u5F3A\u5236\u901A\u8FC7\u3001\u53EB\u505C\u3001\u63D2\u8BDD\u3001\u8FFD\u95EE\u2026\u2026\uFF09\uFF0C\u5E73\u53F0\u4E0D\u4E0B\u7ED3\u8BBA\uFF0C\u6027\u8D28\u7531\u4F60\u5224\u65AD\u3002issue / \u63D2\u8BDD / \u8FFD\u95EE\u539F\u6587\u8FC7\u957F\u65F6\u622A\u65AD\u5E76\u5E26 `[\u5DF2\u7701\u7565 N \u5B57 \u2192 oasis trace outcome <unit> --full]`\u3002",
343818
343928
  positional: [{ name: "<unit>", required: true, desc: "\u5355\u5143 id \u6216 run id" }],
343819
- flags: [{ name: "json", desc: "\u8F93\u51FA\u5951\u7EA6 JSON", boolean: true, own: true }],
343929
+ flags: [
343930
+ { name: "full", desc: "\u957F\u6587\u672C\u4E0D\u622A\u65AD", boolean: true, own: true },
343931
+ { name: "json", desc: "\u8F93\u51FA\u5951\u7EA6 JSON", boolean: true, own: true }
343932
+ ],
343820
343933
  examples: ["oasis trace outcome dlg:7f2c"]
343821
343934
  },
343822
343935
  "trace exogenous": {
343823
343936
  group: "\u6267\u884C\u8BB0\u5F55\uFF08trace\uFF09",
343824
- usage: "oasis trace exogenous <unit> [--json]",
343825
- description: "\u5916\u90E8\u56E0\u7D20\u4E8B\u5B9E\uFF1Arun \u8D85\u65F6 / \u88AB\u6740 / \u5931\u8054\u3001\u767B\u5F55\u5931\u6548\u4E0E\u989D\u5EA6\u4E00\u7C7B\u9519\u8BEF\u7801\u3001\u6362\u673A\u3001\u7CFB\u7EDF\u539F\u56E0\u7684\u53EB\u505C\u3001\u534F\u8BAE\u6062\u590D\u3001\u4E0A\u6E38 issue\u3001\u6267\u884C\u671F\u95F4\u9700\u6C42\u53D8\u4E86\u3002\u53CD\u601D\u65F6\u5148\u770B\u5B83\uFF0C\u5C5E\u4E8E\u5916\u90E8\u539F\u56E0\u7684\u6539\u8FDB\u70B9\u6807 category=external\u3002",
343937
+ usage: "oasis trace exogenous <unit> [--full] [--json]",
343938
+ description: "\u5916\u90E8\u56E0\u7D20\u4E8B\u5B9E\uFF1Arun \u8D85\u65F6 / \u88AB\u6740 / \u5931\u8054\u3001\u767B\u5F55\u5931\u6548\u4E0E\u989D\u5EA6\u4E00\u7C7B\u9519\u8BEF\u7801\u3001\u6362\u673A\u3001\u7CFB\u7EDF\u539F\u56E0\u7684\u53EB\u505C\u3001\u534F\u8BAE\u6062\u590D\u3001\u4E0A\u6E38 issue\u3001\u6267\u884C\u671F\u95F4\u9700\u6C42\u53D8\u4E86\u3002\u53CD\u601D\u65F6\u5148\u770B\u5B83\uFF0C\u5C5E\u4E8E\u5916\u90E8\u539F\u56E0\u7684\u6539\u8FDB\u70B9\u6807 category=external\u3002\u9519\u8BEF\u4FE1\u606F\u4E0E issue \u539F\u6587\u8FC7\u957F\u65F6\u622A\u65AD\u5E76\u5E26 `[\u5DF2\u7701\u7565 N \u5B57 \u2192 oasis trace exogenous <unit> --full]`\u3002",
343826
343939
  positional: [{ name: "<unit>", required: true, desc: "\u5355\u5143 id \u6216 run id" }],
343827
- flags: [{ name: "json", desc: "\u8F93\u51FA\u5951\u7EA6 JSON", boolean: true, own: true }],
343940
+ flags: [
343941
+ { name: "full", desc: "\u957F\u6587\u672C\u4E0D\u622A\u65AD", boolean: true, own: true },
343942
+ { name: "json", desc: "\u8F93\u51FA\u5951\u7EA6 JSON", boolean: true, own: true }
343943
+ ],
343828
343944
  examples: ["oasis trace exogenous wk:n-abc:2"]
343829
343945
  },
343830
343946
  "trace runs": {
@@ -344874,6 +344990,7 @@ function buildTraceRequest(sub, positional, flags, now = Date.now()) {
344874
344990
  return { method: "GET", path: `${unitPath("brief")}${qs({ budget: intFlag(flags, "budget", 6e3, 1) })}` };
344875
344991
  case "outcome":
344876
344992
  case "exogenous":
344993
+ return { method: "GET", path: `${unitPath(sub)}${qs({ full: on(flags, "full") ? 1 : void 0 })}` };
344877
344994
  case "runs":
344878
344995
  return { method: "GET", path: unitPath(sub) };
344879
344996
  case "events": {
@@ -345908,7 +346025,7 @@ async function waitForCommandAuthorization(base, headers, draftId, fallback2) {
345908
346025
  }
345909
346026
  }
345910
346027
  }
345911
- var CLI_VERSION = "2.2.124" ? "2.2.124" : "dev";
346028
+ var CLI_VERSION = "2.2.126" ? "2.2.126" : "dev";
345912
346029
  function apiHeaders(token2, company) {
345913
346030
  const headers = {
345914
346031
  authorization: `Bearer ${token2}`,
@@ -346539,8 +346656,8 @@ async function runCli(argv, println = console.log, progressln = console.error) {
346539
346656
  if (!graph) return;
346540
346657
  for (const line2 of renderGraphLines(graph)) println(line2);
346541
346658
  };
346542
- const printOverlap = async (action, text7, subjectId) => {
346543
- if (!text7.trim()) return;
346659
+ const overlapLines = async (action, text7, subjectId) => {
346660
+ if (!text7.trim()) return [];
346544
346661
  try {
346545
346662
  const chatSessionId = process.env["OASIS_CHAT_SESSION_ID"];
346546
346663
  const r5 = await api.request("POST", "/api/overlap/candidates", {
@@ -346549,11 +346666,14 @@ async function runCli(argv, println = console.log, progressln = console.error) {
346549
346666
  ...subjectId ? { subjectId } : {},
346550
346667
  ...chatSessionId ? { chatSessionId } : {}
346551
346668
  }, { timeoutMs: OVERLAP_TIMEOUT_MS });
346552
- if (!r5?.enabled) return;
346553
- for (const line2 of formatOverlapLines(r5, r5.timeZone)) println(line2);
346669
+ return r5?.enabled ? formatOverlapLines(r5, r5.timeZone) : [];
346554
346670
  } catch {
346671
+ return [];
346555
346672
  }
346556
346673
  };
346674
+ const printOverlap = async (action, text7, subjectId) => {
346675
+ for (const line2 of await overlapLines(action, text7, subjectId)) println(line2);
346676
+ };
346557
346677
  if (process.env["OASIS_STAGE"] === "1" && STAGE_COMMANDS.has(command6)) {
346558
346678
  const op2 = buildStageOp(command6, flags, positional, readFileArg);
346559
346679
  const editWs = flags.get("workspace") ?? process.env["OASIS_WORKSPACE"];
@@ -346711,15 +346831,17 @@ ${round.text}`);
346711
346831
  { to, task, ...flags.get("as") ? { as: flags.get("as") } : {}, ...fileArgs.length ? { files: fileArgs } : {} }
346712
346832
  );
346713
346833
  if (asJson2) {
346714
- println(JSON.stringify(started, null, 2));
346834
+ const overlap2 = await overlapLines("delegate", task, started.delegationId);
346835
+ println(JSON.stringify({ ...started, ...overlap2.length ? { overlap: overlap2 } : {} }, null, 2));
346715
346836
  break;
346716
346837
  }
346717
346838
  println(`\u5DF2\u4EA4\u7ED9 ${to} \u53BB\u505A\uFF08\u5F02\u6B65\uFF0C\u4E0D\u7528\u7B49\uFF09\u3002`);
346718
346839
  println(` \u77ED\u540D\uFF08--follow-up \u7528\u8FD9\u4E2A\uFF09\uFF1A${started.label}`);
346719
346840
  println(` delegationId\uFF1A${started.delegationId}`);
346720
346841
  if (started.attachedFiles?.length) println(` \u5E26\u8FC7\u53BB\u7684\u6587\u4EF6\uFF1A${started.attachedFiles.join("\u3001")}`);
346721
- println("\u7ED3\u679C\u5E72\u5B8C\u4E86\u4F1A\u81EA\u5DF1\u56DE\u5230\u8FD9\u6761\u5BF9\u8BDD\u3002\u8FD9\u4E00\u8F6E\u5148\u6536\u5C3E\u2014\u2014\u53EF\u4EE5\u987A\u624B\u8DDF\u7528\u6237\u8BF4\u4E00\u53E5\u4F60\u628A\u8FD9\u4EF6\u4E8B\u6D3E\u51FA\u53BB\u4E86\u3002");
346722
- await printOverlap("delegate", task, started.delegationId);
346842
+ const overlap = await overlapLines("delegate", task, started.delegationId);
346843
+ for (const line2 of overlap) println(line2);
346844
+ println(overlap.length ? "\u7ED3\u679C\u5E72\u5B8C\u4E86\u4F1A\u81EA\u5DF1\u56DE\u5230\u8FD9\u6761\u5BF9\u8BDD\u3002\u6536\u5C3E\u524D\u5148\u6309\u4E0A\u9762\u300C\u76F8\u8FD1\u7684\u4E8B\u9879\u300D\u9010\u6761\u67E5\u5B8C\uFF08\u786E\u5B9E\u76F8\u5173\u624D\u987A\u5E26\u544A\u8BC9\u7528\u6237\uFF09\uFF0C\u7136\u540E\u8FD9\u4E00\u8F6E\u5C31\u6536\u5C3E\u2014\u2014\u4E0D\u7528\u7B49\u4E13\u5BB6\u3002" : "\u7ED3\u679C\u5E72\u5B8C\u4E86\u4F1A\u81EA\u5DF1\u56DE\u5230\u8FD9\u6761\u5BF9\u8BDD\u3002\u8FD9\u4E00\u8F6E\u5148\u6536\u5C3E\u2014\u2014\u53EF\u4EE5\u987A\u624B\u8DDF\u7528\u6237\u8BF4\u4E00\u53E5\u4F60\u628A\u8FD9\u4EF6\u4E8B\u6D3E\u51FA\u53BB\u4E86\u3002");
346723
346845
  break;
346724
346846
  }
346725
346847
  case "kb": {
@@ -350217,7 +350339,7 @@ function shimScript() {
350217
350339
  }
350218
350340
 
350219
350341
  // src/index.ts
350220
- var PKG_VERSION = true ? "2.2.124" : "dev";
350342
+ var PKG_VERSION = true ? "2.2.126" : "dev";
350221
350343
  var LOCAL_BIN = localBin();
350222
350344
  var NPM_PREFIX = npmPrefix();
350223
350345
  var INSTANCE = DEFAULT_INSTANCE;