oasis_test_v2 2.2.33 → 2.2.35
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 +1279 -692
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -149,6 +149,9 @@ function normalizeGitRemote(remote) {
|
|
|
149
149
|
function projectActorKind(actorId) {
|
|
150
150
|
return actorId.startsWith("actor:human:") ? "human" : "agent";
|
|
151
151
|
}
|
|
152
|
+
function projectIdFromUuid(uuid2) {
|
|
153
|
+
return `proj_${uuid2.replace(/-/g, "").slice(0, 8)}`;
|
|
154
|
+
}
|
|
152
155
|
var init_project = __esm({
|
|
153
156
|
"../contract/src/project.ts"() {
|
|
154
157
|
"use strict";
|
|
@@ -370,10 +373,11 @@ function commentThreadSessionId(a, b2) {
|
|
|
370
373
|
function reviewThreadSessionId(a, b2) {
|
|
371
374
|
return `${REVIEW_THREAD_SESSION_PREFIX}${[a, b2].sort().join("|")}`;
|
|
372
375
|
}
|
|
373
|
-
var GAP_THREAD_SESSION_PREFIX, COMMENT_THREAD_SESSION_PREFIX, REVIEW_THREAD_SESSION_PREFIX;
|
|
376
|
+
var WORKORDER_HOLD_AT_CREATE_REASON, GAP_THREAD_SESSION_PREFIX, COMMENT_THREAD_SESSION_PREFIX, REVIEW_THREAD_SESSION_PREFIX;
|
|
374
377
|
var init_collab_view = __esm({
|
|
375
378
|
"../contract/src/collab-view.ts"() {
|
|
376
379
|
"use strict";
|
|
380
|
+
WORKORDER_HOLD_AT_CREATE_REASON = "\u5EFA\u5355\u65F6\u9009\u62E9\u7A0D\u540E\u6D3E\u53D1";
|
|
377
381
|
GAP_THREAD_SESSION_PREFIX = "gapline:";
|
|
378
382
|
COMMENT_THREAD_SESSION_PREFIX = "commentline:";
|
|
379
383
|
REVIEW_THREAD_SESSION_PREFIX = "reviewline:";
|
|
@@ -406,9 +410,22 @@ var init_inbox_read = __esm({
|
|
|
406
410
|
});
|
|
407
411
|
|
|
408
412
|
// ../contract/src/notifications.ts
|
|
413
|
+
var LEDGER_INBOX_KINDS;
|
|
409
414
|
var init_notifications = __esm({
|
|
410
415
|
"../contract/src/notifications.ts"() {
|
|
411
416
|
"use strict";
|
|
417
|
+
LEDGER_INBOX_KINDS = /* @__PURE__ */ new Set([
|
|
418
|
+
"review-request",
|
|
419
|
+
"rework",
|
|
420
|
+
"stale",
|
|
421
|
+
"pushback",
|
|
422
|
+
"assigned",
|
|
423
|
+
"needs-staffing",
|
|
424
|
+
"gap-escalation",
|
|
425
|
+
"change-confirm",
|
|
426
|
+
"review-waiting",
|
|
427
|
+
"work-waiting"
|
|
428
|
+
]);
|
|
412
429
|
}
|
|
413
430
|
});
|
|
414
431
|
|
|
@@ -1647,7 +1664,7 @@ var init_file_preview = __esm({
|
|
|
1647
1664
|
"../contract/src/file-preview.ts"() {
|
|
1648
1665
|
"use strict";
|
|
1649
1666
|
OFFICE_PREVIEW_MAX_BYTES = 20 * 1024 * 1024;
|
|
1650
|
-
FILE_CONTENT_MAX_BYTES =
|
|
1667
|
+
FILE_CONTENT_MAX_BYTES = 200 * 1024 * 1024;
|
|
1651
1668
|
}
|
|
1652
1669
|
});
|
|
1653
1670
|
|
|
@@ -21293,14 +21310,17 @@ var init_kernel_bridge = __esm({
|
|
|
21293
21310
|
});
|
|
21294
21311
|
}
|
|
21295
21312
|
}
|
|
21296
|
-
/**
|
|
21297
|
-
|
|
21313
|
+
/**
|
|
21314
|
+
* 工单级暂停:workorder.paused handler 杀全部在途会话 + 挡新派发。
|
|
21315
|
+
* `reason` 缺省「暂停派发」(人点暂停);建单即挂起的入口传 `WORKORDER_HOLD_AT_CREATE_REASON`。
|
|
21316
|
+
*/
|
|
21317
|
+
async pauseWorkorder(workorderId, actor, reason = "\u6682\u505C\u6D3E\u53D1") {
|
|
21298
21318
|
this.trackedWorkorders.add(workorderId);
|
|
21299
21319
|
await this.commit({
|
|
21300
21320
|
companyId: "",
|
|
21301
21321
|
workorderId,
|
|
21302
21322
|
actorId: actor,
|
|
21303
|
-
event: { kind: "workorder.paused", workorderId, by: actor, reason
|
|
21323
|
+
event: { kind: "workorder.paused", workorderId, by: actor, reason }
|
|
21304
21324
|
});
|
|
21305
21325
|
}
|
|
21306
21326
|
/**
|
|
@@ -22033,12 +22053,12 @@ async function readArtifactFile(kernel, blobs, artifactId, path41, expectedRef,
|
|
|
22033
22053
|
if (!entry) throw new ApiError(404, "NOT_FOUND", "\u5305\u5185\u6587\u4EF6\u4E0D\u5B58\u5728");
|
|
22034
22054
|
hash2 = entry.hash;
|
|
22035
22055
|
name = entry.path;
|
|
22036
|
-
if (entry.size !== void 0 && entry.size > FILE_CONTENT_MAX_BYTES) throw new ApiError(413, "FILE_TOO_LARGE",
|
|
22056
|
+
if (entry.size !== void 0 && entry.size > FILE_CONTENT_MAX_BYTES) throw new ApiError(413, "FILE_TOO_LARGE", `\u6587\u4EF6\u8D85\u8FC7 ${FILE_CONTENT_MAX_BYTES / 1024 / 1024} MiB \u8BFB\u53D6\u9650\u5236`);
|
|
22037
22057
|
} else if (output.contentKind !== "inline-blob") {
|
|
22038
22058
|
throw new ApiError(404, "NOT_FOUND", "\u6B64\u4EA7\u7269\u6CA1\u6709\u53EF\u4E0B\u8F7D\u7684\u539F\u6587\u4EF6");
|
|
22039
22059
|
}
|
|
22040
22060
|
const meta = await blobs.meta?.(hash2);
|
|
22041
|
-
if (meta && meta.size > FILE_CONTENT_MAX_BYTES) throw new ApiError(413, "FILE_TOO_LARGE",
|
|
22061
|
+
if (meta && meta.size > FILE_CONTENT_MAX_BYTES) throw new ApiError(413, "FILE_TOO_LARGE", `\u6587\u4EF6\u8D85\u8FC7 ${FILE_CONTENT_MAX_BYTES / 1024 / 1024} MiB \u8BFB\u53D6\u9650\u5236`);
|
|
22042
22062
|
try {
|
|
22043
22063
|
return { bytes: await blobs.get(hash2), name, contentType: meta?.contentType };
|
|
22044
22064
|
} catch {
|
|
@@ -22065,7 +22085,7 @@ async function serveFileRequest(req, res, url, engine) {
|
|
|
22065
22085
|
url.searchParams.get("ref"),
|
|
22066
22086
|
url.searchParams.get("revisionId")
|
|
22067
22087
|
);
|
|
22068
|
-
if (bytes2.length > FILE_CONTENT_MAX_BYTES) throw new ApiError(413, "FILE_TOO_LARGE",
|
|
22088
|
+
if (bytes2.length > FILE_CONTENT_MAX_BYTES) throw new ApiError(413, "FILE_TOO_LARGE", `\u6587\u4EF6\u8D85\u8FC7 ${FILE_CONTENT_MAX_BYTES / 1024 / 1024} MiB \u8BFB\u53D6\u9650\u5236`);
|
|
22069
22089
|
res.writeHead(200, {
|
|
22070
22090
|
"content-type": contentType ?? sniffContentType(bytes2) ?? "application/octet-stream",
|
|
22071
22091
|
"content-length": String(bytes2.length),
|
|
@@ -25413,7 +25433,7 @@ async function runProtocolSession(job, cfg) {
|
|
|
25413
25433
|
let appendChain = Promise.resolve();
|
|
25414
25434
|
let eventSeq = 0;
|
|
25415
25435
|
let runtimeSessionId;
|
|
25416
|
-
|
|
25436
|
+
const pendingTurnMessages = [];
|
|
25417
25437
|
const stderrTail = [];
|
|
25418
25438
|
const finish = (info) => {
|
|
25419
25439
|
if (exited) return;
|
|
@@ -25452,7 +25472,15 @@ async function runProtocolSession(job, cfg) {
|
|
|
25452
25472
|
}
|
|
25453
25473
|
});
|
|
25454
25474
|
};
|
|
25475
|
+
const completeTurn = (message) => {
|
|
25476
|
+
if (exited || killReason) return;
|
|
25477
|
+
const result = cfg.turnResult(message, state);
|
|
25478
|
+
if (!result) return;
|
|
25479
|
+
finish(result);
|
|
25480
|
+
child.kill("SIGTERM");
|
|
25481
|
+
};
|
|
25455
25482
|
const handle = (message) => {
|
|
25483
|
+
if (exited || killReason) return;
|
|
25456
25484
|
const responseId = commandId(message.id);
|
|
25457
25485
|
if (isResponse(message) && responseId !== void 0 && pending.has(responseId)) {
|
|
25458
25486
|
const waiter = pending.get(responseId);
|
|
@@ -25468,13 +25496,15 @@ async function runProtocolSession(job, cfg) {
|
|
|
25468
25496
|
const event = { kind: line.kind, payload: line.payload, seq: ++eventSeq, ts: (/* @__PURE__ */ new Date()).toISOString() };
|
|
25469
25497
|
for (const cb of telemetryCbs) cb(event);
|
|
25470
25498
|
}
|
|
25471
|
-
if (
|
|
25472
|
-
|
|
25473
|
-
|
|
25474
|
-
|
|
25475
|
-
|
|
25476
|
-
|
|
25477
|
-
|
|
25499
|
+
if (!started) pendingTurnMessages.push(message);
|
|
25500
|
+
else completeTurn(message);
|
|
25501
|
+
};
|
|
25502
|
+
const consumeLine = (line) => {
|
|
25503
|
+
if (!line) return;
|
|
25504
|
+
transcript.write(line + "\n");
|
|
25505
|
+
try {
|
|
25506
|
+
handle(JSON.parse(line));
|
|
25507
|
+
} catch {
|
|
25478
25508
|
}
|
|
25479
25509
|
};
|
|
25480
25510
|
let buffer = "";
|
|
@@ -25484,13 +25514,7 @@ async function runProtocolSession(job, cfg) {
|
|
|
25484
25514
|
while (newline >= 0) {
|
|
25485
25515
|
const line = buffer.slice(0, newline).replace(/\r$/, "");
|
|
25486
25516
|
buffer = buffer.slice(newline + 1);
|
|
25487
|
-
|
|
25488
|
-
transcript.write(line + "\n");
|
|
25489
|
-
try {
|
|
25490
|
-
handle(JSON.parse(line));
|
|
25491
|
-
} catch {
|
|
25492
|
-
}
|
|
25493
|
-
}
|
|
25517
|
+
consumeLine(line);
|
|
25494
25518
|
newline = buffer.indexOf("\n");
|
|
25495
25519
|
}
|
|
25496
25520
|
});
|
|
@@ -25504,12 +25528,23 @@ async function runProtocolSession(job, cfg) {
|
|
|
25504
25528
|
killReason ??= "timeout";
|
|
25505
25529
|
child.kill("SIGKILL");
|
|
25506
25530
|
}, job.limits.wallClockMs);
|
|
25507
|
-
child.on("error", (error2) =>
|
|
25508
|
-
|
|
25531
|
+
child.on("error", (error2) => {
|
|
25532
|
+
clearTimeout(timer);
|
|
25533
|
+
finish({ code: null, reason: "error", transcriptRef, errorMessage: error2.message });
|
|
25534
|
+
});
|
|
25535
|
+
child.on("close", (code2) => {
|
|
25509
25536
|
clearTimeout(timer);
|
|
25537
|
+
consumeLine(buffer.trim());
|
|
25538
|
+
buffer = "";
|
|
25539
|
+
transcript.end();
|
|
25510
25540
|
if (!exited) {
|
|
25511
25541
|
const reason = killReason ?? (code2 === 0 ? "clean" : "error");
|
|
25512
|
-
|
|
25542
|
+
const info = {
|
|
25543
|
+
code: killReason ? null : code2,
|
|
25544
|
+
reason,
|
|
25545
|
+
...reason === "error" && stderrTail.length ? { errorMessage: stderrTail.join("\n").slice(-4e3) } : {}
|
|
25546
|
+
};
|
|
25547
|
+
finish(!killReason && cfg.processExitInfo ? cfg.processExitInfo(info, state) : info);
|
|
25513
25548
|
}
|
|
25514
25549
|
});
|
|
25515
25550
|
void (async () => {
|
|
@@ -25523,10 +25558,7 @@ async function runProtocolSession(job, cfg) {
|
|
|
25523
25558
|
await cfg.start(send, job, dir, task, state);
|
|
25524
25559
|
runtimeSessionId ??= cfg.runtimeSessionId?.(state);
|
|
25525
25560
|
started = true;
|
|
25526
|
-
|
|
25527
|
-
finish({ code: 0, reason: "clean", transcriptRef, ...runtimeSessionId ? { runtimeSessionId } : {} });
|
|
25528
|
-
child.kill("SIGTERM");
|
|
25529
|
-
}
|
|
25561
|
+
for (const message of pendingTurnMessages.splice(0)) completeTurn(message);
|
|
25530
25562
|
} catch (error2) {
|
|
25531
25563
|
if (!exited) {
|
|
25532
25564
|
const msg = error2 instanceof Error ? error2.message : String(error2);
|
|
@@ -25735,7 +25767,7 @@ function codexSessionsRoot() {
|
|
|
25735
25767
|
}
|
|
25736
25768
|
function listRecentRollouts(root, sinceMs) {
|
|
25737
25769
|
const margin = sinceMs - 6e4;
|
|
25738
|
-
const
|
|
25770
|
+
const found2 = [];
|
|
25739
25771
|
const walk = (d) => {
|
|
25740
25772
|
let ents;
|
|
25741
25773
|
try {
|
|
@@ -25752,16 +25784,16 @@ function listRecentRollouts(root, sinceMs) {
|
|
|
25752
25784
|
m2 = fs8.statSync(p2).mtimeMs;
|
|
25753
25785
|
} catch {
|
|
25754
25786
|
}
|
|
25755
|
-
if (m2 >= margin)
|
|
25787
|
+
if (m2 >= margin) found2.push({ f: p2, m: m2 });
|
|
25756
25788
|
}
|
|
25757
25789
|
}
|
|
25758
25790
|
};
|
|
25759
25791
|
walk(root);
|
|
25760
|
-
return
|
|
25792
|
+
return found2.sort((a, b2) => b2.m - a.m).map((x2) => x2.f);
|
|
25761
25793
|
}
|
|
25762
25794
|
function findRolloutsBySessionId(root, sessionId) {
|
|
25763
25795
|
const suffix = `-${sessionId}.jsonl`;
|
|
25764
|
-
const
|
|
25796
|
+
const found2 = [];
|
|
25765
25797
|
const walk = (d) => {
|
|
25766
25798
|
let ents;
|
|
25767
25799
|
try {
|
|
@@ -25772,11 +25804,11 @@ function findRolloutsBySessionId(root, sessionId) {
|
|
|
25772
25804
|
for (const ent of ents) {
|
|
25773
25805
|
const p2 = path10.join(d, ent.name);
|
|
25774
25806
|
if (ent.isDirectory()) walk(p2);
|
|
25775
|
-
else if (ent.isFile() && ent.name.startsWith("rollout-") && ent.name.endsWith(suffix))
|
|
25807
|
+
else if (ent.isFile() && ent.name.startsWith("rollout-") && ent.name.endsWith(suffix)) found2.push(p2);
|
|
25776
25808
|
}
|
|
25777
25809
|
};
|
|
25778
25810
|
walk(root);
|
|
25779
|
-
return
|
|
25811
|
+
return found2;
|
|
25780
25812
|
}
|
|
25781
25813
|
function telemetryFromRolloutLines(lines, sinceMs) {
|
|
25782
25814
|
const usage = parseCodexTokenUsage(lines, sinceMs);
|
|
@@ -26036,6 +26068,15 @@ function normalizeCodexConsoleLine(line, state = createCodexNormalizeState()) {
|
|
|
26036
26068
|
tool.output.push(line);
|
|
26037
26069
|
return [];
|
|
26038
26070
|
}
|
|
26071
|
+
function codexTurnErrorMessage(value2) {
|
|
26072
|
+
const error2 = record2(value2);
|
|
26073
|
+
const code2 = error2?.codexErrorInfo;
|
|
26074
|
+
const label = typeof code2 === "string" ? code2 : code2 ? JSON.stringify(code2) : "unknown";
|
|
26075
|
+
const message = typeof error2?.message === "string" && error2.message.trim() ? error2.message.trim() : "Codex turn failed without error details";
|
|
26076
|
+
const summary = code2 === "cyberPolicy" || code2 === "misalignmentPolicyViolation" ? `Codex \u5B89\u5168\u7B56\u7565\u62D2\u7EDD [${label}]\uFF1A${message}` : `Codex [${label}]: ${message}`;
|
|
26077
|
+
const detail = typeof error2?.additionalDetails === "string" ? error2.additionalDetails.trim() : "";
|
|
26078
|
+
return [summary, detail].filter(Boolean).join("\n").slice(0, 4e3);
|
|
26079
|
+
}
|
|
26039
26080
|
var import_node_child_process7, import_node_crypto11, fs8, os5, path10, readline2, CODEX_BLOCKED_FLAGS, CODEX_ARGV_PROMPT_MAX_BYTES, CODEX_APP_SERVER_BLOCKED_FLAGS, CodexAdapter;
|
|
26040
26081
|
var init_codex = __esm({
|
|
26041
26082
|
"../adapters/src/codex/index.ts"() {
|
|
@@ -26119,6 +26160,7 @@ var init_codex = __esm({
|
|
|
26119
26160
|
threadId: void 0,
|
|
26120
26161
|
turnId: void 0,
|
|
26121
26162
|
active: false,
|
|
26163
|
+
errorsByTurn: /* @__PURE__ */ new Map(),
|
|
26122
26164
|
pendingInputs: /* @__PURE__ */ new Set(),
|
|
26123
26165
|
codex: createCodexNormalizeState(),
|
|
26124
26166
|
// 本次 run 的用量:`thread/tokenUsage/updated` 的 `last`(见该解析函数注释)按轮次记下,
|
|
@@ -26202,6 +26244,9 @@ ${task}` : task;
|
|
|
26202
26244
|
}
|
|
26203
26245
|
}
|
|
26204
26246
|
if (method === "turn/completed") {
|
|
26247
|
+
const turn = record2(params?.turn);
|
|
26248
|
+
const failure = typeof turn?.id === "string" ? state.errorsByTurn.get(turn.id) : void 0;
|
|
26249
|
+
if (params?.threadId !== state.threadId || turn?.id !== state.turnId || turn?.status !== "completed" || turn.error || failure && !failure.willRetry) return [];
|
|
26205
26250
|
return [{ ...base, itemId: "turn-end", itemType: "control", operation: "completed", payload: { code: "output_block_completed" } }];
|
|
26206
26251
|
}
|
|
26207
26252
|
return [];
|
|
@@ -26209,10 +26254,15 @@ ${task}` : task;
|
|
|
26209
26254
|
normalize(message, state) {
|
|
26210
26255
|
const params = message.params;
|
|
26211
26256
|
const method = typeof message.method === "string" ? message.method : "";
|
|
26257
|
+
if (method === "error" && params?.threadId === state.threadId && typeof params?.turnId === "string") {
|
|
26258
|
+
state.errorsByTurn.set(params.turnId, { error: params.error, willRetry: params.willRetry === true });
|
|
26259
|
+
}
|
|
26212
26260
|
if (method === "thread/started") {
|
|
26213
26261
|
const thread = params?.thread;
|
|
26214
|
-
if (typeof thread?.id === "string"
|
|
26215
|
-
|
|
26262
|
+
if (typeof thread?.id === "string" && (!state.threadId || state.threadId === thread.id)) {
|
|
26263
|
+
state.threadId = thread.id;
|
|
26264
|
+
if (typeof thread.path === "string") state.rolloutPath = thread.path;
|
|
26265
|
+
}
|
|
26216
26266
|
}
|
|
26217
26267
|
if (method === "thread/tokenUsage/updated") {
|
|
26218
26268
|
const turn = parseCodexAppServerTurnUsage(params);
|
|
@@ -26220,7 +26270,7 @@ ${task}` : task;
|
|
|
26220
26270
|
}
|
|
26221
26271
|
if (method === "turn/started") {
|
|
26222
26272
|
const turn = params?.turn;
|
|
26223
|
-
if (typeof turn?.id === "string") {
|
|
26273
|
+
if (params?.threadId === state.threadId && state.turnRequested && typeof turn?.id === "string" && (!state.turnId || state.turnId === turn.id)) {
|
|
26224
26274
|
state.turnId = turn.id;
|
|
26225
26275
|
state.active = true;
|
|
26226
26276
|
if (state.turnRequested) state.runTurnIds.add(turn.id);
|
|
@@ -26241,10 +26291,29 @@ ${task}` : task;
|
|
|
26241
26291
|
}
|
|
26242
26292
|
return [];
|
|
26243
26293
|
},
|
|
26244
|
-
|
|
26245
|
-
if (message.method !== "turn/completed" || !state.active) return
|
|
26294
|
+
turnResult(message, state) {
|
|
26295
|
+
if (message.method !== "turn/completed" || !state.active) return void 0;
|
|
26296
|
+
const params = record2(message.params);
|
|
26297
|
+
const turn = record2(params?.turn);
|
|
26298
|
+
if (params?.threadId !== state.threadId || !state.turnId || turn?.id !== state.turnId) return void 0;
|
|
26246
26299
|
state.active = false;
|
|
26247
|
-
return
|
|
26300
|
+
if (turn.status === "interrupted") return { code: null, reason: "cancelled" };
|
|
26301
|
+
const failure = state.errorsByTurn.get(state.turnId);
|
|
26302
|
+
const error2 = turn.error ?? (turn.status === "failed" || !failure?.willRetry ? failure?.error : void 0);
|
|
26303
|
+
if (turn.status === "completed" && !error2) return { code: 0, reason: "clean" };
|
|
26304
|
+
return { code: 1, reason: "error", errorMessage: codexTurnErrorMessage(error2) };
|
|
26305
|
+
},
|
|
26306
|
+
processExitInfo(info, state) {
|
|
26307
|
+
const error2 = state.turnId ? state.errorsByTurn.get(state.turnId)?.error : void 0;
|
|
26308
|
+
return {
|
|
26309
|
+
code: info.code === 0 ? 1 : info.code,
|
|
26310
|
+
reason: "error",
|
|
26311
|
+
errorMessage: [
|
|
26312
|
+
error2 ? codexTurnErrorMessage(error2) : void 0,
|
|
26313
|
+
info.errorMessage,
|
|
26314
|
+
"Codex app-server exited before reporting a terminal result"
|
|
26315
|
+
].filter(Boolean).join("\n").slice(0, 4e3)
|
|
26316
|
+
};
|
|
26248
26317
|
},
|
|
26249
26318
|
runtimeSessionId: (state) => state.threadId,
|
|
26250
26319
|
exitExtras: (state) => {
|
|
@@ -28304,8 +28373,8 @@ ${task}` : task;
|
|
|
28304
28373
|
normalize(message) {
|
|
28305
28374
|
return normalizePi(JSON.stringify(message));
|
|
28306
28375
|
},
|
|
28307
|
-
|
|
28308
|
-
return message.type === "agent_settled";
|
|
28376
|
+
turnResult(message) {
|
|
28377
|
+
return message.type === "agent_settled" ? { code: 0, reason: "clean" } : void 0;
|
|
28309
28378
|
},
|
|
28310
28379
|
runtimeSessionId(state) {
|
|
28311
28380
|
return state.sessionId;
|
|
@@ -30815,8 +30884,26 @@ function runBackgroundAssistantChatTurn(deps) {
|
|
|
30815
30884
|
}
|
|
30816
30885
|
};
|
|
30817
30886
|
void Promise.resolve(deps.session.done).then(() => finalize("done").catch(() => void 0)).catch((err) => {
|
|
30887
|
+
const chatExit = err instanceof Error ? err.chatExit : void 0;
|
|
30888
|
+
const text5 = chatExit?.summary ?? (err instanceof Error ? err.message : String(err));
|
|
30889
|
+
const extra = {
|
|
30890
|
+
...chatExit?.reason ? { reason: chatExit.reason } : {},
|
|
30891
|
+
...chatExit?.detail ? { detail: chatExit.detail } : {}
|
|
30892
|
+
};
|
|
30893
|
+
const part = { type: "error", seq: ++localSeq, text: text5, ...extra };
|
|
30894
|
+
localParts.push(part);
|
|
30895
|
+
liveTurn?.emit(part);
|
|
30818
30896
|
try {
|
|
30819
|
-
itemLedger.recordError(
|
|
30897
|
+
const outcome = itemLedger.recordError(text5, extra);
|
|
30898
|
+
liveTurn?.publishServerItem({
|
|
30899
|
+
itemId: outcome.itemId,
|
|
30900
|
+
itemType: "control",
|
|
30901
|
+
startedVersion: outcome.startedVersion,
|
|
30902
|
+
version: outcome.version,
|
|
30903
|
+
ord: outcome.ord,
|
|
30904
|
+
status: "failed",
|
|
30905
|
+
payload: { code: "error", note: text5, ...extra }
|
|
30906
|
+
});
|
|
30820
30907
|
} catch {
|
|
30821
30908
|
}
|
|
30822
30909
|
return finalize("error").catch(() => void 0);
|
|
@@ -178838,14 +178925,14 @@ var require_Alias = __commonJS({
|
|
|
178838
178925
|
if (ctx)
|
|
178839
178926
|
ctx.aliasResolveCache = nodes;
|
|
178840
178927
|
}
|
|
178841
|
-
let
|
|
178928
|
+
let found2 = void 0;
|
|
178842
178929
|
for (const node2 of nodes) {
|
|
178843
178930
|
if (node2 === this)
|
|
178844
178931
|
break;
|
|
178845
178932
|
if (node2.anchor === this.source)
|
|
178846
|
-
|
|
178933
|
+
found2 = node2;
|
|
178847
178934
|
}
|
|
178848
|
-
return
|
|
178935
|
+
return found2;
|
|
178849
178936
|
}
|
|
178850
178937
|
toJSON(_arg, ctx) {
|
|
178851
178938
|
if (!ctx)
|
|
@@ -181970,7 +182057,7 @@ var require_resolve_props = __commonJS({
|
|
|
181970
182057
|
let tag = null;
|
|
181971
182058
|
let newlineAfterProp = null;
|
|
181972
182059
|
let comma = null;
|
|
181973
|
-
let
|
|
182060
|
+
let found2 = null;
|
|
181974
182061
|
let start = null;
|
|
181975
182062
|
for (const token of tokens) {
|
|
181976
182063
|
if (reqSpace) {
|
|
@@ -182007,7 +182094,7 @@ var require_resolve_props = __commonJS({
|
|
|
182007
182094
|
if (atNewline) {
|
|
182008
182095
|
if (comment)
|
|
182009
182096
|
comment += token.source;
|
|
182010
|
-
else if (!
|
|
182097
|
+
else if (!found2 || indicator !== "seq-item-ind")
|
|
182011
182098
|
spaceBefore = true;
|
|
182012
182099
|
} else
|
|
182013
182100
|
commentSep += token.source;
|
|
@@ -182041,9 +182128,9 @@ var require_resolve_props = __commonJS({
|
|
|
182041
182128
|
case indicator:
|
|
182042
182129
|
if (anchor || tag)
|
|
182043
182130
|
onError(token, "BAD_PROP_ORDER", `Anchors and tags must be after the ${token.source} indicator`);
|
|
182044
|
-
if (
|
|
182131
|
+
if (found2)
|
|
182045
182132
|
onError(token, "UNEXPECTED_TOKEN", `Unexpected ${token.source} in ${flow3 ?? "collection"}`);
|
|
182046
|
-
|
|
182133
|
+
found2 = token;
|
|
182047
182134
|
atNewline = indicator === "seq-item-ind" || indicator === "explicit-key-ind";
|
|
182048
182135
|
hasSpace = false;
|
|
182049
182136
|
break;
|
|
@@ -182072,7 +182159,7 @@ var require_resolve_props = __commonJS({
|
|
|
182072
182159
|
onError(tab, "TAB_AS_INDENT", "Tabs are not allowed as indentation");
|
|
182073
182160
|
return {
|
|
182074
182161
|
comma,
|
|
182075
|
-
found,
|
|
182162
|
+
found: found2,
|
|
182076
182163
|
spaceBefore,
|
|
182077
182164
|
comment,
|
|
182078
182165
|
hasNewline,
|
|
@@ -201214,8 +201301,8 @@ async function resolveOutlineKnowledgeBinding(credentials, input) {
|
|
|
201214
201301
|
const collections = (await api.listCollections()).filter(isWritableCollection);
|
|
201215
201302
|
for (const collection of collections) {
|
|
201216
201303
|
const documents = await api.listDocuments(collection["id"]);
|
|
201217
|
-
const
|
|
201218
|
-
if (
|
|
201304
|
+
const found2 = documents.find((document4) => string5(document4["url"]) === pasted);
|
|
201305
|
+
if (found2) return bindingFromDocument(api, found2, collection, identity);
|
|
201219
201306
|
}
|
|
201220
201307
|
throw new Error("\u627E\u4E0D\u5230\u8BE5\u6839\u6587\u6863\uFF0C\u6216\u5F53\u524D Token \u5BF9\u5176\u6240\u5728 Collection \u6CA1\u6709\u5199\u6743\u9650");
|
|
201221
201308
|
}
|
|
@@ -204172,10 +204259,10 @@ async function runCommand(kernel, blobs, oplog, engineStore, actor, command, arg
|
|
|
204172
204259
|
}
|
|
204173
204260
|
let artifactId;
|
|
204174
204261
|
if (escalationId !== void 0) {
|
|
204175
|
-
const
|
|
204176
|
-
if (!
|
|
204177
|
-
if (
|
|
204178
|
-
artifactId =
|
|
204262
|
+
const found2 = escalationById(kernel.model, escalationId);
|
|
204263
|
+
if (!found2) throw new Error(`\u4E0A\u62A5 ${escalationId} \u4E0D\u5B58\u5728\uFF08id \u89C1 \`oasis status <\u8282\u70B9>\` \u7684\u300C\u4E0A\u62A5\u300D\u6BB5\uFF09\u3002`);
|
|
204264
|
+
if (found2.resolved) throw new Error(`\u4E0A\u62A5 ${escalationId} \u5DF2\u7ECF\u5173\u95ED\uFF0C\u65E0\u9700\u518D\u5173\u3002`);
|
|
204265
|
+
artifactId = found2.artifactId;
|
|
204179
204266
|
} else {
|
|
204180
204267
|
const argArtifactId = optStr(args, "artifactId");
|
|
204181
204268
|
if (argArtifactId === void 0) {
|
|
@@ -204457,7 +204544,7 @@ ${acceptanceCriteria.map((c) => `- ${c}`).join("\n")}`] : []
|
|
|
204457
204544
|
}
|
|
204458
204545
|
if (args["dispatch"] === false) {
|
|
204459
204546
|
await ctx.artifactState?.setWorkspaceDispatchHold(workspace, true);
|
|
204460
|
-
await kernel.pauseWorkorder?.(workspace, actor);
|
|
204547
|
+
await kernel.pauseWorkorder?.(workspace, actor, WORKORDER_HOLD_AT_CREATE_REASON);
|
|
204461
204548
|
}
|
|
204462
204549
|
return {
|
|
204463
204550
|
message: planned.issues.length > 0 ? `planned ${workspace}: created ${planned.spawned.length} nodes\uFF0C${planned.issues.length} \u4E2A staffing \u63D0\u793A\u5DF2\u5199\u5165\u5DE5\u5355` : `planned ${workspace}: created ${planned.spawned.length} nodes`,
|
|
@@ -205650,10 +205737,10 @@ async function startOasisServer(opts) {
|
|
|
205650
205737
|
...fp(p2)
|
|
205651
205738
|
}))
|
|
205652
205739
|
] : [];
|
|
205653
|
-
const { randomUUID:
|
|
205740
|
+
const { randomUUID: randomUUID42 } = await import("node:crypto");
|
|
205654
205741
|
try {
|
|
205655
205742
|
await store.enqueuePendingMessage({
|
|
205656
|
-
id:
|
|
205743
|
+
id: randomUUID42(),
|
|
205657
205744
|
chatSessionId: input.chatSessionId,
|
|
205658
205745
|
text: input.text,
|
|
205659
205746
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -205686,11 +205773,11 @@ async function startOasisServer(opts) {
|
|
|
205686
205773
|
...f2?.mtime ? { srcMtime: f2.mtime } : {}
|
|
205687
205774
|
};
|
|
205688
205775
|
});
|
|
205689
|
-
const { randomUUID:
|
|
205776
|
+
const { randomUUID: randomUUID42 } = await import("node:crypto");
|
|
205690
205777
|
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
205691
205778
|
try {
|
|
205692
205779
|
await store.enqueuePendingMessage({
|
|
205693
|
-
id:
|
|
205780
|
+
id: randomUUID42(),
|
|
205694
205781
|
chatSessionId: input.chatSessionId,
|
|
205695
205782
|
text: "",
|
|
205696
205783
|
createdAt: nowIso,
|
|
@@ -206700,7 +206787,7 @@ async function startOasisServer(opts) {
|
|
|
206700
206787
|
}
|
|
206701
206788
|
if (body2.dispatch === false) {
|
|
206702
206789
|
await opts.artifactState?.setWorkspaceDispatchHold(workspace, true);
|
|
206703
|
-
await engine.kernel.pauseWorkorder?.(workspace, actor);
|
|
206790
|
+
await engine.kernel.pauseWorkorder?.(workspace, actor, WORKORDER_HOLD_AT_CREATE_REASON);
|
|
206704
206791
|
}
|
|
206705
206792
|
await wodraftPlannerIssues.remove(workspace);
|
|
206706
206793
|
if (opts.chatSession && body2.chatSessionId && workspace !== "ws:default") {
|
|
@@ -207018,7 +207105,7 @@ async function startOasisServer(opts) {
|
|
|
207018
207105
|
const openRoom = async () => {
|
|
207019
207106
|
let chatSessionId2;
|
|
207020
207107
|
if (chatStore) {
|
|
207021
|
-
const { randomUUID:
|
|
207108
|
+
const { randomUUID: randomUUID42 } = await import("node:crypto");
|
|
207022
207109
|
const known = discussSessions.get(itemKey);
|
|
207023
207110
|
const knownSession = known ? await chatStore.getSession(known) : null;
|
|
207024
207111
|
if (knownSession && knownSession.workspace === ctx.workspace && knownSession.humanActorId === ctx.ownerId && (!body2.escalationId || knownSession.escalationId === body2.escalationId)) chatSessionId2 = known;
|
|
@@ -207027,7 +207114,7 @@ async function startOasisServer(opts) {
|
|
|
207027
207114
|
chatSessionId2 = existing[0]?.id;
|
|
207028
207115
|
}
|
|
207029
207116
|
if (!chatSessionId2) {
|
|
207030
|
-
chatSessionId2 =
|
|
207117
|
+
chatSessionId2 = randomUUID42();
|
|
207031
207118
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
207032
207119
|
const title = `\u89E3\u51B3\uFF1A${ctx.seed.slice(ctx.seed.indexOf("\uFF1A") + 1, ctx.seed.indexOf("\uFF1A") + 25) || "\u5DE5\u5355\u5361\u70B9"}`;
|
|
207033
207120
|
const reg0 = (await resolveEngine(currentCompanyId).catch(() => null))?.registry ?? opts.registry;
|
|
@@ -207896,14 +207983,14 @@ ${composed}`;
|
|
|
207896
207983
|
runtimeSessionId: session.nativeSessionId ?? session.id
|
|
207897
207984
|
}).catch(() => void 0);
|
|
207898
207985
|
}
|
|
207899
|
-
const { randomUUID:
|
|
207986
|
+
const { randomUUID: randomUUID43 } = await import("node:crypto");
|
|
207900
207987
|
const persistAttachments = effectiveAttachments.map((a) => ({
|
|
207901
207988
|
name: a.name,
|
|
207902
207989
|
...a.blobRef !== void 0 ? { blobRef: a.blobRef } : {},
|
|
207903
207990
|
...a.contentType !== void 0 ? { contentType: a.contentType } : {}
|
|
207904
207991
|
}));
|
|
207905
207992
|
await chatStore.appendMessage({
|
|
207906
|
-
id:
|
|
207993
|
+
id: randomUUID43(),
|
|
207907
207994
|
sessionId: persistTarget.id,
|
|
207908
207995
|
role: "user",
|
|
207909
207996
|
content: persistedUserMessage,
|
|
@@ -208378,8 +208465,8 @@ ${composed}`;
|
|
|
208378
208465
|
}
|
|
208379
208466
|
}
|
|
208380
208467
|
const { spawn: spawn10 } = await import("node:child_process");
|
|
208381
|
-
const { randomUUID:
|
|
208382
|
-
const sessionId = body2.sessionId ??
|
|
208468
|
+
const { randomUUID: randomUUID42 } = await import("node:crypto");
|
|
208469
|
+
const sessionId = body2.sessionId ?? randomUUID42();
|
|
208383
208470
|
const args = [
|
|
208384
208471
|
"-p",
|
|
208385
208472
|
body2.message,
|
|
@@ -208675,8 +208762,8 @@ ${composed}`;
|
|
|
208675
208762
|
res.writeHead(400, { "content-type": "application/json" }).end(JSON.stringify({ error: `\u56DE\u8C03\u5730\u5740\u4E0D\u53EF\u7528\uFF0C\u5DF2\u4E2D\u6B62\uFF08\u907F\u514D\u5728 GitHub \u4E0A\u7559\u4E0B\u5B64\u513F App\uFF09\uFF1A${e.message}` }));
|
|
208676
208763
|
return;
|
|
208677
208764
|
}
|
|
208678
|
-
const { randomUUID:
|
|
208679
|
-
const state =
|
|
208765
|
+
const { randomUUID: randomUUID42 } = await import("node:crypto");
|
|
208766
|
+
const state = randomUUID42();
|
|
208680
208767
|
const nameSlug = (actorName || actorId?.split(":").pop() || owner?.login || "bot").toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-|-$/g, "").slice(0, 24) || "bot";
|
|
208681
208768
|
const manifest = buildAppManifest({
|
|
208682
208769
|
employeeSlug: nameSlug,
|
|
@@ -212740,6 +212827,19 @@ var init_stats = __esm({
|
|
|
212740
212827
|
}
|
|
212741
212828
|
});
|
|
212742
212829
|
|
|
212830
|
+
// ../server/src/domains/projects/project-id.ts
|
|
212831
|
+
function randomProjectId() {
|
|
212832
|
+
return projectIdFromUuid((0, import_node_crypto41.randomUUID)());
|
|
212833
|
+
}
|
|
212834
|
+
var import_node_crypto41;
|
|
212835
|
+
var init_project_id = __esm({
|
|
212836
|
+
"../server/src/domains/projects/project-id.ts"() {
|
|
212837
|
+
"use strict";
|
|
212838
|
+
import_node_crypto41 = require("node:crypto");
|
|
212839
|
+
init_src();
|
|
212840
|
+
}
|
|
212841
|
+
});
|
|
212842
|
+
|
|
212743
212843
|
// ../server/src/domains/projects/service.ts
|
|
212744
212844
|
function sanitizeCreatorActorId(raw) {
|
|
212745
212845
|
const id = raw?.trim();
|
|
@@ -212881,10 +212981,6 @@ function namedError(name, message) {
|
|
|
212881
212981
|
err.name = name;
|
|
212882
212982
|
return err;
|
|
212883
212983
|
}
|
|
212884
|
-
function slugProjectId(name) {
|
|
212885
|
-
const slug6 = name.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
212886
|
-
return `proj_${slug6 || Date.now()}`;
|
|
212887
|
-
}
|
|
212888
212984
|
function dirname24(path41) {
|
|
212889
212985
|
const norm = path41.replace(/^\/+|\/+$/g, "");
|
|
212890
212986
|
const idx = norm.lastIndexOf("/");
|
|
@@ -213081,6 +213177,7 @@ var init_service4 = __esm({
|
|
|
213081
213177
|
init_uncategorized_project();
|
|
213082
213178
|
init_workorders();
|
|
213083
213179
|
init_stats();
|
|
213180
|
+
init_project_id();
|
|
213084
213181
|
init_node_state();
|
|
213085
213182
|
DEFAULT_AGENT_ACTOR = "actor:agent:system";
|
|
213086
213183
|
CHAT_FOLDER_TASK_LABEL = "\u5BF9\u8BDD";
|
|
@@ -213283,6 +213380,15 @@ var init_service4 = __esm({
|
|
|
213283
213380
|
async getWorkspaceBinding(workOrderId) {
|
|
213284
213381
|
return this.artifacts.getWorkspaceBinding(workOrderId);
|
|
213285
213382
|
}
|
|
213383
|
+
/**
|
|
213384
|
+
* 工单负责人(改挂项目门禁的「条目本人」一支)。与列表「负责人」列**同一个出口**:
|
|
213385
|
+
* `buildWorkorderSummaries` 的 `owner`(页头总纲根的 owner)——判权限与界面上显示的负责人不许是两套。
|
|
213386
|
+
* 内核里没有这张工单 → null。
|
|
213387
|
+
*/
|
|
213388
|
+
workorderOwnerOf(workOrderId) {
|
|
213389
|
+
const summary = buildWorkorderSummaries(this.kernel.model).find((w2) => w2.id === workOrderId);
|
|
213390
|
+
return summary?.owner.id ?? null;
|
|
213391
|
+
}
|
|
213286
213392
|
/** 上传一个项目普通文件:内容入 blob 库,记一条元信息旁存(非 oplog 事实)。 */
|
|
213287
213393
|
async addProjectFile(input) {
|
|
213288
213394
|
if (!this.blobs) throw new Error("\u9879\u76EE\u6587\u4EF6\u4E0A\u4F20\u9700\u8981 blob \u5E93\uFF08domain \u672A\u6CE8\u5165 blobs\uFF09");
|
|
@@ -213361,9 +213467,14 @@ var init_service4 = __esm({
|
|
|
213361
213467
|
async createProject(input) {
|
|
213362
213468
|
if (!input.name.trim()) throw new Error("project name is required");
|
|
213363
213469
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
213364
|
-
|
|
213365
|
-
|
|
213366
|
-
|
|
213470
|
+
let id;
|
|
213471
|
+
if (input.id !== void 0 && input.id.trim() !== "") {
|
|
213472
|
+
id = input.id;
|
|
213473
|
+
const existing = await this.projects.getProject(id);
|
|
213474
|
+
if (existing) return this.withProjectDerivedState(existing);
|
|
213475
|
+
} else {
|
|
213476
|
+
id = await this.allocateProjectId();
|
|
213477
|
+
}
|
|
213367
213478
|
const createdById = sanitizeCreatorActorId(input.createdBy);
|
|
213368
213479
|
const project = {
|
|
213369
213480
|
id,
|
|
@@ -213399,6 +213510,14 @@ var init_service4 = __esm({
|
|
|
213399
213510
|
}
|
|
213400
213511
|
return await this.getProject(id) ?? project;
|
|
213401
213512
|
}
|
|
213513
|
+
/** 给「没带 id 的新建」挑一个本公司还没用过的随机 id(`randomProjectId`);连撞几次说明生成器坏了,直接报错。 */
|
|
213514
|
+
async allocateProjectId() {
|
|
213515
|
+
for (let attempt = 0; attempt < 5; attempt++) {
|
|
213516
|
+
const id = randomProjectId();
|
|
213517
|
+
if (!await this.projects.getProject(id)) return id;
|
|
213518
|
+
}
|
|
213519
|
+
throw new Error("project id allocation failed: random ids kept colliding");
|
|
213520
|
+
}
|
|
213402
213521
|
async getProject(id) {
|
|
213403
213522
|
if (isUncategorizedProjectId(id)) return this.buildUncategorizedProject();
|
|
213404
213523
|
const project = await this.projects.getProject(id);
|
|
@@ -214741,12 +214860,12 @@ var init_service4 = __esm({
|
|
|
214741
214860
|
});
|
|
214742
214861
|
|
|
214743
214862
|
// ../server/src/dev-store.ts
|
|
214744
|
-
var
|
|
214863
|
+
var import_node_crypto42, fs20, path21, NdjsonOplogStore, DirBlobStore, MUTATORS, FileTypeRegistryStore, FileRoleRegistryStore, FileRegistryStore, FileAssistantBindStore, FileHumanPrefsStore, FileProjectStateStore, FileArtifactStateStore, FileTraceStore, MemoryChatSessionStore, FileChatSessionStore, MemoryChatTurnStore, FileChatTurnStore, MemoryReadMarkerStore, FileReadMarkerStore;
|
|
214745
214864
|
var init_dev_store = __esm({
|
|
214746
214865
|
"../server/src/dev-store.ts"() {
|
|
214747
214866
|
"use strict";
|
|
214748
214867
|
init_src();
|
|
214749
|
-
|
|
214868
|
+
import_node_crypto42 = require("node:crypto");
|
|
214750
214869
|
fs20 = __toESM(require("node:fs"), 1);
|
|
214751
214870
|
path21 = __toESM(require("node:path"), 1);
|
|
214752
214871
|
init_src();
|
|
@@ -214800,7 +214919,7 @@ var init_dev_store = __esm({
|
|
|
214800
214919
|
return path21.join(this.dir, hash2);
|
|
214801
214920
|
}
|
|
214802
214921
|
async put(bytes2) {
|
|
214803
|
-
const hash2 = (0,
|
|
214922
|
+
const hash2 = (0, import_node_crypto42.createHash)("sha256").update(bytes2).digest("hex");
|
|
214804
214923
|
const file = this.fileOf(hash2);
|
|
214805
214924
|
if (!fs20.existsSync(file)) fs20.writeFileSync(file, bytes2);
|
|
214806
214925
|
return hash2;
|
|
@@ -215385,6 +215504,10 @@ var init_dev_store = __esm({
|
|
|
215385
215504
|
async listSessionsByWorkspace(workspace) {
|
|
215386
215505
|
return [...this.sessions.values()].filter((s2) => s2.workspace === workspace && !s2.analyzedRunId && s2.visibility !== "internal").sort((a, b2) => b2.touchedAt.localeCompare(a.touchedAt)).map((s2) => this.withQuality(s2));
|
|
215387
215506
|
}
|
|
215507
|
+
/** 语义同 postgres 版:项目「关联对话」,不按人过滤;排除分析 / 内部 / 挂在任务上的会话,created_at 倒序。 */
|
|
215508
|
+
async listSessionsByProject(projectId2) {
|
|
215509
|
+
return [...this.sessions.values()].filter((s2) => (s2.projectId ?? null) === projectId2 && !s2.analyzedRunId && s2.visibility !== "internal" && !s2.workspace).sort((a, b2) => b2.createdAt.localeCompare(a.createdAt) || a.id.localeCompare(b2.id));
|
|
215510
|
+
}
|
|
215388
215511
|
async listAllAnalysisSessions(opts = {}) {
|
|
215389
215512
|
const limit = opts.limit ?? 100;
|
|
215390
215513
|
const sorted = [...this.sessions.values()].filter((s2) => !!s2.analyzedRunId).sort((a, b2) => b2.touchedAt.localeCompare(a.touchedAt) || b2.id.localeCompare(a.id));
|
|
@@ -215996,7 +216119,7 @@ var init_company_engine_router = __esm({
|
|
|
215996
216119
|
|
|
215997
216120
|
// ../server/src/skill-market-client.ts
|
|
215998
216121
|
function digestOf2(bytes2) {
|
|
215999
|
-
return `sha256:${(0,
|
|
216122
|
+
return `sha256:${(0, import_node_crypto43.createHash)("sha256").update(bytes2).digest("hex")}`;
|
|
216000
216123
|
}
|
|
216001
216124
|
function createSkillMarketClientFromEnv(env = process.env) {
|
|
216002
216125
|
const base = env["SKILL_MARKET_BASE_URL"];
|
|
@@ -216007,11 +216130,11 @@ function createSkillMarketClientFromEnv(env = process.env) {
|
|
|
216007
216130
|
function sleep4(ms) {
|
|
216008
216131
|
return new Promise((r) => setTimeout(r, ms));
|
|
216009
216132
|
}
|
|
216010
|
-
var
|
|
216133
|
+
var import_node_crypto43, DisabledSkillMarketClient, HttpSkillMarketClient;
|
|
216011
216134
|
var init_skill_market_client = __esm({
|
|
216012
216135
|
"../server/src/skill-market-client.ts"() {
|
|
216013
216136
|
"use strict";
|
|
216014
|
-
|
|
216137
|
+
import_node_crypto43 = require("node:crypto");
|
|
216015
216138
|
init_src();
|
|
216016
216139
|
DisabledSkillMarketClient = class {
|
|
216017
216140
|
async listSkills(_input) {
|
|
@@ -216933,11 +217056,11 @@ function typeDefError(def, mode) {
|
|
|
216933
217056
|
}
|
|
216934
217057
|
return null;
|
|
216935
217058
|
}
|
|
216936
|
-
var
|
|
217059
|
+
var import_node_crypto44, RESERVED_FIELD_NAMES, ARTIFACT_TYPE_ACCENTS, TYPE_DEF_SCHEMA, TypesAdminService;
|
|
216937
217060
|
var init_types_admin = __esm({
|
|
216938
217061
|
"../server/src/types-admin.ts"() {
|
|
216939
217062
|
"use strict";
|
|
216940
|
-
|
|
217063
|
+
import_node_crypto44 = require("node:crypto");
|
|
216941
217064
|
init_zod();
|
|
216942
217065
|
init_src5();
|
|
216943
217066
|
init_config_audit();
|
|
@@ -217064,7 +217187,7 @@ var init_types_admin = __esm({
|
|
|
217064
217187
|
async trace(change, target, by, detail) {
|
|
217065
217188
|
try {
|
|
217066
217189
|
await this.audit?.({
|
|
217067
|
-
id: `reg_${(0,
|
|
217190
|
+
id: `reg_${(0, import_node_crypto44.randomUUID)()}`,
|
|
217068
217191
|
actor: by ?? SYSTEM_CONFIG_ACTOR,
|
|
217069
217192
|
kind: "registry_change",
|
|
217070
217193
|
target,
|
|
@@ -217212,11 +217335,11 @@ function roleDefError(def, mode) {
|
|
|
217212
217335
|
}
|
|
217213
217336
|
return null;
|
|
217214
217337
|
}
|
|
217215
|
-
var
|
|
217338
|
+
var import_node_crypto45, ACCENTS, ROLE_DEF_SCHEMA, RolesAdminService;
|
|
217216
217339
|
var init_roles_admin = __esm({
|
|
217217
217340
|
"../server/src/roles-admin.ts"() {
|
|
217218
217341
|
"use strict";
|
|
217219
|
-
|
|
217342
|
+
import_node_crypto45 = require("node:crypto");
|
|
217220
217343
|
init_zod();
|
|
217221
217344
|
init_src5();
|
|
217222
217345
|
init_config_audit();
|
|
@@ -217241,7 +217364,7 @@ var init_roles_admin = __esm({
|
|
|
217241
217364
|
async trace(change, target, by, detail) {
|
|
217242
217365
|
try {
|
|
217243
217366
|
await this.deps.audit?.({
|
|
217244
|
-
id: `reg_${(0,
|
|
217367
|
+
id: `reg_${(0, import_node_crypto45.randomUUID)()}`,
|
|
217245
217368
|
actor: by ?? SYSTEM_CONFIG_ACTOR,
|
|
217246
217369
|
kind: "registry_change",
|
|
217247
217370
|
target,
|
|
@@ -219169,7 +219292,9 @@ var init_sink = __esm({
|
|
|
219169
219292
|
st.openTools.set(callId, {
|
|
219170
219293
|
toolName: typeof p2["name"] === "string" ? p2["name"] : "tool",
|
|
219171
219294
|
input: p2["input"] ?? null,
|
|
219172
|
-
startedAt: event.ts
|
|
219295
|
+
startedAt: event.ts,
|
|
219296
|
+
// 子 Agent 里的调用:adapter 给 payload 标了派出它的那次调用(Claude 的 parent_tool_use_id)。
|
|
219297
|
+
parentCallId: typeof p2["parentToolCallId"] === "string" ? p2["parentToolCallId"] : null
|
|
219173
219298
|
});
|
|
219174
219299
|
return;
|
|
219175
219300
|
}
|
|
@@ -219185,7 +219310,7 @@ var init_sink = __esm({
|
|
|
219185
219310
|
id: `tc_${st.runId}_${callId}`,
|
|
219186
219311
|
runId: st.runId,
|
|
219187
219312
|
callId,
|
|
219188
|
-
parentCallId:
|
|
219313
|
+
parentCallId: open3.parentCallId,
|
|
219189
219314
|
toolName: open3.toolName,
|
|
219190
219315
|
toolKind: toolKindOf(open3.toolName),
|
|
219191
219316
|
status: isErr ? "failed" : "succeeded",
|
|
@@ -219490,7 +219615,7 @@ function wireRecoveredChatTurn(deps) {
|
|
|
219490
219615
|
const segText = itemLedger.projectContent();
|
|
219491
219616
|
const segParts = collectedParts();
|
|
219492
219617
|
const closingId = currentMsgId;
|
|
219493
|
-
const nextId = (0,
|
|
219618
|
+
const nextId = (0, import_node_crypto46.randomUUID)();
|
|
219494
219619
|
currentMsgId = nextId;
|
|
219495
219620
|
itemLedger.beginSegment();
|
|
219496
219621
|
live.setAssistantMessageId(nextId);
|
|
@@ -219504,7 +219629,7 @@ function wireRecoveredChatTurn(deps) {
|
|
|
219504
219629
|
...segParts.length ? { parts: segParts } : {}
|
|
219505
219630
|
}).catch(() => void 0);
|
|
219506
219631
|
await store.appendMessage({
|
|
219507
|
-
id: (0,
|
|
219632
|
+
id: (0, import_node_crypto46.randomUUID)(),
|
|
219508
219633
|
sessionId: plan.chatSessionId,
|
|
219509
219634
|
role: "user",
|
|
219510
219635
|
content: text5,
|
|
@@ -219943,11 +220068,11 @@ async function recoverChatTurnsAcrossCompanies(deps) {
|
|
|
219943
220068
|
}
|
|
219944
220069
|
return { ...result, recovered };
|
|
219945
220070
|
}
|
|
219946
|
-
var
|
|
220071
|
+
var import_node_crypto46, asObj3, partsOf, maxPartSeq, exitFailed, exitErrorText, runTerminalPatch;
|
|
219947
220072
|
var init_chat_recovery = __esm({
|
|
219948
220073
|
"../server/src/chat-recovery.ts"() {
|
|
219949
220074
|
"use strict";
|
|
219950
|
-
|
|
220075
|
+
import_node_crypto46 = require("node:crypto");
|
|
219951
220076
|
init_chat_parts();
|
|
219952
220077
|
init_sink();
|
|
219953
220078
|
init_resilient_appender();
|
|
@@ -219965,6 +220090,7 @@ var init_chat_recovery = __esm({
|
|
|
219965
220090
|
durationMs: Date.parse(endedAt) - Date.parse(startedAt),
|
|
219966
220091
|
exitCode: info.code,
|
|
219967
220092
|
exitReason: info.reason ?? null,
|
|
220093
|
+
...exitFailed(info) && info.reason !== "cancelled" ? { errorCode: info.reason ?? "error", errorMessage: formatExitError(info) } : {},
|
|
219968
220094
|
transcriptRef: info.transcriptRef ?? null,
|
|
219969
220095
|
usage: info.usage ?? null,
|
|
219970
220096
|
// 重启前 create/dispatch 路已把 actor/runtime fallback 模型写进 run;退出帧没报 model 时必须保留,
|
|
@@ -219976,8 +220102,8 @@ var init_chat_recovery = __esm({
|
|
|
219976
220102
|
|
|
219977
220103
|
// ../server/src/auth/crypto.ts
|
|
219978
220104
|
function hashPassword(password) {
|
|
219979
|
-
const salt = (0,
|
|
219980
|
-
const dk = (0,
|
|
220105
|
+
const salt = (0, import_node_crypto47.randomBytes)(16);
|
|
220106
|
+
const dk = (0, import_node_crypto47.scryptSync)(password, salt, SCRYPT_KEYLEN, { N: SCRYPT_N, maxmem: 64 * 1024 * 1024 });
|
|
219981
220107
|
return `scrypt$${SCRYPT_N}$${salt.toString("base64url")}$${dk.toString("base64url")}`;
|
|
219982
220108
|
}
|
|
219983
220109
|
function verifyPassword(password, stored) {
|
|
@@ -219994,8 +220120,8 @@ function verifyPassword(password, stored) {
|
|
|
219994
220120
|
return false;
|
|
219995
220121
|
}
|
|
219996
220122
|
if (expected.length === 0) return false;
|
|
219997
|
-
const dk = (0,
|
|
219998
|
-
return dk.length === expected.length && (0,
|
|
220123
|
+
const dk = (0, import_node_crypto47.scryptSync)(password, salt, expected.length, { N, maxmem: 64 * 1024 * 1024 });
|
|
220124
|
+
return dk.length === expected.length && (0, import_node_crypto47.timingSafeEqual)(dk, expected);
|
|
219999
220125
|
}
|
|
220000
220126
|
function b64urlJson(value2) {
|
|
220001
220127
|
return Buffer.from(JSON.stringify(value2)).toString("base64url");
|
|
@@ -220003,17 +220129,17 @@ function b64urlJson(value2) {
|
|
|
220003
220129
|
function signSession(claims, secret) {
|
|
220004
220130
|
const head = b64urlJson({ alg: "HS256", typ: "JWT" });
|
|
220005
220131
|
const body2 = b64urlJson(claims);
|
|
220006
|
-
const sig = (0,
|
|
220132
|
+
const sig = (0, import_node_crypto47.createHmac)("sha256", secret).update(`${head}.${body2}`).digest("base64url");
|
|
220007
220133
|
return `${head}.${body2}.${sig}`;
|
|
220008
220134
|
}
|
|
220009
220135
|
function verifySession(token, secret, nowMs) {
|
|
220010
220136
|
const parts = token.split(".");
|
|
220011
220137
|
if (parts.length !== 3) return null;
|
|
220012
220138
|
const [head, body2, sig] = parts;
|
|
220013
|
-
const expected = (0,
|
|
220139
|
+
const expected = (0, import_node_crypto47.createHmac)("sha256", secret).update(`${head}.${body2}`).digest("base64url");
|
|
220014
220140
|
const got = Buffer.from(sig);
|
|
220015
220141
|
const exp = Buffer.from(expected);
|
|
220016
|
-
if (got.length !== exp.length || !(0,
|
|
220142
|
+
if (got.length !== exp.length || !(0, import_node_crypto47.timingSafeEqual)(got, exp)) return null;
|
|
220017
220143
|
let claims;
|
|
220018
220144
|
try {
|
|
220019
220145
|
claims = JSON.parse(Buffer.from(body2, "base64url").toString("utf8"));
|
|
@@ -220025,21 +220151,21 @@ function verifySession(token, secret, nowMs) {
|
|
|
220025
220151
|
return claims;
|
|
220026
220152
|
}
|
|
220027
220153
|
function generateCode() {
|
|
220028
|
-
return String((0,
|
|
220154
|
+
return String((0, import_node_crypto47.randomInt)(0, 1e6)).padStart(6, "0");
|
|
220029
220155
|
}
|
|
220030
220156
|
function hashCode(code2, secret) {
|
|
220031
|
-
return (0,
|
|
220157
|
+
return (0, import_node_crypto47.createHmac)("sha256", secret).update(`code:${code2}`).digest("base64url");
|
|
220032
220158
|
}
|
|
220033
220159
|
function safeEqualHash(a, b2) {
|
|
220034
220160
|
const ba = Buffer.from(a);
|
|
220035
220161
|
const bb = Buffer.from(b2);
|
|
220036
|
-
return ba.length === bb.length && (0,
|
|
220162
|
+
return ba.length === bb.length && (0, import_node_crypto47.timingSafeEqual)(ba, bb);
|
|
220037
220163
|
}
|
|
220038
|
-
var
|
|
220164
|
+
var import_node_crypto47, SCRYPT_N, SCRYPT_KEYLEN;
|
|
220039
220165
|
var init_crypto2 = __esm({
|
|
220040
220166
|
"../server/src/auth/crypto.ts"() {
|
|
220041
220167
|
"use strict";
|
|
220042
|
-
|
|
220168
|
+
import_node_crypto47 = require("node:crypto");
|
|
220043
220169
|
SCRYPT_N = 16384;
|
|
220044
220170
|
SCRYPT_KEYLEN = 32;
|
|
220045
220171
|
}
|
|
@@ -220262,6 +220388,9 @@ var init_daemon_hub = __esm({
|
|
|
220262
220388
|
this.wss = new import_websocket_server.default({
|
|
220263
220389
|
server,
|
|
220264
220390
|
path: path41,
|
|
220391
|
+
// workdir_read returns base64 plus a JSON envelope. ws defaults to 100 MiB,
|
|
220392
|
+
// which would disconnect the node before a 200 MiB original reaches HTTP.
|
|
220393
|
+
maxPayload: 4 * Math.ceil(FILE_CONTENT_MAX_BYTES / 3) + 64 * 1024,
|
|
220265
220394
|
...resolveNode ? {
|
|
220266
220395
|
// 异步校验:verifyClient 允许延迟回调,故可在此 await 一次 DB 查询后再放行/拒绝。
|
|
220267
220396
|
verifyClient: (info, cb) => {
|
|
@@ -221186,16 +221315,16 @@ function variableKeyFromEnv(env = process.env) {
|
|
|
221186
221315
|
return buf;
|
|
221187
221316
|
}
|
|
221188
221317
|
if (env.NODE_ENV === "production") throw new Error("OASIS_VAR_KEY is required in production");
|
|
221189
|
-
return (0,
|
|
221318
|
+
return (0, import_node_crypto48.createHash)("sha256").update("oasis-dev-only-variable-key").digest();
|
|
221190
221319
|
}
|
|
221191
221320
|
function dedupe(ids2) {
|
|
221192
221321
|
return [...new Set(ids2.filter((x2) => typeof x2 === "string" && x2.length > 0))];
|
|
221193
221322
|
}
|
|
221194
|
-
var
|
|
221323
|
+
var import_node_crypto48, REDACTED_MARKER, ActorsService, mask, changedKeys;
|
|
221195
221324
|
var init_service5 = __esm({
|
|
221196
221325
|
"../server/src/domains/actors/service.ts"() {
|
|
221197
221326
|
"use strict";
|
|
221198
|
-
|
|
221327
|
+
import_node_crypto48 = require("node:crypto");
|
|
221199
221328
|
init_skill_fetcher();
|
|
221200
221329
|
init_identity();
|
|
221201
221330
|
init_migrate();
|
|
@@ -221759,7 +221888,7 @@ ${input.description}
|
|
|
221759
221888
|
*/
|
|
221760
221889
|
buildSkillFile(skillId, path41, content3, now) {
|
|
221761
221890
|
const bytes2 = new TextEncoder().encode(content3);
|
|
221762
|
-
const blobHash = (0,
|
|
221891
|
+
const blobHash = (0, import_node_crypto48.createHash)("sha256").update(bytes2).digest("hex");
|
|
221763
221892
|
return { skillId, path: path41, content: content3, blobHash, size: bytes2.length, updatedAt: now };
|
|
221764
221893
|
}
|
|
221765
221894
|
/**
|
|
@@ -222411,15 +222540,15 @@ ${input.description}
|
|
|
222411
222540
|
return hit ? { value: hit.value, ...hit.origin ? { origin: hit.origin } : {} } : null;
|
|
222412
222541
|
}
|
|
222413
222542
|
encrypt(plain) {
|
|
222414
|
-
const iv = (0,
|
|
222415
|
-
const cipher = (0,
|
|
222543
|
+
const iv = (0, import_node_crypto48.randomBytes)(12);
|
|
222544
|
+
const cipher = (0, import_node_crypto48.createCipheriv)("aes-256-gcm", this.opts.variableKey, iv);
|
|
222416
222545
|
const enc4 = Buffer.concat([cipher.update(plain, "utf8"), cipher.final()]);
|
|
222417
222546
|
return [iv.toString("base64"), cipher.getAuthTag().toString("base64"), enc4.toString("base64")].join(".");
|
|
222418
222547
|
}
|
|
222419
222548
|
decrypt(packed) {
|
|
222420
222549
|
const [iv, tag, data] = packed.split(".");
|
|
222421
222550
|
if (!iv || !tag || typeof data !== "string") throw new Error("malformed ciphertext");
|
|
222422
|
-
const decipher = (0,
|
|
222551
|
+
const decipher = (0, import_node_crypto48.createDecipheriv)("aes-256-gcm", this.opts.variableKey, Buffer.from(iv, "base64"));
|
|
222423
222552
|
decipher.setAuthTag(Buffer.from(tag, "base64"));
|
|
222424
222553
|
return Buffer.concat([decipher.update(Buffer.from(data, "base64")), decipher.final()]).toString("utf8");
|
|
222425
222554
|
}
|
|
@@ -223037,7 +223166,7 @@ async function listSkillMetadataForActor(args) {
|
|
|
223037
223166
|
usedDirs.add(dir);
|
|
223038
223167
|
const sorted = [...metas].sort((a, b2) => a.path.localeCompare(b2.path));
|
|
223039
223168
|
let latest = "1970-01-01T00:00:00.000Z";
|
|
223040
|
-
const hasher = (0,
|
|
223169
|
+
const hasher = (0, import_node_crypto49.createHash)("sha256");
|
|
223041
223170
|
for (const m2 of sorted) {
|
|
223042
223171
|
if (m2.updatedAt > latest) latest = m2.updatedAt;
|
|
223043
223172
|
hasher.update(m2.path);
|
|
@@ -223062,11 +223191,11 @@ async function listSkillMetadataForActor(args) {
|
|
|
223062
223191
|
const dir = sanitizeSkillDir(c.name, c.slug);
|
|
223063
223192
|
if (usedDirs.has(dir)) continue;
|
|
223064
223193
|
usedDirs.add(dir);
|
|
223065
|
-
const hasher = (0,
|
|
223194
|
+
const hasher = (0, import_node_crypto49.createHash)("sha256");
|
|
223066
223195
|
for (const p2 of paths) {
|
|
223067
223196
|
hasher.update(p2);
|
|
223068
223197
|
hasher.update("\0");
|
|
223069
|
-
hasher.update((0,
|
|
223198
|
+
hasher.update((0, import_node_crypto49.createHash)("sha256").update(c.files[p2]).digest("hex"));
|
|
223070
223199
|
hasher.update("\0");
|
|
223071
223200
|
}
|
|
223072
223201
|
out.push({
|
|
@@ -223087,11 +223216,11 @@ async function listSkillMetadataForActor(args) {
|
|
|
223087
223216
|
const dir = sanitizeSkillDir(b2.name, b2.id);
|
|
223088
223217
|
if (usedDirs.has(dir)) continue;
|
|
223089
223218
|
usedDirs.add(dir);
|
|
223090
|
-
const hasher = (0,
|
|
223219
|
+
const hasher = (0, import_node_crypto49.createHash)("sha256");
|
|
223091
223220
|
for (const p2 of paths) {
|
|
223092
223221
|
hasher.update(p2);
|
|
223093
223222
|
hasher.update("\0");
|
|
223094
|
-
hasher.update((0,
|
|
223223
|
+
hasher.update((0, import_node_crypto49.createHash)("sha256").update(b2.files[p2]).digest("hex"));
|
|
223095
223224
|
hasher.update("\0");
|
|
223096
223225
|
}
|
|
223097
223226
|
out.push({
|
|
@@ -223111,7 +223240,7 @@ function builtinSkillToFiles(b2) {
|
|
|
223111
223240
|
skillId: `builtin:${b2.id}`,
|
|
223112
223241
|
path: path41,
|
|
223113
223242
|
content: content3,
|
|
223114
|
-
blobHash: (0,
|
|
223243
|
+
blobHash: (0, import_node_crypto49.createHash)("sha256").update(content3).digest("hex"),
|
|
223115
223244
|
size: Buffer.byteLength(content3, "utf8"),
|
|
223116
223245
|
updatedAt: "1970-01-01T00:00:00.000Z"
|
|
223117
223246
|
}));
|
|
@@ -223135,7 +223264,7 @@ function sanitizeSkillDir(name, fallbackId) {
|
|
|
223135
223264
|
if (byName) return byName;
|
|
223136
223265
|
const byId = fallbackId ? fold2(fallbackId) : "";
|
|
223137
223266
|
if (byId) return byId;
|
|
223138
|
-
return `skill-${(0,
|
|
223267
|
+
return `skill-${(0, import_node_crypto49.createHash)("sha256").update(name).digest("hex").slice(0, 8)}`;
|
|
223139
223268
|
}
|
|
223140
223269
|
async function materializeSkillFiles(args) {
|
|
223141
223270
|
const skills = await args.service.listInstalledSkillsForActor(args.actorId);
|
|
@@ -223168,7 +223297,7 @@ function connectorSkillToFiles(c) {
|
|
|
223168
223297
|
skillId: c.id,
|
|
223169
223298
|
path: path41,
|
|
223170
223299
|
content: content3,
|
|
223171
|
-
blobHash: (0,
|
|
223300
|
+
blobHash: (0, import_node_crypto49.createHash)("sha256").update(content3).digest("hex"),
|
|
223172
223301
|
size: Buffer.byteLength(content3, "utf8"),
|
|
223173
223302
|
updatedAt: "1970-01-01T00:00:00.000Z"
|
|
223174
223303
|
}));
|
|
@@ -223185,11 +223314,11 @@ function connectorSkillDisplayRows(connectorSkills, enabledConnectors) {
|
|
|
223185
223314
|
...s2.version !== void 0 ? { version: s2.version } : {}
|
|
223186
223315
|
}));
|
|
223187
223316
|
}
|
|
223188
|
-
var
|
|
223317
|
+
var import_node_crypto49;
|
|
223189
223318
|
var init_skill_materializer = __esm({
|
|
223190
223319
|
"../server/src/domains/actors/skill-materializer.ts"() {
|
|
223191
223320
|
"use strict";
|
|
223192
|
-
|
|
223321
|
+
import_node_crypto49 = require("node:crypto");
|
|
223193
223322
|
}
|
|
223194
223323
|
});
|
|
223195
223324
|
|
|
@@ -224700,7 +224829,7 @@ function createActorsDomain(opts) {
|
|
|
224700
224829
|
...kernel !== void 0 ? { onRolesChanged: (a, r) => kernel.setActorRoles(a, r) } : {},
|
|
224701
224830
|
audit: async (entry) => {
|
|
224702
224831
|
await opts.audit?.({
|
|
224703
|
-
id: `reg_${(0,
|
|
224832
|
+
id: `reg_${(0, import_node_crypto50.randomUUID)()}`,
|
|
224704
224833
|
actor: entry.by,
|
|
224705
224834
|
kind: "registry_change",
|
|
224706
224835
|
target: entry.actorId,
|
|
@@ -224740,11 +224869,11 @@ function createActorsDomain(opts) {
|
|
|
224740
224869
|
register: actorsDomain({ resolveCtx, ...opts.resolveTrace ? { resolveTrace: opts.resolveTrace } : {}, ...opts.trace ? { trace: opts.trace } : {}, ...opts.listBuiltinSkills ? { listBuiltinSkills: opts.listBuiltinSkills } : {}, ...opts.getBuiltinSkills ? { getBuiltinSkills: opts.getBuiltinSkills } : {}, ...opts.getConnectorSkills ? { getConnectorSkills: opts.getConnectorSkills } : {}, ...opts.refreshConnectorSkills ? { refreshConnectorSkills: opts.refreshConnectorSkills } : {}, ...opts.memory ? { memory: opts.memory } : {}, ...opts.resolveDispatchScope ? { resolveDispatchScope: opts.resolveDispatchScope } : {}, ...opts.projectExists ? { projectExists: opts.projectExists } : {}, ...opts.isCompanyManager ? { isCompanyManager: opts.isCompanyManager } : {}, ...opts.credentialAudit ? { credentialAudit: opts.credentialAudit } : {}, ...opts.readCredentialAudit ? { readCredentialAudit: opts.readCredentialAudit } : {}, ...opts.credentialRevealLimits ? { credentialRevealLimits: opts.credentialRevealLimits } : {}, ...opts.skillMarket ? { skillMarket: opts.skillMarket } : {}, ...opts.resolveNodeTenancy ? { resolveNodeTenancy: opts.resolveNodeTenancy } : {} })
|
|
224741
224870
|
};
|
|
224742
224871
|
}
|
|
224743
|
-
var
|
|
224872
|
+
var import_node_crypto50;
|
|
224744
224873
|
var init_actors = __esm({
|
|
224745
224874
|
"../server/src/domains/actors/index.ts"() {
|
|
224746
224875
|
"use strict";
|
|
224747
|
-
|
|
224876
|
+
import_node_crypto50 = require("node:crypto");
|
|
224748
224877
|
init_service5();
|
|
224749
224878
|
init_routes3();
|
|
224750
224879
|
init_service5();
|
|
@@ -224914,6 +225043,359 @@ var init_assistant_tier_dispatch = __esm({
|
|
|
224914
225043
|
}
|
|
224915
225044
|
});
|
|
224916
225045
|
|
|
225046
|
+
// ../server/src/domains/chat-sessions/files-view.ts
|
|
225047
|
+
function reasonFromWorkdirCode(code2) {
|
|
225048
|
+
switch (code2) {
|
|
225049
|
+
case "NODE_OFFLINE":
|
|
225050
|
+
return "NODE_OFFLINE";
|
|
225051
|
+
case "TIMEOUT":
|
|
225052
|
+
return "TIMEOUT";
|
|
225053
|
+
default:
|
|
225054
|
+
return "ERROR";
|
|
225055
|
+
}
|
|
225056
|
+
}
|
|
225057
|
+
function joinRel2(dir, name) {
|
|
225058
|
+
return dir ? `${dir}/${name}` : name;
|
|
225059
|
+
}
|
|
225060
|
+
function workdirFileItem(rel, name, size, mtime) {
|
|
225061
|
+
return {
|
|
225062
|
+
id: `workdir:${rel}`,
|
|
225063
|
+
name,
|
|
225064
|
+
kind: "file",
|
|
225065
|
+
// 节点侧列目录只报 name/type/size/mtime,没有 MIME——诚实留 null,
|
|
225066
|
+
// 不拿后缀猜(红线:取不到就是取不到,别拿别的字段顶)。
|
|
225067
|
+
content_type: null,
|
|
225068
|
+
size,
|
|
225069
|
+
updated_at: mtime,
|
|
225070
|
+
source: "workdir",
|
|
225071
|
+
blob_ref: null,
|
|
225072
|
+
path: rel,
|
|
225073
|
+
message_id: null,
|
|
225074
|
+
// 工作区文件本期不开写回(brief §4①:要动 node↔server 协议帧,超预算)。
|
|
225075
|
+
// 这里是**按能力不渲染**的判据,不是置灰假钮。
|
|
225076
|
+
editable: false
|
|
225077
|
+
};
|
|
225078
|
+
}
|
|
225079
|
+
async function collectWorkdirFiles(bridge, loc, now = Date.now) {
|
|
225080
|
+
const items = [];
|
|
225081
|
+
if (typeof bridge.walk === "function") {
|
|
225082
|
+
const walked = await bridge.walk(
|
|
225083
|
+
loc.nodeId,
|
|
225084
|
+
{ workdirKey: loc.workdirKey, runtimeKind: loc.runtimeKind, rtId: loc.rtId, path: "" },
|
|
225085
|
+
WORKDIR_TREE_MAX_ENTRIES
|
|
225086
|
+
);
|
|
225087
|
+
if (walked.ok) {
|
|
225088
|
+
let truncated2 = walked.truncated === true;
|
|
225089
|
+
for (const entry of walked.entries) {
|
|
225090
|
+
if (entry.type !== "file") continue;
|
|
225091
|
+
if (items.length >= WORKDIR_WALK_MAX_ENTRIES) {
|
|
225092
|
+
truncated2 = true;
|
|
225093
|
+
break;
|
|
225094
|
+
}
|
|
225095
|
+
const slash = entry.path.lastIndexOf("/");
|
|
225096
|
+
items.push(workdirFileItem(entry.path, entry.path.slice(slash + 1), entry.size, entry.mtime));
|
|
225097
|
+
}
|
|
225098
|
+
return { ok: true, items, truncated: truncated2 };
|
|
225099
|
+
}
|
|
225100
|
+
if (walked.code === "NOT_FOUND") return { ok: true, items: [], truncated: false };
|
|
225101
|
+
if (walked.code !== "UNSUPPORTED") return { ok: false, reason: reasonFromWorkdirCode(walked.code) };
|
|
225102
|
+
}
|
|
225103
|
+
const deadline = now() + WORKDIR_WALK_BUDGET_MS;
|
|
225104
|
+
let listCalls = 0;
|
|
225105
|
+
let truncated = false;
|
|
225106
|
+
const listDir = (path41) => {
|
|
225107
|
+
listCalls += 1;
|
|
225108
|
+
return bridge.list(loc.nodeId, {
|
|
225109
|
+
workdirKey: loc.workdirKey,
|
|
225110
|
+
runtimeKind: loc.runtimeKind,
|
|
225111
|
+
rtId: loc.rtId,
|
|
225112
|
+
path: path41
|
|
225113
|
+
});
|
|
225114
|
+
};
|
|
225115
|
+
const root = await listDir("");
|
|
225116
|
+
if (!root.ok) {
|
|
225117
|
+
if (root.code === "NOT_FOUND") return { ok: true, items: [], truncated: false };
|
|
225118
|
+
return { ok: false, reason: reasonFromWorkdirCode(root.code) };
|
|
225119
|
+
}
|
|
225120
|
+
let level = [{ path: "", outcome: root }];
|
|
225121
|
+
for (let depth = 0; depth <= WORKDIR_WALK_MAX_DEPTH; depth += 1) {
|
|
225122
|
+
const nextDirs = [];
|
|
225123
|
+
for (const { path: dir, outcome } of level) {
|
|
225124
|
+
if (!outcome.ok) {
|
|
225125
|
+
truncated = true;
|
|
225126
|
+
continue;
|
|
225127
|
+
}
|
|
225128
|
+
if (outcome.truncated) truncated = true;
|
|
225129
|
+
for (const entry of outcome.entries) {
|
|
225130
|
+
if (entry.type === "dir") {
|
|
225131
|
+
nextDirs.push(joinRel2(dir, entry.name));
|
|
225132
|
+
continue;
|
|
225133
|
+
}
|
|
225134
|
+
if (items.length >= WORKDIR_WALK_MAX_ENTRIES) {
|
|
225135
|
+
truncated = true;
|
|
225136
|
+
continue;
|
|
225137
|
+
}
|
|
225138
|
+
items.push(workdirFileItem(joinRel2(dir, entry.name), entry.name, entry.size, entry.mtime));
|
|
225139
|
+
}
|
|
225140
|
+
}
|
|
225141
|
+
if (depth === WORKDIR_WALK_MAX_DEPTH || nextDirs.length === 0) {
|
|
225142
|
+
if (nextDirs.length > 0) truncated = true;
|
|
225143
|
+
break;
|
|
225144
|
+
}
|
|
225145
|
+
const budget = WORKDIR_WALK_MAX_LIST_CALLS - listCalls;
|
|
225146
|
+
if (budget <= 0 || now() >= deadline) {
|
|
225147
|
+
truncated = true;
|
|
225148
|
+
break;
|
|
225149
|
+
}
|
|
225150
|
+
const take = nextDirs.slice(0, budget);
|
|
225151
|
+
if (take.length < nextDirs.length) truncated = true;
|
|
225152
|
+
const outcomes = await Promise.all(take.map((p2) => listDir(p2)));
|
|
225153
|
+
level = take.map((p2, i) => ({ path: p2, outcome: outcomes[i] }));
|
|
225154
|
+
}
|
|
225155
|
+
return { ok: true, items, truncated };
|
|
225156
|
+
}
|
|
225157
|
+
async function collectMessageFiles(messages, blobs) {
|
|
225158
|
+
const rows = [];
|
|
225159
|
+
for (const message of messages) {
|
|
225160
|
+
if (!Array.isArray(message.attachments)) continue;
|
|
225161
|
+
message.attachments.forEach((attachment, index2) => {
|
|
225162
|
+
if (!attachment || typeof attachment.name !== "string" || !attachment.name) return;
|
|
225163
|
+
const blobRef = typeof attachment.blobRef === "string" && attachment.blobRef ? attachment.blobRef : null;
|
|
225164
|
+
rows.push({
|
|
225165
|
+
item: {
|
|
225166
|
+
id: `msg:${message.id}:${index2}`,
|
|
225167
|
+
name: attachment.name,
|
|
225168
|
+
kind: "file",
|
|
225169
|
+
updated_at: attachment.updatedAt ?? message.createdAt,
|
|
225170
|
+
source: "message",
|
|
225171
|
+
blob_ref: blobRef,
|
|
225172
|
+
path: null,
|
|
225173
|
+
message_id: message.id,
|
|
225174
|
+
// 没有 blobRef 的是**历史纯文本附件**(契约注释:legacy text attachments may only
|
|
225175
|
+
// contain `name`)——没有可写回的载体,一律不给编辑入口。
|
|
225176
|
+
editable: blobRef !== null && isEditableFileName(attachment.name)
|
|
225177
|
+
},
|
|
225178
|
+
blobRef,
|
|
225179
|
+
declaredType: typeof attachment.contentType === "string" && attachment.contentType ? attachment.contentType : null
|
|
225180
|
+
});
|
|
225181
|
+
});
|
|
225182
|
+
}
|
|
225183
|
+
const metaCache = /* @__PURE__ */ new Map();
|
|
225184
|
+
const metaOf = (ref2) => {
|
|
225185
|
+
if (!blobs) return Promise.resolve(null);
|
|
225186
|
+
let hit = metaCache.get(ref2);
|
|
225187
|
+
if (!hit) {
|
|
225188
|
+
hit = blobs.meta(ref2).catch(() => null);
|
|
225189
|
+
metaCache.set(ref2, hit);
|
|
225190
|
+
}
|
|
225191
|
+
return hit;
|
|
225192
|
+
};
|
|
225193
|
+
return Promise.all(rows.map(async ({ item, blobRef, declaredType }) => {
|
|
225194
|
+
const meta = blobRef ? await metaOf(blobRef) : null;
|
|
225195
|
+
return {
|
|
225196
|
+
...item,
|
|
225197
|
+
content_type: declaredType ?? meta?.contentType ?? null,
|
|
225198
|
+
size: meta?.size ?? null
|
|
225199
|
+
};
|
|
225200
|
+
}));
|
|
225201
|
+
}
|
|
225202
|
+
function mergeChatSessionFiles(messageItems, workdirItems, materializedCopies = /* @__PURE__ */ new Set()) {
|
|
225203
|
+
const out = [];
|
|
225204
|
+
const seenMessageKeys = /* @__PURE__ */ new Set();
|
|
225205
|
+
for (const item of [...messageItems].sort((a, b2) => b2.updated_at.localeCompare(a.updated_at))) {
|
|
225206
|
+
const key = `${item.name}\0${item.blob_ref ?? ""}`;
|
|
225207
|
+
if (seenMessageKeys.has(key)) continue;
|
|
225208
|
+
seenMessageKeys.add(key);
|
|
225209
|
+
out.push(item);
|
|
225210
|
+
}
|
|
225211
|
+
const seenWorkdirPaths = /* @__PURE__ */ new Set();
|
|
225212
|
+
for (const item of workdirItems) {
|
|
225213
|
+
if (item.path && materializedCopies.has(item.path)) continue;
|
|
225214
|
+
if (seenWorkdirPaths.has(item.id)) continue;
|
|
225215
|
+
seenWorkdirPaths.add(item.id);
|
|
225216
|
+
out.push(item);
|
|
225217
|
+
}
|
|
225218
|
+
out.sort((a, b2) => b2.updated_at.localeCompare(a.updated_at) || a.name.localeCompare(b2.name));
|
|
225219
|
+
return out;
|
|
225220
|
+
}
|
|
225221
|
+
async function findMaterializedAttachmentCopies(messageItems, workdirItems, read) {
|
|
225222
|
+
const copies = /* @__PURE__ */ new Set();
|
|
225223
|
+
const attachments = messageItems.filter((item) => item.blob_ref && /^[a-f0-9]{64}$/.test(item.blob_ref));
|
|
225224
|
+
let budget = CHAT_ATTACHMENT_MAX_BYTES;
|
|
225225
|
+
const deadline = Date.now() + WORKDIR_WALK_BUDGET_MS;
|
|
225226
|
+
let reads = 0;
|
|
225227
|
+
for (const file of workdirItems) {
|
|
225228
|
+
const rootFile = file.path === file.name;
|
|
225229
|
+
const inputFile = file.path?.startsWith("inputs/attachments/") && !file.path.slice("inputs/attachments/".length).includes("/");
|
|
225230
|
+
if (!file.path || !rootFile && !inputFile) continue;
|
|
225231
|
+
const candidates = attachments.filter((attachment) => {
|
|
225232
|
+
const safe = safeAttachmentName(attachment.name);
|
|
225233
|
+
const numbered = file.name.endsWith(`-${safe}`) && /^\d+$/.test(file.name.slice(0, -(safe.length + 1)));
|
|
225234
|
+
return (rootFile ? file.name === attachment.name : file.name === safe || numbered) && attachment.size !== null && attachment.size === file.size;
|
|
225235
|
+
});
|
|
225236
|
+
if (Date.now() >= deadline) break;
|
|
225237
|
+
if (!candidates.length || file.size === null || file.size > budget || reads >= 10) continue;
|
|
225238
|
+
reads += 1;
|
|
225239
|
+
budget -= file.size;
|
|
225240
|
+
let timer;
|
|
225241
|
+
try {
|
|
225242
|
+
const result = await Promise.race([
|
|
225243
|
+
read(file.path, file.size),
|
|
225244
|
+
new Promise((resolve10) => {
|
|
225245
|
+
timer = setTimeout(() => resolve10(null), Math.max(0, deadline - Date.now()));
|
|
225246
|
+
})
|
|
225247
|
+
]);
|
|
225248
|
+
if (!result?.ok) continue;
|
|
225249
|
+
const bytes2 = Buffer.from(result.contentBase64, "base64");
|
|
225250
|
+
if (bytes2.length !== file.size) continue;
|
|
225251
|
+
const hash2 = (0, import_node_crypto51.createHash)("sha256").update(bytes2).digest("hex");
|
|
225252
|
+
if (candidates.some((attachment) => attachment.blob_ref === hash2)) copies.add(file.path);
|
|
225253
|
+
} catch {
|
|
225254
|
+
} finally {
|
|
225255
|
+
if (timer) clearTimeout(timer);
|
|
225256
|
+
}
|
|
225257
|
+
}
|
|
225258
|
+
return copies;
|
|
225259
|
+
}
|
|
225260
|
+
var import_node_crypto51, WORKDIR_WALK_MAX_DEPTH, WORKDIR_WALK_MAX_ENTRIES, WORKDIR_WALK_MAX_LIST_CALLS, WORKDIR_WALK_BUDGET_MS, WORKDIR_TREE_MAX_ENTRIES;
|
|
225261
|
+
var init_files_view = __esm({
|
|
225262
|
+
"../server/src/domains/chat-sessions/files-view.ts"() {
|
|
225263
|
+
"use strict";
|
|
225264
|
+
import_node_crypto51 = require("node:crypto");
|
|
225265
|
+
init_chat_attachment_files();
|
|
225266
|
+
init_src();
|
|
225267
|
+
WORKDIR_WALK_MAX_DEPTH = 3;
|
|
225268
|
+
WORKDIR_WALK_MAX_ENTRIES = 200;
|
|
225269
|
+
WORKDIR_WALK_MAX_LIST_CALLS = 20;
|
|
225270
|
+
WORKDIR_WALK_BUDGET_MS = 1e4;
|
|
225271
|
+
WORKDIR_TREE_MAX_ENTRIES = 2e3;
|
|
225272
|
+
}
|
|
225273
|
+
});
|
|
225274
|
+
|
|
225275
|
+
// ../server/src/domains/projects/chat-files.ts
|
|
225276
|
+
function isProjectChatSession(session) {
|
|
225277
|
+
if (session.visibility === "internal") return false;
|
|
225278
|
+
if (session.analyzedRunId) return false;
|
|
225279
|
+
if (session.workspace) return false;
|
|
225280
|
+
return true;
|
|
225281
|
+
}
|
|
225282
|
+
function chatFolderTitle(session) {
|
|
225283
|
+
const title = session.title?.trim();
|
|
225284
|
+
return title ? title : "\u672A\u547D\u540D\u5BF9\u8BDD";
|
|
225285
|
+
}
|
|
225286
|
+
function outputDisplayName(path41) {
|
|
225287
|
+
return path41.startsWith("outputs/") ? path41.slice("outputs/".length) : path41;
|
|
225288
|
+
}
|
|
225289
|
+
async function collectProjectChatFiles(chat, projectId2, meta, options = {}) {
|
|
225290
|
+
const scope = isUncategorizedProjectId(projectId2) ? null : projectId2;
|
|
225291
|
+
const [attachmentMessages, outputSessions] = await Promise.all([
|
|
225292
|
+
chat.listAttachmentMessages ? chat.listAttachmentMessages(scope) : Promise.resolve([]),
|
|
225293
|
+
chat.listOutputCopies ? chat.listOutputCopies(scope) : Promise.resolve([])
|
|
225294
|
+
]);
|
|
225295
|
+
const sessionIds = [.../* @__PURE__ */ new Set([
|
|
225296
|
+
...attachmentMessages.map((m2) => m2.sessionId),
|
|
225297
|
+
...outputSessions.map((s2) => s2.sessionId)
|
|
225298
|
+
])];
|
|
225299
|
+
const sessions = /* @__PURE__ */ new Map();
|
|
225300
|
+
await Promise.all(sessionIds.map(async (id) => {
|
|
225301
|
+
const session = await chat.getSession(id);
|
|
225302
|
+
if (!session) return;
|
|
225303
|
+
if ((session.projectId ?? null) !== scope) return;
|
|
225304
|
+
if (!isProjectChatSession(session)) return;
|
|
225305
|
+
if (options.isDelegationChild && await options.isDelegationChild(id).catch(() => false)) return;
|
|
225306
|
+
sessions.set(id, session);
|
|
225307
|
+
}));
|
|
225308
|
+
const out = [];
|
|
225309
|
+
const base = (session) => ({
|
|
225310
|
+
projectId: projectId2,
|
|
225311
|
+
chatSessionId: session.id,
|
|
225312
|
+
chatTitle: chatFolderTitle(session),
|
|
225313
|
+
chatOwnerId: session.humanActorId
|
|
225314
|
+
});
|
|
225315
|
+
const bySession = /* @__PURE__ */ new Map();
|
|
225316
|
+
for (const message of attachmentMessages) {
|
|
225317
|
+
if (!sessions.has(message.sessionId)) continue;
|
|
225318
|
+
const list2 = bySession.get(message.sessionId) ?? [];
|
|
225319
|
+
list2.push(message);
|
|
225320
|
+
bySession.set(message.sessionId, list2);
|
|
225321
|
+
}
|
|
225322
|
+
for (const [sessionId, messages] of bySession) {
|
|
225323
|
+
const session = sessions.get(sessionId);
|
|
225324
|
+
const rows = await collectMessageFiles(messages.map((m2) => ({ ...m2, id: m2.messageId })), { meta });
|
|
225325
|
+
for (const row of mergeChatSessionFiles(rows, [])) {
|
|
225326
|
+
if (row.blob_ref === null) continue;
|
|
225327
|
+
out.push({
|
|
225328
|
+
...base(session),
|
|
225329
|
+
fileId: `chat:${sessionId}:${row.id}`,
|
|
225330
|
+
name: row.name,
|
|
225331
|
+
blobId: row.blob_ref,
|
|
225332
|
+
...row.content_type ? { contentType: row.content_type } : {},
|
|
225333
|
+
size: row.size,
|
|
225334
|
+
uploadedBy: session.humanActorId,
|
|
225335
|
+
uploadedAt: row.updated_at,
|
|
225336
|
+
chatSource: "attachment"
|
|
225337
|
+
});
|
|
225338
|
+
}
|
|
225339
|
+
}
|
|
225340
|
+
for (const record8 of outputSessions) {
|
|
225341
|
+
const session = sessions.get(record8.sessionId);
|
|
225342
|
+
if (!session) continue;
|
|
225343
|
+
const seen = new Set(out.filter((file) => file.chatSessionId === session.id).map((file) => `${file.name}\0${file.blobId}`));
|
|
225344
|
+
const copies = record8.copies ?? {};
|
|
225345
|
+
for (const path41 of Object.keys(copies).sort((a, b2) => a.localeCompare(b2))) {
|
|
225346
|
+
const copy = copies[path41];
|
|
225347
|
+
if (!copy?.blobRef) continue;
|
|
225348
|
+
if (seen.has(`${copy.name}\0${copy.blobRef}`)) continue;
|
|
225349
|
+
out.push({
|
|
225350
|
+
...base(session),
|
|
225351
|
+
fileId: `chat:${session.id}:out:${copy.path}`,
|
|
225352
|
+
name: outputDisplayName(copy.path),
|
|
225353
|
+
blobId: copy.blobRef,
|
|
225354
|
+
...copy.contentType ? { contentType: copy.contentType } : {},
|
|
225355
|
+
size: copy.size,
|
|
225356
|
+
uploadedBy: session.aiActorId,
|
|
225357
|
+
uploadedAt: Number.isNaN(Date.parse(copy.mtime)) ? copy.copiedAt : new Date(copy.mtime).toISOString(),
|
|
225358
|
+
chatSource: "output"
|
|
225359
|
+
});
|
|
225360
|
+
}
|
|
225361
|
+
}
|
|
225362
|
+
return out;
|
|
225363
|
+
}
|
|
225364
|
+
var init_chat_files2 = __esm({
|
|
225365
|
+
"../server/src/domains/projects/chat-files.ts"() {
|
|
225366
|
+
"use strict";
|
|
225367
|
+
init_files_view();
|
|
225368
|
+
init_uncategorized_project();
|
|
225369
|
+
}
|
|
225370
|
+
});
|
|
225371
|
+
|
|
225372
|
+
// ../server/src/domains/projects/chat-sessions.ts
|
|
225373
|
+
async function listProjectChatSessions(chat, projectId2, delegationChildIds) {
|
|
225374
|
+
if (!chat.listSessionsByProject) return [];
|
|
225375
|
+
const scope = isUncategorizedProjectId(projectId2) ? null : projectId2;
|
|
225376
|
+
const sessions = (await chat.listSessionsByProject(scope)).filter((s2) => (s2.projectId ?? null) === scope && isProjectChatSession(s2));
|
|
225377
|
+
const children = delegationChildIds && sessions.length > 0 ? await delegationChildIds(sessions.map((s2) => s2.id)).catch(() => /* @__PURE__ */ new Set()) : /* @__PURE__ */ new Set();
|
|
225378
|
+
return sessions.filter((s2) => !children.has(s2.id)).map(toRow);
|
|
225379
|
+
}
|
|
225380
|
+
function toRow(s2) {
|
|
225381
|
+
const title = s2.title?.trim();
|
|
225382
|
+
return {
|
|
225383
|
+
id: s2.id,
|
|
225384
|
+
title: title ? title : null,
|
|
225385
|
+
humanActorId: s2.humanActorId,
|
|
225386
|
+
aiActorId: s2.aiActorId,
|
|
225387
|
+
createdAt: s2.createdAt,
|
|
225388
|
+
projectId: s2.projectId ?? null
|
|
225389
|
+
};
|
|
225390
|
+
}
|
|
225391
|
+
var init_chat_sessions = __esm({
|
|
225392
|
+
"../server/src/domains/projects/chat-sessions.ts"() {
|
|
225393
|
+
"use strict";
|
|
225394
|
+
init_chat_files2();
|
|
225395
|
+
init_uncategorized_project();
|
|
225396
|
+
}
|
|
225397
|
+
});
|
|
225398
|
+
|
|
224917
225399
|
// ../server/src/domains/projects/routes.ts
|
|
224918
225400
|
function projectsDomain(opts) {
|
|
224919
225401
|
const svc = async (req) => opts.resolveService ? opts.resolveService(req.auth.companyId) : opts.service;
|
|
@@ -224927,6 +225409,28 @@ function projectsDomain(opts) {
|
|
|
224927
225409
|
if (role === "owner" || role === "admin") return;
|
|
224928
225410
|
throw new ApiError(403, action.code, `\u4F60\u6CA1\u6709${action.verb}\u8BE5\u9879\u76EE\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7EC4\u7EC7\u7BA1\u7406\u5458`);
|
|
224929
225411
|
};
|
|
225412
|
+
const mayReassignProject = async (req, item) => {
|
|
225413
|
+
if (item.actorId && item.actorId === req.auth.actor) return true;
|
|
225414
|
+
if (item.currentProjectId && !isUncategorizedProjectId(item.currentProjectId)) {
|
|
225415
|
+
const project = await (await svc(req)).getProject(item.currentProjectId);
|
|
225416
|
+
if (project?.createdBy && project.createdBy.id === req.auth.actor) return true;
|
|
225417
|
+
}
|
|
225418
|
+
if (!opts.resolveMemberRole) return false;
|
|
225419
|
+
const role = await opts.resolveMemberRole(req.auth.companyId, req.auth.actor);
|
|
225420
|
+
return role === "owner" || role === "admin";
|
|
225421
|
+
};
|
|
225422
|
+
const requireWorkorderReassignPermission = async (req, workOrderId) => {
|
|
225423
|
+
if (!opts.resolveMemberRole) return;
|
|
225424
|
+
const service = await svc(req);
|
|
225425
|
+
const binding = await service.getWorkspaceBinding(workOrderId).catch(() => null);
|
|
225426
|
+
const allowed = await mayReassignProject(req, {
|
|
225427
|
+
actorId: service.workorderOwnerOf(workOrderId),
|
|
225428
|
+
currentProjectId: binding?.projectId ?? null
|
|
225429
|
+
});
|
|
225430
|
+
if (!allowed) {
|
|
225431
|
+
throw new ApiError(403, "WORKORDER_REASSIGN_FORBIDDEN", "\u53EA\u6709\u4EFB\u52A1\u8D1F\u8D23\u4EBA\u3001\u9879\u76EE\u8D1F\u8D23\u4EBA\u6216\u7EC4\u7EC7\u7BA1\u7406\u5458\u53EF\u4EE5\u79FB\u52A8\u8FD9\u4E2A\u4EFB\u52A1");
|
|
225432
|
+
}
|
|
225433
|
+
};
|
|
224930
225434
|
return (router) => {
|
|
224931
225435
|
router.post("/api/projects", async (req) => {
|
|
224932
225436
|
const body2 = req.body;
|
|
@@ -225044,6 +225548,45 @@ function projectsDomain(opts) {
|
|
|
225044
225548
|
const items = await (await svc(req)).listWorkordersForProject(req.params.id);
|
|
225045
225549
|
return { status: 200, body: { items } };
|
|
225046
225550
|
});
|
|
225551
|
+
router.get("/api/projects/:id/chat-sessions", async (req) => {
|
|
225552
|
+
const project = await (await svc(req)).getProject(req.params.id);
|
|
225553
|
+
if (!project) throw new ApiError(404, "NOT_FOUND", `\u6CA1\u6709\u8FD9\u4E2A\u9879\u76EE\uFF1A${req.params.id}`);
|
|
225554
|
+
if (!opts.chatSessionsFor) return { status: 200, body: { items: [] } };
|
|
225555
|
+
const companyId = req.auth.companyId;
|
|
225556
|
+
const rows = await listProjectChatSessions(
|
|
225557
|
+
await opts.chatSessionsFor(companyId),
|
|
225558
|
+
req.params.id,
|
|
225559
|
+
opts.delegationChildIds ? (ids2) => opts.delegationChildIds(companyId, ids2) : void 0
|
|
225560
|
+
);
|
|
225561
|
+
return { status: 200, body: { items: rows.map(toApiProjectChatSession) } };
|
|
225562
|
+
});
|
|
225563
|
+
router.patch("/api/chat-sessions/:id/project", async (req) => {
|
|
225564
|
+
if (!opts.chatSessionsFor) throw new ApiError(404, "NOT_FOUND", "session not found");
|
|
225565
|
+
const store = await opts.chatSessionsFor(req.auth.companyId);
|
|
225566
|
+
const session = await store.getSession(req.params.id);
|
|
225567
|
+
if (!session || !isProjectChatSession(session)) throw new ApiError(404, "NOT_FOUND", "session not found");
|
|
225568
|
+
if (opts.delegationChildIds && (await opts.delegationChildIds(req.auth.companyId, [session.id])).has(session.id)) {
|
|
225569
|
+
throw new ApiError(404, "NOT_FOUND", "session not found");
|
|
225570
|
+
}
|
|
225571
|
+
const allowed = await mayReassignProject(req, {
|
|
225572
|
+
actorId: session.humanActorId,
|
|
225573
|
+
currentProjectId: session.projectId ?? null
|
|
225574
|
+
});
|
|
225575
|
+
if (!allowed) {
|
|
225576
|
+
throw new ApiError(403, "CHAT_SESSION_REASSIGN_FORBIDDEN", "\u53EA\u6709\u5BF9\u8BDD\u53D1\u8D77\u4EBA\u3001\u9879\u76EE\u8D1F\u8D23\u4EBA\u6216\u7EC4\u7EC7\u7BA1\u7406\u5458\u53EF\u4EE5\u79FB\u52A8\u8FD9\u4E2A\u5BF9\u8BDD");
|
|
225577
|
+
}
|
|
225578
|
+
const b2 = req.body ?? {};
|
|
225579
|
+
if (!("project_id" in b2) && !("projectId" in b2)) throw new ApiError(400, "BAD_REQUEST", "\u7F3A\u5C11 project_id");
|
|
225580
|
+
const raw = "project_id" in b2 ? b2.project_id : b2.projectId;
|
|
225581
|
+
const target = raw === null || raw === "" || raw === "null" || typeof raw === "string" && isUncategorizedProjectId(raw) ? null : raw;
|
|
225582
|
+
if (target !== null) {
|
|
225583
|
+
if (typeof target !== "string") throw new ApiError(400, "BAD_REQUEST", "project_id \u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u6216 null");
|
|
225584
|
+
const project = await (await svc(req)).getProject(target);
|
|
225585
|
+
if (!project) throw new ApiError(404, "NOT_FOUND", `\u6CA1\u6709\u8FD9\u4E2A\u9879\u76EE\uFF1A${target}`);
|
|
225586
|
+
}
|
|
225587
|
+
await store.updateSession(session.id, { projectId: target });
|
|
225588
|
+
return { status: 200, body: { chat_session_id: session.id, project_id: target } };
|
|
225589
|
+
});
|
|
225047
225590
|
router.post("/api/projects/:id/files", async (req) => {
|
|
225048
225591
|
const b2 = req.body ?? {};
|
|
225049
225592
|
const base642 = b2.content_base64 ?? b2.contentBase64;
|
|
@@ -225250,6 +225793,7 @@ ${errs.join("\n")}`);
|
|
|
225250
225793
|
return { status: 200, body: toApiNodeOutputValidation(validation) };
|
|
225251
225794
|
});
|
|
225252
225795
|
router.patch("/api/work-orders/:workOrderId/project", async (req) => {
|
|
225796
|
+
await requireWorkorderReassignPermission(req, req.params.workOrderId);
|
|
225253
225797
|
const b2 = req.body ?? {};
|
|
225254
225798
|
const nulledPatch = "project_id" in b2 && b2.project_id === null || "projectId" in b2 && b2.projectId === null || b2.project_id === "null" || b2.project_id === "" || b2.projectId === "null" || b2.projectId === "";
|
|
225255
225799
|
if (nulledPatch) {
|
|
@@ -225270,6 +225814,7 @@ ${errs.join("\n")}`);
|
|
|
225270
225814
|
}
|
|
225271
225815
|
});
|
|
225272
225816
|
router.delete("/api/work-orders/:workOrderId/project", async (req) => {
|
|
225817
|
+
await requireWorkorderReassignPermission(req, req.params.workOrderId);
|
|
225273
225818
|
try {
|
|
225274
225819
|
await (await svc(req)).unlinkWorkorder(req.params.workOrderId);
|
|
225275
225820
|
return { status: 200, body: { work_order_id: req.params.workOrderId, project_id: null } };
|
|
@@ -225743,6 +226288,16 @@ function toApiWorkOrderDetail(detail) {
|
|
|
225743
226288
|
}))
|
|
225744
226289
|
};
|
|
225745
226290
|
}
|
|
226291
|
+
function toApiProjectChatSession(row) {
|
|
226292
|
+
return {
|
|
226293
|
+
id: row.id,
|
|
226294
|
+
title: row.title,
|
|
226295
|
+
human_actor_id: row.humanActorId,
|
|
226296
|
+
ai_actor_id: row.aiActorId,
|
|
226297
|
+
created_at: row.createdAt,
|
|
226298
|
+
project_id: row.projectId
|
|
226299
|
+
};
|
|
226300
|
+
}
|
|
225746
226301
|
function toApiProjectFilesView(view) {
|
|
225747
226302
|
return {
|
|
225748
226303
|
total: view.total,
|
|
@@ -225801,6 +226356,8 @@ var init_routes5 = __esm({
|
|
|
225801
226356
|
"use strict";
|
|
225802
226357
|
init_router();
|
|
225803
226358
|
init_src();
|
|
226359
|
+
init_chat_files2();
|
|
226360
|
+
init_chat_sessions();
|
|
225804
226361
|
init_uncategorized_project();
|
|
225805
226362
|
}
|
|
225806
226363
|
});
|
|
@@ -228095,11 +228652,11 @@ function fromRow(row) {
|
|
|
228095
228652
|
for (const [k2, v2] of opt) if (v2 !== void 0 && v2 !== null) r[k2] = v2;
|
|
228096
228653
|
return r;
|
|
228097
228654
|
}
|
|
228098
|
-
var
|
|
228655
|
+
var import_node_crypto52, import_node_fs14, DEFAULT_PAGE, MAX_PAGE, pageSize, MemoryNotificationStore, ident3, iso2, str2, PostgresNotificationStore;
|
|
228099
228656
|
var init_notification_store = __esm({
|
|
228100
228657
|
"../server/src/domains/collab/notification-store.ts"() {
|
|
228101
228658
|
"use strict";
|
|
228102
|
-
|
|
228659
|
+
import_node_crypto52 = require("node:crypto");
|
|
228103
228660
|
import_node_fs14 = __toESM(require("node:fs"), 1);
|
|
228104
228661
|
DEFAULT_PAGE = 50;
|
|
228105
228662
|
MAX_PAGE = 200;
|
|
@@ -228132,7 +228689,7 @@ var init_notification_store = __esm({
|
|
|
228132
228689
|
async insert(n) {
|
|
228133
228690
|
const existing = this.findLive(n.recipient, n.sourceKey, n.category);
|
|
228134
228691
|
if (existing) return existing;
|
|
228135
|
-
const row = { ...n, id: `ntf:${(0,
|
|
228692
|
+
const row = { ...n, id: `ntf:${(0, import_node_crypto52.randomUUID)()}`, updatedAt: n.enteredAt };
|
|
228136
228693
|
this.rows.set(row.id, row);
|
|
228137
228694
|
this.save();
|
|
228138
228695
|
return row;
|
|
@@ -228151,13 +228708,22 @@ var init_notification_store = __esm({
|
|
|
228151
228708
|
this.rows.set(id, next);
|
|
228152
228709
|
this.save();
|
|
228153
228710
|
}
|
|
228711
|
+
async rekey(id, sourceKey, patch, at) {
|
|
228712
|
+
const r = this.rows.get(id);
|
|
228713
|
+
if (!r || r.status !== "pending" || this.findLive(r.recipient, sourceKey, r.category)) return false;
|
|
228714
|
+
this.rows.set(id, { ...r, sourceKey, ...patch.nodeId ? { nodeId: patch.nodeId } : {} });
|
|
228715
|
+
await this.refresh(id, patch, at);
|
|
228716
|
+
return true;
|
|
228717
|
+
}
|
|
228154
228718
|
async close(id, closure) {
|
|
228155
228719
|
const r = this.rows.get(id);
|
|
228156
228720
|
if (!r || r.status !== "pending") return false;
|
|
228157
228721
|
const next = { ...r, status: closure.status, closedAt: closure.closedAt, updatedAt: closure.closedAt };
|
|
228158
228722
|
if (closure.closedBy) next.closedBy = closure.closedBy;
|
|
228159
|
-
if (closure.status === "handled")
|
|
228160
|
-
|
|
228723
|
+
if (closure.status === "handled") {
|
|
228724
|
+
next.result = closure.result;
|
|
228725
|
+
next.readAt ??= closure.closedAt;
|
|
228726
|
+
} else next.invalidReason = closure.invalidReason;
|
|
228161
228727
|
this.rows.set(id, next);
|
|
228162
228728
|
this.save();
|
|
228163
228729
|
return true;
|
|
@@ -228176,6 +228742,16 @@ var init_notification_store = __esm({
|
|
|
228176
228742
|
}
|
|
228177
228743
|
if (changed) this.save();
|
|
228178
228744
|
}
|
|
228745
|
+
async countUnread(recipient) {
|
|
228746
|
+
let pending = 0;
|
|
228747
|
+
let all2 = 0;
|
|
228748
|
+
for (const r of this.rows.values()) {
|
|
228749
|
+
if (r.recipient !== recipient || r.readAt) continue;
|
|
228750
|
+
all2++;
|
|
228751
|
+
if (r.status === "pending") pending++;
|
|
228752
|
+
}
|
|
228753
|
+
return { pending, all: all2 };
|
|
228754
|
+
}
|
|
228179
228755
|
async purgeBefore(cutoff) {
|
|
228180
228756
|
let n = 0;
|
|
228181
228757
|
for (const [id, r] of this.rows) {
|
|
@@ -228236,7 +228812,7 @@ var init_notification_store = __esm({
|
|
|
228236
228812
|
return new _PostgresNotificationStore(sql, schema);
|
|
228237
228813
|
}
|
|
228238
228814
|
async insert(n) {
|
|
228239
|
-
const id = `ntf:${(0,
|
|
228815
|
+
const id = `ntf:${(0, import_node_crypto52.randomUUID)()}`;
|
|
228240
228816
|
const r = await this.sql.query(
|
|
228241
228817
|
`INSERT INTO ${this.t} (id, recipient, category, source_key, kind, workorder_id, node_id, card_id, actor_id,
|
|
228242
228818
|
title, workspace_title, entered_at, updated_at, status, read_at, item)
|
|
@@ -228289,9 +228865,34 @@ var init_notification_store = __esm({
|
|
|
228289
228865
|
]
|
|
228290
228866
|
);
|
|
228291
228867
|
}
|
|
228868
|
+
async rekey(id, sourceKey, patch, at) {
|
|
228869
|
+
try {
|
|
228870
|
+
const r = await this.sql.query(
|
|
228871
|
+
`UPDATE ${this.t} SET source_key = $2, node_id = COALESCE($3, node_id), title = $4, workspace_title = $5,
|
|
228872
|
+
actor_id = $6, card_id = $7, item = $8, updated_at = $9
|
|
228873
|
+
WHERE id = $1 AND status = 'pending'`,
|
|
228874
|
+
[
|
|
228875
|
+
id,
|
|
228876
|
+
sourceKey,
|
|
228877
|
+
patch.nodeId ?? null,
|
|
228878
|
+
patch.title,
|
|
228879
|
+
patch.workspaceTitle ?? null,
|
|
228880
|
+
patch.actorId ?? null,
|
|
228881
|
+
patch.cardId ?? null,
|
|
228882
|
+
patch.item ? JSON.stringify(patch.item) : null,
|
|
228883
|
+
at
|
|
228884
|
+
]
|
|
228885
|
+
);
|
|
228886
|
+
return (r.rowCount ?? 0) > 0;
|
|
228887
|
+
} catch (err) {
|
|
228888
|
+
if (err.code === "23505") return false;
|
|
228889
|
+
throw err;
|
|
228890
|
+
}
|
|
228891
|
+
}
|
|
228292
228892
|
async close(id, closure) {
|
|
228293
228893
|
const r = await this.sql.query(
|
|
228294
|
-
`UPDATE ${this.t} SET status = $2, closed_at = $3, closed_by = $4, result = $5, invalid_reason = $6, updated_at = $3
|
|
228894
|
+
`UPDATE ${this.t} SET status = $2, closed_at = $3, closed_by = $4, result = $5, invalid_reason = $6, updated_at = $3,
|
|
228895
|
+
read_at = CASE WHEN $2 = 'handled' THEN COALESCE(read_at, $3::timestamptz) ELSE read_at END
|
|
228295
228896
|
WHERE id = $1 AND status = 'pending'`,
|
|
228296
228897
|
[
|
|
228297
228898
|
id,
|
|
@@ -228331,6 +228932,15 @@ var init_notification_store = __esm({
|
|
|
228331
228932
|
[recipient, [...ids2], at]
|
|
228332
228933
|
);
|
|
228333
228934
|
}
|
|
228935
|
+
async countUnread(recipient) {
|
|
228936
|
+
const r = await this.sql.query(
|
|
228937
|
+
`SELECT count(*) FILTER (WHERE status = 'pending')::int AS pending, count(*)::int AS "all"
|
|
228938
|
+
FROM ${this.t} WHERE recipient = $1 AND read_at IS NULL`,
|
|
228939
|
+
[recipient]
|
|
228940
|
+
);
|
|
228941
|
+
const row = r.rows[0] ?? {};
|
|
228942
|
+
return { pending: Number(row["pending"] ?? 0), all: Number(row["all"] ?? 0) };
|
|
228943
|
+
}
|
|
228334
228944
|
async purgeBefore(cutoff) {
|
|
228335
228945
|
const r = await this.sql.query(
|
|
228336
228946
|
`DELETE FROM ${this.t}
|
|
@@ -229153,13 +229763,13 @@ function nameKey(name) {
|
|
|
229153
229763
|
function cleanName(name) {
|
|
229154
229764
|
return name.trim().replace(/\s+/g, " ");
|
|
229155
229765
|
}
|
|
229156
|
-
var import_node_fs15, import_node_path20,
|
|
229766
|
+
var import_node_fs15, import_node_path20, import_node_crypto53, SEP, keyOf, prefixOf, MemoryWorkorderTagStore, FileWorkorderTagStore;
|
|
229157
229767
|
var init_tags = __esm({
|
|
229158
229768
|
"../server/src/domains/collab/tags.ts"() {
|
|
229159
229769
|
"use strict";
|
|
229160
229770
|
import_node_fs15 = __toESM(require("node:fs"), 1);
|
|
229161
229771
|
import_node_path20 = __toESM(require("node:path"), 1);
|
|
229162
|
-
|
|
229772
|
+
import_node_crypto53 = __toESM(require("node:crypto"), 1);
|
|
229163
229773
|
SEP = "::";
|
|
229164
229774
|
keyOf = (companyId, id) => `${companyId}${SEP}${id}`;
|
|
229165
229775
|
prefixOf = (companyId) => `${companyId}${SEP}`;
|
|
@@ -229177,7 +229787,7 @@ var init_tags = __esm({
|
|
|
229177
229787
|
if (!name) return null;
|
|
229178
229788
|
if (this.entries(companyId).some((t) => nameKey(t.name) === nameKey(name))) return null;
|
|
229179
229789
|
const tag = {
|
|
229180
|
-
id: `tag-${
|
|
229790
|
+
id: `tag-${import_node_crypto53.default.randomBytes(6).toString("hex")}`,
|
|
229181
229791
|
name,
|
|
229182
229792
|
...input.color?.trim() ? { color: input.color.trim() } : {},
|
|
229183
229793
|
...input.description?.trim() ? { description: input.description.trim() } : {}
|
|
@@ -230028,7 +230638,27 @@ function collabDomain(opts) {
|
|
|
230028
230638
|
limit
|
|
230029
230639
|
});
|
|
230030
230640
|
const last = items.at(-1);
|
|
230031
|
-
|
|
230641
|
+
const unread = await store.countUnread(req.auth.actor);
|
|
230642
|
+
const body2 = { items, cursor: last && items.length === limit ? notificationCursor(last) : null, unread };
|
|
230643
|
+
return { status: 200, body: body2 };
|
|
230644
|
+
});
|
|
230645
|
+
router.post("/api/notifications/read", async (req) => {
|
|
230646
|
+
if (!opts.resolveNotificationLedger) {
|
|
230647
|
+
return { status: 501, body: { error: { code: "not_implemented", message: "\u672C\u90E8\u7F72\u672A\u542F\u7528\u901A\u77E5\u53F0\u8D26" } } };
|
|
230648
|
+
}
|
|
230649
|
+
const ids2 = req.body?.ids;
|
|
230650
|
+
if (!Array.isArray(ids2) || ids2.length === 0 || ids2.length > 200 || !ids2.every((id) => typeof id === "string" && id.length > 0)) {
|
|
230651
|
+
return { status: 400, body: { error: { code: "bad_request", message: "ids \u5FC5\u987B\u662F 1\u2013200 \u4E2A\u901A\u77E5 id" } } };
|
|
230652
|
+
}
|
|
230653
|
+
let store;
|
|
230654
|
+
try {
|
|
230655
|
+
store = await opts.resolveNotificationLedger(req.auth.companyId);
|
|
230656
|
+
} catch (err) {
|
|
230657
|
+
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)}`);
|
|
230658
|
+
}
|
|
230659
|
+
if (!store) return { status: 503, body: { error: { code: "unavailable", message: "\u901A\u77E5\u53F0\u8D26\u6682\u4E0D\u53EF\u7528" } } };
|
|
230660
|
+
await store.markRead(req.auth.actor, ids2, (/* @__PURE__ */ new Date()).toISOString());
|
|
230661
|
+
return { status: 200, body: { ok: true } };
|
|
230032
230662
|
});
|
|
230033
230663
|
const companyOf = (req) => req.auth.companyId ?? "company:default";
|
|
230034
230664
|
const noTagStore = { status: 501, body: { error: { code: "not_implemented", message: "\u672C\u90E8\u7F72\u672A\u542F\u7528\u5DE5\u5355\u6807\u7B7E" } } };
|
|
@@ -230316,326 +230946,6 @@ var init_collab = __esm({
|
|
|
230316
230946
|
}
|
|
230317
230947
|
});
|
|
230318
230948
|
|
|
230319
|
-
// ../server/src/domains/chat-sessions/files-view.ts
|
|
230320
|
-
function reasonFromWorkdirCode(code2) {
|
|
230321
|
-
switch (code2) {
|
|
230322
|
-
case "NODE_OFFLINE":
|
|
230323
|
-
return "NODE_OFFLINE";
|
|
230324
|
-
case "TIMEOUT":
|
|
230325
|
-
return "TIMEOUT";
|
|
230326
|
-
default:
|
|
230327
|
-
return "ERROR";
|
|
230328
|
-
}
|
|
230329
|
-
}
|
|
230330
|
-
function joinRel2(dir, name) {
|
|
230331
|
-
return dir ? `${dir}/${name}` : name;
|
|
230332
|
-
}
|
|
230333
|
-
function workdirFileItem(rel, name, size, mtime) {
|
|
230334
|
-
return {
|
|
230335
|
-
id: `workdir:${rel}`,
|
|
230336
|
-
name,
|
|
230337
|
-
kind: "file",
|
|
230338
|
-
// 节点侧列目录只报 name/type/size/mtime,没有 MIME——诚实留 null,
|
|
230339
|
-
// 不拿后缀猜(红线:取不到就是取不到,别拿别的字段顶)。
|
|
230340
|
-
content_type: null,
|
|
230341
|
-
size,
|
|
230342
|
-
updated_at: mtime,
|
|
230343
|
-
source: "workdir",
|
|
230344
|
-
blob_ref: null,
|
|
230345
|
-
path: rel,
|
|
230346
|
-
message_id: null,
|
|
230347
|
-
// 工作区文件本期不开写回(brief §4①:要动 node↔server 协议帧,超预算)。
|
|
230348
|
-
// 这里是**按能力不渲染**的判据,不是置灰假钮。
|
|
230349
|
-
editable: false
|
|
230350
|
-
};
|
|
230351
|
-
}
|
|
230352
|
-
async function collectWorkdirFiles(bridge, loc, now = Date.now) {
|
|
230353
|
-
const items = [];
|
|
230354
|
-
if (typeof bridge.walk === "function") {
|
|
230355
|
-
const walked = await bridge.walk(
|
|
230356
|
-
loc.nodeId,
|
|
230357
|
-
{ workdirKey: loc.workdirKey, runtimeKind: loc.runtimeKind, rtId: loc.rtId, path: "" },
|
|
230358
|
-
WORKDIR_TREE_MAX_ENTRIES
|
|
230359
|
-
);
|
|
230360
|
-
if (walked.ok) {
|
|
230361
|
-
let truncated2 = walked.truncated === true;
|
|
230362
|
-
for (const entry of walked.entries) {
|
|
230363
|
-
if (entry.type !== "file") continue;
|
|
230364
|
-
if (items.length >= WORKDIR_WALK_MAX_ENTRIES) {
|
|
230365
|
-
truncated2 = true;
|
|
230366
|
-
break;
|
|
230367
|
-
}
|
|
230368
|
-
const slash = entry.path.lastIndexOf("/");
|
|
230369
|
-
items.push(workdirFileItem(entry.path, entry.path.slice(slash + 1), entry.size, entry.mtime));
|
|
230370
|
-
}
|
|
230371
|
-
return { ok: true, items, truncated: truncated2 };
|
|
230372
|
-
}
|
|
230373
|
-
if (walked.code === "NOT_FOUND") return { ok: true, items: [], truncated: false };
|
|
230374
|
-
if (walked.code !== "UNSUPPORTED") return { ok: false, reason: reasonFromWorkdirCode(walked.code) };
|
|
230375
|
-
}
|
|
230376
|
-
const deadline = now() + WORKDIR_WALK_BUDGET_MS;
|
|
230377
|
-
let listCalls = 0;
|
|
230378
|
-
let truncated = false;
|
|
230379
|
-
const listDir = (path41) => {
|
|
230380
|
-
listCalls += 1;
|
|
230381
|
-
return bridge.list(loc.nodeId, {
|
|
230382
|
-
workdirKey: loc.workdirKey,
|
|
230383
|
-
runtimeKind: loc.runtimeKind,
|
|
230384
|
-
rtId: loc.rtId,
|
|
230385
|
-
path: path41
|
|
230386
|
-
});
|
|
230387
|
-
};
|
|
230388
|
-
const root = await listDir("");
|
|
230389
|
-
if (!root.ok) {
|
|
230390
|
-
if (root.code === "NOT_FOUND") return { ok: true, items: [], truncated: false };
|
|
230391
|
-
return { ok: false, reason: reasonFromWorkdirCode(root.code) };
|
|
230392
|
-
}
|
|
230393
|
-
let level = [{ path: "", outcome: root }];
|
|
230394
|
-
for (let depth = 0; depth <= WORKDIR_WALK_MAX_DEPTH; depth += 1) {
|
|
230395
|
-
const nextDirs = [];
|
|
230396
|
-
for (const { path: dir, outcome } of level) {
|
|
230397
|
-
if (!outcome.ok) {
|
|
230398
|
-
truncated = true;
|
|
230399
|
-
continue;
|
|
230400
|
-
}
|
|
230401
|
-
if (outcome.truncated) truncated = true;
|
|
230402
|
-
for (const entry of outcome.entries) {
|
|
230403
|
-
if (entry.type === "dir") {
|
|
230404
|
-
nextDirs.push(joinRel2(dir, entry.name));
|
|
230405
|
-
continue;
|
|
230406
|
-
}
|
|
230407
|
-
if (items.length >= WORKDIR_WALK_MAX_ENTRIES) {
|
|
230408
|
-
truncated = true;
|
|
230409
|
-
continue;
|
|
230410
|
-
}
|
|
230411
|
-
items.push(workdirFileItem(joinRel2(dir, entry.name), entry.name, entry.size, entry.mtime));
|
|
230412
|
-
}
|
|
230413
|
-
}
|
|
230414
|
-
if (depth === WORKDIR_WALK_MAX_DEPTH || nextDirs.length === 0) {
|
|
230415
|
-
if (nextDirs.length > 0) truncated = true;
|
|
230416
|
-
break;
|
|
230417
|
-
}
|
|
230418
|
-
const budget = WORKDIR_WALK_MAX_LIST_CALLS - listCalls;
|
|
230419
|
-
if (budget <= 0 || now() >= deadline) {
|
|
230420
|
-
truncated = true;
|
|
230421
|
-
break;
|
|
230422
|
-
}
|
|
230423
|
-
const take = nextDirs.slice(0, budget);
|
|
230424
|
-
if (take.length < nextDirs.length) truncated = true;
|
|
230425
|
-
const outcomes = await Promise.all(take.map((p2) => listDir(p2)));
|
|
230426
|
-
level = take.map((p2, i) => ({ path: p2, outcome: outcomes[i] }));
|
|
230427
|
-
}
|
|
230428
|
-
return { ok: true, items, truncated };
|
|
230429
|
-
}
|
|
230430
|
-
async function collectMessageFiles(messages, blobs) {
|
|
230431
|
-
const rows = [];
|
|
230432
|
-
for (const message of messages) {
|
|
230433
|
-
if (!Array.isArray(message.attachments)) continue;
|
|
230434
|
-
message.attachments.forEach((attachment, index2) => {
|
|
230435
|
-
if (!attachment || typeof attachment.name !== "string" || !attachment.name) return;
|
|
230436
|
-
const blobRef = typeof attachment.blobRef === "string" && attachment.blobRef ? attachment.blobRef : null;
|
|
230437
|
-
rows.push({
|
|
230438
|
-
item: {
|
|
230439
|
-
id: `msg:${message.id}:${index2}`,
|
|
230440
|
-
name: attachment.name,
|
|
230441
|
-
kind: "file",
|
|
230442
|
-
updated_at: attachment.updatedAt ?? message.createdAt,
|
|
230443
|
-
source: "message",
|
|
230444
|
-
blob_ref: blobRef,
|
|
230445
|
-
path: null,
|
|
230446
|
-
message_id: message.id,
|
|
230447
|
-
// 没有 blobRef 的是**历史纯文本附件**(契约注释:legacy text attachments may only
|
|
230448
|
-
// contain `name`)——没有可写回的载体,一律不给编辑入口。
|
|
230449
|
-
editable: blobRef !== null && isEditableFileName(attachment.name)
|
|
230450
|
-
},
|
|
230451
|
-
blobRef,
|
|
230452
|
-
declaredType: typeof attachment.contentType === "string" && attachment.contentType ? attachment.contentType : null
|
|
230453
|
-
});
|
|
230454
|
-
});
|
|
230455
|
-
}
|
|
230456
|
-
const metaCache = /* @__PURE__ */ new Map();
|
|
230457
|
-
const metaOf = (ref2) => {
|
|
230458
|
-
if (!blobs) return Promise.resolve(null);
|
|
230459
|
-
let hit = metaCache.get(ref2);
|
|
230460
|
-
if (!hit) {
|
|
230461
|
-
hit = blobs.meta(ref2).catch(() => null);
|
|
230462
|
-
metaCache.set(ref2, hit);
|
|
230463
|
-
}
|
|
230464
|
-
return hit;
|
|
230465
|
-
};
|
|
230466
|
-
return Promise.all(rows.map(async ({ item, blobRef, declaredType }) => {
|
|
230467
|
-
const meta = blobRef ? await metaOf(blobRef) : null;
|
|
230468
|
-
return {
|
|
230469
|
-
...item,
|
|
230470
|
-
content_type: declaredType ?? meta?.contentType ?? null,
|
|
230471
|
-
size: meta?.size ?? null
|
|
230472
|
-
};
|
|
230473
|
-
}));
|
|
230474
|
-
}
|
|
230475
|
-
function mergeChatSessionFiles(messageItems, workdirItems, materializedCopies = /* @__PURE__ */ new Set()) {
|
|
230476
|
-
const out = [];
|
|
230477
|
-
const seenMessageKeys = /* @__PURE__ */ new Set();
|
|
230478
|
-
for (const item of [...messageItems].sort((a, b2) => b2.updated_at.localeCompare(a.updated_at))) {
|
|
230479
|
-
const key = `${item.name}\0${item.blob_ref ?? ""}`;
|
|
230480
|
-
if (seenMessageKeys.has(key)) continue;
|
|
230481
|
-
seenMessageKeys.add(key);
|
|
230482
|
-
out.push(item);
|
|
230483
|
-
}
|
|
230484
|
-
const seenWorkdirPaths = /* @__PURE__ */ new Set();
|
|
230485
|
-
for (const item of workdirItems) {
|
|
230486
|
-
if (item.path && materializedCopies.has(item.path)) continue;
|
|
230487
|
-
if (seenWorkdirPaths.has(item.id)) continue;
|
|
230488
|
-
seenWorkdirPaths.add(item.id);
|
|
230489
|
-
out.push(item);
|
|
230490
|
-
}
|
|
230491
|
-
out.sort((a, b2) => b2.updated_at.localeCompare(a.updated_at) || a.name.localeCompare(b2.name));
|
|
230492
|
-
return out;
|
|
230493
|
-
}
|
|
230494
|
-
async function findMaterializedAttachmentCopies(messageItems, workdirItems, read) {
|
|
230495
|
-
const copies = /* @__PURE__ */ new Set();
|
|
230496
|
-
const attachments = messageItems.filter((item) => item.blob_ref && /^[a-f0-9]{64}$/.test(item.blob_ref));
|
|
230497
|
-
let budget = CHAT_ATTACHMENT_MAX_BYTES;
|
|
230498
|
-
const deadline = Date.now() + WORKDIR_WALK_BUDGET_MS;
|
|
230499
|
-
let reads = 0;
|
|
230500
|
-
for (const file of workdirItems) {
|
|
230501
|
-
const rootFile = file.path === file.name;
|
|
230502
|
-
const inputFile = file.path?.startsWith("inputs/attachments/") && !file.path.slice("inputs/attachments/".length).includes("/");
|
|
230503
|
-
if (!file.path || !rootFile && !inputFile) continue;
|
|
230504
|
-
const candidates = attachments.filter((attachment) => {
|
|
230505
|
-
const safe = safeAttachmentName(attachment.name);
|
|
230506
|
-
const numbered = file.name.endsWith(`-${safe}`) && /^\d+$/.test(file.name.slice(0, -(safe.length + 1)));
|
|
230507
|
-
return (rootFile ? file.name === attachment.name : file.name === safe || numbered) && attachment.size !== null && attachment.size === file.size;
|
|
230508
|
-
});
|
|
230509
|
-
if (Date.now() >= deadline) break;
|
|
230510
|
-
if (!candidates.length || file.size === null || file.size > budget || reads >= 10) continue;
|
|
230511
|
-
reads += 1;
|
|
230512
|
-
budget -= file.size;
|
|
230513
|
-
let timer;
|
|
230514
|
-
try {
|
|
230515
|
-
const result = await Promise.race([
|
|
230516
|
-
read(file.path, file.size),
|
|
230517
|
-
new Promise((resolve10) => {
|
|
230518
|
-
timer = setTimeout(() => resolve10(null), Math.max(0, deadline - Date.now()));
|
|
230519
|
-
})
|
|
230520
|
-
]);
|
|
230521
|
-
if (!result?.ok) continue;
|
|
230522
|
-
const bytes2 = Buffer.from(result.contentBase64, "base64");
|
|
230523
|
-
if (bytes2.length !== file.size) continue;
|
|
230524
|
-
const hash2 = (0, import_node_crypto52.createHash)("sha256").update(bytes2).digest("hex");
|
|
230525
|
-
if (candidates.some((attachment) => attachment.blob_ref === hash2)) copies.add(file.path);
|
|
230526
|
-
} catch {
|
|
230527
|
-
} finally {
|
|
230528
|
-
if (timer) clearTimeout(timer);
|
|
230529
|
-
}
|
|
230530
|
-
}
|
|
230531
|
-
return copies;
|
|
230532
|
-
}
|
|
230533
|
-
var import_node_crypto52, WORKDIR_WALK_MAX_DEPTH, WORKDIR_WALK_MAX_ENTRIES, WORKDIR_WALK_MAX_LIST_CALLS, WORKDIR_WALK_BUDGET_MS, WORKDIR_TREE_MAX_ENTRIES;
|
|
230534
|
-
var init_files_view = __esm({
|
|
230535
|
-
"../server/src/domains/chat-sessions/files-view.ts"() {
|
|
230536
|
-
"use strict";
|
|
230537
|
-
import_node_crypto52 = require("node:crypto");
|
|
230538
|
-
init_chat_attachment_files();
|
|
230539
|
-
init_src();
|
|
230540
|
-
WORKDIR_WALK_MAX_DEPTH = 3;
|
|
230541
|
-
WORKDIR_WALK_MAX_ENTRIES = 200;
|
|
230542
|
-
WORKDIR_WALK_MAX_LIST_CALLS = 20;
|
|
230543
|
-
WORKDIR_WALK_BUDGET_MS = 1e4;
|
|
230544
|
-
WORKDIR_TREE_MAX_ENTRIES = 2e3;
|
|
230545
|
-
}
|
|
230546
|
-
});
|
|
230547
|
-
|
|
230548
|
-
// ../server/src/domains/projects/chat-files.ts
|
|
230549
|
-
function chatFolderTitle(session) {
|
|
230550
|
-
const title = session.title?.trim();
|
|
230551
|
-
return title ? title : "\u672A\u547D\u540D\u5BF9\u8BDD";
|
|
230552
|
-
}
|
|
230553
|
-
function outputDisplayName(path41) {
|
|
230554
|
-
return path41.startsWith("outputs/") ? path41.slice("outputs/".length) : path41;
|
|
230555
|
-
}
|
|
230556
|
-
async function collectProjectChatFiles(chat, projectId2, meta, options = {}) {
|
|
230557
|
-
const scope = isUncategorizedProjectId(projectId2) ? null : projectId2;
|
|
230558
|
-
const [attachmentMessages, outputSessions] = await Promise.all([
|
|
230559
|
-
chat.listAttachmentMessages ? chat.listAttachmentMessages(scope) : Promise.resolve([]),
|
|
230560
|
-
chat.listOutputCopies ? chat.listOutputCopies(scope) : Promise.resolve([])
|
|
230561
|
-
]);
|
|
230562
|
-
const sessionIds = [.../* @__PURE__ */ new Set([
|
|
230563
|
-
...attachmentMessages.map((m2) => m2.sessionId),
|
|
230564
|
-
...outputSessions.map((s2) => s2.sessionId)
|
|
230565
|
-
])];
|
|
230566
|
-
const sessions = /* @__PURE__ */ new Map();
|
|
230567
|
-
await Promise.all(sessionIds.map(async (id) => {
|
|
230568
|
-
const session = await chat.getSession(id);
|
|
230569
|
-
if (!session) return;
|
|
230570
|
-
if ((session.projectId ?? null) !== scope) return;
|
|
230571
|
-
if (session.visibility === "internal" || session.analyzedRunId) return;
|
|
230572
|
-
if (options.isDelegationChild && await options.isDelegationChild(id).catch(() => false)) return;
|
|
230573
|
-
sessions.set(id, session);
|
|
230574
|
-
}));
|
|
230575
|
-
const out = [];
|
|
230576
|
-
const base = (session) => ({
|
|
230577
|
-
projectId: projectId2,
|
|
230578
|
-
chatSessionId: session.id,
|
|
230579
|
-
chatTitle: chatFolderTitle(session),
|
|
230580
|
-
chatOwnerId: session.humanActorId
|
|
230581
|
-
});
|
|
230582
|
-
const bySession = /* @__PURE__ */ new Map();
|
|
230583
|
-
for (const message of attachmentMessages) {
|
|
230584
|
-
if (!sessions.has(message.sessionId)) continue;
|
|
230585
|
-
const list2 = bySession.get(message.sessionId) ?? [];
|
|
230586
|
-
list2.push(message);
|
|
230587
|
-
bySession.set(message.sessionId, list2);
|
|
230588
|
-
}
|
|
230589
|
-
for (const [sessionId, messages] of bySession) {
|
|
230590
|
-
const session = sessions.get(sessionId);
|
|
230591
|
-
const rows = await collectMessageFiles(messages.map((m2) => ({ ...m2, id: m2.messageId })), { meta });
|
|
230592
|
-
for (const row of mergeChatSessionFiles(rows, [])) {
|
|
230593
|
-
if (row.blob_ref === null) continue;
|
|
230594
|
-
out.push({
|
|
230595
|
-
...base(session),
|
|
230596
|
-
fileId: `chat:${sessionId}:${row.id}`,
|
|
230597
|
-
name: row.name,
|
|
230598
|
-
blobId: row.blob_ref,
|
|
230599
|
-
...row.content_type ? { contentType: row.content_type } : {},
|
|
230600
|
-
size: row.size,
|
|
230601
|
-
uploadedBy: session.humanActorId,
|
|
230602
|
-
uploadedAt: row.updated_at,
|
|
230603
|
-
chatSource: "attachment"
|
|
230604
|
-
});
|
|
230605
|
-
}
|
|
230606
|
-
}
|
|
230607
|
-
for (const record8 of outputSessions) {
|
|
230608
|
-
const session = sessions.get(record8.sessionId);
|
|
230609
|
-
if (!session) continue;
|
|
230610
|
-
const seen = new Set(out.filter((file) => file.chatSessionId === session.id).map((file) => `${file.name}\0${file.blobId}`));
|
|
230611
|
-
const copies = record8.copies ?? {};
|
|
230612
|
-
for (const path41 of Object.keys(copies).sort((a, b2) => a.localeCompare(b2))) {
|
|
230613
|
-
const copy = copies[path41];
|
|
230614
|
-
if (!copy?.blobRef) continue;
|
|
230615
|
-
if (seen.has(`${copy.name}\0${copy.blobRef}`)) continue;
|
|
230616
|
-
out.push({
|
|
230617
|
-
...base(session),
|
|
230618
|
-
fileId: `chat:${session.id}:out:${copy.path}`,
|
|
230619
|
-
name: outputDisplayName(copy.path),
|
|
230620
|
-
blobId: copy.blobRef,
|
|
230621
|
-
...copy.contentType ? { contentType: copy.contentType } : {},
|
|
230622
|
-
size: copy.size,
|
|
230623
|
-
uploadedBy: session.aiActorId,
|
|
230624
|
-
uploadedAt: Number.isNaN(Date.parse(copy.mtime)) ? copy.copiedAt : new Date(copy.mtime).toISOString(),
|
|
230625
|
-
chatSource: "output"
|
|
230626
|
-
});
|
|
230627
|
-
}
|
|
230628
|
-
}
|
|
230629
|
-
return out;
|
|
230630
|
-
}
|
|
230631
|
-
var init_chat_files2 = __esm({
|
|
230632
|
-
"../server/src/domains/projects/chat-files.ts"() {
|
|
230633
|
-
"use strict";
|
|
230634
|
-
init_files_view();
|
|
230635
|
-
init_uncategorized_project();
|
|
230636
|
-
}
|
|
230637
|
-
});
|
|
230638
|
-
|
|
230639
230949
|
// ../server/src/domains/projects/index.ts
|
|
230640
230950
|
function createProjectsDomain(opts) {
|
|
230641
230951
|
const build = (companyId, deps) => {
|
|
@@ -230694,7 +231004,9 @@ function createProjectsDomain(opts) {
|
|
|
230694
231004
|
service,
|
|
230695
231005
|
...opts.resolveCompany ? { resolveService } : {},
|
|
230696
231006
|
...opts.defaultBranchResolver ? { defaultBranchResolver: opts.defaultBranchResolver } : {},
|
|
230697
|
-
...opts.resolveMemberRole ? { resolveMemberRole: opts.resolveMemberRole } : {}
|
|
231007
|
+
...opts.resolveMemberRole ? { resolveMemberRole: opts.resolveMemberRole } : {},
|
|
231008
|
+
...opts.chatSessionsFor ? { chatSessionsFor: opts.chatSessionsFor } : {},
|
|
231009
|
+
...opts.delegationChildIds ? { delegationChildIds: opts.delegationChildIds } : {}
|
|
230698
231010
|
}),
|
|
230699
231011
|
...opts.resolveCompany ? { resolveService } : {}
|
|
230700
231012
|
};
|
|
@@ -230721,11 +231033,11 @@ async function isEmployedElsewhere(store, companyId, accountId) {
|
|
|
230721
231033
|
const memberships = await store.listMembershipsForAccount(accountId);
|
|
230722
231034
|
return memberships.some((m2) => m2.companyId !== companyId);
|
|
230723
231035
|
}
|
|
230724
|
-
var
|
|
231036
|
+
var import_node_crypto54, ROLES, INVITABLE_ROLES, INVITATION_TTL_MS, INVITE_LINK_TTL_MS, INVITE_LINK_TOKEN_BYTES, INVITE_LINK_ROLE, SLUG_RE, CompanyError, CompaniesService;
|
|
230725
231037
|
var init_service6 = __esm({
|
|
230726
231038
|
"../server/src/domains/companies/service.ts"() {
|
|
230727
231039
|
"use strict";
|
|
230728
|
-
|
|
231040
|
+
import_node_crypto54 = require("node:crypto");
|
|
230729
231041
|
init_console_url();
|
|
230730
231042
|
ROLES = ["owner", "admin", "member"];
|
|
230731
231043
|
INVITABLE_ROLES = ["admin", "member"];
|
|
@@ -230817,7 +231129,7 @@ var init_service6 = __esm({
|
|
|
230817
231129
|
const existing = await this.store.getAccountByEmail(normalized4);
|
|
230818
231130
|
if (existing) return existing;
|
|
230819
231131
|
const account = {
|
|
230820
|
-
id: `actor:human:${(0,
|
|
231132
|
+
id: `actor:human:${(0, import_node_crypto54.randomUUID)()}`,
|
|
230821
231133
|
email: normalized4,
|
|
230822
231134
|
name: name ?? normalized4,
|
|
230823
231135
|
status: "active"
|
|
@@ -231026,7 +231338,7 @@ var init_service6 = __esm({
|
|
|
231026
231338
|
}
|
|
231027
231339
|
const nowMs = Date.parse(this.now());
|
|
231028
231340
|
const invitation = {
|
|
231029
|
-
id: `invitation:${(0,
|
|
231341
|
+
id: `invitation:${(0, import_node_crypto54.randomUUID)()}`,
|
|
231030
231342
|
companyId,
|
|
231031
231343
|
email: mail,
|
|
231032
231344
|
role,
|
|
@@ -231157,7 +231469,7 @@ var init_service6 = __esm({
|
|
|
231157
231469
|
const nowMs = Date.parse(this.now());
|
|
231158
231470
|
const link = {
|
|
231159
231471
|
companyId,
|
|
231160
|
-
token: (0,
|
|
231472
|
+
token: (0, import_node_crypto54.randomBytes)(INVITE_LINK_TOKEN_BYTES).toString("base64url"),
|
|
231161
231473
|
role: INVITE_LINK_ROLE,
|
|
231162
231474
|
createdAt: new Date(nowMs).toISOString(),
|
|
231163
231475
|
expiresAt: new Date(nowMs + INVITE_LINK_TTL_MS).toISOString(),
|
|
@@ -231214,7 +231526,7 @@ var init_service6 = __esm({
|
|
|
231214
231526
|
const reusable = existing.find((inv) => !this.isExpired(inv));
|
|
231215
231527
|
if (reusable) return reusable;
|
|
231216
231528
|
const invitation = {
|
|
231217
|
-
id: `invitation:${(0,
|
|
231529
|
+
id: `invitation:${(0, import_node_crypto54.randomUUID)()}`,
|
|
231218
231530
|
companyId: link.companyId,
|
|
231219
231531
|
email: mail,
|
|
231220
231532
|
role: link.role,
|
|
@@ -231452,11 +231764,11 @@ var init_service6 = __esm({
|
|
|
231452
231764
|
});
|
|
231453
231765
|
|
|
231454
231766
|
// ../server/src/domains/companies/offboarding.ts
|
|
231455
|
-
var
|
|
231767
|
+
var import_node_crypto55, MemberOffboardingService;
|
|
231456
231768
|
var init_offboarding = __esm({
|
|
231457
231769
|
"../server/src/domains/companies/offboarding.ts"() {
|
|
231458
231770
|
"use strict";
|
|
231459
|
-
|
|
231771
|
+
import_node_crypto55 = require("node:crypto");
|
|
231460
231772
|
init_service6();
|
|
231461
231773
|
MemberOffboardingService = class {
|
|
231462
231774
|
store;
|
|
@@ -231528,7 +231840,7 @@ var init_offboarding = __esm({
|
|
|
231528
231840
|
const { ownedAgents, inFlight } = await this.snapshot(companyId, accountId);
|
|
231529
231841
|
const at = this.now();
|
|
231530
231842
|
const started = await this.store.startMemberOffboarding({
|
|
231531
|
-
operationId: `off:${(0,
|
|
231843
|
+
operationId: `off:${(0, import_node_crypto55.randomUUID)()}`,
|
|
231532
231844
|
companyId,
|
|
231533
231845
|
accountId,
|
|
231534
231846
|
initiatedBy,
|
|
@@ -232038,18 +232350,18 @@ var init_routes6 = __esm({
|
|
|
232038
232350
|
|
|
232039
232351
|
// ../server/src/domains/companies/agent-credentials.ts
|
|
232040
232352
|
function hashAgentToken(token, secret) {
|
|
232041
|
-
return HASH_PREFIX + (0,
|
|
232353
|
+
return HASH_PREFIX + (0, import_node_crypto56.createHmac)("sha256", secret).update(`agent-token:${token}`).digest("base64url");
|
|
232042
232354
|
}
|
|
232043
232355
|
function safeEqual(a, b2) {
|
|
232044
232356
|
const ba = Buffer.from(a);
|
|
232045
232357
|
const bb = Buffer.from(b2);
|
|
232046
|
-
return ba.length === bb.length && (0,
|
|
232358
|
+
return ba.length === bb.length && (0, import_node_crypto56.timingSafeEqual)(ba, bb);
|
|
232047
232359
|
}
|
|
232048
|
-
var
|
|
232360
|
+
var import_node_crypto56, HASH_PREFIX, TOKEN_PREFIX, AgentCredentialService;
|
|
232049
232361
|
var init_agent_credentials = __esm({
|
|
232050
232362
|
"../server/src/domains/companies/agent-credentials.ts"() {
|
|
232051
232363
|
"use strict";
|
|
232052
|
-
|
|
232364
|
+
import_node_crypto56 = require("node:crypto");
|
|
232053
232365
|
init_service6();
|
|
232054
232366
|
HASH_PREFIX = "ac1$";
|
|
232055
232367
|
TOKEN_PREFIX = "oak_";
|
|
@@ -232074,7 +232386,7 @@ var init_agent_credentials = __esm({
|
|
|
232074
232386
|
if (employee.status !== "active") {
|
|
232075
232387
|
throw new CompanyError(409, "AGENT_LEFT", `\u6570\u5B57\u5458\u5DE5\u5DF2\u79BB\u5F00\uFF0C\u4E0D\u80FD\u7B7E\u53D1\u51ED\u8BC1\uFF1A${agentId}`);
|
|
232076
232388
|
}
|
|
232077
|
-
const token = `${TOKEN_PREFIX}${(0,
|
|
232389
|
+
const token = `${TOKEN_PREFIX}${(0, import_node_crypto56.randomBytes)(32).toString("base64url")}`;
|
|
232078
232390
|
const credential = {
|
|
232079
232391
|
tokenHash: hashAgentToken(token, this.secret),
|
|
232080
232392
|
companyId,
|
|
@@ -232494,7 +232806,7 @@ function gatewayInstanceSlug(gatewayUrl) {
|
|
|
232494
232806
|
}
|
|
232495
232807
|
function connectInstanceName(gatewayUrl, token, companyId) {
|
|
232496
232808
|
const scope = companyId?.trim();
|
|
232497
|
-
const suffix = scope ? `c${(0,
|
|
232809
|
+
const suffix = scope ? `c${(0, import_node_crypto57.createHash)("sha256").update(`${gatewayUrl}\0${scope}`).digest("hex").slice(0, 10)}` : token.replace(/[^a-z0-9]/gi, "").slice(-8).toLowerCase() || "enroll";
|
|
232498
232810
|
const base = gatewayInstanceSlug(gatewayUrl);
|
|
232499
232811
|
return base.slice(0, Math.max(1, 64 - suffix.length - 1)) + "-" + suffix;
|
|
232500
232812
|
}
|
|
@@ -232823,12 +233135,12 @@ function buildNpxCmd(p2) {
|
|
|
232823
233135
|
const prefix = daemonNpmPrefix();
|
|
232824
233136
|
return `npm install -g --prefer-online --prefix ${prefix} ${DAEMON_NPM_PACKAGE}@latest && ${prefix}/bin/oasis daemon start --instance ${shellQuote(instanceName)} --server-ws ${shellQuote(p2.gatewayUrl)}${companyPart}${namePart} --pkg ${shellQuote(DAEMON_NPM_PACKAGE)} --upgrade --enroll-token ${shellQuote(p2.token)}`;
|
|
232825
233137
|
}
|
|
232826
|
-
var
|
|
233138
|
+
var import_node_crypto57;
|
|
232827
233139
|
var init_connect_script = __esm({
|
|
232828
233140
|
"../server/src/domains/nodes/connect-script.ts"() {
|
|
232829
233141
|
"use strict";
|
|
232830
233142
|
init_src();
|
|
232831
|
-
|
|
233143
|
+
import_node_crypto57 = require("node:crypto");
|
|
232832
233144
|
}
|
|
232833
233145
|
});
|
|
232834
233146
|
|
|
@@ -233389,7 +233701,7 @@ function nodesDomain(deps) {
|
|
|
233389
233701
|
}
|
|
233390
233702
|
deps.enrollTokens.setIssuedNodeId(enrollToken, nodeId);
|
|
233391
233703
|
} else {
|
|
233392
|
-
nodeId = `node-${(0,
|
|
233704
|
+
nodeId = `node-${(0, import_node_crypto58.randomUUID)().slice(0, 8)}`;
|
|
233393
233705
|
deps.enrollTokens.setIssuedNodeId(enrollToken, nodeId);
|
|
233394
233706
|
}
|
|
233395
233707
|
const existingNode = await deps.nodeStore.getNode(nodeId);
|
|
@@ -233521,21 +233833,21 @@ function nodesDomain(deps) {
|
|
|
233521
233833
|
return { status: 200, body: { override } };
|
|
233522
233834
|
});
|
|
233523
233835
|
router.get("/api/runtimes/:runtimeId/activity", async (req) => {
|
|
233524
|
-
const
|
|
233525
|
-
if (
|
|
233836
|
+
const found2 = await runtimeInScope(req);
|
|
233837
|
+
if (found2.denied) return found2.denied;
|
|
233526
233838
|
const reader = await deps.runtimeRuns?.(req.auth.companyId);
|
|
233527
|
-
const activity = reader ? await reader.runtimeRunActivity(
|
|
233839
|
+
const activity = reader ? await reader.runtimeRunActivity(found2.runtimeId) : null;
|
|
233528
233840
|
return { status: 200, body: { activity } };
|
|
233529
233841
|
});
|
|
233530
233842
|
router.get("/api/runtimes/:runtimeId/usage", async (req) => {
|
|
233531
|
-
const
|
|
233532
|
-
if (
|
|
233843
|
+
const found2 = await runtimeInScope(req);
|
|
233844
|
+
if (found2.denied) return found2.denied;
|
|
233533
233845
|
const granularity = req.query.get("granularity") === "day" ? "day" : "hour";
|
|
233534
233846
|
const window2 = parseRuntimeUsageWindow(req.query, granularity, Date.now());
|
|
233535
233847
|
if (typeof window2 === "string") return { status: 400, body: { error: window2 } };
|
|
233536
233848
|
const reader = await deps.runtimeRuns?.(req.auth.companyId);
|
|
233537
|
-
const runs = reader ? await reader.listRuntimeRuns(
|
|
233538
|
-
return { status: 200, body: { items: bucketRuntimeRuns(
|
|
233849
|
+
const runs = reader ? await reader.listRuntimeRuns(found2.runtimeId, window2) : null;
|
|
233850
|
+
return { status: 200, body: { items: bucketRuntimeRuns(found2.runtimeId, runs ?? [], granularity) } };
|
|
233539
233851
|
});
|
|
233540
233852
|
router.get("/api/runtimes/:runtimeId/config", async (req) => {
|
|
233541
233853
|
const runtimeId = req.params["runtimeId"];
|
|
@@ -233572,13 +233884,13 @@ function normalizeGatewayUrl(raw) {
|
|
|
233572
233884
|
}
|
|
233573
233885
|
}
|
|
233574
233886
|
function newNodeId() {
|
|
233575
|
-
return "node-" + (0,
|
|
233887
|
+
return "node-" + (0, import_node_crypto58.randomUUID)().replace(/-/g, "").slice(0, 12);
|
|
233576
233888
|
}
|
|
233577
|
-
var
|
|
233889
|
+
var import_node_crypto58, import_node_fs16, import_node_url6, import_node_path21;
|
|
233578
233890
|
var init_routes7 = __esm({
|
|
233579
233891
|
"../server/src/domains/nodes/routes.ts"() {
|
|
233580
233892
|
"use strict";
|
|
233581
|
-
|
|
233893
|
+
import_node_crypto58 = require("node:crypto");
|
|
233582
233894
|
import_node_fs16 = require("node:fs");
|
|
233583
233895
|
import_node_url6 = require("node:url");
|
|
233584
233896
|
import_node_path21 = require("node:path");
|
|
@@ -233931,9 +234243,56 @@ var init_node_store = __esm({
|
|
|
233931
234243
|
}
|
|
233932
234244
|
});
|
|
233933
234245
|
|
|
234246
|
+
// ../server/src/domains/collab/task-notices.ts
|
|
234247
|
+
function taskNoticeRecipients(model, workorderId, snapshot, members, trigger) {
|
|
234248
|
+
const out = /* @__PURE__ */ new Set();
|
|
234249
|
+
for (const a of model.artifacts.values()) {
|
|
234250
|
+
if (a.workspace === workorderId && isHumanActorId(a.owner)) out.add(a.owner);
|
|
234251
|
+
}
|
|
234252
|
+
for (const r of snapshot?.requirements ?? []) if (isHumanActorId(r.reviewerActorId)) out.add(r.reviewerActorId);
|
|
234253
|
+
for (const r of snapshot?.reviews ?? []) if (isHumanActorId(r.reviewerActorId)) out.add(r.reviewerActorId);
|
|
234254
|
+
if (trigger) out.delete(trigger);
|
|
234255
|
+
return [...out].filter((id) => members.has(id)).sort();
|
|
234256
|
+
}
|
|
234257
|
+
function settleTrigger(events, accept) {
|
|
234258
|
+
const e = accept.event;
|
|
234259
|
+
if (e.by && isHumanActorId(e.by)) return e.by;
|
|
234260
|
+
const workId = e.workId;
|
|
234261
|
+
const before = events.filter((x2) => x2.seq <= accept.seq);
|
|
234262
|
+
for (let i = before.length - 1; i >= 0; i--) {
|
|
234263
|
+
const x2 = before[i].event;
|
|
234264
|
+
if (x2.kind === "review.response" && x2.targetWorkId === workId && x2.verdict === "approve" && x2.reviewerActorId && isHumanActorId(x2.reviewerActorId)) {
|
|
234265
|
+
return x2.reviewerActorId;
|
|
234266
|
+
}
|
|
234267
|
+
if (x2.kind === "work.conclude" && x2.workId === workId && isHumanActorId(before[i].actorId)) return before[i].actorId;
|
|
234268
|
+
}
|
|
234269
|
+
return void 0;
|
|
234270
|
+
}
|
|
234271
|
+
function isCreationHold(paused) {
|
|
234272
|
+
return paused.event.reason === WORKORDER_HOLD_AT_CREATE_REASON;
|
|
234273
|
+
}
|
|
234274
|
+
function endsCreationHold(pauses, resumed) {
|
|
234275
|
+
let last;
|
|
234276
|
+
for (const p2 of pauses) if (p2.seq < resumed.seq && p2.event.kind === "workorder.paused") last = p2;
|
|
234277
|
+
return last !== void 0 && isCreationHold(last);
|
|
234278
|
+
}
|
|
234279
|
+
var TASK_NOTICE_TITLE;
|
|
234280
|
+
var init_task_notices = __esm({
|
|
234281
|
+
"../server/src/domains/collab/task-notices.ts"() {
|
|
234282
|
+
"use strict";
|
|
234283
|
+
init_src();
|
|
234284
|
+
TASK_NOTICE_TITLE = {
|
|
234285
|
+
"workorder-settled": "\u4EFB\u52A1\u5DF2\u5B8C\u6210",
|
|
234286
|
+
"workorder-cancelled": "\u4EFB\u52A1\u5DF2\u53D6\u6D88",
|
|
234287
|
+
"workorder-paused": "\u4EFB\u52A1\u5DF2\u6682\u505C",
|
|
234288
|
+
"workorder-resumed": "\u4EFB\u52A1\u5DF2\u6062\u590D"
|
|
234289
|
+
};
|
|
234290
|
+
}
|
|
234291
|
+
});
|
|
234292
|
+
|
|
233934
234293
|
// ../server/src/domains/collab/notification-ledger.ts
|
|
233935
234294
|
function isLedgerItem(item) {
|
|
233936
|
-
return item.actionRequired &&
|
|
234295
|
+
return item.actionRequired && LEDGER_INBOX_KINDS.has(item.kind);
|
|
233937
234296
|
}
|
|
233938
234297
|
function generationOf(model, item) {
|
|
233939
234298
|
if (item.kind === "rework") return item.revisionId;
|
|
@@ -233943,7 +234302,17 @@ function generationOf(model, item) {
|
|
|
233943
234302
|
}
|
|
233944
234303
|
return void 0;
|
|
233945
234304
|
}
|
|
234305
|
+
function staffingRoleOf(model, item) {
|
|
234306
|
+
if (item.kind !== "needs-staffing" || !item.artifactId) return void 0;
|
|
234307
|
+
const owner = model.artifacts.get(item.artifactId)?.owner;
|
|
234308
|
+
return owner?.startsWith(PENDING_ROLE_PREFIX) ? owner.slice(PENDING_ROLE_PREFIX.length) : void 0;
|
|
234309
|
+
}
|
|
234310
|
+
function staffingRoleOfKey(sourceKey) {
|
|
234311
|
+
return STAFFING_ROLE_KEY.exec(sourceKey)?.[1];
|
|
234312
|
+
}
|
|
233946
234313
|
function notificationSourceKey(model, item) {
|
|
234314
|
+
const role = staffingRoleOf(model, item);
|
|
234315
|
+
if (role && item.workspace) return `needs-staffing:${item.workspace}:role:${role}`;
|
|
233947
234316
|
const base = inboxItemKey(item);
|
|
233948
234317
|
if (!base) return void 0;
|
|
233949
234318
|
const gen = generationOf(model, item);
|
|
@@ -233953,6 +234322,10 @@ function generationOfKey(sourceKey) {
|
|
|
233953
234322
|
const at = sourceKey.lastIndexOf("@");
|
|
233954
234323
|
return at >= 0 ? sourceKey.slice(at + 1) : void 0;
|
|
233955
234324
|
}
|
|
234325
|
+
function workNumber(workId) {
|
|
234326
|
+
const m2 = /:(\d+)$/.exec(workId);
|
|
234327
|
+
return m2 ? Number(m2[1]) : void 0;
|
|
234328
|
+
}
|
|
233956
234329
|
function nodeOfWork(workId) {
|
|
233957
234330
|
if (!workId.startsWith("wk:")) return null;
|
|
233958
234331
|
const body2 = workId.slice(3);
|
|
@@ -233981,38 +234354,41 @@ function classifyClosure(row, facts) {
|
|
|
233981
234354
|
const o = facts.draftOutcome;
|
|
233982
234355
|
return o.by === me ? handled2(me, o.approved ? "\u5DF2\u786E\u8BA4" : "\u5DF2\u9A73\u56DE", facts.now) : invalidated("handled-by-other", facts.now, o.by);
|
|
233983
234356
|
}
|
|
233984
|
-
const
|
|
233985
|
-
|
|
234357
|
+
const evidence = [];
|
|
234358
|
+
const add = (f2) => {
|
|
234359
|
+
if (f2) evidence.push(f2);
|
|
234360
|
+
};
|
|
234361
|
+
add(resolvedByMe(row, evs, me, onNode));
|
|
233986
234362
|
const sealCancel = evs.find((rec) => {
|
|
233987
234363
|
const e = payload(rec, "plan.delete_node");
|
|
233988
234364
|
return !!e && e.nodeId === node2 && e.sealReason === "cancelled";
|
|
233989
234365
|
});
|
|
233990
|
-
if (facts.workorderCancelled
|
|
233991
|
-
if (sealCancel) return invalidated("node-cancelled", at(sealCancel), sealCancel.actorId);
|
|
234366
|
+
if (sealCancel) add({ rec: sealCancel, closure: invalidated(facts.workorderCancelled ? "workorder-cancelled" : "node-cancelled", at(sealCancel), sealCancel.actorId) });
|
|
233992
234367
|
const deleted = evs.find((rec) => {
|
|
233993
234368
|
const e = payload(rec, "plan.delete_node");
|
|
233994
|
-
return !!e && e.nodeId === node2 && e.sealReason !== "accepted";
|
|
234369
|
+
return !!e && e.nodeId === node2 && e.sealReason !== "accepted" && e.sealReason !== "cancelled";
|
|
233995
234370
|
});
|
|
233996
|
-
if (deleted)
|
|
233997
|
-
|
|
233998
|
-
if (other) return other;
|
|
234371
|
+
if (deleted) add({ rec: deleted, closure: invalidated("node-cancelled", at(deleted), deleted.actorId) });
|
|
234372
|
+
add(resolvedByOther(row, evs, me, onNode));
|
|
233999
234373
|
const gen = generationOfKey(row.sourceKey);
|
|
234000
234374
|
if (gen) {
|
|
234375
|
+
const genNo = workNumber(gen);
|
|
234376
|
+
const isNewer = (workId) => workId !== gen && (genNo === void 0 || (workNumber(workId) ?? Number.POSITIVE_INFINITY) > genNo);
|
|
234001
234377
|
const newer = evs.find((rec) => {
|
|
234002
234378
|
const c = payload(rec, "work.create");
|
|
234003
|
-
if (c && c.nodeId === node2 && c.workId
|
|
234379
|
+
if (c && c.nodeId === node2 && isNewer(c.workId)) return true;
|
|
234004
234380
|
const s2 = payload(rec, "work.submit_output");
|
|
234005
|
-
return !!s2 && nodeOfWork(s2.workId) === node2 && s2.workId
|
|
234381
|
+
return !!s2 && nodeOfWork(s2.workId) === node2 && isNewer(s2.workId);
|
|
234006
234382
|
});
|
|
234007
|
-
if (newer)
|
|
234383
|
+
if (newer) add({ rec: newer, closure: invalidated("superseded", at(newer), newer.actorId) });
|
|
234008
234384
|
}
|
|
234009
234385
|
const reassign = evs.find((rec) => {
|
|
234010
234386
|
const a = payload(rec, "plan.assign_actor");
|
|
234011
234387
|
if (a && a.nodeId === node2 && a.assigneeActorId !== me && ownerKinds.has(row.kind)) return true;
|
|
234012
234388
|
const r = payload(rec, "plan.update_review_requirements");
|
|
234013
|
-
return !!r && r.nodeId === node2 && reviewKinds.has(row.kind);
|
|
234389
|
+
return !!r && r.nodeId === node2 && reviewKinds.has(row.kind) && !r.reviewers.some((x2) => x2.reviewerActorId === me);
|
|
234014
234390
|
});
|
|
234015
|
-
if (reassign)
|
|
234391
|
+
if (reassign) add({ rec: reassign, closure: invalidated("reassigned", at(reassign), reassign.actorId) });
|
|
234016
234392
|
const myReviewPrefix = gen ? `rv:${gen}:${me}:` : void 0;
|
|
234017
234393
|
const withdrawn = evs.find((rec) => {
|
|
234018
234394
|
const k2 = payload(rec, "review.kill") ?? payload(rec, "review.timeout");
|
|
@@ -234020,9 +234396,15 @@ function classifyClosure(row, facts) {
|
|
|
234020
234396
|
if (item?.waitingRowId !== void 0 && k2.reviewId === item.waitingRowId) return true;
|
|
234021
234397
|
return row.kind === "review-request" && !!myReviewPrefix && k2.reviewId.startsWith(myReviewPrefix);
|
|
234022
234398
|
});
|
|
234023
|
-
if (withdrawn)
|
|
234399
|
+
if (withdrawn) add({ rec: withdrawn, closure: invalidated("source-changed", at(withdrawn), withdrawn.actorId) });
|
|
234400
|
+
const first = evidence.reduce((best, f2) => !best || f2.rec.seq < best.rec.seq ? f2 : best, null);
|
|
234401
|
+
if (first) return first.closure;
|
|
234402
|
+
if (facts.workorderCancelled) return invalidated("workorder-cancelled", facts.now);
|
|
234024
234403
|
return null;
|
|
234025
234404
|
}
|
|
234405
|
+
function staffingNodeMatches(row, nodeId) {
|
|
234406
|
+
return staffingRoleOfKey(row.sourceKey) !== void 0 || nodeId === row.nodeId;
|
|
234407
|
+
}
|
|
234026
234408
|
function issueIdsOf(row) {
|
|
234027
234409
|
const it = row.item;
|
|
234028
234410
|
return new Set([it?.gap?.gapId, it?.escalationId, it?.annotationId].filter((x2) => !!x2));
|
|
@@ -234034,16 +234416,16 @@ function resolvedByMe(row, evs, me, onNode) {
|
|
|
234034
234416
|
switch (row.kind) {
|
|
234035
234417
|
case "review-request": {
|
|
234036
234418
|
const v2 = payload(rec, "review.response");
|
|
234037
|
-
if (v2 && v2.reviewerActorId === me && onNode(rec) && (!gen || v2.targetWorkId === gen)) return handled2(me, verdictWord(v2.verdict), rec.createdAt);
|
|
234419
|
+
if (v2 && v2.reviewerActorId === me && onNode(rec) && (!gen || v2.targetWorkId === gen)) return found(rec, handled2(me, verdictWord(v2.verdict), rec.createdAt));
|
|
234038
234420
|
const acc = payload(rec, "work.accept");
|
|
234039
|
-
if (acc && acc.by === me && gen && acc.workId === gen) return handled2(me, "\u5DF2\u9A8C\u6536", rec.createdAt);
|
|
234421
|
+
if (acc && acc.by === me && gen && acc.workId === gen) return found(rec, handled2(me, "\u5DF2\u9A8C\u6536", rec.createdAt));
|
|
234040
234422
|
const rej = payload(rec, "work.reject");
|
|
234041
|
-
if (rej && rej.by === me && gen && rej.workId === gen) return handled2(me, "\u5DF2\u6253\u56DE", rec.createdAt);
|
|
234423
|
+
if (rej && rej.by === me && gen && rej.workId === gen) return found(rec, handled2(me, "\u5DF2\u6253\u56DE", rec.createdAt));
|
|
234042
234424
|
break;
|
|
234043
234425
|
}
|
|
234044
234426
|
case "review-waiting": {
|
|
234045
234427
|
const v2 = payload(rec, "review.response");
|
|
234046
|
-
if (v2 && v2.reviewerActorId === me && item?.waitingRowId && v2.reviewId === item.waitingRowId) return handled2(me, verdictWord(v2.verdict), rec.createdAt);
|
|
234428
|
+
if (v2 && v2.reviewerActorId === me && item?.waitingRowId && v2.reviewId === item.waitingRowId) return found(rec, handled2(me, verdictWord(v2.verdict), rec.createdAt));
|
|
234047
234429
|
break;
|
|
234048
234430
|
}
|
|
234049
234431
|
case "work-waiting":
|
|
@@ -234051,24 +234433,24 @@ function resolvedByMe(row, evs, me, onNode) {
|
|
|
234051
234433
|
case "rework":
|
|
234052
234434
|
case "stale": {
|
|
234053
234435
|
const s2 = payload(rec, "work.submit_output") ?? payload(rec, "work.conclude");
|
|
234054
|
-
if (s2 && doerOf(rec) === me && onNode(rec) && !(row.kind === "rework" && s2.workId === gen)) return handled2(me, "\u5DF2\u63D0\u4EA4", rec.createdAt);
|
|
234436
|
+
if (s2 && doerOf(rec) === me && onNode(rec) && !(row.kind === "rework" && s2.workId === gen)) return found(rec, handled2(me, "\u5DF2\u63D0\u4EA4", rec.createdAt));
|
|
234055
234437
|
break;
|
|
234056
234438
|
}
|
|
234057
234439
|
case "pushback": {
|
|
234058
234440
|
const r = payload(rec, "issue.resolve");
|
|
234059
|
-
if (r && r.by === me && issueIdsOf(row).has(r.issueId)) return handled2(me, "\u5DF2\u5904\u7406", rec.createdAt);
|
|
234441
|
+
if (r && r.by === me && issueIdsOf(row).has(r.issueId)) return found(rec, handled2(me, "\u5DF2\u5904\u7406", rec.createdAt));
|
|
234060
234442
|
const s2 = payload(rec, "work.submit_output");
|
|
234061
|
-
if (s2 && doerOf(rec) === me && onNode(rec)) return handled2(me, "\u5DF2\u63D0\u4EA4", rec.createdAt);
|
|
234443
|
+
if (s2 && doerOf(rec) === me && onNode(rec)) return found(rec, handled2(me, "\u5DF2\u63D0\u4EA4", rec.createdAt));
|
|
234062
234444
|
break;
|
|
234063
234445
|
}
|
|
234064
234446
|
case "gap-escalation": {
|
|
234065
234447
|
const r = payload(rec, "issue.resolve");
|
|
234066
|
-
if (r && r.by === me && issueIdsOf(row).has(r.issueId)) return handled2(me, "\u5DF2\u89E3\u51B3", rec.createdAt);
|
|
234448
|
+
if (r && r.by === me && issueIdsOf(row).has(r.issueId)) return found(rec, handled2(me, "\u5DF2\u89E3\u51B3", rec.createdAt));
|
|
234067
234449
|
break;
|
|
234068
234450
|
}
|
|
234069
234451
|
case "needs-staffing": {
|
|
234070
234452
|
const a = payload(rec, "plan.assign_actor");
|
|
234071
|
-
if (a && rec.actorId === me && a.nodeId
|
|
234453
|
+
if (a && rec.actorId === me && staffingNodeMatches(row, a.nodeId) && a.assigneeActorId) return found(rec, handled2(me, "\u5DF2\u6307\u6D3E", rec.createdAt));
|
|
234072
234454
|
break;
|
|
234073
234455
|
}
|
|
234074
234456
|
default:
|
|
@@ -234085,21 +234467,25 @@ function resolvedByOther(row, evs, me, onNode) {
|
|
|
234085
234467
|
switch (row.kind) {
|
|
234086
234468
|
case "review-request":
|
|
234087
234469
|
case "review-waiting": {
|
|
234088
|
-
const v2 = payload(rec, "review.response");
|
|
234089
|
-
if (v2 && onNode(rec) && (!gen || v2.targetWorkId === gen)) return invalidated("handled-by-other", rec.createdAt, who);
|
|
234090
234470
|
const acc = payload(rec, "work.accept") ?? payload(rec, "work.reject");
|
|
234091
|
-
if (acc && gen && acc.workId === gen)
|
|
234471
|
+
if (acc && gen && acc.workId === gen) {
|
|
234472
|
+
const decider = evs.filter((x2) => x2.seq <= rec.seq).reverse().find((x2) => {
|
|
234473
|
+
const vv = payload(x2, "review.response");
|
|
234474
|
+
return !!vv && vv.targetWorkId === gen && vv.reviewerActorId !== me;
|
|
234475
|
+
});
|
|
234476
|
+
return found(rec, invalidated("handled-by-other", rec.createdAt, decider ? doerOf(decider) : who));
|
|
234477
|
+
}
|
|
234092
234478
|
break;
|
|
234093
234479
|
}
|
|
234094
234480
|
case "gap-escalation":
|
|
234095
234481
|
case "pushback": {
|
|
234096
234482
|
const r = payload(rec, "issue.resolve");
|
|
234097
|
-
if (r && issueIdsOf(row).has(r.issueId)) return invalidated("handled-by-other", rec.createdAt, who);
|
|
234483
|
+
if (r && issueIdsOf(row).has(r.issueId)) return found(rec, invalidated("handled-by-other", rec.createdAt, who));
|
|
234098
234484
|
break;
|
|
234099
234485
|
}
|
|
234100
234486
|
case "needs-staffing": {
|
|
234101
234487
|
const a = payload(rec, "plan.assign_actor");
|
|
234102
|
-
if (a && a.nodeId
|
|
234488
|
+
if (a && staffingNodeMatches(row, a.nodeId) && a.assigneeActorId) return found(rec, invalidated("handled-by-other", rec.createdAt, rec.actorId));
|
|
234103
234489
|
break;
|
|
234104
234490
|
}
|
|
234105
234491
|
case "assigned":
|
|
@@ -234107,7 +234493,7 @@ function resolvedByOther(row, evs, me, onNode) {
|
|
|
234107
234493
|
case "stale":
|
|
234108
234494
|
case "work-waiting": {
|
|
234109
234495
|
const acc = payload(rec, "work.accept");
|
|
234110
|
-
if (acc && onNode(rec)) return invalidated("handled-by-other", rec.createdAt, who);
|
|
234496
|
+
if (acc && onNode(rec)) return found(rec, invalidated("handled-by-other", rec.createdAt, who));
|
|
234111
234497
|
break;
|
|
234112
234498
|
}
|
|
234113
234499
|
default:
|
|
@@ -234119,24 +234505,13 @@ function resolvedByOther(row, evs, me, onNode) {
|
|
|
234119
234505
|
function needsGrace(missingSinceMs, nowMs, graceMs) {
|
|
234120
234506
|
return nowMs - missingSinceMs < graceMs;
|
|
234121
234507
|
}
|
|
234122
|
-
var
|
|
234508
|
+
var STAFFING_ROLE_KEY, CLOSURE_EVENT_KINDS, payload, handled2, invalidated, found, ownerKinds, reviewKinds, verdictWord;
|
|
234123
234509
|
var init_notification_ledger = __esm({
|
|
234124
234510
|
"../server/src/domains/collab/notification-ledger.ts"() {
|
|
234125
234511
|
"use strict";
|
|
234126
234512
|
init_src5();
|
|
234127
234513
|
init_src();
|
|
234128
|
-
|
|
234129
|
-
"review-request",
|
|
234130
|
-
"rework",
|
|
234131
|
-
"stale",
|
|
234132
|
-
"pushback",
|
|
234133
|
-
"assigned",
|
|
234134
|
-
"needs-staffing",
|
|
234135
|
-
"gap-escalation",
|
|
234136
|
-
"change-confirm",
|
|
234137
|
-
"review-waiting",
|
|
234138
|
-
"work-waiting"
|
|
234139
|
-
]);
|
|
234514
|
+
STAFFING_ROLE_KEY = /^needs-staffing:.+:role:([^:@]+)$/;
|
|
234140
234515
|
CLOSURE_EVENT_KINDS = [
|
|
234141
234516
|
"review.response",
|
|
234142
234517
|
"review.kill",
|
|
@@ -234155,6 +234530,7 @@ var init_notification_ledger = __esm({
|
|
|
234155
234530
|
payload = (rec, kind) => rec.event.kind === kind ? rec.event : null;
|
|
234156
234531
|
handled2 = (closedBy, result, at) => ({ status: "handled", closedAt: at, closedBy, result });
|
|
234157
234532
|
invalidated = (invalidReason, at, closedBy) => ({ status: "invalidated", closedAt: at, invalidReason, ...closedBy ? { closedBy } : {} });
|
|
234533
|
+
found = (rec, closure) => ({ rec, closure });
|
|
234158
234534
|
ownerKinds = /* @__PURE__ */ new Set(["assigned", "rework", "stale", "pushback", "work-waiting"]);
|
|
234159
234535
|
reviewKinds = /* @__PURE__ */ new Set(["review-request", "review-waiting"]);
|
|
234160
234536
|
verdictWord = (verdict) => verdict === "approve" ? "\u5BA1\u6838\u901A\u8FC7" : verdict === "request_changes" || verdict === "reject" ? "\u8981\u6C42\u4FEE\u6539" : "\u5DF2\u5BA1\u6838";
|
|
@@ -234218,15 +234594,18 @@ function displayOf(model, item, recipient, reviewOf) {
|
|
|
234218
234594
|
function sameDisplay(row, d) {
|
|
234219
234595
|
return row.title === d.title && row.workspaceTitle === d.workspaceTitle && row.actorId === d.actorId && row.cardId === d.cardId && JSON.stringify(row.item ?? null) === JSON.stringify(d.item ?? null);
|
|
234220
234596
|
}
|
|
234221
|
-
var DAY2, EMPTY, EVENT_WINDOW_SLACK_MS, CLOSURE_EVENT_LIMIT, DRAFT_OUTCOME_TTL_MS, SLOW_RECONCILE_MS, rowKey, NotificationLedgerWorker;
|
|
234597
|
+
var DAY2, EMPTY, EVENT_WINDOW_SLACK_MS, CLOSURE_EVENT_LIMIT, DRAFT_OUTCOME_TTL_MS, SLOW_RECONCILE_MS, TASK_NOTICE_FRESH_MS, TASK_NOTICE_EVENT_LIMIT, rowKey, NotificationLedgerWorker;
|
|
234222
234598
|
var init_notification_reconciler = __esm({
|
|
234223
234599
|
"../server/src/domains/collab/notification-reconciler.ts"() {
|
|
234224
234600
|
"use strict";
|
|
234225
234601
|
init_src5();
|
|
234602
|
+
init_src();
|
|
234226
234603
|
init_inbox();
|
|
234227
234604
|
init_waiting_inbox();
|
|
234228
234605
|
init_node_state();
|
|
234229
234606
|
init_review_activity();
|
|
234607
|
+
init_workorder_terminal();
|
|
234608
|
+
init_task_notices();
|
|
234230
234609
|
init_notification_ledger();
|
|
234231
234610
|
DAY2 = 24 * 36e5;
|
|
234232
234611
|
EMPTY = { inserted: 0, refreshed: 0, closed: 0, pending: 0 };
|
|
@@ -234234,6 +234613,8 @@ var init_notification_reconciler = __esm({
|
|
|
234234
234613
|
CLOSURE_EVENT_LIMIT = 400;
|
|
234235
234614
|
DRAFT_OUTCOME_TTL_MS = 36e5;
|
|
234236
234615
|
SLOW_RECONCILE_MS = 2e3;
|
|
234616
|
+
TASK_NOTICE_FRESH_MS = 15 * 6e4;
|
|
234617
|
+
TASK_NOTICE_EVENT_LIMIT = 500;
|
|
234237
234618
|
rowKey = (recipient, sourceKey) => `${recipient}\0${sourceKey}`;
|
|
234238
234619
|
NotificationLedgerWorker = class {
|
|
234239
234620
|
constructor(deps) {
|
|
@@ -234256,7 +234637,7 @@ var init_notification_reconciler = __esm({
|
|
|
234256
234637
|
state(companyId) {
|
|
234257
234638
|
let st = this.states.get(companyId);
|
|
234258
234639
|
if (!st) {
|
|
234259
|
-
st = { running: false, rerun: false, lastRunAt: 0, snaps: /* @__PURE__ */ new Map(), lastSeenAt: /* @__PURE__ */ new Map(), missingSince: /* @__PURE__ */ new Map(), drafts: /* @__PURE__ */ new Map(), lastPurgeAt: 0, primed: false };
|
|
234640
|
+
st = { running: false, rerun: false, lastRunAt: 0, snaps: /* @__PURE__ */ new Map(), lastSeenAt: /* @__PURE__ */ new Map(), missingSince: /* @__PURE__ */ new Map(), drafts: /* @__PURE__ */ new Map(), lastPurgeAt: 0, primed: false, terminals: /* @__PURE__ */ new Map(), noticeSeq: 0 };
|
|
234260
234641
|
this.states.set(companyId, st);
|
|
234261
234642
|
}
|
|
234262
234643
|
return st;
|
|
@@ -234375,6 +234756,14 @@ var init_notification_reconciler = __esm({
|
|
|
234375
234756
|
const pending = await ctx.store.listPending();
|
|
234376
234757
|
const byKey = new Map(pending.map((r) => [rowKey(r.recipient, r.sourceKey), r]));
|
|
234377
234758
|
const markersOf = /* @__PURE__ */ new Map();
|
|
234759
|
+
const adopted = /* @__PURE__ */ new Set();
|
|
234760
|
+
const roleOfRow = (r) => {
|
|
234761
|
+
const fromKey = staffingRoleOfKey(r.sourceKey);
|
|
234762
|
+
if (fromKey) return fromKey;
|
|
234763
|
+
const owner = r.nodeId ? model.artifacts.get(r.nodeId)?.owner : void 0;
|
|
234764
|
+
return owner?.startsWith(PENDING_ROLE_PREFIX) ? owner.slice(PENDING_ROLE_PREFIX.length) : void 0;
|
|
234765
|
+
};
|
|
234766
|
+
const staffingOrphans = pending.filter((r) => r.kind === "needs-staffing" && !current.has(rowKey(r.recipient, r.sourceKey)));
|
|
234378
234767
|
for (const [k2, c] of current) {
|
|
234379
234768
|
const display = displayOf(model, c.item, c.recipient, reviewOf);
|
|
234380
234769
|
const row = byKey.get(k2);
|
|
@@ -234387,6 +234776,15 @@ var init_notification_reconciler = __esm({
|
|
|
234387
234776
|
}
|
|
234388
234777
|
continue;
|
|
234389
234778
|
}
|
|
234779
|
+
const role = staffingRoleOf(model, c.item);
|
|
234780
|
+
const orphan = role ? staffingOrphans.find((r) => !adopted.has(r.id) && r.recipient === c.recipient && r.workorderId === c.item.workspace && roleOfRow(r) === role) : void 0;
|
|
234781
|
+
if (orphan && await ctx.store.rekey(orphan.id, c.sourceKey, { ...display, ...c.item.artifactId ? { nodeId: c.item.artifactId } : {} }, nowIso)) {
|
|
234782
|
+
adopted.add(orphan.id);
|
|
234783
|
+
st.missingSince.delete(orphan.id);
|
|
234784
|
+
st.lastSeenAt.set(orphan.id, nowIso);
|
|
234785
|
+
stats.refreshed++;
|
|
234786
|
+
continue;
|
|
234787
|
+
}
|
|
234390
234788
|
const readAt = st.primed ? void 0 : await this.alreadyReadAt(ctx, c.recipient, c.item, markersOf, nowIso);
|
|
234391
234789
|
const sinceOk = Number.isFinite(Date.parse(c.item.since));
|
|
234392
234790
|
const enteredAt = st.primed || !sinceOk ? nowIso : new Date(c.item.since).toISOString();
|
|
@@ -234409,7 +234807,7 @@ var init_notification_reconciler = __esm({
|
|
|
234409
234807
|
const cancelledOf = /* @__PURE__ */ new Map();
|
|
234410
234808
|
let waitingForGrace = false;
|
|
234411
234809
|
for (const row of pending) {
|
|
234412
|
-
if (current.has(rowKey(row.recipient, row.sourceKey))) continue;
|
|
234810
|
+
if (current.has(rowKey(row.recipient, row.sourceKey)) || adopted.has(row.id)) continue;
|
|
234413
234811
|
const closure = await this.judge(st, ctx, model, row, nowMs, nowIso, eventsOf, cancelledOf);
|
|
234414
234812
|
if (!closure) {
|
|
234415
234813
|
waitingForGrace = true;
|
|
@@ -234420,6 +234818,7 @@ var init_notification_reconciler = __esm({
|
|
|
234420
234818
|
st.lastSeenAt.delete(row.id);
|
|
234421
234819
|
}
|
|
234422
234820
|
stats.pending = current.size;
|
|
234821
|
+
stats.notices = await this.reconcileTaskNotices(st, ctx, model, nowMs, loadSnapshot2);
|
|
234423
234822
|
if (nowMs - st.lastPurgeAt > (this.deps.purgeEveryMs ?? 6 * 36e5)) {
|
|
234424
234823
|
st.lastPurgeAt = nowMs;
|
|
234425
234824
|
const purged = await ctx.store.purgeBefore(new Date(nowMs - (this.deps.retentionMs ?? 90 * DAY2)).toISOString());
|
|
@@ -234458,6 +234857,74 @@ var init_notification_reconciler = __esm({
|
|
|
234458
234857
|
if (needsGrace(since, nowMs, this.graceMs)) return null;
|
|
234459
234858
|
return { status: "invalidated", closedAt: nowIso, invalidReason: "source-changed" };
|
|
234460
234859
|
}
|
|
234860
|
+
/**
|
|
234861
|
+
* 任务告知(第 2 步 B)。完成 / 取消从当前状态现算(与结案播报、任务列表同一判据),暂停 / 恢复读引擎事件。
|
|
234862
|
+
*
|
|
234863
|
+
* **不补历史**:进程第一次对账时(上线当天、重启后)只发最近 {@link TASK_NOTICE_FRESH_MS} 内发生的变化——
|
|
234864
|
+
* 早就结束的任务不能在上线那一刻集体「任务已完成」一遍。之后每拍新看到的变化都发。
|
|
234865
|
+
* 来源键 = `<种类>:<工单>@<那件事的 seq>`:同一件事重启后再算一遍撞唯一约束即收手;任务重开后再完成是新的一件事。
|
|
234866
|
+
*/
|
|
234867
|
+
async reconcileTaskNotices(st, ctx, model, nowMs, loadSnapshot2) {
|
|
234868
|
+
const store = ctx.engineStore;
|
|
234869
|
+
if (!store) return 0;
|
|
234870
|
+
const members = new Set(ctx.humans);
|
|
234871
|
+
const titleOf = workspaceTitleMap(model);
|
|
234872
|
+
const fresh = (iso7) => nowMs - Date.parse(iso7) <= TASK_NOTICE_FRESH_MS;
|
|
234873
|
+
let sent = 0;
|
|
234874
|
+
const emit = async (workorderId, kind, rec, trigger) => {
|
|
234875
|
+
const recipients = taskNoticeRecipients(model, workorderId, await loadSnapshot2(workorderId), members, trigger);
|
|
234876
|
+
const title = titleOf.get(workorderId);
|
|
234877
|
+
for (const recipient of recipients) {
|
|
234878
|
+
await ctx.store.insert({
|
|
234879
|
+
recipient,
|
|
234880
|
+
category: "task-notice",
|
|
234881
|
+
sourceKey: `${kind}:${workorderId}@${rec.seq}`,
|
|
234882
|
+
kind,
|
|
234883
|
+
workorderId,
|
|
234884
|
+
title: TASK_NOTICE_TITLE[kind],
|
|
234885
|
+
...title ? { workspaceTitle: title } : {},
|
|
234886
|
+
...trigger ? { actorId: trigger } : {},
|
|
234887
|
+
enteredAt: new Date(rec.createdAt).toISOString()
|
|
234888
|
+
});
|
|
234889
|
+
sent++;
|
|
234890
|
+
}
|
|
234891
|
+
};
|
|
234892
|
+
const pauses = await store.transaction((tx) => tx.listEvents(void 0, st.noticeSeq, TASK_NOTICE_EVENT_LIMIT, ["workorder.paused", "workorder.resumed"]));
|
|
234893
|
+
for (const rec of pauses) {
|
|
234894
|
+
st.noticeSeq = Math.max(st.noticeSeq, rec.seq);
|
|
234895
|
+
if (!st.primed && !fresh(rec.createdAt)) continue;
|
|
234896
|
+
const e = rec.event;
|
|
234897
|
+
const paused = e.kind === "workorder.paused";
|
|
234898
|
+
if (paused ? isCreationHold(rec) : endsCreationHold(
|
|
234899
|
+
await store.transaction((tx) => tx.listEvents(rec.workorderId, 0, TASK_NOTICE_EVENT_LIMIT, ["workorder.paused"])),
|
|
234900
|
+
rec
|
|
234901
|
+
)) continue;
|
|
234902
|
+
await emit(rec.workorderId, paused ? "workorder-paused" : "workorder-resumed", rec, e.by ?? rec.actorId);
|
|
234903
|
+
}
|
|
234904
|
+
const terminals = computeWorkorderTerminals(model);
|
|
234905
|
+
const now = /* @__PURE__ */ new Set();
|
|
234906
|
+
for (const t of terminals) {
|
|
234907
|
+
const kind = t.kind;
|
|
234908
|
+
now.add(t.workOrderId);
|
|
234909
|
+
if (st.terminals.get(t.workOrderId) === kind) continue;
|
|
234910
|
+
st.terminals.set(t.workOrderId, kind);
|
|
234911
|
+
if (!st.primed && !(t.terminalAt && fresh(t.terminalAt))) continue;
|
|
234912
|
+
const cancelled = kind === "workorder-cancelled";
|
|
234913
|
+
const evs = await store.transaction((tx) => tx.listEvents(
|
|
234914
|
+
t.workOrderId,
|
|
234915
|
+
0,
|
|
234916
|
+
TASK_NOTICE_EVENT_LIMIT,
|
|
234917
|
+
cancelled ? ["plan.delete_node"] : ["work.accept", "review.response", "work.conclude"]
|
|
234918
|
+
));
|
|
234919
|
+
const decisive = [...evs].reverse().find((rec) => cancelled ? rec.event.sealReason === "cancelled" : rec.event.kind === "work.accept");
|
|
234920
|
+
if (!decisive) continue;
|
|
234921
|
+
if (!st.primed && !fresh(decisive.createdAt)) continue;
|
|
234922
|
+
const trigger = cancelled ? decisive.actorId : settleTrigger(evs, decisive);
|
|
234923
|
+
await emit(t.workOrderId, kind, decisive, trigger && !isSystemActorId(trigger) ? trigger : void 0);
|
|
234924
|
+
}
|
|
234925
|
+
for (const wid of [...st.terminals.keys()]) if (!now.has(wid)) st.terminals.delete(wid);
|
|
234926
|
+
return sent;
|
|
234927
|
+
}
|
|
234461
234928
|
/** 台账上线前已经看过的待办不重新亮红点:沿用 `/api/inbox` 的未读判据(基线 + 逐条水位)。 */
|
|
234462
234929
|
async alreadyReadAt(ctx, recipient, item, cache, nowIso) {
|
|
234463
234930
|
if (!ctx.markers) return void 0;
|
|
@@ -234614,7 +235081,7 @@ function createBundle(root, target, input) {
|
|
|
234614
235081
|
}
|
|
234615
235082
|
}
|
|
234616
235083
|
const bytes2 = fs26.statSync(absBundle).size;
|
|
234617
|
-
const digest = (0,
|
|
235084
|
+
const digest = (0, import_node_crypto59.createHash)("sha256").update(fs26.readFileSync(absBundle)).digest("hex");
|
|
234618
235085
|
const relBase = `inputs/git-bundles/${safeRepo}-${commit.slice(0, 12)}`;
|
|
234619
235086
|
return {
|
|
234620
235087
|
absoluteBundlePath: absBundle,
|
|
@@ -234710,12 +235177,12 @@ function classifyGitError(fallback, err, where) {
|
|
|
234710
235177
|
function oneLine(msg) {
|
|
234711
235178
|
return msg.split("\n").map((s2) => s2.trim()).filter(Boolean).slice(0, 3).join(" ");
|
|
234712
235179
|
}
|
|
234713
|
-
var import_node_child_process17,
|
|
235180
|
+
var import_node_child_process17, import_node_crypto59, fs26, os7, path25, GitReadonlyBundleError, HEX40, FETCH_TIMEOUT_MS2;
|
|
234714
235181
|
var init_readonly_bundle = __esm({
|
|
234715
235182
|
"../server/src/git/readonly-bundle.ts"() {
|
|
234716
235183
|
"use strict";
|
|
234717
235184
|
import_node_child_process17 = require("node:child_process");
|
|
234718
|
-
|
|
235185
|
+
import_node_crypto59 = require("node:crypto");
|
|
234719
235186
|
fs26 = __toESM(require("node:fs"), 1);
|
|
234720
235187
|
os7 = __toESM(require("node:os"), 1);
|
|
234721
235188
|
path25 = __toESM(require("node:path"), 1);
|
|
@@ -234735,7 +235202,7 @@ var init_readonly_bundle = __esm({
|
|
|
234735
235202
|
|
|
234736
235203
|
// ../server/src/domains/collab/create-seeded-workorder.ts
|
|
234737
235204
|
function makeSeededWorkorderCreator(deps) {
|
|
234738
|
-
const genWorkspace = deps.genWorkspace ?? (() => `ws:wo-${(0,
|
|
235205
|
+
const genWorkspace = deps.genWorkspace ?? (() => `ws:wo-${(0, import_node_crypto60.randomUUID)().slice(0, 8)}`);
|
|
234739
235206
|
return async (input) => {
|
|
234740
235207
|
const company = input.companyId && deps.resolveCompany ? await deps.resolveCompany(input.companyId) : void 0;
|
|
234741
235208
|
const kernel = company?.kernel ?? deps.kernel;
|
|
@@ -234822,13 +235289,13 @@ function makeSeededWorkorderCreator(deps) {
|
|
|
234822
235289
|
}
|
|
234823
235290
|
if (input.dispatch === false && artifactState) {
|
|
234824
235291
|
await artifactState.setWorkspaceDispatchHold(workspace, true);
|
|
234825
|
-
await kernel.pauseWorkorder?.(workspace, input.actor);
|
|
235292
|
+
await kernel.pauseWorkorder?.(workspace, input.actor, WORKORDER_HOLD_AT_CREATE_REASON);
|
|
234826
235293
|
}
|
|
234827
235294
|
return { workspace, rootArtifactId: briefId, spawned: planned.spawned };
|
|
234828
235295
|
};
|
|
234829
235296
|
}
|
|
234830
235297
|
function workspaceForKey(key) {
|
|
234831
|
-
return `ws:wo-${(0,
|
|
235298
|
+
return `ws:wo-${(0, import_node_crypto60.createHash)("sha256").update(key).digest("hex").slice(0, 8)}`;
|
|
234832
235299
|
}
|
|
234833
235300
|
function existingWorkorder(kernel, workspace) {
|
|
234834
235301
|
const arts = [...kernel.model.artifacts.values()].filter((a) => a.workspace === workspace);
|
|
@@ -234841,12 +235308,13 @@ function existingWorkorder(kernel, workspace) {
|
|
|
234841
235308
|
spawned: arts.map((a) => ({ id: a.id, type: a.type, owner: a.owner }))
|
|
234842
235309
|
};
|
|
234843
235310
|
}
|
|
234844
|
-
var
|
|
235311
|
+
var import_node_crypto60, enc2;
|
|
234845
235312
|
var init_create_seeded_workorder = __esm({
|
|
234846
235313
|
"../server/src/domains/collab/create-seeded-workorder.ts"() {
|
|
234847
235314
|
"use strict";
|
|
234848
|
-
|
|
235315
|
+
import_node_crypto60 = require("node:crypto");
|
|
234849
235316
|
init_uncategorized_project();
|
|
235317
|
+
init_src();
|
|
234850
235318
|
init_planner();
|
|
234851
235319
|
enc2 = (s2) => new TextEncoder().encode(s2);
|
|
234852
235320
|
}
|
|
@@ -235703,6 +236171,37 @@ var init_trace_health = __esm({
|
|
|
235703
236171
|
}
|
|
235704
236172
|
});
|
|
235705
236173
|
|
|
236174
|
+
// ../server/src/domains/trace/subagent-events.ts
|
|
236175
|
+
function subagentRunEventFromLive(event) {
|
|
236176
|
+
if (event.itemType !== "control") return null;
|
|
236177
|
+
const payload2 = event.payload && typeof event.payload === "object" && !Array.isArray(event.payload) ? event.payload : void 0;
|
|
236178
|
+
if (payload2?.code !== SUBAGENT_TASK_CODE || typeof payload2.toolCallId !== "string") return null;
|
|
236179
|
+
const raw = payload2.task;
|
|
236180
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
|
|
236181
|
+
const task = raw;
|
|
236182
|
+
const cost = task.estimatedCostUsdMicros ?? estimateSubagentCostUsdMicros(task.usage);
|
|
236183
|
+
const enriched = cost !== void 0 ? { ...task, estimatedCostUsdMicros: cost } : task;
|
|
236184
|
+
const eventType = task.status === "running" ? "sub_agent.started" : "sub_agent.finished";
|
|
236185
|
+
return {
|
|
236186
|
+
eventType,
|
|
236187
|
+
stream: "tool",
|
|
236188
|
+
...task.status === "failed" ? { level: "error" } : {},
|
|
236189
|
+
...task.description ? { message: task.description } : {},
|
|
236190
|
+
payload: {
|
|
236191
|
+
kind: "subagent_task",
|
|
236192
|
+
raw: { code: SUBAGENT_TASK_CODE, toolCallId: payload2.toolCallId, task: enriched }
|
|
236193
|
+
},
|
|
236194
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
236195
|
+
};
|
|
236196
|
+
}
|
|
236197
|
+
var init_subagent_events = __esm({
|
|
236198
|
+
"../server/src/domains/trace/subagent-events.ts"() {
|
|
236199
|
+
"use strict";
|
|
236200
|
+
init_src();
|
|
236201
|
+
init_subagent_cost();
|
|
236202
|
+
}
|
|
236203
|
+
});
|
|
236204
|
+
|
|
235706
236205
|
// ../server/src/domains/trace/index.ts
|
|
235707
236206
|
function createTraceDomain(opts) {
|
|
235708
236207
|
const service = new TraceService({ store: opts.store });
|
|
@@ -235735,6 +236234,7 @@ var init_trace2 = __esm({
|
|
|
235735
236234
|
init_chat_parts();
|
|
235736
236235
|
init_trace_health();
|
|
235737
236236
|
init_resilient_appender();
|
|
236237
|
+
init_subagent_events();
|
|
235738
236238
|
}
|
|
235739
236239
|
});
|
|
235740
236240
|
|
|
@@ -236242,12 +236742,12 @@ function stateFromAttempt(attempt, handoff, checkpoint, now, stalledAfterMs, ope
|
|
|
236242
236742
|
if (attempt.status === "no-output") return handoff?.unresolvedIssues.length ? "blocked" : "no_change";
|
|
236243
236743
|
return "failed";
|
|
236244
236744
|
}
|
|
236245
|
-
var
|
|
236745
|
+
var import_node_crypto61, BLOCKING_STATES, HANDOFF_OUTCOMES2, RESUME_EXTERNAL_EFFECT_LIMIT, RESUME_SNAPSHOT_PREFIX, RESUME_SNAPSHOT_SUFFIX, ExecutionContinuityService;
|
|
236246
236746
|
var init_service8 = __esm({
|
|
236247
236747
|
"../server/src/domains/execution-continuity/service.ts"() {
|
|
236248
236748
|
"use strict";
|
|
236249
236749
|
init_src();
|
|
236250
|
-
|
|
236750
|
+
import_node_crypto61 = require("node:crypto");
|
|
236251
236751
|
init_src5();
|
|
236252
236752
|
BLOCKING_STATES = /* @__PURE__ */ new Set(["stalled", "failed", "blocked"]);
|
|
236253
236753
|
HANDOFF_OUTCOMES2 = /* @__PURE__ */ new Set(["succeeded", "no-output", "failed", "cancelled", "timeout", "orphaned"]);
|
|
@@ -236478,7 +236978,7 @@ var init_service8 = __esm({
|
|
|
236478
236978
|
if (typeof expectedHash !== "string" || !this.readBundleFile) return null;
|
|
236479
236979
|
const injectedResume = this.readBundleFile(attempt.id, "execution/RESUME.md");
|
|
236480
236980
|
if (!injectedResume) return null;
|
|
236481
|
-
const actualHash = (0,
|
|
236981
|
+
const actualHash = (0, import_node_crypto61.createHash)("sha256").update(injectedResume).digest("hex");
|
|
236482
236982
|
if (actualHash !== expectedHash) return null;
|
|
236483
236983
|
const recoverySnapshot = parseResumePackSnapshot(injectedResume);
|
|
236484
236984
|
if (!recoverySnapshot || recoverySnapshot.scenario !== "redispatch" || !recoverySnapshot.previousAttempt || recoverySnapshot.node.nodeId !== attempt.nodeId || recoverySnapshot.jobKey !== attempt.jobKey || recoverySnapshot.part !== attempt.part) return null;
|
|
@@ -237385,7 +237885,12 @@ async function buildChatProjectBundle(projectId2, projects, readBlob) {
|
|
|
237385
237885
|
"",
|
|
237386
237886
|
"\u751F\u6210 Brief \u548C\u534F\u4F5C\u56FE\u524D\uFF0C\u5148\u9605\u8BFB\u672C\u6587\u4EF6\u5217\u51FA\u7684\u516C\u5F00\u8F93\u5165\u3002\u4E0D\u8981\u5047\u8BBE Benchmark \u4ED3\u5E93\u3001\u9690\u85CF\u6D4B\u8BD5\u3001Oracle \u6216\u53C2\u8003\u7B54\u6848\u53EF\u89C1\u3002"
|
|
237387
237887
|
].join("\n");
|
|
237388
|
-
return {
|
|
237888
|
+
return {
|
|
237889
|
+
files,
|
|
237890
|
+
binaryFiles,
|
|
237891
|
+
contextLines,
|
|
237892
|
+
project: { id: project.id, name: project.name, ...project.description ? { description: project.description } : {} }
|
|
237893
|
+
};
|
|
237389
237894
|
}
|
|
237390
237895
|
var textFile, safeProjectPath;
|
|
237391
237896
|
var init_project_bundle = __esm({
|
|
@@ -237400,6 +237905,10 @@ var init_project_bundle = __esm({
|
|
|
237400
237905
|
});
|
|
237401
237906
|
|
|
237402
237907
|
// ../server/src/domains/chat-sessions/index.ts
|
|
237908
|
+
function sessionProjectIdToStore(projectId2) {
|
|
237909
|
+
if (typeof projectId2 !== "string" || projectId2.trim() === "") return null;
|
|
237910
|
+
return isUncategorizedProjectId(projectId2) ? null : projectId2;
|
|
237911
|
+
}
|
|
237403
237912
|
function parseDurationMs(raw) {
|
|
237404
237913
|
if (!raw) return null;
|
|
237405
237914
|
const m2 = /^(\d+)\s*(ms|s|m|h|d)?$/i.exec(raw.trim());
|
|
@@ -237573,7 +238082,7 @@ function createChatSessionsDomain(opts) {
|
|
|
237573
238082
|
if (!text5.trim()) throw new ApiError(400, "BAD_REQUEST", "text required");
|
|
237574
238083
|
const now = Date.now();
|
|
237575
238084
|
sweepDrafts(now);
|
|
237576
|
-
const id = `cd_${(0,
|
|
238085
|
+
const id = `cd_${(0, import_node_crypto62.randomUUID)()}`;
|
|
237577
238086
|
drafts.set(id, { text: text5, actor: req.auth.actor, expiresAt: now + DRAFT_TTL_MS });
|
|
237578
238087
|
return { status: 201, body: { id, expiresInMs: DRAFT_TTL_MS } };
|
|
237579
238088
|
});
|
|
@@ -237625,7 +238134,7 @@ function createChatSessionsDomain(opts) {
|
|
|
237625
238134
|
const runtimeId = await currentRuntimeId(body2.aiActorId) ?? "unknown";
|
|
237626
238135
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
237627
238136
|
const session = {
|
|
237628
|
-
id: (0,
|
|
238137
|
+
id: (0, import_node_crypto62.randomUUID)(),
|
|
237629
238138
|
humanActorId: req.auth.actor,
|
|
237630
238139
|
// 注:这里**刻意不写 companyId**。新会话要不要带公司归属,按 ws:wo-6d588f8e 的 ADR
|
|
237631
238140
|
// (每公司 schema、最终移除表内 company 列)统一定,不在本节点自行发明。
|
|
@@ -237638,7 +238147,7 @@ function createChatSessionsDomain(opts) {
|
|
|
237638
238147
|
// 决策 0030 缝合:绑定是会话的语义属性(工单频道/问题会话给、脑暴省略)——发消息端据它带 workspace,
|
|
237639
238148
|
// 两个入口页面行为一致。区别于 linkWorkOrder(出处关联,建单脑暴也有、不构成绑定)。
|
|
237640
238149
|
workspace: body2.workspace ?? null,
|
|
237641
|
-
projectId: body2.projectId
|
|
238150
|
+
projectId: sessionProjectIdToStore(body2.projectId),
|
|
237642
238151
|
// 会话级模型覆盖(口径 A):建会话时就带上选择;空串/空白归 null = 沿用旧解析,不写员工全局配置。
|
|
237643
238152
|
model: normalizeModel(body2.model),
|
|
237644
238153
|
// ADR-0058:分析会话指向被分析 run;非空即"这是分析会话"(不进主聊天列表、进 trace 分析视图)。
|
|
@@ -237707,7 +238216,7 @@ function createChatSessionsDomain(opts) {
|
|
|
237707
238216
|
...body2.runtimeId !== void 0 ? { runtimeId: body2.runtimeId } : {},
|
|
237708
238217
|
...Object.prototype.hasOwnProperty.call(body2, "runtimeSessionId") ? { runtimeSessionId: body2.runtimeSessionId } : {},
|
|
237709
238218
|
...body2.title !== void 0 ? { title: body2.title } : {},
|
|
237710
|
-
...Object.prototype.hasOwnProperty.call(body2, "projectId") ? { projectId: body2.projectId } : {},
|
|
238219
|
+
...Object.prototype.hasOwnProperty.call(body2, "projectId") ? { projectId: sessionProjectIdToStore(body2.projectId) } : {},
|
|
237711
238220
|
// 会话级模型覆盖:显式传 null / 空串 = 清除覆盖(回到旧解析);不传这一项 = 不动它。
|
|
237712
238221
|
...Object.prototype.hasOwnProperty.call(body2, "model") ? { model: normalizeModel(body2.model) } : {},
|
|
237713
238222
|
// 只有显式传了才写——改标题 / 换项目 / 换模型都不是「有新动静」,不该顶掉列表顺序与已读水位。
|
|
@@ -237731,7 +238240,7 @@ function createChatSessionsDomain(opts) {
|
|
|
237731
238240
|
if (body2.role !== "user" && body2.role !== "assistant") throw new ApiError(400, "BAD_REQUEST", "role must be user or assistant");
|
|
237732
238241
|
const role = body2.role;
|
|
237733
238242
|
const msg = await store2.appendMessage({
|
|
237734
|
-
id: (0,
|
|
238243
|
+
id: (0, import_node_crypto62.randomUUID)(),
|
|
237735
238244
|
sessionId: req.params.id,
|
|
237736
238245
|
role,
|
|
237737
238246
|
content: role === "user" ? stripInjectedChatContext(body2.content) : body2.content,
|
|
@@ -237772,7 +238281,7 @@ function createChatSessionsDomain(opts) {
|
|
|
237772
238281
|
const known = key ? cur.find((x2) => x2.clientKey === key) : void 0;
|
|
237773
238282
|
if (!known && cur.length >= QUEUE_MAX) throw new ApiError(409, "QUEUE_FULL", `\u961F\u5217\u5DF2\u6EE1\uFF08\u4E0A\u9650 ${QUEUE_MAX} \u6761\uFF09`);
|
|
237774
238283
|
const item = await store.enqueuePendingMessage({
|
|
237775
|
-
id: (0,
|
|
238284
|
+
id: (0, import_node_crypto62.randomUUID)(),
|
|
237776
238285
|
chatSessionId: sid,
|
|
237777
238286
|
text: text5,
|
|
237778
238287
|
...attachments.length ? { attachments } : {},
|
|
@@ -238095,7 +238604,7 @@ function createChatSessionsDomain(opts) {
|
|
|
238095
238604
|
const outcome = await bridge.read(
|
|
238096
238605
|
loc.nodeId,
|
|
238097
238606
|
{ workdirKey: loc.workdirKey, runtimeKind: loc.runtimeKind, rtId: loc.rtId, path: req.query?.get("path") ?? "" },
|
|
238098
|
-
|
|
238607
|
+
FILE_CONTENT_MAX_BYTES
|
|
238099
238608
|
);
|
|
238100
238609
|
if (outcome.ok) {
|
|
238101
238610
|
const buf = Buffer.from(outcome.contentBase64, "base64");
|
|
@@ -238223,11 +238732,11 @@ function createChatSessionsDomain(opts) {
|
|
|
238223
238732
|
});
|
|
238224
238733
|
};
|
|
238225
238734
|
}
|
|
238226
|
-
var
|
|
238227
|
-
var
|
|
238735
|
+
var import_node_crypto62, DEFAULT_SNAPSHOT_ITEMS, MAX_SNAPSHOT_ITEMS;
|
|
238736
|
+
var init_chat_sessions2 = __esm({
|
|
238228
238737
|
"../server/src/domains/chat-sessions/index.ts"() {
|
|
238229
238738
|
"use strict";
|
|
238230
|
-
|
|
238739
|
+
import_node_crypto62 = require("node:crypto");
|
|
238231
238740
|
init_src();
|
|
238232
238741
|
init_chat_session();
|
|
238233
238742
|
init_files_view();
|
|
@@ -238244,10 +238753,10 @@ var init_chat_sessions = __esm({
|
|
|
238244
238753
|
init_company_data_store_router();
|
|
238245
238754
|
init_workorder_terminal();
|
|
238246
238755
|
init_session_workdir();
|
|
238756
|
+
init_uncategorized_project();
|
|
238247
238757
|
init_project_bundle();
|
|
238248
238758
|
DEFAULT_SNAPSHOT_ITEMS = 400;
|
|
238249
238759
|
MAX_SNAPSHOT_ITEMS = 1e3;
|
|
238250
|
-
WORKDIR_READ_MAX_BYTES = 2 * 1024 * 1024;
|
|
238251
238760
|
}
|
|
238252
238761
|
});
|
|
238253
238762
|
|
|
@@ -239632,7 +240141,7 @@ function busyError(chatSessionId, blockedBy) {
|
|
|
239632
240141
|
return `\u76EE\u6807\u4F1A\u8BDD ${chatSessionId} \u6B63\u6709\u4E00\u8F6E\u5728\u8DD1${blockedBy ? `\uFF08${blockedBy}\uFF09` : ""}\u2014\u2014\u672C\u6B21\u89E6\u53D1\u5DF2\u4E22\u5F03\uFF0C\u4E0D\u6392\u961F\u3001\u4E0D\u8865\u8DD1`;
|
|
239633
240142
|
}
|
|
239634
240143
|
function genWebhookToken() {
|
|
239635
|
-
return `owt_${(0,
|
|
240144
|
+
return `owt_${(0, import_node_crypto63.randomBytes)(32).toString("base64url")}`;
|
|
239636
240145
|
}
|
|
239637
240146
|
function validateTitleTemplate(tpl) {
|
|
239638
240147
|
const residue = tpl.replace(DATE_TOKEN, "");
|
|
@@ -239688,11 +240197,11 @@ function appendSourceNote(brief, automation, source, atIso) {
|
|
|
239688
240197
|
---
|
|
239689
240198
|
\u672C\u5DE5\u5355\u7531\u81EA\u52A8\u5316\u300C${automation.name}\u300D\u4E8E ${atIso} \u89E6\u53D1\uFF08\u6765\u6E90\uFF1A${source}\uFF09\u3002\u5F00\u5DE5\u540E\u8BF7\u628A\u5DE5\u5355\u6807\u9898\u6539\u6210\u51C6\u786E\u53CD\u6620\u5B9E\u9645\u5DE5\u4F5C\u7684\u63CF\u8FF0\u3002`;
|
|
239690
240199
|
}
|
|
239691
|
-
var
|
|
240200
|
+
var import_node_crypto63, DATE_TOKEN, AutomationsService, EVENT_RETRY_BASE_MS, EVENT_RETRY_MAX_MS, EVENT_RETRY_MAX_ATTEMPTS, eventAttempts, eventLastAttemptAt, eventLastError, CHAT_REPLY_MAX;
|
|
239692
240201
|
var init_service9 = __esm({
|
|
239693
240202
|
"../server/src/domains/automations/service.ts"() {
|
|
239694
240203
|
"use strict";
|
|
239695
|
-
|
|
240204
|
+
import_node_crypto63 = require("node:crypto");
|
|
239696
240205
|
init_src();
|
|
239697
240206
|
init_registry3();
|
|
239698
240207
|
init_attribution();
|
|
@@ -240506,11 +241015,11 @@ function verifySignature(rawBody, headers, secret) {
|
|
|
240506
241015
|
if (!secret) return "not_required";
|
|
240507
241016
|
const given = header1(headers, "x-hub-signature-256");
|
|
240508
241017
|
if (!given) return "missing";
|
|
240509
|
-
const expected = `sha256=${(0,
|
|
241018
|
+
const expected = `sha256=${(0, import_node_crypto64.createHmac)("sha256", secret).update(rawBody).digest("hex")}`;
|
|
240510
241019
|
const a = Buffer.from(given);
|
|
240511
241020
|
const b2 = Buffer.from(expected);
|
|
240512
241021
|
if (a.length !== b2.length) return "invalid";
|
|
240513
|
-
return (0,
|
|
241022
|
+
return (0, import_node_crypto64.timingSafeEqual)(a, b2) ? "valid" : "invalid";
|
|
240514
241023
|
}
|
|
240515
241024
|
function eventAllowed(filters, envelope) {
|
|
240516
241025
|
if (!filters || filters.length === 0) return true;
|
|
@@ -240540,11 +241049,11 @@ function splitEvent(envelope) {
|
|
|
240540
241049
|
}
|
|
240541
241050
|
return { eventName, actionCandidates: candidates };
|
|
240542
241051
|
}
|
|
240543
|
-
var
|
|
241052
|
+
var import_node_crypto64, MAX_BODY_BYTES, AutomationWebhookService, header1, PROVIDER_PREFIXES;
|
|
240544
241053
|
var init_webhook = __esm({
|
|
240545
241054
|
"../server/src/domains/automations/webhook.ts"() {
|
|
240546
241055
|
"use strict";
|
|
240547
|
-
|
|
241056
|
+
import_node_crypto64 = require("node:crypto");
|
|
240548
241057
|
MAX_BODY_BYTES = 256 * 1024;
|
|
240549
241058
|
AutomationWebhookService = class {
|
|
240550
241059
|
store;
|
|
@@ -241140,11 +241649,11 @@ function automationsDomain(opts) {
|
|
|
241140
241649
|
});
|
|
241141
241650
|
router.get("/api/automations/:id/runs/:runId", async (req) => {
|
|
241142
241651
|
const automation = await mustGet(req);
|
|
241143
|
-
const
|
|
241144
|
-
if (!
|
|
241652
|
+
const found2 = await service.getRun(req.params.runId);
|
|
241653
|
+
if (!found2 || found2.automationId !== automation.id) {
|
|
241145
241654
|
throw new ApiError(404, "NOT_FOUND", `\u6CA1\u6709\u8FD9\u6761\u8FD0\u884C\u8BB0\u5F55\uFF1A${req.params.runId}`);
|
|
241146
241655
|
}
|
|
241147
|
-
return { status: 200, body:
|
|
241656
|
+
return { status: 200, body: found2 };
|
|
241148
241657
|
});
|
|
241149
241658
|
router.get("/api/automations/:id/deliveries", async (req) => {
|
|
241150
241659
|
const automation = await mustGet(req);
|
|
@@ -241700,7 +242209,7 @@ function playbooksDomain(opts) {
|
|
|
241700
242209
|
opts.overrides.set(companyOf(req), ref2, nodeKey, nextOverride);
|
|
241701
242210
|
try {
|
|
241702
242211
|
await opts.audit?.({
|
|
241703
|
-
id: `reg_${(0,
|
|
242212
|
+
id: `reg_${(0, import_node_crypto65.randomUUID)()}`,
|
|
241704
242213
|
actor: req.auth.actor,
|
|
241705
242214
|
kind: "registry_change",
|
|
241706
242215
|
target: `playbook:${ref2}#${nodeKey}`,
|
|
@@ -241717,11 +242226,11 @@ function playbooksDomain(opts) {
|
|
|
241717
242226
|
});
|
|
241718
242227
|
};
|
|
241719
242228
|
}
|
|
241720
|
-
var
|
|
242229
|
+
var import_node_crypto65;
|
|
241721
242230
|
var init_routes12 = __esm({
|
|
241722
242231
|
"../server/src/domains/playbooks/routes.ts"() {
|
|
241723
242232
|
"use strict";
|
|
241724
|
-
|
|
242233
|
+
import_node_crypto65 = require("node:crypto");
|
|
241725
242234
|
init_router();
|
|
241726
242235
|
init_registry3();
|
|
241727
242236
|
init_planner();
|
|
@@ -241835,17 +242344,17 @@ function completionFingerprint(workspace, members) {
|
|
|
241835
242344
|
workspace,
|
|
241836
242345
|
members: [...members].sort((a, b2) => a.artifactId < b2.artifactId ? -1 : a.artifactId > b2.artifactId ? 1 : 0).map((m2) => ({ artifactId: m2.artifactId, currentRevisionId: m2.currentRevisionId ?? null }))
|
|
241837
242346
|
});
|
|
241838
|
-
return (0,
|
|
242347
|
+
return (0, import_node_crypto66.createHash)("sha256").update(canonical).digest("hex");
|
|
241839
242348
|
}
|
|
241840
242349
|
function eventConsumptionKey(args) {
|
|
241841
242350
|
const raw = `project-event:${EVENT_KEY_VERSION}:${args.triggerId}:${args.event}:${args.workspace}:${args.fingerprint}`;
|
|
241842
|
-
return raw.length <= 200 ? raw : `project-event:${EVENT_KEY_VERSION}:sha256:${(0,
|
|
242351
|
+
return raw.length <= 200 ? raw : `project-event:${EVENT_KEY_VERSION}:sha256:${(0, import_node_crypto66.createHash)("sha256").update(raw).digest("hex")}`;
|
|
241843
242352
|
}
|
|
241844
|
-
var
|
|
242353
|
+
var import_node_crypto66, EVENT_KEY_VERSION, EMPTY_METRICS, AUTOMATION_EVENT_HANDLERS, ProjectEventPoller;
|
|
241845
242354
|
var init_project_event_poller = __esm({
|
|
241846
242355
|
"../server/src/automations/project-event-poller.ts"() {
|
|
241847
242356
|
"use strict";
|
|
241848
|
-
|
|
242357
|
+
import_node_crypto66 = require("node:crypto");
|
|
241849
242358
|
EVENT_KEY_VERSION = "v1";
|
|
241850
242359
|
EMPTY_METRICS = () => ({
|
|
241851
242360
|
scanDurationMs: 0,
|
|
@@ -242056,7 +242565,7 @@ function remoteAppendInput(hub, nodeId, dispatchId, entry, input, timeoutMs) {
|
|
|
242056
242565
|
if (input.requireConsumptionReceipt && !hub.supportsInputConsumptionReceipts?.(dispatchId)) {
|
|
242057
242566
|
return Promise.resolve({ accepted: false, reason: "consumption-unsupported" });
|
|
242058
242567
|
}
|
|
242059
|
-
const requestId = (0,
|
|
242568
|
+
const requestId = (0, import_node_crypto67.randomUUID)();
|
|
242060
242569
|
const sent = routeToSession(hub, nodeId, dispatchId, { type: "append_input", dispatchId, input, requestId });
|
|
242061
242570
|
if (!sent) return Promise.resolve({ accepted: false, reason: "session-closing", ...unknownIfInterrupting });
|
|
242062
242571
|
return new Promise((resolve10) => {
|
|
@@ -242069,11 +242578,11 @@ function remoteAppendInput(hub, nodeId, dispatchId, entry, input, timeoutMs) {
|
|
|
242069
242578
|
entry.appendWaiters.push({ requestId, requireConsumptionReceipt: input.requireConsumptionReceipt, resolve: resolve10, timer });
|
|
242070
242579
|
});
|
|
242071
242580
|
}
|
|
242072
|
-
var
|
|
242581
|
+
var import_node_crypto67, STASH_TTL_MS, STASH_MAX_FRAMES_PER_ID, STASH_MAX_IDS, DaemonHubAdapter, BindingRouterAdapter, WorkdirBridge;
|
|
242073
242582
|
var init_daemon_adapter = __esm({
|
|
242074
242583
|
"../server/src/daemon-adapter.ts"() {
|
|
242075
242584
|
"use strict";
|
|
242076
|
-
|
|
242585
|
+
import_node_crypto67 = require("node:crypto");
|
|
242077
242586
|
init_src();
|
|
242078
242587
|
STASH_TTL_MS = 5 * 6e4;
|
|
242079
242588
|
STASH_MAX_FRAMES_PER_ID = 500;
|
|
@@ -242423,7 +242932,7 @@ var init_daemon_adapter = __esm({
|
|
|
242423
242932
|
async spawn(job) {
|
|
242424
242933
|
const nodeId = job.binding?.nodeId;
|
|
242425
242934
|
if (!nodeId) throw new Error("DaemonHubAdapter \u9700\u8981 job.binding.nodeId\uFF08\u8DEF\u7531\u9519\u8BEF\uFF09");
|
|
242426
|
-
const dispatchId = job.dispatchId ?? `dispatch:${(0,
|
|
242935
|
+
const dispatchId = job.dispatchId ?? `dispatch:${(0, import_node_crypto67.randomUUID)()}`;
|
|
242427
242936
|
if (job.dispatchId && this.pending.has(dispatchId)) {
|
|
242428
242937
|
return this.recover(dispatchId, nodeId, job.binding?.runtimeKind, job.actor);
|
|
242429
242938
|
}
|
|
@@ -242660,7 +243169,7 @@ var init_daemon_adapter = __esm({
|
|
|
242660
243169
|
return daemon?.meta.supportsWorkdirWalk === true;
|
|
242661
243170
|
}
|
|
242662
243171
|
request(nodeId, buildFrame) {
|
|
242663
|
-
const requestId = (0,
|
|
243172
|
+
const requestId = (0, import_node_crypto67.randomUUID)();
|
|
242664
243173
|
const sent = this.hub.dispatch(nodeId, buildFrame(requestId));
|
|
242665
243174
|
if (!sent) return Promise.resolve({ ok: false, code: "NODE_OFFLINE" });
|
|
242666
243175
|
return new Promise((resolve10) => {
|
|
@@ -242768,13 +243277,13 @@ function classifyPage(page, lastPushedHash, serviceAccount) {
|
|
|
242768
243277
|
if (sha(body2) === lastPushedHash) return { kind: "echo" };
|
|
242769
243278
|
return { kind: "human-edit", content: body2, updatedBy: page.updatedBy };
|
|
242770
243279
|
}
|
|
242771
|
-
var
|
|
243280
|
+
var import_node_crypto68, sha, enc3, dec, MirrorEngine, MapMirrorIdentities;
|
|
242772
243281
|
var init_engine = __esm({
|
|
242773
243282
|
"../server/src/mirror/engine.ts"() {
|
|
242774
243283
|
"use strict";
|
|
242775
|
-
|
|
243284
|
+
import_node_crypto68 = require("node:crypto");
|
|
242776
243285
|
init_src();
|
|
242777
|
-
sha = (s2) => (0,
|
|
243286
|
+
sha = (s2) => (0, import_node_crypto68.createHash)("sha256").update(s2, "utf8").digest("hex");
|
|
242778
243287
|
enc3 = (s2) => new TextEncoder().encode(s2);
|
|
242779
243288
|
dec = (b2) => new TextDecoder().decode(b2);
|
|
242780
243289
|
MirrorEngine = class {
|
|
@@ -243021,11 +243530,11 @@ function humanExitCause(exit3) {
|
|
|
243021
243530
|
const base = (exit3.reason ? label[exit3.reason] : void 0) ?? `\u4F1A\u8BDD\u5F02\u5E38\u7ED3\u675F\uFF08${exit3.reason ?? "\u65E0\u9000\u51FA\u4FE1\u606F"}\uFF09`;
|
|
243022
243531
|
return exit3.errorMessage ? `${base}\uFF1A${exit3.errorMessage.slice(0, 200)}` : base;
|
|
243023
243532
|
}
|
|
243024
|
-
var
|
|
243533
|
+
var import_node_crypto69, AUTONOMOUS_ETHOS, CONVERSATIONAL_ETHOS, SHARED_GRAPH_BODY, AUTONOMOUS_RECOVERY_TOOLS, HIGH_RISK_COMMANDS, COORDINATOR_SYSTEM_PROMPT, CONVERSATIONAL_RECOVERY_TOOLS, CONVERSATIONAL_ESCALATION_TOOLS, CONVERSATIONAL_MANAGER_BODY, MACHINE_EXIT_CODES, CoordinatorWorker;
|
|
243025
243534
|
var init_worker = __esm({
|
|
243026
243535
|
"../server/src/coordinator/worker.ts"() {
|
|
243027
243536
|
"use strict";
|
|
243028
|
-
|
|
243537
|
+
import_node_crypto69 = require("node:crypto");
|
|
243029
243538
|
init_src5();
|
|
243030
243539
|
init_identity();
|
|
243031
243540
|
AUTONOMOUS_ETHOS = `\u4F60\u662F\u8FD9\u4E2A\u5DE5\u5355\u7684**\u7BA1\u7406\u8005**\u2014\u2014\u804C\u8D23\u662F\u8BA9\u5B83\u987A\u7545\u8DD1\u5B8C\u3002\u7CFB\u7EDF\u5728\u67D0\u4E2A\u8282\u70B9\u5361\u4F4F\u3001\u673A\u68B0\u5206\u8BCA\u786E\u8BA4"\u9700\u8981\u4F60"\u65F6\u5524\u8D77\u4F60\uFF08\u65E0\u4EBA\u5728\u573A\uFF0C\u4F60\u8FD9\u4E00\u8F6E\u628A\u80FD\u505A\u7684\u505A\u6389\uFF09\u3002\u4F60\u7684\u624B\u6BB5\u5F88\u5BBD\uFF1A
|
|
@@ -243294,7 +243803,7 @@ ${HIGH_RISK_COMMANDS}`;
|
|
|
243294
243803
|
return this.deps.kernel.model.lastSeq.get(artifactId) ?? 0;
|
|
243295
243804
|
}
|
|
243296
243805
|
evaluationKey(kind, artifactId, evidence) {
|
|
243297
|
-
const fingerprint2 = (0,
|
|
243806
|
+
const fingerprint2 = (0, import_node_crypto69.createHash)("sha256").update(JSON.stringify(evidence)).digest("hex");
|
|
243298
243807
|
return `${kind}:${artifactId}:${fingerprint2}`;
|
|
243299
243808
|
}
|
|
243300
243809
|
artifactEvidence(id) {
|
|
@@ -243673,8 +244182,8 @@ ${ctx.nodeFault}
|
|
|
243673
244182
|
this.deps.log?.(`[coordinator] ${workspace} \u5168\u5C40\u4E0A\u4E0B\u6587\u8BFB\u53D6\u5931\u8D25\uFF0C\u7EE7\u7EED\u6CBF\u7528\u539F\u534F\u8C03\u8005\u4EFB\u52A1\uFF1A${String(error2)}`);
|
|
243674
244183
|
}
|
|
243675
244184
|
}
|
|
243676
|
-
const runtimeSessionId = opts?.resumeSessionId ?? (0,
|
|
243677
|
-
const coordinatorRunId = `coordinate:${(0,
|
|
244185
|
+
const runtimeSessionId = opts?.resumeSessionId ?? (0, import_node_crypto69.randomUUID)();
|
|
244186
|
+
const coordinatorRunId = `coordinate:${(0, import_node_crypto69.randomUUID)()}`;
|
|
243678
244187
|
const taskWithContext = coordinatorContext ? [
|
|
243679
244188
|
task,
|
|
243680
244189
|
``,
|
|
@@ -243718,7 +244227,7 @@ ${ctx.nodeFault}
|
|
|
243718
244227
|
const startedAtMs = Date.now();
|
|
243719
244228
|
let trajectoryStarted = false;
|
|
243720
244229
|
if (this.deps.trajectory) {
|
|
243721
|
-
const bundleManifest = Object.fromEntries(Object.entries(job.bundle.files).map(([name, content3]) => [name, (0,
|
|
244230
|
+
const bundleManifest = Object.fromEntries(Object.entries(job.bundle.files).map(([name, content3]) => [name, (0, import_node_crypto69.createHash)("sha256").update(content3).digest("hex")]));
|
|
243722
244231
|
const session = {
|
|
243723
244232
|
runId: coordinatorRunId,
|
|
243724
244233
|
runtimeSessionId,
|
|
@@ -243923,11 +244432,11 @@ var init_pg_ident = __esm({
|
|
|
243923
244432
|
});
|
|
243924
244433
|
|
|
243925
244434
|
// ../storage/src/postgres.ts
|
|
243926
|
-
var
|
|
244435
|
+
var import_node_crypto70, ident4, isUniqueViolation, PostgresOplogStore, PostgresBlobStore;
|
|
243927
244436
|
var init_postgres = __esm({
|
|
243928
244437
|
"../storage/src/postgres.ts"() {
|
|
243929
244438
|
"use strict";
|
|
243930
|
-
|
|
244439
|
+
import_node_crypto70 = require("node:crypto");
|
|
243931
244440
|
init_pg_ident();
|
|
243932
244441
|
init_esm();
|
|
243933
244442
|
init_src();
|
|
@@ -244107,7 +244616,7 @@ var init_postgres = __esm({
|
|
|
244107
244616
|
return new _PostgresBlobStore(pool, schema);
|
|
244108
244617
|
}
|
|
244109
244618
|
async put(bytes2) {
|
|
244110
|
-
const hash2 = (0,
|
|
244619
|
+
const hash2 = (0, import_node_crypto70.createHash)("sha256").update(bytes2).digest("hex");
|
|
244111
244620
|
await this.pool.query(
|
|
244112
244621
|
`INSERT INTO ${this.t} (hash, bytes, size, content_type) VALUES ($1, $2, $3, $4) ON CONFLICT (hash) DO NOTHING`,
|
|
244113
244622
|
[hash2, Buffer.from(bytes2), bytes2.byteLength, sniffContentType(bytes2) ?? null]
|
|
@@ -250504,6 +251013,20 @@ var init_postgres_chat_sessions = __esm({
|
|
|
250504
251013
|
);
|
|
250505
251014
|
return r.rows.map(rowToSessionWithQuality);
|
|
250506
251015
|
}
|
|
251016
|
+
async listSessionsByProject(projectId2) {
|
|
251017
|
+
const r = await this.pool.query(
|
|
251018
|
+
`SELECT s.*
|
|
251019
|
+
FROM ${this.s}.chat_sessions s
|
|
251020
|
+
WHERE s.company_id = $2
|
|
251021
|
+
AND s.project_id IS NOT DISTINCT FROM $1
|
|
251022
|
+
AND s.analyzed_run_id IS NULL
|
|
251023
|
+
AND s.visibility IS DISTINCT FROM 'internal'
|
|
251024
|
+
AND COALESCE(s.workspace, '') = ''
|
|
251025
|
+
ORDER BY s.created_at DESC, s.id`,
|
|
251026
|
+
[projectId2, this.companyId]
|
|
251027
|
+
);
|
|
251028
|
+
return r.rows.map(rowToSession);
|
|
251029
|
+
}
|
|
250507
251030
|
async listSessionsByAnalyzedRun(analyzedRunId) {
|
|
250508
251031
|
const r = await this.pool.query(
|
|
250509
251032
|
`SELECT s.*, lm.status AS last_assistant_status, lm.content AS last_assistant_content
|
|
@@ -252720,11 +253243,11 @@ var init_postgres_delegations = __esm({
|
|
|
252720
253243
|
});
|
|
252721
253244
|
|
|
252722
253245
|
// ../storage/src/postgres-nodes.ts
|
|
252723
|
-
var
|
|
253246
|
+
var import_node_crypto71, ident13, PostgresNodeStore, PostgresNodeTokenStore, rowToNode, rowToRuntime;
|
|
252724
253247
|
var init_postgres_nodes = __esm({
|
|
252725
253248
|
"../storage/src/postgres-nodes.ts"() {
|
|
252726
253249
|
"use strict";
|
|
252727
|
-
|
|
253250
|
+
import_node_crypto71 = require("node:crypto");
|
|
252728
253251
|
init_pg_ident();
|
|
252729
253252
|
init_esm();
|
|
252730
253253
|
ident13 = (s2) => {
|
|
@@ -252941,7 +253464,7 @@ var init_postgres_nodes = __esm({
|
|
|
252941
253464
|
return store;
|
|
252942
253465
|
}
|
|
252943
253466
|
issue(nodeId) {
|
|
252944
|
-
const token = `ont_${(0,
|
|
253467
|
+
const token = `ont_${(0, import_node_crypto71.randomBytes)(24).toString("base64url")}`;
|
|
252945
253468
|
this.cache.set(token, nodeId);
|
|
252946
253469
|
void this.pool.query(`INSERT INTO ${this.s}.node_tokens (token,node_id) VALUES ($1,$2)`, [token, nodeId]);
|
|
252947
253470
|
return token;
|
|
@@ -253207,11 +253730,11 @@ var init_postgres_type_registry = __esm({
|
|
|
253207
253730
|
});
|
|
253208
253731
|
|
|
253209
253732
|
// ../storage/src/postgres-actor-memory.ts
|
|
253210
|
-
var
|
|
253733
|
+
var import_node_crypto72, matchClause, ident15, PostgresActorMemoryStore, rowToIndexEntry, rowToRecord;
|
|
253211
253734
|
var init_postgres_actor_memory = __esm({
|
|
253212
253735
|
"../storage/src/postgres-actor-memory.ts"() {
|
|
253213
253736
|
"use strict";
|
|
253214
|
-
|
|
253737
|
+
import_node_crypto72 = require("node:crypto");
|
|
253215
253738
|
init_pg_ident();
|
|
253216
253739
|
init_src();
|
|
253217
253740
|
matchClause = (q2) => q2.requireMatch && q2.keywords.length > 0 ? " WHERE m > 0" : "";
|
|
@@ -253421,7 +253944,7 @@ var init_postgres_actor_memory = __esm({
|
|
|
253421
253944
|
}
|
|
253422
253945
|
async write(input, now) {
|
|
253423
253946
|
if (input.memId === void 0) {
|
|
253424
|
-
const memId = `mem:${(0,
|
|
253947
|
+
const memId = `mem:${(0, import_node_crypto72.randomUUID)()}`;
|
|
253425
253948
|
const r2 = await this.pool.query(
|
|
253426
253949
|
`INSERT INTO ${this.s}.actor_memories
|
|
253427
253950
|
(mem_id, actor_id, project_id, keywords, content, version, created_at, updated_at, accessed_at, source_artifact_id, source_session_id)
|
|
@@ -254868,14 +255391,14 @@ function companySchemaName(companyId) {
|
|
|
254868
255391
|
if (typeof companyId !== "string" || !companyId.trim()) {
|
|
254869
255392
|
throw new Error("company schema mapping \u9700\u8981\u975E\u7A7A companyId\uFF08fail-closed\uFF1A\u4E0D\u56DE\u9000\u9ED8\u8BA4\u516C\u53F8\uFF09");
|
|
254870
255393
|
}
|
|
254871
|
-
const hex = (0,
|
|
255394
|
+
const hex = (0, import_node_crypto73.createHash)("sha256").update(companyId, "utf8").digest("hex");
|
|
254872
255395
|
return `${COMPANY_SCHEMA_PREFIX}${hex.slice(0, DIGEST_HEX_LEN)}`;
|
|
254873
255396
|
}
|
|
254874
|
-
var
|
|
255397
|
+
var import_node_crypto73, COMPANY_SCHEMA_PREFIX, DIGEST_HEX_LEN, SchemaMappingConflictError, TenantStorageLocationStore;
|
|
254875
255398
|
var init_tenant_schema_mapping = __esm({
|
|
254876
255399
|
"../storage/src/tenant-schema-mapping.ts"() {
|
|
254877
255400
|
"use strict";
|
|
254878
|
-
|
|
255401
|
+
import_node_crypto73 = require("node:crypto");
|
|
254879
255402
|
init_esm();
|
|
254880
255403
|
init_pg_ident();
|
|
254881
255404
|
COMPANY_SCHEMA_PREFIX = "c_";
|
|
@@ -254949,7 +255472,7 @@ var init_tenant_schema_mapping = __esm({
|
|
|
254949
255472
|
|
|
254950
255473
|
// ../storage/src/company-data-plane-schema.ts
|
|
254951
255474
|
function canonicalTypeDefHash(def) {
|
|
254952
|
-
return `sha256:${(0,
|
|
255475
|
+
return `sha256:${(0, import_node_crypto74.createHash)("sha256").update(JSON.stringify(def), "utf8").digest("hex")}`;
|
|
254953
255476
|
}
|
|
254954
255477
|
function defaultArtifactTypeTemplate() {
|
|
254955
255478
|
return [
|
|
@@ -255131,11 +255654,11 @@ async function seedDefaultArtifactTypes(pool, schema, templates = defaultArtifac
|
|
|
255131
255654
|
}
|
|
255132
255655
|
return { inserted };
|
|
255133
255656
|
}
|
|
255134
|
-
var
|
|
255657
|
+
var import_node_crypto74, DEFAULT_ARTIFACT_TYPE_TEMPLATE_VERSION;
|
|
255135
255658
|
var init_company_data_plane_schema = __esm({
|
|
255136
255659
|
"../storage/src/company-data-plane-schema.ts"() {
|
|
255137
255660
|
"use strict";
|
|
255138
|
-
|
|
255661
|
+
import_node_crypto74 = require("node:crypto");
|
|
255139
255662
|
init_esm();
|
|
255140
255663
|
init_pg_ident();
|
|
255141
255664
|
DEFAULT_ARTIFACT_TYPE_TEMPLATE_VERSION = "4c368e5c-types-v1";
|
|
@@ -255215,11 +255738,11 @@ function rowToFile2(row) {
|
|
|
255215
255738
|
updatedAt: new Date(row.updated_at).toISOString()
|
|
255216
255739
|
};
|
|
255217
255740
|
}
|
|
255218
|
-
var
|
|
255741
|
+
var import_node_crypto75, COMPANY_CONFLICT_MSG, CompanyIdentifierConflictError, CompanyOwnedRegistryStore;
|
|
255219
255742
|
var init_company_owned_registry_store = __esm({
|
|
255220
255743
|
"../storage/src/company-owned-registry-store.ts"() {
|
|
255221
255744
|
"use strict";
|
|
255222
|
-
|
|
255745
|
+
import_node_crypto75 = require("node:crypto");
|
|
255223
255746
|
init_esm();
|
|
255224
255747
|
init_src();
|
|
255225
255748
|
init_pg_ident();
|
|
@@ -255605,7 +256128,7 @@ var init_company_owned_registry_store = __esm({
|
|
|
255605
256128
|
enabled: skill.enabled,
|
|
255606
256129
|
files: files.map((f2) => ({ path: f2.path, blobHash: f2.blobHash }))
|
|
255607
256130
|
});
|
|
255608
|
-
return (0,
|
|
256131
|
+
return (0, import_node_crypto75.createHash)("sha256").update(body2).digest("hex");
|
|
255609
256132
|
}
|
|
255610
256133
|
};
|
|
255611
256134
|
}
|
|
@@ -258202,7 +258725,7 @@ function sourceSetConservation(input) {
|
|
|
258202
258725
|
return input.sourceFinal === input.copied + input.approvedRuntimeConversion + input.approvedArchive + input.approvedDiscard;
|
|
258203
258726
|
}
|
|
258204
258727
|
function payloadChecksum(value2) {
|
|
258205
|
-
return (0,
|
|
258728
|
+
return (0, import_node_crypto76.createHash)("sha256").update(JSON.stringify(value2)).digest("hex");
|
|
258206
258729
|
}
|
|
258207
258730
|
async function copyWorkorderDraftsIdempotent(pool, companyId, companySchema, manifestId, opts) {
|
|
258208
258731
|
const cs = quoteIdent2(companySchema);
|
|
@@ -258590,11 +259113,11 @@ async function copyTraceFamilyIdempotent(pool, companyId, companySchema, manifes
|
|
|
258590
259113
|
sequences
|
|
258591
259114
|
};
|
|
258592
259115
|
}
|
|
258593
|
-
var
|
|
259116
|
+
var import_node_crypto76, MissingInstallerActorsError, TypeCatalogNotCoveredError, ORG_REGISTRY_TABLES, TRACE_FAMILY;
|
|
258594
259117
|
var init_tenant_migration_operator = __esm({
|
|
258595
259118
|
"../storage/src/tenant-migration-operator.ts"() {
|
|
258596
259119
|
"use strict";
|
|
258597
|
-
|
|
259120
|
+
import_node_crypto76 = require("node:crypto");
|
|
258598
259121
|
init_esm();
|
|
258599
259122
|
init_pg_ident();
|
|
258600
259123
|
init_tenancy_attribution();
|
|
@@ -258826,8 +259349,8 @@ var init_tenant_new_company_provision = __esm({
|
|
|
258826
259349
|
// ../storage/src/knowledge-snapshot-crypto.ts
|
|
258827
259350
|
function sealSnapshot(snapshot, key) {
|
|
258828
259351
|
if (snapshot.content.startsWith(PREFIX3)) return structuredClone(snapshot);
|
|
258829
|
-
const iv = (0,
|
|
258830
|
-
const cipher = (0,
|
|
259352
|
+
const iv = (0, import_node_crypto77.randomBytes)(12);
|
|
259353
|
+
const cipher = (0, import_node_crypto77.createCipheriv)("aes-256-gcm", bytes(key), iv);
|
|
258831
259354
|
cipher.setAAD(aad2(snapshot));
|
|
258832
259355
|
const encrypted = Buffer.concat([cipher.update(snapshot.content, "utf8"), cipher.final()]);
|
|
258833
259356
|
return { ...structuredClone(snapshot), content: `${PREFIX3}${iv.toString("base64url")}.${cipher.getAuthTag().toString("base64url")}.${encrypted.toString("base64url")}` };
|
|
@@ -258837,7 +259360,7 @@ function openSnapshot(snapshot, key) {
|
|
|
258837
259360
|
const packed = snapshot.content.slice(PREFIX3.length).split(".");
|
|
258838
259361
|
if (packed.length !== 3 || packed.some((part) => !part)) throw new Error(`knowledge snapshot ${snapshot.ref} ciphertext is malformed`);
|
|
258839
259362
|
const [iv, tag, data] = packed;
|
|
258840
|
-
const decipher = (0,
|
|
259363
|
+
const decipher = (0, import_node_crypto77.createDecipheriv)("aes-256-gcm", bytes(key), Buffer.from(iv, "base64url"));
|
|
258841
259364
|
decipher.setAAD(aad2(snapshot));
|
|
258842
259365
|
decipher.setAuthTag(Buffer.from(tag, "base64url"));
|
|
258843
259366
|
return {
|
|
@@ -258845,11 +259368,11 @@ function openSnapshot(snapshot, key) {
|
|
|
258845
259368
|
content: Buffer.concat([decipher.update(Buffer.from(data, "base64url")), decipher.final()]).toString("utf8")
|
|
258846
259369
|
};
|
|
258847
259370
|
}
|
|
258848
|
-
var
|
|
259371
|
+
var import_node_crypto77, PREFIX3, bytes, aad2;
|
|
258849
259372
|
var init_knowledge_snapshot_crypto = __esm({
|
|
258850
259373
|
"../storage/src/knowledge-snapshot-crypto.ts"() {
|
|
258851
259374
|
"use strict";
|
|
258852
|
-
|
|
259375
|
+
import_node_crypto77 = require("node:crypto");
|
|
258853
259376
|
PREFIX3 = "oasis-knowledge:v1:";
|
|
258854
259377
|
bytes = (key) => {
|
|
258855
259378
|
const value2 = Buffer.from(key);
|
|
@@ -260921,7 +261444,7 @@ var init_src11 = __esm({
|
|
|
260921
261444
|
init_experiments2();
|
|
260922
261445
|
init_trace2();
|
|
260923
261446
|
init_execution_continuity2();
|
|
260924
|
-
|
|
261447
|
+
init_chat_sessions2();
|
|
260925
261448
|
init_dev_store();
|
|
260926
261449
|
init_continuation3();
|
|
260927
261450
|
init_knowledge2();
|
|
@@ -261096,20 +261619,20 @@ var fs45 = __toESM(require("node:fs"));
|
|
|
261096
261619
|
var os14 = __toESM(require("node:os"));
|
|
261097
261620
|
var path40 = __toESM(require("node:path"));
|
|
261098
261621
|
var import_node_child_process23 = require("node:child_process");
|
|
261099
|
-
var
|
|
261622
|
+
var import_node_crypto84 = require("node:crypto");
|
|
261100
261623
|
|
|
261101
261624
|
// ../cli/src/cli.ts
|
|
261102
261625
|
var fs40 = __toESM(require("node:fs"), 1);
|
|
261103
261626
|
var os12 = __toESM(require("node:os"), 1);
|
|
261104
261627
|
var path35 = __toESM(require("node:path"), 1);
|
|
261105
|
-
var
|
|
261628
|
+
var import_node_crypto82 = require("node:crypto");
|
|
261106
261629
|
|
|
261107
261630
|
// ../cli/src/serve.ts
|
|
261108
261631
|
var fs34 = __toESM(require("node:fs"), 1);
|
|
261109
261632
|
var os8 = __toESM(require("node:os"), 1);
|
|
261110
261633
|
var path29 = __toESM(require("node:path"), 1);
|
|
261111
261634
|
var import_node_child_process18 = require("node:child_process");
|
|
261112
|
-
var
|
|
261635
|
+
var import_node_crypto78 = require("node:crypto");
|
|
261113
261636
|
var import_node_url7 = require("node:url");
|
|
261114
261637
|
|
|
261115
261638
|
// ../cli/src/artifact-discovery-source.ts
|
|
@@ -261326,6 +261849,54 @@ function buildChatTurnPrompts(input) {
|
|
|
261326
261849
|
};
|
|
261327
261850
|
}
|
|
261328
261851
|
|
|
261852
|
+
// ../cli/src/chat-task-md.ts
|
|
261853
|
+
var CHAT_PROJECT_SECTION_TITLE = "## \u5F53\u524D\u9879\u76EE\uFF08\u4EE5\u672C\u8F6E\u4E3A\u51C6\uFF09";
|
|
261854
|
+
var CHAT_PROJECT_INPUTS_POINTER = [
|
|
261855
|
+
"",
|
|
261856
|
+
"## \u5F53\u524D\u9879\u76EE\u516C\u5F00\u8F93\u5165",
|
|
261857
|
+
"",
|
|
261858
|
+
"\u751F\u6210 Brief \u524D\u5FC5\u987B\u5148\u8BFB\u53D6 `PROJECT_CONTEXT.md` \u53CA\u5176\u4E2D\u5217\u51FA\u7684 `project/` \u6587\u4EF6\uFF1B\u4ED3\u5E93\u7B49\u5916\u90E8\u4F4D\u7F6E\u4E5F\u8BB0\u5F55\u5728\u8BE5\u6587\u4EF6\u4E2D\u3002"
|
|
261859
|
+
];
|
|
261860
|
+
function buildChatProjectSection(project, opts) {
|
|
261861
|
+
if (project.state === "unknown") return [];
|
|
261862
|
+
if (project.state === "none") {
|
|
261863
|
+
return opts.announceNone ? [CHAT_PROJECT_SECTION_TITLE, "", "\u672C\u5BF9\u8BDD\u672A\u5F52\u5C5E\u4EFB\u4F55\u9879\u76EE\u3002"] : [];
|
|
261864
|
+
}
|
|
261865
|
+
const description = project.description?.trim();
|
|
261866
|
+
const descriptionLines = !description ? ["\u9879\u76EE\u63CF\u8FF0: \uFF08\u672A\u586B\u5199\uFF09"] : description.includes("\n") ? ["\u9879\u76EE\u63CF\u8FF0:", description] : [`\u9879\u76EE\u63CF\u8FF0: ${description}`];
|
|
261867
|
+
return [
|
|
261868
|
+
CHAT_PROJECT_SECTION_TITLE,
|
|
261869
|
+
"",
|
|
261870
|
+
`project_id: ${project.id}`,
|
|
261871
|
+
`\u9879\u76EE\u540D\u79F0: ${project.name}`,
|
|
261872
|
+
...descriptionLines
|
|
261873
|
+
];
|
|
261874
|
+
}
|
|
261875
|
+
function buildChatTaskMd(p2) {
|
|
261876
|
+
return [
|
|
261877
|
+
...p2.headerLines,
|
|
261878
|
+
// 项目段紧跟抬头:这一轮在哪个项目里,是读后面所有内容的前提。
|
|
261879
|
+
...p2.projectSection.length ? ["", ...p2.projectSection] : [],
|
|
261880
|
+
...p2.attachmentPaths.length ? ["", "## \u7528\u6237\u9644\u4EF6", "", "\u7528\u6237\u968F\u6D88\u606F\u9644\u5E26\u4E86\u4EE5\u4E0B\u6587\u4EF6\uFF08\u5728\u4F60\u7684\u5DE5\u4F5C\u76EE\u5F55\u4E0B\uFF0C\u53EF\u76F4\u63A5\u8BFB\u53D6\uFF09\uFF1A", ...p2.attachmentPaths.map((x2) => `- ${x2}`)] : [],
|
|
261881
|
+
// 委派子会话的主会话对话快照(提案 §6.1.4):一句固定说明 + 一份清单;没有这个文件时整段不拼。
|
|
261882
|
+
// 指针与文件由 delegationBundleAdditions **一处**给出,拆开迟早漂成「有指针没文件」。
|
|
261883
|
+
...p2.parentConversationLines,
|
|
261884
|
+
// 委派两条路搬过来的文件(去程 `--file` / 回程专家产物):**不能复用「## 用户附件」的措辞**
|
|
261885
|
+
// (专家的产物会被介绍成用户附带的)。
|
|
261886
|
+
...p2.workspaceLines,
|
|
261887
|
+
...p2.projectInputsPointer,
|
|
261888
|
+
// 诊断 1be339c7:身份段紧贴在「## 用户消息」之前——让 agent 先知道「你在跟谁说话」,再读那条消息。
|
|
261889
|
+
...p2.whoLines.length ? ["", ...p2.whoLines] : [],
|
|
261890
|
+
"",
|
|
261891
|
+
"## \u7528\u6237\u6D88\u606F",
|
|
261892
|
+
"",
|
|
261893
|
+
p2.message,
|
|
261894
|
+
...p2.memoryLines,
|
|
261895
|
+
// 压在最末:这条要盖住紧邻其上的「收工前想一下」,否则记忆写入就落到正文之后(见常量注释)。
|
|
261896
|
+
...p2.finalReplyLines
|
|
261897
|
+
].join("\n");
|
|
261898
|
+
}
|
|
261899
|
+
|
|
261329
261900
|
// ../cli/src/company-dispatch-bridge.ts
|
|
261330
261901
|
var CompanyDispatchBridges = class {
|
|
261331
261902
|
constructor(opts) {
|
|
@@ -261802,11 +262373,12 @@ init_src10();
|
|
|
261802
262373
|
init_src11();
|
|
261803
262374
|
init_src11();
|
|
261804
262375
|
init_src11();
|
|
262376
|
+
init_src11();
|
|
261805
262377
|
init_src9();
|
|
261806
262378
|
init_src();
|
|
261807
262379
|
init_trajectory();
|
|
261808
262380
|
function deterministicUuid2(seed) {
|
|
261809
|
-
const h = (0,
|
|
262381
|
+
const h = (0, import_node_crypto78.createHash)("sha256").update(seed).digest();
|
|
261810
262382
|
const b2 = Buffer.from(h.subarray(0, 16));
|
|
261811
262383
|
b2[6] = b2[6] & 15 | 80;
|
|
261812
262384
|
b2[8] = b2[8] & 63 | 128;
|
|
@@ -262006,7 +262578,7 @@ function oasisWrapperScript() {
|
|
|
262006
262578
|
const repoRoot = (0, import_node_url7.fileURLToPath)(new URL("../../../", __esm_import_meta_url));
|
|
262007
262579
|
const tsx = path29.join(repoRoot, "node_modules/.bin/tsx");
|
|
262008
262580
|
const main = path29.join(repoRoot, "packages/cli/src/main.ts");
|
|
262009
|
-
const key = (0,
|
|
262581
|
+
const key = (0, import_node_crypto78.createHash)("sha256").update(repoRoot).digest("hex").slice(0, 12);
|
|
262010
262582
|
const uid = typeof process.getuid === "function" ? process.getuid() : "na";
|
|
262011
262583
|
const stable = path29.join(os8.tmpdir(), `oasis-cli-wrapper-${uid}-${key}`);
|
|
262012
262584
|
let dir;
|
|
@@ -262387,7 +262959,7 @@ async function startServe(opts) {
|
|
|
262387
262959
|
if (!hub) return Promise.resolve({ ok: false, reason: "\u672C\u8FDB\u7A0B\u6CA1\u6709\u8282\u70B9\u7F51\u5173" });
|
|
262388
262960
|
const online = hub.connectedDaemons().some((d) => d.daemonId === nodeId);
|
|
262389
262961
|
if (!online) return Promise.resolve({ ok: false, reason: "\u8282\u70B9\u5F53\u524D\u4E0D\u5728\u7EBF\uFF0C\u7528\u7684\u662F\u5B83\u4E0A\u6B21\u62A5\u7684\u6E05\u5355" });
|
|
262390
|
-
const requestId = (0,
|
|
262962
|
+
const requestId = (0, import_node_crypto78.randomUUID)();
|
|
262391
262963
|
const task = new Promise((resolve10) => {
|
|
262392
262964
|
const timer = setTimeout(() => {
|
|
262393
262965
|
modelRefreshWaiters.delete(requestId);
|
|
@@ -262696,6 +263268,15 @@ async function startServe(opts) {
|
|
|
262696
263268
|
const members = await listCompanyMembers(companyId);
|
|
262697
263269
|
return members.find((m2) => m2.actorId === actorId)?.role;
|
|
262698
263270
|
},
|
|
263271
|
+
// 项目「关联对话」列表与对话改挂项目(2026-09-14)。闭包在请求时才读 chatStoreFor /
|
|
263272
|
+
// delegationStoreFor,避开它们在下方声明的 TDZ(与 listChatFiles 同法)。
|
|
263273
|
+
chatSessionsFor: (companyId) => chatStoreFor(companyId),
|
|
263274
|
+
// 委派子会话不进项目(ADR 0555);一次台账查询批量判,不逐条点查。
|
|
263275
|
+
delegationChildIds: async (companyId, sessionIds) => {
|
|
263276
|
+
const ledger = await delegationStoreFor(companyId).catch(() => null);
|
|
263277
|
+
if (!ledger) return /* @__PURE__ */ new Set();
|
|
263278
|
+
return new Set(await ledger.listChildSessionIds(sessionIds));
|
|
263279
|
+
},
|
|
262699
263280
|
resolveActorContext: (actorId) => buildActorContext(actors.service, actorId),
|
|
262700
263281
|
defaultBranchResolver,
|
|
262701
263282
|
// 展示:GET content-locations 给 git 仓补 resolvedDefaultBranch
|
|
@@ -263130,7 +263711,7 @@ async function startServe(opts) {
|
|
|
263130
263711
|
const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
263131
263712
|
if (buf || session.runId) {
|
|
263132
263713
|
await turnStore.appendMessage({
|
|
263133
|
-
id: (0,
|
|
263714
|
+
id: (0, import_node_crypto78.randomUUID)(),
|
|
263134
263715
|
sessionId: chatSessionId,
|
|
263135
263716
|
role: "assistant",
|
|
263136
263717
|
content: buf,
|
|
@@ -263176,7 +263757,7 @@ async function startServe(opts) {
|
|
|
263176
263757
|
chatTargets: {
|
|
263177
263758
|
inspect: inspectChatTarget,
|
|
263178
263759
|
createTargetSession: async ({ companyId, agentId, ownerHumanActorId, title }) => {
|
|
263179
|
-
const sessionId = (0,
|
|
263760
|
+
const sessionId = (0, import_node_crypto78.randomUUID)();
|
|
263180
263761
|
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
263181
263762
|
const binding = await registryStore.getBinding(agentId).catch(() => null);
|
|
263182
263763
|
await (await chatStoreFor(companyId)).createSession({
|
|
@@ -263651,6 +264232,7 @@ async function startServe(opts) {
|
|
|
263651
264232
|
};
|
|
263652
264233
|
const readMarkerStoreFor = async (companyId) => pgPool && companyId ? (await openCompanyPlane(companyId)).readMarkers : readMarkerStore;
|
|
263653
264234
|
const fileNotificationStore = pgPool ? void 0 : new MemoryNotificationStore(path29.join(opts.dir, "notifications.json"));
|
|
264235
|
+
const notificationLedgerEnabled = process.env["OASIS_NOTIFICATION_LEDGER"] !== "off";
|
|
263654
264236
|
const notificationStoreFor = async (companyId) => pgPool ? (await openCompanyPlane(companyId ?? defaultCompanyId)).notifications : fileNotificationStore;
|
|
263655
264237
|
const actorMemoryFor = async (companyId) => pgPool && companyId ? (await openCompanyPlane(companyId)).memory : actorMemoryService;
|
|
263656
264238
|
const workorderDraftsFor = async (companyId) => pgPool && companyId ? (await openCompanyPlane(companyId)).drafts : workorderDrafts;
|
|
@@ -264220,7 +264802,7 @@ async function startServe(opts) {
|
|
|
264220
264802
|
}));
|
|
264221
264803
|
}
|
|
264222
264804
|
const limits = { wallClockMs: wallClockForKind("planner") };
|
|
264223
|
-
const artifactId = `artifact:planner:${(0,
|
|
264805
|
+
const artifactId = `artifact:planner:${(0, import_node_crypto78.randomUUID)()}`;
|
|
264224
264806
|
const handle = await chatRemoteAdapter.spawn({
|
|
264225
264807
|
actor: planner.id,
|
|
264226
264808
|
// companyId 同协调者:planner 用的就是默认公司的 actors 服务,漏签会让它一调公司域端点就 404。
|
|
@@ -264395,7 +264977,7 @@ async function startServe(opts) {
|
|
|
264395
264977
|
readMarkers: readMarkerStore,
|
|
264396
264978
|
// bundle=`inbox`:水位按当前公司取(与上面 resolveChatSession 成对)。
|
|
264397
264979
|
...pgPool ? { resolveReadMarkers: readMarkerStoreFor } : {},
|
|
264398
|
-
resolveNotificationLedger: notificationStoreFor,
|
|
264980
|
+
...notificationLedgerEnabled ? { resolveNotificationLedger: notificationStoreFor } : {},
|
|
264399
264981
|
escalationReminders: escalationDelivery.policy,
|
|
264400
264982
|
defaultCompanyId,
|
|
264401
264983
|
// 工单标签词表(组织级受控、旁账,与 playbook-overrides 同款侧存)。
|
|
@@ -265122,10 +265704,10 @@ async function startServe(opts) {
|
|
|
265122
265704
|
if (isDeletedActor(dispatchTarget)) {
|
|
265123
265705
|
throw new ApiError(409, ACTOR_DELETED_ERROR_CODE, ACTOR_DELETED_CHAT_MESSAGE);
|
|
265124
265706
|
}
|
|
265125
|
-
const runtimeSessionId = sessionId ?? (requestDispatchId ? deterministicUuid2(`chat-runtime:${requestDispatchId}`) : (0,
|
|
265707
|
+
const runtimeSessionId = sessionId ?? (requestDispatchId ? deterministicUuid2(`chat-runtime:${requestDispatchId}`) : (0, import_node_crypto78.randomUUID)());
|
|
265126
265708
|
const resumeRuntimeSession = Boolean(sessionId);
|
|
265127
|
-
const traceRunId = requestDispatchId ? `chat-run:${deterministicUuid2(`chat-trace:${requestDispatchId}`)}` : `chat-run:${(0,
|
|
265128
|
-
const artifactId = requestDispatchId ? `artifact:chat:${deterministicUuid2(`chat-artifact:${requestDispatchId}`)}` : `artifact:chat:${(0,
|
|
265709
|
+
const traceRunId = requestDispatchId ? `chat-run:${deterministicUuid2(`chat-trace:${requestDispatchId}`)}` : `chat-run:${(0, import_node_crypto78.randomUUID)()}`;
|
|
265710
|
+
const artifactId = requestDispatchId ? `artifact:chat:${deterministicUuid2(`chat-artifact:${requestDispatchId}`)}` : `artifact:chat:${(0, import_node_crypto78.randomUUID)()}`;
|
|
265129
265711
|
let stableDispatch = requestDispatchId ? await resolveStableChatDispatch({ store: await traceStoreFor(runCompanyId), runId: traceRunId }) : null;
|
|
265130
265712
|
if (stableDispatch && !stableDispatch.shouldDispatch) {
|
|
265131
265713
|
return {
|
|
@@ -265189,7 +265771,11 @@ async function startServe(opts) {
|
|
|
265189
265771
|
}
|
|
265190
265772
|
}
|
|
265191
265773
|
}
|
|
265192
|
-
const
|
|
265774
|
+
const turnChatStore = chatSessionId ? await chatStoreFor(runCompanyId).catch((err) => {
|
|
265775
|
+
console.warn(`[chat] \u53D6\u516C\u53F8 ${runCompanyId} \u7684\u4F1A\u8BDD\u5B58\u50A8\u5931\u8D25\uFF08\u672C\u8F6E\u6309\u65E0\u4F1A\u8BDD\u8BB0\u5F55\u5904\u7406\uFF09: ${String(err)}`);
|
|
265776
|
+
return null;
|
|
265777
|
+
}) : null;
|
|
265778
|
+
const analyzedRunId = chatSessionId ? (await turnChatStore?.getSession(chatSessionId).catch(() => null))?.analyzedRunId ?? void 0 : void 0;
|
|
265193
265779
|
const actorConfigVersion = await actorService.latestConfig(actorId).then((c) => c?.version ?? null).catch(() => null);
|
|
265194
265780
|
const candidateTraceStartedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
265195
265781
|
const traceCreateInput = (target, startedAt) => ({
|
|
@@ -265243,7 +265829,7 @@ async function startServe(opts) {
|
|
|
265243
265829
|
requireNodeConnectors();
|
|
265244
265830
|
}
|
|
265245
265831
|
}
|
|
265246
|
-
const priorChatSession = chatSessionId ? await
|
|
265832
|
+
const priorChatSession = chatSessionId ? await turnChatStore?.getSession(chatSessionId).catch(() => null) : null;
|
|
265247
265833
|
const freshChatWorkdir = chatSessionId ? chatNodeChanged(
|
|
265248
265834
|
{ nodeId: priorChatSession?.runtimeId, runtimeKind: priorChatSession?.runtimeKind },
|
|
265249
265835
|
{ nodeId: binding.nodeId, runtimeKind: binding.runtimeKind }
|
|
@@ -265301,17 +265887,19 @@ async function startServe(opts) {
|
|
|
265301
265887
|
const attachmentFiles = { ...preparedAttachments.files };
|
|
265302
265888
|
const attachmentBinary = { ...preparedAttachments.binaryFiles };
|
|
265303
265889
|
const attachmentPaths = [...preparedAttachments.paths];
|
|
265304
|
-
let
|
|
265890
|
+
let turnProject = priorChatSession ? { state: "none" } : { state: "unknown" };
|
|
265305
265891
|
if (priorChatSession?.projectId) {
|
|
265306
|
-
const
|
|
265307
|
-
|
|
265308
|
-
|
|
265309
|
-
|
|
265310
|
-
)
|
|
265892
|
+
const projectId2 = priorChatSession.projectId;
|
|
265893
|
+
const projectBundle = await projectStateFor(runCompanyId).then((projects) => buildChatProjectBundle(projectId2, projects, (blobId) => assets.get(blobId))).catch((err) => {
|
|
265894
|
+
console.warn(`[chat] \u8BFB\u9879\u76EE ${projectId2} \u5931\u8D25\uFF08\u672C\u8F6E\u4E0D\u5199\u9879\u76EE\u6BB5\uFF09: ${String(err)}`);
|
|
265895
|
+
return void 0;
|
|
265896
|
+
});
|
|
265311
265897
|
if (projectBundle) {
|
|
265312
265898
|
Object.assign(attachmentFiles, projectBundle.files);
|
|
265313
265899
|
Object.assign(attachmentBinary, projectBundle.binaryFiles);
|
|
265314
|
-
|
|
265900
|
+
turnProject = { state: "bound", ...projectBundle.project };
|
|
265901
|
+
} else if (projectBundle === void 0) {
|
|
265902
|
+
turnProject = { state: "unknown" };
|
|
265315
265903
|
}
|
|
265316
265904
|
}
|
|
265317
265905
|
const sessionLine = chatSessionId ? `chat_session_id: ${chatSessionId}` : `runtime_session_id: ${runtimeSessionId}`;
|
|
@@ -265334,29 +265922,21 @@ async function startServe(opts) {
|
|
|
265334
265922
|
const chatMemoryLines = chatMemorySvc ? await chatMemorySvc.list({ actorId }, { scope: "all", keywords: ngramQueryTerms([message]), limit: MEMORY_INJECT_MAX, offset: 0 }).then((out) => [...memoryIndexLines(out.items), ...memoryHowToLines()]).catch(() => []) : [];
|
|
265335
265923
|
const parentConversationBundle = delegationBundleAdditions(parentConversationSnapshot);
|
|
265336
265924
|
const files = {
|
|
265337
|
-
"TASK.md":
|
|
265338
|
-
|
|
265339
|
-
|
|
265340
|
-
//
|
|
265341
|
-
|
|
265342
|
-
|
|
265343
|
-
|
|
265344
|
-
|
|
265345
|
-
|
|
265346
|
-
|
|
265347
|
-
|
|
265348
|
-
...workspaceBundle?.taskLines ?? [],
|
|
265349
|
-
...projectContextLines.length ? ["", "## \u5F53\u524D\u9879\u76EE\u516C\u5F00\u8F93\u5165", "", "\u751F\u6210 Brief \u524D\u5FC5\u987B\u5148\u8BFB\u53D6 `PROJECT_CONTEXT.md` \u53CA\u5176\u4E2D\u5217\u51FA\u7684 `project/` \u6587\u4EF6\uFF1B\u4ED3\u5E93\u7B49\u5916\u90E8\u4F4D\u7F6E\u4E5F\u8BB0\u5F55\u5728\u8BE5\u6587\u4EF6\u4E2D\u3002"] : [],
|
|
265350
|
-
// 诊断 1be339c7:身份段紧贴在「## 用户消息」之前——让 agent 先知道「你在跟谁说话」,再读那条消息。
|
|
265351
|
-
...whoLines.length ? ["", ...whoLines] : [],
|
|
265352
|
-
"",
|
|
265353
|
-
"## \u7528\u6237\u6D88\u606F",
|
|
265354
|
-
"",
|
|
265925
|
+
"TASK.md": buildChatTaskMd({
|
|
265926
|
+
headerLines: taskHeader,
|
|
265927
|
+
// 「未归属」只对普通对话说:挂在工单上的对话(协调者 / 上报讨论房)项目看工单绑定,
|
|
265928
|
+
// 委派子会话建出来本就不带项目;知识库单轮受限生成连抬头都是另一套。
|
|
265929
|
+
projectSection: isolatedKnowledgeTurn ? [] : buildChatProjectSection(turnProject, { announceNone: !workspace && !delegatedChildTurn }),
|
|
265930
|
+
attachmentPaths,
|
|
265931
|
+
parentConversationLines: parentConversationBundle.taskLines,
|
|
265932
|
+
workspaceLines: workspaceBundle?.taskLines ?? [],
|
|
265933
|
+
// 项目公开输入指针:文字、位置、出现条件(查到了项目)都与改动前一致。
|
|
265934
|
+
projectInputsPointer: turnProject.state === "bound" ? CHAT_PROJECT_INPUTS_POINTER : [],
|
|
265935
|
+
whoLines,
|
|
265355
265936
|
message,
|
|
265356
|
-
|
|
265357
|
-
|
|
265358
|
-
|
|
265359
|
-
].join("\n")
|
|
265937
|
+
memoryLines: chatMemoryLines,
|
|
265938
|
+
finalReplyLines: isolatedKnowledgeTurn ? [] : chatFinalReplyRule({ memoryEnabled: chatMemoryEnabled })
|
|
265939
|
+
})
|
|
265360
265940
|
};
|
|
265361
265941
|
Object.assign(files, attachmentFiles);
|
|
265362
265942
|
Object.assign(files, parentConversationBundle.files);
|
|
@@ -265472,6 +266052,8 @@ async function startServe(opts) {
|
|
|
265472
266052
|
handle.onLiveEvent?.((event) => {
|
|
265473
266053
|
if (liveEventCbs.length === 0) bufferedLiveEvents.push(event);
|
|
265474
266054
|
for (const cb of liveEventCbs) cb(event);
|
|
266055
|
+
const subagentEvent = subagentRunEventFromLive(event);
|
|
266056
|
+
if (subagentEvent) enqueueTrace(() => traceAppender.append([subagentEvent]).then(() => void 0));
|
|
265475
266057
|
});
|
|
265476
266058
|
let capturedNativeSessionId;
|
|
265477
266059
|
const done = new Promise((resolve10, reject) => {
|
|
@@ -265498,6 +266080,7 @@ async function startServe(opts) {
|
|
|
265498
266080
|
durationMs: durationMs3,
|
|
265499
266081
|
exitCode: info.code,
|
|
265500
266082
|
exitReason: info.reason ?? null,
|
|
266083
|
+
...!isHealthySessionExit(info) && info.reason !== "cancelled" ? { errorCode: info.reason ?? "error", errorMessage: formatExitError(info) } : {},
|
|
265501
266084
|
transcriptRef: info.transcriptRef ?? null,
|
|
265502
266085
|
usage,
|
|
265503
266086
|
effectiveModel,
|
|
@@ -266251,7 +266834,7 @@ async function startServe(opts) {
|
|
|
266251
266834
|
console.log(`[new-engine] dispatchWork ${workId} \u662F human work\u2014\u2014\u4E0D\u6D3E runtime\uFF0C\u7B49\u5F85\u4EBA\u5DE5\u5904\u7406`);
|
|
266252
266835
|
return;
|
|
266253
266836
|
}
|
|
266254
|
-
const ledgerId = `dispatch:${(0,
|
|
266837
|
+
const ledgerId = `dispatch:${(0, import_node_crypto78.randomUUID)()}`;
|
|
266255
266838
|
try {
|
|
266256
266839
|
await (await dispatchLedgerFor(companyId)).insertOpen({
|
|
266257
266840
|
id: ledgerId,
|
|
@@ -266336,7 +266919,7 @@ async function startServe(opts) {
|
|
|
266336
266919
|
const kernelModel = newKernel.model;
|
|
266337
266920
|
const art = kernelModel.artifacts.get(nodeId);
|
|
266338
266921
|
const revWid = art?.workspace ?? "";
|
|
266339
|
-
const ledgerId = `dispatch:${(0,
|
|
266922
|
+
const ledgerId = `dispatch:${(0, import_node_crypto78.randomUUID)()}`;
|
|
266340
266923
|
try {
|
|
266341
266924
|
await (await dispatchLedgerFor(companyId)).insertOpen({
|
|
266342
266925
|
id: ledgerId,
|
|
@@ -266714,7 +267297,7 @@ async function startServe(opts) {
|
|
|
266714
267297
|
resolveSupplementalContext: server.knowledgeGovernance ? async ({ actorId, artifactId, workOrderId, action, part, runtimeKind, taskMarkdown }) => {
|
|
266715
267298
|
try {
|
|
266716
267299
|
const governance = server.knowledgeGovernance;
|
|
266717
|
-
const taskFingerprint = (0,
|
|
267300
|
+
const taskFingerprint = (0, import_node_crypto78.createHash)("sha256").update(JSON.stringify({ artifactId, workOrderId, action, part: part ?? null, taskMarkdown })).digest("hex");
|
|
266718
267301
|
const requestContext = {
|
|
266719
267302
|
organizationId: companyId,
|
|
266720
267303
|
actorId,
|
|
@@ -267202,28 +267785,28 @@ async function startServe(opts) {
|
|
|
267202
267785
|
const isDefault = cid === defaultCompanyId;
|
|
267203
267786
|
const cacheKey = `${cid}::${workspace}`;
|
|
267204
267787
|
if (initiatorCache.has(cacheKey)) return initiatorCache.get(cacheKey);
|
|
267205
|
-
let
|
|
267788
|
+
let found2 = null;
|
|
267206
267789
|
const kernelToRead = engine2?.kernel ?? newEngine.kernel;
|
|
267207
267790
|
const store = kernelToRead.getStore?.();
|
|
267208
267791
|
if (store) {
|
|
267209
267792
|
try {
|
|
267210
267793
|
const events = await store.transaction((tx) => tx.listEvents(workspace));
|
|
267211
267794
|
const spawn10 = events.find((e) => e.event.kind === "plan.changed");
|
|
267212
|
-
|
|
267795
|
+
found2 = spawn10?.actorId ?? null;
|
|
267213
267796
|
} catch {
|
|
267214
267797
|
}
|
|
267215
267798
|
}
|
|
267216
|
-
if (
|
|
267799
|
+
if (found2 === null && isDefault) {
|
|
267217
267800
|
for await (const entry of oplog.readAll()) {
|
|
267218
267801
|
const op = entry.op;
|
|
267219
267802
|
if (op.kind === "spawn_artifact" && op.payload.workspace === workspace) {
|
|
267220
|
-
|
|
267803
|
+
found2 = op.actor;
|
|
267221
267804
|
break;
|
|
267222
267805
|
}
|
|
267223
267806
|
}
|
|
267224
267807
|
}
|
|
267225
|
-
initiatorCache.set(cacheKey,
|
|
267226
|
-
return
|
|
267808
|
+
initiatorCache.set(cacheKey, found2);
|
|
267809
|
+
return found2;
|
|
267227
267810
|
};
|
|
267228
267811
|
const leadOf = async (actor, registry2) => {
|
|
267229
267812
|
const reg = registry2 ?? registryStore;
|
|
@@ -267407,7 +267990,7 @@ async function startServe(opts) {
|
|
|
267407
267990
|
},
|
|
267408
267991
|
log: (message) => console.warn(message)
|
|
267409
267992
|
});
|
|
267410
|
-
if (
|
|
267993
|
+
if (notificationLedgerEnabled) {
|
|
267411
267994
|
const ledgerPeople = /* @__PURE__ */ new Map();
|
|
267412
267995
|
const worker = new NotificationLedgerWorker({
|
|
267413
267996
|
listCompanies: async () => engineRouter.liveEntries().map((e) => e.companyId),
|
|
@@ -268662,7 +269245,7 @@ var SessionProcessState = class {
|
|
|
268662
269245
|
// ../cli/src/daemon/ws-client.ts
|
|
268663
269246
|
init_wrapper();
|
|
268664
269247
|
var import_node_os9 = require("node:os");
|
|
268665
|
-
var
|
|
269248
|
+
var import_node_crypto79 = require("node:crypto");
|
|
268666
269249
|
init_src8();
|
|
268667
269250
|
init_src6();
|
|
268668
269251
|
|
|
@@ -268731,7 +269314,7 @@ var import_node_fs20 = __toESM(require("node:fs"), 1);
|
|
|
268731
269314
|
var import_node_path26 = __toESM(require("node:path"), 1);
|
|
268732
269315
|
init_src6();
|
|
268733
269316
|
init_src();
|
|
268734
|
-
var
|
|
269317
|
+
var WORKDIR_READ_MAX_BYTES = 2 * 1024 * 1024;
|
|
268735
269318
|
var WORKDIR_LIST_MAX_ENTRIES = 500;
|
|
268736
269319
|
var WORKDIR_WALK_MAX_ENTRIES2 = 1e4;
|
|
268737
269320
|
var WORKDIR_WALK_BUDGET_MS2 = 1e4;
|
|
@@ -268909,7 +269492,7 @@ async function verifyOpenedFd(fh, base, fallback) {
|
|
|
268909
269492
|
return { anchor: `/proc/self/fd/${fh.fd}` };
|
|
268910
269493
|
}
|
|
268911
269494
|
async function handleWorkdirRead(req) {
|
|
268912
|
-
const maxBytes = req.maxBytes ??
|
|
269495
|
+
const maxBytes = req.maxBytes ?? WORKDIR_READ_MAX_BYTES;
|
|
268913
269496
|
try {
|
|
268914
269497
|
const resolved = await resolveWithinWorkdir(req);
|
|
268915
269498
|
if (!resolved.ok) return resolved;
|
|
@@ -269434,7 +270017,7 @@ var DaemonWsClient = class {
|
|
|
269434
270017
|
*/
|
|
269435
270018
|
async queryArtifactStates(artifactIds, timeoutMs = 15e3) {
|
|
269436
270019
|
if (artifactIds.length === 0) return {};
|
|
269437
|
-
const requestId = (0,
|
|
270020
|
+
const requestId = (0, import_node_crypto79.randomUUID)();
|
|
269438
270021
|
return new Promise((resolve10, reject) => {
|
|
269439
270022
|
const timer = setTimeout(() => {
|
|
269440
270023
|
this.gcPending.delete(requestId);
|
|
@@ -269836,7 +270419,7 @@ function forwardSignal(child, sig, killGroup = (pgid, signal) => {
|
|
|
269836
270419
|
// ../cli/src/daemon/machine-id.ts
|
|
269837
270420
|
var import_node_child_process21 = require("node:child_process");
|
|
269838
270421
|
var import_node_fs22 = require("node:fs");
|
|
269839
|
-
var
|
|
270422
|
+
var import_node_crypto80 = require("node:crypto");
|
|
269840
270423
|
var import_node_os12 = require("node:os");
|
|
269841
270424
|
function linuxMachineId() {
|
|
269842
270425
|
for (const p2 of ["/etc/machine-id", "/var/lib/dbus/machine-id"]) {
|
|
@@ -269902,7 +270485,7 @@ var defaultSources = {
|
|
|
269902
270485
|
function resolveNodeId(sources = {}) {
|
|
269903
270486
|
const s2 = { ...defaultSources, ...sources };
|
|
269904
270487
|
const material = `${s2.machineFingerprint()}:${s2.osUser()}`;
|
|
269905
|
-
const digest = (0,
|
|
270488
|
+
const digest = (0, import_node_crypto80.createHash)("sha256").update(material).digest("hex").slice(0, 12);
|
|
269906
270489
|
return `node-${digest}`;
|
|
269907
270490
|
}
|
|
269908
270491
|
|
|
@@ -270913,7 +271496,7 @@ var COMMAND_DECLS = {
|
|
|
270913
271496
|
flags: [
|
|
270914
271497
|
{ name: "name", desc: "\u9879\u76EE\u540D", required: true },
|
|
270915
271498
|
{ name: "goal", desc: "\u9879\u76EE\u76EE\u6807" },
|
|
270916
|
-
{ name: "slug", desc: "
|
|
271499
|
+
{ name: "slug", desc: "\u81EA\u5B9A\u4E49\u9879\u76EE id\uFF08\u53EF\u9009\uFF09\u3002\u4E0D\u7ED9\u5219\u968F\u673A\u751F\u6210 proj_xxxxxxxx\uFF1B\u7ED9\u4E86\u4E14\u8BE5 id \u5DF2\u5B58\u5728\uFF0C\u8FD4\u56DE\u7684\u662F\u5DF2\u6709\u9879\u76EE\uFF08\u4F1A\u63D0\u793A\uFF09" },
|
|
270917
271500
|
{ name: "members", desc: "\u6210\u5458 JSON \u6570\u7EC4" }
|
|
270918
271501
|
],
|
|
270919
271502
|
examples: ['oasis project create --name "My Project" --goal "\u6784\u5EFA\u534F\u4F5C\u5E73\u53F0"']
|
|
@@ -271673,13 +272256,13 @@ function ownFlagsFromDecl(command) {
|
|
|
271673
272256
|
}
|
|
271674
272257
|
|
|
271675
272258
|
// ../cli/src/connector-effect-runner.ts
|
|
271676
|
-
var
|
|
272259
|
+
var import_node_crypto81 = require("node:crypto");
|
|
271677
272260
|
var import_node_child_process22 = require("node:child_process");
|
|
271678
272261
|
init_src8();
|
|
271679
272262
|
function stableKey(effect) {
|
|
271680
272263
|
const keyFields = Object.fromEntries(Object.entries(effect.keyFields).sort(([a], [b2]) => a.localeCompare(b2)));
|
|
271681
272264
|
const canonical = JSON.stringify({ kind: effect.kind, target: effect.target, keyFields });
|
|
271682
|
-
return `sha256:${(0,
|
|
272265
|
+
return `sha256:${(0, import_node_crypto81.createHash)("sha256").update(canonical).digest("hex")}`;
|
|
271683
272266
|
}
|
|
271684
272267
|
async function runConnectorEffect(connector, toolArgs, deps) {
|
|
271685
272268
|
const effect = connector.describeExternalEffect?.(toolArgs) ?? null;
|
|
@@ -271915,7 +272498,7 @@ async function waitForCommandAuthorization(base, headers, draftId, fallback) {
|
|
|
271915
272498
|
const timeoutMs = resolveAuthWaitMs();
|
|
271916
272499
|
const controller = new AbortController();
|
|
271917
272500
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
271918
|
-
const waiterId = (0,
|
|
272501
|
+
const waiterId = (0, import_node_crypto82.randomUUID)();
|
|
271919
272502
|
process.stderr.write(
|
|
271920
272503
|
`\u7B49\u5F85\u4EBA\u5DE5\u6388\u6743\u4E2D\u2026\u2026\u6700\u591A ${Math.round(timeoutMs / 1e3)} \u79D2\uFF0C\u8D85\u65F6\u4F1A\u81EA\u52A8\u8F6C\u4E3A\u5F85\u5BA1\uFF1B\u8FD9\u4E0D\u662F\u9519\u8BEF\uFF0C\u8BF7\u52FF\u91CD\u8BD5\u540C\u4E00\u6761\u547D\u4EE4\u3002
|
|
271921
272504
|
`
|
|
@@ -272338,7 +272921,7 @@ async function runCli(argv, println = console.log, progressln = console.error) {
|
|
|
272338
272921
|
const store = createNodeTokenStore(path35.join(dir, "node-tokens.json"));
|
|
272339
272922
|
const sub = positional[0];
|
|
272340
272923
|
if (sub === "issue") {
|
|
272341
|
-
const id = flags.get("id") ?? `node-${(0,
|
|
272924
|
+
const id = flags.get("id") ?? `node-${(0, import_node_crypto82.randomUUID)()}`;
|
|
272342
272925
|
const token2 = store.issue(id);
|
|
272343
272926
|
println(token2);
|
|
272344
272927
|
process.stderr.write(
|
|
@@ -273362,7 +273945,8 @@ ${t.ref} ${t.name} [\u5267\u672C=${t.playbookRef}]`);
|
|
|
273362
273945
|
const name = need(flags, "name").trim();
|
|
273363
273946
|
if (!name) throw new Error("\u9879\u76EE\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A");
|
|
273364
273947
|
const goal = flags.get("goal")?.trim();
|
|
273365
|
-
const
|
|
273948
|
+
const slug6 = flags.get("slug");
|
|
273949
|
+
const id = slug6 !== void 0 ? projectSlug(slug6) : projectIdFromUuid((0, import_node_crypto82.randomUUID)());
|
|
273366
273950
|
const result = await api.request("POST", "/api/projects", {
|
|
273367
273951
|
...id ? { id } : {},
|
|
273368
273952
|
name,
|
|
@@ -273370,6 +273954,9 @@ ${t.ref} ${t.name} [\u5267\u672C=${t.playbookRef}]`);
|
|
|
273370
273954
|
...flags.has("members") ? { member_ids: parseStringArrayFlag(flags.get("members"), "members") } : {}
|
|
273371
273955
|
});
|
|
273372
273956
|
println(JSON.stringify(result, null, 2));
|
|
273957
|
+
if (typeof result?.name === "string" && result.name !== name) {
|
|
273958
|
+
println(`\u26A0\uFE0F \u9879\u76EE id\u300C${result.project_id ?? id}\u300D\u5DF2\u88AB\u300C${result.name}\u300D\u5360\u7528\uFF0C\u4E0A\u9762\u8FD4\u56DE\u7684\u662F\u90A3\u4E2A\u5DF2\u6709\u9879\u76EE\uFF0C\u6CA1\u6709\u65B0\u5EFA\u3002\u6362\u4E00\u4E2A --slug \u6216\u53BB\u6389 --slug \u91CD\u8BD5\u3002`);
|
|
273959
|
+
}
|
|
273373
273960
|
break;
|
|
273374
273961
|
}
|
|
273375
273962
|
if (positional[0] === "member") {
|
|
@@ -275308,20 +275895,20 @@ function instancePaths(name) {
|
|
|
275308
275895
|
};
|
|
275309
275896
|
}
|
|
275310
275897
|
function listInstances() {
|
|
275311
|
-
const
|
|
275312
|
-
if (fs43.existsSync(instancePaths(DEFAULT_INSTANCE).configFile))
|
|
275898
|
+
const found2 = [];
|
|
275899
|
+
if (fs43.existsSync(instancePaths(DEFAULT_INSTANCE).configFile)) found2.push(DEFAULT_INSTANCE);
|
|
275313
275900
|
let entries = [];
|
|
275314
275901
|
try {
|
|
275315
275902
|
entries = fs43.readdirSync(instancesRoot());
|
|
275316
275903
|
} catch {
|
|
275317
|
-
return
|
|
275904
|
+
return found2;
|
|
275318
275905
|
}
|
|
275319
275906
|
for (const name of entries.sort()) {
|
|
275320
275907
|
if (name === DEFAULT_INSTANCE) continue;
|
|
275321
275908
|
if (!isValidInstanceName(name)) continue;
|
|
275322
|
-
if (fs43.existsSync(instancePaths(name).configFile))
|
|
275909
|
+
if (fs43.existsSync(instancePaths(name).configFile)) found2.push(name);
|
|
275323
275910
|
}
|
|
275324
|
-
return
|
|
275911
|
+
return found2;
|
|
275325
275912
|
}
|
|
275326
275913
|
function referencedVersionLabels() {
|
|
275327
275914
|
const labels = /* @__PURE__ */ new Set();
|
|
@@ -275351,13 +275938,13 @@ var LEGACY_SYSTEMD_UNIT = "oasis-node.service";
|
|
|
275351
275938
|
var LEGACY_LAUNCHD_LABEL = "com.oasis.node";
|
|
275352
275939
|
|
|
275353
275940
|
// src/install.ts
|
|
275354
|
-
var
|
|
275941
|
+
var import_node_crypto83 = require("node:crypto");
|
|
275355
275942
|
var fs44 = __toESM(require("node:fs"));
|
|
275356
275943
|
var path39 = __toESM(require("node:path"));
|
|
275357
275944
|
function versionLabel(sourceFile, pkgVersion, npmPrefixDir, pkgName = LEGACY_PKG_NAME) {
|
|
275358
275945
|
const tag = pkgName === LEGACY_PKG_NAME ? "" : `+pkg.${pkgName.replace(/[^A-Za-z0-9-]/g, "-")}`;
|
|
275359
275946
|
if (isFromNpmPrefix(sourceFile, npmPrefixDir)) return `${pkgVersion}${tag}`;
|
|
275360
|
-
const digest = (0,
|
|
275947
|
+
const digest = (0, import_node_crypto83.createHash)("sha256").update(fs44.readFileSync(sourceFile)).digest("hex").slice(0, 8);
|
|
275361
275948
|
return tag ? `${pkgVersion}${tag}.local.${digest}` : `${pkgVersion}+local.${digest}`;
|
|
275362
275949
|
}
|
|
275363
275950
|
function isFromNpmPrefix(sourceFile, npmPrefixDir) {
|
|
@@ -275480,7 +276067,7 @@ function shimScript() {
|
|
|
275480
276067
|
}
|
|
275481
276068
|
|
|
275482
276069
|
// src/index.ts
|
|
275483
|
-
var PKG_VERSION = true ? "2.2.
|
|
276070
|
+
var PKG_VERSION = true ? "2.2.35" : "dev";
|
|
275484
276071
|
var LOCAL_BIN = localBin();
|
|
275485
276072
|
var NPM_PREFIX = npmPrefix();
|
|
275486
276073
|
var INSTANCE = DEFAULT_INSTANCE;
|
|
@@ -275765,7 +276352,7 @@ function newInstanceName() {
|
|
|
275765
276352
|
const existing = new Set(listInstances());
|
|
275766
276353
|
if (!existing.has(DEFAULT_INSTANCE)) return DEFAULT_INSTANCE;
|
|
275767
276354
|
for (; ; ) {
|
|
275768
|
-
const n = `inst-${(0,
|
|
276355
|
+
const n = `inst-${(0, import_node_crypto84.randomBytes)(3).toString("hex")}`;
|
|
275769
276356
|
if (!existing.has(n)) return n;
|
|
275770
276357
|
}
|
|
275771
276358
|
}
|