oasis_test_v2 2.2.47 → 2.2.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1004 -638
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -440,6 +440,9 @@ function isUnread(eventAt, marker) {
|
|
|
440
440
|
if (Number.isNaN(e) || Number.isNaN(m2)) return true;
|
|
441
441
|
return e > m2;
|
|
442
442
|
}
|
|
443
|
+
function isChatSessionUnread(session, marker) {
|
|
444
|
+
return session.lastTurnQuality !== void 0 && isUnread(session.touchedAt, marker);
|
|
445
|
+
}
|
|
443
446
|
var chatScope, letterScope, INBOX_BASELINE_SCOPE;
|
|
444
447
|
var init_inbox_read = __esm({
|
|
445
448
|
"../contract/src/inbox-read.ts"() {
|
|
@@ -4185,7 +4188,7 @@ var init_claude_code = __esm({
|
|
|
4185
4188
|
if (composed) errorParts.push(composed);
|
|
4186
4189
|
}
|
|
4187
4190
|
if (stderrTail2.length) errorParts.push(stderrTail2.join("\n").trim());
|
|
4188
|
-
const
|
|
4191
|
+
const errorMessage2 = isError ? errorParts.filter(Boolean).join("\n---\n").slice(-4e3).trim() || void 0 : void 0;
|
|
4189
4192
|
exited = {
|
|
4190
4193
|
code: killReason ? null : code2,
|
|
4191
4194
|
...reason ? { reason } : {},
|
|
@@ -4193,7 +4196,7 @@ var init_claude_code = __esm({
|
|
|
4193
4196
|
workdirRef,
|
|
4194
4197
|
...usage ? { usage } : {},
|
|
4195
4198
|
...sessionModel ? { model: sessionModel } : {},
|
|
4196
|
-
...
|
|
4199
|
+
...errorMessage2 ? { errorMessage: errorMessage2 } : {},
|
|
4197
4200
|
// ADR-0147:容器化会话带上镜像 digest(可复现凭据,经 dispatcher 落 agent_runs.metadata)。
|
|
4198
4201
|
...containerized?.imageDigest ? { imageDigest: containerized.imageDigest } : {}
|
|
4199
4202
|
};
|
|
@@ -5952,6 +5955,9 @@ var init_protocol_session = __esm({
|
|
|
5952
5955
|
function codexNum(v2) {
|
|
5953
5956
|
return typeof v2 === "number" && Number.isFinite(v2) ? v2 : 0;
|
|
5954
5957
|
}
|
|
5958
|
+
function codexOutputTokens(output, reasoning) {
|
|
5959
|
+
return Math.max(codexNum(output), codexNum(reasoning));
|
|
5960
|
+
}
|
|
5955
5961
|
function parseCodexAppServerTurnUsage(params) {
|
|
5956
5962
|
const p2 = params;
|
|
5957
5963
|
const last = p2?.tokenUsage?.last;
|
|
@@ -5960,7 +5966,7 @@ function parseCodexAppServerTurnUsage(params) {
|
|
|
5960
5966
|
input: codexNum(last["inputTokens"]),
|
|
5961
5967
|
cacheRead: codexNum(last["cachedInputTokens"]),
|
|
5962
5968
|
cacheWrite: codexNum(last["cacheWriteInputTokens"]),
|
|
5963
|
-
output:
|
|
5969
|
+
output: codexOutputTokens(last["outputTokens"], last["reasoningOutputTokens"])
|
|
5964
5970
|
};
|
|
5965
5971
|
}
|
|
5966
5972
|
function addCodexBuckets(acc, add) {
|
|
@@ -5992,8 +5998,8 @@ function bucketsOf(usage) {
|
|
|
5992
5998
|
// cache 字段名跨版本有两种
|
|
5993
5999
|
cacheRead: codexNum(usage["cached_input_tokens"]) || codexNum(usage["cache_read_input_tokens"]),
|
|
5994
6000
|
cacheWrite: codexNum(usage["cache_write_input_tokens"]),
|
|
5995
|
-
//
|
|
5996
|
-
output:
|
|
6001
|
+
// output_tokens 已含 reasoning,见 codexOutputTokens。
|
|
6002
|
+
output: codexOutputTokens(usage["output_tokens"], usage["reasoning_output_tokens"])
|
|
5997
6003
|
};
|
|
5998
6004
|
}
|
|
5999
6005
|
function usageFromBuckets(b2) {
|
|
@@ -6903,7 +6909,7 @@ ${task}` : task;
|
|
|
6903
6909
|
const runtimeSessionId = telemetry.sessionId ?? resumeSessionId;
|
|
6904
6910
|
const sawStreamError = streamErrorMessages.length > 0;
|
|
6905
6911
|
const isError = !killReason && (code2 !== 0 || sawStreamError);
|
|
6906
|
-
const
|
|
6912
|
+
const errorMessage2 = isError ? [...streamErrorMessages, ...stdoutErrorLines, ...stderrTail2].join("\n").trim().slice(-4e3) || void 0 : void 0;
|
|
6907
6913
|
const sessionNotFound = !killReason && isResume && isSessionNotFoundError([...streamErrorMessages, ...stdoutErrorLines, ...stderrTail2].join("\n"));
|
|
6908
6914
|
const reason = killReason ? killReason : sessionNotFound ? "session-not-found" : sawStreamError ? "error" : code2 === 0 ? "clean" : "error";
|
|
6909
6915
|
finish({
|
|
@@ -6916,7 +6922,7 @@ ${task}` : task;
|
|
|
6916
6922
|
...telemetry.usage ? { usage: telemetry.usage } : {},
|
|
6917
6923
|
...model ? { model } : {},
|
|
6918
6924
|
...runtimeSessionId ? { runtimeSessionId } : {},
|
|
6919
|
-
...
|
|
6925
|
+
...errorMessage2 ? { errorMessage: errorMessage2 } : {},
|
|
6920
6926
|
// 跑在哪个镜像上要落账:同一题换了镜像,分数就不可比(ADR-0147 M5)
|
|
6921
6927
|
...containerized?.imageDigest ? { imageDigest: containerized.imageDigest } : {}
|
|
6922
6928
|
});
|
|
@@ -8236,8 +8242,8 @@ function classifyHermesPromptFailure(turn) {
|
|
|
8236
8242
|
if (errors.length === 0 && !failedSentence && !silent) return void 0;
|
|
8237
8243
|
return failure(errors.length > 0 ? clip(errors.slice(-MAX_ERROR_RECORDS).join("\n")) : failedSentence ?? `hermes \u672C\u8F6E\u6CA1\u6709\u6B63\u5E38\u6536\u5C3E\uFF08\u54CD\u5E94\u4E0D\u5E26\u7528\u91CF\uFF09\uFF0C\u6CA1\u6709\u8F93\u51FA\uFF0Cstderr \u4E5F\u6CA1\u6709 ERROR \u65E5\u5FD7\u3002${stderrTail(turn.stderrLines)}`);
|
|
8238
8244
|
}
|
|
8239
|
-
function failure(
|
|
8240
|
-
return { reason: QUOTA_RE.test(
|
|
8245
|
+
function failure(errorMessage2) {
|
|
8246
|
+
return { reason: QUOTA_RE.test(errorMessage2) ? "rate-limit" : "error", errorMessage: errorMessage2 };
|
|
8241
8247
|
}
|
|
8242
8248
|
function promptResultHasUsage(result) {
|
|
8243
8249
|
if (typeof result !== "object" || result === null) return false;
|
|
@@ -9000,12 +9006,12 @@ async function runStreamJson(job, cfg) {
|
|
|
9000
9006
|
child.on("exit", (code2) => {
|
|
9001
9007
|
clearTimeout(timer);
|
|
9002
9008
|
const isError = !killReason && typeof code2 === "number" && code2 !== 0;
|
|
9003
|
-
const
|
|
9009
|
+
const errorMessage2 = isError ? stderrTail2.join("\n").trim().slice(-4e3) || void 0 : void 0;
|
|
9004
9010
|
finish({
|
|
9005
9011
|
code: killReason ? null : code2,
|
|
9006
9012
|
reason: killReason ?? (code2 === 0 ? "clean" : "error"),
|
|
9007
9013
|
transcriptRef: transcriptRefPtr.value,
|
|
9008
|
-
...
|
|
9014
|
+
...errorMessage2 ? { errorMessage: errorMessage2 } : {},
|
|
9009
9015
|
// ADR-0147:容器化会话带上镜像 digest(可复现凭据)。
|
|
9010
9016
|
...containerized?.imageDigest ? { imageDigest: containerized.imageDigest } : {}
|
|
9011
9017
|
});
|
|
@@ -9103,12 +9109,12 @@ async function runOneShotText(job, cfg) {
|
|
|
9103
9109
|
child.on("exit", (code2) => {
|
|
9104
9110
|
clearTimeout(timer);
|
|
9105
9111
|
const isError = !killReason && typeof code2 === "number" && code2 !== 0;
|
|
9106
|
-
const
|
|
9112
|
+
const errorMessage2 = isError ? stderrTail2.join("\n").trim().slice(-4e3) || void 0 : void 0;
|
|
9107
9113
|
finish({
|
|
9108
9114
|
code: killReason ? null : code2,
|
|
9109
9115
|
reason: killReason ?? (code2 === 0 ? "clean" : "error"),
|
|
9110
9116
|
transcriptRef: transcriptRefPtr.value,
|
|
9111
|
-
...
|
|
9117
|
+
...errorMessage2 ? { errorMessage: errorMessage2 } : {},
|
|
9112
9118
|
// ADR-0147:容器化会话带上镜像 digest(可复现凭据)。
|
|
9113
9119
|
...containerized?.imageDigest ? { imageDigest: containerized.imageDigest } : {}
|
|
9114
9120
|
});
|
|
@@ -10493,6 +10499,9 @@ var init_chat_item_ledger = __esm({
|
|
|
10493
10499
|
finished = false;
|
|
10494
10500
|
/** 上一次见到的归一层 turnId——变了就清映射(provider 开了新 turn)。 */
|
|
10495
10501
|
lastTurnId = null;
|
|
10502
|
+
/** 本账本已经落库的 user 行(按落库顺序)。{@link onUserItemPersisted} 的晚到订阅者从这里补。 */
|
|
10503
|
+
persistedUserItems = [];
|
|
10504
|
+
userItemListeners = /* @__PURE__ */ new Set();
|
|
10496
10505
|
/** 会话逻辑时钟走一格。**唯一发号点**(ADR-0510 附录 A.4)——别在别处自己数。 */
|
|
10497
10506
|
tick() {
|
|
10498
10507
|
return ++this.clock;
|
|
@@ -10505,6 +10514,42 @@ var init_chat_item_ledger = __esm({
|
|
|
10505
10514
|
const ord = this.rows.get(itemId)?.ord;
|
|
10506
10515
|
return ord === null ? void 0 : ord;
|
|
10507
10516
|
}
|
|
10517
|
+
/** 展示时间与持久行同源;不以浏览器收到帧的时间代替。 */
|
|
10518
|
+
timestampsFor(itemId) {
|
|
10519
|
+
const row = this.rows.get(itemId);
|
|
10520
|
+
return row ? { createdAt: row.createdAt, completedAt: row.completedAt } : void 0;
|
|
10521
|
+
}
|
|
10522
|
+
/**
|
|
10523
|
+
* 订阅「本账本的 **user 行**真的落库了」(拿到服务端派的 `ord`、写号与这一行自己的 payload)。
|
|
10524
|
+
* 订阅那一刻**已经**落库的先按落库顺序同步补一遍,之后的逐条到达。返回退订。
|
|
10525
|
+
*
|
|
10526
|
+
* ## 为什么是订阅而不是构造参数
|
|
10527
|
+
*
|
|
10528
|
+
* 唯一的消费者是 `LiveChatRegistry.start`:用户那条消息(首条提交 / 中途插话)落库即推上 v3 流。
|
|
10529
|
+
* 此前这件事挂在 `server.ts` 构造账本时给的 {@link ChatItemLedgerDeps.onPersisted} 上,
|
|
10530
|
+
* 于是**只有 `/api/chat` 那一条开轮入口**接了;后台自起轮(工单播报 / 委派回流 / 授权卡续跑)、
|
|
10531
|
+
* serve 重启重挂、委派子会话三条入口建账本时都没给——插话已被 runtime 消费、库里也记了送达,
|
|
10532
|
+
* 页面却收不到那一行,排队区一直转圈,直到本轮结束重拉快照才出现
|
|
10533
|
+
* (2026-09-17 生产会话 `3b89b474`,子任务回传唤起的那一轮,插话晚显示约 4 分钟)。
|
|
10534
|
+
* 挂到「有 live 轮就有」的那一处,新长出来的开轮入口不需要记得再接一次。
|
|
10535
|
+
*
|
|
10536
|
+
* ## 为什么要补发
|
|
10537
|
+
*
|
|
10538
|
+
* `/api/chat` 的首条提交在 `liveChat.start` **之前**就排进落库链,谁先完成纯看 INSERT 往返
|
|
10539
|
+
* (2026-09-10「位置有时候变来变去」那场竞速)。补发让「落库早于开轮」与「开轮早于落库」同一个结果。
|
|
10540
|
+
*/
|
|
10541
|
+
onUserItemPersisted(cb) {
|
|
10542
|
+
for (const info of this.persistedUserItems.slice()) {
|
|
10543
|
+
try {
|
|
10544
|
+
cb(info);
|
|
10545
|
+
} catch {
|
|
10546
|
+
}
|
|
10547
|
+
}
|
|
10548
|
+
this.userItemListeners.add(cb);
|
|
10549
|
+
return () => {
|
|
10550
|
+
this.userItemListeners.delete(cb);
|
|
10551
|
+
};
|
|
10552
|
+
}
|
|
10508
10553
|
get failures() {
|
|
10509
10554
|
return this.failureCount;
|
|
10510
10555
|
}
|
|
@@ -10708,6 +10753,8 @@ var init_chat_item_ledger = __esm({
|
|
|
10708
10753
|
if (this.rows.has(row.id)) continue;
|
|
10709
10754
|
const { text: text6, attrs } = restoredTextAndAttrs(row);
|
|
10710
10755
|
const item = {
|
|
10756
|
+
createdAt: row.createdAt,
|
|
10757
|
+
completedAt: row.completedAt,
|
|
10711
10758
|
id: row.id,
|
|
10712
10759
|
seq: ++this.seqCounter,
|
|
10713
10760
|
ord: row.ord,
|
|
@@ -10767,6 +10814,9 @@ var init_chat_item_ledger = __esm({
|
|
|
10767
10814
|
/**
|
|
10768
10815
|
* 切段(人中途插入):此刻起建的 item 属于**下一条** assistant 行。
|
|
10769
10816
|
* 已有 provider item 保留身份与位置;新 item 才归下一段,迟到快照不能复制旧块。
|
|
10817
|
+
*
|
|
10818
|
+
* 返回新段的段号。那条 assistant 行落库后回填归属时**必须带上它**({@link bindMessage}):
|
|
10819
|
+
* 行是异步落库的,回填到达时后面可能已经又切过段。
|
|
10770
10820
|
*/
|
|
10771
10821
|
beginSegment() {
|
|
10772
10822
|
if (this.segmentEndEmitted) {
|
|
@@ -10778,6 +10828,7 @@ var init_chat_item_ledger = __esm({
|
|
|
10778
10828
|
this.messageId = null;
|
|
10779
10829
|
this.segment += 1;
|
|
10780
10830
|
this.segmentItemCount = 0;
|
|
10831
|
+
return this.segment;
|
|
10781
10832
|
}
|
|
10782
10833
|
/**
|
|
10783
10834
|
* 人插话时,先把「这一段到此为止」落定;**必须在那条 user 行之前调用**。
|
|
@@ -10814,15 +10865,31 @@ var init_chat_item_ledger = __esm({
|
|
|
10814
10865
|
payload: { code: "segment_end", note: SEGMENT_END_NOTE }
|
|
10815
10866
|
});
|
|
10816
10867
|
}
|
|
10817
|
-
/**
|
|
10818
|
-
|
|
10819
|
-
|
|
10868
|
+
/**
|
|
10869
|
+
* 第 `segment` 段那条 assistant 行落库了:把**那一段**还挂着 NULL 的 assistant item 认领回去;
|
|
10870
|
+
* 那一段仍是当前段时,后续 item 直接带上它。缺省段号 = 当前段。
|
|
10871
|
+
*
|
|
10872
|
+
* ## 为什么必须按段收窄(2026-09-17)
|
|
10873
|
+
*
|
|
10874
|
+
* 切段后新行的落库挂在调用方的 checkpoint 链上(先收口前段、再落 user 行、再落新 assistant 行),
|
|
10875
|
+
* 回填要等这几次写都完成;而 runtime 的输出和第二次插话不等它。库慢一点时事件序可以是:
|
|
10876
|
+
* 插话 1 切到第 1 段 → 第 1 段输出 → 插话 2 切到第 2 段 → 第 2 段输出 → 第 1 段的行才落库、回填到达。
|
|
10877
|
+
* 此前回填把**全部** NULL 的 assistant item 认给这一行、并无条件把当前归属改成它:第 2 段的 item
|
|
10878
|
+
* 被归到第 1 段那条消息上(库里与帧上都是),之后新建的 item 也跟着倒退到第 1 段,
|
|
10879
|
+
* 直到第 2 段的回填到达也认领不回来(它们已经不是 NULL)。所以回填只认这一段、只认此刻在账本里的
|
|
10880
|
+
* 那几条 item(store 侧按精确 id 更新),当前归属只在段号仍是当前段时才前进。
|
|
10881
|
+
*/
|
|
10882
|
+
bindMessage(messageId, segment = this.segment) {
|
|
10883
|
+
if (segment === this.segment) this.messageId = messageId;
|
|
10884
|
+
const itemIds = [];
|
|
10820
10885
|
for (const row of this.rows.values()) {
|
|
10821
|
-
if (row.role
|
|
10886
|
+
if (row.role !== "assistant" || row.messageId !== null || row.segment !== segment) continue;
|
|
10887
|
+
row.messageId = messageId;
|
|
10888
|
+
if (row.persist) itemIds.push(row.id);
|
|
10822
10889
|
}
|
|
10823
|
-
if (!this.persistEnabled) return;
|
|
10890
|
+
if (!this.persistEnabled || itemIds.length === 0) return;
|
|
10824
10891
|
this.enqueue(async () => {
|
|
10825
|
-
await this.deps.items.bindMessage(this.deps.sessionId, this.deps.turnId, messageId);
|
|
10892
|
+
await this.deps.items.bindMessage(this.deps.sessionId, this.deps.turnId, messageId, itemIds);
|
|
10826
10893
|
}, "bindMessage");
|
|
10827
10894
|
}
|
|
10828
10895
|
/**
|
|
@@ -10962,7 +11029,10 @@ var init_chat_item_ledger = __esm({
|
|
|
10962
11029
|
const id = input.deterministicId ?? this.newId();
|
|
10963
11030
|
const startedVersion = this.tick();
|
|
10964
11031
|
const writeVersion = this.tick();
|
|
11032
|
+
const createdAt = this.now();
|
|
10965
11033
|
const row = {
|
|
11034
|
+
createdAt,
|
|
11035
|
+
completedAt: null,
|
|
10966
11036
|
id,
|
|
10967
11037
|
seq: ++this.seqCounter,
|
|
10968
11038
|
ord: null,
|
|
@@ -10986,7 +11056,6 @@ var init_chat_item_ledger = __esm({
|
|
|
10986
11056
|
if (!input.forceNullMessage) this.segmentItemCount += 1;
|
|
10987
11057
|
if (!input.persist || !this.persistEnabled) return id;
|
|
10988
11058
|
const messageId = row.messageId;
|
|
10989
|
-
const createdAt = this.now();
|
|
10990
11059
|
const payload2 = input.payload ?? this.payloadOf(row);
|
|
10991
11060
|
const metadata = input.metadata ?? { [CHAT_ITEM_META_LEGACY_CONTENT]: input.inContent };
|
|
10992
11061
|
this.enqueue(async () => {
|
|
@@ -11006,17 +11075,27 @@ var init_chat_item_ledger = __esm({
|
|
|
11006
11075
|
version: writeVersion
|
|
11007
11076
|
});
|
|
11008
11077
|
row.ord = created.ord;
|
|
11078
|
+
const info = {
|
|
11079
|
+
itemId: id,
|
|
11080
|
+
ord: created.ord,
|
|
11081
|
+
version: writeVersion,
|
|
11082
|
+
role: input.role,
|
|
11083
|
+
text: input.text,
|
|
11084
|
+
payload: payload2
|
|
11085
|
+
};
|
|
11009
11086
|
try {
|
|
11010
|
-
this.deps.onPersisted?.(
|
|
11011
|
-
itemId: id,
|
|
11012
|
-
ord: created.ord,
|
|
11013
|
-
version: writeVersion,
|
|
11014
|
-
role: input.role,
|
|
11015
|
-
text: input.text,
|
|
11016
|
-
payload: payload2
|
|
11017
|
-
});
|
|
11087
|
+
this.deps.onPersisted?.(info);
|
|
11018
11088
|
} catch {
|
|
11019
11089
|
}
|
|
11090
|
+
if (input.role === "user") {
|
|
11091
|
+
this.persistedUserItems.push(info);
|
|
11092
|
+
for (const cb of this.userItemListeners) {
|
|
11093
|
+
try {
|
|
11094
|
+
cb(info);
|
|
11095
|
+
} catch {
|
|
11096
|
+
}
|
|
11097
|
+
}
|
|
11098
|
+
}
|
|
11020
11099
|
}, `create:${input.kind}`);
|
|
11021
11100
|
return id;
|
|
11022
11101
|
}
|
|
@@ -11054,9 +11133,11 @@ var init_chat_item_ledger = __esm({
|
|
|
11054
11133
|
persist(row, op, what) {
|
|
11055
11134
|
const version2 = this.tick();
|
|
11056
11135
|
row.wireVersion = version2;
|
|
11136
|
+
const at = this.now();
|
|
11137
|
+
if (op.op === "set_status" && op.status !== "streaming") row.completedAt = at;
|
|
11057
11138
|
if (!row.persist || !this.persistEnabled) return;
|
|
11058
11139
|
this.enqueue(async () => {
|
|
11059
|
-
await this.deps.items.applyOp(row.id, op, { at
|
|
11140
|
+
await this.deps.items.applyOp(row.id, op, { at, version: version2 });
|
|
11060
11141
|
}, what);
|
|
11061
11142
|
}
|
|
11062
11143
|
/** 串行链 + 失败吞掉计数。**串行是必须的**:append_text 依赖建行已经落地。 */
|
|
@@ -11202,6 +11283,46 @@ async function finalizeAssistantRow(deps) {
|
|
|
11202
11283
|
} catch {
|
|
11203
11284
|
}
|
|
11204
11285
|
}
|
|
11286
|
+
function beginInsertedAssistantSegment(deps) {
|
|
11287
|
+
const segText = deps.ledger.projectContent();
|
|
11288
|
+
const nextId = (deps.newId ?? import_node_crypto14.randomUUID)();
|
|
11289
|
+
const segment = deps.ledger.beginSegment();
|
|
11290
|
+
deps.live.setAssistantMessageId(nextId);
|
|
11291
|
+
const at = (deps.now ?? (() => (/* @__PURE__ */ new Date()).toISOString()))();
|
|
11292
|
+
const { chatStore, closingId, segParts } = deps;
|
|
11293
|
+
const persist = async () => {
|
|
11294
|
+
if (closingId) {
|
|
11295
|
+
await chatStore.updateMessage(closingId, {
|
|
11296
|
+
content: segText,
|
|
11297
|
+
status: "done",
|
|
11298
|
+
completedAt: at,
|
|
11299
|
+
...segParts.length ? { parts: segParts } : {}
|
|
11300
|
+
}).catch(() => void 0);
|
|
11301
|
+
}
|
|
11302
|
+
await chatStore.appendMessage({
|
|
11303
|
+
id: (0, import_node_crypto14.randomUUID)(),
|
|
11304
|
+
sessionId: deps.chatSessionId,
|
|
11305
|
+
role: "user",
|
|
11306
|
+
content: deps.text,
|
|
11307
|
+
createdAt: at,
|
|
11308
|
+
// ADR-0166 D9.1:插入带的附件也落在**这条 user 行**上(同 `/api/chat` 那侧只存引用)。
|
|
11309
|
+
...deps.attachments?.length ? { attachments: deps.attachments } : {},
|
|
11310
|
+
...deps.turnId ? { turnId: deps.turnId } : {}
|
|
11311
|
+
// 插话切段仍属同一轮(同 turnId)
|
|
11312
|
+
}).catch(() => void 0);
|
|
11313
|
+
await chatStore.appendMessage({
|
|
11314
|
+
id: nextId,
|
|
11315
|
+
sessionId: deps.chatSessionId,
|
|
11316
|
+
role: "assistant",
|
|
11317
|
+
content: "",
|
|
11318
|
+
createdAt: at,
|
|
11319
|
+
status: "running",
|
|
11320
|
+
...deps.runId ? { runId: deps.runId } : {},
|
|
11321
|
+
...deps.turnId ? { turnId: deps.turnId } : {}
|
|
11322
|
+
}).then(() => deps.ledger.bindMessage(nextId, segment)).catch(() => void 0);
|
|
11323
|
+
};
|
|
11324
|
+
return { nextId, segText, persist };
|
|
11325
|
+
}
|
|
11205
11326
|
function outputsPartProvider(scan2, chatSessionId, companyId) {
|
|
11206
11327
|
if (!scan2) return void 0;
|
|
11207
11328
|
return async () => {
|
|
@@ -11293,6 +11414,8 @@ function runBackgroundAssistantChatTurn(deps) {
|
|
|
11293
11414
|
chatStore: deps.chatStore,
|
|
11294
11415
|
chatSessionId: deps.chatSessionId,
|
|
11295
11416
|
...runId ? { runId } : {},
|
|
11417
|
+
// 与 `/api/chat` 同口径(ADR 0300 I1):消息行带这一轮的 `chat_session_turns.id`。此前后台轮不带。
|
|
11418
|
+
...deps.turnId ? { turnId: deps.turnId } : {},
|
|
11296
11419
|
now
|
|
11297
11420
|
});
|
|
11298
11421
|
const itemLedger = new ChatItemLedger({
|
|
@@ -11325,9 +11448,34 @@ function runBackgroundAssistantChatTurn(deps) {
|
|
|
11325
11448
|
);
|
|
11326
11449
|
const localParts = [];
|
|
11327
11450
|
let localSeq = 0;
|
|
11328
|
-
|
|
11451
|
+
let segmentBaseSeq = 0;
|
|
11452
|
+
const collectedParts = () => localParts.filter((p2) => p2.type !== "done" && p2.type !== "user" && p2.seq > segmentBaseSeq);
|
|
11453
|
+
let currentMsgId = assistantMsgId;
|
|
11454
|
+
const closedSegmentsText = [];
|
|
11329
11455
|
let checkpointChain = Promise.resolve();
|
|
11330
11456
|
let ckptDirty = false;
|
|
11457
|
+
if (liveTurn && typeof deps.chatStore.appendMessage === "function" && typeof deps.chatStore.updateMessage === "function") {
|
|
11458
|
+
const live = liveTurn;
|
|
11459
|
+
live.onUserInput((text6, attachments) => {
|
|
11460
|
+
const split = beginInsertedAssistantSegment({
|
|
11461
|
+
chatStore: deps.chatStore,
|
|
11462
|
+
chatSessionId: deps.chatSessionId,
|
|
11463
|
+
ledger: itemLedger,
|
|
11464
|
+
live,
|
|
11465
|
+
closingId: currentMsgId,
|
|
11466
|
+
segParts: collectedParts(),
|
|
11467
|
+
text: text6,
|
|
11468
|
+
attachments,
|
|
11469
|
+
...runId ? { runId } : {},
|
|
11470
|
+
turnId: deps.turnId,
|
|
11471
|
+
now
|
|
11472
|
+
});
|
|
11473
|
+
closedSegmentsText.push(split.segText);
|
|
11474
|
+
currentMsgId = split.nextId;
|
|
11475
|
+
segmentBaseSeq = localSeq;
|
|
11476
|
+
checkpointChain = checkpointChain.then(split.persist).catch(() => void 0);
|
|
11477
|
+
});
|
|
11478
|
+
}
|
|
11331
11479
|
normalizedSource.onNormalizedProviderEvent((event) => {
|
|
11332
11480
|
try {
|
|
11333
11481
|
if (liveTurn) liveTurn.applyNormalizedEvent(event);
|
|
@@ -11355,11 +11503,12 @@ function runBackgroundAssistantChatTurn(deps) {
|
|
|
11355
11503
|
let ckptTimer = null;
|
|
11356
11504
|
if (checkpointMs > 0 && assistantMsgId) {
|
|
11357
11505
|
ckptTimer = setInterval(() => {
|
|
11358
|
-
if (!ckptDirty) return;
|
|
11506
|
+
if (!ckptDirty || !currentMsgId) return;
|
|
11359
11507
|
ckptDirty = false;
|
|
11360
11508
|
const parts = collectedParts();
|
|
11361
11509
|
const content3 = itemLedger.projectContent();
|
|
11362
|
-
|
|
11510
|
+
const target = currentMsgId;
|
|
11511
|
+
checkpointChain = checkpointChain.then(() => deps.chatStore.updateMessage(target, {
|
|
11363
11512
|
content: content3,
|
|
11364
11513
|
status: "running",
|
|
11365
11514
|
...parts.length ? { parts } : {}
|
|
@@ -11379,11 +11528,13 @@ function runBackgroundAssistantChatTurn(deps) {
|
|
|
11379
11528
|
await finalizeAssistantRow({
|
|
11380
11529
|
chatStore: deps.chatStore,
|
|
11381
11530
|
chatSessionId: deps.chatSessionId,
|
|
11382
|
-
|
|
11531
|
+
// 插话切过段就收最后一段那一行;前面各段在切段时已转 done。
|
|
11532
|
+
assistantMsgId: currentMsgId,
|
|
11383
11533
|
content: projectedContent,
|
|
11384
11534
|
parts,
|
|
11385
11535
|
status,
|
|
11386
11536
|
...runId ? { runId } : {},
|
|
11537
|
+
...deps.turnId ? { turnId: deps.turnId } : {},
|
|
11387
11538
|
...deps.outputsPart ? { outputsPart: deps.outputsPart } : {},
|
|
11388
11539
|
now
|
|
11389
11540
|
});
|
|
@@ -11399,7 +11550,8 @@ function runBackgroundAssistantChatTurn(deps) {
|
|
|
11399
11550
|
}
|
|
11400
11551
|
}
|
|
11401
11552
|
if (liveTurn) {
|
|
11402
|
-
|
|
11553
|
+
const turnText = [...closedSegmentsText, projectedContent].join("");
|
|
11554
|
+
if (turnText) liveTurn.emit({ type: "text", text: turnText });
|
|
11403
11555
|
liveTurn.emitLive({
|
|
11404
11556
|
protocolVersion: 2,
|
|
11405
11557
|
streamId: `background:${deps.chatSessionId}`,
|
|
@@ -11407,7 +11559,7 @@ function runBackgroundAssistantChatTurn(deps) {
|
|
|
11407
11559
|
itemId: `background:${assistantMsgId ?? runId}`,
|
|
11408
11560
|
itemType: "message",
|
|
11409
11561
|
operation: "completed",
|
|
11410
|
-
payload: { role: "assistant", text:
|
|
11562
|
+
payload: { role: "assistant", text: turnText }
|
|
11411
11563
|
});
|
|
11412
11564
|
}
|
|
11413
11565
|
try {
|
|
@@ -11881,11 +12033,11 @@ function decryptFeishu(encrypt, encryptKey) {
|
|
|
11881
12033
|
function decodeBody(body2, encryptKey) {
|
|
11882
12034
|
if (typeof body2 !== "object" || body2 === null) return null;
|
|
11883
12035
|
const rec = body2;
|
|
11884
|
-
const
|
|
11885
|
-
if (typeof
|
|
12036
|
+
const enc3 = rec["encrypt"];
|
|
12037
|
+
if (typeof enc3 === "string") {
|
|
11886
12038
|
if (!encryptKey) return null;
|
|
11887
12039
|
try {
|
|
11888
|
-
const parsed = JSON.parse(decryptFeishu(
|
|
12040
|
+
const parsed = JSON.parse(decryptFeishu(enc3, encryptKey));
|
|
11889
12041
|
return typeof parsed === "object" && parsed !== null ? parsed : null;
|
|
11890
12042
|
} catch {
|
|
11891
12043
|
return null;
|
|
@@ -121002,11 +121154,11 @@ var require_lib2 = __commonJS({
|
|
|
121002
121154
|
var DEFAULT_INITIAL = "Thinking...";
|
|
121003
121155
|
var DEFAULT_EMPTY = "(no content)";
|
|
121004
121156
|
var INITIAL_SUMMARY = "[Generating...]";
|
|
121005
|
-
var
|
|
121157
|
+
var SUMMARY_MAX_CHARS2 = 50;
|
|
121006
121158
|
var ERROR_FOOTER = "\n\n\u2014 _(Generation interrupted)_";
|
|
121007
121159
|
var DEFAULT_MAX_ELEMENT_CHARS = 3e4;
|
|
121008
121160
|
var ELEMENT_ID = "stream_md";
|
|
121009
|
-
function truncateSummary(text6, max =
|
|
121161
|
+
function truncateSummary(text6, max = SUMMARY_MAX_CHARS2) {
|
|
121010
121162
|
if (!text6)
|
|
121011
121163
|
return "";
|
|
121012
121164
|
const cleaned = text6.replace(/\s+/g, " ").trim();
|
|
@@ -125204,6 +125356,90 @@ var init_state = __esm({
|
|
|
125204
125356
|
}
|
|
125205
125357
|
});
|
|
125206
125358
|
|
|
125359
|
+
// ../engine/src/upstream-stability.ts
|
|
125360
|
+
function inputsMatch(state, node2, latestWork) {
|
|
125361
|
+
const inbound = state.edgesInto(node2.id);
|
|
125362
|
+
const currInputs = new Set(
|
|
125363
|
+
inbound.filter((e) => e.kind === "data" && e.pinnedWorkId).map((e) => e.pinnedWorkId)
|
|
125364
|
+
);
|
|
125365
|
+
const latestInputs = new Set(state.workInputsOf(latestWork.id).map((i) => i.upstreamWorkId));
|
|
125366
|
+
return currInputs.size === latestInputs.size && [...currInputs].every((x2) => latestInputs.has(x2));
|
|
125367
|
+
}
|
|
125368
|
+
function isEdgeInputUnobtainable(state, edge) {
|
|
125369
|
+
const upstream = state.node(edge.fromNodeId);
|
|
125370
|
+
return !!upstream?.cancelledAt && !upstream.latestAcceptId;
|
|
125371
|
+
}
|
|
125372
|
+
function concernsCurrentDelivery(state, node2, issue2) {
|
|
125373
|
+
const targetNode = issue2.aboutNodeId ? state.node(issue2.aboutNodeId) : node2;
|
|
125374
|
+
if (!issue2.aboutWorkId || issue2.aboutWorkId === targetNode?.latestAcceptId) return true;
|
|
125375
|
+
const target = state.work(issue2.aboutWorkId);
|
|
125376
|
+
return !target?.acceptedAt;
|
|
125377
|
+
}
|
|
125378
|
+
function hasDeliveryIssue(state, node2) {
|
|
125379
|
+
return state.allIssues().some((issue2) => {
|
|
125380
|
+
if (issue2.resolvedAt !== null || issue2.intent === "advisory" || !concernsCurrentDelivery(state, node2, issue2)) return false;
|
|
125381
|
+
if (issue2.kind === "gap") return issue2.raisedByNodeId === node2.id;
|
|
125382
|
+
if (issue2.kind === "escalation") return issue2.aboutNodeId === node2.id;
|
|
125383
|
+
if (issue2.kind === "change_request") return issue2.aboutNodeId === node2.id || issue2.raisedByNodeId === node2.id;
|
|
125384
|
+
return issue2.kind === "comment" && issue2.raisedByNodeId !== null && (issue2.aboutNodeId === node2.id || issue2.raisedByNodeId === node2.id);
|
|
125385
|
+
});
|
|
125386
|
+
}
|
|
125387
|
+
function unsettledResolvedGap(state, nodeId) {
|
|
125388
|
+
return findUndeliveredResolvedGap(nodeId, state.mainWorksOf(nodeId).filter((work) => workState(work, hasOutput(work, state.artifactsOf(work.id).length)) === "success" && (!!work.acceptedAt || !hasOutput(work, state.artifactsOf(work.id).length))), state.allIssues());
|
|
125389
|
+
}
|
|
125390
|
+
function hasOrdinaryNotificationBatch(state, nodeId, issueIds) {
|
|
125391
|
+
return issueIds.some((id) => state.issue(id)?.kind === "comment") && issueIds.every((id) => {
|
|
125392
|
+
const issue2 = state.issue(id);
|
|
125393
|
+
return issue2?.kind === "comment" && issue2.aboutNodeId === nodeId && issue2.raisedByNodeId === null || issue2?.kind === "gap" && issue2.resolvedAt !== null && issue2.raisedByNodeId === nodeId;
|
|
125394
|
+
});
|
|
125395
|
+
}
|
|
125396
|
+
function isNotificationDispatch(state, node2, issueIds) {
|
|
125397
|
+
const accepted = node2.latestAcceptId ? state.work(node2.latestAcceptId) : void 0;
|
|
125398
|
+
return !!accepted && accepted.nodeVersion === node2.version && inputsMatch(state, node2, accepted) && (node2.latestProposedWorkId === accepted.id || node2.latestWorkId === accepted.id) && !unsettledResolvedGap(state, node2.id) && hasOrdinaryNotificationBatch(state, node2.id, issueIds);
|
|
125399
|
+
}
|
|
125400
|
+
function isNotificationWork(state, node2, work) {
|
|
125401
|
+
return isMainWork(work) && work.id !== node2.latestAcceptId && !hasOutput(work, state.artifactsOf(work.id).length) && work.nodeVersion === node2.version && inputsMatch(state, node2, work) && isNotificationDispatch(state, node2, work.frozenIssueIds ?? []);
|
|
125402
|
+
}
|
|
125403
|
+
function findUnstableRequiredUpstream(state, nodeId, pendingEvents = []) {
|
|
125404
|
+
const memo = /* @__PURE__ */ new Map();
|
|
125405
|
+
const visiting = /* @__PURE__ */ new Set();
|
|
125406
|
+
const mayStillChange2 = (id) => {
|
|
125407
|
+
const cached3 = memo.get(id);
|
|
125408
|
+
if (cached3 !== void 0) return cached3;
|
|
125409
|
+
if (visiting.has(id)) return true;
|
|
125410
|
+
visiting.add(id);
|
|
125411
|
+
const node2 = state.node(id);
|
|
125412
|
+
let unstable = true;
|
|
125413
|
+
if (node2?.cancelledAt && node2.latestAcceptId) {
|
|
125414
|
+
unstable = false;
|
|
125415
|
+
} else if (node2?.latestAcceptId) {
|
|
125416
|
+
const accepted = state.work(node2.latestAcceptId);
|
|
125417
|
+
const latest = node2.latestWorkId ? state.work(node2.latestWorkId) : void 0;
|
|
125418
|
+
const acceptedIsCurrent = node2.latestAcceptId === node2.latestWorkId || node2.latestAcceptId === node2.latestProposedWorkId;
|
|
125419
|
+
const latestHasOutput = latest ? hasOutput(latest, state.artifactsOf(latest.id).length) : false;
|
|
125420
|
+
const latestState = latest ? workState(latest, latestHasOutput) : null;
|
|
125421
|
+
const producing = latest && latest.id !== accepted?.id && isMainWork(latest) && !isNotificationWork(state, node2, latest) && (latestState === "running" || latestState === "retry" || latestHasOutput && latestState !== "dead");
|
|
125422
|
+
const queued = [...state.emitted, ...pendingEvents].some((event) => event.kind === "work.create" && event.nodeId === id && !isNotificationDispatch(state, node2, event.reasons.filter((r) => r.kind === "issue").map((r) => r.issueId)));
|
|
125423
|
+
unstable = !accepted || accepted.nodeVersion !== node2.version || !inputsMatch(state, node2, accepted) || !acceptedIsCurrent || !!producing || hasDeliveryIssue(state, node2) || !!unsettledResolvedGap(state, id) || queued;
|
|
125424
|
+
if (!unstable) unstable = state.edgesInto(id).some((edge) => edge.kind === "data" && edge.required && !isEdgeInputUnobtainable(state, edge) && mayStillChange2(edge.fromNodeId));
|
|
125425
|
+
}
|
|
125426
|
+
visiting.delete(id);
|
|
125427
|
+
memo.set(id, unstable);
|
|
125428
|
+
return unstable;
|
|
125429
|
+
};
|
|
125430
|
+
for (const edge of state.edgesInto(nodeId)) {
|
|
125431
|
+
if (edge.kind === "data" && edge.required && !isEdgeInputUnobtainable(state, edge) && mayStillChange2(edge.fromNodeId)) return edge.fromNodeId;
|
|
125432
|
+
}
|
|
125433
|
+
return null;
|
|
125434
|
+
}
|
|
125435
|
+
var init_upstream_stability = __esm({
|
|
125436
|
+
"../engine/src/upstream-stability.ts"() {
|
|
125437
|
+
"use strict";
|
|
125438
|
+
init_model();
|
|
125439
|
+
init_views2();
|
|
125440
|
+
}
|
|
125441
|
+
});
|
|
125442
|
+
|
|
125207
125443
|
// ../engine/src/letters.ts
|
|
125208
125444
|
function repliesSorted(state, issueId) {
|
|
125209
125445
|
return [...state.repliesOf(issueId)].sort((a, b2) => a.createdAt.localeCompare(b2.createdAt));
|
|
@@ -125578,8 +125814,17 @@ function scan(state, ctx) {
|
|
|
125578
125814
|
continue;
|
|
125579
125815
|
}
|
|
125580
125816
|
}
|
|
125581
|
-
const
|
|
125582
|
-
|
|
125817
|
+
const admitted = events.filter((event) => {
|
|
125818
|
+
if (event.kind !== "work.create") return true;
|
|
125819
|
+
const node2 = state.node(event.nodeId);
|
|
125820
|
+
return !!node2 && !dispatchBlock(state, node2, events, isNotificationDispatch(
|
|
125821
|
+
state,
|
|
125822
|
+
node2,
|
|
125823
|
+
event.reasons.filter((r) => r.kind === "issue").map((r) => r.issueId)
|
|
125824
|
+
));
|
|
125825
|
+
});
|
|
125826
|
+
const terminated = admitted.length === 0 && checkTerminated(state);
|
|
125827
|
+
return { events: admitted, terminated };
|
|
125583
125828
|
}
|
|
125584
125829
|
function checkRunningWorkTimeout(state, node2, work, ctx, events) {
|
|
125585
125830
|
const start = work.lastActivityAt ?? work.startedAt ?? work.createdAt;
|
|
@@ -125670,6 +125915,18 @@ function scanBlockersForNode(state, node2, latest) {
|
|
|
125670
125915
|
}
|
|
125671
125916
|
return blockers;
|
|
125672
125917
|
}
|
|
125918
|
+
function dispatchBlock(state, node2, pendingEvents = [], notification = false) {
|
|
125919
|
+
if (!node2.assigneeActorId) return "no_assignee";
|
|
125920
|
+
const latest = node2.latestWorkId ? state.work(node2.latestWorkId) ?? null : null;
|
|
125921
|
+
if (unexemptedVetoBlockers(scanBlockersForNode(state, node2, latest), "dispatch").length > 0) return "issue";
|
|
125922
|
+
if (notification) return null;
|
|
125923
|
+
for (const edge of state.edgesInto(node2.id)) {
|
|
125924
|
+
if (edge.kind !== "data" || !edge.required || isEdgeInputUnobtainable(state, edge)) continue;
|
|
125925
|
+
const upstream = state.node(edge.fromNodeId);
|
|
125926
|
+
if (!upstream?.latestAcceptId || isBusinessDependencyEdge(state, edge) && !businessHandoffBarrierSatisfied(state, upstream.id, upstream.latestAcceptId)) return "upstream_not_ready";
|
|
125927
|
+
}
|
|
125928
|
+
return findUnstableRequiredUpstream(state, node2.id, pendingEvents) ? "upstream_unstable" : null;
|
|
125929
|
+
}
|
|
125673
125930
|
function tryToRun(state, nodeId, ctx, events) {
|
|
125674
125931
|
const node2 = state.node(nodeId);
|
|
125675
125932
|
if (!node2) return;
|
|
@@ -125695,15 +125952,6 @@ function tryToRun(state, nodeId, ctx, events) {
|
|
|
125695
125952
|
}
|
|
125696
125953
|
return;
|
|
125697
125954
|
}
|
|
125698
|
-
const inbound = state.edgesInto(nodeId);
|
|
125699
|
-
for (const e of inbound) {
|
|
125700
|
-
if (e.kind !== "data" || !e.required) continue;
|
|
125701
|
-
if (isEdgeInputUnobtainable(state, e)) continue;
|
|
125702
|
-
const upstream = state.node(e.fromNodeId);
|
|
125703
|
-
if (!upstream?.latestAcceptId) return;
|
|
125704
|
-
if (isBusinessDependencyEdge(state, e) && !businessHandoffBarrierSatisfied(state, upstream.id, upstream.latestAcceptId)) return;
|
|
125705
|
-
}
|
|
125706
|
-
if (findUnstableRequiredUpstream(state, nodeId, events)) return;
|
|
125707
125955
|
if (state.hasQueuedWorkFor(nodeId)) return;
|
|
125708
125956
|
const workId = deriveWorkId(nodeId, state.allWorksIncludingReplies(nodeId).length + 1);
|
|
125709
125957
|
const letters = pendingLetters(state, node2);
|
|
@@ -125719,6 +125967,8 @@ function tryToRun(state, nodeId, ctx, events) {
|
|
|
125719
125967
|
if (deliveredNow.has(g2.id)) continue;
|
|
125720
125968
|
reasons.push({ kind: "issue", issueId: g2.id, issueKind: g2.kind });
|
|
125721
125969
|
}
|
|
125970
|
+
const notification = isNotificationDispatch(state, node2, reasons.filter((r) => r.kind === "issue").map((r) => r.issueId));
|
|
125971
|
+
if (dispatchBlock(state, node2, events, notification)) return;
|
|
125722
125972
|
events.push({
|
|
125723
125973
|
kind: "work.create",
|
|
125724
125974
|
workorderId: state.workorder.id,
|
|
@@ -125868,59 +126118,6 @@ function collectStallTrips(state, node2, ctx) {
|
|
|
125868
126118
|
}
|
|
125869
126119
|
return out;
|
|
125870
126120
|
}
|
|
125871
|
-
function inputsMatch(state, node2, latestWork) {
|
|
125872
|
-
const inbound = state.edgesInto(node2.id);
|
|
125873
|
-
const currInputs = new Set(
|
|
125874
|
-
inbound.filter((e) => e.kind === "data" && e.pinnedWorkId).map((e) => e.pinnedWorkId)
|
|
125875
|
-
);
|
|
125876
|
-
const latestInputs = new Set(state.workInputsOf(latestWork.id).map((i) => i.upstreamWorkId));
|
|
125877
|
-
return currInputs.size === latestInputs.size && [...currInputs].every((x2) => latestInputs.has(x2));
|
|
125878
|
-
}
|
|
125879
|
-
function findUnstableRequiredUpstream(state, nodeId, pendingEvents = []) {
|
|
125880
|
-
const memo = /* @__PURE__ */ new Map();
|
|
125881
|
-
const visiting = /* @__PURE__ */ new Set();
|
|
125882
|
-
const mayStillChange2 = (candidateId) => {
|
|
125883
|
-
const cached3 = memo.get(candidateId);
|
|
125884
|
-
if (cached3 !== void 0) return cached3;
|
|
125885
|
-
if (visiting.has(candidateId)) return true;
|
|
125886
|
-
visiting.add(candidateId);
|
|
125887
|
-
const candidate = state.node(candidateId);
|
|
125888
|
-
let unstable = false;
|
|
125889
|
-
if (!candidate) {
|
|
125890
|
-
unstable = true;
|
|
125891
|
-
} else if (candidate.cancelledAt && candidate.latestAcceptId) {
|
|
125892
|
-
unstable = false;
|
|
125893
|
-
} else if (!candidate.latestAcceptId) {
|
|
125894
|
-
unstable = true;
|
|
125895
|
-
} else {
|
|
125896
|
-
const accepted = state.work(candidate.latestAcceptId);
|
|
125897
|
-
if (!accepted || accepted.nodeVersion !== candidate.version || !inputsMatch(state, candidate, accepted)) {
|
|
125898
|
-
unstable = true;
|
|
125899
|
-
} else {
|
|
125900
|
-
const acceptedIsCurrent = candidate.latestAcceptId === candidate.latestWorkId || candidate.latestAcceptId === candidate.latestProposedWorkId;
|
|
125901
|
-
const queuedThisScan = pendingEvents.some((event) => event.kind === "work.create" && event.nodeId === candidateId);
|
|
125902
|
-
unstable = !acceptedIsCurrent || state.hasQueuedWorkFor(candidateId) || queuedThisScan;
|
|
125903
|
-
}
|
|
125904
|
-
if (!unstable) {
|
|
125905
|
-
for (const edge of state.edgesInto(candidateId)) {
|
|
125906
|
-
if (edge.kind !== "data" || !edge.required || isEdgeInputUnobtainable(state, edge)) continue;
|
|
125907
|
-
if (mayStillChange2(edge.fromNodeId)) {
|
|
125908
|
-
unstable = true;
|
|
125909
|
-
break;
|
|
125910
|
-
}
|
|
125911
|
-
}
|
|
125912
|
-
}
|
|
125913
|
-
}
|
|
125914
|
-
visiting.delete(candidateId);
|
|
125915
|
-
memo.set(candidateId, unstable);
|
|
125916
|
-
return unstable;
|
|
125917
|
-
};
|
|
125918
|
-
for (const edge of state.edgesInto(nodeId)) {
|
|
125919
|
-
if (edge.kind !== "data" || !edge.required || isEdgeInputUnobtainable(state, edge)) continue;
|
|
125920
|
-
if (mayStillChange2(edge.fromNodeId)) return edge.fromNodeId;
|
|
125921
|
-
}
|
|
125922
|
-
return null;
|
|
125923
|
-
}
|
|
125924
126121
|
function reviewMaxRetriesOf(policy) {
|
|
125925
126122
|
const act = policy.resolve({ executor: "agent", scenario: "review" }).timeoutAction;
|
|
125926
126123
|
return act.kind === "kill-rebuild" ? act.maxRetries : AGENT_REVIEW_MAX_RETRIES;
|
|
@@ -126082,10 +126279,6 @@ function mergedClosureRequirements(state, nodeId, closureActors) {
|
|
|
126082
126279
|
const kept = state.requirementsOf(nodeId).filter((r) => r.source !== "closure").map((r) => ({ reviewerActorId: r.reviewerActorId, reviewGroup: r.reviewGroup, source: r.source }));
|
|
126083
126280
|
return [...kept, ...closureReviewerSpecs(wantedClosureActors(state, nodeId, closureActors))];
|
|
126084
126281
|
}
|
|
126085
|
-
function isEdgeInputUnobtainable(state, edge) {
|
|
126086
|
-
const upstream = state.node(edge.fromNodeId);
|
|
126087
|
-
return !!upstream?.cancelledAt && !upstream.latestAcceptId;
|
|
126088
|
-
}
|
|
126089
126282
|
function isBusinessDependencyEdge(state, edge) {
|
|
126090
126283
|
const downstream = state.node(edge.toNodeId);
|
|
126091
126284
|
return edge.kind === "data" && edge.required && downstream?.fields?.[BUSINESS_HANDOFF_POLICY_FIELD] !== BUSINESS_HANDOFF_POLICY_EXEMPT;
|
|
@@ -126192,6 +126385,8 @@ function assessConvergence(state, ctx) {
|
|
|
126192
126385
|
var init_activate = __esm({
|
|
126193
126386
|
"../engine/src/activate.ts"() {
|
|
126194
126387
|
"use strict";
|
|
126388
|
+
init_upstream_stability();
|
|
126389
|
+
init_upstream_stability();
|
|
126195
126390
|
init_continuation();
|
|
126196
126391
|
init_src4();
|
|
126197
126392
|
init_src5();
|
|
@@ -130083,7 +130278,7 @@ var require_split2 = __commonJS({
|
|
|
130083
130278
|
var { StringDecoder } = require("string_decoder");
|
|
130084
130279
|
var kLast = Symbol("last");
|
|
130085
130280
|
var kDecoder = Symbol("decoder");
|
|
130086
|
-
function transform2(chunk,
|
|
130281
|
+
function transform2(chunk, enc3, cb) {
|
|
130087
130282
|
let list2;
|
|
130088
130283
|
if (this.overflow) {
|
|
130089
130284
|
const buf = this[kDecoder].write(chunk);
|
|
@@ -132699,7 +132894,9 @@ var init_store_postgres = __esm({
|
|
|
132699
132894
|
WHERE (
|
|
132700
132895
|
(e.status = 'pending' AND (e.available_at IS NULL OR e.available_at <= $1))
|
|
132701
132896
|
-- \u5D29\u6E83\u81EA\u6108\uFF1A\u5361\u5728 applied \u592A\u4E45\u7684\uFF08\u8FDB\u7A0B\u6B7B\u5728\u300C\u843D\u72B6\u6001\u300D\u4E0E\u300C\u6536\u5C3E\u300D\u4E4B\u95F4\uFF09\u4E5F\u56DE\u6536\u91CD\u8DD1
|
|
132702
|
-
OR (
|
|
132897
|
+
OR (e.status = 'applied' AND (
|
|
132898
|
+
(e.available_at IS NOT NULL AND e.available_at <= $1)
|
|
132899
|
+
OR (e.available_at IS NULL AND $2::timestamptz IS NOT NULL AND e.applied_at < $2::timestamptz)))
|
|
132703
132900
|
)
|
|
132704
132901
|
AND NOT EXISTS (
|
|
132705
132902
|
SELECT 1 FROM ${this.s}.events p
|
|
@@ -132716,13 +132913,23 @@ var init_store_postgres = __esm({
|
|
|
132716
132913
|
async markEvent(seq, status, failedReason, at) {
|
|
132717
132914
|
await this.c.query(
|
|
132718
132915
|
`UPDATE ${this.s}.events
|
|
132719
|
-
SET status = $2, failed_reason = $3,
|
|
132916
|
+
SET status = $2, failed_reason = $3, available_at = NULL,
|
|
132720
132917
|
applied_at = CASE WHEN $2 = 'applied' THEN $4::timestamptz ELSE applied_at END,
|
|
132721
132918
|
done_at = CASE WHEN $2 = 'done' THEN $4::timestamptz ELSE done_at END
|
|
132722
132919
|
WHERE seq = $1`,
|
|
132723
132920
|
[seq, status, failedReason, at]
|
|
132724
132921
|
);
|
|
132725
132922
|
}
|
|
132923
|
+
async getEvent(seq) {
|
|
132924
|
+
const res = await this.c.query(`SELECT * FROM ${this.s}.events WHERE seq = $1`, [seq]);
|
|
132925
|
+
return res.rows[0] ? toRecord(res.rows[0]) : null;
|
|
132926
|
+
}
|
|
132927
|
+
async deferEvent(seq, status, reason, availableAt) {
|
|
132928
|
+
await this.c.query(
|
|
132929
|
+
`UPDATE ${this.s}.events SET status = $2, failed_reason = $3, available_at = $4::timestamptz WHERE seq = $1`,
|
|
132930
|
+
[seq, status, reason, availableAt]
|
|
132931
|
+
);
|
|
132932
|
+
}
|
|
132726
132933
|
async isHandlerDone(seq, handlerName) {
|
|
132727
132934
|
const res = await this.c.query(
|
|
132728
132935
|
`SELECT 1 FROM ${this.s}.event_handler_log WHERE event_seq = $1 AND handler_name = $2`,
|
|
@@ -132756,7 +132963,9 @@ var init_store_postgres = __esm({
|
|
|
132756
132963
|
WHERE (
|
|
132757
132964
|
(e.status = 'pending' AND (e.available_at IS NULL OR e.available_at <= $1))
|
|
132758
132965
|
-- \u5D29\u6E83\u81EA\u6108\uFF1A\u89C1 claimNextEvent \u7684\u6CE8\u91CA
|
|
132759
|
-
OR (
|
|
132966
|
+
OR (e.status = 'applied' AND (
|
|
132967
|
+
(e.available_at IS NOT NULL AND e.available_at <= $1)
|
|
132968
|
+
OR (e.available_at IS NULL AND $2::timestamptz IS NOT NULL AND e.applied_at < $2::timestamptz)))
|
|
132760
132969
|
)
|
|
132761
132970
|
AND NOT EXISTS (SELECT 1 FROM ${this.s}.events p WHERE p.workorder_id = e.workorder_id
|
|
132762
132971
|
AND p.status IN ('pending','applied') AND p.seq < e.seq)
|
|
@@ -133139,12 +133348,29 @@ var init_plan = __esm({
|
|
|
133139
133348
|
});
|
|
133140
133349
|
|
|
133141
133350
|
// ../engine/src/handlers/workorder.ts
|
|
133142
|
-
var workorderCreate, workorderMeta, workorderPause, workorderResume, workorderPing;
|
|
133351
|
+
var workorderInitialize, workorderCreate, workorderMeta, workorderPause, workorderResume, workorderPing;
|
|
133143
133352
|
var init_workorder = __esm({
|
|
133144
133353
|
"../engine/src/handlers/workorder.ts"() {
|
|
133145
133354
|
"use strict";
|
|
133146
133355
|
init_kill();
|
|
133147
133356
|
init_plan();
|
|
133357
|
+
workorderInitialize = {
|
|
133358
|
+
name: "workorder/initialize",
|
|
133359
|
+
kind: "workorder.initialized",
|
|
133360
|
+
retryFailedEffect: true,
|
|
133361
|
+
apply(e, state, ctx) {
|
|
133362
|
+
state.updateWorkorder({ lifecycle: "active", updatedAt: ctx.at });
|
|
133363
|
+
if (!e.dispatch && !state.workorder.dispatchPaused) workorderPause.apply({
|
|
133364
|
+
kind: "workorder.paused",
|
|
133365
|
+
workorderId: e.workorderId,
|
|
133366
|
+
by: ctx.actorId,
|
|
133367
|
+
reason: e.reason ?? ""
|
|
133368
|
+
}, state, ctx);
|
|
133369
|
+
},
|
|
133370
|
+
async effect(e, ctx) {
|
|
133371
|
+
if (!e.dispatch) await ctx.cancelKilledSessions(e.workorderId);
|
|
133372
|
+
}
|
|
133373
|
+
};
|
|
133148
133374
|
workorderCreate = {
|
|
133149
133375
|
name: "workorder/create",
|
|
133150
133376
|
kind: "workorder.created",
|
|
@@ -133181,6 +133407,7 @@ var init_workorder = __esm({
|
|
|
133181
133407
|
workorderPause = {
|
|
133182
133408
|
name: "workorder/pause",
|
|
133183
133409
|
kind: "workorder.paused",
|
|
133410
|
+
retryFailedEffect: true,
|
|
133184
133411
|
apply(e, state, ctx) {
|
|
133185
133412
|
state.updateWorkorder({ dispatchPaused: true, pausedBy: e.by, pausedReason: e.reason, updatedAt: ctx.at });
|
|
133186
133413
|
killAllWorks(state, ctx.at);
|
|
@@ -133226,6 +133453,7 @@ var workCreate, workRedispatch, workSnapshotRecorded, workKill, workResponse, wo
|
|
|
133226
133453
|
var init_work = __esm({
|
|
133227
133454
|
"../engine/src/handlers/work.ts"() {
|
|
133228
133455
|
"use strict";
|
|
133456
|
+
init_upstream_stability();
|
|
133229
133457
|
init_continuation();
|
|
133230
133458
|
init_views2();
|
|
133231
133459
|
init_kill();
|
|
@@ -133538,6 +133766,10 @@ var init_work = __esm({
|
|
|
133538
133766
|
apply(e, state, ctx) {
|
|
133539
133767
|
const w2 = state.work(e.workId);
|
|
133540
133768
|
if (!w2 || w2.deadAt) return;
|
|
133769
|
+
const node2 = state.node(w2.nodeId);
|
|
133770
|
+
if (e.upstreamStabilityVersion === 1 && node2 && isMainWork(w2) && w2.id !== node2.latestAcceptId && !hasOutput(w2, state.artifactsOf(w2.id).length) && (e.artifacts.length > 0 || e.conclusion != null) && hasOrdinaryNotificationBatch(state, node2.id, w2.frozenIssueIds ?? []) && findUnstableRequiredUpstream(state, node2.id)) {
|
|
133771
|
+
throw new Error("\u4E0A\u6E38\u4EA4\u4ED8\u5C1A\u672A\u7A33\u5B9A\uFF1A\u672C\u8F6E\u53EF\u7EE7\u7EED\u7B54\u590D\u901A\u77E5\uFF0C\u6682\u4E0D\u80FD\u63D0\u4EA4\u65B0\u4EA4\u4ED8\uFF1B\u8BF7\u5728\u4E0A\u6E38\u7A33\u5B9A\u540E\u91CD\u8BD5");
|
|
133772
|
+
}
|
|
133541
133773
|
if (e.artifacts.length === 0 && w2.acceptanceState === "accepted" && state.artifactsOf(e.workId).length > 0) {
|
|
133542
133774
|
return;
|
|
133543
133775
|
}
|
|
@@ -134150,8 +134382,9 @@ var init_handlers = __esm({
|
|
|
134150
134382
|
init_continuation2();
|
|
134151
134383
|
init_types();
|
|
134152
134384
|
HANDLERS = [
|
|
134153
|
-
/* ── 工作区级(
|
|
134385
|
+
/* ── 工作区级(6)── */
|
|
134154
134386
|
erase(workorderCreate),
|
|
134387
|
+
erase(workorderInitialize),
|
|
134155
134388
|
erase(workorderMeta),
|
|
134156
134389
|
erase(workorderPause),
|
|
134157
134390
|
erase(workorderResume),
|
|
@@ -134204,6 +134437,7 @@ var init_handlers = __esm({
|
|
|
134204
134437
|
|
|
134205
134438
|
// ../engine/src/bus.ts
|
|
134206
134439
|
function versionCommandEvent(event) {
|
|
134440
|
+
if (event.kind === "work.submit_output") return { ...event, upstreamStabilityVersion: 1 };
|
|
134207
134441
|
if (event.kind === "work.create" || event.kind === "review.create") {
|
|
134208
134442
|
return { ...event, pauseGateVersion: 1, ...event.kind === "work.create" ? { continuationGateVersion: 1 } : {} };
|
|
134209
134443
|
}
|
|
@@ -134228,6 +134462,9 @@ function versionCommandEvent(event) {
|
|
|
134228
134462
|
return event;
|
|
134229
134463
|
}
|
|
134230
134464
|
}
|
|
134465
|
+
function errorMessage(err) {
|
|
134466
|
+
return err instanceof Error ? err.message : String(err);
|
|
134467
|
+
}
|
|
134231
134468
|
function emptySnapshotPlaceholder(record8) {
|
|
134232
134469
|
return {
|
|
134233
134470
|
workorder: {
|
|
@@ -134258,7 +134495,7 @@ function emptySnapshotPlaceholder(record8) {
|
|
|
134258
134495
|
reviews: []
|
|
134259
134496
|
};
|
|
134260
134497
|
}
|
|
134261
|
-
var SYSTEM_ACTOR, NOOP_IO, SYSTEM_CLOCK, HandlerRegistry, DEFAULT_STUCK_APPLIED_RECOVERY_MS, SETTLE_FOREIGN_PROGRESS_FALLBACK_MS, EngineBus, ApplyFailure, sleep3;
|
|
134498
|
+
var SYSTEM_ACTOR, NOOP_IO, SYSTEM_CLOCK, HandlerRegistry, DEFAULT_STUCK_APPLIED_RECOVERY_MS, SETTLE_FOREIGN_PROGRESS_FALLBACK_MS, EVENT_RETRY_DELAY_MS, EngineBus, ApplyFailure, sleep3;
|
|
134262
134499
|
var init_bus = __esm({
|
|
134263
134500
|
"../engine/src/bus.ts"() {
|
|
134264
134501
|
"use strict";
|
|
@@ -134268,6 +134505,7 @@ var init_bus = __esm({
|
|
|
134268
134505
|
init_model();
|
|
134269
134506
|
init_handlers();
|
|
134270
134507
|
init_state();
|
|
134508
|
+
init_upstream_stability();
|
|
134271
134509
|
init_continuation();
|
|
134272
134510
|
SYSTEM_ACTOR = "actor:system:engine";
|
|
134273
134511
|
NOOP_IO = {
|
|
@@ -134299,6 +134537,7 @@ var init_bus = __esm({
|
|
|
134299
134537
|
};
|
|
134300
134538
|
DEFAULT_STUCK_APPLIED_RECOVERY_MS = 5 * 6e4;
|
|
134301
134539
|
SETTLE_FOREIGN_PROGRESS_FALLBACK_MS = 200;
|
|
134540
|
+
EVENT_RETRY_DELAY_MS = 1e3;
|
|
134302
134541
|
EngineBus = class {
|
|
134303
134542
|
store;
|
|
134304
134543
|
io;
|
|
@@ -134458,6 +134697,7 @@ var init_bus = __esm({
|
|
|
134458
134697
|
if (!await this.drainOne()) break;
|
|
134459
134698
|
}
|
|
134460
134699
|
}
|
|
134700
|
+
await this.assertProcessed([seq]);
|
|
134461
134701
|
}
|
|
134462
134702
|
/** 同一命令的一组最终修改一起入队。scan-on-empty 在末项之前始终看到 pending,不能派发中间状态。 */
|
|
134463
134703
|
async submitBatchAndProcess(inputs) {
|
|
@@ -134484,6 +134724,17 @@ var init_bus = __esm({
|
|
|
134484
134724
|
} else {
|
|
134485
134725
|
for (let i = 0; i < 2e3; i++) if (!await this.drainOne()) break;
|
|
134486
134726
|
}
|
|
134727
|
+
await this.assertProcessed(seqs);
|
|
134728
|
+
}
|
|
134729
|
+
async assertProcessed(seqs) {
|
|
134730
|
+
await this.store.transaction(async (tx) => {
|
|
134731
|
+
for (const seq of seqs) {
|
|
134732
|
+
const record8 = await tx.getEvent(seq);
|
|
134733
|
+
if (record8?.status !== "done" || record8.failedReason) {
|
|
134734
|
+
throw new Error(`engine event ${seq} ${record8?.status ?? "missing"}: ${record8?.failedReason ?? "processing has not completed; retry later"}`);
|
|
134735
|
+
}
|
|
134736
|
+
}
|
|
134737
|
+
});
|
|
134487
134738
|
}
|
|
134488
134739
|
/* ═══════════════════════ 调度器主循环 ═══════════════════════ */
|
|
134489
134740
|
/**
|
|
@@ -134533,8 +134784,7 @@ var init_bus = __esm({
|
|
|
134533
134784
|
}
|
|
134534
134785
|
touched.add(record8.workorderId);
|
|
134535
134786
|
try {
|
|
134536
|
-
await this.applyRecord(record8);
|
|
134537
|
-
await this.effectRecord(record8);
|
|
134787
|
+
if (await this.applyRecord(record8)) await this.effectRecord(record8);
|
|
134538
134788
|
} catch (err) {
|
|
134539
134789
|
console.error(`[bus] event ${record8.seq} ${record8.event.kind}:`, err);
|
|
134540
134790
|
}
|
|
@@ -134665,9 +134915,10 @@ var init_bus = __esm({
|
|
|
134665
134915
|
/* ═══════════════════════ 旧 drain(测试兼容) ═══════════════════════ */
|
|
134666
134916
|
/** 取一条事件 apply+effect,然后 scan 其工单。仅测试用——生产代码走 run() 循环。 */
|
|
134667
134917
|
async drainOne() {
|
|
134668
|
-
const
|
|
134669
|
-
if (!
|
|
134670
|
-
|
|
134918
|
+
const phase = await this.applyPhase();
|
|
134919
|
+
if (!phase) return false;
|
|
134920
|
+
const { record: record8, applied } = phase;
|
|
134921
|
+
if (applied) await this.effectPhase(record8);
|
|
134671
134922
|
this.emitEvents([record8]);
|
|
134672
134923
|
try {
|
|
134673
134924
|
const result = await this.scan(record8.workorderId);
|
|
@@ -134684,10 +134935,11 @@ var init_bus = __esm({
|
|
|
134684
134935
|
async drain(limit = 1e3) {
|
|
134685
134936
|
let processed = 0, failed = 0;
|
|
134686
134937
|
for (let i = 0; i < limit; i++) {
|
|
134687
|
-
const
|
|
134688
|
-
if (!
|
|
134938
|
+
const phase = await this.applyPhase();
|
|
134939
|
+
if (!phase) break;
|
|
134940
|
+
const { record: record8, applied } = phase;
|
|
134689
134941
|
processed++;
|
|
134690
|
-
const ok3 = await this.effectPhase(record8);
|
|
134942
|
+
const ok3 = applied && await this.effectPhase(record8);
|
|
134691
134943
|
if (!ok3) failed++;
|
|
134692
134944
|
this.emitEvents([record8]);
|
|
134693
134945
|
}
|
|
@@ -134699,7 +134951,7 @@ var init_bus = __esm({
|
|
|
134699
134951
|
* 公开方法,供 kernel-bridge 和 run() 共用。
|
|
134700
134952
|
*/
|
|
134701
134953
|
async applyRecord(record8) {
|
|
134702
|
-
await this.store.transaction(async (tx) => {
|
|
134954
|
+
const applied = await this.store.transaction(async (tx) => {
|
|
134703
134955
|
const snapshot = await tx.loadWorkorder(record8.workorderId);
|
|
134704
134956
|
const state = new WorkorderState(snapshot ?? emptySnapshotPlaceholder(record8));
|
|
134705
134957
|
const ctx = {
|
|
@@ -134708,10 +134960,15 @@ var init_bus = __esm({
|
|
|
134708
134960
|
actorId: record8.actorId,
|
|
134709
134961
|
config: this.config
|
|
134710
134962
|
};
|
|
134963
|
+
const completedHandlers = [];
|
|
134711
134964
|
for (const h of this.registry.for(record8.event.kind)) {
|
|
134712
134965
|
if (await tx.isHandlerDone(record8.seq, h.name)) continue;
|
|
134713
|
-
|
|
134714
|
-
|
|
134966
|
+
try {
|
|
134967
|
+
h.apply(record8.event, state, ctx);
|
|
134968
|
+
} catch (err) {
|
|
134969
|
+
throw new ApplyFailure(record8, errorMessage(err));
|
|
134970
|
+
}
|
|
134971
|
+
completedHandlers.push(h.name);
|
|
134715
134972
|
}
|
|
134716
134973
|
await tx.applyMutations(record8.workorderId, state.mutations);
|
|
134717
134974
|
if (state.emitted.length) {
|
|
@@ -134728,20 +134985,28 @@ var init_bus = __esm({
|
|
|
134728
134985
|
...eventAnchors(event)
|
|
134729
134986
|
})));
|
|
134730
134987
|
}
|
|
134988
|
+
for (const name of completedHandlers) await tx.markHandlerDone(record8.seq, name);
|
|
134731
134989
|
await tx.markEvent(record8.seq, "applied", null, this.clock.now());
|
|
134990
|
+
return true;
|
|
134732
134991
|
}).catch(async (err) => {
|
|
134733
|
-
|
|
134734
|
-
|
|
134735
|
-
|
|
134736
|
-
|
|
134737
|
-
|
|
134738
|
-
}
|
|
134739
|
-
|
|
134992
|
+
const permanent = !record8.appliedAt && (err instanceof ApplyFailure || /^(22|23)/.test(String(err?.code ?? "")));
|
|
134993
|
+
const reason = errorMessage(err);
|
|
134994
|
+
const retryStatus = record8.appliedAt ? "applied" : "pending";
|
|
134995
|
+
await this.store.transaction((tx) => permanent ? tx.markEvent(record8.seq, "failed", reason, this.clock.now()) : tx.deferEvent(record8.seq, retryStatus, reason, this.retryAt()));
|
|
134996
|
+
record8.status = permanent ? "failed" : retryStatus;
|
|
134997
|
+
console.error(`[bus] apply ${record8.seq} ${record8.status}: ${reason}`);
|
|
134998
|
+
return false;
|
|
134740
134999
|
});
|
|
134741
135000
|
this.emitApplied(record8.workorderId);
|
|
135001
|
+
if (applied) record8.status = "applied";
|
|
135002
|
+
return applied;
|
|
135003
|
+
}
|
|
135004
|
+
retryAt() {
|
|
135005
|
+
return new Date(Date.parse(this.clock.now()) + EVENT_RETRY_DELAY_MS).toISOString();
|
|
134742
135006
|
}
|
|
134743
135007
|
/** 事务二:跑 IO + 收尾。 */
|
|
134744
135008
|
async effectRecord(record8) {
|
|
135009
|
+
if (record8.status !== "applied") return false;
|
|
134745
135010
|
const handlers = this.registry.for(record8.event.kind).filter((h) => h.effect);
|
|
134746
135011
|
const buffered = [];
|
|
134747
135012
|
const ctx = {
|
|
@@ -134753,32 +135018,53 @@ var init_bus = __esm({
|
|
|
134753
135018
|
dispatchReview: (id, nodeId, reviewerActorId) => this.io.dispatchReview(id, nodeId, reviewerActorId),
|
|
134754
135019
|
canDispatchWork: async (workorderId, workId, opts) => {
|
|
134755
135020
|
const snap = await this.store.transaction((tx) => tx.loadWorkorder(workorderId));
|
|
134756
|
-
if (!snap || snap.workorder.dispatchPaused) return false;
|
|
135021
|
+
if (!snap || snap.workorder.lifecycle !== "active" || snap.workorder.dispatchPaused) return false;
|
|
134757
135022
|
const work = snap.works.find((row) => row.id === workId);
|
|
134758
135023
|
if (work && work.lane === "main" && !work.startedAt && !work.sessionRef && !work.lastActivityAt) {
|
|
134759
|
-
const
|
|
134760
|
-
if (
|
|
135024
|
+
const node3 = snap.nodes.find((row) => row.id === work.nodeId);
|
|
135025
|
+
if (node3 && !node3.continuationBudget && this.io.continuationPolicy) {
|
|
134761
135026
|
const policy = await this.io.continuationPolicy(work.assigneeActorId);
|
|
134762
135027
|
if (policy) {
|
|
134763
135028
|
if (!Number.isSafeInteger(policy.maxRounds) || policy.maxRounds < 1 || policy.maxRounds > 100) {
|
|
134764
135029
|
throw new Error(`invalid continuation round limit for ${work.assigneeActorId}`);
|
|
134765
135030
|
}
|
|
134766
|
-
buffered.push({ event: { kind: "continuation.initialized", workorderId, nodeId:
|
|
135031
|
+
buffered.push({ event: { kind: "continuation.initialized", workorderId, nodeId: node3.id, rounds: policy.maxRounds } });
|
|
134767
135032
|
buffered.push({ event: { kind: "work.redispatch", workorderId, workId } });
|
|
134768
135033
|
return false;
|
|
134769
135034
|
}
|
|
134770
135035
|
}
|
|
134771
|
-
if (
|
|
135036
|
+
if (node3 && continuationExhausted(new WorkorderState(snap), node3)) return false;
|
|
134772
135037
|
}
|
|
134773
135038
|
if (opts?.neverStarted && work) {
|
|
134774
|
-
const
|
|
134775
|
-
if (work.startedAt || work.sessionRef || !
|
|
135039
|
+
const node3 = snap.nodes.find((row) => row.id === work.nodeId);
|
|
135040
|
+
if (work.startedAt || work.sessionRef || !node3 || node3.cancelledAt || node3.latestWorkId !== workId) return false;
|
|
134776
135041
|
}
|
|
134777
|
-
|
|
135042
|
+
if (!work || work.status !== "running" || work.deadAt || work.cancelledAt || work.endedAt) return false;
|
|
135043
|
+
const node2 = snap.nodes.find((row) => row.id === work.nodeId);
|
|
135044
|
+
if (!node2 || node2.cancelledAt) return false;
|
|
135045
|
+
const forced = record8.event.kind === "work.create" && record8.event.reasons.some((r) => r.kind === "forced");
|
|
135046
|
+
if (work.lane === "main" && !forced && !work.startedAt && !work.sessionRef) {
|
|
135047
|
+
if (node2.latestWorkId !== work.id) return false;
|
|
135048
|
+
const state = new WorkorderState(snap);
|
|
135049
|
+
const blocked = work.nodeVersion !== node2.version || !inputsMatch(state, node2, work) || dispatchBlock(state, node2, [], isNotificationWork(state, node2, work));
|
|
135050
|
+
if (blocked) {
|
|
135051
|
+
if (record8.event.kind === "work.create") await ctx.cancelPreviousWork(node2.id, work.id);
|
|
135052
|
+
buffered.push({ event: {
|
|
135053
|
+
kind: "work.kill",
|
|
135054
|
+
workorderId,
|
|
135055
|
+
nodeId: node2.id,
|
|
135056
|
+
workId: work.id,
|
|
135057
|
+
reason: "\u6D3E\u53D1\u524D\u6761\u4EF6\u5DF2\u53D8\u5316\uFF0C\u7B49\u5F85\u4F9D\u8D56\u6216\u4E8B\u9879\u89E3\u9664\u540E\u91CD\u8BD5"
|
|
135058
|
+
} });
|
|
135059
|
+
buffered.push({ event: { kind: "plan.node_retry", workorderId, nodeId: node2.id, by: SYSTEM_ACTOR } });
|
|
135060
|
+
return false;
|
|
135061
|
+
}
|
|
135062
|
+
}
|
|
135063
|
+
return true;
|
|
134778
135064
|
},
|
|
134779
135065
|
canDispatchReview: async (workorderId, reviewId) => {
|
|
134780
135066
|
const snap = await this.store.transaction((tx) => tx.loadWorkorder(workorderId));
|
|
134781
|
-
if (!snap || snap.workorder.dispatchPaused) return false;
|
|
135067
|
+
if (!snap || snap.workorder.lifecycle !== "active" || snap.workorder.dispatchPaused) return false;
|
|
134782
135068
|
const review = snap.reviews.find((row) => row.id === reviewId);
|
|
134783
135069
|
return review?.status === "running" && !review.cancelledAt && !review.endedAt;
|
|
134784
135070
|
},
|
|
@@ -134795,19 +135081,14 @@ var init_bus = __esm({
|
|
|
134795
135081
|
// apply 已把被杀 work/review 置 deadAt/cancelledAt,这里按 store 找它们仍挂着的会话 cancel
|
|
134796
135082
|
//(deadAt 且 endedAt 未置 = 刚被杀未退出的在途会话)。没会话 / 已退 → no-op。
|
|
134797
135083
|
cancelKilledSessions: async (_workorderId, reviewScope) => {
|
|
134798
|
-
|
|
134799
|
-
try {
|
|
134800
|
-
snap = await this.store.transaction((tx) => tx.loadWorkorder(record8.workorderId));
|
|
134801
|
-
} catch (err) {
|
|
134802
|
-
console.warn(`[bus] cancelKilledSessions ${record8.workorderId} \u8BFB\u5FEB\u7167\u5931\u8D25: ${String(err)}`);
|
|
134803
|
-
return;
|
|
134804
|
-
}
|
|
135084
|
+
const snap = await this.store.transaction((tx) => tx.loadWorkorder(record8.workorderId));
|
|
134805
135085
|
if (!snap) return;
|
|
135086
|
+
const failures = [];
|
|
134806
135087
|
const cancel = async (id, what) => {
|
|
134807
135088
|
try {
|
|
134808
135089
|
await this.io.cancelSession(id);
|
|
134809
135090
|
} catch (err) {
|
|
134810
|
-
|
|
135091
|
+
failures.push(`${what} ${id}: ${errorMessage(err)}`);
|
|
134811
135092
|
}
|
|
134812
135093
|
};
|
|
134813
135094
|
for (const w2 of reviewScope === void 0 ? snap.works : []) {
|
|
@@ -134819,10 +135100,12 @@ var init_bus = __esm({
|
|
|
134819
135100
|
))) continue;
|
|
134820
135101
|
if (r.cancelledAt && r.endedAt === null) await cancel(r.id, "review");
|
|
134821
135102
|
}
|
|
135103
|
+
if (failures.length) throw new Error(`session cancellation incomplete: ${failures.join("; ")}`);
|
|
134822
135104
|
},
|
|
134823
135105
|
notify: (ids2, payload2) => this.io.notify(ids2, payload2)
|
|
134824
135106
|
};
|
|
134825
135107
|
let ok3 = true;
|
|
135108
|
+
let failureReason = null;
|
|
134826
135109
|
for (const h of handlers) {
|
|
134827
135110
|
const effectKey = `${h.name}#effect`;
|
|
134828
135111
|
if (record8.appliedAt && await this.store.transaction((tx) => tx.isHandlerDone(record8.seq, effectKey))) {
|
|
@@ -134830,6 +135113,7 @@ var init_bus = __esm({
|
|
|
134830
135113
|
}
|
|
134831
135114
|
let lastErr = "";
|
|
134832
135115
|
for (let attempt = 1; attempt <= this.maxEffectAttempts; attempt++) {
|
|
135116
|
+
buffered.length = 0;
|
|
134833
135117
|
try {
|
|
134834
135118
|
await h.effect(record8.event, ctx);
|
|
134835
135119
|
lastErr = "";
|
|
@@ -134840,27 +135124,30 @@ var init_bus = __esm({
|
|
|
134840
135124
|
}
|
|
134841
135125
|
if (lastErr) {
|
|
134842
135126
|
ok3 = false;
|
|
135127
|
+
if (h.retryFailedEffect) {
|
|
135128
|
+
await this.store.transaction((tx) => tx.deferEvent(record8.seq, "applied", lastErr, this.retryAt()));
|
|
135129
|
+
return false;
|
|
135130
|
+
}
|
|
135131
|
+
failureReason = lastErr;
|
|
134843
135132
|
} else {
|
|
134844
|
-
await this.store.transaction((tx) =>
|
|
135133
|
+
await this.store.transaction(async (tx) => {
|
|
135134
|
+
if (buffered.length) await tx.appendEvents(buffered.map((b2) => ({
|
|
135135
|
+
companyId: record8.companyId,
|
|
135136
|
+
workorderId: record8.workorderId,
|
|
135137
|
+
actorId: b2.actorId ?? SYSTEM_ACTOR,
|
|
135138
|
+
handActorId: null,
|
|
135139
|
+
event: versionCommandEvent(b2.event),
|
|
135140
|
+
causedBySeq: record8.seq,
|
|
135141
|
+
origin: "effect",
|
|
135142
|
+
dedupKey: b2.dedupKey ?? null,
|
|
135143
|
+
createdAt: this.clock.now(),
|
|
135144
|
+
...eventAnchors(b2.event)
|
|
135145
|
+
})));
|
|
135146
|
+
await tx.markHandlerDone(record8.seq, effectKey);
|
|
135147
|
+
});
|
|
134845
135148
|
}
|
|
134846
135149
|
}
|
|
134847
|
-
await this.store.transaction(
|
|
134848
|
-
if (buffered.length) {
|
|
134849
|
-
await tx.appendEvents(buffered.map((b2) => ({
|
|
134850
|
-
companyId: record8.companyId,
|
|
134851
|
-
workorderId: record8.workorderId,
|
|
134852
|
-
actorId: b2.actorId ?? SYSTEM_ACTOR,
|
|
134853
|
-
handActorId: null,
|
|
134854
|
-
event: versionCommandEvent(b2.event),
|
|
134855
|
-
causedBySeq: record8.seq,
|
|
134856
|
-
origin: "effect",
|
|
134857
|
-
dedupKey: b2.dedupKey ?? null,
|
|
134858
|
-
createdAt: this.clock.now(),
|
|
134859
|
-
...eventAnchors(b2.event)
|
|
134860
|
-
})));
|
|
134861
|
-
}
|
|
134862
|
-
await tx.markEvent(record8.seq, "done", null, this.clock.now());
|
|
134863
|
-
});
|
|
135150
|
+
await this.store.transaction((tx) => tx.markEvent(record8.seq, "done", failureReason, this.clock.now()));
|
|
134864
135151
|
return ok3;
|
|
134865
135152
|
}
|
|
134866
135153
|
/* ═══════════════════════ scan:唯一的调度入口 ═══════════════════════ */
|
|
@@ -134926,57 +135213,10 @@ var init_bus = __esm({
|
|
|
134926
135213
|
}
|
|
134927
135214
|
/* ═══════════════════════ 内部:旧 applyPhase(claim + apply 一体) ═══════════════════════ */
|
|
134928
135215
|
async applyPhase() {
|
|
134929
|
-
|
|
134930
|
-
|
|
134931
|
-
|
|
134932
|
-
|
|
134933
|
-
if (snapshot?.workorder.doneAt && record8.event.kind !== "work.content_edited") {
|
|
134934
|
-
await tx.applyMutations(record8.workorderId, [{
|
|
134935
|
-
t: "workorder.update",
|
|
134936
|
-
patch: { doneAt: null }
|
|
134937
|
-
}]);
|
|
134938
|
-
}
|
|
134939
|
-
const state = new WorkorderState(snapshot ?? emptySnapshotPlaceholder(record8));
|
|
134940
|
-
const ctx = {
|
|
134941
|
-
seq: record8.seq,
|
|
134942
|
-
at: record8.createdAt,
|
|
134943
|
-
actorId: record8.actorId,
|
|
134944
|
-
config: this.config
|
|
134945
|
-
};
|
|
134946
|
-
for (const h of this.registry.for(record8.event.kind)) {
|
|
134947
|
-
if (await tx.isHandlerDone(record8.seq, h.name)) continue;
|
|
134948
|
-
h.apply(record8.event, state, ctx);
|
|
134949
|
-
await tx.markHandlerDone(record8.seq, h.name);
|
|
134950
|
-
}
|
|
134951
|
-
await tx.applyMutations(record8.workorderId, state.mutations);
|
|
134952
|
-
if (state.emitted.length) {
|
|
134953
|
-
await tx.appendEvents(state.emitted.map((event) => ({
|
|
134954
|
-
companyId: record8.companyId,
|
|
134955
|
-
workorderId: record8.workorderId,
|
|
134956
|
-
actorId: SYSTEM_ACTOR,
|
|
134957
|
-
handActorId: null,
|
|
134958
|
-
event: versionCommandEvent(event),
|
|
134959
|
-
causedBySeq: record8.seq,
|
|
134960
|
-
origin: "apply",
|
|
134961
|
-
dedupKey: null,
|
|
134962
|
-
createdAt: record8.createdAt,
|
|
134963
|
-
...eventAnchors(event)
|
|
134964
|
-
})));
|
|
134965
|
-
}
|
|
134966
|
-
await tx.markEvent(record8.seq, "applied", null, this.clock.now());
|
|
134967
|
-
return record8;
|
|
134968
|
-
}).catch(async (err) => {
|
|
134969
|
-
if (err instanceof ApplyFailure) {
|
|
134970
|
-
await this.store.transaction(
|
|
134971
|
-
(tx) => tx.markEvent(err.record.seq, "failed", err.reason, this.clock.now())
|
|
134972
|
-
);
|
|
134973
|
-
return err.record;
|
|
134974
|
-
}
|
|
134975
|
-
throw err;
|
|
134976
|
-
}).then((record8) => {
|
|
134977
|
-
if (record8) this.emitApplied(record8.workorderId);
|
|
134978
|
-
return record8;
|
|
134979
|
-
});
|
|
135216
|
+
const record8 = await this.store.transaction((tx) => tx.claimNextEvent(this.clock.now(), this.recoverAppliedBefore()));
|
|
135217
|
+
if (!record8) return null;
|
|
135218
|
+
if (record8.event.kind !== "work.content_edited") await this.unmarkDone(record8.workorderId);
|
|
135219
|
+
return { record: record8, applied: await this.applyRecord(record8) };
|
|
134980
135220
|
}
|
|
134981
135221
|
async effectPhase(record8) {
|
|
134982
135222
|
return this.effectRecord(record8);
|
|
@@ -134998,7 +135238,7 @@ var init_bus = __esm({
|
|
|
134998
135238
|
const events = await this.store.transaction((tx) => tx.listEvents(workorderId));
|
|
134999
135239
|
let state = null;
|
|
135000
135240
|
for (const record8 of events) {
|
|
135001
|
-
if (record8.origin === "effect") continue;
|
|
135241
|
+
if (record8.status === "failed" || record8.status === "pending" || record8.origin === "effect") continue;
|
|
135002
135242
|
if (!state) state = new WorkorderState(emptySnapshotPlaceholder(record8));
|
|
135003
135243
|
for (const h of this.registry.for(record8.event.kind)) {
|
|
135004
135244
|
h.apply(record8.event, state, {
|
|
@@ -138992,16 +139232,16 @@ function classifyExitReason(info) {
|
|
|
138992
139232
|
if (AUTH_RE.test(msg)) return "auth-error";
|
|
138993
139233
|
return info.reason;
|
|
138994
139234
|
}
|
|
138995
|
-
function quotaResetHorizon(
|
|
138996
|
-
if (!
|
|
138997
|
-
if (/\b(?:jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)[a-z]*\.?\s+\d{1,2}/i.test(
|
|
138998
|
-
if (/\d{4}-\d{2}-\d{2}/.test(
|
|
138999
|
-
if (/\b\d{1,2}(?::\d{2})?\s*(?:am|pm)\b/i.test(
|
|
139235
|
+
function quotaResetHorizon(errorMessage2) {
|
|
139236
|
+
if (!errorMessage2) return "unknown";
|
|
139237
|
+
if (/\b(?:jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)[a-z]*\.?\s+\d{1,2}/i.test(errorMessage2)) return "long";
|
|
139238
|
+
if (/\d{4}-\d{2}-\d{2}/.test(errorMessage2)) return "long";
|
|
139239
|
+
if (/\b\d{1,2}(?::\d{2})?\s*(?:am|pm)\b/i.test(errorMessage2)) return "short";
|
|
139000
139240
|
return "unknown";
|
|
139001
139241
|
}
|
|
139002
|
-
function extractResetHint(
|
|
139003
|
-
if (!
|
|
139004
|
-
const m2 = /((?:resets?|try again at)\s+[^·。\n]{1,48})/i.exec(
|
|
139242
|
+
function extractResetHint(errorMessage2) {
|
|
139243
|
+
if (!errorMessage2) return void 0;
|
|
139244
|
+
const m2 = /((?:resets?|try again at)\s+[^·。\n]{1,48})/i.exec(errorMessage2);
|
|
139005
139245
|
return m2?.[1]?.trim().replace(/[.,;]$/, "");
|
|
139006
139246
|
}
|
|
139007
139247
|
var QUOTA_RE2, UNREACHABLE_RE, AUTH_RE;
|
|
@@ -140312,7 +140552,7 @@ var init_dispatcher = __esm({
|
|
|
140312
140552
|
assertSpawnAttemptCurrent(jobKey, attempt) {
|
|
140313
140553
|
if (!this.isSpawnAttemptCurrent(jobKey, attempt)) throw new SpawnAttemptStale(jobKey);
|
|
140314
140554
|
}
|
|
140315
|
-
async recordSpawnFailure(jobKey, spec, reason,
|
|
140555
|
+
async recordSpawnFailure(jobKey, spec, reason, errorMessage2, bypassScheduling = false) {
|
|
140316
140556
|
if (bypassScheduling) return;
|
|
140317
140557
|
if (!this.strikeLedgerLive) return;
|
|
140318
140558
|
const seqAtVerdict = this.opts.kernel.model.lastSeq.get(spec.artifactId) ?? 0;
|
|
@@ -140341,7 +140581,7 @@ var init_dispatcher = __esm({
|
|
|
140341
140581
|
firstFailedAt: prev?.firstFailedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
140342
140582
|
lastReason: reason,
|
|
140343
140583
|
totalFailures: (prev?.totalFailures ?? prev?.count ?? 0) + 1,
|
|
140344
|
-
...
|
|
140584
|
+
...errorMessage2 ? { lastErrorMessage: errorMessage2.slice(0, 400) } : {},
|
|
140345
140585
|
// 半开一旦开启就**粘着**,直到真的成功(自己落了 op)才随整条记录清掉。
|
|
140346
140586
|
// 不粘的话:试探失败却因自愈类/宽限期没能立刻回熔断时,标记会丢,等于白送回满血 3 次。
|
|
140347
140587
|
...prev?.halfOpen ? { halfOpen: true } : {},
|
|
@@ -142800,6 +143040,10 @@ var init_kernel_bridge = __esm({
|
|
|
142800
143040
|
* 用来兜住"本进程没收到事件"的写入——多实例部署下别的实例改的工单就属于这种。
|
|
142801
143041
|
*/
|
|
142802
143042
|
async refreshModel(opts) {
|
|
143043
|
+
if (opts?.workorderId) {
|
|
143044
|
+
this.trackedWorkorders.add(opts.workorderId);
|
|
143045
|
+
this.markWorkorderDirty(opts.workorderId);
|
|
143046
|
+
}
|
|
142803
143047
|
if (opts?.resync) this.resyncRequested = true;
|
|
142804
143048
|
await this.refreshTracked();
|
|
142805
143049
|
}
|
|
@@ -144289,6 +144533,24 @@ var init_kernel_bridge = __esm({
|
|
|
144289
144533
|
}
|
|
144290
144534
|
});
|
|
144291
144535
|
}
|
|
144536
|
+
/** Durable creation receipt, separate from later pause/resume and work outcomes. */
|
|
144537
|
+
async isWorkorderCreationComplete(workorderId) {
|
|
144538
|
+
return this.store.transaction((tx) => tx.isEventDone(`workorder-initialized:${workorderId}`));
|
|
144539
|
+
}
|
|
144540
|
+
async completeWorkorderCreation(workorderId, actor, dispatch, reason = null) {
|
|
144541
|
+
if (await this.isWorkorderCreationComplete(workorderId)) return;
|
|
144542
|
+
if (!dispatch) {
|
|
144543
|
+
const snap = await this.store.transaction((tx) => tx.loadWorkorder(workorderId));
|
|
144544
|
+
if (snap && !snap.workorder.dispatchPaused) await this.pauseWorkorder(workorderId, actor, reason ?? "");
|
|
144545
|
+
}
|
|
144546
|
+
await this.commit({
|
|
144547
|
+
companyId: "",
|
|
144548
|
+
workorderId,
|
|
144549
|
+
actorId: actor,
|
|
144550
|
+
dedupKey: `workorder-initialized:${workorderId}`,
|
|
144551
|
+
event: { kind: "workorder.initialized", workorderId, dispatch, reason }
|
|
144552
|
+
});
|
|
144553
|
+
}
|
|
144292
144554
|
/** 工单级恢复:workorder.resumed handler 解冻全部节点 + scan 重建 work。 */
|
|
144293
144555
|
async resumeWorkorder(workorderId, actor) {
|
|
144294
144556
|
this.trackedWorkorders.add(workorderId);
|
|
@@ -144586,7 +144848,7 @@ var init_kernel_bridge = __esm({
|
|
|
144586
144848
|
const scopedModel = ws ? filterReadModelByWorkspace(this.model, ws) : this.model;
|
|
144587
144849
|
return previewIntervention(scopedModel, plan, { schema: this.schema, roleIndex: this.roleIndex });
|
|
144588
144850
|
}
|
|
144589
|
-
async applyIntervention(plan, _baseSeqs, _actor) {
|
|
144851
|
+
async applyIntervention(plan, _baseSeqs, _actor, options = {}) {
|
|
144590
144852
|
const ws = this.effectiveWorkspace(plan);
|
|
144591
144853
|
const scopedModel = ws ? filterReadModelByWorkspace(this.model, ws) : this.model;
|
|
144592
144854
|
plan = resolveInterventionRefs(scopedModel, plan, this.schema);
|
|
@@ -144835,7 +145097,7 @@ var init_kernel_bridge = __esm({
|
|
|
144835
145097
|
break;
|
|
144836
145098
|
}
|
|
144837
145099
|
}
|
|
144838
|
-
await queue({
|
|
145100
|
+
if (!options.deferActivation) await queue({
|
|
144839
145101
|
companyId: "",
|
|
144840
145102
|
workorderId: wid,
|
|
144841
145103
|
actorId: _actor,
|
|
@@ -145662,15 +145924,15 @@ var init_parseUtil = __esm({
|
|
|
145662
145924
|
message: issueData.message
|
|
145663
145925
|
};
|
|
145664
145926
|
}
|
|
145665
|
-
let
|
|
145927
|
+
let errorMessage2 = "";
|
|
145666
145928
|
const maps = errorMaps.filter((m2) => !!m2).slice().reverse();
|
|
145667
145929
|
for (const map of maps) {
|
|
145668
|
-
|
|
145930
|
+
errorMessage2 = map(fullIssue, { data, defaultError: errorMessage2 }).message;
|
|
145669
145931
|
}
|
|
145670
145932
|
return {
|
|
145671
145933
|
...issueData,
|
|
145672
145934
|
path: fullPath,
|
|
145673
|
-
message:
|
|
145935
|
+
message: errorMessage2
|
|
145674
145936
|
};
|
|
145675
145937
|
};
|
|
145676
145938
|
EMPTY_PATH = [];
|
|
@@ -162237,7 +162499,52 @@ var init_keyed_mutex = __esm({
|
|
|
162237
162499
|
}
|
|
162238
162500
|
});
|
|
162239
162501
|
|
|
162502
|
+
// ../server/src/domains/collab/initialize-workorder.ts
|
|
162503
|
+
async function seedWorkorderBrief(kernel, blobs, workspace, briefId, actor, text6) {
|
|
162504
|
+
await kernel.refreshModel({ workorderId: workspace });
|
|
162505
|
+
const snap = await kernel.getStore().transaction((tx) => tx.loadWorkorder(workspace));
|
|
162506
|
+
const node2 = snap?.nodes.find((row) => row.id === briefId);
|
|
162507
|
+
if (!node2) throw new Error(`\u5EFA\u5355\u6536\u5C3E\u627E\u4E0D\u5230\u603B\u7EB2\u8282\u70B9\uFF1A${briefId}`);
|
|
162508
|
+
const work = snap.works.find((row) => row.id === node2.latestWorkId);
|
|
162509
|
+
const hasBody = !!work && snap.artifacts.some((row) => row.workId === work.id);
|
|
162510
|
+
if (hasBody && work?.status === "success" && work.endedAt && work.conclusion && !work.deadAt && !work.cancelledAt) return;
|
|
162511
|
+
if (snap.workorder.dispatchPaused || node2.cancelledAt || work?.deadAt || work?.cancelledAt) {
|
|
162512
|
+
throw new Error("\u5DE5\u5355\u5DF2\u88AB\u6682\u505C\u6216\u53D6\u6D88\uFF0C\u4E0D\u80FD\u901A\u8FC7\u91CD\u8BD5\u5EFA\u5355\u6062\u590D\u6267\u884C");
|
|
162513
|
+
}
|
|
162514
|
+
if (!text6.trim() && !hasBody) return;
|
|
162515
|
+
if (!hasBody) {
|
|
162516
|
+
const contentRef = await blobs.put(new TextEncoder().encode(text6));
|
|
162517
|
+
await kernel.proposeRevision({ artifactId: briefId, actor, contentRef, reason: "\u5EFA\u5355\uFF1A\u843D\u5B9A brief \u9996\u7248" });
|
|
162518
|
+
}
|
|
162519
|
+
await kernel.advanceQueue(briefId, actor);
|
|
162520
|
+
await kernel.conclude({ artifactId: briefId, actor, note: "\u5EFA\u5355\u65F6\u7531\u53D1\u8D77\u4EBA\u62CD\u677F\u5B9A\u7A3F" });
|
|
162521
|
+
}
|
|
162522
|
+
function legacyCreationComplete(snap, briefId) {
|
|
162523
|
+
if (snap?.workorder.lifecycle !== "active") return false;
|
|
162524
|
+
return snap.works.some((work) => work.nodeId === briefId && work.status === "success" && !!work.endedAt && !!work.conclusion && !work.deadAt && !work.cancelledAt && snap.artifacts.some((row) => row.workId === work.id));
|
|
162525
|
+
}
|
|
162526
|
+
var init_initialize_workorder = __esm({
|
|
162527
|
+
"../server/src/domains/collab/initialize-workorder.ts"() {
|
|
162528
|
+
"use strict";
|
|
162529
|
+
}
|
|
162530
|
+
});
|
|
162531
|
+
|
|
162240
162532
|
// ../server/src/live-chat.ts
|
|
162533
|
+
function publishInputFromPersisted(info) {
|
|
162534
|
+
const payload2 = info.payload && typeof info.payload === "object" && !Array.isArray(info.payload) ? info.payload : void 0;
|
|
162535
|
+
const csid = typeof payload2?.["clientSubmitId"] === "string" ? payload2["clientSubmitId"] : void 0;
|
|
162536
|
+
const csids = Array.isArray(payload2?.["clientSubmitIds"]) ? payload2["clientSubmitIds"].filter((v2) => typeof v2 === "string") : void 0;
|
|
162537
|
+
const attachments = Array.isArray(payload2?.["attachments"]) ? payload2["attachments"] : void 0;
|
|
162538
|
+
return {
|
|
162539
|
+
itemId: info.itemId,
|
|
162540
|
+
ord: info.ord,
|
|
162541
|
+
version: info.version,
|
|
162542
|
+
text: info.text,
|
|
162543
|
+
...csid ? { clientSubmitId: csid } : {},
|
|
162544
|
+
...csids?.length ? { clientSubmitIds: csids } : {},
|
|
162545
|
+
...attachments?.length ? { attachments } : {}
|
|
162546
|
+
};
|
|
162547
|
+
}
|
|
162241
162548
|
function normalizedKindToItemType(kind) {
|
|
162242
162549
|
if (kind === "text") return "message";
|
|
162243
162550
|
if (kind === "thinking") return "thinking";
|
|
@@ -162329,6 +162636,8 @@ var init_live_chat = __esm({
|
|
|
162329
162636
|
};
|
|
162330
162637
|
this.turns.set(chatSessionId, turn);
|
|
162331
162638
|
this.flushPendingUserItems(chatSessionId);
|
|
162639
|
+
const ledger = opts.items;
|
|
162640
|
+
const stopUserItems = ledger && typeof ledger.onUserItemPersisted === "function" ? ledger.onUserItemPersisted((info) => this.publishPersistedUserItem(turn, info)) : void 0;
|
|
162332
162641
|
const waiters = this.turnStartWaiters.get(chatSessionId);
|
|
162333
162642
|
this.turnStartWaiters.delete(chatSessionId);
|
|
162334
162643
|
for (const wake of waiters ?? []) {
|
|
@@ -162379,6 +162688,7 @@ var init_live_chat = __esm({
|
|
|
162379
162688
|
};
|
|
162380
162689
|
},
|
|
162381
162690
|
finish: (status) => {
|
|
162691
|
+
stopUserItems?.();
|
|
162382
162692
|
for (const receipt of turn.inputReceipts.values()) receipt.abandon();
|
|
162383
162693
|
turn.inputReceipts.clear();
|
|
162384
162694
|
try {
|
|
@@ -162579,8 +162889,12 @@ var init_live_chat = __esm({
|
|
|
162579
162889
|
payload: item.payload
|
|
162580
162890
|
});
|
|
162581
162891
|
}
|
|
162582
|
-
assignV3Seq(turn, frame) {
|
|
162583
|
-
|
|
162892
|
+
assignV3Seq(turn, frame, times = turn.items?.timestampsFor(frame.itemId)) {
|
|
162893
|
+
const payload2 = times ? {
|
|
162894
|
+
...frame.payload && typeof frame.payload === "object" && !Array.isArray(frame.payload) ? frame.payload : {},
|
|
162895
|
+
...times
|
|
162896
|
+
} : frame.payload;
|
|
162897
|
+
return { ...frame, ...payload2 !== void 0 ? { payload: payload2 } : {}, epoch: turn.liveEpoch, seq: ++turn.v3Seq };
|
|
162584
162898
|
}
|
|
162585
162899
|
/**
|
|
162586
162900
|
* v3 帧的**唯一**发布出口:按 24ms 窗口合并同一 item 上相邻的 `append_text`,其余一律是顺序屏障。
|
|
@@ -162664,11 +162978,11 @@ var init_live_chat = __esm({
|
|
|
162664
162978
|
* 空对话首次发送时那个最大号是 0,随后到达的历史(号更大)会全部排到乐观条**后面**——
|
|
162665
162979
|
* 正是 ADR D9 点名必须验的「空桶先发送」那一档。号只能由服务端给。
|
|
162666
162980
|
*
|
|
162667
|
-
* ##
|
|
162981
|
+
* ## 谁来调
|
|
162668
162982
|
*
|
|
162669
|
-
*
|
|
162670
|
-
*
|
|
162671
|
-
*
|
|
162983
|
+
* 生产上只有 {@link start} 订阅账本(`ChatItemLedger.onUserItemPersisted`)之后经
|
|
162984
|
+
* {@link publishPersistedUserItem} 调,四条开轮入口一处接好;「落库早于开轮」由账本订阅时补发兜住。
|
|
162985
|
+
* 下面按会话号暂存的那条路只服务直接调本方法、手上又没有轮的调用方。
|
|
162672
162986
|
*/
|
|
162673
162987
|
/**
|
|
162674
162988
|
* 「user item 已落库、但这条会话的 live 轮还没 start」时的暂存位(见 {@link publishUserItem})。
|
|
@@ -162718,6 +163032,18 @@ var init_live_chat = __esm({
|
|
|
162718
163032
|
this.publishV3(turn, this.assignV3Seq(turn, frame));
|
|
162719
163033
|
return true;
|
|
162720
163034
|
}
|
|
163035
|
+
/**
|
|
163036
|
+
* 账本订阅回来的 user 行 → 推给**持有这本账本的那一轮**({@link start} 里订阅)。
|
|
163037
|
+
*
|
|
163038
|
+
* 只认这条轮本身,不按会话号重新查:这条会话若已经换了一轮(上一轮在 grace、新一轮已 start),
|
|
163039
|
+
* 旧账本迟到的回执不许推进新一轮的流。收了尾的轮也不推——观众已散,页面收尾后会重读快照;
|
|
163040
|
+
* 各入口都在 `finish` 之前抽干账本,已消费的插话在那之前就落了库、发了帧。
|
|
163041
|
+
*/
|
|
163042
|
+
publishPersistedUserItem(turn, info) {
|
|
163043
|
+
if (info.role !== "user") return;
|
|
163044
|
+
if (this.turns.get(turn.chatSessionId) !== turn || turn.status !== "running") return;
|
|
163045
|
+
this.publishUserItem(turn.chatSessionId, publishInputFromPersisted(info));
|
|
163046
|
+
}
|
|
162721
163047
|
/** 恢复路在 DB 收口旧 item 后,将同一身份/版本的终态发给已挂上的观众。 */
|
|
162722
163048
|
publishItemStatus(chatSessionId, item) {
|
|
162723
163049
|
const turn = this.turns.get(chatSessionId);
|
|
@@ -162733,7 +163059,7 @@ var init_live_chat = __esm({
|
|
|
162733
163059
|
operation: item.status === "completed" ? "completed" : "failed",
|
|
162734
163060
|
itemVersion: item.version,
|
|
162735
163061
|
...item.ord !== null ? { ord: item.ord } : {}
|
|
162736
|
-
}));
|
|
163062
|
+
}, { createdAt: item.createdAt, completedAt: item.completedAt }));
|
|
162737
163063
|
return true;
|
|
162738
163064
|
}
|
|
162739
163065
|
emitV3TurnTerminal(turn, status) {
|
|
@@ -200837,7 +201163,34 @@ function registerDelegatedChildTurn(liveChat, childSessionId, session, deps = {}
|
|
|
200837
201163
|
} catch {
|
|
200838
201164
|
}
|
|
200839
201165
|
});
|
|
200840
|
-
const
|
|
201166
|
+
const recordFailure = (err) => {
|
|
201167
|
+
const chatExit = err instanceof Error ? err.chatExit : void 0;
|
|
201168
|
+
const text6 = chatExit?.summary ?? (err instanceof Error ? err.message : String(err));
|
|
201169
|
+
const extra = {
|
|
201170
|
+
...chatExit?.reason ? { reason: chatExit.reason } : {},
|
|
201171
|
+
...chatExit?.detail ? { detail: chatExit.detail } : {}
|
|
201172
|
+
};
|
|
201173
|
+
try {
|
|
201174
|
+
ctrl.emit({ type: "error", text: text6, ...extra });
|
|
201175
|
+
} catch {
|
|
201176
|
+
}
|
|
201177
|
+
try {
|
|
201178
|
+
const outcome = ledger.recordError(text6, extra);
|
|
201179
|
+
ctrl.publishServerItem({
|
|
201180
|
+
itemId: outcome.itemId,
|
|
201181
|
+
itemType: "control",
|
|
201182
|
+
startedVersion: outcome.startedVersion,
|
|
201183
|
+
version: outcome.version,
|
|
201184
|
+
ord: outcome.ord,
|
|
201185
|
+
status: "failed",
|
|
201186
|
+
payload: { code: "error", note: text6, ...extra }
|
|
201187
|
+
});
|
|
201188
|
+
} catch (e) {
|
|
201189
|
+
log3(`[delegation] \u5B50\u4F1A\u8BDD ${childSessionId} \u5931\u8D25\u539F\u56E0\u843D\u8D26\u5931\u8D25: ${String(e)}`);
|
|
201190
|
+
}
|
|
201191
|
+
};
|
|
201192
|
+
const settle = async (signal, err) => {
|
|
201193
|
+
if (signal === "failed") recordFailure(err);
|
|
200841
201194
|
try {
|
|
200842
201195
|
normalized4?.finishTurn(signal);
|
|
200843
201196
|
} catch {
|
|
@@ -200845,12 +201198,12 @@ function registerDelegatedChildTurn(liveChat, childSessionId, session, deps = {}
|
|
|
200845
201198
|
try {
|
|
200846
201199
|
ledger.finish(signal);
|
|
200847
201200
|
await ledger.drain();
|
|
200848
|
-
} catch (
|
|
200849
|
-
log3(`[delegation] \u5B50\u4F1A\u8BDD ${childSessionId} \u8D26\u672C\u6536\u5C3E\u5931\u8D25: ${String(
|
|
201201
|
+
} catch (err2) {
|
|
201202
|
+
log3(`[delegation] \u5B50\u4F1A\u8BDD ${childSessionId} \u8D26\u672C\u6536\u5C3E\u5931\u8D25: ${String(err2)}`);
|
|
200850
201203
|
}
|
|
200851
201204
|
ctrl.finish(signal === "completed" ? "done" : "error");
|
|
200852
201205
|
};
|
|
200853
|
-
void session.done.then(() => settle("completed"), () => settle("failed"));
|
|
201206
|
+
void session.done.then(() => settle("completed"), (err) => settle("failed", err));
|
|
200854
201207
|
}
|
|
200855
201208
|
var init_child_live_turn = __esm({
|
|
200856
201209
|
"../server/src/domains/delegations/child-live-turn.ts"() {
|
|
@@ -205328,15 +205681,6 @@ async function loadWorkorderSnapshot(kernel, workorderId) {
|
|
|
205328
205681
|
if (!store) return null;
|
|
205329
205682
|
return store.transaction((tx) => tx.loadWorkorder(workorderId));
|
|
205330
205683
|
}
|
|
205331
|
-
function workorderCreationState(snap, briefArtifactId) {
|
|
205332
|
-
const briefWorkIds = new Set(
|
|
205333
|
-
snap.works.filter((w2) => w2.nodeId === briefArtifactId).map((w2) => w2.id)
|
|
205334
|
-
);
|
|
205335
|
-
return {
|
|
205336
|
-
hasNodes: snap.nodes.length > 0,
|
|
205337
|
-
briefHasBody: snap.artifacts.some((a) => briefWorkIds.has(a.workId))
|
|
205338
|
-
};
|
|
205339
|
-
}
|
|
205340
205684
|
function wantsChatParts(req) {
|
|
205341
205685
|
const accept = req.headers.accept;
|
|
205342
205686
|
return typeof accept === "string" && accept.includes("application/x-ndjson");
|
|
@@ -205985,18 +206329,12 @@ ${acceptanceCriteria.map((c) => `- ${c}`).join("\n")}`] : []
|
|
|
205985
206329
|
}
|
|
205986
206330
|
};
|
|
205987
206331
|
}
|
|
205988
|
-
const applied = await kernel.applyIntervention(planned.plan, preview2.baseSeqs, actor);
|
|
206332
|
+
const applied = await kernel.applyIntervention(planned.plan, preview2.baseSeqs, actor, { deferActivation: true });
|
|
205989
206333
|
const briefArtifactId = planned.rootArtifactId;
|
|
205990
|
-
|
|
205991
|
-
|
|
205992
|
-
|
|
205993
|
-
|
|
205994
|
-
await kernel.conclude({ artifactId: briefArtifactId, actor, note: "\u5EFA\u5355\u65F6\u7531\u53D1\u8D77\u4EBA\u62CD\u677F\u5B9A\u7A3F" });
|
|
205995
|
-
}
|
|
205996
|
-
if (args["dispatch"] === false) {
|
|
205997
|
-
await ctx.artifactState?.setWorkspaceDispatchHold(workspace, true);
|
|
205998
|
-
await kernel.pauseWorkorder?.(workspace, actor, WORKORDER_HOLD_AT_CREATE_REASON);
|
|
205999
|
-
}
|
|
206334
|
+
await seedWorkorderBrief(kernel, blobs, workspace, briefArtifactId, actor, brief ?? "");
|
|
206335
|
+
const dispatch = args["dispatch"] !== false;
|
|
206336
|
+
if (!dispatch) await ctx.artifactState?.setWorkspaceDispatchHold?.(workspace, true);
|
|
206337
|
+
await kernel.completeWorkorderCreation(workspace, actor, dispatch, WORKORDER_HOLD_AT_CREATE_REASON);
|
|
206000
206338
|
return {
|
|
206001
206339
|
message: planned.issues.length > 0 ? `planned ${workspace}: created ${planned.spawned.length} nodes\uFF0C${planned.issues.length} \u4E2A staffing \u63D0\u793A\u5DF2\u5199\u5165\u5DE5\u5355` : `planned ${workspace}: created ${planned.spawned.length} nodes`,
|
|
206002
206340
|
data: {
|
|
@@ -207246,10 +207584,10 @@ async function startOasisServer(opts) {
|
|
|
207246
207584
|
...fp(p2)
|
|
207247
207585
|
}))
|
|
207248
207586
|
] : [];
|
|
207249
|
-
const { randomUUID:
|
|
207587
|
+
const { randomUUID: randomUUID46 } = await import("node:crypto");
|
|
207250
207588
|
try {
|
|
207251
207589
|
await store.enqueuePendingMessage({
|
|
207252
|
-
id:
|
|
207590
|
+
id: randomUUID46(),
|
|
207253
207591
|
chatSessionId: input.chatSessionId,
|
|
207254
207592
|
text: input.text,
|
|
207255
207593
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -207282,11 +207620,11 @@ async function startOasisServer(opts) {
|
|
|
207282
207620
|
...f2?.mtime ? { srcMtime: f2.mtime } : {}
|
|
207283
207621
|
};
|
|
207284
207622
|
});
|
|
207285
|
-
const { randomUUID:
|
|
207623
|
+
const { randomUUID: randomUUID46 } = await import("node:crypto");
|
|
207286
207624
|
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
207287
207625
|
try {
|
|
207288
207626
|
await store.enqueuePendingMessage({
|
|
207289
|
-
id:
|
|
207627
|
+
id: randomUUID46(),
|
|
207290
207628
|
chatSessionId: input.chatSessionId,
|
|
207291
207629
|
text: "",
|
|
207292
207630
|
createdAt: nowIso,
|
|
@@ -208214,14 +208552,13 @@ async function startOasisServer(opts) {
|
|
|
208214
208552
|
}
|
|
208215
208553
|
}
|
|
208216
208554
|
const existingSnap = targetWs ? await loadWorkorderSnapshot(engine.kernel, targetWs) : null;
|
|
208217
|
-
|
|
208218
|
-
if (resumeState.hasNodes && resumeState.briefHasBody) {
|
|
208555
|
+
if (targetWs && (await engine.kernel.isWorkorderCreationComplete(targetWs) || legacyCreationComplete(existingSnap, body2.briefArtifactId))) {
|
|
208219
208556
|
res.writeHead(409, { "content-type": "application/json" }).end(
|
|
208220
208557
|
JSON.stringify({ error: "WORKORDER_ALREADY_CREATED", message: "\u8BE5\u5DE5\u5355\u5DF2\u521B\u5EFA\uFF0C\u4E0D\u80FD\u91CD\u590D\u521B\u5EFA\uFF08\u53EF\u76F4\u63A5\u6253\u5F00\u5DF2\u521B\u5EFA\u7684\u5DE5\u5355\uFF09", workspace: targetWs })
|
|
208221
208558
|
);
|
|
208222
208559
|
return;
|
|
208223
208560
|
}
|
|
208224
|
-
const resuming =
|
|
208561
|
+
const resuming = (existingSnap?.nodes.length ?? 0) > 0;
|
|
208225
208562
|
let sessionProjectId;
|
|
208226
208563
|
let sessionBindingState;
|
|
208227
208564
|
if (body2.chatSessionId && opts.chatSession) {
|
|
@@ -208285,10 +208622,7 @@ async function startOasisServer(opts) {
|
|
|
208285
208622
|
if (targetWs && sessionProjectId) {
|
|
208286
208623
|
await sessionBindingState.upsertWorkspaceBinding({ workOrderId: targetWs, projectId: sessionProjectId });
|
|
208287
208624
|
}
|
|
208288
|
-
const result = resuming ? { interventionId: "", applied: 0, resumed: true } : await engine.kernel.applyIntervention(body2.plan, body2.baseSeqs, actor);
|
|
208289
|
-
if (resuming) {
|
|
208290
|
-
await engine.kernel.activateWorkorder?.(targetWs, actor);
|
|
208291
|
-
}
|
|
208625
|
+
const result = resuming ? { interventionId: "", applied: 0, resumed: true } : await engine.kernel.applyIntervention(body2.plan, body2.baseSeqs, actor, { deferActivation: true });
|
|
208292
208626
|
const briefSpawn = body2.plan.ops.find(
|
|
208293
208627
|
(op) => op.action === "spawn" && op.id === body2.briefArtifactId
|
|
208294
208628
|
);
|
|
@@ -208299,26 +208633,15 @@ async function startOasisServer(opts) {
|
|
|
208299
208633
|
throw new Error(`\u5EFA\u5355\u6536\u5C3E\u62FF\u4E0D\u5230 workspace\uFF08brief=${body2.briefArtifactId}\uFF09\u2014\u2014\u62D2\u7EDD\u62A5\u6210\u529F\uFF0C\u8BF7\u91CD\u8BD5`);
|
|
208300
208634
|
}
|
|
208301
208635
|
const warnings = [];
|
|
208302
|
-
|
|
208303
|
-
|
|
208304
|
-
await engine.kernel.proposeRevision({ artifactId: body2.briefArtifactId, actor, contentRef: briefRef, reason: "\u5EFA\u5355\uFF1A\u843D\u5B9A\u53D1\u8D77\u4EBA\u6572\u5B9A\u7684 brief \u9996\u7248" });
|
|
208305
|
-
await engine.kernel.advanceQueue(body2.briefArtifactId, actor);
|
|
208306
|
-
await engine.kernel.conclude({ artifactId: body2.briefArtifactId, actor, note: "\u5EFA\u5355\u65F6\u7531\u53D1\u8D77\u4EBA\u62CD\u677F\u5B9A\u7A3F" });
|
|
208307
|
-
} else {
|
|
208308
|
-
warnings.push("\u5DE5\u5355\u603B\u7EB2\u6CA1\u6709\u6B63\u6587\uFF0C\u672A\u843D\u9996\u7248");
|
|
208309
|
-
}
|
|
208636
|
+
await seedWorkorderBrief(engine.kernel, engine.blobs, workspace, body2.briefArtifactId, actor, briefText);
|
|
208637
|
+
if (!briefText) warnings.push("\u5DE5\u5355\u603B\u7EB2\u6CA1\u6709\u6B63\u6587\uFF0C\u672A\u843D\u9996\u7248");
|
|
208310
208638
|
if (body2.dispatch === false) {
|
|
208311
|
-
await
|
|
208312
|
-
await engine.kernel.pauseWorkorder?.(workspace, actor, WORKORDER_HOLD_AT_CREATE_REASON);
|
|
208639
|
+
await (await artifactStateNow())?.setWorkspaceDispatchHold?.(workspace, true);
|
|
208313
208640
|
}
|
|
208314
208641
|
await wodraftPlannerIssues.remove(workspace);
|
|
208315
208642
|
if (opts.chatSession && body2.chatSessionId && workspace !== "ws:default") {
|
|
208316
208643
|
const applyLinkStore = await chatStoreNow();
|
|
208317
|
-
await applyLinkStore.linkWorkOrder(body2.chatSessionId, workspace, "origin")
|
|
208318
|
-
const detail = err instanceof Error ? err.message : String(err);
|
|
208319
|
-
console.error(`[chat-session] Failed to link work order ${workspace} to session ${body2.chatSessionId}:`, err);
|
|
208320
|
-
warnings.push(`\u672A\u80FD\u628A\u5DE5\u5355\u5173\u8054\u56DE\u672C\u6B21\u5BF9\u8BDD\uFF1A${detail}`);
|
|
208321
|
-
});
|
|
208644
|
+
await applyLinkStore.linkWorkOrder(body2.chatSessionId, workspace, "origin");
|
|
208322
208645
|
const handoffArtifacts = await artifactStateNow();
|
|
208323
208646
|
if (handoffArtifacts?.addWorkOrderFile) {
|
|
208324
208647
|
const handoff = await linkChatAttachmentsToWorkOrder({
|
|
@@ -208348,6 +208671,7 @@ async function startOasisServer(opts) {
|
|
|
208348
208671
|
const missing = plannedSpawnIds.filter((id) => !present.has(id));
|
|
208349
208672
|
if (missing.length > 0) warnings.push(`\u534F\u4F5C\u56FE\u7F3A ${missing.length} \u4E2A\u8282\u70B9\u672A\u5EFA\u51FA\uFF1A${missing.join("\u3001")}`);
|
|
208350
208673
|
}
|
|
208674
|
+
await engine.kernel.completeWorkorderCreation(workspace, actor, body2.dispatch !== false, WORKORDER_HOLD_AT_CREATE_REASON);
|
|
208351
208675
|
res.writeHead(200, { "content-type": "application/json" }).end(
|
|
208352
208676
|
JSON.stringify({
|
|
208353
208677
|
...result,
|
|
@@ -208629,7 +208953,7 @@ async function startOasisServer(opts) {
|
|
|
208629
208953
|
const openRoom = async () => {
|
|
208630
208954
|
let chatSessionId2;
|
|
208631
208955
|
if (chatStore) {
|
|
208632
|
-
const { randomUUID:
|
|
208956
|
+
const { randomUUID: randomUUID46 } = await import("node:crypto");
|
|
208633
208957
|
const known = discussSessions.get(itemKey);
|
|
208634
208958
|
const knownSession = known ? await chatStore.getSession(known) : null;
|
|
208635
208959
|
if (knownSession && knownSession.workspace === ctx.workspace && knownSession.humanActorId === ctx.ownerId && (!body2.escalationId || knownSession.escalationId === body2.escalationId)) chatSessionId2 = known;
|
|
@@ -208638,7 +208962,7 @@ async function startOasisServer(opts) {
|
|
|
208638
208962
|
chatSessionId2 = existing[0]?.id;
|
|
208639
208963
|
}
|
|
208640
208964
|
if (!chatSessionId2) {
|
|
208641
|
-
chatSessionId2 =
|
|
208965
|
+
chatSessionId2 = randomUUID46();
|
|
208642
208966
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
208643
208967
|
const title = `\u89E3\u51B3\uFF1A${ctx.seed.slice(ctx.seed.indexOf("\uFF1A") + 1, ctx.seed.indexOf("\uFF1A") + 25) || "\u5DE5\u5355\u5361\u70B9"}`;
|
|
208644
208968
|
const reg0 = (await resolveEngine(currentCompanyId).catch(() => null))?.registry ?? opts.registry;
|
|
@@ -209537,7 +209861,7 @@ ${composed}`;
|
|
|
209537
209861
|
});
|
|
209538
209862
|
await rejectedLedger.drain();
|
|
209539
209863
|
if (rejectedLedger.failures === 0) {
|
|
209540
|
-
const { randomUUID:
|
|
209864
|
+
const { randomUUID: randomUUID47 } = await import("node:crypto");
|
|
209541
209865
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
209542
209866
|
const rejectedAttachments = effectiveAttachments.map((a) => ({
|
|
209543
209867
|
name: a.name,
|
|
@@ -209545,7 +209869,7 @@ ${composed}`;
|
|
|
209545
209869
|
...a.contentType !== void 0 ? { contentType: a.contentType } : {}
|
|
209546
209870
|
}));
|
|
209547
209871
|
await chatStore.appendMessage({
|
|
209548
|
-
id:
|
|
209872
|
+
id: randomUUID47(),
|
|
209549
209873
|
sessionId: persistTarget.id,
|
|
209550
209874
|
role: "user",
|
|
209551
209875
|
content: persistedUserMessage,
|
|
@@ -209623,14 +209947,14 @@ ${composed}`;
|
|
|
209623
209947
|
runtimeSessionId: session.nativeSessionId ?? session.id
|
|
209624
209948
|
}).catch(() => void 0);
|
|
209625
209949
|
}
|
|
209626
|
-
const { randomUUID:
|
|
209950
|
+
const { randomUUID: randomUUID47 } = await import("node:crypto");
|
|
209627
209951
|
const persistAttachments = effectiveAttachments.map((a) => ({
|
|
209628
209952
|
name: a.name,
|
|
209629
209953
|
...a.blobRef !== void 0 ? { blobRef: a.blobRef } : {},
|
|
209630
209954
|
...a.contentType !== void 0 ? { contentType: a.contentType } : {}
|
|
209631
209955
|
}));
|
|
209632
209956
|
await chatStore.appendMessage({
|
|
209633
|
-
id:
|
|
209957
|
+
id: randomUUID47(),
|
|
209634
209958
|
sessionId: persistTarget.id,
|
|
209635
209959
|
role: "user",
|
|
209636
209960
|
content: persistedUserMessage,
|
|
@@ -209656,27 +209980,10 @@ ${composed}`;
|
|
|
209656
209980
|
const itemLedger = new ChatItemLedger({
|
|
209657
209981
|
...itemStore ? { items: itemStore } : {},
|
|
209658
209982
|
versionSeed,
|
|
209659
|
-
/*
|
|
209660
|
-
|
|
209661
|
-
|
|
209662
|
-
|
|
209663
|
-
只推 user:assistant 的每一条本来就走 `emitV3`。 */
|
|
209664
|
-
onPersisted: (info) => {
|
|
209665
|
-
if (info.role !== "user") return;
|
|
209666
|
-
const rowPayload = info.payload && typeof info.payload === "object" && !Array.isArray(info.payload) ? info.payload : void 0;
|
|
209667
|
-
const rowCsid = typeof rowPayload?.["clientSubmitId"] === "string" ? rowPayload["clientSubmitId"] : void 0;
|
|
209668
|
-
const rowCsids = Array.isArray(rowPayload?.["clientSubmitIds"]) ? rowPayload["clientSubmitIds"].filter((v2) => typeof v2 === "string") : void 0;
|
|
209669
|
-
const rowAttachments = Array.isArray(rowPayload?.["attachments"]) ? rowPayload["attachments"] : void 0;
|
|
209670
|
-
opts.liveChat?.publishUserItem(persistTarget?.id ?? session.id, {
|
|
209671
|
-
itemId: info.itemId,
|
|
209672
|
-
ord: info.ord,
|
|
209673
|
-
version: info.version,
|
|
209674
|
-
text: info.text,
|
|
209675
|
-
...rowCsid ? { clientSubmitId: rowCsid } : {},
|
|
209676
|
-
...rowCsids?.length ? { clientSubmitIds: rowCsids } : {},
|
|
209677
|
-
...rowAttachments?.length ? { attachments: rowAttachments } : {}
|
|
209678
|
-
});
|
|
209679
|
-
},
|
|
209983
|
+
/* 用户那条消息(首条提交与中途插话)一落库就推上 v3 流(ADR-0510 D2 的收口)——
|
|
209984
|
+
**不在这里接**:`liveChat.start` 带着这本账本开轮时统一订阅
|
|
209985
|
+
(`LiveChatRegistry.start` → `ChatItemLedger.onUserItemPersisted`),开轮前已落库的会补发。
|
|
209986
|
+
四条开轮入口共用那一处;这里再接一次就是同一行两帧、同一版本号,客户端判 stale 并 resync。 */
|
|
209680
209987
|
sessionId: persistTarget?.id ?? session.id,
|
|
209681
209988
|
// 优先账本 id(`chat_session_turns.id`,跨进程唯一、重启不失忆);账本没接入才兜底。
|
|
209682
209989
|
turnId: heldTurn?.id ?? fallbackTurnId(session.runId),
|
|
@@ -209778,52 +210085,27 @@ ${composed}`;
|
|
|
209778
210085
|
}, { items: itemLedger }) : null;
|
|
209779
210086
|
if (live && assistantMsgId) live.setAssistantMessageId(assistantMsgId);
|
|
209780
210087
|
if (live && chatStore && persistTarget) {
|
|
209781
|
-
const { randomUUID: newId } = await import("node:crypto");
|
|
209782
210088
|
const liveCtl = live;
|
|
209783
210089
|
const target = persistTarget;
|
|
209784
210090
|
const store = chatStore;
|
|
209785
210091
|
liveCtl.onUserInput((text6, insertedAttachments) => {
|
|
209786
|
-
const segText = itemLedger.projectContent();
|
|
209787
210092
|
const segParts = collectedParts();
|
|
209788
|
-
const
|
|
209789
|
-
|
|
209790
|
-
|
|
209791
|
-
|
|
209792
|
-
|
|
210093
|
+
const split = beginInsertedAssistantSegment({
|
|
210094
|
+
chatStore: store,
|
|
210095
|
+
chatSessionId: target.id,
|
|
210096
|
+
ledger: itemLedger,
|
|
210097
|
+
live: liveCtl,
|
|
210098
|
+
closingId: assistantMsgId,
|
|
210099
|
+
segParts,
|
|
210100
|
+
text: text6,
|
|
210101
|
+
attachments: insertedAttachments,
|
|
210102
|
+
...session.runId ? { runId: session.runId } : {},
|
|
210103
|
+
turnId: heldTurn?.id
|
|
210104
|
+
// 插话切段仍属同一轮(同 turnId)
|
|
210105
|
+
});
|
|
210106
|
+
assistantMsgId = split.nextId;
|
|
209793
210107
|
segmentBaseSeq = liveCtl.bufferedParts().reduce((max, p2) => p2.seq > max ? p2.seq : max, 0);
|
|
209794
|
-
|
|
209795
|
-
checkpointChain = checkpointChain.then(async () => {
|
|
209796
|
-
if (closingId) {
|
|
209797
|
-
await store.updateMessage(closingId, {
|
|
209798
|
-
content: segText,
|
|
209799
|
-
status: "done",
|
|
209800
|
-
completedAt: at,
|
|
209801
|
-
...segParts.length ? { parts: segParts } : {}
|
|
209802
|
-
}).catch(() => void 0);
|
|
209803
|
-
}
|
|
209804
|
-
await store.appendMessage({
|
|
209805
|
-
id: newId(),
|
|
209806
|
-
sessionId: target.id,
|
|
209807
|
-
role: "user",
|
|
209808
|
-
content: text6,
|
|
209809
|
-
createdAt: at,
|
|
209810
|
-
// ADR-0166 D9.1:插入带的附件也落在**这条 user 行**上——否则重载后这条气泡
|
|
209811
|
-
// 只剩一行字,而同样带图直接发送的那条有缩略图。同 `/api/chat` 那侧只存引用。
|
|
209812
|
-
...insertedAttachments?.length ? { attachments: insertedAttachments } : {},
|
|
209813
|
-
...heldTurn ? { turnId: heldTurn.id } : {}
|
|
209814
|
-
// 插话切段仍属同一轮(同 turnId)
|
|
209815
|
-
}).catch(() => void 0);
|
|
209816
|
-
await store.appendMessage({
|
|
209817
|
-
id: nextId,
|
|
209818
|
-
sessionId: target.id,
|
|
209819
|
-
role: "assistant",
|
|
209820
|
-
content: "",
|
|
209821
|
-
createdAt: at,
|
|
209822
|
-
status: "running",
|
|
209823
|
-
...session.runId ? { runId: session.runId } : {},
|
|
209824
|
-
...heldTurn ? { turnId: heldTurn.id } : {}
|
|
209825
|
-
}).then(() => itemLedger.bindMessage(nextId)).catch(() => void 0);
|
|
209826
|
-
}).catch(() => void 0);
|
|
210108
|
+
checkpointChain = checkpointChain.then(split.persist).catch(() => void 0);
|
|
209827
210109
|
});
|
|
209828
210110
|
}
|
|
209829
210111
|
let localSeq = 0;
|
|
@@ -210106,8 +210388,8 @@ ${composed}`;
|
|
|
210106
210388
|
}
|
|
210107
210389
|
}
|
|
210108
210390
|
const { spawn: spawn10 } = await import("node:child_process");
|
|
210109
|
-
const { randomUUID:
|
|
210110
|
-
const sessionId = body2.sessionId ??
|
|
210391
|
+
const { randomUUID: randomUUID46 } = await import("node:crypto");
|
|
210392
|
+
const sessionId = body2.sessionId ?? randomUUID46();
|
|
210111
210393
|
const args = [
|
|
210112
210394
|
"-p",
|
|
210113
210395
|
body2.message,
|
|
@@ -210403,8 +210685,8 @@ ${composed}`;
|
|
|
210403
210685
|
res.writeHead(400, { "content-type": "application/json" }).end(JSON.stringify({ error: `\u56DE\u8C03\u5730\u5740\u4E0D\u53EF\u7528\uFF0C\u5DF2\u4E2D\u6B62\uFF08\u907F\u514D\u5728 GitHub \u4E0A\u7559\u4E0B\u5B64\u513F App\uFF09\uFF1A${e.message}` }));
|
|
210404
210686
|
return;
|
|
210405
210687
|
}
|
|
210406
|
-
const { randomUUID:
|
|
210407
|
-
const state =
|
|
210688
|
+
const { randomUUID: randomUUID46 } = await import("node:crypto");
|
|
210689
|
+
const state = randomUUID46();
|
|
210408
210690
|
const nameSlug = (actorName || actorId?.split(":").pop() || owner?.login || "bot").toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-|-$/g, "").slice(0, 24) || "bot";
|
|
210409
210691
|
const manifest = buildAppManifest({
|
|
210410
210692
|
employeeSlug: nameSlug,
|
|
@@ -211212,6 +211494,7 @@ var init_server3 = __esm({
|
|
|
211212
211494
|
init_router();
|
|
211213
211495
|
init_infra_error();
|
|
211214
211496
|
init_keyed_mutex();
|
|
211497
|
+
init_initialize_workorder();
|
|
211215
211498
|
init_live_chat();
|
|
211216
211499
|
init_chat_turn_wait();
|
|
211217
211500
|
init_append_now();
|
|
@@ -220992,7 +221275,11 @@ function wireRecoveredChatTurn(deps) {
|
|
|
220992
221275
|
void handle.kill();
|
|
220993
221276
|
},
|
|
220994
221277
|
// ADR-0093 chat 道:重挂的轮同样能被插入——否则「serve 重启过」会变成一条人看不见的能力差异。
|
|
220995
|
-
|
|
221278
|
+
// **整份透传**(2026-09-17):此前只转 `text`,插话链路要的消费回执(`requireConsumptionReceipt`)、
|
|
221279
|
+
// 幂等键(`clientMessageKey`)与附件(`files` / `binaryFiles`)全被剥掉——runtime 照样读到了正文,
|
|
221280
|
+
// 却回不了带键的 `input_consumed`,服务端等到本轮收尾判 `unconfirmed`:agent 处理了那句话,
|
|
221281
|
+
// 对话流里从头到尾没有它,附件也没送到。
|
|
221282
|
+
...typeof handle.appendInput === "function" ? { appendInput: (input) => handle.appendInput(input) } : {},
|
|
220996
221283
|
get canAppendInput() {
|
|
220997
221284
|
return handle.canAppendInput !== false && typeof handle.appendInput === "function";
|
|
220998
221285
|
}
|
|
@@ -221084,40 +221371,25 @@ function wireRecoveredChatTurn(deps) {
|
|
|
221084
221371
|
let checkpointChain = Promise.resolve();
|
|
221085
221372
|
{
|
|
221086
221373
|
const store = deps.chatStore;
|
|
221087
|
-
live.onUserInput((text6) => {
|
|
221088
|
-
const segText = itemLedger.projectContent();
|
|
221374
|
+
live.onUserInput((text6, attachments) => {
|
|
221089
221375
|
const segParts = collectedParts();
|
|
221090
|
-
const
|
|
221091
|
-
|
|
221092
|
-
|
|
221093
|
-
|
|
221094
|
-
|
|
221376
|
+
const split = beginInsertedAssistantSegment({
|
|
221377
|
+
chatStore: store,
|
|
221378
|
+
chatSessionId: plan.chatSessionId,
|
|
221379
|
+
ledger: itemLedger,
|
|
221380
|
+
live,
|
|
221381
|
+
closingId: currentMsgId,
|
|
221382
|
+
segParts,
|
|
221383
|
+
text: text6,
|
|
221384
|
+
attachments,
|
|
221385
|
+
runId: plan.runId,
|
|
221386
|
+
// 账本那一轮的 `chat_session_turns.id`(与重启前 `/api/chat` 写在开轮行上的同一个);不取 `itemsTurnId`——
|
|
221387
|
+
// 那是 items 上接着写的键,没接轮次账本时是兜底串。
|
|
221388
|
+
turnId: plan.turnId
|
|
221389
|
+
});
|
|
221390
|
+
currentMsgId = split.nextId;
|
|
221095
221391
|
segmentBaseSeq = live.bufferedParts().reduce((max, p2) => p2.seq > max ? p2.seq : max, 0);
|
|
221096
|
-
|
|
221097
|
-
checkpointChain = checkpointChain.then(async () => {
|
|
221098
|
-
await store.updateMessage(closingId, {
|
|
221099
|
-
content: segText,
|
|
221100
|
-
status: "done",
|
|
221101
|
-
completedAt: at,
|
|
221102
|
-
...segParts.length ? { parts: segParts } : {}
|
|
221103
|
-
}).catch(() => void 0);
|
|
221104
|
-
await store.appendMessage({
|
|
221105
|
-
id: (0, import_node_crypto49.randomUUID)(),
|
|
221106
|
-
sessionId: plan.chatSessionId,
|
|
221107
|
-
role: "user",
|
|
221108
|
-
content: text6,
|
|
221109
|
-
createdAt: at
|
|
221110
|
-
}).catch(() => void 0);
|
|
221111
|
-
await store.appendMessage({
|
|
221112
|
-
id: nextId,
|
|
221113
|
-
sessionId: plan.chatSessionId,
|
|
221114
|
-
role: "assistant",
|
|
221115
|
-
content: "",
|
|
221116
|
-
createdAt: at,
|
|
221117
|
-
status: "running",
|
|
221118
|
-
runId: plan.runId
|
|
221119
|
-
}).then(() => itemLedger.bindMessage(nextId)).catch(() => void 0);
|
|
221120
|
-
}).catch(() => void 0);
|
|
221392
|
+
checkpointChain = checkpointChain.then(split.persist).catch(() => void 0);
|
|
221121
221393
|
});
|
|
221122
221394
|
}
|
|
221123
221395
|
const ckptTimer = setInterval(() => {
|
|
@@ -221589,12 +221861,11 @@ async function recoverChatTurnsAcrossCompanies(deps) {
|
|
|
221589
221861
|
}
|
|
221590
221862
|
return { ...result, recovered };
|
|
221591
221863
|
}
|
|
221592
|
-
var
|
|
221864
|
+
var asObj3, partsOf, maxPartSeq, exitFailed, exitErrorText, runTerminalPatch;
|
|
221593
221865
|
var init_chat_recovery = __esm({
|
|
221594
221866
|
"../server/src/chat-recovery.ts"() {
|
|
221595
221867
|
"use strict";
|
|
221596
221868
|
init_file_restore();
|
|
221597
|
-
import_node_crypto49 = require("node:crypto");
|
|
221598
221869
|
init_chat_parts();
|
|
221599
221870
|
init_sink();
|
|
221600
221871
|
init_resilient_appender();
|
|
@@ -221625,8 +221896,8 @@ var init_chat_recovery = __esm({
|
|
|
221625
221896
|
|
|
221626
221897
|
// ../server/src/auth/crypto.ts
|
|
221627
221898
|
function hashPassword(password) {
|
|
221628
|
-
const salt = (0,
|
|
221629
|
-
const dk = (0,
|
|
221899
|
+
const salt = (0, import_node_crypto49.randomBytes)(16);
|
|
221900
|
+
const dk = (0, import_node_crypto49.scryptSync)(password, salt, SCRYPT_KEYLEN, { N: SCRYPT_N, maxmem: 64 * 1024 * 1024 });
|
|
221630
221901
|
return `scrypt$${SCRYPT_N}$${salt.toString("base64url")}$${dk.toString("base64url")}`;
|
|
221631
221902
|
}
|
|
221632
221903
|
function verifyPassword(password, stored) {
|
|
@@ -221643,8 +221914,8 @@ function verifyPassword(password, stored) {
|
|
|
221643
221914
|
return false;
|
|
221644
221915
|
}
|
|
221645
221916
|
if (expected.length === 0) return false;
|
|
221646
|
-
const dk = (0,
|
|
221647
|
-
return dk.length === expected.length && (0,
|
|
221917
|
+
const dk = (0, import_node_crypto49.scryptSync)(password, salt, expected.length, { N, maxmem: 64 * 1024 * 1024 });
|
|
221918
|
+
return dk.length === expected.length && (0, import_node_crypto49.timingSafeEqual)(dk, expected);
|
|
221648
221919
|
}
|
|
221649
221920
|
function b64urlJson(value2) {
|
|
221650
221921
|
return Buffer.from(JSON.stringify(value2)).toString("base64url");
|
|
@@ -221652,17 +221923,17 @@ function b64urlJson(value2) {
|
|
|
221652
221923
|
function signSession(claims, secret) {
|
|
221653
221924
|
const head = b64urlJson({ alg: "HS256", typ: "JWT" });
|
|
221654
221925
|
const body2 = b64urlJson(claims);
|
|
221655
|
-
const sig = (0,
|
|
221926
|
+
const sig = (0, import_node_crypto49.createHmac)("sha256", secret).update(`${head}.${body2}`).digest("base64url");
|
|
221656
221927
|
return `${head}.${body2}.${sig}`;
|
|
221657
221928
|
}
|
|
221658
221929
|
function verifySession(token, secret, nowMs) {
|
|
221659
221930
|
const parts = token.split(".");
|
|
221660
221931
|
if (parts.length !== 3) return null;
|
|
221661
221932
|
const [head, body2, sig] = parts;
|
|
221662
|
-
const expected = (0,
|
|
221933
|
+
const expected = (0, import_node_crypto49.createHmac)("sha256", secret).update(`${head}.${body2}`).digest("base64url");
|
|
221663
221934
|
const got = Buffer.from(sig);
|
|
221664
221935
|
const exp = Buffer.from(expected);
|
|
221665
|
-
if (got.length !== exp.length || !(0,
|
|
221936
|
+
if (got.length !== exp.length || !(0, import_node_crypto49.timingSafeEqual)(got, exp)) return null;
|
|
221666
221937
|
let claims;
|
|
221667
221938
|
try {
|
|
221668
221939
|
claims = JSON.parse(Buffer.from(body2, "base64url").toString("utf8"));
|
|
@@ -221674,21 +221945,21 @@ function verifySession(token, secret, nowMs) {
|
|
|
221674
221945
|
return claims;
|
|
221675
221946
|
}
|
|
221676
221947
|
function generateCode() {
|
|
221677
|
-
return String((0,
|
|
221948
|
+
return String((0, import_node_crypto49.randomInt)(0, 1e6)).padStart(6, "0");
|
|
221678
221949
|
}
|
|
221679
221950
|
function hashCode(code2, secret) {
|
|
221680
|
-
return (0,
|
|
221951
|
+
return (0, import_node_crypto49.createHmac)("sha256", secret).update(`code:${code2}`).digest("base64url");
|
|
221681
221952
|
}
|
|
221682
221953
|
function safeEqualHash(a, b2) {
|
|
221683
221954
|
const ba = Buffer.from(a);
|
|
221684
221955
|
const bb = Buffer.from(b2);
|
|
221685
|
-
return ba.length === bb.length && (0,
|
|
221956
|
+
return ba.length === bb.length && (0, import_node_crypto49.timingSafeEqual)(ba, bb);
|
|
221686
221957
|
}
|
|
221687
|
-
var
|
|
221958
|
+
var import_node_crypto49, SCRYPT_N, SCRYPT_KEYLEN;
|
|
221688
221959
|
var init_crypto2 = __esm({
|
|
221689
221960
|
"../server/src/auth/crypto.ts"() {
|
|
221690
221961
|
"use strict";
|
|
221691
|
-
|
|
221962
|
+
import_node_crypto49 = require("node:crypto");
|
|
221692
221963
|
SCRYPT_N = 16384;
|
|
221693
221964
|
SCRYPT_KEYLEN = 32;
|
|
221694
221965
|
}
|
|
@@ -222851,18 +223122,18 @@ function variableKeyFromEnv(env = process.env) {
|
|
|
222851
223122
|
return buf;
|
|
222852
223123
|
}
|
|
222853
223124
|
if (env.NODE_ENV === "production") throw new Error("OASIS_VAR_KEY is required in production");
|
|
222854
|
-
return (0,
|
|
223125
|
+
return (0, import_node_crypto50.createHash)("sha256").update("oasis-dev-only-variable-key").digest();
|
|
222855
223126
|
}
|
|
222856
223127
|
function dedupe(ids2) {
|
|
222857
223128
|
return [...new Set(ids2.filter((x2) => typeof x2 === "string" && x2.length > 0))];
|
|
222858
223129
|
}
|
|
222859
|
-
var
|
|
223130
|
+
var import_node_crypto50, REDACTED_MARKER, ActorsService, mask, changedKeys;
|
|
222860
223131
|
var init_service5 = __esm({
|
|
222861
223132
|
"../server/src/domains/actors/service.ts"() {
|
|
222862
223133
|
"use strict";
|
|
222863
223134
|
init_file_limits2();
|
|
222864
223135
|
init_keyed_mutex();
|
|
222865
|
-
|
|
223136
|
+
import_node_crypto50 = require("node:crypto");
|
|
222866
223137
|
init_skill_fetcher();
|
|
222867
223138
|
init_identity();
|
|
222868
223139
|
init_migrate();
|
|
@@ -223430,7 +223701,7 @@ ${input.description}
|
|
|
223430
223701
|
*/
|
|
223431
223702
|
buildSkillFile(skillId, path40, content3, now) {
|
|
223432
223703
|
const bytes2 = new TextEncoder().encode(content3);
|
|
223433
|
-
const blobHash = (0,
|
|
223704
|
+
const blobHash = (0, import_node_crypto50.createHash)("sha256").update(bytes2).digest("hex");
|
|
223434
223705
|
return { skillId, path: path40, content: content3, blobHash, size: bytes2.length, updatedAt: now };
|
|
223435
223706
|
}
|
|
223436
223707
|
/**
|
|
@@ -224211,15 +224482,15 @@ ${input.description}
|
|
|
224211
224482
|
return hit ? { value: hit.value, ...hit.origin ? { origin: hit.origin } : {} } : null;
|
|
224212
224483
|
}
|
|
224213
224484
|
encrypt(plain) {
|
|
224214
|
-
const iv = (0,
|
|
224215
|
-
const cipher = (0,
|
|
224216
|
-
const
|
|
224217
|
-
return [iv.toString("base64"), cipher.getAuthTag().toString("base64"),
|
|
224485
|
+
const iv = (0, import_node_crypto50.randomBytes)(12);
|
|
224486
|
+
const cipher = (0, import_node_crypto50.createCipheriv)("aes-256-gcm", this.opts.variableKey, iv);
|
|
224487
|
+
const enc3 = Buffer.concat([cipher.update(plain, "utf8"), cipher.final()]);
|
|
224488
|
+
return [iv.toString("base64"), cipher.getAuthTag().toString("base64"), enc3.toString("base64")].join(".");
|
|
224218
224489
|
}
|
|
224219
224490
|
decrypt(packed) {
|
|
224220
224491
|
const [iv, tag, data] = packed.split(".");
|
|
224221
224492
|
if (!iv || !tag || typeof data !== "string") throw new Error("malformed ciphertext");
|
|
224222
|
-
const decipher = (0,
|
|
224493
|
+
const decipher = (0, import_node_crypto50.createDecipheriv)("aes-256-gcm", this.opts.variableKey, Buffer.from(iv, "base64"));
|
|
224223
224494
|
decipher.setAuthTag(Buffer.from(tag, "base64"));
|
|
224224
224495
|
return Buffer.concat([decipher.update(Buffer.from(data, "base64")), decipher.final()]).toString("utf8");
|
|
224225
224496
|
}
|
|
@@ -224831,7 +225102,7 @@ async function listSkillMetadataForActor(args) {
|
|
|
224831
225102
|
usedDirs.add(dir);
|
|
224832
225103
|
const sorted = [...metas].sort((a, b2) => a.path.localeCompare(b2.path));
|
|
224833
225104
|
let latest = "1970-01-01T00:00:00.000Z";
|
|
224834
|
-
const hasher = (0,
|
|
225105
|
+
const hasher = (0, import_node_crypto51.createHash)("sha256");
|
|
224835
225106
|
for (const m2 of sorted) {
|
|
224836
225107
|
if (m2.updatedAt > latest) latest = m2.updatedAt;
|
|
224837
225108
|
hasher.update(m2.path);
|
|
@@ -224856,11 +225127,11 @@ async function listSkillMetadataForActor(args) {
|
|
|
224856
225127
|
const dir = sanitizeSkillDir(c.name, c.slug);
|
|
224857
225128
|
if (usedDirs.has(dir)) continue;
|
|
224858
225129
|
usedDirs.add(dir);
|
|
224859
|
-
const hasher = (0,
|
|
225130
|
+
const hasher = (0, import_node_crypto51.createHash)("sha256");
|
|
224860
225131
|
for (const p2 of paths) {
|
|
224861
225132
|
hasher.update(p2);
|
|
224862
225133
|
hasher.update("\0");
|
|
224863
|
-
hasher.update((0,
|
|
225134
|
+
hasher.update((0, import_node_crypto51.createHash)("sha256").update(c.files[p2]).digest("hex"));
|
|
224864
225135
|
hasher.update("\0");
|
|
224865
225136
|
}
|
|
224866
225137
|
out.push({
|
|
@@ -224881,11 +225152,11 @@ async function listSkillMetadataForActor(args) {
|
|
|
224881
225152
|
const dir = sanitizeSkillDir(b2.name, b2.id);
|
|
224882
225153
|
if (usedDirs.has(dir)) continue;
|
|
224883
225154
|
usedDirs.add(dir);
|
|
224884
|
-
const hasher = (0,
|
|
225155
|
+
const hasher = (0, import_node_crypto51.createHash)("sha256");
|
|
224885
225156
|
for (const p2 of paths) {
|
|
224886
225157
|
hasher.update(p2);
|
|
224887
225158
|
hasher.update("\0");
|
|
224888
|
-
hasher.update((0,
|
|
225159
|
+
hasher.update((0, import_node_crypto51.createHash)("sha256").update(b2.files[p2]).digest("hex"));
|
|
224889
225160
|
hasher.update("\0");
|
|
224890
225161
|
}
|
|
224891
225162
|
out.push({
|
|
@@ -224905,7 +225176,7 @@ function builtinSkillToFiles(b2) {
|
|
|
224905
225176
|
skillId: `builtin:${b2.id}`,
|
|
224906
225177
|
path: path40,
|
|
224907
225178
|
content: content3,
|
|
224908
|
-
blobHash: (0,
|
|
225179
|
+
blobHash: (0, import_node_crypto51.createHash)("sha256").update(content3).digest("hex"),
|
|
224909
225180
|
size: Buffer.byteLength(content3, "utf8"),
|
|
224910
225181
|
updatedAt: "1970-01-01T00:00:00.000Z"
|
|
224911
225182
|
}));
|
|
@@ -224929,7 +225200,7 @@ function sanitizeSkillDir(name, fallbackId) {
|
|
|
224929
225200
|
if (byName) return byName;
|
|
224930
225201
|
const byId = fallbackId ? fold2(fallbackId) : "";
|
|
224931
225202
|
if (byId) return byId;
|
|
224932
|
-
return `skill-${(0,
|
|
225203
|
+
return `skill-${(0, import_node_crypto51.createHash)("sha256").update(name).digest("hex").slice(0, 8)}`;
|
|
224933
225204
|
}
|
|
224934
225205
|
async function materializeSkillFiles(args) {
|
|
224935
225206
|
const skills = await args.service.listInstalledSkillsForActor(args.actorId);
|
|
@@ -224962,7 +225233,7 @@ function connectorSkillToFiles(c) {
|
|
|
224962
225233
|
skillId: c.id,
|
|
224963
225234
|
path: path40,
|
|
224964
225235
|
content: content3,
|
|
224965
|
-
blobHash: (0,
|
|
225236
|
+
blobHash: (0, import_node_crypto51.createHash)("sha256").update(content3).digest("hex"),
|
|
224966
225237
|
size: Buffer.byteLength(content3, "utf8"),
|
|
224967
225238
|
updatedAt: "1970-01-01T00:00:00.000Z"
|
|
224968
225239
|
}));
|
|
@@ -224979,11 +225250,11 @@ function connectorSkillDisplayRows(connectorSkills, enabledConnectors) {
|
|
|
224979
225250
|
...s2.version !== void 0 ? { version: s2.version } : {}
|
|
224980
225251
|
}));
|
|
224981
225252
|
}
|
|
224982
|
-
var
|
|
225253
|
+
var import_node_crypto51;
|
|
224983
225254
|
var init_skill_materializer = __esm({
|
|
224984
225255
|
"../server/src/domains/actors/skill-materializer.ts"() {
|
|
224985
225256
|
"use strict";
|
|
224986
|
-
|
|
225257
|
+
import_node_crypto51 = require("node:crypto");
|
|
224987
225258
|
}
|
|
224988
225259
|
});
|
|
224989
225260
|
|
|
@@ -226551,7 +226822,7 @@ function createActorsDomain(opts) {
|
|
|
226551
226822
|
...kernel !== void 0 ? { onRolesChanged: (a, r) => kernel.setActorRoles(a, r) } : {},
|
|
226552
226823
|
audit: async (entry) => {
|
|
226553
226824
|
await opts.audit?.({
|
|
226554
|
-
id: `reg_${(0,
|
|
226825
|
+
id: `reg_${(0, import_node_crypto52.randomUUID)()}`,
|
|
226555
226826
|
actor: entry.by,
|
|
226556
226827
|
kind: "registry_change",
|
|
226557
226828
|
target: entry.actorId,
|
|
@@ -226591,11 +226862,11 @@ function createActorsDomain(opts) {
|
|
|
226591
226862
|
register: actorsDomain({ resolveCtx, ...opts.resolveTrace ? { resolveTrace: opts.resolveTrace } : {}, ...opts.trace ? { trace: opts.trace } : {}, ...opts.listBuiltinSkills ? { listBuiltinSkills: opts.listBuiltinSkills } : {}, ...opts.getBuiltinSkills ? { getBuiltinSkills: opts.getBuiltinSkills } : {}, ...opts.getConnectorSkills ? { getConnectorSkills: opts.getConnectorSkills } : {}, ...opts.refreshConnectorSkills ? { refreshConnectorSkills: opts.refreshConnectorSkills } : {}, ...opts.memory ? { memory: opts.memory } : {}, ...opts.resolveDispatchScope ? { resolveDispatchScope: opts.resolveDispatchScope } : {}, ...opts.projectExists ? { projectExists: opts.projectExists } : {}, ...opts.isCompanyManager ? { isCompanyManager: opts.isCompanyManager } : {}, ...opts.credentialAudit ? { credentialAudit: opts.credentialAudit } : {}, ...opts.readCredentialAudit ? { readCredentialAudit: opts.readCredentialAudit } : {}, ...opts.credentialRevealLimits ? { credentialRevealLimits: opts.credentialRevealLimits } : {}, ...opts.skillMarket ? { skillMarket: opts.skillMarket } : {}, ...opts.resolveNodeTenancy ? { resolveNodeTenancy: opts.resolveNodeTenancy } : {} })
|
|
226592
226863
|
};
|
|
226593
226864
|
}
|
|
226594
|
-
var
|
|
226865
|
+
var import_node_crypto52;
|
|
226595
226866
|
var init_actors = __esm({
|
|
226596
226867
|
"../server/src/domains/actors/index.ts"() {
|
|
226597
226868
|
"use strict";
|
|
226598
|
-
|
|
226869
|
+
import_node_crypto52 = require("node:crypto");
|
|
226599
226870
|
init_service5();
|
|
226600
226871
|
init_routes3();
|
|
226601
226872
|
init_service5();
|
|
@@ -228093,6 +228364,7 @@ function buildWorkorderActivity(input) {
|
|
|
228093
228364
|
const nodeCancelledAt = node2?.cancelledAt ?? null;
|
|
228094
228365
|
const name = nodeName(nodeId);
|
|
228095
228366
|
let fold2 = null;
|
|
228367
|
+
let handoverFold = null;
|
|
228096
228368
|
for (const [idx, w2] of works.entries()) {
|
|
228097
228369
|
const next = works[idx + 1];
|
|
228098
228370
|
const artifacts = artifactsByWork.get(w2.id) ?? [];
|
|
@@ -228102,6 +228374,7 @@ function buildWorkorderActivity(input) {
|
|
|
228102
228374
|
const reassigned = !!next && next.assigneeActorId !== w2.assigneeActorId;
|
|
228103
228375
|
const killedByPlan = !!(w2.deadAt || w2.cancelledAt) && !!next && (reassigned || (next.nodeVersion ?? 0) > (w2.nodeVersion ?? 0));
|
|
228104
228376
|
const failedRound = !w2.conclusion && !interrupt && !removedHere && !killedByPlan && (!!w2.deadAt || !!w2.cancelledAt || st === "failed" || st === "retry");
|
|
228377
|
+
const handedOverRound = !w2.conclusion && !interrupt && !removedHere && !killedByPlan && !failedRound && st === "success" && !!w2.endedAt && !!next;
|
|
228105
228378
|
if (failedRound && fold2) {
|
|
228106
228379
|
fold2.traceWorkIds.push(w2.id);
|
|
228107
228380
|
cardOfWork.set(w2.id, fold2);
|
|
@@ -228112,6 +228385,16 @@ function buildWorkorderActivity(input) {
|
|
|
228112
228385
|
continue;
|
|
228113
228386
|
}
|
|
228114
228387
|
fold2 = null;
|
|
228388
|
+
if (handedOverRound && handoverFold && handoverFold.executorId === w2.assigneeActorId) {
|
|
228389
|
+
handoverFold.traceWorkIds.push(w2.id);
|
|
228390
|
+
cardOfWork.set(w2.id, handoverFold);
|
|
228391
|
+
handoverFold.updatedAt = lastStampOf(w2);
|
|
228392
|
+
handoverFold.artifacts = artifacts;
|
|
228393
|
+
handoverFold.foldedRounds = (handoverFold.foldedRounds ?? 1) + 1;
|
|
228394
|
+
handoverFold.status = ACTIVITY_COPY.foldedStageHandedOver(name, handoverFold.foldedRounds);
|
|
228395
|
+
continue;
|
|
228396
|
+
}
|
|
228397
|
+
handoverFold = null;
|
|
228115
228398
|
const card2 = {
|
|
228116
228399
|
/* 卡 id = 这一轮的 workId(连败折叠时取第一轮,React key 与滚动锚点因此稳定)。 */
|
|
228117
228400
|
id: `work:${w2.id}`,
|
|
@@ -228159,6 +228442,10 @@ function buildWorkorderActivity(input) {
|
|
|
228159
228442
|
card2.stuckReason = stuckKind;
|
|
228160
228443
|
card2.status = w2.deadAt || w2.cancelledAt ? ACTIVITY_COPY.killed(name) : st === "retry" ? ACTIVITY_COPY.awaitingRedispatch(nameOf(card2.executorId), name) : stuckKind === "timeout" ? ACTIVITY_COPY.timedOut(nameOf(card2.executorId)) : ACTIVITY_COPY.failed(nameOf(card2.executorId));
|
|
228161
228444
|
fold2 = card2;
|
|
228445
|
+
} else if (handedOverRound) {
|
|
228446
|
+
card2.phase = "done";
|
|
228447
|
+
card2.status = ACTIVITY_COPY.stageHandedOver(name);
|
|
228448
|
+
handoverFold = card2;
|
|
228162
228449
|
} else if (w2.endedAt) {
|
|
228163
228450
|
card2.phase = "running";
|
|
228164
228451
|
card2.status = ACTIVITY_COPY.awaitingConclude(name);
|
|
@@ -228822,8 +229109,20 @@ var init_activity2 = __esm({
|
|
|
228822
229109
|
/**
|
|
228823
229110
|
* 引擎判卷 success、`endedAt` 也写了,却始终没有 `work.conclude`:**交了稿没收口**。
|
|
228824
229111
|
* 如实说这一档,不冒充「正在处理」——后者把一轮早就结束的执行画成还在跑。
|
|
229112
|
+
* 只剩**节点最新一轮**会落到这里;同节点已有下一轮接手的,见 {@link stageHandedOver}。
|
|
228825
229113
|
*/
|
|
228826
229114
|
awaitingConclude: (node2) => `\u300A${node2}\u300B\u5DF2\u4EA4\u4ED8\uFF0C\u7B49\u5F85\u6536\u53E3\u3002`,
|
|
229115
|
+
/**
|
|
229116
|
+
* **阶段交付已被接手**:这一轮交了稿、没收口,同节点已经派出下一轮接着做(分批 `propose --checkpoint
|
|
229117
|
+
* --continue`,或派活说明要求先别收口)。这一段到此已经交付——等收口的是接手的那一轮,不是它。
|
|
229118
|
+
* 此前落在 {@link awaitingConclude}、永远「进行中」:生产 2026-09-17 近 7 天 40 张进行中卡全是僵尸,
|
|
229119
|
+
* 38 张是这一档,`ws:wo-da302dca` 一个 QA 节点分批测就留下 24 张(Bug 0053)。
|
|
229120
|
+
*
|
|
229121
|
+
* 不说「已完成」:节点并没有完成,说了会让人以为这一步做完、在等审核。
|
|
229122
|
+
*/
|
|
229123
|
+
stageHandedOver: (node2) => `\u300A${node2}\u300B\u5DF2\u63D0\u4EA4\u9636\u6BB5\u6210\u679C\uFF0C\u7531\u4E0B\u4E00\u8F6E\u7EE7\u7EED\u3002`,
|
|
229124
|
+
/** 同一节点上紧挨着的阶段交付轮折成一张(与连败折叠同一套机制),批数写进句子。 */
|
|
229125
|
+
foldedStageHandedOver: (node2, n) => `\u300A${node2}\u300B\u5DF2\u5206 ${n} \u6279\u63D0\u4EA4\u9636\u6BB5\u6210\u679C\uFF0C\u7531\u4E0B\u4E00\u8F6E\u7EE7\u7EED\u3002`,
|
|
228827
229126
|
/** `works.status=retry`:这一轮没跑成,等引擎重派。谁按的重试由 `plan.node_retry` 补进这句。 */
|
|
228828
229127
|
awaitingRedispatch: (executor, node2) => `${executor} \u8FD9\u4E00\u8F6E\u6CA1\u8DD1\u6210\u300A${node2}\u300B\uFF0C\u7B49\u5F85\u91CD\u6D3E\u3002`,
|
|
228829
229128
|
doneAwaitingReview: (name) => `\u300A${name}\u300B\u5DF2\u5B8C\u6210\uFF0C\u7B49\u5F85\u5BA1\u6838\u3002`,
|
|
@@ -229795,7 +230094,7 @@ async function buildChatPreview(chatStore, sessionId, who) {
|
|
|
229795
230094
|
async function buildChatInbox(chatStore, markers, me, resolveActor, excludeChildSessions) {
|
|
229796
230095
|
const sessions = await chatStore.listSessions(me);
|
|
229797
230096
|
const byScope = new Map(markers.map((m2) => [m2.scope, m2]));
|
|
229798
|
-
const unread = sessions.filter((s2) =>
|
|
230097
|
+
const unread = sessions.filter((s2) => isChatSessionUnread(s2, byScope.get(chatScope(s2.id)))).sort((a, b2) => a.touchedAt < b2.touchedAt ? 1 : a.touchedAt > b2.touchedAt ? -1 : 0);
|
|
229799
230098
|
const excluded = excludeChildSessions ? new Set(await excludeChildSessions(unread.map((s2) => s2.id)).catch(() => [])) : /* @__PURE__ */ new Set();
|
|
229800
230099
|
const out = [];
|
|
229801
230100
|
let previewsFetched = 0;
|
|
@@ -230065,11 +230364,11 @@ function fromRow(row) {
|
|
|
230065
230364
|
for (const [k2, v2] of opt) if (v2 !== void 0 && v2 !== null) r[k2] = v2;
|
|
230066
230365
|
return r;
|
|
230067
230366
|
}
|
|
230068
|
-
var
|
|
230367
|
+
var import_node_crypto53, import_node_fs14, DEFAULT_PAGE, MAX_PAGE, pageSize, MemoryNotificationStore, ident3, iso2, str2, PostgresNotificationStore;
|
|
230069
230368
|
var init_notification_store = __esm({
|
|
230070
230369
|
"../server/src/domains/collab/notification-store.ts"() {
|
|
230071
230370
|
"use strict";
|
|
230072
|
-
|
|
230371
|
+
import_node_crypto53 = require("node:crypto");
|
|
230073
230372
|
import_node_fs14 = __toESM(require("node:fs"), 1);
|
|
230074
230373
|
DEFAULT_PAGE = 50;
|
|
230075
230374
|
MAX_PAGE = 200;
|
|
@@ -230102,7 +230401,7 @@ var init_notification_store = __esm({
|
|
|
230102
230401
|
async insert(n) {
|
|
230103
230402
|
const existing = this.findLive(n.recipient, n.sourceKey, n.category);
|
|
230104
230403
|
if (existing) return existing;
|
|
230105
|
-
const row = { ...n, id: `ntf:${(0,
|
|
230404
|
+
const row = { ...n, id: `ntf:${(0, import_node_crypto53.randomUUID)()}`, updatedAt: n.enteredAt };
|
|
230106
230405
|
this.rows.set(row.id, row);
|
|
230107
230406
|
this.save();
|
|
230108
230407
|
return row;
|
|
@@ -230225,7 +230524,7 @@ var init_notification_store = __esm({
|
|
|
230225
230524
|
return new _PostgresNotificationStore(sql, schema);
|
|
230226
230525
|
}
|
|
230227
230526
|
async insert(n) {
|
|
230228
|
-
const id = `ntf:${(0,
|
|
230527
|
+
const id = `ntf:${(0, import_node_crypto53.randomUUID)()}`;
|
|
230229
230528
|
const r = await this.sql.query(
|
|
230230
230529
|
`INSERT INTO ${this.t} (id, recipient, category, source_key, kind, workorder_id, node_id, card_id, actor_id,
|
|
230231
230530
|
title, workspace_title, entered_at, updated_at, status, read_at, item)
|
|
@@ -231176,13 +231475,13 @@ function nameKey(name) {
|
|
|
231176
231475
|
function cleanName(name) {
|
|
231177
231476
|
return name.trim().replace(/\s+/g, " ");
|
|
231178
231477
|
}
|
|
231179
|
-
var import_node_fs15, import_node_path21,
|
|
231478
|
+
var import_node_fs15, import_node_path21, import_node_crypto54, SEP, keyOf, prefixOf, MemoryWorkorderTagStore, FileWorkorderTagStore;
|
|
231180
231479
|
var init_tags = __esm({
|
|
231181
231480
|
"../server/src/domains/collab/tags.ts"() {
|
|
231182
231481
|
"use strict";
|
|
231183
231482
|
import_node_fs15 = __toESM(require("node:fs"), 1);
|
|
231184
231483
|
import_node_path21 = __toESM(require("node:path"), 1);
|
|
231185
|
-
|
|
231484
|
+
import_node_crypto54 = __toESM(require("node:crypto"), 1);
|
|
231186
231485
|
SEP = "::";
|
|
231187
231486
|
keyOf = (companyId, id) => `${companyId}${SEP}${id}`;
|
|
231188
231487
|
prefixOf = (companyId) => `${companyId}${SEP}`;
|
|
@@ -231200,7 +231499,7 @@ var init_tags = __esm({
|
|
|
231200
231499
|
if (!name) return null;
|
|
231201
231500
|
if (this.entries(companyId).some((t) => nameKey(t.name) === nameKey(name))) return null;
|
|
231202
231501
|
const tag = {
|
|
231203
|
-
id: `tag-${
|
|
231502
|
+
id: `tag-${import_node_crypto54.default.randomBytes(6).toString("hex")}`,
|
|
231204
231503
|
name,
|
|
231205
231504
|
...input.color?.trim() ? { color: input.color.trim() } : {},
|
|
231206
231505
|
...input.description?.trim() ? { description: input.description.trim() } : {}
|
|
@@ -232516,11 +232815,11 @@ async function isEmployedElsewhere(store, companyId, accountId) {
|
|
|
232516
232815
|
const memberships = await store.listMembershipsForAccount(accountId);
|
|
232517
232816
|
return memberships.some((m2) => m2.companyId !== companyId);
|
|
232518
232817
|
}
|
|
232519
|
-
var
|
|
232818
|
+
var import_node_crypto55, ROLES, INVITABLE_ROLES, INVITATION_TTL_MS, INVITE_LINK_TTL_MS, INVITE_LINK_TOKEN_BYTES, INVITE_LINK_ROLE, SLUG_RE, CompanyError, CompaniesService;
|
|
232520
232819
|
var init_service6 = __esm({
|
|
232521
232820
|
"../server/src/domains/companies/service.ts"() {
|
|
232522
232821
|
"use strict";
|
|
232523
|
-
|
|
232822
|
+
import_node_crypto55 = require("node:crypto");
|
|
232524
232823
|
init_console_url();
|
|
232525
232824
|
ROLES = ["owner", "admin", "member"];
|
|
232526
232825
|
INVITABLE_ROLES = ["admin", "member"];
|
|
@@ -232612,7 +232911,7 @@ var init_service6 = __esm({
|
|
|
232612
232911
|
const existing = await this.store.getAccountByEmail(normalized4);
|
|
232613
232912
|
if (existing) return existing;
|
|
232614
232913
|
const account = {
|
|
232615
|
-
id: `actor:human:${(0,
|
|
232914
|
+
id: `actor:human:${(0, import_node_crypto55.randomUUID)()}`,
|
|
232616
232915
|
email: normalized4,
|
|
232617
232916
|
name: name ?? normalized4,
|
|
232618
232917
|
status: "active"
|
|
@@ -232821,7 +233120,7 @@ var init_service6 = __esm({
|
|
|
232821
233120
|
}
|
|
232822
233121
|
const nowMs = Date.parse(this.now());
|
|
232823
233122
|
const invitation = {
|
|
232824
|
-
id: `invitation:${(0,
|
|
233123
|
+
id: `invitation:${(0, import_node_crypto55.randomUUID)()}`,
|
|
232825
233124
|
companyId,
|
|
232826
233125
|
email: mail,
|
|
232827
233126
|
role,
|
|
@@ -232952,7 +233251,7 @@ var init_service6 = __esm({
|
|
|
232952
233251
|
const nowMs = Date.parse(this.now());
|
|
232953
233252
|
const link = {
|
|
232954
233253
|
companyId,
|
|
232955
|
-
token: (0,
|
|
233254
|
+
token: (0, import_node_crypto55.randomBytes)(INVITE_LINK_TOKEN_BYTES).toString("base64url"),
|
|
232956
233255
|
role: INVITE_LINK_ROLE,
|
|
232957
233256
|
createdAt: new Date(nowMs).toISOString(),
|
|
232958
233257
|
expiresAt: new Date(nowMs + INVITE_LINK_TTL_MS).toISOString(),
|
|
@@ -233009,7 +233308,7 @@ var init_service6 = __esm({
|
|
|
233009
233308
|
const reusable = existing.find((inv) => !this.isExpired(inv));
|
|
233010
233309
|
if (reusable) return reusable;
|
|
233011
233310
|
const invitation = {
|
|
233012
|
-
id: `invitation:${(0,
|
|
233311
|
+
id: `invitation:${(0, import_node_crypto55.randomUUID)()}`,
|
|
233013
233312
|
companyId: link.companyId,
|
|
233014
233313
|
email: mail,
|
|
233015
233314
|
role: link.role,
|
|
@@ -233247,11 +233546,11 @@ var init_service6 = __esm({
|
|
|
233247
233546
|
});
|
|
233248
233547
|
|
|
233249
233548
|
// ../server/src/domains/companies/offboarding.ts
|
|
233250
|
-
var
|
|
233549
|
+
var import_node_crypto56, MemberOffboardingService;
|
|
233251
233550
|
var init_offboarding = __esm({
|
|
233252
233551
|
"../server/src/domains/companies/offboarding.ts"() {
|
|
233253
233552
|
"use strict";
|
|
233254
|
-
|
|
233553
|
+
import_node_crypto56 = require("node:crypto");
|
|
233255
233554
|
init_service6();
|
|
233256
233555
|
MemberOffboardingService = class {
|
|
233257
233556
|
store;
|
|
@@ -233323,7 +233622,7 @@ var init_offboarding = __esm({
|
|
|
233323
233622
|
const { ownedAgents, inFlight } = await this.snapshot(companyId, accountId);
|
|
233324
233623
|
const at = this.now();
|
|
233325
233624
|
const started = await this.store.startMemberOffboarding({
|
|
233326
|
-
operationId: `off:${(0,
|
|
233625
|
+
operationId: `off:${(0, import_node_crypto56.randomUUID)()}`,
|
|
233327
233626
|
companyId,
|
|
233328
233627
|
accountId,
|
|
233329
233628
|
initiatedBy,
|
|
@@ -233833,18 +234132,18 @@ var init_routes6 = __esm({
|
|
|
233833
234132
|
|
|
233834
234133
|
// ../server/src/domains/companies/agent-credentials.ts
|
|
233835
234134
|
function hashAgentToken(token, secret) {
|
|
233836
|
-
return HASH_PREFIX + (0,
|
|
234135
|
+
return HASH_PREFIX + (0, import_node_crypto57.createHmac)("sha256", secret).update(`agent-token:${token}`).digest("base64url");
|
|
233837
234136
|
}
|
|
233838
234137
|
function safeEqual(a, b2) {
|
|
233839
234138
|
const ba = Buffer.from(a);
|
|
233840
234139
|
const bb = Buffer.from(b2);
|
|
233841
|
-
return ba.length === bb.length && (0,
|
|
234140
|
+
return ba.length === bb.length && (0, import_node_crypto57.timingSafeEqual)(ba, bb);
|
|
233842
234141
|
}
|
|
233843
|
-
var
|
|
234142
|
+
var import_node_crypto57, HASH_PREFIX, TOKEN_PREFIX, AgentCredentialService;
|
|
233844
234143
|
var init_agent_credentials = __esm({
|
|
233845
234144
|
"../server/src/domains/companies/agent-credentials.ts"() {
|
|
233846
234145
|
"use strict";
|
|
233847
|
-
|
|
234146
|
+
import_node_crypto57 = require("node:crypto");
|
|
233848
234147
|
init_service6();
|
|
233849
234148
|
HASH_PREFIX = "ac1$";
|
|
233850
234149
|
TOKEN_PREFIX = "oak_";
|
|
@@ -233869,7 +234168,7 @@ var init_agent_credentials = __esm({
|
|
|
233869
234168
|
if (employee.status !== "active") {
|
|
233870
234169
|
throw new CompanyError(409, "AGENT_LEFT", `\u6570\u5B57\u5458\u5DE5\u5DF2\u79BB\u5F00\uFF0C\u4E0D\u80FD\u7B7E\u53D1\u51ED\u8BC1\uFF1A${agentId}`);
|
|
233871
234170
|
}
|
|
233872
|
-
const token = `${TOKEN_PREFIX}${(0,
|
|
234171
|
+
const token = `${TOKEN_PREFIX}${(0, import_node_crypto57.randomBytes)(32).toString("base64url")}`;
|
|
233873
234172
|
const credential = {
|
|
233874
234173
|
tokenHash: hashAgentToken(token, this.secret),
|
|
233875
234174
|
companyId,
|
|
@@ -234307,7 +234606,7 @@ function gatewayInstanceSlug(gatewayUrl) {
|
|
|
234307
234606
|
}
|
|
234308
234607
|
function connectInstanceName(gatewayUrl, token, companyId) {
|
|
234309
234608
|
const scope2 = companyId?.trim();
|
|
234310
|
-
const suffix = scope2 ? `c${(0,
|
|
234609
|
+
const suffix = scope2 ? `c${(0, import_node_crypto58.createHash)("sha256").update(`${gatewayUrl}\0${scope2}`).digest("hex").slice(0, 10)}` : token.replace(/[^a-z0-9]/gi, "").slice(-8).toLowerCase() || "enroll";
|
|
234311
234610
|
const base = gatewayInstanceSlug(gatewayUrl);
|
|
234312
234611
|
return base.slice(0, Math.max(1, 64 - suffix.length - 1)) + "-" + suffix;
|
|
234313
234612
|
}
|
|
@@ -234636,12 +234935,12 @@ function buildNpxCmd(p2) {
|
|
|
234636
234935
|
const prefix = daemonNpmPrefix();
|
|
234637
234936
|
return `npm install -g --prefer-online --prefix ${prefix} ${DAEMON_NPM_PACKAGE}@latest && ${prefix}/bin/oasis daemon start --instance ${shellQuote(instanceName)} --server-ws ${shellQuote(p2.gatewayUrl)}${companyPart}${namePart} --pkg ${shellQuote(DAEMON_NPM_PACKAGE)} --upgrade --enroll-token ${shellQuote(p2.token)}`;
|
|
234638
234937
|
}
|
|
234639
|
-
var
|
|
234938
|
+
var import_node_crypto58;
|
|
234640
234939
|
var init_connect_script = __esm({
|
|
234641
234940
|
"../server/src/domains/nodes/connect-script.ts"() {
|
|
234642
234941
|
"use strict";
|
|
234643
234942
|
init_src();
|
|
234644
|
-
|
|
234943
|
+
import_node_crypto58 = require("node:crypto");
|
|
234645
234944
|
}
|
|
234646
234945
|
});
|
|
234647
234946
|
|
|
@@ -235248,7 +235547,7 @@ function nodesDomain(deps) {
|
|
|
235248
235547
|
}
|
|
235249
235548
|
deps.enrollTokens.setIssuedNodeId(enrollToken, nodeId);
|
|
235250
235549
|
} else {
|
|
235251
|
-
nodeId = `node-${(0,
|
|
235550
|
+
nodeId = `node-${(0, import_node_crypto59.randomUUID)().slice(0, 8)}`;
|
|
235252
235551
|
deps.enrollTokens.setIssuedNodeId(enrollToken, nodeId);
|
|
235253
235552
|
}
|
|
235254
235553
|
const existingNode = await deps.nodeStore.getNode(nodeId);
|
|
@@ -235433,14 +235732,14 @@ function normalizeGatewayUrl(raw) {
|
|
|
235433
235732
|
}
|
|
235434
235733
|
}
|
|
235435
235734
|
function newNodeId() {
|
|
235436
|
-
return "node-" + (0,
|
|
235735
|
+
return "node-" + (0, import_node_crypto59.randomUUID)().replace(/-/g, "").slice(0, 12);
|
|
235437
235736
|
}
|
|
235438
|
-
var
|
|
235737
|
+
var import_node_crypto59, import_node_fs16, import_node_url6, import_node_path22;
|
|
235439
235738
|
var init_routes7 = __esm({
|
|
235440
235739
|
"../server/src/domains/nodes/routes.ts"() {
|
|
235441
235740
|
"use strict";
|
|
235442
235741
|
init_runtime_status();
|
|
235443
|
-
|
|
235742
|
+
import_node_crypto59 = require("node:crypto");
|
|
235444
235743
|
import_node_fs16 = require("node:fs");
|
|
235445
235744
|
import_node_url6 = require("node:url");
|
|
235446
235745
|
import_node_path22 = require("node:path");
|
|
@@ -236631,7 +236930,7 @@ function createBundle(root, target, input) {
|
|
|
236631
236930
|
}
|
|
236632
236931
|
}
|
|
236633
236932
|
const bytes2 = fs25.statSync(absBundle).size;
|
|
236634
|
-
const digest = (0,
|
|
236933
|
+
const digest = (0, import_node_crypto60.createHash)("sha256").update(fs25.readFileSync(absBundle)).digest("hex");
|
|
236635
236934
|
const relBase = `inputs/git-bundles/${safeRepo}-${commit.slice(0, 12)}`;
|
|
236636
236935
|
return {
|
|
236637
236936
|
absoluteBundlePath: absBundle,
|
|
@@ -236727,12 +237026,12 @@ function classifyGitError(fallback, err, where) {
|
|
|
236727
237026
|
function oneLine(msg) {
|
|
236728
237027
|
return msg.split("\n").map((s2) => s2.trim()).filter(Boolean).slice(0, 3).join(" ");
|
|
236729
237028
|
}
|
|
236730
|
-
var import_node_child_process16,
|
|
237029
|
+
var import_node_child_process16, import_node_crypto60, fs25, os7, path24, GitReadonlyBundleError, HEX40, FETCH_TIMEOUT_MS2;
|
|
236731
237030
|
var init_readonly_bundle = __esm({
|
|
236732
237031
|
"../server/src/git/readonly-bundle.ts"() {
|
|
236733
237032
|
"use strict";
|
|
236734
237033
|
import_node_child_process16 = require("node:child_process");
|
|
236735
|
-
|
|
237034
|
+
import_node_crypto60 = require("node:crypto");
|
|
236736
237035
|
fs25 = __toESM(require("node:fs"), 1);
|
|
236737
237036
|
os7 = __toESM(require("node:os"), 1);
|
|
236738
237037
|
path24 = __toESM(require("node:path"), 1);
|
|
@@ -236752,8 +237051,9 @@ var init_readonly_bundle = __esm({
|
|
|
236752
237051
|
|
|
236753
237052
|
// ../server/src/domains/collab/create-seeded-workorder.ts
|
|
236754
237053
|
function makeSeededWorkorderCreator(deps) {
|
|
236755
|
-
const
|
|
236756
|
-
|
|
237054
|
+
const locks = createKeyedMutex();
|
|
237055
|
+
const genWorkspace = deps.genWorkspace ?? (() => `ws:wo-${(0, import_node_crypto61.randomUUID)().slice(0, 8)}`);
|
|
237056
|
+
const create = async (input) => {
|
|
236757
237057
|
const company = input.companyId && deps.resolveCompany ? await deps.resolveCompany(input.companyId) : void 0;
|
|
236758
237058
|
const kernel = company?.kernel ?? deps.kernel;
|
|
236759
237059
|
const blobs = company?.blobs ?? deps.blobs;
|
|
@@ -236761,10 +237061,9 @@ function makeSeededWorkorderCreator(deps) {
|
|
|
236761
237061
|
const artifactState = company ? company.artifactState : deps.artifactState;
|
|
236762
237062
|
const workorderDrafts = company ? company.workorderDrafts : deps.workorderDrafts;
|
|
236763
237063
|
const workspace = input.idempotencyKey ? workspaceForKey(input.idempotencyKey) : genWorkspace();
|
|
236764
|
-
|
|
236765
|
-
|
|
236766
|
-
|
|
236767
|
-
}
|
|
237064
|
+
const snapshot = input.idempotencyKey ? await kernel.getStore().transaction((tx) => tx.loadWorkorder(workspace)) : null;
|
|
237065
|
+
const existing = existingWorkorder(snapshot, workspace, input.actor);
|
|
237066
|
+
if (existing && (await kernel.isWorkorderCreationComplete(workspace) || legacyCreationComplete(snapshot, existing.rootArtifactId))) return existing;
|
|
236768
237067
|
if (artifactState && input.projectId) {
|
|
236769
237068
|
await bindWorkorderProject({
|
|
236770
237069
|
workOrderId: workspace,
|
|
@@ -236773,6 +237072,13 @@ function makeSeededWorkorderCreator(deps) {
|
|
|
236773
237072
|
...deps.onWarn ? { onWarn: deps.onWarn } : {}
|
|
236774
237073
|
});
|
|
236775
237074
|
}
|
|
237075
|
+
const finishCreation = async (result) => {
|
|
237076
|
+
await seedWorkorderBrief(kernel, blobs, workspace, result.rootArtifactId, input.actor, input.brief);
|
|
237077
|
+
if (input.dispatch === false) await artifactState?.setWorkspaceDispatchHold(workspace, true);
|
|
237078
|
+
await kernel.completeWorkorderCreation(workspace, input.actor, input.dispatch !== false, WORKORDER_HOLD_AT_CREATE_REASON);
|
|
237079
|
+
return result;
|
|
237080
|
+
};
|
|
237081
|
+
if (existing) return await finishCreation(existing);
|
|
236776
237082
|
const planned = await buildDynamicWorkorderPlan({
|
|
236777
237083
|
// requestedType 在 agentPlan 路仅用于兜底;给第一个节点类型即可,图仍以 plan 为准。
|
|
236778
237084
|
requestedType: input.plan.nodes[0]?.type ?? "prd",
|
|
@@ -236829,44 +237135,41 @@ function makeSeededWorkorderCreator(deps) {
|
|
|
236829
237135
|
}
|
|
236830
237136
|
};
|
|
236831
237137
|
}
|
|
236832
|
-
await kernel.applyIntervention(planned.plan, preview2.baseSeqs, input.humanActorId ?? input.actor);
|
|
236833
|
-
|
|
236834
|
-
|
|
236835
|
-
|
|
236836
|
-
|
|
236837
|
-
|
|
236838
|
-
await
|
|
236839
|
-
}
|
|
236840
|
-
|
|
236841
|
-
await artifactState.setWorkspaceDispatchHold(workspace, true);
|
|
236842
|
-
await kernel.pauseWorkorder?.(workspace, input.actor, WORKORDER_HOLD_AT_CREATE_REASON);
|
|
237138
|
+
await kernel.applyIntervention(planned.plan, preview2.baseSeqs, input.humanActorId ?? input.actor, { deferActivation: true });
|
|
237139
|
+
return await finishCreation({ workspace, rootArtifactId: planned.rootArtifactId, spawned: planned.spawned });
|
|
237140
|
+
};
|
|
237141
|
+
return async (input) => {
|
|
237142
|
+
const release = await locks.acquire(`${input.companyId ?? ""}\0${input.idempotencyKey ?? (0, import_node_crypto61.randomUUID)()}`);
|
|
237143
|
+
try {
|
|
237144
|
+
return await create(input);
|
|
237145
|
+
} finally {
|
|
237146
|
+
release();
|
|
236843
237147
|
}
|
|
236844
|
-
return { workspace, rootArtifactId: briefId, spawned: planned.spawned };
|
|
236845
237148
|
};
|
|
236846
237149
|
}
|
|
236847
237150
|
function workspaceForKey(key2) {
|
|
236848
|
-
return `ws:wo-${(0,
|
|
237151
|
+
return `ws:wo-${(0, import_node_crypto61.createHash)("sha256").update(key2).digest("hex").slice(0, 8)}`;
|
|
236849
237152
|
}
|
|
236850
|
-
function existingWorkorder(
|
|
236851
|
-
|
|
236852
|
-
|
|
236853
|
-
|
|
237153
|
+
function existingWorkorder(snapshot, workspace, actor) {
|
|
237154
|
+
if (!snapshot?.nodes.length) return null;
|
|
237155
|
+
const seed = snapshot.nodes.find((node2) => node2.type === "brief") ?? snapshot.nodes.find((node2) => !snapshot.edges.some((edge) => edge.toNodeId === node2.id));
|
|
237156
|
+
if (!seed) throw new Error(`\u65E2\u6709\u5DE5\u5355\u7F3A\u5C11\u603B\u7EB2\u8282\u70B9\uFF1A${workspace}`);
|
|
236854
237157
|
return {
|
|
236855
237158
|
workspace,
|
|
236856
237159
|
rootArtifactId: seed.id,
|
|
236857
|
-
|
|
236858
|
-
spawned: arts.map((a) => ({ id: a.id, type: a.type, owner: a.owner }))
|
|
237160
|
+
spawned: snapshot.nodes.map((node2) => ({ id: node2.id, type: node2.type, owner: node2.assigneeActorId ?? actor }))
|
|
236859
237161
|
};
|
|
236860
237162
|
}
|
|
236861
|
-
var
|
|
237163
|
+
var import_node_crypto61;
|
|
236862
237164
|
var init_create_seeded_workorder = __esm({
|
|
236863
237165
|
"../server/src/domains/collab/create-seeded-workorder.ts"() {
|
|
236864
237166
|
"use strict";
|
|
236865
|
-
|
|
237167
|
+
import_node_crypto61 = require("node:crypto");
|
|
236866
237168
|
init_uncategorized_project();
|
|
236867
237169
|
init_src();
|
|
236868
237170
|
init_planner();
|
|
236869
|
-
|
|
237171
|
+
init_keyed_mutex();
|
|
237172
|
+
init_initialize_workorder();
|
|
236870
237173
|
}
|
|
236871
237174
|
});
|
|
236872
237175
|
|
|
@@ -238290,12 +238593,12 @@ function stateFromAttempt(attempt, handoff, checkpoint, now, stalledAfterMs, ope
|
|
|
238290
238593
|
if (attempt.status === "no-output") return handoff?.unresolvedIssues.length ? "blocked" : "no_change";
|
|
238291
238594
|
return "failed";
|
|
238292
238595
|
}
|
|
238293
|
-
var
|
|
238596
|
+
var import_node_crypto62, BLOCKING_STATES, HANDOFF_OUTCOMES2, RESUME_EXTERNAL_EFFECT_LIMIT, RESUME_SNAPSHOT_PREFIX, RESUME_SNAPSHOT_SUFFIX, ExecutionContinuityService;
|
|
238294
238597
|
var init_service8 = __esm({
|
|
238295
238598
|
"../server/src/domains/execution-continuity/service.ts"() {
|
|
238296
238599
|
"use strict";
|
|
238297
238600
|
init_src();
|
|
238298
|
-
|
|
238601
|
+
import_node_crypto62 = require("node:crypto");
|
|
238299
238602
|
init_src7();
|
|
238300
238603
|
BLOCKING_STATES = /* @__PURE__ */ new Set(["stalled", "failed", "blocked"]);
|
|
238301
238604
|
HANDOFF_OUTCOMES2 = /* @__PURE__ */ new Set(["succeeded", "no-output", "failed", "cancelled", "timeout", "orphaned"]);
|
|
@@ -238526,7 +238829,7 @@ var init_service8 = __esm({
|
|
|
238526
238829
|
if (typeof expectedHash !== "string" || !this.readBundleFile) return null;
|
|
238527
238830
|
const injectedResume = this.readBundleFile(attempt.id, "execution/RESUME.md");
|
|
238528
238831
|
if (!injectedResume) return null;
|
|
238529
|
-
const actualHash = (0,
|
|
238832
|
+
const actualHash = (0, import_node_crypto62.createHash)("sha256").update(injectedResume).digest("hex");
|
|
238530
238833
|
if (actualHash !== expectedHash) return null;
|
|
238531
238834
|
const recoverySnapshot = parseResumePackSnapshot(injectedResume);
|
|
238532
238835
|
if (!recoverySnapshot || recoverySnapshot.scenario !== "redispatch" || !recoverySnapshot.previousAttempt || recoverySnapshot.node.nodeId !== attempt.nodeId || recoverySnapshot.jobKey !== attempt.jobKey || recoverySnapshot.part !== attempt.part) return null;
|
|
@@ -239394,6 +239697,25 @@ var init_escalation_opening = __esm({
|
|
|
239394
239697
|
}
|
|
239395
239698
|
});
|
|
239396
239699
|
|
|
239700
|
+
// ../server/src/domains/delegations/reply-anchors.ts
|
|
239701
|
+
function delegationReplyAnchors(record8) {
|
|
239702
|
+
const bySequence = /* @__PURE__ */ new Map();
|
|
239703
|
+
for (const summary of record8.roundSummaries) {
|
|
239704
|
+
const sequence = summary.settledSeq;
|
|
239705
|
+
if (typeof sequence !== "number" || !Number.isSafeInteger(sequence) || sequence < 1 || !Number.isSafeInteger(summary.round) || summary.round < 1) continue;
|
|
239706
|
+
const ids2 = bySequence.get(sequence) ?? /* @__PURE__ */ new Set();
|
|
239707
|
+
ids2.add(childRoundMessageIds(record8.childSessionId, summary.round).placeholderId);
|
|
239708
|
+
bySequence.set(sequence, ids2);
|
|
239709
|
+
}
|
|
239710
|
+
return [...bySequence].flatMap(([settledSeq, ids2]) => ids2.size === 1 ? [{ settledSeq, childMessageId: [...ids2][0] }] : []);
|
|
239711
|
+
}
|
|
239712
|
+
var init_reply_anchors = __esm({
|
|
239713
|
+
"../server/src/domains/delegations/reply-anchors.ts"() {
|
|
239714
|
+
"use strict";
|
|
239715
|
+
init_service3();
|
|
239716
|
+
}
|
|
239717
|
+
});
|
|
239718
|
+
|
|
239397
239719
|
// ../server/src/domains/chat-sessions/project-bundle.ts
|
|
239398
239720
|
async function buildChatProjectBundle(projectId2, projects, readBlob) {
|
|
239399
239721
|
const project = await projects.getProject(projectId2);
|
|
@@ -239493,7 +239815,11 @@ function mapChatItemToSnapshotEntry(row) {
|
|
|
239493
239815
|
ord: row.ord,
|
|
239494
239816
|
messageId: row.messageId,
|
|
239495
239817
|
updatedAt: row.updatedAt,
|
|
239496
|
-
payload:
|
|
239818
|
+
payload: {
|
|
239819
|
+
...row.payload && typeof row.payload === "object" && !Array.isArray(row.payload) ? row.payload : {},
|
|
239820
|
+
createdAt: row.createdAt,
|
|
239821
|
+
completedAt: row.completedAt
|
|
239822
|
+
}
|
|
239497
239823
|
};
|
|
239498
239824
|
}
|
|
239499
239825
|
function throwWorkdirError(code2) {
|
|
@@ -239630,7 +239956,7 @@ function createChatSessionsDomain(opts) {
|
|
|
239630
239956
|
if (!text6.trim()) throw new ApiError(400, "BAD_REQUEST", "text required");
|
|
239631
239957
|
const now = Date.now();
|
|
239632
239958
|
sweepDrafts(now);
|
|
239633
|
-
const id = `cd_${(0,
|
|
239959
|
+
const id = `cd_${(0, import_node_crypto63.randomUUID)()}`;
|
|
239634
239960
|
drafts.set(id, { text: text6, actor: req.auth.actor, expiresAt: now + DRAFT_TTL_MS });
|
|
239635
239961
|
return { status: 201, body: { id, expiresInMs: DRAFT_TTL_MS } };
|
|
239636
239962
|
});
|
|
@@ -239662,6 +239988,13 @@ function createChatSessionsDomain(opts) {
|
|
|
239662
239988
|
...runningParentIds.has(s2.id) ? { hasRunningDelegation: true } : {}
|
|
239663
239989
|
}));
|
|
239664
239990
|
}
|
|
239991
|
+
async function markSessionUnread(sessions, actor, companyId) {
|
|
239992
|
+
if (!opts.resolveReadMarkers || !isHumanActorId(actor) || sessions.length === 0) return sessions;
|
|
239993
|
+
const markers = await opts.resolveReadMarkers(companyId).then((store2) => store2.listMarkers(actor)).catch(() => null);
|
|
239994
|
+
if (!markers) return sessions;
|
|
239995
|
+
const byScope = new Map(markers.map((m2) => [m2.scope, m2]));
|
|
239996
|
+
return sessions.map((s2) => ({ ...s2, unread: isChatSessionUnread(s2, byScope.get(chatScope(s2.id))) }));
|
|
239997
|
+
}
|
|
239665
239998
|
router.get("/api/chat-sessions", async (req) => {
|
|
239666
239999
|
const store2 = await storeFor(req);
|
|
239667
240000
|
if (req.query?.get("analysis") === "all") {
|
|
@@ -239676,7 +240009,8 @@ function createChatSessionsDomain(opts) {
|
|
|
239676
240009
|
}
|
|
239677
240010
|
const analyzedRunId = req.query?.get("analyzedRunId") ?? void 0;
|
|
239678
240011
|
const sessions = analyzedRunId ? await store2.listSessionsByAnalyzedRun(analyzedRunId) : await store2.listSessions(req.auth.actor);
|
|
239679
|
-
const
|
|
240012
|
+
const marked = await markSessionDelegations(sessions, req.auth.companyId ?? void 0);
|
|
240013
|
+
const items = analyzedRunId ? marked : await markSessionUnread(marked, req.auth.actor, req.auth.companyId ?? void 0);
|
|
239680
240014
|
return { status: 200, body: { items } };
|
|
239681
240015
|
});
|
|
239682
240016
|
router.post("/api/chat-sessions", async (req) => {
|
|
@@ -239690,7 +240024,7 @@ function createChatSessionsDomain(opts) {
|
|
|
239690
240024
|
const runtimeId = await currentRuntimeId(body2.aiActorId) ?? "unknown";
|
|
239691
240025
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
239692
240026
|
const session = {
|
|
239693
|
-
id: (0,
|
|
240027
|
+
id: (0, import_node_crypto63.randomUUID)(),
|
|
239694
240028
|
humanActorId: req.auth.actor,
|
|
239695
240029
|
// 注:这里**刻意不写 companyId**。新会话要不要带公司归属,按 ws:wo-6d588f8e 的 ADR
|
|
239696
240030
|
// (每公司 schema、最终移除表内 company 列)统一定,不在本节点自行发明。
|
|
@@ -239796,7 +240130,7 @@ function createChatSessionsDomain(opts) {
|
|
|
239796
240130
|
if (body2.role !== "user" && body2.role !== "assistant") throw new ApiError(400, "BAD_REQUEST", "role must be user or assistant");
|
|
239797
240131
|
const role = body2.role;
|
|
239798
240132
|
const msg = await store2.appendMessage({
|
|
239799
|
-
id: (0,
|
|
240133
|
+
id: (0, import_node_crypto63.randomUUID)(),
|
|
239800
240134
|
sessionId: req.params.id,
|
|
239801
240135
|
role,
|
|
239802
240136
|
content: role === "user" ? stripInjectedChatContext(body2.content) : body2.content,
|
|
@@ -239837,7 +240171,7 @@ function createChatSessionsDomain(opts) {
|
|
|
239837
240171
|
const known = key2 ? cur.find((x2) => x2.clientKey === key2) : void 0;
|
|
239838
240172
|
if (!known && cur.length >= QUEUE_MAX) throw new ApiError(409, "QUEUE_FULL", `\u961F\u5217\u5DF2\u6EE1\uFF08\u4E0A\u9650 ${QUEUE_MAX} \u6761\uFF09`);
|
|
239839
240173
|
const item = await store.enqueuePendingMessage({
|
|
239840
|
-
id: (0,
|
|
240174
|
+
id: (0, import_node_crypto63.randomUUID)(),
|
|
239841
240175
|
chatSessionId: sid,
|
|
239842
240176
|
text: text6,
|
|
239843
240177
|
...attachments.length ? { attachments } : {},
|
|
@@ -240015,6 +240349,7 @@ function createChatSessionsDomain(opts) {
|
|
|
240015
240349
|
/* 与协调者读口**同一个函数**——两侧 artifacts 有「逐字同源」的既有断言。它顺带给每份产物
|
|
240016
240350
|
填上 `childMessageId`(子会话面板把产出卡挂到产出它的那一轮下面要用)。 */
|
|
240017
240351
|
artifacts: delegationArtifactsView(record8),
|
|
240352
|
+
replyAnchors: delegationReplyAnchors(record8),
|
|
240018
240353
|
createdAt: record8.createdAt,
|
|
240019
240354
|
...record8.settledAt ? { settledAt: record8.settledAt } : {}
|
|
240020
240355
|
});
|
|
@@ -240385,12 +240720,12 @@ function createChatSessionsDomain(opts) {
|
|
|
240385
240720
|
});
|
|
240386
240721
|
};
|
|
240387
240722
|
}
|
|
240388
|
-
var
|
|
240723
|
+
var import_node_crypto63, DEFAULT_SNAPSHOT_ITEMS, MAX_SNAPSHOT_ITEMS;
|
|
240389
240724
|
var init_chat_sessions2 = __esm({
|
|
240390
240725
|
"../server/src/domains/chat-sessions/index.ts"() {
|
|
240391
240726
|
"use strict";
|
|
240392
240727
|
init_file_limits2();
|
|
240393
|
-
|
|
240728
|
+
import_node_crypto63 = require("node:crypto");
|
|
240394
240729
|
init_src();
|
|
240395
240730
|
init_chat_session();
|
|
240396
240731
|
init_persistent_files();
|
|
@@ -240402,6 +240737,7 @@ var init_chat_sessions2 = __esm({
|
|
|
240402
240737
|
init_workorders();
|
|
240403
240738
|
init_chat_parts();
|
|
240404
240739
|
init_service3();
|
|
240740
|
+
init_reply_anchors();
|
|
240405
240741
|
init_injected_context();
|
|
240406
240742
|
init_deletion();
|
|
240407
240743
|
init_chat_turn_gate();
|
|
@@ -241780,7 +242116,7 @@ function busyError(chatSessionId, blockedBy) {
|
|
|
241780
242116
|
return `\u76EE\u6807\u4F1A\u8BDD ${chatSessionId} \u6B63\u6709\u4E00\u8F6E\u5728\u8DD1${blockedBy ? `\uFF08${blockedBy}\uFF09` : ""}\u2014\u2014\u672C\u6B21\u89E6\u53D1\u5DF2\u4E22\u5F03\uFF0C\u4E0D\u6392\u961F\u3001\u4E0D\u8865\u8DD1`;
|
|
241781
242117
|
}
|
|
241782
242118
|
function genWebhookToken() {
|
|
241783
|
-
return `owt_${(0,
|
|
242119
|
+
return `owt_${(0, import_node_crypto64.randomBytes)(32).toString("base64url")}`;
|
|
241784
242120
|
}
|
|
241785
242121
|
function validateTitleTemplate(tpl) {
|
|
241786
242122
|
const residue = tpl.replace(DATE_TOKEN, "");
|
|
@@ -241836,11 +242172,11 @@ function appendSourceNote(brief, automation, source, atIso) {
|
|
|
241836
242172
|
---
|
|
241837
242173
|
\u672C\u5DE5\u5355\u7531\u81EA\u52A8\u5316\u300C${automation.name}\u300D\u4E8E ${atIso} \u89E6\u53D1\uFF08\u6765\u6E90\uFF1A${source}\uFF09\u3002\u5F00\u5DE5\u540E\u8BF7\u628A\u5DE5\u5355\u6807\u9898\u6539\u6210\u51C6\u786E\u53CD\u6620\u5B9E\u9645\u5DE5\u4F5C\u7684\u63CF\u8FF0\u3002`;
|
|
241838
242174
|
}
|
|
241839
|
-
var
|
|
242175
|
+
var import_node_crypto64, DATE_TOKEN, AutomationsService, EVENT_RETRY_BASE_MS, EVENT_RETRY_MAX_MS, EVENT_RETRY_MAX_ATTEMPTS, eventAttempts, eventLastAttemptAt, eventLastError, CHAT_REPLY_MAX;
|
|
241840
242176
|
var init_service9 = __esm({
|
|
241841
242177
|
"../server/src/domains/automations/service.ts"() {
|
|
241842
242178
|
"use strict";
|
|
241843
|
-
|
|
242179
|
+
import_node_crypto64 = require("node:crypto");
|
|
241844
242180
|
init_src();
|
|
241845
242181
|
init_registry3();
|
|
241846
242182
|
init_attribution();
|
|
@@ -242654,11 +242990,11 @@ function verifySignature(rawBody, headers, secret) {
|
|
|
242654
242990
|
if (!secret) return "not_required";
|
|
242655
242991
|
const given = header1(headers, "x-hub-signature-256");
|
|
242656
242992
|
if (!given) return "missing";
|
|
242657
|
-
const expected = `sha256=${(0,
|
|
242993
|
+
const expected = `sha256=${(0, import_node_crypto65.createHmac)("sha256", secret).update(rawBody).digest("hex")}`;
|
|
242658
242994
|
const a = Buffer.from(given);
|
|
242659
242995
|
const b2 = Buffer.from(expected);
|
|
242660
242996
|
if (a.length !== b2.length) return "invalid";
|
|
242661
|
-
return (0,
|
|
242997
|
+
return (0, import_node_crypto65.timingSafeEqual)(a, b2) ? "valid" : "invalid";
|
|
242662
242998
|
}
|
|
242663
242999
|
function eventAllowed(filters, envelope) {
|
|
242664
243000
|
if (!filters || filters.length === 0) return true;
|
|
@@ -242688,11 +243024,11 @@ function splitEvent(envelope) {
|
|
|
242688
243024
|
}
|
|
242689
243025
|
return { eventName, actionCandidates: candidates };
|
|
242690
243026
|
}
|
|
242691
|
-
var
|
|
243027
|
+
var import_node_crypto65, MAX_BODY_BYTES, AutomationWebhookService, header1, PROVIDER_PREFIXES;
|
|
242692
243028
|
var init_webhook = __esm({
|
|
242693
243029
|
"../server/src/domains/automations/webhook.ts"() {
|
|
242694
243030
|
"use strict";
|
|
242695
|
-
|
|
243031
|
+
import_node_crypto65 = require("node:crypto");
|
|
242696
243032
|
MAX_BODY_BYTES = 256 * 1024;
|
|
242697
243033
|
AutomationWebhookService = class {
|
|
242698
243034
|
store;
|
|
@@ -243840,7 +244176,7 @@ function playbooksDomain(opts) {
|
|
|
243840
244176
|
opts.overrides.set(companyOf(req), ref2, nodeKey, nextOverride);
|
|
243841
244177
|
try {
|
|
243842
244178
|
await opts.audit?.({
|
|
243843
|
-
id: `reg_${(0,
|
|
244179
|
+
id: `reg_${(0, import_node_crypto66.randomUUID)()}`,
|
|
243844
244180
|
actor: req.auth.actor,
|
|
243845
244181
|
kind: "registry_change",
|
|
243846
244182
|
target: `playbook:${ref2}#${nodeKey}`,
|
|
@@ -243857,11 +244193,11 @@ function playbooksDomain(opts) {
|
|
|
243857
244193
|
});
|
|
243858
244194
|
};
|
|
243859
244195
|
}
|
|
243860
|
-
var
|
|
244196
|
+
var import_node_crypto66;
|
|
243861
244197
|
var init_routes12 = __esm({
|
|
243862
244198
|
"../server/src/domains/playbooks/routes.ts"() {
|
|
243863
244199
|
"use strict";
|
|
243864
|
-
|
|
244200
|
+
import_node_crypto66 = require("node:crypto");
|
|
243865
244201
|
init_router();
|
|
243866
244202
|
init_registry3();
|
|
243867
244203
|
init_planner();
|
|
@@ -243990,17 +244326,17 @@ function completionFingerprint(workspace, members) {
|
|
|
243990
244326
|
workspace,
|
|
243991
244327
|
members: [...members].sort((a, b2) => a.artifactId < b2.artifactId ? -1 : a.artifactId > b2.artifactId ? 1 : 0).map((m2) => ({ artifactId: m2.artifactId, currentRevisionId: m2.currentRevisionId ?? null }))
|
|
243992
244328
|
});
|
|
243993
|
-
return (0,
|
|
244329
|
+
return (0, import_node_crypto67.createHash)("sha256").update(canonical2).digest("hex");
|
|
243994
244330
|
}
|
|
243995
244331
|
function eventConsumptionKey(args) {
|
|
243996
244332
|
const raw = `project-event:${EVENT_KEY_VERSION}:${args.triggerId}:${args.event}:${args.workspace}:${args.fingerprint}`;
|
|
243997
|
-
return raw.length <= 200 ? raw : `project-event:${EVENT_KEY_VERSION}:sha256:${(0,
|
|
244333
|
+
return raw.length <= 200 ? raw : `project-event:${EVENT_KEY_VERSION}:sha256:${(0, import_node_crypto67.createHash)("sha256").update(raw).digest("hex")}`;
|
|
243998
244334
|
}
|
|
243999
|
-
var
|
|
244335
|
+
var import_node_crypto67, EVENT_KEY_VERSION, EMPTY_METRICS, AUTOMATION_EVENT_HANDLERS, ProjectEventPoller;
|
|
244000
244336
|
var init_project_event_poller = __esm({
|
|
244001
244337
|
"../server/src/automations/project-event-poller.ts"() {
|
|
244002
244338
|
"use strict";
|
|
244003
|
-
|
|
244339
|
+
import_node_crypto67 = require("node:crypto");
|
|
244004
244340
|
EVENT_KEY_VERSION = "v1";
|
|
244005
244341
|
EMPTY_METRICS = () => ({
|
|
244006
244342
|
scanDurationMs: 0,
|
|
@@ -244211,7 +244547,7 @@ function remoteAppendInput(hub, nodeId, dispatchId, entry, input, timeoutMs) {
|
|
|
244211
244547
|
if (input.requireConsumptionReceipt && !hub.supportsInputConsumptionReceipts?.(dispatchId)) {
|
|
244212
244548
|
return Promise.resolve({ accepted: false, reason: "consumption-unsupported" });
|
|
244213
244549
|
}
|
|
244214
|
-
const requestId = (0,
|
|
244550
|
+
const requestId = (0, import_node_crypto68.randomUUID)();
|
|
244215
244551
|
const sent = routeToSession(hub, nodeId, dispatchId, { type: "append_input", dispatchId, input, requestId });
|
|
244216
244552
|
if (!sent) return Promise.resolve({ accepted: false, reason: "session-closing", ...unknownIfInterrupting });
|
|
244217
244553
|
return new Promise((resolve10) => {
|
|
@@ -244224,11 +244560,11 @@ function remoteAppendInput(hub, nodeId, dispatchId, entry, input, timeoutMs) {
|
|
|
244224
244560
|
entry.appendWaiters.push({ requestId, requireConsumptionReceipt: input.requireConsumptionReceipt, resolve: resolve10, timer });
|
|
244225
244561
|
});
|
|
244226
244562
|
}
|
|
244227
|
-
var
|
|
244563
|
+
var import_node_crypto68, STASH_TTL_MS, STASH_MAX_FRAMES_PER_ID, STASH_MAX_IDS, DaemonHubAdapter, BindingRouterAdapter, WorkdirBridge;
|
|
244228
244564
|
var init_daemon_adapter = __esm({
|
|
244229
244565
|
"../server/src/daemon-adapter.ts"() {
|
|
244230
244566
|
"use strict";
|
|
244231
|
-
|
|
244567
|
+
import_node_crypto68 = require("node:crypto");
|
|
244232
244568
|
init_src();
|
|
244233
244569
|
STASH_TTL_MS = 5 * 6e4;
|
|
244234
244570
|
STASH_MAX_FRAMES_PER_ID = 500;
|
|
@@ -244578,7 +244914,7 @@ var init_daemon_adapter = __esm({
|
|
|
244578
244914
|
async spawn(job) {
|
|
244579
244915
|
const nodeId = job.binding?.nodeId;
|
|
244580
244916
|
if (!nodeId) throw new Error("DaemonHubAdapter \u9700\u8981 job.binding.nodeId\uFF08\u8DEF\u7531\u9519\u8BEF\uFF09");
|
|
244581
|
-
const dispatchId = job.dispatchId ?? `dispatch:${(0,
|
|
244917
|
+
const dispatchId = job.dispatchId ?? `dispatch:${(0, import_node_crypto68.randomUUID)()}`;
|
|
244582
244918
|
if (job.dispatchId && this.pending.has(dispatchId)) {
|
|
244583
244919
|
return this.recover(dispatchId, nodeId, job.binding?.runtimeKind, job.actor);
|
|
244584
244920
|
}
|
|
@@ -244821,7 +245157,7 @@ var init_daemon_adapter = __esm({
|
|
|
244821
245157
|
return daemon?.meta.supportsWorkdirWalk === true;
|
|
244822
245158
|
}
|
|
244823
245159
|
request(nodeId, buildFrame) {
|
|
244824
|
-
const requestId = (0,
|
|
245160
|
+
const requestId = (0, import_node_crypto68.randomUUID)();
|
|
244825
245161
|
const sent = this.hub.dispatch(nodeId, buildFrame(requestId));
|
|
244826
245162
|
if (!sent) return Promise.resolve({ ok: false, code: "NODE_OFFLINE" });
|
|
244827
245163
|
return new Promise((resolve10) => {
|
|
@@ -244929,14 +245265,14 @@ function classifyPage(page, lastPushedHash, serviceAccount) {
|
|
|
244929
245265
|
if (sha(body2) === lastPushedHash) return { kind: "echo" };
|
|
244930
245266
|
return { kind: "human-edit", content: body2, updatedBy: page.updatedBy };
|
|
244931
245267
|
}
|
|
244932
|
-
var
|
|
245268
|
+
var import_node_crypto69, sha, enc2, dec, MirrorEngine, MapMirrorIdentities;
|
|
244933
245269
|
var init_engine = __esm({
|
|
244934
245270
|
"../server/src/mirror/engine.ts"() {
|
|
244935
245271
|
"use strict";
|
|
244936
|
-
|
|
245272
|
+
import_node_crypto69 = require("node:crypto");
|
|
244937
245273
|
init_src();
|
|
244938
|
-
sha = (s2) => (0,
|
|
244939
|
-
|
|
245274
|
+
sha = (s2) => (0, import_node_crypto69.createHash)("sha256").update(s2, "utf8").digest("hex");
|
|
245275
|
+
enc2 = (s2) => new TextEncoder().encode(s2);
|
|
244940
245276
|
dec = (b2) => new TextDecoder().decode(b2);
|
|
244941
245277
|
MirrorEngine = class {
|
|
244942
245278
|
constructor(deps) {
|
|
@@ -245010,7 +245346,7 @@ var init_engine = __esm({
|
|
|
245010
245346
|
continue;
|
|
245011
245347
|
}
|
|
245012
245348
|
try {
|
|
245013
|
-
const contentRef = await this.deps.blobs.put(
|
|
245349
|
+
const contentRef = await this.deps.blobs.put(enc2(cls.content));
|
|
245014
245350
|
const rev = await this.deps.kernel.proposeRevision({
|
|
245015
245351
|
artifactId,
|
|
245016
245352
|
actor,
|
|
@@ -245196,11 +245532,11 @@ function humanExitCause(exit3) {
|
|
|
245196
245532
|
const base = (exit3.reason ? label[exit3.reason] : void 0) ?? `\u4F1A\u8BDD\u5F02\u5E38\u7ED3\u675F\uFF08${exit3.reason ?? "\u65E0\u9000\u51FA\u4FE1\u606F"}\uFF09`;
|
|
245197
245533
|
return exit3.errorMessage ? `${base}\uFF1A${exit3.errorMessage.slice(0, 200)}` : base;
|
|
245198
245534
|
}
|
|
245199
|
-
var
|
|
245535
|
+
var import_node_crypto70, AUTONOMOUS_ETHOS, CONVERSATIONAL_ETHOS, SHARED_GRAPH_BODY, AUTONOMOUS_RECOVERY_TOOLS, HIGH_RISK_COMMANDS, REJECTED_PROPOSALS_IN_TASK, COORDINATOR_SYSTEM_PROMPT, CONVERSATIONAL_RECOVERY_TOOLS, CONVERSATIONAL_ESCALATION_TOOLS, CONVERSATIONAL_MANAGER_BODY, MACHINE_EXIT_CODES, CoordinatorWorker;
|
|
245200
245536
|
var init_worker = __esm({
|
|
245201
245537
|
"../server/src/coordinator/worker.ts"() {
|
|
245202
245538
|
"use strict";
|
|
245203
|
-
|
|
245539
|
+
import_node_crypto70 = require("node:crypto");
|
|
245204
245540
|
init_src7();
|
|
245205
245541
|
init_identity();
|
|
245206
245542
|
AUTONOMOUS_ETHOS = `\u4F60\u662F\u8FD9\u4E2A\u5DE5\u5355\u7684**\u7BA1\u7406\u8005**\u2014\u2014\u804C\u8D23\u662F\u8BA9\u5B83\u987A\u7545\u8DD1\u5B8C\u3002\u7CFB\u7EDF\u5728\u67D0\u4E2A\u8282\u70B9\u5361\u4F4F\u3001\u673A\u68B0\u5206\u8BCA\u786E\u8BA4"\u9700\u8981\u4F60"\u65F6\u5524\u8D77\u4F60\uFF08\u65E0\u4EBA\u5728\u573A\uFF0C\u4F60\u8FD9\u4E00\u8F6E\u628A\u80FD\u505A\u7684\u505A\u6389\uFF09\u3002\u4F60\u7684\u624B\u6BB5\u5F88\u5BBD\uFF1A
|
|
@@ -245470,7 +245806,7 @@ ${HIGH_RISK_COMMANDS}`;
|
|
|
245470
245806
|
return this.deps.kernel.model.lastSeq.get(artifactId) ?? 0;
|
|
245471
245807
|
}
|
|
245472
245808
|
evaluationKey(kind, artifactId, evidence) {
|
|
245473
|
-
const fingerprint2 = (0,
|
|
245809
|
+
const fingerprint2 = (0, import_node_crypto70.createHash)("sha256").update(JSON.stringify(evidence)).digest("hex");
|
|
245474
245810
|
return `${kind}:${artifactId}:${fingerprint2}`;
|
|
245475
245811
|
}
|
|
245476
245812
|
artifactEvidence(id) {
|
|
@@ -245859,8 +246195,8 @@ ${ctx.nodeFault}
|
|
|
245859
246195
|
const taskWithRejections = rejectedSection ? `${task}
|
|
245860
246196
|
|
|
245861
246197
|
${rejectedSection}` : task;
|
|
245862
|
-
const runtimeSessionId = opts?.resumeSessionId ?? (0,
|
|
245863
|
-
const coordinatorRunId = `coordinate:${(0,
|
|
246198
|
+
const runtimeSessionId = opts?.resumeSessionId ?? (0, import_node_crypto70.randomUUID)();
|
|
246199
|
+
const coordinatorRunId = `coordinate:${(0, import_node_crypto70.randomUUID)()}`;
|
|
245864
246200
|
const taskWithContext = coordinatorContext ? [
|
|
245865
246201
|
taskWithRejections,
|
|
245866
246202
|
``,
|
|
@@ -245904,7 +246240,7 @@ ${rejectedSection}` : task;
|
|
|
245904
246240
|
const startedAtMs = Date.now();
|
|
245905
246241
|
let trajectoryStarted = false;
|
|
245906
246242
|
if (this.deps.trajectory) {
|
|
245907
|
-
const bundleManifest = Object.fromEntries(Object.entries(job.bundle.files).map(([name, content3]) => [name, (0,
|
|
246243
|
+
const bundleManifest = Object.fromEntries(Object.entries(job.bundle.files).map(([name, content3]) => [name, (0, import_node_crypto70.createHash)("sha256").update(content3).digest("hex")]));
|
|
245908
246244
|
const session = {
|
|
245909
246245
|
runId: coordinatorRunId,
|
|
245910
246246
|
runtimeSessionId,
|
|
@@ -246110,11 +246446,11 @@ var init_pg_ident = __esm({
|
|
|
246110
246446
|
});
|
|
246111
246447
|
|
|
246112
246448
|
// ../storage/src/postgres.ts
|
|
246113
|
-
var
|
|
246449
|
+
var import_node_crypto71, ident4, isUniqueViolation, PostgresOplogStore, PostgresBlobStore;
|
|
246114
246450
|
var init_postgres = __esm({
|
|
246115
246451
|
"../storage/src/postgres.ts"() {
|
|
246116
246452
|
"use strict";
|
|
246117
|
-
|
|
246453
|
+
import_node_crypto71 = require("node:crypto");
|
|
246118
246454
|
init_pg_ident();
|
|
246119
246455
|
init_esm();
|
|
246120
246456
|
init_src();
|
|
@@ -246294,7 +246630,7 @@ var init_postgres = __esm({
|
|
|
246294
246630
|
return new _PostgresBlobStore(pool, schema);
|
|
246295
246631
|
}
|
|
246296
246632
|
async put(bytes2) {
|
|
246297
|
-
const hash3 = (0,
|
|
246633
|
+
const hash3 = (0, import_node_crypto71.createHash)("sha256").update(bytes2).digest("hex");
|
|
246298
246634
|
await this.pool.query(
|
|
246299
246635
|
`INSERT INTO ${this.t} (hash, bytes, size, content_type) VALUES ($1, $2, $3, $4) ON CONFLICT (hash) DO NOTHING`,
|
|
246300
246636
|
[hash3, Buffer.from(bytes2), bytes2.byteLength, sniffContentType(bytes2) ?? null]
|
|
@@ -253965,14 +254301,22 @@ var init_postgres_chat_items = __esm({
|
|
|
253965
254301
|
* ——此刻起的 chunk 已经算下一段,但那条行还不存在。先写 `message_id = NULL`、行落库后回填,
|
|
253966
254302
|
* 比让写入等一次 DB 往返更安全(等 = 丢帧或阻塞流)。
|
|
253967
254303
|
*
|
|
253968
|
-
* `message_id IS NULL`
|
|
254304
|
+
* `message_id IS NULL` 只能把**已经绑好的**上一段隔开,隔不开**后面**的段:新行落库慢于下一次插话时,
|
|
254305
|
+
* 后一段的 item 同样是 NULL。所以切段回填给 `itemIds`,只更新那一段自己的 item(2026-09-17)。
|
|
253969
254306
|
* 回填**不动** `version`/`turn_version`——归属关系不是 item 内容的一次修订。
|
|
253970
254307
|
*/
|
|
253971
|
-
async bindMessage(sessionId, turnId, messageId) {
|
|
253972
|
-
|
|
254308
|
+
async bindMessage(sessionId, turnId, messageId, itemIds) {
|
|
254309
|
+
if (itemIds && itemIds.length === 0) return 0;
|
|
254310
|
+
const r = itemIds ? await this.pool.query(
|
|
253973
254311
|
`UPDATE ${this.s}.chat_items
|
|
253974
|
-
|
|
253975
|
-
|
|
254312
|
+
SET message_id = $3
|
|
254313
|
+
WHERE session_id = $1 AND turn_id = $2 AND message_id IS NULL AND role = 'assistant'
|
|
254314
|
+
AND id = ANY($4::text[])`,
|
|
254315
|
+
[sessionId, turnId, messageId, [...itemIds]]
|
|
254316
|
+
) : await this.pool.query(
|
|
254317
|
+
`UPDATE ${this.s}.chat_items
|
|
254318
|
+
SET message_id = $3
|
|
254319
|
+
WHERE session_id = $1 AND turn_id = $2 AND message_id IS NULL AND role = 'assistant'`,
|
|
253976
254320
|
[sessionId, turnId, messageId]
|
|
253977
254321
|
);
|
|
253978
254322
|
return r.rowCount ?? 0;
|
|
@@ -254982,11 +255326,11 @@ var init_postgres_delegations = __esm({
|
|
|
254982
255326
|
});
|
|
254983
255327
|
|
|
254984
255328
|
// ../storage/src/postgres-nodes.ts
|
|
254985
|
-
var
|
|
255329
|
+
var import_node_crypto72, ident13, PostgresNodeStore, PostgresNodeTokenStore, rowToNode, rowToRuntime;
|
|
254986
255330
|
var init_postgres_nodes = __esm({
|
|
254987
255331
|
"../storage/src/postgres-nodes.ts"() {
|
|
254988
255332
|
"use strict";
|
|
254989
|
-
|
|
255333
|
+
import_node_crypto72 = require("node:crypto");
|
|
254990
255334
|
init_pg_ident();
|
|
254991
255335
|
init_esm();
|
|
254992
255336
|
ident13 = (s2) => {
|
|
@@ -255203,7 +255547,7 @@ var init_postgres_nodes = __esm({
|
|
|
255203
255547
|
return store;
|
|
255204
255548
|
}
|
|
255205
255549
|
issue(nodeId) {
|
|
255206
|
-
const token = `ont_${(0,
|
|
255550
|
+
const token = `ont_${(0, import_node_crypto72.randomBytes)(24).toString("base64url")}`;
|
|
255207
255551
|
this.cache.set(token, nodeId);
|
|
255208
255552
|
void this.pool.query(`INSERT INTO ${this.s}.node_tokens (token,node_id) VALUES ($1,$2)`, [token, nodeId]);
|
|
255209
255553
|
return token;
|
|
@@ -255469,11 +255813,11 @@ var init_postgres_type_registry = __esm({
|
|
|
255469
255813
|
});
|
|
255470
255814
|
|
|
255471
255815
|
// ../storage/src/postgres-actor-memory.ts
|
|
255472
|
-
var
|
|
255816
|
+
var import_node_crypto73, matchClause, ident15, PostgresActorMemoryStore, rowToIndexEntry, rowToRecord;
|
|
255473
255817
|
var init_postgres_actor_memory = __esm({
|
|
255474
255818
|
"../storage/src/postgres-actor-memory.ts"() {
|
|
255475
255819
|
"use strict";
|
|
255476
|
-
|
|
255820
|
+
import_node_crypto73 = require("node:crypto");
|
|
255477
255821
|
init_pg_ident();
|
|
255478
255822
|
init_src();
|
|
255479
255823
|
matchClause = (q2) => q2.requireMatch && q2.keywords.length > 0 ? " WHERE m > 0" : "";
|
|
@@ -255683,7 +256027,7 @@ var init_postgres_actor_memory = __esm({
|
|
|
255683
256027
|
}
|
|
255684
256028
|
async write(input, now) {
|
|
255685
256029
|
if (input.memId === void 0) {
|
|
255686
|
-
const memId = `mem:${(0,
|
|
256030
|
+
const memId = `mem:${(0, import_node_crypto73.randomUUID)()}`;
|
|
255687
256031
|
const r2 = await this.pool.query(
|
|
255688
256032
|
`INSERT INTO ${this.s}.actor_memories
|
|
255689
256033
|
(mem_id, actor_id, project_id, keywords, content, version, created_at, updated_at, accessed_at, source_artifact_id, source_session_id)
|
|
@@ -257130,14 +257474,14 @@ function companySchemaName(companyId) {
|
|
|
257130
257474
|
if (typeof companyId !== "string" || !companyId.trim()) {
|
|
257131
257475
|
throw new Error("company schema mapping \u9700\u8981\u975E\u7A7A companyId\uFF08fail-closed\uFF1A\u4E0D\u56DE\u9000\u9ED8\u8BA4\u516C\u53F8\uFF09");
|
|
257132
257476
|
}
|
|
257133
|
-
const hex = (0,
|
|
257477
|
+
const hex = (0, import_node_crypto74.createHash)("sha256").update(companyId, "utf8").digest("hex");
|
|
257134
257478
|
return `${COMPANY_SCHEMA_PREFIX}${hex.slice(0, DIGEST_HEX_LEN)}`;
|
|
257135
257479
|
}
|
|
257136
|
-
var
|
|
257480
|
+
var import_node_crypto74, COMPANY_SCHEMA_PREFIX, DIGEST_HEX_LEN, SchemaMappingConflictError, TenantStorageLocationStore;
|
|
257137
257481
|
var init_tenant_schema_mapping = __esm({
|
|
257138
257482
|
"../storage/src/tenant-schema-mapping.ts"() {
|
|
257139
257483
|
"use strict";
|
|
257140
|
-
|
|
257484
|
+
import_node_crypto74 = require("node:crypto");
|
|
257141
257485
|
init_esm();
|
|
257142
257486
|
init_pg_ident();
|
|
257143
257487
|
COMPANY_SCHEMA_PREFIX = "c_";
|
|
@@ -257211,7 +257555,7 @@ var init_tenant_schema_mapping = __esm({
|
|
|
257211
257555
|
|
|
257212
257556
|
// ../storage/src/company-data-plane-schema.ts
|
|
257213
257557
|
function canonicalTypeDefHash(def) {
|
|
257214
|
-
return `sha256:${(0,
|
|
257558
|
+
return `sha256:${(0, import_node_crypto75.createHash)("sha256").update(JSON.stringify(def), "utf8").digest("hex")}`;
|
|
257215
257559
|
}
|
|
257216
257560
|
function defaultArtifactTypeTemplate() {
|
|
257217
257561
|
return [
|
|
@@ -257393,11 +257737,11 @@ async function seedDefaultArtifactTypes(pool, schema, templates = defaultArtifac
|
|
|
257393
257737
|
}
|
|
257394
257738
|
return { inserted };
|
|
257395
257739
|
}
|
|
257396
|
-
var
|
|
257740
|
+
var import_node_crypto75, DEFAULT_ARTIFACT_TYPE_TEMPLATE_VERSION;
|
|
257397
257741
|
var init_company_data_plane_schema = __esm({
|
|
257398
257742
|
"../storage/src/company-data-plane-schema.ts"() {
|
|
257399
257743
|
"use strict";
|
|
257400
|
-
|
|
257744
|
+
import_node_crypto75 = require("node:crypto");
|
|
257401
257745
|
init_esm();
|
|
257402
257746
|
init_pg_ident();
|
|
257403
257747
|
DEFAULT_ARTIFACT_TYPE_TEMPLATE_VERSION = "4c368e5c-types-v1";
|
|
@@ -257477,11 +257821,11 @@ function rowToFile2(row) {
|
|
|
257477
257821
|
updatedAt: new Date(row.updated_at).toISOString()
|
|
257478
257822
|
};
|
|
257479
257823
|
}
|
|
257480
|
-
var
|
|
257824
|
+
var import_node_crypto76, COMPANY_CONFLICT_MSG, CompanyIdentifierConflictError, CompanyOwnedRegistryStore;
|
|
257481
257825
|
var init_company_owned_registry_store = __esm({
|
|
257482
257826
|
"../storage/src/company-owned-registry-store.ts"() {
|
|
257483
257827
|
"use strict";
|
|
257484
|
-
|
|
257828
|
+
import_node_crypto76 = require("node:crypto");
|
|
257485
257829
|
init_esm();
|
|
257486
257830
|
init_src();
|
|
257487
257831
|
init_pg_ident();
|
|
@@ -257867,7 +258211,7 @@ var init_company_owned_registry_store = __esm({
|
|
|
257867
258211
|
enabled: skill.enabled,
|
|
257868
258212
|
files: files.map((f2) => ({ path: f2.path, blobHash: f2.blobHash }))
|
|
257869
258213
|
});
|
|
257870
|
-
return (0,
|
|
258214
|
+
return (0, import_node_crypto76.createHash)("sha256").update(body2).digest("hex");
|
|
257871
258215
|
}
|
|
257872
258216
|
};
|
|
257873
258217
|
}
|
|
@@ -260467,7 +260811,7 @@ function sourceSetConservation(input) {
|
|
|
260467
260811
|
return input.sourceFinal === input.copied + input.approvedRuntimeConversion + input.approvedArchive + input.approvedDiscard;
|
|
260468
260812
|
}
|
|
260469
260813
|
function payloadChecksum(value2) {
|
|
260470
|
-
return (0,
|
|
260814
|
+
return (0, import_node_crypto77.createHash)("sha256").update(JSON.stringify(value2)).digest("hex");
|
|
260471
260815
|
}
|
|
260472
260816
|
async function copyWorkorderDraftsIdempotent(pool, companyId, companySchema, manifestId, opts) {
|
|
260473
260817
|
const cs = quoteIdent2(companySchema);
|
|
@@ -260855,11 +261199,11 @@ async function copyTraceFamilyIdempotent(pool, companyId, companySchema, manifes
|
|
|
260855
261199
|
sequences
|
|
260856
261200
|
};
|
|
260857
261201
|
}
|
|
260858
|
-
var
|
|
261202
|
+
var import_node_crypto77, MissingInstallerActorsError, TypeCatalogNotCoveredError, ORG_REGISTRY_TABLES, TRACE_FAMILY;
|
|
260859
261203
|
var init_tenant_migration_operator = __esm({
|
|
260860
261204
|
"../storage/src/tenant-migration-operator.ts"() {
|
|
260861
261205
|
"use strict";
|
|
260862
|
-
|
|
261206
|
+
import_node_crypto77 = require("node:crypto");
|
|
260863
261207
|
init_esm();
|
|
260864
261208
|
init_pg_ident();
|
|
260865
261209
|
init_tenancy_attribution();
|
|
@@ -261091,8 +261435,8 @@ var init_tenant_new_company_provision = __esm({
|
|
|
261091
261435
|
// ../storage/src/knowledge-snapshot-crypto.ts
|
|
261092
261436
|
function sealSnapshot(snapshot, key2) {
|
|
261093
261437
|
if (snapshot.content.startsWith(PREFIX3)) return structuredClone(snapshot);
|
|
261094
|
-
const iv = (0,
|
|
261095
|
-
const cipher = (0,
|
|
261438
|
+
const iv = (0, import_node_crypto78.randomBytes)(12);
|
|
261439
|
+
const cipher = (0, import_node_crypto78.createCipheriv)("aes-256-gcm", bytes(key2), iv);
|
|
261096
261440
|
cipher.setAAD(aad2(snapshot));
|
|
261097
261441
|
const encrypted = Buffer.concat([cipher.update(snapshot.content, "utf8"), cipher.final()]);
|
|
261098
261442
|
return { ...structuredClone(snapshot), content: `${PREFIX3}${iv.toString("base64url")}.${cipher.getAuthTag().toString("base64url")}.${encrypted.toString("base64url")}` };
|
|
@@ -261102,7 +261446,7 @@ function openSnapshot(snapshot, key2) {
|
|
|
261102
261446
|
const packed = snapshot.content.slice(PREFIX3.length).split(".");
|
|
261103
261447
|
if (packed.length !== 3 || packed.some((part) => !part)) throw new Error(`knowledge snapshot ${snapshot.ref} ciphertext is malformed`);
|
|
261104
261448
|
const [iv, tag, data] = packed;
|
|
261105
|
-
const decipher = (0,
|
|
261449
|
+
const decipher = (0, import_node_crypto78.createDecipheriv)("aes-256-gcm", bytes(key2), Buffer.from(iv, "base64url"));
|
|
261106
261450
|
decipher.setAAD(aad2(snapshot));
|
|
261107
261451
|
decipher.setAuthTag(Buffer.from(tag, "base64url"));
|
|
261108
261452
|
return {
|
|
@@ -261110,11 +261454,11 @@ function openSnapshot(snapshot, key2) {
|
|
|
261110
261454
|
content: Buffer.concat([decipher.update(Buffer.from(data, "base64url")), decipher.final()]).toString("utf8")
|
|
261111
261455
|
};
|
|
261112
261456
|
}
|
|
261113
|
-
var
|
|
261457
|
+
var import_node_crypto78, PREFIX3, bytes, aad2;
|
|
261114
261458
|
var init_knowledge_snapshot_crypto = __esm({
|
|
261115
261459
|
"../storage/src/knowledge-snapshot-crypto.ts"() {
|
|
261116
261460
|
"use strict";
|
|
261117
|
-
|
|
261461
|
+
import_node_crypto78 = require("node:crypto");
|
|
261118
261462
|
PREFIX3 = "oasis-knowledge:v1:";
|
|
261119
261463
|
bytes = (key2) => {
|
|
261120
261464
|
const value2 = Buffer.from(key2);
|
|
@@ -263368,14 +263712,14 @@ init_src();
|
|
|
263368
263712
|
var os14 = __toESM(require("node:os"));
|
|
263369
263713
|
var path39 = __toESM(require("node:path"));
|
|
263370
263714
|
var import_node_child_process22 = require("node:child_process");
|
|
263371
|
-
var
|
|
263715
|
+
var import_node_crypto89 = require("node:crypto");
|
|
263372
263716
|
|
|
263373
263717
|
// ../cli/src/cli.ts
|
|
263374
263718
|
init_src();
|
|
263375
263719
|
var fs39 = __toESM(require("node:fs"), 1);
|
|
263376
263720
|
var os12 = __toESM(require("node:os"), 1);
|
|
263377
263721
|
var path34 = __toESM(require("node:path"), 1);
|
|
263378
|
-
var
|
|
263722
|
+
var import_node_crypto87 = require("node:crypto");
|
|
263379
263723
|
|
|
263380
263724
|
// ../cli/src/serve.ts
|
|
263381
263725
|
init_src();
|
|
@@ -263384,11 +263728,11 @@ var fs33 = __toESM(require("node:fs"), 1);
|
|
|
263384
263728
|
var os8 = __toESM(require("node:os"), 1);
|
|
263385
263729
|
var path28 = __toESM(require("node:path"), 1);
|
|
263386
263730
|
var import_node_child_process17 = require("node:child_process");
|
|
263387
|
-
var
|
|
263731
|
+
var import_node_crypto83 = require("node:crypto");
|
|
263388
263732
|
var import_node_url7 = require("node:url");
|
|
263389
263733
|
|
|
263390
263734
|
// ../cli/src/artifact-discovery-source.ts
|
|
263391
|
-
var
|
|
263735
|
+
var import_node_crypto79 = require("node:crypto");
|
|
263392
263736
|
init_src7();
|
|
263393
263737
|
var ArtifactDiscoverySourceUnreadableError = class extends Error {
|
|
263394
263738
|
constructor(message) {
|
|
@@ -263418,7 +263762,7 @@ async function resolveArtifactDiscoverySourceContent(blobs, input) {
|
|
|
263418
263762
|
throw new ArtifactDiscoverySourceUnreadableError(`Artifact Revision ${input.revisionId} \u7684 contentKind \u4E0D\u53D7\u652F\u6301\uFF1A${String(input.contentKind)}`);
|
|
263419
263763
|
}
|
|
263420
263764
|
const rootBytes = await blobs.get(input.contentRef);
|
|
263421
|
-
const sourceFingerprint = (0,
|
|
263765
|
+
const sourceFingerprint = (0, import_node_crypto79.createHash)("sha256").update(rootBytes).digest("hex");
|
|
263422
263766
|
if (input.contentKind === "inline-blob") {
|
|
263423
263767
|
const sourceContent = decodeText3(rootBytes);
|
|
263424
263768
|
if (sourceContent === null) {
|
|
@@ -263442,7 +263786,7 @@ ${entry.text}`).join("\n\n"),
|
|
|
263442
263786
|
}
|
|
263443
263787
|
|
|
263444
263788
|
// ../server/src/domains/discussions/service.ts
|
|
263445
|
-
var
|
|
263789
|
+
var import_node_crypto80 = require("node:crypto");
|
|
263446
263790
|
init_zod();
|
|
263447
263791
|
|
|
263448
263792
|
// ../contract/src/discussions.ts
|
|
@@ -263479,7 +263823,7 @@ var generationSchema = external_exports.discriminatedUnion("result", [
|
|
|
263479
263823
|
}).strict()
|
|
263480
263824
|
]);
|
|
263481
263825
|
var entryId = (projectId2, id) => JSON.stringify([projectId2, id]);
|
|
263482
|
-
var hash2 = (s2) => (0,
|
|
263826
|
+
var hash2 = (s2) => (0, import_node_crypto80.createHash)("sha256").update(s2).digest("hex").slice(0, 24);
|
|
263483
263827
|
var canonical = (s2) => s2.normalize("NFKC").trim().toLocaleLowerCase();
|
|
263484
263828
|
function decisionFingerprint(d) {
|
|
263485
263829
|
return hash2(JSON.stringify([d.statement, d.rationale, d.alternatives]));
|
|
@@ -263634,7 +263978,7 @@ var DiscussionService = class {
|
|
|
263634
263978
|
let id = t.topic_id;
|
|
263635
263979
|
if (id.startsWith("new:")) {
|
|
263636
263980
|
const existing = [...topicMap.values()].find((x2) => canonical(x2.title) === canonical(t.title));
|
|
263637
|
-
id = existing?.topicId ?? `topic_${(0,
|
|
263981
|
+
id = existing?.topicId ?? `topic_${(0, import_node_crypto80.randomUUID)()}`;
|
|
263638
263982
|
} else if (!topicMap.has(id)) invalid("topics.topic_id", `\u8BAE\u9898 ${id} \u4E0D\u5B58\u5728\uFF1B\u65B0\u8BAE\u9898\u4F7F\u7528 new: \u524D\u7F00`);
|
|
263639
263983
|
topicAliases.set(t.topic_id, id);
|
|
263640
263984
|
const value2 = { projectId: input.projectId, topicId: id, title: t.title };
|
|
@@ -263655,7 +263999,7 @@ var DiscussionService = class {
|
|
|
263655
263999
|
if (id.startsWith("new:")) {
|
|
263656
264000
|
const candidateKey = JSON.stringify([topicId, canonical(d.record.statement)]);
|
|
263657
264001
|
const existing = [...decisionMap.values()].find((x2) => x2.topicId === topicId && canonical(x2.record.statement) === canonical(d.record.statement));
|
|
263658
|
-
id = existing?.decisionId ?? candidateIds.get(candidateKey) ?? `decision_${(0,
|
|
264002
|
+
id = existing?.decisionId ?? candidateIds.get(candidateKey) ?? `decision_${(0, import_node_crypto80.randomUUID)()}`;
|
|
263659
264003
|
candidateIds.set(candidateKey, id);
|
|
263660
264004
|
} else if (!decisionMap.has(id)) invalid("decision_id", `\u51B3\u7B56 ${id} \u4E0D\u5B58\u5728\uFF1B\u65B0\u51B3\u7B56\u4F7F\u7528 new: \u524D\u7F00`);
|
|
263661
264005
|
decisionAliases.set(d.decision_id, id);
|
|
@@ -263788,7 +264132,7 @@ var DiscussionService = class {
|
|
|
263788
264132
|
});
|
|
263789
264133
|
}
|
|
263790
264134
|
async operation(tx, actorId, kind, id, from, to) {
|
|
263791
|
-
await tx.put("operation", (0,
|
|
264135
|
+
await tx.put("operation", (0, import_node_crypto80.randomUUID)(), { actorId, kind, id, from, to, at: new Date(this.now()).toISOString() });
|
|
263792
264136
|
}
|
|
263793
264137
|
};
|
|
263794
264138
|
function pickDiscussionContent(d) {
|
|
@@ -263800,6 +264144,16 @@ function pickDecisionContent(d) {
|
|
|
263800
264144
|
|
|
263801
264145
|
// ../server/src/domains/discussions/context.ts
|
|
263802
264146
|
init_project_bundle();
|
|
264147
|
+
var decisionLabels = {
|
|
264148
|
+
proposed: "\u63D0\u8BAE\u4E2D",
|
|
264149
|
+
accepted: "\u5DF2\u786E\u8BA4",
|
|
264150
|
+
rejected: "\u5DF2\u5426\u51B3",
|
|
264151
|
+
superseded: "\u5DF2\u88AB\u66FF\u4EE3",
|
|
264152
|
+
withdrawn: "\u5DF2\u64A4\u9500"
|
|
264153
|
+
};
|
|
264154
|
+
function listField(label, items) {
|
|
264155
|
+
return items.length > 1 ? [`- ${label}\uFF1A`, ...items.map((item) => ` - ${item}`)] : [`- ${label}\uFF1A${items[0] ?? "\u65E0"}`];
|
|
264156
|
+
}
|
|
263803
264157
|
function renderDiscussionContext(input) {
|
|
263804
264158
|
const lines = [
|
|
263805
264159
|
"# \u5F53\u524D\u4F1A\u8BDD\u4E0A\u4E0B\u6587",
|
|
@@ -263820,44 +264174,37 @@ function renderDiscussionContext(input) {
|
|
|
263820
264174
|
if (!input.discussions.length) lines.push("\u5F53\u524D\u6682\u65E0\u5386\u53F2\u8BA8\u8BBA\u8BB0\u5F55\u3002", "");
|
|
263821
264175
|
for (const row of input.discussions) {
|
|
263822
264176
|
const d = row.value.record;
|
|
264177
|
+
const topicNames = d.topics.map((t) => input.topics.find((topic) => topic.value.projectId === d.project_id && topic.value.topicId === t.topic_id)?.value.title ?? "\u8BAE\u9898\u540D\u79F0\u7F3A\u5931");
|
|
263823
264178
|
lines.push(
|
|
263824
|
-
`### ${d.
|
|
263825
|
-
|
|
263826
|
-
`- \
|
|
263827
|
-
`- \
|
|
263828
|
-
`- \u6700\u540E\u8986\u76D6\u7684\u5BF9\u8BDD\u65F6\u95F4\uFF1A${row.value.discussedAt}`,
|
|
263829
|
-
`- \u6D88\u606F\u622A\u6B62\u70B9\uFF1A${d.source_cutoff}`,
|
|
264179
|
+
`### ${d.title}`,
|
|
264180
|
+
"",
|
|
264181
|
+
...!input.projectId ? [`- \u9879\u76EE\u5F52\u5C5E\uFF1A${d.project_id ?? "\u975E\u9879\u76EE\u8BA8\u8BBA"}`] : [],
|
|
264182
|
+
`- \u8BA8\u8BBA\u65E5\u671F\uFF1A${row.value.discussedAt.slice(0, 10)}`,
|
|
263830
264183
|
`- \u6458\u8981\uFF1A${d.summary}`,
|
|
263831
|
-
|
|
263832
|
-
...
|
|
263833
|
-
"
|
|
263834
|
-
...d.open_questions.map((q2) => ` - ${q2}`),
|
|
263835
|
-
"- \u4E0B\u4E00\u6B65\uFF1A",
|
|
263836
|
-
...d.next_steps.map((n) => ` - ${n}`),
|
|
264184
|
+
`- \u6D89\u53CA\u8BAE\u9898\uFF1A${topicNames.join("\u3001") || "\u65E0"}`,
|
|
264185
|
+
...listField("\u672A\u51B3\u95EE\u9898", d.open_questions),
|
|
264186
|
+
...listField("\u4E0B\u4E00\u6B65", d.next_steps),
|
|
263837
264187
|
""
|
|
263838
264188
|
);
|
|
263839
264189
|
}
|
|
263840
264190
|
if (input.projectId) {
|
|
263841
|
-
lines.push("## \u9879\u76EE\u8BAE\u9898\u4E0E\u51B3\u7B56", "", "\u4EC5
|
|
264191
|
+
lines.push("## \u9879\u76EE\u8BAE\u9898\u4E0E\u51B3\u7B56", "", "\u4EC5\u201C\u5DF2\u786E\u8BA4\u201D\u8868\u793A\u5DF2\u786E\u8BA4\u65B9\u6848\uFF1B\u201C\u63D0\u8BAE\u4E2D\u201D\u5C1A\u672A\u786E\u8BA4\uFF1B\u201C\u5DF2\u5426\u51B3\u201D\u201C\u5DF2\u64A4\u9500\u201D\u201C\u5DF2\u88AB\u66FF\u4EE3\u201D\u4E3A\u5931\u6548\u6216\u5386\u53F2\u65B9\u6848\u3002", "");
|
|
263842
264192
|
if (!input.topics.length) lines.push("\u5F53\u524D\u6682\u65E0\u9879\u76EE\u8BAE\u9898\u4E0E\u51B3\u7B56\u3002", "");
|
|
263843
264193
|
for (const t of input.topics) {
|
|
263844
|
-
lines.push(`###
|
|
264194
|
+
lines.push(`### \u8BAE\u9898\uFF1A${t.value.title}`, "");
|
|
263845
264195
|
const decisions = input.decisions.filter((d) => d.value.topicId === t.value.topicId);
|
|
263846
264196
|
if (!decisions.length) lines.push("\u6682\u65E0\u51B3\u7B56\u3002", "");
|
|
263847
|
-
for (const d of decisions) {
|
|
264197
|
+
for (const [index2, d] of decisions.entries()) {
|
|
263848
264198
|
const r = d.value.record;
|
|
263849
264199
|
lines.push(
|
|
263850
|
-
`#### ${
|
|
263851
|
-
|
|
263852
|
-
`- \
|
|
263853
|
-
`- \u539F\u56E0\uFF1A${r.rationale}`,
|
|
264200
|
+
`#### \u51B3\u7B56 ${index2 + 1}\uFF1A${r.statement}`,
|
|
264201
|
+
"",
|
|
264202
|
+
`- \u72B6\u6001\uFF1A${decisionLabels[r.state]}`,
|
|
264203
|
+
`- \u539F\u56E0\uFF1A${r.rationale || "\u672A\u8BF4\u660E"}`,
|
|
263854
264204
|
`- \u786E\u8BA4\u4EBA\uFF1A${r.confirmer ?? "\u672A\u786E\u8BA4"}`,
|
|
263855
|
-
"
|
|
263856
|
-
...r.
|
|
263857
|
-
|
|
263858
|
-
...r.source_refs.map((s2) => ` - ${s2.session_id} / ${s2.message_id}\uFF1A${JSON.stringify(s2.content)}`),
|
|
263859
|
-
`- \u66FF\u4EE3\u5173\u7CFB\uFF1A${r.supersedes.join("\u3001") || "\u65E0"}`,
|
|
263860
|
-
`- \u6700\u8FD1\u66F4\u65B0\u65F6\u95F4\uFF1A${r.updated_at}`,
|
|
264205
|
+
...listField("\u5907\u9009\u65B9\u6848", r.alternatives.map((a) => `${a.statement}\uFF0C${a.reason || "\u672A\u8BF4\u660E\u539F\u56E0"}`)),
|
|
264206
|
+
...r.supersedes.length ? listField("\u66FF\u4EE3\u51B3\u7B56", r.supersedes.map((id) => input.decisions.find((other) => other.value.decisionId === id)?.value.record.statement ?? "\u672A\u627E\u5230\u5BF9\u5E94\u51B3\u7B56")) : [],
|
|
264207
|
+
`- \u66F4\u65B0\u65F6\u95F4\uFF1A${r.updated_at.slice(0, 10)}`,
|
|
263861
264208
|
""
|
|
263862
264209
|
);
|
|
263863
264210
|
}
|
|
@@ -263890,7 +264237,12 @@ var DiscussionContext = class {
|
|
|
263890
264237
|
let discussions = (await tx.list("discussion")).filter((r) => r.value.userId === session.humanActorId);
|
|
263891
264238
|
discussions.sort((a, b2) => Date.parse(a.value.discussedAt) - Date.parse(b2.value.discussedAt) || a.id.localeCompare(b2.id));
|
|
263892
264239
|
discussions = projectId2 ? discussions.filter((r) => r.value.record.project_id === projectId2) : discussions.slice(-10);
|
|
263893
|
-
const
|
|
264240
|
+
const discussionProjects = new Set(discussions.map((d) => d.value.record.project_id));
|
|
264241
|
+
const view = projectId2 ? await this.service.view(projectId2, tx) : {
|
|
264242
|
+
// Resolve names for the selected personal history without loading project decisions.
|
|
264243
|
+
topics: (await tx.list("topic")).filter((t) => discussionProjects.has(t.value.projectId)),
|
|
264244
|
+
decisions: []
|
|
264245
|
+
};
|
|
263894
264246
|
const markdown = renderDiscussionContext({
|
|
263895
264247
|
userName,
|
|
263896
264248
|
projectId: projectId2,
|
|
@@ -263926,7 +264278,7 @@ var DiscussionContext = class {
|
|
|
263926
264278
|
};
|
|
263927
264279
|
|
|
263928
264280
|
// ../server/src/domains/discussions/worker.ts
|
|
263929
|
-
var
|
|
264281
|
+
var import_node_crypto81 = require("node:crypto");
|
|
263930
264282
|
var DISCUSSION_IDLE_MS = 15 * 6e4;
|
|
263931
264283
|
var DISCUSSION_MAX_CORRECTIONS = 3;
|
|
263932
264284
|
var DISCUSSION_LEASE_MS = 2 * 6e4;
|
|
@@ -263952,7 +264304,7 @@ var DiscussionWorker = class {
|
|
|
263952
264304
|
if (await this.isReplying(sessionId)) return false;
|
|
263953
264305
|
const cutoff = eligibleCutoff(await this.service.chat.listMessages(sessionId), this.service.now());
|
|
263954
264306
|
if (!cutoff) return false;
|
|
263955
|
-
const owner = (0,
|
|
264307
|
+
const owner = (0, import_node_crypto81.randomUUID)();
|
|
263956
264308
|
const claimed = await this.service.store.transaction(async (tx) => {
|
|
263957
264309
|
const old = (await tx.get("job", sessionId))?.value;
|
|
263958
264310
|
if (old?.status === "running" && (old.leaseUntil ?? 0) > this.service.now()) return null;
|
|
@@ -264385,7 +264737,7 @@ function createDiscussionRuntime(options) {
|
|
|
264385
264737
|
}
|
|
264386
264738
|
|
|
264387
264739
|
// ../server/src/domains/discussions/store.ts
|
|
264388
|
-
var
|
|
264740
|
+
var import_node_crypto82 = require("node:crypto");
|
|
264389
264741
|
var import_promises16 = require("node:fs/promises");
|
|
264390
264742
|
var import_node_path27 = require("node:path");
|
|
264391
264743
|
var key = (kind, id) => JSON.stringify([kind, id]);
|
|
@@ -264423,7 +264775,7 @@ var MemoryDiscussionStore = class _MemoryDiscussionStore {
|
|
|
264423
264775
|
if (changed) {
|
|
264424
264776
|
if (this.filename) {
|
|
264425
264777
|
await (0, import_promises16.mkdir)((0, import_node_path27.dirname)(this.filename), { recursive: true });
|
|
264426
|
-
const temp = `${this.filename}.${(0,
|
|
264778
|
+
const temp = `${this.filename}.${(0, import_node_crypto82.randomUUID)()}.tmp`;
|
|
264427
264779
|
await (0, import_promises16.writeFile)(temp, JSON.stringify(next), "utf8");
|
|
264428
264780
|
await (0, import_promises16.rename)(temp, this.filename);
|
|
264429
264781
|
}
|
|
@@ -264568,6 +264920,15 @@ function transcriptTail(ref2) {
|
|
|
264568
264920
|
return "";
|
|
264569
264921
|
}
|
|
264570
264922
|
}
|
|
264923
|
+
var SUMMARY_MAX_CHARS = 500;
|
|
264924
|
+
function clipLine(line) {
|
|
264925
|
+
return line.length > SUMMARY_MAX_CHARS ? `${line.slice(0, SUMMARY_MAX_CHARS)}\u2026` : line;
|
|
264926
|
+
}
|
|
264927
|
+
function providerMessage(line) {
|
|
264928
|
+
const m2 = /['"]message['"]\s*:\s*(?:'((?:[^'\\]|\\.)*)'|"((?:[^"\\]|\\.)*)")/.exec(line);
|
|
264929
|
+
const text6 = (m2?.[1] ?? m2?.[2])?.trim();
|
|
264930
|
+
return text6 ? text6 : void 0;
|
|
264931
|
+
}
|
|
264571
264932
|
function buildChatExitError(info) {
|
|
264572
264933
|
const genericLine = `runtime exited with code ${info.code ?? "null"}${info.reason ? ` (${info.reason})` : ""}`;
|
|
264573
264934
|
let detail = "";
|
|
@@ -264577,8 +264938,9 @@ function buildChatExitError(info) {
|
|
|
264577
264938
|
}
|
|
264578
264939
|
const firstDetailLine = detail.split("\n").map((line) => line.trim()).find(Boolean) ?? "";
|
|
264579
264940
|
const firstErrorLine = info.errorMessage?.split("\n").map((line) => line.trim()).find(Boolean) ?? "";
|
|
264941
|
+
const readableError = firstErrorLine ? clipLine(providerMessage(firstErrorLine) ?? firstErrorLine) : "";
|
|
264580
264942
|
const fixed = info.reason ? SUMMARY_BY_REASON[info.reason] : void 0;
|
|
264581
|
-
const summary = fixed ?
|
|
264943
|
+
const summary = fixed ? readableError && info.reason !== "cancelled" && info.reason !== "timeout" ? `${fixed}\uFF1A${readableError}` : fixed : readableError ? `\u5BF9\u8BDD\u5931\u8D25\uFF1A${readableError}` : firstDetailLine ? `\u5BF9\u8BDD\u5931\u8D25\uFF1A${clipLine(firstDetailLine)}` : `\u5BF9\u8BDD\u5931\u8D25\uFF08${genericLine}\uFF09`;
|
|
264582
264944
|
const chatExit = {
|
|
264583
264945
|
...info.reason ? { reason: info.reason } : {},
|
|
264584
264946
|
summary,
|
|
@@ -265181,7 +265543,7 @@ init_src9();
|
|
|
265181
265543
|
init_src();
|
|
265182
265544
|
init_trajectory();
|
|
265183
265545
|
function deterministicUuid2(seed) {
|
|
265184
|
-
const h = (0,
|
|
265546
|
+
const h = (0, import_node_crypto83.createHash)("sha256").update(seed).digest();
|
|
265185
265547
|
const b2 = Buffer.from(h.subarray(0, 16));
|
|
265186
265548
|
b2[6] = b2[6] & 15 | 80;
|
|
265187
265549
|
b2[8] = b2[8] & 63 | 128;
|
|
@@ -265381,7 +265743,7 @@ function oasisWrapperScript() {
|
|
|
265381
265743
|
const repoRoot = (0, import_node_url7.fileURLToPath)(new URL("../../../", __esm_import_meta_url));
|
|
265382
265744
|
const tsx = path28.join(repoRoot, "node_modules/.bin/tsx");
|
|
265383
265745
|
const main = path28.join(repoRoot, "packages/cli/src/main.ts");
|
|
265384
|
-
const key2 = (0,
|
|
265746
|
+
const key2 = (0, import_node_crypto83.createHash)("sha256").update(repoRoot).digest("hex").slice(0, 12);
|
|
265385
265747
|
const uid = typeof process.getuid === "function" ? process.getuid() : "na";
|
|
265386
265748
|
const stable = path28.join(os8.tmpdir(), `oasis-cli-wrapper-${uid}-${key2}`);
|
|
265387
265749
|
let dir;
|
|
@@ -265767,7 +266129,7 @@ async function startServe(opts) {
|
|
|
265767
266129
|
if (!hub) return Promise.resolve({ ok: false, reason: "\u672C\u8FDB\u7A0B\u6CA1\u6709\u8282\u70B9\u7F51\u5173" });
|
|
265768
266130
|
const online = hub.connectedDaemons().some((d) => d.daemonId === nodeId);
|
|
265769
266131
|
if (!online) return Promise.resolve({ ok: false, reason: "\u8282\u70B9\u5F53\u524D\u4E0D\u5728\u7EBF\uFF0C\u7528\u7684\u662F\u5B83\u4E0A\u6B21\u62A5\u7684\u6E05\u5355" });
|
|
265770
|
-
const requestId = (0,
|
|
266132
|
+
const requestId = (0, import_node_crypto83.randomUUID)();
|
|
265771
266133
|
const task = new Promise((resolve10) => {
|
|
265772
266134
|
const timer = setTimeout(() => {
|
|
265773
266135
|
modelRefreshWaiters.delete(requestId);
|
|
@@ -266535,7 +266897,7 @@ async function startServe(opts) {
|
|
|
266535
266897
|
const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
266536
266898
|
if (buf || session.runId) {
|
|
266537
266899
|
await turnStore.appendMessage({
|
|
266538
|
-
id: (0,
|
|
266900
|
+
id: (0, import_node_crypto83.randomUUID)(),
|
|
266539
266901
|
sessionId: chatSessionId,
|
|
266540
266902
|
role: "assistant",
|
|
266541
266903
|
content: buf,
|
|
@@ -266581,7 +266943,7 @@ async function startServe(opts) {
|
|
|
266581
266943
|
chatTargets: {
|
|
266582
266944
|
inspect: inspectChatTarget,
|
|
266583
266945
|
createTargetSession: async ({ companyId, agentId, ownerHumanActorId, title }) => {
|
|
266584
|
-
const sessionId = (0,
|
|
266946
|
+
const sessionId = (0, import_node_crypto83.randomUUID)();
|
|
266585
266947
|
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
266586
266948
|
const binding = await registryStore.getBinding(agentId).catch(() => null);
|
|
266587
266949
|
await (await chatStoreFor(companyId)).createSession({
|
|
@@ -267727,7 +268089,7 @@ async function startServe(opts) {
|
|
|
267727
268089
|
}));
|
|
267728
268090
|
}
|
|
267729
268091
|
const limits = { wallClockMs: wallClockForKind("planner") };
|
|
267730
|
-
const artifactId = `artifact:planner:${(0,
|
|
268092
|
+
const artifactId = `artifact:planner:${(0, import_node_crypto83.randomUUID)()}`;
|
|
267731
268093
|
const handle = await chatRemoteAdapter.spawn({
|
|
267732
268094
|
actor: planner.id,
|
|
267733
268095
|
// companyId 同协调者:planner 用的就是默认公司的 actors 服务,漏签会让它一调公司域端点就 404。
|
|
@@ -268023,7 +268385,9 @@ async function startServe(opts) {
|
|
|
268023
268385
|
// v3 快照端点(ws:wo-81de04dc S3 恢复路径唯一入口):`chat_items` 权威读口 +
|
|
268024
268386
|
// live 注册表算 `frameCursor`。与 server.ts 的双写解析同一层,与 attach 路径共享 registry。
|
|
268025
268387
|
resolveChatItems: (companyId) => chatItemsFor(companyId),
|
|
268026
|
-
liveChat
|
|
268388
|
+
liveChat,
|
|
268389
|
+
// ADR-0587:列表行派生 `unread`,与 collab 域收件箱读同一份按公司的水位(无 PG 时闭包自己回落单实例)。
|
|
268390
|
+
resolveReadMarkers: readMarkerStoreFor
|
|
268027
268391
|
})] : []
|
|
268028
268392
|
],
|
|
268029
268393
|
workorderDrafts,
|
|
@@ -268610,10 +268974,10 @@ async function startServe(opts) {
|
|
|
268610
268974
|
if (isDeletedActor(dispatchTarget)) {
|
|
268611
268975
|
throw new ApiError(409, ACTOR_DELETED_ERROR_CODE, ACTOR_DELETED_CHAT_MESSAGE);
|
|
268612
268976
|
}
|
|
268613
|
-
const runtimeSessionId = sessionId ?? (requestDispatchId ? deterministicUuid2(`chat-runtime:${requestDispatchId}`) : (0,
|
|
268977
|
+
const runtimeSessionId = sessionId ?? (requestDispatchId ? deterministicUuid2(`chat-runtime:${requestDispatchId}`) : (0, import_node_crypto83.randomUUID)());
|
|
268614
268978
|
const resumeRuntimeSession = Boolean(sessionId);
|
|
268615
|
-
const traceRunId = requestDispatchId ? `chat-run:${deterministicUuid2(`chat-trace:${requestDispatchId}`)}` : `chat-run:${(0,
|
|
268616
|
-
const artifactId = requestDispatchId ? `artifact:chat:${deterministicUuid2(`chat-artifact:${requestDispatchId}`)}` : `artifact:chat:${(0,
|
|
268979
|
+
const traceRunId = requestDispatchId ? `chat-run:${deterministicUuid2(`chat-trace:${requestDispatchId}`)}` : `chat-run:${(0, import_node_crypto83.randomUUID)()}`;
|
|
268980
|
+
const artifactId = requestDispatchId ? `artifact:chat:${deterministicUuid2(`chat-artifact:${requestDispatchId}`)}` : `artifact:chat:${(0, import_node_crypto83.randomUUID)()}`;
|
|
268617
268981
|
let stableDispatch = requestDispatchId ? await resolveStableChatDispatch({ store: await traceStoreFor(runCompanyId), runId: traceRunId }) : null;
|
|
268618
268982
|
if (stableDispatch && !stableDispatch.shouldDispatch) {
|
|
268619
268983
|
return {
|
|
@@ -269793,7 +270157,7 @@ async function startServe(opts) {
|
|
|
269793
270157
|
console.log(`[new-engine] dispatchWork ${workId} \u662F human work\u2014\u2014\u4E0D\u6D3E runtime\uFF0C\u7B49\u5F85\u4EBA\u5DE5\u5904\u7406`);
|
|
269794
270158
|
return;
|
|
269795
270159
|
}
|
|
269796
|
-
const ledgerId = `dispatch:${(0,
|
|
270160
|
+
const ledgerId = `dispatch:${(0, import_node_crypto83.randomUUID)()}`;
|
|
269797
270161
|
try {
|
|
269798
270162
|
await (await dispatchLedgerFor(companyId)).insertOpen({
|
|
269799
270163
|
id: ledgerId,
|
|
@@ -269878,7 +270242,7 @@ async function startServe(opts) {
|
|
|
269878
270242
|
const kernelModel = newKernel.model;
|
|
269879
270243
|
const art = kernelModel.artifacts.get(nodeId);
|
|
269880
270244
|
const revWid = art?.workspace ?? "";
|
|
269881
|
-
const ledgerId = `dispatch:${(0,
|
|
270245
|
+
const ledgerId = `dispatch:${(0, import_node_crypto83.randomUUID)()}`;
|
|
269882
270246
|
try {
|
|
269883
270247
|
await (await dispatchLedgerFor(companyId)).insertOpen({
|
|
269884
270248
|
id: ledgerId,
|
|
@@ -270252,7 +270616,7 @@ async function startServe(opts) {
|
|
|
270252
270616
|
resolveSupplementalContext: server.knowledgeGovernance ? async ({ actorId, artifactId, workOrderId, action, part, runtimeKind, taskMarkdown }) => {
|
|
270253
270617
|
try {
|
|
270254
270618
|
const governance = server.knowledgeGovernance;
|
|
270255
|
-
const taskFingerprint = (0,
|
|
270619
|
+
const taskFingerprint = (0, import_node_crypto83.createHash)("sha256").update(JSON.stringify({ artifactId, workOrderId, action, part: part ?? null, taskMarkdown })).digest("hex");
|
|
270256
270620
|
const requestContext = {
|
|
270257
270621
|
organizationId: companyId,
|
|
270258
270622
|
actorId,
|
|
@@ -270716,10 +271080,10 @@ async function startServe(opts) {
|
|
|
270716
271080
|
if (h < 24) return `${h} \u5C0F\u65F6\u524D`;
|
|
270717
271081
|
return `${Math.floor(h / 24)} \u5929\u524D`;
|
|
270718
271082
|
};
|
|
270719
|
-
const humanFailCause = (reason,
|
|
270720
|
-
const quote =
|
|
271083
|
+
const humanFailCause = (reason, errorMessage2) => {
|
|
271084
|
+
const quote = errorMessage2?.trim().slice(0, 300);
|
|
270721
271085
|
if (reason === "rate-limit") {
|
|
270722
|
-
const hint = extractResetHint(
|
|
271086
|
+
const hint = extractResetHint(errorMessage2);
|
|
270723
271087
|
return `**\u5B83\u7684\u989D\u5EA6\u88AB\u6253\u6EE1\u4E86**${hint ? `\uFF08runtime \u539F\u8BDD\uFF1A\`${hint}\`\uFF09` : ""}\u2014\u2014\u989D\u5EA6\u5230\u70B9\u4F1A\u81EA\u5DF1\u6062\u590D\uFF0C**\u4E0D\u9700\u8981\u4F60\u4FEE\u4EFB\u4F55\u4E1C\u897F**\uFF1B\u4E0D\u60F3\u7B49\u5C31\u7ED9\u8FD9\u4E2A\u5458\u5DE5\u6362\u4E2A runtime\u3002` + (quote ? `
|
|
270724
271088
|
> ${quote}` : "");
|
|
270725
271089
|
}
|
|
@@ -271869,11 +272233,11 @@ async function runSession(dispatchId, job, deps) {
|
|
|
271869
272233
|
} catch (err) {
|
|
271870
272234
|
deps.onFailure?.();
|
|
271871
272235
|
log2("[node-cli]", ` spawn failed: ${err}`);
|
|
271872
|
-
const
|
|
272236
|
+
const errorMessage2 = String(err?.stack ?? err).slice(0, 8e3);
|
|
271873
272237
|
deps.sink.keyFrame({ type: "session_exited", dispatchId, sessionId: "spawn-failed", info: {
|
|
271874
272238
|
code: null,
|
|
271875
272239
|
reason: "error",
|
|
271876
|
-
errorMessage,
|
|
272240
|
+
errorMessage: errorMessage2,
|
|
271877
272241
|
...err instanceof BundleRestoreError ? { fileRestoreError: { path: err.filePath, message: err.message } } : {}
|
|
271878
272242
|
} });
|
|
271879
272243
|
}
|
|
@@ -271882,7 +272246,6 @@ async function runSession(dispatchId, job, deps) {
|
|
|
271882
272246
|
// ../cli/src/daemon/session-process.ts
|
|
271883
272247
|
var RECONNECT_MIN_MS = 1e3;
|
|
271884
272248
|
var RECONNECT_MAX_MS = 3e4;
|
|
271885
|
-
var EXIT_ACK_WAIT_MS = LINK_WINDOWS.exitAckWaitMs;
|
|
271886
272249
|
var OUTBOX_MAX_FRAMES = 8e3;
|
|
271887
272250
|
var isKeyFrame = (m2) => m2.type === "session_started" || m2.type === "session_exited";
|
|
271888
272251
|
async function runSessionProcess(specFile, adapter) {
|
|
@@ -271928,6 +272291,7 @@ var SessionProcessState = class {
|
|
|
271928
272291
|
this.hardTtlMs = o.hardTtlMs ?? SESSION_LIMITS.hardTtlMs;
|
|
271929
272292
|
this.suicideAfterUnreachableMs = o.suicideAfterUnreachableMs ?? SESSION_LIMITS.suicideAfterUnreachableMs;
|
|
271930
272293
|
this.watchdogIntervalMs = o.watchdogIntervalMs ?? 3e4;
|
|
272294
|
+
this.exitAckWaitMs = o.exitAckWaitMs ?? LINK_WINDOWS.exitAckWaitMs;
|
|
271931
272295
|
}
|
|
271932
272296
|
ws = null;
|
|
271933
272297
|
connected = false;
|
|
@@ -271941,6 +272305,8 @@ var SessionProcessState = class {
|
|
|
271941
272305
|
hardTtlMs;
|
|
271942
272306
|
suicideAfterUnreachableMs;
|
|
271943
272307
|
watchdogIntervalMs;
|
|
272308
|
+
/** 发完 session_exited 后等 ack 的时限;等不到也退——outbox 那份由服务端 L3 时钟扫描兜底。 */
|
|
272309
|
+
exitAckWaitMs;
|
|
271944
272310
|
watchdog = null;
|
|
271945
272311
|
exitAckResolve = null;
|
|
271946
272312
|
/** 整个会话进程「可以退了」的信号:会话正常退出、或被 evict / TTL / 失联自尽。 */
|
|
@@ -272163,7 +272529,7 @@ var SessionProcessState = class {
|
|
|
272163
272529
|
this.exitAckResolve = null;
|
|
272164
272530
|
resolve10();
|
|
272165
272531
|
};
|
|
272166
|
-
const timer = setTimeout(finish,
|
|
272532
|
+
const timer = setTimeout(finish, this.exitAckWaitMs);
|
|
272167
272533
|
this.exitAckResolve = finish;
|
|
272168
272534
|
});
|
|
272169
272535
|
}
|
|
@@ -272186,7 +272552,7 @@ var SessionProcessState = class {
|
|
|
272186
272552
|
init_wrapper();
|
|
272187
272553
|
init_src();
|
|
272188
272554
|
var import_node_os9 = require("node:os");
|
|
272189
|
-
var
|
|
272555
|
+
var import_node_crypto84 = require("node:crypto");
|
|
272190
272556
|
init_src8();
|
|
272191
272557
|
init_src2();
|
|
272192
272558
|
|
|
@@ -272971,7 +273337,7 @@ var DaemonWsClient = class {
|
|
|
272971
273337
|
*/
|
|
272972
273338
|
async queryArtifactStates(artifactIds, timeoutMs = 15e3) {
|
|
272973
273339
|
if (artifactIds.length === 0) return {};
|
|
272974
|
-
const requestId = (0,
|
|
273340
|
+
const requestId = (0, import_node_crypto84.randomUUID)();
|
|
272975
273341
|
return new Promise((resolve10, reject) => {
|
|
272976
273342
|
const timer = setTimeout(() => {
|
|
272977
273343
|
this.gcPending.delete(requestId);
|
|
@@ -273377,7 +273743,7 @@ function forwardSignal(child, sig, killGroup = (pgid, signal) => {
|
|
|
273377
273743
|
// ../cli/src/daemon/machine-id.ts
|
|
273378
273744
|
var import_node_child_process20 = require("node:child_process");
|
|
273379
273745
|
var import_node_fs22 = require("node:fs");
|
|
273380
|
-
var
|
|
273746
|
+
var import_node_crypto85 = require("node:crypto");
|
|
273381
273747
|
var import_node_os12 = require("node:os");
|
|
273382
273748
|
function linuxMachineId() {
|
|
273383
273749
|
for (const p2 of ["/etc/machine-id", "/var/lib/dbus/machine-id"]) {
|
|
@@ -273443,7 +273809,7 @@ var defaultSources = {
|
|
|
273443
273809
|
function resolveNodeId(sources = {}) {
|
|
273444
273810
|
const s2 = { ...defaultSources, ...sources };
|
|
273445
273811
|
const material = `${s2.machineFingerprint()}:${s2.osUser()}`;
|
|
273446
|
-
const digest = (0,
|
|
273812
|
+
const digest = (0, import_node_crypto85.createHash)("sha256").update(material).digest("hex").slice(0, 12);
|
|
273447
273813
|
return `node-${digest}`;
|
|
273448
273814
|
}
|
|
273449
273815
|
|
|
@@ -275214,13 +275580,13 @@ function ownFlagsFromDecl(command) {
|
|
|
275214
275580
|
}
|
|
275215
275581
|
|
|
275216
275582
|
// ../cli/src/connector-effect-runner.ts
|
|
275217
|
-
var
|
|
275583
|
+
var import_node_crypto86 = require("node:crypto");
|
|
275218
275584
|
var import_node_child_process21 = require("node:child_process");
|
|
275219
275585
|
init_src8();
|
|
275220
275586
|
function stableKey(effect) {
|
|
275221
275587
|
const keyFields = Object.fromEntries(Object.entries(effect.keyFields).sort(([a], [b2]) => a.localeCompare(b2)));
|
|
275222
275588
|
const canonical2 = JSON.stringify({ kind: effect.kind, target: effect.target, keyFields });
|
|
275223
|
-
return `sha256:${(0,
|
|
275589
|
+
return `sha256:${(0, import_node_crypto86.createHash)("sha256").update(canonical2).digest("hex")}`;
|
|
275224
275590
|
}
|
|
275225
275591
|
async function runConnectorEffect(connector, toolArgs, deps) {
|
|
275226
275592
|
const effect = connector.describeExternalEffect?.(toolArgs) ?? null;
|
|
@@ -275457,7 +275823,7 @@ async function waitForCommandAuthorization(base, headers, draftId, fallback) {
|
|
|
275457
275823
|
const timeoutMs = resolveAuthWaitMs();
|
|
275458
275824
|
const controller = new AbortController();
|
|
275459
275825
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
275460
|
-
const waiterId = (0,
|
|
275826
|
+
const waiterId = (0, import_node_crypto87.randomUUID)();
|
|
275461
275827
|
process.stderr.write(
|
|
275462
275828
|
`\u7B49\u5F85\u4EBA\u5DE5\u6388\u6743\u4E2D\u2026\u2026\u6700\u591A ${Math.round(timeoutMs / 1e3)} \u79D2\uFF0C\u8D85\u65F6\u4F1A\u81EA\u52A8\u8F6C\u4E3A\u5F85\u5BA1\uFF1B\u8FD9\u4E0D\u662F\u9519\u8BEF\uFF0C\u8BF7\u52FF\u91CD\u8BD5\u540C\u4E00\u6761\u547D\u4EE4\u3002
|
|
275463
275829
|
`
|
|
@@ -275885,7 +276251,7 @@ async function runCli(argv, println = console.log, progressln = console.error) {
|
|
|
275885
276251
|
const store = createNodeTokenStore(path34.join(dir, "node-tokens.json"));
|
|
275886
276252
|
const sub = positional[0];
|
|
275887
276253
|
if (sub === "issue") {
|
|
275888
|
-
const id = flags.get("id") ?? `node-${(0,
|
|
276254
|
+
const id = flags.get("id") ?? `node-${(0, import_node_crypto87.randomUUID)()}`;
|
|
275889
276255
|
const token2 = store.issue(id);
|
|
275890
276256
|
println(token2);
|
|
275891
276257
|
process.stderr.write(
|
|
@@ -276916,7 +277282,7 @@ ${t.ref} ${t.name} [\u5267\u672C=${t.playbookRef}]`);
|
|
|
276916
277282
|
if (!name) throw new Error("\u9879\u76EE\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A");
|
|
276917
277283
|
const goal = flags.get("goal")?.trim();
|
|
276918
277284
|
const slug6 = flags.get("slug");
|
|
276919
|
-
const id = slug6 !== void 0 ? projectSlug(slug6) : projectIdFromUuid((0,
|
|
277285
|
+
const id = slug6 !== void 0 ? projectSlug(slug6) : projectIdFromUuid((0, import_node_crypto87.randomUUID)());
|
|
276920
277286
|
const result = await api.request("POST", "/api/projects", {
|
|
276921
277287
|
...id ? { id } : {},
|
|
276922
277288
|
name,
|
|
@@ -278908,13 +279274,13 @@ var LEGACY_SYSTEMD_UNIT = "oasis-node.service";
|
|
|
278908
279274
|
var LEGACY_LAUNCHD_LABEL = "com.oasis.node";
|
|
278909
279275
|
|
|
278910
279276
|
// src/install.ts
|
|
278911
|
-
var
|
|
279277
|
+
var import_node_crypto88 = require("node:crypto");
|
|
278912
279278
|
var fs43 = __toESM(require("node:fs"));
|
|
278913
279279
|
var path38 = __toESM(require("node:path"));
|
|
278914
279280
|
function versionLabel(sourceFile, pkgVersion, npmPrefixDir, pkgName = LEGACY_PKG_NAME) {
|
|
278915
279281
|
const tag = pkgName === LEGACY_PKG_NAME ? "" : `+pkg.${pkgName.replace(/[^A-Za-z0-9-]/g, "-")}`;
|
|
278916
279282
|
if (isFromNpmPrefix(sourceFile, npmPrefixDir)) return `${pkgVersion}${tag}`;
|
|
278917
|
-
const digest = (0,
|
|
279283
|
+
const digest = (0, import_node_crypto88.createHash)("sha256").update(fs43.readFileSync(sourceFile)).digest("hex").slice(0, 8);
|
|
278918
279284
|
return tag ? `${pkgVersion}${tag}.local.${digest}` : `${pkgVersion}+local.${digest}`;
|
|
278919
279285
|
}
|
|
278920
279286
|
function isFromNpmPrefix(sourceFile, npmPrefixDir) {
|
|
@@ -279037,7 +279403,7 @@ function shimScript() {
|
|
|
279037
279403
|
}
|
|
279038
279404
|
|
|
279039
279405
|
// src/index.ts
|
|
279040
|
-
var PKG_VERSION = true ? "2.2.
|
|
279406
|
+
var PKG_VERSION = true ? "2.2.49" : "dev";
|
|
279041
279407
|
var LOCAL_BIN = localBin();
|
|
279042
279408
|
var NPM_PREFIX = npmPrefix();
|
|
279043
279409
|
var INSTANCE = DEFAULT_INSTANCE;
|
|
@@ -279322,7 +279688,7 @@ function newInstanceName() {
|
|
|
279322
279688
|
const existing = new Set(listInstances());
|
|
279323
279689
|
if (!existing.has(DEFAULT_INSTANCE)) return DEFAULT_INSTANCE;
|
|
279324
279690
|
for (; ; ) {
|
|
279325
|
-
const n = `inst-${(0,
|
|
279691
|
+
const n = `inst-${(0, import_node_crypto89.randomBytes)(3).toString("hex")}`;
|
|
279326
279692
|
if (!existing.has(n)) return n;
|
|
279327
279693
|
}
|
|
279328
279694
|
}
|