oasis_test_v2 2.2.125 → 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 +777 -666
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -1778,6 +1778,14 @@ var init_overlap = __esm({
1778
1778
  "\u4E4B\u540E",
1779
1779
  "\u4EE5\u524D",
1780
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",
1781
1789
  "the",
1782
1790
  "and",
1783
1791
  "for",
@@ -1787,7 +1795,10 @@ var init_overlap = __esm({
1787
1795
  "that",
1788
1796
  "into",
1789
1797
  "todo",
1790
- "task"
1798
+ "task",
1799
+ "markdown",
1800
+ "outputs",
1801
+ "md"
1791
1802
  ]);
1792
1803
  isCjk = (ch) => /[㐀-鿿豈-﫿]/u.test(ch);
1793
1804
  COVER_MIN_SHARED = 3;
@@ -237390,6 +237401,16 @@ async function listSkillMetadataForActor(args) {
237390
237401
  }
237391
237402
  return out;
237392
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
+ }
237393
237414
  function builtinSkillToFiles(b6) {
237394
237415
  return Object.entries(b6.files ?? {}).map(([path50, content3]) => ({
237395
237416
  skillId: `builtin:${b6.id}`,
@@ -238897,14 +238918,11 @@ function actorsDomain(opts) {
238897
238918
  const { service } = await resolveCtx(req.auth.companyId);
238898
238919
  const claim = req.auth.dispatch?.chatSessionId ? { chatSessionId: req.auth.dispatch.chatSessionId, companyId: req.auth.companyId } : void 0;
238899
238920
  const builtins = await opts.getBuiltinSkills?.(claim) ?? [];
238900
- const connectorSkills = opts.getConnectorSkills?.() ?? [];
238901
- const enabledConnectors = connectorSkills.length > 0 ? await service.effectiveEnabledConnectors(req.auth.actor) : /* @__PURE__ */ new Set();
238902
- const items = await listSkillMetadataForActor({
238921
+ const items = await skillManifestForActor({
238903
238922
  service,
238904
238923
  actorId: req.auth.actor,
238905
238924
  builtins,
238906
- connectorSkills,
238907
- enabledConnectors
238925
+ connectorSkills: opts.getConnectorSkills?.() ?? []
238908
238926
  });
238909
238927
  return { status: 200, body: { items } };
238910
238928
  });
@@ -255147,6 +255165,562 @@ var init_renderer = __esm({
255147
255165
  }
255148
255166
  });
255149
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
+
255150
255724
  // ../server/src/domains/trace/units.ts
255151
255725
  function splitSegments(turns, gapMs = SEGMENT_IDLE_GAP_MS) {
255152
255726
  const sorted = [...turns].sort((a5, b6) => {
@@ -255241,6 +255815,23 @@ function parseSince(since, nowMs) {
255241
255815
  if (!Number.isFinite(t)) throw new RangeError(`--since \u4E0D\u5408\u6CD5\uFF1A${since}\uFF08\u8981 ISO \u65F6\u95F4\u6216 7d / 12h / 30m\uFF09`);
255242
255816
  return new Date(t).toISOString();
255243
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
+ }
255244
255835
  function memo(map3, key2, fn) {
255245
255836
  let p4 = map3.get(key2);
255246
255837
  if (!p4) {
@@ -255265,11 +255856,13 @@ function metaString(meta, key2) {
255265
255856
  }
255266
255857
  return null;
255267
255858
  }
255268
- 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;
255269
255860
  var init_units = __esm({
255270
255861
  "../server/src/domains/trace/units.ts"() {
255271
255862
  "use strict";
255272
255863
  init_src();
255864
+ init_unit_data();
255865
+ init_renderer();
255273
255866
  SEG_TURN_CAP = 2e3;
255274
255867
  RUN_PAGE = 200;
255275
255868
  RUN_CAP = 2e3;
@@ -255277,7 +255870,9 @@ var init_units = __esm({
255277
255870
  MAX_CHAIN_NODES = 200;
255278
255871
  MESSAGE_CAP = 1e3;
255279
255872
  SIGNAL_TEXT_CAP = 2e3;
255873
+ EXOGENOUS_TEXT_CAP = 500;
255280
255874
  FIND_DEFAULT_LIMIT = 20;
255875
+ FIND_BATCH_MAX = 200;
255281
255876
  FIND_MAX_LIMIT = 200;
255282
255877
  RUN_ROW_CAP = 50;
255283
255878
  TURN_TERMINAL = /* @__PURE__ */ new Set(["succeeded", "failed", "cancelled", "orphaned"]);
@@ -255326,11 +255921,12 @@ var init_units = __esm({
255326
255921
  async evidenceScope(unitId, maxHop) {
255327
255922
  return this.reader().evidenceScope(unitId, maxHop);
255328
255923
  }
255329
- async outcome(unitId) {
255330
- return this.reader().outcome(unitId);
255924
+ /** `full`:长文本不截(`oasis trace outcome <unit> --full`,即截断标记里给的取回命令)。 */
255925
+ async outcome(unitId, opts = {}) {
255926
+ return this.reader().outcome(unitId, opts);
255331
255927
  }
255332
- async exogenous(unitId) {
255333
- return this.reader().exogenous(unitId);
255928
+ async exogenous(unitId, opts = {}) {
255929
+ return this.reader().exogenous(unitId, opts);
255334
255930
  }
255335
255931
  async peers(unitId, limit) {
255336
255932
  return this.reader().peers(unitId, limit);
@@ -255341,7 +255937,9 @@ var init_units = __esm({
255341
255937
  };
255342
255938
  unitTypeOf = (u) => u.kind === "work" || u.kind === "review" ? "work" : u.kind === "delegation" ? "delegation" : "chat";
255343
255939
  segId = (sessionId, firstTurnId) => `seg:${sessionId}:${firstTurnId}`;
255344
- 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`;
255345
255943
  UnitReader = class {
255346
255944
  constructor(deps) {
255347
255945
  this.deps = deps;
@@ -255590,7 +256188,7 @@ var init_units = __esm({
255590
256188
  const ended = reviewEnded(u.review);
255591
256189
  return {
255592
256190
  ended,
255593
- endedAt: ended ? u.review.endedAt ?? u.review.decidedAt ?? u.review.createdAt : null,
256191
+ endedAt: ended ? unitListKey.review(u.review).at : null,
255594
256192
  startedAt: u.review.startedAt ?? u.review.createdAt,
255595
256193
  actorId: u.review.reviewerActorId,
255596
256194
  cursor: u.unitId,
@@ -255646,14 +256244,16 @@ var init_units = __esm({
255646
256244
  async find(q4) {
255647
256245
  const limit = Math.max(1, Math.min(FIND_MAX_LIMIT, Math.floor(q4.limit ?? FIND_DEFAULT_LIMIT)));
255648
256246
  const sinceIso = parseSince(q4.since, this.nowMs);
255649
- const fetchN = limit * 3;
256247
+ const batch = Math.min(FIND_BATCH_MAX, limit * 3);
255650
256248
  const wants = (t) => !q4.type || q4.type === t;
255651
- const cands = [];
256249
+ const base = { ...sinceIso ? { sinceIso } : {}, ...q4.actor ? { actorId: q4.actor } : {} };
256250
+ const sources = [];
255652
256251
  if (wants("work")) {
255653
- const works = await this.data.listEndedWorks({ ...sinceIso ? { sinceIso } : {}, ...q4.actor ? { actorId: q4.actor } : {}, limit: fetchN });
255654
- for (const w2 of works) {
255655
- if (!workEnded(w2)) continue;
255656
- 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) ? [{
255657
256257
  unitId: w2.id,
255658
256258
  type: "work",
255659
256259
  endedAt: w2.endedAt ?? w2.deadAt,
@@ -255661,69 +256261,81 @@ var init_units = __esm({
255661
256261
  sessionId: null,
255662
256262
  cursor: w2.id,
255663
256263
  load: async () => this.cacheUnit({ kind: "work", unitId: w2.id, work: w2 })
255664
- });
255665
- }
255666
- const reviews = await this.data.listEndedReviews({ ...sinceIso ? { sinceIso } : {}, ...q4.actor ? { actorId: q4.actor } : {}, limit: fetchN });
255667
- for (const r5 of reviews) {
255668
- if (!reviewEnded(r5)) continue;
255669
- 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) ? [{
255670
256271
  unitId: r5.id,
255671
256272
  type: "work",
255672
- endedAt: r5.endedAt ?? r5.decidedAt ?? r5.createdAt,
256273
+ endedAt: unitListKey.review(r5).at,
255673
256274
  actorId: r5.reviewerActorId,
255674
256275
  sessionId: null,
255675
256276
  cursor: r5.id,
255676
256277
  load: async () => this.cacheUnit({ kind: "review", unitId: r5.id, review: r5 })
255677
- });
255678
- }
256278
+ }] : []
256279
+ ));
255679
256280
  }
255680
256281
  if (wants("delegation")) {
255681
- const dlgs = await this.data.listEndedDelegations({ ...sinceIso ? { sinceIso } : {}, ...q4.actor ? { actorId: q4.actor } : {}, limit: fetchN });
255682
- for (const d5 of dlgs) {
255683
- if (!delegationEnded(d5)) continue;
255684
- const unitId = `dlg:${d5.id}`;
255685
- cands.push({
255686
- unitId,
255687
- type: "delegation",
255688
- endedAt: d5.settledAt ?? d5.createdAt,
255689
- actorId: d5.expertActorId,
255690
- sessionId: null,
255691
- cursor: delegationCursor(d5),
255692
- load: async () => this.cacheUnit({ kind: "delegation", unitId, dlg: d5 })
255693
- });
255694
- }
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
+ ));
255695
256300
  }
255696
256301
  if (wants("chat")) {
255697
256302
  const excluded = new Set(!q4.includeMeta && this.deps.reflectorSessionIds ? await this.deps.reflectorSessionIds() : []);
255698
- const sessions = await this.data.listRecentSessions({
255699
- ...sinceIso ? { sinceIso } : {},
255700
- ...q4.actor ? { aiActorId: q4.actor } : {},
255701
- includeAnalysis: q4.includeMeta === true,
255702
- limit: fetchN
255703
- });
255704
- for (const s3 of sessions) {
255705
- if (excluded.has(s3.id)) continue;
255706
- const ss = await this.sessionSegments(s3.id);
255707
- if (!ss) continue;
255708
- for (let i5 = 0; i5 < ss.segments.length; i5++) {
255709
- const seg = ss.segments[i5];
255710
- if (!segmentEnded(seg, i5 < ss.segments.length - 1, this.nowMs)) continue;
255711
- const endedAt = turnEnd(seg.turns[seg.turns.length - 1]);
255712
- if (sinceIso && ms(endedAt) < ms(sinceIso)) continue;
255713
- const idx = i5;
255714
- cands.push({
255715
- unitId: segId(s3.id, seg.firstTurnId),
255716
- type: "chat",
255717
- endedAt,
255718
- actorId: s3.aiActorId,
255719
- sessionId: s3.id,
255720
- cursor: seg.lastTurnId,
255721
- load: () => this.segmentUnit(ss, idx)
255722
- });
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;
255723
256336
  }
255724
- }
256337
+ ));
255725
256338
  }
255726
- cands.sort((a5, b6) => ms(b6.endedAt) - ms(a5.endedAt) || (a5.unitId < b6.unitId ? 1 : -1));
255727
256339
  const roleCache = /* @__PURE__ */ new Map();
255728
256340
  const roleOk = async (actorId) => {
255729
256341
  if (!q4.role) return true;
@@ -255732,22 +256344,34 @@ var init_units = __esm({
255732
256344
  const roles = await memo(roleCache, actorId, () => fn(actorId)) ?? "";
255733
256345
  return roles.split(",").map((r5) => r5.trim()).includes(q4.role);
255734
256346
  };
255735
- const reflected = this.deps.reflectedCursors ? await this.deps.reflectedCursors(cands.map((c5) => c5.unitId)) : /* @__PURE__ */ new Map();
255736
256347
  const out = [];
255737
- let built = 0;
255738
- for (const c5 of cands) {
255739
- if (out.length >= limit || built >= limit * 5) break;
255740
- if (!await roleOk(c5.actorId)) continue;
255741
- if (q4.unreflected && (reflected.get(c5.unitId) ?? []).some((r5) => cursorCovers(r5, c5.cursor, c5.type))) continue;
255742
- const u = await c5.load();
255743
- if (!u) continue;
255744
- built++;
255745
- const s3 = await this.summary(u, reflected);
255746
- if (!s3.ended) continue;
255747
- if (q4.outcome && s3.outcome !== q4.outcome) continue;
255748
- 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());
255749
256374
  }
255750
- return out;
255751
256375
  }
255752
256376
  cacheUnit(u) {
255753
256377
  if (!this.units.has(u.unitId)) this.units.set(u.unitId, Promise.resolve(u));
@@ -255948,9 +256572,10 @@ var init_units = __esm({
255948
256572
  return { runHop, nodes: nodes5 };
255949
256573
  }
255950
256574
  /* ── outcome ── */
255951
- async outcome(unitId) {
256575
+ async outcome(unitId, opts = {}) {
255952
256576
  const u = await this.mustLoad(unitId);
255953
256577
  const signals = {};
256578
+ const field = (s3) => clipField(s3, outcomeFetchCmd(u.unitId), opts.full === true);
255954
256579
  switch (u.kind) {
255955
256580
  case "work": {
255956
256581
  const w2 = u.work;
@@ -255977,8 +256602,7 @@ var init_units = __esm({
255977
256602
  decidedAt: r5.decidedAt
255978
256603
  }));
255979
256604
  signals["issues"] = (await this.data.issuesInWorkorder(w2.workorderId, { aboutWorkIds: [w2.id], limit: 100 })).map((i5) => {
255980
- const b6 = clip4(i5.body);
255981
- 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) };
255982
256606
  });
255983
256607
  signals["reworkedBy"] = await this.data.reworkedBy(w2);
255984
256608
  break;
@@ -256024,16 +256648,16 @@ var init_units = __esm({
256024
256648
  const inter = await this.segmentInterjections(u);
256025
256649
  signals["interjections"] = [...inter].map(([turnId, msgs]) => ({
256026
256650
  turnId,
256027
- messages: msgs.map((m4) => {
256028
- const c5 = clip4(m4.content);
256029
- return { messageId: m4.id, at: m4.at, text: c5.text, chars: c5.chars };
256030
- })
256651
+ messages: msgs.map((m4) => ({ messageId: m4.id, at: m4.at, body: field(m4.content) }))
256031
256652
  }));
256032
256653
  const endIso = new Date(last.completedAt ? ms(last.completedAt) : this.nowMs).toISOString();
256033
- signals["pending"] = (await this.data.pendingMessagesOf(u.session.id, u.seg.turns[0].reservedAt, endIso, 200)).map((p4) => {
256034
- const c5 = clip4(p4.text);
256035
- return { id: p4.id, at: p4.createdAt, state: p4.state, flavour: p4.flavour, text: c5.text, chars: c5.chars };
256036
- });
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
+ }));
256037
256661
  break;
256038
256662
  }
256039
256663
  }
@@ -256048,9 +256672,10 @@ var init_units = __esm({
256048
256672
  }
256049
256673
  return out;
256050
256674
  }
256051
- async exogenous(unitId) {
256675
+ async exogenous(unitId, opts = {}) {
256052
256676
  const u = await this.mustLoad(unitId);
256053
256677
  const facts = [];
256678
+ const field = (s3) => clipField(s3, exogenousFetchCmd(u.unitId), opts.full === true, EXOGENOUS_TEXT_CAP);
256054
256679
  const runs = await this.runRows(await this.runIdsOf(u));
256055
256680
  for (const r5 of runs) {
256056
256681
  const abnormal = EXOGENOUS_RUN_STATUS.has(r5.status);
@@ -256060,7 +256685,7 @@ var init_units = __esm({
256060
256685
  at: r5.endedAt ?? r5.startedAt,
256061
256686
  runId: r5.id,
256062
256687
  summary: `run ${r5.id} \u72B6\u6001 ${r5.status}${r5.exitReason ? `\uFF0Cexit_reason=${r5.exitReason}` : ""}${r5.errorCode ? `\uFF0Cerror_code=${r5.errorCode}` : ""}`,
256063
- 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 }
256064
256689
  });
256065
256690
  }
256066
256691
  const instances = [...new Set(runs.map((r5) => r5.runtimeInstanceId).filter((x2) => !!x2))];
@@ -256103,11 +256728,11 @@ var init_units = __esm({
256103
256728
  });
256104
256729
  }
256105
256730
  }
256106
- if (u.kind === "work") facts.push(...await this.upstreamFacts(u.work));
256731
+ if (u.kind === "work") facts.push(...await this.upstreamFacts(u.work, field));
256107
256732
  return facts;
256108
256733
  }
256109
256734
  /** 单元时间窗里上游(输入节点、brief)收到的 issue、出的新版本。 */
256110
- async upstreamFacts(w2) {
256735
+ async upstreamFacts(w2, field) {
256111
256736
  const out = [];
256112
256737
  const from = w2.startedAt ?? w2.createdAt;
256113
256738
  const to = w2.endedAt ?? w2.deadAt ?? new Date(this.nowMs).toISOString();
@@ -256119,13 +256744,13 @@ var init_units = __esm({
256119
256744
  if (nodes5.size === 0) return out;
256120
256745
  const nodeIds = [...nodes5];
256121
256746
  for (const i5 of await this.data.issuesInWorkorder(w2.workorderId, { aboutNodeIds: nodeIds, fromIso: from, toIso: to, limit: 50 })) {
256122
- const b6 = clip4(i5.body, 500);
256747
+ const b6 = field(i5.body);
256123
256748
  out.push({
256124
256749
  kind: "upstream-issue",
256125
256750
  at: i5.createdAt,
256126
256751
  runId: null,
256127
256752
  summary: `\u6267\u884C\u671F\u95F4\u4E0A\u6E38\u8282\u70B9 ${i5.aboutNodeId} \u6536\u5230 ${i5.kind}\uFF1A${b6.text.split("\n")[0]}`,
256128
- 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 }
256129
256754
  });
256130
256755
  }
256131
256756
  for (const x2 of await this.data.worksAcceptedInWindow(nodeIds, from, to, 50)) {
@@ -256548,12 +257173,13 @@ function reflectionDomain(opts) {
256548
257173
  router.get("/api/traces/units/:unit/outcome", async (req) => {
256549
257174
  const d5 = await deps(req);
256550
257175
  const u = await requireUnit(d5, req.params.unit);
256551
- 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) };
256552
257177
  });
256553
257178
  router.get("/api/traces/units/:unit/exogenous", async (req) => {
256554
257179
  const d5 = await deps(req);
256555
257180
  const u = await requireUnit(d5, req.params.unit);
256556
- 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 } };
256557
257183
  });
256558
257184
  router.get("/api/traces/units/:unit/runs", async (req) => {
256559
257185
  const d5 = await deps(req);
@@ -257714,546 +258340,6 @@ var init_reflection_service = __esm({
257714
258340
  }
257715
258341
  });
257716
258342
 
257717
- // ../server/src/domains/trace/unit-data.ts
257718
- function quoteSchema(name) {
257719
- if (!/^[A-Za-z0-9_][A-Za-z0-9_.-]*$/.test(name)) throw new Error(`invalid schema name: ${name}`);
257720
- return `"${name}"`;
257721
- }
257722
- function dispatchSchemaIdent(name) {
257723
- const s3 = name.replace(/[^a-zA-Z0-9_]/g, "");
257724
- if (!s3) throw new Error(`invalid dispatch schema name: ${name}`);
257725
- return `"${s3}"`;
257726
- }
257727
- function replyIssueIdFromWorkId(workId) {
257728
- const m4 = /^wk:reply:(.+):\d+$/.exec(workId);
257729
- return m4 ? m4[1] : null;
257730
- }
257731
- function toWork(r5) {
257732
- return {
257733
- id: String(r5["id"]),
257734
- workorderId: String(r5["workorder_id"]),
257735
- nodeId: String(r5["node_id"]),
257736
- nodeType: str5(r5["node_type"]),
257737
- nodeTitle: str5(r5["node_title"]),
257738
- assigneeActorId: String(r5["assignee_actor_id"]),
257739
- createdAt: isoReq(r5["created_at"]),
257740
- startedAt: iso4(r5["started_at"]),
257741
- endedAt: iso4(r5["ended_at"]),
257742
- deadAt: iso4(r5["dead_at"]),
257743
- status: str5(r5["status"]),
257744
- outcome: str5(r5["outcome"]),
257745
- // 存量 lane 为空时按 work id 前缀兜底(回信轮 id 恒为 `wk:reply:<issueId>:<n>`)。
257746
- lane: r5["lane"] === "reply" || r5["lane"] == null && String(r5["id"]).startsWith("wk:reply:") ? "reply" : "main",
257747
- replyIssueId: replyIssueIdFromWorkId(String(r5["id"])),
257748
- continuesWorkId: str5(r5["continues_work_id"]),
257749
- acceptanceState: str5(r5["acceptance_state"]) ?? null,
257750
- acceptedAt: iso4(r5["accepted_at"]),
257751
- rejectedReason: str5(r5["rejected_reason"]),
257752
- overrideBy: str5(r5["override_by"]),
257753
- overrideReason: str5(r5["override_reason"]),
257754
- frozenIssueIds: strArr(r5["frozen_issue_ids"]),
257755
- protocolRecovery: r5["protocol_recovery"] ?? null,
257756
- killSource: str5(r5["kill_source"]),
257757
- outputVersionNo: num3(r5["output_version_no"])
257758
- };
257759
- }
257760
- function toReview(r5) {
257761
- const verdict = str5(r5["verdict"]);
257762
- let status = str5(r5["status"]);
257763
- if (!status) {
257764
- if (r5["retry_at"] != null) status = "retry";
257765
- else if (r5["cancelled_at"] != null) status = "dead";
257766
- else if (verdict === "approve" && r5["decided_at"] != null) status = "accept";
257767
- else if (verdict === "request_changes" && r5["decided_at"] != null) status = "reject";
257768
- else if (r5["ended_at"] != null) status = verdict ? verdict === "approve" ? "accept" : "reject" : "failed";
257769
- else status = "running";
257770
- }
257771
- return {
257772
- id: String(r5["id"]),
257773
- workorderId: String(r5["workorder_id"]),
257774
- nodeId: String(r5["node_id"]),
257775
- nodeTitle: str5(r5["node_title"]),
257776
- targetWorkId: String(r5["target_work_id"]),
257777
- reviewerActorId: String(r5["reviewer_actor_id"]),
257778
- reviewGroup: String(r5["review_group"] ?? ""),
257779
- status,
257780
- verdict: verdict ?? null,
257781
- note: str5(r5["note"]),
257782
- createdAt: isoReq(r5["created_at"]),
257783
- startedAt: iso4(r5["started_at"]),
257784
- endedAt: iso4(r5["ended_at"]),
257785
- decidedAt: iso4(r5["decided_at"]),
257786
- killSource: str5(r5["kill_source"])
257787
- };
257788
- }
257789
- function toIssue(r5) {
257790
- return {
257791
- id: String(r5["id"]),
257792
- workorderId: String(r5["workorder_id"]),
257793
- kind: String(r5["kind"]),
257794
- body: String(r5["body"] ?? ""),
257795
- aboutNodeId: str5(r5["about_node_id"]),
257796
- aboutWorkId: str5(r5["about_work_id"]),
257797
- raisedByNodeId: str5(r5["raised_by_node_id"]),
257798
- authorActorId: String(r5["author_actor_id"]),
257799
- resolvedAt: iso4(r5["resolved_at"]),
257800
- createdAt: isoReq(r5["created_at"])
257801
- };
257802
- }
257803
- function toDispatch(r5) {
257804
- return {
257805
- id: String(r5["id"]),
257806
- targetKind: String(r5["target_kind"]),
257807
- targetId: String(r5["target_id"]),
257808
- actorId: str5(r5["actor_id"]),
257809
- createdAt: isoReq(r5["created_at"]),
257810
- startedAt: iso4(r5["started_at"]),
257811
- endedAt: iso4(r5["ended_at"]),
257812
- outcome: str5(r5["outcome"]),
257813
- reason: str5(r5["reason"]),
257814
- protocolRecoveryRound: num3(r5["protocol_recovery_round"])
257815
- };
257816
- }
257817
- function toDelegation(r5) {
257818
- return {
257819
- id: String(r5["id"]),
257820
- parentSessionId: String(r5["parent_session_id"]),
257821
- parentMessageId: String(r5["parent_message_id"] ?? ""),
257822
- childSessionId: String(r5["child_session_id"]),
257823
- expertActorId: String(r5["expert_actor_id"]),
257824
- state: String(r5["state"]),
257825
- failureKind: str5(r5["failure_kind"]),
257826
- failureReason: str5(r5["failure_reason"]),
257827
- consecutiveFails: num3(r5["consecutive_fails"]) ?? 0,
257828
- dispatchSeq: num3(r5["dispatch_seq"]),
257829
- createdAt: isoReq(r5["created_at"]),
257830
- settledAt: iso4(r5["settled_at"]),
257831
- label: str5(r5["label"]),
257832
- taskDigest: str5(r5["task_digest"])
257833
- };
257834
- }
257835
- function toSession(r5) {
257836
- return {
257837
- id: String(r5["id"]),
257838
- humanActorId: String(r5["human_actor_id"]),
257839
- aiActorId: String(r5["ai_actor_id"]),
257840
- title: str5(r5["title"]),
257841
- analyzedRunId: str5(r5["analyzed_run_id"]),
257842
- runtimeSessionId: str5(r5["runtime_session_id"]),
257843
- touchedAt: isoReq(r5["touched_at"]),
257844
- createdAt: isoReq(r5["created_at"])
257845
- };
257846
- }
257847
- function toTurn(r5) {
257848
- return {
257849
- id: String(r5["id"]),
257850
- chatSessionId: String(r5["chat_session_id"]),
257851
- source: String(r5["source"]),
257852
- status: String(r5["status"]),
257853
- reservedAt: isoReq(r5["reserved_at"]),
257854
- startedAt: iso4(r5["started_at"]),
257855
- completedAt: iso4(r5["completed_at"]),
257856
- cancelledBy: str5(r5["cancelled_by"]),
257857
- dispatchId: str5(r5["dispatch_id"]),
257858
- assistantRunId: str5(r5["assistant_run_id"])
257859
- };
257860
- }
257861
- function toMessage(r5) {
257862
- return {
257863
- id: String(r5["id"]),
257864
- sessionId: String(r5["session_id"]),
257865
- role: String(r5["role"]),
257866
- content: String(r5["content"] ?? ""),
257867
- seq: Number(r5["seq"]),
257868
- createdAt: isoReq(r5["created_at"]),
257869
- runId: str5(r5["run_id"]),
257870
- turnId: str5(r5["turn_id"]),
257871
- source: str5(r5["source"])
257872
- };
257873
- }
257874
- function toLink(r5) {
257875
- return { sessionId: String(r5["session_id"]), workOrderId: String(r5["work_order_id"]), linkedAt: isoReq(r5["linked_at"]) };
257876
- }
257877
- var iso4, isoReq, str5, num3, strArr, WORK_COLS, REVIEW_COLS, MAX_IDS, capIds, PgUnitDataSource;
257878
- var init_unit_data = __esm({
257879
- "../server/src/domains/trace/unit-data.ts"() {
257880
- "use strict";
257881
- iso4 = (v2) => v2 == null ? null : v2 instanceof Date ? v2.toISOString() : typeof v2 === "string" ? new Date(v2).toISOString() : null;
257882
- isoReq = (v2) => iso4(v2) ?? (/* @__PURE__ */ new Date(0)).toISOString();
257883
- str5 = (v2) => typeof v2 === "string" ? v2 : v2 == null ? null : String(v2);
257884
- num3 = (v2) => v2 == null ? null : Number.isFinite(Number(v2)) ? Number(v2) : null;
257885
- strArr = (v2) => Array.isArray(v2) ? v2.filter((x2) => typeof x2 === "string") : [];
257886
- WORK_COLS = `w.id, w.workorder_id, w.node_id, n.type AS node_type, n.title AS node_title, w.assignee_actor_id,
257887
- w.created_at, w.started_at, w.ended_at, w.dead_at, w.status, w.outcome, w.lane, w.continues_work_id,
257888
- w.acceptance_state, w.accepted_at, w.rejected_reason, w.override_by, w.override_reason, w.frozen_issue_ids,
257889
- w.protocol_recovery, w.kill_source, w.output_version_no`;
257890
- 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,
257891
- 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`;
257892
- MAX_IDS = 500;
257893
- capIds = (ids2) => [...new Set(ids2)].slice(0, MAX_IDS);
257894
- PgUnitDataSource = class {
257895
- pool;
257896
- /** 引擎 schema(works / reviews / issues / events / workflow_*)。 */
257897
- e;
257898
- /** chat 一族(chat_sessions / chat_messages / chat_session_turns / 委派);缺省与引擎同 schema。 */
257899
- c;
257900
- /** 派发台账 schema(按 dispatches store 的口径净化)。 */
257901
- d;
257902
- constructor(opts) {
257903
- this.pool = opts.pool;
257904
- this.e = quoteSchema(opts.engineSchema);
257905
- this.c = quoteSchema(opts.chatSchema ?? opts.engineSchema);
257906
- this.d = dispatchSchemaIdent(opts.dispatchSchema);
257907
- }
257908
- async q(text7, values = []) {
257909
- return (await this.pool.query(text7, values)).rows;
257910
- }
257911
- /* ── work / review ── */
257912
- async getWorks(ids2) {
257913
- if (ids2.length === 0) return [];
257914
- const rows = await this.q(
257915
- `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)`,
257916
- [capIds(ids2)]
257917
- );
257918
- return rows.map(toWork);
257919
- }
257920
- async getReview(id) {
257921
- const rows = await this.q(
257922
- `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`,
257923
- [id]
257924
- );
257925
- return rows[0] ? toReview(rows[0]) : null;
257926
- }
257927
- async reviewsOfWorks(workIds) {
257928
- if (workIds.length === 0) return [];
257929
- const rows = await this.q(
257930
- `SELECT ${REVIEW_COLS} FROM ${this.e}.reviews r LEFT JOIN ${this.e}.workflow_nodes n ON n.id = r.node_id
257931
- WHERE r.target_work_id = ANY($1) ORDER BY r.created_at ASC, r.id ASC LIMIT 500`,
257932
- [capIds(workIds)]
257933
- );
257934
- return rows.map(toReview);
257935
- }
257936
- async worksOfNode(nodeId, limit) {
257937
- const rows = await this.q(
257938
- `SELECT ${WORK_COLS} FROM ${this.e}.works w LEFT JOIN ${this.e}.workflow_nodes n ON n.id = w.node_id
257939
- WHERE w.node_id = $1 ORDER BY w.created_at DESC, w.id DESC LIMIT $2`,
257940
- [nodeId, limit]
257941
- );
257942
- return rows.map(toWork);
257943
- }
257944
- async workInputsOf(workIds) {
257945
- if (workIds.length === 0) return [];
257946
- const rows = await this.q(
257947
- `SELECT work_id, upstream_node_id, upstream_work_id FROM ${this.e}.work_inputs WHERE work_id = ANY($1) LIMIT 2000`,
257948
- [capIds(workIds)]
257949
- );
257950
- return rows.map((r5) => ({
257951
- workId: String(r5["work_id"]),
257952
- upstreamNodeId: String(r5["upstream_node_id"]),
257953
- upstreamWorkId: String(r5["upstream_work_id"])
257954
- }));
257955
- }
257956
- async inputNodesOf(nodeId) {
257957
- const rows = await this.q(
257958
- `SELECT from_node_id FROM ${this.e}.workflow_edges WHERE to_node_id = $1 AND kind = 'data' ORDER BY from_node_id LIMIT 100`,
257959
- [nodeId]
257960
- );
257961
- return rows.map((r5) => String(r5["from_node_id"]));
257962
- }
257963
- async outputNodesOf(nodeId) {
257964
- const rows = await this.q(
257965
- `SELECT to_node_id FROM ${this.e}.workflow_edges WHERE from_node_id = $1 AND kind = 'data' ORDER BY to_node_id LIMIT 100`,
257966
- [nodeId]
257967
- );
257968
- return rows.map((r5) => String(r5["to_node_id"]));
257969
- }
257970
- async latestAcceptedWorkOfNodeBefore(nodeId, beforeIso) {
257971
- const rows = await this.q(
257972
- `SELECT ${WORK_COLS} FROM ${this.e}.works w LEFT JOIN ${this.e}.workflow_nodes n ON n.id = w.node_id
257973
- WHERE w.node_id = $1 AND w.acceptance_state = 'accepted' AND w.accepted_at IS NOT NULL AND w.accepted_at <= $2
257974
- ORDER BY w.accepted_at DESC, w.id DESC LIMIT 1`,
257975
- [nodeId, beforeIso]
257976
- );
257977
- return rows[0] ? toWork(rows[0]) : null;
257978
- }
257979
- async worksAcceptedInWindow(nodeIds, fromIso, toIso2, limit) {
257980
- if (nodeIds.length === 0) return [];
257981
- const rows = await this.q(
257982
- `SELECT ${WORK_COLS} FROM ${this.e}.works w LEFT JOIN ${this.e}.workflow_nodes n ON n.id = w.node_id
257983
- WHERE w.node_id = ANY($1) AND w.acceptance_state = 'accepted' AND w.accepted_at >= $2 AND w.accepted_at <= $3
257984
- ORDER BY w.accepted_at ASC, w.id ASC LIMIT $4`,
257985
- [capIds(nodeIds), fromIso, toIso2, limit]
257986
- );
257987
- return rows.map(toWork);
257988
- }
257989
- async reworkSourcesOf(work) {
257990
- const rows = await this.q(
257991
- `SELECT DISTINCT x.reason->>'workId' AS src
257992
- FROM (SELECT payload FROM ${this.e}.events
257993
- WHERE node_id = $1 AND kind = 'work.create' AND payload->>'workId' = $2
257994
- ORDER BY seq DESC LIMIT 20) ev,
257995
- LATERAL jsonb_array_elements(COALESCE(ev.payload->'reasons', '[]'::jsonb)) AS x(reason)
257996
- WHERE x.reason->>'kind' = 'rework' AND x.reason->>'workId' IS NOT NULL`,
257997
- [work.nodeId, work.id]
257998
- );
257999
- return rows.map((r5) => String(r5["src"]));
258000
- }
258001
- async reworkedBy(work) {
258002
- const viaCol = await this.q(
258003
- `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`,
258004
- [work.nodeId, work.id]
258005
- );
258006
- const viaEvents = await this.q(
258007
- `SELECT DISTINCT ev.payload->>'workId' AS wid
258008
- FROM (SELECT payload FROM ${this.e}.events WHERE node_id = $1 AND kind = 'work.create' ORDER BY seq DESC LIMIT 200) ev,
258009
- LATERAL jsonb_array_elements(COALESCE(ev.payload->'reasons', '[]'::jsonb)) AS x(reason)
258010
- WHERE x.reason->>'kind' = 'rework' AND x.reason->>'workId' = $2`,
258011
- [work.nodeId, work.id]
258012
- );
258013
- const out = /* @__PURE__ */ new Set();
258014
- for (const r5 of viaCol) out.add(String(r5["id"]));
258015
- for (const r5 of viaEvents) if (r5["wid"] != null && r5["wid"] !== work.id) out.add(String(r5["wid"]));
258016
- return [...out];
258017
- }
258018
- async briefNodesOf(workorderId) {
258019
- const rows = await this.q(
258020
- `SELECT id FROM ${this.e}.workflow_nodes WHERE workorder_id = $1 AND type = 'brief' ORDER BY created_at ASC LIMIT 10`,
258021
- [workorderId]
258022
- );
258023
- return rows.map((r5) => String(r5["id"]));
258024
- }
258025
- /* ── issue ── */
258026
- async issuesByIds(ids2) {
258027
- if (ids2.length === 0) return [];
258028
- const rows = await this.q(`SELECT * FROM ${this.e}.issues WHERE id = ANY($1)`, [capIds(ids2)]);
258029
- return rows.map(toIssue);
258030
- }
258031
- async issuesInWorkorder(workorderId, q4) {
258032
- const args = [workorderId];
258033
- const conds = ["workorder_id = $1"];
258034
- const ors = [];
258035
- const push2 = (v2) => {
258036
- args.push(v2);
258037
- return `$${args.length}`;
258038
- };
258039
- if (q4.aboutWorkIds?.length) ors.push(`about_work_id = ANY(${push2(capIds(q4.aboutWorkIds))})`);
258040
- if (q4.aboutNodeIds?.length) ors.push(`about_node_id = ANY(${push2(capIds(q4.aboutNodeIds))})`);
258041
- if (q4.raisedByNodeIds?.length) ors.push(`raised_by_node_id = ANY(${push2(capIds(q4.raisedByNodeIds))})`);
258042
- if (ors.length) conds.push(`(${ors.join(" OR ")})`);
258043
- if (q4.fromIso) conds.push(`created_at >= ${push2(q4.fromIso)}`);
258044
- if (q4.toIso) conds.push(`created_at <= ${push2(q4.toIso)}`);
258045
- const rows = await this.q(
258046
- `SELECT * FROM ${this.e}.issues WHERE ${conds.join(" AND ")} ORDER BY created_at ASC, id ASC LIMIT ${push2(q4.limit)}`,
258047
- args
258048
- );
258049
- return rows.map(toIssue);
258050
- }
258051
- async worksHandlingIssues(workorderId, issueIds, limit) {
258052
- if (issueIds.length === 0) return [];
258053
- const ids2 = capIds(issueIds);
258054
- const rows = await this.q(
258055
- `SELECT ${WORK_COLS} FROM ${this.e}.works w LEFT JOIN ${this.e}.workflow_nodes n ON n.id = w.node_id
258056
- WHERE w.workorder_id = $1
258057
- AND (w.id LIKE ANY($4::text[]) OR (jsonb_typeof(w.frozen_issue_ids) = 'array' AND w.frozen_issue_ids ?| $2))
258058
- ORDER BY w.created_at ASC, w.id ASC LIMIT $3`,
258059
- [workorderId, ids2, limit, ids2.map((i5) => `wk:reply:${i5.replace(/[\\%_]/g, (c5) => `\\${c5}`)}:%`)]
258060
- );
258061
- return rows.map(toWork);
258062
- }
258063
- /* ── dispatches ── */
258064
- async dispatchesOf(kind, targetIds) {
258065
- if (targetIds.length === 0) return [];
258066
- const rows = await this.q(
258067
- `SELECT id, target_kind, target_id, actor_id, created_at, started_at, ended_at, outcome, reason, protocol_recovery_round
258068
- FROM ${this.d}.dispatches WHERE target_kind = $1 AND target_id = ANY($2) ORDER BY created_at ASC, id ASC LIMIT 1000`,
258069
- [kind, capIds(targetIds)]
258070
- );
258071
- return rows.map(toDispatch);
258072
- }
258073
- async dispatchTargetOf(runId) {
258074
- const rows = await this.q(`SELECT target_kind, target_id FROM ${this.d}.dispatches WHERE id = $1`, [runId]);
258075
- const r5 = rows[0];
258076
- return r5 ? { targetKind: String(r5["target_kind"]), targetId: String(r5["target_id"]) } : null;
258077
- }
258078
- /* ── 委派 ── */
258079
- async getDelegation(id) {
258080
- const rows = await this.q(`SELECT * FROM ${this.c}.chat_session_delegations WHERE id = $1`, [id]);
258081
- return rows[0] ? toDelegation(rows[0]) : null;
258082
- }
258083
- async delegationByChildSession(childSessionId) {
258084
- const rows = await this.q(`SELECT * FROM ${this.c}.chat_session_delegations WHERE child_session_id = $1`, [childSessionId]);
258085
- return rows[0] ? toDelegation(rows[0]) : null;
258086
- }
258087
- async delegationsOfParent(parentSessionId, limit) {
258088
- const rows = await this.q(
258089
- `SELECT * FROM ${this.c}.chat_session_delegations WHERE parent_session_id = $1 ORDER BY created_at ASC, id ASC LIMIT $2`,
258090
- [parentSessionId, limit]
258091
- );
258092
- return rows.map(toDelegation);
258093
- }
258094
- async touchesOf(delegationId) {
258095
- const rows = await this.q(
258096
- `SELECT delegation_id, message_id, kind, at FROM ${this.c}.chat_session_delegation_touches
258097
- WHERE delegation_id = $1 ORDER BY at ASC LIMIT 500`,
258098
- [delegationId]
258099
- );
258100
- return rows.map((r5) => ({
258101
- delegationId: String(r5["delegation_id"]),
258102
- messageId: String(r5["message_id"]),
258103
- kind: String(r5["kind"]),
258104
- at: isoReq(r5["at"])
258105
- }));
258106
- }
258107
- /* ── 会话 / 轮次 / 消息 ── */
258108
- async getSession(id) {
258109
- const rows = await this.q(`SELECT * FROM ${this.c}.chat_sessions WHERE id = $1`, [id]);
258110
- return rows[0] ? toSession(rows[0]) : null;
258111
- }
258112
- async getTurn(id) {
258113
- const rows = await this.q(`SELECT * FROM ${this.c}.chat_session_turns WHERE id = $1`, [id]);
258114
- return rows[0] ? toTurn(rows[0]) : null;
258115
- }
258116
- async turnsOfSession(sessionId, limit) {
258117
- const rows = await this.q(
258118
- `SELECT * FROM ${this.c}.chat_session_turns WHERE chat_session_id = $1 ORDER BY reserved_at DESC, id DESC LIMIT $2`,
258119
- [sessionId, limit + 1]
258120
- );
258121
- const truncated = rows.length > limit;
258122
- const turns = (truncated ? rows.slice(0, limit) : rows).map(toTurn).reverse();
258123
- return { turns, truncated };
258124
- }
258125
- async getMessage(id) {
258126
- const rows = await this.q(`SELECT * FROM ${this.c}.chat_messages WHERE id = $1`, [id]);
258127
- return rows[0] ? toMessage(rows[0]) : null;
258128
- }
258129
- async messagesOf(sessionId, q4) {
258130
- const args = [sessionId];
258131
- const push2 = (v2) => {
258132
- args.push(v2);
258133
- return `$${args.length}`;
258134
- };
258135
- const conds = ["session_id = $1"];
258136
- if (q4.turnIds) {
258137
- const window3 = ["turn_id IS NULL"];
258138
- if (q4.fromIso) window3.push(`created_at >= ${push2(q4.fromIso)}`);
258139
- if (q4.toIso) window3.push(`created_at <= ${push2(q4.toIso)}`);
258140
- conds.push(`(turn_id = ANY(${push2(capIds(q4.turnIds))}) OR (${window3.join(" AND ")}))`);
258141
- } else {
258142
- if (q4.fromIso) conds.push(`created_at >= ${push2(q4.fromIso)}`);
258143
- if (q4.toIso) conds.push(`created_at <= ${push2(q4.toIso)}`);
258144
- }
258145
- if (q4.roles?.length) conds.push(`role = ANY(${push2(q4.roles)})`);
258146
- const rows = await this.q(
258147
- `SELECT id, session_id, role, content, seq, created_at, run_id, turn_id, source FROM ${this.c}.chat_messages
258148
- WHERE ${conds.join(" AND ")} ORDER BY seq ASC LIMIT ${push2(q4.limit)}`,
258149
- args
258150
- );
258151
- return rows.map(toMessage);
258152
- }
258153
- async pendingMessagesOf(sessionId, fromIso, toIso2, limit) {
258154
- const rows = await this.q(
258155
- `SELECT id, chat_session_id, text, created_at, state, flavour FROM ${this.c}.chat_pending_messages
258156
- WHERE chat_session_id = $1 AND created_at >= $2 AND created_at <= $3 ORDER BY seq ASC LIMIT $4`,
258157
- [sessionId, fromIso, toIso2, limit]
258158
- );
258159
- return rows.map((r5) => ({
258160
- id: String(r5["id"]),
258161
- chatSessionId: String(r5["chat_session_id"]),
258162
- text: String(r5["text"] ?? ""),
258163
- createdAt: isoReq(r5["created_at"]),
258164
- state: str5(r5["state"]),
258165
- flavour: str5(r5["flavour"])
258166
- }));
258167
- }
258168
- async originLinksOfWorkorder(workorderId) {
258169
- const rows = await this.q(
258170
- `SELECT session_id, work_order_id, linked_at FROM ${this.c}.chat_session_work_orders
258171
- WHERE work_order_id = $1 AND link_kind = 'origin' ORDER BY linked_at ASC LIMIT 20`,
258172
- [workorderId]
258173
- );
258174
- return rows.map(toLink);
258175
- }
258176
- async originLinksOfSession(sessionId) {
258177
- const rows = await this.q(
258178
- `SELECT session_id, work_order_id, linked_at FROM ${this.c}.chat_session_work_orders
258179
- WHERE session_id = $1 AND link_kind = 'origin' ORDER BY linked_at ASC LIMIT 200`,
258180
- [sessionId]
258181
- );
258182
- return rows.map(toLink);
258183
- }
258184
- /* ── find / peers 候选 ── */
258185
- async listEndedWorks(q4) {
258186
- const args = [];
258187
- const push2 = (v2) => {
258188
- args.push(v2);
258189
- return `$${args.length}`;
258190
- };
258191
- const conds = [`(w.ended_at IS NOT NULL OR w.dead_at IS NOT NULL)`, `w.acceptance_state IS DISTINCT FROM 'draft'`];
258192
- if (q4.sinceIso) conds.push(`COALESCE(w.ended_at, w.dead_at) >= ${push2(q4.sinceIso)}`);
258193
- if (q4.actorId) conds.push(`w.assignee_actor_id = ${push2(q4.actorId)}`);
258194
- if (q4.nodeType) conds.push(`n.type = ${push2(q4.nodeType)}`);
258195
- if (q4.lane) conds.push(`COALESCE(w.lane, CASE WHEN w.id LIKE 'wk:reply:%' THEN 'reply' ELSE 'main' END) = ${push2(q4.lane)}`);
258196
- const rows = await this.q(
258197
- `SELECT ${WORK_COLS} FROM ${this.e}.works w LEFT JOIN ${this.e}.workflow_nodes n ON n.id = w.node_id
258198
- WHERE ${conds.join(" AND ")} ORDER BY COALESCE(w.ended_at, w.dead_at) DESC, w.id DESC LIMIT ${push2(q4.limit)}`,
258199
- args
258200
- );
258201
- return rows.map(toWork);
258202
- }
258203
- async listEndedReviews(q4) {
258204
- const args = [];
258205
- const push2 = (v2) => {
258206
- args.push(v2);
258207
- return `$${args.length}`;
258208
- };
258209
- const endExpr = `COALESCE(r.ended_at, r.decided_at, r.cancelled_at, r.created_at)`;
258210
- const conds = [`r.status IN ('accept','reject','failed','dead')`];
258211
- if (q4.sinceIso) conds.push(`${endExpr} >= ${push2(q4.sinceIso)}`);
258212
- if (q4.actorId) conds.push(`r.reviewer_actor_id = ${push2(q4.actorId)}`);
258213
- const rows = await this.q(
258214
- `SELECT ${REVIEW_COLS} FROM ${this.e}.reviews r LEFT JOIN ${this.e}.workflow_nodes n ON n.id = r.node_id
258215
- WHERE ${conds.join(" AND ")} ORDER BY ${endExpr} DESC, r.id DESC LIMIT ${push2(q4.limit)}`,
258216
- args
258217
- );
258218
- return rows.map(toReview);
258219
- }
258220
- async listEndedDelegations(q4) {
258221
- const args = [];
258222
- const push2 = (v2) => {
258223
- args.push(v2);
258224
- return `$${args.length}`;
258225
- };
258226
- const conds = [`state IN ('done','failed')`];
258227
- if (q4.sinceIso) conds.push(`COALESCE(settled_at, created_at) >= ${push2(q4.sinceIso)}`);
258228
- if (q4.actorId) conds.push(`expert_actor_id = ${push2(q4.actorId)}`);
258229
- const rows = await this.q(
258230
- `SELECT * FROM ${this.c}.chat_session_delegations WHERE ${conds.join(" AND ")}
258231
- ORDER BY COALESCE(settled_at, created_at) DESC, id DESC LIMIT ${push2(q4.limit)}`,
258232
- args
258233
- );
258234
- return rows.map(toDelegation);
258235
- }
258236
- async listRecentSessions(q4) {
258237
- const args = [];
258238
- const push2 = (v2) => {
258239
- args.push(v2);
258240
- return `$${args.length}`;
258241
- };
258242
- const conds = [`NOT EXISTS (SELECT 1 FROM ${this.c}.chat_session_delegations d WHERE d.child_session_id = s.id)`];
258243
- if (!q4.includeAnalysis) conds.push(`s.analyzed_run_id IS NULL`);
258244
- if (q4.sinceIso) conds.push(`s.touched_at >= ${push2(q4.sinceIso)}`);
258245
- if (q4.aiActorId) conds.push(`s.ai_actor_id = ${push2(q4.aiActorId)}`);
258246
- const rows = await this.q(
258247
- `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
258248
- FROM ${this.c}.chat_sessions s WHERE ${conds.join(" AND ")} ORDER BY s.touched_at DESC, s.id DESC LIMIT ${push2(q4.limit)}`,
258249
- args
258250
- );
258251
- return rows.map(toSession);
258252
- }
258253
- };
258254
- }
258255
- });
258256
-
258257
258343
  // ../server/src/domains/trace/index.ts
258258
258344
  function createTraceDomain(opts) {
258259
258345
  const service = new TraceService({ store: opts.store });
@@ -261512,7 +261598,7 @@ function shown(field, v2, nameOf2) {
261512
261598
  if (v2 === void 0 || v2 === "") return "\uFF08\u7A7A\uFF09";
261513
261599
  if (field === "dueDate" || field === "startDate") return formatTodoDue(v2);
261514
261600
  if (field === "assignee") return nameOf2(v2);
261515
- return clip5(v2);
261601
+ return clip4(v2);
261516
261602
  }
261517
261603
  function assignedTitle(who2, todo) {
261518
261604
  return `${who2} \u6D3E\u7ED9\u4F60\uFF1A${todo.title}\uFF0C${formatTodoSpan(todo)}`;
@@ -261523,13 +261609,13 @@ function unseenTitle(assigneeName, todo) {
261523
261609
  function changedTitle(who2, todo, changes, nameOf2) {
261524
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)}`);
261525
261611
  const reason2 = changes.find((c5) => c5.reason)?.reason;
261526
- 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)}` : ""}`;
261527
261613
  }
261528
261614
  function statusTitle(who2, todo, kind, reason2, result) {
261529
261615
  const verb = kind === "todo-done" ? "\u5B8C\u6210\u4E86" : kind === "todo-reopened" ? "\u91CD\u65B0\u6253\u5F00\u4E86" : "\u53D6\u6D88\u4E86";
261530
- 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)}` : ""}`;
261531
261617
  }
261532
- var VALUE_MAX, FIELD_LABEL, clip5, todoAssignedSourceKey, todoChangeSourceKey, todoUnseenSourceKey;
261618
+ var VALUE_MAX, FIELD_LABEL, clip4, todoAssignedSourceKey, todoChangeSourceKey, todoUnseenSourceKey;
261533
261619
  var init_notices = __esm({
261534
261620
  "../server/src/domains/todos/notices.ts"() {
261535
261621
  "use strict";
@@ -261546,7 +261632,7 @@ var init_notices = __esm({
261546
261632
  assignee: "\u627F\u63A5\u4EBA",
261547
261633
  result: "\u7ED3\u679C\u5728\u54EA"
261548
261634
  };
261549
- 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;
261550
261636
  todoAssignedSourceKey = (todoId) => `todo:${todoId}@assigned`;
261551
261637
  todoChangeSourceKey = (todoId, changeId) => `todo:${todoId}@change:${changeId}`;
261552
261638
  todoUnseenSourceKey = (todo) => `todo:${todo.id}@unseen:${todo.dueDate}`;
@@ -327226,6 +327312,7 @@ __export(src_exports2, {
327226
327312
  shouldInjectResumePack: () => shouldInjectResumePack,
327227
327313
  shouldPush: () => shouldPush,
327228
327314
  singlePushPayload: () => singlePushPayload,
327315
+ skillManifestForActor: () => skillManifestForActor,
327229
327316
  skillsDirForRuntime: () => skillsDirForRuntime,
327230
327317
  splitKnowledgeChunks: () => splitKnowledgeChunks,
327231
327318
  stableChatTraceRunId: () => stableChatTraceRunId,
@@ -331029,6 +331116,18 @@ function skillContentHash(files) {
331029
331116
  }
331030
331117
  return `sha256:${h5.digest("hex")}`;
331031
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
+ }
331032
331131
  function scopedTrace(trace, scope2) {
331033
331132
  if (scope2.companyScoped) return trace;
331034
331133
  const allows = traceReadAllows(scope2);
@@ -331154,7 +331253,10 @@ ${f6.content}`).join("\n\n");
331154
331253
  const svc = await exposureServiceFor(cid, await deps.traceStoreFor(cid), reflection);
331155
331254
  await svc.recordDispatch({
331156
331255
  runId: input.runId,
331157
- 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
+ }),
331158
331260
  memories: input.memories ? input.memories.map((m4) => ({ memId: m4.memId, version: m4.version })) : null
331159
331261
  });
331160
331262
  })().catch((e5) => log3(`[reflection] ${cid} chat run ${input.runId} \u57CB\u70B9\u5931\u8D25\uFF08\u4E0D\u5F71\u54CD\u5BF9\u8BDD\uFF09\uFF1A${String(e5)}`));
@@ -334938,9 +335040,12 @@ async function startServe(opts) {
334938
335040
  traceReadScopeFor: (cid) => traceReadScopeFor(cid),
334939
335041
  blobStoreFor: (cid) => blobStoreFor(cid),
334940
335042
  readBundleFile: (id, rel) => trajReader.readBundleFile(id, rel),
335043
+ // 与 `GET /api/skill-cache/manifest` 同一个函数、同一组参数(ADR 0641 §3.3):内置按会话 claim 投影
335044
+ //(管理者会话不给委派变体),连接器技能按该员工启用的 connector 门禁——节点拿到什么就记什么。
334941
335045
  listSkills: async (cid, actorId, o3) => {
334942
335046
  const { service } = await actors.resolveCtx(cid);
334943
- 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 });
334944
335049
  },
334945
335050
  readMemories: async (cid, actorId, memIds) => {
334946
335051
  const svc = await actorMemoryFor(cid);
@@ -334957,11 +335062,8 @@ async function startServe(opts) {
334957
335062
  return cfg ? { prompt: cfg.prompt ?? "", version: cfg.version } : null;
334958
335063
  },
334959
335064
  readSkillFiles: async (cid, skillId) => {
334960
- if (skillId.startsWith("builtin:")) {
334961
- const b6 = builtinSkills.find((x2) => `builtin:${x2.id}` === skillId);
334962
- return b6 ? Object.entries(b6.files).map(([path50, content3]) => ({ path: path50, content: content3 })) : null;
334963
- }
334964
- if (skillId.startsWith("connector:")) return null;
335065
+ const mem = inMemorySkillFiles(skillId, { builtins: effectiveBuiltinSkills(), connectorSkills });
335066
+ if (mem !== void 0) return mem;
334965
335067
  const files = await (await actors.resolveCtx(cid)).service.listSkillFiles(skillId).catch(() => []);
334966
335068
  return files.length ? files.map((f6) => ({ path: f6.path, content: f6.content })) : null;
334967
335069
  },
@@ -336475,6 +336577,7 @@ async function startServe(opts) {
336475
336577
  actorId,
336476
336578
  turnId: chatTurnId,
336477
336579
  builtins: !isolatedBackground,
336580
+ ...chatSessionId !== void 0 ? { chatSessionId } : {},
336478
336581
  memories: chatInjectedMemories,
336479
336582
  files: { ...files },
336480
336583
  systemPromptFingerprint: null
@@ -343820,18 +343923,24 @@ var COMMAND_DECLS = {
343820
343923
  },
343821
343924
  "trace outcome": {
343822
343925
  group: "\u6267\u884C\u8BB0\u5F55\uFF08trace\uFF09",
343823
- usage: "oasis trace outcome <unit> [--json]",
343824
- 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",
343825
343928
  positional: [{ name: "<unit>", required: true, desc: "\u5355\u5143 id \u6216 run id" }],
343826
- 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
+ ],
343827
343933
  examples: ["oasis trace outcome dlg:7f2c"]
343828
343934
  },
343829
343935
  "trace exogenous": {
343830
343936
  group: "\u6267\u884C\u8BB0\u5F55\uFF08trace\uFF09",
343831
- usage: "oasis trace exogenous <unit> [--json]",
343832
- 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",
343833
343939
  positional: [{ name: "<unit>", required: true, desc: "\u5355\u5143 id \u6216 run id" }],
343834
- 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
+ ],
343835
343944
  examples: ["oasis trace exogenous wk:n-abc:2"]
343836
343945
  },
343837
343946
  "trace runs": {
@@ -344881,6 +344990,7 @@ function buildTraceRequest(sub, positional, flags, now = Date.now()) {
344881
344990
  return { method: "GET", path: `${unitPath("brief")}${qs({ budget: intFlag(flags, "budget", 6e3, 1) })}` };
344882
344991
  case "outcome":
344883
344992
  case "exogenous":
344993
+ return { method: "GET", path: `${unitPath(sub)}${qs({ full: on(flags, "full") ? 1 : void 0 })}` };
344884
344994
  case "runs":
344885
344995
  return { method: "GET", path: unitPath(sub) };
344886
344996
  case "events": {
@@ -345915,7 +346025,7 @@ async function waitForCommandAuthorization(base, headers, draftId, fallback2) {
345915
346025
  }
345916
346026
  }
345917
346027
  }
345918
- var CLI_VERSION = "2.2.125" ? "2.2.125" : "dev";
346028
+ var CLI_VERSION = "2.2.126" ? "2.2.126" : "dev";
345919
346029
  function apiHeaders(token2, company) {
345920
346030
  const headers = {
345921
346031
  authorization: `Bearer ${token2}`,
@@ -346721,16 +346831,17 @@ ${round.text}`);
346721
346831
  { to, task, ...flags.get("as") ? { as: flags.get("as") } : {}, ...fileArgs.length ? { files: fileArgs } : {} }
346722
346832
  );
346723
346833
  if (asJson2) {
346724
- const overlap = await overlapLines("delegate", task, started.delegationId);
346725
- println(JSON.stringify({ ...started, ...overlap.length ? { overlap } : {} }, null, 2));
346834
+ const overlap2 = await overlapLines("delegate", task, started.delegationId);
346835
+ println(JSON.stringify({ ...started, ...overlap2.length ? { overlap: overlap2 } : {} }, null, 2));
346726
346836
  break;
346727
346837
  }
346728
346838
  println(`\u5DF2\u4EA4\u7ED9 ${to} \u53BB\u505A\uFF08\u5F02\u6B65\uFF0C\u4E0D\u7528\u7B49\uFF09\u3002`);
346729
346839
  println(` \u77ED\u540D\uFF08--follow-up \u7528\u8FD9\u4E2A\uFF09\uFF1A${started.label}`);
346730
346840
  println(` delegationId\uFF1A${started.delegationId}`);
346731
346841
  if (started.attachedFiles?.length) println(` \u5E26\u8FC7\u53BB\u7684\u6587\u4EF6\uFF1A${started.attachedFiles.join("\u3001")}`);
346732
- 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");
346733
- 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");
346734
346845
  break;
346735
346846
  }
346736
346847
  case "kb": {
@@ -350228,7 +350339,7 @@ function shimScript() {
350228
350339
  }
350229
350340
 
350230
350341
  // src/index.ts
350231
- var PKG_VERSION = true ? "2.2.125" : "dev";
350342
+ var PKG_VERSION = true ? "2.2.126" : "dev";
350232
350343
  var LOCAL_BIN = localBin();
350233
350344
  var NPM_PREFIX = npmPrefix();
350234
350345
  var INSTANCE = DEFAULT_INSTANCE;