oasis_test_v2 2.2.48 → 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 +874 -596
- 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
|
};
|
|
@@ -6906,7 +6909,7 @@ ${task}` : task;
|
|
|
6906
6909
|
const runtimeSessionId = telemetry.sessionId ?? resumeSessionId;
|
|
6907
6910
|
const sawStreamError = streamErrorMessages.length > 0;
|
|
6908
6911
|
const isError = !killReason && (code2 !== 0 || sawStreamError);
|
|
6909
|
-
const
|
|
6912
|
+
const errorMessage2 = isError ? [...streamErrorMessages, ...stdoutErrorLines, ...stderrTail2].join("\n").trim().slice(-4e3) || void 0 : void 0;
|
|
6910
6913
|
const sessionNotFound = !killReason && isResume && isSessionNotFoundError([...streamErrorMessages, ...stdoutErrorLines, ...stderrTail2].join("\n"));
|
|
6911
6914
|
const reason = killReason ? killReason : sessionNotFound ? "session-not-found" : sawStreamError ? "error" : code2 === 0 ? "clean" : "error";
|
|
6912
6915
|
finish({
|
|
@@ -6919,7 +6922,7 @@ ${task}` : task;
|
|
|
6919
6922
|
...telemetry.usage ? { usage: telemetry.usage } : {},
|
|
6920
6923
|
...model ? { model } : {},
|
|
6921
6924
|
...runtimeSessionId ? { runtimeSessionId } : {},
|
|
6922
|
-
...
|
|
6925
|
+
...errorMessage2 ? { errorMessage: errorMessage2 } : {},
|
|
6923
6926
|
// 跑在哪个镜像上要落账:同一题换了镜像,分数就不可比(ADR-0147 M5)
|
|
6924
6927
|
...containerized?.imageDigest ? { imageDigest: containerized.imageDigest } : {}
|
|
6925
6928
|
});
|
|
@@ -8239,8 +8242,8 @@ function classifyHermesPromptFailure(turn) {
|
|
|
8239
8242
|
if (errors.length === 0 && !failedSentence && !silent) return void 0;
|
|
8240
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)}`);
|
|
8241
8244
|
}
|
|
8242
|
-
function failure(
|
|
8243
|
-
return { reason: QUOTA_RE.test(
|
|
8245
|
+
function failure(errorMessage2) {
|
|
8246
|
+
return { reason: QUOTA_RE.test(errorMessage2) ? "rate-limit" : "error", errorMessage: errorMessage2 };
|
|
8244
8247
|
}
|
|
8245
8248
|
function promptResultHasUsage(result) {
|
|
8246
8249
|
if (typeof result !== "object" || result === null) return false;
|
|
@@ -9003,12 +9006,12 @@ async function runStreamJson(job, cfg) {
|
|
|
9003
9006
|
child.on("exit", (code2) => {
|
|
9004
9007
|
clearTimeout(timer);
|
|
9005
9008
|
const isError = !killReason && typeof code2 === "number" && code2 !== 0;
|
|
9006
|
-
const
|
|
9009
|
+
const errorMessage2 = isError ? stderrTail2.join("\n").trim().slice(-4e3) || void 0 : void 0;
|
|
9007
9010
|
finish({
|
|
9008
9011
|
code: killReason ? null : code2,
|
|
9009
9012
|
reason: killReason ?? (code2 === 0 ? "clean" : "error"),
|
|
9010
9013
|
transcriptRef: transcriptRefPtr.value,
|
|
9011
|
-
...
|
|
9014
|
+
...errorMessage2 ? { errorMessage: errorMessage2 } : {},
|
|
9012
9015
|
// ADR-0147:容器化会话带上镜像 digest(可复现凭据)。
|
|
9013
9016
|
...containerized?.imageDigest ? { imageDigest: containerized.imageDigest } : {}
|
|
9014
9017
|
});
|
|
@@ -9106,12 +9109,12 @@ async function runOneShotText(job, cfg) {
|
|
|
9106
9109
|
child.on("exit", (code2) => {
|
|
9107
9110
|
clearTimeout(timer);
|
|
9108
9111
|
const isError = !killReason && typeof code2 === "number" && code2 !== 0;
|
|
9109
|
-
const
|
|
9112
|
+
const errorMessage2 = isError ? stderrTail2.join("\n").trim().slice(-4e3) || void 0 : void 0;
|
|
9110
9113
|
finish({
|
|
9111
9114
|
code: killReason ? null : code2,
|
|
9112
9115
|
reason: killReason ?? (code2 === 0 ? "clean" : "error"),
|
|
9113
9116
|
transcriptRef: transcriptRefPtr.value,
|
|
9114
|
-
...
|
|
9117
|
+
...errorMessage2 ? { errorMessage: errorMessage2 } : {},
|
|
9115
9118
|
// ADR-0147:容器化会话带上镜像 digest(可复现凭据)。
|
|
9116
9119
|
...containerized?.imageDigest ? { imageDigest: containerized.imageDigest } : {}
|
|
9117
9120
|
});
|
|
@@ -10496,6 +10499,9 @@ var init_chat_item_ledger = __esm({
|
|
|
10496
10499
|
finished = false;
|
|
10497
10500
|
/** 上一次见到的归一层 turnId——变了就清映射(provider 开了新 turn)。 */
|
|
10498
10501
|
lastTurnId = null;
|
|
10502
|
+
/** 本账本已经落库的 user 行(按落库顺序)。{@link onUserItemPersisted} 的晚到订阅者从这里补。 */
|
|
10503
|
+
persistedUserItems = [];
|
|
10504
|
+
userItemListeners = /* @__PURE__ */ new Set();
|
|
10499
10505
|
/** 会话逻辑时钟走一格。**唯一发号点**(ADR-0510 附录 A.4)——别在别处自己数。 */
|
|
10500
10506
|
tick() {
|
|
10501
10507
|
return ++this.clock;
|
|
@@ -10513,6 +10519,37 @@ var init_chat_item_ledger = __esm({
|
|
|
10513
10519
|
const row = this.rows.get(itemId);
|
|
10514
10520
|
return row ? { createdAt: row.createdAt, completedAt: row.completedAt } : void 0;
|
|
10515
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
|
+
}
|
|
10516
10553
|
get failures() {
|
|
10517
10554
|
return this.failureCount;
|
|
10518
10555
|
}
|
|
@@ -10777,6 +10814,9 @@ var init_chat_item_ledger = __esm({
|
|
|
10777
10814
|
/**
|
|
10778
10815
|
* 切段(人中途插入):此刻起建的 item 属于**下一条** assistant 行。
|
|
10779
10816
|
* 已有 provider item 保留身份与位置;新 item 才归下一段,迟到快照不能复制旧块。
|
|
10817
|
+
*
|
|
10818
|
+
* 返回新段的段号。那条 assistant 行落库后回填归属时**必须带上它**({@link bindMessage}):
|
|
10819
|
+
* 行是异步落库的,回填到达时后面可能已经又切过段。
|
|
10780
10820
|
*/
|
|
10781
10821
|
beginSegment() {
|
|
10782
10822
|
if (this.segmentEndEmitted) {
|
|
@@ -10788,6 +10828,7 @@ var init_chat_item_ledger = __esm({
|
|
|
10788
10828
|
this.messageId = null;
|
|
10789
10829
|
this.segment += 1;
|
|
10790
10830
|
this.segmentItemCount = 0;
|
|
10831
|
+
return this.segment;
|
|
10791
10832
|
}
|
|
10792
10833
|
/**
|
|
10793
10834
|
* 人插话时,先把「这一段到此为止」落定;**必须在那条 user 行之前调用**。
|
|
@@ -10824,15 +10865,31 @@ var init_chat_item_ledger = __esm({
|
|
|
10824
10865
|
payload: { code: "segment_end", note: SEGMENT_END_NOTE }
|
|
10825
10866
|
});
|
|
10826
10867
|
}
|
|
10827
|
-
/**
|
|
10828
|
-
|
|
10829
|
-
|
|
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 = [];
|
|
10830
10885
|
for (const row of this.rows.values()) {
|
|
10831
|
-
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);
|
|
10832
10889
|
}
|
|
10833
|
-
if (!this.persistEnabled) return;
|
|
10890
|
+
if (!this.persistEnabled || itemIds.length === 0) return;
|
|
10834
10891
|
this.enqueue(async () => {
|
|
10835
|
-
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);
|
|
10836
10893
|
}, "bindMessage");
|
|
10837
10894
|
}
|
|
10838
10895
|
/**
|
|
@@ -11018,17 +11075,27 @@ var init_chat_item_ledger = __esm({
|
|
|
11018
11075
|
version: writeVersion
|
|
11019
11076
|
});
|
|
11020
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
|
+
};
|
|
11021
11086
|
try {
|
|
11022
|
-
this.deps.onPersisted?.(
|
|
11023
|
-
itemId: id,
|
|
11024
|
-
ord: created.ord,
|
|
11025
|
-
version: writeVersion,
|
|
11026
|
-
role: input.role,
|
|
11027
|
-
text: input.text,
|
|
11028
|
-
payload: payload2
|
|
11029
|
-
});
|
|
11087
|
+
this.deps.onPersisted?.(info);
|
|
11030
11088
|
} catch {
|
|
11031
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
|
+
}
|
|
11032
11099
|
}, `create:${input.kind}`);
|
|
11033
11100
|
return id;
|
|
11034
11101
|
}
|
|
@@ -11216,6 +11283,46 @@ async function finalizeAssistantRow(deps) {
|
|
|
11216
11283
|
} catch {
|
|
11217
11284
|
}
|
|
11218
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
|
+
}
|
|
11219
11326
|
function outputsPartProvider(scan2, chatSessionId, companyId) {
|
|
11220
11327
|
if (!scan2) return void 0;
|
|
11221
11328
|
return async () => {
|
|
@@ -11307,6 +11414,8 @@ function runBackgroundAssistantChatTurn(deps) {
|
|
|
11307
11414
|
chatStore: deps.chatStore,
|
|
11308
11415
|
chatSessionId: deps.chatSessionId,
|
|
11309
11416
|
...runId ? { runId } : {},
|
|
11417
|
+
// 与 `/api/chat` 同口径(ADR 0300 I1):消息行带这一轮的 `chat_session_turns.id`。此前后台轮不带。
|
|
11418
|
+
...deps.turnId ? { turnId: deps.turnId } : {},
|
|
11310
11419
|
now
|
|
11311
11420
|
});
|
|
11312
11421
|
const itemLedger = new ChatItemLedger({
|
|
@@ -11339,9 +11448,34 @@ function runBackgroundAssistantChatTurn(deps) {
|
|
|
11339
11448
|
);
|
|
11340
11449
|
const localParts = [];
|
|
11341
11450
|
let localSeq = 0;
|
|
11342
|
-
|
|
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 = [];
|
|
11343
11455
|
let checkpointChain = Promise.resolve();
|
|
11344
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
|
+
}
|
|
11345
11479
|
normalizedSource.onNormalizedProviderEvent((event) => {
|
|
11346
11480
|
try {
|
|
11347
11481
|
if (liveTurn) liveTurn.applyNormalizedEvent(event);
|
|
@@ -11369,11 +11503,12 @@ function runBackgroundAssistantChatTurn(deps) {
|
|
|
11369
11503
|
let ckptTimer = null;
|
|
11370
11504
|
if (checkpointMs > 0 && assistantMsgId) {
|
|
11371
11505
|
ckptTimer = setInterval(() => {
|
|
11372
|
-
if (!ckptDirty) return;
|
|
11506
|
+
if (!ckptDirty || !currentMsgId) return;
|
|
11373
11507
|
ckptDirty = false;
|
|
11374
11508
|
const parts = collectedParts();
|
|
11375
11509
|
const content3 = itemLedger.projectContent();
|
|
11376
|
-
|
|
11510
|
+
const target = currentMsgId;
|
|
11511
|
+
checkpointChain = checkpointChain.then(() => deps.chatStore.updateMessage(target, {
|
|
11377
11512
|
content: content3,
|
|
11378
11513
|
status: "running",
|
|
11379
11514
|
...parts.length ? { parts } : {}
|
|
@@ -11393,11 +11528,13 @@ function runBackgroundAssistantChatTurn(deps) {
|
|
|
11393
11528
|
await finalizeAssistantRow({
|
|
11394
11529
|
chatStore: deps.chatStore,
|
|
11395
11530
|
chatSessionId: deps.chatSessionId,
|
|
11396
|
-
|
|
11531
|
+
// 插话切过段就收最后一段那一行;前面各段在切段时已转 done。
|
|
11532
|
+
assistantMsgId: currentMsgId,
|
|
11397
11533
|
content: projectedContent,
|
|
11398
11534
|
parts,
|
|
11399
11535
|
status,
|
|
11400
11536
|
...runId ? { runId } : {},
|
|
11537
|
+
...deps.turnId ? { turnId: deps.turnId } : {},
|
|
11401
11538
|
...deps.outputsPart ? { outputsPart: deps.outputsPart } : {},
|
|
11402
11539
|
now
|
|
11403
11540
|
});
|
|
@@ -11413,7 +11550,8 @@ function runBackgroundAssistantChatTurn(deps) {
|
|
|
11413
11550
|
}
|
|
11414
11551
|
}
|
|
11415
11552
|
if (liveTurn) {
|
|
11416
|
-
|
|
11553
|
+
const turnText = [...closedSegmentsText, projectedContent].join("");
|
|
11554
|
+
if (turnText) liveTurn.emit({ type: "text", text: turnText });
|
|
11417
11555
|
liveTurn.emitLive({
|
|
11418
11556
|
protocolVersion: 2,
|
|
11419
11557
|
streamId: `background:${deps.chatSessionId}`,
|
|
@@ -11421,7 +11559,7 @@ function runBackgroundAssistantChatTurn(deps) {
|
|
|
11421
11559
|
itemId: `background:${assistantMsgId ?? runId}`,
|
|
11422
11560
|
itemType: "message",
|
|
11423
11561
|
operation: "completed",
|
|
11424
|
-
payload: { role: "assistant", text:
|
|
11562
|
+
payload: { role: "assistant", text: turnText }
|
|
11425
11563
|
});
|
|
11426
11564
|
}
|
|
11427
11565
|
try {
|
|
@@ -11895,11 +12033,11 @@ function decryptFeishu(encrypt, encryptKey) {
|
|
|
11895
12033
|
function decodeBody(body2, encryptKey) {
|
|
11896
12034
|
if (typeof body2 !== "object" || body2 === null) return null;
|
|
11897
12035
|
const rec = body2;
|
|
11898
|
-
const
|
|
11899
|
-
if (typeof
|
|
12036
|
+
const enc3 = rec["encrypt"];
|
|
12037
|
+
if (typeof enc3 === "string") {
|
|
11900
12038
|
if (!encryptKey) return null;
|
|
11901
12039
|
try {
|
|
11902
|
-
const parsed = JSON.parse(decryptFeishu(
|
|
12040
|
+
const parsed = JSON.parse(decryptFeishu(enc3, encryptKey));
|
|
11903
12041
|
return typeof parsed === "object" && parsed !== null ? parsed : null;
|
|
11904
12042
|
} catch {
|
|
11905
12043
|
return null;
|
|
@@ -125218,6 +125356,90 @@ var init_state = __esm({
|
|
|
125218
125356
|
}
|
|
125219
125357
|
});
|
|
125220
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
|
+
|
|
125221
125443
|
// ../engine/src/letters.ts
|
|
125222
125444
|
function repliesSorted(state, issueId) {
|
|
125223
125445
|
return [...state.repliesOf(issueId)].sort((a, b2) => a.createdAt.localeCompare(b2.createdAt));
|
|
@@ -125592,8 +125814,17 @@ function scan(state, ctx) {
|
|
|
125592
125814
|
continue;
|
|
125593
125815
|
}
|
|
125594
125816
|
}
|
|
125595
|
-
const
|
|
125596
|
-
|
|
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 };
|
|
125597
125828
|
}
|
|
125598
125829
|
function checkRunningWorkTimeout(state, node2, work, ctx, events) {
|
|
125599
125830
|
const start = work.lastActivityAt ?? work.startedAt ?? work.createdAt;
|
|
@@ -125684,6 +125915,18 @@ function scanBlockersForNode(state, node2, latest) {
|
|
|
125684
125915
|
}
|
|
125685
125916
|
return blockers;
|
|
125686
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
|
+
}
|
|
125687
125930
|
function tryToRun(state, nodeId, ctx, events) {
|
|
125688
125931
|
const node2 = state.node(nodeId);
|
|
125689
125932
|
if (!node2) return;
|
|
@@ -125709,15 +125952,6 @@ function tryToRun(state, nodeId, ctx, events) {
|
|
|
125709
125952
|
}
|
|
125710
125953
|
return;
|
|
125711
125954
|
}
|
|
125712
|
-
const inbound = state.edgesInto(nodeId);
|
|
125713
|
-
for (const e of inbound) {
|
|
125714
|
-
if (e.kind !== "data" || !e.required) continue;
|
|
125715
|
-
if (isEdgeInputUnobtainable(state, e)) continue;
|
|
125716
|
-
const upstream = state.node(e.fromNodeId);
|
|
125717
|
-
if (!upstream?.latestAcceptId) return;
|
|
125718
|
-
if (isBusinessDependencyEdge(state, e) && !businessHandoffBarrierSatisfied(state, upstream.id, upstream.latestAcceptId)) return;
|
|
125719
|
-
}
|
|
125720
|
-
if (findUnstableRequiredUpstream(state, nodeId, events)) return;
|
|
125721
125955
|
if (state.hasQueuedWorkFor(nodeId)) return;
|
|
125722
125956
|
const workId = deriveWorkId(nodeId, state.allWorksIncludingReplies(nodeId).length + 1);
|
|
125723
125957
|
const letters = pendingLetters(state, node2);
|
|
@@ -125733,6 +125967,8 @@ function tryToRun(state, nodeId, ctx, events) {
|
|
|
125733
125967
|
if (deliveredNow.has(g2.id)) continue;
|
|
125734
125968
|
reasons.push({ kind: "issue", issueId: g2.id, issueKind: g2.kind });
|
|
125735
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;
|
|
125736
125972
|
events.push({
|
|
125737
125973
|
kind: "work.create",
|
|
125738
125974
|
workorderId: state.workorder.id,
|
|
@@ -125882,59 +126118,6 @@ function collectStallTrips(state, node2, ctx) {
|
|
|
125882
126118
|
}
|
|
125883
126119
|
return out;
|
|
125884
126120
|
}
|
|
125885
|
-
function inputsMatch(state, node2, latestWork) {
|
|
125886
|
-
const inbound = state.edgesInto(node2.id);
|
|
125887
|
-
const currInputs = new Set(
|
|
125888
|
-
inbound.filter((e) => e.kind === "data" && e.pinnedWorkId).map((e) => e.pinnedWorkId)
|
|
125889
|
-
);
|
|
125890
|
-
const latestInputs = new Set(state.workInputsOf(latestWork.id).map((i) => i.upstreamWorkId));
|
|
125891
|
-
return currInputs.size === latestInputs.size && [...currInputs].every((x2) => latestInputs.has(x2));
|
|
125892
|
-
}
|
|
125893
|
-
function findUnstableRequiredUpstream(state, nodeId, pendingEvents = []) {
|
|
125894
|
-
const memo = /* @__PURE__ */ new Map();
|
|
125895
|
-
const visiting = /* @__PURE__ */ new Set();
|
|
125896
|
-
const mayStillChange2 = (candidateId) => {
|
|
125897
|
-
const cached3 = memo.get(candidateId);
|
|
125898
|
-
if (cached3 !== void 0) return cached3;
|
|
125899
|
-
if (visiting.has(candidateId)) return true;
|
|
125900
|
-
visiting.add(candidateId);
|
|
125901
|
-
const candidate = state.node(candidateId);
|
|
125902
|
-
let unstable = false;
|
|
125903
|
-
if (!candidate) {
|
|
125904
|
-
unstable = true;
|
|
125905
|
-
} else if (candidate.cancelledAt && candidate.latestAcceptId) {
|
|
125906
|
-
unstable = false;
|
|
125907
|
-
} else if (!candidate.latestAcceptId) {
|
|
125908
|
-
unstable = true;
|
|
125909
|
-
} else {
|
|
125910
|
-
const accepted = state.work(candidate.latestAcceptId);
|
|
125911
|
-
if (!accepted || accepted.nodeVersion !== candidate.version || !inputsMatch(state, candidate, accepted)) {
|
|
125912
|
-
unstable = true;
|
|
125913
|
-
} else {
|
|
125914
|
-
const acceptedIsCurrent = candidate.latestAcceptId === candidate.latestWorkId || candidate.latestAcceptId === candidate.latestProposedWorkId;
|
|
125915
|
-
const queuedThisScan = pendingEvents.some((event) => event.kind === "work.create" && event.nodeId === candidateId);
|
|
125916
|
-
unstable = !acceptedIsCurrent || state.hasQueuedWorkFor(candidateId) || queuedThisScan;
|
|
125917
|
-
}
|
|
125918
|
-
if (!unstable) {
|
|
125919
|
-
for (const edge of state.edgesInto(candidateId)) {
|
|
125920
|
-
if (edge.kind !== "data" || !edge.required || isEdgeInputUnobtainable(state, edge)) continue;
|
|
125921
|
-
if (mayStillChange2(edge.fromNodeId)) {
|
|
125922
|
-
unstable = true;
|
|
125923
|
-
break;
|
|
125924
|
-
}
|
|
125925
|
-
}
|
|
125926
|
-
}
|
|
125927
|
-
}
|
|
125928
|
-
visiting.delete(candidateId);
|
|
125929
|
-
memo.set(candidateId, unstable);
|
|
125930
|
-
return unstable;
|
|
125931
|
-
};
|
|
125932
|
-
for (const edge of state.edgesInto(nodeId)) {
|
|
125933
|
-
if (edge.kind !== "data" || !edge.required || isEdgeInputUnobtainable(state, edge)) continue;
|
|
125934
|
-
if (mayStillChange2(edge.fromNodeId)) return edge.fromNodeId;
|
|
125935
|
-
}
|
|
125936
|
-
return null;
|
|
125937
|
-
}
|
|
125938
126121
|
function reviewMaxRetriesOf(policy) {
|
|
125939
126122
|
const act = policy.resolve({ executor: "agent", scenario: "review" }).timeoutAction;
|
|
125940
126123
|
return act.kind === "kill-rebuild" ? act.maxRetries : AGENT_REVIEW_MAX_RETRIES;
|
|
@@ -126096,10 +126279,6 @@ function mergedClosureRequirements(state, nodeId, closureActors) {
|
|
|
126096
126279
|
const kept = state.requirementsOf(nodeId).filter((r) => r.source !== "closure").map((r) => ({ reviewerActorId: r.reviewerActorId, reviewGroup: r.reviewGroup, source: r.source }));
|
|
126097
126280
|
return [...kept, ...closureReviewerSpecs(wantedClosureActors(state, nodeId, closureActors))];
|
|
126098
126281
|
}
|
|
126099
|
-
function isEdgeInputUnobtainable(state, edge) {
|
|
126100
|
-
const upstream = state.node(edge.fromNodeId);
|
|
126101
|
-
return !!upstream?.cancelledAt && !upstream.latestAcceptId;
|
|
126102
|
-
}
|
|
126103
126282
|
function isBusinessDependencyEdge(state, edge) {
|
|
126104
126283
|
const downstream = state.node(edge.toNodeId);
|
|
126105
126284
|
return edge.kind === "data" && edge.required && downstream?.fields?.[BUSINESS_HANDOFF_POLICY_FIELD] !== BUSINESS_HANDOFF_POLICY_EXEMPT;
|
|
@@ -126206,6 +126385,8 @@ function assessConvergence(state, ctx) {
|
|
|
126206
126385
|
var init_activate = __esm({
|
|
126207
126386
|
"../engine/src/activate.ts"() {
|
|
126208
126387
|
"use strict";
|
|
126388
|
+
init_upstream_stability();
|
|
126389
|
+
init_upstream_stability();
|
|
126209
126390
|
init_continuation();
|
|
126210
126391
|
init_src4();
|
|
126211
126392
|
init_src5();
|
|
@@ -130097,7 +130278,7 @@ var require_split2 = __commonJS({
|
|
|
130097
130278
|
var { StringDecoder } = require("string_decoder");
|
|
130098
130279
|
var kLast = Symbol("last");
|
|
130099
130280
|
var kDecoder = Symbol("decoder");
|
|
130100
|
-
function transform2(chunk,
|
|
130281
|
+
function transform2(chunk, enc3, cb) {
|
|
130101
130282
|
let list2;
|
|
130102
130283
|
if (this.overflow) {
|
|
130103
130284
|
const buf = this[kDecoder].write(chunk);
|
|
@@ -132713,7 +132894,9 @@ var init_store_postgres = __esm({
|
|
|
132713
132894
|
WHERE (
|
|
132714
132895
|
(e.status = 'pending' AND (e.available_at IS NULL OR e.available_at <= $1))
|
|
132715
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
|
|
132716
|
-
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)))
|
|
132717
132900
|
)
|
|
132718
132901
|
AND NOT EXISTS (
|
|
132719
132902
|
SELECT 1 FROM ${this.s}.events p
|
|
@@ -132730,13 +132913,23 @@ var init_store_postgres = __esm({
|
|
|
132730
132913
|
async markEvent(seq, status, failedReason, at) {
|
|
132731
132914
|
await this.c.query(
|
|
132732
132915
|
`UPDATE ${this.s}.events
|
|
132733
|
-
SET status = $2, failed_reason = $3,
|
|
132916
|
+
SET status = $2, failed_reason = $3, available_at = NULL,
|
|
132734
132917
|
applied_at = CASE WHEN $2 = 'applied' THEN $4::timestamptz ELSE applied_at END,
|
|
132735
132918
|
done_at = CASE WHEN $2 = 'done' THEN $4::timestamptz ELSE done_at END
|
|
132736
132919
|
WHERE seq = $1`,
|
|
132737
132920
|
[seq, status, failedReason, at]
|
|
132738
132921
|
);
|
|
132739
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
|
+
}
|
|
132740
132933
|
async isHandlerDone(seq, handlerName) {
|
|
132741
132934
|
const res = await this.c.query(
|
|
132742
132935
|
`SELECT 1 FROM ${this.s}.event_handler_log WHERE event_seq = $1 AND handler_name = $2`,
|
|
@@ -132770,7 +132963,9 @@ var init_store_postgres = __esm({
|
|
|
132770
132963
|
WHERE (
|
|
132771
132964
|
(e.status = 'pending' AND (e.available_at IS NULL OR e.available_at <= $1))
|
|
132772
132965
|
-- \u5D29\u6E83\u81EA\u6108\uFF1A\u89C1 claimNextEvent \u7684\u6CE8\u91CA
|
|
132773
|
-
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)))
|
|
132774
132969
|
)
|
|
132775
132970
|
AND NOT EXISTS (SELECT 1 FROM ${this.s}.events p WHERE p.workorder_id = e.workorder_id
|
|
132776
132971
|
AND p.status IN ('pending','applied') AND p.seq < e.seq)
|
|
@@ -133153,12 +133348,29 @@ var init_plan = __esm({
|
|
|
133153
133348
|
});
|
|
133154
133349
|
|
|
133155
133350
|
// ../engine/src/handlers/workorder.ts
|
|
133156
|
-
var workorderCreate, workorderMeta, workorderPause, workorderResume, workorderPing;
|
|
133351
|
+
var workorderInitialize, workorderCreate, workorderMeta, workorderPause, workorderResume, workorderPing;
|
|
133157
133352
|
var init_workorder = __esm({
|
|
133158
133353
|
"../engine/src/handlers/workorder.ts"() {
|
|
133159
133354
|
"use strict";
|
|
133160
133355
|
init_kill();
|
|
133161
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
|
+
};
|
|
133162
133374
|
workorderCreate = {
|
|
133163
133375
|
name: "workorder/create",
|
|
133164
133376
|
kind: "workorder.created",
|
|
@@ -133195,6 +133407,7 @@ var init_workorder = __esm({
|
|
|
133195
133407
|
workorderPause = {
|
|
133196
133408
|
name: "workorder/pause",
|
|
133197
133409
|
kind: "workorder.paused",
|
|
133410
|
+
retryFailedEffect: true,
|
|
133198
133411
|
apply(e, state, ctx) {
|
|
133199
133412
|
state.updateWorkorder({ dispatchPaused: true, pausedBy: e.by, pausedReason: e.reason, updatedAt: ctx.at });
|
|
133200
133413
|
killAllWorks(state, ctx.at);
|
|
@@ -133240,6 +133453,7 @@ var workCreate, workRedispatch, workSnapshotRecorded, workKill, workResponse, wo
|
|
|
133240
133453
|
var init_work = __esm({
|
|
133241
133454
|
"../engine/src/handlers/work.ts"() {
|
|
133242
133455
|
"use strict";
|
|
133456
|
+
init_upstream_stability();
|
|
133243
133457
|
init_continuation();
|
|
133244
133458
|
init_views2();
|
|
133245
133459
|
init_kill();
|
|
@@ -133552,6 +133766,10 @@ var init_work = __esm({
|
|
|
133552
133766
|
apply(e, state, ctx) {
|
|
133553
133767
|
const w2 = state.work(e.workId);
|
|
133554
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
|
+
}
|
|
133555
133773
|
if (e.artifacts.length === 0 && w2.acceptanceState === "accepted" && state.artifactsOf(e.workId).length > 0) {
|
|
133556
133774
|
return;
|
|
133557
133775
|
}
|
|
@@ -134164,8 +134382,9 @@ var init_handlers = __esm({
|
|
|
134164
134382
|
init_continuation2();
|
|
134165
134383
|
init_types();
|
|
134166
134384
|
HANDLERS = [
|
|
134167
|
-
/* ── 工作区级(
|
|
134385
|
+
/* ── 工作区级(6)── */
|
|
134168
134386
|
erase(workorderCreate),
|
|
134387
|
+
erase(workorderInitialize),
|
|
134169
134388
|
erase(workorderMeta),
|
|
134170
134389
|
erase(workorderPause),
|
|
134171
134390
|
erase(workorderResume),
|
|
@@ -134218,6 +134437,7 @@ var init_handlers = __esm({
|
|
|
134218
134437
|
|
|
134219
134438
|
// ../engine/src/bus.ts
|
|
134220
134439
|
function versionCommandEvent(event) {
|
|
134440
|
+
if (event.kind === "work.submit_output") return { ...event, upstreamStabilityVersion: 1 };
|
|
134221
134441
|
if (event.kind === "work.create" || event.kind === "review.create") {
|
|
134222
134442
|
return { ...event, pauseGateVersion: 1, ...event.kind === "work.create" ? { continuationGateVersion: 1 } : {} };
|
|
134223
134443
|
}
|
|
@@ -134242,6 +134462,9 @@ function versionCommandEvent(event) {
|
|
|
134242
134462
|
return event;
|
|
134243
134463
|
}
|
|
134244
134464
|
}
|
|
134465
|
+
function errorMessage(err) {
|
|
134466
|
+
return err instanceof Error ? err.message : String(err);
|
|
134467
|
+
}
|
|
134245
134468
|
function emptySnapshotPlaceholder(record8) {
|
|
134246
134469
|
return {
|
|
134247
134470
|
workorder: {
|
|
@@ -134272,7 +134495,7 @@ function emptySnapshotPlaceholder(record8) {
|
|
|
134272
134495
|
reviews: []
|
|
134273
134496
|
};
|
|
134274
134497
|
}
|
|
134275
|
-
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;
|
|
134276
134499
|
var init_bus = __esm({
|
|
134277
134500
|
"../engine/src/bus.ts"() {
|
|
134278
134501
|
"use strict";
|
|
@@ -134282,6 +134505,7 @@ var init_bus = __esm({
|
|
|
134282
134505
|
init_model();
|
|
134283
134506
|
init_handlers();
|
|
134284
134507
|
init_state();
|
|
134508
|
+
init_upstream_stability();
|
|
134285
134509
|
init_continuation();
|
|
134286
134510
|
SYSTEM_ACTOR = "actor:system:engine";
|
|
134287
134511
|
NOOP_IO = {
|
|
@@ -134313,6 +134537,7 @@ var init_bus = __esm({
|
|
|
134313
134537
|
};
|
|
134314
134538
|
DEFAULT_STUCK_APPLIED_RECOVERY_MS = 5 * 6e4;
|
|
134315
134539
|
SETTLE_FOREIGN_PROGRESS_FALLBACK_MS = 200;
|
|
134540
|
+
EVENT_RETRY_DELAY_MS = 1e3;
|
|
134316
134541
|
EngineBus = class {
|
|
134317
134542
|
store;
|
|
134318
134543
|
io;
|
|
@@ -134472,6 +134697,7 @@ var init_bus = __esm({
|
|
|
134472
134697
|
if (!await this.drainOne()) break;
|
|
134473
134698
|
}
|
|
134474
134699
|
}
|
|
134700
|
+
await this.assertProcessed([seq]);
|
|
134475
134701
|
}
|
|
134476
134702
|
/** 同一命令的一组最终修改一起入队。scan-on-empty 在末项之前始终看到 pending,不能派发中间状态。 */
|
|
134477
134703
|
async submitBatchAndProcess(inputs) {
|
|
@@ -134498,6 +134724,17 @@ var init_bus = __esm({
|
|
|
134498
134724
|
} else {
|
|
134499
134725
|
for (let i = 0; i < 2e3; i++) if (!await this.drainOne()) break;
|
|
134500
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
|
+
});
|
|
134501
134738
|
}
|
|
134502
134739
|
/* ═══════════════════════ 调度器主循环 ═══════════════════════ */
|
|
134503
134740
|
/**
|
|
@@ -134547,8 +134784,7 @@ var init_bus = __esm({
|
|
|
134547
134784
|
}
|
|
134548
134785
|
touched.add(record8.workorderId);
|
|
134549
134786
|
try {
|
|
134550
|
-
await this.applyRecord(record8);
|
|
134551
|
-
await this.effectRecord(record8);
|
|
134787
|
+
if (await this.applyRecord(record8)) await this.effectRecord(record8);
|
|
134552
134788
|
} catch (err) {
|
|
134553
134789
|
console.error(`[bus] event ${record8.seq} ${record8.event.kind}:`, err);
|
|
134554
134790
|
}
|
|
@@ -134679,9 +134915,10 @@ var init_bus = __esm({
|
|
|
134679
134915
|
/* ═══════════════════════ 旧 drain(测试兼容) ═══════════════════════ */
|
|
134680
134916
|
/** 取一条事件 apply+effect,然后 scan 其工单。仅测试用——生产代码走 run() 循环。 */
|
|
134681
134917
|
async drainOne() {
|
|
134682
|
-
const
|
|
134683
|
-
if (!
|
|
134684
|
-
|
|
134918
|
+
const phase = await this.applyPhase();
|
|
134919
|
+
if (!phase) return false;
|
|
134920
|
+
const { record: record8, applied } = phase;
|
|
134921
|
+
if (applied) await this.effectPhase(record8);
|
|
134685
134922
|
this.emitEvents([record8]);
|
|
134686
134923
|
try {
|
|
134687
134924
|
const result = await this.scan(record8.workorderId);
|
|
@@ -134698,10 +134935,11 @@ var init_bus = __esm({
|
|
|
134698
134935
|
async drain(limit = 1e3) {
|
|
134699
134936
|
let processed = 0, failed = 0;
|
|
134700
134937
|
for (let i = 0; i < limit; i++) {
|
|
134701
|
-
const
|
|
134702
|
-
if (!
|
|
134938
|
+
const phase = await this.applyPhase();
|
|
134939
|
+
if (!phase) break;
|
|
134940
|
+
const { record: record8, applied } = phase;
|
|
134703
134941
|
processed++;
|
|
134704
|
-
const ok3 = await this.effectPhase(record8);
|
|
134942
|
+
const ok3 = applied && await this.effectPhase(record8);
|
|
134705
134943
|
if (!ok3) failed++;
|
|
134706
134944
|
this.emitEvents([record8]);
|
|
134707
134945
|
}
|
|
@@ -134713,7 +134951,7 @@ var init_bus = __esm({
|
|
|
134713
134951
|
* 公开方法,供 kernel-bridge 和 run() 共用。
|
|
134714
134952
|
*/
|
|
134715
134953
|
async applyRecord(record8) {
|
|
134716
|
-
await this.store.transaction(async (tx) => {
|
|
134954
|
+
const applied = await this.store.transaction(async (tx) => {
|
|
134717
134955
|
const snapshot = await tx.loadWorkorder(record8.workorderId);
|
|
134718
134956
|
const state = new WorkorderState(snapshot ?? emptySnapshotPlaceholder(record8));
|
|
134719
134957
|
const ctx = {
|
|
@@ -134722,10 +134960,15 @@ var init_bus = __esm({
|
|
|
134722
134960
|
actorId: record8.actorId,
|
|
134723
134961
|
config: this.config
|
|
134724
134962
|
};
|
|
134963
|
+
const completedHandlers = [];
|
|
134725
134964
|
for (const h of this.registry.for(record8.event.kind)) {
|
|
134726
134965
|
if (await tx.isHandlerDone(record8.seq, h.name)) continue;
|
|
134727
|
-
|
|
134728
|
-
|
|
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);
|
|
134729
134972
|
}
|
|
134730
134973
|
await tx.applyMutations(record8.workorderId, state.mutations);
|
|
134731
134974
|
if (state.emitted.length) {
|
|
@@ -134742,20 +134985,28 @@ var init_bus = __esm({
|
|
|
134742
134985
|
...eventAnchors(event)
|
|
134743
134986
|
})));
|
|
134744
134987
|
}
|
|
134988
|
+
for (const name of completedHandlers) await tx.markHandlerDone(record8.seq, name);
|
|
134745
134989
|
await tx.markEvent(record8.seq, "applied", null, this.clock.now());
|
|
134990
|
+
return true;
|
|
134746
134991
|
}).catch(async (err) => {
|
|
134747
|
-
|
|
134748
|
-
|
|
134749
|
-
|
|
134750
|
-
|
|
134751
|
-
|
|
134752
|
-
}
|
|
134753
|
-
|
|
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;
|
|
134754
134999
|
});
|
|
134755
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();
|
|
134756
135006
|
}
|
|
134757
135007
|
/** 事务二:跑 IO + 收尾。 */
|
|
134758
135008
|
async effectRecord(record8) {
|
|
135009
|
+
if (record8.status !== "applied") return false;
|
|
134759
135010
|
const handlers = this.registry.for(record8.event.kind).filter((h) => h.effect);
|
|
134760
135011
|
const buffered = [];
|
|
134761
135012
|
const ctx = {
|
|
@@ -134767,32 +135018,53 @@ var init_bus = __esm({
|
|
|
134767
135018
|
dispatchReview: (id, nodeId, reviewerActorId) => this.io.dispatchReview(id, nodeId, reviewerActorId),
|
|
134768
135019
|
canDispatchWork: async (workorderId, workId, opts) => {
|
|
134769
135020
|
const snap = await this.store.transaction((tx) => tx.loadWorkorder(workorderId));
|
|
134770
|
-
if (!snap || snap.workorder.dispatchPaused) return false;
|
|
135021
|
+
if (!snap || snap.workorder.lifecycle !== "active" || snap.workorder.dispatchPaused) return false;
|
|
134771
135022
|
const work = snap.works.find((row) => row.id === workId);
|
|
134772
135023
|
if (work && work.lane === "main" && !work.startedAt && !work.sessionRef && !work.lastActivityAt) {
|
|
134773
|
-
const
|
|
134774
|
-
if (
|
|
135024
|
+
const node3 = snap.nodes.find((row) => row.id === work.nodeId);
|
|
135025
|
+
if (node3 && !node3.continuationBudget && this.io.continuationPolicy) {
|
|
134775
135026
|
const policy = await this.io.continuationPolicy(work.assigneeActorId);
|
|
134776
135027
|
if (policy) {
|
|
134777
135028
|
if (!Number.isSafeInteger(policy.maxRounds) || policy.maxRounds < 1 || policy.maxRounds > 100) {
|
|
134778
135029
|
throw new Error(`invalid continuation round limit for ${work.assigneeActorId}`);
|
|
134779
135030
|
}
|
|
134780
|
-
buffered.push({ event: { kind: "continuation.initialized", workorderId, nodeId:
|
|
135031
|
+
buffered.push({ event: { kind: "continuation.initialized", workorderId, nodeId: node3.id, rounds: policy.maxRounds } });
|
|
134781
135032
|
buffered.push({ event: { kind: "work.redispatch", workorderId, workId } });
|
|
134782
135033
|
return false;
|
|
134783
135034
|
}
|
|
134784
135035
|
}
|
|
134785
|
-
if (
|
|
135036
|
+
if (node3 && continuationExhausted(new WorkorderState(snap), node3)) return false;
|
|
134786
135037
|
}
|
|
134787
135038
|
if (opts?.neverStarted && work) {
|
|
134788
|
-
const
|
|
134789
|
-
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;
|
|
135041
|
+
}
|
|
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
|
+
}
|
|
134790
135062
|
}
|
|
134791
|
-
return
|
|
135063
|
+
return true;
|
|
134792
135064
|
},
|
|
134793
135065
|
canDispatchReview: async (workorderId, reviewId) => {
|
|
134794
135066
|
const snap = await this.store.transaction((tx) => tx.loadWorkorder(workorderId));
|
|
134795
|
-
if (!snap || snap.workorder.dispatchPaused) return false;
|
|
135067
|
+
if (!snap || snap.workorder.lifecycle !== "active" || snap.workorder.dispatchPaused) return false;
|
|
134796
135068
|
const review = snap.reviews.find((row) => row.id === reviewId);
|
|
134797
135069
|
return review?.status === "running" && !review.cancelledAt && !review.endedAt;
|
|
134798
135070
|
},
|
|
@@ -134809,19 +135081,14 @@ var init_bus = __esm({
|
|
|
134809
135081
|
// apply 已把被杀 work/review 置 deadAt/cancelledAt,这里按 store 找它们仍挂着的会话 cancel
|
|
134810
135082
|
//(deadAt 且 endedAt 未置 = 刚被杀未退出的在途会话)。没会话 / 已退 → no-op。
|
|
134811
135083
|
cancelKilledSessions: async (_workorderId, reviewScope) => {
|
|
134812
|
-
|
|
134813
|
-
try {
|
|
134814
|
-
snap = await this.store.transaction((tx) => tx.loadWorkorder(record8.workorderId));
|
|
134815
|
-
} catch (err) {
|
|
134816
|
-
console.warn(`[bus] cancelKilledSessions ${record8.workorderId} \u8BFB\u5FEB\u7167\u5931\u8D25: ${String(err)}`);
|
|
134817
|
-
return;
|
|
134818
|
-
}
|
|
135084
|
+
const snap = await this.store.transaction((tx) => tx.loadWorkorder(record8.workorderId));
|
|
134819
135085
|
if (!snap) return;
|
|
135086
|
+
const failures = [];
|
|
134820
135087
|
const cancel = async (id, what) => {
|
|
134821
135088
|
try {
|
|
134822
135089
|
await this.io.cancelSession(id);
|
|
134823
135090
|
} catch (err) {
|
|
134824
|
-
|
|
135091
|
+
failures.push(`${what} ${id}: ${errorMessage(err)}`);
|
|
134825
135092
|
}
|
|
134826
135093
|
};
|
|
134827
135094
|
for (const w2 of reviewScope === void 0 ? snap.works : []) {
|
|
@@ -134833,10 +135100,12 @@ var init_bus = __esm({
|
|
|
134833
135100
|
))) continue;
|
|
134834
135101
|
if (r.cancelledAt && r.endedAt === null) await cancel(r.id, "review");
|
|
134835
135102
|
}
|
|
135103
|
+
if (failures.length) throw new Error(`session cancellation incomplete: ${failures.join("; ")}`);
|
|
134836
135104
|
},
|
|
134837
135105
|
notify: (ids2, payload2) => this.io.notify(ids2, payload2)
|
|
134838
135106
|
};
|
|
134839
135107
|
let ok3 = true;
|
|
135108
|
+
let failureReason = null;
|
|
134840
135109
|
for (const h of handlers) {
|
|
134841
135110
|
const effectKey = `${h.name}#effect`;
|
|
134842
135111
|
if (record8.appliedAt && await this.store.transaction((tx) => tx.isHandlerDone(record8.seq, effectKey))) {
|
|
@@ -134844,6 +135113,7 @@ var init_bus = __esm({
|
|
|
134844
135113
|
}
|
|
134845
135114
|
let lastErr = "";
|
|
134846
135115
|
for (let attempt = 1; attempt <= this.maxEffectAttempts; attempt++) {
|
|
135116
|
+
buffered.length = 0;
|
|
134847
135117
|
try {
|
|
134848
135118
|
await h.effect(record8.event, ctx);
|
|
134849
135119
|
lastErr = "";
|
|
@@ -134854,27 +135124,30 @@ var init_bus = __esm({
|
|
|
134854
135124
|
}
|
|
134855
135125
|
if (lastErr) {
|
|
134856
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;
|
|
134857
135132
|
} else {
|
|
134858
|
-
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
|
+
});
|
|
134859
135148
|
}
|
|
134860
135149
|
}
|
|
134861
|
-
await this.store.transaction(
|
|
134862
|
-
if (buffered.length) {
|
|
134863
|
-
await tx.appendEvents(buffered.map((b2) => ({
|
|
134864
|
-
companyId: record8.companyId,
|
|
134865
|
-
workorderId: record8.workorderId,
|
|
134866
|
-
actorId: b2.actorId ?? SYSTEM_ACTOR,
|
|
134867
|
-
handActorId: null,
|
|
134868
|
-
event: versionCommandEvent(b2.event),
|
|
134869
|
-
causedBySeq: record8.seq,
|
|
134870
|
-
origin: "effect",
|
|
134871
|
-
dedupKey: b2.dedupKey ?? null,
|
|
134872
|
-
createdAt: this.clock.now(),
|
|
134873
|
-
...eventAnchors(b2.event)
|
|
134874
|
-
})));
|
|
134875
|
-
}
|
|
134876
|
-
await tx.markEvent(record8.seq, "done", null, this.clock.now());
|
|
134877
|
-
});
|
|
135150
|
+
await this.store.transaction((tx) => tx.markEvent(record8.seq, "done", failureReason, this.clock.now()));
|
|
134878
135151
|
return ok3;
|
|
134879
135152
|
}
|
|
134880
135153
|
/* ═══════════════════════ scan:唯一的调度入口 ═══════════════════════ */
|
|
@@ -134940,57 +135213,10 @@ var init_bus = __esm({
|
|
|
134940
135213
|
}
|
|
134941
135214
|
/* ═══════════════════════ 内部:旧 applyPhase(claim + apply 一体) ═══════════════════════ */
|
|
134942
135215
|
async applyPhase() {
|
|
134943
|
-
|
|
134944
|
-
|
|
134945
|
-
|
|
134946
|
-
|
|
134947
|
-
if (snapshot?.workorder.doneAt && record8.event.kind !== "work.content_edited") {
|
|
134948
|
-
await tx.applyMutations(record8.workorderId, [{
|
|
134949
|
-
t: "workorder.update",
|
|
134950
|
-
patch: { doneAt: null }
|
|
134951
|
-
}]);
|
|
134952
|
-
}
|
|
134953
|
-
const state = new WorkorderState(snapshot ?? emptySnapshotPlaceholder(record8));
|
|
134954
|
-
const ctx = {
|
|
134955
|
-
seq: record8.seq,
|
|
134956
|
-
at: record8.createdAt,
|
|
134957
|
-
actorId: record8.actorId,
|
|
134958
|
-
config: this.config
|
|
134959
|
-
};
|
|
134960
|
-
for (const h of this.registry.for(record8.event.kind)) {
|
|
134961
|
-
if (await tx.isHandlerDone(record8.seq, h.name)) continue;
|
|
134962
|
-
h.apply(record8.event, state, ctx);
|
|
134963
|
-
await tx.markHandlerDone(record8.seq, h.name);
|
|
134964
|
-
}
|
|
134965
|
-
await tx.applyMutations(record8.workorderId, state.mutations);
|
|
134966
|
-
if (state.emitted.length) {
|
|
134967
|
-
await tx.appendEvents(state.emitted.map((event) => ({
|
|
134968
|
-
companyId: record8.companyId,
|
|
134969
|
-
workorderId: record8.workorderId,
|
|
134970
|
-
actorId: SYSTEM_ACTOR,
|
|
134971
|
-
handActorId: null,
|
|
134972
|
-
event: versionCommandEvent(event),
|
|
134973
|
-
causedBySeq: record8.seq,
|
|
134974
|
-
origin: "apply",
|
|
134975
|
-
dedupKey: null,
|
|
134976
|
-
createdAt: record8.createdAt,
|
|
134977
|
-
...eventAnchors(event)
|
|
134978
|
-
})));
|
|
134979
|
-
}
|
|
134980
|
-
await tx.markEvent(record8.seq, "applied", null, this.clock.now());
|
|
134981
|
-
return record8;
|
|
134982
|
-
}).catch(async (err) => {
|
|
134983
|
-
if (err instanceof ApplyFailure) {
|
|
134984
|
-
await this.store.transaction(
|
|
134985
|
-
(tx) => tx.markEvent(err.record.seq, "failed", err.reason, this.clock.now())
|
|
134986
|
-
);
|
|
134987
|
-
return err.record;
|
|
134988
|
-
}
|
|
134989
|
-
throw err;
|
|
134990
|
-
}).then((record8) => {
|
|
134991
|
-
if (record8) this.emitApplied(record8.workorderId);
|
|
134992
|
-
return record8;
|
|
134993
|
-
});
|
|
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) };
|
|
134994
135220
|
}
|
|
134995
135221
|
async effectPhase(record8) {
|
|
134996
135222
|
return this.effectRecord(record8);
|
|
@@ -135012,7 +135238,7 @@ var init_bus = __esm({
|
|
|
135012
135238
|
const events = await this.store.transaction((tx) => tx.listEvents(workorderId));
|
|
135013
135239
|
let state = null;
|
|
135014
135240
|
for (const record8 of events) {
|
|
135015
|
-
if (record8.origin === "effect") continue;
|
|
135241
|
+
if (record8.status === "failed" || record8.status === "pending" || record8.origin === "effect") continue;
|
|
135016
135242
|
if (!state) state = new WorkorderState(emptySnapshotPlaceholder(record8));
|
|
135017
135243
|
for (const h of this.registry.for(record8.event.kind)) {
|
|
135018
135244
|
h.apply(record8.event, state, {
|
|
@@ -139006,16 +139232,16 @@ function classifyExitReason(info) {
|
|
|
139006
139232
|
if (AUTH_RE.test(msg)) return "auth-error";
|
|
139007
139233
|
return info.reason;
|
|
139008
139234
|
}
|
|
139009
|
-
function quotaResetHorizon(
|
|
139010
|
-
if (!
|
|
139011
|
-
if (/\b(?:jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)[a-z]*\.?\s+\d{1,2}/i.test(
|
|
139012
|
-
if (/\d{4}-\d{2}-\d{2}/.test(
|
|
139013
|
-
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";
|
|
139014
139240
|
return "unknown";
|
|
139015
139241
|
}
|
|
139016
|
-
function extractResetHint(
|
|
139017
|
-
if (!
|
|
139018
|
-
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);
|
|
139019
139245
|
return m2?.[1]?.trim().replace(/[.,;]$/, "");
|
|
139020
139246
|
}
|
|
139021
139247
|
var QUOTA_RE2, UNREACHABLE_RE, AUTH_RE;
|
|
@@ -140326,7 +140552,7 @@ var init_dispatcher = __esm({
|
|
|
140326
140552
|
assertSpawnAttemptCurrent(jobKey, attempt) {
|
|
140327
140553
|
if (!this.isSpawnAttemptCurrent(jobKey, attempt)) throw new SpawnAttemptStale(jobKey);
|
|
140328
140554
|
}
|
|
140329
|
-
async recordSpawnFailure(jobKey, spec, reason,
|
|
140555
|
+
async recordSpawnFailure(jobKey, spec, reason, errorMessage2, bypassScheduling = false) {
|
|
140330
140556
|
if (bypassScheduling) return;
|
|
140331
140557
|
if (!this.strikeLedgerLive) return;
|
|
140332
140558
|
const seqAtVerdict = this.opts.kernel.model.lastSeq.get(spec.artifactId) ?? 0;
|
|
@@ -140355,7 +140581,7 @@ var init_dispatcher = __esm({
|
|
|
140355
140581
|
firstFailedAt: prev?.firstFailedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
140356
140582
|
lastReason: reason,
|
|
140357
140583
|
totalFailures: (prev?.totalFailures ?? prev?.count ?? 0) + 1,
|
|
140358
|
-
...
|
|
140584
|
+
...errorMessage2 ? { lastErrorMessage: errorMessage2.slice(0, 400) } : {},
|
|
140359
140585
|
// 半开一旦开启就**粘着**,直到真的成功(自己落了 op)才随整条记录清掉。
|
|
140360
140586
|
// 不粘的话:试探失败却因自愈类/宽限期没能立刻回熔断时,标记会丢,等于白送回满血 3 次。
|
|
140361
140587
|
...prev?.halfOpen ? { halfOpen: true } : {},
|
|
@@ -142814,6 +143040,10 @@ var init_kernel_bridge = __esm({
|
|
|
142814
143040
|
* 用来兜住"本进程没收到事件"的写入——多实例部署下别的实例改的工单就属于这种。
|
|
142815
143041
|
*/
|
|
142816
143042
|
async refreshModel(opts) {
|
|
143043
|
+
if (opts?.workorderId) {
|
|
143044
|
+
this.trackedWorkorders.add(opts.workorderId);
|
|
143045
|
+
this.markWorkorderDirty(opts.workorderId);
|
|
143046
|
+
}
|
|
142817
143047
|
if (opts?.resync) this.resyncRequested = true;
|
|
142818
143048
|
await this.refreshTracked();
|
|
142819
143049
|
}
|
|
@@ -144303,6 +144533,24 @@ var init_kernel_bridge = __esm({
|
|
|
144303
144533
|
}
|
|
144304
144534
|
});
|
|
144305
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
|
+
}
|
|
144306
144554
|
/** 工单级恢复:workorder.resumed handler 解冻全部节点 + scan 重建 work。 */
|
|
144307
144555
|
async resumeWorkorder(workorderId, actor) {
|
|
144308
144556
|
this.trackedWorkorders.add(workorderId);
|
|
@@ -144600,7 +144848,7 @@ var init_kernel_bridge = __esm({
|
|
|
144600
144848
|
const scopedModel = ws ? filterReadModelByWorkspace(this.model, ws) : this.model;
|
|
144601
144849
|
return previewIntervention(scopedModel, plan, { schema: this.schema, roleIndex: this.roleIndex });
|
|
144602
144850
|
}
|
|
144603
|
-
async applyIntervention(plan, _baseSeqs, _actor) {
|
|
144851
|
+
async applyIntervention(plan, _baseSeqs, _actor, options = {}) {
|
|
144604
144852
|
const ws = this.effectiveWorkspace(plan);
|
|
144605
144853
|
const scopedModel = ws ? filterReadModelByWorkspace(this.model, ws) : this.model;
|
|
144606
144854
|
plan = resolveInterventionRefs(scopedModel, plan, this.schema);
|
|
@@ -144849,7 +145097,7 @@ var init_kernel_bridge = __esm({
|
|
|
144849
145097
|
break;
|
|
144850
145098
|
}
|
|
144851
145099
|
}
|
|
144852
|
-
await queue({
|
|
145100
|
+
if (!options.deferActivation) await queue({
|
|
144853
145101
|
companyId: "",
|
|
144854
145102
|
workorderId: wid,
|
|
144855
145103
|
actorId: _actor,
|
|
@@ -145676,15 +145924,15 @@ var init_parseUtil = __esm({
|
|
|
145676
145924
|
message: issueData.message
|
|
145677
145925
|
};
|
|
145678
145926
|
}
|
|
145679
|
-
let
|
|
145927
|
+
let errorMessage2 = "";
|
|
145680
145928
|
const maps = errorMaps.filter((m2) => !!m2).slice().reverse();
|
|
145681
145929
|
for (const map of maps) {
|
|
145682
|
-
|
|
145930
|
+
errorMessage2 = map(fullIssue, { data, defaultError: errorMessage2 }).message;
|
|
145683
145931
|
}
|
|
145684
145932
|
return {
|
|
145685
145933
|
...issueData,
|
|
145686
145934
|
path: fullPath,
|
|
145687
|
-
message:
|
|
145935
|
+
message: errorMessage2
|
|
145688
145936
|
};
|
|
145689
145937
|
};
|
|
145690
145938
|
EMPTY_PATH = [];
|
|
@@ -162251,7 +162499,52 @@ var init_keyed_mutex = __esm({
|
|
|
162251
162499
|
}
|
|
162252
162500
|
});
|
|
162253
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
|
+
|
|
162254
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
|
+
}
|
|
162255
162548
|
function normalizedKindToItemType(kind) {
|
|
162256
162549
|
if (kind === "text") return "message";
|
|
162257
162550
|
if (kind === "thinking") return "thinking";
|
|
@@ -162343,6 +162636,8 @@ var init_live_chat = __esm({
|
|
|
162343
162636
|
};
|
|
162344
162637
|
this.turns.set(chatSessionId, turn);
|
|
162345
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;
|
|
162346
162641
|
const waiters = this.turnStartWaiters.get(chatSessionId);
|
|
162347
162642
|
this.turnStartWaiters.delete(chatSessionId);
|
|
162348
162643
|
for (const wake of waiters ?? []) {
|
|
@@ -162393,6 +162688,7 @@ var init_live_chat = __esm({
|
|
|
162393
162688
|
};
|
|
162394
162689
|
},
|
|
162395
162690
|
finish: (status) => {
|
|
162691
|
+
stopUserItems?.();
|
|
162396
162692
|
for (const receipt of turn.inputReceipts.values()) receipt.abandon();
|
|
162397
162693
|
turn.inputReceipts.clear();
|
|
162398
162694
|
try {
|
|
@@ -162682,11 +162978,11 @@ var init_live_chat = __esm({
|
|
|
162682
162978
|
* 空对话首次发送时那个最大号是 0,随后到达的历史(号更大)会全部排到乐观条**后面**——
|
|
162683
162979
|
* 正是 ADR D9 点名必须验的「空桶先发送」那一档。号只能由服务端给。
|
|
162684
162980
|
*
|
|
162685
|
-
* ##
|
|
162981
|
+
* ## 谁来调
|
|
162686
162982
|
*
|
|
162687
|
-
*
|
|
162688
|
-
*
|
|
162689
|
-
*
|
|
162983
|
+
* 生产上只有 {@link start} 订阅账本(`ChatItemLedger.onUserItemPersisted`)之后经
|
|
162984
|
+
* {@link publishPersistedUserItem} 调,四条开轮入口一处接好;「落库早于开轮」由账本订阅时补发兜住。
|
|
162985
|
+
* 下面按会话号暂存的那条路只服务直接调本方法、手上又没有轮的调用方。
|
|
162690
162986
|
*/
|
|
162691
162987
|
/**
|
|
162692
162988
|
* 「user item 已落库、但这条会话的 live 轮还没 start」时的暂存位(见 {@link publishUserItem})。
|
|
@@ -162736,6 +163032,18 @@ var init_live_chat = __esm({
|
|
|
162736
163032
|
this.publishV3(turn, this.assignV3Seq(turn, frame));
|
|
162737
163033
|
return true;
|
|
162738
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
|
+
}
|
|
162739
163047
|
/** 恢复路在 DB 收口旧 item 后,将同一身份/版本的终态发给已挂上的观众。 */
|
|
162740
163048
|
publishItemStatus(chatSessionId, item) {
|
|
162741
163049
|
const turn = this.turns.get(chatSessionId);
|
|
@@ -205373,15 +205681,6 @@ async function loadWorkorderSnapshot(kernel, workorderId) {
|
|
|
205373
205681
|
if (!store) return null;
|
|
205374
205682
|
return store.transaction((tx) => tx.loadWorkorder(workorderId));
|
|
205375
205683
|
}
|
|
205376
|
-
function workorderCreationState(snap, briefArtifactId) {
|
|
205377
|
-
const briefWorkIds = new Set(
|
|
205378
|
-
snap.works.filter((w2) => w2.nodeId === briefArtifactId).map((w2) => w2.id)
|
|
205379
|
-
);
|
|
205380
|
-
return {
|
|
205381
|
-
hasNodes: snap.nodes.length > 0,
|
|
205382
|
-
briefHasBody: snap.artifacts.some((a) => briefWorkIds.has(a.workId))
|
|
205383
|
-
};
|
|
205384
|
-
}
|
|
205385
205684
|
function wantsChatParts(req) {
|
|
205386
205685
|
const accept = req.headers.accept;
|
|
205387
205686
|
return typeof accept === "string" && accept.includes("application/x-ndjson");
|
|
@@ -206030,18 +206329,12 @@ ${acceptanceCriteria.map((c) => `- ${c}`).join("\n")}`] : []
|
|
|
206030
206329
|
}
|
|
206031
206330
|
};
|
|
206032
206331
|
}
|
|
206033
|
-
const applied = await kernel.applyIntervention(planned.plan, preview2.baseSeqs, actor);
|
|
206332
|
+
const applied = await kernel.applyIntervention(planned.plan, preview2.baseSeqs, actor, { deferActivation: true });
|
|
206034
206333
|
const briefArtifactId = planned.rootArtifactId;
|
|
206035
|
-
|
|
206036
|
-
|
|
206037
|
-
|
|
206038
|
-
|
|
206039
|
-
await kernel.conclude({ artifactId: briefArtifactId, actor, note: "\u5EFA\u5355\u65F6\u7531\u53D1\u8D77\u4EBA\u62CD\u677F\u5B9A\u7A3F" });
|
|
206040
|
-
}
|
|
206041
|
-
if (args["dispatch"] === false) {
|
|
206042
|
-
await ctx.artifactState?.setWorkspaceDispatchHold(workspace, true);
|
|
206043
|
-
await kernel.pauseWorkorder?.(workspace, actor, WORKORDER_HOLD_AT_CREATE_REASON);
|
|
206044
|
-
}
|
|
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);
|
|
206045
206338
|
return {
|
|
206046
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`,
|
|
206047
206340
|
data: {
|
|
@@ -207291,10 +207584,10 @@ async function startOasisServer(opts) {
|
|
|
207291
207584
|
...fp(p2)
|
|
207292
207585
|
}))
|
|
207293
207586
|
] : [];
|
|
207294
|
-
const { randomUUID:
|
|
207587
|
+
const { randomUUID: randomUUID46 } = await import("node:crypto");
|
|
207295
207588
|
try {
|
|
207296
207589
|
await store.enqueuePendingMessage({
|
|
207297
|
-
id:
|
|
207590
|
+
id: randomUUID46(),
|
|
207298
207591
|
chatSessionId: input.chatSessionId,
|
|
207299
207592
|
text: input.text,
|
|
207300
207593
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -207327,11 +207620,11 @@ async function startOasisServer(opts) {
|
|
|
207327
207620
|
...f2?.mtime ? { srcMtime: f2.mtime } : {}
|
|
207328
207621
|
};
|
|
207329
207622
|
});
|
|
207330
|
-
const { randomUUID:
|
|
207623
|
+
const { randomUUID: randomUUID46 } = await import("node:crypto");
|
|
207331
207624
|
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
207332
207625
|
try {
|
|
207333
207626
|
await store.enqueuePendingMessage({
|
|
207334
|
-
id:
|
|
207627
|
+
id: randomUUID46(),
|
|
207335
207628
|
chatSessionId: input.chatSessionId,
|
|
207336
207629
|
text: "",
|
|
207337
207630
|
createdAt: nowIso,
|
|
@@ -208259,14 +208552,13 @@ async function startOasisServer(opts) {
|
|
|
208259
208552
|
}
|
|
208260
208553
|
}
|
|
208261
208554
|
const existingSnap = targetWs ? await loadWorkorderSnapshot(engine.kernel, targetWs) : null;
|
|
208262
|
-
|
|
208263
|
-
if (resumeState.hasNodes && resumeState.briefHasBody) {
|
|
208555
|
+
if (targetWs && (await engine.kernel.isWorkorderCreationComplete(targetWs) || legacyCreationComplete(existingSnap, body2.briefArtifactId))) {
|
|
208264
208556
|
res.writeHead(409, { "content-type": "application/json" }).end(
|
|
208265
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 })
|
|
208266
208558
|
);
|
|
208267
208559
|
return;
|
|
208268
208560
|
}
|
|
208269
|
-
const resuming =
|
|
208561
|
+
const resuming = (existingSnap?.nodes.length ?? 0) > 0;
|
|
208270
208562
|
let sessionProjectId;
|
|
208271
208563
|
let sessionBindingState;
|
|
208272
208564
|
if (body2.chatSessionId && opts.chatSession) {
|
|
@@ -208330,10 +208622,7 @@ async function startOasisServer(opts) {
|
|
|
208330
208622
|
if (targetWs && sessionProjectId) {
|
|
208331
208623
|
await sessionBindingState.upsertWorkspaceBinding({ workOrderId: targetWs, projectId: sessionProjectId });
|
|
208332
208624
|
}
|
|
208333
|
-
const result = resuming ? { interventionId: "", applied: 0, resumed: true } : await engine.kernel.applyIntervention(body2.plan, body2.baseSeqs, actor);
|
|
208334
|
-
if (resuming) {
|
|
208335
|
-
await engine.kernel.activateWorkorder?.(targetWs, actor);
|
|
208336
|
-
}
|
|
208625
|
+
const result = resuming ? { interventionId: "", applied: 0, resumed: true } : await engine.kernel.applyIntervention(body2.plan, body2.baseSeqs, actor, { deferActivation: true });
|
|
208337
208626
|
const briefSpawn = body2.plan.ops.find(
|
|
208338
208627
|
(op) => op.action === "spawn" && op.id === body2.briefArtifactId
|
|
208339
208628
|
);
|
|
@@ -208344,26 +208633,15 @@ async function startOasisServer(opts) {
|
|
|
208344
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`);
|
|
208345
208634
|
}
|
|
208346
208635
|
const warnings = [];
|
|
208347
|
-
|
|
208348
|
-
|
|
208349
|
-
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" });
|
|
208350
|
-
await engine.kernel.advanceQueue(body2.briefArtifactId, actor);
|
|
208351
|
-
await engine.kernel.conclude({ artifactId: body2.briefArtifactId, actor, note: "\u5EFA\u5355\u65F6\u7531\u53D1\u8D77\u4EBA\u62CD\u677F\u5B9A\u7A3F" });
|
|
208352
|
-
} else {
|
|
208353
|
-
warnings.push("\u5DE5\u5355\u603B\u7EB2\u6CA1\u6709\u6B63\u6587\uFF0C\u672A\u843D\u9996\u7248");
|
|
208354
|
-
}
|
|
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");
|
|
208355
208638
|
if (body2.dispatch === false) {
|
|
208356
|
-
await
|
|
208357
|
-
await engine.kernel.pauseWorkorder?.(workspace, actor, WORKORDER_HOLD_AT_CREATE_REASON);
|
|
208639
|
+
await (await artifactStateNow())?.setWorkspaceDispatchHold?.(workspace, true);
|
|
208358
208640
|
}
|
|
208359
208641
|
await wodraftPlannerIssues.remove(workspace);
|
|
208360
208642
|
if (opts.chatSession && body2.chatSessionId && workspace !== "ws:default") {
|
|
208361
208643
|
const applyLinkStore = await chatStoreNow();
|
|
208362
|
-
await applyLinkStore.linkWorkOrder(body2.chatSessionId, workspace, "origin")
|
|
208363
|
-
const detail = err instanceof Error ? err.message : String(err);
|
|
208364
|
-
console.error(`[chat-session] Failed to link work order ${workspace} to session ${body2.chatSessionId}:`, err);
|
|
208365
|
-
warnings.push(`\u672A\u80FD\u628A\u5DE5\u5355\u5173\u8054\u56DE\u672C\u6B21\u5BF9\u8BDD\uFF1A${detail}`);
|
|
208366
|
-
});
|
|
208644
|
+
await applyLinkStore.linkWorkOrder(body2.chatSessionId, workspace, "origin");
|
|
208367
208645
|
const handoffArtifacts = await artifactStateNow();
|
|
208368
208646
|
if (handoffArtifacts?.addWorkOrderFile) {
|
|
208369
208647
|
const handoff = await linkChatAttachmentsToWorkOrder({
|
|
@@ -208393,6 +208671,7 @@ async function startOasisServer(opts) {
|
|
|
208393
208671
|
const missing = plannedSpawnIds.filter((id) => !present.has(id));
|
|
208394
208672
|
if (missing.length > 0) warnings.push(`\u534F\u4F5C\u56FE\u7F3A ${missing.length} \u4E2A\u8282\u70B9\u672A\u5EFA\u51FA\uFF1A${missing.join("\u3001")}`);
|
|
208395
208673
|
}
|
|
208674
|
+
await engine.kernel.completeWorkorderCreation(workspace, actor, body2.dispatch !== false, WORKORDER_HOLD_AT_CREATE_REASON);
|
|
208396
208675
|
res.writeHead(200, { "content-type": "application/json" }).end(
|
|
208397
208676
|
JSON.stringify({
|
|
208398
208677
|
...result,
|
|
@@ -208674,7 +208953,7 @@ async function startOasisServer(opts) {
|
|
|
208674
208953
|
const openRoom = async () => {
|
|
208675
208954
|
let chatSessionId2;
|
|
208676
208955
|
if (chatStore) {
|
|
208677
|
-
const { randomUUID:
|
|
208956
|
+
const { randomUUID: randomUUID46 } = await import("node:crypto");
|
|
208678
208957
|
const known = discussSessions.get(itemKey);
|
|
208679
208958
|
const knownSession = known ? await chatStore.getSession(known) : null;
|
|
208680
208959
|
if (knownSession && knownSession.workspace === ctx.workspace && knownSession.humanActorId === ctx.ownerId && (!body2.escalationId || knownSession.escalationId === body2.escalationId)) chatSessionId2 = known;
|
|
@@ -208683,7 +208962,7 @@ async function startOasisServer(opts) {
|
|
|
208683
208962
|
chatSessionId2 = existing[0]?.id;
|
|
208684
208963
|
}
|
|
208685
208964
|
if (!chatSessionId2) {
|
|
208686
|
-
chatSessionId2 =
|
|
208965
|
+
chatSessionId2 = randomUUID46();
|
|
208687
208966
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
208688
208967
|
const title = `\u89E3\u51B3\uFF1A${ctx.seed.slice(ctx.seed.indexOf("\uFF1A") + 1, ctx.seed.indexOf("\uFF1A") + 25) || "\u5DE5\u5355\u5361\u70B9"}`;
|
|
208689
208968
|
const reg0 = (await resolveEngine(currentCompanyId).catch(() => null))?.registry ?? opts.registry;
|
|
@@ -209582,7 +209861,7 @@ ${composed}`;
|
|
|
209582
209861
|
});
|
|
209583
209862
|
await rejectedLedger.drain();
|
|
209584
209863
|
if (rejectedLedger.failures === 0) {
|
|
209585
|
-
const { randomUUID:
|
|
209864
|
+
const { randomUUID: randomUUID47 } = await import("node:crypto");
|
|
209586
209865
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
209587
209866
|
const rejectedAttachments = effectiveAttachments.map((a) => ({
|
|
209588
209867
|
name: a.name,
|
|
@@ -209590,7 +209869,7 @@ ${composed}`;
|
|
|
209590
209869
|
...a.contentType !== void 0 ? { contentType: a.contentType } : {}
|
|
209591
209870
|
}));
|
|
209592
209871
|
await chatStore.appendMessage({
|
|
209593
|
-
id:
|
|
209872
|
+
id: randomUUID47(),
|
|
209594
209873
|
sessionId: persistTarget.id,
|
|
209595
209874
|
role: "user",
|
|
209596
209875
|
content: persistedUserMessage,
|
|
@@ -209668,14 +209947,14 @@ ${composed}`;
|
|
|
209668
209947
|
runtimeSessionId: session.nativeSessionId ?? session.id
|
|
209669
209948
|
}).catch(() => void 0);
|
|
209670
209949
|
}
|
|
209671
|
-
const { randomUUID:
|
|
209950
|
+
const { randomUUID: randomUUID47 } = await import("node:crypto");
|
|
209672
209951
|
const persistAttachments = effectiveAttachments.map((a) => ({
|
|
209673
209952
|
name: a.name,
|
|
209674
209953
|
...a.blobRef !== void 0 ? { blobRef: a.blobRef } : {},
|
|
209675
209954
|
...a.contentType !== void 0 ? { contentType: a.contentType } : {}
|
|
209676
209955
|
}));
|
|
209677
209956
|
await chatStore.appendMessage({
|
|
209678
|
-
id:
|
|
209957
|
+
id: randomUUID47(),
|
|
209679
209958
|
sessionId: persistTarget.id,
|
|
209680
209959
|
role: "user",
|
|
209681
209960
|
content: persistedUserMessage,
|
|
@@ -209701,27 +209980,10 @@ ${composed}`;
|
|
|
209701
209980
|
const itemLedger = new ChatItemLedger({
|
|
209702
209981
|
...itemStore ? { items: itemStore } : {},
|
|
209703
209982
|
versionSeed,
|
|
209704
|
-
/*
|
|
209705
|
-
|
|
209706
|
-
|
|
209707
|
-
|
|
209708
|
-
只推 user:assistant 的每一条本来就走 `emitV3`。 */
|
|
209709
|
-
onPersisted: (info) => {
|
|
209710
|
-
if (info.role !== "user") return;
|
|
209711
|
-
const rowPayload = info.payload && typeof info.payload === "object" && !Array.isArray(info.payload) ? info.payload : void 0;
|
|
209712
|
-
const rowCsid = typeof rowPayload?.["clientSubmitId"] === "string" ? rowPayload["clientSubmitId"] : void 0;
|
|
209713
|
-
const rowCsids = Array.isArray(rowPayload?.["clientSubmitIds"]) ? rowPayload["clientSubmitIds"].filter((v2) => typeof v2 === "string") : void 0;
|
|
209714
|
-
const rowAttachments = Array.isArray(rowPayload?.["attachments"]) ? rowPayload["attachments"] : void 0;
|
|
209715
|
-
opts.liveChat?.publishUserItem(persistTarget?.id ?? session.id, {
|
|
209716
|
-
itemId: info.itemId,
|
|
209717
|
-
ord: info.ord,
|
|
209718
|
-
version: info.version,
|
|
209719
|
-
text: info.text,
|
|
209720
|
-
...rowCsid ? { clientSubmitId: rowCsid } : {},
|
|
209721
|
-
...rowCsids?.length ? { clientSubmitIds: rowCsids } : {},
|
|
209722
|
-
...rowAttachments?.length ? { attachments: rowAttachments } : {}
|
|
209723
|
-
});
|
|
209724
|
-
},
|
|
209983
|
+
/* 用户那条消息(首条提交与中途插话)一落库就推上 v3 流(ADR-0510 D2 的收口)——
|
|
209984
|
+
**不在这里接**:`liveChat.start` 带着这本账本开轮时统一订阅
|
|
209985
|
+
(`LiveChatRegistry.start` → `ChatItemLedger.onUserItemPersisted`),开轮前已落库的会补发。
|
|
209986
|
+
四条开轮入口共用那一处;这里再接一次就是同一行两帧、同一版本号,客户端判 stale 并 resync。 */
|
|
209725
209987
|
sessionId: persistTarget?.id ?? session.id,
|
|
209726
209988
|
// 优先账本 id(`chat_session_turns.id`,跨进程唯一、重启不失忆);账本没接入才兜底。
|
|
209727
209989
|
turnId: heldTurn?.id ?? fallbackTurnId(session.runId),
|
|
@@ -209823,52 +210085,27 @@ ${composed}`;
|
|
|
209823
210085
|
}, { items: itemLedger }) : null;
|
|
209824
210086
|
if (live && assistantMsgId) live.setAssistantMessageId(assistantMsgId);
|
|
209825
210087
|
if (live && chatStore && persistTarget) {
|
|
209826
|
-
const { randomUUID: newId } = await import("node:crypto");
|
|
209827
210088
|
const liveCtl = live;
|
|
209828
210089
|
const target = persistTarget;
|
|
209829
210090
|
const store = chatStore;
|
|
209830
210091
|
liveCtl.onUserInput((text6, insertedAttachments) => {
|
|
209831
|
-
const segText = itemLedger.projectContent();
|
|
209832
210092
|
const segParts = collectedParts();
|
|
209833
|
-
const
|
|
209834
|
-
|
|
209835
|
-
|
|
209836
|
-
|
|
209837
|
-
|
|
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;
|
|
209838
210107
|
segmentBaseSeq = liveCtl.bufferedParts().reduce((max, p2) => p2.seq > max ? p2.seq : max, 0);
|
|
209839
|
-
|
|
209840
|
-
checkpointChain = checkpointChain.then(async () => {
|
|
209841
|
-
if (closingId) {
|
|
209842
|
-
await store.updateMessage(closingId, {
|
|
209843
|
-
content: segText,
|
|
209844
|
-
status: "done",
|
|
209845
|
-
completedAt: at,
|
|
209846
|
-
...segParts.length ? { parts: segParts } : {}
|
|
209847
|
-
}).catch(() => void 0);
|
|
209848
|
-
}
|
|
209849
|
-
await store.appendMessage({
|
|
209850
|
-
id: newId(),
|
|
209851
|
-
sessionId: target.id,
|
|
209852
|
-
role: "user",
|
|
209853
|
-
content: text6,
|
|
209854
|
-
createdAt: at,
|
|
209855
|
-
// ADR-0166 D9.1:插入带的附件也落在**这条 user 行**上——否则重载后这条气泡
|
|
209856
|
-
// 只剩一行字,而同样带图直接发送的那条有缩略图。同 `/api/chat` 那侧只存引用。
|
|
209857
|
-
...insertedAttachments?.length ? { attachments: insertedAttachments } : {},
|
|
209858
|
-
...heldTurn ? { turnId: heldTurn.id } : {}
|
|
209859
|
-
// 插话切段仍属同一轮(同 turnId)
|
|
209860
|
-
}).catch(() => void 0);
|
|
209861
|
-
await store.appendMessage({
|
|
209862
|
-
id: nextId,
|
|
209863
|
-
sessionId: target.id,
|
|
209864
|
-
role: "assistant",
|
|
209865
|
-
content: "",
|
|
209866
|
-
createdAt: at,
|
|
209867
|
-
status: "running",
|
|
209868
|
-
...session.runId ? { runId: session.runId } : {},
|
|
209869
|
-
...heldTurn ? { turnId: heldTurn.id } : {}
|
|
209870
|
-
}).then(() => itemLedger.bindMessage(nextId)).catch(() => void 0);
|
|
209871
|
-
}).catch(() => void 0);
|
|
210108
|
+
checkpointChain = checkpointChain.then(split.persist).catch(() => void 0);
|
|
209872
210109
|
});
|
|
209873
210110
|
}
|
|
209874
210111
|
let localSeq = 0;
|
|
@@ -210151,8 +210388,8 @@ ${composed}`;
|
|
|
210151
210388
|
}
|
|
210152
210389
|
}
|
|
210153
210390
|
const { spawn: spawn10 } = await import("node:child_process");
|
|
210154
|
-
const { randomUUID:
|
|
210155
|
-
const sessionId = body2.sessionId ??
|
|
210391
|
+
const { randomUUID: randomUUID46 } = await import("node:crypto");
|
|
210392
|
+
const sessionId = body2.sessionId ?? randomUUID46();
|
|
210156
210393
|
const args = [
|
|
210157
210394
|
"-p",
|
|
210158
210395
|
body2.message,
|
|
@@ -210448,8 +210685,8 @@ ${composed}`;
|
|
|
210448
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}` }));
|
|
210449
210686
|
return;
|
|
210450
210687
|
}
|
|
210451
|
-
const { randomUUID:
|
|
210452
|
-
const state =
|
|
210688
|
+
const { randomUUID: randomUUID46 } = await import("node:crypto");
|
|
210689
|
+
const state = randomUUID46();
|
|
210453
210690
|
const nameSlug = (actorName || actorId?.split(":").pop() || owner?.login || "bot").toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-|-$/g, "").slice(0, 24) || "bot";
|
|
210454
210691
|
const manifest = buildAppManifest({
|
|
210455
210692
|
employeeSlug: nameSlug,
|
|
@@ -211257,6 +211494,7 @@ var init_server3 = __esm({
|
|
|
211257
211494
|
init_router();
|
|
211258
211495
|
init_infra_error();
|
|
211259
211496
|
init_keyed_mutex();
|
|
211497
|
+
init_initialize_workorder();
|
|
211260
211498
|
init_live_chat();
|
|
211261
211499
|
init_chat_turn_wait();
|
|
211262
211500
|
init_append_now();
|
|
@@ -221037,7 +221275,11 @@ function wireRecoveredChatTurn(deps) {
|
|
|
221037
221275
|
void handle.kill();
|
|
221038
221276
|
},
|
|
221039
221277
|
// ADR-0093 chat 道:重挂的轮同样能被插入——否则「serve 重启过」会变成一条人看不见的能力差异。
|
|
221040
|
-
|
|
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) } : {},
|
|
221041
221283
|
get canAppendInput() {
|
|
221042
221284
|
return handle.canAppendInput !== false && typeof handle.appendInput === "function";
|
|
221043
221285
|
}
|
|
@@ -221129,40 +221371,25 @@ function wireRecoveredChatTurn(deps) {
|
|
|
221129
221371
|
let checkpointChain = Promise.resolve();
|
|
221130
221372
|
{
|
|
221131
221373
|
const store = deps.chatStore;
|
|
221132
|
-
live.onUserInput((text6) => {
|
|
221133
|
-
const segText = itemLedger.projectContent();
|
|
221374
|
+
live.onUserInput((text6, attachments) => {
|
|
221134
221375
|
const segParts = collectedParts();
|
|
221135
|
-
const
|
|
221136
|
-
|
|
221137
|
-
|
|
221138
|
-
|
|
221139
|
-
|
|
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;
|
|
221140
221391
|
segmentBaseSeq = live.bufferedParts().reduce((max, p2) => p2.seq > max ? p2.seq : max, 0);
|
|
221141
|
-
|
|
221142
|
-
checkpointChain = checkpointChain.then(async () => {
|
|
221143
|
-
await store.updateMessage(closingId, {
|
|
221144
|
-
content: segText,
|
|
221145
|
-
status: "done",
|
|
221146
|
-
completedAt: at,
|
|
221147
|
-
...segParts.length ? { parts: segParts } : {}
|
|
221148
|
-
}).catch(() => void 0);
|
|
221149
|
-
await store.appendMessage({
|
|
221150
|
-
id: (0, import_node_crypto49.randomUUID)(),
|
|
221151
|
-
sessionId: plan.chatSessionId,
|
|
221152
|
-
role: "user",
|
|
221153
|
-
content: text6,
|
|
221154
|
-
createdAt: at
|
|
221155
|
-
}).catch(() => void 0);
|
|
221156
|
-
await store.appendMessage({
|
|
221157
|
-
id: nextId,
|
|
221158
|
-
sessionId: plan.chatSessionId,
|
|
221159
|
-
role: "assistant",
|
|
221160
|
-
content: "",
|
|
221161
|
-
createdAt: at,
|
|
221162
|
-
status: "running",
|
|
221163
|
-
runId: plan.runId
|
|
221164
|
-
}).then(() => itemLedger.bindMessage(nextId)).catch(() => void 0);
|
|
221165
|
-
}).catch(() => void 0);
|
|
221392
|
+
checkpointChain = checkpointChain.then(split.persist).catch(() => void 0);
|
|
221166
221393
|
});
|
|
221167
221394
|
}
|
|
221168
221395
|
const ckptTimer = setInterval(() => {
|
|
@@ -221634,12 +221861,11 @@ async function recoverChatTurnsAcrossCompanies(deps) {
|
|
|
221634
221861
|
}
|
|
221635
221862
|
return { ...result, recovered };
|
|
221636
221863
|
}
|
|
221637
|
-
var
|
|
221864
|
+
var asObj3, partsOf, maxPartSeq, exitFailed, exitErrorText, runTerminalPatch;
|
|
221638
221865
|
var init_chat_recovery = __esm({
|
|
221639
221866
|
"../server/src/chat-recovery.ts"() {
|
|
221640
221867
|
"use strict";
|
|
221641
221868
|
init_file_restore();
|
|
221642
|
-
import_node_crypto49 = require("node:crypto");
|
|
221643
221869
|
init_chat_parts();
|
|
221644
221870
|
init_sink();
|
|
221645
221871
|
init_resilient_appender();
|
|
@@ -221670,8 +221896,8 @@ var init_chat_recovery = __esm({
|
|
|
221670
221896
|
|
|
221671
221897
|
// ../server/src/auth/crypto.ts
|
|
221672
221898
|
function hashPassword(password) {
|
|
221673
|
-
const salt = (0,
|
|
221674
|
-
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 });
|
|
221675
221901
|
return `scrypt$${SCRYPT_N}$${salt.toString("base64url")}$${dk.toString("base64url")}`;
|
|
221676
221902
|
}
|
|
221677
221903
|
function verifyPassword(password, stored) {
|
|
@@ -221688,8 +221914,8 @@ function verifyPassword(password, stored) {
|
|
|
221688
221914
|
return false;
|
|
221689
221915
|
}
|
|
221690
221916
|
if (expected.length === 0) return false;
|
|
221691
|
-
const dk = (0,
|
|
221692
|
-
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);
|
|
221693
221919
|
}
|
|
221694
221920
|
function b64urlJson(value2) {
|
|
221695
221921
|
return Buffer.from(JSON.stringify(value2)).toString("base64url");
|
|
@@ -221697,17 +221923,17 @@ function b64urlJson(value2) {
|
|
|
221697
221923
|
function signSession(claims, secret) {
|
|
221698
221924
|
const head = b64urlJson({ alg: "HS256", typ: "JWT" });
|
|
221699
221925
|
const body2 = b64urlJson(claims);
|
|
221700
|
-
const sig = (0,
|
|
221926
|
+
const sig = (0, import_node_crypto49.createHmac)("sha256", secret).update(`${head}.${body2}`).digest("base64url");
|
|
221701
221927
|
return `${head}.${body2}.${sig}`;
|
|
221702
221928
|
}
|
|
221703
221929
|
function verifySession(token, secret, nowMs) {
|
|
221704
221930
|
const parts = token.split(".");
|
|
221705
221931
|
if (parts.length !== 3) return null;
|
|
221706
221932
|
const [head, body2, sig] = parts;
|
|
221707
|
-
const expected = (0,
|
|
221933
|
+
const expected = (0, import_node_crypto49.createHmac)("sha256", secret).update(`${head}.${body2}`).digest("base64url");
|
|
221708
221934
|
const got = Buffer.from(sig);
|
|
221709
221935
|
const exp = Buffer.from(expected);
|
|
221710
|
-
if (got.length !== exp.length || !(0,
|
|
221936
|
+
if (got.length !== exp.length || !(0, import_node_crypto49.timingSafeEqual)(got, exp)) return null;
|
|
221711
221937
|
let claims;
|
|
221712
221938
|
try {
|
|
221713
221939
|
claims = JSON.parse(Buffer.from(body2, "base64url").toString("utf8"));
|
|
@@ -221719,21 +221945,21 @@ function verifySession(token, secret, nowMs) {
|
|
|
221719
221945
|
return claims;
|
|
221720
221946
|
}
|
|
221721
221947
|
function generateCode() {
|
|
221722
|
-
return String((0,
|
|
221948
|
+
return String((0, import_node_crypto49.randomInt)(0, 1e6)).padStart(6, "0");
|
|
221723
221949
|
}
|
|
221724
221950
|
function hashCode(code2, secret) {
|
|
221725
|
-
return (0,
|
|
221951
|
+
return (0, import_node_crypto49.createHmac)("sha256", secret).update(`code:${code2}`).digest("base64url");
|
|
221726
221952
|
}
|
|
221727
221953
|
function safeEqualHash(a, b2) {
|
|
221728
221954
|
const ba = Buffer.from(a);
|
|
221729
221955
|
const bb = Buffer.from(b2);
|
|
221730
|
-
return ba.length === bb.length && (0,
|
|
221956
|
+
return ba.length === bb.length && (0, import_node_crypto49.timingSafeEqual)(ba, bb);
|
|
221731
221957
|
}
|
|
221732
|
-
var
|
|
221958
|
+
var import_node_crypto49, SCRYPT_N, SCRYPT_KEYLEN;
|
|
221733
221959
|
var init_crypto2 = __esm({
|
|
221734
221960
|
"../server/src/auth/crypto.ts"() {
|
|
221735
221961
|
"use strict";
|
|
221736
|
-
|
|
221962
|
+
import_node_crypto49 = require("node:crypto");
|
|
221737
221963
|
SCRYPT_N = 16384;
|
|
221738
221964
|
SCRYPT_KEYLEN = 32;
|
|
221739
221965
|
}
|
|
@@ -222896,18 +223122,18 @@ function variableKeyFromEnv(env = process.env) {
|
|
|
222896
223122
|
return buf;
|
|
222897
223123
|
}
|
|
222898
223124
|
if (env.NODE_ENV === "production") throw new Error("OASIS_VAR_KEY is required in production");
|
|
222899
|
-
return (0,
|
|
223125
|
+
return (0, import_node_crypto50.createHash)("sha256").update("oasis-dev-only-variable-key").digest();
|
|
222900
223126
|
}
|
|
222901
223127
|
function dedupe(ids2) {
|
|
222902
223128
|
return [...new Set(ids2.filter((x2) => typeof x2 === "string" && x2.length > 0))];
|
|
222903
223129
|
}
|
|
222904
|
-
var
|
|
223130
|
+
var import_node_crypto50, REDACTED_MARKER, ActorsService, mask, changedKeys;
|
|
222905
223131
|
var init_service5 = __esm({
|
|
222906
223132
|
"../server/src/domains/actors/service.ts"() {
|
|
222907
223133
|
"use strict";
|
|
222908
223134
|
init_file_limits2();
|
|
222909
223135
|
init_keyed_mutex();
|
|
222910
|
-
|
|
223136
|
+
import_node_crypto50 = require("node:crypto");
|
|
222911
223137
|
init_skill_fetcher();
|
|
222912
223138
|
init_identity();
|
|
222913
223139
|
init_migrate();
|
|
@@ -223475,7 +223701,7 @@ ${input.description}
|
|
|
223475
223701
|
*/
|
|
223476
223702
|
buildSkillFile(skillId, path40, content3, now) {
|
|
223477
223703
|
const bytes2 = new TextEncoder().encode(content3);
|
|
223478
|
-
const blobHash = (0,
|
|
223704
|
+
const blobHash = (0, import_node_crypto50.createHash)("sha256").update(bytes2).digest("hex");
|
|
223479
223705
|
return { skillId, path: path40, content: content3, blobHash, size: bytes2.length, updatedAt: now };
|
|
223480
223706
|
}
|
|
223481
223707
|
/**
|
|
@@ -224256,15 +224482,15 @@ ${input.description}
|
|
|
224256
224482
|
return hit ? { value: hit.value, ...hit.origin ? { origin: hit.origin } : {} } : null;
|
|
224257
224483
|
}
|
|
224258
224484
|
encrypt(plain) {
|
|
224259
|
-
const iv = (0,
|
|
224260
|
-
const cipher = (0,
|
|
224261
|
-
const
|
|
224262
|
-
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(".");
|
|
224263
224489
|
}
|
|
224264
224490
|
decrypt(packed) {
|
|
224265
224491
|
const [iv, tag, data] = packed.split(".");
|
|
224266
224492
|
if (!iv || !tag || typeof data !== "string") throw new Error("malformed ciphertext");
|
|
224267
|
-
const decipher = (0,
|
|
224493
|
+
const decipher = (0, import_node_crypto50.createDecipheriv)("aes-256-gcm", this.opts.variableKey, Buffer.from(iv, "base64"));
|
|
224268
224494
|
decipher.setAuthTag(Buffer.from(tag, "base64"));
|
|
224269
224495
|
return Buffer.concat([decipher.update(Buffer.from(data, "base64")), decipher.final()]).toString("utf8");
|
|
224270
224496
|
}
|
|
@@ -224876,7 +225102,7 @@ async function listSkillMetadataForActor(args) {
|
|
|
224876
225102
|
usedDirs.add(dir);
|
|
224877
225103
|
const sorted = [...metas].sort((a, b2) => a.path.localeCompare(b2.path));
|
|
224878
225104
|
let latest = "1970-01-01T00:00:00.000Z";
|
|
224879
|
-
const hasher = (0,
|
|
225105
|
+
const hasher = (0, import_node_crypto51.createHash)("sha256");
|
|
224880
225106
|
for (const m2 of sorted) {
|
|
224881
225107
|
if (m2.updatedAt > latest) latest = m2.updatedAt;
|
|
224882
225108
|
hasher.update(m2.path);
|
|
@@ -224901,11 +225127,11 @@ async function listSkillMetadataForActor(args) {
|
|
|
224901
225127
|
const dir = sanitizeSkillDir(c.name, c.slug);
|
|
224902
225128
|
if (usedDirs.has(dir)) continue;
|
|
224903
225129
|
usedDirs.add(dir);
|
|
224904
|
-
const hasher = (0,
|
|
225130
|
+
const hasher = (0, import_node_crypto51.createHash)("sha256");
|
|
224905
225131
|
for (const p2 of paths) {
|
|
224906
225132
|
hasher.update(p2);
|
|
224907
225133
|
hasher.update("\0");
|
|
224908
|
-
hasher.update((0,
|
|
225134
|
+
hasher.update((0, import_node_crypto51.createHash)("sha256").update(c.files[p2]).digest("hex"));
|
|
224909
225135
|
hasher.update("\0");
|
|
224910
225136
|
}
|
|
224911
225137
|
out.push({
|
|
@@ -224926,11 +225152,11 @@ async function listSkillMetadataForActor(args) {
|
|
|
224926
225152
|
const dir = sanitizeSkillDir(b2.name, b2.id);
|
|
224927
225153
|
if (usedDirs.has(dir)) continue;
|
|
224928
225154
|
usedDirs.add(dir);
|
|
224929
|
-
const hasher = (0,
|
|
225155
|
+
const hasher = (0, import_node_crypto51.createHash)("sha256");
|
|
224930
225156
|
for (const p2 of paths) {
|
|
224931
225157
|
hasher.update(p2);
|
|
224932
225158
|
hasher.update("\0");
|
|
224933
|
-
hasher.update((0,
|
|
225159
|
+
hasher.update((0, import_node_crypto51.createHash)("sha256").update(b2.files[p2]).digest("hex"));
|
|
224934
225160
|
hasher.update("\0");
|
|
224935
225161
|
}
|
|
224936
225162
|
out.push({
|
|
@@ -224950,7 +225176,7 @@ function builtinSkillToFiles(b2) {
|
|
|
224950
225176
|
skillId: `builtin:${b2.id}`,
|
|
224951
225177
|
path: path40,
|
|
224952
225178
|
content: content3,
|
|
224953
|
-
blobHash: (0,
|
|
225179
|
+
blobHash: (0, import_node_crypto51.createHash)("sha256").update(content3).digest("hex"),
|
|
224954
225180
|
size: Buffer.byteLength(content3, "utf8"),
|
|
224955
225181
|
updatedAt: "1970-01-01T00:00:00.000Z"
|
|
224956
225182
|
}));
|
|
@@ -224974,7 +225200,7 @@ function sanitizeSkillDir(name, fallbackId) {
|
|
|
224974
225200
|
if (byName) return byName;
|
|
224975
225201
|
const byId = fallbackId ? fold2(fallbackId) : "";
|
|
224976
225202
|
if (byId) return byId;
|
|
224977
|
-
return `skill-${(0,
|
|
225203
|
+
return `skill-${(0, import_node_crypto51.createHash)("sha256").update(name).digest("hex").slice(0, 8)}`;
|
|
224978
225204
|
}
|
|
224979
225205
|
async function materializeSkillFiles(args) {
|
|
224980
225206
|
const skills = await args.service.listInstalledSkillsForActor(args.actorId);
|
|
@@ -225007,7 +225233,7 @@ function connectorSkillToFiles(c) {
|
|
|
225007
225233
|
skillId: c.id,
|
|
225008
225234
|
path: path40,
|
|
225009
225235
|
content: content3,
|
|
225010
|
-
blobHash: (0,
|
|
225236
|
+
blobHash: (0, import_node_crypto51.createHash)("sha256").update(content3).digest("hex"),
|
|
225011
225237
|
size: Buffer.byteLength(content3, "utf8"),
|
|
225012
225238
|
updatedAt: "1970-01-01T00:00:00.000Z"
|
|
225013
225239
|
}));
|
|
@@ -225024,11 +225250,11 @@ function connectorSkillDisplayRows(connectorSkills, enabledConnectors) {
|
|
|
225024
225250
|
...s2.version !== void 0 ? { version: s2.version } : {}
|
|
225025
225251
|
}));
|
|
225026
225252
|
}
|
|
225027
|
-
var
|
|
225253
|
+
var import_node_crypto51;
|
|
225028
225254
|
var init_skill_materializer = __esm({
|
|
225029
225255
|
"../server/src/domains/actors/skill-materializer.ts"() {
|
|
225030
225256
|
"use strict";
|
|
225031
|
-
|
|
225257
|
+
import_node_crypto51 = require("node:crypto");
|
|
225032
225258
|
}
|
|
225033
225259
|
});
|
|
225034
225260
|
|
|
@@ -226596,7 +226822,7 @@ function createActorsDomain(opts) {
|
|
|
226596
226822
|
...kernel !== void 0 ? { onRolesChanged: (a, r) => kernel.setActorRoles(a, r) } : {},
|
|
226597
226823
|
audit: async (entry) => {
|
|
226598
226824
|
await opts.audit?.({
|
|
226599
|
-
id: `reg_${(0,
|
|
226825
|
+
id: `reg_${(0, import_node_crypto52.randomUUID)()}`,
|
|
226600
226826
|
actor: entry.by,
|
|
226601
226827
|
kind: "registry_change",
|
|
226602
226828
|
target: entry.actorId,
|
|
@@ -226636,11 +226862,11 @@ function createActorsDomain(opts) {
|
|
|
226636
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 } : {} })
|
|
226637
226863
|
};
|
|
226638
226864
|
}
|
|
226639
|
-
var
|
|
226865
|
+
var import_node_crypto52;
|
|
226640
226866
|
var init_actors = __esm({
|
|
226641
226867
|
"../server/src/domains/actors/index.ts"() {
|
|
226642
226868
|
"use strict";
|
|
226643
|
-
|
|
226869
|
+
import_node_crypto52 = require("node:crypto");
|
|
226644
226870
|
init_service5();
|
|
226645
226871
|
init_routes3();
|
|
226646
226872
|
init_service5();
|
|
@@ -228138,6 +228364,7 @@ function buildWorkorderActivity(input) {
|
|
|
228138
228364
|
const nodeCancelledAt = node2?.cancelledAt ?? null;
|
|
228139
228365
|
const name = nodeName(nodeId);
|
|
228140
228366
|
let fold2 = null;
|
|
228367
|
+
let handoverFold = null;
|
|
228141
228368
|
for (const [idx, w2] of works.entries()) {
|
|
228142
228369
|
const next = works[idx + 1];
|
|
228143
228370
|
const artifacts = artifactsByWork.get(w2.id) ?? [];
|
|
@@ -228147,6 +228374,7 @@ function buildWorkorderActivity(input) {
|
|
|
228147
228374
|
const reassigned = !!next && next.assigneeActorId !== w2.assigneeActorId;
|
|
228148
228375
|
const killedByPlan = !!(w2.deadAt || w2.cancelledAt) && !!next && (reassigned || (next.nodeVersion ?? 0) > (w2.nodeVersion ?? 0));
|
|
228149
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;
|
|
228150
228378
|
if (failedRound && fold2) {
|
|
228151
228379
|
fold2.traceWorkIds.push(w2.id);
|
|
228152
228380
|
cardOfWork.set(w2.id, fold2);
|
|
@@ -228157,6 +228385,16 @@ function buildWorkorderActivity(input) {
|
|
|
228157
228385
|
continue;
|
|
228158
228386
|
}
|
|
228159
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;
|
|
228160
228398
|
const card2 = {
|
|
228161
228399
|
/* 卡 id = 这一轮的 workId(连败折叠时取第一轮,React key 与滚动锚点因此稳定)。 */
|
|
228162
228400
|
id: `work:${w2.id}`,
|
|
@@ -228204,6 +228442,10 @@ function buildWorkorderActivity(input) {
|
|
|
228204
228442
|
card2.stuckReason = stuckKind;
|
|
228205
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));
|
|
228206
228444
|
fold2 = card2;
|
|
228445
|
+
} else if (handedOverRound) {
|
|
228446
|
+
card2.phase = "done";
|
|
228447
|
+
card2.status = ACTIVITY_COPY.stageHandedOver(name);
|
|
228448
|
+
handoverFold = card2;
|
|
228207
228449
|
} else if (w2.endedAt) {
|
|
228208
228450
|
card2.phase = "running";
|
|
228209
228451
|
card2.status = ACTIVITY_COPY.awaitingConclude(name);
|
|
@@ -228867,8 +229109,20 @@ var init_activity2 = __esm({
|
|
|
228867
229109
|
/**
|
|
228868
229110
|
* 引擎判卷 success、`endedAt` 也写了,却始终没有 `work.conclude`:**交了稿没收口**。
|
|
228869
229111
|
* 如实说这一档,不冒充「正在处理」——后者把一轮早就结束的执行画成还在跑。
|
|
229112
|
+
* 只剩**节点最新一轮**会落到这里;同节点已有下一轮接手的,见 {@link stageHandedOver}。
|
|
228870
229113
|
*/
|
|
228871
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`,
|
|
228872
229126
|
/** `works.status=retry`:这一轮没跑成,等引擎重派。谁按的重试由 `plan.node_retry` 补进这句。 */
|
|
228873
229127
|
awaitingRedispatch: (executor, node2) => `${executor} \u8FD9\u4E00\u8F6E\u6CA1\u8DD1\u6210\u300A${node2}\u300B\uFF0C\u7B49\u5F85\u91CD\u6D3E\u3002`,
|
|
228874
229128
|
doneAwaitingReview: (name) => `\u300A${name}\u300B\u5DF2\u5B8C\u6210\uFF0C\u7B49\u5F85\u5BA1\u6838\u3002`,
|
|
@@ -229840,7 +230094,7 @@ async function buildChatPreview(chatStore, sessionId, who) {
|
|
|
229840
230094
|
async function buildChatInbox(chatStore, markers, me, resolveActor, excludeChildSessions) {
|
|
229841
230095
|
const sessions = await chatStore.listSessions(me);
|
|
229842
230096
|
const byScope = new Map(markers.map((m2) => [m2.scope, m2]));
|
|
229843
|
-
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);
|
|
229844
230098
|
const excluded = excludeChildSessions ? new Set(await excludeChildSessions(unread.map((s2) => s2.id)).catch(() => [])) : /* @__PURE__ */ new Set();
|
|
229845
230099
|
const out = [];
|
|
229846
230100
|
let previewsFetched = 0;
|
|
@@ -230110,11 +230364,11 @@ function fromRow(row) {
|
|
|
230110
230364
|
for (const [k2, v2] of opt) if (v2 !== void 0 && v2 !== null) r[k2] = v2;
|
|
230111
230365
|
return r;
|
|
230112
230366
|
}
|
|
230113
|
-
var
|
|
230367
|
+
var import_node_crypto53, import_node_fs14, DEFAULT_PAGE, MAX_PAGE, pageSize, MemoryNotificationStore, ident3, iso2, str2, PostgresNotificationStore;
|
|
230114
230368
|
var init_notification_store = __esm({
|
|
230115
230369
|
"../server/src/domains/collab/notification-store.ts"() {
|
|
230116
230370
|
"use strict";
|
|
230117
|
-
|
|
230371
|
+
import_node_crypto53 = require("node:crypto");
|
|
230118
230372
|
import_node_fs14 = __toESM(require("node:fs"), 1);
|
|
230119
230373
|
DEFAULT_PAGE = 50;
|
|
230120
230374
|
MAX_PAGE = 200;
|
|
@@ -230147,7 +230401,7 @@ var init_notification_store = __esm({
|
|
|
230147
230401
|
async insert(n) {
|
|
230148
230402
|
const existing = this.findLive(n.recipient, n.sourceKey, n.category);
|
|
230149
230403
|
if (existing) return existing;
|
|
230150
|
-
const row = { ...n, id: `ntf:${(0,
|
|
230404
|
+
const row = { ...n, id: `ntf:${(0, import_node_crypto53.randomUUID)()}`, updatedAt: n.enteredAt };
|
|
230151
230405
|
this.rows.set(row.id, row);
|
|
230152
230406
|
this.save();
|
|
230153
230407
|
return row;
|
|
@@ -230270,7 +230524,7 @@ var init_notification_store = __esm({
|
|
|
230270
230524
|
return new _PostgresNotificationStore(sql, schema);
|
|
230271
230525
|
}
|
|
230272
230526
|
async insert(n) {
|
|
230273
|
-
const id = `ntf:${(0,
|
|
230527
|
+
const id = `ntf:${(0, import_node_crypto53.randomUUID)()}`;
|
|
230274
230528
|
const r = await this.sql.query(
|
|
230275
230529
|
`INSERT INTO ${this.t} (id, recipient, category, source_key, kind, workorder_id, node_id, card_id, actor_id,
|
|
230276
230530
|
title, workspace_title, entered_at, updated_at, status, read_at, item)
|
|
@@ -231221,13 +231475,13 @@ function nameKey(name) {
|
|
|
231221
231475
|
function cleanName(name) {
|
|
231222
231476
|
return name.trim().replace(/\s+/g, " ");
|
|
231223
231477
|
}
|
|
231224
|
-
var import_node_fs15, import_node_path21,
|
|
231478
|
+
var import_node_fs15, import_node_path21, import_node_crypto54, SEP, keyOf, prefixOf, MemoryWorkorderTagStore, FileWorkorderTagStore;
|
|
231225
231479
|
var init_tags = __esm({
|
|
231226
231480
|
"../server/src/domains/collab/tags.ts"() {
|
|
231227
231481
|
"use strict";
|
|
231228
231482
|
import_node_fs15 = __toESM(require("node:fs"), 1);
|
|
231229
231483
|
import_node_path21 = __toESM(require("node:path"), 1);
|
|
231230
|
-
|
|
231484
|
+
import_node_crypto54 = __toESM(require("node:crypto"), 1);
|
|
231231
231485
|
SEP = "::";
|
|
231232
231486
|
keyOf = (companyId, id) => `${companyId}${SEP}${id}`;
|
|
231233
231487
|
prefixOf = (companyId) => `${companyId}${SEP}`;
|
|
@@ -231245,7 +231499,7 @@ var init_tags = __esm({
|
|
|
231245
231499
|
if (!name) return null;
|
|
231246
231500
|
if (this.entries(companyId).some((t) => nameKey(t.name) === nameKey(name))) return null;
|
|
231247
231501
|
const tag = {
|
|
231248
|
-
id: `tag-${
|
|
231502
|
+
id: `tag-${import_node_crypto54.default.randomBytes(6).toString("hex")}`,
|
|
231249
231503
|
name,
|
|
231250
231504
|
...input.color?.trim() ? { color: input.color.trim() } : {},
|
|
231251
231505
|
...input.description?.trim() ? { description: input.description.trim() } : {}
|
|
@@ -232561,11 +232815,11 @@ async function isEmployedElsewhere(store, companyId, accountId) {
|
|
|
232561
232815
|
const memberships = await store.listMembershipsForAccount(accountId);
|
|
232562
232816
|
return memberships.some((m2) => m2.companyId !== companyId);
|
|
232563
232817
|
}
|
|
232564
|
-
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;
|
|
232565
232819
|
var init_service6 = __esm({
|
|
232566
232820
|
"../server/src/domains/companies/service.ts"() {
|
|
232567
232821
|
"use strict";
|
|
232568
|
-
|
|
232822
|
+
import_node_crypto55 = require("node:crypto");
|
|
232569
232823
|
init_console_url();
|
|
232570
232824
|
ROLES = ["owner", "admin", "member"];
|
|
232571
232825
|
INVITABLE_ROLES = ["admin", "member"];
|
|
@@ -232657,7 +232911,7 @@ var init_service6 = __esm({
|
|
|
232657
232911
|
const existing = await this.store.getAccountByEmail(normalized4);
|
|
232658
232912
|
if (existing) return existing;
|
|
232659
232913
|
const account = {
|
|
232660
|
-
id: `actor:human:${(0,
|
|
232914
|
+
id: `actor:human:${(0, import_node_crypto55.randomUUID)()}`,
|
|
232661
232915
|
email: normalized4,
|
|
232662
232916
|
name: name ?? normalized4,
|
|
232663
232917
|
status: "active"
|
|
@@ -232866,7 +233120,7 @@ var init_service6 = __esm({
|
|
|
232866
233120
|
}
|
|
232867
233121
|
const nowMs = Date.parse(this.now());
|
|
232868
233122
|
const invitation = {
|
|
232869
|
-
id: `invitation:${(0,
|
|
233123
|
+
id: `invitation:${(0, import_node_crypto55.randomUUID)()}`,
|
|
232870
233124
|
companyId,
|
|
232871
233125
|
email: mail,
|
|
232872
233126
|
role,
|
|
@@ -232997,7 +233251,7 @@ var init_service6 = __esm({
|
|
|
232997
233251
|
const nowMs = Date.parse(this.now());
|
|
232998
233252
|
const link = {
|
|
232999
233253
|
companyId,
|
|
233000
|
-
token: (0,
|
|
233254
|
+
token: (0, import_node_crypto55.randomBytes)(INVITE_LINK_TOKEN_BYTES).toString("base64url"),
|
|
233001
233255
|
role: INVITE_LINK_ROLE,
|
|
233002
233256
|
createdAt: new Date(nowMs).toISOString(),
|
|
233003
233257
|
expiresAt: new Date(nowMs + INVITE_LINK_TTL_MS).toISOString(),
|
|
@@ -233054,7 +233308,7 @@ var init_service6 = __esm({
|
|
|
233054
233308
|
const reusable = existing.find((inv) => !this.isExpired(inv));
|
|
233055
233309
|
if (reusable) return reusable;
|
|
233056
233310
|
const invitation = {
|
|
233057
|
-
id: `invitation:${(0,
|
|
233311
|
+
id: `invitation:${(0, import_node_crypto55.randomUUID)()}`,
|
|
233058
233312
|
companyId: link.companyId,
|
|
233059
233313
|
email: mail,
|
|
233060
233314
|
role: link.role,
|
|
@@ -233292,11 +233546,11 @@ var init_service6 = __esm({
|
|
|
233292
233546
|
});
|
|
233293
233547
|
|
|
233294
233548
|
// ../server/src/domains/companies/offboarding.ts
|
|
233295
|
-
var
|
|
233549
|
+
var import_node_crypto56, MemberOffboardingService;
|
|
233296
233550
|
var init_offboarding = __esm({
|
|
233297
233551
|
"../server/src/domains/companies/offboarding.ts"() {
|
|
233298
233552
|
"use strict";
|
|
233299
|
-
|
|
233553
|
+
import_node_crypto56 = require("node:crypto");
|
|
233300
233554
|
init_service6();
|
|
233301
233555
|
MemberOffboardingService = class {
|
|
233302
233556
|
store;
|
|
@@ -233368,7 +233622,7 @@ var init_offboarding = __esm({
|
|
|
233368
233622
|
const { ownedAgents, inFlight } = await this.snapshot(companyId, accountId);
|
|
233369
233623
|
const at = this.now();
|
|
233370
233624
|
const started = await this.store.startMemberOffboarding({
|
|
233371
|
-
operationId: `off:${(0,
|
|
233625
|
+
operationId: `off:${(0, import_node_crypto56.randomUUID)()}`,
|
|
233372
233626
|
companyId,
|
|
233373
233627
|
accountId,
|
|
233374
233628
|
initiatedBy,
|
|
@@ -233878,18 +234132,18 @@ var init_routes6 = __esm({
|
|
|
233878
234132
|
|
|
233879
234133
|
// ../server/src/domains/companies/agent-credentials.ts
|
|
233880
234134
|
function hashAgentToken(token, secret) {
|
|
233881
|
-
return HASH_PREFIX + (0,
|
|
234135
|
+
return HASH_PREFIX + (0, import_node_crypto57.createHmac)("sha256", secret).update(`agent-token:${token}`).digest("base64url");
|
|
233882
234136
|
}
|
|
233883
234137
|
function safeEqual(a, b2) {
|
|
233884
234138
|
const ba = Buffer.from(a);
|
|
233885
234139
|
const bb = Buffer.from(b2);
|
|
233886
|
-
return ba.length === bb.length && (0,
|
|
234140
|
+
return ba.length === bb.length && (0, import_node_crypto57.timingSafeEqual)(ba, bb);
|
|
233887
234141
|
}
|
|
233888
|
-
var
|
|
234142
|
+
var import_node_crypto57, HASH_PREFIX, TOKEN_PREFIX, AgentCredentialService;
|
|
233889
234143
|
var init_agent_credentials = __esm({
|
|
233890
234144
|
"../server/src/domains/companies/agent-credentials.ts"() {
|
|
233891
234145
|
"use strict";
|
|
233892
|
-
|
|
234146
|
+
import_node_crypto57 = require("node:crypto");
|
|
233893
234147
|
init_service6();
|
|
233894
234148
|
HASH_PREFIX = "ac1$";
|
|
233895
234149
|
TOKEN_PREFIX = "oak_";
|
|
@@ -233914,7 +234168,7 @@ var init_agent_credentials = __esm({
|
|
|
233914
234168
|
if (employee.status !== "active") {
|
|
233915
234169
|
throw new CompanyError(409, "AGENT_LEFT", `\u6570\u5B57\u5458\u5DE5\u5DF2\u79BB\u5F00\uFF0C\u4E0D\u80FD\u7B7E\u53D1\u51ED\u8BC1\uFF1A${agentId}`);
|
|
233916
234170
|
}
|
|
233917
|
-
const token = `${TOKEN_PREFIX}${(0,
|
|
234171
|
+
const token = `${TOKEN_PREFIX}${(0, import_node_crypto57.randomBytes)(32).toString("base64url")}`;
|
|
233918
234172
|
const credential = {
|
|
233919
234173
|
tokenHash: hashAgentToken(token, this.secret),
|
|
233920
234174
|
companyId,
|
|
@@ -234352,7 +234606,7 @@ function gatewayInstanceSlug(gatewayUrl) {
|
|
|
234352
234606
|
}
|
|
234353
234607
|
function connectInstanceName(gatewayUrl, token, companyId) {
|
|
234354
234608
|
const scope2 = companyId?.trim();
|
|
234355
|
-
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";
|
|
234356
234610
|
const base = gatewayInstanceSlug(gatewayUrl);
|
|
234357
234611
|
return base.slice(0, Math.max(1, 64 - suffix.length - 1)) + "-" + suffix;
|
|
234358
234612
|
}
|
|
@@ -234681,12 +234935,12 @@ function buildNpxCmd(p2) {
|
|
|
234681
234935
|
const prefix = daemonNpmPrefix();
|
|
234682
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)}`;
|
|
234683
234937
|
}
|
|
234684
|
-
var
|
|
234938
|
+
var import_node_crypto58;
|
|
234685
234939
|
var init_connect_script = __esm({
|
|
234686
234940
|
"../server/src/domains/nodes/connect-script.ts"() {
|
|
234687
234941
|
"use strict";
|
|
234688
234942
|
init_src();
|
|
234689
|
-
|
|
234943
|
+
import_node_crypto58 = require("node:crypto");
|
|
234690
234944
|
}
|
|
234691
234945
|
});
|
|
234692
234946
|
|
|
@@ -235293,7 +235547,7 @@ function nodesDomain(deps) {
|
|
|
235293
235547
|
}
|
|
235294
235548
|
deps.enrollTokens.setIssuedNodeId(enrollToken, nodeId);
|
|
235295
235549
|
} else {
|
|
235296
|
-
nodeId = `node-${(0,
|
|
235550
|
+
nodeId = `node-${(0, import_node_crypto59.randomUUID)().slice(0, 8)}`;
|
|
235297
235551
|
deps.enrollTokens.setIssuedNodeId(enrollToken, nodeId);
|
|
235298
235552
|
}
|
|
235299
235553
|
const existingNode = await deps.nodeStore.getNode(nodeId);
|
|
@@ -235478,14 +235732,14 @@ function normalizeGatewayUrl(raw) {
|
|
|
235478
235732
|
}
|
|
235479
235733
|
}
|
|
235480
235734
|
function newNodeId() {
|
|
235481
|
-
return "node-" + (0,
|
|
235735
|
+
return "node-" + (0, import_node_crypto59.randomUUID)().replace(/-/g, "").slice(0, 12);
|
|
235482
235736
|
}
|
|
235483
|
-
var
|
|
235737
|
+
var import_node_crypto59, import_node_fs16, import_node_url6, import_node_path22;
|
|
235484
235738
|
var init_routes7 = __esm({
|
|
235485
235739
|
"../server/src/domains/nodes/routes.ts"() {
|
|
235486
235740
|
"use strict";
|
|
235487
235741
|
init_runtime_status();
|
|
235488
|
-
|
|
235742
|
+
import_node_crypto59 = require("node:crypto");
|
|
235489
235743
|
import_node_fs16 = require("node:fs");
|
|
235490
235744
|
import_node_url6 = require("node:url");
|
|
235491
235745
|
import_node_path22 = require("node:path");
|
|
@@ -236676,7 +236930,7 @@ function createBundle(root, target, input) {
|
|
|
236676
236930
|
}
|
|
236677
236931
|
}
|
|
236678
236932
|
const bytes2 = fs25.statSync(absBundle).size;
|
|
236679
|
-
const digest = (0,
|
|
236933
|
+
const digest = (0, import_node_crypto60.createHash)("sha256").update(fs25.readFileSync(absBundle)).digest("hex");
|
|
236680
236934
|
const relBase = `inputs/git-bundles/${safeRepo}-${commit.slice(0, 12)}`;
|
|
236681
236935
|
return {
|
|
236682
236936
|
absoluteBundlePath: absBundle,
|
|
@@ -236772,12 +237026,12 @@ function classifyGitError(fallback, err, where) {
|
|
|
236772
237026
|
function oneLine(msg) {
|
|
236773
237027
|
return msg.split("\n").map((s2) => s2.trim()).filter(Boolean).slice(0, 3).join(" ");
|
|
236774
237028
|
}
|
|
236775
|
-
var import_node_child_process16,
|
|
237029
|
+
var import_node_child_process16, import_node_crypto60, fs25, os7, path24, GitReadonlyBundleError, HEX40, FETCH_TIMEOUT_MS2;
|
|
236776
237030
|
var init_readonly_bundle = __esm({
|
|
236777
237031
|
"../server/src/git/readonly-bundle.ts"() {
|
|
236778
237032
|
"use strict";
|
|
236779
237033
|
import_node_child_process16 = require("node:child_process");
|
|
236780
|
-
|
|
237034
|
+
import_node_crypto60 = require("node:crypto");
|
|
236781
237035
|
fs25 = __toESM(require("node:fs"), 1);
|
|
236782
237036
|
os7 = __toESM(require("node:os"), 1);
|
|
236783
237037
|
path24 = __toESM(require("node:path"), 1);
|
|
@@ -236797,8 +237051,9 @@ var init_readonly_bundle = __esm({
|
|
|
236797
237051
|
|
|
236798
237052
|
// ../server/src/domains/collab/create-seeded-workorder.ts
|
|
236799
237053
|
function makeSeededWorkorderCreator(deps) {
|
|
236800
|
-
const
|
|
236801
|
-
|
|
237054
|
+
const locks = createKeyedMutex();
|
|
237055
|
+
const genWorkspace = deps.genWorkspace ?? (() => `ws:wo-${(0, import_node_crypto61.randomUUID)().slice(0, 8)}`);
|
|
237056
|
+
const create = async (input) => {
|
|
236802
237057
|
const company = input.companyId && deps.resolveCompany ? await deps.resolveCompany(input.companyId) : void 0;
|
|
236803
237058
|
const kernel = company?.kernel ?? deps.kernel;
|
|
236804
237059
|
const blobs = company?.blobs ?? deps.blobs;
|
|
@@ -236806,10 +237061,9 @@ function makeSeededWorkorderCreator(deps) {
|
|
|
236806
237061
|
const artifactState = company ? company.artifactState : deps.artifactState;
|
|
236807
237062
|
const workorderDrafts = company ? company.workorderDrafts : deps.workorderDrafts;
|
|
236808
237063
|
const workspace = input.idempotencyKey ? workspaceForKey(input.idempotencyKey) : genWorkspace();
|
|
236809
|
-
|
|
236810
|
-
|
|
236811
|
-
|
|
236812
|
-
}
|
|
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;
|
|
236813
237067
|
if (artifactState && input.projectId) {
|
|
236814
237068
|
await bindWorkorderProject({
|
|
236815
237069
|
workOrderId: workspace,
|
|
@@ -236818,6 +237072,13 @@ function makeSeededWorkorderCreator(deps) {
|
|
|
236818
237072
|
...deps.onWarn ? { onWarn: deps.onWarn } : {}
|
|
236819
237073
|
});
|
|
236820
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);
|
|
236821
237082
|
const planned = await buildDynamicWorkorderPlan({
|
|
236822
237083
|
// requestedType 在 agentPlan 路仅用于兜底;给第一个节点类型即可,图仍以 plan 为准。
|
|
236823
237084
|
requestedType: input.plan.nodes[0]?.type ?? "prd",
|
|
@@ -236874,44 +237135,41 @@ function makeSeededWorkorderCreator(deps) {
|
|
|
236874
237135
|
}
|
|
236875
237136
|
};
|
|
236876
237137
|
}
|
|
236877
|
-
await kernel.applyIntervention(planned.plan, preview2.baseSeqs, input.humanActorId ?? input.actor);
|
|
236878
|
-
|
|
236879
|
-
|
|
236880
|
-
|
|
236881
|
-
|
|
236882
|
-
|
|
236883
|
-
await
|
|
236884
|
-
}
|
|
236885
|
-
|
|
236886
|
-
await artifactState.setWorkspaceDispatchHold(workspace, true);
|
|
236887
|
-
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();
|
|
236888
237147
|
}
|
|
236889
|
-
return { workspace, rootArtifactId: briefId, spawned: planned.spawned };
|
|
236890
237148
|
};
|
|
236891
237149
|
}
|
|
236892
237150
|
function workspaceForKey(key2) {
|
|
236893
|
-
return `ws:wo-${(0,
|
|
237151
|
+
return `ws:wo-${(0, import_node_crypto61.createHash)("sha256").update(key2).digest("hex").slice(0, 8)}`;
|
|
236894
237152
|
}
|
|
236895
|
-
function existingWorkorder(
|
|
236896
|
-
|
|
236897
|
-
|
|
236898
|
-
|
|
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}`);
|
|
236899
237157
|
return {
|
|
236900
237158
|
workspace,
|
|
236901
237159
|
rootArtifactId: seed.id,
|
|
236902
|
-
|
|
236903
|
-
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 }))
|
|
236904
237161
|
};
|
|
236905
237162
|
}
|
|
236906
|
-
var
|
|
237163
|
+
var import_node_crypto61;
|
|
236907
237164
|
var init_create_seeded_workorder = __esm({
|
|
236908
237165
|
"../server/src/domains/collab/create-seeded-workorder.ts"() {
|
|
236909
237166
|
"use strict";
|
|
236910
|
-
|
|
237167
|
+
import_node_crypto61 = require("node:crypto");
|
|
236911
237168
|
init_uncategorized_project();
|
|
236912
237169
|
init_src();
|
|
236913
237170
|
init_planner();
|
|
236914
|
-
|
|
237171
|
+
init_keyed_mutex();
|
|
237172
|
+
init_initialize_workorder();
|
|
236915
237173
|
}
|
|
236916
237174
|
});
|
|
236917
237175
|
|
|
@@ -238335,12 +238593,12 @@ function stateFromAttempt(attempt, handoff, checkpoint, now, stalledAfterMs, ope
|
|
|
238335
238593
|
if (attempt.status === "no-output") return handoff?.unresolvedIssues.length ? "blocked" : "no_change";
|
|
238336
238594
|
return "failed";
|
|
238337
238595
|
}
|
|
238338
|
-
var
|
|
238596
|
+
var import_node_crypto62, BLOCKING_STATES, HANDOFF_OUTCOMES2, RESUME_EXTERNAL_EFFECT_LIMIT, RESUME_SNAPSHOT_PREFIX, RESUME_SNAPSHOT_SUFFIX, ExecutionContinuityService;
|
|
238339
238597
|
var init_service8 = __esm({
|
|
238340
238598
|
"../server/src/domains/execution-continuity/service.ts"() {
|
|
238341
238599
|
"use strict";
|
|
238342
238600
|
init_src();
|
|
238343
|
-
|
|
238601
|
+
import_node_crypto62 = require("node:crypto");
|
|
238344
238602
|
init_src7();
|
|
238345
238603
|
BLOCKING_STATES = /* @__PURE__ */ new Set(["stalled", "failed", "blocked"]);
|
|
238346
238604
|
HANDOFF_OUTCOMES2 = /* @__PURE__ */ new Set(["succeeded", "no-output", "failed", "cancelled", "timeout", "orphaned"]);
|
|
@@ -238571,7 +238829,7 @@ var init_service8 = __esm({
|
|
|
238571
238829
|
if (typeof expectedHash !== "string" || !this.readBundleFile) return null;
|
|
238572
238830
|
const injectedResume = this.readBundleFile(attempt.id, "execution/RESUME.md");
|
|
238573
238831
|
if (!injectedResume) return null;
|
|
238574
|
-
const actualHash = (0,
|
|
238832
|
+
const actualHash = (0, import_node_crypto62.createHash)("sha256").update(injectedResume).digest("hex");
|
|
238575
238833
|
if (actualHash !== expectedHash) return null;
|
|
238576
238834
|
const recoverySnapshot = parseResumePackSnapshot(injectedResume);
|
|
238577
238835
|
if (!recoverySnapshot || recoverySnapshot.scenario !== "redispatch" || !recoverySnapshot.previousAttempt || recoverySnapshot.node.nodeId !== attempt.nodeId || recoverySnapshot.jobKey !== attempt.jobKey || recoverySnapshot.part !== attempt.part) return null;
|
|
@@ -239698,7 +239956,7 @@ function createChatSessionsDomain(opts) {
|
|
|
239698
239956
|
if (!text6.trim()) throw new ApiError(400, "BAD_REQUEST", "text required");
|
|
239699
239957
|
const now = Date.now();
|
|
239700
239958
|
sweepDrafts(now);
|
|
239701
|
-
const id = `cd_${(0,
|
|
239959
|
+
const id = `cd_${(0, import_node_crypto63.randomUUID)()}`;
|
|
239702
239960
|
drafts.set(id, { text: text6, actor: req.auth.actor, expiresAt: now + DRAFT_TTL_MS });
|
|
239703
239961
|
return { status: 201, body: { id, expiresInMs: DRAFT_TTL_MS } };
|
|
239704
239962
|
});
|
|
@@ -239730,6 +239988,13 @@ function createChatSessionsDomain(opts) {
|
|
|
239730
239988
|
...runningParentIds.has(s2.id) ? { hasRunningDelegation: true } : {}
|
|
239731
239989
|
}));
|
|
239732
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
|
+
}
|
|
239733
239998
|
router.get("/api/chat-sessions", async (req) => {
|
|
239734
239999
|
const store2 = await storeFor(req);
|
|
239735
240000
|
if (req.query?.get("analysis") === "all") {
|
|
@@ -239744,7 +240009,8 @@ function createChatSessionsDomain(opts) {
|
|
|
239744
240009
|
}
|
|
239745
240010
|
const analyzedRunId = req.query?.get("analyzedRunId") ?? void 0;
|
|
239746
240011
|
const sessions = analyzedRunId ? await store2.listSessionsByAnalyzedRun(analyzedRunId) : await store2.listSessions(req.auth.actor);
|
|
239747
|
-
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);
|
|
239748
240014
|
return { status: 200, body: { items } };
|
|
239749
240015
|
});
|
|
239750
240016
|
router.post("/api/chat-sessions", async (req) => {
|
|
@@ -239758,7 +240024,7 @@ function createChatSessionsDomain(opts) {
|
|
|
239758
240024
|
const runtimeId = await currentRuntimeId(body2.aiActorId) ?? "unknown";
|
|
239759
240025
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
239760
240026
|
const session = {
|
|
239761
|
-
id: (0,
|
|
240027
|
+
id: (0, import_node_crypto63.randomUUID)(),
|
|
239762
240028
|
humanActorId: req.auth.actor,
|
|
239763
240029
|
// 注:这里**刻意不写 companyId**。新会话要不要带公司归属,按 ws:wo-6d588f8e 的 ADR
|
|
239764
240030
|
// (每公司 schema、最终移除表内 company 列)统一定,不在本节点自行发明。
|
|
@@ -239864,7 +240130,7 @@ function createChatSessionsDomain(opts) {
|
|
|
239864
240130
|
if (body2.role !== "user" && body2.role !== "assistant") throw new ApiError(400, "BAD_REQUEST", "role must be user or assistant");
|
|
239865
240131
|
const role = body2.role;
|
|
239866
240132
|
const msg = await store2.appendMessage({
|
|
239867
|
-
id: (0,
|
|
240133
|
+
id: (0, import_node_crypto63.randomUUID)(),
|
|
239868
240134
|
sessionId: req.params.id,
|
|
239869
240135
|
role,
|
|
239870
240136
|
content: role === "user" ? stripInjectedChatContext(body2.content) : body2.content,
|
|
@@ -239905,7 +240171,7 @@ function createChatSessionsDomain(opts) {
|
|
|
239905
240171
|
const known = key2 ? cur.find((x2) => x2.clientKey === key2) : void 0;
|
|
239906
240172
|
if (!known && cur.length >= QUEUE_MAX) throw new ApiError(409, "QUEUE_FULL", `\u961F\u5217\u5DF2\u6EE1\uFF08\u4E0A\u9650 ${QUEUE_MAX} \u6761\uFF09`);
|
|
239907
240173
|
const item = await store.enqueuePendingMessage({
|
|
239908
|
-
id: (0,
|
|
240174
|
+
id: (0, import_node_crypto63.randomUUID)(),
|
|
239909
240175
|
chatSessionId: sid,
|
|
239910
240176
|
text: text6,
|
|
239911
240177
|
...attachments.length ? { attachments } : {},
|
|
@@ -240454,12 +240720,12 @@ function createChatSessionsDomain(opts) {
|
|
|
240454
240720
|
});
|
|
240455
240721
|
};
|
|
240456
240722
|
}
|
|
240457
|
-
var
|
|
240723
|
+
var import_node_crypto63, DEFAULT_SNAPSHOT_ITEMS, MAX_SNAPSHOT_ITEMS;
|
|
240458
240724
|
var init_chat_sessions2 = __esm({
|
|
240459
240725
|
"../server/src/domains/chat-sessions/index.ts"() {
|
|
240460
240726
|
"use strict";
|
|
240461
240727
|
init_file_limits2();
|
|
240462
|
-
|
|
240728
|
+
import_node_crypto63 = require("node:crypto");
|
|
240463
240729
|
init_src();
|
|
240464
240730
|
init_chat_session();
|
|
240465
240731
|
init_persistent_files();
|
|
@@ -241850,7 +242116,7 @@ function busyError(chatSessionId, blockedBy) {
|
|
|
241850
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`;
|
|
241851
242117
|
}
|
|
241852
242118
|
function genWebhookToken() {
|
|
241853
|
-
return `owt_${(0,
|
|
242119
|
+
return `owt_${(0, import_node_crypto64.randomBytes)(32).toString("base64url")}`;
|
|
241854
242120
|
}
|
|
241855
242121
|
function validateTitleTemplate(tpl) {
|
|
241856
242122
|
const residue = tpl.replace(DATE_TOKEN, "");
|
|
@@ -241906,11 +242172,11 @@ function appendSourceNote(brief, automation, source, atIso) {
|
|
|
241906
242172
|
---
|
|
241907
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`;
|
|
241908
242174
|
}
|
|
241909
|
-
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;
|
|
241910
242176
|
var init_service9 = __esm({
|
|
241911
242177
|
"../server/src/domains/automations/service.ts"() {
|
|
241912
242178
|
"use strict";
|
|
241913
|
-
|
|
242179
|
+
import_node_crypto64 = require("node:crypto");
|
|
241914
242180
|
init_src();
|
|
241915
242181
|
init_registry3();
|
|
241916
242182
|
init_attribution();
|
|
@@ -242724,11 +242990,11 @@ function verifySignature(rawBody, headers, secret) {
|
|
|
242724
242990
|
if (!secret) return "not_required";
|
|
242725
242991
|
const given = header1(headers, "x-hub-signature-256");
|
|
242726
242992
|
if (!given) return "missing";
|
|
242727
|
-
const expected = `sha256=${(0,
|
|
242993
|
+
const expected = `sha256=${(0, import_node_crypto65.createHmac)("sha256", secret).update(rawBody).digest("hex")}`;
|
|
242728
242994
|
const a = Buffer.from(given);
|
|
242729
242995
|
const b2 = Buffer.from(expected);
|
|
242730
242996
|
if (a.length !== b2.length) return "invalid";
|
|
242731
|
-
return (0,
|
|
242997
|
+
return (0, import_node_crypto65.timingSafeEqual)(a, b2) ? "valid" : "invalid";
|
|
242732
242998
|
}
|
|
242733
242999
|
function eventAllowed(filters, envelope) {
|
|
242734
243000
|
if (!filters || filters.length === 0) return true;
|
|
@@ -242758,11 +243024,11 @@ function splitEvent(envelope) {
|
|
|
242758
243024
|
}
|
|
242759
243025
|
return { eventName, actionCandidates: candidates };
|
|
242760
243026
|
}
|
|
242761
|
-
var
|
|
243027
|
+
var import_node_crypto65, MAX_BODY_BYTES, AutomationWebhookService, header1, PROVIDER_PREFIXES;
|
|
242762
243028
|
var init_webhook = __esm({
|
|
242763
243029
|
"../server/src/domains/automations/webhook.ts"() {
|
|
242764
243030
|
"use strict";
|
|
242765
|
-
|
|
243031
|
+
import_node_crypto65 = require("node:crypto");
|
|
242766
243032
|
MAX_BODY_BYTES = 256 * 1024;
|
|
242767
243033
|
AutomationWebhookService = class {
|
|
242768
243034
|
store;
|
|
@@ -243910,7 +244176,7 @@ function playbooksDomain(opts) {
|
|
|
243910
244176
|
opts.overrides.set(companyOf(req), ref2, nodeKey, nextOverride);
|
|
243911
244177
|
try {
|
|
243912
244178
|
await opts.audit?.({
|
|
243913
|
-
id: `reg_${(0,
|
|
244179
|
+
id: `reg_${(0, import_node_crypto66.randomUUID)()}`,
|
|
243914
244180
|
actor: req.auth.actor,
|
|
243915
244181
|
kind: "registry_change",
|
|
243916
244182
|
target: `playbook:${ref2}#${nodeKey}`,
|
|
@@ -243927,11 +244193,11 @@ function playbooksDomain(opts) {
|
|
|
243927
244193
|
});
|
|
243928
244194
|
};
|
|
243929
244195
|
}
|
|
243930
|
-
var
|
|
244196
|
+
var import_node_crypto66;
|
|
243931
244197
|
var init_routes12 = __esm({
|
|
243932
244198
|
"../server/src/domains/playbooks/routes.ts"() {
|
|
243933
244199
|
"use strict";
|
|
243934
|
-
|
|
244200
|
+
import_node_crypto66 = require("node:crypto");
|
|
243935
244201
|
init_router();
|
|
243936
244202
|
init_registry3();
|
|
243937
244203
|
init_planner();
|
|
@@ -244060,17 +244326,17 @@ function completionFingerprint(workspace, members) {
|
|
|
244060
244326
|
workspace,
|
|
244061
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 }))
|
|
244062
244328
|
});
|
|
244063
|
-
return (0,
|
|
244329
|
+
return (0, import_node_crypto67.createHash)("sha256").update(canonical2).digest("hex");
|
|
244064
244330
|
}
|
|
244065
244331
|
function eventConsumptionKey(args) {
|
|
244066
244332
|
const raw = `project-event:${EVENT_KEY_VERSION}:${args.triggerId}:${args.event}:${args.workspace}:${args.fingerprint}`;
|
|
244067
|
-
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")}`;
|
|
244068
244334
|
}
|
|
244069
|
-
var
|
|
244335
|
+
var import_node_crypto67, EVENT_KEY_VERSION, EMPTY_METRICS, AUTOMATION_EVENT_HANDLERS, ProjectEventPoller;
|
|
244070
244336
|
var init_project_event_poller = __esm({
|
|
244071
244337
|
"../server/src/automations/project-event-poller.ts"() {
|
|
244072
244338
|
"use strict";
|
|
244073
|
-
|
|
244339
|
+
import_node_crypto67 = require("node:crypto");
|
|
244074
244340
|
EVENT_KEY_VERSION = "v1";
|
|
244075
244341
|
EMPTY_METRICS = () => ({
|
|
244076
244342
|
scanDurationMs: 0,
|
|
@@ -244281,7 +244547,7 @@ function remoteAppendInput(hub, nodeId, dispatchId, entry, input, timeoutMs) {
|
|
|
244281
244547
|
if (input.requireConsumptionReceipt && !hub.supportsInputConsumptionReceipts?.(dispatchId)) {
|
|
244282
244548
|
return Promise.resolve({ accepted: false, reason: "consumption-unsupported" });
|
|
244283
244549
|
}
|
|
244284
|
-
const requestId = (0,
|
|
244550
|
+
const requestId = (0, import_node_crypto68.randomUUID)();
|
|
244285
244551
|
const sent = routeToSession(hub, nodeId, dispatchId, { type: "append_input", dispatchId, input, requestId });
|
|
244286
244552
|
if (!sent) return Promise.resolve({ accepted: false, reason: "session-closing", ...unknownIfInterrupting });
|
|
244287
244553
|
return new Promise((resolve10) => {
|
|
@@ -244294,11 +244560,11 @@ function remoteAppendInput(hub, nodeId, dispatchId, entry, input, timeoutMs) {
|
|
|
244294
244560
|
entry.appendWaiters.push({ requestId, requireConsumptionReceipt: input.requireConsumptionReceipt, resolve: resolve10, timer });
|
|
244295
244561
|
});
|
|
244296
244562
|
}
|
|
244297
|
-
var
|
|
244563
|
+
var import_node_crypto68, STASH_TTL_MS, STASH_MAX_FRAMES_PER_ID, STASH_MAX_IDS, DaemonHubAdapter, BindingRouterAdapter, WorkdirBridge;
|
|
244298
244564
|
var init_daemon_adapter = __esm({
|
|
244299
244565
|
"../server/src/daemon-adapter.ts"() {
|
|
244300
244566
|
"use strict";
|
|
244301
|
-
|
|
244567
|
+
import_node_crypto68 = require("node:crypto");
|
|
244302
244568
|
init_src();
|
|
244303
244569
|
STASH_TTL_MS = 5 * 6e4;
|
|
244304
244570
|
STASH_MAX_FRAMES_PER_ID = 500;
|
|
@@ -244648,7 +244914,7 @@ var init_daemon_adapter = __esm({
|
|
|
244648
244914
|
async spawn(job) {
|
|
244649
244915
|
const nodeId = job.binding?.nodeId;
|
|
244650
244916
|
if (!nodeId) throw new Error("DaemonHubAdapter \u9700\u8981 job.binding.nodeId\uFF08\u8DEF\u7531\u9519\u8BEF\uFF09");
|
|
244651
|
-
const dispatchId = job.dispatchId ?? `dispatch:${(0,
|
|
244917
|
+
const dispatchId = job.dispatchId ?? `dispatch:${(0, import_node_crypto68.randomUUID)()}`;
|
|
244652
244918
|
if (job.dispatchId && this.pending.has(dispatchId)) {
|
|
244653
244919
|
return this.recover(dispatchId, nodeId, job.binding?.runtimeKind, job.actor);
|
|
244654
244920
|
}
|
|
@@ -244891,7 +245157,7 @@ var init_daemon_adapter = __esm({
|
|
|
244891
245157
|
return daemon?.meta.supportsWorkdirWalk === true;
|
|
244892
245158
|
}
|
|
244893
245159
|
request(nodeId, buildFrame) {
|
|
244894
|
-
const requestId = (0,
|
|
245160
|
+
const requestId = (0, import_node_crypto68.randomUUID)();
|
|
244895
245161
|
const sent = this.hub.dispatch(nodeId, buildFrame(requestId));
|
|
244896
245162
|
if (!sent) return Promise.resolve({ ok: false, code: "NODE_OFFLINE" });
|
|
244897
245163
|
return new Promise((resolve10) => {
|
|
@@ -244999,14 +245265,14 @@ function classifyPage(page, lastPushedHash, serviceAccount) {
|
|
|
244999
245265
|
if (sha(body2) === lastPushedHash) return { kind: "echo" };
|
|
245000
245266
|
return { kind: "human-edit", content: body2, updatedBy: page.updatedBy };
|
|
245001
245267
|
}
|
|
245002
|
-
var
|
|
245268
|
+
var import_node_crypto69, sha, enc2, dec, MirrorEngine, MapMirrorIdentities;
|
|
245003
245269
|
var init_engine = __esm({
|
|
245004
245270
|
"../server/src/mirror/engine.ts"() {
|
|
245005
245271
|
"use strict";
|
|
245006
|
-
|
|
245272
|
+
import_node_crypto69 = require("node:crypto");
|
|
245007
245273
|
init_src();
|
|
245008
|
-
sha = (s2) => (0,
|
|
245009
|
-
|
|
245274
|
+
sha = (s2) => (0, import_node_crypto69.createHash)("sha256").update(s2, "utf8").digest("hex");
|
|
245275
|
+
enc2 = (s2) => new TextEncoder().encode(s2);
|
|
245010
245276
|
dec = (b2) => new TextDecoder().decode(b2);
|
|
245011
245277
|
MirrorEngine = class {
|
|
245012
245278
|
constructor(deps) {
|
|
@@ -245080,7 +245346,7 @@ var init_engine = __esm({
|
|
|
245080
245346
|
continue;
|
|
245081
245347
|
}
|
|
245082
245348
|
try {
|
|
245083
|
-
const contentRef = await this.deps.blobs.put(
|
|
245349
|
+
const contentRef = await this.deps.blobs.put(enc2(cls.content));
|
|
245084
245350
|
const rev = await this.deps.kernel.proposeRevision({
|
|
245085
245351
|
artifactId,
|
|
245086
245352
|
actor,
|
|
@@ -245266,11 +245532,11 @@ function humanExitCause(exit3) {
|
|
|
245266
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`;
|
|
245267
245533
|
return exit3.errorMessage ? `${base}\uFF1A${exit3.errorMessage.slice(0, 200)}` : base;
|
|
245268
245534
|
}
|
|
245269
|
-
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;
|
|
245270
245536
|
var init_worker = __esm({
|
|
245271
245537
|
"../server/src/coordinator/worker.ts"() {
|
|
245272
245538
|
"use strict";
|
|
245273
|
-
|
|
245539
|
+
import_node_crypto70 = require("node:crypto");
|
|
245274
245540
|
init_src7();
|
|
245275
245541
|
init_identity();
|
|
245276
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
|
|
@@ -245540,7 +245806,7 @@ ${HIGH_RISK_COMMANDS}`;
|
|
|
245540
245806
|
return this.deps.kernel.model.lastSeq.get(artifactId) ?? 0;
|
|
245541
245807
|
}
|
|
245542
245808
|
evaluationKey(kind, artifactId, evidence) {
|
|
245543
|
-
const fingerprint2 = (0,
|
|
245809
|
+
const fingerprint2 = (0, import_node_crypto70.createHash)("sha256").update(JSON.stringify(evidence)).digest("hex");
|
|
245544
245810
|
return `${kind}:${artifactId}:${fingerprint2}`;
|
|
245545
245811
|
}
|
|
245546
245812
|
artifactEvidence(id) {
|
|
@@ -245929,8 +246195,8 @@ ${ctx.nodeFault}
|
|
|
245929
246195
|
const taskWithRejections = rejectedSection ? `${task}
|
|
245930
246196
|
|
|
245931
246197
|
${rejectedSection}` : task;
|
|
245932
|
-
const runtimeSessionId = opts?.resumeSessionId ?? (0,
|
|
245933
|
-
const coordinatorRunId = `coordinate:${(0,
|
|
246198
|
+
const runtimeSessionId = opts?.resumeSessionId ?? (0, import_node_crypto70.randomUUID)();
|
|
246199
|
+
const coordinatorRunId = `coordinate:${(0, import_node_crypto70.randomUUID)()}`;
|
|
245934
246200
|
const taskWithContext = coordinatorContext ? [
|
|
245935
246201
|
taskWithRejections,
|
|
245936
246202
|
``,
|
|
@@ -245974,7 +246240,7 @@ ${rejectedSection}` : task;
|
|
|
245974
246240
|
const startedAtMs = Date.now();
|
|
245975
246241
|
let trajectoryStarted = false;
|
|
245976
246242
|
if (this.deps.trajectory) {
|
|
245977
|
-
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")]));
|
|
245978
246244
|
const session = {
|
|
245979
246245
|
runId: coordinatorRunId,
|
|
245980
246246
|
runtimeSessionId,
|
|
@@ -246180,11 +246446,11 @@ var init_pg_ident = __esm({
|
|
|
246180
246446
|
});
|
|
246181
246447
|
|
|
246182
246448
|
// ../storage/src/postgres.ts
|
|
246183
|
-
var
|
|
246449
|
+
var import_node_crypto71, ident4, isUniqueViolation, PostgresOplogStore, PostgresBlobStore;
|
|
246184
246450
|
var init_postgres = __esm({
|
|
246185
246451
|
"../storage/src/postgres.ts"() {
|
|
246186
246452
|
"use strict";
|
|
246187
|
-
|
|
246453
|
+
import_node_crypto71 = require("node:crypto");
|
|
246188
246454
|
init_pg_ident();
|
|
246189
246455
|
init_esm();
|
|
246190
246456
|
init_src();
|
|
@@ -246364,7 +246630,7 @@ var init_postgres = __esm({
|
|
|
246364
246630
|
return new _PostgresBlobStore(pool, schema);
|
|
246365
246631
|
}
|
|
246366
246632
|
async put(bytes2) {
|
|
246367
|
-
const hash3 = (0,
|
|
246633
|
+
const hash3 = (0, import_node_crypto71.createHash)("sha256").update(bytes2).digest("hex");
|
|
246368
246634
|
await this.pool.query(
|
|
246369
246635
|
`INSERT INTO ${this.t} (hash, bytes, size, content_type) VALUES ($1, $2, $3, $4) ON CONFLICT (hash) DO NOTHING`,
|
|
246370
246636
|
[hash3, Buffer.from(bytes2), bytes2.byteLength, sniffContentType(bytes2) ?? null]
|
|
@@ -254035,14 +254301,22 @@ var init_postgres_chat_items = __esm({
|
|
|
254035
254301
|
* ——此刻起的 chunk 已经算下一段,但那条行还不存在。先写 `message_id = NULL`、行落库后回填,
|
|
254036
254302
|
* 比让写入等一次 DB 往返更安全(等 = 丢帧或阻塞流)。
|
|
254037
254303
|
*
|
|
254038
|
-
* `message_id IS NULL`
|
|
254304
|
+
* `message_id IS NULL` 只能把**已经绑好的**上一段隔开,隔不开**后面**的段:新行落库慢于下一次插话时,
|
|
254305
|
+
* 后一段的 item 同样是 NULL。所以切段回填给 `itemIds`,只更新那一段自己的 item(2026-09-17)。
|
|
254039
254306
|
* 回填**不动** `version`/`turn_version`——归属关系不是 item 内容的一次修订。
|
|
254040
254307
|
*/
|
|
254041
|
-
async bindMessage(sessionId, turnId, messageId) {
|
|
254042
|
-
|
|
254308
|
+
async bindMessage(sessionId, turnId, messageId, itemIds) {
|
|
254309
|
+
if (itemIds && itemIds.length === 0) return 0;
|
|
254310
|
+
const r = itemIds ? await this.pool.query(
|
|
254311
|
+
`UPDATE ${this.s}.chat_items
|
|
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(
|
|
254043
254317
|
`UPDATE ${this.s}.chat_items
|
|
254044
|
-
|
|
254045
|
-
|
|
254318
|
+
SET message_id = $3
|
|
254319
|
+
WHERE session_id = $1 AND turn_id = $2 AND message_id IS NULL AND role = 'assistant'`,
|
|
254046
254320
|
[sessionId, turnId, messageId]
|
|
254047
254321
|
);
|
|
254048
254322
|
return r.rowCount ?? 0;
|
|
@@ -255052,11 +255326,11 @@ var init_postgres_delegations = __esm({
|
|
|
255052
255326
|
});
|
|
255053
255327
|
|
|
255054
255328
|
// ../storage/src/postgres-nodes.ts
|
|
255055
|
-
var
|
|
255329
|
+
var import_node_crypto72, ident13, PostgresNodeStore, PostgresNodeTokenStore, rowToNode, rowToRuntime;
|
|
255056
255330
|
var init_postgres_nodes = __esm({
|
|
255057
255331
|
"../storage/src/postgres-nodes.ts"() {
|
|
255058
255332
|
"use strict";
|
|
255059
|
-
|
|
255333
|
+
import_node_crypto72 = require("node:crypto");
|
|
255060
255334
|
init_pg_ident();
|
|
255061
255335
|
init_esm();
|
|
255062
255336
|
ident13 = (s2) => {
|
|
@@ -255273,7 +255547,7 @@ var init_postgres_nodes = __esm({
|
|
|
255273
255547
|
return store;
|
|
255274
255548
|
}
|
|
255275
255549
|
issue(nodeId) {
|
|
255276
|
-
const token = `ont_${(0,
|
|
255550
|
+
const token = `ont_${(0, import_node_crypto72.randomBytes)(24).toString("base64url")}`;
|
|
255277
255551
|
this.cache.set(token, nodeId);
|
|
255278
255552
|
void this.pool.query(`INSERT INTO ${this.s}.node_tokens (token,node_id) VALUES ($1,$2)`, [token, nodeId]);
|
|
255279
255553
|
return token;
|
|
@@ -255539,11 +255813,11 @@ var init_postgres_type_registry = __esm({
|
|
|
255539
255813
|
});
|
|
255540
255814
|
|
|
255541
255815
|
// ../storage/src/postgres-actor-memory.ts
|
|
255542
|
-
var
|
|
255816
|
+
var import_node_crypto73, matchClause, ident15, PostgresActorMemoryStore, rowToIndexEntry, rowToRecord;
|
|
255543
255817
|
var init_postgres_actor_memory = __esm({
|
|
255544
255818
|
"../storage/src/postgres-actor-memory.ts"() {
|
|
255545
255819
|
"use strict";
|
|
255546
|
-
|
|
255820
|
+
import_node_crypto73 = require("node:crypto");
|
|
255547
255821
|
init_pg_ident();
|
|
255548
255822
|
init_src();
|
|
255549
255823
|
matchClause = (q2) => q2.requireMatch && q2.keywords.length > 0 ? " WHERE m > 0" : "";
|
|
@@ -255753,7 +256027,7 @@ var init_postgres_actor_memory = __esm({
|
|
|
255753
256027
|
}
|
|
255754
256028
|
async write(input, now) {
|
|
255755
256029
|
if (input.memId === void 0) {
|
|
255756
|
-
const memId = `mem:${(0,
|
|
256030
|
+
const memId = `mem:${(0, import_node_crypto73.randomUUID)()}`;
|
|
255757
256031
|
const r2 = await this.pool.query(
|
|
255758
256032
|
`INSERT INTO ${this.s}.actor_memories
|
|
255759
256033
|
(mem_id, actor_id, project_id, keywords, content, version, created_at, updated_at, accessed_at, source_artifact_id, source_session_id)
|
|
@@ -257200,14 +257474,14 @@ function companySchemaName(companyId) {
|
|
|
257200
257474
|
if (typeof companyId !== "string" || !companyId.trim()) {
|
|
257201
257475
|
throw new Error("company schema mapping \u9700\u8981\u975E\u7A7A companyId\uFF08fail-closed\uFF1A\u4E0D\u56DE\u9000\u9ED8\u8BA4\u516C\u53F8\uFF09");
|
|
257202
257476
|
}
|
|
257203
|
-
const hex = (0,
|
|
257477
|
+
const hex = (0, import_node_crypto74.createHash)("sha256").update(companyId, "utf8").digest("hex");
|
|
257204
257478
|
return `${COMPANY_SCHEMA_PREFIX}${hex.slice(0, DIGEST_HEX_LEN)}`;
|
|
257205
257479
|
}
|
|
257206
|
-
var
|
|
257480
|
+
var import_node_crypto74, COMPANY_SCHEMA_PREFIX, DIGEST_HEX_LEN, SchemaMappingConflictError, TenantStorageLocationStore;
|
|
257207
257481
|
var init_tenant_schema_mapping = __esm({
|
|
257208
257482
|
"../storage/src/tenant-schema-mapping.ts"() {
|
|
257209
257483
|
"use strict";
|
|
257210
|
-
|
|
257484
|
+
import_node_crypto74 = require("node:crypto");
|
|
257211
257485
|
init_esm();
|
|
257212
257486
|
init_pg_ident();
|
|
257213
257487
|
COMPANY_SCHEMA_PREFIX = "c_";
|
|
@@ -257281,7 +257555,7 @@ var init_tenant_schema_mapping = __esm({
|
|
|
257281
257555
|
|
|
257282
257556
|
// ../storage/src/company-data-plane-schema.ts
|
|
257283
257557
|
function canonicalTypeDefHash(def) {
|
|
257284
|
-
return `sha256:${(0,
|
|
257558
|
+
return `sha256:${(0, import_node_crypto75.createHash)("sha256").update(JSON.stringify(def), "utf8").digest("hex")}`;
|
|
257285
257559
|
}
|
|
257286
257560
|
function defaultArtifactTypeTemplate() {
|
|
257287
257561
|
return [
|
|
@@ -257463,11 +257737,11 @@ async function seedDefaultArtifactTypes(pool, schema, templates = defaultArtifac
|
|
|
257463
257737
|
}
|
|
257464
257738
|
return { inserted };
|
|
257465
257739
|
}
|
|
257466
|
-
var
|
|
257740
|
+
var import_node_crypto75, DEFAULT_ARTIFACT_TYPE_TEMPLATE_VERSION;
|
|
257467
257741
|
var init_company_data_plane_schema = __esm({
|
|
257468
257742
|
"../storage/src/company-data-plane-schema.ts"() {
|
|
257469
257743
|
"use strict";
|
|
257470
|
-
|
|
257744
|
+
import_node_crypto75 = require("node:crypto");
|
|
257471
257745
|
init_esm();
|
|
257472
257746
|
init_pg_ident();
|
|
257473
257747
|
DEFAULT_ARTIFACT_TYPE_TEMPLATE_VERSION = "4c368e5c-types-v1";
|
|
@@ -257547,11 +257821,11 @@ function rowToFile2(row) {
|
|
|
257547
257821
|
updatedAt: new Date(row.updated_at).toISOString()
|
|
257548
257822
|
};
|
|
257549
257823
|
}
|
|
257550
|
-
var
|
|
257824
|
+
var import_node_crypto76, COMPANY_CONFLICT_MSG, CompanyIdentifierConflictError, CompanyOwnedRegistryStore;
|
|
257551
257825
|
var init_company_owned_registry_store = __esm({
|
|
257552
257826
|
"../storage/src/company-owned-registry-store.ts"() {
|
|
257553
257827
|
"use strict";
|
|
257554
|
-
|
|
257828
|
+
import_node_crypto76 = require("node:crypto");
|
|
257555
257829
|
init_esm();
|
|
257556
257830
|
init_src();
|
|
257557
257831
|
init_pg_ident();
|
|
@@ -257937,7 +258211,7 @@ var init_company_owned_registry_store = __esm({
|
|
|
257937
258211
|
enabled: skill.enabled,
|
|
257938
258212
|
files: files.map((f2) => ({ path: f2.path, blobHash: f2.blobHash }))
|
|
257939
258213
|
});
|
|
257940
|
-
return (0,
|
|
258214
|
+
return (0, import_node_crypto76.createHash)("sha256").update(body2).digest("hex");
|
|
257941
258215
|
}
|
|
257942
258216
|
};
|
|
257943
258217
|
}
|
|
@@ -260537,7 +260811,7 @@ function sourceSetConservation(input) {
|
|
|
260537
260811
|
return input.sourceFinal === input.copied + input.approvedRuntimeConversion + input.approvedArchive + input.approvedDiscard;
|
|
260538
260812
|
}
|
|
260539
260813
|
function payloadChecksum(value2) {
|
|
260540
|
-
return (0,
|
|
260814
|
+
return (0, import_node_crypto77.createHash)("sha256").update(JSON.stringify(value2)).digest("hex");
|
|
260541
260815
|
}
|
|
260542
260816
|
async function copyWorkorderDraftsIdempotent(pool, companyId, companySchema, manifestId, opts) {
|
|
260543
260817
|
const cs = quoteIdent2(companySchema);
|
|
@@ -260925,11 +261199,11 @@ async function copyTraceFamilyIdempotent(pool, companyId, companySchema, manifes
|
|
|
260925
261199
|
sequences
|
|
260926
261200
|
};
|
|
260927
261201
|
}
|
|
260928
|
-
var
|
|
261202
|
+
var import_node_crypto77, MissingInstallerActorsError, TypeCatalogNotCoveredError, ORG_REGISTRY_TABLES, TRACE_FAMILY;
|
|
260929
261203
|
var init_tenant_migration_operator = __esm({
|
|
260930
261204
|
"../storage/src/tenant-migration-operator.ts"() {
|
|
260931
261205
|
"use strict";
|
|
260932
|
-
|
|
261206
|
+
import_node_crypto77 = require("node:crypto");
|
|
260933
261207
|
init_esm();
|
|
260934
261208
|
init_pg_ident();
|
|
260935
261209
|
init_tenancy_attribution();
|
|
@@ -261161,8 +261435,8 @@ var init_tenant_new_company_provision = __esm({
|
|
|
261161
261435
|
// ../storage/src/knowledge-snapshot-crypto.ts
|
|
261162
261436
|
function sealSnapshot(snapshot, key2) {
|
|
261163
261437
|
if (snapshot.content.startsWith(PREFIX3)) return structuredClone(snapshot);
|
|
261164
|
-
const iv = (0,
|
|
261165
|
-
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);
|
|
261166
261440
|
cipher.setAAD(aad2(snapshot));
|
|
261167
261441
|
const encrypted = Buffer.concat([cipher.update(snapshot.content, "utf8"), cipher.final()]);
|
|
261168
261442
|
return { ...structuredClone(snapshot), content: `${PREFIX3}${iv.toString("base64url")}.${cipher.getAuthTag().toString("base64url")}.${encrypted.toString("base64url")}` };
|
|
@@ -261172,7 +261446,7 @@ function openSnapshot(snapshot, key2) {
|
|
|
261172
261446
|
const packed = snapshot.content.slice(PREFIX3.length).split(".");
|
|
261173
261447
|
if (packed.length !== 3 || packed.some((part) => !part)) throw new Error(`knowledge snapshot ${snapshot.ref} ciphertext is malformed`);
|
|
261174
261448
|
const [iv, tag, data] = packed;
|
|
261175
|
-
const decipher = (0,
|
|
261449
|
+
const decipher = (0, import_node_crypto78.createDecipheriv)("aes-256-gcm", bytes(key2), Buffer.from(iv, "base64url"));
|
|
261176
261450
|
decipher.setAAD(aad2(snapshot));
|
|
261177
261451
|
decipher.setAuthTag(Buffer.from(tag, "base64url"));
|
|
261178
261452
|
return {
|
|
@@ -261180,11 +261454,11 @@ function openSnapshot(snapshot, key2) {
|
|
|
261180
261454
|
content: Buffer.concat([decipher.update(Buffer.from(data, "base64url")), decipher.final()]).toString("utf8")
|
|
261181
261455
|
};
|
|
261182
261456
|
}
|
|
261183
|
-
var
|
|
261457
|
+
var import_node_crypto78, PREFIX3, bytes, aad2;
|
|
261184
261458
|
var init_knowledge_snapshot_crypto = __esm({
|
|
261185
261459
|
"../storage/src/knowledge-snapshot-crypto.ts"() {
|
|
261186
261460
|
"use strict";
|
|
261187
|
-
|
|
261461
|
+
import_node_crypto78 = require("node:crypto");
|
|
261188
261462
|
PREFIX3 = "oasis-knowledge:v1:";
|
|
261189
261463
|
bytes = (key2) => {
|
|
261190
261464
|
const value2 = Buffer.from(key2);
|
|
@@ -263438,14 +263712,14 @@ init_src();
|
|
|
263438
263712
|
var os14 = __toESM(require("node:os"));
|
|
263439
263713
|
var path39 = __toESM(require("node:path"));
|
|
263440
263714
|
var import_node_child_process22 = require("node:child_process");
|
|
263441
|
-
var
|
|
263715
|
+
var import_node_crypto89 = require("node:crypto");
|
|
263442
263716
|
|
|
263443
263717
|
// ../cli/src/cli.ts
|
|
263444
263718
|
init_src();
|
|
263445
263719
|
var fs39 = __toESM(require("node:fs"), 1);
|
|
263446
263720
|
var os12 = __toESM(require("node:os"), 1);
|
|
263447
263721
|
var path34 = __toESM(require("node:path"), 1);
|
|
263448
|
-
var
|
|
263722
|
+
var import_node_crypto87 = require("node:crypto");
|
|
263449
263723
|
|
|
263450
263724
|
// ../cli/src/serve.ts
|
|
263451
263725
|
init_src();
|
|
@@ -263454,11 +263728,11 @@ var fs33 = __toESM(require("node:fs"), 1);
|
|
|
263454
263728
|
var os8 = __toESM(require("node:os"), 1);
|
|
263455
263729
|
var path28 = __toESM(require("node:path"), 1);
|
|
263456
263730
|
var import_node_child_process17 = require("node:child_process");
|
|
263457
|
-
var
|
|
263731
|
+
var import_node_crypto83 = require("node:crypto");
|
|
263458
263732
|
var import_node_url7 = require("node:url");
|
|
263459
263733
|
|
|
263460
263734
|
// ../cli/src/artifact-discovery-source.ts
|
|
263461
|
-
var
|
|
263735
|
+
var import_node_crypto79 = require("node:crypto");
|
|
263462
263736
|
init_src7();
|
|
263463
263737
|
var ArtifactDiscoverySourceUnreadableError = class extends Error {
|
|
263464
263738
|
constructor(message) {
|
|
@@ -263488,7 +263762,7 @@ async function resolveArtifactDiscoverySourceContent(blobs, input) {
|
|
|
263488
263762
|
throw new ArtifactDiscoverySourceUnreadableError(`Artifact Revision ${input.revisionId} \u7684 contentKind \u4E0D\u53D7\u652F\u6301\uFF1A${String(input.contentKind)}`);
|
|
263489
263763
|
}
|
|
263490
263764
|
const rootBytes = await blobs.get(input.contentRef);
|
|
263491
|
-
const sourceFingerprint = (0,
|
|
263765
|
+
const sourceFingerprint = (0, import_node_crypto79.createHash)("sha256").update(rootBytes).digest("hex");
|
|
263492
263766
|
if (input.contentKind === "inline-blob") {
|
|
263493
263767
|
const sourceContent = decodeText3(rootBytes);
|
|
263494
263768
|
if (sourceContent === null) {
|
|
@@ -263512,7 +263786,7 @@ ${entry.text}`).join("\n\n"),
|
|
|
263512
263786
|
}
|
|
263513
263787
|
|
|
263514
263788
|
// ../server/src/domains/discussions/service.ts
|
|
263515
|
-
var
|
|
263789
|
+
var import_node_crypto80 = require("node:crypto");
|
|
263516
263790
|
init_zod();
|
|
263517
263791
|
|
|
263518
263792
|
// ../contract/src/discussions.ts
|
|
@@ -263549,7 +263823,7 @@ var generationSchema = external_exports.discriminatedUnion("result", [
|
|
|
263549
263823
|
}).strict()
|
|
263550
263824
|
]);
|
|
263551
263825
|
var entryId = (projectId2, id) => JSON.stringify([projectId2, id]);
|
|
263552
|
-
var hash2 = (s2) => (0,
|
|
263826
|
+
var hash2 = (s2) => (0, import_node_crypto80.createHash)("sha256").update(s2).digest("hex").slice(0, 24);
|
|
263553
263827
|
var canonical = (s2) => s2.normalize("NFKC").trim().toLocaleLowerCase();
|
|
263554
263828
|
function decisionFingerprint(d) {
|
|
263555
263829
|
return hash2(JSON.stringify([d.statement, d.rationale, d.alternatives]));
|
|
@@ -263704,7 +263978,7 @@ var DiscussionService = class {
|
|
|
263704
263978
|
let id = t.topic_id;
|
|
263705
263979
|
if (id.startsWith("new:")) {
|
|
263706
263980
|
const existing = [...topicMap.values()].find((x2) => canonical(x2.title) === canonical(t.title));
|
|
263707
|
-
id = existing?.topicId ?? `topic_${(0,
|
|
263981
|
+
id = existing?.topicId ?? `topic_${(0, import_node_crypto80.randomUUID)()}`;
|
|
263708
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`);
|
|
263709
263983
|
topicAliases.set(t.topic_id, id);
|
|
263710
263984
|
const value2 = { projectId: input.projectId, topicId: id, title: t.title };
|
|
@@ -263725,7 +263999,7 @@ var DiscussionService = class {
|
|
|
263725
263999
|
if (id.startsWith("new:")) {
|
|
263726
264000
|
const candidateKey = JSON.stringify([topicId, canonical(d.record.statement)]);
|
|
263727
264001
|
const existing = [...decisionMap.values()].find((x2) => x2.topicId === topicId && canonical(x2.record.statement) === canonical(d.record.statement));
|
|
263728
|
-
id = existing?.decisionId ?? candidateIds.get(candidateKey) ?? `decision_${(0,
|
|
264002
|
+
id = existing?.decisionId ?? candidateIds.get(candidateKey) ?? `decision_${(0, import_node_crypto80.randomUUID)()}`;
|
|
263729
264003
|
candidateIds.set(candidateKey, id);
|
|
263730
264004
|
} else if (!decisionMap.has(id)) invalid("decision_id", `\u51B3\u7B56 ${id} \u4E0D\u5B58\u5728\uFF1B\u65B0\u51B3\u7B56\u4F7F\u7528 new: \u524D\u7F00`);
|
|
263731
264005
|
decisionAliases.set(d.decision_id, id);
|
|
@@ -263858,7 +264132,7 @@ var DiscussionService = class {
|
|
|
263858
264132
|
});
|
|
263859
264133
|
}
|
|
263860
264134
|
async operation(tx, actorId, kind, id, from, to) {
|
|
263861
|
-
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() });
|
|
263862
264136
|
}
|
|
263863
264137
|
};
|
|
263864
264138
|
function pickDiscussionContent(d) {
|
|
@@ -264004,7 +264278,7 @@ var DiscussionContext = class {
|
|
|
264004
264278
|
};
|
|
264005
264279
|
|
|
264006
264280
|
// ../server/src/domains/discussions/worker.ts
|
|
264007
|
-
var
|
|
264281
|
+
var import_node_crypto81 = require("node:crypto");
|
|
264008
264282
|
var DISCUSSION_IDLE_MS = 15 * 6e4;
|
|
264009
264283
|
var DISCUSSION_MAX_CORRECTIONS = 3;
|
|
264010
264284
|
var DISCUSSION_LEASE_MS = 2 * 6e4;
|
|
@@ -264030,7 +264304,7 @@ var DiscussionWorker = class {
|
|
|
264030
264304
|
if (await this.isReplying(sessionId)) return false;
|
|
264031
264305
|
const cutoff = eligibleCutoff(await this.service.chat.listMessages(sessionId), this.service.now());
|
|
264032
264306
|
if (!cutoff) return false;
|
|
264033
|
-
const owner = (0,
|
|
264307
|
+
const owner = (0, import_node_crypto81.randomUUID)();
|
|
264034
264308
|
const claimed = await this.service.store.transaction(async (tx) => {
|
|
264035
264309
|
const old = (await tx.get("job", sessionId))?.value;
|
|
264036
264310
|
if (old?.status === "running" && (old.leaseUntil ?? 0) > this.service.now()) return null;
|
|
@@ -264463,7 +264737,7 @@ function createDiscussionRuntime(options) {
|
|
|
264463
264737
|
}
|
|
264464
264738
|
|
|
264465
264739
|
// ../server/src/domains/discussions/store.ts
|
|
264466
|
-
var
|
|
264740
|
+
var import_node_crypto82 = require("node:crypto");
|
|
264467
264741
|
var import_promises16 = require("node:fs/promises");
|
|
264468
264742
|
var import_node_path27 = require("node:path");
|
|
264469
264743
|
var key = (kind, id) => JSON.stringify([kind, id]);
|
|
@@ -264501,7 +264775,7 @@ var MemoryDiscussionStore = class _MemoryDiscussionStore {
|
|
|
264501
264775
|
if (changed) {
|
|
264502
264776
|
if (this.filename) {
|
|
264503
264777
|
await (0, import_promises16.mkdir)((0, import_node_path27.dirname)(this.filename), { recursive: true });
|
|
264504
|
-
const temp = `${this.filename}.${(0,
|
|
264778
|
+
const temp = `${this.filename}.${(0, import_node_crypto82.randomUUID)()}.tmp`;
|
|
264505
264779
|
await (0, import_promises16.writeFile)(temp, JSON.stringify(next), "utf8");
|
|
264506
264780
|
await (0, import_promises16.rename)(temp, this.filename);
|
|
264507
264781
|
}
|
|
@@ -265269,7 +265543,7 @@ init_src9();
|
|
|
265269
265543
|
init_src();
|
|
265270
265544
|
init_trajectory();
|
|
265271
265545
|
function deterministicUuid2(seed) {
|
|
265272
|
-
const h = (0,
|
|
265546
|
+
const h = (0, import_node_crypto83.createHash)("sha256").update(seed).digest();
|
|
265273
265547
|
const b2 = Buffer.from(h.subarray(0, 16));
|
|
265274
265548
|
b2[6] = b2[6] & 15 | 80;
|
|
265275
265549
|
b2[8] = b2[8] & 63 | 128;
|
|
@@ -265469,7 +265743,7 @@ function oasisWrapperScript() {
|
|
|
265469
265743
|
const repoRoot = (0, import_node_url7.fileURLToPath)(new URL("../../../", __esm_import_meta_url));
|
|
265470
265744
|
const tsx = path28.join(repoRoot, "node_modules/.bin/tsx");
|
|
265471
265745
|
const main = path28.join(repoRoot, "packages/cli/src/main.ts");
|
|
265472
|
-
const key2 = (0,
|
|
265746
|
+
const key2 = (0, import_node_crypto83.createHash)("sha256").update(repoRoot).digest("hex").slice(0, 12);
|
|
265473
265747
|
const uid = typeof process.getuid === "function" ? process.getuid() : "na";
|
|
265474
265748
|
const stable = path28.join(os8.tmpdir(), `oasis-cli-wrapper-${uid}-${key2}`);
|
|
265475
265749
|
let dir;
|
|
@@ -265855,7 +266129,7 @@ async function startServe(opts) {
|
|
|
265855
266129
|
if (!hub) return Promise.resolve({ ok: false, reason: "\u672C\u8FDB\u7A0B\u6CA1\u6709\u8282\u70B9\u7F51\u5173" });
|
|
265856
266130
|
const online = hub.connectedDaemons().some((d) => d.daemonId === nodeId);
|
|
265857
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" });
|
|
265858
|
-
const requestId = (0,
|
|
266132
|
+
const requestId = (0, import_node_crypto83.randomUUID)();
|
|
265859
266133
|
const task = new Promise((resolve10) => {
|
|
265860
266134
|
const timer = setTimeout(() => {
|
|
265861
266135
|
modelRefreshWaiters.delete(requestId);
|
|
@@ -266623,7 +266897,7 @@ async function startServe(opts) {
|
|
|
266623
266897
|
const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
266624
266898
|
if (buf || session.runId) {
|
|
266625
266899
|
await turnStore.appendMessage({
|
|
266626
|
-
id: (0,
|
|
266900
|
+
id: (0, import_node_crypto83.randomUUID)(),
|
|
266627
266901
|
sessionId: chatSessionId,
|
|
266628
266902
|
role: "assistant",
|
|
266629
266903
|
content: buf,
|
|
@@ -266669,7 +266943,7 @@ async function startServe(opts) {
|
|
|
266669
266943
|
chatTargets: {
|
|
266670
266944
|
inspect: inspectChatTarget,
|
|
266671
266945
|
createTargetSession: async ({ companyId, agentId, ownerHumanActorId, title }) => {
|
|
266672
|
-
const sessionId = (0,
|
|
266946
|
+
const sessionId = (0, import_node_crypto83.randomUUID)();
|
|
266673
266947
|
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
266674
266948
|
const binding = await registryStore.getBinding(agentId).catch(() => null);
|
|
266675
266949
|
await (await chatStoreFor(companyId)).createSession({
|
|
@@ -267815,7 +268089,7 @@ async function startServe(opts) {
|
|
|
267815
268089
|
}));
|
|
267816
268090
|
}
|
|
267817
268091
|
const limits = { wallClockMs: wallClockForKind("planner") };
|
|
267818
|
-
const artifactId = `artifact:planner:${(0,
|
|
268092
|
+
const artifactId = `artifact:planner:${(0, import_node_crypto83.randomUUID)()}`;
|
|
267819
268093
|
const handle = await chatRemoteAdapter.spawn({
|
|
267820
268094
|
actor: planner.id,
|
|
267821
268095
|
// companyId 同协调者:planner 用的就是默认公司的 actors 服务,漏签会让它一调公司域端点就 404。
|
|
@@ -268111,7 +268385,9 @@ async function startServe(opts) {
|
|
|
268111
268385
|
// v3 快照端点(ws:wo-81de04dc S3 恢复路径唯一入口):`chat_items` 权威读口 +
|
|
268112
268386
|
// live 注册表算 `frameCursor`。与 server.ts 的双写解析同一层,与 attach 路径共享 registry。
|
|
268113
268387
|
resolveChatItems: (companyId) => chatItemsFor(companyId),
|
|
268114
|
-
liveChat
|
|
268388
|
+
liveChat,
|
|
268389
|
+
// ADR-0587:列表行派生 `unread`,与 collab 域收件箱读同一份按公司的水位(无 PG 时闭包自己回落单实例)。
|
|
268390
|
+
resolveReadMarkers: readMarkerStoreFor
|
|
268115
268391
|
})] : []
|
|
268116
268392
|
],
|
|
268117
268393
|
workorderDrafts,
|
|
@@ -268698,10 +268974,10 @@ async function startServe(opts) {
|
|
|
268698
268974
|
if (isDeletedActor(dispatchTarget)) {
|
|
268699
268975
|
throw new ApiError(409, ACTOR_DELETED_ERROR_CODE, ACTOR_DELETED_CHAT_MESSAGE);
|
|
268700
268976
|
}
|
|
268701
|
-
const runtimeSessionId = sessionId ?? (requestDispatchId ? deterministicUuid2(`chat-runtime:${requestDispatchId}`) : (0,
|
|
268977
|
+
const runtimeSessionId = sessionId ?? (requestDispatchId ? deterministicUuid2(`chat-runtime:${requestDispatchId}`) : (0, import_node_crypto83.randomUUID)());
|
|
268702
268978
|
const resumeRuntimeSession = Boolean(sessionId);
|
|
268703
|
-
const traceRunId = requestDispatchId ? `chat-run:${deterministicUuid2(`chat-trace:${requestDispatchId}`)}` : `chat-run:${(0,
|
|
268704
|
-
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)()}`;
|
|
268705
268981
|
let stableDispatch = requestDispatchId ? await resolveStableChatDispatch({ store: await traceStoreFor(runCompanyId), runId: traceRunId }) : null;
|
|
268706
268982
|
if (stableDispatch && !stableDispatch.shouldDispatch) {
|
|
268707
268983
|
return {
|
|
@@ -269881,7 +270157,7 @@ async function startServe(opts) {
|
|
|
269881
270157
|
console.log(`[new-engine] dispatchWork ${workId} \u662F human work\u2014\u2014\u4E0D\u6D3E runtime\uFF0C\u7B49\u5F85\u4EBA\u5DE5\u5904\u7406`);
|
|
269882
270158
|
return;
|
|
269883
270159
|
}
|
|
269884
|
-
const ledgerId = `dispatch:${(0,
|
|
270160
|
+
const ledgerId = `dispatch:${(0, import_node_crypto83.randomUUID)()}`;
|
|
269885
270161
|
try {
|
|
269886
270162
|
await (await dispatchLedgerFor(companyId)).insertOpen({
|
|
269887
270163
|
id: ledgerId,
|
|
@@ -269966,7 +270242,7 @@ async function startServe(opts) {
|
|
|
269966
270242
|
const kernelModel = newKernel.model;
|
|
269967
270243
|
const art = kernelModel.artifacts.get(nodeId);
|
|
269968
270244
|
const revWid = art?.workspace ?? "";
|
|
269969
|
-
const ledgerId = `dispatch:${(0,
|
|
270245
|
+
const ledgerId = `dispatch:${(0, import_node_crypto83.randomUUID)()}`;
|
|
269970
270246
|
try {
|
|
269971
270247
|
await (await dispatchLedgerFor(companyId)).insertOpen({
|
|
269972
270248
|
id: ledgerId,
|
|
@@ -270340,7 +270616,7 @@ async function startServe(opts) {
|
|
|
270340
270616
|
resolveSupplementalContext: server.knowledgeGovernance ? async ({ actorId, artifactId, workOrderId, action, part, runtimeKind, taskMarkdown }) => {
|
|
270341
270617
|
try {
|
|
270342
270618
|
const governance = server.knowledgeGovernance;
|
|
270343
|
-
const taskFingerprint = (0,
|
|
270619
|
+
const taskFingerprint = (0, import_node_crypto83.createHash)("sha256").update(JSON.stringify({ artifactId, workOrderId, action, part: part ?? null, taskMarkdown })).digest("hex");
|
|
270344
270620
|
const requestContext = {
|
|
270345
270621
|
organizationId: companyId,
|
|
270346
270622
|
actorId,
|
|
@@ -270804,10 +271080,10 @@ async function startServe(opts) {
|
|
|
270804
271080
|
if (h < 24) return `${h} \u5C0F\u65F6\u524D`;
|
|
270805
271081
|
return `${Math.floor(h / 24)} \u5929\u524D`;
|
|
270806
271082
|
};
|
|
270807
|
-
const humanFailCause = (reason,
|
|
270808
|
-
const quote =
|
|
271083
|
+
const humanFailCause = (reason, errorMessage2) => {
|
|
271084
|
+
const quote = errorMessage2?.trim().slice(0, 300);
|
|
270809
271085
|
if (reason === "rate-limit") {
|
|
270810
|
-
const hint = extractResetHint(
|
|
271086
|
+
const hint = extractResetHint(errorMessage2);
|
|
270811
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 ? `
|
|
270812
271088
|
> ${quote}` : "");
|
|
270813
271089
|
}
|
|
@@ -271957,11 +272233,11 @@ async function runSession(dispatchId, job, deps) {
|
|
|
271957
272233
|
} catch (err) {
|
|
271958
272234
|
deps.onFailure?.();
|
|
271959
272235
|
log2("[node-cli]", ` spawn failed: ${err}`);
|
|
271960
|
-
const
|
|
272236
|
+
const errorMessage2 = String(err?.stack ?? err).slice(0, 8e3);
|
|
271961
272237
|
deps.sink.keyFrame({ type: "session_exited", dispatchId, sessionId: "spawn-failed", info: {
|
|
271962
272238
|
code: null,
|
|
271963
272239
|
reason: "error",
|
|
271964
|
-
errorMessage,
|
|
272240
|
+
errorMessage: errorMessage2,
|
|
271965
272241
|
...err instanceof BundleRestoreError ? { fileRestoreError: { path: err.filePath, message: err.message } } : {}
|
|
271966
272242
|
} });
|
|
271967
272243
|
}
|
|
@@ -271970,7 +272246,6 @@ async function runSession(dispatchId, job, deps) {
|
|
|
271970
272246
|
// ../cli/src/daemon/session-process.ts
|
|
271971
272247
|
var RECONNECT_MIN_MS = 1e3;
|
|
271972
272248
|
var RECONNECT_MAX_MS = 3e4;
|
|
271973
|
-
var EXIT_ACK_WAIT_MS = LINK_WINDOWS.exitAckWaitMs;
|
|
271974
272249
|
var OUTBOX_MAX_FRAMES = 8e3;
|
|
271975
272250
|
var isKeyFrame = (m2) => m2.type === "session_started" || m2.type === "session_exited";
|
|
271976
272251
|
async function runSessionProcess(specFile, adapter) {
|
|
@@ -272016,6 +272291,7 @@ var SessionProcessState = class {
|
|
|
272016
272291
|
this.hardTtlMs = o.hardTtlMs ?? SESSION_LIMITS.hardTtlMs;
|
|
272017
272292
|
this.suicideAfterUnreachableMs = o.suicideAfterUnreachableMs ?? SESSION_LIMITS.suicideAfterUnreachableMs;
|
|
272018
272293
|
this.watchdogIntervalMs = o.watchdogIntervalMs ?? 3e4;
|
|
272294
|
+
this.exitAckWaitMs = o.exitAckWaitMs ?? LINK_WINDOWS.exitAckWaitMs;
|
|
272019
272295
|
}
|
|
272020
272296
|
ws = null;
|
|
272021
272297
|
connected = false;
|
|
@@ -272029,6 +272305,8 @@ var SessionProcessState = class {
|
|
|
272029
272305
|
hardTtlMs;
|
|
272030
272306
|
suicideAfterUnreachableMs;
|
|
272031
272307
|
watchdogIntervalMs;
|
|
272308
|
+
/** 发完 session_exited 后等 ack 的时限;等不到也退——outbox 那份由服务端 L3 时钟扫描兜底。 */
|
|
272309
|
+
exitAckWaitMs;
|
|
272032
272310
|
watchdog = null;
|
|
272033
272311
|
exitAckResolve = null;
|
|
272034
272312
|
/** 整个会话进程「可以退了」的信号:会话正常退出、或被 evict / TTL / 失联自尽。 */
|
|
@@ -272251,7 +272529,7 @@ var SessionProcessState = class {
|
|
|
272251
272529
|
this.exitAckResolve = null;
|
|
272252
272530
|
resolve10();
|
|
272253
272531
|
};
|
|
272254
|
-
const timer = setTimeout(finish,
|
|
272532
|
+
const timer = setTimeout(finish, this.exitAckWaitMs);
|
|
272255
272533
|
this.exitAckResolve = finish;
|
|
272256
272534
|
});
|
|
272257
272535
|
}
|
|
@@ -272274,7 +272552,7 @@ var SessionProcessState = class {
|
|
|
272274
272552
|
init_wrapper();
|
|
272275
272553
|
init_src();
|
|
272276
272554
|
var import_node_os9 = require("node:os");
|
|
272277
|
-
var
|
|
272555
|
+
var import_node_crypto84 = require("node:crypto");
|
|
272278
272556
|
init_src8();
|
|
272279
272557
|
init_src2();
|
|
272280
272558
|
|
|
@@ -273059,7 +273337,7 @@ var DaemonWsClient = class {
|
|
|
273059
273337
|
*/
|
|
273060
273338
|
async queryArtifactStates(artifactIds, timeoutMs = 15e3) {
|
|
273061
273339
|
if (artifactIds.length === 0) return {};
|
|
273062
|
-
const requestId = (0,
|
|
273340
|
+
const requestId = (0, import_node_crypto84.randomUUID)();
|
|
273063
273341
|
return new Promise((resolve10, reject) => {
|
|
273064
273342
|
const timer = setTimeout(() => {
|
|
273065
273343
|
this.gcPending.delete(requestId);
|
|
@@ -273465,7 +273743,7 @@ function forwardSignal(child, sig, killGroup = (pgid, signal) => {
|
|
|
273465
273743
|
// ../cli/src/daemon/machine-id.ts
|
|
273466
273744
|
var import_node_child_process20 = require("node:child_process");
|
|
273467
273745
|
var import_node_fs22 = require("node:fs");
|
|
273468
|
-
var
|
|
273746
|
+
var import_node_crypto85 = require("node:crypto");
|
|
273469
273747
|
var import_node_os12 = require("node:os");
|
|
273470
273748
|
function linuxMachineId() {
|
|
273471
273749
|
for (const p2 of ["/etc/machine-id", "/var/lib/dbus/machine-id"]) {
|
|
@@ -273531,7 +273809,7 @@ var defaultSources = {
|
|
|
273531
273809
|
function resolveNodeId(sources = {}) {
|
|
273532
273810
|
const s2 = { ...defaultSources, ...sources };
|
|
273533
273811
|
const material = `${s2.machineFingerprint()}:${s2.osUser()}`;
|
|
273534
|
-
const digest = (0,
|
|
273812
|
+
const digest = (0, import_node_crypto85.createHash)("sha256").update(material).digest("hex").slice(0, 12);
|
|
273535
273813
|
return `node-${digest}`;
|
|
273536
273814
|
}
|
|
273537
273815
|
|
|
@@ -275302,13 +275580,13 @@ function ownFlagsFromDecl(command) {
|
|
|
275302
275580
|
}
|
|
275303
275581
|
|
|
275304
275582
|
// ../cli/src/connector-effect-runner.ts
|
|
275305
|
-
var
|
|
275583
|
+
var import_node_crypto86 = require("node:crypto");
|
|
275306
275584
|
var import_node_child_process21 = require("node:child_process");
|
|
275307
275585
|
init_src8();
|
|
275308
275586
|
function stableKey(effect) {
|
|
275309
275587
|
const keyFields = Object.fromEntries(Object.entries(effect.keyFields).sort(([a], [b2]) => a.localeCompare(b2)));
|
|
275310
275588
|
const canonical2 = JSON.stringify({ kind: effect.kind, target: effect.target, keyFields });
|
|
275311
|
-
return `sha256:${(0,
|
|
275589
|
+
return `sha256:${(0, import_node_crypto86.createHash)("sha256").update(canonical2).digest("hex")}`;
|
|
275312
275590
|
}
|
|
275313
275591
|
async function runConnectorEffect(connector, toolArgs, deps) {
|
|
275314
275592
|
const effect = connector.describeExternalEffect?.(toolArgs) ?? null;
|
|
@@ -275545,7 +275823,7 @@ async function waitForCommandAuthorization(base, headers, draftId, fallback) {
|
|
|
275545
275823
|
const timeoutMs = resolveAuthWaitMs();
|
|
275546
275824
|
const controller = new AbortController();
|
|
275547
275825
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
275548
|
-
const waiterId = (0,
|
|
275826
|
+
const waiterId = (0, import_node_crypto87.randomUUID)();
|
|
275549
275827
|
process.stderr.write(
|
|
275550
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
|
|
275551
275829
|
`
|
|
@@ -275973,7 +276251,7 @@ async function runCli(argv, println = console.log, progressln = console.error) {
|
|
|
275973
276251
|
const store = createNodeTokenStore(path34.join(dir, "node-tokens.json"));
|
|
275974
276252
|
const sub = positional[0];
|
|
275975
276253
|
if (sub === "issue") {
|
|
275976
|
-
const id = flags.get("id") ?? `node-${(0,
|
|
276254
|
+
const id = flags.get("id") ?? `node-${(0, import_node_crypto87.randomUUID)()}`;
|
|
275977
276255
|
const token2 = store.issue(id);
|
|
275978
276256
|
println(token2);
|
|
275979
276257
|
process.stderr.write(
|
|
@@ -277004,7 +277282,7 @@ ${t.ref} ${t.name} [\u5267\u672C=${t.playbookRef}]`);
|
|
|
277004
277282
|
if (!name) throw new Error("\u9879\u76EE\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A");
|
|
277005
277283
|
const goal = flags.get("goal")?.trim();
|
|
277006
277284
|
const slug6 = flags.get("slug");
|
|
277007
|
-
const id = slug6 !== void 0 ? projectSlug(slug6) : projectIdFromUuid((0,
|
|
277285
|
+
const id = slug6 !== void 0 ? projectSlug(slug6) : projectIdFromUuid((0, import_node_crypto87.randomUUID)());
|
|
277008
277286
|
const result = await api.request("POST", "/api/projects", {
|
|
277009
277287
|
...id ? { id } : {},
|
|
277010
277288
|
name,
|
|
@@ -278996,13 +279274,13 @@ var LEGACY_SYSTEMD_UNIT = "oasis-node.service";
|
|
|
278996
279274
|
var LEGACY_LAUNCHD_LABEL = "com.oasis.node";
|
|
278997
279275
|
|
|
278998
279276
|
// src/install.ts
|
|
278999
|
-
var
|
|
279277
|
+
var import_node_crypto88 = require("node:crypto");
|
|
279000
279278
|
var fs43 = __toESM(require("node:fs"));
|
|
279001
279279
|
var path38 = __toESM(require("node:path"));
|
|
279002
279280
|
function versionLabel(sourceFile, pkgVersion, npmPrefixDir, pkgName = LEGACY_PKG_NAME) {
|
|
279003
279281
|
const tag = pkgName === LEGACY_PKG_NAME ? "" : `+pkg.${pkgName.replace(/[^A-Za-z0-9-]/g, "-")}`;
|
|
279004
279282
|
if (isFromNpmPrefix(sourceFile, npmPrefixDir)) return `${pkgVersion}${tag}`;
|
|
279005
|
-
const digest = (0,
|
|
279283
|
+
const digest = (0, import_node_crypto88.createHash)("sha256").update(fs43.readFileSync(sourceFile)).digest("hex").slice(0, 8);
|
|
279006
279284
|
return tag ? `${pkgVersion}${tag}.local.${digest}` : `${pkgVersion}+local.${digest}`;
|
|
279007
279285
|
}
|
|
279008
279286
|
function isFromNpmPrefix(sourceFile, npmPrefixDir) {
|
|
@@ -279125,7 +279403,7 @@ function shimScript() {
|
|
|
279125
279403
|
}
|
|
279126
279404
|
|
|
279127
279405
|
// src/index.ts
|
|
279128
|
-
var PKG_VERSION = true ? "2.2.
|
|
279406
|
+
var PKG_VERSION = true ? "2.2.49" : "dev";
|
|
279129
279407
|
var LOCAL_BIN = localBin();
|
|
279130
279408
|
var NPM_PREFIX = npmPrefix();
|
|
279131
279409
|
var INSTANCE = DEFAULT_INSTANCE;
|
|
@@ -279410,7 +279688,7 @@ function newInstanceName() {
|
|
|
279410
279688
|
const existing = new Set(listInstances());
|
|
279411
279689
|
if (!existing.has(DEFAULT_INSTANCE)) return DEFAULT_INSTANCE;
|
|
279412
279690
|
for (; ; ) {
|
|
279413
|
-
const n = `inst-${(0,
|
|
279691
|
+
const n = `inst-${(0, import_node_crypto89.randomBytes)(3).toString("hex")}`;
|
|
279414
279692
|
if (!existing.has(n)) return n;
|
|
279415
279693
|
}
|
|
279416
279694
|
}
|