oasis_test_v2 2.2.68 → 2.2.70
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 +1763 -545
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -444,13 +444,14 @@ function isUnread(eventAt, marker) {
|
|
|
444
444
|
function isChatSessionUnread(session, marker) {
|
|
445
445
|
return session.lastTurnQuality !== void 0 && isUnread(session.touchedAt, marker);
|
|
446
446
|
}
|
|
447
|
-
var chatScope, letterScope, INBOX_BASELINE_SCOPE;
|
|
447
|
+
var chatScope, letterScope, INBOX_BASELINE_SCOPE, INBOX_READ_ALL_SCOPE;
|
|
448
448
|
var init_inbox_read = __esm({
|
|
449
449
|
"../contract/src/inbox-read.ts"() {
|
|
450
450
|
"use strict";
|
|
451
451
|
chatScope = (sessionId) => `chat:${sessionId}`;
|
|
452
452
|
letterScope = (annotationId) => `letter:${annotationId}`;
|
|
453
453
|
INBOX_BASELINE_SCOPE = "inbox-baseline";
|
|
454
|
+
INBOX_READ_ALL_SCOPE = "inbox-read-all";
|
|
454
455
|
}
|
|
455
456
|
});
|
|
456
457
|
|
|
@@ -1464,6 +1465,22 @@ var init_chat = __esm({
|
|
|
1464
1465
|
});
|
|
1465
1466
|
|
|
1466
1467
|
// ../contract/src/session-outputs.ts
|
|
1468
|
+
function sessionOutputFilesOfParts(parts) {
|
|
1469
|
+
if (!Array.isArray(parts)) return [];
|
|
1470
|
+
const out = [];
|
|
1471
|
+
for (const raw of parts) {
|
|
1472
|
+
if (!raw || typeof raw !== "object") continue;
|
|
1473
|
+
const p2 = raw;
|
|
1474
|
+
if (p2.type !== "outputs" || !Array.isArray(p2.outputs)) continue;
|
|
1475
|
+
for (const f2 of p2.outputs) {
|
|
1476
|
+
if (!f2 || typeof f2 !== "object") continue;
|
|
1477
|
+
const file = f2;
|
|
1478
|
+
if (typeof file.path !== "string" || !file.path) continue;
|
|
1479
|
+
out.push({ path: file.path, name: typeof file.name === "string" && file.name ? file.name : file.path });
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
return out;
|
|
1483
|
+
}
|
|
1467
1484
|
function diffSessionOutputs(scanned, previous3) {
|
|
1468
1485
|
const prev = previous3 ?? {};
|
|
1469
1486
|
const changed = [];
|
|
@@ -1484,11 +1501,13 @@ function basenameOf(path44) {
|
|
|
1484
1501
|
const i = path44.lastIndexOf("/");
|
|
1485
1502
|
return i >= 0 ? path44.slice(i + 1) : path44;
|
|
1486
1503
|
}
|
|
1487
|
-
var SESSION_OUTPUTS_DIR;
|
|
1504
|
+
var SESSION_OUTPUTS_DIR, SESSION_OUTPUTS_ITEM_CODE, sessionOutputsItemId;
|
|
1488
1505
|
var init_session_outputs = __esm({
|
|
1489
1506
|
"../contract/src/session-outputs.ts"() {
|
|
1490
1507
|
"use strict";
|
|
1491
1508
|
SESSION_OUTPUTS_DIR = "outputs";
|
|
1509
|
+
SESSION_OUTPUTS_ITEM_CODE = "session_outputs";
|
|
1510
|
+
sessionOutputsItemId = (messageId) => `oasis-outputs:${messageId}`;
|
|
1492
1511
|
}
|
|
1493
1512
|
});
|
|
1494
1513
|
|
|
@@ -1676,6 +1695,24 @@ var init_chat_turn = __esm({
|
|
|
1676
1695
|
});
|
|
1677
1696
|
|
|
1678
1697
|
// ../contract/src/delegation.ts
|
|
1698
|
+
function hasDelegationDelivery(ev) {
|
|
1699
|
+
if (!ev) return false;
|
|
1700
|
+
return (ev.movedFiles ?? 0) > 0 || (ev.unchangedFiles ?? 0) > 0 || (ev.artifacts ?? 0) > 0 || Boolean(ev.roundText?.trim());
|
|
1701
|
+
}
|
|
1702
|
+
function delegationEnding(record9, evidence) {
|
|
1703
|
+
if (record9.state === "done") return "done";
|
|
1704
|
+
if (record9.state !== "failed") return "done";
|
|
1705
|
+
if (record9.failureKind !== "timeout") return "failed";
|
|
1706
|
+
return hasDelegationDelivery(evidence) ? "timeout-delivered" : "timeout-empty";
|
|
1707
|
+
}
|
|
1708
|
+
function delegationEndingOfRecord(record9, artifacts = []) {
|
|
1709
|
+
const last = record9.roundSummaries[record9.roundSummaries.length - 1];
|
|
1710
|
+
const lastRound = last?.round;
|
|
1711
|
+
return delegationEnding(record9, {
|
|
1712
|
+
...last?.text ? { roundText: last.text } : {},
|
|
1713
|
+
artifacts: lastRound === void 0 ? 0 : artifacts.filter((a) => a.round === lastRound).length
|
|
1714
|
+
});
|
|
1715
|
+
}
|
|
1679
1716
|
function trimRoundSummariesForReturn(summaries, recentRounds = DELEGATION_RETURN_RECENT_ROUNDS) {
|
|
1680
1717
|
const keep = Math.max(0, recentRounds);
|
|
1681
1718
|
const cut = Math.max(0, summaries.length - keep);
|
|
@@ -2045,6 +2082,94 @@ var init_chunked_message = __esm({
|
|
|
2045
2082
|
}
|
|
2046
2083
|
});
|
|
2047
2084
|
|
|
2085
|
+
// ../contract/src/command-card-copy.ts
|
|
2086
|
+
function stripInternalIds(text7, placeholder = "\u2026") {
|
|
2087
|
+
if (!text7) return text7;
|
|
2088
|
+
let out = text7;
|
|
2089
|
+
for (const re of [PREFIXED_ID_RE, UUID_RE, SHORT_ID_RE]) {
|
|
2090
|
+
out = out.replace(re, placeholder);
|
|
2091
|
+
}
|
|
2092
|
+
return out.replace(new RegExp(`[ \\t]+${placeholder}`, "gu"), placeholder);
|
|
2093
|
+
}
|
|
2094
|
+
function firstSentenceSummary(text7, max = CARD_SUMMARY_MAX) {
|
|
2095
|
+
const raw = (text7 ?? "").trim();
|
|
2096
|
+
if (!raw) return "";
|
|
2097
|
+
const cut = raw.split(/[。!?\n]|——/u)[0].trim() || raw.trim();
|
|
2098
|
+
const clean = stripInternalIds(cut).trim();
|
|
2099
|
+
const cps = [...clean];
|
|
2100
|
+
return cps.length > max ? `${cps.slice(0, max).join("")}\u2026` : clean;
|
|
2101
|
+
}
|
|
2102
|
+
function nodePhrase(args, refs) {
|
|
2103
|
+
const id = argStr(args, "artifactId");
|
|
2104
|
+
const title = id ? refs.nodeTitle?.(id)?.trim() : void 0;
|
|
2105
|
+
return title ? `\u300A${title}\u300B` : NEUTRAL_NODE;
|
|
2106
|
+
}
|
|
2107
|
+
function targetPhrase(naming, neutral) {
|
|
2108
|
+
const summary = firstSentenceSummary(naming?.summary);
|
|
2109
|
+
const nodeTitle = naming?.nodeTitle?.trim();
|
|
2110
|
+
if (summary) {
|
|
2111
|
+
return { phrase: nodeTitle && !summary.includes(nodeTitle) ? `\u300A${nodeTitle}\u300B\u2014\u2014${summary}` : summary, named: true };
|
|
2112
|
+
}
|
|
2113
|
+
if (nodeTitle) return { phrase: `\u300A${nodeTitle}\u300B\u4E0A\u7684${neutral}`, named: true };
|
|
2114
|
+
return { phrase: neutral, named: false };
|
|
2115
|
+
}
|
|
2116
|
+
function escalationPhraseOf(refs, escalationId) {
|
|
2117
|
+
return targetPhrase(escalationId ? refs.escalation?.(escalationId) : void 0, NEUTRAL_ESCALATION);
|
|
2118
|
+
}
|
|
2119
|
+
function gapPhraseOf(refs, gapId) {
|
|
2120
|
+
return targetPhrase(gapId ? refs.gap?.(gapId) : void 0, NEUTRAL_GAP);
|
|
2121
|
+
}
|
|
2122
|
+
function actionPhrase(verb, noun, target, neutralVerb = verb) {
|
|
2123
|
+
return target.named ? `${verb}${noun}\uFF1A${target.phrase}` : `${neutralVerb}${target.phrase}`;
|
|
2124
|
+
}
|
|
2125
|
+
function describeCommandForHuman(command2, args, refs = {}) {
|
|
2126
|
+
const reason = argStr(args, "reason");
|
|
2127
|
+
const reasonTail = reason ? `\uFF08\u7406\u7531\uFF1A${stripInternalIds(reason)}\uFF09` : "";
|
|
2128
|
+
switch (command2) {
|
|
2129
|
+
case "forceConclude":
|
|
2130
|
+
return `\u5F3A\u5236\u6536\u53E3${nodePhrase(args, refs)}${reasonTail}\u2014\u2014\u7ED5\u8FC7\u8BC4\u5BA1\u76F4\u63A5\u76D6\u91CC\u7A0B\u7891\u3002`;
|
|
2131
|
+
case "promote":
|
|
2132
|
+
return `\u628A${nodePhrase(args, refs)}\u8F6C\u4E3A\u957F\u671F\u4FDD\u7559\u7684\u8282\u70B9\uFF08\u4E0D\u518D\u968F\u4EFB\u52A1\u7ED3\u675F\u56DE\u6536\uFF09\u3002`;
|
|
2133
|
+
// continueBatch(续跑额度卡)**故意不在这里**:它的文案由引擎写好放在 `continuationBudget.request.summary`
|
|
2134
|
+
// 里,本来就是「《节点名》尚未完成,已达到自动派发上限。累计已运行 N 轮…」这种名称式写法,没有 id。
|
|
2135
|
+
// 重写一遍只会让同一句话有两个事实源,交给 {@link commandCardDisplayLabel} 的兜底清洗即可。
|
|
2136
|
+
case "resolveEscalation": {
|
|
2137
|
+
const escalation = escalationPhraseOf(refs, argStr(args, "escalationId"));
|
|
2138
|
+
const gapId = argStr(args, "gapId");
|
|
2139
|
+
if (!gapId) return `${actionPhrase("\u5173\u95ED", "\u6C42\u52A9", escalation)}${reasonTail}`;
|
|
2140
|
+
return [
|
|
2141
|
+
reason ? `\u91C7\u7528\u65B9\u6848\uFF1A${stripInternalIds(reason)}` : "\u786E\u8BA4\u6062\u590D\u65B9\u6848",
|
|
2142
|
+
actionPhrase("\u89E3\u51B3", "\u7F3A\u53E3", gapPhraseOf(refs, gapId)),
|
|
2143
|
+
actionPhrase("\u5173\u95ED\u5173\u8054", "\u6C42\u52A9", escalation, "\u5173\u95ED\u5173\u8054\u7684"),
|
|
2144
|
+
"\u7EE7\u7EED\u6267\u884C\uFF1A\u662F\uFF08\u4ECD\u987B\u6EE1\u8DB3\u5176\u4ED6\u963B\u585E\u6761\u4EF6\uFF09"
|
|
2145
|
+
].join("\uFF1B");
|
|
2146
|
+
}
|
|
2147
|
+
default:
|
|
2148
|
+
return void 0;
|
|
2149
|
+
}
|
|
2150
|
+
}
|
|
2151
|
+
function commandCardDisplayLabel(command2, args, storedLabel, refs = {}) {
|
|
2152
|
+
const described = command2 ? describeCommandForHuman(command2, args ?? {}, refs) : void 0;
|
|
2153
|
+
return described ?? stripInternalIds(storedLabel ?? "");
|
|
2154
|
+
}
|
|
2155
|
+
var PREFIXED_ID_RE, UUID_RE, SHORT_ID_RE, CARD_SUMMARY_MAX, NEUTRAL_NODE, NEUTRAL_ESCALATION, NEUTRAL_GAP, argStr;
|
|
2156
|
+
var init_command_card_copy = __esm({
|
|
2157
|
+
"../contract/src/command-card-copy.ts"() {
|
|
2158
|
+
"use strict";
|
|
2159
|
+
PREFIXED_ID_RE = /(?:artifact|esc|gap|wk|ws|actor|draft|issue|review|rev|work|node|company|chat|sess|int|blob|run|continuation)[::][A-Za-z0-9][A-Za-z0-9:._#-]*/gu;
|
|
2160
|
+
UUID_RE = /\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/giu;
|
|
2161
|
+
SHORT_ID_RE = /\b(?=[0-9a-f-]*[0-9])(?=[0-9a-f-]*[a-f])[0-9a-f]{8,}(?:-[0-9a-f]{4,})*\b/giu;
|
|
2162
|
+
CARD_SUMMARY_MAX = 48;
|
|
2163
|
+
NEUTRAL_NODE = "\u8FD9\u4E00\u6B65";
|
|
2164
|
+
NEUTRAL_ESCALATION = "\u8FD9\u6761\u6C42\u52A9";
|
|
2165
|
+
NEUTRAL_GAP = "\u8FD9\u4E2A\u7F3A\u53E3";
|
|
2166
|
+
argStr = (args, key2) => {
|
|
2167
|
+
const v2 = args[key2];
|
|
2168
|
+
return typeof v2 === "string" && v2.trim() ? v2.trim() : void 0;
|
|
2169
|
+
};
|
|
2170
|
+
}
|
|
2171
|
+
});
|
|
2172
|
+
|
|
2048
2173
|
// ../contract/src/index.ts
|
|
2049
2174
|
var init_src = __esm({
|
|
2050
2175
|
"../contract/src/index.ts"() {
|
|
@@ -2107,6 +2232,7 @@ var init_src = __esm({
|
|
|
2107
2232
|
init_chat_turn();
|
|
2108
2233
|
init_delegation();
|
|
2109
2234
|
init_delegation();
|
|
2235
|
+
init_delegation();
|
|
2110
2236
|
init_delegation_prompts();
|
|
2111
2237
|
init_knowledge();
|
|
2112
2238
|
init_knowledge_governance();
|
|
@@ -2114,6 +2240,7 @@ var init_src = __esm({
|
|
|
2114
2240
|
init_file_preview();
|
|
2115
2241
|
init_file_limits();
|
|
2116
2242
|
init_chunked_message();
|
|
2243
|
+
init_command_card_copy();
|
|
2117
2244
|
}
|
|
2118
2245
|
});
|
|
2119
2246
|
|
|
@@ -2263,6 +2390,21 @@ function sessionRuntimeOverride(session) {
|
|
|
2263
2390
|
if (!nodeId || !runtimeKind) return null;
|
|
2264
2391
|
return { nodeId, runtimeKind };
|
|
2265
2392
|
}
|
|
2393
|
+
function chatSessionInitialRuntime(input) {
|
|
2394
|
+
const trimmed = (v2) => typeof v2 === "string" && v2.trim() ? v2.trim() : null;
|
|
2395
|
+
const binding = input.binding?.nodeId && input.binding?.runtimeKind ? { nodeId: input.binding.nodeId, runtimeKind: input.binding.runtimeKind } : null;
|
|
2396
|
+
const requestedOverride = input.requested?.override;
|
|
2397
|
+
const picked = requestedOverride?.nodeId && requestedOverride?.runtimeKind ? { nodeId: requestedOverride.nodeId, runtimeKind: requestedOverride.runtimeKind } : null;
|
|
2398
|
+
const target = picked ?? binding;
|
|
2399
|
+
const followsAgentTarget = !picked || !!binding && picked.nodeId === binding.nodeId && picked.runtimeKind === binding.runtimeKind;
|
|
2400
|
+
const requestedModel = input.requested?.model;
|
|
2401
|
+
const model = requestedModel !== void 0 ? trimmed(requestedModel) : followsAgentTarget ? trimmed(input.agentModel) : null;
|
|
2402
|
+
return {
|
|
2403
|
+
overrideNodeId: target?.nodeId ?? null,
|
|
2404
|
+
overrideRuntimeKind: target?.runtimeKind ?? null,
|
|
2405
|
+
model
|
|
2406
|
+
};
|
|
2407
|
+
}
|
|
2266
2408
|
function sessionRuntimeOverrideChangesTarget(session, binding) {
|
|
2267
2409
|
const override = sessionRuntimeOverride(session);
|
|
2268
2410
|
if (!override) return false;
|
|
@@ -2322,7 +2464,7 @@ var init_session_runtime_target = __esm({
|
|
|
2322
2464
|
this.name = "SessionRuntimeOverrideError";
|
|
2323
2465
|
}
|
|
2324
2466
|
};
|
|
2325
|
-
CLEAR_SESSION_RUNTIME_HINT = "\
|
|
2467
|
+
CLEAR_SESSION_RUNTIME_HINT = "\u5728\u8FD0\u884C\u65F6\u9009\u62E9\u91CC\u70B9\u300C\u6062\u590D\u4E3A\u5458\u5DE5\u9ED8\u8BA4\u8FD0\u884C\u914D\u7F6E\u300D\u5373\u53EF\u7EE7\u7EED\uFF08\u4F1A\u628A\u8FD9\u4F4D Agent \u6B64\u523B\u7684\u9ED8\u8BA4\u914D\u7F6E\u6284\u8FDB\u8FD9\u6761\u4F1A\u8BDD\uFF09\u3002";
|
|
2326
2468
|
}
|
|
2327
2469
|
});
|
|
2328
2470
|
|
|
@@ -3904,9 +4046,57 @@ function newClaudeUsageAcc() {
|
|
|
3904
4046
|
costUsd: null,
|
|
3905
4047
|
messageUsageById: /* @__PURE__ */ new Map(),
|
|
3906
4048
|
finalUsage: null,
|
|
4049
|
+
restored: null,
|
|
3907
4050
|
saw: false
|
|
3908
4051
|
};
|
|
3909
4052
|
}
|
|
4053
|
+
function findClaudeSessionFile(configDir, cwd, runtimeSessionId) {
|
|
4054
|
+
const root = path7.join(configDir, "projects");
|
|
4055
|
+
const name = `${runtimeSessionId}.jsonl`;
|
|
4056
|
+
const direct = path7.join(root, cwd.replace(/[^a-zA-Z0-9]/g, "-"), name);
|
|
4057
|
+
if (fs7.existsSync(direct)) return direct;
|
|
4058
|
+
try {
|
|
4059
|
+
for (const slug6 of fs7.readdirSync(root)) {
|
|
4060
|
+
const candidate = path7.join(root, slug6, name);
|
|
4061
|
+
if (fs7.existsSync(candidate)) return candidate;
|
|
4062
|
+
}
|
|
4063
|
+
} catch {
|
|
4064
|
+
}
|
|
4065
|
+
return void 0;
|
|
4066
|
+
}
|
|
4067
|
+
function readClaudeRestoredCost(sessionFile) {
|
|
4068
|
+
try {
|
|
4069
|
+
const stat4 = fs7.statSync(sessionFile);
|
|
4070
|
+
if (!stat4.isFile() || stat4.size === 0) return null;
|
|
4071
|
+
const length = Math.min(stat4.size, RESTORED_COST_TAIL_BYTES);
|
|
4072
|
+
const buf = Buffer.alloc(length);
|
|
4073
|
+
const fd = fs7.openSync(sessionFile, "r");
|
|
4074
|
+
try {
|
|
4075
|
+
fs7.readSync(fd, buf, 0, length, stat4.size - length);
|
|
4076
|
+
} finally {
|
|
4077
|
+
fs7.closeSync(fd);
|
|
4078
|
+
}
|
|
4079
|
+
const lines = buf.toString("utf8").split("\n");
|
|
4080
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
4081
|
+
const line2 = lines[i];
|
|
4082
|
+
if (!line2.includes('"cost-state"')) continue;
|
|
4083
|
+
let parsed;
|
|
4084
|
+
try {
|
|
4085
|
+
parsed = JSON.parse(line2);
|
|
4086
|
+
} catch {
|
|
4087
|
+
continue;
|
|
4088
|
+
}
|
|
4089
|
+
if (parsed["type"] !== "cost-state") continue;
|
|
4090
|
+
const cost = parsed["totalCostUSD"];
|
|
4091
|
+
return {
|
|
4092
|
+
usage: parseModelUsage(parsed["modelUsage"]),
|
|
4093
|
+
costUsd: typeof cost === "number" && Number.isFinite(cost) && cost >= 0 ? cost : null
|
|
4094
|
+
};
|
|
4095
|
+
}
|
|
4096
|
+
} catch {
|
|
4097
|
+
}
|
|
4098
|
+
return null;
|
|
4099
|
+
}
|
|
3910
4100
|
function usageNum(v2) {
|
|
3911
4101
|
return typeof v2 === "number" && Number.isFinite(v2) && v2 >= 0 ? v2 : void 0;
|
|
3912
4102
|
}
|
|
@@ -3980,14 +4170,34 @@ function accumulateClaudeUsage(acc, p2) {
|
|
|
3980
4170
|
acc.saw = true;
|
|
3981
4171
|
}
|
|
3982
4172
|
} else if (type === "result") {
|
|
3983
|
-
acc.finalUsage = mergeFinalUsage(parseModelUsage(p2["modelUsage"]), parseResultUsage(p2["usage"]));
|
|
3984
4173
|
const c = p2["total_cost_usd"];
|
|
3985
|
-
|
|
3986
|
-
|
|
4174
|
+
const cost = typeof c === "number" && Number.isFinite(c) ? c : null;
|
|
4175
|
+
const { usage: modelUsage, costUsd } = sinceRestored(acc.restored, parseModelUsage(p2["modelUsage"]), cost);
|
|
4176
|
+
acc.finalUsage = mergeFinalUsage(modelUsage, parseResultUsage(p2["usage"]));
|
|
4177
|
+
if (costUsd != null) {
|
|
4178
|
+
acc.costUsd = costUsd;
|
|
3987
4179
|
}
|
|
3988
4180
|
if (acc.finalUsage || acc.costUsd != null) acc.saw = true;
|
|
3989
4181
|
}
|
|
3990
4182
|
}
|
|
4183
|
+
function sinceRestored(restored, usage, costUsd) {
|
|
4184
|
+
if (!restored) return { usage, costUsd };
|
|
4185
|
+
const out = usage ? { ...usage } : null;
|
|
4186
|
+
if (out && restored.usage) {
|
|
4187
|
+
for (const k2 of ["input", "output", "cacheRead", "cacheCreation"]) {
|
|
4188
|
+
const base = restored.usage[k2];
|
|
4189
|
+
const total = out[k2];
|
|
4190
|
+
if (total == null || base == null) continue;
|
|
4191
|
+
if (total < base) return { usage, costUsd };
|
|
4192
|
+
out[k2] = total - base;
|
|
4193
|
+
}
|
|
4194
|
+
}
|
|
4195
|
+
if (costUsd != null && restored.costUsd != null) {
|
|
4196
|
+
if (costUsd < restored.costUsd) return { usage, costUsd };
|
|
4197
|
+
return { usage: out, costUsd: costUsd - restored.costUsd };
|
|
4198
|
+
}
|
|
4199
|
+
return { usage: out, costUsd };
|
|
4200
|
+
}
|
|
3991
4201
|
function newClaudeRunningUsage() {
|
|
3992
4202
|
return { byMessage: /* @__PURE__ */ new Map(), currentMessageId: null, lastKey: "" };
|
|
3993
4203
|
}
|
|
@@ -4088,13 +4298,14 @@ function classifyExit(result) {
|
|
|
4088
4298
|
if (status === 429 || status === 529) return "rate-limit";
|
|
4089
4299
|
return "error";
|
|
4090
4300
|
}
|
|
4091
|
-
var import_node_child_process3, import_node_crypto6, fs7, path7, readline, CLAUDE_BLOCKED_FLAGS, SUBAGENT_TRANSCRIPT_MAX_BYTES, SUBAGENT_TERMINAL, ONE_SHOT_UNSAFE_TOOLS, ClaudeCodeAdapter;
|
|
4301
|
+
var import_node_child_process3, import_node_crypto6, fs7, os4, path7, readline, CLAUDE_BLOCKED_FLAGS, SUBAGENT_TRANSCRIPT_MAX_BYTES, SUBAGENT_TERMINAL, RESTORED_COST_TAIL_BYTES, ONE_SHOT_UNSAFE_TOOLS, ClaudeCodeAdapter;
|
|
4092
4302
|
var init_claude_code = __esm({
|
|
4093
4303
|
"../adapters/src/claude-code/index.ts"() {
|
|
4094
4304
|
"use strict";
|
|
4095
4305
|
import_node_child_process3 = require("node:child_process");
|
|
4096
4306
|
import_node_crypto6 = require("node:crypto");
|
|
4097
4307
|
fs7 = __toESM(require("node:fs"), 1);
|
|
4308
|
+
os4 = __toESM(require("node:os"), 1);
|
|
4098
4309
|
path7 = __toESM(require("node:path"), 1);
|
|
4099
4310
|
readline = __toESM(require("node:readline"), 1);
|
|
4100
4311
|
init_sync_skills();
|
|
@@ -4141,6 +4352,7 @@ var init_claude_code = __esm({
|
|
|
4141
4352
|
killed: "stopped",
|
|
4142
4353
|
stopped: "stopped"
|
|
4143
4354
|
};
|
|
4355
|
+
RESTORED_COST_TAIL_BYTES = 4 * 1024 * 1024;
|
|
4144
4356
|
ONE_SHOT_UNSAFE_TOOLS = ["ScheduleWakeup", "CronCreate", "CronDelete", "CronList"];
|
|
4145
4357
|
ClaudeCodeAdapter = class {
|
|
4146
4358
|
constructor(opts = {}) {
|
|
@@ -4237,6 +4449,9 @@ var init_claude_code = __esm({
|
|
|
4237
4449
|
{ runtime: "claude-code", actor: job.actor, ...job.dispatchId ? { dispatchId: job.dispatchId } : {} }
|
|
4238
4450
|
)
|
|
4239
4451
|
];
|
|
4452
|
+
const claudeConfigDir = job.env?.["CLAUDE_CONFIG_DIR"] || this.opts.env?.["CLAUDE_CONFIG_DIR"] || process.env["CLAUDE_CONFIG_DIR"] || path7.join(os4.homedir(), ".claude");
|
|
4453
|
+
const resumedSessionFile = job.runtimeSessionId && job.resumeRuntimeSession ? findClaudeSessionFile(claudeConfigDir, dir, job.runtimeSessionId) : void 0;
|
|
4454
|
+
const restoredCost = resumedSessionFile ? readClaudeRestoredCost(resumedSessionFile) : null;
|
|
4240
4455
|
const otelEnv = this.resolveOtelEnv(job, id);
|
|
4241
4456
|
const containerized = await maybeContainerize({
|
|
4242
4457
|
bin: this.opts.claudeBin ?? "claude",
|
|
@@ -4364,6 +4579,7 @@ var init_claude_code = __esm({
|
|
|
4364
4579
|
const STDERR_MAX_LINES = 40;
|
|
4365
4580
|
const STDERR_MAX_BYTES = 4e3;
|
|
4366
4581
|
const usageAcc = newClaudeUsageAcc();
|
|
4582
|
+
usageAcc.restored = restoredCost;
|
|
4367
4583
|
const runningUsage = newClaudeRunningUsage();
|
|
4368
4584
|
const usageCheckpointCbs = [];
|
|
4369
4585
|
let sessionModel;
|
|
@@ -4833,7 +5049,7 @@ var init_resilient = __esm({
|
|
|
4833
5049
|
|
|
4834
5050
|
// ../adapters/src/_core/skill-cache.ts
|
|
4835
5051
|
function defaultCacheRoot() {
|
|
4836
|
-
return path8.join(
|
|
5052
|
+
return path8.join(os5.homedir(), ".oasis", "skill-cache");
|
|
4837
5053
|
}
|
|
4838
5054
|
function sessionSkillsSubdir(runtimeKind) {
|
|
4839
5055
|
switch (runtimeKind) {
|
|
@@ -5238,13 +5454,13 @@ async function verifyPendingLink(skillsDir, name, pend, log3) {
|
|
|
5238
5454
|
}
|
|
5239
5455
|
return true;
|
|
5240
5456
|
}
|
|
5241
|
-
var import_node_crypto7, fsp,
|
|
5457
|
+
var import_node_crypto7, fsp, os5, path8, MANIFEST_SCHEMA_VERSION, STALE_LOCK_MS, LOCK_ACQUIRE_TIMEOUT_MS, LOCK_POLL_MS;
|
|
5242
5458
|
var init_skill_cache = __esm({
|
|
5243
5459
|
"../adapters/src/_core/skill-cache.ts"() {
|
|
5244
5460
|
"use strict";
|
|
5245
5461
|
import_node_crypto7 = require("node:crypto");
|
|
5246
5462
|
fsp = __toESM(require("node:fs/promises"), 1);
|
|
5247
|
-
|
|
5463
|
+
os5 = __toESM(require("node:os"), 1);
|
|
5248
5464
|
path8 = __toESM(require("node:path"), 1);
|
|
5249
5465
|
MANIFEST_SCHEMA_VERSION = 2;
|
|
5250
5466
|
STALE_LOCK_MS = 6e4;
|
|
@@ -6434,7 +6650,7 @@ function codexSessionsRoot() {
|
|
|
6434
6650
|
const candidates = [];
|
|
6435
6651
|
const ch = process.env["CODEX_HOME"];
|
|
6436
6652
|
if (ch) candidates.push(path10.join(ch, "sessions"));
|
|
6437
|
-
const home2 = process.env["HOME"] ||
|
|
6653
|
+
const home2 = process.env["HOME"] || os6.homedir();
|
|
6438
6654
|
if (home2) candidates.push(path10.join(home2, ".codex", "sessions"));
|
|
6439
6655
|
for (const c of candidates) {
|
|
6440
6656
|
try {
|
|
@@ -6757,7 +6973,7 @@ function codexTurnErrorMessage(value2) {
|
|
|
6757
6973
|
const detail = typeof error2?.additionalDetails === "string" ? error2.additionalDetails.trim() : "";
|
|
6758
6974
|
return [summary, detail].filter(Boolean).join("\n").slice(0, 4e3);
|
|
6759
6975
|
}
|
|
6760
|
-
var import_node_child_process7, import_node_crypto9, fs8,
|
|
6976
|
+
var import_node_child_process7, import_node_crypto9, fs8, os6, path10, readline2, CODEX_BLOCKED_FLAGS, CODEX_ARGV_PROMPT_MAX_BYTES, CodexRolloutUsageTail, CODEX_APP_SERVER_BLOCKED_FLAGS, CodexAdapter;
|
|
6761
6977
|
var init_codex = __esm({
|
|
6762
6978
|
"../adapters/src/codex/index.ts"() {
|
|
6763
6979
|
"use strict";
|
|
@@ -6765,7 +6981,7 @@ var init_codex = __esm({
|
|
|
6765
6981
|
init_container_runtime();
|
|
6766
6982
|
import_node_crypto9 = require("node:crypto");
|
|
6767
6983
|
fs8 = __toESM(require("node:fs"), 1);
|
|
6768
|
-
|
|
6984
|
+
os6 = __toESM(require("node:os"), 1);
|
|
6769
6985
|
path10 = __toESM(require("node:path"), 1);
|
|
6770
6986
|
readline2 = __toESM(require("node:readline"), 1);
|
|
6771
6987
|
init_sync_skills();
|
|
@@ -9371,7 +9587,7 @@ function pdeathsigAvailable(probe = defaultProbe) {
|
|
|
9371
9587
|
return cachedAvailable;
|
|
9372
9588
|
}
|
|
9373
9589
|
function defaultProbe() {
|
|
9374
|
-
if (
|
|
9590
|
+
if (os7.platform() !== "linux") return false;
|
|
9375
9591
|
try {
|
|
9376
9592
|
const help = (0, import_node_child_process9.execFileSync)("setpriv", ["--help"], { stdio: ["ignore", "pipe", "ignore"], timeout: 2e3 }).toString();
|
|
9377
9593
|
return help.includes("--pdeathsig");
|
|
@@ -9385,12 +9601,12 @@ function pdeathsigWrap(bin, args) {
|
|
|
9385
9601
|
function shouldBindRuntimePdeathsig() {
|
|
9386
9602
|
return process.env["OASIS_BIND_RUNTIME_PDEATHSIG"] === "1" && pdeathsigAvailable();
|
|
9387
9603
|
}
|
|
9388
|
-
var import_node_child_process9,
|
|
9604
|
+
var import_node_child_process9, os7, cachedAvailable;
|
|
9389
9605
|
var init_pdeathsig = __esm({
|
|
9390
9606
|
"../adapters/src/_core/pdeathsig.ts"() {
|
|
9391
9607
|
"use strict";
|
|
9392
9608
|
import_node_child_process9 = require("node:child_process");
|
|
9393
|
-
|
|
9609
|
+
os7 = __toESM(require("node:os"), 1);
|
|
9394
9610
|
}
|
|
9395
9611
|
});
|
|
9396
9612
|
|
|
@@ -12831,7 +13047,13 @@ async function reconcileChatTurn(turn, deps) {
|
|
|
12831
13047
|
...status === "succeeded" || !restartCause ? {} : { cancelledBy: restartCause }
|
|
12832
13048
|
});
|
|
12833
13049
|
if (!ok3) return raced;
|
|
12834
|
-
return {
|
|
13050
|
+
return {
|
|
13051
|
+
settled: true,
|
|
13052
|
+
turnId: turn.id,
|
|
13053
|
+
status,
|
|
13054
|
+
reason: `run \u7EC8\u6001 ${run.status}`,
|
|
13055
|
+
...run.exitReason ? { exitReason: run.exitReason } : {}
|
|
13056
|
+
};
|
|
12835
13057
|
}
|
|
12836
13058
|
async function sweepStaleChatTurns(deps) {
|
|
12837
13059
|
const before = new Date(deps.now - (deps.staleAfterMs ?? 2 * 6e4)).toISOString();
|
|
@@ -12853,7 +13075,8 @@ async function sweepStaleChatTurns(deps) {
|
|
|
12853
13075
|
chatSessionId: turn.chatSessionId,
|
|
12854
13076
|
turnId: turn.id,
|
|
12855
13077
|
status: settledStatus,
|
|
12856
|
-
reason: outcome.reason ?? `\u8F6E\u6B21\u6536\u53E3\u4E3A ${settledStatus}
|
|
13078
|
+
reason: outcome.reason ?? `\u8F6E\u6B21\u6536\u53E3\u4E3A ${settledStatus}`,
|
|
13079
|
+
...outcome.settled && outcome.exitReason ? { exitReason: outcome.exitReason } : {}
|
|
12857
13080
|
}).catch((e) => {
|
|
12858
13081
|
deps.log?.(`[chat-turn-sweep] \u8F6E\u6B21 ${turn.id} \u6536\u53E3\u540E\u7684\u56DE\u8C03\u5931\u8D25\uFF08\u4E0D\u5F71\u54CD\u672C\u62CD\uFF09: ${String(e)}`);
|
|
12859
13082
|
});
|
|
@@ -125858,7 +126081,7 @@ function isReplyWork(w2) {
|
|
|
125858
126081
|
function replyIssueIdOf(w2) {
|
|
125859
126082
|
return w2.lane === "reply" ? w2.replyToIssueId ?? null : null;
|
|
125860
126083
|
}
|
|
125861
|
-
var BUSINESS_HANDOFF_POLICY_FIELD, BUSINESS_HANDOFF_POLICY_EXEMPT, DEFAULT_CONFIG, deriveWorkId, deriveReviewId, deriveReplyId;
|
|
126084
|
+
var BUSINESS_HANDOFF_POLICY_FIELD, BUSINESS_HANDOFF_POLICY_EXEMPT, DEFAULT_CONFIG, deriveWorkId, deriveReviewId, ENGINE_SYSTEM_ACTOR, REVIEW_EXHAUSTED_ESC_PREFIX, deriveReplyId;
|
|
125862
126085
|
var init_model = __esm({
|
|
125863
126086
|
"../engine/src/model.ts"() {
|
|
125864
126087
|
"use strict";
|
|
@@ -125871,6 +126094,8 @@ var init_model = __esm({
|
|
|
125871
126094
|
};
|
|
125872
126095
|
deriveWorkId = (nodeId, version2) => `wk:${nodeId}:${version2}`;
|
|
125873
126096
|
deriveReviewId = (workId, reviewer, group) => `rv:${workId}:${reviewer}:${group}`;
|
|
126097
|
+
ENGINE_SYSTEM_ACTOR = "actor:system:engine";
|
|
126098
|
+
REVIEW_EXHAUSTED_ESC_PREFIX = "esc:review-exhausted:";
|
|
125874
126099
|
deriveReplyId = (issueId, salt) => `ir:${issueId}:${salt}`;
|
|
125875
126100
|
}
|
|
125876
126101
|
});
|
|
@@ -126414,6 +126639,7 @@ var init_kill = __esm({
|
|
|
126414
126639
|
function scan(state, ctx) {
|
|
126415
126640
|
if (state.workorder.dispatchPaused) return { events: [], terminated: false };
|
|
126416
126641
|
const events = [];
|
|
126642
|
+
closeSettledReviewEscalations(state, events);
|
|
126417
126643
|
for (const node2 of state.liveNodes()) {
|
|
126418
126644
|
const lw = node2.latestWorkId ? state.work(node2.latestWorkId) : null;
|
|
126419
126645
|
const continuationPolicy = node2.assigneeActorId ? ctx.continuationPolicies?.get(node2.assigneeActorId) : null;
|
|
@@ -126942,6 +127168,55 @@ function reviewMaxRetriesOf(policy) {
|
|
|
126942
127168
|
const act = policy.resolve({ executor: "agent", scenario: "review" }).timeoutAction;
|
|
126943
127169
|
return act.kind === "kill-rebuild" ? act.maxRetries : AGENT_REVIEW_MAX_RETRIES;
|
|
126944
127170
|
}
|
|
127171
|
+
function pushReviewExhaustedEscalation(state, nodeId, workId, reviewId, reviewerActorId, rounds, events) {
|
|
127172
|
+
const node2 = state.node(nodeId);
|
|
127173
|
+
if (!node2) return;
|
|
127174
|
+
if (node2.latestAcceptId === workId) return;
|
|
127175
|
+
const escId = `${REVIEW_EXHAUSTED_ESC_PREFIX}${reviewId}`;
|
|
127176
|
+
if (state.allIssues().some((i) => i.id === escId)) return;
|
|
127177
|
+
events.push({
|
|
127178
|
+
kind: "issue.create",
|
|
127179
|
+
workorderId: state.workorder.id,
|
|
127180
|
+
issueId: escId,
|
|
127181
|
+
issueKind: "escalation",
|
|
127182
|
+
body: `\u300A${node2.title}\u300B\u7684\u8BC4\u5BA1\u8FDE\u7EED ${rounds} \u6B21\u5931\u8D25\uFF0C\u8FD9\u4E00\u8F6E\u8BC4\u5BA1\u6536\u4E0D\u9F50\u2014\u2014\u9700\u8981\u6709\u4EBA\u91CD\u5F00\u3002
|
|
127183
|
+
|
|
127184
|
+
\u672B\u6B21\u8BC4\u5BA1\u4F1A\u8BDD\u7ED3\u675F\u65F6\u6CA1\u6709\u6295\u7968\uFF1B\u62A5\u9519\u539F\u8BDD\u89C1\u8FD9\u4E2A\u8282\u70B9\u7684\u6267\u884C\u8F68\u8FF9\u3002`,
|
|
127185
|
+
aboutNodeId: nodeId,
|
|
127186
|
+
aboutWorkId: workId,
|
|
127187
|
+
raisedByNodeId: null,
|
|
127188
|
+
authorActorId: reviewerActorId,
|
|
127189
|
+
handActorId: null,
|
|
127190
|
+
recipients: [state.workorder.ownerActorId],
|
|
127191
|
+
attachments: [],
|
|
127192
|
+
intent: "advisory"
|
|
127193
|
+
});
|
|
127194
|
+
}
|
|
127195
|
+
function closeSettledReviewEscalations(state, events) {
|
|
127196
|
+
for (const issue2 of state.allIssues()) {
|
|
127197
|
+
if (issue2.resolvedAt !== null || issue2.kind !== "escalation") continue;
|
|
127198
|
+
const id = issue2.id;
|
|
127199
|
+
if (!id.startsWith(REVIEW_EXHAUSTED_ESC_PREFIX)) continue;
|
|
127200
|
+
const node2 = issue2.aboutNodeId ? state.node(issue2.aboutNodeId) : void 0;
|
|
127201
|
+
if (!node2 || node2.cancelledAt) continue;
|
|
127202
|
+
const lw = node2.latestWorkId ? state.work(node2.latestWorkId) : null;
|
|
127203
|
+
if (lw && workState(lw, hasOutput(lw, state.artifactsOf(lw.id).length)) === "dead") continue;
|
|
127204
|
+
const review = state.review(id.slice(REVIEW_EXHAUSTED_ESC_PREFIX.length));
|
|
127205
|
+
if (!review) continue;
|
|
127206
|
+
const head = state.requirementsOf(node2.id).find((r) => r.reviewGroup === review.reviewGroup)?.latestReviewId ?? null;
|
|
127207
|
+
const note = head !== review.id ? "\u8BC4\u5BA1\u5DF2\u91CD\u65B0\u5B89\u6392" : node2.latestAcceptId === review.targetWorkId ? "\u8FD9\u4E00\u7248\u5DF2\u9A8C\u6536" : null;
|
|
127208
|
+
if (note === null) continue;
|
|
127209
|
+
events.push({
|
|
127210
|
+
kind: "issue.resolve",
|
|
127211
|
+
workorderId: state.workorder.id,
|
|
127212
|
+
issueId: issue2.id,
|
|
127213
|
+
state: "resolved",
|
|
127214
|
+
by: SYSTEM_ENGINE_ACTOR,
|
|
127215
|
+
note,
|
|
127216
|
+
viaWorkId: null
|
|
127217
|
+
});
|
|
127218
|
+
}
|
|
127219
|
+
}
|
|
126945
127220
|
function processReviews(state, nodeId, workId, ctx, events) {
|
|
126946
127221
|
const policy = ctx.policy ?? CODE_DEFAULT_POLICY;
|
|
126947
127222
|
const reqs = state.requirementsOf(nodeId);
|
|
@@ -127003,15 +127278,19 @@ function processReviews(state, nodeId, workId, ctx, events) {
|
|
|
127003
127278
|
}
|
|
127004
127279
|
} else if (info.status === "failed") {
|
|
127005
127280
|
const req = reqs.find((r) => r.reviewGroup === g2);
|
|
127006
|
-
const
|
|
127281
|
+
const exhausted = reviewRetriesExhausted(g2, reviews, { policy });
|
|
127282
|
+
const overLimit = exhausted !== null;
|
|
127007
127283
|
if (overLimit && classify(req.reviewerActorId) === "agent") {
|
|
127008
127284
|
const lrId = req.latestReviewId;
|
|
127009
|
-
if (lrId)
|
|
127010
|
-
|
|
127011
|
-
|
|
127012
|
-
|
|
127013
|
-
|
|
127014
|
-
|
|
127285
|
+
if (lrId) {
|
|
127286
|
+
events.push({
|
|
127287
|
+
kind: "review.kill",
|
|
127288
|
+
workorderId: state.workorder.id,
|
|
127289
|
+
reviewId: lrId,
|
|
127290
|
+
reason: "exhausted"
|
|
127291
|
+
});
|
|
127292
|
+
pushReviewExhaustedEscalation(state, nodeId, workId, lrId, req.reviewerActorId, exhausted.rounds, events);
|
|
127293
|
+
}
|
|
127015
127294
|
} else if (!overLimit) {
|
|
127016
127295
|
events.push({
|
|
127017
127296
|
kind: "review.create",
|
|
@@ -127202,6 +127481,7 @@ function assessConvergence(state, ctx) {
|
|
|
127202
127481
|
const anyUnfinished = state.liveNodes().some((n) => !n.latestAcceptId);
|
|
127203
127482
|
return { stuck: !anyRunning && !anyBlockingIssue && allIdle && anyUnfinished, codes };
|
|
127204
127483
|
}
|
|
127484
|
+
var SYSTEM_ENGINE_ACTOR;
|
|
127205
127485
|
var init_activate = __esm({
|
|
127206
127486
|
"../engine/src/activate.ts"() {
|
|
127207
127487
|
"use strict";
|
|
@@ -127216,6 +127496,7 @@ var init_activate = __esm({
|
|
|
127216
127496
|
init_model();
|
|
127217
127497
|
init_views2();
|
|
127218
127498
|
init_kill();
|
|
127499
|
+
SYSTEM_ENGINE_ACTOR = ENGINE_SYSTEM_ACTOR;
|
|
127219
127500
|
}
|
|
127220
127501
|
});
|
|
127221
127502
|
|
|
@@ -135090,6 +135371,7 @@ var init_issue = __esm({
|
|
|
135090
135371
|
"../engine/src/handlers/issue.ts"() {
|
|
135091
135372
|
"use strict";
|
|
135092
135373
|
init_plan();
|
|
135374
|
+
init_model();
|
|
135093
135375
|
init_letters();
|
|
135094
135376
|
issueCreate = {
|
|
135095
135377
|
name: "issue/create",
|
|
@@ -135181,7 +135463,8 @@ var init_issue = __esm({
|
|
|
135181
135463
|
}
|
|
135182
135464
|
if (issue2.resolvedAt !== null) return;
|
|
135183
135465
|
const humanResolution = e.by.startsWith("actor:human:") && e.by === ctx.actorId;
|
|
135184
|
-
|
|
135466
|
+
const engineSelfClosure = e.by === ENGINE_SYSTEM_ACTOR && ctx.actorId === ENGINE_SYSTEM_ACTOR && issue2.id.startsWith(REVIEW_EXHAUSTED_ESC_PREFIX);
|
|
135467
|
+
if (e.semanticsVersion === 2 && issue2.kind === "escalation" && !humanResolution && !engineSelfClosure) {
|
|
135185
135468
|
throw new Error("\u5173\u95ED\u5347\u7EA7\u9700\u8981\u4EBA\u660E\u786E\u786E\u8BA4\uFF1Bagent \u8BF7\u63D0\u4EA4\u5173\u95ED\u6388\u6743\u7533\u8BF7");
|
|
135186
135469
|
}
|
|
135187
135470
|
state.updateIssue(e.issueId, {
|
|
@@ -138078,6 +138361,13 @@ function openBackpressureOf(model, id) {
|
|
|
138078
138361
|
function unresolvedGapsOf(model, id) {
|
|
138079
138362
|
return (model.gaps.get(id) ?? []).filter((g2) => !g2.resolved);
|
|
138080
138363
|
}
|
|
138364
|
+
function findGap(model, gapId) {
|
|
138365
|
+
for (const [artifactId, list2] of model.gaps) {
|
|
138366
|
+
const gap = list2.find((g2) => g2.gapId === gapId);
|
|
138367
|
+
if (gap) return { artifactId, gap };
|
|
138368
|
+
}
|
|
138369
|
+
return null;
|
|
138370
|
+
}
|
|
138081
138371
|
function unresolvedEscalationsOf(model, id) {
|
|
138082
138372
|
return (model.escalations.get(id) ?? []).filter((e) => !e.resolved).map((e) => ({
|
|
138083
138373
|
// ADR 0079 D4:把稳定 id 一并带出——inbox / 卡片要靠它指明「关哪一条」(现状 resolve 是 artifact 级全清)。
|
|
@@ -142128,9 +142418,6 @@ ${supplemental.taskAppend.trim()}
|
|
|
142128
142418
|
`;
|
|
142129
142419
|
}
|
|
142130
142420
|
}
|
|
142131
|
-
if (this.opts.executionContinuityInstructions && continuityExposureOn && (spec.action === "produce" || spec.action === "integrate") && continuityArtifact) {
|
|
142132
|
-
bundle.files["execution/CONTINUITY.md"] = this.opts.executionContinuityInstructions;
|
|
142133
|
-
}
|
|
142134
142421
|
if (this.opts.resolveExecutionResumePack && continuityExposureOn && (spec.action === "produce" || spec.action === "integrate") && continuityArtifact) {
|
|
142135
142422
|
let resumePack = null;
|
|
142136
142423
|
try {
|
|
@@ -142738,6 +143025,9 @@ ${supplemental.taskAppend.trim()}
|
|
|
142738
143025
|
});
|
|
142739
143026
|
|
|
142740
143027
|
// ../core/src/session-limits.ts
|
|
143028
|
+
function sessionWallClockMs(kind) {
|
|
143029
|
+
return SESSION_WALL_CLOCK_MS[kind];
|
|
143030
|
+
}
|
|
142741
143031
|
var SESSION_WALL_CLOCK_MS;
|
|
142742
143032
|
var init_session_limits = __esm({
|
|
142743
143033
|
"../core/src/session-limits.ts"() {
|
|
@@ -142868,6 +143158,41 @@ ${lines.join("\n")}`, "rejected-proposal-repeat");
|
|
|
142868
143158
|
}
|
|
142869
143159
|
});
|
|
142870
143160
|
|
|
143161
|
+
// ../core/src/command-card-naming.ts
|
|
143162
|
+
function commandCardRefsOf(model) {
|
|
143163
|
+
const nodeTitle = (id) => model.artifacts.get(id)?.title?.trim() || void 0;
|
|
143164
|
+
return {
|
|
143165
|
+
nodeTitle,
|
|
143166
|
+
escalation: (escalationId) => {
|
|
143167
|
+
const found2 = escalationById(model, escalationId);
|
|
143168
|
+
if (!found2) return void 0;
|
|
143169
|
+
return { summary: found2.reason, ...nodeTitle(found2.artifactId) ? { nodeTitle: nodeTitle(found2.artifactId) } : {} };
|
|
143170
|
+
},
|
|
143171
|
+
gap: (gapId) => {
|
|
143172
|
+
const found2 = findGap(model, gapId);
|
|
143173
|
+
if (!found2) return void 0;
|
|
143174
|
+
return { summary: found2.gap.description, ...nodeTitle(found2.artifactId) ? { nodeTitle: nodeTitle(found2.artifactId) } : {} };
|
|
143175
|
+
}
|
|
143176
|
+
};
|
|
143177
|
+
}
|
|
143178
|
+
function annotateCommandCardLabels(model) {
|
|
143179
|
+
const refs = commandCardRefsOf(model);
|
|
143180
|
+
for (const review of model.pendingReviews.values()) {
|
|
143181
|
+
if (!review.command) continue;
|
|
143182
|
+
review.command = {
|
|
143183
|
+
...review.command,
|
|
143184
|
+
displayLabel: commandCardDisplayLabel(review.command.command, review.command.args, review.command.effectLabel, refs)
|
|
143185
|
+
};
|
|
143186
|
+
}
|
|
143187
|
+
}
|
|
143188
|
+
var init_command_card_naming = __esm({
|
|
143189
|
+
"../core/src/command-card-naming.ts"() {
|
|
143190
|
+
"use strict";
|
|
143191
|
+
init_src();
|
|
143192
|
+
init_read_model();
|
|
143193
|
+
}
|
|
143194
|
+
});
|
|
143195
|
+
|
|
142871
143196
|
// ../core/src/queue-retirement.ts
|
|
142872
143197
|
function isSettledProduction(w2) {
|
|
142873
143198
|
if (w2.lane === "reply") return false;
|
|
@@ -144183,6 +144508,7 @@ var init_kernel_bridge = __esm({
|
|
|
144183
144508
|
init_closure_gate2();
|
|
144184
144509
|
init_kernel();
|
|
144185
144510
|
init_bridge_readmodel();
|
|
144511
|
+
init_command_card_naming();
|
|
144186
144512
|
init_propose_guard();
|
|
144187
144513
|
init_src6();
|
|
144188
144514
|
init_src6();
|
|
@@ -144508,6 +144834,7 @@ var init_kernel_bridge = __esm({
|
|
|
144508
144834
|
...card2.priorRejections && card2.priorRejections.length > 0 ? { priorRejections: card2.priorRejections } : {}
|
|
144509
144835
|
});
|
|
144510
144836
|
}
|
|
144837
|
+
annotateCommandCardLabels(fresh);
|
|
144511
144838
|
Object.assign(this.model, fresh);
|
|
144512
144839
|
if (!this.sweepingStaleDrafts && this.draftCards.size > 0) {
|
|
144513
144840
|
this.sweepingStaleDrafts = true;
|
|
@@ -146614,6 +146941,7 @@ var init_src7 = __esm({
|
|
|
146614
146941
|
init_dispatcher();
|
|
146615
146942
|
init_session_limits();
|
|
146616
146943
|
init_rejected_proposals();
|
|
146944
|
+
init_command_card_naming();
|
|
146617
146945
|
init_kernel_bridge();
|
|
146618
146946
|
init_bridge_readmodel();
|
|
146619
146947
|
init_queue_retirement();
|
|
@@ -165172,6 +165500,23 @@ async function waitForInflightInsert(rowId, timeoutMs) {
|
|
|
165172
165500
|
})]);
|
|
165173
165501
|
if (timer) clearTimeout(timer);
|
|
165174
165502
|
}
|
|
165503
|
+
async function waitForAdmittedTurnStart(chatSessionId, deps) {
|
|
165504
|
+
if (deps.liveChat.isRunning(chatSessionId)) return;
|
|
165505
|
+
if (!await deps.ledgerTurnRunning()) return;
|
|
165506
|
+
await new Promise((resolve11) => {
|
|
165507
|
+
let stop = () => {
|
|
165508
|
+
};
|
|
165509
|
+
const timer = setTimeout(() => {
|
|
165510
|
+
stop();
|
|
165511
|
+
resolve11();
|
|
165512
|
+
}, deps.timeoutMs);
|
|
165513
|
+
timer.unref?.();
|
|
165514
|
+
stop = deps.liveChat.onNextTurn(chatSessionId, () => {
|
|
165515
|
+
clearTimeout(timer);
|
|
165516
|
+
resolve11();
|
|
165517
|
+
});
|
|
165518
|
+
});
|
|
165519
|
+
}
|
|
165175
165520
|
async function appendNowThroughQueue(chatSessionId, text7, deps, clientKey, attachments, retainLocallyOnFailure = false, opts) {
|
|
165176
165521
|
const newId = deps.newId ?? import_node_crypto22.randomUUID;
|
|
165177
165522
|
const now = deps.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
@@ -200719,6 +201064,150 @@ var init_knowledge2 = __esm({
|
|
|
200719
201064
|
}
|
|
200720
201065
|
});
|
|
200721
201066
|
|
|
201067
|
+
// ../server/src/chat-exit.ts
|
|
201068
|
+
function transcriptTail(ref2) {
|
|
201069
|
+
try {
|
|
201070
|
+
const stat4 = fs17.statSync(ref2);
|
|
201071
|
+
const size = Math.min(stat4.size, 4e3);
|
|
201072
|
+
const buf = Buffer.alloc(size);
|
|
201073
|
+
const fd = fs17.openSync(ref2, "r");
|
|
201074
|
+
try {
|
|
201075
|
+
fs17.readSync(fd, buf, 0, size, Math.max(0, stat4.size - size));
|
|
201076
|
+
} finally {
|
|
201077
|
+
fs17.closeSync(fd);
|
|
201078
|
+
}
|
|
201079
|
+
return buf.toString("utf8").trim();
|
|
201080
|
+
} catch {
|
|
201081
|
+
return "";
|
|
201082
|
+
}
|
|
201083
|
+
}
|
|
201084
|
+
function clipLine(line2) {
|
|
201085
|
+
return line2.length > SUMMARY_MAX_CHARS ? `${line2.slice(0, SUMMARY_MAX_CHARS)}\u2026` : line2;
|
|
201086
|
+
}
|
|
201087
|
+
function providerMessage(line2) {
|
|
201088
|
+
const m2 = /['"]message['"]\s*:\s*(?:'((?:[^'\\]|\\.)*)'|"((?:[^"\\]|\\.)*)")/.exec(line2);
|
|
201089
|
+
const text7 = (m2?.[1] ?? m2?.[2])?.trim();
|
|
201090
|
+
return text7 ? text7 : void 0;
|
|
201091
|
+
}
|
|
201092
|
+
function failureKind(reason, line2) {
|
|
201093
|
+
if (line2.startsWith(SESSION_STARTUP_FAILED_PREFIX)) return "startup-failed";
|
|
201094
|
+
switch (reason) {
|
|
201095
|
+
case "auth-error":
|
|
201096
|
+
return "auth";
|
|
201097
|
+
case "server-unreachable":
|
|
201098
|
+
return "node-unreachable";
|
|
201099
|
+
case "timeout":
|
|
201100
|
+
return "timeout";
|
|
201101
|
+
case "output-limit":
|
|
201102
|
+
return "output-limit";
|
|
201103
|
+
case "rate-limit":
|
|
201104
|
+
return QUOTA_RE3.test(line2) ? "quota" : "rate-limit";
|
|
201105
|
+
default:
|
|
201106
|
+
break;
|
|
201107
|
+
}
|
|
201108
|
+
if (!line2) return "unknown";
|
|
201109
|
+
if (DISK_FULL_RE.test(line2)) return "disk-full";
|
|
201110
|
+
if (QUOTA_RE3.test(line2)) return "quota";
|
|
201111
|
+
if (AUTH_RE2.test(line2)) return "auth";
|
|
201112
|
+
if (RATE_LIMIT_RE.test(line2)) return "rate-limit";
|
|
201113
|
+
if (MODEL_RE.test(line2)) return "model";
|
|
201114
|
+
if (UNREACHABLE_RE2.test(line2)) return "node-unreachable";
|
|
201115
|
+
return "unknown";
|
|
201116
|
+
}
|
|
201117
|
+
function setChatWallClockMs(ms) {
|
|
201118
|
+
effectiveChatWallClockMs = typeof ms === "number" && ms > 0 ? ms : void 0;
|
|
201119
|
+
}
|
|
201120
|
+
function wallClockText(ms = effectiveChatWallClockMs ?? sessionWallClockMs("chat")) {
|
|
201121
|
+
const minutes = Math.round(ms / 6e4);
|
|
201122
|
+
return minutes > 0 && minutes % 60 === 0 ? `${minutes / 60} \u5C0F\u65F6` : `${minutes} \u5206\u949F`;
|
|
201123
|
+
}
|
|
201124
|
+
function resetTime(line2) {
|
|
201125
|
+
return extractResetHint(line2)?.replace(/^(?:resets?|try again at)\s+/i, "").trim() || void 0;
|
|
201126
|
+
}
|
|
201127
|
+
function failureSummary(kind, ctx) {
|
|
201128
|
+
switch (kind) {
|
|
201129
|
+
case "auth":
|
|
201130
|
+
return `\u5BF9\u8BDD\u5931\u8D25\uFF1A\u8FD0\u884C\u65F6\u7684\u767B\u5F55\u5DF2\u8FC7\u671F\u6216\u51ED\u8BC1\u65E0\u6548\uFF0C\u8C03\u7528\u4E0D\u4E86\u6A21\u578B\u3002\u8BF7\u8282\u70B9\u7BA1\u7406\u5458\u5728\u90A3\u53F0\u673A\u5668\u4E0A\u91CD\u65B0\u767B\u5F55\u8FD9\u4E2A\u8FD0\u884C\u65F6\uFF08\u6216\u66F4\u65B0 API Key\uFF09\u540E\u518D\u53D1\u4E00\u6B21\uFF1B\u7740\u6025\u7684\u8BDD\u4E5F\u53EF\u4EE5${chatRebindHint("\u6362\u4E00\u4E2A\u53EF\u7528\u7684\u8FD0\u884C\u65F6")}\u3002`;
|
|
201131
|
+
case "quota": {
|
|
201132
|
+
const at = resetTime(ctx.line);
|
|
201133
|
+
return `\u5BF9\u8BDD\u5931\u8D25\uFF1A\u6A21\u578B\u989D\u5EA6\u5DF2\u7528\u5B8C${at ? `\uFF0C\u9884\u8BA1 ${at} \u6062\u590D` : ""}\u3002\u8BF7\u7B49\u989D\u5EA6\u6062\u590D\u540E\u518D\u53D1\u4E00\u6B21\uFF1B\u7740\u6025\u7684\u8BDD\u53EF\u4EE5${chatRebindHint("\u6362\u4E00\u4E2A\u989D\u5EA6\u5145\u8DB3\u7684\u8FD0\u884C\u65F6")}\u3002`;
|
|
201134
|
+
}
|
|
201135
|
+
case "rate-limit":
|
|
201136
|
+
return "\u5BF9\u8BDD\u5931\u8D25\uFF1A\u6A21\u578B\u670D\u52A1\u6682\u65F6\u9650\u6D41\u6216\u7E41\u5FD9\u3002\u8BF7\u7B49\u4E00\u4E24\u5206\u949F\u518D\u53D1\u4E00\u6B21\u3002";
|
|
201137
|
+
case "node-unreachable":
|
|
201138
|
+
return `\u5BF9\u8BDD\u5931\u8D25\uFF1A\u8FD0\u884C\u8FD9\u4F4D Agent \u7684\u8282\u70B9\u79BB\u7EBF\u6216\u8FDE\u63A5\u4E2D\u65AD\u3002\u8BF7\u786E\u8BA4\u90A3\u53F0\u673A\u5668\u5F00\u7740\u3001\u8282\u70B9\u7A0B\u5E8F\u5728\u8FD0\u884C\u3001\u7F51\u7EDC\u6B63\u5E38\u540E\u518D\u53D1\u4E00\u6B21\uFF1B\u4E5F\u53EF\u4EE5${chatRebindHint("\u6362\u4E00\u4E2A\u5728\u7EBF\u7684\u8FD0\u884C\u65F6")}\u3002`;
|
|
201139
|
+
case "model":
|
|
201140
|
+
return `\u5BF9\u8BDD\u5931\u8D25\uFF1A\u8FD9\u4E2A\u8FD0\u884C\u65F6\u7528\u4E0D\u4E86\u5F53\u524D\u914D\u7F6E\u7684\u6A21\u578B\u3002\u8BF7${chatRebindHint("\u6362\u4E00\u4E2A\u53EF\u7528\u7684\u6A21\u578B")}\u540E\u518D\u53D1\u4E00\u6B21\u3002`;
|
|
201141
|
+
case "timeout":
|
|
201142
|
+
return `\u8FD9\u4E00\u6B21\u6267\u884C\u8DD1\u6EE1\u4E86\u5355\u6B21\u8FD0\u884C\u7684\u65F6\u95F4\u4E0A\u9650\uFF08${wallClockText()}\uFF09\uFF0C\u88AB\u7CFB\u7EDF\u505C\u4E0B\u4E86\u3002\u5DF2\u7ECF\u505A\u5B8C\u7684\u90E8\u5206\u4E0D\u4F1A\u4E22\uFF1B\u8981\u63A5\u7740\u505A\u7684\u8BDD\uFF0C\u628A\u5269\u4E0B\u7684\u90E8\u5206\u62C6\u5C0F\u4E00\u4E9B\u518D\u53D1\u4E00\u6B21\u3002`;
|
|
201143
|
+
case "startup-failed":
|
|
201144
|
+
return `\u5BF9\u8BDD\u5931\u8D25\uFF1A${ctx.readable || SESSION_STARTUP_FAILED_PREFIX}\u3002\u8FD9\u4E00\u8F6E\u6CA1\u6709\u5F00\u59CB\u8FD0\u884C\uFF0C\u53EF\u4EE5\u76F4\u63A5\u518D\u53D1\u4E00\u6B21\uFF1B\u53CD\u590D\u51FA\u73B0\u7684\u8BDD\uFF0C\u591A\u534A\u662F\u90A3\u53F0\u8282\u70B9\u8D1F\u8F7D\u8FC7\u9AD8\uFF0C\u8BF7\u7BA1\u7406\u5458\u7ED9\u5B83\u51CF\u8D1F\u6216${chatRebindHint("\u6362\u4E00\u4E2A\u8FD0\u884C\u65F6")}\u3002`;
|
|
201145
|
+
case "disk-full":
|
|
201146
|
+
return `\u5BF9\u8BDD\u5931\u8D25\uFF1A\u8FD0\u884C\u8FD9\u4F4D Agent \u7684\u8282\u70B9\u78C1\u76D8\u7A7A\u95F4\u6EE1\u4E86\uFF0C\u8FD9\u4E00\u8F6E\u5199\u4E0D\u4E86\u6587\u4EF6\u3002\u8BF7\u8282\u70B9\u7BA1\u7406\u5458\u6E05\u7406\u90A3\u53F0\u673A\u5668\u7684\u78C1\u76D8\u540E\u518D\u53D1\u4E00\u6B21\uFF1B\u7740\u6025\u7684\u8BDD\u4E5F\u53EF\u4EE5${chatRebindHint("\u6362\u4E00\u4E2A\u8FD0\u884C\u65F6")}\u3002`;
|
|
201147
|
+
case "output-limit":
|
|
201148
|
+
return "\u5BF9\u8BDD\u5931\u8D25\uFF1A\u6A21\u578B\u8F93\u51FA\u8D85\u51FA\u957F\u5EA6\u4E0A\u9650\uFF0C\u56DE\u590D\u88AB\u622A\u65AD\u4E86\u3002\u53EF\u4EE5\u8BA9\u5B83\u5206\u51E0\u6B21\u8F93\u51FA\uFF0C\u6216\u628A\u4EFB\u52A1\u62C6\u5C0F\u4E00\u4E9B\u518D\u53D1\u3002";
|
|
201149
|
+
case "unknown":
|
|
201150
|
+
if (ctx.line) {
|
|
201151
|
+
return "\u5BF9\u8BDD\u5931\u8D25\uFF1A\u8FD0\u884C\u65F6\u62A5\u9519\u4E86\uFF0C\u6682\u65F6\u6CA1\u8BA4\u51FA\u662F\u4EC0\u4E48\u539F\u56E0\u3002\u53EF\u4EE5\u7A0D\u540E\u518D\u53D1\u4E00\u6B21\uFF1B\u53CD\u590D\u51FA\u73B0\u7684\u8BDD\uFF0C\u8BF7\u70B9\u300C\u5C55\u5F00\u8BE6\u60C5\u300D\u628A\u539F\u59CB\u62A5\u9519\u53D1\u7ED9\u7BA1\u7406\u5458\u3002";
|
|
201152
|
+
}
|
|
201153
|
+
return ctx.hasDetail ? "\u5BF9\u8BDD\u5931\u8D25\uFF1A\u8FD0\u884C\u65F6\u5F02\u5E38\u9000\u51FA\uFF0C\u6CA1\u6709\u7ED9\u51FA\u62A5\u9519\u539F\u56E0\u3002\u53EF\u4EE5\u7A0D\u540E\u518D\u53D1\u4E00\u6B21\uFF1B\u53CD\u590D\u51FA\u73B0\u7684\u8BDD\uFF0C\u8BF7\u70B9\u300C\u5C55\u5F00\u8BE6\u60C5\u300D\u628A\u539F\u59CB\u8BB0\u5F55\u53D1\u7ED9\u7BA1\u7406\u5458\u3002" : `\u5BF9\u8BDD\u5931\u8D25\uFF1A\u8FD0\u884C\u65F6\u5F02\u5E38\u9000\u51FA\uFF08\u9000\u51FA\u7801 ${ctx.code ?? "\u65E0"}\uFF09\uFF0C\u6CA1\u6709\u7559\u4E0B\u62A5\u9519\u4FE1\u606F\u3002\u53EF\u4EE5\u7A0D\u540E\u518D\u53D1\u4E00\u6B21\uFF1B\u53CD\u590D\u51FA\u73B0\u7684\u8BDD\uFF0C\u8BF7\u7BA1\u7406\u5458\u5230\u300C\u8FD0\u884C\u8F68\u8FF9\u300D\u91CC\u67E5\u8FD9\u4E00\u8F6E\u3002`;
|
|
201154
|
+
}
|
|
201155
|
+
}
|
|
201156
|
+
function buildChatExitError(info) {
|
|
201157
|
+
const chatExit = chatExitSummary(info);
|
|
201158
|
+
return Object.assign(new Error(chatExit.summary), { chatExit });
|
|
201159
|
+
}
|
|
201160
|
+
function chatExitSummary(info) {
|
|
201161
|
+
const genericLine = `runtime exited with code ${info.code ?? "null"}${info.reason ? ` (${info.reason})` : ""}`;
|
|
201162
|
+
let detail = "";
|
|
201163
|
+
if (info.reason !== "cancelled") {
|
|
201164
|
+
detail = info.errorMessage?.trim() ?? "";
|
|
201165
|
+
if (!detail && info.transcriptRef) detail = transcriptTail(info.transcriptRef);
|
|
201166
|
+
}
|
|
201167
|
+
let summary;
|
|
201168
|
+
let cancelledBy;
|
|
201169
|
+
if (info.reason === "cancelled") {
|
|
201170
|
+
cancelledBy = cancelCauseFromExitMessage(info.errorMessage);
|
|
201171
|
+
summary = chatCancelNote(cancelledBy);
|
|
201172
|
+
} else {
|
|
201173
|
+
const firstErrorLine = (info.errorMessage?.split("\n").map((line2) => line2.trim()).find(Boolean) ?? "").replace(INTERNAL_PREFIX_RE, "");
|
|
201174
|
+
const readable = firstErrorLine ? clipLine(providerMessage(firstErrorLine) ?? firstErrorLine) : "";
|
|
201175
|
+
summary = failureSummary(failureKind(info.reason, firstErrorLine), {
|
|
201176
|
+
readable,
|
|
201177
|
+
line: firstErrorLine,
|
|
201178
|
+
hasDetail: Boolean(detail),
|
|
201179
|
+
code: info.code
|
|
201180
|
+
});
|
|
201181
|
+
}
|
|
201182
|
+
return {
|
|
201183
|
+
...info.reason ? { reason: info.reason } : {},
|
|
201184
|
+
summary,
|
|
201185
|
+
...cancelledBy ? { cancelledBy } : {},
|
|
201186
|
+
...info.reason !== "cancelled" ? { detail: (detail ? `${genericLine}
|
|
201187
|
+
|
|
201188
|
+
${detail}` : genericLine).slice(0, 4200) } : {}
|
|
201189
|
+
};
|
|
201190
|
+
}
|
|
201191
|
+
var fs17, SUMMARY_MAX_CHARS, INTERNAL_PREFIX_RE, QUOTA_RE3, RATE_LIMIT_RE, AUTH_RE2, MODEL_RE, DISK_FULL_RE, UNREACHABLE_RE2, effectiveChatWallClockMs, chatRebindHint;
|
|
201192
|
+
var init_chat_exit = __esm({
|
|
201193
|
+
"../server/src/chat-exit.ts"() {
|
|
201194
|
+
"use strict";
|
|
201195
|
+
fs17 = __toESM(require("node:fs"), 1);
|
|
201196
|
+
init_src();
|
|
201197
|
+
init_src7();
|
|
201198
|
+
init_chat_cancel_attribution();
|
|
201199
|
+
SUMMARY_MAX_CHARS = 500;
|
|
201200
|
+
INTERNAL_PREFIX_RE = /^\[[a-z][a-z0-9_]*\]\s*/;
|
|
201201
|
+
QUOTA_RE3 = /hit your (?:\w+ )?limit|usage limit|quota|insufficient[_ ](?:balance|credit|funds)|credit balance|billing|\b402\b|额度|余额/i;
|
|
201202
|
+
RATE_LIMIT_RE = /rate.?limit|too many requests|\b429\b|\b529\b|overloaded|限流/i;
|
|
201203
|
+
AUTH_RE2 = /\b401\b|\b403\b|unauthori[sz]ed|authenticat|oauth|invalid[_ -]?(?:api[_ -]?key|token|x-api-key)|api[_ -]?key[^\n]{0,40}\b(?:invalid|expired|revoked)|token[^\n]{0,30}\b(?:expired|invalid|revoked)|not logged in|\/login|credential|凭证|登录/i;
|
|
201204
|
+
MODEL_RE = /\bmodel\b[^\n]{0,120}?\b(?:not found|not exist|does not exist|not available|not supported|unavailable|unknown)\b|\b(?:unknown|invalid|unsupported) model\b|model_not_found/i;
|
|
201205
|
+
DISK_FULL_RE = /\bENOSPC\b|no space left on device|\bEDQUOT\b|disk quota exceeded|\[Errno 28\]|disk (?:is )?full|磁盘(?:空间)?(?:已满|不足)/i;
|
|
201206
|
+
UNREACHABLE_RE2 = /不在线|socket 非 OPEN|帧未送达|失联/;
|
|
201207
|
+
chatRebindHint = (what) => `\u5728\u7EC4\u7EC7\u9875\u8FD9\u4F4D Agent \u7684\u300C\u6A21\u578B\u300D\u9875\u7B7E\u91CC${what}`;
|
|
201208
|
+
}
|
|
201209
|
+
});
|
|
201210
|
+
|
|
200722
201211
|
// ../server/src/domains/delegations/parent-conversation.ts
|
|
200723
201212
|
function firstLine2(content3) {
|
|
200724
201213
|
const line2 = content3.split("\n").map((s2) => s2.trim()).find((s2) => s2.length > 0);
|
|
@@ -201119,6 +201608,14 @@ var init_files = __esm({
|
|
|
201119
201608
|
});
|
|
201120
201609
|
|
|
201121
201610
|
// ../server/src/domains/delegations/service.ts
|
|
201611
|
+
function exitReasonOf(err) {
|
|
201612
|
+
if (!(err instanceof Error)) return void 0;
|
|
201613
|
+
const chatExit = err.chatExit;
|
|
201614
|
+
return chatExit?.reason;
|
|
201615
|
+
}
|
|
201616
|
+
function roundFailureText(kind, error2) {
|
|
201617
|
+
return kind === "timeout" ? `\u8FD9\u4E00\u6B21\u6267\u884C\u8DD1\u6EE1\u4E86\u5355\u6B21\u8FD0\u884C\u7684\u65F6\u95F4\u4E0A\u9650\uFF08${wallClockText()}\uFF09\uFF0C\u88AB\u7CFB\u7EDF\u505C\u4E0B\u4E86\uFF08${error2}\uFF09` : `\u8FD9\u4E00\u8F6E\u6CA1\u8DD1\u5B8C\uFF1A${error2}`;
|
|
201618
|
+
}
|
|
201122
201619
|
function deterministicUuid2(seed) {
|
|
201123
201620
|
const h = (0, import_node_crypto36.createHash)("sha256").update(seed).digest();
|
|
201124
201621
|
const b2 = Buffer.from(h.subarray(0, 16));
|
|
@@ -201181,6 +201678,7 @@ var init_service3 = __esm({
|
|
|
201181
201678
|
"use strict";
|
|
201182
201679
|
import_node_crypto36 = require("node:crypto");
|
|
201183
201680
|
init_src();
|
|
201681
|
+
init_chat_exit();
|
|
201184
201682
|
init_parent_conversation();
|
|
201185
201683
|
init_title();
|
|
201186
201684
|
init_deletion();
|
|
@@ -201868,7 +202366,7 @@ var init_service3 = __esm({
|
|
|
201868
202366
|
try {
|
|
201869
202367
|
await dispatched.done;
|
|
201870
202368
|
} catch (err) {
|
|
201871
|
-
failureKind2 = "interrupted";
|
|
202369
|
+
failureKind2 = exitReasonOf(err) === "timeout" ? "timeout" : "interrupted";
|
|
201872
202370
|
error2 = err instanceof Error ? err.message : String(err);
|
|
201873
202371
|
}
|
|
201874
202372
|
const at = this.now();
|
|
@@ -201885,7 +202383,11 @@ var init_service3 = __esm({
|
|
|
201885
202383
|
const round = (fresh.roundSummaries[fresh.roundSummaries.length - 1]?.round ?? 0) + 1;
|
|
201886
202384
|
const newSummary = {
|
|
201887
202385
|
round,
|
|
201888
|
-
|
|
202386
|
+
/* ⚠️ 到点被停下那一档**不往摘要里合成句子**(Bug 0221):`text` 从此是「专家这一轮到底
|
|
202387
|
+
写出没写出正文」的判据——回流通告据它判「有没有可验证的交付」(`hasDelegationDelivery`)。
|
|
202388
|
+
合成的那句话仍写进下面子会话的占位行(用户在子会话里要看到一句交代),
|
|
202389
|
+
通告里空正文由 `delegationReturnText` 渲染成「(这一轮没有文本产出)」。 */
|
|
202390
|
+
text: text7 || (failureKind2 && failureKind2 !== "timeout" ? roundFailureText(failureKind2, error2) : ""),
|
|
201889
202391
|
at,
|
|
201890
202392
|
// 本轮的键 = 派发这一轮时的 dispatchSeq(`record` 就是派发时那一份,轮次账本业务键也由它算)。
|
|
201891
202393
|
dispatchSeq: record9.dispatchSeq ?? 0
|
|
@@ -201895,7 +202397,7 @@ var init_service3 = __esm({
|
|
|
201895
202397
|
const stopLoss = consecutiveFails >= CONSECUTIVE_FAIL_LIMIT;
|
|
201896
202398
|
const chatStore = await this.options.resolveChatSessions(companyId).catch(() => null);
|
|
201897
202399
|
await chatStore?.updateMessage(childRoundMessageIds(fresh.childSessionId, round).placeholderId, {
|
|
201898
|
-
content: text7 || (failureKind2 ?
|
|
202400
|
+
content: text7 || (failureKind2 ? roundFailureText(failureKind2, error2) : ""),
|
|
201899
202401
|
status: failureKind2 ? "error" : "done",
|
|
201900
202402
|
completedAt: at
|
|
201901
202403
|
}).catch(() => void 0);
|
|
@@ -201968,9 +202470,11 @@ var init_service3 = __esm({
|
|
|
201968
202470
|
if (opts?.outcome === "succeeded") return this.settleSucceededFromSweep(record9, dispatchSeq, companyId);
|
|
201969
202471
|
const at = this.now();
|
|
201970
202472
|
const settledSeqAtRound = record9.settledSeq + 1;
|
|
202473
|
+
const timedOut = opts?.exitReason === "timeout";
|
|
202474
|
+
const partialAnswer = timedOut ? await this.readChildRoundAnswer(record9, dispatchSeq + 1, companyId).catch(() => "") : "";
|
|
201971
202475
|
const newSummary = {
|
|
201972
202476
|
round: (record9.roundSummaries[record9.roundSummaries.length - 1]?.round ?? 0) + 1,
|
|
201973
|
-
text: `\u8FD9\u4E00\u8F6E\u88AB\u65F6\u949F\u95ED\u5408\uFF1A${reason}`,
|
|
202477
|
+
text: timedOut ? partialAnswer : `\u8FD9\u4E00\u8F6E\u88AB\u65F6\u949F\u95ED\u5408\uFF1A${reason}`,
|
|
201974
202478
|
at,
|
|
201975
202479
|
settledSeq: settledSeqAtRound,
|
|
201976
202480
|
dispatchSeq
|
|
@@ -201978,7 +202482,8 @@ var init_service3 = __esm({
|
|
|
201978
202482
|
const settled = await store.appendRoundSummary(record9.id, newSummary, {
|
|
201979
202483
|
state: "failed",
|
|
201980
202484
|
// 退出帧丢失后被时钟闭合 = `interrupted`(§9),不是 `not-started`——它确实起来过。
|
|
201981
|
-
|
|
202485
|
+
// run 报的是墙钟超时时归 `timeout`(Bug 0221):同样起来过,但「到点被停」与「断了」说法不同。
|
|
202486
|
+
failureKind: timedOut ? "timeout" : "interrupted",
|
|
201982
202487
|
consecutiveFails: record9.consecutiveFails + 1,
|
|
201983
202488
|
settledSeq: settledSeqAtRound,
|
|
201984
202489
|
settledAt: at
|
|
@@ -202579,11 +203084,11 @@ var init_routes2 = __esm({
|
|
|
202579
203084
|
});
|
|
202580
203085
|
|
|
202581
203086
|
// ../server/src/domains/delegations/store.ts
|
|
202582
|
-
var
|
|
203087
|
+
var fs18, path18, touchKey, settlesTerminal, MemoryDelegationStore, FileDelegationStore;
|
|
202583
203088
|
var init_store2 = __esm({
|
|
202584
203089
|
"../server/src/domains/delegations/store.ts"() {
|
|
202585
203090
|
"use strict";
|
|
202586
|
-
|
|
203091
|
+
fs18 = __toESM(require("node:fs"), 1);
|
|
202587
203092
|
path18 = __toESM(require("node:path"), 1);
|
|
202588
203093
|
init_src();
|
|
202589
203094
|
touchKey = (delegationId, messageId) => `${delegationId}\0${messageId}`;
|
|
@@ -202727,13 +203232,13 @@ var init_store2 = __esm({
|
|
|
202727
203232
|
}
|
|
202728
203233
|
static async open(file) {
|
|
202729
203234
|
const store = new _FileDelegationStore(file);
|
|
202730
|
-
if (
|
|
202731
|
-
const snap = JSON.parse(
|
|
203235
|
+
if (fs18.existsSync(file)) {
|
|
203236
|
+
const snap = JSON.parse(fs18.readFileSync(file, "utf8"));
|
|
202732
203237
|
for (const d of snap.delegations ?? []) store.rows.set(d.id, d);
|
|
202733
203238
|
for (const t of snap.touches ?? []) store.touches.set(touchKey(t.delegationId, t.messageId), t);
|
|
202734
203239
|
} else {
|
|
202735
|
-
|
|
202736
|
-
|
|
203240
|
+
fs18.mkdirSync(path18.dirname(file), { recursive: true });
|
|
203241
|
+
fs18.writeFileSync(file, JSON.stringify({ delegations: [], touches: [] }, null, 2));
|
|
202737
203242
|
}
|
|
202738
203243
|
return store;
|
|
202739
203244
|
}
|
|
@@ -202742,7 +203247,7 @@ var init_store2 = __esm({
|
|
|
202742
203247
|
delegations: [...this.rows.values()],
|
|
202743
203248
|
touches: [...this.touches.values()]
|
|
202744
203249
|
};
|
|
202745
|
-
|
|
203250
|
+
fs18.writeFileSync(this.file, JSON.stringify(snapshot, null, 2));
|
|
202746
203251
|
}
|
|
202747
203252
|
async create(record9) {
|
|
202748
203253
|
const r = await super.create(record9);
|
|
@@ -202946,8 +203451,18 @@ function delegationReturnText(terminal, opts) {
|
|
|
202946
203451
|
const { record: record9 } = terminal;
|
|
202947
203452
|
const who = terminal.expertName ?? record9.expertActorId;
|
|
202948
203453
|
const name = record9.label ? `${who}\uFF08${record9.label}\uFF09` : who;
|
|
202949
|
-
const
|
|
202950
|
-
const
|
|
203454
|
+
const lastRoundText = record9.roundSummaries[record9.roundSummaries.length - 1]?.text;
|
|
203455
|
+
const ending = delegationEnding(record9, {
|
|
203456
|
+
movedFiles: opts.movedPaths.length,
|
|
203457
|
+
unchangedFiles: opts.unchangedPaths?.length ?? 0,
|
|
203458
|
+
...lastRoundText ? { roundText: lastRoundText } : {}
|
|
203459
|
+
});
|
|
203460
|
+
const cap = wallClockText();
|
|
203461
|
+
const head = ending === "done" ? `\u3010\u7CFB\u7EDF\u3011${name} \u5DF2\u5B8C\u6210\u3002` : ending === "timeout-delivered" ? `\u3010\u7CFB\u7EDF\u3011${name} \u8FD9\u4E00\u6B21\u6267\u884C\u8DD1\u6EE1\u4E86\u5355\u6B21\u8FD0\u884C\u7684\u65F6\u95F4\u4E0A\u9650\uFF08${cap}\uFF09\uFF0C\u88AB\u7CFB\u7EDF\u505C\u4E0B\u4E86\u2014\u2014\u5DF2\u7ECF\u4EA4\u56DE\u7684\u5185\u5BB9\u89C1\u4E0B\u3002` : ending === "timeout-empty" ? `\u3010\u7CFB\u7EDF\u3011${name} \u8FD9\u4E00\u6B21\u6267\u884C\u8DD1\u6EE1\u4E86\u5355\u6B21\u8FD0\u884C\u7684\u65F6\u95F4\u4E0A\u9650\uFF08${cap}\uFF09\uFF0C\u88AB\u7CFB\u7EDF\u505C\u4E0B\u4E86\uFF0C\u8FD9\u4E00\u8F6E\u6CA1\u6709\u4EA4\u56DE\u4EFB\u4F55\u5185\u5BB9\u3002` : `\u3010\u7CFB\u7EDF\u3011${name} \u65E0\u6CD5\u5B8C\u6210\u3002`;
|
|
203462
|
+
const lines = [
|
|
203463
|
+
head,
|
|
203464
|
+
`\u59D4\u6D3E id\uFF1A${record9.id.slice(0, 8)}\u3000label\uFF1A${record9.label ?? "\uFF08\u65E0\uFF09"}` + (record9.failureKind ? `\u3000\u7ED3\u675F\u539F\u56E0\uFF1A${record9.failureKind}` : "")
|
|
203465
|
+
];
|
|
202951
203466
|
const trimmed = trimRoundSummariesForReturn(record9.roundSummaries, opts.recentRounds);
|
|
202952
203467
|
if (trimmed.length > 0) {
|
|
202953
203468
|
lines.push("", `\u4E13\u5BB6\u5404\u8F6E\u5C0F\u7ED3\uFF08\u5171 ${trimmed.length} \u8F6E\uFF1B\u6700\u8FD1 ${opts.recentRounds} \u8F6E\u7ED9\u5168\u6587\uFF0C\u66F4\u65E9\u7684\u53EA\u7559\u9996\u884C\uFF0C\u5168\u6587\u7528 \`oasis delegate --status\` \u770B\uFF09\uFF1A`);
|
|
@@ -202982,7 +203497,7 @@ function delegationReturnText(terminal, opts) {
|
|
|
202982
203497
|
}
|
|
202983
203498
|
lines.push(
|
|
202984
203499
|
"",
|
|
202985
|
-
record9.state === "done" ? "\u8FD9\u4E9B\u662F\u6750\u6599\uFF0C\u4E0D\u662F\u7ED9\u7528\u6237\u7684\u6210\u54C1\uFF1A\u4F60\u6709\u8FD9\u6761\u5BF9\u8BDD\u7684\u5B8C\u6574\u4E0A\u4E0B\u6587\uFF0C\u81EA\u5DF1\u5224\u65AD\u8BE5\u8BB2\u54EA\u4E00\u53E5\u3001\u8981\u4E0D\u8981\u63A5\u7740\u5F80\u4E0B\u505A\u3002" : "\u5148\u81EA\u5DF1\u5224\u65AD\u80FD\u4E0D\u80FD\u63A5\u4F4F\uFF1A\u63A5\u7BA1\u3001\u6362\u4E2A\u505A\u6CD5\u3001\u8FD8\u662F\u91CD\u6D3E\u3002**\u522B\u628A\u4E13\u4E1A\u5931\u8D25\u539F\u6837\u4E22\u56DE\u7ED9\u7528\u6237**\u3002"
|
|
203500
|
+
record9.state === "done" ? "\u8FD9\u4E9B\u662F\u6750\u6599\uFF0C\u4E0D\u662F\u7ED9\u7528\u6237\u7684\u6210\u54C1\uFF1A\u4F60\u6709\u8FD9\u6761\u5BF9\u8BDD\u7684\u5B8C\u6574\u4E0A\u4E0B\u6587\uFF0C\u81EA\u5DF1\u5224\u65AD\u8BE5\u8BB2\u54EA\u4E00\u53E5\u3001\u8981\u4E0D\u8981\u63A5\u7740\u5F80\u4E0B\u505A\u3002" : ending === "timeout-delivered" ? "**\u8FD9\u4E0D\u662F\u4E13\u4E1A\u5931\u8D25\uFF0C\u662F\u65F6\u95F4\u5230\u4E86**\uFF1A\u5148\u770B\u4E0A\u9762\u5DF2\u7ECF\u4EA4\u56DE\u7684\u4E1C\u897F\uFF0C\u80FD\u7528\u5C31\u63A5\u7740\u7528\uFF1B\u8FD8\u6CA1\u505A\u5B8C\u7684\u90E8\u5206\uFF0C\u62C6\u6210\u4E00\u8F6E\u8DD1\u5F97\u5B8C\u7684\u91CF\u518D\u6D3E\u4E00\u6B21\u3002\u7ED9\u7528\u6237\u4EA4\u4EE3\u65F6\u522B\u8BF4\u300C\u65E0\u6CD5\u5B8C\u6210\u300D\u2014\u2014\u5DF2\u7ECF\u505A\u6210\u7684\u90E8\u5206\u7167\u5B9E\u8BF4\u3002" : ending === "timeout-empty" ? "**\u8FD9\u4E0D\u662F\u4E13\u4E1A\u5931\u8D25\uFF0C\u662F\u65F6\u95F4\u5230\u4E86**\uFF1A\u8FD9\u4E00\u8F6E\u6CA1\u6709\u7559\u4E0B\u53EF\u7528\u7684\u4EA7\u51FA\uFF0C\u628A\u4EFB\u52A1\u62C6\u5C0F\u4E00\u4E9B\u518D\u6D3E\u4E00\u6B21\u3002" : "\u5148\u81EA\u5DF1\u5224\u65AD\u80FD\u4E0D\u80FD\u63A5\u4F4F\uFF1A\u63A5\u7BA1\u3001\u6362\u4E2A\u505A\u6CD5\u3001\u8FD8\u662F\u91CD\u6D3E\u3002**\u522B\u628A\u4E13\u4E1A\u5931\u8D25\u539F\u6837\u4E22\u56DE\u7ED9\u7528\u6237**\u3002"
|
|
202986
203501
|
);
|
|
202987
203502
|
if (opts.movedPaths.length > 0 || (opts.unchangedPaths?.length ?? 0) > 0) {
|
|
202988
203503
|
lines.push(
|
|
@@ -203136,6 +203651,7 @@ var init_return_flow = __esm({
|
|
|
203136
203651
|
"use strict";
|
|
203137
203652
|
init_chat_session();
|
|
203138
203653
|
init_src();
|
|
203654
|
+
init_chat_exit();
|
|
203139
203655
|
init_chat_system_message();
|
|
203140
203656
|
init_chat_broadcast();
|
|
203141
203657
|
init_files();
|
|
@@ -208277,7 +208793,7 @@ async function resolveProposeContent(kernel, blobs, args, artifactId, ctx) {
|
|
|
208277
208793
|
}
|
|
208278
208794
|
return resolveContent2(blobs, args);
|
|
208279
208795
|
}
|
|
208280
|
-
function authorizedCommandReceipt(command2, args, actor) {
|
|
208796
|
+
function authorizedCommandReceipt(command2, args, actor, refs = {}) {
|
|
208281
208797
|
switch (command2) {
|
|
208282
208798
|
case "continueBatch":
|
|
208283
208799
|
return { message: `\u5DF2\u6388\u6743\u518D\u8FD0\u884C ${args.rounds} \u8F6E\uFF1B\u5176\u4ED6\u963B\u585E\u89E3\u9664\u540E\u7EE7\u7EED\u3002` };
|
|
@@ -208286,7 +208802,7 @@ function authorizedCommandReceipt(command2, args, actor) {
|
|
|
208286
208802
|
case "promote":
|
|
208287
208803
|
return { message: "promoted to persistent" };
|
|
208288
208804
|
case "resolveEscalation":
|
|
208289
|
-
return { message: optStr(args, "gapId") ? `\u5DF2\u786E\u8BA4\u6062\u590D\u65B9\u6848\uFF0C\u89E3\u51B3\u7F3A\u53E3
|
|
208805
|
+
return { message: optStr(args, "gapId") ? `\u5DF2\u786E\u8BA4\u6062\u590D\u65B9\u6848\uFF0C${actionPhrase("\u89E3\u51B3", "\u7F3A\u53E3", gapPhraseOf(refs, optStr(args, "gapId")))}\u3001${actionPhrase("\u5173\u95ED\u5173\u8054", "\u6C42\u52A9", escalationPhraseOf(refs, optStr(args, "escalationId")), "\u5173\u95ED\u5173\u8054\u7684")}\uFF1B\u8C03\u5EA6\u5668\u5C06\u5728\u5176\u4ED6\u963B\u585E\u89E3\u9664\u540E\u7EE7\u7EED\u6267\u884C\u3002` : `\u5DF2${actionPhrase("\u5173\u95ED", "\u6C42\u52A9", escalationPhraseOf(refs, optStr(args, "escalationId")))}\u3002` };
|
|
208290
208806
|
default:
|
|
208291
208807
|
throw new Error(`\u547D\u4EE4\u6388\u6743\uFF1A\u6682\u65E0\u56DE\u6267\u6784\u9020 ${command2}`);
|
|
208292
208808
|
}
|
|
@@ -209008,7 +209524,7 @@ ${acceptanceCriteria.map((c) => `- ${c}`).join("\n")}`] : []
|
|
|
209008
209524
|
...optStr(args, "reason") !== void 0 ? { reason: optStr(args, "reason") } : {},
|
|
209009
209525
|
...escId !== void 0 ? { escalationId: escId } : {}
|
|
209010
209526
|
});
|
|
209011
|
-
return { message: escId !== void 0 ? `\u5DF2\u5173\u95ED\
|
|
209527
|
+
return { message: escId !== void 0 ? `\u5DF2${actionPhrase("\u5173\u95ED", "\u6C42\u52A9", escalationPhraseOf(commandCardRefsOf(kernel.model), escId))}\u3002` : "\u8BE5\u8282\u70B9\u7684\u672A\u89E3\u4E0A\u62A5\u5DF2\u5168\u90E8\u5173\u95ED\u3002" };
|
|
209012
209528
|
}
|
|
209013
209529
|
case "addRevision": {
|
|
209014
209530
|
const addRevId = str(args, "artifactId");
|
|
@@ -209074,7 +209590,7 @@ ${acceptanceCriteria.map((c) => `- ${c}`).join("\n")}`] : []
|
|
|
209074
209590
|
}
|
|
209075
209591
|
case "promote": {
|
|
209076
209592
|
await kernel.promote({ artifactId: str(args, "artifactId"), actor });
|
|
209077
|
-
return authorizedCommandReceipt(command2, args, actor);
|
|
209593
|
+
return authorizedCommandReceipt(command2, args, actor, commandCardRefsOf(kernel.model));
|
|
209078
209594
|
}
|
|
209079
209595
|
case "hold": {
|
|
209080
209596
|
const artifactId = str(args, "artifactId");
|
|
@@ -209118,7 +209634,7 @@ ${acceptanceCriteria.map((c) => `- ${c}`).join("\n")}`] : []
|
|
|
209118
209634
|
reason: str(args, "reason"),
|
|
209119
209635
|
note: optStr(args, "note")
|
|
209120
209636
|
});
|
|
209121
|
-
return authorizedCommandReceipt(command2, args, actor);
|
|
209637
|
+
return authorizedCommandReceipt(command2, args, actor, commandCardRefsOf(kernel.model));
|
|
209122
209638
|
}
|
|
209123
209639
|
case "unlink": {
|
|
209124
209640
|
await kernel.unlinkInput({ artifactId: str(args, "artifactId"), to: str(args, "to"), actor });
|
|
@@ -209644,19 +210160,20 @@ async function startOasisServer(opts) {
|
|
|
209644
210160
|
return { accepted: r.accepted, ...r.reason ? { reason: r.reason } : {}, queued: r.queued, insertStatus: r.insertStatus };
|
|
209645
210161
|
};
|
|
209646
210162
|
const GRAPH_EDIT_SUMMARY_MAX = 60;
|
|
210163
|
+
const NEUTRAL_APPROVER = "\u8D1F\u8D23\u4EBA";
|
|
209647
210164
|
const truncateSummary = (s2) => {
|
|
209648
210165
|
const cps = [...s2];
|
|
209649
210166
|
return cps.length > GRAPH_EDIT_SUMMARY_MAX ? `${cps.slice(0, GRAPH_EDIT_SUMMARY_MAX).join("")}\u2026` : s2;
|
|
209650
210167
|
};
|
|
209651
210168
|
const authorizationStatusText = (resolution, ctx) => {
|
|
209652
210169
|
const approved = resolution.status === "approved";
|
|
209653
|
-
const by = ctx.
|
|
210170
|
+
const by = ctx.authorizedByName?.trim() || NEUTRAL_APPROVER;
|
|
209654
210171
|
const reason = resolution.status === "denied" ? resolution.reason ?? ctx.reason : ctx.reason;
|
|
209655
210172
|
if (ctx.kind === "graph-edit") {
|
|
209656
210173
|
const summary = truncateSummary((ctx.effectLabel ?? "").trim()) || "\uFF08\u672A\u586B\u5199\u7406\u7531\u7684\u56FE\u53D8\u66F4\uFF09";
|
|
209657
210174
|
return approved ? `\u300C${summary}\u300D\u7684\u53D8\u66F4\u5DF2\u7531 ${by} \u6279\u51C6\u5E76\u843D\u5730\u3002` : `\u300C${summary}\u300D\u7684\u53D8\u66F4\u5DF2\u88AB ${by} \u9A73\u56DE${reason ? `\uFF1B\u7406\u7531\uFF1A${reason}` : ""}\u3002`;
|
|
209658
210175
|
}
|
|
209659
|
-
const label2 = ctx.effectLabel || ctx.command || "";
|
|
210176
|
+
const label2 = ctx.displayLabel || stripInternalIds(ctx.effectLabel ?? "") || ctx.command || "";
|
|
209660
210177
|
return approved ? `\u547D\u4EE4\u5DF2\u7531 ${by} \u6279\u51C6\u5E76\u4EE5\u5176\u540D\u4E49\u6267\u884C${label2 ? `\uFF1A${label2}` : ""}\u3002` : `\u547D\u4EE4\u5DF2\u88AB ${by} \u9A73\u56DE${reason ? `\uFF1A${reason}` : ""}\u3002`;
|
|
209661
210178
|
};
|
|
209662
210179
|
const GRAPH_EDIT_IN_FLIGHT_SUFFIX = "\uFF08\u8FD9\u6761\u662F\u5728\u4F60\u672C\u8F6E\u8FDB\u884C\u4E2D\u63D2\u5165\u7684\u901A\u77E5\uFF1A\u56DE\u5E94\u5B8C\u540E\u63A5\u7740\u505A\u4F60\u624B\u4E0A\u8FD8\u6CA1\u505A\u5B8C\u7684\u4E8B\uFF0C\u522B\u5C31\u6B64\u6536\u5C3E\u3002\uFF09";
|
|
@@ -211079,13 +211596,23 @@ async function startOasisServer(opts) {
|
|
|
211079
211596
|
const { draftId } = JSON.parse(rawBody);
|
|
211080
211597
|
const review = engine.kernel.model.pendingReviews.get(draftId);
|
|
211081
211598
|
if (!review) throw new Error(`\u8349\u6848\u4E0D\u5B58\u5728\u6216\u5DF2\u5904\u7406\uFF1A${draftId}`);
|
|
211599
|
+
const authorizedByName = (await (engine.registry ?? opts.registry)?.getActor(actor).catch(() => null))?.name?.trim();
|
|
211082
211600
|
if (review.kind === "command" && review.command) {
|
|
211083
211601
|
const { command: command2, artifactId } = await engine.kernel.applyAuthorizedCommand({ draftId, actor });
|
|
211084
|
-
const receipt = authorizedCommandReceipt(command2, review.command.args, actor);
|
|
211602
|
+
const receipt = authorizedCommandReceipt(command2, review.command.args, actor, commandCardRefsOf(engine.kernel.model));
|
|
211085
211603
|
notifyReviewResolved(
|
|
211086
211604
|
draftId,
|
|
211087
211605
|
{ status: "approved", command: command2, effectLabel: review.command.effectLabel, authorizedBy: actor, receipt },
|
|
211088
|
-
{
|
|
211606
|
+
{
|
|
211607
|
+
origin: review.origin,
|
|
211608
|
+
kind: "command",
|
|
211609
|
+
authorizedBy: actor,
|
|
211610
|
+
...authorizedByName ? { authorizedByName } : {},
|
|
211611
|
+
// effectLabel 带 id:RESUME 提示词给起草 agent 用;displayLabel 是状态条(给人)那句。
|
|
211612
|
+
effectLabel: review.command.effectLabel,
|
|
211613
|
+
...review.command.displayLabel ? { displayLabel: review.command.displayLabel } : {},
|
|
211614
|
+
command: command2
|
|
211615
|
+
},
|
|
211089
211616
|
chatStoreNowOrNull,
|
|
211090
211617
|
currentCompanyId
|
|
211091
211618
|
);
|
|
@@ -211104,7 +211631,7 @@ async function startOasisServer(opts) {
|
|
|
211104
211631
|
{ status: "approved", command: "", effectLabel: review.plan.reason, authorizedBy: actor },
|
|
211105
211632
|
// 状态条要的两样也得进 resume 上下文(不能只放在 resolution 里):`effectLabel` 是改图卡的
|
|
211106
211633
|
// 「改动摘要」(= plan.reason,见 diagnosis 口径 1),`authorizedBy` 是「谁批的」。
|
|
211107
|
-
{ origin: review.origin, kind: review.kind ?? "graph-edit", authorizedBy: actor, effectLabel: review.plan.reason },
|
|
211634
|
+
{ origin: review.origin, kind: review.kind ?? "graph-edit", authorizedBy: actor, ...authorizedByName ? { authorizedByName } : {}, effectLabel: review.plan.reason },
|
|
211108
211635
|
chatStoreNowOrNull,
|
|
211109
211636
|
// 续跑那一轮照样可能往 outputs/ 写东西——按公司出产出卡(与命令卡那支同口径)。
|
|
211110
211637
|
currentCompanyId
|
|
@@ -211134,6 +211661,7 @@ async function startOasisServer(opts) {
|
|
|
211134
211661
|
return;
|
|
211135
211662
|
}
|
|
211136
211663
|
const { recorded } = await engine.kernel.rejectIntervention({ draftId, anchor: review.anchor, actor, ...reason !== void 0 ? { reason } : {} });
|
|
211664
|
+
const authorizedByName = (await (engine.registry ?? opts.registry)?.getActor(actor).catch(() => null))?.name?.trim();
|
|
211137
211665
|
notifyReviewResolved(
|
|
211138
211666
|
draftId,
|
|
211139
211667
|
{ status: "denied", ...reason !== void 0 ? { reason } : {} },
|
|
@@ -211141,10 +211669,13 @@ async function startOasisServer(opts) {
|
|
|
211141
211669
|
origin: review.origin,
|
|
211142
211670
|
kind: review.kind ?? "graph-edit",
|
|
211143
211671
|
authorizedBy: actor,
|
|
211672
|
+
...authorizedByName ? { authorizedByName } : {},
|
|
211144
211673
|
// 状态条要的那段「效果标签 / 改动摘要」:命令卡用命令的效果标签,改图卡用 `plan.reason`
|
|
211145
211674
|
// ——与 apply-draft 改图那一支同源(那里传的就是 `review.plan.reason`),否则驳回档的
|
|
211146
211675
|
// 改图卡状态条会永远拿不到摘要、只能落占位符(diagnosis 口径 1)。
|
|
211147
211676
|
...review.command?.effectLabel || review.plan.reason ? { effectLabel: review.command?.effectLabel || review.plan.reason } : {},
|
|
211677
|
+
// Bug 0215:驳回档的状态条同样走人读那句(命令卡才有;改图卡的摘要仍是 plan.reason)。
|
|
211678
|
+
...review.command?.displayLabel ? { displayLabel: review.command.displayLabel } : {},
|
|
211148
211679
|
...review.command?.command ? { command: review.command.command } : {},
|
|
211149
211680
|
...reason !== void 0 ? { reason } : {}
|
|
211150
211681
|
},
|
|
@@ -211975,6 +212506,15 @@ async function startOasisServer(opts) {
|
|
|
211975
212506
|
res.writeHead(400, { "content-type": "application/json" }).end(JSON.stringify({ error: "EMPTY_TEXT" }));
|
|
211976
212507
|
return;
|
|
211977
212508
|
}
|
|
212509
|
+
await waitForAdmittedTurnStart(sid, {
|
|
212510
|
+
liveChat,
|
|
212511
|
+
ledgerTurnRunning: async () => {
|
|
212512
|
+
const turns = opts.resolveChatTurns ? await opts.resolveChatTurns(currentCompanyId) : opts.chatTurns;
|
|
212513
|
+
const status = (await turns?.activeTurn(sid).catch(() => null))?.status;
|
|
212514
|
+
return status === "reserved" || status === "running";
|
|
212515
|
+
},
|
|
212516
|
+
timeoutMs: APPEND_TURN_START_WAIT_MS
|
|
212517
|
+
});
|
|
211978
212518
|
await respondAppend(res, wantsAppendProgress(req), (onAwaitingConsumption) => appendNowThroughQueue2(sid, text7, clientKey, insertAttachments, perCompanyStore, retainLocallyOnFailure, onAwaitingConsumption, resend));
|
|
211979
212519
|
return;
|
|
211980
212520
|
}
|
|
@@ -213900,7 +214440,10 @@ ${composed}`;
|
|
|
213900
214440
|
auth: {
|
|
213901
214441
|
actor,
|
|
213902
214442
|
...companyId !== void 0 ? { companyId } : {},
|
|
213903
|
-
...dispatch && Object.keys(dispatch).length > 0 ? { dispatch } : {}
|
|
214443
|
+
...dispatch && Object.keys(dispatch).length > 0 ? { dispatch } : {},
|
|
214444
|
+
// 签名 scopes 原样透出(ADR 0609 D1):部署级 operator-token 靠它被认出来。
|
|
214445
|
+
// 只来自签名 token;cookie / 简单 token 没有这一项。
|
|
214446
|
+
...domainClaims?.scopes ? { scopes: domainClaims.scopes } : {}
|
|
213904
214447
|
},
|
|
213905
214448
|
raw: req
|
|
213906
214449
|
});
|
|
@@ -214043,7 +214586,7 @@ async function markDeliveredWithRetry(store, messageId, attempts = 3) {
|
|
|
214043
214586
|
}
|
|
214044
214587
|
return false;
|
|
214045
214588
|
}
|
|
214046
|
-
var http, import_node_crypto41, githubAppPending, connectorAuthSnapshots, CONNECTOR_AUTH_SNAPSHOT_TTL_MS, defaultResolveActor, enc, CHAT_OUTPUT_LIMIT, STREAMING_PATHS, PLANNER_BLOCKING_CODES, WILL_VERBS, GOVERNANCE_COMMANDS, READ_ONLY_COMMANDS, isAgent, isHuman;
|
|
214589
|
+
var http, import_node_crypto41, githubAppPending, connectorAuthSnapshots, CONNECTOR_AUTH_SNAPSHOT_TTL_MS, defaultResolveActor, enc, CHAT_OUTPUT_LIMIT, APPEND_TURN_START_WAIT_MS, STREAMING_PATHS, PLANNER_BLOCKING_CODES, WILL_VERBS, GOVERNANCE_COMMANDS, READ_ONLY_COMMANDS, isAgent, isHuman;
|
|
214047
214590
|
var init_server3 = __esm({
|
|
214048
214591
|
"../server/src/server.ts"() {
|
|
214049
214592
|
"use strict";
|
|
@@ -214058,6 +214601,7 @@ var init_server3 = __esm({
|
|
|
214058
214601
|
init_src();
|
|
214059
214602
|
init_src();
|
|
214060
214603
|
init_src();
|
|
214604
|
+
init_src();
|
|
214061
214605
|
init_file_http();
|
|
214062
214606
|
init_build_info();
|
|
214063
214607
|
init_artifact_content2();
|
|
@@ -214117,6 +214661,7 @@ var init_server3 = __esm({
|
|
|
214117
214661
|
defaultResolveActor = (token) => token.startsWith("token:") ? token.slice("token:".length) : null;
|
|
214118
214662
|
enc = (s2) => new TextEncoder().encode(s2);
|
|
214119
214663
|
CHAT_OUTPUT_LIMIT = 16e3;
|
|
214664
|
+
APPEND_TURN_START_WAIT_MS = 1e4;
|
|
214120
214665
|
STREAMING_PATHS = ["/api/events", "/api/chat", "/api/trajectory/events", "/api/intervention/wait"];
|
|
214121
214666
|
PLANNER_BLOCKING_CODES = /* @__PURE__ */ new Set([
|
|
214122
214667
|
"title_collision",
|
|
@@ -214207,12 +214752,12 @@ function createTokenIssuer(opts = {}) {
|
|
|
214207
214752
|
function createNodeTokenStore(file) {
|
|
214208
214753
|
const read3 = () => {
|
|
214209
214754
|
try {
|
|
214210
|
-
return JSON.parse(
|
|
214755
|
+
return JSON.parse(fs19.readFileSync(file, "utf8"));
|
|
214211
214756
|
} catch {
|
|
214212
214757
|
return {};
|
|
214213
214758
|
}
|
|
214214
214759
|
};
|
|
214215
|
-
const write = (table) =>
|
|
214760
|
+
const write = (table) => fs19.writeFileSync(file, JSON.stringify(table, null, 2), { mode: 384 });
|
|
214216
214761
|
return {
|
|
214217
214762
|
issue(nodeId) {
|
|
214218
214763
|
const table = read3();
|
|
@@ -214238,14 +214783,14 @@ function createEnrollTokenStore(defaultTtlMs = 30 * 60 * 1e3, file) {
|
|
|
214238
214783
|
const read3 = () => {
|
|
214239
214784
|
if (!file) return table;
|
|
214240
214785
|
try {
|
|
214241
|
-
return new Map(Object.entries(JSON.parse(
|
|
214786
|
+
return new Map(Object.entries(JSON.parse(fs19.readFileSync(file, "utf8"))));
|
|
214242
214787
|
} catch {
|
|
214243
214788
|
return /* @__PURE__ */ new Map();
|
|
214244
214789
|
}
|
|
214245
214790
|
};
|
|
214246
214791
|
const write = (m2) => {
|
|
214247
214792
|
if (!file) return;
|
|
214248
|
-
|
|
214793
|
+
fs19.writeFileSync(file, JSON.stringify(Object.fromEntries(m2), null, 2), { mode: 384 });
|
|
214249
214794
|
};
|
|
214250
214795
|
const table = /* @__PURE__ */ new Map();
|
|
214251
214796
|
const prune = () => {
|
|
@@ -214307,12 +214852,12 @@ function createEnrollTokenStore(defaultTtlMs = 30 * 60 * 1e3, file) {
|
|
|
214307
214852
|
}
|
|
214308
214853
|
};
|
|
214309
214854
|
}
|
|
214310
|
-
var import_node_crypto42,
|
|
214855
|
+
var import_node_crypto42, fs19, path19, SESSION_TOKEN_PREFIX, b64url2, fromB64url, readOrCreateSecret, sign, signatureMatches, isTokenClaims;
|
|
214311
214856
|
var init_tokens = __esm({
|
|
214312
214857
|
"../server/src/tokens.ts"() {
|
|
214313
214858
|
"use strict";
|
|
214314
214859
|
import_node_crypto42 = require("node:crypto");
|
|
214315
|
-
|
|
214860
|
+
fs19 = __toESM(require("node:fs"), 1);
|
|
214316
214861
|
path19 = __toESM(require("node:path"), 1);
|
|
214317
214862
|
SESSION_TOKEN_PREFIX = "oat_v2_";
|
|
214318
214863
|
b64url2 = (value2) => Buffer.from(value2).toString("base64url");
|
|
@@ -214320,13 +214865,13 @@ var init_tokens = __esm({
|
|
|
214320
214865
|
readOrCreateSecret = (file) => {
|
|
214321
214866
|
if (!file) return (0, import_node_crypto42.randomBytes)(32);
|
|
214322
214867
|
try {
|
|
214323
|
-
const raw =
|
|
214868
|
+
const raw = fs19.readFileSync(file, "utf8").trim();
|
|
214324
214869
|
if (raw) return Buffer.from(raw, "base64url");
|
|
214325
214870
|
} catch {
|
|
214326
214871
|
}
|
|
214327
214872
|
const secret = (0, import_node_crypto42.randomBytes)(32);
|
|
214328
|
-
|
|
214329
|
-
|
|
214873
|
+
fs19.mkdirSync(path19.dirname(file), { recursive: true });
|
|
214874
|
+
fs19.writeFileSync(file, secret.toString("base64url"), { mode: 384 });
|
|
214330
214875
|
return secret;
|
|
214331
214876
|
};
|
|
214332
214877
|
sign = (secret, payload2) => (0, import_node_crypto42.createHmac)("sha256", secret).update(payload2).digest("base64url");
|
|
@@ -214351,6 +214896,18 @@ var init_tokens = __esm({
|
|
|
214351
214896
|
}
|
|
214352
214897
|
});
|
|
214353
214898
|
|
|
214899
|
+
// ../server/src/auth/operator.ts
|
|
214900
|
+
function isOperatorRequest(auth) {
|
|
214901
|
+
return auth.scopes?.includes(OPERATOR_SCOPE) === true;
|
|
214902
|
+
}
|
|
214903
|
+
var OPERATOR_SCOPE;
|
|
214904
|
+
var init_operator = __esm({
|
|
214905
|
+
"../server/src/auth/operator.ts"() {
|
|
214906
|
+
"use strict";
|
|
214907
|
+
OPERATOR_SCOPE = "oasis:operator";
|
|
214908
|
+
}
|
|
214909
|
+
});
|
|
214910
|
+
|
|
214354
214911
|
// ../server/src/session-dataplane-token.ts
|
|
214355
214912
|
function createDataplaneTokenIssuer(opts = {}) {
|
|
214356
214913
|
const secret = readOrCreateSecret2(opts.secretFile);
|
|
@@ -214380,12 +214937,12 @@ function createDataplaneTokenIssuer(opts = {}) {
|
|
|
214380
214937
|
}
|
|
214381
214938
|
};
|
|
214382
214939
|
}
|
|
214383
|
-
var import_node_crypto43,
|
|
214940
|
+
var import_node_crypto43, fs20, path20, PREFIX2, b64url3, fromB64url2, sign2, sigMatches, readOrCreateSecret2, isClaims, isDataplaneToken;
|
|
214384
214941
|
var init_session_dataplane_token = __esm({
|
|
214385
214942
|
"../server/src/session-dataplane-token.ts"() {
|
|
214386
214943
|
"use strict";
|
|
214387
214944
|
import_node_crypto43 = require("node:crypto");
|
|
214388
|
-
|
|
214945
|
+
fs20 = __toESM(require("node:fs"), 1);
|
|
214389
214946
|
path20 = __toESM(require("node:path"), 1);
|
|
214390
214947
|
init_src();
|
|
214391
214948
|
PREFIX2 = "osd_";
|
|
@@ -214400,13 +214957,13 @@ var init_session_dataplane_token = __esm({
|
|
|
214400
214957
|
readOrCreateSecret2 = (file) => {
|
|
214401
214958
|
if (!file) return (0, import_node_crypto43.randomBytes)(32);
|
|
214402
214959
|
try {
|
|
214403
|
-
const raw =
|
|
214960
|
+
const raw = fs20.readFileSync(file, "utf8").trim();
|
|
214404
214961
|
if (raw) return Buffer.from(raw, "base64url");
|
|
214405
214962
|
} catch {
|
|
214406
214963
|
}
|
|
214407
214964
|
const secret = (0, import_node_crypto43.randomBytes)(32);
|
|
214408
|
-
|
|
214409
|
-
|
|
214965
|
+
fs20.mkdirSync(path20.dirname(file), { recursive: true });
|
|
214966
|
+
fs20.writeFileSync(file, secret.toString("base64url"), { mode: 384 });
|
|
214410
214967
|
return secret;
|
|
214411
214968
|
};
|
|
214412
214969
|
isClaims = (v2) => {
|
|
@@ -220004,13 +220561,13 @@ function applyTurnPatch(t, patch) {
|
|
|
220004
220561
|
...patch.lastError !== void 0 ? { lastError: patch.lastError } : {}
|
|
220005
220562
|
};
|
|
220006
220563
|
}
|
|
220007
|
-
var import_node_crypto46,
|
|
220564
|
+
var import_node_crypto46, fs21, path21, NdjsonOplogStore, DirBlobStore, MUTATORS, FileTypeRegistryStore, FileRoleRegistryStore, FileRegistryStore, FileAssistantBindStore, FileHumanPrefsStore, FileProjectStateStore, FileArtifactStateStore, FileTraceStore, MemoryChatSessionStore, FileChatSessionStore, MemoryChatTurnStore, FileChatTurnStore, MemoryReadMarkerStore, FileReadMarkerStore;
|
|
220008
220565
|
var init_dev_store = __esm({
|
|
220009
220566
|
"../server/src/dev-store.ts"() {
|
|
220010
220567
|
"use strict";
|
|
220011
220568
|
init_src();
|
|
220012
220569
|
import_node_crypto46 = require("node:crypto");
|
|
220013
|
-
|
|
220570
|
+
fs21 = __toESM(require("node:fs"), 1);
|
|
220014
220571
|
path21 = __toESM(require("node:path"), 1);
|
|
220015
220572
|
init_src();
|
|
220016
220573
|
init_src9();
|
|
@@ -220024,8 +220581,8 @@ var init_dev_store = __esm({
|
|
|
220024
220581
|
}
|
|
220025
220582
|
static async open(file) {
|
|
220026
220583
|
const memory = new MemoryOplogStore();
|
|
220027
|
-
if (
|
|
220028
|
-
for (const line2 of
|
|
220584
|
+
if (fs21.existsSync(file)) {
|
|
220585
|
+
for (const line2 of fs21.readFileSync(file, "utf8").split("\n")) {
|
|
220029
220586
|
if (!line2.trim()) continue;
|
|
220030
220587
|
const stored = JSON.parse(line2);
|
|
220031
220588
|
const { artifactId, seq, ...op } = stored;
|
|
@@ -220033,15 +220590,15 @@ var init_dev_store = __esm({
|
|
|
220033
220590
|
if (assigned !== seq) throw new Error(`corrupt ndjson log: seq mismatch at ${line2}`);
|
|
220034
220591
|
}
|
|
220035
220592
|
} else {
|
|
220036
|
-
|
|
220037
|
-
|
|
220593
|
+
fs21.mkdirSync(path21.dirname(file), { recursive: true });
|
|
220594
|
+
fs21.writeFileSync(file, "");
|
|
220038
220595
|
}
|
|
220039
220596
|
return new _NdjsonOplogStore(file, memory);
|
|
220040
220597
|
}
|
|
220041
220598
|
async append(artifactId, op, expectedSeq) {
|
|
220042
220599
|
const seq = await this.memory.append(artifactId, op, expectedSeq);
|
|
220043
220600
|
const stored = { ...op, artifactId, seq };
|
|
220044
|
-
|
|
220601
|
+
fs21.appendFileSync(this.file, JSON.stringify(stored) + "\n");
|
|
220045
220602
|
return seq;
|
|
220046
220603
|
}
|
|
220047
220604
|
read(artifactId, fromSeq) {
|
|
@@ -220057,7 +220614,7 @@ var init_dev_store = __esm({
|
|
|
220057
220614
|
DirBlobStore = class {
|
|
220058
220615
|
constructor(dir) {
|
|
220059
220616
|
this.dir = dir;
|
|
220060
|
-
|
|
220617
|
+
fs21.mkdirSync(dir, { recursive: true });
|
|
220061
220618
|
}
|
|
220062
220619
|
fileOf(hash3) {
|
|
220063
220620
|
return path21.join(this.dir, hash3);
|
|
@@ -220065,31 +220622,31 @@ var init_dev_store = __esm({
|
|
|
220065
220622
|
async put(bytes2) {
|
|
220066
220623
|
const hash3 = (0, import_node_crypto46.createHash)("sha256").update(bytes2).digest("hex");
|
|
220067
220624
|
const file = this.fileOf(hash3);
|
|
220068
|
-
if (!
|
|
220625
|
+
if (!fs21.existsSync(file)) fs21.writeFileSync(file, bytes2);
|
|
220069
220626
|
return hash3;
|
|
220070
220627
|
}
|
|
220071
220628
|
async meta(hash3) {
|
|
220072
220629
|
const file = this.fileOf(hash3);
|
|
220073
|
-
if (!
|
|
220074
|
-
const size =
|
|
220075
|
-
const fd =
|
|
220630
|
+
if (!fs21.existsSync(file)) return null;
|
|
220631
|
+
const size = fs21.statSync(file).size;
|
|
220632
|
+
const fd = fs21.openSync(file, "r");
|
|
220076
220633
|
const head = Buffer.alloc(16);
|
|
220077
|
-
|
|
220078
|
-
|
|
220634
|
+
fs21.readSync(fd, head, 0, 16, 0);
|
|
220635
|
+
fs21.closeSync(fd);
|
|
220079
220636
|
const contentType = sniffContentType(new Uint8Array(head));
|
|
220080
220637
|
return { size, ...contentType ? { contentType } : {} };
|
|
220081
220638
|
}
|
|
220082
220639
|
async get(hash3) {
|
|
220083
220640
|
const file = this.fileOf(hash3);
|
|
220084
|
-
if (!
|
|
220085
|
-
return new Uint8Array(
|
|
220641
|
+
if (!fs21.existsSync(file)) throw new BlobNotFoundError(hash3);
|
|
220642
|
+
return new Uint8Array(fs21.readFileSync(file));
|
|
220086
220643
|
}
|
|
220087
220644
|
async has(hash3) {
|
|
220088
|
-
return
|
|
220645
|
+
return fs21.existsSync(this.fileOf(hash3));
|
|
220089
220646
|
}
|
|
220090
220647
|
async sweep(reachable) {
|
|
220091
|
-
for (const name of
|
|
220092
|
-
if (!reachable.has(name))
|
|
220648
|
+
for (const name of fs21.readdirSync(this.dir)) {
|
|
220649
|
+
if (!reachable.has(name)) fs21.unlinkSync(this.fileOf(name));
|
|
220093
220650
|
}
|
|
220094
220651
|
}
|
|
220095
220652
|
};
|
|
@@ -220118,7 +220675,7 @@ var init_dev_store = __esm({
|
|
|
220118
220675
|
this.file = file;
|
|
220119
220676
|
}
|
|
220120
220677
|
static async open(file) {
|
|
220121
|
-
const seed =
|
|
220678
|
+
const seed = fs21.existsSync(file) ? JSON.parse(fs21.readFileSync(file, "utf8")) : [];
|
|
220122
220679
|
return new _FileTypeRegistryStore(file, seed);
|
|
220123
220680
|
}
|
|
220124
220681
|
async put(def) {
|
|
@@ -220131,8 +220688,8 @@ var init_dev_store = __esm({
|
|
|
220131
220688
|
}
|
|
220132
220689
|
async save() {
|
|
220133
220690
|
const tmp = `${this.file}.tmp`;
|
|
220134
|
-
|
|
220135
|
-
|
|
220691
|
+
fs21.writeFileSync(tmp, JSON.stringify(await this.list(), null, 2));
|
|
220692
|
+
fs21.renameSync(tmp, this.file);
|
|
220136
220693
|
}
|
|
220137
220694
|
};
|
|
220138
220695
|
FileRoleRegistryStore = class _FileRoleRegistryStore extends MemoryRoleRegistryStore {
|
|
@@ -220141,7 +220698,7 @@ var init_dev_store = __esm({
|
|
|
220141
220698
|
this.file = file;
|
|
220142
220699
|
}
|
|
220143
220700
|
static async open(file) {
|
|
220144
|
-
const seed =
|
|
220701
|
+
const seed = fs21.existsSync(file) ? JSON.parse(fs21.readFileSync(file, "utf8")) : [];
|
|
220145
220702
|
return new _FileRoleRegistryStore(file, seed);
|
|
220146
220703
|
}
|
|
220147
220704
|
async put(def) {
|
|
@@ -220154,8 +220711,8 @@ var init_dev_store = __esm({
|
|
|
220154
220711
|
}
|
|
220155
220712
|
async save() {
|
|
220156
220713
|
const tmp = `${this.file}.tmp`;
|
|
220157
|
-
|
|
220158
|
-
|
|
220714
|
+
fs21.writeFileSync(tmp, JSON.stringify(await this.list(), null, 2));
|
|
220715
|
+
fs21.renameSync(tmp, this.file);
|
|
220159
220716
|
}
|
|
220160
220717
|
};
|
|
220161
220718
|
FileRegistryStore = class _FileRegistryStore extends MemoryRegistryStore {
|
|
@@ -220173,8 +220730,8 @@ var init_dev_store = __esm({
|
|
|
220173
220730
|
}
|
|
220174
220731
|
static async open(file) {
|
|
220175
220732
|
const store = new _FileRegistryStore(file);
|
|
220176
|
-
if (
|
|
220177
|
-
const snap = JSON.parse(
|
|
220733
|
+
if (fs21.existsSync(file)) {
|
|
220734
|
+
const snap = JSON.parse(fs21.readFileSync(file, "utf8"));
|
|
220178
220735
|
for (const a of snap.actors) await MemoryRegistryStore.prototype.upsertActor.call(store, a);
|
|
220179
220736
|
for (const c of snap.configs) await MemoryRegistryStore.prototype.appendConfig.call(store, c);
|
|
220180
220737
|
for (const t of snap.teams) await MemoryRegistryStore.prototype.upsertTeam.call(store, t);
|
|
@@ -220215,7 +220772,7 @@ var init_dev_store = __esm({
|
|
|
220215
220772
|
skillFiles: skillFilesEntries,
|
|
220216
220773
|
connections
|
|
220217
220774
|
};
|
|
220218
|
-
|
|
220775
|
+
fs21.writeFileSync(this.file, JSON.stringify(snap, null, 2));
|
|
220219
220776
|
}
|
|
220220
220777
|
};
|
|
220221
220778
|
FileAssistantBindStore = class _FileAssistantBindStore extends MemoryAssistantBindStore {
|
|
@@ -220233,11 +220790,11 @@ var init_dev_store = __esm({
|
|
|
220233
220790
|
}
|
|
220234
220791
|
static async open(file) {
|
|
220235
220792
|
const store = new _FileAssistantBindStore(file);
|
|
220236
|
-
if (
|
|
220793
|
+
if (fs21.existsSync(file)) store._load(JSON.parse(fs21.readFileSync(file, "utf8")));
|
|
220237
220794
|
return store;
|
|
220238
220795
|
}
|
|
220239
220796
|
async save() {
|
|
220240
|
-
|
|
220797
|
+
fs21.writeFileSync(this.file, JSON.stringify(this._dump(), null, 2));
|
|
220241
220798
|
}
|
|
220242
220799
|
};
|
|
220243
220800
|
FileHumanPrefsStore = class _FileHumanPrefsStore extends MemoryHumanPrefsStore {
|
|
@@ -220255,11 +220812,11 @@ var init_dev_store = __esm({
|
|
|
220255
220812
|
}
|
|
220256
220813
|
static async open(file) {
|
|
220257
220814
|
const store = new _FileHumanPrefsStore(file);
|
|
220258
|
-
if (
|
|
220815
|
+
if (fs21.existsSync(file)) store._load(JSON.parse(fs21.readFileSync(file, "utf8")));
|
|
220259
220816
|
return store;
|
|
220260
220817
|
}
|
|
220261
220818
|
async save() {
|
|
220262
|
-
|
|
220819
|
+
fs21.writeFileSync(this.file, JSON.stringify(this._dump(), null, 2));
|
|
220263
220820
|
}
|
|
220264
220821
|
};
|
|
220265
220822
|
FileProjectStateStore = class _FileProjectStateStore extends MemoryProjectStateStore {
|
|
@@ -220269,8 +220826,8 @@ var init_dev_store = __esm({
|
|
|
220269
220826
|
}
|
|
220270
220827
|
static async open(file) {
|
|
220271
220828
|
const store = new _FileProjectStateStore(file);
|
|
220272
|
-
if (
|
|
220273
|
-
const snap = JSON.parse(
|
|
220829
|
+
if (fs21.existsSync(file)) {
|
|
220830
|
+
const snap = JSON.parse(fs21.readFileSync(file, "utf8"));
|
|
220274
220831
|
for (const project of snap.projects ?? []) await MemoryProjectStateStore.prototype.upsertProject.call(store, project);
|
|
220275
220832
|
const membersByProject = /* @__PURE__ */ new Map();
|
|
220276
220833
|
for (const member of snap.members ?? []) {
|
|
@@ -220282,8 +220839,8 @@ var init_dev_store = __esm({
|
|
|
220282
220839
|
await MemoryProjectStateStore.prototype.replaceProjectMembers.call(store, projectId2, members);
|
|
220283
220840
|
}
|
|
220284
220841
|
} else {
|
|
220285
|
-
|
|
220286
|
-
|
|
220842
|
+
fs21.mkdirSync(path21.dirname(file), { recursive: true });
|
|
220843
|
+
fs21.writeFileSync(file, JSON.stringify({ projects: [], members: [] }, null, 2));
|
|
220287
220844
|
}
|
|
220288
220845
|
return store;
|
|
220289
220846
|
}
|
|
@@ -220302,7 +220859,7 @@ var init_dev_store = __esm({
|
|
|
220302
220859
|
async save() {
|
|
220303
220860
|
const projects = await this.listProjects();
|
|
220304
220861
|
const members = (await Promise.all(projects.map((project) => this.listProjectMembers(project.id)))).flat();
|
|
220305
|
-
|
|
220862
|
+
fs21.writeFileSync(this.file, JSON.stringify({ projects, members }, null, 2));
|
|
220306
220863
|
}
|
|
220307
220864
|
};
|
|
220308
220865
|
FileArtifactStateStore = class _FileArtifactStateStore extends MemoryArtifactStateStore {
|
|
@@ -220312,8 +220869,8 @@ var init_dev_store = __esm({
|
|
|
220312
220869
|
}
|
|
220313
220870
|
static async open(file) {
|
|
220314
220871
|
const store = new _FileArtifactStateStore(file);
|
|
220315
|
-
if (
|
|
220316
|
-
const snap = JSON.parse(
|
|
220872
|
+
if (fs21.existsSync(file)) {
|
|
220873
|
+
const snap = JSON.parse(fs21.readFileSync(file, "utf8"));
|
|
220317
220874
|
for (const artifact of snap.artifacts ?? []) await MemoryArtifactStateStore.prototype.upsertArtifact.call(store, artifact);
|
|
220318
220875
|
for (const revision of snap.revisions ?? []) await MemoryArtifactStateStore.prototype.upsertRevision.call(store, revision);
|
|
220319
220876
|
for (const event of snap.events ?? []) await MemoryArtifactStateStore.prototype.appendEvent.call(store, event);
|
|
@@ -220323,8 +220880,8 @@ var init_dev_store = __esm({
|
|
|
220323
220880
|
for (const ws of snap.workspaceDispatchHeld ?? []) await MemoryArtifactStateStore.prototype.setWorkspaceDispatchHold.call(store, ws, true);
|
|
220324
220881
|
for (const f2 of snap.workOrderFiles ?? []) await MemoryArtifactStateStore.prototype.addWorkOrderFile.call(store, f2);
|
|
220325
220882
|
} else {
|
|
220326
|
-
|
|
220327
|
-
|
|
220883
|
+
fs21.mkdirSync(path21.dirname(file), { recursive: true });
|
|
220884
|
+
fs21.writeFileSync(file, JSON.stringify({ artifacts: [], revisions: [], events: [], annotations: [], nodeOutputs: [], workspaceBindings: [], workspaceDispatchHeld: [], workOrderFiles: [] }, null, 2));
|
|
220328
220885
|
}
|
|
220329
220886
|
return store;
|
|
220330
220887
|
}
|
|
@@ -220361,7 +220918,7 @@ var init_dev_store = __esm({
|
|
|
220361
220918
|
await this.save();
|
|
220362
220919
|
}
|
|
220363
220920
|
async save() {
|
|
220364
|
-
|
|
220921
|
+
fs21.writeFileSync(this.file, JSON.stringify(await this.listAll(), null, 2));
|
|
220365
220922
|
}
|
|
220366
220923
|
};
|
|
220367
220924
|
FileTraceStore = class _FileTraceStore extends MemoryTraceStore {
|
|
@@ -220388,25 +220945,25 @@ var init_dev_store = __esm({
|
|
|
220388
220945
|
return path21.join(this.eventsDir, `${encodeURIComponent(runId)}.ndjson`);
|
|
220389
220946
|
}
|
|
220390
220947
|
appendLine(file, obj2) {
|
|
220391
|
-
|
|
220948
|
+
fs21.appendFileSync(file, JSON.stringify(obj2) + "\n");
|
|
220392
220949
|
}
|
|
220393
220950
|
static replay(file, fn) {
|
|
220394
|
-
if (!
|
|
220395
|
-
for (const line2 of
|
|
220951
|
+
if (!fs21.existsSync(file)) return;
|
|
220952
|
+
for (const line2 of fs21.readFileSync(file, "utf8").split("\n")) {
|
|
220396
220953
|
if (!line2.trim()) continue;
|
|
220397
220954
|
fn(JSON.parse(line2));
|
|
220398
220955
|
}
|
|
220399
220956
|
}
|
|
220400
220957
|
static async open(dir) {
|
|
220401
220958
|
const store = new _FileTraceStore(dir);
|
|
220402
|
-
|
|
220959
|
+
fs21.mkdirSync(store.eventsDir, { recursive: true });
|
|
220403
220960
|
_FileTraceStore.replay(store.runsFile, (r) => store.restoreRun(r));
|
|
220404
|
-
for (const name of
|
|
220961
|
+
for (const name of fs21.readdirSync(store.eventsDir)) {
|
|
220405
220962
|
_FileTraceStore.replay(path21.join(store.eventsDir, name), (e) => store.restoreEvent(e));
|
|
220406
220963
|
}
|
|
220407
220964
|
_FileTraceStore.replay(store.toolCallsFile, (c) => store.restoreToolCall(c));
|
|
220408
220965
|
_FileTraceStore.replay(store.linksFile, (l) => store.restoreLink(l));
|
|
220409
|
-
store.restoreContinuity(
|
|
220966
|
+
store.restoreContinuity(fs21.existsSync(store.continuityFile) ? JSON.parse(fs21.readFileSync(store.continuityFile, "utf8")) : {});
|
|
220410
220967
|
return store;
|
|
220411
220968
|
}
|
|
220412
220969
|
async createRun(input) {
|
|
@@ -220458,8 +221015,8 @@ var init_dev_store = __esm({
|
|
|
220458
221015
|
}
|
|
220459
221016
|
saveContinuity() {
|
|
220460
221017
|
const tmp = `${this.continuityFile}.tmp`;
|
|
220461
|
-
|
|
220462
|
-
|
|
221018
|
+
fs21.writeFileSync(tmp, JSON.stringify(this.continuitySnapshot(), null, 2));
|
|
221019
|
+
fs21.renameSync(tmp, this.continuityFile);
|
|
220463
221020
|
}
|
|
220464
221021
|
async appendEvents(runId, inputs) {
|
|
220465
221022
|
const existing = await super.listEvents(runId, {});
|
|
@@ -220920,8 +221477,8 @@ var init_dev_store = __esm({
|
|
|
220920
221477
|
}
|
|
220921
221478
|
static async open(file) {
|
|
220922
221479
|
const store = new _FileChatSessionStore(file);
|
|
220923
|
-
if (
|
|
220924
|
-
const snap = JSON.parse(
|
|
221480
|
+
if (fs21.existsSync(file)) {
|
|
221481
|
+
const snap = JSON.parse(fs21.readFileSync(file, "utf8"));
|
|
220925
221482
|
for (const [sid, copies] of Object.entries(snap.outputCopies ?? {})) store.outputCopies.set(sid, copies);
|
|
220926
221483
|
for (const [sid, fps] of Object.entries(snap.outputFingerprints ?? {})) store.outputFingerprints.set(sid, fps);
|
|
220927
221484
|
for (const [sid, issues] of Object.entries(snap.fileIssues ?? {})) store.fileIssues.set(sid, issues);
|
|
@@ -220931,8 +221488,8 @@ var init_dev_store = __esm({
|
|
|
220931
221488
|
for (const [sid, kinds] of Object.entries(snap.sessionWorkOrderKinds ?? {})) store.sessionWorkOrderKinds.set(sid, new Map(Object.entries(kinds)));
|
|
220932
221489
|
for (const [sid, list2] of Object.entries(snap.pending ?? {})) store.pending.set(sid, list2);
|
|
220933
221490
|
} else {
|
|
220934
|
-
|
|
220935
|
-
|
|
221491
|
+
fs21.mkdirSync(path21.dirname(file), { recursive: true });
|
|
221492
|
+
fs21.writeFileSync(file, JSON.stringify({ sessions: [], messages: {}, sessionWorkOrders: {} }, null, 2));
|
|
220936
221493
|
}
|
|
220937
221494
|
return store;
|
|
220938
221495
|
}
|
|
@@ -221026,7 +221583,7 @@ var init_dev_store = __esm({
|
|
|
221026
221583
|
sessionWorkOrderKinds: Object.fromEntries([...this.sessionWorkOrderKinds].map(([k2, v2]) => [k2, Object.fromEntries(v2)])),
|
|
221027
221584
|
pending: Object.fromEntries(this.pending)
|
|
221028
221585
|
};
|
|
221029
|
-
|
|
221586
|
+
fs21.writeFileSync(this.file, JSON.stringify(snap, null, 2));
|
|
221030
221587
|
}
|
|
221031
221588
|
};
|
|
221032
221589
|
MemoryChatTurnStore = class {
|
|
@@ -221109,17 +221666,17 @@ var init_dev_store = __esm({
|
|
|
221109
221666
|
}
|
|
221110
221667
|
static async open(file) {
|
|
221111
221668
|
const store = new _FileChatTurnStore(file);
|
|
221112
|
-
if (
|
|
221113
|
-
const snap = JSON.parse(
|
|
221669
|
+
if (fs21.existsSync(file)) {
|
|
221670
|
+
const snap = JSON.parse(fs21.readFileSync(file, "utf8"));
|
|
221114
221671
|
for (const t of snap.turns ?? []) store.turns.set(t.id, t);
|
|
221115
221672
|
} else {
|
|
221116
|
-
|
|
221117
|
-
|
|
221673
|
+
fs21.mkdirSync(path21.dirname(file), { recursive: true });
|
|
221674
|
+
fs21.writeFileSync(file, JSON.stringify({ turns: [] }, null, 2));
|
|
221118
221675
|
}
|
|
221119
221676
|
return store;
|
|
221120
221677
|
}
|
|
221121
221678
|
persist() {
|
|
221122
|
-
|
|
221679
|
+
fs21.writeFileSync(this.file, JSON.stringify({ turns: [...this.turns.values()] }, null, 2));
|
|
221123
221680
|
}
|
|
221124
221681
|
};
|
|
221125
221682
|
MemoryReadMarkerStore = class _MemoryReadMarkerStore {
|
|
@@ -221145,12 +221702,12 @@ var init_dev_store = __esm({
|
|
|
221145
221702
|
}
|
|
221146
221703
|
static async open(file) {
|
|
221147
221704
|
const store = new _FileReadMarkerStore(file);
|
|
221148
|
-
if (
|
|
221149
|
-
const snap = JSON.parse(
|
|
221705
|
+
if (fs21.existsSync(file)) {
|
|
221706
|
+
const snap = JSON.parse(fs21.readFileSync(file, "utf8"));
|
|
221150
221707
|
for (const m2 of snap.markers ?? []) store.markers.set(`${m2.actorId}\0${m2.scope}`, m2);
|
|
221151
221708
|
} else {
|
|
221152
|
-
|
|
221153
|
-
|
|
221709
|
+
fs21.mkdirSync(path21.dirname(file), { recursive: true });
|
|
221710
|
+
fs21.writeFileSync(file, JSON.stringify({ markers: [] }, null, 2));
|
|
221154
221711
|
}
|
|
221155
221712
|
return store;
|
|
221156
221713
|
}
|
|
@@ -221159,18 +221716,18 @@ var init_dev_store = __esm({
|
|
|
221159
221716
|
this.save();
|
|
221160
221717
|
}
|
|
221161
221718
|
save() {
|
|
221162
|
-
|
|
221719
|
+
fs21.writeFileSync(this.file, JSON.stringify({ markers: [...this.markers.values()] }, null, 2));
|
|
221163
221720
|
}
|
|
221164
221721
|
};
|
|
221165
221722
|
}
|
|
221166
221723
|
});
|
|
221167
221724
|
|
|
221168
221725
|
// ../server/src/control-plane-file-store.ts
|
|
221169
|
-
var
|
|
221726
|
+
var fs22, path22, MUTATORS2, SNAPSHOT_VERSION, FileControlPlaneStore;
|
|
221170
221727
|
var init_control_plane_file_store = __esm({
|
|
221171
221728
|
"../server/src/control-plane-file-store.ts"() {
|
|
221172
221729
|
"use strict";
|
|
221173
|
-
|
|
221730
|
+
fs22 = __toESM(require("node:fs"), 1);
|
|
221174
221731
|
path22 = __toESM(require("node:path"), 1);
|
|
221175
221732
|
init_src9();
|
|
221176
221733
|
MUTATORS2 = [
|
|
@@ -221213,8 +221770,8 @@ var init_control_plane_file_store = __esm({
|
|
|
221213
221770
|
}
|
|
221214
221771
|
static async open(file) {
|
|
221215
221772
|
const store = new _FileControlPlaneStore(file);
|
|
221216
|
-
if (
|
|
221217
|
-
const snap = JSON.parse(
|
|
221773
|
+
if (fs22.existsSync(file)) {
|
|
221774
|
+
const snap = JSON.parse(fs22.readFileSync(file, "utf8"));
|
|
221218
221775
|
const needsOnboardingBackfill = (snap.version ?? 1) < 2;
|
|
221219
221776
|
const backfillAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
221220
221777
|
for (const c of snap.companies ?? []) await MemoryControlPlaneStore.prototype.createCompany.call(store, c);
|
|
@@ -221232,7 +221789,7 @@ var init_control_plane_file_store = __esm({
|
|
|
221232
221789
|
for (const op of snap.offboardings ?? []) store.offboardings.set(`${op.companyId}\0${op.operationId}`, op);
|
|
221233
221790
|
if (needsOnboardingBackfill) await store.save();
|
|
221234
221791
|
} else {
|
|
221235
|
-
|
|
221792
|
+
fs22.mkdirSync(path22.dirname(file), { recursive: true });
|
|
221236
221793
|
}
|
|
221237
221794
|
return store;
|
|
221238
221795
|
}
|
|
@@ -221269,7 +221826,7 @@ var init_control_plane_file_store = __esm({
|
|
|
221269
221826
|
// 交接操作无按公司列举的读面(按 operationId / accountId 定位),直接读 protected map。
|
|
221270
221827
|
offboardings: [...this.offboardings.values()]
|
|
221271
221828
|
};
|
|
221272
|
-
|
|
221829
|
+
fs22.writeFileSync(this.file, JSON.stringify(snap, null, 2));
|
|
221273
221830
|
}
|
|
221274
221831
|
};
|
|
221275
221832
|
}
|
|
@@ -223441,8 +223998,12 @@ var init_dispatch_binding_diagnosis = __esm({
|
|
|
223441
223998
|
});
|
|
223442
223999
|
|
|
223443
224000
|
// ../server/src/zero-output-breaker.ts
|
|
224001
|
+
function roundKeyOfZeroOutputRun(run) {
|
|
224002
|
+
return run.workId ?? run.id.replace(PROTOCOL_RECOVERY_SUFFIX, "");
|
|
224003
|
+
}
|
|
223444
224004
|
function absorb(b2, r, startedMs) {
|
|
223445
224005
|
b2.count += 1;
|
|
224006
|
+
b2.rounds.add(roundKeyOfZeroOutputRun(r));
|
|
223446
224007
|
b2.costUsdMicros += r.costUsdMicros ?? 0;
|
|
223447
224008
|
if (startedMs >= b2.latestStartedMs) {
|
|
223448
224009
|
b2.latestStartedMs = startedMs;
|
|
@@ -223510,6 +224071,7 @@ async function scanZeroOutputBreaker(deps) {
|
|
|
223510
224071
|
actorId: axis === "count" ? b2.actorId : null,
|
|
223511
224072
|
cls: axis === "count" ? b2.cls : null,
|
|
223512
224073
|
count: b2.count,
|
|
224074
|
+
workCount: b2.rounds.size,
|
|
223513
224075
|
costUsdMicros: b2.costUsdMicros,
|
|
223514
224076
|
windowMs: deps.windowMs,
|
|
223515
224077
|
latestRunId: b2.latestRunId,
|
|
@@ -223519,7 +224081,7 @@ async function scanZeroOutputBreaker(deps) {
|
|
|
223519
224081
|
const who = axis === "count" ? `${b2.actorId}\uFF08${b2.cls}\uFF09` : "\u8BE5\u8282\u70B9\u5168\u90E8\u6267\u884C\u4EBA\u5408\u8BA1";
|
|
223520
224082
|
const cidTag = deps.defaultCompanyId && b2.companyId !== deps.defaultCompanyId ? ` [${b2.companyId}]` : "";
|
|
223521
224083
|
deps.log?.(
|
|
223522
|
-
`[zero-output-breaker] ${b2.artifactId}${cidTag}\uFF1A\u6700\u8FD1 ${Math.round(deps.windowMs / 6e4)} \u5206\u949F\u5185 ${who} \u7D2F\u8BA1 ${b2.count} \u6B21\u96F6\u4EA7\u51FA\uFF08\u7EA6 $${(b2.costUsdMicros / 1e6).toFixed(1)}\uFF09\u2192 ${axis} \u8F74\u8DF3\u95F8`
|
|
224084
|
+
`[zero-output-breaker] ${b2.artifactId}${cidTag}\uFF1A\u6700\u8FD1 ${Math.round(deps.windowMs / 6e4)} \u5206\u949F\u5185 ${who} \u7D2F\u8BA1 ${b2.count} \u6B21\u96F6\u4EA7\u51FA\uFF08${b2.rounds.size} \u8F6E\uFF0C\u7EA6 $${(b2.costUsdMicros / 1e6).toFixed(1)}\uFF09\u2192 ${axis} \u8F74\u8DF3\u95F8`
|
|
223523
224085
|
);
|
|
223524
224086
|
};
|
|
223525
224087
|
const byKey = (a, b2) => a.artifactId.localeCompare(b2.artifactId) || (a.actorId ?? "").localeCompare(b2.actorId ?? "");
|
|
@@ -223545,32 +224107,35 @@ async function scanZeroOutputBreaker(deps) {
|
|
|
223545
224107
|
function formatZeroOutputNotice(t) {
|
|
223546
224108
|
const usd2 = (t.costUsdMicros / 1e6).toFixed(1);
|
|
223547
224109
|
const mins = Math.round(t.windowMs / 6e4);
|
|
224110
|
+
const runs = t.count > t.workCount ? `\u5171 ${t.count} \u6B21\u8FD0\u884C\uFF0C\u542B\u540C\u4E00\u8F6E\u5185\u7684\u81EA\u52A8\u7EED\u8DD1\uFF1B` : "";
|
|
223548
224111
|
const remark = t.closingRemark && t.closingRemark.trim() ? `
|
|
223549
224112
|
|
|
223550
224113
|
\u6700\u8FD1\u4E00\u6B21\u8FD0\u884C\u7684\u6536\u5C3E\u53D1\u8A00\uFF08\u5F80\u5F80\u76F4\u63A5\u5199\u7740\u5361\u5728\u54EA\uFF09\uFF1A
|
|
223551
224114
|
${t.closingRemark.trim()}` : "";
|
|
223552
224115
|
const tail = `\u8FD9\u4E0D\u662F\u5728\u5224\u67D0\u4E00\u6B21\u8FD0\u884C\u5931\u8D25\u2014\u2014\u662F\u5728\u8FD9\u6BB5\u65F6\u95F4\u91CC\u53CD\u590D\u96F6\u4EA7\u51FA\u3002\u65E0\u8BBA\u6BCF\u4E00\u6B21\u9000\u51FA\u591A\u4E48\u300C\u6B63\u5E38\u300D\uFF0C\u53CD\u590D\u5230\u8FD9\u4E2A\u6B21\u6570\u901A\u5E38\u610F\u5473\u7740\u5361\u5728\u4E00\u4E2A\u53CD\u590D\u91CD\u8BD5\u4E5F\u8FC7\u4E0D\u53BB\u7684\u574E\u4E0A\uFF08\u7F3A\u51ED\u636E\u3001\u4E0A\u6E38\u670D\u52A1\u8FDE\u4E0D\u4E0A\u3001\u6216\u649E\u4E0A\u4E86\u522B\u7684\u6B7B\u5FAA\u73AF\uFF09\u3002\u8BF7\u770B\u4E00\u773C\u6839\u56E0\uFF1B\u5904\u7406\u5B8C\u7528 \`oasis release\` \u6062\u590D\u3002` + remark;
|
|
223553
224116
|
if (t.axis === "cost") {
|
|
223554
|
-
return `\u8FD9\u4E2A\u4EA7\u7269\u5728\u6700\u8FD1 ${mins} \u5206\u949F\u5185\
|
|
224117
|
+
return `\u8FD9\u4E2A\u4EA7\u7269\u5728\u6700\u8FD1 ${mins} \u5206\u949F\u5185\u6709 ${t.workCount} \u8F6E**\u4EC0\u4E48\u90FD\u6CA1\u4EA4\u51FA\u6765**\uFF08${runs}\u8FD9\u4E9B\u7A7A\u8DD1\u5408\u8BA1\u5DF2\u7ECF\u82B1\u6389\u7EA6 $${usd2}\uFF09\uFF0C\u5DF2\u81EA\u52A8\u6682\u505C\u6D3E\u53D1\u4EE5\u6B62\u635F\u3002
|
|
223555
224118
|
|
|
223556
224119
|
` + tail;
|
|
223557
224120
|
}
|
|
223558
224121
|
const who = t.cls === "review" ? `\u8BC4\u5BA1\u5458 ${t.actorId}` : `\u6267\u884C\u4EBA ${t.actorId}`;
|
|
223559
224122
|
const what = t.cls === "review" ? `\u5DF2\u505C\u6389\u8FD9\u540D\u8BC4\u5BA1\u5458\u5728\u672C\u8282\u70B9\u4E0A\u7684\u8BC4\u5BA1\uFF08**\u4EA4\u4ED8\u5185\u5BB9\u539F\u6837\u4FDD\u7559**\uFF0C\u6062\u590D\u540E\u53EF\u7EE7\u7EED\u6295\u7968\uFF09` : `\u5DF2\u81EA\u52A8\u6682\u505C\u8BE5\u4EA7\u7269\u7684\u6D3E\u53D1\u4EE5\u6B62\u635F`;
|
|
223560
|
-
return `${who} \u5728\u6700\u8FD1 ${mins} \u5206\u949F\u5185\u4E3A\u8FD9\u4E2A\u4EA7\u7269\u8DD1\u4E86 ${t.
|
|
224123
|
+
return `${who} \u5728\u6700\u8FD1 ${mins} \u5206\u949F\u5185\u4E3A\u8FD9\u4E2A\u4EA7\u7269\u8DD1\u4E86 ${t.workCount} \u8F6E\uFF0C**\u6BCF\u4E00\u8F6E\u90FD\u4EC0\u4E48\u90FD\u6CA1\u4EA4\u51FA\u6765**\uFF08${runs}\u8FD9\u4E9B\u7A7A\u8DD1\u7D2F\u8BA1\u82B1\u8D39\u7EA6 $${usd2}\uFF09\uFF0C${what}\u3002
|
|
223561
224124
|
|
|
223562
224125
|
` + tail;
|
|
223563
224126
|
}
|
|
223564
|
-
var emptyBucket;
|
|
224127
|
+
var PROTOCOL_RECOVERY_SUFFIX, emptyBucket;
|
|
223565
224128
|
var init_zero_output_breaker = __esm({
|
|
223566
224129
|
"../server/src/zero-output-breaker.ts"() {
|
|
223567
224130
|
"use strict";
|
|
224131
|
+
PROTOCOL_RECOVERY_SUFFIX = /(?::protocol-recovery)+$/;
|
|
223568
224132
|
emptyBucket = (artifactId, companyId, actorId, cls) => ({
|
|
223569
224133
|
artifactId,
|
|
223570
224134
|
companyId,
|
|
223571
224135
|
actorId,
|
|
223572
224136
|
cls,
|
|
223573
224137
|
count: 0,
|
|
224138
|
+
rounds: /* @__PURE__ */ new Set(),
|
|
223574
224139
|
costUsdMicros: 0,
|
|
223575
224140
|
latestRunId: "",
|
|
223576
224141
|
latestStartedMs: -Infinity
|
|
@@ -223970,6 +224535,11 @@ function chatRunLedgerFields(req) {
|
|
|
223970
224535
|
if (req.executionProfile === "discussion-background") return { chatSessionId: null, chatTurnId: null };
|
|
223971
224536
|
return { chatSessionId: req.chatSessionId ?? null, chatTurnId: req.chatTurnId ?? null };
|
|
223972
224537
|
}
|
|
224538
|
+
function chatExitModelFields(runtimeReportedModel, dispatchedModel, dispatchedModelSource) {
|
|
224539
|
+
const effectiveModel = runtimeReportedModel || dispatchedModel || null;
|
|
224540
|
+
if (!effectiveModel) return {};
|
|
224541
|
+
return { effectiveModel, modelSource: runtimeReportedModel ? "runtime" : dispatchedModelSource };
|
|
224542
|
+
}
|
|
223973
224543
|
function createUsageLedgerResolver(deps) {
|
|
223974
224544
|
const safeCompanyOfRun = (runId) => deps.companyOfRun(runId).catch(() => null);
|
|
223975
224545
|
return async (dispatchId) => {
|
|
@@ -223985,6 +224555,15 @@ function createUsageLedgerResolver(deps) {
|
|
|
223985
224555
|
return chatCid ? { runId: stable, store: await deps.storeFor(chatCid) } : null;
|
|
223986
224556
|
};
|
|
223987
224557
|
}
|
|
224558
|
+
async function backfillRunModel(target, run, model, warn) {
|
|
224559
|
+
if (!model || model.trim().length === 0) return;
|
|
224560
|
+
if (run.effectiveModel && run.effectiveModel.trim().length > 0) return;
|
|
224561
|
+
try {
|
|
224562
|
+
await target.store.updateRun(target.runId, { effectiveModel: model, modelSource: "runtime" });
|
|
224563
|
+
} catch (err) {
|
|
224564
|
+
warn(`[usage-ledger] run ${target.runId} \u7684\u6A21\u578B\u540D\u8865\u5199\u5931\u8D25\uFF08\u4E0D\u5F71\u54CD\u4F1A\u8BDD\uFF09\uFF1A${String(err)}`);
|
|
224565
|
+
}
|
|
224566
|
+
}
|
|
223988
224567
|
function createUsageLedgerFrameHandler(deps) {
|
|
223989
224568
|
const warn = deps.warn ?? defaultWarn;
|
|
223990
224569
|
const marker = deps.marker ?? new RuntimeStartMarker({ warn });
|
|
@@ -224046,6 +224625,7 @@ function createUsageLedgerFrameHandler(deps) {
|
|
|
224046
224625
|
usage: msg.usage,
|
|
224047
224626
|
model: msg.model ?? null
|
|
224048
224627
|
});
|
|
224628
|
+
await backfillRunModel(target, run, msg.model, warn);
|
|
224049
224629
|
} catch (err) {
|
|
224050
224630
|
warn(`[usage-ledger] \u5904\u7406 ${msg.type} dispatch=${dispatchId} \u5931\u8D25\uFF08\u4E0D\u5F71\u54CD\u4F1A\u8BDD\uFF09\uFF1A${String(err)}`);
|
|
224051
224631
|
}
|
|
@@ -225048,18 +225628,27 @@ function wireRecoveredChatTurn(deps) {
|
|
|
225048
225628
|
log3(`[chat-recovery] \u4F1A\u8BDD ${plan.chatSessionId} \u91CD\u6302\uFF1A\u8865\u53D1\u6709 ${droppedFrames} \u5E27\u6CA1\u63A5\u4F4F\uFF08run ${plan.runId}\uFF09\uFF0C\u672C\u8F6E\u6309\u300C\u8F93\u51FA\u4E0D\u5B8C\u6574\u300D\u6536\u5C3E${exitIsFailure ? "\uFF08\u9000\u51FA\u5E27\u672C\u8EAB\u4E5F\u662F\u5931\u8D25\uFF09" : "\uFF0C\u4E0D\u8BB0\u6210\u6210\u529F"}`);
|
|
225049
225629
|
}
|
|
225050
225630
|
if (failed) {
|
|
225051
|
-
const
|
|
225052
|
-
|
|
225053
|
-
...
|
|
225631
|
+
const exitSummary = exitIsFailure ? chatExitSummary(info) : void 0;
|
|
225632
|
+
const exitAttribution = exitSummary ? attributeChatExit(exitSummary.summary, {
|
|
225633
|
+
...exitSummary.reason ? { reason: exitSummary.reason } : {},
|
|
225634
|
+
...exitSummary.detail ? { detail: exitSummary.detail } : {},
|
|
225635
|
+
...exitSummary.cancelledBy ? { cancelledBy: exitSummary.cancelledBy } : {}
|
|
225054
225636
|
}, live.cancelCause()) : void 0;
|
|
225055
225637
|
const errText2 = [
|
|
225056
225638
|
exitAttribution?.text,
|
|
225057
225639
|
droppedFrames > 0 ? outputGapNotice(droppedFrames) : void 0
|
|
225058
225640
|
].filter((t) => Boolean(t)).join("\n\n");
|
|
225059
|
-
live.emit({
|
|
225641
|
+
live.emit({
|
|
225642
|
+
type: "error",
|
|
225643
|
+
text: errText2,
|
|
225644
|
+
...exitAttribution?.extra.detail ? { detail: exitAttribution.extra.detail } : {},
|
|
225645
|
+
...exitAttribution?.extra.cancelledBy ? { cancelledBy: exitAttribution.extra.cancelledBy } : {}
|
|
225646
|
+
});
|
|
225060
225647
|
const errReason = exitIsFailure ? info.reason : OUTPUT_GAP_ERROR_CODE;
|
|
225061
225648
|
const errExtra = {
|
|
225062
225649
|
...errReason ? { reason: errReason } : {},
|
|
225650
|
+
/* 运行时原文只进 detail:刷新后读的是这一行,「展开详情」要能翻出退出码与原始报错。 */
|
|
225651
|
+
...exitAttribution?.extra.detail ? { detail: exitAttribution.extra.detail } : {},
|
|
225063
225652
|
...exitAttribution?.extra.cancelledBy ? { cancelledBy: exitAttribution.extra.cancelledBy } : {}
|
|
225064
225653
|
};
|
|
225065
225654
|
const errorOutcome = itemLedger.recordError(errText2, errExtra);
|
|
@@ -225100,7 +225689,7 @@ function wireRecoveredChatTurn(deps) {
|
|
|
225100
225689
|
touchedAt: finishedAt
|
|
225101
225690
|
}).catch(() => void 0);
|
|
225102
225691
|
if (deps.onTurnSettled) {
|
|
225103
|
-
await deps.onTurnSettled(failed ? "failed" : "succeeded", finishedAt).catch((err) => {
|
|
225692
|
+
await deps.onTurnSettled(failed ? "failed" : "succeeded", finishedAt, info.reason ?? void 0).catch((err) => {
|
|
225104
225693
|
log3(`[chat-recovery] \u4F1A\u8BDD ${plan.chatSessionId} \u6536\u53E3\u8BB0\u8D26\u5931\u8D25\uFF08\u9000\u56DE\u6E05\u626B\u62CD\u515C\u5E95\uFF09: ${String(err)}`);
|
|
225105
225694
|
});
|
|
225106
225695
|
}
|
|
@@ -225297,13 +225886,26 @@ async function reconcileChatExitFrame(deps) {
|
|
|
225297
225886
|
if (part) parts.push({ ...part, seq: ++seq });
|
|
225298
225887
|
}
|
|
225299
225888
|
if (failed) {
|
|
225889
|
+
const exitSummary = exitIsFailure ? chatExitSummary(info) : void 0;
|
|
225300
225890
|
const errText2 = [
|
|
225301
|
-
|
|
225891
|
+
exitSummary?.summary,
|
|
225302
225892
|
droppedFrames > 0 ? outputGapNotice(droppedFrames) : void 0
|
|
225303
225893
|
].filter((t) => Boolean(t)).join("\n\n");
|
|
225304
225894
|
const errReason = exitIsFailure ? info.reason : OUTPUT_GAP_ERROR_CODE;
|
|
225305
|
-
|
|
225306
|
-
|
|
225895
|
+
const errExtra = {
|
|
225896
|
+
...errReason ? { reason: errReason } : {},
|
|
225897
|
+
...exitSummary?.detail ? { detail: exitSummary.detail } : {},
|
|
225898
|
+
...exitSummary?.cancelledBy ? { cancelledBy: exitSummary.cancelledBy } : {}
|
|
225899
|
+
};
|
|
225900
|
+
itemLedger.recordError(errText2, errExtra);
|
|
225901
|
+
parts.push({
|
|
225902
|
+
type: "error",
|
|
225903
|
+
seq: ++seq,
|
|
225904
|
+
text: errText2,
|
|
225905
|
+
...exitIsFailure && info.reason ? { reason: info.reason } : {},
|
|
225906
|
+
...exitSummary?.detail ? { detail: exitSummary.detail } : {},
|
|
225907
|
+
...exitSummary?.cancelledBy ? { cancelledBy: exitSummary.cancelledBy } : {}
|
|
225908
|
+
});
|
|
225307
225909
|
}
|
|
225308
225910
|
normalizer.turnFinished(failed ? "failed" : "completed");
|
|
225309
225911
|
itemLedger.finish(failed ? "failed" : "completed");
|
|
@@ -225364,7 +225966,8 @@ async function reconcileChatExitFrame(deps) {
|
|
|
225364
225966
|
chatSessionId: row.sessionId,
|
|
225365
225967
|
turnId: turn.id,
|
|
225366
225968
|
status,
|
|
225367
|
-
reason: `\u505C\u673A\u7A97\u53E3\u5185\u7ED3\u675F\u7684\u8F6E\u4EE5 ${status} \u6536\u5C3E
|
|
225969
|
+
reason: `\u505C\u673A\u7A97\u53E3\u5185\u7ED3\u675F\u7684\u8F6E\u4EE5 ${status} \u6536\u5C3E`,
|
|
225970
|
+
...info.reason ? { exitReason: info.reason } : {}
|
|
225368
225971
|
});
|
|
225369
225972
|
} catch (err) {
|
|
225370
225973
|
deps.log?.(`[chat-recovery] \u8F6E\u6B21 ${turn.id} \u6536\u53E3\u540E\u7684\u8BB0\u8D26/\u5916\u62A5\u5931\u8D25\uFF08\u884C\u5DF2\u6536\u5C3E\uFF09: ${String(err)}`);
|
|
@@ -225520,7 +226123,7 @@ async function recoverChatTurnsAcrossCompanies(deps) {
|
|
|
225520
226123
|
}
|
|
225521
226124
|
const handle = deps.recover(plan);
|
|
225522
226125
|
const settleTurnId = turn?.id;
|
|
225523
|
-
const onTurnSettled = settleTurnId && stores.settleTurn ? async (status, completedAt) => {
|
|
226126
|
+
const onTurnSettled = settleTurnId && stores.settleTurn ? async (status, completedAt, exitReason) => {
|
|
225524
226127
|
await stores.settleTurn(settleTurnId, {
|
|
225525
226128
|
status,
|
|
225526
226129
|
completedAt,
|
|
@@ -225532,6 +226135,7 @@ async function recoverChatTurnsAcrossCompanies(deps) {
|
|
|
225532
226135
|
turnId: settleTurnId,
|
|
225533
226136
|
status,
|
|
225534
226137
|
reason: `\u91CD\u6302\u7684\u8F6E\u4EE5 ${status} \u6536\u5C3E`,
|
|
226138
|
+
...exitReason ? { exitReason } : {},
|
|
225535
226139
|
...companyId ? { companyId } : {}
|
|
225536
226140
|
});
|
|
225537
226141
|
} : void 0;
|
|
@@ -225577,6 +226181,7 @@ var init_chat_recovery = __esm({
|
|
|
225577
226181
|
init_chat_assistant_turn();
|
|
225578
226182
|
init_src2();
|
|
225579
226183
|
init_session_exit_outcome();
|
|
226184
|
+
init_chat_exit();
|
|
225580
226185
|
init_chat_cancel_attribution();
|
|
225581
226186
|
asObj3 = (v2) => v2 && typeof v2 === "object" && !Array.isArray(v2) ? v2 : void 0;
|
|
225582
226187
|
partsOf = (parts) => Array.isArray(parts) ? parts.filter((p2) => p2 && typeof p2 === "object" && typeof p2.type === "string") : [];
|
|
@@ -225826,6 +226431,8 @@ var init_daemon_hub = __esm({
|
|
|
225826
226431
|
sessionMeta = /* @__PURE__ */ new Map();
|
|
225827
226432
|
sessionConnectListeners = [];
|
|
225828
226433
|
sessionDisconnectListeners = [];
|
|
226434
|
+
/** Bug 0224:等某条会话连上数据面的一次性等待者(dispatchId → 兑现函数)。见 {@link waitForSession}。 */
|
|
226435
|
+
sessionReadyWaiters = /* @__PURE__ */ new Map();
|
|
225829
226436
|
// ── ADR 0300 D2「日志复制」:帧号 + 累积 ackSeq + 幂等摄入 ────────────────────────────
|
|
225830
226437
|
// 只对自报 supportsFrameSeq 的会话生效;老会话这三张表始终为空、逐字走原 outbox 语义。
|
|
225831
226438
|
/** 自报支持帧号的 dispatchId。 */
|
|
@@ -226089,6 +226696,11 @@ var init_daemon_hub = __esm({
|
|
|
226089
226696
|
...msg.jobArtifactId ? { jobArtifactId: msg.jobArtifactId } : {}
|
|
226090
226697
|
});
|
|
226091
226698
|
for (const l of this.sessionConnectListeners) l({ dispatchId, sessionId: msg.sessionId, nodeId });
|
|
226699
|
+
const readyWaiters = this.sessionReadyWaiters.get(dispatchId);
|
|
226700
|
+
if (readyWaiters) {
|
|
226701
|
+
this.sessionReadyWaiters.delete(dispatchId);
|
|
226702
|
+
for (const w2 of readyWaiters) w2(true);
|
|
226703
|
+
}
|
|
226092
226704
|
void this.judgeSession(dispatchId, ws);
|
|
226093
226705
|
}
|
|
226094
226706
|
if (msg.supportsFrameSeq) {
|
|
@@ -226260,6 +226872,35 @@ var init_daemon_hub = __esm({
|
|
|
226260
226872
|
addSessionDisconnectListener(l) {
|
|
226261
226873
|
this.sessionDisconnectListeners.push(l);
|
|
226262
226874
|
}
|
|
226875
|
+
/**
|
|
226876
|
+
* Bug 0224:等这次派发的会话进程连上数据面(`session_hello` 登记完),最多等 `timeoutMs`。
|
|
226877
|
+
* 已连着立即回 true;等到了回 true;超时回 false。
|
|
226878
|
+
*
|
|
226879
|
+
* 为什么要等:每一轮开始时节点另起一个会话进程,它自己连回来、在 hello 里报「能回报插话读到的位置」。
|
|
226880
|
+
* 连上之前 {@link supportsInputConsumptionReceipts} 只能答 false——那不是「不支持」,是「还没到」。
|
|
226881
|
+
*/
|
|
226882
|
+
waitForSession(dispatchId, timeoutMs) {
|
|
226883
|
+
if (this.hasSession(dispatchId)) return Promise.resolve(true);
|
|
226884
|
+
return new Promise((resolve11) => {
|
|
226885
|
+
let waiters = this.sessionReadyWaiters.get(dispatchId);
|
|
226886
|
+
if (!waiters) {
|
|
226887
|
+
waiters = /* @__PURE__ */ new Set();
|
|
226888
|
+
this.sessionReadyWaiters.set(dispatchId, waiters);
|
|
226889
|
+
}
|
|
226890
|
+
const done = (connected) => {
|
|
226891
|
+
clearTimeout(timer);
|
|
226892
|
+
resolve11(connected);
|
|
226893
|
+
};
|
|
226894
|
+
const timer = setTimeout(() => {
|
|
226895
|
+
const set = this.sessionReadyWaiters.get(dispatchId);
|
|
226896
|
+
set?.delete(done);
|
|
226897
|
+
if (set && set.size === 0) this.sessionReadyWaiters.delete(dispatchId);
|
|
226898
|
+
resolve11(false);
|
|
226899
|
+
}, timeoutMs);
|
|
226900
|
+
timer.unref?.();
|
|
226901
|
+
waiters.add(done);
|
|
226902
|
+
});
|
|
226903
|
+
}
|
|
226263
226904
|
/** 这次派发有没有一根活着的数据面连接(有 = 会话自己在说话,不必再问节点)。 */
|
|
226264
226905
|
hasSession(dispatchId) {
|
|
226265
226906
|
return this.sessionSockets.get(dispatchId)?.readyState === import_websocket.default.OPEN;
|
|
@@ -231236,7 +231877,7 @@ function createRegistryAuditSink(file) {
|
|
|
231236
231877
|
return {
|
|
231237
231878
|
/** 登记审计:落盘 + 推 registry 通知(前端据此重拉登记类投影)。 */
|
|
231238
231879
|
registryAudit: (record9) => {
|
|
231239
|
-
|
|
231880
|
+
fs23.appendFile(file, JSON.stringify(record9) + "\n", () => {
|
|
231240
231881
|
});
|
|
231241
231882
|
notify({ kind: record9.kind, actor: record9.actor, target: record9.target, timestamp: record9.timestamp });
|
|
231242
231883
|
},
|
|
@@ -231250,7 +231891,7 @@ function createRegistryAuditSink(file) {
|
|
|
231250
231891
|
* 得先让通知带组织、`/api/events` 按组织过滤(recvvzbhOGiS7l 的完整修复),再放回来。
|
|
231251
231892
|
*/
|
|
231252
231893
|
credentialAudit: (record9) => {
|
|
231253
|
-
|
|
231894
|
+
fs23.appendFile(file, JSON.stringify(record9) + "\n", () => {
|
|
231254
231895
|
});
|
|
231255
231896
|
},
|
|
231256
231897
|
/** runtime 状态变了:只发无内容的失效提示(ADR 0576)。 */
|
|
@@ -231267,11 +231908,11 @@ function createRegistryAuditSink(file) {
|
|
|
231267
231908
|
}
|
|
231268
231909
|
};
|
|
231269
231910
|
}
|
|
231270
|
-
var
|
|
231911
|
+
var fs23;
|
|
231271
231912
|
var init_registry_audit_sink = __esm({
|
|
231272
231913
|
"../server/src/domains/actors/registry-audit-sink.ts"() {
|
|
231273
231914
|
"use strict";
|
|
231274
|
-
|
|
231915
|
+
fs23 = __toESM(require("node:fs"), 1);
|
|
231275
231916
|
}
|
|
231276
231917
|
});
|
|
231277
231918
|
|
|
@@ -233201,8 +233842,18 @@ var init_review_requirement_activity = __esm({
|
|
|
233201
233842
|
});
|
|
233202
233843
|
|
|
233203
233844
|
// ../server/src/domains/collab/activity.ts
|
|
233845
|
+
function coordinatorCardGapId(cardId) {
|
|
233846
|
+
return cardId.startsWith(COORDINATOR_CARD_PREFIX) ? cardId.slice(COORDINATOR_CARD_PREFIX.length) : void 0;
|
|
233847
|
+
}
|
|
233848
|
+
function coordinatorRunOfGap(gap, runs) {
|
|
233849
|
+
const opensAt = gap.createdAt;
|
|
233850
|
+
const closesAt = gap.resolvedAt ?? null;
|
|
233851
|
+
const overlapping = runs.filter((r) => (!closesAt || r.startedAt <= closesAt) && (!r.endedAt || r.endedAt >= opensAt)).sort((a, b2) => a.startedAt.localeCompare(b2.startedAt) || a.id.localeCompare(b2.id));
|
|
233852
|
+
return overlapping.find((r) => r.startedAt >= opensAt) ?? overlapping.at(-1);
|
|
233853
|
+
}
|
|
233204
233854
|
function escalationKindOf(issueId, authorActorId) {
|
|
233205
233855
|
if (issueId.startsWith(RETRY_EXHAUSTED_ESC_PREFIX)) return "retry_exhausted";
|
|
233856
|
+
if (issueId.startsWith(REVIEW_EXHAUSTED_ESC_PREFIX2)) return "review_exhausted";
|
|
233206
233857
|
return isSystemActorId(authorActorId) ? "output_stall" : "manual";
|
|
233207
233858
|
}
|
|
233208
233859
|
function parseStopLossFacts(kind, body2) {
|
|
@@ -233211,7 +233862,7 @@ function parseStopLossFacts(kind, body2) {
|
|
|
233211
233862
|
const reason = /末次失败原因(原文):([^\n]+)/.exec(body2)?.[1]?.trim();
|
|
233212
233863
|
return { ...n2 ? { count: Number(n2) } : {}, ...reason ? { lastReason: firstSentence(reason) } : {} };
|
|
233213
233864
|
}
|
|
233214
|
-
const n = /(?:跑了|累计有)\s*(\d+)\s*次/.exec(body2)?.[1];
|
|
233865
|
+
const n = /(?:跑了|有)\s*(\d+)\s*轮/.exec(body2)?.[1] ?? /(?:跑了|累计有)\s*(\d+)\s*次/.exec(body2)?.[1];
|
|
233215
233866
|
const rawCost = /约\s*\$([\d.]+)/.exec(body2)?.[1];
|
|
233216
233867
|
const cost = rawCost !== void 0 && Number.isFinite(Number(rawCost)) ? `$${Number(rawCost).toFixed(2)}` : void 0;
|
|
233217
233868
|
return { ...n ? { count: Number(n) } : {}, ...cost ? { cost } : {} };
|
|
@@ -233569,7 +234220,7 @@ function buildWorkorderActivity(input) {
|
|
|
233569
234220
|
card2.segmentOpen = false;
|
|
233570
234221
|
card2.status = interrupt.kind === "gap" ? ACTIVITY_COPY.interruptedByGap(name, nameOf(managerId ?? ownerId)) : ACTIVITY_COPY.interruptedByIssue(name);
|
|
233571
234222
|
if (interrupt.kind === "gap" && interrupt.authorId) {
|
|
233572
|
-
card2.actions = [{ kind: "open_thread", label: BUTTON.
|
|
234223
|
+
card2.actions = [{ kind: "open_thread", label: BUTTON.view, target: gapThreadSessionId(interrupt.authorId) }];
|
|
233573
234224
|
}
|
|
233574
234225
|
if (interrupt.at > card2.updatedAt) card2.updatedAt = interrupt.at;
|
|
233575
234226
|
} else if (supersededBy) {
|
|
@@ -233623,6 +234274,7 @@ function buildWorkorderActivity(input) {
|
|
|
233623
234274
|
const recoveryLetterIssueIds = /* @__PURE__ */ new Set();
|
|
233624
234275
|
const plainComments = [];
|
|
233625
234276
|
const escalations = [];
|
|
234277
|
+
const gapCreatedSeq = /* @__PURE__ */ new Map();
|
|
233626
234278
|
const plainResolveEvents = /* @__PURE__ */ new Map();
|
|
233627
234279
|
const acceptCards = /* @__PURE__ */ new Map();
|
|
233628
234280
|
const standalone = [];
|
|
@@ -233879,7 +234531,10 @@ function buildWorkorderActivity(input) {
|
|
|
233879
234531
|
});
|
|
233880
234532
|
break;
|
|
233881
234533
|
}
|
|
233882
|
-
if (isGap)
|
|
234534
|
+
if (isGap) {
|
|
234535
|
+
gapCreatedSeq.set(issueId, rec2.seq);
|
|
234536
|
+
break;
|
|
234537
|
+
}
|
|
233883
234538
|
if (isRecoveryLetter) recoveryLetterIssueIds.add(issueId);
|
|
233884
234539
|
const nodeAssignee = nodeId ? nodeById.get(nodeId)?.assigneeActorId : void 0;
|
|
233885
234540
|
const commentCounterpart = nodeAssignee ?? ownerId;
|
|
@@ -233905,7 +234560,7 @@ function buildWorkorderActivity(input) {
|
|
|
233905
234560
|
全库实测最长 8096 字印两遍(`ws:wo-56bba3c1`),一张卡顶掉整屏。 */
|
|
233906
234561
|
artifacts: [],
|
|
233907
234562
|
/* 缺口不出按钮(处置在缺口线上,由「任务内沟通」那一列进);
|
|
233908
|
-
|
|
234563
|
+
留言给「查看留言」直达留言线——线是投影出来的、恒存在,id 这里就能算;
|
|
233909
234564
|
回压仍给「去处理」落到产物预览栏(那儿才有批注的处置面)。
|
|
233910
234565
|
留言算不出对面是谁(该产物没负责人)时退回「去处理」,别给一个开不了的落点。 */
|
|
233911
234566
|
actions: isBackpressure || !commentTargetId ? [{ kind: "open_issue", label: BUTTON.handle, target: issueId }] : [{ kind: "open_thread", label: BUTTON.view, target: commentThreadSessionId(authorId, commentTargetId) }]
|
|
@@ -234079,150 +234734,135 @@ function buildWorkorderActivity(input) {
|
|
|
234079
234734
|
commentIssueIds: ids2
|
|
234080
234735
|
});
|
|
234081
234736
|
}
|
|
234082
|
-
{
|
|
234083
|
-
const
|
|
234084
|
-
const
|
|
234085
|
-
|
|
234086
|
-
|
|
234087
|
-
|
|
234088
|
-
|
|
234089
|
-
|
|
234090
|
-
|
|
234091
|
-
|
|
234092
|
-
|
|
234093
|
-
|
|
234094
|
-
|
|
234095
|
-
|
|
234096
|
-
|
|
234097
|
-
|
|
234098
|
-
|
|
234099
|
-
|
|
234100
|
-
|
|
234101
|
-
|
|
234102
|
-
|
|
234103
|
-
|
|
234104
|
-
|
|
234105
|
-
|
|
234106
|
-
|
|
234107
|
-
|
|
234108
|
-
|
|
234109
|
-
|
|
234110
|
-
|
|
234111
|
-
|
|
234112
|
-
|
|
234113
|
-
|
|
234114
|
-
|
|
234115
|
-
|
|
234116
|
-
|
|
234117
|
-
|
|
234118
|
-
|
|
234119
|
-
|
|
234120
|
-
|
|
234121
|
-
|
|
234122
|
-
|
|
234123
|
-
|
|
234124
|
-
|
|
234125
|
-
|
|
234126
|
-
|
|
234127
|
-
|
|
234128
|
-
|
|
234129
|
-
|
|
234130
|
-
|
|
234131
|
-
|
|
234132
|
-
|
|
234133
|
-
|
|
234134
|
-
|
|
234135
|
-
|
|
234136
|
-
|
|
234137
|
-
|
|
234138
|
-
|
|
234139
|
-
|
|
234140
|
-
|
|
234141
|
-
|
|
234142
|
-
|
|
234143
|
-
|
|
234144
|
-
|
|
234145
|
-
|
|
234146
|
-
|
|
234147
|
-
|
|
234148
|
-
|
|
234149
|
-
|
|
234150
|
-
|
|
234151
|
-
|
|
234152
|
-
|
|
234153
|
-
|
|
234154
|
-
关掉之后按钮不收走、只换成「去查看」:那间讨论房是这条上报唯一的来龙去脉。 */
|
|
234155
|
-
actions: open3.length === 0 ? [{ kind: "discuss_escalation", label: BUTTON.view, target: latest.id }] : offerRerun ? [
|
|
234156
|
-
{ kind: "rerun_node", label: BUTTON.rerun, target: active.id, variant: "primary" },
|
|
234157
|
-
{ kind: "discuss_escalation", label: BUTTON.handle, target: active.id, variant: "secondary" }
|
|
234158
|
-
] : [{
|
|
234159
|
-
kind: "discuss_escalation",
|
|
234160
|
-
label: viewerIsTarget ? BUTTON.handle : BUTTON.view,
|
|
234161
|
-
target: active.id
|
|
234162
|
-
}]
|
|
234163
|
-
});
|
|
234164
|
-
}
|
|
234737
|
+
for (const e of [...escalations].sort((a, b2) => a.at.localeCompare(b2.at) || a.seq - b2.seq)) {
|
|
234738
|
+
const kind = escalationKindOf(e.id, issueById.get(e.id)?.authorActorId ?? e.authorId);
|
|
234739
|
+
const resolvedAt = (id) => issueById.get(id)?.resolvedAt ?? null;
|
|
234740
|
+
const closedAt = resolvedAt(e.id);
|
|
234741
|
+
const open3 = !closedAt;
|
|
234742
|
+
const target = resolveEscalationRecipient({
|
|
234743
|
+
recipients: e.recipients,
|
|
234744
|
+
authorActorId: e.authorId,
|
|
234745
|
+
stuckActorId: e.stuckActorId,
|
|
234746
|
+
ownerActorId: ownerId,
|
|
234747
|
+
managerActorId: managerId
|
|
234748
|
+
});
|
|
234749
|
+
const stuckActor = (isStopLoss(kind) ? e.nodeId ? nodeById.get(e.nodeId)?.assigneeActorId : void 0 : void 0) ?? e.stuckActorId;
|
|
234750
|
+
const inDiscussion = open3 && !!input.escalationsInDiscussion?.has(e.id);
|
|
234751
|
+
const gapBehind = (id) => {
|
|
234752
|
+
const gapId = issueById.get(id)?.gapId;
|
|
234753
|
+
return typeof gapId === "string" && !!issueById.get(gapId);
|
|
234754
|
+
};
|
|
234755
|
+
const head = kind === "retry_exhausted" ? ACTIVITY_COPY.escalationHeadRetryExhausted(nodeName(e.nodeId)) : kind === "review_exhausted" ? ACTIVITY_COPY.escalationHeadReviewExhausted(nodeName(e.nodeId)) : kind === "output_stall" ? ACTIVITY_COPY.escalationHeadOutputStall(nodeName(e.nodeId)) : gapBehind(e.id) ? ACTIVITY_COPY.escalationHeadGapEscalated(nameOf(e.authorId), nodeName(e.nodeId)) : ACTIVITY_COPY.escalationHeadManual(nameOf(stuckActor));
|
|
234756
|
+
const howTo = kind === "retry_exhausted" ? ACTIVITY_COPY.escalationHowToRetryExhausted : kind === "review_exhausted" ? ACTIVITY_COPY.escalationHowToReviewExhausted : kind === "output_stall" ? ACTIVITY_COPY.escalationHowToOutputStall : void 0;
|
|
234757
|
+
const closing = issueById.get(e.id);
|
|
234758
|
+
const closeEvent = plainResolveEvents.get(e.id);
|
|
234759
|
+
const closedBy = text5(closing?.resolvedBy) ?? closeEvent?.by ?? target;
|
|
234760
|
+
const closingNote = text5(closing?.resolvedNote) ?? text5(closeEvent?.note);
|
|
234761
|
+
const noteOf = (id) => text5(issueById.get(id)?.resolvedNote) ?? text5(plainResolveEvents.get(id)?.note);
|
|
234762
|
+
const rerunClosed = closingNote === ESCALATION_RERUN_NOTE;
|
|
234763
|
+
const rerunOrdinal = escalations.filter((x2) => x2.nodeId === e.nodeId && noteOf(x2.id) === ESCALATION_RERUN_NOTE && (resolvedAt(x2.id) ?? "") <= (closedAt ?? "")).length;
|
|
234764
|
+
const doneStatus = rerunClosed ? ACTIVITY_COPY.escalationRerun(nameOf(closedBy), Math.max(rerunOrdinal, 1)) : ACTIVITY_COPY.escalationHandled(head, nameOf(closedBy), closingNote);
|
|
234765
|
+
const retryExhaustedSoFar = escalations.filter((x2) => x2.nodeId === e.nodeId && escalationKindOf(x2.id, issueById.get(x2.id)?.authorActorId ?? x2.authorId) === "retry_exhausted" && x2.at <= e.at).length;
|
|
234766
|
+
const viewerIsTarget = !input.viewerActorId || input.viewerActorId === target;
|
|
234767
|
+
const offerRerun = kind === "retry_exhausted" && viewerIsTarget && retryExhaustedSoFar < 2 && !!e.nodeId;
|
|
234768
|
+
issueCards.set(e.id, {
|
|
234769
|
+
id: `issue:${e.id}`,
|
|
234770
|
+
seq: e.seq,
|
|
234771
|
+
at: e.at,
|
|
234772
|
+
updatedAt: closedAt ?? e.at,
|
|
234773
|
+
...e.nodeId ? { nodeId: e.nodeId } : {},
|
|
234774
|
+
executorId: target,
|
|
234775
|
+
/* 代操作人只在**还没关**的时候带:那是「谁替谁把这条上报派成待办」的事实。
|
|
234776
|
+
关掉之后归因只认这次收口(`resolvedBy`),不沿用派发待办时的代操作者。 */
|
|
234777
|
+
...open3 && e.handActorId ? { handActorId: e.handActorId } : {},
|
|
234778
|
+
escalationKind: kind,
|
|
234779
|
+
/* 大状态三档(F5):待处理 → 处理中(讨论房里已经有人说过话)→ 已完成。
|
|
234780
|
+
关掉那一档不覆写 `phaseLabel`,用四档默认的「已完成」。 */
|
|
234781
|
+
phase: !open3 ? "done" : inDiscussion ? "running" : "not_started",
|
|
234782
|
+
segmentOpen: open3,
|
|
234783
|
+
/* 颜色(奕璇 2026-09-22 定的判据「是不是在等人动手」):**上报没关 ⇒ 砖红**——这一段就卡在人
|
|
234784
|
+
身上,卡面给的正是「去处理」/「重新运行」。关了 ⇒ 不再等人,`segmentOpen` 也随之为假 ⇒ 灰。
|
|
234785
|
+
⚠ **不按查看者分**:非收件人看到的按钮词是「查看留言」(Bug 0151 / 用例 T-31),但这件事照样
|
|
234786
|
+
卡在人身上——颜色说的是这一段的状态,不是「轮到你了没有」。 */
|
|
234787
|
+
awaitingHuman: open3,
|
|
234788
|
+
...open3 ? { phaseLabel: inDiscussion ? PHASE_LABEL.escalationInProgress : PHASE_LABEL.escalationPending } : {},
|
|
234789
|
+
status: open3 ? ACTIVITY_COPY.escalationPendingWith(head, nameOf(target), howTo) : doneStatus,
|
|
234790
|
+
/* 上报正文**不上卡**——与缺口 / 回压同一条口径。此前这里把整封信塞进展开区,
|
|
234791
|
+
`ws:wo-635d7add` 那条渲染出的是一屏字,连内部 artifact id 都印在卡面上。
|
|
234792
|
+
全文的去处,就是那个「去处理」按钮。 */
|
|
234793
|
+
artifacts: [],
|
|
234794
|
+
/* 「去处理」进**这条上报自己的**讨论房(`discuss_escalation`)——卡与房一一对应(ADR 0079 D1
|
|
234795
|
+
「一上报一房」),所以关掉之后这张卡仍然指着当初处理它的那间房,不会被后来新开的上报改指。
|
|
234796
|
+
房间不在这里造:前端拿 escalationId 去打 `POST /api/inbox/discuss`,那个端点按项幂等。
|
|
234797
|
+
按钮文案按**查看者**分两态(Bug 0151 / PR #2003 / 用例 T-31):不是收件人就写「查看留言」
|
|
234798
|
+
——他点进去只有只读视图,按钮不该承诺一件他做不到的事。查看者取不到时保持「去处理」。
|
|
234799
|
+
关掉之后按钮不收走、只换成「查看留言」:那间讨论房是这条上报唯一的来龙去脉。 */
|
|
234800
|
+
actions: !open3 ? [{ kind: "discuss_escalation", label: BUTTON.view, target: e.id }] : offerRerun ? [
|
|
234801
|
+
{ kind: "rerun_node", label: BUTTON.rerun, target: e.id, variant: "primary" },
|
|
234802
|
+
{ kind: "discuss_escalation", label: BUTTON.handle, target: e.id, variant: "secondary" }
|
|
234803
|
+
] : [{
|
|
234804
|
+
kind: "discuss_escalation",
|
|
234805
|
+
label: viewerIsTarget ? BUTTON.handle : BUTTON.view,
|
|
234806
|
+
target: e.id
|
|
234807
|
+
}]
|
|
234808
|
+
});
|
|
234165
234809
|
}
|
|
234166
234810
|
const coordinatorCards = [];
|
|
234811
|
+
const gapsClosedByCoordinatorCard = /* @__PURE__ */ new Set();
|
|
234167
234812
|
{
|
|
234168
|
-
const
|
|
234169
|
-
const
|
|
234170
|
-
|
|
234171
|
-
const
|
|
234172
|
-
const
|
|
234173
|
-
|
|
234174
|
-
|
|
234175
|
-
|
|
234176
|
-
|
|
234177
|
-
|
|
234178
|
-
|
|
234179
|
-
|
|
234180
|
-
|
|
234181
|
-
|
|
234182
|
-
|
|
234183
|
-
endedAt: r.endedAt ?? null,
|
|
234184
|
-
statuses: [r.status ?? null]
|
|
234185
|
-
});
|
|
234186
|
-
}
|
|
234187
|
-
for (const run of episodes) {
|
|
234188
|
-
const name = nodeName(run.nodeId);
|
|
234189
|
-
const endedAt = run.endedAt;
|
|
234190
|
-
const inWindow2 = (at) => !!at && at >= run.startedAt && (!endedAt || at <= endedAt);
|
|
234191
|
-
const escalated = snap.issues.find((i) => i.kind === "escalation" && (i.aboutNodeId ?? i.raisedByNodeId) === run.nodeId && escalationKindOf(i.id, i.authorActorId) === "manual" && inWindow2(i.createdAt));
|
|
234192
|
-
const fixedGap = snap.issues.find((i) => i.kind === "gap" && (i.aboutNodeId ?? i.raisedByNodeId) === run.nodeId && inWindow2(i.resolvedAt));
|
|
234193
|
-
const gapOnNode = snap.issues.find((i) => i.kind === "gap" && (i.aboutNodeId ?? i.raisedByNodeId) === run.nodeId && i.createdAt <= (endedAt ?? run.startedAt));
|
|
234194
|
-
const failedRun = !!endedAt && run.statuses.every((st) => !!st && st !== "succeeded");
|
|
234813
|
+
const gaps = [...snap.issues].filter((i) => i.kind === "gap" && !!(i.aboutNodeId ?? i.raisedByNodeId)).sort((a, b2) => a.createdAt.localeCompare(b2.createdAt) || a.id.localeCompare(b2.id));
|
|
234814
|
+
for (const gap of gaps) {
|
|
234815
|
+
const gapId = gap.id;
|
|
234816
|
+
const nodeId = gap.aboutNodeId ?? gap.raisedByNodeId;
|
|
234817
|
+
const name = nodeName(nodeId);
|
|
234818
|
+
const resolvedAt = gap.resolvedAt ?? null;
|
|
234819
|
+
const inWindow2 = (at) => !!at && at >= gap.createdAt && (!resolvedAt || at <= resolvedAt);
|
|
234820
|
+
const escalated = snap.issues.find((i) => i.kind === "escalation" && escalationKindOf(i.id, i.authorActorId) === "manual" && (i.gapId === gapId || (i.aboutNodeId ?? i.raisedByNodeId) === nodeId && inWindow2(i.createdAt)));
|
|
234821
|
+
const run = coordinatorRunOfGap(
|
|
234822
|
+
{ createdAt: gap.createdAt, resolvedAt },
|
|
234823
|
+
(input.coordinatorRuns ?? []).filter((r) => !!r.id && r.nodeId === nodeId)
|
|
234824
|
+
);
|
|
234825
|
+
const failedRun = !!run?.endedAt && !!run.status && run.status !== "succeeded";
|
|
234826
|
+
const coordinatorId = gap.resolvedBy ?? run?.actorId ?? managerId ?? ownerId;
|
|
234827
|
+
const executorId = gap.authorActorId;
|
|
234195
234828
|
const recipient = escalated ? resolveEscalationRecipient({
|
|
234196
234829
|
recipients: (snap.issueRecipients ?? []).filter((r) => r.issueId === escalated.id).map((r) => r.actorId),
|
|
234197
234830
|
authorActorId: escalated.authorActorId,
|
|
234198
|
-
stuckActorId:
|
|
234831
|
+
stuckActorId: executorId,
|
|
234199
234832
|
ownerActorId: ownerId,
|
|
234200
234833
|
managerActorId: managerId
|
|
234201
234834
|
}) : void 0;
|
|
234202
|
-
|
|
234203
|
-
|
|
234204
|
-
|
|
234205
|
-
|
|
234206
|
-
|
|
234207
|
-
|
|
234208
|
-
|
|
234209
|
-
|
|
234210
|
-
|
|
234211
|
-
|
|
234212
|
-
segmentOpen:
|
|
234213
|
-
|
|
234835
|
+
const segmentOpen = !resolvedAt && !escalated;
|
|
234836
|
+
const draft = {
|
|
234837
|
+
id: coordinatorCardId(gapId),
|
|
234838
|
+
seq: gapCreatedSeq.get(gapId) ?? 0,
|
|
234839
|
+
at: gap.createdAt,
|
|
234840
|
+
updatedAt: [gap.createdAt, resolvedAt, escalated?.createdAt, run?.endedAt].filter((t) => !!t).sort().at(-1),
|
|
234841
|
+
nodeId,
|
|
234842
|
+
executorId: coordinatorId,
|
|
234843
|
+
/* 大状态用四档默认词(进行中 / 已完成 / 执行中断),不覆写 `phaseLabel`——「补上了还是升级了」
|
|
234844
|
+
在小状态那句话里说得比一个词清楚。颜色跟着 `segmentOpen` 走。 */
|
|
234845
|
+
phase: !segmentOpen ? "done" : failedRun ? "stuck" : "running",
|
|
234846
|
+
segmentOpen,
|
|
234847
|
+
/* 协调者卡**从不砖红**:缺口的第一接手人恒是协调者本人,这一段没有人在等着动手
|
|
234848
|
+
(奕璇 2026-09-22 的判据)。连它自己那一段跑挂了(`failedRun` ⇒ `phase: "stuck"`)也一样,
|
|
234849
|
+
那时按 `segmentOpen` 走暖橙——真要人动手的是它升级出去的那张升级卡,红归那一张。
|
|
234850
|
+
显式写 `false` 而不是省略:省略 = 不表态,前端会退回老规则(`stuck` + 开着 ⇒ 砖红)。 */
|
|
234851
|
+
awaitingHuman: false,
|
|
234852
|
+
status: resolvedAt ? ACTIVITY_COPY.coordinatorFixedGap(nameOf(coordinatorId), nameOf(executorId)) : escalated ? ACTIVITY_COPY.coordinatorEscalated(nameOf(coordinatorId), name, nameOf(recipient)) : failedRun ? ACTIVITY_COPY.coordinatorFailed(name) : ACTIVITY_COPY.coordinatingGap(nameOf(coordinatorId), name),
|
|
234214
234853
|
artifacts: [],
|
|
234215
|
-
/* 点进去 = **这段协调轨迹**(run 在 `agent_runs` 里,`runId` 直接给)+ 缺口线。
|
|
234216
|
-
|
|
234217
|
-
runId: run.id,
|
|
234218
|
-
actions:
|
|
234219
|
-
}
|
|
234854
|
+
/* 点进去 = **这段协调轨迹**(run 在 `agent_runs` 里,`runId` 直接给)+ 缺口线。
|
|
234855
|
+
查不到那一段运行 ⇒ 不给轨迹入口,卡与那颗「查看留言」照旧。 */
|
|
234856
|
+
...run ? { traceAvailable: true, runId: run.id } : {},
|
|
234857
|
+
actions: [{ kind: "open_thread", label: BUTTON.view, target: gapThreadSessionId(executorId) }]
|
|
234858
|
+
};
|
|
234859
|
+
coordinatorCards.push(draft);
|
|
234860
|
+
if (resolvedAt) gapsClosedByCoordinatorCard.add(gapId);
|
|
234220
234861
|
}
|
|
234221
234862
|
}
|
|
234222
|
-
for (const
|
|
234863
|
+
for (const issueId of [...issueCards.keys()]) {
|
|
234223
234864
|
if (!issueId.startsWith(REWORK_ANNOTATION_PREFIX)) continue;
|
|
234224
|
-
|
|
234225
|
-
if (covered) issueCards.delete(issueId);
|
|
234865
|
+
if (gapsClosedByCoordinatorCard.has(issueId.slice(REWORK_ANNOTATION_PREFIX.length))) issueCards.delete(issueId);
|
|
234226
234866
|
}
|
|
234227
234867
|
const lastFailureOf = (card2, trip) => {
|
|
234228
234868
|
const message = (input.runFailures ?? []).filter((f2) => f2.nodeId === card2.nodeId && f2.startedAt >= card2.at && f2.startedAt <= trip.at && f2.message.trim()).sort((a, b2) => a.startedAt.localeCompare(b2.startedAt)).at(-1)?.message;
|
|
@@ -234349,6 +234989,7 @@ function buildWorkorderActivity(input) {
|
|
|
234349
234989
|
d.phase = "done";
|
|
234350
234990
|
delete d.phaseLabel;
|
|
234351
234991
|
d.segmentOpen = false;
|
|
234992
|
+
d.awaitingHuman = false;
|
|
234352
234993
|
d.status = ACTIVITY_COPY.closedNoAction(terminal);
|
|
234353
234994
|
if (!d.commentIssueIds) d.actions = [];
|
|
234354
234995
|
}
|
|
@@ -234417,6 +235058,7 @@ function buildWorkorderActivity(input) {
|
|
|
234417
235058
|
phase: d.phase,
|
|
234418
235059
|
...d.phaseLabel ? { phaseLabel: d.phaseLabel } : {},
|
|
234419
235060
|
...d.segmentOpen === void 0 ? {} : { segmentOpen: d.segmentOpen },
|
|
235061
|
+
...d.awaitingHuman === void 0 ? {} : { awaitingHuman: d.awaitingHuman },
|
|
234420
235062
|
...d.escalationKind ? { escalationKind: d.escalationKind } : {},
|
|
234421
235063
|
...d.noticeTitle ? { noticeTitle: d.noticeTitle } : {},
|
|
234422
235064
|
status: d.status,
|
|
@@ -234434,7 +235076,7 @@ function buildWorkorderActivity(input) {
|
|
|
234434
235076
|
cards.sort((a, b2) => a.at.localeCompare(b2.at) || a.seq - b2.seq || a.id.localeCompare(b2.id));
|
|
234435
235077
|
return { workorderId, cards, truncated };
|
|
234436
235078
|
}
|
|
234437
|
-
var ACTIVITY_EVENT_KINDS, LEGACY_PAUSE_REASON, ACTIVITY_EVENT_LIMIT, UPSTREAM_ACK_NOTE_CAP, ACTIVITY_COPY, REWORK_ANNOTATION_PREFIX, RECOVERY_ANNOTATION_PREFIX, ENGINE_RETRY_EXHAUSTED, BUTTON, PHASE_LABEL, COORDINATOR_CARD_PREFIX, RETRY_EXHAUSTED_ESC_PREFIX, isStopLoss;
|
|
235079
|
+
var ACTIVITY_EVENT_KINDS, LEGACY_PAUSE_REASON, ACTIVITY_EVENT_LIMIT, UPSTREAM_ACK_NOTE_CAP, ACTIVITY_COPY, REWORK_ANNOTATION_PREFIX, RECOVERY_ANNOTATION_PREFIX, ENGINE_RETRY_EXHAUSTED, BUTTON, PHASE_LABEL, COORDINATOR_CARD_PREFIX, coordinatorCardId, RETRY_EXHAUSTED_ESC_PREFIX, REVIEW_EXHAUSTED_ESC_PREFIX2, isStopLoss;
|
|
234438
235080
|
var init_activity2 = __esm({
|
|
234439
235081
|
"../server/src/domains/collab/activity.ts"() {
|
|
234440
235082
|
"use strict";
|
|
@@ -234567,9 +235209,10 @@ var init_activity2 = __esm({
|
|
|
234567
235209
|
改完之后两种止损的**执行者是一样的**(执行卡挂执行人、升级卡挂等处理的那个人),
|
|
234568
235210
|
能不能分辨全落在这几句话上。投影侧怎么判是哪一种见 {@link escalationKindOf}。
|
|
234569
235211
|
次数与花费**取上报正文里系统自己算出来的那个数**(引擎 `activate.ts` 的 `连续 N 次执行失败`、
|
|
234570
|
-
serve `zero-output-breaker.ts` 的 `跑了 N
|
|
234571
|
-
|
|
234572
|
-
|
|
235212
|
+
serve `zero-output-breaker.ts` 的 `跑了 N 轮 … 约 $X`)——本投影手上没有第二份可信来源,
|
|
235213
|
+
上报正文是唯一事实源(奕璇 2026-09-22 定)。两头的口径都已经是**轮**:引擎那条本来就数
|
|
235214
|
+
work,保险丝那条 Bug 0211 起把同一轮里的协议续唤 run 折回去再数(老正文不回填,见
|
|
235215
|
+
{@link parseStopLossFacts})。 */
|
|
234573
235216
|
retryExhausted: (executor, node2, n, lastReason) => `${executor} \u8FDE\u7EED ${n} \u6B21\u6CA1\u8DD1\u6210\u300A${node2}\u300B\uFF0C\u91CD\u8BD5\u5DF2\u7528\u5C3D${lastReason ? `\uFF08\u672B\u6B21\uFF1A${lastReason}\uFF09` : ""}\u3002`,
|
|
234574
235217
|
outputStalled: (executor, node2, n, cost) => `${executor} \u8FDE\u7EED ${n} \u6B21\u6CA1\u4EA4\u51FA\u300A${node2}\u300B\u7684\u4EFB\u4F55\u6210\u679C${cost ? `\uFF08\u7EA6 ${cost}\uFF09` : ""}\uFF0C\u7CFB\u7EDF\u5DF2\u6B62\u635F\u3002`,
|
|
234575
235218
|
/* ── 升级卡(上报)的整句 ───────────────────────────────────────────────────────────
|
|
@@ -234578,6 +235221,16 @@ var init_activity2 = __esm({
|
|
|
234578
235221
|
同一件事,只换后半句(「等 @X 处理」→「X 已处理:…」)。 */
|
|
234579
235222
|
escalationHeadRetryExhausted: (node2) => `\u300A${node2}\u300B\u91CD\u8BD5\u5DF2\u7528\u5C3D\uFF0C`,
|
|
234580
235223
|
escalationHeadOutputStall: (node2) => `\u7CFB\u7EDF\u6B62\u635F\uFF1A\u300A${node2}\u300B\u505C\u4F4F\u4E86\uFF0C`,
|
|
235224
|
+
/**
|
|
235225
|
+
* 评审连败熔断(Bug 0212):卡住的是**这一轮评审**,不是那一版活——话不能写成「执行异常」。
|
|
235226
|
+
*
|
|
235227
|
+
* 🚨 **这里没有「(末次:…)」**,与连败熔断卡不同:报错原话只在 `agent_runs.error_message`,
|
|
235228
|
+
* 而**评审派发的 run 行 `node_id` 与 `work_order_id` 双双为 null**(v2 `ws:wo-65841524` 实测:
|
|
235229
|
+
* qa-quality 连败那 4 条只有 `artifact_id`)——`listRunFailures` 按 `work_order_id` 圈范围,
|
|
235230
|
+
* 这批行根本取不到。硬拼一句取不到值的模板只会永远不出现,不如不写。
|
|
235231
|
+
* 要补这半句,得先让评审派发把 `work_order_id` / `node_id` 记进 `agent_runs`(另开单)。
|
|
235232
|
+
*/
|
|
235233
|
+
escalationHeadReviewExhausted: (node2) => `\u300A${node2}\u300B\u7684\u8BC4\u5BA1\u8FDE\u7740\u6CA1\u8DD1\u6210\uFF0C\u8FD9\u4E00\u8F6E\u6536\u4E0D\u9F50\uFF0C`,
|
|
234581
235234
|
/** 人工上报里**关联着缺口**的那一档:协调者接了缺口、补不了,于是升级给人(四种停法的第二种)。 */
|
|
234582
235235
|
escalationHeadGapEscalated: (coordinator, node2) => `${coordinator} \u8865\u4E0D\u4E86\u300A${node2}\u300B\u7684\u7F3A\u53E3\uFF0C`,
|
|
234583
235236
|
/** 其余人工上报:主语是卡住的那个执行人(异常是它的,不是上报作者的)。 */
|
|
@@ -234593,6 +235246,8 @@ var init_activity2 = __esm({
|
|
|
234593
235246
|
/** 「你要做什么」那半句——两种系统止损各一份(F6 的立论就在这里:执行者一样,只有话不一样)。 */
|
|
234594
235247
|
escalationHowToRetryExhausted: "\u5904\u7406\u5E76\u5173\u6389\u8FD9\u6761\u4E0A\u62A5\u540E\uFF0C\u8FD9\u4E00\u6B65\u4F1A\u81EA\u52A8\u91CD\u8BD5\uFF1B\u591A\u534A\u662F\u989D\u5EA6 / \u767B\u5F55\u8FC7\u671F / \u9650\u6D41\u8FD9\u7C7B\u73AF\u5883\u95EE\u9898\uFF0C\u5148\u770B\u8F68\u8FF9\u518D\u51B3\u5B9A\u91CD\u8BD5\u3002",
|
|
234595
235248
|
escalationHowToOutputStall: "\u5904\u7406\u5E76\u5173\u6389\u8FD9\u6761\u4E0A\u62A5\u540E\uFF0C\u8FD9\u4E00\u6B65\u4F1A\u81EA\u52A8\u91CD\u8BD5\uFF1B\u4E0D\u67E5\u6E05\u539F\u56E0\u5C31\u91CD\u8BD5\u4F1A\u7EE7\u7EED\u7A7A\u70E7\uFF0C\u5148\u8FDB\u8BA8\u8BBA\u623F\u3002",
|
|
235249
|
+
/** 评审熔断那一份:关掉之后重开的是**评审**,不是这一步的活(活已经交了,等的是审)。 */
|
|
235250
|
+
escalationHowToReviewExhausted: "\u5904\u7406\u5E76\u5173\u6389\u8FD9\u6761\u4E0A\u62A5\u540E\uFF0C\u8FD9\u4E00\u8F6E\u8BC4\u5BA1\u4F1A\u81EA\u52A8\u91CD\u5F00\uFF1B\u591A\u534A\u662F\u8BC4\u5BA1\u5458\u7684\u8FD0\u884C\u73AF\u5883\u51FA\u4E86\u95EE\u9898\uFF08\u989D\u5EA6 / \u767B\u5F55\u8FC7\u671F / \u9650\u6D41\uFF09\uFF0C\u5148\u770B\u8F68\u8FF9\u518D\u51B3\u5B9A\u3002",
|
|
234596
235251
|
/** 关掉了:接着开头那半句说「谁处理的、怎么处理的」。没写处置说明就只说「已处理」。
|
|
234597
235252
|
* 处置说明常常是人自己写的一整段、末尾自带句号——**别再补一个**,否则卡面收在「。。」上。 */
|
|
234598
235253
|
escalationHandled: (head, by, note) => `${head}${by} \u5DF2\u5904\u7406${note ? `\uFF1A${note}` : ""}${note && /[。!?.!?]$/.test(note) ? "" : "\u3002"}`,
|
|
@@ -234601,15 +235256,20 @@ var init_activity2 = __esm({
|
|
|
234601
235256
|
* ——人并没有写说明,说明是这颗按钮替他写的。次数是**这个节点上第几次这么重试**。
|
|
234602
235257
|
*/
|
|
234603
235258
|
escalationRerun: (by, n) => `${by} \u91CD\u65B0\u8FD0\u884C\u4E86\u8FD9\u4E00\u6B65\uFF08\u7B2C ${n} \u6B21\u91CD\u8BD5\uFF09\u3002`,
|
|
234604
|
-
/* ── 协调者卡(F2
|
|
234605
|
-
|
|
234606
|
-
|
|
234607
|
-
|
|
235259
|
+
/* ── 协调者卡(F2)──────────────────────────────────────────────────────────────────
|
|
235260
|
+
「协调者处理**某条缺口**的那一段」。三句话对应缺口的三种去向(已补齐 / 补不了升级给人 /
|
|
235261
|
+
还开着),判据全在缺口这条 issue 上,不看旁账那条 `coordinate:` 运行有没有留下结论
|
|
235262
|
+
(Bug 0213;前两句 T-104 / T-113 已验收,逐字不动)。 */
|
|
235263
|
+
coordinatingGap: (coordinator, node2) => `${coordinator} \u6B63\u5728\u5904\u7406\u300A${node2}\u300B\u7684\u7F3A\u53E3\u3002`,
|
|
234608
235264
|
coordinatorFixedGap: (coordinator, executor) => `${coordinator} \u5DF2\u8865\u9F50\u7F3A\u53E3\uFF0C${executor} \u7EE7\u7EED\u6267\u884C\u3002`,
|
|
234609
235265
|
coordinatorEscalated: (coordinator, node2, target) => `${coordinator} \u8865\u4E0D\u4E86\u300A${node2}\u300B\u7684\u7F3A\u53E3\uFF0C\u5DF2\u5347\u7EA7\u7ED9 @${target} \u5904\u7406\u3002`,
|
|
234610
|
-
/**
|
|
234611
|
-
|
|
234612
|
-
|
|
235266
|
+
/**
|
|
235267
|
+
* 缺口还开着、也没升级给人,而这一段协调运行已经结束且没跑成(failed / orphaned / timeout)——
|
|
235268
|
+
* 如实说这一轮没跑成,别说「正在处理」(没人在处理),也别替它宣布一个没发生的结局。
|
|
235269
|
+
*
|
|
235270
|
+
* 🚨 兜底句「{协调者} 处理《X》的缺口,这一段没有结论」**已删**(Bug 0213):那句是拿 run 的结论
|
|
235271
|
+
* 拼卡时的产物——取不到结论就替这一段下一个空结论。缺口自己的状态永远答得出「补上了没有」。
|
|
235272
|
+
*/
|
|
234613
235273
|
coordinatorFailed: (node2) => `\u5904\u7406\u300A${node2}\u300B\u7684\u7F3A\u53E3\u65F6\u8FD9\u4E00\u8F6E\u6CA1\u8DD1\u6210\u3002`,
|
|
234614
235274
|
/**
|
|
234615
235275
|
* 这一轮**被计划变更打断**(P15)。与卡点中断同级:计划一动,这一轮就不再是「还在跑」,
|
|
@@ -234724,7 +235384,7 @@ var init_activity2 = __esm({
|
|
|
234724
235384
|
*
|
|
234725
235385
|
* 此前走 `issueOpen`:正文整段当小状态,`detail` 又是同一段。全库实测最长
|
|
234726
235386
|
* **8096 字印两遍**(`ws:wo-56bba3c1`),一张卡顶掉整屏。正文的去处是「留言线」——
|
|
234727
|
-
* 与缺口线同一套投影(`gap-thread.ts` 的 `buildCommentThread
|
|
235387
|
+
* 与缺口线同一套投影(`gap-thread.ts` 的 `buildCommentThread`),卡上给「查看留言」。
|
|
234728
235388
|
*/
|
|
234729
235389
|
commentRaised: (author, target, node2) => `${author} \u5728\u300A${node2}\u300B\u7559\u8A00\uFF0C\u9700\u8981 @${target} \u67E5\u770B\u3002`,
|
|
234730
235390
|
/* ── 普通留言卡(奕璇 2026-09-18 定,ADR 0594)────────────────────────────────────────
|
|
@@ -234766,9 +235426,17 @@ var init_activity2 = __esm({
|
|
|
234766
235426
|
acceptPass: "\u9A8C\u6536\u901A\u8FC7",
|
|
234767
235427
|
acceptFail: "\u9A8C\u6536\u4E0D\u901A\u8FC7",
|
|
234768
235428
|
handle: "\u53BB\u5904\u7406",
|
|
234769
|
-
|
|
234770
|
-
|
|
234771
|
-
|
|
235429
|
+
/**
|
|
235430
|
+
* **只读进房**那一档:留言线、缺口线(执行人 ↔ 协调者)、上报讨论房(旁观者 / 已关掉)共用这一个词。
|
|
235431
|
+
*
|
|
235432
|
+
* 2026-09-22 奕璇拍板把旧的两个名字**并成一个**:缺口线那两处原来写「去缺口线」
|
|
235433
|
+
* (`BUTTON.gapThread`),其余只读入口原来写「去查看」——三处点进去做的是同一件事:
|
|
235434
|
+
* **进这条线看聊天记录**,用户视角没有第二、第三个名字。目标(`open_thread` /
|
|
235435
|
+
* `discuss_escalation` 与 target)一个字没动,只是不再自造第二个词。
|
|
235436
|
+
* 于是卡上只剩三种按钮:「去处理」(等人动手)、「查看留言」(只读进房)、
|
|
235437
|
+
* 「重新运行」(连败熔断升级卡的主按钮)。
|
|
235438
|
+
*/
|
|
235439
|
+
view: "\u67E5\u770B\u7559\u8A00",
|
|
234772
235440
|
/** 连败熔断升级卡的主按钮(F7):重开这一步,并把那条上报一并关掉。 */
|
|
234773
235441
|
rerun: "\u91CD\u65B0\u8FD0\u884C"
|
|
234774
235442
|
};
|
|
@@ -234781,8 +235449,10 @@ var init_activity2 = __esm({
|
|
|
234781
235449
|
escalationInProgress: "\u5904\u7406\u4E2D"
|
|
234782
235450
|
};
|
|
234783
235451
|
COORDINATOR_CARD_PREFIX = "coordinator:";
|
|
235452
|
+
coordinatorCardId = (gapId) => `${COORDINATOR_CARD_PREFIX}${gapId}`;
|
|
234784
235453
|
RETRY_EXHAUSTED_ESC_PREFIX = "esc:retry-exhausted:";
|
|
234785
|
-
|
|
235454
|
+
REVIEW_EXHAUSTED_ESC_PREFIX2 = "esc:review-exhausted:";
|
|
235455
|
+
isStopLoss = (kind) => kind === "retry_exhausted" || kind === "output_stall";
|
|
234786
235456
|
}
|
|
234787
235457
|
});
|
|
234788
235458
|
|
|
@@ -234800,10 +235470,12 @@ function buildWorkorderActivityTrace(input) {
|
|
|
234800
235470
|
const reviews = activityReviews(snap, input.events ?? []);
|
|
234801
235471
|
const reviewTarget = reviewCardTarget(cardId, reviews);
|
|
234802
235472
|
if (reviewTarget) return buildReviewHistory(input, reviewTarget.targetWorkId, reviewTarget.reviewerActorId, reviews);
|
|
234803
|
-
|
|
234804
|
-
|
|
234805
|
-
const
|
|
234806
|
-
|
|
235473
|
+
const coordinatorGapId = coordinatorCardGapId(cardId);
|
|
235474
|
+
if (coordinatorGapId !== void 0) {
|
|
235475
|
+
const gap2 = snap.issues.find((i) => i.id === coordinatorGapId && i.kind === "gap");
|
|
235476
|
+
const gapNodeId = gap2 ? gap2.aboutNodeId ?? gap2.raisedByNodeId : null;
|
|
235477
|
+
const run = gap2 && gapNodeId ? coordinatorRunOfGap(gap2, (input.coordinatorRuns ?? []).filter((r) => r.nodeId === gapNodeId)) : void 0;
|
|
235478
|
+
if (!run) return { ...empty2, notice: "\u534F\u8C03\u8005\u5904\u7406\u8FD9\u6761\u7F3A\u53E3\u7684\u90A3\u4E00\u6BB5\u6CA1\u6709\u7559\u4E0B\u8FD0\u884C\u8BB0\u5F55\uFF0C\u6682\u65F6\u65E0\u6CD5\u786E\u8BA4\u8FD0\u884C\u8F68\u8FF9\u3002" };
|
|
234807
235479
|
const node2 = snap.nodes.find((n) => n.id === run.nodeId);
|
|
234808
235480
|
const spec = node2?.spec?.trim();
|
|
234809
235481
|
return {
|
|
@@ -235080,11 +235752,14 @@ var init_activity_trace = __esm({
|
|
|
235080
235752
|
});
|
|
235081
235753
|
|
|
235082
235754
|
// ../server/src/domains/collab/inbox.ts
|
|
235755
|
+
function commandCardLine(command2) {
|
|
235756
|
+
return command2.displayLabel?.trim() || stripInternalIds(command2.effectLabel ?? "");
|
|
235757
|
+
}
|
|
235083
235758
|
function changeConfirmSummary(r) {
|
|
235084
235759
|
if (r.continuation) return `\u81EA\u52A8\u7EED\u8DD1\u5DF2\u5230\u9650\uFF0C\u7B49\u5F85\u4F60\u5BA1\u6838\uFF1A${r.plan.reason}`;
|
|
235085
235760
|
const why = r.plan.reason.slice(0, 100);
|
|
235086
235761
|
if (r.kind === "command" && r.command) {
|
|
235087
|
-
return `\u7BA1\u7406\u8005\u8BF7\u6C42\u6267\u884C\u4E00\u4E2A\u9AD8\u5371\u64CD\u4F5C\uFF0C\u7B49\u4F60\u6388\u6743\uFF1A${r.command
|
|
235762
|
+
return `\u7BA1\u7406\u8005\u8BF7\u6C42\u6267\u884C\u4E00\u4E2A\u9AD8\u5371\u64CD\u4F5C\uFF0C\u7B49\u4F60\u6388\u6743\uFF1A${commandCardLine(r.command)}`;
|
|
235088
235763
|
}
|
|
235089
235764
|
const ops = r.plan.ops ?? [];
|
|
235090
235765
|
if (ops.length > 0 && ops.every((o) => o.action === "resolveEscalation")) {
|
|
@@ -235260,7 +235935,7 @@ function buildInbox(model, me, leadOf, resolveActor, markers = [], slaMs, nowIso
|
|
|
235260
235935
|
// 仍回落工单详情。
|
|
235261
235936
|
...r.origin ? { chatSessionId: r.origin } : {},
|
|
235262
235937
|
...anchorArt ? { title: nodeLabel(anchorArt) } : {},
|
|
235263
|
-
detail: `${actorName(r.proposedBy) || "\u7BA1\u7406\u8005"}\uFF1A${r.command
|
|
235938
|
+
detail: `${actorName(r.proposedBy) || "\u7BA1\u7406\u8005"}\uFF1A${r.command ? commandCardLine(r.command) : firstSentence2(r.plan.reason)}`,
|
|
235264
235939
|
...r.kind !== "command" && opCount > 0 ? { impact: `\u6D89\u53CA ${opCount} \u5904\u6539\u52A8${r.nonMonotonicOps.length > 0 ? " \xB7 \u542B\u9500\u6BC1\u6027" : ""}` } : {},
|
|
235265
235940
|
actor: actorRef2(r.proposedBy),
|
|
235266
235941
|
...overdueField(r.at)
|
|
@@ -235482,6 +236157,15 @@ function backfillInboxUnread(items, markers) {
|
|
|
235482
236157
|
item.unread = !Number.isFinite(effective) ? true : sinceMs > effective;
|
|
235483
236158
|
}
|
|
235484
236159
|
}
|
|
236160
|
+
function applyReadAllWatermark(items, markers) {
|
|
236161
|
+
const at = markers.find((m2) => m2.scope === INBOX_READ_ALL_SCOPE)?.readAt;
|
|
236162
|
+
const atMs = at ? Date.parse(at) : Number.NaN;
|
|
236163
|
+
if (!Number.isFinite(atMs)) return;
|
|
236164
|
+
for (const item of items) {
|
|
236165
|
+
const sinceMs = Date.parse(item.since);
|
|
236166
|
+
if (Number.isFinite(sinceMs) && sinceMs <= atMs) item.unread = false;
|
|
236167
|
+
}
|
|
236168
|
+
}
|
|
235485
236169
|
var C_ACTION_LABEL;
|
|
235486
236170
|
var init_inbox = __esm({
|
|
235487
236171
|
"../server/src/domains/collab/inbox.ts"() {
|
|
@@ -236060,6 +236744,16 @@ var init_notification_store = __esm({
|
|
|
236060
236744
|
}
|
|
236061
236745
|
if (changed) this.save();
|
|
236062
236746
|
}
|
|
236747
|
+
async markAllRead(recipient, at) {
|
|
236748
|
+
let n = 0;
|
|
236749
|
+
for (const [id, r] of this.rows) {
|
|
236750
|
+
if (r.recipient !== recipient || r.readAt) continue;
|
|
236751
|
+
this.rows.set(id, { ...r, readAt: at });
|
|
236752
|
+
n++;
|
|
236753
|
+
}
|
|
236754
|
+
if (n > 0) this.save();
|
|
236755
|
+
return n;
|
|
236756
|
+
}
|
|
236063
236757
|
async countUnread(recipient) {
|
|
236064
236758
|
let pending = 0;
|
|
236065
236759
|
let all2 = 0;
|
|
@@ -236250,6 +236944,13 @@ var init_notification_store = __esm({
|
|
|
236250
236944
|
[recipient, [...ids2], at]
|
|
236251
236945
|
);
|
|
236252
236946
|
}
|
|
236947
|
+
async markAllRead(recipient, at) {
|
|
236948
|
+
const r = await this.sql.query(
|
|
236949
|
+
`UPDATE ${this.t} SET read_at = $2::timestamptz WHERE recipient = $1 AND read_at IS NULL`,
|
|
236950
|
+
[recipient, at]
|
|
236951
|
+
);
|
|
236952
|
+
return r.rowCount ?? 0;
|
|
236953
|
+
}
|
|
236253
236954
|
async countUnread(recipient) {
|
|
236254
236955
|
const r = await this.sql.query(
|
|
236255
236956
|
`SELECT count(*) FILTER (WHERE status = 'pending')::int AS pending, count(*)::int AS "all"
|
|
@@ -236780,7 +237481,7 @@ var init_workorder_metrics = __esm({
|
|
|
236780
237481
|
});
|
|
236781
237482
|
|
|
236782
237483
|
// ../server/src/domains/usage/statistics-model.ts
|
|
236783
|
-
var UsageQueryError;
|
|
237484
|
+
var UsageQueryError, ZERO_USAGE_AMOUNT;
|
|
236784
237485
|
var init_statistics_model = __esm({
|
|
236785
237486
|
"../server/src/domains/usage/statistics-model.ts"() {
|
|
236786
237487
|
"use strict";
|
|
@@ -236791,6 +237492,13 @@ var init_statistics_model = __esm({
|
|
|
236791
237492
|
this.name = "UsageQueryError";
|
|
236792
237493
|
}
|
|
236793
237494
|
};
|
|
237495
|
+
ZERO_USAGE_AMOUNT = {
|
|
237496
|
+
tokens: { input: 0, cache: 0, cacheRead: 0, cacheCreation: 0, output: 0, total: 0 },
|
|
237497
|
+
costUsdMicros: 0,
|
|
237498
|
+
costParts: { input: 0, cacheRead: 0, cacheCreation: 0, output: 0, unsplit: 0 },
|
|
237499
|
+
costKnown: "full",
|
|
237500
|
+
costUnknownTokens: 0
|
|
237501
|
+
};
|
|
236794
237502
|
}
|
|
236795
237503
|
});
|
|
236796
237504
|
|
|
@@ -236999,6 +237707,16 @@ function effectivePoints(run) {
|
|
|
236999
237707
|
}
|
|
237000
237708
|
return points;
|
|
237001
237709
|
}
|
|
237710
|
+
function ledgerRunModel(run) {
|
|
237711
|
+
const onRow = resolvedModel(run.effectiveModel);
|
|
237712
|
+
if (onRow) return onRow;
|
|
237713
|
+
let best = null;
|
|
237714
|
+
for (const p2 of run.points) {
|
|
237715
|
+
const m2 = resolvedModel(p2.model);
|
|
237716
|
+
if (m2 && (!best || p2.seq < best.seq)) best = { seq: p2.seq, model: m2 };
|
|
237717
|
+
}
|
|
237718
|
+
return best?.model ?? null;
|
|
237719
|
+
}
|
|
237002
237720
|
function distribute(total, weights) {
|
|
237003
237721
|
const sum = weights.reduce((s2, w2) => s2 + w2, 0);
|
|
237004
237722
|
if (sum <= 0) return weights.map(() => 0);
|
|
@@ -237166,6 +237884,11 @@ function bucketIndex(starts, ms) {
|
|
|
237166
237884
|
}
|
|
237167
237885
|
return ans;
|
|
237168
237886
|
}
|
|
237887
|
+
function pushView(map, key2, v2) {
|
|
237888
|
+
const list2 = map.get(key2);
|
|
237889
|
+
if (list2) list2.push(v2);
|
|
237890
|
+
else map.set(key2, [v2]);
|
|
237891
|
+
}
|
|
237169
237892
|
function getCell(map, key2) {
|
|
237170
237893
|
let c = map.get(key2);
|
|
237171
237894
|
if (!c) {
|
|
@@ -237336,14 +238059,15 @@ function runtimeRows(facts, relations) {
|
|
|
237336
238059
|
if (!v2.relevant) continue;
|
|
237337
238060
|
const key2 = keyOf4(v2.run.runtimeInstanceId, v2.run.runtimeKind);
|
|
237338
238061
|
getCell(cells, key2).addView(v2);
|
|
237339
|
-
modelsOf(key2).cell(v2.run
|
|
238062
|
+
modelsOf(key2).cell(ledgerRunModel(v2.run)).addView(v2);
|
|
237340
238063
|
}
|
|
237341
238064
|
for (const r of facts.rounds) {
|
|
237342
238065
|
const key2 = keyOf4(r.runtimeInstanceId, r.runtimeKind);
|
|
237343
238066
|
const c = getCell(cells, key2);
|
|
237344
238067
|
c.active = true;
|
|
237345
238068
|
c.runCount += 1;
|
|
237346
|
-
const
|
|
238069
|
+
const firstRun = runById.get(r.firstRunId);
|
|
238070
|
+
const m2 = modelsOf(key2).cell(firstRun ? ledgerRunModel(firstRun) : null);
|
|
237347
238071
|
m2.active = true;
|
|
237348
238072
|
m2.runCount += 1;
|
|
237349
238073
|
}
|
|
@@ -237403,12 +238127,15 @@ function attributed(facts, relations) {
|
|
|
237403
238127
|
const taskCells = /* @__PURE__ */ new Map();
|
|
237404
238128
|
const taskActorCells = /* @__PURE__ */ new Map();
|
|
237405
238129
|
const convSessionCells = /* @__PURE__ */ new Map();
|
|
238130
|
+
const convViews = /* @__PURE__ */ new Map();
|
|
238131
|
+
const taskViews = /* @__PURE__ */ new Map();
|
|
237406
238132
|
const unlinked = new Cell();
|
|
237407
238133
|
for (const v2 of facts.views) {
|
|
237408
238134
|
if (!v2.relevant) continue;
|
|
237409
238135
|
const attr = runAttribution(relations, v2.run, memo);
|
|
237410
238136
|
if (attr.kind === "task") {
|
|
237411
238137
|
getCell(taskCells, attr.workorderId).addView(v2);
|
|
238138
|
+
pushView(taskViews, attr.workorderId, v2);
|
|
237412
238139
|
let byActor2 = taskActorCells.get(attr.workorderId);
|
|
237413
238140
|
if (!byActor2) {
|
|
237414
238141
|
byActor2 = /* @__PURE__ */ new Map();
|
|
@@ -237422,6 +238149,7 @@ function attributed(facts, relations) {
|
|
|
237422
238149
|
convSessionCells.set(attr.rootSessionId, bySession);
|
|
237423
238150
|
}
|
|
237424
238151
|
getCell(bySession, attr.sessionId).addView(v2);
|
|
238152
|
+
pushView(convViews, attr.rootSessionId, v2);
|
|
237425
238153
|
} else unlinked.addView(v2);
|
|
237426
238154
|
}
|
|
237427
238155
|
const taskAmount = /* @__PURE__ */ new Map();
|
|
@@ -237453,8 +238181,13 @@ function attributed(facts, relations) {
|
|
|
237453
238181
|
}
|
|
237454
238182
|
const conversations = [];
|
|
237455
238183
|
const convGroupAcc = /* @__PURE__ */ new Map();
|
|
238184
|
+
const treeViews = /* @__PURE__ */ new Map();
|
|
237456
238185
|
for (const rootId of /* @__PURE__ */ new Set([...convSessionCells.keys(), ...tasksByRoot.keys()])) {
|
|
237457
238186
|
const root = relations.sessions.get(rootId);
|
|
238187
|
+
treeViews.set(rootId, [
|
|
238188
|
+
...convViews.get(rootId) ?? [],
|
|
238189
|
+
...(tasksByRoot.get(rootId) ?? []).flatMap((workorderId) => taskViews.get(workorderId) ?? [])
|
|
238190
|
+
]);
|
|
237458
238191
|
const group = new Cell();
|
|
237459
238192
|
const rows = [];
|
|
237460
238193
|
const sessionRows = [];
|
|
@@ -237576,9 +238309,83 @@ function attributed(facts, relations) {
|
|
|
237576
238309
|
{ amount: a.amount, name: a.name, id: a.projectId ?? "" },
|
|
237577
238310
|
{ amount: b2.amount, name: b2.name, id: b2.projectId ?? "" }
|
|
237578
238311
|
));
|
|
237579
|
-
return { conversations, tasks, projects };
|
|
238312
|
+
return { conversations, tasks, projects, treeViews };
|
|
238313
|
+
}
|
|
238314
|
+
function deriveTreeDuration(views, now) {
|
|
238315
|
+
const nowMs = now.getTime();
|
|
238316
|
+
const spans = [];
|
|
238317
|
+
let countedRuns = 0;
|
|
238318
|
+
let unstartedRuns = 0;
|
|
238319
|
+
let inProgress = false;
|
|
238320
|
+
let firstMs = Infinity;
|
|
238321
|
+
let lastMs = -Infinity;
|
|
238322
|
+
let runtimeMs = 0;
|
|
238323
|
+
for (const v2 of views) {
|
|
238324
|
+
const startMs = v2.run.runtimeStartedAt ? Date.parse(v2.run.runtimeStartedAt) : NaN;
|
|
238325
|
+
if (!Number.isFinite(startMs)) {
|
|
238326
|
+
unstartedRuns += 1;
|
|
238327
|
+
continue;
|
|
238328
|
+
}
|
|
238329
|
+
const endedMs = v2.run.endedAt ? Date.parse(v2.run.endedAt) : NaN;
|
|
238330
|
+
const running = !Number.isFinite(endedMs) && !isRunEnded(v2.run);
|
|
238331
|
+
if (running) inProgress = true;
|
|
238332
|
+
const rawEnd = Number.isFinite(endedMs) ? endedMs : running ? nowMs : startMs;
|
|
238333
|
+
const end = Math.max(rawEnd, startMs);
|
|
238334
|
+
countedRuns += 1;
|
|
238335
|
+
runtimeMs += end - startMs;
|
|
238336
|
+
spans.push({ start: startMs, end });
|
|
238337
|
+
if (startMs < firstMs) firstMs = startMs;
|
|
238338
|
+
if (end > lastMs) lastMs = end;
|
|
238339
|
+
}
|
|
238340
|
+
if (countedRuns === 0) return { ...ZERO_DURATION, unstartedRuns };
|
|
238341
|
+
spans.sort((a, b2) => a.start - b2.start || a.end - b2.end);
|
|
238342
|
+
let activeMs = 0;
|
|
238343
|
+
let curStart = spans[0].start;
|
|
238344
|
+
let curEnd = spans[0].end;
|
|
238345
|
+
for (const span of spans.slice(1)) {
|
|
238346
|
+
if (span.start > curEnd) {
|
|
238347
|
+
activeMs += curEnd - curStart;
|
|
238348
|
+
curStart = span.start;
|
|
238349
|
+
curEnd = span.end;
|
|
238350
|
+
} else if (span.end > curEnd) curEnd = span.end;
|
|
238351
|
+
}
|
|
238352
|
+
activeMs += curEnd - curStart;
|
|
238353
|
+
return {
|
|
238354
|
+
firstStartedAt: new Date(firstMs).toISOString(),
|
|
238355
|
+
lastEndedAt: new Date(lastMs).toISOString(),
|
|
238356
|
+
inProgress,
|
|
238357
|
+
wallClockMs: lastMs - firstMs,
|
|
238358
|
+
runtimeMs,
|
|
238359
|
+
activeMs,
|
|
238360
|
+
countedRuns,
|
|
238361
|
+
unstartedRuns
|
|
238362
|
+
};
|
|
237580
238363
|
}
|
|
237581
|
-
|
|
238364
|
+
function buildChatSessionUsage(sessionId, input) {
|
|
238365
|
+
const facts = computeFacts(input);
|
|
238366
|
+
const lists = attributed(facts, input.relations);
|
|
238367
|
+
const attr = sessionAttribution(input.relations, sessionId, /* @__PURE__ */ new Map());
|
|
238368
|
+
const rootId = attr.kind === "conversation" ? attr.rootSessionId : sessionId;
|
|
238369
|
+
const session = input.relations.sessions.get(rootId);
|
|
238370
|
+
const group = lists.conversations.find((g2) => g2.sessionId === rootId) ?? {
|
|
238371
|
+
sessionId: rootId,
|
|
238372
|
+
title: session?.title || UNTITLED_CONVERSATION,
|
|
238373
|
+
projectId: session?.projectId ?? null,
|
|
238374
|
+
createdAt: session?.createdAt ?? null,
|
|
238375
|
+
amount: ZERO_USAGE_AMOUNT,
|
|
238376
|
+
flags: { inProgress: false, usagePending: false, costUnknownRuns: 0 },
|
|
238377
|
+
rows: []
|
|
238378
|
+
};
|
|
238379
|
+
return {
|
|
238380
|
+
companyId: input.companyId,
|
|
238381
|
+
sessionId,
|
|
238382
|
+
window: input.resolved.window,
|
|
238383
|
+
generatedAt: input.now.toISOString(),
|
|
238384
|
+
group,
|
|
238385
|
+
duration: deriveTreeDuration(lists.treeViews.get(rootId) ?? [], input.now)
|
|
238386
|
+
};
|
|
238387
|
+
}
|
|
238388
|
+
var UNKNOWN_AGENT_NAME, UNREGISTERED_RUNTIME_NAME, UNSPECIFIED_PROJECT_NAME, UNLINKED_ROW_TITLE, UNTITLED_CONVERSATION, BUCKET_KEYS, AmountAcc, FlagAcc, Cell, collator, ModelCells, ZERO_DURATION;
|
|
237582
238389
|
var init_statistics = __esm({
|
|
237583
238390
|
"../server/src/domains/usage/statistics.ts"() {
|
|
237584
238391
|
"use strict";
|
|
@@ -237586,6 +238393,7 @@ var init_statistics = __esm({
|
|
|
237586
238393
|
init_uncategorized_project();
|
|
237587
238394
|
init_model_pricing();
|
|
237588
238395
|
init_accounting();
|
|
238396
|
+
init_statistics_model();
|
|
237589
238397
|
UNKNOWN_AGENT_NAME = "\u672A\u77E5 Agent";
|
|
237590
238398
|
UNREGISTERED_RUNTIME_NAME = "\u672A\u767B\u8BB0\u8FD0\u884C\u65F6";
|
|
237591
238399
|
UNSPECIFIED_PROJECT_NAME = UNCATEGORIZED_PROJECT_NAME;
|
|
@@ -237704,6 +238512,16 @@ var init_statistics = __esm({
|
|
|
237704
238512
|
return [...this.cells].map(([model, c]) => ({ model, runCount: c.runCount, amount: c.amount.toAmount(), flags: c.flags.toFlags() })).filter((r) => r.runCount > 0 || r.amount.tokens.total > 0 || r.amount.costUsdMicros > 0 || r.amount.costKnown !== "full").sort((a, b2) => b2.amount.tokens.total - a.amount.tokens.total || b2.runCount - a.runCount || (a.model === null ? 1 : b2.model === null ? -1 : collator.compare(a.model, b2.model)));
|
|
237705
238513
|
}
|
|
237706
238514
|
};
|
|
238515
|
+
ZERO_DURATION = {
|
|
238516
|
+
firstStartedAt: null,
|
|
238517
|
+
lastEndedAt: null,
|
|
238518
|
+
inProgress: false,
|
|
238519
|
+
wallClockMs: null,
|
|
238520
|
+
runtimeMs: 0,
|
|
238521
|
+
activeMs: 0,
|
|
238522
|
+
countedRuns: 0,
|
|
238523
|
+
unstartedRuns: 0
|
|
238524
|
+
};
|
|
237707
238525
|
}
|
|
237708
238526
|
});
|
|
237709
238527
|
|
|
@@ -237959,6 +238777,22 @@ function createUsageReadService(deps) {
|
|
|
237959
238777
|
logRequest({ companyId, op: "breakdown", range: r.query.range, dimension, runs: r.runs.length, companyScoped: r.target.companyScoped, startedMs });
|
|
237960
238778
|
return body2;
|
|
237961
238779
|
},
|
|
238780
|
+
async conversationUsage(companyId, sessionId, raw) {
|
|
238781
|
+
const startedMs = Date.now();
|
|
238782
|
+
const loads = requestLoads(companyId);
|
|
238783
|
+
const r = await readLedger(companyId, { ...raw, range: raw.range ?? "all" }, loads);
|
|
238784
|
+
const relations = await loadRelations(companyId, loads);
|
|
238785
|
+
const body2 = buildChatSessionUsage(sessionId, {
|
|
238786
|
+
companyId,
|
|
238787
|
+
resolved: r.resolved,
|
|
238788
|
+
runs: r.runs,
|
|
238789
|
+
coverage: r.coverage,
|
|
238790
|
+
now: r.now,
|
|
238791
|
+
relations
|
|
238792
|
+
});
|
|
238793
|
+
logRequest({ companyId, op: "conversation", range: r.query.range, runs: r.runs.length, companyScoped: r.target.companyScoped, startedMs });
|
|
238794
|
+
return body2;
|
|
238795
|
+
},
|
|
237962
238796
|
async runtimeLedger(companyId, runtimeInstanceId, raw) {
|
|
237963
238797
|
const startedMs = Date.now();
|
|
237964
238798
|
const loads = requestLoads(companyId);
|
|
@@ -238936,6 +239770,7 @@ function collabDomain(opts) {
|
|
|
238936
239770
|
backfillInboxUnread(waitingItems, markers);
|
|
238937
239771
|
}
|
|
238938
239772
|
const items = mergeInbox(kernelItems, [...chatItems, ...waitingItems]);
|
|
239773
|
+
if (myReadMarkers) applyReadAllWatermark(items, markers);
|
|
238939
239774
|
return { status: 200, body: { items: myReadMarkers ? withEscalationAttention(items, req.auth.companyId ?? opts.defaultCompanyId ?? "", markers, Date.now(), opts.escalationReminders) : items } };
|
|
238940
239775
|
});
|
|
238941
239776
|
router.post("/api/inbox/escalations/:id/acknowledge", async (req) => {
|
|
@@ -239205,6 +240040,28 @@ function collabDomain(opts) {
|
|
|
239205
240040
|
await marks.markRead(me, scope2, (/* @__PURE__ */ new Date()).toISOString());
|
|
239206
240041
|
return { status: 200, body: { ok: true } };
|
|
239207
240042
|
});
|
|
240043
|
+
router.post("/api/inbox/read-all", async (req) => {
|
|
240044
|
+
const me = req.auth.actor;
|
|
240045
|
+
if (!isHumanActor(me)) {
|
|
240046
|
+
return { status: 403, body: { error: { code: "human_only", message: "\u53EA\u6709\u4EBA\u7C7B\u8EAB\u4EFD\u53EF\u4EE5\u6807\u8BB0\u5DF2\u8BFB" } } };
|
|
240047
|
+
}
|
|
240048
|
+
const marks = opts.resolveReadMarkers ? await opts.resolveReadMarkers(req.auth.companyId).catch(() => void 0) : opts.readMarkers;
|
|
240049
|
+
let ledger;
|
|
240050
|
+
if (opts.resolveNotificationLedger) {
|
|
240051
|
+
try {
|
|
240052
|
+
ledger = await opts.resolveNotificationLedger(req.auth.companyId);
|
|
240053
|
+
} catch (err) {
|
|
240054
|
+
console.warn(`[notifications] \u65E0\u53EF\u4FE1\u516C\u53F8\u4E0A\u4E0B\u6587\uFF0C\u4E0D\u6807\u5DF2\u8BFB\uFF08\u4E0D\u56DE\u843D\u9ED8\u8BA4\u516C\u53F8\uFF09: ${String(err)}`);
|
|
240055
|
+
}
|
|
240056
|
+
}
|
|
240057
|
+
if (!marks && !ledger) {
|
|
240058
|
+
return { status: 503, body: { error: { code: "unavailable", message: "\u5DF2\u8BFB\u6C34\u4F4D\u4E0E\u901A\u77E5\u53F0\u8D26\u90FD\u4E0D\u53EF\u7528" } } };
|
|
240059
|
+
}
|
|
240060
|
+
const readAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
240061
|
+
const notifications = ledger ? await ledger.markAllRead(me, readAt) : 0;
|
|
240062
|
+
if (marks) await marks.markRead(me, INBOX_READ_ALL_SCOPE, readAt);
|
|
240063
|
+
return { status: 200, body: { ok: true, readAt, notifications } };
|
|
240064
|
+
});
|
|
239208
240065
|
router.get("/api/audit", async (req) => {
|
|
239209
240066
|
const { engineStore, oplog, kernel } = await resolveCtx(req.auth.companyId);
|
|
239210
240067
|
const q2 = req.query;
|
|
@@ -241643,9 +242500,17 @@ function bucketLabelOf(slice, index2) {
|
|
|
241643
242500
|
function runtimeUsageFromLedger(runtimeInstanceId, slice) {
|
|
241644
242501
|
const rows = /* @__PURE__ */ new Map();
|
|
241645
242502
|
const runById = new Map(slice.runs.map((r) => [r.id, r]));
|
|
242503
|
+
const modelByRun = /* @__PURE__ */ new Map();
|
|
242504
|
+
const modelOf = (run) => {
|
|
242505
|
+
const hit = modelByRun.get(run.id);
|
|
242506
|
+
if (hit !== void 0) return hit;
|
|
242507
|
+
const m2 = ledgerRunModel(run);
|
|
242508
|
+
modelByRun.set(run.id, m2);
|
|
242509
|
+
return m2;
|
|
242510
|
+
};
|
|
241646
242511
|
const rowOf = (bucketIndex2, run) => {
|
|
241647
242512
|
const bucket2 = bucketLabelOf(slice, bucketIndex2);
|
|
241648
|
-
const model =
|
|
242513
|
+
const model = modelOf(run);
|
|
241649
242514
|
const key2 = `${bucket2}\0${run.actorId}\0${model ?? ""}`;
|
|
241650
242515
|
let row = rows.get(key2);
|
|
241651
242516
|
if (!row) {
|
|
@@ -242641,11 +243506,11 @@ var init_roles = __esm({
|
|
|
242641
243506
|
});
|
|
242642
243507
|
|
|
242643
243508
|
// ../server/src/node-store.ts
|
|
242644
|
-
var
|
|
243509
|
+
var fs26, MemoryNodeStore, FileNodeStore;
|
|
242645
243510
|
var init_node_store = __esm({
|
|
242646
243511
|
"../server/src/node-store.ts"() {
|
|
242647
243512
|
"use strict";
|
|
242648
|
-
|
|
243513
|
+
fs26 = __toESM(require("node:fs"), 1);
|
|
242649
243514
|
MemoryNodeStore = class {
|
|
242650
243515
|
nodes = /* @__PURE__ */ new Map();
|
|
242651
243516
|
runtimes = /* @__PURE__ */ new Map();
|
|
@@ -242770,16 +243635,16 @@ var init_node_store = __esm({
|
|
|
242770
243635
|
static async open(file) {
|
|
242771
243636
|
const s2 = new _FileNodeStore(file);
|
|
242772
243637
|
try {
|
|
242773
|
-
const snap = JSON.parse(
|
|
243638
|
+
const snap = JSON.parse(fs26.readFileSync(file, "utf8"));
|
|
242774
243639
|
for (const n of snap.nodes ?? []) s2.nodes.set(n.id, n);
|
|
242775
243640
|
for (const r of snap.runtimes ?? []) s2.runtimes.set(r.id, r);
|
|
242776
243641
|
} catch {
|
|
242777
|
-
|
|
243642
|
+
fs26.writeFileSync(file, JSON.stringify({ nodes: [], runtimes: [] }, null, 2));
|
|
242778
243643
|
}
|
|
242779
243644
|
return s2;
|
|
242780
243645
|
}
|
|
242781
243646
|
flush() {
|
|
242782
|
-
|
|
243647
|
+
fs26.writeFileSync(this.file, JSON.stringify({
|
|
242783
243648
|
nodes: [...this.nodes.values()],
|
|
242784
243649
|
runtimes: [...this.runtimes.values()]
|
|
242785
243650
|
}, null, 2));
|
|
@@ -243570,9 +244435,9 @@ function prepareReadonlyGitBundles(input) {
|
|
|
243570
244435
|
if (repos.length === 0) return null;
|
|
243571
244436
|
const targets = collectTargets(repos, input.pinnedRevisions);
|
|
243572
244437
|
if (targets.length === 0) return null;
|
|
243573
|
-
const bundleRoot = input.bundleRoot ??
|
|
243574
|
-
|
|
243575
|
-
const root =
|
|
244438
|
+
const bundleRoot = input.bundleRoot ?? os8.tmpdir();
|
|
244439
|
+
fs27.mkdirSync(bundleRoot, { recursive: true });
|
|
244440
|
+
const root = fs27.mkdtempSync(path24.join(bundleRoot, "oasis-git-bundles-"));
|
|
243576
244441
|
const files = {};
|
|
243577
244442
|
const binaryFiles = {};
|
|
243578
244443
|
const metas = [];
|
|
@@ -243580,7 +244445,7 @@ function prepareReadonlyGitBundles(input) {
|
|
|
243580
244445
|
for (const target of targets) {
|
|
243581
244446
|
const generated = createBundle(root, target, input);
|
|
243582
244447
|
files[generated.metaPath] = JSON.stringify(generated.meta, null, 2) + "\n";
|
|
243583
|
-
binaryFiles[generated.bundlePath] =
|
|
244448
|
+
binaryFiles[generated.bundlePath] = fs27.readFileSync(generated.absoluteBundlePath).toString("base64");
|
|
243584
244449
|
metas.push(generated.meta);
|
|
243585
244450
|
}
|
|
243586
244451
|
files["inputs/git-bundles/MANIFEST.json"] = JSON.stringify({
|
|
@@ -243601,10 +244466,10 @@ function prepareReadonlyGitBundles(input) {
|
|
|
243601
244466
|
return {
|
|
243602
244467
|
files,
|
|
243603
244468
|
binaryFiles,
|
|
243604
|
-
cleanup: () =>
|
|
244469
|
+
cleanup: () => fs27.rmSync(root, { recursive: true, force: true })
|
|
243605
244470
|
};
|
|
243606
244471
|
} catch (err) {
|
|
243607
|
-
|
|
244472
|
+
fs27.rmSync(root, { recursive: true, force: true });
|
|
243608
244473
|
throw err;
|
|
243609
244474
|
}
|
|
243610
244475
|
}
|
|
@@ -243663,7 +244528,7 @@ function createBundle(root, target, input) {
|
|
|
243663
244528
|
if (!HEX40.test(commit)) throw new GitReadonlyBundleError("COMMIT_NOT_FOUND", `commit \u683C\u5F0F\u4E0D\u662F 40 \u4F4D sha: ${commit.slice(0, 48)}`);
|
|
243664
244529
|
const safeRepo = repo.id.replace(/[^a-zA-Z0-9_-]+/g, "_");
|
|
243665
244530
|
const work = path24.join(root, safeRepo);
|
|
243666
|
-
|
|
244531
|
+
fs27.mkdirSync(work, { recursive: true });
|
|
243667
244532
|
const source = ensureSourceRepo(work, repo, commit, input.env);
|
|
243668
244533
|
const tree = git2(source, ["rev-parse", `${commit}^{tree}`], input.env, "COMMIT_NOT_FOUND").trim();
|
|
243669
244534
|
if (target.expectedTree && target.expectedTree.toLowerCase() !== tree.toLowerCase()) {
|
|
@@ -243690,8 +244555,8 @@ function createBundle(root, target, input) {
|
|
|
243690
244555
|
} catch {
|
|
243691
244556
|
}
|
|
243692
244557
|
}
|
|
243693
|
-
const bytes2 =
|
|
243694
|
-
const digest = (0, import_node_crypto62.createHash)("sha256").update(
|
|
244558
|
+
const bytes2 = fs27.statSync(absBundle).size;
|
|
244559
|
+
const digest = (0, import_node_crypto62.createHash)("sha256").update(fs27.readFileSync(absBundle)).digest("hex");
|
|
243695
244560
|
const relBase = `inputs/git-bundles/${safeRepo}-${commit.slice(0, 12)}`;
|
|
243696
244561
|
return {
|
|
243697
244562
|
absoluteBundlePath: absBundle,
|
|
@@ -243715,7 +244580,7 @@ function createBundle(root, target, input) {
|
|
|
243715
244580
|
};
|
|
243716
244581
|
}
|
|
243717
244582
|
function verifyBundleReadable(dir, bundlePath, _bundleRef, commit, expectedTree, env) {
|
|
243718
|
-
|
|
244583
|
+
fs27.rmSync(dir, { recursive: true, force: true });
|
|
243719
244584
|
try {
|
|
243720
244585
|
(0, import_node_child_process16.execFileSync)("git", ["clone", bundlePath, dir], { stdio: "ignore", ...env ? { env } : {} });
|
|
243721
244586
|
git2(dir, ["cat-file", "-e", `${commit}^{commit}`], env, "COMMIT_NOT_FOUND");
|
|
@@ -243757,8 +244622,8 @@ function ensureSourceRepo(work, repo, commit, env) {
|
|
|
243757
244622
|
}
|
|
243758
244623
|
}
|
|
243759
244624
|
function gitInitBare(dir, env) {
|
|
243760
|
-
if (
|
|
243761
|
-
|
|
244625
|
+
if (fs27.existsSync(path24.join(dir, "objects"))) return;
|
|
244626
|
+
fs27.mkdirSync(dir, { recursive: true });
|
|
243762
244627
|
(0, import_node_child_process16.execFileSync)("git", ["init", "--bare", dir], { stdio: "ignore", ...env ? { env } : {} });
|
|
243763
244628
|
}
|
|
243764
244629
|
function git2(cwd, args, env, fallback, timeout) {
|
|
@@ -243787,14 +244652,14 @@ function classifyGitError(fallback, err, where) {
|
|
|
243787
244652
|
function oneLine(msg) {
|
|
243788
244653
|
return msg.split("\n").map((s2) => s2.trim()).filter(Boolean).slice(0, 3).join(" ");
|
|
243789
244654
|
}
|
|
243790
|
-
var import_node_child_process16, import_node_crypto62,
|
|
244655
|
+
var import_node_child_process16, import_node_crypto62, fs27, os8, path24, GitReadonlyBundleError, HEX40, FETCH_TIMEOUT_MS2;
|
|
243791
244656
|
var init_readonly_bundle = __esm({
|
|
243792
244657
|
"../server/src/git/readonly-bundle.ts"() {
|
|
243793
244658
|
"use strict";
|
|
243794
244659
|
import_node_child_process16 = require("node:child_process");
|
|
243795
244660
|
import_node_crypto62 = require("node:crypto");
|
|
243796
|
-
|
|
243797
|
-
|
|
244661
|
+
fs27 = __toESM(require("node:fs"), 1);
|
|
244662
|
+
os8 = __toESM(require("node:os"), 1);
|
|
243798
244663
|
path24 = __toESM(require("node:path"), 1);
|
|
243799
244664
|
init_remote_util();
|
|
243800
244665
|
GitReadonlyBundleError = class extends Error {
|
|
@@ -244601,6 +245466,7 @@ function parseFilters(q2) {
|
|
|
244601
245466
|
const actorId = q2.get("actorId");
|
|
244602
245467
|
const artifactId = q2.get("artifactId");
|
|
244603
245468
|
const projectId2 = q2.get("projectId");
|
|
245469
|
+
const chatSessionId = q2.get("chatSessionId");
|
|
244604
245470
|
const runtimeKind = q2.get("runtimeKind");
|
|
244605
245471
|
const status = q2.get("status");
|
|
244606
245472
|
const rootRunId = q2.get("rootRunId");
|
|
@@ -244611,6 +245477,7 @@ function parseFilters(q2) {
|
|
|
244611
245477
|
if (actorId) f2.actorId = actorId;
|
|
244612
245478
|
if (artifactId) f2.artifactId = artifactId;
|
|
244613
245479
|
if (projectId2) f2.projectId = projectId2;
|
|
245480
|
+
if (chatSessionId) f2.chatSessionId = chatSessionId;
|
|
244614
245481
|
if (runtimeKind) f2.runtimeKind = runtimeKind;
|
|
244615
245482
|
if (status) f2.status = status;
|
|
244616
245483
|
if (rootRunId) f2.rootRunId = rootRunId;
|
|
@@ -246517,6 +247384,19 @@ function createChatSessionsDomain(opts) {
|
|
|
246517
247384
|
const binding = await bindingFor(companyId, aiActorId).catch(() => null);
|
|
246518
247385
|
return binding?.nodeId ?? null;
|
|
246519
247386
|
}
|
|
247387
|
+
async function agentDefaultRuntime(companyId, aiActorId) {
|
|
247388
|
+
const binding = await bindingFor(companyId, aiActorId).catch(() => null);
|
|
247389
|
+
let model = null;
|
|
247390
|
+
try {
|
|
247391
|
+
model = opts.resolveActorModel ? await opts.resolveActorModel(companyId, aiActorId) : (await registry2.latestConfig(aiActorId))?.model ?? null;
|
|
247392
|
+
} catch {
|
|
247393
|
+
model = null;
|
|
247394
|
+
}
|
|
247395
|
+
return {
|
|
247396
|
+
binding: binding ? { nodeId: binding.nodeId, runtimeKind: binding.runtimeKind } : null,
|
|
247397
|
+
model: normalizeModel(model)
|
|
247398
|
+
};
|
|
247399
|
+
}
|
|
246520
247400
|
function normalizeModel(raw) {
|
|
246521
247401
|
return typeof raw === "string" && raw.trim() ? raw.trim() : null;
|
|
246522
247402
|
}
|
|
@@ -246581,9 +247461,12 @@ function createChatSessionsDomain(opts) {
|
|
|
246581
247461
|
}
|
|
246582
247462
|
return manager ? manager : null;
|
|
246583
247463
|
}
|
|
246584
|
-
function
|
|
247464
|
+
function ownsSessionOrOperator(session, auth) {
|
|
247465
|
+
return session.humanActorId === auth.actor || isOperatorRequest(auth);
|
|
247466
|
+
}
|
|
247467
|
+
function ensureSessionReadable(session, auth, kernel) {
|
|
246585
247468
|
if (!session) throw new ApiError(404, "NOT_FOUND", "session not found");
|
|
246586
|
-
if (session
|
|
247469
|
+
if (ownsSessionOrOperator(session, auth)) return session;
|
|
246587
247470
|
if (session.workspace) {
|
|
246588
247471
|
const coordinator = coordinatorOfWorkspace(kernel, session.workspace);
|
|
246589
247472
|
if (coordinator && session.aiActorId === coordinator) return session;
|
|
@@ -246681,7 +247564,16 @@ function createChatSessionsDomain(opts) {
|
|
|
246681
247564
|
if (isDeletedActor(aiActor)) {
|
|
246682
247565
|
throw new ApiError(409, ACTOR_DELETED_ERROR_CODE, ACTOR_DELETED_CHAT_MESSAGE);
|
|
246683
247566
|
}
|
|
246684
|
-
const
|
|
247567
|
+
const agentDefault = await agentDefaultRuntime(req.auth.companyId, body2.aiActorId);
|
|
247568
|
+
const initial = chatSessionInitialRuntime({
|
|
247569
|
+
binding: agentDefault.binding,
|
|
247570
|
+
agentModel: agentDefault.model,
|
|
247571
|
+
requested: {
|
|
247572
|
+
override: normalizeOverride(body2.overrideNodeId) && normalizeOverride(body2.overrideRuntimeKind) ? { nodeId: normalizeOverride(body2.overrideNodeId), runtimeKind: normalizeOverride(body2.overrideRuntimeKind) } : null,
|
|
247573
|
+
...Object.prototype.hasOwnProperty.call(body2, "model") ? { model: normalizeModel(body2.model) } : {}
|
|
247574
|
+
}
|
|
247575
|
+
});
|
|
247576
|
+
const runtimeId = agentDefault.binding?.nodeId ?? "unknown";
|
|
246685
247577
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
246686
247578
|
const session = {
|
|
246687
247579
|
id: (0, import_node_crypto65.randomUUID)(),
|
|
@@ -246698,12 +247590,12 @@ function createChatSessionsDomain(opts) {
|
|
|
246698
247590
|
// 两个入口页面行为一致。区别于 linkWorkOrder(出处关联,建单脑暴也有、不构成绑定)。
|
|
246699
247591
|
workspace: sessionWorkspaceToStore(body2.workspace),
|
|
246700
247592
|
projectId: sessionProjectIdToStore(body2.projectId),
|
|
246701
|
-
|
|
246702
|
-
|
|
246703
|
-
|
|
246704
|
-
|
|
246705
|
-
overrideNodeId:
|
|
246706
|
-
overrideRuntimeKind:
|
|
247593
|
+
/* 三列一起由 `chatSessionInitialRuntime` 给(ADR 0613):用户在欢迎态挑过就用他挑的,
|
|
247594
|
+
没挑就抄员工此刻的默认运行配置。**员工没绑定 = 三列留空**,逐字回到 ADR 0604 的旧语义
|
|
247595
|
+
(跟随员工 binding),绑上之后那条路照旧管用。 */
|
|
247596
|
+
model: initial.model,
|
|
247597
|
+
overrideNodeId: initial.overrideNodeId,
|
|
247598
|
+
overrideRuntimeKind: initial.overrideRuntimeKind,
|
|
246707
247599
|
// ADR-0058:分析会话指向被分析 run;非空即"这是分析会话"(不进主聊天列表、进 trace 分析视图)。
|
|
246708
247600
|
analyzedRunId: body2.analyzedRunId ?? null
|
|
246709
247601
|
};
|
|
@@ -246748,7 +247640,7 @@ function createChatSessionsDomain(opts) {
|
|
|
246748
247640
|
router.get("/api/chat-sessions/:id", async (req) => {
|
|
246749
247641
|
const store2 = await storeFor(req);
|
|
246750
247642
|
const [raw, kernel] = await Promise.all([store2.getSession(req.params.id), kernelFor(req)]);
|
|
246751
|
-
const session = ensureSessionReadable(raw, req.auth
|
|
247643
|
+
const session = ensureSessionReadable(raw, req.auth, kernel);
|
|
246752
247644
|
const [window3, curRuntimeId] = await Promise.all([
|
|
246753
247645
|
listRecentTurns(store2, session.id, parseTurns(req.query?.get("turns"))),
|
|
246754
247646
|
currentRuntimeId(req.auth.companyId, session.aiActorId)
|
|
@@ -246803,6 +247695,19 @@ function createChatSessionsDomain(opts) {
|
|
|
246803
247695
|
});
|
|
246804
247696
|
return { status: 200, body: await store2.getSession(req.params.id) };
|
|
246805
247697
|
});
|
|
247698
|
+
router.post("/api/chat-sessions/:id/runtime/reset-to-agent-default", async (req) => {
|
|
247699
|
+
const store2 = await storeFor(req);
|
|
247700
|
+
const session = await store2.getSession(req.params.id);
|
|
247701
|
+
if (!session || session.humanActorId !== req.auth.actor) throw new ApiError(404, "NOT_FOUND", "session not found");
|
|
247702
|
+
const agentDefault = await agentDefaultRuntime(req.auth.companyId, session.aiActorId);
|
|
247703
|
+
const initial = chatSessionInitialRuntime({ binding: agentDefault.binding, agentModel: agentDefault.model });
|
|
247704
|
+
await store2.updateSession(req.params.id, {
|
|
247705
|
+
overrideNodeId: initial.overrideNodeId,
|
|
247706
|
+
overrideRuntimeKind: initial.overrideRuntimeKind,
|
|
247707
|
+
model: initial.model
|
|
247708
|
+
});
|
|
247709
|
+
return { status: 200, body: await store2.getSession(req.params.id) };
|
|
247710
|
+
});
|
|
246806
247711
|
router.delete("/api/chat-sessions/:id", async (req) => {
|
|
246807
247712
|
const store2 = await storeFor(req);
|
|
246808
247713
|
const session = await store2.getSession(req.params.id);
|
|
@@ -246889,7 +247794,7 @@ function createChatSessionsDomain(opts) {
|
|
|
246889
247794
|
if (!items) throw new ApiError(404, "NOT_FOUND", "\u672C\u5B9E\u4F8B\u672A\u63A5 chat_items \u5FEB\u7167\u8BFB\u53E3");
|
|
246890
247795
|
const store2 = await storeFor(req);
|
|
246891
247796
|
const [session, kernel] = await Promise.all([store2.getSession(req.params.id), kernelFor(req)]);
|
|
246892
|
-
ensureSessionReadable(session, req.auth
|
|
247797
|
+
ensureSessionReadable(session, req.auth, kernel);
|
|
246893
247798
|
const chatSessionId = req.params.id;
|
|
246894
247799
|
const sinceVersion = Math.max(0, Number(req.query?.get("sinceVersion") ?? "0") || 0);
|
|
246895
247800
|
const beforeOrdRaw = Number(req.query?.get("beforeOrd") ?? "0") || 0;
|
|
@@ -246964,6 +247869,14 @@ function createChatSessionsDomain(opts) {
|
|
|
246964
247869
|
snapshotEntries.splice(at + 1, 0, entry);
|
|
246965
247870
|
}
|
|
246966
247871
|
}
|
|
247872
|
+
const outputCards = await sessionOutputCards(snapshotEntries, store2, chatSessionId).catch((e) => {
|
|
247873
|
+
console.warn(`[chat] \u4EA7\u51FA\u5361\u73B0\u62FC\u5931\u8D25\uFF08session=${chatSessionId}\uFF09\uFF0C\u8FD9\u6B21\u5FEB\u7167\u4E0D\u5E26\u5361: ${String(e)}`);
|
|
247874
|
+
return [];
|
|
247875
|
+
});
|
|
247876
|
+
for (const { after, entry } of outputCards) {
|
|
247877
|
+
const at = snapshotEntries.findIndex((e) => e.itemId === after);
|
|
247878
|
+
snapshotEntries.splice(at + 1, 0, entry);
|
|
247879
|
+
}
|
|
246967
247880
|
const oldestOrd = snapshotEntries.find((e) => e.ord !== null)?.ord ?? null;
|
|
246968
247881
|
const body2 = {
|
|
246969
247882
|
chatSessionId,
|
|
@@ -247060,7 +247973,7 @@ function createChatSessionsDomain(opts) {
|
|
|
247060
247973
|
router.get("/api/chat-sessions/:id/delegations", async (req) => {
|
|
247061
247974
|
const store2 = await storeFor(req);
|
|
247062
247975
|
const session = await store2.getSession(req.params.id);
|
|
247063
|
-
if (!session || session
|
|
247976
|
+
if (!session || !ownsSessionOrOperator(session, req.auth)) throw new ApiError(404, "NOT_FOUND", "session not found");
|
|
247064
247977
|
const wiring = opts.delegations;
|
|
247065
247978
|
if (!wiring || !wiring.enabled()) return { status: 200, body: { items: [] } };
|
|
247066
247979
|
const companyId = session.companyId ?? req.auth.companyId ?? void 0;
|
|
@@ -247081,6 +247994,9 @@ function createChatSessionsDomain(opts) {
|
|
|
247081
247994
|
...expert?.avatar ? { expertAvatar: expert.avatar } : {},
|
|
247082
247995
|
state: record9.state,
|
|
247083
247996
|
...record9.failureKind ? { failureKind: record9.failureKind } : {},
|
|
247997
|
+
/* 给人看的那一档由服务端算(Bug 0221):委派卡、徽章、子会话面板三处渲染同一个值。 */
|
|
247998
|
+
ending: delegationEndingOfRecord(record9, delegationArtifactsView(record9)),
|
|
247999
|
+
settledSeq: record9.settledSeq,
|
|
247084
248000
|
...record9.label ? { label: record9.label } : {},
|
|
247085
248001
|
...record9.taskDigest ? { taskDigest: record9.taskDigest } : {},
|
|
247086
248002
|
parentMessageId: record9.parentMessageId,
|
|
@@ -247126,7 +248042,7 @@ function createChatSessionsDomain(opts) {
|
|
|
247126
248042
|
router.get("/api/chat-sessions/:id/work-orders", async (req) => {
|
|
247127
248043
|
const store2 = await storeFor(req);
|
|
247128
248044
|
const session = await store2.getSession(req.params.id);
|
|
247129
|
-
if (!session || session
|
|
248045
|
+
if (!session || !ownsSessionOrOperator(session, req.auth)) throw new ApiError(404, "NOT_FOUND", "session not found");
|
|
247130
248046
|
const workOrderIds = await store2.listWorkOrdersForSession(req.params.id);
|
|
247131
248047
|
const wkKernel = await kernelFor(req);
|
|
247132
248048
|
if (!wkKernel || workOrderIds.length === 0) return { status: 200, body: { items: [] } };
|
|
@@ -247149,6 +248065,29 @@ function createChatSessionsDomain(opts) {
|
|
|
247149
248065
|
});
|
|
247150
248066
|
return { status: 200, body: { items } };
|
|
247151
248067
|
});
|
|
248068
|
+
router.get("/api/chat-sessions/:id/usage", async (req) => {
|
|
248069
|
+
const store2 = await storeFor(req);
|
|
248070
|
+
const session = await store2.getSession(req.params.id);
|
|
248071
|
+
if (!session || !ownsSessionOrOperator(session, req.auth)) throw new ApiError(404, "NOT_FOUND", "session not found");
|
|
248072
|
+
const companyId = req.auth.companyId ?? session.companyId ?? opts.defaultCompanyId;
|
|
248073
|
+
if (!opts.usageRead || !companyId) {
|
|
248074
|
+
return { status: 503, body: { error: { code: "usage_ledger_unavailable", message: "\u4F7F\u7528\u4E0E\u7EDF\u8BA1\u6570\u636E\u6E90\u672A\u63A5\u5165" } } };
|
|
248075
|
+
}
|
|
248076
|
+
try {
|
|
248077
|
+
return {
|
|
248078
|
+
status: 200,
|
|
248079
|
+
body: await opts.usageRead.conversationUsage(companyId, session.id, {
|
|
248080
|
+
range: req.query.get("range") ?? void 0,
|
|
248081
|
+
asOf: req.query.get("asOf") ?? void 0,
|
|
248082
|
+
timeZone: req.query.get("timeZone") ?? void 0
|
|
248083
|
+
})
|
|
248084
|
+
};
|
|
248085
|
+
} catch (err) {
|
|
248086
|
+
const mapped = usageErrorResponse(err);
|
|
248087
|
+
if (mapped) return mapped;
|
|
248088
|
+
throw err;
|
|
248089
|
+
}
|
|
248090
|
+
});
|
|
247152
248091
|
router.get("/api/chat-broadcasts/pending", async (req) => {
|
|
247153
248092
|
if (!opts.broadcastOps) throw new ApiError(404, "NOT_FOUND", "\u672C\u5B9E\u4F8B\u672A\u542F\u7528\u5DE5\u5355\u7EC8\u6001\u64AD\u62A5");
|
|
247154
248093
|
const store2 = await storeFor(req);
|
|
@@ -247463,6 +248402,44 @@ function createChatSessionsDomain(opts) {
|
|
|
247463
248402
|
});
|
|
247464
248403
|
};
|
|
247465
248404
|
}
|
|
248405
|
+
async function sessionOutputCards(entries, store, chatSessionId) {
|
|
248406
|
+
const lastEntryOf = /* @__PURE__ */ new Map();
|
|
248407
|
+
for (const e of entries) {
|
|
248408
|
+
if (e.role === "assistant" && e.messageId) lastEntryOf.set(e.messageId, e);
|
|
248409
|
+
}
|
|
248410
|
+
if (lastEntryOf.size === 0) return [];
|
|
248411
|
+
const ids2 = [...lastEntryOf.keys()];
|
|
248412
|
+
const rows = store.listMessageOutputParts ? await store.listMessageOutputParts(chatSessionId, ids2) : (await store.listMessages(chatSessionId)).filter((m2) => m2.role === "assistant" && lastEntryOf.has(m2.id)).map((m2) => ({ messageId: m2.id, outputs: Array.isArray(m2.parts) ? m2.parts.filter((p2) => p2?.type === "outputs") : [] }));
|
|
248413
|
+
const out = [];
|
|
248414
|
+
for (const { messageId, outputs } of rows) {
|
|
248415
|
+
const anchor = lastEntryOf.get(messageId);
|
|
248416
|
+
const files = sessionOutputFilesOfParts(outputs);
|
|
248417
|
+
if (!anchor || files.length === 0) continue;
|
|
248418
|
+
const anchorPayload = anchor.payload && typeof anchor.payload === "object" && !Array.isArray(anchor.payload) ? anchor.payload : {};
|
|
248419
|
+
out.push({
|
|
248420
|
+
after: anchor.itemId,
|
|
248421
|
+
entry: {
|
|
248422
|
+
itemId: sessionOutputsItemId(messageId),
|
|
248423
|
+
turnId: anchor.turnId,
|
|
248424
|
+
itemType: "control",
|
|
248425
|
+
role: "assistant",
|
|
248426
|
+
status: "completed",
|
|
248427
|
+
itemVersion: anchor.itemVersion,
|
|
248428
|
+
seq: anchor.seq,
|
|
248429
|
+
ord: anchor.ord,
|
|
248430
|
+
messageId,
|
|
248431
|
+
updatedAt: anchor.updatedAt,
|
|
248432
|
+
payload: {
|
|
248433
|
+
code: SESSION_OUTPUTS_ITEM_CODE,
|
|
248434
|
+
files: files.map((f2) => ({ path: f2.path, name: f2.name })),
|
|
248435
|
+
...anchorPayload.createdAt !== void 0 ? { createdAt: anchorPayload.createdAt } : {},
|
|
248436
|
+
...anchorPayload.completedAt !== void 0 ? { completedAt: anchorPayload.completedAt } : {}
|
|
248437
|
+
}
|
|
248438
|
+
}
|
|
248439
|
+
});
|
|
248440
|
+
}
|
|
248441
|
+
return out;
|
|
248442
|
+
}
|
|
247466
248443
|
async function submissionCardProjection(entries, deps) {
|
|
247467
248444
|
const out = { add: [], resolved: [] };
|
|
247468
248445
|
const turns = deps.turns;
|
|
@@ -247605,6 +248582,8 @@ var init_chat_sessions2 = __esm({
|
|
|
247605
248582
|
init_persistent_files();
|
|
247606
248583
|
init_files_view();
|
|
247607
248584
|
init_router();
|
|
248585
|
+
init_operator();
|
|
248586
|
+
init_usage_read();
|
|
247608
248587
|
init_collab();
|
|
247609
248588
|
init_gap_thread();
|
|
247610
248589
|
init_escalation_opening();
|
|
@@ -247619,6 +248598,7 @@ var init_chat_sessions2 = __esm({
|
|
|
247619
248598
|
init_company_data_store_router();
|
|
247620
248599
|
init_workorder_terminal();
|
|
247621
248600
|
init_session_workdir();
|
|
248601
|
+
init_session_runtime_target();
|
|
247622
248602
|
init_uncategorized_project();
|
|
247623
248603
|
init_chat_submission();
|
|
247624
248604
|
init_project_bundle();
|
|
@@ -251454,14 +252434,41 @@ function daemonMetaOf(hub, nodeId) {
|
|
|
251454
252434
|
if (typeof connectedDaemons !== "function") return void 0;
|
|
251455
252435
|
return connectedDaemons.call(hub).find((candidate) => candidate.daemonId === nodeId)?.meta;
|
|
251456
252436
|
}
|
|
251457
|
-
function remoteAppendInput(hub, nodeId, dispatchId, entry, input, timeoutMs, confirm) {
|
|
252437
|
+
function remoteAppendInput(hub, nodeId, dispatchId, entry, input, timeoutMs, sessionReadyWaitMs, confirm) {
|
|
251458
252438
|
const key2 = input.requireConsumptionReceipt ? input.clientMessageKey : void 0;
|
|
251459
|
-
if (!key2 || !confirm) return sendAppendInput(hub, nodeId, dispatchId, entry, input, timeoutMs);
|
|
251460
|
-
return sendAppendInput(hub, nodeId, dispatchId, entry, input, timeoutMs).then((result) => ({ ...result, receiptProbe: { nodeId, dispatchId, confirm: () => confirm(key2) } }));
|
|
252439
|
+
if (!key2 || !confirm) return sendAppendInput(hub, nodeId, dispatchId, entry, input, timeoutMs, sessionReadyWaitMs);
|
|
252440
|
+
return sendAppendInput(hub, nodeId, dispatchId, entry, input, timeoutMs, sessionReadyWaitMs).then((result) => ({ ...result, receiptProbe: { nodeId, dispatchId, confirm: () => confirm(key2) } }));
|
|
252441
|
+
}
|
|
252442
|
+
async function waitSessionReady(hub, dispatchId, entry, timeoutMs) {
|
|
252443
|
+
const deadline = Date.now() + timeoutMs;
|
|
252444
|
+
const ready = () => hub.hasSession?.(dispatchId) === true && entry.deliveryState === "started";
|
|
252445
|
+
while (!entry.exited && !ready()) {
|
|
252446
|
+
const left = deadline - Date.now();
|
|
252447
|
+
if (left <= 0) return;
|
|
252448
|
+
await new Promise((resolve11) => {
|
|
252449
|
+
let settled = false;
|
|
252450
|
+
const finish = () => {
|
|
252451
|
+
if (settled) return;
|
|
252452
|
+
settled = true;
|
|
252453
|
+
const i = entry.readyWaiters?.indexOf(finish) ?? -1;
|
|
252454
|
+
if (i >= 0) entry.readyWaiters.splice(i, 1);
|
|
252455
|
+
resolve11();
|
|
252456
|
+
};
|
|
252457
|
+
(entry.readyWaiters ??= []).push(finish);
|
|
252458
|
+
if (hub.hasSession?.(dispatchId) !== true) void hub.waitForSession(dispatchId, left).then(finish, finish);
|
|
252459
|
+
else {
|
|
252460
|
+
const t = setTimeout(finish, left);
|
|
252461
|
+
t.unref?.();
|
|
252462
|
+
}
|
|
252463
|
+
});
|
|
252464
|
+
}
|
|
251461
252465
|
}
|
|
251462
|
-
function sendAppendInput(hub, nodeId, dispatchId, entry, input, timeoutMs) {
|
|
252466
|
+
function sendAppendInput(hub, nodeId, dispatchId, entry, input, timeoutMs, sessionReadyWaitMs) {
|
|
251463
252467
|
const unknownIfInterrupting = input.interrupt ? { interrupt: "unknown" } : {};
|
|
251464
252468
|
if (entry.exited) return Promise.resolve({ accepted: false, reason: "session-closing", ...unknownIfInterrupting });
|
|
252469
|
+
if (input.requireConsumptionReceipt && sessionReadyWaitMs > 0 && (hub.hasSession?.(dispatchId) === false || entry.deliveryState !== "started") && typeof hub.waitForSession === "function" && daemonMetaOf(hub, nodeId)?.supportsInputReceiptQuery === true) {
|
|
252470
|
+
return waitSessionReady(hub, dispatchId, entry, sessionReadyWaitMs).then(() => sendAppendInput(hub, nodeId, dispatchId, entry, input, timeoutMs, 0));
|
|
252471
|
+
}
|
|
251465
252472
|
if (input.requireConsumptionReceipt && !hub.supportsInputConsumptionReceipts?.(dispatchId)) {
|
|
251466
252473
|
return Promise.resolve({ accepted: false, reason: "consumption-unsupported" });
|
|
251467
252474
|
}
|
|
@@ -251498,6 +252505,7 @@ var init_daemon_adapter = __esm({
|
|
|
251498
252505
|
this.nodeLostGraceMs = opts.nodeLostGraceMs ?? graceFromEnv(12e4);
|
|
251499
252506
|
this.ackTimeoutMs = opts.ackTimeoutMs ?? ackMsFromEnv(15e3);
|
|
251500
252507
|
this.appendTimeoutMs = opts.appendTimeoutMs ?? 1e4;
|
|
252508
|
+
this.sessionReadyWaitMs = opts.sessionReadyWaitMs ?? 1e4;
|
|
251501
252509
|
this.receiptQueryTimeoutMs = opts.receiptQueryTimeoutMs ?? 5e3;
|
|
251502
252510
|
this.log = opts.log ?? ((m2) => console.warn(m2));
|
|
251503
252511
|
this.health = opts.health;
|
|
@@ -251519,6 +252527,7 @@ var init_daemon_adapter = __esm({
|
|
|
251519
252527
|
ackTimeoutMs;
|
|
251520
252528
|
/** ADR-0093:append_input 回执时限;超时(老节点忽略帧)→ unsupported,上层降级 kill+resume。 */
|
|
251521
252529
|
appendTimeoutMs;
|
|
252530
|
+
sessionReadyWaitMs;
|
|
251522
252531
|
log;
|
|
251523
252532
|
health;
|
|
251524
252533
|
stashEnabled;
|
|
@@ -251671,6 +252680,7 @@ var init_daemon_adapter = __esm({
|
|
|
251671
252680
|
clearTimeout(w2.timer);
|
|
251672
252681
|
w2.resolve({ accepted: false, reason: w2.requireConsumptionReceipt ? "unconfirmed" : "session-closing" });
|
|
251673
252682
|
}
|
|
252683
|
+
for (const w2 of entry.readyWaiters?.splice(0) ?? []) w2();
|
|
251674
252684
|
if (info.reason === "server-unreachable") this.health?.recordUnreachable(entry.nodeId, info.reason);
|
|
251675
252685
|
else this.health?.recordReachable(entry.nodeId);
|
|
251676
252686
|
for (const cb of entry.exitCbs.splice(0)) cb(info);
|
|
@@ -251730,6 +252740,7 @@ var init_daemon_adapter = __esm({
|
|
|
251730
252740
|
entry.ackTimer = void 0;
|
|
251731
252741
|
}
|
|
251732
252742
|
if (entry) entry.deliveryState = state;
|
|
252743
|
+
if (entry && state === "started") for (const w2 of entry.readyWaiters?.splice(0) ?? []) w2();
|
|
251733
252744
|
}
|
|
251734
252745
|
onNodeDown(daemonId) {
|
|
251735
252746
|
if (this.reapTimers.has(daemonId)) return;
|
|
@@ -251938,6 +252949,7 @@ var init_daemon_adapter = __esm({
|
|
|
251938
252949
|
}
|
|
251939
252950
|
const hub = this.hub;
|
|
251940
252951
|
const appendTimeoutMs = this.appendTimeoutMs;
|
|
252952
|
+
const sessionReadyWaitMs = this.sessionReadyWaitMs;
|
|
251941
252953
|
const confirm = (key2) => this.confirmInputReceipt(nodeId, dispatchId, key2);
|
|
251942
252954
|
return {
|
|
251943
252955
|
id: dispatchId,
|
|
@@ -251971,7 +252983,7 @@ var init_daemon_adapter = __esm({
|
|
|
251971
252983
|
} : {},
|
|
251972
252984
|
// ADR-0093 对话追加:经 WS 把输入送到节点上的会话,等 append_result 回执;节点不认帧
|
|
251973
252985
|
// (老节点)则超时 unsupported,上层降级 kill+resume。
|
|
251974
|
-
appendInput: (input) => remoteAppendInput(hub, nodeId, dispatchId, entry, input, appendTimeoutMs, confirm)
|
|
252986
|
+
appendInput: (input) => remoteAppendInput(hub, nodeId, dispatchId, entry, input, appendTimeoutMs, sessionReadyWaitMs, confirm)
|
|
251975
252987
|
};
|
|
251976
252988
|
}
|
|
251977
252989
|
recover(dispatchId, nodeId, runtimeKind, actorId) {
|
|
@@ -252029,6 +253041,7 @@ var init_daemon_adapter = __esm({
|
|
|
252029
253041
|
};
|
|
252030
253042
|
const hub = this.hub;
|
|
252031
253043
|
const appendTimeoutMs = this.appendTimeoutMs;
|
|
253044
|
+
const sessionReadyWaitMs = this.sessionReadyWaitMs;
|
|
252032
253045
|
const confirm = (key2) => this.confirmInputReceipt(nodeId, dispatchId, key2);
|
|
252033
253046
|
return {
|
|
252034
253047
|
id: dispatchId,
|
|
@@ -252068,7 +253081,7 @@ var init_daemon_adapter = __esm({
|
|
|
252068
253081
|
}
|
|
252069
253082
|
} : {},
|
|
252070
253083
|
// ADR-0093 对话追加(重挂句柄同 spawn 句柄)。
|
|
252071
|
-
appendInput: (input) => remoteAppendInput(hub, nodeId, dispatchId, entry, input, appendTimeoutMs, confirm)
|
|
253084
|
+
appendInput: (input) => remoteAppendInput(hub, nodeId, dispatchId, entry, input, appendTimeoutMs, sessionReadyWaitMs, confirm)
|
|
252072
253085
|
};
|
|
252073
253086
|
}
|
|
252074
253087
|
};
|
|
@@ -252382,22 +253395,22 @@ var init_engine = __esm({
|
|
|
252382
253395
|
});
|
|
252383
253396
|
|
|
252384
253397
|
// ../server/src/mirror/fs-state.ts
|
|
252385
|
-
var
|
|
253398
|
+
var fs30, FsMirrorStateStore;
|
|
252386
253399
|
var init_fs_state = __esm({
|
|
252387
253400
|
"../server/src/mirror/fs-state.ts"() {
|
|
252388
253401
|
"use strict";
|
|
252389
|
-
|
|
253402
|
+
fs30 = __toESM(require("node:fs"), 1);
|
|
252390
253403
|
FsMirrorStateStore = class {
|
|
252391
253404
|
constructor(file) {
|
|
252392
253405
|
this.file = file;
|
|
252393
|
-
if (
|
|
252394
|
-
const obj2 = JSON.parse(
|
|
253406
|
+
if (fs30.existsSync(file)) {
|
|
253407
|
+
const obj2 = JSON.parse(fs30.readFileSync(file, "utf8"));
|
|
252395
253408
|
for (const [k2, v2] of Object.entries(obj2)) this.map.set(k2, v2);
|
|
252396
253409
|
}
|
|
252397
253410
|
}
|
|
252398
253411
|
map = /* @__PURE__ */ new Map();
|
|
252399
253412
|
flush() {
|
|
252400
|
-
|
|
253413
|
+
fs30.writeFileSync(this.file, JSON.stringify(Object.fromEntries(this.map), null, 2));
|
|
252401
253414
|
}
|
|
252402
253415
|
async get(artifactId) {
|
|
252403
253416
|
return this.map.get(artifactId) ?? null;
|
|
@@ -258375,6 +259388,7 @@ var init_postgres_trace = __esm({
|
|
|
258375
259388
|
if (filter.actorId) push2((n) => `r.actor_id = $${n}`, filter.actorId);
|
|
258376
259389
|
if (filter.artifactId) push2((n) => `r.artifact_id = $${n}`, filter.artifactId);
|
|
258377
259390
|
if (filter.projectId) push2((n) => `r.project_id = $${n}`, filter.projectId);
|
|
259391
|
+
if (filter.chatSessionId) push2((n) => `r.chat_session_id = $${n}`, filter.chatSessionId);
|
|
258378
259392
|
if (filter.runtimeKind) push2((n) => `r.runtime_kind = $${n}`, filter.runtimeKind);
|
|
258379
259393
|
if (filter.status) push2((n) => `r.status = $${n}`, filter.status);
|
|
258380
259394
|
if (filter.rootRunId) push2((n) => `r.root_run_id = $${n}`, filter.rootRunId);
|
|
@@ -261775,6 +262789,34 @@ var init_postgres_chat_sessions = __esm({
|
|
|
261775
262789
|
attachments: row.attachments ?? []
|
|
261776
262790
|
}));
|
|
261777
262791
|
}
|
|
262792
|
+
/**
|
|
262793
|
+
* `/items` 快照出产出卡的窄读(Bug 0217):按主键批量命中,在库里把 `parts` 展开、只挑 `type='outputs'`
|
|
262794
|
+
* 那几段聚回一个数组送出来——整轮过程时间线不出库。只看 assistant 行(outputs 段只在助手轮收尾写)。
|
|
262795
|
+
*/
|
|
262796
|
+
async listMessageOutputParts(sessionId, messageIds) {
|
|
262797
|
+
if (messageIds.length === 0) return [];
|
|
262798
|
+
const r = await this.pool.query(
|
|
262799
|
+
`SELECT m.id, o.outputs
|
|
262800
|
+
FROM ${this.s}.chat_messages m
|
|
262801
|
+
JOIN ${this.s}.chat_sessions s ON s.id = m.session_id
|
|
262802
|
+
CROSS JOIN LATERAL (
|
|
262803
|
+
SELECT jsonb_agg(p ORDER BY i) AS outputs
|
|
262804
|
+
FROM jsonb_array_elements(CASE WHEN jsonb_typeof(m.parts) = 'array' THEN m.parts ELSE '[]'::jsonb END)
|
|
262805
|
+
WITH ORDINALITY AS e(p, i)
|
|
262806
|
+
WHERE p->>'type' = 'outputs'
|
|
262807
|
+
) o
|
|
262808
|
+
WHERE m.id = ANY($1::text[])
|
|
262809
|
+
AND m.session_id = $2
|
|
262810
|
+
AND s.company_id = $3
|
|
262811
|
+
AND m.role = 'assistant'
|
|
262812
|
+
AND o.outputs IS NOT NULL`,
|
|
262813
|
+
[[...messageIds], sessionId, this.companyId]
|
|
262814
|
+
);
|
|
262815
|
+
return r.rows.map((row) => ({
|
|
262816
|
+
messageId: row.id,
|
|
262817
|
+
outputs: Array.isArray(row.outputs) ? row.outputs : []
|
|
262818
|
+
}));
|
|
262819
|
+
}
|
|
261778
262820
|
/**
|
|
261779
262821
|
* 末尾 N 轮视窗(详情读侧默认):先定位「从尾部数第 N 条 user 消息」的 seq 作为窗口起点,再取
|
|
261780
262822
|
* seq >= 起点的全部消息。语义与内存版 windowMessagesByTurns 一致,但把裁剪下推到 SQL——长会话
|
|
@@ -263212,6 +264254,68 @@ var init_chat_items_ord_backfill = __esm({
|
|
|
263212
264254
|
}
|
|
263213
264255
|
});
|
|
263214
264256
|
|
|
264257
|
+
// ../storage/src/chat-session-runtime-pin-backfill.ts
|
|
264258
|
+
async function hasChatSessions(pool, schema) {
|
|
264259
|
+
const r = await pool.query(`SELECT to_regclass($1) IS NOT NULL AS ok`, [`${schema}.chat_sessions`]);
|
|
264260
|
+
return r.rows[0]?.ok === true;
|
|
264261
|
+
}
|
|
264262
|
+
async function pinChatSessionsToAgentDefault(pool, schema, opts) {
|
|
264263
|
+
const s2 = quoteIdent2(schema);
|
|
264264
|
+
const dryRun = opts.dryRun === true;
|
|
264265
|
+
const base = {
|
|
264266
|
+
schema,
|
|
264267
|
+
companyId: opts.companyId,
|
|
264268
|
+
scanned: 0,
|
|
264269
|
+
pinned: 0,
|
|
264270
|
+
leftUnbound: 0,
|
|
264271
|
+
unresolved: 0,
|
|
264272
|
+
dryRun
|
|
264273
|
+
};
|
|
264274
|
+
if (!await hasChatSessions(pool, schema)) return base;
|
|
264275
|
+
const pending = await pool.query(
|
|
264276
|
+
`SELECT ai_actor_id, count(*)::int AS n
|
|
264277
|
+
FROM ${s2}.chat_sessions
|
|
264278
|
+
WHERE company_id = $1
|
|
264279
|
+
AND (override_node_id IS NULL OR override_runtime_kind IS NULL)
|
|
264280
|
+
GROUP BY ai_actor_id`,
|
|
264281
|
+
[opts.companyId]
|
|
264282
|
+
);
|
|
264283
|
+
for (const row of pending.rows) {
|
|
264284
|
+
base.scanned += row.n;
|
|
264285
|
+
let binding;
|
|
264286
|
+
try {
|
|
264287
|
+
binding = await opts.resolveBinding(row.ai_actor_id);
|
|
264288
|
+
} catch {
|
|
264289
|
+
base.unresolved += row.n;
|
|
264290
|
+
continue;
|
|
264291
|
+
}
|
|
264292
|
+
if (!binding?.nodeId || !binding?.runtimeKind) {
|
|
264293
|
+
base.leftUnbound += row.n;
|
|
264294
|
+
continue;
|
|
264295
|
+
}
|
|
264296
|
+
if (dryRun) {
|
|
264297
|
+
base.pinned += row.n;
|
|
264298
|
+
continue;
|
|
264299
|
+
}
|
|
264300
|
+
const upd = await pool.query(
|
|
264301
|
+
`UPDATE ${s2}.chat_sessions
|
|
264302
|
+
SET override_node_id = $3, override_runtime_kind = $4
|
|
264303
|
+
WHERE company_id = $1
|
|
264304
|
+
AND ai_actor_id = $2
|
|
264305
|
+
AND (override_node_id IS NULL OR override_runtime_kind IS NULL)`,
|
|
264306
|
+
[opts.companyId, row.ai_actor_id, binding.nodeId, binding.runtimeKind]
|
|
264307
|
+
);
|
|
264308
|
+
base.pinned += upd.rowCount ?? 0;
|
|
264309
|
+
}
|
|
264310
|
+
return base;
|
|
264311
|
+
}
|
|
264312
|
+
var init_chat_session_runtime_pin_backfill = __esm({
|
|
264313
|
+
"../storage/src/chat-session-runtime-pin-backfill.ts"() {
|
|
264314
|
+
"use strict";
|
|
264315
|
+
init_pg_ident();
|
|
264316
|
+
}
|
|
264317
|
+
});
|
|
264318
|
+
|
|
263215
264319
|
// ../storage/src/postgres-delegations.ts
|
|
263216
264320
|
function toRecord2(row) {
|
|
263217
264321
|
return {
|
|
@@ -267580,7 +268684,7 @@ var init_cutover_aware_trace = __esm({
|
|
|
267580
268684
|
const s2 = await this.pick();
|
|
267581
268685
|
return typeof s2.runtimeRunActivity === "function" ? s2.runtimeRunActivity(runtimeInstanceId) : null;
|
|
267582
268686
|
}
|
|
267583
|
-
/**
|
|
268687
|
+
/** 协调运行(协调者卡的轨迹入口):落点 store 没实现就当没有这份数据,卡照出、只是没图标,不报错。 */
|
|
267584
268688
|
async listCoordinatorRuns(workOrderId) {
|
|
267585
268689
|
const store = await this.pick();
|
|
267586
268690
|
return await store.listCoordinatorRuns?.(workOrderId) ?? [];
|
|
@@ -267907,7 +269011,7 @@ var init_cutover_aware_trace = __esm({
|
|
|
267907
269011
|
/**
|
|
267908
269012
|
* 协调运行按工单扇出(任务动态协调者卡)。与 `FanOutDispatchLedger.listByWorkorder` 同理:
|
|
267909
269013
|
* **一张工单只属于一家公司**,所以逐家查出来的并集恰好就是那一家的行;漏扇会让非默认公司的
|
|
267910
|
-
*
|
|
269014
|
+
* 协调者卡全都点不进轨迹。某家查不动只记一笔,不让整块读失败。
|
|
267911
269015
|
*/
|
|
267912
269016
|
async listCoordinatorRuns(workOrderId) {
|
|
267913
269017
|
const out = [];
|
|
@@ -270859,7 +271963,8 @@ async function backfillUsageLedger(ledger, opts) {
|
|
|
270859
271963
|
manifestId: opts.dryRun ? null : opts.manifestId,
|
|
270860
271964
|
usagePoints: emptyStep(),
|
|
270861
271965
|
runtimeStartedAt: emptyStep(),
|
|
270862
|
-
chat: { ...emptyStep(), notFound: 0, ambiguous: 0, turnFilled: 0 }
|
|
271966
|
+
chat: { ...emptyStep(), notFound: 0, ambiguous: 0, turnFilled: 0 },
|
|
271967
|
+
claudeResume: null
|
|
270863
271968
|
};
|
|
270864
271969
|
const sample = (step, id) => {
|
|
270865
271970
|
if (step.samples.length < sampleSize) step.samples.push(id);
|
|
@@ -270997,8 +272102,134 @@ async function backfillUsageLedger(ledger, opts) {
|
|
|
270997
272102
|
}
|
|
270998
272103
|
});
|
|
270999
272104
|
}
|
|
272105
|
+
if (opts.claudeResumeBefore) {
|
|
272106
|
+
report.claudeResume = await fixClaudeResumeUsage(ledger.pool, s2, opts.claudeResumeBefore, {
|
|
272107
|
+
dryRun: opts.dryRun,
|
|
272108
|
+
manifestId: opts.manifestId,
|
|
272109
|
+
batch,
|
|
272110
|
+
sample: (step, id) => sample(step, id),
|
|
272111
|
+
now
|
|
272112
|
+
});
|
|
272113
|
+
}
|
|
272114
|
+
return report;
|
|
272115
|
+
}
|
|
272116
|
+
function claudeResumeNetUsage(raw) {
|
|
272117
|
+
const out = [];
|
|
272118
|
+
let prev = null;
|
|
272119
|
+
for (const u of raw) {
|
|
272120
|
+
const cost = reportedCost(u["costUsdMicros"]);
|
|
272121
|
+
if (cost === null) {
|
|
272122
|
+
out.push(u);
|
|
272123
|
+
continue;
|
|
272124
|
+
}
|
|
272125
|
+
const prevCost = prev ? reportedCost(prev["costUsdMicros"]) : null;
|
|
272126
|
+
const cumulative = prev !== null && prevCost !== null && cost >= prevCost && BUCKETS.every(([k2]) => usageBucket(u[k2]) >= usageBucket(prev[k2]));
|
|
272127
|
+
if (!cumulative) {
|
|
272128
|
+
out.push(u);
|
|
272129
|
+
prev = u;
|
|
272130
|
+
continue;
|
|
272131
|
+
}
|
|
272132
|
+
const input = usageBucket(u["inputTokens"]) - usageBucket(prev["inputTokens"]);
|
|
272133
|
+
const output = usageBucket(u["outputTokens"]) - usageBucket(prev["outputTokens"]);
|
|
272134
|
+
out.push({
|
|
272135
|
+
...u,
|
|
272136
|
+
inputTokens: input,
|
|
272137
|
+
outputTokens: output,
|
|
272138
|
+
totalTokens: input + output,
|
|
272139
|
+
cacheReadTokens: usageBucket(u["cacheReadTokens"]) - usageBucket(prev["cacheReadTokens"]),
|
|
272140
|
+
cacheCreationTokens: usageBucket(u["cacheCreationTokens"]) - usageBucket(prev["cacheCreationTokens"]),
|
|
272141
|
+
costUsdMicros: cost - prevCost
|
|
272142
|
+
});
|
|
272143
|
+
prev = u;
|
|
272144
|
+
}
|
|
272145
|
+
return out;
|
|
272146
|
+
}
|
|
272147
|
+
async function fixClaudeResumeUsage(pool, s2, before, o) {
|
|
272148
|
+
const report = { ...emptyStep(), sessions: 0, costBefore: 0, costAfter: 0 };
|
|
272149
|
+
const audited = /* @__PURE__ */ new Map();
|
|
272150
|
+
const auditRows = await pool.query(
|
|
272151
|
+
`SELECT run_id, manifest_id, before, after FROM ${s2}.agent_run_usage_backfill_audit
|
|
272152
|
+
WHERE field = 'claude_resume_usage' ORDER BY id`
|
|
272153
|
+
);
|
|
272154
|
+
for (const a of auditRows.rows) {
|
|
272155
|
+
audited.set(a.run_id, { manifest: a.manifest_id, before: a.before, after: a.after });
|
|
272156
|
+
}
|
|
272157
|
+
const { rows } = await pool.query(
|
|
272158
|
+
`SELECT r.id, r.usage, COALESCE(r.runtime_session_id, r.metadata->>'runtimeSessionId') AS rt
|
|
272159
|
+
FROM ${s2}.agent_runs r
|
|
272160
|
+
WHERE r.runtime_kind = 'claude-code' AND ${ENDED_SQL} AND jsonb_typeof(r.usage) = 'object'
|
|
272161
|
+
AND COALESCE(r.runtime_session_id, r.metadata->>'runtimeSessionId') IS NOT NULL
|
|
272162
|
+
AND r.started_at < $1
|
|
272163
|
+
ORDER BY rt, r.started_at, r.id`,
|
|
272164
|
+
[before]
|
|
272165
|
+
);
|
|
272166
|
+
const chains = /* @__PURE__ */ new Map();
|
|
272167
|
+
for (const row of rows) {
|
|
272168
|
+
const current = row.usage;
|
|
272169
|
+
let raw = current;
|
|
272170
|
+
const last = audited.get(row.id);
|
|
272171
|
+
if (last && !last.manifest.endsWith(":undo")) {
|
|
272172
|
+
const after = last.after?.usage;
|
|
272173
|
+
const prior = last.before?.usage;
|
|
272174
|
+
if (after && prior && sameUsage(after, current)) raw = prior;
|
|
272175
|
+
}
|
|
272176
|
+
const rt = row.rt;
|
|
272177
|
+
const chain = chains.get(rt) ?? [];
|
|
272178
|
+
chains.set(rt, chain);
|
|
272179
|
+
chain.push({ id: row.id, current, raw });
|
|
272180
|
+
}
|
|
272181
|
+
report.sessions = chains.size;
|
|
272182
|
+
const plan = [];
|
|
272183
|
+
for (const chain of chains.values()) {
|
|
272184
|
+
const net = claudeResumeNetUsage(chain.map((r) => r.raw));
|
|
272185
|
+
chain.forEach((r, i) => {
|
|
272186
|
+
if (sameUsage(net[i], r.current)) return;
|
|
272187
|
+
plan.push({ id: r.id, current: r.current, next: net[i] });
|
|
272188
|
+
});
|
|
272189
|
+
}
|
|
272190
|
+
report.candidates = plan.length;
|
|
272191
|
+
for (const p2 of plan) {
|
|
272192
|
+
o.sample(report, p2.id);
|
|
272193
|
+
report.costBefore += reportedCost(p2.current["costUsdMicros"]) ?? 0;
|
|
272194
|
+
report.costAfter += reportedCost(p2.next["costUsdMicros"]) ?? 0;
|
|
272195
|
+
}
|
|
272196
|
+
if (o.dryRun) return report;
|
|
272197
|
+
for (let i = 0; i < plan.length; i += o.batch) {
|
|
272198
|
+
const slice = plan.slice(i, i + o.batch);
|
|
272199
|
+
await inTx(pool, async (c) => {
|
|
272200
|
+
const at = o.now();
|
|
272201
|
+
for (const p2 of slice) {
|
|
272202
|
+
const r = await c.query(
|
|
272203
|
+
`UPDATE ${s2}.agent_runs SET usage = $2::jsonb WHERE id = $1 AND usage = $3::jsonb RETURNING id`,
|
|
272204
|
+
[p2.id, JSON.stringify(p2.next), JSON.stringify(p2.current)]
|
|
272205
|
+
);
|
|
272206
|
+
if (!r.rowCount) continue;
|
|
272207
|
+
await setFinalPoint(c, s2, p2.id, p2.next);
|
|
272208
|
+
report.changed += 1;
|
|
272209
|
+
await audit(
|
|
272210
|
+
c,
|
|
272211
|
+
s2,
|
|
272212
|
+
o.manifestId,
|
|
272213
|
+
p2.id,
|
|
272214
|
+
"claude_resume_usage",
|
|
272215
|
+
{ usage: p2.current },
|
|
272216
|
+
{ usage: p2.next },
|
|
272217
|
+
at
|
|
272218
|
+
);
|
|
272219
|
+
}
|
|
272220
|
+
});
|
|
272221
|
+
}
|
|
271000
272222
|
return report;
|
|
271001
272223
|
}
|
|
272224
|
+
async function setFinalPoint(c, s2, runId, usage) {
|
|
272225
|
+
const f2 = fourOf(usage);
|
|
272226
|
+
await c.query(
|
|
272227
|
+
`UPDATE ${s2}.agent_run_usage_points
|
|
272228
|
+
SET input_tokens = $3, output_tokens = $4, cache_read_tokens = $5, cache_creation_tokens = $6, cost_usd_micros = $7
|
|
272229
|
+
WHERE run_id = $1 AND seq = $2`,
|
|
272230
|
+
[runId, USAGE_POINT_FINAL_SEQ, f2.inputTokens, f2.outputTokens, f2.cacheReadTokens, f2.cacheCreationTokens, reportedCost(usage["costUsdMicros"])]
|
|
272231
|
+
);
|
|
272232
|
+
}
|
|
271002
272233
|
function usageLedgerViolationCount(r) {
|
|
271003
272234
|
return Object.values(r.violations).reduce((n, ids2) => n + ids2.length, 0);
|
|
271004
272235
|
}
|
|
@@ -271092,6 +272323,17 @@ async function undoUsageLedgerBackfill(ledger, manifestId, opts = {}) {
|
|
|
271092
272323
|
} else if (before !== null) {
|
|
271093
272324
|
ok3 = await insertPoint(c, s2, runId, before);
|
|
271094
272325
|
}
|
|
272326
|
+
} else if (field === "claude_resume_usage") {
|
|
272327
|
+
const prior = before?.usage;
|
|
272328
|
+
const cur = after?.usage;
|
|
272329
|
+
if (prior && cur) {
|
|
272330
|
+
const r = await c.query(
|
|
272331
|
+
`UPDATE ${s2}.agent_runs SET usage = $2::jsonb WHERE id = $1 AND usage = $3::jsonb RETURNING id`,
|
|
272332
|
+
[runId, JSON.stringify(prior), JSON.stringify(cur)]
|
|
272333
|
+
);
|
|
272334
|
+
ok3 = (r.rowCount ?? 0) > 0;
|
|
272335
|
+
if (ok3) await setFinalPoint(c, s2, runId, prior);
|
|
272336
|
+
}
|
|
271095
272337
|
} else if (field === "runtime_started_at" || field === "chat_session_id" || field === "chat_turn_id") {
|
|
271096
272338
|
const r = await c.query(
|
|
271097
272339
|
`UPDATE ${s2}.agent_runs SET ${field} = $2 WHERE id = $1 AND ${field} IS NOT DISTINCT FROM $3`,
|
|
@@ -271140,7 +272382,7 @@ async function audit(c, s2, manifestId, runId, field, before, after, createdAt)
|
|
|
271140
272382
|
[manifestId, runId, field, before == null ? null : JSON.stringify(before), after == null ? null : JSON.stringify(after), createdAt]
|
|
271141
272383
|
);
|
|
271142
272384
|
}
|
|
271143
|
-
var import_node_crypto82, BUCKETS, ENDED_SQL, START_EVIDENCE_SQL, CHAT_RUN_SQL, emptyStep, ChatRunLookup;
|
|
272385
|
+
var import_node_crypto82, BUCKETS, ENDED_SQL, START_EVIDENCE_SQL, CHAT_RUN_SQL, emptyStep, fourOf, sameUsage, ChatRunLookup;
|
|
271144
272386
|
var init_usage_ledger_backfill = __esm({
|
|
271145
272387
|
"../storage/src/usage-ledger-backfill.ts"() {
|
|
271146
272388
|
"use strict";
|
|
@@ -271163,6 +272405,13 @@ var init_usage_ledger_backfill = __esm({
|
|
|
271163
272405
|
)`;
|
|
271164
272406
|
CHAT_RUN_SQL = `r.id LIKE 'chat-run:%'`;
|
|
271165
272407
|
emptyStep = () => ({ candidates: 0, changed: 0, samples: [] });
|
|
272408
|
+
fourOf = (u) => ({
|
|
272409
|
+
inputTokens: usageBucket(u["inputTokens"]),
|
|
272410
|
+
outputTokens: usageBucket(u["outputTokens"]),
|
|
272411
|
+
cacheReadTokens: usageBucket(u["cacheReadTokens"]),
|
|
272412
|
+
cacheCreationTokens: usageBucket(u["cacheCreationTokens"])
|
|
272413
|
+
});
|
|
272414
|
+
sameUsage = (a, b2) => BUCKETS.every(([k2]) => usageBucket(a[k2]) === usageBucket(b2[k2])) && reportedCost(a["costUsdMicros"]) === reportedCost(b2["costUsdMicros"]);
|
|
271166
272415
|
ChatRunLookup = class {
|
|
271167
272416
|
constructor(sources) {
|
|
271168
272417
|
this.sources = sources;
|
|
@@ -271314,6 +272563,7 @@ __export(src_exports, {
|
|
|
271314
272563
|
buildTrigger: () => buildTrigger,
|
|
271315
272564
|
buildWorkorderIndex: () => buildWorkorderIndex,
|
|
271316
272565
|
canonicalTypeDefHash: () => canonicalTypeDefHash,
|
|
272566
|
+
claudeResumeNetUsage: () => claudeResumeNetUsage,
|
|
271317
272567
|
companySchemaName: () => companySchemaName,
|
|
271318
272568
|
copyActorMemoriesIdempotent: () => copyActorMemoriesIdempotent,
|
|
271319
272569
|
copyActorsIdempotent: () => copyActorsIdempotent,
|
|
@@ -271351,6 +272601,7 @@ __export(src_exports, {
|
|
|
271351
272601
|
newUsageBackfillManifestId: () => newUsageBackfillManifestId,
|
|
271352
272602
|
openUsageLedgerForBackfill: () => openUsageLedgerForBackfill,
|
|
271353
272603
|
payloadChecksum: () => payloadChecksum,
|
|
272604
|
+
pinChatSessionsToAgentDefault: () => pinChatSessionsToAgentDefault,
|
|
271354
272605
|
planSessionOrd: () => planSessionOrd,
|
|
271355
272606
|
provisionCompanyDataPlaneSchema: () => provisionCompanyDataPlaneSchema,
|
|
271356
272607
|
provisionNewCompanyDataPlane: () => provisionNewCompanyDataPlane,
|
|
@@ -271396,6 +272647,7 @@ var init_src10 = __esm({
|
|
|
271396
272647
|
init_postgres_chat_turns();
|
|
271397
272648
|
init_postgres_chat_items();
|
|
271398
272649
|
init_chat_items_ord_backfill();
|
|
272650
|
+
init_chat_session_runtime_pin_backfill();
|
|
271399
272651
|
init_postgres_delegations();
|
|
271400
272652
|
init_postgres_nodes();
|
|
271401
272653
|
init_postgres_model_prices();
|
|
@@ -272632,6 +273884,7 @@ __export(src_exports2, {
|
|
|
272632
273884
|
NdjsonOplogStore: () => NdjsonOplogStore,
|
|
272633
273885
|
NodeHealthTracker: () => NodeHealthTracker,
|
|
272634
273886
|
NotificationLedgerWorker: () => NotificationLedgerWorker,
|
|
273887
|
+
OPERATOR_SCOPE: () => OPERATOR_SCOPE,
|
|
272635
273888
|
ORPHANED_TURN_ASSISTANT_NOTICE: () => ORPHANED_TURN_ASSISTANT_NOTICE,
|
|
272636
273889
|
OUTPUT_COPY_LIMITS: () => OUTPUT_COPY_LIMITS,
|
|
272637
273890
|
PARENT_CONVERSATION_PATH: () => PARENT_CONVERSATION_PATH,
|
|
@@ -272723,11 +273976,13 @@ __export(src_exports2, {
|
|
|
272723
273976
|
chatBroadcastEnabledFromEnv: () => chatBroadcastEnabledFromEnv,
|
|
272724
273977
|
chatDelegationEnabledFromEnv: () => chatDelegationEnabledFromEnv,
|
|
272725
273978
|
chatDispatchScope: () => chatDispatchScope,
|
|
273979
|
+
chatExitModelFields: () => chatExitModelFields,
|
|
272726
273980
|
chatInterruptCauseOf: () => chatInterruptCauseOf,
|
|
272727
273981
|
chatInterruptItemId: () => chatInterruptItemId,
|
|
272728
273982
|
chatItemsDoubleWriteEnabled: () => chatItemsDoubleWriteEnabled,
|
|
272729
273983
|
chatNodeChanged: () => chatNodeChanged,
|
|
272730
273984
|
chatRunLedgerFields: () => chatRunLedgerFields,
|
|
273985
|
+
chatSessionInitialRuntime: () => chatSessionInitialRuntime,
|
|
272731
273986
|
childRoundMessageIds: () => childRoundMessageIds,
|
|
272732
273987
|
clampObservedAt: () => clampObservedAt,
|
|
272733
273988
|
classifyPage: () => classifyPage,
|
|
@@ -272868,6 +274123,7 @@ __export(src_exports2, {
|
|
|
272868
274123
|
isKnowledgeQueryPlanV2: () => isKnowledgeQueryPlanV2,
|
|
272869
274124
|
isLocationFailureCode: () => isLocationFailureCode,
|
|
272870
274125
|
isNodeHealthy: () => isNodeHealthy,
|
|
274126
|
+
isOperatorRequest: () => isOperatorRequest,
|
|
272871
274127
|
isRunTerminalStatus: () => isRunTerminalStatus,
|
|
272872
274128
|
isRuntimeDrifted: () => isRuntimeDrifted,
|
|
272873
274129
|
isRuntimeRunReader: () => isRuntimeRunReader,
|
|
@@ -273097,6 +274353,7 @@ var init_src11 = __esm({
|
|
|
273097
274353
|
"use strict";
|
|
273098
274354
|
init_server3();
|
|
273099
274355
|
init_tokens();
|
|
274356
|
+
init_operator();
|
|
273100
274357
|
init_session_dataplane_token();
|
|
273101
274358
|
init_dev_store();
|
|
273102
274359
|
init_control_plane_file_store();
|
|
@@ -273385,7 +274642,23 @@ function parseUsageLedgerBackfillArgs(flags) {
|
|
|
273385
274642
|
if (modes.length !== 1) {
|
|
273386
274643
|
throw new UsageLedgerBackfillArgError("--dry-run / --execute / --verify / --undo \u5FC5\u987B\u4E14\u53EA\u80FD\u9009\u4E00\u4E2A");
|
|
273387
274644
|
}
|
|
273388
|
-
|
|
274645
|
+
const mode = modes[0];
|
|
274646
|
+
let claudeResumeBefore;
|
|
274647
|
+
if (flags.has("claude-resume-before")) {
|
|
274648
|
+
const raw = flags.get("claude-resume-before");
|
|
274649
|
+
if (raw === "" || raw === "true" || Number.isNaN(Date.parse(raw))) {
|
|
274650
|
+
throw new UsageLedgerBackfillArgError("--claude-resume-before \u9700\u8981 ISO \u65F6\u523B\uFF08\u5982 2026-09-23T00:00:00Z\uFF09\uFF1A\u4FEE\u597D\u7684\u8282\u70B9\u5305\u5728\u5168\u90E8\u8282\u70B9\u88C5\u4E0A\u7684\u65F6\u523B");
|
|
274651
|
+
}
|
|
274652
|
+
if (mode.kind !== "dry-run" && mode.kind !== "execute") {
|
|
274653
|
+
throw new UsageLedgerBackfillArgError("--claude-resume-before \u53EA\u80FD\u914D --dry-run \u6216 --execute\uFF08\u64A4\u9500\u7167\u5E38\u7528 --undo\uFF09");
|
|
274654
|
+
}
|
|
274655
|
+
claudeResumeBefore = new Date(raw).toISOString();
|
|
274656
|
+
}
|
|
274657
|
+
return {
|
|
274658
|
+
scope: company !== void 0 ? { companyId: company } : { all: true },
|
|
274659
|
+
mode,
|
|
274660
|
+
...claudeResumeBefore ? { claudeResumeBefore } : {}
|
|
274661
|
+
};
|
|
273389
274662
|
}
|
|
273390
274663
|
async function runUsageLedgerBackfill(flags, io) {
|
|
273391
274664
|
let args;
|
|
@@ -273427,7 +274700,11 @@ ${USAGE_LEDGER_BACKFILL_USAGE}`);
|
|
|
273427
274700
|
const dryRun = args.mode.kind === "dry-run";
|
|
273428
274701
|
const manifestId2 = dryRun ? void 0 : storage.newUsageBackfillManifestId();
|
|
273429
274702
|
for (const l of ledgers) {
|
|
273430
|
-
const r = await storage.backfillUsageLedger(l, {
|
|
274703
|
+
const r = await storage.backfillUsageLedger(l, {
|
|
274704
|
+
dryRun,
|
|
274705
|
+
...manifestId2 ? { manifestId: manifestId2 } : {},
|
|
274706
|
+
...args.claudeResumeBefore ? { claudeResumeBefore: args.claudeResumeBefore } : {}
|
|
274707
|
+
});
|
|
273431
274708
|
const n = (step) => dryRun ? `\u5F85\u6539 ${step.candidates}` : `\u5DF2\u6539 ${step.changed}/${step.candidates}`;
|
|
273432
274709
|
io.out(`\u2014 \u8D26\u672C ${r.label}\uFF08schema=${r.schema}\uFF09`);
|
|
273433
274710
|
io.out(` 1 \u7528\u91CF\u70B9(backfill)\uFF1A${n(r.usagePoints)}${samples(r.usagePoints.samples)}`);
|
|
@@ -273435,6 +274712,12 @@ ${USAGE_LEDGER_BACKFILL_USAGE}`);
|
|
|
273435
274712
|
io.out(
|
|
273436
274713
|
` 3 \u4F1A\u8BDD/\u8F6E\u6B21\uFF1A${n(r.chat)}\uFF08\u5176\u4E2D\u8865\u8F6E\u6B21 ${r.chat.turnFilled}\uFF1B\u67E5\u4E0D\u5230 ${r.chat.notFound}\u3001\u6B67\u4E49 ${r.chat.ambiguous}\uFF0C\u4FDD\u6301 NULL\uFF09` + samples(r.chat.samples)
|
|
273437
274714
|
);
|
|
274715
|
+
if (r.claudeResume) {
|
|
274716
|
+
const c = r.claudeResume;
|
|
274717
|
+
io.out(
|
|
274718
|
+
` 4 Claude \u7EED\u8DD1\u7D2F\u8BA1\u503C\u6263\u56DE\uFF08\u5F00\u8DD1\u65E9\u4E8E ${args.claudeResumeBefore}\uFF0C${c.sessions} \u6761\u4F1A\u8BDD\u7EBF\uFF09\uFF1A${n(c)}\uFF1B\u8FD9\u4E9B run \u7684\u8D39\u7528\u5408\u8BA1 $${(c.costBefore / 1e6).toFixed(2)} \u2192 $${(c.costAfter / 1e6).toFixed(2)}` + samples(c.samples)
|
|
274719
|
+
);
|
|
274720
|
+
}
|
|
273438
274721
|
}
|
|
273439
274722
|
if (dryRun) io.out("[usage-ledger-backfill] dry-run\uFF1A\u4E00\u884C\u672A\u5199\u3002\u4E0B\u4E00\u6B65 --execute\u3002");
|
|
273440
274723
|
else {
|
|
@@ -273482,7 +274765,7 @@ var USAGE_LEDGER_BACKFILL_USAGE, UsageLedgerBackfillArgError, MAX_LISTED;
|
|
|
273482
274765
|
var init_usage_ledger_backfill_command = __esm({
|
|
273483
274766
|
"../cli/src/usage-ledger-backfill-command.ts"() {
|
|
273484
274767
|
"use strict";
|
|
273485
|
-
USAGE_LEDGER_BACKFILL_USAGE = "\u7528\u6CD5\uFF1Aoasis usage-ledger-backfill (--company <id> | --all) (--dry-run | --execute | --verify | --undo <manifestId>)";
|
|
274768
|
+
USAGE_LEDGER_BACKFILL_USAGE = "\u7528\u6CD5\uFF1Aoasis usage-ledger-backfill (--company <id> | --all) (--dry-run | --execute | --verify | --undo <manifestId>) [--claude-resume-before <ISO \u65F6\u523B>]";
|
|
273486
274769
|
UsageLedgerBackfillArgError = class extends Error {
|
|
273487
274770
|
};
|
|
273488
274771
|
MAX_LISTED = 50;
|
|
@@ -273492,7 +274775,7 @@ var init_usage_ledger_backfill_command = __esm({
|
|
|
273492
274775
|
// src/index.ts
|
|
273493
274776
|
var fs48 = __toESM(require("node:fs"));
|
|
273494
274777
|
init_src();
|
|
273495
|
-
var
|
|
274778
|
+
var os15 = __toESM(require("node:os"));
|
|
273496
274779
|
var path43 = __toESM(require("node:path"));
|
|
273497
274780
|
var import_node_child_process24 = require("node:child_process");
|
|
273498
274781
|
var import_node_crypto93 = require("node:crypto");
|
|
@@ -273500,7 +274783,7 @@ var import_node_crypto93 = require("node:crypto");
|
|
|
273500
274783
|
// ../cli/src/cli.ts
|
|
273501
274784
|
init_src();
|
|
273502
274785
|
var fs42 = __toESM(require("node:fs"), 1);
|
|
273503
|
-
var
|
|
274786
|
+
var os13 = __toESM(require("node:os"), 1);
|
|
273504
274787
|
var path37 = __toESM(require("node:path"), 1);
|
|
273505
274788
|
var import_node_crypto91 = require("node:crypto");
|
|
273506
274789
|
|
|
@@ -273510,7 +274793,7 @@ init_chat_cancel_attribution();
|
|
|
273510
274793
|
init_src();
|
|
273511
274794
|
init_src11();
|
|
273512
274795
|
var fs34 = __toESM(require("node:fs"), 1);
|
|
273513
|
-
var
|
|
274796
|
+
var os9 = __toESM(require("node:os"), 1);
|
|
273514
274797
|
var path28 = __toESM(require("node:path"), 1);
|
|
273515
274798
|
var import_node_child_process17 = require("node:child_process");
|
|
273516
274799
|
var import_node_crypto87 = require("node:crypto");
|
|
@@ -275480,132 +276763,7 @@ init_src11();
|
|
|
275480
276763
|
init_src4();
|
|
275481
276764
|
|
|
275482
276765
|
// ../cli/src/chat-exit.ts
|
|
275483
|
-
|
|
275484
|
-
init_src();
|
|
275485
|
-
init_src7();
|
|
275486
|
-
init_chat_cancel_attribution();
|
|
275487
|
-
function transcriptTail(ref2) {
|
|
275488
|
-
try {
|
|
275489
|
-
const stat4 = fs31.statSync(ref2);
|
|
275490
|
-
const size = Math.min(stat4.size, 4e3);
|
|
275491
|
-
const buf = Buffer.alloc(size);
|
|
275492
|
-
const fd = fs31.openSync(ref2, "r");
|
|
275493
|
-
try {
|
|
275494
|
-
fs31.readSync(fd, buf, 0, size, Math.max(0, stat4.size - size));
|
|
275495
|
-
} finally {
|
|
275496
|
-
fs31.closeSync(fd);
|
|
275497
|
-
}
|
|
275498
|
-
return buf.toString("utf8").trim();
|
|
275499
|
-
} catch {
|
|
275500
|
-
return "";
|
|
275501
|
-
}
|
|
275502
|
-
}
|
|
275503
|
-
var SUMMARY_MAX_CHARS = 500;
|
|
275504
|
-
function clipLine(line2) {
|
|
275505
|
-
return line2.length > SUMMARY_MAX_CHARS ? `${line2.slice(0, SUMMARY_MAX_CHARS)}\u2026` : line2;
|
|
275506
|
-
}
|
|
275507
|
-
function providerMessage(line2) {
|
|
275508
|
-
const m2 = /['"]message['"]\s*:\s*(?:'((?:[^'\\]|\\.)*)'|"((?:[^"\\]|\\.)*)")/.exec(line2);
|
|
275509
|
-
const text7 = (m2?.[1] ?? m2?.[2])?.trim();
|
|
275510
|
-
return text7 ? text7 : void 0;
|
|
275511
|
-
}
|
|
275512
|
-
var INTERNAL_PREFIX_RE = /^\[[a-z][a-z0-9_]*\]\s*/;
|
|
275513
|
-
var QUOTA_RE3 = /hit your (?:\w+ )?limit|usage limit|quota|insufficient[_ ](?:balance|credit|funds)|credit balance|billing|\b402\b|额度|余额/i;
|
|
275514
|
-
var RATE_LIMIT_RE = /rate.?limit|too many requests|\b429\b|\b529\b|overloaded|限流/i;
|
|
275515
|
-
var AUTH_RE2 = /\b401\b|\b403\b|unauthori[sz]ed|authenticat|oauth|invalid[_ -]?(?:api[_ -]?key|token|x-api-key)|api[_ -]?key[^\n]{0,40}\b(?:invalid|expired|revoked)|token[^\n]{0,30}\b(?:expired|invalid|revoked)|not logged in|\/login|credential|凭证|登录/i;
|
|
275516
|
-
var MODEL_RE = /\bmodel\b[^\n]{0,120}?\b(?:not found|not exist|does not exist|not available|not supported|unavailable|unknown)\b|\b(?:unknown|invalid|unsupported) model\b|model_not_found/i;
|
|
275517
|
-
var DISK_FULL_RE = /\bENOSPC\b|no space left on device|\bEDQUOT\b|disk quota exceeded|\[Errno 28\]|disk (?:is )?full|磁盘(?:空间)?(?:已满|不足)/i;
|
|
275518
|
-
var UNREACHABLE_RE2 = /不在线|socket 非 OPEN|帧未送达|失联/;
|
|
275519
|
-
function failureKind(reason, line2) {
|
|
275520
|
-
if (line2.startsWith(SESSION_STARTUP_FAILED_PREFIX)) return "startup-failed";
|
|
275521
|
-
switch (reason) {
|
|
275522
|
-
case "auth-error":
|
|
275523
|
-
return "auth";
|
|
275524
|
-
case "server-unreachable":
|
|
275525
|
-
return "node-unreachable";
|
|
275526
|
-
case "timeout":
|
|
275527
|
-
return "timeout";
|
|
275528
|
-
case "output-limit":
|
|
275529
|
-
return "output-limit";
|
|
275530
|
-
case "rate-limit":
|
|
275531
|
-
return QUOTA_RE3.test(line2) ? "quota" : "rate-limit";
|
|
275532
|
-
default:
|
|
275533
|
-
break;
|
|
275534
|
-
}
|
|
275535
|
-
if (!line2) return "unknown";
|
|
275536
|
-
if (DISK_FULL_RE.test(line2)) return "disk-full";
|
|
275537
|
-
if (QUOTA_RE3.test(line2)) return "quota";
|
|
275538
|
-
if (AUTH_RE2.test(line2)) return "auth";
|
|
275539
|
-
if (RATE_LIMIT_RE.test(line2)) return "rate-limit";
|
|
275540
|
-
if (MODEL_RE.test(line2)) return "model";
|
|
275541
|
-
if (UNREACHABLE_RE2.test(line2)) return "node-unreachable";
|
|
275542
|
-
return "unknown";
|
|
275543
|
-
}
|
|
275544
|
-
var chatRebindHint = (what) => `\u5728\u7EC4\u7EC7\u9875\u8FD9\u4F4D Agent \u7684\u300C\u6A21\u578B\u300D\u9875\u7B7E\u91CC${what}`;
|
|
275545
|
-
function resetTime(line2) {
|
|
275546
|
-
return extractResetHint(line2)?.replace(/^(?:resets?|try again at)\s+/i, "").trim() || void 0;
|
|
275547
|
-
}
|
|
275548
|
-
function failureSummary(kind, ctx) {
|
|
275549
|
-
switch (kind) {
|
|
275550
|
-
case "auth":
|
|
275551
|
-
return `\u5BF9\u8BDD\u5931\u8D25\uFF1A\u8FD0\u884C\u65F6\u7684\u767B\u5F55\u5DF2\u8FC7\u671F\u6216\u51ED\u8BC1\u65E0\u6548\uFF0C\u8C03\u7528\u4E0D\u4E86\u6A21\u578B\u3002\u8BF7\u8282\u70B9\u7BA1\u7406\u5458\u5728\u90A3\u53F0\u673A\u5668\u4E0A\u91CD\u65B0\u767B\u5F55\u8FD9\u4E2A\u8FD0\u884C\u65F6\uFF08\u6216\u66F4\u65B0 API Key\uFF09\u540E\u518D\u53D1\u4E00\u6B21\uFF1B\u7740\u6025\u7684\u8BDD\u4E5F\u53EF\u4EE5${chatRebindHint("\u6362\u4E00\u4E2A\u53EF\u7528\u7684\u8FD0\u884C\u65F6")}\u3002`;
|
|
275552
|
-
case "quota": {
|
|
275553
|
-
const at = resetTime(ctx.line);
|
|
275554
|
-
return `\u5BF9\u8BDD\u5931\u8D25\uFF1A\u6A21\u578B\u989D\u5EA6\u5DF2\u7528\u5B8C${at ? `\uFF0C\u9884\u8BA1 ${at} \u6062\u590D` : ""}\u3002\u8BF7\u7B49\u989D\u5EA6\u6062\u590D\u540E\u518D\u53D1\u4E00\u6B21\uFF1B\u7740\u6025\u7684\u8BDD\u53EF\u4EE5${chatRebindHint("\u6362\u4E00\u4E2A\u989D\u5EA6\u5145\u8DB3\u7684\u8FD0\u884C\u65F6")}\u3002`;
|
|
275555
|
-
}
|
|
275556
|
-
case "rate-limit":
|
|
275557
|
-
return "\u5BF9\u8BDD\u5931\u8D25\uFF1A\u6A21\u578B\u670D\u52A1\u6682\u65F6\u9650\u6D41\u6216\u7E41\u5FD9\u3002\u8BF7\u7B49\u4E00\u4E24\u5206\u949F\u518D\u53D1\u4E00\u6B21\u3002";
|
|
275558
|
-
case "node-unreachable":
|
|
275559
|
-
return `\u5BF9\u8BDD\u5931\u8D25\uFF1A\u8FD0\u884C\u8FD9\u4F4D Agent \u7684\u8282\u70B9\u79BB\u7EBF\u6216\u8FDE\u63A5\u4E2D\u65AD\u3002\u8BF7\u786E\u8BA4\u90A3\u53F0\u673A\u5668\u5F00\u7740\u3001\u8282\u70B9\u7A0B\u5E8F\u5728\u8FD0\u884C\u3001\u7F51\u7EDC\u6B63\u5E38\u540E\u518D\u53D1\u4E00\u6B21\uFF1B\u4E5F\u53EF\u4EE5${chatRebindHint("\u6362\u4E00\u4E2A\u5728\u7EBF\u7684\u8FD0\u884C\u65F6")}\u3002`;
|
|
275560
|
-
case "model":
|
|
275561
|
-
return `\u5BF9\u8BDD\u5931\u8D25\uFF1A\u8FD9\u4E2A\u8FD0\u884C\u65F6\u7528\u4E0D\u4E86\u5F53\u524D\u914D\u7F6E\u7684\u6A21\u578B\u3002\u8BF7${chatRebindHint("\u6362\u4E00\u4E2A\u53EF\u7528\u7684\u6A21\u578B")}\u540E\u518D\u53D1\u4E00\u6B21\u3002`;
|
|
275562
|
-
case "timeout":
|
|
275563
|
-
return "\u5BF9\u8BDD\u5931\u8D25\uFF1A\u8FD9\u4E00\u8F6E\u8FD0\u884C\u8D85\u8FC7\u4E86\u65F6\u95F4\u4E0A\u9650\uFF0C\u5DF2\u88AB\u7EC8\u6B62\u3002\u53EF\u4EE5\u628A\u4EFB\u52A1\u62C6\u5C0F\u4E00\u4E9B\u518D\u53D1\u3002";
|
|
275564
|
-
case "startup-failed":
|
|
275565
|
-
return `\u5BF9\u8BDD\u5931\u8D25\uFF1A${ctx.readable || SESSION_STARTUP_FAILED_PREFIX}\u3002\u8FD9\u4E00\u8F6E\u6CA1\u6709\u5F00\u59CB\u8FD0\u884C\uFF0C\u53EF\u4EE5\u76F4\u63A5\u518D\u53D1\u4E00\u6B21\uFF1B\u53CD\u590D\u51FA\u73B0\u7684\u8BDD\uFF0C\u591A\u534A\u662F\u90A3\u53F0\u8282\u70B9\u8D1F\u8F7D\u8FC7\u9AD8\uFF0C\u8BF7\u7BA1\u7406\u5458\u7ED9\u5B83\u51CF\u8D1F\u6216${chatRebindHint("\u6362\u4E00\u4E2A\u8FD0\u884C\u65F6")}\u3002`;
|
|
275566
|
-
case "disk-full":
|
|
275567
|
-
return `\u5BF9\u8BDD\u5931\u8D25\uFF1A\u8FD0\u884C\u8FD9\u4F4D Agent \u7684\u8282\u70B9\u78C1\u76D8\u7A7A\u95F4\u6EE1\u4E86\uFF0C\u8FD9\u4E00\u8F6E\u5199\u4E0D\u4E86\u6587\u4EF6\u3002\u8BF7\u8282\u70B9\u7BA1\u7406\u5458\u6E05\u7406\u90A3\u53F0\u673A\u5668\u7684\u78C1\u76D8\u540E\u518D\u53D1\u4E00\u6B21\uFF1B\u7740\u6025\u7684\u8BDD\u4E5F\u53EF\u4EE5${chatRebindHint("\u6362\u4E00\u4E2A\u8FD0\u884C\u65F6")}\u3002`;
|
|
275568
|
-
case "output-limit":
|
|
275569
|
-
return "\u5BF9\u8BDD\u5931\u8D25\uFF1A\u6A21\u578B\u8F93\u51FA\u8D85\u51FA\u957F\u5EA6\u4E0A\u9650\uFF0C\u56DE\u590D\u88AB\u622A\u65AD\u4E86\u3002\u53EF\u4EE5\u8BA9\u5B83\u5206\u51E0\u6B21\u8F93\u51FA\uFF0C\u6216\u628A\u4EFB\u52A1\u62C6\u5C0F\u4E00\u4E9B\u518D\u53D1\u3002";
|
|
275570
|
-
case "unknown":
|
|
275571
|
-
if (ctx.line) {
|
|
275572
|
-
return "\u5BF9\u8BDD\u5931\u8D25\uFF1A\u8FD0\u884C\u65F6\u62A5\u9519\u4E86\uFF0C\u6682\u65F6\u6CA1\u8BA4\u51FA\u662F\u4EC0\u4E48\u539F\u56E0\u3002\u53EF\u4EE5\u7A0D\u540E\u518D\u53D1\u4E00\u6B21\uFF1B\u53CD\u590D\u51FA\u73B0\u7684\u8BDD\uFF0C\u8BF7\u70B9\u300C\u5C55\u5F00\u8BE6\u60C5\u300D\u628A\u539F\u59CB\u62A5\u9519\u53D1\u7ED9\u7BA1\u7406\u5458\u3002";
|
|
275573
|
-
}
|
|
275574
|
-
return ctx.hasDetail ? "\u5BF9\u8BDD\u5931\u8D25\uFF1A\u8FD0\u884C\u65F6\u5F02\u5E38\u9000\u51FA\uFF0C\u6CA1\u6709\u7ED9\u51FA\u62A5\u9519\u539F\u56E0\u3002\u53EF\u4EE5\u7A0D\u540E\u518D\u53D1\u4E00\u6B21\uFF1B\u53CD\u590D\u51FA\u73B0\u7684\u8BDD\uFF0C\u8BF7\u70B9\u300C\u5C55\u5F00\u8BE6\u60C5\u300D\u628A\u539F\u59CB\u8BB0\u5F55\u53D1\u7ED9\u7BA1\u7406\u5458\u3002" : `\u5BF9\u8BDD\u5931\u8D25\uFF1A\u8FD0\u884C\u65F6\u5F02\u5E38\u9000\u51FA\uFF08\u9000\u51FA\u7801 ${ctx.code ?? "\u65E0"}\uFF09\uFF0C\u6CA1\u6709\u7559\u4E0B\u62A5\u9519\u4FE1\u606F\u3002\u53EF\u4EE5\u7A0D\u540E\u518D\u53D1\u4E00\u6B21\uFF1B\u53CD\u590D\u51FA\u73B0\u7684\u8BDD\uFF0C\u8BF7\u7BA1\u7406\u5458\u5230\u300C\u8FD0\u884C\u8F68\u8FF9\u300D\u91CC\u67E5\u8FD9\u4E00\u8F6E\u3002`;
|
|
275575
|
-
}
|
|
275576
|
-
}
|
|
275577
|
-
function buildChatExitError(info) {
|
|
275578
|
-
const genericLine = `runtime exited with code ${info.code ?? "null"}${info.reason ? ` (${info.reason})` : ""}`;
|
|
275579
|
-
let detail = "";
|
|
275580
|
-
if (info.reason !== "cancelled") {
|
|
275581
|
-
detail = info.errorMessage?.trim() ?? "";
|
|
275582
|
-
if (!detail && info.transcriptRef) detail = transcriptTail(info.transcriptRef);
|
|
275583
|
-
}
|
|
275584
|
-
let summary;
|
|
275585
|
-
let cancelledBy;
|
|
275586
|
-
if (info.reason === "cancelled") {
|
|
275587
|
-
cancelledBy = cancelCauseFromExitMessage(info.errorMessage);
|
|
275588
|
-
summary = chatCancelNote(cancelledBy);
|
|
275589
|
-
} else {
|
|
275590
|
-
const firstErrorLine = (info.errorMessage?.split("\n").map((line2) => line2.trim()).find(Boolean) ?? "").replace(INTERNAL_PREFIX_RE, "");
|
|
275591
|
-
const readable = firstErrorLine ? clipLine(providerMessage(firstErrorLine) ?? firstErrorLine) : "";
|
|
275592
|
-
summary = failureSummary(failureKind(info.reason, firstErrorLine), {
|
|
275593
|
-
readable,
|
|
275594
|
-
line: firstErrorLine,
|
|
275595
|
-
hasDetail: Boolean(detail),
|
|
275596
|
-
code: info.code
|
|
275597
|
-
});
|
|
275598
|
-
}
|
|
275599
|
-
const chatExit = {
|
|
275600
|
-
...info.reason ? { reason: info.reason } : {},
|
|
275601
|
-
summary,
|
|
275602
|
-
...cancelledBy ? { cancelledBy } : {},
|
|
275603
|
-
...detail ? { detail: `${genericLine}
|
|
275604
|
-
|
|
275605
|
-
${detail}`.slice(0, 4200) } : {}
|
|
275606
|
-
};
|
|
275607
|
-
return Object.assign(new Error(summary), { chatExit });
|
|
275608
|
-
}
|
|
276766
|
+
init_chat_exit();
|
|
275609
276767
|
|
|
275610
276768
|
// ../cli/src/chat-task-header.ts
|
|
275611
276769
|
init_src11();
|
|
@@ -276398,15 +277556,15 @@ function oasisWrapperScript() {
|
|
|
276398
277556
|
const main = path28.join(repoRoot, "packages/cli/src/main.ts");
|
|
276399
277557
|
const key2 = (0, import_node_crypto87.createHash)("sha256").update(repoRoot).digest("hex").slice(0, 12);
|
|
276400
277558
|
const uid = typeof process.getuid === "function" ? process.getuid() : "na";
|
|
276401
|
-
const stable = path28.join(
|
|
277559
|
+
const stable = path28.join(os9.tmpdir(), `oasis-cli-wrapper-${uid}-${key2}`);
|
|
276402
277560
|
let dir;
|
|
276403
277561
|
try {
|
|
276404
277562
|
fs34.mkdirSync(stable, { recursive: true, mode: 448 });
|
|
276405
277563
|
const st = fs34.lstatSync(stable);
|
|
276406
277564
|
const mine = st.isDirectory() && !st.isSymbolicLink() && (typeof process.getuid !== "function" || st.uid === process.getuid());
|
|
276407
|
-
dir = mine ? stable : fs34.mkdtempSync(path28.join(
|
|
277565
|
+
dir = mine ? stable : fs34.mkdtempSync(path28.join(os9.tmpdir(), "oasis-cli-"));
|
|
276408
277566
|
} catch {
|
|
276409
|
-
dir = fs34.mkdtempSync(path28.join(
|
|
277567
|
+
dir = fs34.mkdtempSync(path28.join(os9.tmpdir(), "oasis-cli-"));
|
|
276410
277568
|
}
|
|
276411
277569
|
const wrapper = path28.join(dir, "oasis");
|
|
276412
277570
|
fs34.writeFileSync(wrapper, `#!/usr/bin/env bash
|
|
@@ -276632,7 +277790,8 @@ async function startServe(opts) {
|
|
|
276632
277790
|
const reloadTimeoutPolicy = () => {
|
|
276633
277791
|
try {
|
|
276634
277792
|
activeTimeoutPolicy = loadPolicyFromFile(resolvePolicyFilePath());
|
|
276635
|
-
|
|
277793
|
+
syncChatWallClockCopy();
|
|
277794
|
+
console.log(`[serve] timeout-policy \u5DF2\u70ED\u8F7D\uFF08version=${activeTimeoutPolicy.version}\uFF0Cchat \u5899\u949F=${wallClockForKind("chat")}ms\uFF09`);
|
|
276636
277795
|
return { ok: true, version: activeTimeoutPolicy.version };
|
|
276637
277796
|
} catch (err) {
|
|
276638
277797
|
console.error(`[serve] timeout-policy \u70ED\u8F7D\u5931\u8D25\uFF0C\u4FDD\u7559\u65E7\u7B56\u7565\uFF1A${err.message}`);
|
|
@@ -276646,6 +277805,8 @@ async function startServe(opts) {
|
|
|
276646
277805
|
return (act.cadence.find((s2) => s2.reassignAfter) ?? act.cadence[act.cadence.length - 1]).atMs;
|
|
276647
277806
|
};
|
|
276648
277807
|
const wallClockForKind = (runtimeKind) => activeTimeoutPolicy.resolve({ executor: "agent", scenario: "wall-clock", runtimeKind }).wallClockMs ?? 120 * 6e4;
|
|
277808
|
+
const syncChatWallClockCopy = () => setChatWallClockMs(wallClockForKind("chat"));
|
|
277809
|
+
syncChatWallClockCopy();
|
|
276649
277810
|
const loadJson = (name) => {
|
|
276650
277811
|
const file = path28.join(opts.dir, name);
|
|
276651
277812
|
return fs34.existsSync(file) ? JSON.parse(fs34.readFileSync(file, "utf8")) : void 0;
|
|
@@ -276767,8 +277928,8 @@ async function startServe(opts) {
|
|
|
276767
277928
|
);
|
|
276768
277929
|
const issuer = createTokenIssuer({ secretFile: path28.join(opts.dir, "session-token-secret") });
|
|
276769
277930
|
const apiActivity = createApiActivityLedger();
|
|
276770
|
-
const operatorActor = `actor:human:${
|
|
276771
|
-
const operatorToken = issuer.issue(operatorActor);
|
|
277931
|
+
const operatorActor = `actor:human:${os9.userInfo().username}`;
|
|
277932
|
+
const operatorToken = issuer.issue(operatorActor, { scopes: [OPERATOR_SCOPE] });
|
|
276772
277933
|
fs34.writeFileSync(path28.join(opts.dir, "operator-token"), operatorToken, { mode: 384 });
|
|
276773
277934
|
let nodeTokens = createNodeTokenStore(path28.join(opts.dir, "node-tokens.json"));
|
|
276774
277935
|
const enrollTokens = createEnrollTokenStore(30 * 60 * 1e3, path28.join(opts.dir, "enroll-tokens.json"));
|
|
@@ -278605,6 +279766,37 @@ async function startServe(opts) {
|
|
|
278605
279766
|
return plan && plan.injectedHistoryCount > 0 ? plan.runtimeMessage : void 0;
|
|
278606
279767
|
};
|
|
278607
279768
|
const resolveCompanyBinding = createCompanyBindingResolver({ actors, defaultCompanyId });
|
|
279769
|
+
if (pgPool) {
|
|
279770
|
+
const pinPool = pgPool;
|
|
279771
|
+
void (async () => {
|
|
279772
|
+
try {
|
|
279773
|
+
const companies2 = await controlPlaneStore.listCompanies();
|
|
279774
|
+
const total = { scanned: 0, pinned: 0, leftUnbound: 0, unresolved: 0 };
|
|
279775
|
+
for (const c of companies2) {
|
|
279776
|
+
const rep = await pinChatSessionsToAgentDefault(pinPool, engineSchemaFor(c.id), {
|
|
279777
|
+
companyId: c.id,
|
|
279778
|
+
// 与派发、与委派回流、与 chat 工作区读口**同一个** resolver 实例——存量钉住的目标必须
|
|
279779
|
+
// 与「不钉时这一轮会派到哪」逐字相同,否则这条迁移本身就改了行为。
|
|
279780
|
+
resolveBinding: async (actorId) => {
|
|
279781
|
+
const b2 = await resolveCompanyBinding(c.id, actorId);
|
|
279782
|
+
return b2 ? { nodeId: b2.nodeId, runtimeKind: b2.runtimeKind } : null;
|
|
279783
|
+
}
|
|
279784
|
+
});
|
|
279785
|
+
total.scanned += rep.scanned;
|
|
279786
|
+
total.pinned += rep.pinned;
|
|
279787
|
+
total.leftUnbound += rep.leftUnbound;
|
|
279788
|
+
total.unresolved += rep.unresolved;
|
|
279789
|
+
}
|
|
279790
|
+
if (total.scanned > 0) {
|
|
279791
|
+
console.log(
|
|
279792
|
+
`[chat-runtime-pin] ADR 0613 \u5B58\u91CF\u4F1A\u8BDD\u9489\u76EE\u6807\uFF1A\u547D\u4E2D ${total.scanned} \u6761\u3001\u5199\u5165 ${total.pinned} \u6761\u3001\u5458\u5DE5\u672A\u7ED1\u5B9A\u7559\u7A7A ${total.leftUnbound} \u6761\u3001binding \u89E3\u6790\u5931\u8D25 ${total.unresolved} \u6761`
|
|
279793
|
+
);
|
|
279794
|
+
}
|
|
279795
|
+
} catch (err) {
|
|
279796
|
+
console.warn(`[chat-runtime-pin] \u5B58\u91CF\u4F1A\u8BDD\u9489\u76EE\u6807\u5931\u8D25\uFF08\u4E0D\u5F71\u54CD\u542F\u52A8\uFF0C\u4E0B\u6B21\u542F\u52A8\u5E42\u7B49\u91CD\u8BD5\uFF09\uFF1A`, err);
|
|
279797
|
+
}
|
|
279798
|
+
})();
|
|
279799
|
+
}
|
|
278608
279800
|
const delegationWorkdirLocator = buildDelegationWorkdirLocator({
|
|
278609
279801
|
// ⭐ 与派发、与 chat-sessions 域**同一个 resolver 实例**(评审 blocker ① 五修):
|
|
278610
279802
|
// 生产 `resolveCompanyBinding` 在上文构造一次,喂给这里、`dispatchChatImpl`、
|
|
@@ -279036,7 +280228,7 @@ async function startServe(opts) {
|
|
|
279036
280228
|
// 派发台账:动态卡的 runId 与「执行轨迹」抽屉靠它把 work/review 硬关联到 agent_runs.id。
|
|
279037
280229
|
// 与上面 createServer 的 `dispatchesOfWorkorder`(timeline 用)是同一个闭包,别分叉。
|
|
279038
280230
|
dispatchesOfWorkorder: (wid) => fanOutLedger.listByWorkorder(wid),
|
|
279039
|
-
// 任务动态**协调者卡**(F2
|
|
280231
|
+
// 任务动态**协调者卡**(F2)的轨迹入口:协调者不走 dispatcher,台账里没有它,只能从 agent_runs 取。
|
|
279040
280232
|
// 扇出理由同 `dispatchesOfWorkorder`:这个回调拿不到公司,而一张工单只属于一家。
|
|
279041
280233
|
coordinatorRunsOfWorkorder: (wid) => fanOutTrace.listCoordinatorRuns(wid),
|
|
279042
280234
|
// 连败熔断卡面的「末次:{失败原文首句}」:原话只在 `agent_runs.error_message`,快照里只有分类词。
|
|
@@ -279113,6 +280305,13 @@ async function startServe(opts) {
|
|
|
279113
280305
|
// store(`public.actor_bindings`),org-registry cutover 之后它是冻结旧镜像——只留给
|
|
279114
280306
|
// 本域其它老读口,工作区定位一律不许再用它。
|
|
279115
280307
|
resolveBinding: resolveCompanyBinding,
|
|
280308
|
+
/* ADR 0613:建会话 / 「恢复为员工默认运行配置」这两下要读员工详情页配的型号,按**当前公司**读
|
|
280309
|
+
(与 `resolveBinding` 同一条理由:全局 `registry` 对已切 `actor-config` 的公司是冻结旧镜像)。
|
|
280310
|
+
⚠ 只有这两下读它;解析每一轮的模型依旧不读员工配置(ADR 0610 D1)。 */
|
|
280311
|
+
resolveActorModel: async (cid, actorId) => {
|
|
280312
|
+
const ctx = await actors.resolveCtx(cid ?? defaultCompanyId);
|
|
280313
|
+
return (await ctx.service.latestConfig(actorId))?.model ?? null;
|
|
280314
|
+
},
|
|
279116
280315
|
// 按 runId 路由:切换后新会话的事件落在本公司库里,共享 store 会一条都补不出 parts。
|
|
279117
280316
|
// ⚠ `runRoutedTrace` 声明在本行**之后**:包成箭头函数避 TDZ(本域只需要 listEvents)。
|
|
279118
280317
|
trace: { listEvents: (runId, o) => runRoutedTrace.listEvents(runId, o) },
|
|
@@ -279200,7 +280399,11 @@ async function startServe(opts) {
|
|
|
279200
280399
|
resolveChatItems: (companyId) => chatItemsFor(companyId),
|
|
279201
280400
|
liveChat,
|
|
279202
280401
|
// ADR-0587:列表行派生 `unread`,与 collab 域收件箱读同一份按公司的水位(无 PG 时闭包自己回落单实例)。
|
|
279203
|
-
resolveReadMarkers: readMarkerStoreFor
|
|
280402
|
+
resolveReadMarkers: readMarkerStoreFor,
|
|
280403
|
+
// ADR 0610 D4:`GET /api/chat-sessions/:id/usage` 的取数口——**与 collab 域是同一个实例**,
|
|
280404
|
+
// 按会话取数与组织统计因此永远同一份账本、同一套归属,不会出现两条路各算各的。
|
|
280405
|
+
usageRead,
|
|
280406
|
+
defaultCompanyId
|
|
279204
280407
|
})] : []
|
|
279205
280408
|
],
|
|
279206
280409
|
workorderDrafts,
|
|
@@ -279747,7 +280950,9 @@ async function startServe(opts) {
|
|
|
279747
280950
|
...c.dispatchId !== void 0 ? { dispatchId: c.dispatchId } : {},
|
|
279748
280951
|
// ADR-0078 D3:写入围栏的钥匙
|
|
279749
280952
|
...c.artifactId !== void 0 ? { artifactId: c.artifactId } : {},
|
|
279750
|
-
...c.sessionId !== void 0 ? { sessionId: c.sessionId } : {}
|
|
280953
|
+
...c.sessionId !== void 0 ? { sessionId: c.sessionId } : {},
|
|
280954
|
+
// ADR 0610 D1:签名 scopes 透给域路由,`isOperatorRequest` 据此认出部署级 operator-token。
|
|
280955
|
+
...c.scopes !== void 0 ? { scopes: c.scopes } : {}
|
|
279751
280956
|
} : null;
|
|
279752
280957
|
},
|
|
279753
280958
|
/**
|
|
@@ -280071,9 +281276,10 @@ async function startServe(opts) {
|
|
|
280071
281276
|
const provision = isolatedKnowledgeTurn ? { env: {}, wrapperPaths: [], requiredTools: [], requiredToolVersions: {}, connectorCreds: [], cleanup: async () => void 0 } : await buildActorProvision(actorService, actorId, chatDispatchScope(priorChatSession));
|
|
280072
281277
|
const actorCtx = await buildActorContext(actorService, actorId).catch(() => null);
|
|
280073
281278
|
const sessionModel = configuredModel(sessionModelOverride);
|
|
280074
|
-
const
|
|
281279
|
+
const actorConfiguredModel = isolatedBackground ? configuredModel(actorCtx?.config?.model) : void 0;
|
|
281280
|
+
const chatResolvedModel = sessionModel ?? actorConfiguredModel;
|
|
280075
281281
|
const chatModel = chatResolvedModel ?? await registryStore.getRuntimeConfig(`runtime:${binding.nodeId}:${binding.runtimeKind}`).then((c) => configuredModel(c?.model)).catch(() => void 0);
|
|
280076
|
-
const chatModelSource = sessionModel ? "session_override" :
|
|
281282
|
+
const chatModelSource = sessionModel ? "session_override" : actorConfiguredModel ? "actor_config" : chatModel ? "runtime_default" : null;
|
|
280077
281283
|
const attachmentFiles = { ...preparedAttachments.files, ...restore ? { "SESSION_FILES.md": restore.index } : {} };
|
|
280078
281284
|
const attachmentBinary = { ...preparedAttachments.binaryFiles };
|
|
280079
281285
|
const attachmentPaths = [...preparedAttachments.paths];
|
|
@@ -280290,8 +281496,7 @@ async function startServe(opts) {
|
|
|
280290
281496
|
startedAt: endedAt
|
|
280291
281497
|
}]);
|
|
280292
281498
|
const usage = info.usage ?? null;
|
|
280293
|
-
const
|
|
280294
|
-
const modelSource = info.model ? "runtime" : chatModelSource;
|
|
281499
|
+
const modelFields = chatExitModelFields(info.model, chatModel, chatModelSource);
|
|
280295
281500
|
let nativeSessionMetadata;
|
|
280296
281501
|
if (info.runtimeSessionId && info.runtimeSessionId !== runtimeSessionId) {
|
|
280297
281502
|
const run = await (await traceStoreFor(runCompanyId)).getRun(traceRunId).catch(() => null);
|
|
@@ -280306,8 +281511,7 @@ async function startServe(opts) {
|
|
|
280306
281511
|
...!isHealthySessionExit(info) && info.reason !== "cancelled" ? { errorCode: info.reason ?? "error", errorMessage: formatExitError(info) } : {},
|
|
280307
281512
|
transcriptRef: info.transcriptRef ?? null,
|
|
280308
281513
|
usage,
|
|
280309
|
-
|
|
280310
|
-
modelSource,
|
|
281514
|
+
...modelFields,
|
|
280311
281515
|
...nativeSessionMetadata ? { metadata: nativeSessionMetadata } : {}
|
|
280312
281516
|
});
|
|
280313
281517
|
if (usage) await settleRunUsage(await traceStoreFor(runCompanyId), traceRunId);
|
|
@@ -280420,7 +281624,11 @@ async function startServe(opts) {
|
|
|
280420
281624
|
info.chatSessionId,
|
|
280421
281625
|
`\u5B50\u4F1A\u8BDD\u8FD9\u4E00\u8F6E\u88AB\u6062\u590D\u5668\u6536\u53E3\u4E3A ${info.status}\uFF08${info.reason}\uFF09`,
|
|
280422
281626
|
info.companyId,
|
|
280423
|
-
{
|
|
281627
|
+
{
|
|
281628
|
+
outcome: info.status === "succeeded" ? "succeeded" : "failed",
|
|
281629
|
+
...info.turnId ? { turnId: info.turnId } : {},
|
|
281630
|
+
...info.exitReason ? { exitReason: info.exitReason } : {}
|
|
281631
|
+
}
|
|
280424
281632
|
);
|
|
280425
281633
|
};
|
|
280426
281634
|
const handshakeThrottleOpts = {};
|
|
@@ -282883,6 +284091,11 @@ ${nodeFault}` : "");
|
|
|
282883
284091
|
const zbCostThresholdMicros = opts.zeroOutputBreaker?.costThresholdMicros ?? (envInt("OASIS_ZERO_OUTPUT_BREAKER_COST_USD") ?? 0) * 1e6;
|
|
282884
284092
|
if (zbEnabled && zbIntervalMs > 0 && (zbThreshold > 0 || zbCostThresholdMicros > 0)) {
|
|
282885
284093
|
const zbActions = /* @__PURE__ */ new Set(["produce", "review"]);
|
|
284094
|
+
const engineWorkIdOf = (metadata) => {
|
|
284095
|
+
if (!metadata || typeof metadata !== "object" || Array.isArray(metadata)) return null;
|
|
284096
|
+
const v2 = metadata["engineWorkId"];
|
|
284097
|
+
return typeof v2 === "string" && v2.trim() ? v2 : null;
|
|
284098
|
+
};
|
|
282886
284099
|
const listRecentZeroOutputRuns = async (sinceIso) => {
|
|
282887
284100
|
const items = await fanOutTrace.listRunsAcrossWithCompany(
|
|
282888
284101
|
{ status: "no-output", from: sinceIso, limit: 1e3 },
|
|
@@ -282896,7 +284109,10 @@ ${nodeFault}` : "");
|
|
|
282896
284109
|
actorId: r.actorId,
|
|
282897
284110
|
action: r.action,
|
|
282898
284111
|
startedAt: r.startedAt,
|
|
282899
|
-
costUsdMicros: r.usage?.costUsdMicros ?? null
|
|
284112
|
+
costUsdMicros: r.usage?.costUsdMicros ?? null,
|
|
284113
|
+
// ★ 轮次维度(Bug 0211):同一轮里的协议续唤各是一条 run,只数 run 会让上报正文那个数
|
|
284114
|
+
// 比人点开轨迹数到的段数大。**只影响正文措辞,不影响跳闸判据**(阈值仍按 run 数判)。
|
|
284115
|
+
workId: engineWorkIdOf(r.metadata)
|
|
282900
284116
|
}));
|
|
282901
284117
|
};
|
|
282902
284118
|
const latestClosingRemark = async (runId) => {
|
|
@@ -285433,7 +286649,7 @@ async function startNode(opts) {
|
|
|
285433
286649
|
}
|
|
285434
286650
|
|
|
285435
286651
|
// ../cli/src/exec.ts
|
|
285436
|
-
var
|
|
286652
|
+
var os12 = __toESM(require("node:os"), 1);
|
|
285437
286653
|
var UnsafeExecArgvError = class extends Error {
|
|
285438
286654
|
code = "ERR_UNSAFE_EXEC_ARGV";
|
|
285439
286655
|
constructor(message) {
|
|
@@ -285470,7 +286686,7 @@ function planExec(opts) {
|
|
|
285470
286686
|
function computeExitCode(code2, signal) {
|
|
285471
286687
|
if (code2 !== null) return code2;
|
|
285472
286688
|
if (signal) {
|
|
285473
|
-
const num4 =
|
|
286689
|
+
const num4 = os12.constants.signals[signal];
|
|
285474
286690
|
return 128 + (typeof num4 === "number" ? num4 : 1);
|
|
285475
286691
|
}
|
|
285476
286692
|
return 1;
|
|
@@ -285720,7 +286936,7 @@ var COMMAND_DECLS = {
|
|
|
285720
286936
|
},
|
|
285721
286937
|
"usage-ledger-backfill": {
|
|
285722
286938
|
group: "\u57FA\u7840\u8BBE\u65BD",
|
|
285723
|
-
usage: "oasis usage-ledger-backfill (--company <id> | --all) (--dry-run | --execute | --verify | --undo <manifestId>)",
|
|
286939
|
+
usage: "oasis usage-ledger-backfill (--company <id> | --all) (--dry-run | --execute | --verify | --undo <manifestId>) [--claude-resume-before <ISO>]",
|
|
285724
286940
|
description: "\u7528\u91CF\u8D26\u672C\u5386\u53F2\u56DE\u586B\uFF08\u4F7F\u7528\u4E0E\u7EDF\u8BA1\uFF09\uFF1A\u8865\u7EC8\u503C\u7528\u91CF\u70B9\u3001runtime_started_at\u3001chat \u4F1A\u8BDD/\u8F6E\u6B21\uFF1B\u5E42\u7B49\uFF0C\u6539\u52A8\u5199\u5BA1\u8BA1\u8868\uFF0C\u53EF\u6309 manifest \u64A4\u9500\u3002\u4EE5 serve \u7684\u73AF\u5883\u5728\u90E8\u7F72\u673A\u4E0A\u6267\u884C\u3002",
|
|
285725
286941
|
flags: [
|
|
285726
286942
|
{ name: "company", desc: "\u53EA\u5904\u7406\u8FD9\u5BB6\u516C\u53F8\u7684\u8D26\u672C\uFF08\u4ECD\u5728 legacy \u7684\u516C\u53F8 = \u5171\u4EAB\u8D26\u672C + \u672C\u516C\u53F8 chat \u53CD\u67E5\uFF09" },
|
|
@@ -285728,10 +286944,12 @@ var COMMAND_DECLS = {
|
|
|
285728
286944
|
{ name: "dry-run", desc: "\u53EA\u62A5\u6BCF\u4E2A\u8D26\u672C\u5404\u6B65\u5F85\u6539\u6761\u6570\u548C\u6837\u4F8B run id\uFF0C\u4E00\u884C\u4E0D\u5199", boolean: true },
|
|
285729
286945
|
{ name: "execute", desc: "\u5199\u5165\uFF1B\u7ED3\u675F\u65F6\u6253\u5370 manifestId", boolean: true },
|
|
285730
286946
|
{ name: "verify", desc: "\u6838\u5BF9 I6\uFF08\u7EC8\u503C\u70B9 = agent_runs.usage\u3001\u68C0\u67E5\u70B9\u4E0D\u8D85\u7EC8\u503C\uFF09\u4E0E\u542F\u52A8\u8BC1\u636E\uFF1B\u6709\u8FDD\u4F8B\u9000\u51FA\u7801 1", boolean: true },
|
|
285731
|
-
{ name: "undo", desc: "\u6309\u5BA1\u8BA1\u8868\u628A\u67D0\u4E2A manifestId \u7684\u6539\u52A8\u6062\u590D\u539F\u503C" }
|
|
286947
|
+
{ name: "undo", desc: "\u6309\u5BA1\u8BA1\u8868\u628A\u67D0\u4E2A manifestId \u7684\u6539\u52A8\u6062\u590D\u539F\u503C" },
|
|
286948
|
+
{ name: "claude-resume-before", desc: "\u52A0\u8DD1\u7B2C 4 \u6B65\uFF1A\u5F00\u8DD1\u65E9\u4E8E\u8FD9\u4E2A\u65F6\u523B\u7684 claude-code run\uFF0C\u628A\u7EED\u8DD1\u5E26\u8FDB\u6765\u7684\u6574\u6761\u4F1A\u8BDD\u7EBF\u7D2F\u8BA1\u503C\u6263\u56DE\u6210\u672C\u8F6E\u51C0\u503C\uFF08\u53D6\u4FEE\u597D\u7684\u8282\u70B9\u5305\u5728\u5168\u90E8\u8282\u70B9\u88C5\u4E0A\u7684\u65F6\u523B\uFF09" }
|
|
285732
286949
|
],
|
|
285733
286950
|
examples: [
|
|
285734
286951
|
"oasis usage-ledger-backfill --all --dry-run",
|
|
286952
|
+
"oasis usage-ledger-backfill --all --dry-run --claude-resume-before 2026-09-23T00:00:00Z",
|
|
285735
286953
|
"oasis usage-ledger-backfill --all --execute",
|
|
285736
286954
|
"oasis usage-ledger-backfill --all --verify"
|
|
285737
286955
|
]
|
|
@@ -288074,7 +289292,7 @@ async function waitForCommandAuthorization(base, headers, draftId, fallback) {
|
|
|
288074
289292
|
}
|
|
288075
289293
|
}
|
|
288076
289294
|
}
|
|
288077
|
-
var CLI_VERSION = "2.2.
|
|
289295
|
+
var CLI_VERSION = "2.2.70" ? "2.2.70" : "dev";
|
|
288078
289296
|
function apiHeaders(token, company) {
|
|
288079
289297
|
const headers = {
|
|
288080
289298
|
authorization: `Bearer ${token}`,
|
|
@@ -288309,7 +289527,7 @@ async function runCli(argv, println = console.log, progressln = console.error) {
|
|
|
288309
289527
|
const res = await fetch(`${httpBase2}/api/nodes/exchange`, {
|
|
288310
289528
|
method: "POST",
|
|
288311
289529
|
headers: { "content-type": "application/json" },
|
|
288312
|
-
body: JSON.stringify({ enrollToken, nodeId, hostname:
|
|
289530
|
+
body: JSON.stringify({ enrollToken, nodeId, hostname: os13.hostname(), serverUrl, ...companyId ? { companyId } : {} })
|
|
288313
289531
|
});
|
|
288314
289532
|
if (!res.ok) throw new Error(`enroll token exchange failed: HTTP ${res.status}`);
|
|
288315
289533
|
const body2 = await res.json();
|
|
@@ -288342,7 +289560,7 @@ async function runCli(argv, println = console.log, progressln = console.error) {
|
|
|
288342
289560
|
const binPath = path37.join(prefix, "bin", "oasis_test");
|
|
288343
289561
|
const svcArgs = `node --server-ws ${serverUrl} --dir ${dir}${nodeName ? ` --name ${nodeName}` : ""}`;
|
|
288344
289562
|
if (process.platform === "linux") {
|
|
288345
|
-
const svcFile = path37.join(
|
|
289563
|
+
const svcFile = path37.join(os13.homedir(), ".config/systemd/user/oasis-node.service");
|
|
288346
289564
|
fs42.mkdirSync(path37.dirname(svcFile), { recursive: true });
|
|
288347
289565
|
if (spawnSync3("systemctl", ["--user", "is-active", "--quiet", "oasis-node"], {}).status === 0)
|
|
288348
289566
|
spawnSync3("systemctl", ["--user", "stop", "oasis-node"], { stdio: "inherit" });
|
|
@@ -288355,7 +289573,7 @@ async function runCli(argv, println = console.log, progressln = console.error) {
|
|
|
288355
289573
|
`ExecStart=${binPath} ${svcArgs}`,
|
|
288356
289574
|
// Carry the install-time PATH so the detached daemon detects CLIs in user dirs
|
|
288357
289575
|
// (~/.npm-global/bin, ~/.local/bin) — systemd --user otherwise gives a minimal PATH.
|
|
288358
|
-
`Environment=PATH=${process.env["PATH"] ?? ""}:${path37.join(
|
|
289576
|
+
`Environment=PATH=${process.env["PATH"] ?? ""}:${path37.join(os13.homedir(), ".npm-global/bin")}:${path37.join(os13.homedir(), ".local/bin")}:/usr/local/bin`,
|
|
288359
289577
|
"Restart=on-failure",
|
|
288360
289578
|
"RestartSec=5",
|
|
288361
289579
|
"StandardOutput=journal",
|
|
@@ -288367,23 +289585,23 @@ async function runCli(argv, println = console.log, progressln = console.error) {
|
|
|
288367
289585
|
].join("\n"));
|
|
288368
289586
|
spawnSync3("systemctl", ["--user", "daemon-reload"], { stdio: "inherit" });
|
|
288369
289587
|
spawnSync3("systemctl", ["--user", "enable", "--now", "oasis-node"], { stdio: "inherit" });
|
|
288370
|
-
spawnSync3("loginctl", ["enable-linger",
|
|
289588
|
+
spawnSync3("loginctl", ["enable-linger", os13.userInfo().username], { stdio: "ignore" });
|
|
288371
289589
|
println("\u2713 Oasis node service started (systemd --user oasis-node)");
|
|
288372
289590
|
println(" Status : systemctl --user status oasis-node");
|
|
288373
289591
|
println(" Logs : journalctl --user -u oasis-node -f");
|
|
288374
289592
|
println(" Stop : systemctl --user stop oasis-node");
|
|
288375
289593
|
} else if (process.platform === "darwin") {
|
|
288376
|
-
const plist = path37.join(
|
|
289594
|
+
const plist = path37.join(os13.homedir(), "Library/LaunchAgents/com.oasis.node.plist");
|
|
288377
289595
|
fs42.mkdirSync(path37.dirname(plist), { recursive: true });
|
|
288378
289596
|
spawnSync3("launchctl", ["unload", plist], { stdio: "ignore" });
|
|
288379
289597
|
const argXml = [binPath, "node", "--server-ws", serverUrl, "--dir", dir, ...nodeName ? ["--name", nodeName] : []].map((a) => `<string>${a}</string>`).join("");
|
|
288380
|
-
fs42.writeFileSync(plist, `<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"><dict><key>Label</key><string>com.oasis.node</string><key>ProgramArguments</key><array>${argXml}</array><key>RunAtLoad</key><true/><key>KeepAlive</key><true/><key>StandardOutPath</key><string>${
|
|
289598
|
+
fs42.writeFileSync(plist, `<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"><dict><key>Label</key><string>com.oasis.node</string><key>ProgramArguments</key><array>${argXml}</array><key>RunAtLoad</key><true/><key>KeepAlive</key><true/><key>StandardOutPath</key><string>${os13.homedir()}/.oasis-node.log</string><key>StandardErrorPath</key><string>${os13.homedir()}/.oasis-node.err</string></dict></plist>`);
|
|
288381
289599
|
spawnSync3("launchctl", ["load", plist], { stdio: "inherit" });
|
|
288382
289600
|
println("\u2713 Oasis node service started (macOS LaunchAgent com.oasis.node)");
|
|
288383
|
-
println(` Logs : tail -f ${
|
|
289601
|
+
println(` Logs : tail -f ${os13.homedir()}/.oasis-node.log`);
|
|
288384
289602
|
println(` Stop : launchctl unload ${plist}`);
|
|
288385
289603
|
} else {
|
|
288386
|
-
spawnSync3("sh", ["-c", `nohup ${binPath} ${svcArgs} > ${path37.join(
|
|
289604
|
+
spawnSync3("sh", ["-c", `nohup ${binPath} ${svcArgs} > ${path37.join(os13.homedir(), ".oasis-node.log")} 2>&1 &`], { stdio: "inherit" });
|
|
288387
289605
|
println(`\u2713 Oasis node started in background (nohup). Logs: ~/.oasis-node.log`);
|
|
288388
289606
|
println(" Note: no automatic restart on reboot in this environment.");
|
|
288389
289607
|
}
|
|
@@ -288492,8 +289710,8 @@ async function runCli(argv, println = console.log, progressln = console.error) {
|
|
|
288492
289710
|
if (command2 === "serve" && positional[0] === "install") {
|
|
288493
289711
|
const absDir = path37.resolve(dir);
|
|
288494
289712
|
const name = `oasis-serve-${path37.basename(absDir)}`;
|
|
288495
|
-
const unitDir = flags.get("unit-dir") ?? path37.join(
|
|
288496
|
-
const bin = flags.get("bin") ?? path37.join(
|
|
289713
|
+
const unitDir = flags.get("unit-dir") ?? path37.join(os13.homedir(), ".config", "systemd", "user");
|
|
289714
|
+
const bin = flags.get("bin") ?? path37.join(os13.homedir(), ".local", "bin", "oasis");
|
|
288497
289715
|
const port = flags.get("port") ?? "7320";
|
|
288498
289716
|
const extra = (flags.get("dispatch") === "true" ? ` --dispatch true` : "") + (flags.has("model") ? ` --model ${flags.get("model")}` : "");
|
|
288499
289717
|
const unit = [
|
|
@@ -288982,7 +290200,7 @@ Trace: ${run.traceRunId}`);
|
|
|
288982
290200
|
if (plan.inject.mode === "env") {
|
|
288983
290201
|
childEnv[plan.inject.envName] = value2;
|
|
288984
290202
|
} else {
|
|
288985
|
-
tmpDir = await fs42.promises.mkdtemp(path37.join(
|
|
290203
|
+
tmpDir = await fs42.promises.mkdtemp(path37.join(os13.tmpdir(), "oasis-var-exec-"));
|
|
288986
290204
|
const keyfile = path37.join(tmpDir, "value");
|
|
288987
290205
|
await fs42.promises.writeFile(keyfile, value2, { mode: 384 });
|
|
288988
290206
|
childEnv[plan.inject.fileEnv] = keyfile;
|
|
@@ -289868,7 +291086,7 @@ ${res.warning}`);
|
|
|
289868
291086
|
for (const a of st.artifacts) println(` - ${a.path}\uFF08${a.kind ?? "?"}\uFF09status=${a.status ?? "?"}${a.mtime ? ` \xB7 ${new Date(a.mtime).toISOString()}` : ""}`);
|
|
289869
291087
|
if (flags.get("pull") === "true") {
|
|
289870
291088
|
const odPublic2 = (flags.get("od-public-url") ?? process.env["OASIS_OPEN_DESIGN_PUBLIC_URL"] ?? "https://design.open-friday.com").replace(/\/$/, "");
|
|
289871
|
-
const { dir: dir3, entry: entry2 } = await harvestBoard(odBase2, fetch, odPublic2,
|
|
291089
|
+
const { dir: dir3, entry: entry2 } = await harvestBoard(odBase2, fetch, odPublic2, os13.tmpdir(), st.boardKey, st.runs[0]?.runId ?? "status-pull");
|
|
289872
291090
|
println(`[design] \u5DF2\u62C9\u5230\u672C\u5730\uFF1A${dir3}\uFF08\u5165\u53E3 ${entry2}\uFF09`);
|
|
289873
291091
|
println(`[design] \u8BFB\u5B8C\u6EE1\u610F\u5373\u4EA4\u7A3F\uFF1Aoasis propose ${artifactId2} --from-dir ${dir3} --reason "<\u8FD9\u7248\u505A\u4E86\u4EC0\u4E48>"`);
|
|
289874
291092
|
} else {
|
|
@@ -291676,10 +292894,10 @@ function runtimeAssetSourceRoots(input) {
|
|
|
291676
292894
|
|
|
291677
292895
|
// src/paths.ts
|
|
291678
292896
|
var fs46 = __toESM(require("node:fs"));
|
|
291679
|
-
var
|
|
292897
|
+
var os14 = __toESM(require("node:os"));
|
|
291680
292898
|
var path41 = __toESM(require("node:path"));
|
|
291681
292899
|
var DEFAULT_INSTANCE = "default";
|
|
291682
|
-
var home = () =>
|
|
292900
|
+
var home = () => os14.homedir();
|
|
291683
292901
|
var oasisDir = () => path41.join(home(), ".oasis");
|
|
291684
292902
|
var versionsDir = () => path41.join(oasisDir(), "versions");
|
|
291685
292903
|
var versionDir = (label2) => path41.join(versionsDir(), label2);
|
|
@@ -291880,7 +293098,7 @@ function shimScript() {
|
|
|
291880
293098
|
}
|
|
291881
293099
|
|
|
291882
293100
|
// src/index.ts
|
|
291883
|
-
var PKG_VERSION = true ? "2.2.
|
|
293101
|
+
var PKG_VERSION = true ? "2.2.70" : "dev";
|
|
291884
293102
|
var LOCAL_BIN = localBin();
|
|
291885
293103
|
var NPM_PREFIX = npmPrefix();
|
|
291886
293104
|
var INSTANCE = DEFAULT_INSTANCE;
|
|
@@ -291986,7 +293204,7 @@ function installSoftware(label2) {
|
|
|
291986
293204
|
function setupAutostart(name) {
|
|
291987
293205
|
const inst = instancePaths(name);
|
|
291988
293206
|
const cmd = `${process.execPath} "${inst.binFile}" --_daemon --instance ${name}`;
|
|
291989
|
-
const home2 =
|
|
293207
|
+
const home2 = os15.homedir();
|
|
291990
293208
|
const pnpmHome = process.env["PNPM_HOME"] || path43.join(home2, ".local", "share", "pnpm");
|
|
291991
293209
|
const extraBins = [
|
|
291992
293210
|
path43.join(home2, ".npm-global", "bin"),
|
|
@@ -291996,7 +293214,7 @@ function setupAutostart(name) {
|
|
|
291996
293214
|
];
|
|
291997
293215
|
const daemonPath = sanitizeDaemonPath([process.env["PATH"] ?? "", ...extraBins].filter(Boolean).join(":"));
|
|
291998
293216
|
if (process.platform === "linux") {
|
|
291999
|
-
const unitDir = path43.join(
|
|
293217
|
+
const unitDir = path43.join(os15.homedir(), ".config", "systemd", "user");
|
|
292000
293218
|
fs48.mkdirSync(unitDir, { recursive: true });
|
|
292001
293219
|
const unit = systemdUnitName(name);
|
|
292002
293220
|
fs48.mkdirSync(path43.dirname(inst.logFile), { recursive: true });
|
|
@@ -292021,7 +293239,7 @@ function setupAutostart(name) {
|
|
|
292021
293239
|
return false;
|
|
292022
293240
|
} else if (process.platform === "darwin") {
|
|
292023
293241
|
const label2 = launchdLabel(name);
|
|
292024
|
-
const plist = path43.join(
|
|
293242
|
+
const plist = path43.join(os15.homedir(), "Library", "LaunchAgents", `${label2}.plist`);
|
|
292025
293243
|
fs48.mkdirSync(path43.dirname(plist), { recursive: true });
|
|
292026
293244
|
fs48.writeFileSync(plist, `<?xml version="1.0" encoding="UTF-8"?>
|
|
292027
293245
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
@@ -292203,7 +293421,7 @@ async function startOneInstance(o) {
|
|
|
292203
293421
|
const res = await fetch(`${httpBase(serverUrl)}/api/nodes/exchange`, {
|
|
292204
293422
|
method: "POST",
|
|
292205
293423
|
headers: { "content-type": "application/json" },
|
|
292206
|
-
body: JSON.stringify({ enrollToken, nodeId: derivedNodeId, hostname:
|
|
293424
|
+
body: JSON.stringify({ enrollToken, nodeId: derivedNodeId, hostname: os15.hostname(), serverUrl, ...companyId ? { companyId } : {} })
|
|
292207
293425
|
});
|
|
292208
293426
|
if (!res.ok) throw new Error(`enroll token exchange failed: HTTP ${res.status}`);
|
|
292209
293427
|
const body2 = await res.json();
|
|
@@ -292268,7 +293486,7 @@ function derivedNodeIdFor(name) {
|
|
|
292268
293486
|
if (name === DEFAULT_INSTANCE) return resolveNodeId();
|
|
292269
293487
|
const user = (() => {
|
|
292270
293488
|
try {
|
|
292271
|
-
return
|
|
293489
|
+
return os15.userInfo().username;
|
|
292272
293490
|
} catch {
|
|
292273
293491
|
return process.env["USER"] ?? process.env["USERNAME"] ?? "unknown";
|
|
292274
293492
|
}
|