oasis_test_v2 2.2.105 → 2.2.107
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 +1792 -374
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -388,9 +388,14 @@ var init_org_model = __esm({
|
|
|
388
388
|
});
|
|
389
389
|
|
|
390
390
|
// ../contract/src/company.ts
|
|
391
|
+
function profileNameLength(value2) {
|
|
392
|
+
return Array.from(value2.trim()).length;
|
|
393
|
+
}
|
|
394
|
+
var PROFILE_NAME_MAX;
|
|
391
395
|
var init_company = __esm({
|
|
392
396
|
"../contract/src/company.ts"() {
|
|
393
397
|
"use strict";
|
|
398
|
+
PROFILE_NAME_MAX = 30;
|
|
394
399
|
}
|
|
395
400
|
});
|
|
396
401
|
|
|
@@ -492,6 +497,7 @@ function inboxItemTargetPath(item) {
|
|
|
492
497
|
return null;
|
|
493
498
|
}
|
|
494
499
|
function notificationTargetPath(r) {
|
|
500
|
+
if (r.category === "todo") return r.chatSessionId ? chatPath(r.chatSessionId) : null;
|
|
495
501
|
if (r.category !== "action") return r.workorderId ? taskPath(r.workorderId) : null;
|
|
496
502
|
const viaItem = r.item ? inboxItemTargetPath(r.item) : null;
|
|
497
503
|
const wid = r.workorderId ?? r.item?.workspace;
|
|
@@ -1350,6 +1356,137 @@ var init_variable_name = __esm({
|
|
|
1350
1356
|
}
|
|
1351
1357
|
});
|
|
1352
1358
|
|
|
1359
|
+
// ../contract/src/time-zone.ts
|
|
1360
|
+
function canonicalTimeZone(name) {
|
|
1361
|
+
if (typeof name !== "string") return null;
|
|
1362
|
+
const trimmed = name.trim();
|
|
1363
|
+
if (!trimmed || /^[+-]/.test(trimmed)) return null;
|
|
1364
|
+
try {
|
|
1365
|
+
return new Intl.DateTimeFormat("en-US", { timeZone: trimmed }).resolvedOptions().timeZone;
|
|
1366
|
+
} catch {
|
|
1367
|
+
return null;
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
function isValidTimeZone(name) {
|
|
1371
|
+
return canonicalTimeZone(name) !== null;
|
|
1372
|
+
}
|
|
1373
|
+
function effectiveTimeZone(company, deploymentDefault) {
|
|
1374
|
+
return company?.timeZone || deploymentDefault;
|
|
1375
|
+
}
|
|
1376
|
+
function zoneOffsetMs(ms, timeZone) {
|
|
1377
|
+
const parts = new Intl.DateTimeFormat("en-US", {
|
|
1378
|
+
timeZone,
|
|
1379
|
+
hour12: false,
|
|
1380
|
+
year: "numeric",
|
|
1381
|
+
month: "2-digit",
|
|
1382
|
+
day: "2-digit",
|
|
1383
|
+
hour: "2-digit",
|
|
1384
|
+
minute: "2-digit",
|
|
1385
|
+
second: "2-digit"
|
|
1386
|
+
}).formatToParts(new Date(ms));
|
|
1387
|
+
const get = (type) => Number(parts.find((p2) => p2.type === type)?.value ?? "0");
|
|
1388
|
+
const asIfUtc = Date.UTC(get("year"), get("month") - 1, get("day"), get("hour") % 24, get("minute"), get("second"));
|
|
1389
|
+
return asIfUtc - (ms - (ms % 1e3 + 1e3) % 1e3);
|
|
1390
|
+
}
|
|
1391
|
+
function zonedDateOf(ms, timeZone) {
|
|
1392
|
+
const d = new Date(ms + zoneOffsetMs(ms, timeZone));
|
|
1393
|
+
return {
|
|
1394
|
+
date: `${d.getUTCFullYear()}-${pad2(d.getUTCMonth() + 1)}-${pad2(d.getUTCDate())}`,
|
|
1395
|
+
weekday: d.getUTCDay()
|
|
1396
|
+
};
|
|
1397
|
+
}
|
|
1398
|
+
function zonedToday(timeZone, nowMs = Date.now()) {
|
|
1399
|
+
return zonedDateOf(nowMs, timeZone);
|
|
1400
|
+
}
|
|
1401
|
+
function isValidDay(day) {
|
|
1402
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(day)) return false;
|
|
1403
|
+
const t = Date.parse(`${day}T00:00:00Z`);
|
|
1404
|
+
return !Number.isNaN(t) && new Date(t).toISOString().slice(0, 10) === day;
|
|
1405
|
+
}
|
|
1406
|
+
function zonedDateTimeToUtcMs(day, time3, timeZone) {
|
|
1407
|
+
if (!isValidDay(day)) throw new RangeError(`\u4E0D\u662F\u6709\u6548\u65E5\u671F\uFF08\u987B\u4E3A YYYY-MM-DD\uFF09\uFF1A${day}`);
|
|
1408
|
+
const m2 = /^(\d{2}):(\d{2})$/.exec(time3);
|
|
1409
|
+
if (!m2 || Number(m2[1]) > 23 || Number(m2[2]) > 59) throw new RangeError(`\u4E0D\u662F\u6709\u6548\u65F6\u523B\uFF08\u987B\u4E3A HH:mm\uFF09\uFF1A${time3}`);
|
|
1410
|
+
const local = Date.parse(`${day}T${time3}:00Z`);
|
|
1411
|
+
const before = local - zoneOffsetMs(local - DAY_MS, timeZone);
|
|
1412
|
+
const after = local - zoneOffsetMs(local + DAY_MS, timeZone);
|
|
1413
|
+
const fits = (t) => t + zoneOffsetMs(t, timeZone) === local;
|
|
1414
|
+
const okBefore = fits(before);
|
|
1415
|
+
const okAfter = fits(after);
|
|
1416
|
+
if (okBefore && okAfter) return Math.min(before, after);
|
|
1417
|
+
if (okBefore) return before;
|
|
1418
|
+
if (okAfter) return after;
|
|
1419
|
+
return before;
|
|
1420
|
+
}
|
|
1421
|
+
function zonedStartOfDayMs(day, timeZone) {
|
|
1422
|
+
return zonedDateTimeToUtcMs(day, "00:00", timeZone);
|
|
1423
|
+
}
|
|
1424
|
+
var DEFAULT_TIME_ZONE, DAY_MS, pad2;
|
|
1425
|
+
var init_time_zone = __esm({
|
|
1426
|
+
"../contract/src/time-zone.ts"() {
|
|
1427
|
+
"use strict";
|
|
1428
|
+
DEFAULT_TIME_ZONE = "Asia/Shanghai";
|
|
1429
|
+
DAY_MS = 24 * 60 * 60 * 1e3;
|
|
1430
|
+
pad2 = (n) => String(n).padStart(2, "0");
|
|
1431
|
+
}
|
|
1432
|
+
});
|
|
1433
|
+
|
|
1434
|
+
// ../contract/src/todos.ts
|
|
1435
|
+
function todoAssignees(todo) {
|
|
1436
|
+
return [todo.assigneeActorId];
|
|
1437
|
+
}
|
|
1438
|
+
function isTodoParty(todo, actorId) {
|
|
1439
|
+
return todo.creatorActorId === actorId || todoAssignees(todo).includes(actorId);
|
|
1440
|
+
}
|
|
1441
|
+
function isValidTodoTime(time3) {
|
|
1442
|
+
const m2 = /^(\d{2}):(\d{2})$/.exec(time3);
|
|
1443
|
+
return !!m2 && Number(m2[1]) <= 23 && Number(m2[2]) <= 59;
|
|
1444
|
+
}
|
|
1445
|
+
function weekdayOfDay(day) {
|
|
1446
|
+
return (/* @__PURE__ */ new Date(`${day}T00:00:00Z`)).getUTCDay();
|
|
1447
|
+
}
|
|
1448
|
+
function isTodoStartBeforeDue(t) {
|
|
1449
|
+
if (!t.startDate) return true;
|
|
1450
|
+
if (t.startDate !== t.dueDate) return t.startDate < t.dueDate;
|
|
1451
|
+
return !(t.startTime && t.dueTime) || t.startTime <= t.dueTime;
|
|
1452
|
+
}
|
|
1453
|
+
function formatTodoDue(day, time3) {
|
|
1454
|
+
const [, m2, d] = day.split("-");
|
|
1455
|
+
return `${Number(m2)} \u6708 ${Number(d)} \u65E5\uFF08${WEEKDAY_LABEL[weekdayOfDay(day)]}\uFF09${time3 ? ` ${time3}` : ""}`;
|
|
1456
|
+
}
|
|
1457
|
+
function formatTodoSpan(t) {
|
|
1458
|
+
const due = formatTodoDue(t.dueDate, t.dueTime);
|
|
1459
|
+
if (!t.startDate) return `\u622A\u6B62 ${due}`;
|
|
1460
|
+
const join48 = (text7, time3) => `${text7}${time3 ? " " : ""}`;
|
|
1461
|
+
return `${join48(formatTodoDue(t.startDate, t.startTime), t.startTime)}\u5F00\u59CB \u2192 ${join48(due, t.dueTime)}\u622A\u6B62`;
|
|
1462
|
+
}
|
|
1463
|
+
function todoToday(timeZone, nowMs = Date.now()) {
|
|
1464
|
+
return { ...zonedToday(timeZone, nowMs), timeZone };
|
|
1465
|
+
}
|
|
1466
|
+
function formatTodayLine(today) {
|
|
1467
|
+
return `\u4ECA\u5929\uFF1A${today.date} ${WEEKDAY_LABEL[today.weekday]}\uFF08${today.timeZone}\uFF09`;
|
|
1468
|
+
}
|
|
1469
|
+
function shiftDay(day, n) {
|
|
1470
|
+
const t = Date.parse(`${day}T00:00:00Z`) + n * 864e5;
|
|
1471
|
+
return new Date(t).toISOString().slice(0, 10);
|
|
1472
|
+
}
|
|
1473
|
+
function compareTodos(a, b2) {
|
|
1474
|
+
if (a.dueDate !== b2.dueDate) return a.dueDate < b2.dueDate ? -1 : 1;
|
|
1475
|
+
const ta = a.dueTime ?? "99:99";
|
|
1476
|
+
const tb = b2.dueTime ?? "99:99";
|
|
1477
|
+
if (ta !== tb) return ta < tb ? -1 : 1;
|
|
1478
|
+
if (a.createdAt !== b2.createdAt) return a.createdAt < b2.createdAt ? -1 : 1;
|
|
1479
|
+
return a.id < b2.id ? -1 : a.id > b2.id ? 1 : 0;
|
|
1480
|
+
}
|
|
1481
|
+
var WEEKDAY_LABEL;
|
|
1482
|
+
var init_todos = __esm({
|
|
1483
|
+
"../contract/src/todos.ts"() {
|
|
1484
|
+
"use strict";
|
|
1485
|
+
init_time_zone();
|
|
1486
|
+
WEEKDAY_LABEL = ["\u5468\u65E5", "\u5468\u4E00", "\u5468\u4E8C", "\u5468\u4E09", "\u5468\u56DB", "\u5468\u4E94", "\u5468\u516D"];
|
|
1487
|
+
}
|
|
1488
|
+
});
|
|
1489
|
+
|
|
1353
1490
|
// ../contract/src/credential-gap.ts
|
|
1354
1491
|
function buildCredentialGapDescription(opts) {
|
|
1355
1492
|
const { key: key2, scope: scope2, project, desc } = opts;
|
|
@@ -2236,9 +2373,9 @@ function firstSentenceSummary(text7, max = CARD_SUMMARY_MAX) {
|
|
|
2236
2373
|
const raw = (text7 ?? "").trim();
|
|
2237
2374
|
if (!raw) return "";
|
|
2238
2375
|
const cut = raw.split(/[。!?\n]|——/u)[0].trim() || raw.trim();
|
|
2239
|
-
const
|
|
2240
|
-
const cps = [...
|
|
2241
|
-
return cps.length > max ? `${cps.slice(0, max).join("")}\u2026` :
|
|
2376
|
+
const clean3 = stripInternalIds(cut).trim();
|
|
2377
|
+
const cps = [...clean3];
|
|
2378
|
+
return cps.length > max ? `${cps.slice(0, max).join("")}\u2026` : clean3;
|
|
2242
2379
|
}
|
|
2243
2380
|
function requoteStepTitle(text7, title) {
|
|
2244
2381
|
const t = title?.trim();
|
|
@@ -2415,6 +2552,8 @@ var init_src = __esm({
|
|
|
2415
2552
|
init_skill_market();
|
|
2416
2553
|
init_credential_ref();
|
|
2417
2554
|
init_variable_name();
|
|
2555
|
+
init_time_zone();
|
|
2556
|
+
init_todos();
|
|
2418
2557
|
init_credential_gap();
|
|
2419
2558
|
init_views();
|
|
2420
2559
|
init_telemetry();
|
|
@@ -20258,10 +20397,10 @@ var init_chat_item_ledger = __esm({
|
|
|
20258
20397
|
}
|
|
20259
20398
|
insert(input) {
|
|
20260
20399
|
const prepared = this.prepareInsert(input);
|
|
20261
|
-
const
|
|
20262
|
-
if (!
|
|
20400
|
+
const create2 = prepared.create;
|
|
20401
|
+
if (!create2) return prepared.id;
|
|
20263
20402
|
this.enqueue(async () => {
|
|
20264
|
-
prepared.persisted(await this.deps.items.createItem(
|
|
20403
|
+
prepared.persisted(await this.deps.items.createItem(create2));
|
|
20265
20404
|
}, `create:${input.kind}`);
|
|
20266
20405
|
return prepared.id;
|
|
20267
20406
|
}
|
|
@@ -20303,7 +20442,7 @@ var init_chat_item_ledger = __esm({
|
|
|
20303
20442
|
const messageId = row.messageId;
|
|
20304
20443
|
const payload2 = input.payload ?? this.payloadOf(row);
|
|
20305
20444
|
const metadata = input.metadata ?? { [CHAT_ITEM_META_LEGACY_CONTENT]: input.inContent };
|
|
20306
|
-
const
|
|
20445
|
+
const create2 = {
|
|
20307
20446
|
id,
|
|
20308
20447
|
sessionId: this.deps.sessionId,
|
|
20309
20448
|
messageId,
|
|
@@ -20344,7 +20483,7 @@ var init_chat_item_ledger = __esm({
|
|
|
20344
20483
|
}
|
|
20345
20484
|
}
|
|
20346
20485
|
};
|
|
20347
|
-
return { id, create, persisted };
|
|
20486
|
+
return { id, create: create2, persisted };
|
|
20348
20487
|
}
|
|
20349
20488
|
/**
|
|
20350
20489
|
* 追加合并:**排队期间到达的片段合进同一次 `append_text`**,一串片段一次往返。
|
|
@@ -31305,10 +31444,10 @@ var require_abort = __commonJS({
|
|
|
31305
31444
|
"../../node_modules/.pnpm/asynckit@0.4.0/node_modules/asynckit/lib/abort.js"(exports2, module2) {
|
|
31306
31445
|
module2.exports = abort;
|
|
31307
31446
|
function abort(state) {
|
|
31308
|
-
Object.keys(state.jobs).forEach(
|
|
31447
|
+
Object.keys(state.jobs).forEach(clean3.bind(state));
|
|
31309
31448
|
state.jobs = {};
|
|
31310
31449
|
}
|
|
31311
|
-
function
|
|
31450
|
+
function clean3(key2) {
|
|
31312
31451
|
if (typeof this.jobs[key2] == "function") {
|
|
31313
31452
|
this.jobs[key2]();
|
|
31314
31453
|
}
|
|
@@ -35639,29 +35778,29 @@ var require_axios = __commonJS({
|
|
|
35639
35778
|
}
|
|
35640
35779
|
}
|
|
35641
35780
|
}
|
|
35642
|
-
let
|
|
35781
|
+
let pad3 = 0;
|
|
35643
35782
|
let idx = len - 1;
|
|
35644
35783
|
const tailIsPct3D = (j) => j >= 2 && body2.charCodeAt(j - 2) === 37 && // '%'
|
|
35645
35784
|
body2.charCodeAt(j - 1) === 51 && // '3'
|
|
35646
35785
|
(body2.charCodeAt(j) === 68 || body2.charCodeAt(j) === 100);
|
|
35647
35786
|
if (idx >= 0) {
|
|
35648
35787
|
if (body2.charCodeAt(idx) === 61) {
|
|
35649
|
-
|
|
35788
|
+
pad3++;
|
|
35650
35789
|
idx--;
|
|
35651
35790
|
} else if (tailIsPct3D(idx)) {
|
|
35652
|
-
|
|
35791
|
+
pad3++;
|
|
35653
35792
|
idx -= 3;
|
|
35654
35793
|
}
|
|
35655
35794
|
}
|
|
35656
|
-
if (
|
|
35795
|
+
if (pad3 === 1 && idx >= 0) {
|
|
35657
35796
|
if (body2.charCodeAt(idx) === 61) {
|
|
35658
|
-
|
|
35797
|
+
pad3++;
|
|
35659
35798
|
} else if (tailIsPct3D(idx)) {
|
|
35660
|
-
|
|
35799
|
+
pad3++;
|
|
35661
35800
|
}
|
|
35662
35801
|
}
|
|
35663
35802
|
const groups = Math.floor(effectiveLen / 4);
|
|
35664
|
-
const bytes2 = groups * 3 - (
|
|
35803
|
+
const bytes2 = groups * 3 - (pad3 || 0);
|
|
35665
35804
|
return bytes2 > 0 ? bytes2 : 0;
|
|
35666
35805
|
}
|
|
35667
35806
|
return Buffer.byteLength(body2, "utf8");
|
|
@@ -37520,7 +37659,7 @@ var require_axios = __commonJS({
|
|
|
37520
37659
|
const instance = bind(Axios$1.prototype.request, context2);
|
|
37521
37660
|
utils$1.extend(instance, Axios$1.prototype, context2, { allOwnKeys: true });
|
|
37522
37661
|
utils$1.extend(instance, context2, null, { allOwnKeys: true });
|
|
37523
|
-
instance.create = function
|
|
37662
|
+
instance.create = function create2(instanceConfig) {
|
|
37524
37663
|
return createInstance(mergeConfig2(defaultConfig, instanceConfig));
|
|
37525
37664
|
};
|
|
37526
37665
|
return instance;
|
|
@@ -43137,7 +43276,7 @@ var require_websocket = __commonJS({
|
|
|
43137
43276
|
var http2 = require("http");
|
|
43138
43277
|
var net = require("net");
|
|
43139
43278
|
var tls = require("tls");
|
|
43140
|
-
var { randomBytes:
|
|
43279
|
+
var { randomBytes: randomBytes17, createHash: createHash47 } = require("crypto");
|
|
43141
43280
|
var { Duplex, Readable } = require("stream");
|
|
43142
43281
|
var { URL: URL2 } = require("url");
|
|
43143
43282
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
@@ -43675,7 +43814,7 @@ var require_websocket = __commonJS({
|
|
|
43675
43814
|
}
|
|
43676
43815
|
}
|
|
43677
43816
|
const defaultPort = isSecure ? 443 : 80;
|
|
43678
|
-
const key2 =
|
|
43817
|
+
const key2 = randomBytes17(16).toString("base64");
|
|
43679
43818
|
const request2 = isSecure ? https.request : http2.request;
|
|
43680
43819
|
const protocolSet = /* @__PURE__ */ new Set();
|
|
43681
43820
|
let perMessageDeflate;
|
|
@@ -43805,7 +43944,7 @@ var require_websocket = __commonJS({
|
|
|
43805
43944
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
43806
43945
|
return;
|
|
43807
43946
|
}
|
|
43808
|
-
const digest =
|
|
43947
|
+
const digest = createHash47("sha1").update(key2 + GUID).digest("base64");
|
|
43809
43948
|
if (res.headers["sec-websocket-accept"] !== digest) {
|
|
43810
43949
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
43811
43950
|
return;
|
|
@@ -44174,7 +44313,7 @@ var require_websocket_server = __commonJS({
|
|
|
44174
44313
|
var EventEmitter = require("events");
|
|
44175
44314
|
var http2 = require("http");
|
|
44176
44315
|
var { Duplex } = require("stream");
|
|
44177
|
-
var { createHash:
|
|
44316
|
+
var { createHash: createHash47 } = require("crypto");
|
|
44178
44317
|
var extension3 = require_extension();
|
|
44179
44318
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
44180
44319
|
var subprotocol2 = require_subprotocol();
|
|
@@ -44481,7 +44620,7 @@ var require_websocket_server = __commonJS({
|
|
|
44481
44620
|
);
|
|
44482
44621
|
}
|
|
44483
44622
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
44484
|
-
const digest =
|
|
44623
|
+
const digest = createHash47("sha1").update(key2 + GUID).digest("base64");
|
|
44485
44624
|
const headers = [
|
|
44486
44625
|
"HTTP/1.1 101 Switching Protocols",
|
|
44487
44626
|
"Upgrade: websocket",
|
|
@@ -46393,7 +46532,7 @@ var require_writer = __commonJS({
|
|
|
46393
46532
|
this.tail = this.head;
|
|
46394
46533
|
this.states = null;
|
|
46395
46534
|
}
|
|
46396
|
-
var
|
|
46535
|
+
var create2 = function create3() {
|
|
46397
46536
|
return util2.Buffer ? function create_buffer_setup() {
|
|
46398
46537
|
return (Writer.create = function create_buffer() {
|
|
46399
46538
|
return new BufferWriter();
|
|
@@ -46402,7 +46541,7 @@ var require_writer = __commonJS({
|
|
|
46402
46541
|
return new Writer();
|
|
46403
46542
|
};
|
|
46404
46543
|
};
|
|
46405
|
-
Writer.create =
|
|
46544
|
+
Writer.create = create2();
|
|
46406
46545
|
Writer.alloc = function alloc(size) {
|
|
46407
46546
|
return new util2.Array(size);
|
|
46408
46547
|
};
|
|
@@ -46549,7 +46688,7 @@ var require_writer = __commonJS({
|
|
|
46549
46688
|
};
|
|
46550
46689
|
Writer._configure = function(BufferWriter_) {
|
|
46551
46690
|
BufferWriter = BufferWriter_;
|
|
46552
|
-
Writer.create =
|
|
46691
|
+
Writer.create = create2();
|
|
46553
46692
|
BufferWriter._configure();
|
|
46554
46693
|
};
|
|
46555
46694
|
}
|
|
@@ -46631,14 +46770,14 @@ var require_reader = __commonJS({
|
|
|
46631
46770
|
return new Reader(buffer);
|
|
46632
46771
|
throw Error("illegal buffer");
|
|
46633
46772
|
};
|
|
46634
|
-
var
|
|
46773
|
+
var create2 = function create3() {
|
|
46635
46774
|
return util2.Buffer ? function create_buffer_setup(buffer) {
|
|
46636
46775
|
return (Reader.create = function create_buffer(buffer2) {
|
|
46637
46776
|
return util2.Buffer.isBuffer(buffer2) ? new BufferReader(buffer2) : create_array(buffer2);
|
|
46638
46777
|
})(buffer);
|
|
46639
46778
|
} : create_array;
|
|
46640
46779
|
};
|
|
46641
|
-
Reader.create =
|
|
46780
|
+
Reader.create = create2();
|
|
46642
46781
|
Reader.prototype._slice = util2.Array.prototype.subarray || /* istanbul ignore next */
|
|
46643
46782
|
util2.Array.prototype.slice;
|
|
46644
46783
|
Reader.prototype.uint32 = /* @__PURE__ */ function read_uint32_setup() {
|
|
@@ -46806,7 +46945,7 @@ var require_reader = __commonJS({
|
|
|
46806
46945
|
};
|
|
46807
46946
|
Reader._configure = function(BufferReader_) {
|
|
46808
46947
|
BufferReader = BufferReader_;
|
|
46809
|
-
Reader.create =
|
|
46948
|
+
Reader.create = create2();
|
|
46810
46949
|
BufferReader._configure();
|
|
46811
46950
|
var fn = util2.Long ? "toLong" : (
|
|
46812
46951
|
/* istanbul ignore next */
|
|
@@ -47144,15 +47283,15 @@ var require_lib2 = __commonJS({
|
|
|
47144
47283
|
function buildUserAgent(source, opts) {
|
|
47145
47284
|
let ua = `oapi-node-sdk/${getSdkVersion()}`;
|
|
47146
47285
|
if (source) {
|
|
47147
|
-
const
|
|
47148
|
-
if (
|
|
47149
|
-
ua += ` source/${
|
|
47286
|
+
const clean3 = sanitizeSource(source);
|
|
47287
|
+
if (clean3)
|
|
47288
|
+
ua += ` source/${clean3}`;
|
|
47150
47289
|
}
|
|
47151
47290
|
if (opts === null || opts === void 0 ? void 0 : opts.extraTags) {
|
|
47152
47291
|
for (const t of opts.extraTags) {
|
|
47153
|
-
const
|
|
47154
|
-
if (
|
|
47155
|
-
ua += ` ${
|
|
47292
|
+
const clean3 = sanitizeSource(t);
|
|
47293
|
+
if (clean3)
|
|
47294
|
+
ua += ` ${clean3}`;
|
|
47156
47295
|
}
|
|
47157
47296
|
}
|
|
47158
47297
|
return ua;
|
|
@@ -129101,7 +129240,7 @@ var require_lib2 = __commonJS({
|
|
|
129101
129240
|
}
|
|
129102
129241
|
Header.prototype.key = "";
|
|
129103
129242
|
Header.prototype.value = "";
|
|
129104
|
-
Header.create = function
|
|
129243
|
+
Header.create = function create2(properties) {
|
|
129105
129244
|
return new Header(properties);
|
|
129106
129245
|
};
|
|
129107
129246
|
Header.encode = function encode(message, writer) {
|
|
@@ -129213,7 +129352,7 @@ var require_lib2 = __commonJS({
|
|
|
129213
129352
|
Frame.prototype.payloadType = "";
|
|
129214
129353
|
Frame.prototype.payload = $util.newBuffer([]);
|
|
129215
129354
|
Frame.prototype.LogIDNew = "";
|
|
129216
|
-
Frame.create = function
|
|
129355
|
+
Frame.create = function create2(properties) {
|
|
129217
129356
|
return new Frame(properties);
|
|
129218
129357
|
};
|
|
129219
129358
|
Frame.encode = function encode(message, writer) {
|
|
@@ -137317,7 +137456,7 @@ var require_pg_int8 = __commonJS({
|
|
|
137317
137456
|
var carry;
|
|
137318
137457
|
var t;
|
|
137319
137458
|
var digits;
|
|
137320
|
-
var
|
|
137459
|
+
var pad3;
|
|
137321
137460
|
var l;
|
|
137322
137461
|
var i;
|
|
137323
137462
|
{
|
|
@@ -137329,12 +137468,12 @@ var require_pg_int8 = __commonJS({
|
|
|
137329
137468
|
if (low === 0 && high === 0) {
|
|
137330
137469
|
return sign3 + digits + result;
|
|
137331
137470
|
}
|
|
137332
|
-
|
|
137471
|
+
pad3 = "";
|
|
137333
137472
|
l = 6 - digits.length;
|
|
137334
137473
|
for (i = 0; i < l; i++) {
|
|
137335
|
-
|
|
137474
|
+
pad3 += "0";
|
|
137336
137475
|
}
|
|
137337
|
-
result =
|
|
137476
|
+
result = pad3 + digits + result;
|
|
137338
137477
|
}
|
|
137339
137478
|
{
|
|
137340
137479
|
carry = high % BASE2;
|
|
@@ -137345,12 +137484,12 @@ var require_pg_int8 = __commonJS({
|
|
|
137345
137484
|
if (low === 0 && high === 0) {
|
|
137346
137485
|
return sign3 + digits + result;
|
|
137347
137486
|
}
|
|
137348
|
-
|
|
137487
|
+
pad3 = "";
|
|
137349
137488
|
l = 6 - digits.length;
|
|
137350
137489
|
for (i = 0; i < l; i++) {
|
|
137351
|
-
|
|
137490
|
+
pad3 += "0";
|
|
137352
137491
|
}
|
|
137353
|
-
result =
|
|
137492
|
+
result = pad3 + digits + result;
|
|
137354
137493
|
}
|
|
137355
137494
|
{
|
|
137356
137495
|
carry = high % BASE2;
|
|
@@ -137361,12 +137500,12 @@ var require_pg_int8 = __commonJS({
|
|
|
137361
137500
|
if (low === 0 && high === 0) {
|
|
137362
137501
|
return sign3 + digits + result;
|
|
137363
137502
|
}
|
|
137364
|
-
|
|
137503
|
+
pad3 = "";
|
|
137365
137504
|
l = 6 - digits.length;
|
|
137366
137505
|
for (i = 0; i < l; i++) {
|
|
137367
|
-
|
|
137506
|
+
pad3 += "0";
|
|
137368
137507
|
}
|
|
137369
|
-
result =
|
|
137508
|
+
result = pad3 + digits + result;
|
|
137370
137509
|
}
|
|
137371
137510
|
{
|
|
137372
137511
|
carry = high % BASE2;
|
|
@@ -137909,7 +138048,7 @@ var require_utils3 = __commonJS({
|
|
|
137909
138048
|
var nodeCrypto = require("crypto");
|
|
137910
138049
|
module2.exports = {
|
|
137911
138050
|
postgresMd5PasswordHash,
|
|
137912
|
-
randomBytes:
|
|
138051
|
+
randomBytes: randomBytes17,
|
|
137913
138052
|
deriveKey,
|
|
137914
138053
|
sha256: sha2563,
|
|
137915
138054
|
hashByName,
|
|
@@ -137919,7 +138058,7 @@ var require_utils3 = __commonJS({
|
|
|
137919
138058
|
var webCrypto = nodeCrypto.webcrypto || globalThis.crypto;
|
|
137920
138059
|
var subtleCrypto = webCrypto.subtle;
|
|
137921
138060
|
var textEncoder = new TextEncoder();
|
|
137922
|
-
function
|
|
138061
|
+
function randomBytes17(length) {
|
|
137923
138062
|
return webCrypto.getRandomValues(Buffer.alloc(length));
|
|
137924
138063
|
}
|
|
137925
138064
|
async function md5(string7) {
|
|
@@ -153397,14 +153536,14 @@ var init_kernel_bridge = __esm({
|
|
|
153397
153536
|
fresh.add(id);
|
|
153398
153537
|
}
|
|
153399
153538
|
}
|
|
153400
|
-
const
|
|
153539
|
+
const clean3 = this.resyncRequested ? ids2.filter((id) => !fresh.has(id)) : [];
|
|
153401
153540
|
this.resyncRequested = false;
|
|
153402
|
-
if (
|
|
153403
|
-
const slice = Math.min(_EngineKernel.REFRESH_RESYNC_SLICE,
|
|
153541
|
+
if (clean3.length > 0) {
|
|
153542
|
+
const slice = Math.min(_EngineKernel.REFRESH_RESYNC_SLICE, clean3.length);
|
|
153404
153543
|
for (let i = 0; i < slice; i++) {
|
|
153405
|
-
toLoad.push(
|
|
153544
|
+
toLoad.push(clean3[(this.resyncCursor + i) % clean3.length]);
|
|
153406
153545
|
}
|
|
153407
|
-
this.resyncCursor = (this.resyncCursor + slice) %
|
|
153546
|
+
this.resyncCursor = (this.resyncCursor + slice) % clean3.length;
|
|
153408
153547
|
}
|
|
153409
153548
|
const claimed = toLoad.filter((id) => this.dirtyWorkorders.delete(id));
|
|
153410
153549
|
let loaded;
|
|
@@ -175535,7 +175674,11 @@ var init_assistants = __esm({
|
|
|
175535
175674
|
return p2?.autoAssignAssistant !== false;
|
|
175536
175675
|
}
|
|
175537
175676
|
/* ---------- 懒创建(原子 + 幂等 + 探针 + opt-out) ---------- */
|
|
175538
|
-
|
|
175677
|
+
/**
|
|
175678
|
+
* @param preferred 调用方(入职向导「我的助理」)指定的那台运行时。只是**偏好**:在本公司在线运行时里
|
|
175679
|
+
* 找得到就用它建,找不到(下线了 / 不是本公司的 / 乱填)就当没给,照常按负载挑——见 {@link pickAssistantRuntime}。
|
|
175680
|
+
*/
|
|
175681
|
+
async ensureFor(humanId, by = humanId, preferred) {
|
|
175539
175682
|
const pre = await this.opts.bindStore.getByHuman(humanId);
|
|
175540
175683
|
if (pre) return { agentId: pre.agentActorId, created: false, source: "existing" };
|
|
175541
175684
|
if (!await this.isAutoAssignOn(humanId)) {
|
|
@@ -175563,7 +175706,7 @@ var init_assistants = __esm({
|
|
|
175563
175706
|
return { agentId: restored.agentActorId, created: false, source: "existing" };
|
|
175564
175707
|
}
|
|
175565
175708
|
}
|
|
175566
|
-
const agentId = await this._createLocked(humanId, by, "lazy-create");
|
|
175709
|
+
const agentId = await this._createLocked(humanId, by, "lazy-create", preferred);
|
|
175567
175710
|
return { agentId, created: true, source: "lazy-created" };
|
|
175568
175711
|
});
|
|
175569
175712
|
}
|
|
@@ -175817,11 +175960,11 @@ var init_assistants = __esm({
|
|
|
175817
175960
|
}
|
|
175818
175961
|
}
|
|
175819
175962
|
/* ---------- 私有:创建流水线(不加锁;调用方须已持 withHumanLock) ---------- */
|
|
175820
|
-
async _createLocked(humanId, by, origin) {
|
|
175963
|
+
async _createLocked(humanId, by, origin, preferred) {
|
|
175821
175964
|
const human = await this.opts.registry.getActor(humanId);
|
|
175822
175965
|
if (!human) throw new AssistantLazyCreateError("human-not-found");
|
|
175823
175966
|
if (human.kind !== "human" || human.status !== "active") throw new AssistantLazyCreateError("human-inactive");
|
|
175824
|
-
const runtime = await this.pickAssistantRuntime();
|
|
175967
|
+
const runtime = await this.pickAssistantRuntime(preferred);
|
|
175825
175968
|
if (!runtime) throw new AssistantLazyCreateError("no-runtime");
|
|
175826
175969
|
const agentId = `actor:agent:asst-${slug4(human.name)}-${short6()}`;
|
|
175827
175970
|
await this.opts.actors.upsertActor({ id: agentId, kind: "agent", name: `${human.name}\u7684\u52A9\u7406`, status: "active", roles: ["assistant"] }, by);
|
|
@@ -175860,7 +176003,18 @@ var init_assistants = __esm({
|
|
|
175860
176003
|
return companyId ? { companyId } : void 0;
|
|
175861
176004
|
}
|
|
175862
176005
|
/* ---------- runtime 挑选(ADR §3.3.a):负载均衡 + 幂等 tie-break ---------- */
|
|
175863
|
-
|
|
176006
|
+
/**
|
|
176007
|
+
* 挑一台给助理用的运行时。优先级:
|
|
176008
|
+
* ① 调用方指定的那台(入职向导里用户在「我的助理」下拉选的),且它**在本公司在线**;
|
|
176009
|
+
* ② 公司默认 kind(`runtime_configs.default_assistant_runtime_kind`,缺省 claude-code)里按负载挑;
|
|
176010
|
+
* ③ 默认 kind 一台在线的都没有 → 退回本公司任意在线运行时,同样按负载挑。
|
|
176011
|
+
* 本公司一台在线的都没有才返回 null(→ 503 no-runtime)。
|
|
176012
|
+
*
|
|
176013
|
+
* ①③ 是 Bug 0308(2026-10-06)补的:此前只认默认 kind,团队只接了 codex / hermes 等机器时
|
|
176014
|
+
* 懒建助理 100% `no-runtime`——入职向导里用户明明选了 codex,助理照样建不出来,进团队后
|
|
176015
|
+
* 「没有可用的 Agent」。用户选了哪台就该用哪台;没选时有机器也不该因为 kind 不是默认值就一个不给。
|
|
176016
|
+
*/
|
|
176017
|
+
async pickAssistantRuntime(preferred) {
|
|
175864
176018
|
const runtimes = (await this.opts.listRuntimes(void 0, this.scope())).filter((r) => r.status === "online");
|
|
175865
176019
|
if (runtimes.length === 0) return null;
|
|
175866
176020
|
let defaultKind = DEFAULT_ASSISTANT_RUNTIME_KIND;
|
|
@@ -175871,8 +176025,12 @@ var init_assistants = __esm({
|
|
|
175871
176025
|
break;
|
|
175872
176026
|
}
|
|
175873
176027
|
}
|
|
175874
|
-
|
|
175875
|
-
|
|
176028
|
+
if (preferred) {
|
|
176029
|
+
const hit = runtimes.find((r) => r.nodeId === preferred.nodeId && r.kind === preferred.runtimeKind);
|
|
176030
|
+
if (hit) return hit;
|
|
176031
|
+
}
|
|
176032
|
+
const ofDefaultKind = runtimes.filter((r) => r.kind === defaultKind);
|
|
176033
|
+
const candidates = ofDefaultKind.length > 0 ? ofDefaultKind : runtimes;
|
|
175876
176034
|
const bindings = (await this.opts.registry.listBindings()).filter((b2) => b2.status === "active");
|
|
175877
176035
|
const load = (r) => bindings.filter((b2) => b2.nodeId === r.nodeId && b2.runtimeKind === r.kind).length;
|
|
175878
176036
|
return candidates.slice().sort((a, b2) => {
|
|
@@ -177316,7 +177474,7 @@ function buildWorkorderDraftDetail(draft, resolveActor, spawnReviewers, resolveR
|
|
|
177316
177474
|
const hasDeliverySummary = spawns.some((op) => op.type === DELIVERY_SUMMARY_ARTIFACT_TYPE);
|
|
177317
177475
|
const nodes = spawns.map((op) => {
|
|
177318
177476
|
const rows = spawnReviewers ? draft.plan.ops.filter((o) => o.action === "edit" && o.artifactId === op.id && o.reviewers !== void 0).reduce(
|
|
177319
|
-
(current,
|
|
177477
|
+
(current, edit3) => applyReviewerList({ current, next: edit3.reviewers }),
|
|
177320
177478
|
[...spawnReviewers(op.type, op.reviewers ?? [], { reviewersFinal: op.reviewersFinal === true })]
|
|
177321
177479
|
) : [];
|
|
177322
177480
|
const pv = rows.length > 0 ? reviewerPreviewOfRows(rows.map((r) => ({ actor: r.reviewerActorId, source: r.source, reviewGroup: r.reviewGroup }))) : null;
|
|
@@ -188413,16 +188571,16 @@ function parse2(options) {
|
|
|
188413
188571
|
);
|
|
188414
188572
|
const parser = {
|
|
188415
188573
|
constructs: constructs2,
|
|
188416
|
-
content:
|
|
188574
|
+
content: create2(content),
|
|
188417
188575
|
defined: [],
|
|
188418
|
-
document:
|
|
188419
|
-
flow:
|
|
188576
|
+
document: create2(document2),
|
|
188577
|
+
flow: create2(flow),
|
|
188420
188578
|
lazy: {},
|
|
188421
|
-
string:
|
|
188422
|
-
text:
|
|
188579
|
+
string: create2(string3),
|
|
188580
|
+
text: create2(text)
|
|
188423
188581
|
};
|
|
188424
188582
|
return parser;
|
|
188425
|
-
function
|
|
188583
|
+
function create2(initial) {
|
|
188426
188584
|
return creator;
|
|
188427
188585
|
function creator(from) {
|
|
188428
188586
|
return createTokenizer(parser, initial, from);
|
|
@@ -188866,10 +189024,10 @@ function compiler(options) {
|
|
|
188866
189024
|
events[start][1]._spread = listSpread;
|
|
188867
189025
|
return length;
|
|
188868
189026
|
}
|
|
188869
|
-
function opener(
|
|
189027
|
+
function opener(create2, and) {
|
|
188870
189028
|
return open3;
|
|
188871
189029
|
function open3(token2) {
|
|
188872
|
-
enter.call(this,
|
|
189030
|
+
enter.call(this, create2(token2), token2);
|
|
188873
189031
|
if (and) and.call(this, token2);
|
|
188874
189032
|
}
|
|
188875
189033
|
}
|
|
@@ -212960,10 +213118,10 @@ async function startOasisServer(opts) {
|
|
|
212960
213118
|
...fp(p2)
|
|
212961
213119
|
}))
|
|
212962
213120
|
] : [];
|
|
212963
|
-
const { randomUUID:
|
|
213121
|
+
const { randomUUID: randomUUID50 } = await import("node:crypto");
|
|
212964
213122
|
try {
|
|
212965
213123
|
await store.enqueuePendingMessage({
|
|
212966
|
-
id:
|
|
213124
|
+
id: randomUUID50(),
|
|
212967
213125
|
chatSessionId: input.chatSessionId,
|
|
212968
213126
|
text: input.text,
|
|
212969
213127
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -212996,11 +213154,11 @@ async function startOasisServer(opts) {
|
|
|
212996
213154
|
...f2?.mtime ? { srcMtime: f2.mtime } : {}
|
|
212997
213155
|
};
|
|
212998
213156
|
});
|
|
212999
|
-
const { randomUUID:
|
|
213157
|
+
const { randomUUID: randomUUID50 } = await import("node:crypto");
|
|
213000
213158
|
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
213001
213159
|
try {
|
|
213002
213160
|
await store.enqueuePendingMessage({
|
|
213003
|
-
id:
|
|
213161
|
+
id: randomUUID50(),
|
|
213004
213162
|
chatSessionId: input.chatSessionId,
|
|
213005
213163
|
text: "",
|
|
213006
213164
|
createdAt: nowIso,
|
|
@@ -214475,7 +214633,7 @@ async function startOasisServer(opts) {
|
|
|
214475
214633
|
const openRoom = async () => {
|
|
214476
214634
|
let chatSessionId2;
|
|
214477
214635
|
if (chatStore) {
|
|
214478
|
-
const { randomUUID:
|
|
214636
|
+
const { randomUUID: randomUUID50 } = await import("node:crypto");
|
|
214479
214637
|
const known = discussSessions.get(itemKey);
|
|
214480
214638
|
const knownSession = known ? await chatStore.getSession(known) : null;
|
|
214481
214639
|
if (knownSession && knownSession.workspace === ctx.workspace && knownSession.humanActorId === ctx.ownerId && (!body2.escalationId || knownSession.escalationId === body2.escalationId)) chatSessionId2 = known;
|
|
@@ -214484,7 +214642,7 @@ async function startOasisServer(opts) {
|
|
|
214484
214642
|
chatSessionId2 = existing[0]?.id;
|
|
214485
214643
|
}
|
|
214486
214644
|
if (!chatSessionId2) {
|
|
214487
|
-
chatSessionId2 =
|
|
214645
|
+
chatSessionId2 = randomUUID50();
|
|
214488
214646
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
214489
214647
|
const title = `\u89E3\u51B3\uFF1A${ctx.seed.slice(ctx.seed.indexOf("\uFF1A") + 1, ctx.seed.indexOf("\uFF1A") + 25) || "\u5DE5\u5355\u5361\u70B9"}`;
|
|
214490
214648
|
const reg0 = (await resolveEngine(currentCompanyId).catch(() => null))?.registry ?? opts.registry;
|
|
@@ -215690,7 +215848,7 @@ ${composed}`;
|
|
|
215690
215848
|
if (rejectedLedger.failures === 0 && retriedRow) {
|
|
215691
215849
|
turnPersisted = true;
|
|
215692
215850
|
} else if (rejectedLedger.failures === 0) {
|
|
215693
|
-
const { randomUUID:
|
|
215851
|
+
const { randomUUID: randomUUID50 } = await import("node:crypto");
|
|
215694
215852
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
215695
215853
|
const rejectedAttachments = effectiveAttachments.map((a) => ({
|
|
215696
215854
|
name: a.name,
|
|
@@ -215698,7 +215856,7 @@ ${composed}`;
|
|
|
215698
215856
|
...a.contentType !== void 0 ? { contentType: a.contentType } : {}
|
|
215699
215857
|
}));
|
|
215700
215858
|
await chatStore.appendMessage({
|
|
215701
|
-
id:
|
|
215859
|
+
id: randomUUID50(),
|
|
215702
215860
|
sessionId: persistTarget.id,
|
|
215703
215861
|
role: "user",
|
|
215704
215862
|
content: persistedUserMessage,
|
|
@@ -215783,14 +215941,14 @@ ${composed}`;
|
|
|
215783
215941
|
runtimeSessionId: session.nativeSessionId ?? session.id
|
|
215784
215942
|
}).catch(() => void 0);
|
|
215785
215943
|
}
|
|
215786
|
-
const { randomUUID:
|
|
215944
|
+
const { randomUUID: randomUUID50 } = await import("node:crypto");
|
|
215787
215945
|
const persistAttachments = effectiveAttachments.map((a) => ({
|
|
215788
215946
|
name: a.name,
|
|
215789
215947
|
...a.blobRef !== void 0 ? { blobRef: a.blobRef } : {},
|
|
215790
215948
|
...a.contentType !== void 0 ? { contentType: a.contentType } : {}
|
|
215791
215949
|
}));
|
|
215792
215950
|
if (!retriedRow) await chatStore.appendMessage({
|
|
215793
|
-
id:
|
|
215951
|
+
id: randomUUID50(),
|
|
215794
215952
|
sessionId: persistTarget.id,
|
|
215795
215953
|
role: "user",
|
|
215796
215954
|
content: persistedUserMessage,
|
|
@@ -216442,8 +216600,8 @@ ${composed}`;
|
|
|
216442
216600
|
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}` }));
|
|
216443
216601
|
return;
|
|
216444
216602
|
}
|
|
216445
|
-
const { randomUUID:
|
|
216446
|
-
const state =
|
|
216603
|
+
const { randomUUID: randomUUID50 } = await import("node:crypto");
|
|
216604
|
+
const state = randomUUID50();
|
|
216447
216605
|
const nameSlug = (actorName || actorId?.split(":").pop() || owner?.login || "bot").toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-|-$/g, "").slice(0, 24) || "bot";
|
|
216448
216606
|
const nameSuffix = await chooseAppNameSuffix(
|
|
216449
216607
|
{ employeeSlug: nameSlug, namePrefix: "oasis" },
|
|
@@ -220112,6 +220270,9 @@ var init_memory_control_plane_store = __esm({
|
|
|
220112
220270
|
/** protected:FileControlPlaneStore 子类 open() 回放快照时直接恢复(密码须持久化)。 */
|
|
220113
220271
|
accountSecrets = /* @__PURE__ */ new Map();
|
|
220114
220272
|
// accountId → { passwordHash?, tokenVersion }
|
|
220273
|
+
/** 已登出会话(ADR 0636;protected:文件版子类回放快照时直接恢复——不持久化的话重启即「复活」)。 */
|
|
220274
|
+
revokedSessions = /* @__PURE__ */ new Map();
|
|
220275
|
+
// tokenHash → record
|
|
220115
220276
|
verificationCodes = /* @__PURE__ */ new Map();
|
|
220116
220277
|
// email → record(短 TTL,文件版不持久化)
|
|
220117
220278
|
/** 组织模型三表(protected:文件版子类回放快照时直接恢复)。 */
|
|
@@ -220173,6 +220334,10 @@ var init_memory_control_plane_store = __esm({
|
|
|
220173
220334
|
}
|
|
220174
220335
|
if (patch.status !== void 0) c.status = patch.status;
|
|
220175
220336
|
if (patch.onboardingVariant !== void 0) c.onboardingVariant = patch.onboardingVariant;
|
|
220337
|
+
if (patch.timeZone !== void 0) {
|
|
220338
|
+
if (patch.timeZone === null) delete c.timeZone;
|
|
220339
|
+
else c.timeZone = patch.timeZone;
|
|
220340
|
+
}
|
|
220176
220341
|
if (patch.dissolvedAt !== void 0) {
|
|
220177
220342
|
if (patch.dissolvedAt === null) delete c.dissolvedAt;
|
|
220178
220343
|
else c.dissolvedAt = patch.dissolvedAt;
|
|
@@ -220469,6 +220634,15 @@ var init_memory_control_plane_store = __esm({
|
|
|
220469
220634
|
this.accountSecrets.set(accountId, { ...cur, tokenVersion: next });
|
|
220470
220635
|
return next;
|
|
220471
220636
|
}
|
|
220637
|
+
// —— 已登出会话(ADR 0636)——
|
|
220638
|
+
async revokeSession(rec2) {
|
|
220639
|
+
const cutoff = Date.parse(rec2.revokedAt);
|
|
220640
|
+
for (const [k2, r] of this.revokedSessions) if (Date.parse(r.expiresAt) < cutoff) this.revokedSessions.delete(k2);
|
|
220641
|
+
if (!this.revokedSessions.has(rec2.tokenHash)) this.revokedSessions.set(rec2.tokenHash, { ...rec2 });
|
|
220642
|
+
}
|
|
220643
|
+
async isSessionRevoked(tokenHash) {
|
|
220644
|
+
return this.revokedSessions.has(tokenHash);
|
|
220645
|
+
}
|
|
220472
220646
|
// —— 邮箱验证码(单邮箱一条 active)——
|
|
220473
220647
|
async putVerificationCode(rec2) {
|
|
220474
220648
|
this.verificationCodes.set(rec2.email, { ...rec2 });
|
|
@@ -220816,12 +220990,12 @@ function isUncategorizedProjectId(projectId2) {
|
|
|
220816
220990
|
function latestUncategorizedActivityAt(candidates) {
|
|
220817
220991
|
let bestIso = UNCATEGORIZED_UNKNOWN_TIME;
|
|
220818
220992
|
let bestMs = Date.parse(UNCATEGORIZED_UNKNOWN_TIME);
|
|
220819
|
-
for (const
|
|
220820
|
-
if (!
|
|
220821
|
-
const ms = Date.parse(
|
|
220993
|
+
for (const iso9 of candidates) {
|
|
220994
|
+
if (!iso9) continue;
|
|
220995
|
+
const ms = Date.parse(iso9);
|
|
220822
220996
|
if (Number.isNaN(ms) || ms <= bestMs) continue;
|
|
220823
220997
|
bestMs = ms;
|
|
220824
|
-
bestIso =
|
|
220998
|
+
bestIso = iso9;
|
|
220825
220999
|
}
|
|
220826
221000
|
return bestIso;
|
|
220827
221001
|
}
|
|
@@ -221594,9 +221768,9 @@ function deriveRounds(runs) {
|
|
|
221594
221768
|
}
|
|
221595
221769
|
return rounds.sort((a, b2) => Date.parse(a.startedAt) - Date.parse(b2.startedAt) || a.key.localeCompare(b2.key));
|
|
221596
221770
|
}
|
|
221597
|
-
function inWindow(
|
|
221598
|
-
if (!
|
|
221599
|
-
const ms = Date.parse(
|
|
221771
|
+
function inWindow(iso9, fromMs, toMs) {
|
|
221772
|
+
if (!iso9) return false;
|
|
221773
|
+
const ms = Date.parse(iso9);
|
|
221600
221774
|
return Number.isFinite(ms) && ms >= fromMs && ms <= toMs;
|
|
221601
221775
|
}
|
|
221602
221776
|
function computeFacts(input) {
|
|
@@ -225671,6 +225845,7 @@ var init_control_plane_file_store = __esm({
|
|
|
225671
225845
|
"upsertAccount",
|
|
225672
225846
|
"setAccountPassword",
|
|
225673
225847
|
"bumpAccountTokenVersion",
|
|
225848
|
+
"revokeSession",
|
|
225674
225849
|
"upsertDigitalEmployee",
|
|
225675
225850
|
"patchDigitalEmployee",
|
|
225676
225851
|
"putAgentCredential",
|
|
@@ -225710,6 +225885,7 @@ var init_control_plane_file_store = __esm({
|
|
|
225710
225885
|
for (const link of snap.inviteLinks ?? []) await MemoryControlPlaneStore.prototype.createInviteLink.call(store, link);
|
|
225711
225886
|
for (const a of snap.accounts ?? []) await MemoryControlPlaneStore.prototype.upsertAccount.call(store, a);
|
|
225712
225887
|
for (const e of snap.accountSecrets ?? []) store.accountSecrets.set(e.accountId, { ...e.secret });
|
|
225888
|
+
for (const r of snap.revokedSessions ?? []) store.revokedSessions.set(r.tokenHash, { ...r });
|
|
225713
225889
|
for (const e of snap.digitalEmployees ?? []) await MemoryControlPlaneStore.prototype.upsertDigitalEmployee.call(store, e);
|
|
225714
225890
|
for (const c of snap.agentCredentials ?? []) await MemoryControlPlaneStore.prototype.putAgentCredential.call(store, c);
|
|
225715
225891
|
for (const b2 of snap.principalBridges ?? []) await MemoryControlPlaneStore.prototype.putPrincipalBridge.call(store, b2);
|
|
@@ -225748,6 +225924,8 @@ var init_control_plane_file_store = __esm({
|
|
|
225748
225924
|
inviteLinks: [...this.inviteLinks.values()],
|
|
225749
225925
|
accounts,
|
|
225750
225926
|
accountSecrets,
|
|
225927
|
+
// 只有按哈希查的读面,直接读 protected map(同 offboardings)。
|
|
225928
|
+
revokedSessions: [...this.revokedSessions.values()],
|
|
225751
225929
|
digitalEmployees,
|
|
225752
225930
|
agentCredentials,
|
|
225753
225931
|
principalBridges,
|
|
@@ -230414,6 +230592,12 @@ function verifySession(token2, secret, nowMs) {
|
|
|
230414
230592
|
if (typeof claims.exp !== "number" || claims.exp <= nowMs) return null;
|
|
230415
230593
|
return claims;
|
|
230416
230594
|
}
|
|
230595
|
+
function sessionTokenHash(token2) {
|
|
230596
|
+
return (0, import_node_crypto54.createHash)("sha256").update(token2).digest("base64url");
|
|
230597
|
+
}
|
|
230598
|
+
function newSessionId() {
|
|
230599
|
+
return (0, import_node_crypto54.randomBytes)(16).toString("base64url");
|
|
230600
|
+
}
|
|
230417
230601
|
function generateCode() {
|
|
230418
230602
|
return String((0, import_node_crypto54.randomInt)(0, 1e6)).padStart(6, "0");
|
|
230419
230603
|
}
|
|
@@ -231728,40 +231912,21 @@ var init_migrate = __esm({
|
|
|
231728
231912
|
});
|
|
231729
231913
|
|
|
231730
231914
|
// ../server/src/domains/actors/variable-expiry.ts
|
|
231731
|
-
function zoneOffsetMs(ms, timeZone) {
|
|
231732
|
-
const parts = new Intl.DateTimeFormat("en-US", {
|
|
231733
|
-
timeZone,
|
|
231734
|
-
hour12: false,
|
|
231735
|
-
year: "numeric",
|
|
231736
|
-
month: "2-digit",
|
|
231737
|
-
day: "2-digit",
|
|
231738
|
-
hour: "2-digit",
|
|
231739
|
-
minute: "2-digit",
|
|
231740
|
-
second: "2-digit"
|
|
231741
|
-
}).formatToParts(new Date(ms));
|
|
231742
|
-
const get = (type) => Number(parts.find((p2) => p2.type === type)?.value ?? "0");
|
|
231743
|
-
const asIfUtc = Date.UTC(get("year"), get("month") - 1, get("day"), get("hour") % 24, get("minute"), get("second"));
|
|
231744
|
-
return asIfUtc - ms;
|
|
231745
|
-
}
|
|
231746
|
-
function zonedStartOfDayMs(dateStr, timeZone) {
|
|
231747
|
-
const utcMidnight = Date.parse(`${dateStr}T00:00:00Z`);
|
|
231748
|
-
const firstGuess = utcMidnight - zoneOffsetMs(utcMidnight, timeZone);
|
|
231749
|
-
const corrected = utcMidnight - zoneOffsetMs(firstGuess, timeZone);
|
|
231750
|
-
return corrected;
|
|
231751
|
-
}
|
|
231752
231915
|
function isVariableExpired(expiresAt2, nowMs, timeZone = DEFAULT_VARIABLE_TIME_ZONE) {
|
|
231753
231916
|
if (!expiresAt2) return false;
|
|
231754
231917
|
const t = Date.parse(expiresAt2);
|
|
231755
231918
|
if (Number.isNaN(t)) return false;
|
|
231756
231919
|
const d = new Date(t);
|
|
231757
231920
|
const dateStr = `${d.getUTCFullYear()}-${pad(d.getUTCMonth() + 1)}-${pad(d.getUTCDate())}`;
|
|
231921
|
+
if (!isValidDay(dateStr)) return false;
|
|
231758
231922
|
return nowMs >= zonedStartOfDayMs(dateStr, timeZone);
|
|
231759
231923
|
}
|
|
231760
231924
|
var DEFAULT_VARIABLE_TIME_ZONE, pad;
|
|
231761
231925
|
var init_variable_expiry = __esm({
|
|
231762
231926
|
"../server/src/domains/actors/variable-expiry.ts"() {
|
|
231763
231927
|
"use strict";
|
|
231764
|
-
|
|
231928
|
+
init_src();
|
|
231929
|
+
DEFAULT_VARIABLE_TIME_ZONE = DEFAULT_TIME_ZONE;
|
|
231765
231930
|
pad = (n) => String(n).padStart(2, "0");
|
|
231766
231931
|
}
|
|
231767
231932
|
});
|
|
@@ -233300,6 +233465,19 @@ ${input.description}
|
|
|
233300
233465
|
if (rows.some((r) => r.key === key2)) return true;
|
|
233301
233466
|
return this.variableRecordsEnabled() && (await this.opts.store.listVariableRecords()).some((r) => r.key === key2);
|
|
233302
233467
|
}
|
|
233468
|
+
/**
|
|
233469
|
+
* 变量到期按哪个时区算日界:本组织的生效时区(PRD v1.2 §7「按组织时区,未设置时按默认」)。
|
|
233470
|
+
* 读失败回落 Asia/Shanghai 并告警——宁可按默认日界判,也不让一次控制面抖动把整次派单打挂。
|
|
233471
|
+
*/
|
|
233472
|
+
async variableTimeZone() {
|
|
233473
|
+
if (!this.opts.timeZone) return DEFAULT_VARIABLE_TIME_ZONE;
|
|
233474
|
+
try {
|
|
233475
|
+
return await this.opts.timeZone();
|
|
233476
|
+
} catch (err) {
|
|
233477
|
+
console.warn(`[variables] \u8BFB\u7EC4\u7EC7\u65F6\u533A\u5931\u8D25\uFF0C\u6309 ${DEFAULT_VARIABLE_TIME_ZONE} \u5224\u5230\u671F\uFF1A${err.message}`);
|
|
233478
|
+
return DEFAULT_VARIABLE_TIME_ZONE;
|
|
233479
|
+
}
|
|
233480
|
+
}
|
|
233303
233481
|
async resolveActorEnv(actorId) {
|
|
233304
233482
|
const cfg = await this.opts.store.latestConfig(actorId);
|
|
233305
233483
|
const enabledConnectors = await this.effectiveEnabledConnectors(actorId, cfg);
|
|
@@ -233319,12 +233497,13 @@ ${input.description}
|
|
|
233319
233497
|
const decode2 = (ct) => ct.startsWith("plain:") ? ct.slice(6) : this.decrypt(ct);
|
|
233320
233498
|
const expiredWinner = /* @__PURE__ */ new Map();
|
|
233321
233499
|
const nowMs = Date.now();
|
|
233500
|
+
const timeZone = await this.variableTimeZone();
|
|
233322
233501
|
for (const row of rows) {
|
|
233323
233502
|
if (row.scope !== "global") continue;
|
|
233324
233503
|
if (row.actorId) continue;
|
|
233325
233504
|
if (!row.connectorId || enabledConnectors.has(row.connectorId)) {
|
|
233326
233505
|
env[row.key] = decode2(row.valueEncrypted);
|
|
233327
|
-
expiredWinner.set(row.key, isVariableExpired(row.expiresAt, nowMs));
|
|
233506
|
+
expiredWinner.set(row.key, isVariableExpired(row.expiresAt, nowMs, timeZone));
|
|
233328
233507
|
}
|
|
233329
233508
|
}
|
|
233330
233509
|
for (const row of rows) {
|
|
@@ -233332,7 +233511,7 @@ ${input.description}
|
|
|
233332
233511
|
if (row.actorId && row.actorId !== actorId) continue;
|
|
233333
233512
|
if (!row.connectorId || enabledConnectors.has(row.connectorId)) {
|
|
233334
233513
|
env[row.key] = decode2(row.valueEncrypted);
|
|
233335
|
-
expiredWinner.set(row.key, isVariableExpired(row.expiresAt, nowMs));
|
|
233514
|
+
expiredWinner.set(row.key, isVariableExpired(row.expiresAt, nowMs, timeZone));
|
|
233336
233515
|
}
|
|
233337
233516
|
}
|
|
233338
233517
|
for (const [key2, expired] of expiredWinner) if (expired) delete env[key2];
|
|
@@ -233376,13 +233555,14 @@ ${input.description}
|
|
|
233376
233555
|
if (!prev || rank[row.binding.kind] > rank[prev.binding.kind]) best.set(row.key, row);
|
|
233377
233556
|
}
|
|
233378
233557
|
const nowMs = Date.now();
|
|
233558
|
+
const timeZone = await this.variableTimeZone();
|
|
233379
233559
|
const out = [];
|
|
233380
233560
|
for (const row of best.values()) {
|
|
233381
233561
|
if (!isInjectableVariableName(row.key)) {
|
|
233382
233562
|
skipUninjectable(row.key);
|
|
233383
233563
|
continue;
|
|
233384
233564
|
}
|
|
233385
|
-
if (isVariableExpired(row.expiresAt, nowMs)) continue;
|
|
233565
|
+
if (isVariableExpired(row.expiresAt, nowMs, timeZone)) continue;
|
|
233386
233566
|
out.push(row);
|
|
233387
233567
|
}
|
|
233388
233568
|
return out;
|
|
@@ -233559,6 +233739,7 @@ ${input.description}
|
|
|
233559
233739
|
const merged = /* @__PURE__ */ new Map();
|
|
233560
233740
|
const expiredWinner = /* @__PURE__ */ new Map();
|
|
233561
233741
|
const nowMs = Date.now();
|
|
233742
|
+
const timeZone = await this.variableTimeZone();
|
|
233562
233743
|
const gated = (row) => !row.connectorId || enabledConnectors.has(row.connectorId);
|
|
233563
233744
|
const put3 = (row) => {
|
|
233564
233745
|
if (!gated(row)) return;
|
|
@@ -233572,7 +233753,7 @@ ${input.description}
|
|
|
233572
233753
|
deliveryMode: row.deliveryMode ?? "env",
|
|
233573
233754
|
origin: { ...row.actorId !== void 0 ? { actorId: row.actorId } : {}, ...row.projectId !== void 0 ? { projectId: row.projectId } : {} }
|
|
233574
233755
|
});
|
|
233575
|
-
expiredWinner.set(row.key, isVariableExpired(row.expiresAt, nowMs));
|
|
233756
|
+
expiredWinner.set(row.key, isVariableExpired(row.expiresAt, nowMs, timeZone));
|
|
233576
233757
|
};
|
|
233577
233758
|
for (const row of rows) {
|
|
233578
233759
|
if (row.scope === "global" && !row.actorId) put3(row);
|
|
@@ -234511,10 +234692,10 @@ function normalizeExpiresAt(raw) {
|
|
|
234511
234692
|
if (Number.isNaN(t)) throw new ApiError(400, "BAD_REQUEST", `expiresAt \u4E0D\u662F\u5408\u6CD5\u65E5\u671F\uFF1A${raw}`);
|
|
234512
234693
|
return new Date(t).toISOString();
|
|
234513
234694
|
}
|
|
234514
|
-
function assertCreatableVariable(key2, expiresAt2, nowMs = Date.now()) {
|
|
234695
|
+
function assertCreatableVariable(key2, expiresAt2, nowMs = Date.now(), timeZone = DEFAULT_VARIABLE_TIME_ZONE) {
|
|
234515
234696
|
const problem = variableNameProblem(key2);
|
|
234516
234697
|
if (problem) throw new ApiError(400, problem.code, problem.message);
|
|
234517
|
-
if (expiresAt2 && isVariableExpired(expiresAt2, nowMs)) {
|
|
234698
|
+
if (expiresAt2 && isVariableExpired(expiresAt2, nowMs, timeZone)) {
|
|
234518
234699
|
throw new ApiError(400, "VARIABLE_EXPIRY_NOT_FUTURE", "\u65B0\u5EFA\u53D8\u91CF\u7684\u5230\u671F\u65F6\u95F4\u987B\u665A\u4E8E\u4ECA\u5929");
|
|
234519
234700
|
}
|
|
234520
234701
|
}
|
|
@@ -235069,7 +235250,7 @@ function actorsDomain(opts) {
|
|
|
235069
235250
|
const { service } = await resolveCtx(req.auth.companyId);
|
|
235070
235251
|
const b2 = req.body;
|
|
235071
235252
|
if (typeof b2?.key !== "string" || !b2.key) throw new ApiError(400, "BAD_REQUEST", "\u7F3A\u5C11 key");
|
|
235072
|
-
const
|
|
235253
|
+
const create2 = parseCreateFlag(b2.create);
|
|
235073
235254
|
const legacyOpts = { replace: parseReplaceFlag(b2.replace), displaced: [] };
|
|
235074
235255
|
const expiresAt2 = normalizeExpiresAt(b2.expiresAt);
|
|
235075
235256
|
const audienceMeta = parseAudienceMeta(b2);
|
|
@@ -235123,9 +235304,9 @@ function actorsDomain(opts) {
|
|
|
235123
235304
|
by: req.auth.actor,
|
|
235124
235305
|
expiresAt: expiresAt2
|
|
235125
235306
|
};
|
|
235126
|
-
if (
|
|
235307
|
+
if (create2) {
|
|
235127
235308
|
if (b2.value === void 0 || b2.value === "") throw new ApiError(400, "BAD_REQUEST", "\u65B0\u5EFA\u53D8\u91CF\u5FC5\u987B\u63D0\u4F9B\u53D8\u91CF\u503C");
|
|
235128
|
-
assertCreatableVariable(b2.key, expiresAt2);
|
|
235309
|
+
assertCreatableVariable(b2.key, expiresAt2, Date.now(), await service.variableTimeZone());
|
|
235129
235310
|
const outcome = await service.createVariable({ ...input, value: b2.value }, legacyOpts).catch(rethrowBindingConflict);
|
|
235130
235311
|
if (outcome === "exists") throw await variableExistsError(service, b2.key, selector);
|
|
235131
235312
|
} else {
|
|
@@ -235262,7 +235443,7 @@ function actorsDomain(opts) {
|
|
|
235262
235443
|
throw new ApiError(400, "MISSING_DELIVERY_MODE", "\u5FC5\u987B\u663E\u5F0F\u63D0\u4F9B deliveryMode\uFF08env | ref | broker\uFF09\u2014\u2014\u6295\u9012\u6863\u51B3\u5B9A\u660E\u6587\u662F\u5426\u8FDB agent env\uFF0C\u4E0D\u8BBE\u7F3A\u7701");
|
|
235263
235444
|
}
|
|
235264
235445
|
const expiresAt2 = normalizeExpiresAt(b2.expiresAt);
|
|
235265
|
-
assertCreatableVariable(b2.key, expiresAt2);
|
|
235446
|
+
assertCreatableVariable(b2.key, expiresAt2, Date.now(), await service.variableTimeZone());
|
|
235266
235447
|
const bindings = parseBindingTargets(b2.bindings, "bindings");
|
|
235267
235448
|
const replace2 = parseBindingTargets(b2.replace, "replace");
|
|
235268
235449
|
const connectorId = await connectorOwner(service, b2.key);
|
|
@@ -235353,9 +235534,9 @@ function actorsDomain(opts) {
|
|
|
235353
235534
|
const actorId = req.params.id;
|
|
235354
235535
|
const b2 = req.body;
|
|
235355
235536
|
if (typeof b2?.key !== "string" || !b2.key) throw new ApiError(400, "BAD_REQUEST", "\u7F3A\u5C11 key");
|
|
235356
|
-
const
|
|
235537
|
+
const create2 = parseCreateFlag(b2.create);
|
|
235357
235538
|
const legacyOpts = { replace: parseReplaceFlag(b2.replace), displaced: [] };
|
|
235358
|
-
if (
|
|
235539
|
+
if (create2) {
|
|
235359
235540
|
const owner = await service.getActor(actorId);
|
|
235360
235541
|
if (!owner) throw new ApiError(404, "NOT_FOUND", `\u6CA1\u6709\u8FD9\u4E2A Agent\uFF1A${actorId}`);
|
|
235361
235542
|
if (owner.kind !== "agent") throw new ApiError(400, "BAD_REQUEST", "\u4E2A\u4EBA\u53D8\u91CF\u53EA\u80FD\u5EFA\u5728 Agent \u4E0A");
|
|
@@ -235371,8 +235552,8 @@ function actorsDomain(opts) {
|
|
|
235371
235552
|
"\u5FC5\u987B\u663E\u5F0F\u63D0\u4F9B deliveryMode\uFF08env | ref | broker\uFF09\u2014\u2014\u6295\u9012\u6863\u51B3\u5B9A\u660E\u6587\u662F\u5426\u8FDB agent env\uFF0C\u4E0D\u8BBE\u7F3A\u7701"
|
|
235372
235553
|
);
|
|
235373
235554
|
}
|
|
235374
|
-
if (
|
|
235375
|
-
if (
|
|
235555
|
+
if (create2 && (b2.value === void 0 || b2.value === "")) throw new ApiError(400, "BAD_REQUEST", "\u65B0\u5EFA\u53D8\u91CF\u5FC5\u987B\u63D0\u4F9B\u53D8\u91CF\u503C");
|
|
235556
|
+
if (create2) assertCreatableVariable(b2.key, expiresAt2, Date.now(), await service.variableTimeZone());
|
|
235376
235557
|
if (b2.value === void 0 || b2.value === "") return { status: 200, body: { ok: true } };
|
|
235377
235558
|
assertInjectableVariableName(b2.key);
|
|
235378
235559
|
if (b2.connectorId === void 0) {
|
|
@@ -235400,7 +235581,7 @@ function actorsDomain(opts) {
|
|
|
235400
235581
|
by: req.auth.actor,
|
|
235401
235582
|
expiresAt: expiresAt2
|
|
235402
235583
|
};
|
|
235403
|
-
if (
|
|
235584
|
+
if (create2) {
|
|
235404
235585
|
const outcome = await service.createVariable(input, legacyOpts).catch(rethrowBindingConflict);
|
|
235405
235586
|
if (outcome === "exists") throw await variableExistsError(service, b2.key, { actorId });
|
|
235406
235587
|
} else {
|
|
@@ -236431,6 +236612,7 @@ function createActorsDomain(opts) {
|
|
|
236431
236612
|
...opts.listSharedSkillFiles !== void 0 ? { listSharedSkillFiles: opts.listSharedSkillFiles } : {},
|
|
236432
236613
|
...opts.isInstalledSkillAvailable !== void 0 ? { isInstalledSkillAvailable: opts.isInstalledSkillAvailable } : {},
|
|
236433
236614
|
...opts.listBindingModelIds !== void 0 ? { listBindingModelIds: opts.listBindingModelIds } : {},
|
|
236615
|
+
...opts.companyTimeZone !== void 0 ? { timeZone: () => opts.companyTimeZone(companyOf()) } : {},
|
|
236434
236616
|
// 服务内部的变量写入(连接器授权)抢占记录时由服务自己记审计(ADR 0578 评审 N-3),与路由同一个旁账。
|
|
236435
236617
|
...opts.credentialAudit !== void 0 ? { credentialAudit: (r) => opts.credentialAudit({ ...r, companyId: companyOf() }) } : {},
|
|
236436
236618
|
...kernel !== void 0 ? { onRolesChanged: (a, r) => kernel.setActorRoles(a, r) } : {},
|
|
@@ -236555,7 +236737,9 @@ function assistantsDomain(opts) {
|
|
|
236555
236737
|
const humanId = req.params.humanId;
|
|
236556
236738
|
try {
|
|
236557
236739
|
await service.assertWritePermission(req.auth.actor, humanId);
|
|
236558
|
-
const
|
|
236740
|
+
const b2 = req.body ?? {};
|
|
236741
|
+
const preferred = typeof b2.nodeId === "string" && b2.nodeId && typeof b2.runtimeKind === "string" && b2.runtimeKind ? { nodeId: b2.nodeId, runtimeKind: b2.runtimeKind } : void 0;
|
|
236742
|
+
const r = await service.ensureFor(humanId, req.auth.actor, preferred);
|
|
236559
236743
|
return { status: 201, body: { agentId: r.agentId, source: r.source } };
|
|
236560
236744
|
} catch (e) {
|
|
236561
236745
|
toApiError2(e);
|
|
@@ -241623,7 +241807,8 @@ function fromRow(row) {
|
|
|
241623
241807
|
["result", str2(row["result"])],
|
|
241624
241808
|
["invalidReason", str2(row["invalid_reason"])],
|
|
241625
241809
|
["readAt", iso2(row["read_at"])],
|
|
241626
|
-
["item", row["item"] ?? void 0]
|
|
241810
|
+
["item", row["item"] ?? void 0],
|
|
241811
|
+
["chatSessionId", str2(row["chat_session_id"])]
|
|
241627
241812
|
];
|
|
241628
241813
|
for (const [k2, v2] of opt) if (v2 !== void 0 && v2 !== null) r[k2] = v2;
|
|
241629
241814
|
return r;
|
|
@@ -241789,6 +241974,7 @@ var init_notification_store = __esm({
|
|
|
241789
241974
|
read_at timestamptz,
|
|
241790
241975
|
item jsonb
|
|
241791
241976
|
)`);
|
|
241977
|
+
await sql.query(`ALTER TABLE "${s2}".notifications ADD COLUMN IF NOT EXISTS chat_session_id text`);
|
|
241792
241978
|
await sql.query(`CREATE UNIQUE INDEX IF NOT EXISTS notifications_pending_source_uq
|
|
241793
241979
|
ON "${s2}".notifications (recipient, source_key) WHERE status = 'pending'`);
|
|
241794
241980
|
await sql.query(`CREATE UNIQUE INDEX IF NOT EXISTS notifications_notice_source_uq
|
|
@@ -241801,8 +241987,8 @@ var init_notification_store = __esm({
|
|
|
241801
241987
|
const id = `ntf:${(0, import_node_crypto58.randomUUID)()}`;
|
|
241802
241988
|
const r = await this.sql.query(
|
|
241803
241989
|
`INSERT INTO ${this.t} (id, recipient, category, source_key, kind, workorder_id, node_id, card_id, actor_id,
|
|
241804
|
-
title, workspace_title, entered_at, updated_at, status, read_at, item)
|
|
241805
|
-
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$12,$13,$14,$15)
|
|
241990
|
+
title, workspace_title, entered_at, updated_at, status, read_at, item, chat_session_id)
|
|
241991
|
+
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$12,$13,$14,$15,$16)
|
|
241806
241992
|
ON CONFLICT DO NOTHING
|
|
241807
241993
|
RETURNING *`,
|
|
241808
241994
|
[
|
|
@@ -241820,7 +242006,8 @@ var init_notification_store = __esm({
|
|
|
241820
242006
|
n.enteredAt,
|
|
241821
242007
|
n.status ?? null,
|
|
241822
242008
|
n.readAt ?? null,
|
|
241823
|
-
n.item ? JSON.stringify(n.item) : null
|
|
242009
|
+
n.item ? JSON.stringify(n.item) : null,
|
|
242010
|
+
n.chatSessionId ?? null
|
|
241824
242011
|
]
|
|
241825
242012
|
);
|
|
241826
242013
|
if (r.rows[0]) return fromRow(r.rows[0]);
|
|
@@ -242472,11 +242659,11 @@ function parseUsageQuery(raw, now) {
|
|
|
242472
242659
|
let timeZone = "UTC";
|
|
242473
242660
|
if (raw.timeZone !== void 0 && raw.timeZone !== null && raw.timeZone !== "") {
|
|
242474
242661
|
if (typeof raw.timeZone !== "string") throw new UsageQueryError("timeZone \u5FC5\u987B\u662F IANA \u65F6\u533A\u540D");
|
|
242475
|
-
timeZone =
|
|
242662
|
+
timeZone = canonicalTimeZone2(raw.timeZone.trim());
|
|
242476
242663
|
}
|
|
242477
242664
|
return { range, asOf: new Date(asOfMs).toISOString(), timeZone };
|
|
242478
242665
|
}
|
|
242479
|
-
function
|
|
242666
|
+
function canonicalTimeZone2(tz) {
|
|
242480
242667
|
if (!tz) throw new UsageQueryError("timeZone \u5FC5\u987B\u662F IANA \u65F6\u533A\u540D");
|
|
242481
242668
|
try {
|
|
242482
242669
|
return new Intl.DateTimeFormat("en-US", { timeZone: tz }).resolvedOptions().timeZone;
|
|
@@ -242995,10 +243182,10 @@ var init_tags = __esm({
|
|
|
242995
243182
|
return [...new Set(ids2.map((s2) => String(s2).trim()).filter(Boolean))].filter((id) => known.has(id));
|
|
242996
243183
|
}
|
|
242997
243184
|
ensureByName(companyId, name) {
|
|
242998
|
-
const
|
|
242999
|
-
if (!
|
|
243000
|
-
const hit = this.entries(companyId).find((t) => nameKey(t.name) === nameKey(
|
|
243001
|
-
return hit ?? this.create(companyId, { name:
|
|
243185
|
+
const clean3 = cleanName(name ?? "");
|
|
243186
|
+
if (!clean3) return null;
|
|
243187
|
+
const hit = this.entries(companyId).find((t) => nameKey(t.name) === nameKey(clean3));
|
|
243188
|
+
return hit ?? this.create(companyId, { name: clean3 });
|
|
243002
243189
|
}
|
|
243003
243190
|
/** 子类落盘钩子(内存实现为空)。 */
|
|
243004
243191
|
persist() {
|
|
@@ -244383,6 +244570,11 @@ var init_projects = __esm({
|
|
|
244383
244570
|
});
|
|
244384
244571
|
|
|
244385
244572
|
// ../server/src/domains/companies/service.ts
|
|
244573
|
+
function assertProfileNameLength(value2, label2) {
|
|
244574
|
+
if (profileNameLength(value2) > PROFILE_NAME_MAX) {
|
|
244575
|
+
throw new CompanyError(400, "NAME_TOO_LONG", `${label2}\u6700\u591A ${PROFILE_NAME_MAX} \u4E2A\u5B57\u7B26`);
|
|
244576
|
+
}
|
|
244577
|
+
}
|
|
244386
244578
|
function normalizeEmail(raw) {
|
|
244387
244579
|
const v2 = raw?.trim().toLowerCase() ?? "";
|
|
244388
244580
|
return v2.length > 0 ? v2 : void 0;
|
|
@@ -244396,6 +244588,7 @@ var init_service6 = __esm({
|
|
|
244396
244588
|
"../server/src/domains/companies/service.ts"() {
|
|
244397
244589
|
"use strict";
|
|
244398
244590
|
import_node_crypto60 = require("node:crypto");
|
|
244591
|
+
init_src();
|
|
244399
244592
|
init_console_url();
|
|
244400
244593
|
ROLES = ["owner", "admin", "member"];
|
|
244401
244594
|
INVITABLE_ROLES = ["admin", "member"];
|
|
@@ -244417,8 +244610,11 @@ var init_service6 = __esm({
|
|
|
244417
244610
|
now;
|
|
244418
244611
|
sender;
|
|
244419
244612
|
consoleUrl;
|
|
244613
|
+
/** 部署默认时区,见 {@link CompaniesServiceOptions.defaultTimeZone}。 */
|
|
244614
|
+
defaultTimeZone;
|
|
244420
244615
|
constructor(opts) {
|
|
244421
244616
|
this.store = opts.store;
|
|
244617
|
+
this.defaultTimeZone = opts.defaultTimeZone ?? DEFAULT_TIME_ZONE;
|
|
244422
244618
|
this.now = opts.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
244423
244619
|
this.sender = opts.sender;
|
|
244424
244620
|
this.consoleUrl = opts.consoleUrl;
|
|
@@ -244484,12 +244680,47 @@ var init_service6 = __esm({
|
|
|
244484
244680
|
await this.store.updateCompany(companyId, { onboardingVariant: variant });
|
|
244485
244681
|
return { ...company, onboardingVariant: variant };
|
|
244486
244682
|
}
|
|
244683
|
+
/** 给成员看的公司:存的字段 + 实际生效的时区(含部署默认值回落)+ 部署默认时区。 */
|
|
244684
|
+
view(company) {
|
|
244685
|
+
return { ...company, effectiveTimeZone: effectiveTimeZone(company, this.defaultTimeZone), defaultTimeZone: this.defaultTimeZone };
|
|
244686
|
+
}
|
|
244687
|
+
/**
|
|
244688
|
+
* 这家组织实际生效的时区。组织不存在、或控制面读失败时回落部署默认值并告警——
|
|
244689
|
+
* 调用方是变量到期这类「必须给出一个答案」的判定,读不到组织行不该让派单整个失败。
|
|
244690
|
+
*/
|
|
244691
|
+
async effectiveTimeZoneOf(companyId) {
|
|
244692
|
+
if (!companyId) return this.defaultTimeZone;
|
|
244693
|
+
try {
|
|
244694
|
+
return effectiveTimeZone(await this.store.getCompany(companyId), this.defaultTimeZone);
|
|
244695
|
+
} catch (err) {
|
|
244696
|
+
console.warn(`[companies] \u8BFB\u7EC4\u7EC7 ${companyId} \u7684\u65F6\u533A\u5931\u8D25\uFF0C\u6309\u90E8\u7F72\u9ED8\u8BA4 ${this.defaultTimeZone}\uFF1A${err.message}`);
|
|
244697
|
+
return this.defaultTimeZone;
|
|
244698
|
+
}
|
|
244699
|
+
}
|
|
244700
|
+
/**
|
|
244701
|
+
* 设置组织时区(IANA 名,存规范写法);`null` = 清空,回到部署默认值。非法名 400。
|
|
244702
|
+
* 权限(owner/admin)由路由层强制;这里守「组织还可用」(D8.2)。
|
|
244703
|
+
*/
|
|
244704
|
+
async setTimeZone(companyId, timeZone) {
|
|
244705
|
+
const canonical2 = timeZone === null ? null : canonicalTimeZone(timeZone);
|
|
244706
|
+
if (timeZone !== null && !canonical2) {
|
|
244707
|
+
throw new CompanyError(400, "INVALID_TIME_ZONE", `timeZone \u4E0D\u662F\u5408\u6CD5\u7684 IANA \u65F6\u533A\u540D\uFF1A${JSON.stringify(timeZone)}`);
|
|
244708
|
+
}
|
|
244709
|
+
const company = await this.requireActiveCompany(companyId);
|
|
244710
|
+
await this.store.updateCompany(companyId, { timeZone: canonical2 });
|
|
244711
|
+
if (canonical2 === null) {
|
|
244712
|
+
const { timeZone: _drop, ...rest } = company;
|
|
244713
|
+
return rest;
|
|
244714
|
+
}
|
|
244715
|
+
return { ...company, timeZone: canonical2 };
|
|
244716
|
+
}
|
|
244487
244717
|
/**
|
|
244488
244718
|
* 改团队名称。**只改 name,不动 slug**——slug 是路由键(company:<slug> 与引擎 schema co_<slug>
|
|
244489
244719
|
* 的一部分,`create` 里注释「建成不可改」),改它会让所有历史链接失效。
|
|
244490
244720
|
* 校验(非空 / trim)在路由层做完了,这里假设 name 已经是非空 trim 过的字符串。
|
|
244491
244721
|
*/
|
|
244492
244722
|
async renameCompany(id, name) {
|
|
244723
|
+
assertProfileNameLength(name, "\u56E2\u961F\u7A7A\u95F4\u540D\u79F0");
|
|
244493
244724
|
const company = await this.requireCompany(id);
|
|
244494
244725
|
await this.store.updateCompany(id, { name });
|
|
244495
244726
|
return { ...company, name };
|
|
@@ -244608,6 +244839,7 @@ var init_service6 = __esm({
|
|
|
244608
244839
|
if (!SLUG_RE.test(slug5)) throw new CompanyError(400, "BAD_SLUG", "slug \u987B\u4E3A URL \u5B89\u5168\u7684\u5C0F\u5199\u4E32\uFF08^[a-z][a-z0-9-]*$\uFF09");
|
|
244609
244840
|
const name = input.name?.trim() ?? "";
|
|
244610
244841
|
if (!name) throw new CompanyError(400, "BAD_REQUEST", "\u7F3A\u5C11 name");
|
|
244842
|
+
assertProfileNameLength(name, "\u56E2\u961F\u7A7A\u95F4\u540D\u79F0");
|
|
244611
244843
|
if (await this.store.getCompanyBySlug(slug5)) throw new CompanyError(409, "SLUG_TAKEN", `slug \u5DF2\u88AB\u5360\u7528\uFF1A${slug5}`);
|
|
244612
244844
|
const company = {
|
|
244613
244845
|
id: `company:${slug5}`,
|
|
@@ -244800,6 +245032,7 @@ var init_service6 = __esm({
|
|
|
244800
245032
|
async setMemberDisplayName(companyId, accountId, displayName3, callerAccountId) {
|
|
244801
245033
|
const trimmed = displayName3.trim();
|
|
244802
245034
|
if (!trimmed) throw new CompanyError(400, "BAD_REQUEST", "displayName \u4E0D\u80FD\u4E3A\u7A7A");
|
|
245035
|
+
assertProfileNameLength(trimmed, "\u540D\u5B57");
|
|
244803
245036
|
await this.requireCompany(companyId);
|
|
244804
245037
|
const editingSomeoneElse = callerAccountId !== accountId;
|
|
244805
245038
|
const res = await this.store.updateMemberDisplayName(companyId, accountId, trimmed, {
|
|
@@ -245687,7 +245920,7 @@ function isCompanyCrossTenantPath(pathname) {
|
|
|
245687
245920
|
return COMPANY_CROSS_TENANT_PREFIXES.some((p2) => pathname === p2 || pathname.startsWith(`${p2}/`));
|
|
245688
245921
|
}
|
|
245689
245922
|
function companiesDomain(opts) {
|
|
245690
|
-
const { service, currentUser, blobs, resolveActorsCtx, offboarding, agentCredentials } = opts;
|
|
245923
|
+
const { service, currentUser, blobs, resolveActorsCtx, offboarding, agentCredentials, verifyAccountDeletionTicket, assistantOfHuman } = opts;
|
|
245691
245924
|
const mapErr = (e) => {
|
|
245692
245925
|
if (e instanceof CompanyError) throw new ApiError(e.status, e.code, e.message, e.details);
|
|
245693
245926
|
throw e;
|
|
@@ -245707,8 +245940,13 @@ function companiesDomain(opts) {
|
|
|
245707
245940
|
if (!name) return;
|
|
245708
245941
|
const { service: actorsSvc } = await resolveActorsCtx(member.companyId);
|
|
245709
245942
|
const existing = await actorsSvc.getActor(member.actorId);
|
|
245710
|
-
if (
|
|
245711
|
-
await
|
|
245943
|
+
if (existing && existing.name !== name) await actorsSvc.upsertActor({ ...existing, name }, by);
|
|
245944
|
+
const bond = assistantOfHuman ? await assistantOfHuman(member.companyId, member.actorId) : null;
|
|
245945
|
+
if (!bond || bond.origin !== "lazy-create") return;
|
|
245946
|
+
const assistant = await actorsSvc.getActor(bond.agentActorId);
|
|
245947
|
+
const assistantName = assistantNameFor(name);
|
|
245948
|
+
if (!assistant || assistant.name === assistantName) return;
|
|
245949
|
+
await actorsSvc.upsertActor({ ...assistant, name: assistantName }, by);
|
|
245712
245950
|
};
|
|
245713
245951
|
const requireIfMatch = (req) => {
|
|
245714
245952
|
const raw = req.raw.headers["if-match"];
|
|
@@ -245752,13 +245990,13 @@ function companiesDomain(opts) {
|
|
|
245752
245990
|
router.get("/api/companies", async (req) => {
|
|
245753
245991
|
const me = await whoami(req);
|
|
245754
245992
|
const items = await service.listForUser(me.accountId);
|
|
245755
|
-
return { status: 200, body: { items } };
|
|
245993
|
+
return { status: 200, body: { items: items.map((c) => service.view(c)) } };
|
|
245756
245994
|
});
|
|
245757
245995
|
router.get("/api/companies/:id", async (req) => {
|
|
245758
245996
|
const cid = req.params.id;
|
|
245759
245997
|
const me = await whoami(req);
|
|
245760
245998
|
const company = await service.get(cid);
|
|
245761
|
-
if (company && await service.getMember(cid, me.accountId)) return { status: 200, body: company };
|
|
245999
|
+
if (company && await service.getMember(cid, me.accountId)) return { status: 200, body: service.view(company) };
|
|
245762
246000
|
if (company && await service.hasPendingInvitation(cid, me.email)) {
|
|
245763
246001
|
return { status: 200, body: { id: company.id, name: company.name } };
|
|
245764
246002
|
}
|
|
@@ -245769,8 +246007,9 @@ function companiesDomain(opts) {
|
|
|
245769
246007
|
const b2 = req.body ?? {};
|
|
245770
246008
|
const hasName = b2.name !== void 0;
|
|
245771
246009
|
const hasVariant = b2.onboardingVariant !== void 0;
|
|
245772
|
-
|
|
245773
|
-
|
|
246010
|
+
const hasTimeZone = b2.timeZone !== void 0;
|
|
246011
|
+
if (!hasName && !hasVariant && !hasTimeZone) {
|
|
246012
|
+
throw new ApiError(400, "BAD_REQUEST", "\u7F3A\u5C11\u53EF\u66F4\u65B0\u5B57\u6BB5\uFF08name / onboardingVariant / timeZone\uFF09");
|
|
245774
246013
|
}
|
|
245775
246014
|
let trimmedName;
|
|
245776
246015
|
if (hasName) {
|
|
@@ -245782,6 +246021,9 @@ function companiesDomain(opts) {
|
|
|
245782
246021
|
if (hasVariant && b2.onboardingVariant !== "A" && b2.onboardingVariant !== "B") {
|
|
245783
246022
|
throw new ApiError(400, "BAD_REQUEST", `onboardingVariant \u987B\u4E3A "A" | "B"`);
|
|
245784
246023
|
}
|
|
246024
|
+
if (hasTimeZone && b2.timeZone !== null && !isValidTimeZone(b2.timeZone)) {
|
|
246025
|
+
throw new ApiError(400, "INVALID_TIME_ZONE", `timeZone \u987B\u4E3A\u5408\u6CD5\u7684 IANA \u65F6\u533A\u540D\uFF08\u5982 "Asia/Shanghai"\uFF09\uFF0C\u6216 null \u6E05\u7A7A\uFF1A${JSON.stringify(b2.timeZone)}`);
|
|
246026
|
+
}
|
|
245785
246027
|
await requireOwnerOrAdmin(req, cid);
|
|
245786
246028
|
let company;
|
|
245787
246029
|
if (trimmedName !== void 0) {
|
|
@@ -245790,7 +246032,10 @@ function companiesDomain(opts) {
|
|
|
245790
246032
|
if (hasVariant) {
|
|
245791
246033
|
company = await service.setOnboardingVariant(cid, b2.onboardingVariant).catch(mapErr);
|
|
245792
246034
|
}
|
|
245793
|
-
|
|
246035
|
+
if (hasTimeZone) {
|
|
246036
|
+
company = await service.setTimeZone(cid, b2.timeZone).catch(mapErr);
|
|
246037
|
+
}
|
|
246038
|
+
return { status: 200, body: service.view(company) };
|
|
245794
246039
|
});
|
|
245795
246040
|
router.post("/api/companies", async (req) => {
|
|
245796
246041
|
const b2 = req.body ?? {};
|
|
@@ -245942,6 +246187,16 @@ function companiesDomain(opts) {
|
|
|
245942
246187
|
router.delete("/api/accounts/me", async (req) => {
|
|
245943
246188
|
const off = requireOffboarding();
|
|
245944
246189
|
const me = await whoami(req);
|
|
246190
|
+
if (!verifyAccountDeletionTicket) {
|
|
246191
|
+
throw new ApiError(501, "NOT_IMPLEMENTED", "\u672C\u90E8\u7F72\u672A\u63A5\u5165\u6CE8\u9500\u90AE\u7BB1\u9A8C\u8BC1\uFF0C\u6682\u4E0D\u80FD\u6CE8\u9500\u8D26\u53F7");
|
|
246192
|
+
}
|
|
246193
|
+
const ticket = req.body?.ticket;
|
|
246194
|
+
if (typeof ticket !== "string" || !ticket) {
|
|
246195
|
+
throw new ApiError(403, "DELETION_VERIFICATION_REQUIRED", "\u6CE8\u9500\u524D\u9700\u8981\u5148\u5B8C\u6210\u90AE\u7BB1\u9A8C\u8BC1\u7801\u9A8C\u8BC1");
|
|
246196
|
+
}
|
|
246197
|
+
if (!await verifyAccountDeletionTicket(me.accountId, ticket)) {
|
|
246198
|
+
throw new ApiError(403, "DELETION_VERIFICATION_INVALID", "\u90AE\u7BB1\u9A8C\u8BC1\u5DF2\u5931\u6548\uFF0C\u8BF7\u91CD\u65B0\u83B7\u53D6\u9A8C\u8BC1\u7801");
|
|
246199
|
+
}
|
|
245945
246200
|
const { soloOwned, memberships } = await service.peekAccountDeletion(me.accountId).catch(mapErr);
|
|
245946
246201
|
for (const c of soloOwned) {
|
|
245947
246202
|
await service.dissolveSoloCompanyOnAccountDeletion(c.id, me.accountId).catch(mapErr);
|
|
@@ -246140,14 +246395,16 @@ function companiesDomain(opts) {
|
|
|
246140
246395
|
});
|
|
246141
246396
|
};
|
|
246142
246397
|
}
|
|
246143
|
-
var COMPANY_CROSS_TENANT_PREFIXES;
|
|
246398
|
+
var COMPANY_CROSS_TENANT_PREFIXES, assistantNameFor;
|
|
246144
246399
|
var init_routes6 = __esm({
|
|
246145
246400
|
"../server/src/domains/companies/routes.ts"() {
|
|
246146
246401
|
"use strict";
|
|
246402
|
+
init_src();
|
|
246147
246403
|
init_router();
|
|
246148
246404
|
init_service6();
|
|
246149
246405
|
init_image_upload();
|
|
246150
246406
|
COMPANY_CROSS_TENANT_PREFIXES = ["/api/companies", "/api/invitations", "/api/invite-links", "/api/accounts"];
|
|
246407
|
+
assistantNameFor = (humanName) => `${humanName}\u7684\u52A9\u7406`;
|
|
246151
246408
|
}
|
|
246152
246409
|
});
|
|
246153
246410
|
|
|
@@ -246273,13 +246530,35 @@ var init_agent_credentials = __esm({
|
|
|
246273
246530
|
}
|
|
246274
246531
|
});
|
|
246275
246532
|
|
|
246533
|
+
// ../server/src/domains/companies/time-zone.ts
|
|
246534
|
+
function defaultTimeZoneFromEnv(raw) {
|
|
246535
|
+
const v2 = raw?.trim();
|
|
246536
|
+
if (!v2) return DEFAULT_TIME_ZONE;
|
|
246537
|
+
const canonical2 = canonicalTimeZone(v2);
|
|
246538
|
+
if (!canonical2) {
|
|
246539
|
+
throw new Error(
|
|
246540
|
+
`${DEFAULT_TIME_ZONE_ENV}=${JSON.stringify(raw)} \u4E0D\u662F\u5408\u6CD5\u7684 IANA \u65F6\u533A\u540D\uFF08\u4F8B\uFF1AAsia/Shanghai\u3001America/New_York\u3001UTC\uFF09\uFF1B\u4E0D\u8BBE\u5219\u9ED8\u8BA4 ${DEFAULT_TIME_ZONE}\u3002\u62D2\u7EDD\u5E26\u7740\u9519\u8BEF\u65F6\u533A\u542F\u52A8\u3002`
|
|
246541
|
+
);
|
|
246542
|
+
}
|
|
246543
|
+
return canonical2;
|
|
246544
|
+
}
|
|
246545
|
+
var DEFAULT_TIME_ZONE_ENV;
|
|
246546
|
+
var init_time_zone2 = __esm({
|
|
246547
|
+
"../server/src/domains/companies/time-zone.ts"() {
|
|
246548
|
+
"use strict";
|
|
246549
|
+
init_src();
|
|
246550
|
+
DEFAULT_TIME_ZONE_ENV = "OASIS_DEFAULT_TIMEZONE";
|
|
246551
|
+
}
|
|
246552
|
+
});
|
|
246553
|
+
|
|
246276
246554
|
// ../server/src/domains/companies/index.ts
|
|
246277
246555
|
function createCompaniesDomain(opts) {
|
|
246278
246556
|
const service = new CompaniesService({
|
|
246279
246557
|
store: opts.store,
|
|
246280
246558
|
...opts.now !== void 0 ? { now: opts.now } : {},
|
|
246281
246559
|
...opts.sender !== void 0 ? { sender: opts.sender } : {},
|
|
246282
|
-
...opts.consoleUrl !== void 0 ? { consoleUrl: opts.consoleUrl } : {}
|
|
246560
|
+
...opts.consoleUrl !== void 0 ? { consoleUrl: opts.consoleUrl } : {},
|
|
246561
|
+
...opts.defaultTimeZone !== void 0 ? { defaultTimeZone: opts.defaultTimeZone } : {}
|
|
246283
246562
|
});
|
|
246284
246563
|
const currentUser = opts.currentUser ?? makeCurrentUser(opts.store);
|
|
246285
246564
|
const offboarding = new MemberOffboardingService({
|
|
@@ -246325,8 +246604,10 @@ function createCompaniesDomain(opts) {
|
|
|
246325
246604
|
offboarding,
|
|
246326
246605
|
currentUser,
|
|
246327
246606
|
...opts.agentCredentials !== void 0 ? { agentCredentials: opts.agentCredentials } : {},
|
|
246607
|
+
...opts.verifyAccountDeletionTicket !== void 0 ? { verifyAccountDeletionTicket: opts.verifyAccountDeletionTicket } : {},
|
|
246328
246608
|
...opts.blobs !== void 0 ? { blobs: opts.blobs } : {},
|
|
246329
|
-
...opts.resolveActorsCtx !== void 0 ? { resolveActorsCtx: opts.resolveActorsCtx } : {}
|
|
246609
|
+
...opts.resolveActorsCtx !== void 0 ? { resolveActorsCtx: opts.resolveActorsCtx } : {},
|
|
246610
|
+
...opts.assistantOfHuman !== void 0 ? { assistantOfHuman: opts.assistantOfHuman } : {}
|
|
246330
246611
|
}),
|
|
246331
246612
|
currentUser
|
|
246332
246613
|
};
|
|
@@ -246348,6 +246629,7 @@ var init_companies = __esm({
|
|
|
246348
246629
|
init_agent_credentials();
|
|
246349
246630
|
init_routes6();
|
|
246350
246631
|
init_migrate();
|
|
246632
|
+
init_time_zone2();
|
|
246351
246633
|
}
|
|
246352
246634
|
});
|
|
246353
246635
|
|
|
@@ -246365,6 +246647,14 @@ function parseCookies(header) {
|
|
|
246365
246647
|
function looksLikeEmail(s2) {
|
|
246366
246648
|
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(s2);
|
|
246367
246649
|
}
|
|
246650
|
+
function meetsChangePasswordPolicy(pw) {
|
|
246651
|
+
if (pw.length < 8) return false;
|
|
246652
|
+
let classes = 0;
|
|
246653
|
+
if (/[A-Za-z]/.test(pw)) classes++;
|
|
246654
|
+
if (/\d/.test(pw)) classes++;
|
|
246655
|
+
if (/[^A-Za-z0-9]/.test(pw)) classes++;
|
|
246656
|
+
return classes >= 2;
|
|
246657
|
+
}
|
|
246368
246658
|
function maskEmail(email2) {
|
|
246369
246659
|
const at2 = email2.indexOf("@");
|
|
246370
246660
|
if (at2 <= 0) return "***";
|
|
@@ -246378,11 +246668,13 @@ function createAuth(opts) {
|
|
|
246378
246668
|
const maxAttempts = opts.maxCodeAttempts ?? 5;
|
|
246379
246669
|
const resendThrottleMs = opts.resendThrottleMs ?? 60 * 1e3;
|
|
246380
246670
|
const riskFailureThreshold = opts.riskFailureThreshold ?? 3;
|
|
246671
|
+
const deletionTicketTtlMs = opts.deletionTicketTtlMs ?? 10 * 60 * 1e3;
|
|
246381
246672
|
const { store, sender, jwtSecret } = opts;
|
|
246673
|
+
const deletionTicketSecret = `${jwtSecret}\0account-deletion-ticket`;
|
|
246382
246674
|
const passwordFailures = /* @__PURE__ */ new Map();
|
|
246383
246675
|
const sessionCookie = (accountId, tokenVersion) => {
|
|
246384
246676
|
const t = now();
|
|
246385
|
-
const jwt = signSession({ sub: accountId, tokenVersion, iat: t, exp: t + sessionTtlMs }, jwtSecret);
|
|
246677
|
+
const jwt = signSession({ sub: accountId, tokenVersion, iat: t, exp: t + sessionTtlMs, jti: newSessionId() }, jwtSecret);
|
|
246386
246678
|
const attrs = [`${cookieName}=${jwt}`, "Path=/", "HttpOnly", "SameSite=Lax", `Max-Age=${Math.floor(sessionTtlMs / 1e3)}`];
|
|
246387
246679
|
if (opts.secureCookie) attrs.push("Secure");
|
|
246388
246680
|
return attrs.join("; ");
|
|
@@ -246398,45 +246690,55 @@ function createAuth(opts) {
|
|
|
246398
246690
|
const tokenVersion = sec?.tokenVersion ?? 0;
|
|
246399
246691
|
return { status: 200, body: account, setCookie: sessionCookie(account.id, tokenVersion) };
|
|
246400
246692
|
};
|
|
246401
|
-
const
|
|
246402
|
-
|
|
246403
|
-
const
|
|
246404
|
-
|
|
246693
|
+
const codeKey = (email2, purpose = "login") => purpose === "login" ? email2 : `${purpose} ${email2}`;
|
|
246694
|
+
const sendCodeDetailed = async (email2, purpose = "login") => {
|
|
246695
|
+
const key2 = codeKey(email2, purpose);
|
|
246696
|
+
const existing = await store.getVerificationCode(key2);
|
|
246697
|
+
const createdAt = existing ? Date.parse(existing.createdAt) : Number.NaN;
|
|
246698
|
+
if (existing && createdAt > now() - resendThrottleMs) {
|
|
246699
|
+
return { sent: false, retryAfterMs: createdAt + resendThrottleMs - now() };
|
|
246700
|
+
}
|
|
246405
246701
|
const code2 = generateCode();
|
|
246406
246702
|
const t = now();
|
|
246407
246703
|
await store.putVerificationCode({
|
|
246408
|
-
email:
|
|
246704
|
+
email: key2,
|
|
246409
246705
|
codeHash: hashCode(code2, jwtSecret),
|
|
246410
246706
|
createdAt: new Date(t).toISOString(),
|
|
246411
246707
|
expiresAt: new Date(t + codeTtlMs).toISOString(),
|
|
246412
246708
|
attempts: 0
|
|
246413
246709
|
});
|
|
246414
246710
|
try {
|
|
246415
|
-
await sender.sendCode(email2, code2);
|
|
246711
|
+
if (purpose === "login") await sender.sendCode(email2, code2);
|
|
246712
|
+
else await sender.sendCode(email2, code2, purpose);
|
|
246416
246713
|
} catch (e) {
|
|
246417
246714
|
console.error(`[auth] \u9A8C\u8BC1\u7801\u53D1\u9001\u5931\u8D25 ${maskEmail(email2)}: ${e instanceof Error ? e.message : String(e)}`);
|
|
246418
246715
|
}
|
|
246716
|
+
return { sent: true, retryAfterMs: resendThrottleMs };
|
|
246419
246717
|
};
|
|
246420
|
-
const
|
|
246421
|
-
|
|
246718
|
+
const sendCode = async (email2, purpose = "login") => (await sendCodeDetailed(email2, purpose)).sent;
|
|
246719
|
+
const verifyEmailCode = async (email2, code2, purpose = "login") => {
|
|
246720
|
+
const key2 = codeKey(email2, purpose);
|
|
246721
|
+
const rec2 = email2 ? await store.getVerificationCode(key2) : null;
|
|
246422
246722
|
if (!rec2) return "invalid";
|
|
246423
246723
|
if (Date.parse(rec2.expiresAt) <= now()) {
|
|
246424
|
-
await store.deleteVerificationCode(
|
|
246724
|
+
await store.deleteVerificationCode(key2);
|
|
246425
246725
|
return "expired";
|
|
246426
246726
|
}
|
|
246427
|
-
if (rec2.attempts >= maxAttempts) return "
|
|
246727
|
+
if (rec2.attempts >= maxAttempts) return "locked";
|
|
246428
246728
|
if (!code2 || !safeEqualHash(rec2.codeHash, hashCode(code2, jwtSecret))) {
|
|
246429
|
-
await store.incrementCodeAttempts(
|
|
246729
|
+
await store.incrementCodeAttempts(key2);
|
|
246430
246730
|
return "invalid";
|
|
246431
246731
|
}
|
|
246432
|
-
await store.deleteVerificationCode(
|
|
246732
|
+
await store.deleteVerificationCode(key2);
|
|
246433
246733
|
return "ok";
|
|
246434
246734
|
};
|
|
246735
|
+
const sessionToken = (headers) => parseCookies(typeof headers.cookie === "string" ? headers.cookie : void 0)[cookieName];
|
|
246435
246736
|
const currentAccount = async (headers) => {
|
|
246436
|
-
const raw =
|
|
246737
|
+
const raw = sessionToken(headers);
|
|
246437
246738
|
if (!raw) return null;
|
|
246438
246739
|
const claims = verifySession(raw, jwtSecret, now());
|
|
246439
246740
|
if (!claims) return null;
|
|
246741
|
+
if (await store.isSessionRevoked(sessionTokenHash(raw))) return null;
|
|
246440
246742
|
const sec = await store.getAccountSecret(claims.sub);
|
|
246441
246743
|
if (!sec || sec.tokenVersion !== claims.tokenVersion) return null;
|
|
246442
246744
|
const account = await store.getAccount(claims.sub);
|
|
@@ -246447,6 +246749,15 @@ function createAuth(opts) {
|
|
|
246447
246749
|
async sessionAccountId(headers) {
|
|
246448
246750
|
return (await currentAccount(headers))?.id ?? null;
|
|
246449
246751
|
},
|
|
246752
|
+
async verifyAccountDeletionTicket(accountId, ticket) {
|
|
246753
|
+
if (!ticket) return false;
|
|
246754
|
+
const claims = verifySession(ticket, deletionTicketSecret, now());
|
|
246755
|
+
if (!claims || claims.sub !== accountId) return false;
|
|
246756
|
+
const sec = await store.getAccountSecret(accountId);
|
|
246757
|
+
if (!sec || sec.tokenVersion !== claims.tokenVersion) return false;
|
|
246758
|
+
const account = await store.getAccount(accountId);
|
|
246759
|
+
return Boolean(account && mayHoldSession(account));
|
|
246760
|
+
},
|
|
246450
246761
|
async handle(method, pathname, rawBody, headers) {
|
|
246451
246762
|
const route2 = pathname.replace(/^\/api\/auth\//, "");
|
|
246452
246763
|
if (method === "GET" && route2 === "me") {
|
|
@@ -246550,7 +246861,75 @@ function createAuth(opts) {
|
|
|
246550
246861
|
await store.setAccountPassword(account.id, hashPassword(password));
|
|
246551
246862
|
return { status: 200, body: { ok: true } };
|
|
246552
246863
|
}
|
|
246864
|
+
if (route2 === "change-password/request-code") {
|
|
246865
|
+
const account = await currentAccount(headers);
|
|
246866
|
+
if (!account) return { status: 401, body: { error: { code: "UNAUTHENTICATED", message: "\u672A\u767B\u5F55" } } };
|
|
246867
|
+
const email2 = account.email.trim().toLowerCase();
|
|
246868
|
+
const { sent, retryAfterMs: retryAfterMs2 } = await sendCodeDetailed(email2, "change-password");
|
|
246869
|
+
return {
|
|
246870
|
+
status: 202,
|
|
246871
|
+
body: { ok: true, maskedEmail: maskEmail(email2), resent: sent, retryAfterSeconds: Math.max(0, Math.ceil(retryAfterMs2 / 1e3)) }
|
|
246872
|
+
};
|
|
246873
|
+
}
|
|
246874
|
+
if (route2 === "change-password") {
|
|
246875
|
+
const account = await currentAccount(headers);
|
|
246876
|
+
if (!account) return { status: 401, body: { error: { code: "UNAUTHENTICATED", message: "\u672A\u767B\u5F55" } } };
|
|
246877
|
+
const code2 = typeof parsed.code === "string" ? parsed.code.trim() : "";
|
|
246878
|
+
const password = typeof parsed.password === "string" ? parsed.password : "";
|
|
246879
|
+
if (!meetsChangePasswordPolicy(password)) {
|
|
246880
|
+
return { status: 400, body: { error: { code: "WEAK_PASSWORD", message: "\u81F3\u5C11 8 \u4F4D\uFF0C\u5305\u542B\u5B57\u6BCD\u3001\u6570\u5B57\u3001\u7B26\u53F7\u4E2D\u7684\u81F3\u5C11\u4E24\u7C7B" } } };
|
|
246881
|
+
}
|
|
246882
|
+
if (!/^\d{6}$/.test(code2)) {
|
|
246883
|
+
return { status: 400, body: { error: { code: "BAD_CODE_FORMAT", message: "\u8BF7\u8F93\u5165 6 \u4F4D\u6570\u5B57\u9A8C\u8BC1\u7801" } } };
|
|
246884
|
+
}
|
|
246885
|
+
const verdict = await verifyEmailCode(account.email.trim().toLowerCase(), code2, "change-password");
|
|
246886
|
+
if (verdict !== "ok") {
|
|
246887
|
+
return { status: 401, body: { error: { code: "INVALID_CODE", message: "\u9A8C\u8BC1\u7801\u5931\u6548\uFF0C\u8BF7\u91CD\u65B0\u83B7\u53D6", reason: verdict } } };
|
|
246888
|
+
}
|
|
246889
|
+
await store.setAccountPassword(account.id, hashPassword(password));
|
|
246890
|
+
return { status: 200, body: { ok: true } };
|
|
246891
|
+
}
|
|
246892
|
+
if (route2 === "account-deletion/request-code") {
|
|
246893
|
+
const account = await currentAccount(headers);
|
|
246894
|
+
if (!account) return { status: 401, body: { error: { code: "UNAUTHENTICATED", message: "\u672A\u767B\u5F55" } } };
|
|
246895
|
+
const email2 = account.email.trim().toLowerCase();
|
|
246896
|
+
const sent = await sendCode(email2, "account-deletion");
|
|
246897
|
+
return { status: 202, body: { ok: true, maskedEmail: maskEmail(email2), resent: sent } };
|
|
246898
|
+
}
|
|
246899
|
+
if (route2 === "account-deletion/verify-code") {
|
|
246900
|
+
const account = await currentAccount(headers);
|
|
246901
|
+
if (!account) return { status: 401, body: { error: { code: "UNAUTHENTICATED", message: "\u672A\u767B\u5F55" } } };
|
|
246902
|
+
const code2 = typeof parsed.code === "string" ? parsed.code.trim() : "";
|
|
246903
|
+
if (!/^\d{6}$/.test(code2)) {
|
|
246904
|
+
return { status: 400, body: { error: { code: "BAD_CODE_FORMAT", message: "\u8BF7\u8F93\u5165 6 \u4F4D\u6570\u5B57\u9A8C\u8BC1\u7801" } } };
|
|
246905
|
+
}
|
|
246906
|
+
const verdict = await verifyEmailCode(account.email.trim().toLowerCase(), code2, "account-deletion");
|
|
246907
|
+
if (verdict !== "ok") {
|
|
246908
|
+
const message = verdict === "expired" ? "\u9A8C\u8BC1\u7801\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u91CD\u65B0\u83B7\u53D6" : verdict === "locked" ? "\u9A8C\u8BC1\u7801\u9519\u8BEF\u6B21\u6570\u8FC7\u591A\uFF0C\u8BF7\u91CD\u65B0\u83B7\u53D6" : "\u9A8C\u8BC1\u7801\u9519\u8BEF\u6216\u5DF2\u5931\u6548\uFF0C\u8BF7\u68C0\u67E5\u540E\u91CD\u8BD5";
|
|
246909
|
+
return { status: 401, body: { error: { code: "INVALID_CODE", message, reason: verdict } } };
|
|
246910
|
+
}
|
|
246911
|
+
const sec = await store.getAccountSecret(account.id);
|
|
246912
|
+
const t = now();
|
|
246913
|
+
const exp = t + deletionTicketTtlMs;
|
|
246914
|
+
const ticket = signSession({ sub: account.id, tokenVersion: sec?.tokenVersion ?? 0, iat: t, exp }, deletionTicketSecret);
|
|
246915
|
+
return { status: 200, body: { ticket, expiresAt: new Date(exp).toISOString() } };
|
|
246916
|
+
}
|
|
246553
246917
|
if (route2 === "logout") {
|
|
246918
|
+
const raw = sessionToken(headers);
|
|
246919
|
+
const claims = raw ? verifySession(raw, jwtSecret, now()) : null;
|
|
246920
|
+
if (raw && claims) {
|
|
246921
|
+
try {
|
|
246922
|
+
await store.revokeSession({
|
|
246923
|
+
tokenHash: sessionTokenHash(raw),
|
|
246924
|
+
accountId: claims.sub,
|
|
246925
|
+
revokedAt: new Date(now()).toISOString(),
|
|
246926
|
+
expiresAt: new Date(claims.exp).toISOString()
|
|
246927
|
+
});
|
|
246928
|
+
} catch (e) {
|
|
246929
|
+
console.error(`[auth] \u767B\u51FA\u540A\u9500\u5931\u8D25 ${claims.sub}: ${e instanceof Error ? e.message : String(e)}`);
|
|
246930
|
+
return { status: 500, body: { error: { code: "LOGOUT_REVOKE_FAILED", message: "\u767B\u51FA\u672A\u5B8C\u6210\uFF0C\u8BF7\u91CD\u8BD5" } }, setCookie: clearCookie() };
|
|
246931
|
+
}
|
|
246932
|
+
}
|
|
246554
246933
|
return { status: 200, body: { ok: true }, setCookie: clearCookie() };
|
|
246555
246934
|
}
|
|
246556
246935
|
return { status: 404, body: { error: { code: "NOT_FOUND", message: pathname } } };
|
|
@@ -246574,8 +246953,8 @@ var init_auth = __esm({
|
|
|
246574
246953
|
// ../server/src/auth/sender.ts
|
|
246575
246954
|
function consoleSender() {
|
|
246576
246955
|
return {
|
|
246577
|
-
async sendCode(email2, code2) {
|
|
246578
|
-
console.log(`[auth] \u9A8C\u8BC1\u7801 \u2192 ${email2}: ${code2}`);
|
|
246956
|
+
async sendCode(email2, code2, purpose) {
|
|
246957
|
+
console.log(`[auth] ${purpose && purpose !== "login" ? CODE_PURPOSE_LABEL[purpose] : "\u9A8C\u8BC1\u7801"} \u2192 ${email2}: ${code2}`);
|
|
246579
246958
|
},
|
|
246580
246959
|
async sendInvitation(email2, opts) {
|
|
246581
246960
|
console.log(
|
|
@@ -246587,15 +246966,17 @@ function consoleSender() {
|
|
|
246587
246966
|
function resendSender(opts) {
|
|
246588
246967
|
const doFetch = opts.fetchImpl ?? fetch;
|
|
246589
246968
|
return {
|
|
246590
|
-
async sendCode(email2, code2) {
|
|
246969
|
+
async sendCode(email2, code2, purpose) {
|
|
246970
|
+
const deletion = purpose === "account-deletion";
|
|
246971
|
+
const label2 = CODE_PURPOSE_LABEL[purpose ?? "login"];
|
|
246591
246972
|
const res = await doFetch("https://api.resend.com/emails", {
|
|
246592
246973
|
method: "POST",
|
|
246593
246974
|
headers: { authorization: `Bearer ${opts.apiKey}`, "content-type": "application/json" },
|
|
246594
246975
|
body: JSON.stringify({
|
|
246595
246976
|
from: opts.from,
|
|
246596
246977
|
to: [email2],
|
|
246597
|
-
subject:
|
|
246598
|
-
html: `<div style="font-family:sans-serif;max-width:400px;margin:0 auto"><h2
|
|
246978
|
+
subject: `\u4F60\u7684 Oasis ${label2}`,
|
|
246979
|
+
html: `<div style="font-family:sans-serif;max-width:400px;margin:0 auto"><h2>${label2}</h2><p style="font-size:32px;font-weight:bold;letter-spacing:8px;margin:24px 0">${code2}</p><p>\u9A8C\u8BC1\u7801 10 \u5206\u949F\u5185\u6709\u6548\u3002</p>` + (deletion ? `<p style="color:#b42318;font-size:14px">\u4F60\u6B63\u5728\u6CE8\u9500 Oasis \u8D26\u53F7\uFF0C\u6CE8\u9500\u540E\u4E0D\u53EF\u6062\u590D\u3002\u8BF7\u52FF\u628A\u9A8C\u8BC1\u7801\u544A\u8BC9\u4EFB\u4F55\u4EBA\uFF1B\u5982\u679C\u4E0D\u662F\u4F60\u672C\u4EBA\u64CD\u4F5C\uFF0C\u8BF7\u5FFD\u7565\u6B64\u90AE\u4EF6\u5E76\u5C3D\u5FEB\u4FEE\u6539\u5BC6\u7801\u3002</p></div>` : purpose === "change-password" ? `<p style="color:#b42318;font-size:14px">\u4F60\u6B63\u5728\u4FEE\u6539 Oasis \u767B\u5F55\u5BC6\u7801\u3002\u8BF7\u52FF\u628A\u9A8C\u8BC1\u7801\u544A\u8BC9\u4EFB\u4F55\u4EBA\uFF1B\u5982\u679C\u4E0D\u662F\u4F60\u672C\u4EBA\u64CD\u4F5C\uFF0C\u8BF7\u5FFD\u7565\u6B64\u90AE\u4EF6\u5E76\u5C3D\u5FEB\u68C0\u67E5\u8D26\u53F7\u5B89\u5168\u3002</p></div>` : `<p style="color:#666;font-size:14px">\u5982\u679C\u4E0D\u662F\u4F60\u672C\u4EBA\u64CD\u4F5C\uFF0C\u5FFD\u7565\u6B64\u90AE\u4EF6\u5373\u53EF\u3002</p></div>`)
|
|
246599
246980
|
})
|
|
246600
246981
|
});
|
|
246601
246982
|
if (!res.ok) {
|
|
@@ -246622,9 +247003,15 @@ function resendSender(opts) {
|
|
|
246622
247003
|
}
|
|
246623
247004
|
};
|
|
246624
247005
|
}
|
|
247006
|
+
var CODE_PURPOSE_LABEL;
|
|
246625
247007
|
var init_sender = __esm({
|
|
246626
247008
|
"../server/src/auth/sender.ts"() {
|
|
246627
247009
|
"use strict";
|
|
247010
|
+
CODE_PURPOSE_LABEL = {
|
|
247011
|
+
login: "\u767B\u5F55\u9A8C\u8BC1\u7801",
|
|
247012
|
+
"account-deletion": "\u6CE8\u9500\u8D26\u53F7\u9A8C\u8BC1\u7801",
|
|
247013
|
+
"change-password": "\u4FEE\u6539\u5BC6\u7801\u9A8C\u8BC1\u7801"
|
|
247014
|
+
};
|
|
246628
247015
|
}
|
|
246629
247016
|
});
|
|
246630
247017
|
|
|
@@ -249921,7 +250308,7 @@ var init_notification_reconciler = __esm({
|
|
|
249921
250308
|
if (!store) return 0;
|
|
249922
250309
|
const members = new Set(ctx.humans);
|
|
249923
250310
|
const titleOf = workspaceTitleMap(model);
|
|
249924
|
-
const fresh = (
|
|
250311
|
+
const fresh = (iso9) => nowMs - Date.parse(iso9) <= TASK_NOTICE_FRESH_MS;
|
|
249925
250312
|
let sent = 0;
|
|
249926
250313
|
const emit = async (workorderId, kind, rec2, trigger) => {
|
|
249927
250314
|
const recipients = taskNoticeRecipients(model, workorderId, await loadSnapshot2(workorderId), members, trigger);
|
|
@@ -250143,6 +250530,7 @@ function pushThrottleOptionsFromEnv(env = process.env) {
|
|
|
250143
250530
|
};
|
|
250144
250531
|
}
|
|
250145
250532
|
function shouldPush(record10) {
|
|
250533
|
+
if (record10.category === "todo") return !record10.readAt;
|
|
250146
250534
|
if (record10.category !== "action") return false;
|
|
250147
250535
|
if (record10.readAt) return false;
|
|
250148
250536
|
return record10.status === "pending";
|
|
@@ -250458,7 +250846,7 @@ var init_push_notifier = __esm({
|
|
|
250458
250846
|
function makeSeededWorkorderCreator(deps) {
|
|
250459
250847
|
const locks = createKeyedMutex();
|
|
250460
250848
|
const genWorkspace = deps.genWorkspace ?? (() => `ws:wo-${(0, import_node_crypto66.randomUUID)().slice(0, 8)}`);
|
|
250461
|
-
const
|
|
250849
|
+
const create2 = async (input) => {
|
|
250462
250850
|
const company = input.companyId && deps.resolveCompany ? await deps.resolveCompany(input.companyId) : void 0;
|
|
250463
250851
|
const kernel = company?.kernel ?? deps.kernel;
|
|
250464
250852
|
const blobs = company?.blobs ?? deps.blobs;
|
|
@@ -250546,7 +250934,7 @@ function makeSeededWorkorderCreator(deps) {
|
|
|
250546
250934
|
return async (input) => {
|
|
250547
250935
|
const release = await locks.acquire(`${input.companyId ?? ""}\0${input.idempotencyKey ?? (0, import_node_crypto66.randomUUID)()}`);
|
|
250548
250936
|
try {
|
|
250549
|
-
return await
|
|
250937
|
+
return await create2(input);
|
|
250550
250938
|
} finally {
|
|
250551
250939
|
release();
|
|
250552
250940
|
}
|
|
@@ -254763,6 +255151,496 @@ var init_agent_default_runtime_store = __esm({
|
|
|
254763
255151
|
}
|
|
254764
255152
|
});
|
|
254765
255153
|
|
|
255154
|
+
// ../server/src/domains/todos/flag.ts
|
|
255155
|
+
function personalTodoEnabledFromEnv(env = process.env) {
|
|
255156
|
+
const raw = (env["OASIS_PERSONAL_TODO"] ?? "").trim().toLowerCase();
|
|
255157
|
+
return !(raw === "off" || raw === "0" || raw === "false");
|
|
255158
|
+
}
|
|
255159
|
+
var init_flag = __esm({
|
|
255160
|
+
"../server/src/domains/todos/flag.ts"() {
|
|
255161
|
+
"use strict";
|
|
255162
|
+
}
|
|
255163
|
+
});
|
|
255164
|
+
|
|
255165
|
+
// ../server/src/domains/todos/service.ts
|
|
255166
|
+
function assertFirstVersionAssignee(creator, assignee) {
|
|
255167
|
+
if (creator !== assignee) {
|
|
255168
|
+
throw new ApiError(403, "TODO_ASSIGNEE_NOT_SELF", "\u4E2A\u4EBA\u5F85\u529E\u7B2C\u4E00\u7248\u53EA\u80FD\u8BB0\u7ED9\u81EA\u5DF1\uFF1A\u53D1\u8D77\u4EBA\u548C\u627F\u63A5\u4EBA\u5FC5\u987B\u662F\u540C\u4E00\u4E2A\u4EBA\u3002");
|
|
255169
|
+
}
|
|
255170
|
+
}
|
|
255171
|
+
function canAccessTodo(todo, caller) {
|
|
255172
|
+
return isTodoParty(todo, caller.principal);
|
|
255173
|
+
}
|
|
255174
|
+
function newTodoId() {
|
|
255175
|
+
return `td_${(0, import_node_crypto69.randomBytes)(4).toString("hex")}`;
|
|
255176
|
+
}
|
|
255177
|
+
function assertDay(day, what = "\u622A\u6B62\u65E5") {
|
|
255178
|
+
if (typeof day !== "string" || !isValidDay(day)) {
|
|
255179
|
+
throw new ApiError(400, "TODO_INVALID_DATE", `${what}\u987B\u4E3A\u4E0D\u5E26\u65F6\u533A\u7684\u771F\u5B9E\u65E5\u671F YYYY-MM-DD\uFF08\u4F8B\uFF1A2026-10-09\uFF09\uFF0C\u6536\u5230\uFF1A${String(day)}`);
|
|
255180
|
+
}
|
|
255181
|
+
}
|
|
255182
|
+
function assertTime(time3, what = "\u622A\u6B62\u65F6\u523B") {
|
|
255183
|
+
if (typeof time3 !== "string" || !isValidTodoTime(time3)) {
|
|
255184
|
+
throw new ApiError(400, "TODO_INVALID_TIME", `${what}\u987B\u4E3A 24 \u5C0F\u65F6\u5236 HH:mm\uFF08\u4F8B\uFF1A18:00\uFF09\uFF0C\u6536\u5230\uFF1A${String(time3)}`);
|
|
255185
|
+
}
|
|
255186
|
+
}
|
|
255187
|
+
function assertStartBeforeDue(t) {
|
|
255188
|
+
if (!isTodoStartBeforeDue(t)) {
|
|
255189
|
+
const fmt = (d, h) => `${d}${h ? ` ${h}` : ""}`;
|
|
255190
|
+
throw new ApiError(400, "TODO_START_AFTER_DUE", `\u5F00\u59CB\uFF08${fmt(t.startDate, t.startTime)}\uFF09\u4E0D\u80FD\u665A\u4E8E\u622A\u6B62\uFF08${fmt(t.dueDate, t.dueTime)}\uFF09`);
|
|
255191
|
+
}
|
|
255192
|
+
}
|
|
255193
|
+
var import_node_crypto69, TITLE_MAX, NOTE_MAX, REASON_MAX, clean2, TodoService;
|
|
255194
|
+
var init_service10 = __esm({
|
|
255195
|
+
"../server/src/domains/todos/service.ts"() {
|
|
255196
|
+
"use strict";
|
|
255197
|
+
import_node_crypto69 = require("node:crypto");
|
|
255198
|
+
init_src();
|
|
255199
|
+
init_router();
|
|
255200
|
+
TITLE_MAX = 200;
|
|
255201
|
+
NOTE_MAX = 4e3;
|
|
255202
|
+
REASON_MAX = 500;
|
|
255203
|
+
clean2 = (v2) => {
|
|
255204
|
+
const t = v2?.trim();
|
|
255205
|
+
return t ? t : void 0;
|
|
255206
|
+
};
|
|
255207
|
+
TodoService = class {
|
|
255208
|
+
constructor(deps) {
|
|
255209
|
+
this.deps = deps;
|
|
255210
|
+
}
|
|
255211
|
+
nowMs() {
|
|
255212
|
+
return this.deps.now?.() ?? Date.now();
|
|
255213
|
+
}
|
|
255214
|
+
async today() {
|
|
255215
|
+
return todoToday(await this.deps.timeZone(), this.nowMs());
|
|
255216
|
+
}
|
|
255217
|
+
async respond(todo) {
|
|
255218
|
+
const today = await this.today();
|
|
255219
|
+
return { today, todayLine: formatTodayLine(today), todo };
|
|
255220
|
+
}
|
|
255221
|
+
change(todoId, caller, at2, field, oldValue, newValue, reason) {
|
|
255222
|
+
return {
|
|
255223
|
+
id: `tdc_${(0, import_node_crypto69.randomUUID)()}`,
|
|
255224
|
+
todoId,
|
|
255225
|
+
actorId: caller.principal,
|
|
255226
|
+
at: at2,
|
|
255227
|
+
field,
|
|
255228
|
+
...caller.hand ? { handActorId: caller.hand } : {},
|
|
255229
|
+
...oldValue !== void 0 ? { oldValue } : {},
|
|
255230
|
+
...newValue !== void 0 ? { newValue } : {},
|
|
255231
|
+
...reason ? { reason } : {}
|
|
255232
|
+
};
|
|
255233
|
+
}
|
|
255234
|
+
async create(caller, input) {
|
|
255235
|
+
const title = clean2(input.title);
|
|
255236
|
+
if (!title) throw new ApiError(400, "TODO_INVALID", "title \u4E0D\u80FD\u4E3A\u7A7A");
|
|
255237
|
+
if (title.length > TITLE_MAX) throw new ApiError(400, "TODO_INVALID", `title \u4E0D\u80FD\u8D85\u8FC7 ${TITLE_MAX} \u5B57`);
|
|
255238
|
+
const note = clean2(input.note);
|
|
255239
|
+
if (note && note.length > NOTE_MAX) throw new ApiError(400, "TODO_INVALID", `note \u4E0D\u80FD\u8D85\u8FC7 ${NOTE_MAX} \u5B57`);
|
|
255240
|
+
assertDay(input.dueDate);
|
|
255241
|
+
if (input.dueTime !== void 0) assertTime(input.dueTime);
|
|
255242
|
+
if (input.startDate !== void 0) assertDay(input.startDate, "\u5F00\u59CB\u65E5");
|
|
255243
|
+
if (input.startTime !== void 0) {
|
|
255244
|
+
if (input.startDate === void 0) throw new ApiError(400, "TODO_INVALID", "\u6709\u5F00\u59CB\u65F6\u523B\u5C31\u8981\u6709\u5F00\u59CB\u65E5\uFF08startTime \u987B\u914D startDate\uFF09");
|
|
255245
|
+
assertTime(input.startTime, "\u5F00\u59CB\u65F6\u523B");
|
|
255246
|
+
}
|
|
255247
|
+
assertStartBeforeDue({ ...input });
|
|
255248
|
+
const creator = caller.principal;
|
|
255249
|
+
const assignee = caller.principal;
|
|
255250
|
+
assertFirstVersionAssignee(creator, assignee);
|
|
255251
|
+
const at2 = new Date(this.nowMs()).toISOString();
|
|
255252
|
+
const todo = {
|
|
255253
|
+
id: newTodoId(),
|
|
255254
|
+
title,
|
|
255255
|
+
...note ? { note } : {},
|
|
255256
|
+
creatorActorId: creator,
|
|
255257
|
+
assigneeActorId: assignee,
|
|
255258
|
+
recordedByActorId: caller.actor,
|
|
255259
|
+
dueDate: input.dueDate,
|
|
255260
|
+
...input.dueTime ? { dueTime: input.dueTime } : {},
|
|
255261
|
+
...input.startDate ? { startDate: input.startDate } : {},
|
|
255262
|
+
...input.startTime ? { startTime: input.startTime } : {},
|
|
255263
|
+
status: "open",
|
|
255264
|
+
...clean2(input.sourceChatSessionId) ? { sourceChatSessionId: clean2(input.sourceChatSessionId) } : {},
|
|
255265
|
+
createdAt: at2,
|
|
255266
|
+
updatedAt: at2
|
|
255267
|
+
};
|
|
255268
|
+
const saved = await this.deps.store.create(todo, [this.change(todo.id, caller, at2, "created", void 0, title)]);
|
|
255269
|
+
return this.respond(saved);
|
|
255270
|
+
}
|
|
255271
|
+
async list(caller, opts = {}) {
|
|
255272
|
+
const statuses2 = opts.all ? ["open", "done", "cancelled"] : ["open"];
|
|
255273
|
+
const items = (await this.deps.store.listInvolving(caller.principal, statuses2)).filter((t) => canAccessTodo(t, caller));
|
|
255274
|
+
const today = await this.today();
|
|
255275
|
+
return { today, todayLine: formatTodayLine(today), items };
|
|
255276
|
+
}
|
|
255277
|
+
/** 读一条并校验权限:不存在与无权限分开报(无权限 403——任务书口径「其他人 403」)。 */
|
|
255278
|
+
async get(caller, id) {
|
|
255279
|
+
const todo = await this.deps.store.get(id);
|
|
255280
|
+
if (!todo) throw new ApiError(404, "TODO_NOT_FOUND", `\u5F85\u529E ${id} \u4E0D\u5B58\u5728`);
|
|
255281
|
+
if (!canAccessTodo(todo, caller)) throw new ApiError(403, "TODO_FORBIDDEN", "\u65E0\u6743\u67E5\u770B\u6216\u4FEE\u6539\u8FD9\u6761\u5F85\u529E");
|
|
255282
|
+
return todo;
|
|
255283
|
+
}
|
|
255284
|
+
async save(caller, before, next, changes) {
|
|
255285
|
+
if (changes.length === 0) return this.respond(before);
|
|
255286
|
+
const saved = await this.deps.store.update(next, before.updatedAt, changes);
|
|
255287
|
+
if (!saved) throw new ApiError(409, "TODO_CONFLICT", "\u8FD9\u6761\u5F85\u529E\u521A\u88AB\u522B\u5904\u6539\u8FC7\uFF0C\u8BF7\u91CD\u65B0\u8BFB\u53D6\u540E\u518D\u6539");
|
|
255288
|
+
return this.respond(saved);
|
|
255289
|
+
}
|
|
255290
|
+
async edit(caller, id, input) {
|
|
255291
|
+
const before = await this.get(caller, id);
|
|
255292
|
+
const reason = clean2(input.reason);
|
|
255293
|
+
if (reason && reason.length > REASON_MAX) throw new ApiError(400, "TODO_INVALID", `reason \u4E0D\u80FD\u8D85\u8FC7 ${REASON_MAX} \u5B57`);
|
|
255294
|
+
const at2 = new Date(this.nowMs()).toISOString();
|
|
255295
|
+
const next = { ...before };
|
|
255296
|
+
const changes = [];
|
|
255297
|
+
const set = (field, value2) => {
|
|
255298
|
+
const old = before[field];
|
|
255299
|
+
if (old === value2) return;
|
|
255300
|
+
if (value2 === void 0) delete next[field];
|
|
255301
|
+
else next[field] = value2;
|
|
255302
|
+
changes.push(this.change(id, caller, at2, field, old, value2, reason));
|
|
255303
|
+
};
|
|
255304
|
+
if (input.title !== void 0) {
|
|
255305
|
+
const title = clean2(input.title);
|
|
255306
|
+
if (!title) throw new ApiError(400, "TODO_INVALID", "title \u4E0D\u80FD\u6E05\u7A7A");
|
|
255307
|
+
if (title.length > TITLE_MAX) throw new ApiError(400, "TODO_INVALID", `title \u4E0D\u80FD\u8D85\u8FC7 ${TITLE_MAX} \u5B57`);
|
|
255308
|
+
set("title", title);
|
|
255309
|
+
}
|
|
255310
|
+
if (input.note !== void 0) {
|
|
255311
|
+
const note = clean2(input.note);
|
|
255312
|
+
if (note && note.length > NOTE_MAX) throw new ApiError(400, "TODO_INVALID", `note \u4E0D\u80FD\u8D85\u8FC7 ${NOTE_MAX} \u5B57`);
|
|
255313
|
+
set("note", note);
|
|
255314
|
+
}
|
|
255315
|
+
if (input.startDate !== void 0) {
|
|
255316
|
+
if (input.startDate === null) {
|
|
255317
|
+
set("startDate", void 0);
|
|
255318
|
+
if (input.startTime === void 0) set("startTime", void 0);
|
|
255319
|
+
} else {
|
|
255320
|
+
assertDay(input.startDate, "\u5F00\u59CB\u65E5");
|
|
255321
|
+
set("startDate", input.startDate);
|
|
255322
|
+
}
|
|
255323
|
+
}
|
|
255324
|
+
if (input.startTime !== void 0) {
|
|
255325
|
+
if (input.startTime !== null) assertTime(input.startTime, "\u5F00\u59CB\u65F6\u523B");
|
|
255326
|
+
set("startTime", input.startTime ?? void 0);
|
|
255327
|
+
}
|
|
255328
|
+
if (input.dueDate !== void 0) {
|
|
255329
|
+
assertDay(input.dueDate);
|
|
255330
|
+
set("dueDate", input.dueDate);
|
|
255331
|
+
}
|
|
255332
|
+
if (input.dueTime !== void 0) {
|
|
255333
|
+
if (input.dueTime !== null) assertTime(input.dueTime);
|
|
255334
|
+
set("dueTime", input.dueTime ?? void 0);
|
|
255335
|
+
}
|
|
255336
|
+
if (input.linkedWorkorderId !== void 0) set("linkedWorkorderId", clean2(input.linkedWorkorderId));
|
|
255337
|
+
if (next.startTime && !next.startDate) throw new ApiError(400, "TODO_INVALID", "\u6709\u5F00\u59CB\u65F6\u523B\u5C31\u8981\u6709\u5F00\u59CB\u65E5\uFF08\u5148\u8BBE startDate\uFF09");
|
|
255338
|
+
assertStartBeforeDue(next);
|
|
255339
|
+
if (changes.length > 0) {
|
|
255340
|
+
next.updatedAt = at2;
|
|
255341
|
+
next.recordedByActorId = caller.actor;
|
|
255342
|
+
}
|
|
255343
|
+
return this.save(caller, before, next, changes);
|
|
255344
|
+
}
|
|
255345
|
+
async setStatus(caller, id, status, reason) {
|
|
255346
|
+
const before = await this.get(caller, id);
|
|
255347
|
+
const why = clean2(reason);
|
|
255348
|
+
if (why && why.length > REASON_MAX) throw new ApiError(400, "TODO_INVALID", `reason \u4E0D\u80FD\u8D85\u8FC7 ${REASON_MAX} \u5B57`);
|
|
255349
|
+
if (before.status === status) return this.respond(before);
|
|
255350
|
+
const at2 = new Date(this.nowMs()).toISOString();
|
|
255351
|
+
const next = { ...before, status, updatedAt: at2, recordedByActorId: caller.actor };
|
|
255352
|
+
delete next.doneAt;
|
|
255353
|
+
delete next.cancelledAt;
|
|
255354
|
+
if (status === "done") next.doneAt = at2;
|
|
255355
|
+
if (status === "cancelled") next.cancelledAt = at2;
|
|
255356
|
+
return this.save(caller, before, next, [this.change(id, caller, at2, "status", before.status, status, why)]);
|
|
255357
|
+
}
|
|
255358
|
+
history(caller, id) {
|
|
255359
|
+
return this.get(caller, id).then(() => this.deps.store.listChanges(id));
|
|
255360
|
+
}
|
|
255361
|
+
};
|
|
255362
|
+
}
|
|
255363
|
+
});
|
|
255364
|
+
|
|
255365
|
+
// ../server/src/domains/todos/store.ts
|
|
255366
|
+
var import_node_crypto70, import_promises15, import_node_path25, MemoryTodoStore;
|
|
255367
|
+
var init_store3 = __esm({
|
|
255368
|
+
"../server/src/domains/todos/store.ts"() {
|
|
255369
|
+
"use strict";
|
|
255370
|
+
import_node_crypto70 = require("node:crypto");
|
|
255371
|
+
import_promises15 = require("node:fs/promises");
|
|
255372
|
+
import_node_path25 = require("node:path");
|
|
255373
|
+
init_src();
|
|
255374
|
+
MemoryTodoStore = class _MemoryTodoStore {
|
|
255375
|
+
constructor(filename) {
|
|
255376
|
+
this.filename = filename;
|
|
255377
|
+
}
|
|
255378
|
+
rows = { todos: {}, changes: [] };
|
|
255379
|
+
tail = Promise.resolve();
|
|
255380
|
+
static async open(filename) {
|
|
255381
|
+
const store = new _MemoryTodoStore(filename);
|
|
255382
|
+
try {
|
|
255383
|
+
store.rows = JSON.parse(await (0, import_promises15.readFile)(filename, "utf8"));
|
|
255384
|
+
} catch (error2) {
|
|
255385
|
+
if (error2.code !== "ENOENT") throw error2;
|
|
255386
|
+
}
|
|
255387
|
+
return store;
|
|
255388
|
+
}
|
|
255389
|
+
write(run) {
|
|
255390
|
+
const pending = this.tail.then(async () => {
|
|
255391
|
+
const next = structuredClone(this.rows);
|
|
255392
|
+
const result = run(next);
|
|
255393
|
+
if (result === null) return null;
|
|
255394
|
+
if (this.filename) {
|
|
255395
|
+
await (0, import_promises15.mkdir)((0, import_node_path25.dirname)(this.filename), { recursive: true });
|
|
255396
|
+
const temp = `${this.filename}.${(0, import_node_crypto70.randomUUID)()}.tmp`;
|
|
255397
|
+
await (0, import_promises15.writeFile)(temp, JSON.stringify(next), "utf8");
|
|
255398
|
+
await (0, import_promises15.rename)(temp, this.filename);
|
|
255399
|
+
}
|
|
255400
|
+
this.rows = next;
|
|
255401
|
+
return structuredClone(result);
|
|
255402
|
+
});
|
|
255403
|
+
this.tail = pending.catch(() => void 0);
|
|
255404
|
+
return pending;
|
|
255405
|
+
}
|
|
255406
|
+
async create(todo, changes) {
|
|
255407
|
+
const saved = await this.write((next) => {
|
|
255408
|
+
if (next.todos[todo.id]) throw new Error(`todo ${todo.id} already exists`);
|
|
255409
|
+
next.todos[todo.id] = structuredClone(todo);
|
|
255410
|
+
next.changes.push(...structuredClone(changes));
|
|
255411
|
+
return todo;
|
|
255412
|
+
});
|
|
255413
|
+
return saved;
|
|
255414
|
+
}
|
|
255415
|
+
async get(id) {
|
|
255416
|
+
await this.tail;
|
|
255417
|
+
return structuredClone(this.rows.todos[id] ?? null);
|
|
255418
|
+
}
|
|
255419
|
+
update(next, expectedUpdatedAt, changes) {
|
|
255420
|
+
return this.write((rows) => {
|
|
255421
|
+
const current = rows.todos[next.id];
|
|
255422
|
+
if (!current || current.updatedAt !== expectedUpdatedAt) return null;
|
|
255423
|
+
rows.todos[next.id] = structuredClone(next);
|
|
255424
|
+
rows.changes.push(...structuredClone(changes));
|
|
255425
|
+
return next;
|
|
255426
|
+
});
|
|
255427
|
+
}
|
|
255428
|
+
async listInvolving(actorId, statuses2) {
|
|
255429
|
+
await this.tail;
|
|
255430
|
+
return Object.values(this.rows.todos).filter((t) => statuses2.includes(t.status) && (t.creatorActorId === actorId || todoAssignees(t).includes(actorId))).sort(compareTodos).map((t) => structuredClone(t));
|
|
255431
|
+
}
|
|
255432
|
+
async listOpenReminderCandidates(fromDay, toDay) {
|
|
255433
|
+
await this.tail;
|
|
255434
|
+
const within = (day) => day !== void 0 && day >= fromDay && day <= toDay;
|
|
255435
|
+
return Object.values(this.rows.todos).filter((t) => t.status === "open" && (within(t.dueDate) || within(t.startDate))).sort(compareTodos).map((t) => structuredClone(t));
|
|
255436
|
+
}
|
|
255437
|
+
async listChanges(todoId) {
|
|
255438
|
+
await this.tail;
|
|
255439
|
+
return this.rows.changes.filter((c) => c.todoId === todoId).map((c) => structuredClone(c));
|
|
255440
|
+
}
|
|
255441
|
+
};
|
|
255442
|
+
}
|
|
255443
|
+
});
|
|
255444
|
+
|
|
255445
|
+
// ../server/src/domains/todos/routes.ts
|
|
255446
|
+
function todosDomain(options) {
|
|
255447
|
+
const wrap = (fn) => async (req) => {
|
|
255448
|
+
if (!options.enabled()) throw new ApiError(404, "NOT_FOUND", "\u4E2A\u4EBA\u5F85\u529E\u672A\u5F00\u542F");
|
|
255449
|
+
try {
|
|
255450
|
+
const service = await options.serviceFor(req.auth.companyId);
|
|
255451
|
+
const caller = await options.resolveCaller(req.auth.actor, req.auth.companyId);
|
|
255452
|
+
return await fn(req, service, caller);
|
|
255453
|
+
} catch (e) {
|
|
255454
|
+
if (e instanceof ZodError) throw new ApiError(400, "TODO_INVALID", e.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; "));
|
|
255455
|
+
throw e;
|
|
255456
|
+
}
|
|
255457
|
+
};
|
|
255458
|
+
const sourceSession = (req, fromBody) => req.auth.dispatch?.chatSessionId ?? fromBody;
|
|
255459
|
+
return (router) => {
|
|
255460
|
+
router.get("/api/todos", wrap(async (req, service, caller) => {
|
|
255461
|
+
const all2 = ["1", "true"].includes((req.query.get("all") ?? "").toLowerCase());
|
|
255462
|
+
return { status: 200, body: await service.list(caller, { all: all2 }) };
|
|
255463
|
+
}));
|
|
255464
|
+
router.post("/api/todos", wrap(async (req, service, caller) => {
|
|
255465
|
+
const body2 = create.parse(req.body ?? {});
|
|
255466
|
+
const sourceChatSessionId = sourceSession(req, body2.sourceChatSessionId);
|
|
255467
|
+
return { status: 201, body: await service.create(caller, { ...body2, ...sourceChatSessionId ? { sourceChatSessionId } : {} }) };
|
|
255468
|
+
}));
|
|
255469
|
+
router.get("/api/todos/:id", wrap(async (req, service, caller) => {
|
|
255470
|
+
const todo = await service.get(caller, req.params.id);
|
|
255471
|
+
return { status: 200, body: { todo, changes: await service.history(caller, todo.id) } };
|
|
255472
|
+
}));
|
|
255473
|
+
router.patch("/api/todos/:id", wrap(async (req, service, caller) => {
|
|
255474
|
+
const body2 = edit.parse(req.body ?? {});
|
|
255475
|
+
return { status: 200, body: await service.edit(caller, req.params.id, body2) };
|
|
255476
|
+
}));
|
|
255477
|
+
const status = (path47, to) => router.post(`/api/todos/:id/${path47}`, wrap(async (req, service, caller) => {
|
|
255478
|
+
const body2 = statusBody.parse(req.body ?? {});
|
|
255479
|
+
return { status: 200, body: await service.setStatus(caller, req.params.id, to, body2.reason) };
|
|
255480
|
+
}));
|
|
255481
|
+
status("done", "done");
|
|
255482
|
+
status("cancel", "cancelled");
|
|
255483
|
+
status("reopen", "open");
|
|
255484
|
+
};
|
|
255485
|
+
}
|
|
255486
|
+
var create, edit, statusBody;
|
|
255487
|
+
var init_routes11 = __esm({
|
|
255488
|
+
"../server/src/domains/todos/routes.ts"() {
|
|
255489
|
+
"use strict";
|
|
255490
|
+
init_zod();
|
|
255491
|
+
init_router();
|
|
255492
|
+
create = external_exports.object({
|
|
255493
|
+
title: external_exports.string(),
|
|
255494
|
+
note: external_exports.string().optional(),
|
|
255495
|
+
dueDate: external_exports.string(),
|
|
255496
|
+
dueTime: external_exports.string().optional(),
|
|
255497
|
+
startDate: external_exports.string().optional(),
|
|
255498
|
+
startTime: external_exports.string().optional(),
|
|
255499
|
+
sourceChatSessionId: external_exports.string().optional()
|
|
255500
|
+
}).strict();
|
|
255501
|
+
edit = external_exports.object({
|
|
255502
|
+
title: external_exports.string().optional(),
|
|
255503
|
+
note: external_exports.string().nullable().optional(),
|
|
255504
|
+
dueDate: external_exports.string().optional(),
|
|
255505
|
+
dueTime: external_exports.string().nullable().optional(),
|
|
255506
|
+
startDate: external_exports.string().nullable().optional(),
|
|
255507
|
+
startTime: external_exports.string().nullable().optional(),
|
|
255508
|
+
linkedWorkorderId: external_exports.string().nullable().optional(),
|
|
255509
|
+
reason: external_exports.string().optional()
|
|
255510
|
+
}).strict();
|
|
255511
|
+
statusBody = external_exports.object({ reason: external_exports.string().optional() }).strict();
|
|
255512
|
+
}
|
|
255513
|
+
});
|
|
255514
|
+
|
|
255515
|
+
// ../server/src/domains/todos/reminders.ts
|
|
255516
|
+
function todoReminderSourceKey(todo, kind) {
|
|
255517
|
+
if (kind === "todo-start") return `todo:${todo.id}@start:${todo.startDate}`;
|
|
255518
|
+
return `todo:${todo.id}@${kind === "todo-due-1d" ? "due-1d" : "due"}:${todo.dueDate}`;
|
|
255519
|
+
}
|
|
255520
|
+
function dueReminders(todo, timeZone, nowMs) {
|
|
255521
|
+
if (todo.status !== "open") return [];
|
|
255522
|
+
const created = Date.parse(todo.createdAt);
|
|
255523
|
+
const dayBefore = zonedDateTimeToUtcMs(shiftDay(todo.dueDate, -1), TODO_REMINDER_TIME, timeZone);
|
|
255524
|
+
const onDay = zonedDateTimeToUtcMs(todo.dueDate, TODO_REMINDER_TIME, timeZone);
|
|
255525
|
+
const dayEnd = zonedStartOfDayMs(shiftDay(todo.dueDate, 1), timeZone);
|
|
255526
|
+
const out = [];
|
|
255527
|
+
if (nowMs >= dayBefore && nowMs < onDay && created <= dayBefore) {
|
|
255528
|
+
out.push({ kind: "todo-due-1d", sourceKey: todoReminderSourceKey(todo, "todo-due-1d"), fireAt: dayBefore });
|
|
255529
|
+
}
|
|
255530
|
+
if (nowMs >= onDay && nowMs < dayEnd && created <= onDay) {
|
|
255531
|
+
out.push({ kind: "todo-due", sourceKey: todoReminderSourceKey(todo, "todo-due"), fireAt: onDay });
|
|
255532
|
+
}
|
|
255533
|
+
if (todo.startDate && todo.startDate !== todo.dueDate) {
|
|
255534
|
+
const startAt = zonedDateTimeToUtcMs(todo.startDate, TODO_REMINDER_TIME, timeZone);
|
|
255535
|
+
const startEnd = zonedStartOfDayMs(shiftDay(todo.startDate, 1), timeZone);
|
|
255536
|
+
if (nowMs >= startAt && nowMs < startEnd && created <= startAt) {
|
|
255537
|
+
out.push({ kind: "todo-start", sourceKey: todoReminderSourceKey(todo, "todo-start"), fireAt: startAt });
|
|
255538
|
+
}
|
|
255539
|
+
}
|
|
255540
|
+
return out;
|
|
255541
|
+
}
|
|
255542
|
+
var TODO_REMINDER_TIME, TODO_REMINDER_SCAN_MS, TODO_REMINDER_TITLE, TodoReminderScanner;
|
|
255543
|
+
var init_reminders = __esm({
|
|
255544
|
+
"../server/src/domains/todos/reminders.ts"() {
|
|
255545
|
+
"use strict";
|
|
255546
|
+
init_src();
|
|
255547
|
+
TODO_REMINDER_TIME = "09:00";
|
|
255548
|
+
TODO_REMINDER_SCAN_MS = 6e4;
|
|
255549
|
+
TODO_REMINDER_TITLE = {
|
|
255550
|
+
"todo-due-1d": (title) => `\u5F85\u529E\u660E\u5929\u5230\u671F\uFF1A${title}`,
|
|
255551
|
+
"todo-due": (title) => `\u5F85\u529E\u4ECA\u5929\u5230\u671F\uFF1A${title}`,
|
|
255552
|
+
"todo-start": (title) => `\u5F85\u529E\u4ECA\u5929\u5F00\u59CB\uFF1A${title}`
|
|
255553
|
+
};
|
|
255554
|
+
TodoReminderScanner = class {
|
|
255555
|
+
constructor(deps) {
|
|
255556
|
+
this.deps = deps;
|
|
255557
|
+
}
|
|
255558
|
+
timer;
|
|
255559
|
+
first;
|
|
255560
|
+
scanning = false;
|
|
255561
|
+
/** 本进程已经确认在台账里的 (公司, 收件人, 来源键):省掉每拍对同一条的重复 insert。重启后靠台账唯一约束兜底。 */
|
|
255562
|
+
seen = /* @__PURE__ */ new Set();
|
|
255563
|
+
/** 扫一遍所有公司。防重入:上一拍没扫完,这一拍直接跳过。返回本拍新写入的条数。 */
|
|
255564
|
+
async sweep() {
|
|
255565
|
+
if (this.scanning || !this.deps.enabled()) return 0;
|
|
255566
|
+
this.scanning = true;
|
|
255567
|
+
let inserted = 0;
|
|
255568
|
+
try {
|
|
255569
|
+
for (const companyId of await this.deps.companies()) {
|
|
255570
|
+
try {
|
|
255571
|
+
inserted += await this.sweepCompany(companyId);
|
|
255572
|
+
} catch (error2) {
|
|
255573
|
+
this.deps.warn(new Error(`\u5F85\u529E\u63D0\u9192 company=${companyId}: ${String(error2)}`));
|
|
255574
|
+
}
|
|
255575
|
+
}
|
|
255576
|
+
} catch (error2) {
|
|
255577
|
+
this.deps.warn(error2);
|
|
255578
|
+
} finally {
|
|
255579
|
+
this.scanning = false;
|
|
255580
|
+
}
|
|
255581
|
+
return inserted;
|
|
255582
|
+
}
|
|
255583
|
+
async sweepCompany(companyId) {
|
|
255584
|
+
const ledger = await this.deps.notifications(companyId);
|
|
255585
|
+
if (!ledger) return 0;
|
|
255586
|
+
const nowMs = this.deps.now?.() ?? Date.now();
|
|
255587
|
+
const timeZone = await this.deps.timeZone(companyId);
|
|
255588
|
+
const today = zonedToday(timeZone, nowMs).date;
|
|
255589
|
+
const candidates = await (await this.deps.todos(companyId)).listOpenReminderCandidates(today, shiftDay(today, 1));
|
|
255590
|
+
const enteredAt = new Date(nowMs).toISOString();
|
|
255591
|
+
const fresh = [];
|
|
255592
|
+
for (const todo of candidates) {
|
|
255593
|
+
for (const r of dueReminders(todo, timeZone, nowMs)) {
|
|
255594
|
+
for (const recipient of todoAssignees(todo)) {
|
|
255595
|
+
const key2 = JSON.stringify([companyId, recipient, r.sourceKey]);
|
|
255596
|
+
if (this.seen.has(key2)) continue;
|
|
255597
|
+
const row = await ledger.insert({
|
|
255598
|
+
recipient,
|
|
255599
|
+
category: "todo",
|
|
255600
|
+
sourceKey: r.sourceKey,
|
|
255601
|
+
kind: r.kind,
|
|
255602
|
+
title: TODO_REMINDER_TITLE[r.kind](todo.title),
|
|
255603
|
+
enteredAt,
|
|
255604
|
+
...todo.sourceChatSessionId ? { chatSessionId: todo.sourceChatSessionId } : {}
|
|
255605
|
+
});
|
|
255606
|
+
this.seen.add(key2);
|
|
255607
|
+
if (row.enteredAt === enteredAt) fresh.push(row);
|
|
255608
|
+
}
|
|
255609
|
+
}
|
|
255610
|
+
}
|
|
255611
|
+
if (fresh.length > 0) this.deps.onInserted?.(companyId, fresh);
|
|
255612
|
+
return fresh.length;
|
|
255613
|
+
}
|
|
255614
|
+
/** 首拍延后一点(默认 10 秒,与通知对账器同款):等 serve 把推送、台账都装好再扫。 */
|
|
255615
|
+
start(intervalMs = TODO_REMINDER_SCAN_MS, firstDelayMs = 1e4) {
|
|
255616
|
+
if (this.timer) return;
|
|
255617
|
+
this.timer = setInterval(() => void this.sweep(), intervalMs);
|
|
255618
|
+
this.timer.unref?.();
|
|
255619
|
+
this.first = setTimeout(() => void this.sweep(), firstDelayMs);
|
|
255620
|
+
this.first.unref?.();
|
|
255621
|
+
}
|
|
255622
|
+
stop() {
|
|
255623
|
+
if (this.timer) clearInterval(this.timer);
|
|
255624
|
+
if (this.first) clearTimeout(this.first);
|
|
255625
|
+
this.timer = void 0;
|
|
255626
|
+
this.first = void 0;
|
|
255627
|
+
}
|
|
255628
|
+
};
|
|
255629
|
+
}
|
|
255630
|
+
});
|
|
255631
|
+
|
|
255632
|
+
// ../server/src/domains/todos/index.ts
|
|
255633
|
+
var init_todos2 = __esm({
|
|
255634
|
+
"../server/src/domains/todos/index.ts"() {
|
|
255635
|
+
"use strict";
|
|
255636
|
+
init_flag();
|
|
255637
|
+
init_service10();
|
|
255638
|
+
init_store3();
|
|
255639
|
+
init_routes11();
|
|
255640
|
+
init_reminders();
|
|
255641
|
+
}
|
|
255642
|
+
});
|
|
255643
|
+
|
|
254766
255644
|
// ../server/src/domains/playbooks/registry.ts
|
|
254767
255645
|
function deriveGraph(structure, filerReviews) {
|
|
254768
255646
|
const idOf = (n) => `${n.type}:${n.title}`;
|
|
@@ -256128,7 +257006,7 @@ function busyError(chatSessionId, blockedBy) {
|
|
|
256128
257006
|
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`;
|
|
256129
257007
|
}
|
|
256130
257008
|
function genWebhookToken() {
|
|
256131
|
-
return `owt_${(0,
|
|
257009
|
+
return `owt_${(0, import_node_crypto71.randomBytes)(32).toString("base64url")}`;
|
|
256132
257010
|
}
|
|
256133
257011
|
function validateTitleTemplate(tpl) {
|
|
256134
257012
|
const residue = tpl.replace(DATE_TOKEN, "");
|
|
@@ -256184,11 +257062,11 @@ function appendSourceNote(brief, automation, source, atIso) {
|
|
|
256184
257062
|
---
|
|
256185
257063
|
\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`;
|
|
256186
257064
|
}
|
|
256187
|
-
var
|
|
256188
|
-
var
|
|
257065
|
+
var import_node_crypto71, DATE_TOKEN, AutomationsService, EVENT_RETRY_BASE_MS, EVENT_RETRY_MAX_MS, EVENT_RETRY_MAX_ATTEMPTS, eventAttempts, eventLastAttemptAt, eventLastError, CHAT_REPLY_MAX;
|
|
257066
|
+
var init_service11 = __esm({
|
|
256189
257067
|
"../server/src/domains/automations/service.ts"() {
|
|
256190
257068
|
"use strict";
|
|
256191
|
-
|
|
257069
|
+
import_node_crypto71 = require("node:crypto");
|
|
256192
257070
|
init_src();
|
|
256193
257071
|
init_registry3();
|
|
256194
257072
|
init_attribution();
|
|
@@ -257002,11 +257880,11 @@ function verifySignature(rawBody, headers, secret) {
|
|
|
257002
257880
|
if (!secret) return "not_required";
|
|
257003
257881
|
const given = header1(headers, "x-hub-signature-256");
|
|
257004
257882
|
if (!given) return "missing";
|
|
257005
|
-
const expected = `sha256=${(0,
|
|
257883
|
+
const expected = `sha256=${(0, import_node_crypto72.createHmac)("sha256", secret).update(rawBody).digest("hex")}`;
|
|
257006
257884
|
const a = Buffer.from(given);
|
|
257007
257885
|
const b2 = Buffer.from(expected);
|
|
257008
257886
|
if (a.length !== b2.length) return "invalid";
|
|
257009
|
-
return (0,
|
|
257887
|
+
return (0, import_node_crypto72.timingSafeEqual)(a, b2) ? "valid" : "invalid";
|
|
257010
257888
|
}
|
|
257011
257889
|
function eventAllowed(filters, envelope) {
|
|
257012
257890
|
if (!filters || filters.length === 0) return true;
|
|
@@ -257036,11 +257914,11 @@ function splitEvent(envelope) {
|
|
|
257036
257914
|
}
|
|
257037
257915
|
return { eventName, actionCandidates: candidates };
|
|
257038
257916
|
}
|
|
257039
|
-
var
|
|
257917
|
+
var import_node_crypto72, MAX_BODY_BYTES, AutomationWebhookService, header1, PROVIDER_PREFIXES;
|
|
257040
257918
|
var init_webhook = __esm({
|
|
257041
257919
|
"../server/src/domains/automations/webhook.ts"() {
|
|
257042
257920
|
"use strict";
|
|
257043
|
-
|
|
257921
|
+
import_node_crypto72 = require("node:crypto");
|
|
257044
257922
|
MAX_BODY_BYTES = 256 * 1024;
|
|
257045
257923
|
AutomationWebhookService = class {
|
|
257046
257924
|
store;
|
|
@@ -257914,13 +258792,13 @@ function automationsDomain(opts) {
|
|
|
257914
258792
|
};
|
|
257915
258793
|
}
|
|
257916
258794
|
var RECENT_LIMIT2, TARGET_ISSUE_MESSAGE;
|
|
257917
|
-
var
|
|
258795
|
+
var init_routes12 = __esm({
|
|
257918
258796
|
"../server/src/domains/automations/routes.ts"() {
|
|
257919
258797
|
"use strict";
|
|
257920
258798
|
init_src();
|
|
257921
258799
|
init_templates();
|
|
257922
258800
|
init_router();
|
|
257923
|
-
|
|
258801
|
+
init_service11();
|
|
257924
258802
|
init_projection2();
|
|
257925
258803
|
init_scheduler();
|
|
257926
258804
|
init_registry3();
|
|
@@ -258035,11 +258913,11 @@ function createAutomationsDomain(opts) {
|
|
|
258035
258913
|
var init_automations = __esm({
|
|
258036
258914
|
"../server/src/domains/automations/index.ts"() {
|
|
258037
258915
|
"use strict";
|
|
258038
|
-
|
|
258916
|
+
init_service11();
|
|
258039
258917
|
init_webhook();
|
|
258040
|
-
|
|
258041
|
-
|
|
258042
|
-
|
|
258918
|
+
init_routes12();
|
|
258919
|
+
init_service11();
|
|
258920
|
+
init_routes12();
|
|
258043
258921
|
init_projection2();
|
|
258044
258922
|
init_webhook();
|
|
258045
258923
|
init_attribution();
|
|
@@ -258192,7 +259070,7 @@ function playbooksDomain(opts) {
|
|
|
258192
259070
|
opts.overrides.set(companyOf(req), ref2, nodeKey, nextOverride);
|
|
258193
259071
|
try {
|
|
258194
259072
|
await opts.audit?.({
|
|
258195
|
-
id: `reg_${(0,
|
|
259073
|
+
id: `reg_${(0, import_node_crypto73.randomUUID)()}`,
|
|
258196
259074
|
actor: req.auth.actor,
|
|
258197
259075
|
kind: "registry_change",
|
|
258198
259076
|
target: `playbook:${ref2}#${nodeKey}`,
|
|
@@ -258209,11 +259087,11 @@ function playbooksDomain(opts) {
|
|
|
258209
259087
|
});
|
|
258210
259088
|
};
|
|
258211
259089
|
}
|
|
258212
|
-
var
|
|
258213
|
-
var
|
|
259090
|
+
var import_node_crypto73;
|
|
259091
|
+
var init_routes13 = __esm({
|
|
258214
259092
|
"../server/src/domains/playbooks/routes.ts"() {
|
|
258215
259093
|
"use strict";
|
|
258216
|
-
|
|
259094
|
+
import_node_crypto73 = require("node:crypto");
|
|
258217
259095
|
init_router();
|
|
258218
259096
|
init_registry3();
|
|
258219
259097
|
init_planner();
|
|
@@ -258232,12 +259110,12 @@ function normalize(patch) {
|
|
|
258232
259110
|
...reviewers !== void 0 ? { reviewers: [...new Set(reviewers.map((r) => r.trim()).filter(Boolean))] } : {}
|
|
258233
259111
|
};
|
|
258234
259112
|
}
|
|
258235
|
-
var import_node_fs22,
|
|
259113
|
+
var import_node_fs22, import_node_path26, SEP3, keyOf2, prefixOf2, MemoryPlaybookOverrideStore, FilePlaybookOverrideStore;
|
|
258236
259114
|
var init_overrides = __esm({
|
|
258237
259115
|
"../server/src/domains/playbooks/overrides.ts"() {
|
|
258238
259116
|
"use strict";
|
|
258239
259117
|
import_node_fs22 = __toESM(require("node:fs"), 1);
|
|
258240
|
-
|
|
259118
|
+
import_node_path26 = __toESM(require("node:path"), 1);
|
|
258241
259119
|
SEP3 = "::";
|
|
258242
259120
|
keyOf2 = (companyId, ref2, nodeKey) => `${companyId}${SEP3}${ref2}${SEP3}${nodeKey}`;
|
|
258243
259121
|
prefixOf2 = (companyId, ref2) => `${companyId}${SEP3}${ref2}${SEP3}`;
|
|
@@ -258293,7 +259171,7 @@ var init_overrides = __esm({
|
|
|
258293
259171
|
}
|
|
258294
259172
|
persist() {
|
|
258295
259173
|
try {
|
|
258296
|
-
import_node_fs22.default.mkdirSync(
|
|
259174
|
+
import_node_fs22.default.mkdirSync(import_node_path26.default.dirname(this.file), { recursive: true });
|
|
258297
259175
|
const tmp = `${this.file}.tmp`;
|
|
258298
259176
|
import_node_fs22.default.writeFileSync(tmp, JSON.stringify(Object.fromEntries(this.map), null, 2));
|
|
258299
259177
|
import_node_fs22.default.renameSync(tmp, this.file);
|
|
@@ -258329,9 +259207,9 @@ function createPlaybooksDomain(opts) {
|
|
|
258329
259207
|
var init_playbooks = __esm({
|
|
258330
259208
|
"../server/src/domains/playbooks/index.ts"() {
|
|
258331
259209
|
"use strict";
|
|
258332
|
-
|
|
259210
|
+
init_routes13();
|
|
258333
259211
|
init_registry3();
|
|
258334
|
-
|
|
259212
|
+
init_routes13();
|
|
258335
259213
|
init_overrides();
|
|
258336
259214
|
}
|
|
258337
259215
|
});
|
|
@@ -258342,17 +259220,17 @@ function completionFingerprint(workspace, members) {
|
|
|
258342
259220
|
workspace,
|
|
258343
259221
|
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 }))
|
|
258344
259222
|
});
|
|
258345
|
-
return (0,
|
|
259223
|
+
return (0, import_node_crypto74.createHash)("sha256").update(canonical2).digest("hex");
|
|
258346
259224
|
}
|
|
258347
259225
|
function eventConsumptionKey(args) {
|
|
258348
259226
|
const raw = `project-event:${EVENT_KEY_VERSION}:${args.triggerId}:${args.event}:${args.workspace}:${args.fingerprint}`;
|
|
258349
|
-
return raw.length <= 200 ? raw : `project-event:${EVENT_KEY_VERSION}:sha256:${(0,
|
|
259227
|
+
return raw.length <= 200 ? raw : `project-event:${EVENT_KEY_VERSION}:sha256:${(0, import_node_crypto74.createHash)("sha256").update(raw).digest("hex")}`;
|
|
258350
259228
|
}
|
|
258351
|
-
var
|
|
259229
|
+
var import_node_crypto74, EVENT_KEY_VERSION, EMPTY_METRICS, AUTOMATION_EVENT_HANDLERS, ProjectEventPoller;
|
|
258352
259230
|
var init_project_event_poller = __esm({
|
|
258353
259231
|
"../server/src/automations/project-event-poller.ts"() {
|
|
258354
259232
|
"use strict";
|
|
258355
|
-
|
|
259233
|
+
import_node_crypto74 = require("node:crypto");
|
|
258356
259234
|
EVENT_KEY_VERSION = "v1";
|
|
258357
259235
|
EMPTY_METRICS = () => ({
|
|
258358
259236
|
scanDurationMs: 0,
|
|
@@ -258562,7 +259440,7 @@ function queryInputReceipt(hub, nodeId, dispatchId, clientMessageKey, pending, t
|
|
|
258562
259440
|
const viaSession = hub.hasSession?.(dispatchId) === true;
|
|
258563
259441
|
const supported = viaSession ? hub.supportsInputReceiptQuery?.(dispatchId) === true : daemonMetaOf(hub, nodeId)?.supportsInputReceiptQuery === true;
|
|
258564
259442
|
if (!supported) return Promise.resolve({ status: "unknown", reason: "unsupported" });
|
|
258565
|
-
const requestId = (0,
|
|
259443
|
+
const requestId = (0, import_node_crypto75.randomUUID)();
|
|
258566
259444
|
return new Promise((resolve11) => {
|
|
258567
259445
|
const timer = setTimeout(() => {
|
|
258568
259446
|
pending.delete(requestId);
|
|
@@ -258624,7 +259502,7 @@ function sendAppendInput(hub, nodeId, dispatchId, entry, input, timeoutMs, sessi
|
|
|
258624
259502
|
if (input.requireConsumptionReceipt && !hub.supportsInputConsumptionReceipts?.(dispatchId)) {
|
|
258625
259503
|
return Promise.resolve({ accepted: false, reason: "consumption-unsupported" });
|
|
258626
259504
|
}
|
|
258627
|
-
const requestId = (0,
|
|
259505
|
+
const requestId = (0, import_node_crypto75.randomUUID)();
|
|
258628
259506
|
const sent = routeToSession(hub, nodeId, dispatchId, { type: "append_input", dispatchId, input, requestId });
|
|
258629
259507
|
if (!sent) return Promise.resolve({ accepted: false, reason: "session-closing", ...unknownIfInterrupting });
|
|
258630
259508
|
return new Promise((resolve11) => {
|
|
@@ -258637,11 +259515,11 @@ function sendAppendInput(hub, nodeId, dispatchId, entry, input, timeoutMs, sessi
|
|
|
258637
259515
|
entry.appendWaiters.push({ requestId, requireConsumptionReceipt: input.requireConsumptionReceipt, resolve: resolve11, timer });
|
|
258638
259516
|
});
|
|
258639
259517
|
}
|
|
258640
|
-
var
|
|
259518
|
+
var import_node_crypto75, STASH_TTL_MS, STASH_MAX_FRAMES_PER_ID, STASH_MAX_TOTAL_FRAMES, STASH_MAX_IDS, STASH_LOSS_MAX_IDS, STASH_LOSS_TTL_MS, DaemonHubAdapter, BindingRouterAdapter, WorkdirBridge;
|
|
258641
259519
|
var init_daemon_adapter = __esm({
|
|
258642
259520
|
"../server/src/daemon-adapter.ts"() {
|
|
258643
259521
|
"use strict";
|
|
258644
|
-
|
|
259522
|
+
import_node_crypto75 = require("node:crypto");
|
|
258645
259523
|
init_src();
|
|
258646
259524
|
STASH_TTL_MS = 5 * 6e4;
|
|
258647
259525
|
STASH_MAX_FRAMES_PER_ID = 1e4;
|
|
@@ -259100,7 +259978,7 @@ var init_daemon_adapter = __esm({
|
|
|
259100
259978
|
async spawn(job) {
|
|
259101
259979
|
const nodeId = job.binding?.nodeId;
|
|
259102
259980
|
if (!nodeId) throw new Error("DaemonHubAdapter \u9700\u8981 job.binding.nodeId\uFF08\u8DEF\u7531\u9519\u8BEF\uFF09");
|
|
259103
|
-
const dispatchId = job.dispatchId ?? `dispatch:${(0,
|
|
259981
|
+
const dispatchId = job.dispatchId ?? `dispatch:${(0, import_node_crypto75.randomUUID)()}`;
|
|
259104
259982
|
if (job.dispatchId && this.pending.has(dispatchId)) {
|
|
259105
259983
|
return this.recover(dispatchId, nodeId, job.binding?.runtimeKind, job.actor);
|
|
259106
259984
|
}
|
|
@@ -259357,7 +260235,7 @@ var init_daemon_adapter = __esm({
|
|
|
259357
260235
|
return daemon?.meta.supportsWorkdirWalk === true;
|
|
259358
260236
|
}
|
|
259359
260237
|
request(nodeId, buildFrame) {
|
|
259360
|
-
const requestId = (0,
|
|
260238
|
+
const requestId = (0, import_node_crypto75.randomUUID)();
|
|
259361
260239
|
const sent = this.hub.dispatch(nodeId, buildFrame(requestId));
|
|
259362
260240
|
if (!sent) return Promise.resolve({ ok: false, code: "NODE_OFFLINE" });
|
|
259363
260241
|
return new Promise((resolve11) => {
|
|
@@ -259415,12 +260293,12 @@ var init_dispatch_fence = __esm({
|
|
|
259415
260293
|
});
|
|
259416
260294
|
|
|
259417
260295
|
// ../server/src/side-map.ts
|
|
259418
|
-
var import_node_fs23,
|
|
260296
|
+
var import_node_fs23, import_node_path27, FileSideMap;
|
|
259419
260297
|
var init_side_map = __esm({
|
|
259420
260298
|
"../server/src/side-map.ts"() {
|
|
259421
260299
|
"use strict";
|
|
259422
260300
|
import_node_fs23 = __toESM(require("node:fs"), 1);
|
|
259423
|
-
|
|
260301
|
+
import_node_path27 = __toESM(require("node:path"), 1);
|
|
259424
260302
|
FileSideMap = class {
|
|
259425
260303
|
constructor(file) {
|
|
259426
260304
|
this.file = file;
|
|
@@ -259447,7 +260325,7 @@ var init_side_map = __esm({
|
|
|
259447
260325
|
}
|
|
259448
260326
|
persist() {
|
|
259449
260327
|
try {
|
|
259450
|
-
import_node_fs23.default.mkdirSync(
|
|
260328
|
+
import_node_fs23.default.mkdirSync(import_node_path27.default.dirname(this.file), { recursive: true });
|
|
259451
260329
|
const tmp = `${this.file}.tmp`;
|
|
259452
260330
|
import_node_fs23.default.writeFileSync(tmp, JSON.stringify(Object.fromEntries(this.map), null, 2));
|
|
259453
260331
|
import_node_fs23.default.renameSync(tmp, this.file);
|
|
@@ -259465,13 +260343,13 @@ function classifyPage(page, lastPushedHash, serviceAccount) {
|
|
|
259465
260343
|
if (sha(body2) === lastPushedHash) return { kind: "echo" };
|
|
259466
260344
|
return { kind: "human-edit", content: body2, updatedBy: page.updatedBy };
|
|
259467
260345
|
}
|
|
259468
|
-
var
|
|
260346
|
+
var import_node_crypto76, sha, enc2, dec, MirrorEngine, MemoryMirrorStateStore, MapMirrorIdentities;
|
|
259469
260347
|
var init_engine = __esm({
|
|
259470
260348
|
"../server/src/mirror/engine.ts"() {
|
|
259471
260349
|
"use strict";
|
|
259472
|
-
|
|
260350
|
+
import_node_crypto76 = require("node:crypto");
|
|
259473
260351
|
init_src();
|
|
259474
|
-
sha = (s2) => (0,
|
|
260352
|
+
sha = (s2) => (0, import_node_crypto76.createHash)("sha256").update(s2, "utf8").digest("hex");
|
|
259475
260353
|
enc2 = (s2) => new TextEncoder().encode(s2);
|
|
259476
260354
|
dec = (b2) => new TextDecoder().decode(b2);
|
|
259477
260355
|
MirrorEngine = class {
|
|
@@ -259752,11 +260630,11 @@ function humanExitCause(exit3) {
|
|
|
259752
260630
|
const base = (exit3.reason ? label2[exit3.reason] : void 0) ?? `\u4F1A\u8BDD\u5F02\u5E38\u7ED3\u675F\uFF08${exit3.reason ?? "\u65E0\u9000\u51FA\u4FE1\u606F"}\uFF09`;
|
|
259753
260631
|
return exit3.errorMessage ? `${base}\uFF1A${exit3.errorMessage.slice(0, 200)}` : base;
|
|
259754
260632
|
}
|
|
259755
|
-
var
|
|
260633
|
+
var import_node_crypto77, AUTONOMOUS_ETHOS, CONVERSATIONAL_ETHOS, SHARED_GRAPH_BODY, AUTONOMOUS_RECOVERY_TOOLS, HIGH_RISK_COMMANDS, REJECTED_PROPOSALS_IN_TASK, COORDINATOR_SYSTEM_PROMPT, CONVERSATIONAL_RECOVERY_TOOLS, CONVERSATIONAL_ESCALATION_TOOLS, CONVERSATIONAL_MANAGER_BODY, MACHINE_EXIT_CODES, CoordinatorWorker;
|
|
259756
260634
|
var init_worker = __esm({
|
|
259757
260635
|
"../server/src/coordinator/worker.ts"() {
|
|
259758
260636
|
"use strict";
|
|
259759
|
-
|
|
260637
|
+
import_node_crypto77 = require("node:crypto");
|
|
259760
260638
|
init_src7();
|
|
259761
260639
|
init_identity();
|
|
259762
260640
|
init_escalation_kind();
|
|
@@ -260029,7 +260907,7 @@ ${HIGH_RISK_COMMANDS}`;
|
|
|
260029
260907
|
return this.deps.kernel.model.lastSeq.get(artifactId) ?? 0;
|
|
260030
260908
|
}
|
|
260031
260909
|
evaluationKey(kind, artifactId, evidence) {
|
|
260032
|
-
const fingerprint2 = (0,
|
|
260910
|
+
const fingerprint2 = (0, import_node_crypto77.createHash)("sha256").update(JSON.stringify(evidence)).digest("hex");
|
|
260033
260911
|
return `${kind}:${artifactId}:${fingerprint2}`;
|
|
260034
260912
|
}
|
|
260035
260913
|
artifactEvidence(id) {
|
|
@@ -260420,8 +261298,8 @@ ${ctx.nodeFault}
|
|
|
260420
261298
|
const taskWithRejections = rejectedSection ? `${task}
|
|
260421
261299
|
|
|
260422
261300
|
${rejectedSection}` : task;
|
|
260423
|
-
const runtimeSessionId = opts?.resumeSessionId ?? (0,
|
|
260424
|
-
const coordinatorRunId = `coordinate:${(0,
|
|
261301
|
+
const runtimeSessionId = opts?.resumeSessionId ?? (0, import_node_crypto77.randomUUID)();
|
|
261302
|
+
const coordinatorRunId = `coordinate:${(0, import_node_crypto77.randomUUID)()}`;
|
|
260425
261303
|
const taskWithContext = coordinatorContext ? [
|
|
260426
261304
|
taskWithRejections,
|
|
260427
261305
|
``,
|
|
@@ -260465,7 +261343,7 @@ ${rejectedSection}` : task;
|
|
|
260465
261343
|
const startedAtMs = Date.now();
|
|
260466
261344
|
let trajectoryStarted = false;
|
|
260467
261345
|
if (this.deps.trajectory) {
|
|
260468
|
-
const bundleManifest = Object.fromEntries(Object.entries(job.bundle.files).map(([name, content3]) => [name, (0,
|
|
261346
|
+
const bundleManifest = Object.fromEntries(Object.entries(job.bundle.files).map(([name, content3]) => [name, (0, import_node_crypto77.createHash)("sha256").update(content3).digest("hex")]));
|
|
260469
261347
|
const session = {
|
|
260470
261348
|
runId: coordinatorRunId,
|
|
260471
261349
|
runtimeSessionId,
|
|
@@ -260676,11 +261554,11 @@ var init_pg_ident = __esm({
|
|
|
260676
261554
|
});
|
|
260677
261555
|
|
|
260678
261556
|
// ../storage/src/postgres.ts
|
|
260679
|
-
var
|
|
261557
|
+
var import_node_crypto78, ident5, isUniqueViolation, PostgresOplogStore, PostgresBlobStore;
|
|
260680
261558
|
var init_postgres = __esm({
|
|
260681
261559
|
"../storage/src/postgres.ts"() {
|
|
260682
261560
|
"use strict";
|
|
260683
|
-
|
|
261561
|
+
import_node_crypto78 = require("node:crypto");
|
|
260684
261562
|
init_pg_ident();
|
|
260685
261563
|
init_esm();
|
|
260686
261564
|
init_src();
|
|
@@ -260860,7 +261738,7 @@ var init_postgres = __esm({
|
|
|
260860
261738
|
return new _PostgresBlobStore(pool, schema);
|
|
260861
261739
|
}
|
|
260862
261740
|
async put(bytes2) {
|
|
260863
|
-
const hash3 = (0,
|
|
261741
|
+
const hash3 = (0, import_node_crypto78.createHash)("sha256").update(bytes2).digest("hex");
|
|
260864
261742
|
await this.pool.query(
|
|
260865
261743
|
`INSERT INTO ${this.t} (hash, bytes, size, content_type) VALUES ($1, $2, $3, $4) ON CONFLICT (hash) DO NOTHING`,
|
|
260866
261744
|
[hash3, Buffer.from(bytes2), bytes2.byteLength, sniffContentType(bytes2) ?? null]
|
|
@@ -260908,7 +261786,7 @@ function stageAtLeast(stage, min2) {
|
|
|
260908
261786
|
return STAGES.indexOf(stage) >= STAGES.indexOf(min2);
|
|
260909
261787
|
}
|
|
260910
261788
|
function newVariableId() {
|
|
260911
|
-
return `var_${(0,
|
|
261789
|
+
return `var_${(0, import_node_crypto79.randomUUID)()}`;
|
|
260912
261790
|
}
|
|
260913
261791
|
async function declareRecordsAware(db) {
|
|
260914
261792
|
await db.query(`SELECT set_config('${RECORDS_AWARE_SETTING}', 'on', true)`);
|
|
@@ -261264,11 +262142,11 @@ async function listBindingTargetIds(db, s2, kind) {
|
|
|
261264
262142
|
[kind]
|
|
261265
262143
|
)).rows.map((x2) => x2.target_id);
|
|
261266
262144
|
}
|
|
261267
|
-
var
|
|
262145
|
+
var import_node_crypto79, STAGES, RECORDS_AWARE_SETTING, markLockName;
|
|
261268
262146
|
var init_variable_bindings = __esm({
|
|
261269
262147
|
"../storage/src/variable-bindings.ts"() {
|
|
261270
262148
|
"use strict";
|
|
261271
|
-
|
|
262149
|
+
import_node_crypto79 = require("node:crypto");
|
|
261272
262150
|
init_src();
|
|
261273
262151
|
STAGES = ["off", "dual", "read", "records"];
|
|
261274
262152
|
RECORDS_AWARE_SETTING = "oasis.variable_records_aware";
|
|
@@ -264020,9 +264898,11 @@ var init_postgres_control_plane = __esm({
|
|
|
264020
264898
|
avatar text, -- "blob:<hash>"\uFF0C\u7A7A=\u9ED8\u8BA4
|
|
264021
264899
|
status text NOT NULL, -- active | suspended
|
|
264022
264900
|
created_at timestamptz NOT NULL,
|
|
264023
|
-
onboarding_variant text
|
|
264901
|
+
onboarding_variant text, -- \u767B\u5F55\u540E\u52A9\u7406\u5F15\u5BFC\u53D8\u4F53 A|B\uFF1BNULL=\u7F3A\u7701\u89C6\u4E3A A
|
|
264902
|
+
time_zone text -- \u7EC4\u7EC7\u65F6\u533A IANA \u540D\uFF1BNULL=\u6309\u90E8\u7F72\u9ED8\u8BA4\u503C
|
|
264024
264903
|
)`);
|
|
264025
264904
|
await pool.query(`ALTER TABLE "${s2}".companies ADD COLUMN IF NOT EXISTS onboarding_variant text`);
|
|
264905
|
+
await pool.query(`ALTER TABLE "${s2}".companies ADD COLUMN IF NOT EXISTS time_zone text`);
|
|
264026
264906
|
await pool.query(`ALTER TABLE "${s2}".companies ADD COLUMN IF NOT EXISTS dissolved_at timestamptz`);
|
|
264027
264907
|
await pool.query(`ALTER TABLE "${s2}".companies ADD COLUMN IF NOT EXISTS dissolved_by text`);
|
|
264028
264908
|
await pool.query(`
|
|
@@ -264076,6 +264956,14 @@ var init_postgres_control_plane = __esm({
|
|
|
264076
264956
|
expires_at timestamptz NOT NULL,
|
|
264077
264957
|
attempts int NOT NULL DEFAULT 0
|
|
264078
264958
|
)`);
|
|
264959
|
+
await pool.query(`
|
|
264960
|
+
CREATE TABLE IF NOT EXISTS "${s2}".revoked_sessions (
|
|
264961
|
+
token_hash text PRIMARY KEY, -- SHA-256(base64url) of the oasis_auth JWT
|
|
264962
|
+
account_id text NOT NULL,
|
|
264963
|
+
revoked_at timestamptz NOT NULL,
|
|
264964
|
+
expires_at timestamptz NOT NULL -- = \u4EE4\u724C exp\uFF1B\u8FC7\u4E86\u4EE4\u724C\u672C\u6765\u5C31\u9A8C\u4E0D\u8FC7\uFF0C\u884C\u53EF\u5220
|
|
264965
|
+
)`);
|
|
264966
|
+
await pool.query(`CREATE INDEX IF NOT EXISTS revoked_sessions_expires_idx ON "${s2}".revoked_sessions (expires_at)`);
|
|
264079
264967
|
await pool.query(`ALTER TABLE "${s2}".company_members ADD COLUMN IF NOT EXISTS display_name text`);
|
|
264080
264968
|
await pool.query(`ALTER TABLE "${s2}".company_members ADD COLUMN IF NOT EXISTS created_at timestamptz`);
|
|
264081
264969
|
await pool.query(`ALTER TABLE "${s2}".company_members ADD COLUMN IF NOT EXISTS updated_at timestamptz`);
|
|
@@ -264231,8 +265119,8 @@ var init_postgres_control_plane = __esm({
|
|
|
264231
265119
|
// —— 公司 ——
|
|
264232
265120
|
async createCompany(c) {
|
|
264233
265121
|
await this.pool.query(
|
|
264234
|
-
`INSERT INTO ${this.s}.companies (id, slug, name, avatar, status, created_at, onboarding_variant) VALUES ($1,$2,$3,$4,$5,$6,$7)`,
|
|
264235
|
-
[c.id, c.slug, c.name, c.avatar ?? null, c.status, c.createdAt, c.onboardingVariant ?? null]
|
|
265122
|
+
`INSERT INTO ${this.s}.companies (id, slug, name, avatar, status, created_at, onboarding_variant, time_zone) VALUES ($1,$2,$3,$4,$5,$6,$7,$8)`,
|
|
265123
|
+
[c.id, c.slug, c.name, c.avatar ?? null, c.status, c.createdAt, c.onboardingVariant ?? null, c.timeZone ?? null]
|
|
264236
265124
|
);
|
|
264237
265125
|
}
|
|
264238
265126
|
async getCompany(id) {
|
|
@@ -264266,6 +265154,10 @@ var init_postgres_control_plane = __esm({
|
|
|
264266
265154
|
args.push(patch.onboardingVariant);
|
|
264267
265155
|
sets.push(`onboarding_variant = $${args.length}`);
|
|
264268
265156
|
}
|
|
265157
|
+
if (patch.timeZone !== void 0) {
|
|
265158
|
+
args.push(patch.timeZone);
|
|
265159
|
+
sets.push(`time_zone = $${args.length}`);
|
|
265160
|
+
}
|
|
264269
265161
|
if (patch.dissolvedAt !== void 0) {
|
|
264270
265162
|
args.push(patch.dissolvedAt);
|
|
264271
265163
|
sets.push(`dissolved_at = $${args.length}`);
|
|
@@ -264962,6 +265854,19 @@ var init_postgres_control_plane = __esm({
|
|
|
264962
265854
|
if (r.rowCount === 0) throw new Error(`account not found: ${accountId}`);
|
|
264963
265855
|
return Number(r.rows[0].token_version);
|
|
264964
265856
|
}
|
|
265857
|
+
// —— 已登出会话(ADR 0636)——
|
|
265858
|
+
async revokeSession(rec2) {
|
|
265859
|
+
await this.pool.query(`DELETE FROM ${this.s}.revoked_sessions WHERE expires_at < $1`, [rec2.revokedAt]);
|
|
265860
|
+
await this.pool.query(
|
|
265861
|
+
`INSERT INTO ${this.s}.revoked_sessions (token_hash, account_id, revoked_at, expires_at) VALUES ($1,$2,$3,$4)
|
|
265862
|
+
ON CONFLICT (token_hash) DO NOTHING`,
|
|
265863
|
+
[rec2.tokenHash, rec2.accountId, rec2.revokedAt, rec2.expiresAt]
|
|
265864
|
+
);
|
|
265865
|
+
}
|
|
265866
|
+
async isSessionRevoked(tokenHash) {
|
|
265867
|
+
const r = await this.pool.query(`SELECT 1 FROM ${this.s}.revoked_sessions WHERE token_hash = $1`, [tokenHash]);
|
|
265868
|
+
return (r.rowCount ?? 0) > 0;
|
|
265869
|
+
}
|
|
264965
265870
|
// —— 邮箱验证码(单邮箱一条 active)——
|
|
264966
265871
|
async putVerificationCode(rec2) {
|
|
264967
265872
|
await this.pool.query(
|
|
@@ -265274,6 +266179,7 @@ var init_postgres_control_plane = __esm({
|
|
|
265274
266179
|
status: row.status,
|
|
265275
266180
|
createdAt: new Date(row.created_at).toISOString(),
|
|
265276
266181
|
...row.onboarding_variant ? { onboardingVariant: row.onboarding_variant } : {},
|
|
266182
|
+
...row.time_zone ? { timeZone: row.time_zone } : {},
|
|
265277
266183
|
// 解散痕迹(组织三层身份 ADR D9.2):两列一起有、一起空。普通运维停用不写它们。
|
|
265278
266184
|
...row.dissolved_at != null ? { dissolvedAt: toIso(row.dissolved_at) } : {},
|
|
265279
266185
|
...row.dissolved_by != null ? { dissolvedBy: row.dissolved_by } : {}
|
|
@@ -271571,11 +272477,11 @@ var init_postgres_delegations = __esm({
|
|
|
271571
272477
|
});
|
|
271572
272478
|
|
|
271573
272479
|
// ../storage/src/postgres-nodes.ts
|
|
271574
|
-
var
|
|
272480
|
+
var import_node_crypto80, ident14, PostgresNodeStore, PostgresNodeTokenStore, rowToNode, rowToFault, rowToQuota, rowToRuntime;
|
|
271575
272481
|
var init_postgres_nodes = __esm({
|
|
271576
272482
|
"../storage/src/postgres-nodes.ts"() {
|
|
271577
272483
|
"use strict";
|
|
271578
|
-
|
|
272484
|
+
import_node_crypto80 = require("node:crypto");
|
|
271579
272485
|
init_pg_ident();
|
|
271580
272486
|
init_esm();
|
|
271581
272487
|
ident14 = (s2) => {
|
|
@@ -271929,7 +272835,7 @@ var init_postgres_nodes = __esm({
|
|
|
271929
272835
|
return store;
|
|
271930
272836
|
}
|
|
271931
272837
|
issue(nodeId) {
|
|
271932
|
-
const token2 = `ont_${(0,
|
|
272838
|
+
const token2 = `ont_${(0, import_node_crypto80.randomBytes)(24).toString("base64url")}`;
|
|
271933
272839
|
this.cache.set(token2, nodeId);
|
|
271934
272840
|
void this.pool.query(`INSERT INTO ${this.s}.node_tokens (token,node_id) VALUES ($1,$2)`, [token2, nodeId]);
|
|
271935
272841
|
return token2;
|
|
@@ -272231,11 +273137,11 @@ var init_postgres_type_registry = __esm({
|
|
|
272231
273137
|
});
|
|
272232
273138
|
|
|
272233
273139
|
// ../storage/src/postgres-actor-memory.ts
|
|
272234
|
-
var
|
|
273140
|
+
var import_node_crypto81, matchClause, ident16, PostgresActorMemoryStore, rowToIndexEntry, rowToRecord;
|
|
272235
273141
|
var init_postgres_actor_memory = __esm({
|
|
272236
273142
|
"../storage/src/postgres-actor-memory.ts"() {
|
|
272237
273143
|
"use strict";
|
|
272238
|
-
|
|
273144
|
+
import_node_crypto81 = require("node:crypto");
|
|
272239
273145
|
init_pg_ident();
|
|
272240
273146
|
init_src();
|
|
272241
273147
|
matchClause = (q2) => q2.requireMatch && q2.keywords.length > 0 ? " WHERE m > 0" : "";
|
|
@@ -272445,7 +273351,7 @@ var init_postgres_actor_memory = __esm({
|
|
|
272445
273351
|
}
|
|
272446
273352
|
async write(input, now) {
|
|
272447
273353
|
if (input.memId === void 0) {
|
|
272448
|
-
const memId = `mem:${(0,
|
|
273354
|
+
const memId = `mem:${(0, import_node_crypto81.randomUUID)()}`;
|
|
272449
273355
|
const r2 = await this.pool.query(
|
|
272450
273356
|
`INSERT INTO ${this.s}.actor_memories
|
|
272451
273357
|
(mem_id, actor_id, project_id, keywords, content, version, created_at, updated_at, accessed_at, source_artifact_id, source_session_id)
|
|
@@ -274016,14 +274922,14 @@ function companySchemaName(companyId) {
|
|
|
274016
274922
|
if (typeof companyId !== "string" || !companyId.trim()) {
|
|
274017
274923
|
throw new Error("company schema mapping \u9700\u8981\u975E\u7A7A companyId\uFF08fail-closed\uFF1A\u4E0D\u56DE\u9000\u9ED8\u8BA4\u516C\u53F8\uFF09");
|
|
274018
274924
|
}
|
|
274019
|
-
const hex = (0,
|
|
274925
|
+
const hex = (0, import_node_crypto82.createHash)("sha256").update(companyId, "utf8").digest("hex");
|
|
274020
274926
|
return `${COMPANY_SCHEMA_PREFIX}${hex.slice(0, DIGEST_HEX_LEN)}`;
|
|
274021
274927
|
}
|
|
274022
|
-
var
|
|
274928
|
+
var import_node_crypto82, COMPANY_SCHEMA_PREFIX, DIGEST_HEX_LEN, SchemaMappingConflictError, TenantStorageLocationStore;
|
|
274023
274929
|
var init_tenant_schema_mapping = __esm({
|
|
274024
274930
|
"../storage/src/tenant-schema-mapping.ts"() {
|
|
274025
274931
|
"use strict";
|
|
274026
|
-
|
|
274932
|
+
import_node_crypto82 = require("node:crypto");
|
|
274027
274933
|
init_esm();
|
|
274028
274934
|
init_pg_ident();
|
|
274029
274935
|
COMPANY_SCHEMA_PREFIX = "c_";
|
|
@@ -274097,7 +275003,7 @@ var init_tenant_schema_mapping = __esm({
|
|
|
274097
275003
|
|
|
274098
275004
|
// ../storage/src/company-data-plane-schema.ts
|
|
274099
275005
|
function canonicalTypeDefHash(def) {
|
|
274100
|
-
return `sha256:${(0,
|
|
275006
|
+
return `sha256:${(0, import_node_crypto83.createHash)("sha256").update(JSON.stringify(def), "utf8").digest("hex")}`;
|
|
274101
275007
|
}
|
|
274102
275008
|
function defaultArtifactTypeTemplate() {
|
|
274103
275009
|
return [
|
|
@@ -274279,11 +275185,11 @@ async function seedDefaultArtifactTypes(pool, schema, templates = defaultArtifac
|
|
|
274279
275185
|
}
|
|
274280
275186
|
return { inserted };
|
|
274281
275187
|
}
|
|
274282
|
-
var
|
|
275188
|
+
var import_node_crypto83, DEFAULT_ARTIFACT_TYPE_TEMPLATE_VERSION;
|
|
274283
275189
|
var init_company_data_plane_schema = __esm({
|
|
274284
275190
|
"../storage/src/company-data-plane-schema.ts"() {
|
|
274285
275191
|
"use strict";
|
|
274286
|
-
|
|
275192
|
+
import_node_crypto83 = require("node:crypto");
|
|
274287
275193
|
init_esm();
|
|
274288
275194
|
init_pg_ident();
|
|
274289
275195
|
DEFAULT_ARTIFACT_TYPE_TEMPLATE_VERSION = "4c368e5c-types-v1";
|
|
@@ -274362,11 +275268,11 @@ function rowToFile2(row) {
|
|
|
274362
275268
|
updatedAt: new Date(row.updated_at).toISOString()
|
|
274363
275269
|
};
|
|
274364
275270
|
}
|
|
274365
|
-
var
|
|
275271
|
+
var import_node_crypto84, COMPANY_CONFLICT_MSG, CompanyIdentifierConflictError, CompanyOwnedRegistryStore;
|
|
274366
275272
|
var init_company_owned_registry_store = __esm({
|
|
274367
275273
|
"../storage/src/company-owned-registry-store.ts"() {
|
|
274368
275274
|
"use strict";
|
|
274369
|
-
|
|
275275
|
+
import_node_crypto84 = require("node:crypto");
|
|
274370
275276
|
init_esm();
|
|
274371
275277
|
init_src();
|
|
274372
275278
|
init_pg_ident();
|
|
@@ -274751,7 +275657,7 @@ var init_company_owned_registry_store = __esm({
|
|
|
274751
275657
|
enabled: skill.enabled,
|
|
274752
275658
|
files: files.map((f2) => ({ path: f2.path, blobHash: f2.blobHash }))
|
|
274753
275659
|
});
|
|
274754
|
-
return (0,
|
|
275660
|
+
return (0, import_node_crypto84.createHash)("sha256").update(body2).digest("hex");
|
|
274755
275661
|
}
|
|
274756
275662
|
};
|
|
274757
275663
|
}
|
|
@@ -277561,7 +278467,7 @@ function sourceSetConservation(input) {
|
|
|
277561
278467
|
return input.sourceFinal === input.copied + input.approvedRuntimeConversion + input.approvedArchive + input.approvedDiscard;
|
|
277562
278468
|
}
|
|
277563
278469
|
function payloadChecksum(value2) {
|
|
277564
|
-
return (0,
|
|
278470
|
+
return (0, import_node_crypto85.createHash)("sha256").update(JSON.stringify(value2)).digest("hex");
|
|
277565
278471
|
}
|
|
277566
278472
|
async function copyWorkorderDraftsIdempotent(pool, companyId, companySchema, manifestId, opts) {
|
|
277567
278473
|
const cs = quoteIdent2(companySchema);
|
|
@@ -277953,11 +278859,11 @@ async function copyTraceFamilyIdempotent(pool, companyId, companySchema, manifes
|
|
|
277953
278859
|
sequences
|
|
277954
278860
|
};
|
|
277955
278861
|
}
|
|
277956
|
-
var
|
|
278862
|
+
var import_node_crypto85, MissingInstallerActorsError, TypeCatalogNotCoveredError, ORG_REGISTRY_TABLES, TRACE_FAMILY;
|
|
277957
278863
|
var init_tenant_migration_operator = __esm({
|
|
277958
278864
|
"../storage/src/tenant-migration-operator.ts"() {
|
|
277959
278865
|
"use strict";
|
|
277960
|
-
|
|
278866
|
+
import_node_crypto85 = require("node:crypto");
|
|
277961
278867
|
init_esm();
|
|
277962
278868
|
init_pg_ident();
|
|
277963
278869
|
init_tenancy_attribution();
|
|
@@ -278193,8 +279099,8 @@ var init_tenant_new_company_provision = __esm({
|
|
|
278193
279099
|
// ../storage/src/knowledge-snapshot-crypto.ts
|
|
278194
279100
|
function sealSnapshot(snapshot, key2) {
|
|
278195
279101
|
if (snapshot.content.startsWith(PREFIX3)) return structuredClone(snapshot);
|
|
278196
|
-
const iv = (0,
|
|
278197
|
-
const cipher = (0,
|
|
279102
|
+
const iv = (0, import_node_crypto86.randomBytes)(12);
|
|
279103
|
+
const cipher = (0, import_node_crypto86.createCipheriv)("aes-256-gcm", bytes(key2), iv);
|
|
278198
279104
|
cipher.setAAD(aad2(snapshot));
|
|
278199
279105
|
const encrypted = Buffer.concat([cipher.update(snapshot.content, "utf8"), cipher.final()]);
|
|
278200
279106
|
return { ...structuredClone(snapshot), content: `${PREFIX3}${iv.toString("base64url")}.${cipher.getAuthTag().toString("base64url")}.${encrypted.toString("base64url")}` };
|
|
@@ -278204,7 +279110,7 @@ function openSnapshot(snapshot, key2) {
|
|
|
278204
279110
|
const packed = snapshot.content.slice(PREFIX3.length).split(".");
|
|
278205
279111
|
if (packed.length !== 3 || packed.some((part) => !part)) throw new Error(`knowledge snapshot ${snapshot.ref} ciphertext is malformed`);
|
|
278206
279112
|
const [iv, tag, data] = packed;
|
|
278207
|
-
const decipher = (0,
|
|
279113
|
+
const decipher = (0, import_node_crypto86.createDecipheriv)("aes-256-gcm", bytes(key2), Buffer.from(iv, "base64url"));
|
|
278208
279114
|
decipher.setAAD(aad2(snapshot));
|
|
278209
279115
|
decipher.setAuthTag(Buffer.from(tag, "base64url"));
|
|
278210
279116
|
return {
|
|
@@ -278212,11 +279118,11 @@ function openSnapshot(snapshot, key2) {
|
|
|
278212
279118
|
content: Buffer.concat([decipher.update(Buffer.from(data, "base64url")), decipher.final()]).toString("utf8")
|
|
278213
279119
|
};
|
|
278214
279120
|
}
|
|
278215
|
-
var
|
|
279121
|
+
var import_node_crypto86, PREFIX3, bytes, aad2;
|
|
278216
279122
|
var init_knowledge_snapshot_crypto = __esm({
|
|
278217
279123
|
"../storage/src/knowledge-snapshot-crypto.ts"() {
|
|
278218
279124
|
"use strict";
|
|
278219
|
-
|
|
279125
|
+
import_node_crypto86 = require("node:crypto");
|
|
278220
279126
|
PREFIX3 = "oasis-knowledge:v1:";
|
|
278221
279127
|
bytes = (key2) => {
|
|
278222
279128
|
const value2 = Buffer.from(key2);
|
|
@@ -278965,6 +279871,9 @@ var init_default_company_schema_move = __esm({
|
|
|
278965
279871
|
"review_requirements",
|
|
278966
279872
|
"review_view",
|
|
278967
279873
|
"reviews",
|
|
279874
|
+
// 个人待办与它的变更记录(2026-10-08 落库,ADR 0635):每行锚在本公司成员与会话上,整表搬(与 discussion_entries 同理)。
|
|
279875
|
+
"todo_changes",
|
|
279876
|
+
"todos",
|
|
278968
279877
|
"work_artifacts",
|
|
278969
279878
|
"work_inputs",
|
|
278970
279879
|
"work_order_files",
|
|
@@ -279111,7 +280020,7 @@ function reportedCost(v2) {
|
|
|
279111
280020
|
}
|
|
279112
280021
|
function newUsageBackfillManifestId(now = /* @__PURE__ */ new Date()) {
|
|
279113
280022
|
const stamp = now.toISOString().replace(/[-:]/g, "").replace(/\.\d+Z$/, "Z");
|
|
279114
|
-
return `ulb-${stamp}-${(0,
|
|
280023
|
+
return `ulb-${stamp}-${(0, import_node_crypto87.randomBytes)(3).toString("hex")}`;
|
|
279115
280024
|
}
|
|
279116
280025
|
async function backfillUsageLedger(ledger, opts) {
|
|
279117
280026
|
if (!opts.dryRun && !opts.manifestId) throw new Error("execute \u9700\u8981 manifestId");
|
|
@@ -279660,11 +280569,11 @@ async function audit(c, s2, manifestId, runId, field, before, after, createdAt)
|
|
|
279660
280569
|
[manifestId, runId, field, before == null ? null : JSON.stringify(before), after == null ? null : JSON.stringify(after), createdAt]
|
|
279661
280570
|
);
|
|
279662
280571
|
}
|
|
279663
|
-
var
|
|
280572
|
+
var import_node_crypto87, BUCKETS, ENDED_SQL, START_EVIDENCE_SQL, CHAT_RUN_SQL, ALLOWED_MODEL_EVIDENCE_TIERS, emptyStep, MODEL_BACKFILL_SOURCE, fourOf, sameUsage, ChatRunLookup;
|
|
279664
280573
|
var init_usage_ledger_backfill = __esm({
|
|
279665
280574
|
"../storage/src/usage-ledger-backfill.ts"() {
|
|
279666
280575
|
"use strict";
|
|
279667
|
-
|
|
280576
|
+
import_node_crypto87 = require("node:crypto");
|
|
279668
280577
|
init_src();
|
|
279669
280578
|
init_pg_ident();
|
|
279670
280579
|
init_postgres_trace();
|
|
@@ -280049,26 +280958,26 @@ var init_cutover_aware_workorder_drafts = __esm({
|
|
|
280049
280958
|
|
|
280050
280959
|
// ../server/src/governance/builtin-skills.ts
|
|
280051
280960
|
async function collectDir(root, dir, out) {
|
|
280052
|
-
const entries = await (0,
|
|
280961
|
+
const entries = await (0, import_promises16.readdir)(dir, { withFileTypes: true });
|
|
280053
280962
|
for (const e of entries) {
|
|
280054
|
-
const abs = (0,
|
|
280963
|
+
const abs = (0, import_node_path28.join)(dir, e.name);
|
|
280055
280964
|
if (e.isDirectory()) {
|
|
280056
280965
|
await collectDir(root, abs, out);
|
|
280057
280966
|
} else if (e.isFile()) {
|
|
280058
|
-
const info = await (0,
|
|
280967
|
+
const info = await (0, import_promises16.stat)(abs);
|
|
280059
280968
|
if (info.size > MAX_FILE_BYTES2) {
|
|
280060
280969
|
console.warn(`[builtin-skills] skip oversized file (${info.size}B): ${abs}`);
|
|
280061
280970
|
continue;
|
|
280062
280971
|
}
|
|
280063
|
-
const rel = (0,
|
|
280064
|
-
out[rel] = await (0,
|
|
280972
|
+
const rel = (0, import_node_path28.relative)(root, abs).split(/[\\/]/).join("/");
|
|
280973
|
+
out[rel] = await (0, import_promises16.readFile)(abs, "utf8");
|
|
280065
280974
|
}
|
|
280066
280975
|
}
|
|
280067
280976
|
}
|
|
280068
280977
|
async function loadBuiltinSkills(skillsDir) {
|
|
280069
280978
|
let dirents;
|
|
280070
280979
|
try {
|
|
280071
|
-
dirents = await (0,
|
|
280980
|
+
dirents = await (0, import_promises16.readdir)(skillsDir, { withFileTypes: true });
|
|
280072
280981
|
} catch {
|
|
280073
280982
|
return [];
|
|
280074
280983
|
}
|
|
@@ -280076,7 +280985,7 @@ async function loadBuiltinSkills(skillsDir) {
|
|
|
280076
280985
|
for (const d of dirents) {
|
|
280077
280986
|
if (!d.isDirectory()) continue;
|
|
280078
280987
|
const slug5 = d.name;
|
|
280079
|
-
const skillDir = (0,
|
|
280988
|
+
const skillDir = (0, import_node_path28.join)(skillsDir, slug5);
|
|
280080
280989
|
const files = {};
|
|
280081
280990
|
try {
|
|
280082
280991
|
await collectDir(skillDir, skillDir, files);
|
|
@@ -280105,7 +281014,8 @@ function materializeBuiltinSkills(builtins, skillsDirPrefix) {
|
|
|
280105
281014
|
return out;
|
|
280106
281015
|
}
|
|
280107
281016
|
function applyBuiltinSkillVariants(builtins, opts) {
|
|
280108
|
-
|
|
281017
|
+
const personalTodoEnabled = opts.personalTodoEnabled ?? personalTodoEnabledFromEnv();
|
|
281018
|
+
return builtins.filter((skill) => skill.id !== PERSONAL_TODO_SKILL_ID || personalTodoEnabled).map((skill) => {
|
|
280109
281019
|
const variant = skill.files[BUILTIN_SKILL_DELEGATION_VARIANT];
|
|
280110
281020
|
if (variant === void 0) return skill;
|
|
280111
281021
|
const files = { ...skill.files };
|
|
@@ -280116,16 +281026,18 @@ function applyBuiltinSkillVariants(builtins, opts) {
|
|
|
280116
281026
|
return { ...skill, name: name || skill.id, description, files };
|
|
280117
281027
|
});
|
|
280118
281028
|
}
|
|
280119
|
-
var
|
|
281029
|
+
var import_promises16, import_node_path28, MAX_FILE_BYTES2, BUILTIN_SKILL_DELEGATION_VARIANT, PERSONAL_TODO_SKILL_ID;
|
|
280120
281030
|
var init_builtin_skills = __esm({
|
|
280121
281031
|
"../server/src/governance/builtin-skills.ts"() {
|
|
280122
281032
|
"use strict";
|
|
280123
|
-
|
|
280124
|
-
|
|
281033
|
+
import_promises16 = require("node:fs/promises");
|
|
281034
|
+
import_node_path28 = require("node:path");
|
|
280125
281035
|
init_skill_fetcher();
|
|
280126
281036
|
init_skill_materializer();
|
|
281037
|
+
init_flag();
|
|
280127
281038
|
MAX_FILE_BYTES2 = 1 << 20;
|
|
280128
281039
|
BUILTIN_SKILL_DELEGATION_VARIANT = "SKILL.delegation.md";
|
|
281040
|
+
PERSONAL_TODO_SKILL_ID = "personal-todo";
|
|
280129
281041
|
}
|
|
280130
281042
|
});
|
|
280131
281043
|
|
|
@@ -280153,7 +281065,7 @@ var init_chat_builtin_skills = __esm({
|
|
|
280153
281065
|
|
|
280154
281066
|
// ../server/src/governance/connector-tool-versions.ts
|
|
280155
281067
|
function connectorToolVersionsFile(dataDir) {
|
|
280156
|
-
return (0,
|
|
281068
|
+
return (0, import_node_path29.join)(dataDir, "connector-tools", "versions.json");
|
|
280157
281069
|
}
|
|
280158
281070
|
function registryBase() {
|
|
280159
281071
|
const raw = process.env["npm_config_registry"] || process.env["NPM_CONFIG_REGISTRY"] || "https://registry.npmjs.org";
|
|
@@ -280172,7 +281084,7 @@ async function fetchLatestNpmVersion(pkg) {
|
|
|
280172
281084
|
}
|
|
280173
281085
|
async function readRegisteredToolVersions(dataDir) {
|
|
280174
281086
|
try {
|
|
280175
|
-
const raw = JSON.parse(await (0,
|
|
281087
|
+
const raw = JSON.parse(await (0, import_promises17.readFile)(connectorToolVersionsFile(dataDir), "utf8"));
|
|
280176
281088
|
if (!raw || typeof raw !== "object") return {};
|
|
280177
281089
|
const out = {};
|
|
280178
281090
|
for (const [k2, v2] of Object.entries(raw)) {
|
|
@@ -280185,11 +281097,11 @@ async function readRegisteredToolVersions(dataDir) {
|
|
|
280185
281097
|
}
|
|
280186
281098
|
async function writeRegisteredToolVersions(dataDir, versions) {
|
|
280187
281099
|
const file = connectorToolVersionsFile(dataDir);
|
|
280188
|
-
await (0,
|
|
281100
|
+
await (0, import_promises17.mkdir)((0, import_node_path29.join)(dataDir, "connector-tools"), { recursive: true });
|
|
280189
281101
|
const tmp = `${file}.${process.pid}.tmp`;
|
|
280190
|
-
await (0,
|
|
281102
|
+
await (0, import_promises17.writeFile)(tmp, `${JSON.stringify(versions, null, 2)}
|
|
280191
281103
|
`, "utf8");
|
|
280192
|
-
await (0,
|
|
281104
|
+
await (0, import_promises17.rename)(tmp, file);
|
|
280193
281105
|
}
|
|
280194
281106
|
async function refreshConnectorToolVersions(opts) {
|
|
280195
281107
|
const fetchLatest = opts.fetchLatest ?? fetchLatestNpmVersion;
|
|
@@ -280232,12 +281144,12 @@ function pickToolVersions(registered, tools) {
|
|
|
280232
281144
|
}
|
|
280233
281145
|
return out;
|
|
280234
281146
|
}
|
|
280235
|
-
var
|
|
281147
|
+
var import_promises17, import_node_path29, NPM_PROBE_TIMEOUT_MS;
|
|
280236
281148
|
var init_connector_tool_versions = __esm({
|
|
280237
281149
|
"../server/src/governance/connector-tool-versions.ts"() {
|
|
280238
281150
|
"use strict";
|
|
280239
|
-
|
|
280240
|
-
|
|
281151
|
+
import_promises17 = require("node:fs/promises");
|
|
281152
|
+
import_node_path29 = require("node:path");
|
|
280241
281153
|
init_src8();
|
|
280242
281154
|
NPM_PROBE_TIMEOUT_MS = 3e3;
|
|
280243
281155
|
}
|
|
@@ -281330,6 +282242,7 @@ __export(src_exports2, {
|
|
|
281330
282242
|
DEFAULT_PUSH_THROTTLE_MS: () => DEFAULT_PUSH_THROTTLE_MS,
|
|
281331
282243
|
DEFAULT_SIMPLE_QUERY_MAX_CHARS: () => DEFAULT_SIMPLE_QUERY_MAX_CHARS,
|
|
281332
282244
|
DEFAULT_TERMINAL_MAX_AGE_MS: () => DEFAULT_TERMINAL_MAX_AGE_MS,
|
|
282245
|
+
DEFAULT_TIME_ZONE_ENV: () => DEFAULT_TIME_ZONE_ENV,
|
|
281333
282246
|
DELIVERY_REPAIR_BATCH: () => DELIVERY_REPAIR_BATCH,
|
|
281334
282247
|
DENY_ALL_TRACE_READ: () => DENY_ALL_TRACE_READ,
|
|
281335
282248
|
DISPATCH_DROP_BACKOFF_MS: () => DISPATCH_DROP_BACKOFF_MS,
|
|
@@ -281413,6 +282326,7 @@ __export(src_exports2, {
|
|
|
281413
282326
|
MemoryProjectStateStore: () => MemoryProjectStateStore,
|
|
281414
282327
|
MemoryPushSubscriptionStore: () => MemoryPushSubscriptionStore,
|
|
281415
282328
|
MemoryReadMarkerStore: () => MemoryReadMarkerStore,
|
|
282329
|
+
MemoryTodoStore: () => MemoryTodoStore,
|
|
281416
282330
|
MemoryWorkorderDraftPlannerIssuesStore: () => MemoryWorkorderDraftPlannerIssuesStore,
|
|
281417
282331
|
MemoryWorkorderTagStore: () => MemoryWorkorderTagStore,
|
|
281418
282332
|
MemoryWriteConflictError: () => MemoryWriteConflictError,
|
|
@@ -281431,6 +282345,7 @@ __export(src_exports2, {
|
|
|
281431
282345
|
OWNER_PROTECTED_PROFILE_MESSAGE: () => OWNER_PROTECTED_PROFILE_MESSAGE,
|
|
281432
282346
|
PARENT_CONVERSATION_PATH: () => PARENT_CONVERSATION_PATH,
|
|
281433
282347
|
PARENT_CONVERSATION_RECENT_TURNS: () => PARENT_CONVERSATION_RECENT_TURNS,
|
|
282348
|
+
PERSONAL_TODO_SKILL_ID: () => PERSONAL_TODO_SKILL_ID,
|
|
281434
282349
|
PostgresNotificationStore: () => PostgresNotificationStore,
|
|
281435
282350
|
PostgresPushSubscriptionStore: () => PostgresPushSubscriptionStore,
|
|
281436
282351
|
PostgresWorkorderDraftPlannerIssuesStore: () => PostgresWorkorderDraftPlannerIssuesStore,
|
|
@@ -281461,7 +282376,12 @@ __export(src_exports2, {
|
|
|
281461
282376
|
STATUS_MARKER: () => STATUS_MARKER,
|
|
281462
282377
|
SessionRuntimeOverrideError: () => SessionRuntimeOverrideError,
|
|
281463
282378
|
SkillFetchHttpError: () => SkillFetchHttpError,
|
|
282379
|
+
TODO_REMINDER_SCAN_MS: () => TODO_REMINDER_SCAN_MS,
|
|
282380
|
+
TODO_REMINDER_TIME: () => TODO_REMINDER_TIME,
|
|
282381
|
+
TODO_REMINDER_TITLE: () => TODO_REMINDER_TITLE,
|
|
281464
282382
|
TenancyVisibilityInputError: () => TenancyVisibilityInputError,
|
|
282383
|
+
TodoReminderScanner: () => TodoReminderScanner,
|
|
282384
|
+
TodoService: () => TodoService,
|
|
281465
282385
|
TraceService: () => TraceService,
|
|
281466
282386
|
TraceStoreSink: () => TraceStoreSink,
|
|
281467
282387
|
TypesAdminService: () => TypesAdminService,
|
|
@@ -281487,10 +282407,12 @@ __export(src_exports2, {
|
|
|
281487
282407
|
assertBindingWritePermission: () => assertBindingWritePermission,
|
|
281488
282408
|
assertCompanyManager: () => assertCompanyManager,
|
|
281489
282409
|
assertCreatableVariable: () => assertCreatableVariable,
|
|
282410
|
+
assertFirstVersionAssignee: () => assertFirstVersionAssignee,
|
|
281490
282411
|
assertMayCreateAgent: () => assertMayCreateAgent,
|
|
281491
282412
|
assertMayManageAgent: () => assertMayManageAgent,
|
|
281492
282413
|
assertMaySelfOrManage: () => assertMaySelfOrManage,
|
|
281493
282414
|
assistantBoundToMember: () => assistantBoundToMember,
|
|
282415
|
+
assistantNameFor: () => assistantNameFor,
|
|
281494
282416
|
assistantRowRecovery: () => assistantRowRecovery,
|
|
281495
282417
|
assistantsDomain: () => assistantsDomain,
|
|
281496
282418
|
atCapacity: () => atCapacity,
|
|
@@ -281526,6 +282448,7 @@ __export(src_exports2, {
|
|
|
281526
282448
|
buildWorkorderMetrics: () => buildWorkorderMetrics,
|
|
281527
282449
|
buildWorkorderSummaries: () => buildWorkorderSummaries,
|
|
281528
282450
|
builtinSkillToFiles: () => builtinSkillToFiles,
|
|
282451
|
+
canAccessTodo: () => canAccessTodo,
|
|
281529
282452
|
canAnnounceRuntimeSwitch: () => canAnnounceRuntimeSwitch,
|
|
281530
282453
|
canRetryAllocation: () => canRetryAllocation,
|
|
281531
282454
|
chatBroadcastEnabledFromEnv: () => chatBroadcastEnabledFromEnv,
|
|
@@ -281611,6 +282534,7 @@ __export(src_exports2, {
|
|
|
281611
282534
|
decideArrival: () => decideArrival,
|
|
281612
282535
|
decideFlush: () => decideFlush,
|
|
281613
282536
|
defaultAvatarRefOf: () => defaultAvatarRefOf,
|
|
282537
|
+
defaultTimeZoneFromEnv: () => defaultTimeZoneFromEnv,
|
|
281614
282538
|
delegationArtifactsView: () => delegationArtifactsView,
|
|
281615
282539
|
delegationBundleAdditions: () => delegationBundleAdditions,
|
|
281616
282540
|
delegationDirName: () => delegationDirName,
|
|
@@ -281635,6 +282559,7 @@ __export(src_exports2, {
|
|
|
281635
282559
|
dispatchIntentMarker: () => dispatchIntentMarker,
|
|
281636
282560
|
displayCostUsdMicros: () => displayCostUsdMicros,
|
|
281637
282561
|
dropUnchangedOutputs: () => dropUnchangedOutputs,
|
|
282562
|
+
dueReminders: () => dueReminders,
|
|
281638
282563
|
employeeHref: () => employeeHref,
|
|
281639
282564
|
encryptPushMessage: () => encryptPushMessage,
|
|
281640
282565
|
ensureCompanyActors: () => ensureCompanyActors,
|
|
@@ -281770,6 +282695,7 @@ __export(src_exports2, {
|
|
|
281770
282695
|
parseWriteScope: () => parseWriteScope,
|
|
281771
282696
|
parseZhizengzengMarkdown: () => parseZhizengzengMarkdown,
|
|
281772
282697
|
participatingTaskCount: () => participatingTaskCount,
|
|
282698
|
+
personalTodoEnabledFromEnv: () => personalTodoEnabledFromEnv,
|
|
281773
282699
|
pickToolVersions: () => pickToolVersions,
|
|
281774
282700
|
placeholderRuntimeSessionFlag: () => placeholderRuntimeSessionFlag,
|
|
281775
282701
|
planChatContinuation: () => planChatContinuation,
|
|
@@ -281911,6 +282837,8 @@ __export(src_exports2, {
|
|
|
281911
282837
|
toBundleFiles: () => toBundleFiles,
|
|
281912
282838
|
toChatDispatchRequest: () => toChatDispatchRequest,
|
|
281913
282839
|
toYamlDoubleQuoted: () => toYamlDoubleQuoted,
|
|
282840
|
+
todoReminderSourceKey: () => todoReminderSourceKey,
|
|
282841
|
+
todosDomain: () => todosDomain,
|
|
281914
282842
|
touchKey: () => touchKey,
|
|
281915
282843
|
traceDomain: () => traceDomain,
|
|
281916
282844
|
traceReadAllows: () => traceReadAllows,
|
|
@@ -282039,6 +282967,7 @@ var init_src11 = __esm({
|
|
|
282039
282967
|
init_agent_default_runtime_store();
|
|
282040
282968
|
init_knowledge2();
|
|
282041
282969
|
init_delegations();
|
|
282970
|
+
init_todos2();
|
|
282042
282971
|
init_automations();
|
|
282043
282972
|
init_automations();
|
|
282044
282973
|
init_playbooks();
|
|
@@ -282450,14 +283379,14 @@ init_src();
|
|
|
282450
283379
|
var os16 = __toESM(require("node:os"));
|
|
282451
283380
|
var path46 = __toESM(require("node:path"));
|
|
282452
283381
|
var import_node_child_process23 = require("node:child_process");
|
|
282453
|
-
var
|
|
283382
|
+
var import_node_crypto100 = require("node:crypto");
|
|
282454
283383
|
|
|
282455
283384
|
// ../cli/src/cli.ts
|
|
282456
283385
|
init_src();
|
|
282457
283386
|
var fs44 = __toESM(require("node:fs"), 1);
|
|
282458
283387
|
var os13 = __toESM(require("node:os"), 1);
|
|
282459
283388
|
var path39 = __toESM(require("node:path"), 1);
|
|
282460
|
-
var
|
|
283389
|
+
var import_node_crypto98 = require("node:crypto");
|
|
282461
283390
|
|
|
282462
283391
|
// ../cli/src/serve.ts
|
|
282463
283392
|
init_src11();
|
|
@@ -282470,11 +283399,11 @@ var fs36 = __toESM(require("node:fs"), 1);
|
|
|
282470
283399
|
var os9 = __toESM(require("node:os"), 1);
|
|
282471
283400
|
var path29 = __toESM(require("node:path"), 1);
|
|
282472
283401
|
var import_node_child_process15 = require("node:child_process");
|
|
282473
|
-
var
|
|
283402
|
+
var import_node_crypto93 = require("node:crypto");
|
|
282474
283403
|
var import_node_url7 = require("node:url");
|
|
282475
283404
|
|
|
282476
283405
|
// ../cli/src/artifact-discovery-source.ts
|
|
282477
|
-
var
|
|
283406
|
+
var import_node_crypto88 = require("node:crypto");
|
|
282478
283407
|
init_src7();
|
|
282479
283408
|
var ArtifactDiscoverySourceUnreadableError = class extends Error {
|
|
282480
283409
|
constructor(message) {
|
|
@@ -282504,7 +283433,7 @@ async function resolveArtifactDiscoverySourceContent(blobs, input) {
|
|
|
282504
283433
|
throw new ArtifactDiscoverySourceUnreadableError(`Artifact Revision ${input.revisionId} \u7684 contentKind \u4E0D\u53D7\u652F\u6301\uFF1A${String(input.contentKind)}`);
|
|
282505
283434
|
}
|
|
282506
283435
|
const rootBytes = await blobs.get(input.contentRef);
|
|
282507
|
-
const sourceFingerprint = (0,
|
|
283436
|
+
const sourceFingerprint = (0, import_node_crypto88.createHash)("sha256").update(rootBytes).digest("hex");
|
|
282508
283437
|
if (input.contentKind === "inline-blob") {
|
|
282509
283438
|
const sourceContent = decodeText3(rootBytes);
|
|
282510
283439
|
if (sourceContent === null) {
|
|
@@ -282528,7 +283457,7 @@ ${entry.text}`).join("\n\n"),
|
|
|
282528
283457
|
}
|
|
282529
283458
|
|
|
282530
283459
|
// ../server/src/domains/discussions/service.ts
|
|
282531
|
-
var
|
|
283460
|
+
var import_node_crypto89 = require("node:crypto");
|
|
282532
283461
|
init_zod();
|
|
282533
283462
|
init_discussions();
|
|
282534
283463
|
init_router();
|
|
@@ -282597,7 +283526,7 @@ var decisionOption = (row) => ({
|
|
|
282597
283526
|
state: row.value.record.state,
|
|
282598
283527
|
revision: row.revision
|
|
282599
283528
|
});
|
|
282600
|
-
var hash2 = (s2) => (0,
|
|
283529
|
+
var hash2 = (s2) => (0, import_node_crypto89.createHash)("sha256").update(s2).digest("hex").slice(0, 24);
|
|
282601
283530
|
var canonical = (s2) => s2.normalize("NFKC").trim().toLocaleLowerCase();
|
|
282602
283531
|
function decisionFingerprint(d) {
|
|
282603
283532
|
return hash2(JSON.stringify([d.statement, d.rationale, d.alternatives]));
|
|
@@ -282870,7 +283799,7 @@ var DiscussionService = class {
|
|
|
282870
283799
|
throw new ApiError(409, "DISCUSSION_CONFLICT", "\u9879\u76EE\u8BAE\u9898\u6216\u51B3\u7B56\u5DF2\u53D8\u5316\uFF0C\u8BF7\u8BFB\u53D6\u6700\u65B0\u5185\u5BB9\u540E\u4FEE\u6B63");
|
|
282871
283800
|
}
|
|
282872
283801
|
}
|
|
282873
|
-
const operation = (value2) => tx.put("operation", (0,
|
|
283802
|
+
const operation = (value2) => tx.put("operation", (0, import_node_crypto89.randomUUID)(), {
|
|
282874
283803
|
...value2,
|
|
282875
283804
|
projectId: projectId2,
|
|
282876
283805
|
actorId: ctx.actorId,
|
|
@@ -282887,7 +283816,7 @@ var DiscussionService = class {
|
|
|
282887
283816
|
if (id.startsWith("new:")) {
|
|
282888
283817
|
if (BUG_TOPIC.test(t.title.trim())) invalid("topics.title", `\u300C${t.title}\u300D\u662F\u5355\u4E2A Bug\uFF1A\u4FEE\u590D\u60C5\u51B5\u5199\u8FDB\u8BA8\u8BBA\u8BB0\u5F55\uFF0C\u5B9A\u51FA\u7684\u89C4\u5219\u6302\u5230\u5BF9\u5E94\u529F\u80FD\u8BAE\u9898\u4E0B\uFF0C\u4E0D\u6309 Bug \u53F7\u5EFA\u8BAE\u9898`);
|
|
282889
283818
|
const existing = [...topicMap.values()].find((x2) => canonical(x2.title) === canonical(t.title));
|
|
282890
|
-
id = existing?.topicId ?? `topic_${(0,
|
|
283819
|
+
id = existing?.topicId ?? `topic_${(0, import_node_crypto89.randomUUID)()}`;
|
|
282891
283820
|
if (!existing) createdTopics.add(id);
|
|
282892
283821
|
} else if (!topicMap.has(id)) invalid("topics.topic_id", `\u8BAE\u9898 ${id} \u4E0D\u5B58\u5728\uFF1B\u65B0\u8BAE\u9898\u4F7F\u7528 new: \u524D\u7F00`);
|
|
282893
283822
|
topicAliases.set(t.topic_id, id);
|
|
@@ -282939,7 +283868,7 @@ var DiscussionService = class {
|
|
|
282939
283868
|
if (id.startsWith("new:")) {
|
|
282940
283869
|
const candidateKey = JSON.stringify([topicId, canonical(d.record.statement)]);
|
|
282941
283870
|
const existing = [...decisionMap.values()].find((x2) => x2.topicId === topicId && canonical(x2.record.statement) === canonical(d.record.statement));
|
|
282942
|
-
id = existing?.decisionId ?? candidateIds.get(candidateKey) ?? `decision_${(0,
|
|
283871
|
+
id = existing?.decisionId ?? candidateIds.get(candidateKey) ?? `decision_${(0, import_node_crypto89.randomUUID)()}`;
|
|
282943
283872
|
candidateIds.set(candidateKey, id);
|
|
282944
283873
|
} else if (!decisionMap.has(id)) invalid("decision_id", `\u51B3\u7B56 ${id} \u4E0D\u5B58\u5728\uFF1B\u65B0\u51B3\u7B56\u4F7F\u7528 new: \u524D\u7F00`);
|
|
282945
283874
|
decisionAliases.set(d.decision_id, id);
|
|
@@ -283063,15 +283992,15 @@ var DiscussionService = class {
|
|
|
283063
283992
|
});
|
|
283064
283993
|
}
|
|
283065
283994
|
async editTopic(projectId2, topicId, revision, raw, actorId) {
|
|
283066
|
-
const
|
|
283995
|
+
const edit3 = external_exports.object({ title: nonempty, summary: text6.optional() }).strict().parse(raw);
|
|
283067
283996
|
return this.store.transaction(async (tx) => {
|
|
283068
283997
|
const key2 = entryId(projectId2, topicId);
|
|
283069
283998
|
const old = await tx.get("topic", key2);
|
|
283070
283999
|
if (!old) throw new ApiError(404, "NOT_FOUND", "\u8BAE\u9898\u4E0D\u5B58\u5728");
|
|
283071
284000
|
assertRevision(old.revision, revision);
|
|
283072
|
-
const summary = (
|
|
283073
|
-
if (old.value.title ===
|
|
283074
|
-
const result = await tx.put("topic", key2, { ...old.value, title:
|
|
284001
|
+
const summary = (edit3.summary ?? old.value.summary ?? "").trim();
|
|
284002
|
+
if (old.value.title === edit3.title && (old.value.summary ?? "") === summary) return old;
|
|
284003
|
+
const result = await tx.put("topic", key2, { ...old.value, title: edit3.title, summary, updated_at: new Date(this.now()).toISOString() });
|
|
283075
284004
|
await this.operation(tx, actorId, "topic", key2, old.revision, result.revision);
|
|
283076
284005
|
return result;
|
|
283077
284006
|
});
|
|
@@ -283201,7 +284130,7 @@ var DiscussionService = class {
|
|
|
283201
284130
|
...row.value.confirmation ? { confirmation: { ...row.value.confirmation, fingerprint: decisionFingerprint(record10) } } : {}
|
|
283202
284131
|
};
|
|
283203
284132
|
await tx.put("decision", row.id, value2);
|
|
283204
|
-
await tx.put("operation", (0,
|
|
284133
|
+
await tx.put("operation", (0, import_node_crypto89.randomUUID)(), {
|
|
283205
284134
|
action: "edit",
|
|
283206
284135
|
kind: "decision",
|
|
283207
284136
|
projectId: projectId2,
|
|
@@ -283265,7 +284194,7 @@ var DiscussionService = class {
|
|
|
283265
284194
|
if (!current || current.revision !== row.revision) throw new ApiError(409, "DISCUSSION_CONFLICT", `\u8BA8\u8BBA ${row.id} \u5DF2\u88AB\u4FEE\u6539\uFF0C\u8BF7\u8BFB\u53D6\u6700\u65B0\u5185\u5BB9\u540E\u91CD\u8BD5`);
|
|
283266
284195
|
const summary = given.get(row.id);
|
|
283267
284196
|
await tx.put("discussion", row.id, { ...current.value, record: { ...current.value.record, summary } });
|
|
283268
|
-
await tx.put("operation", (0,
|
|
284197
|
+
await tx.put("operation", (0, import_node_crypto89.randomUUID)(), {
|
|
283269
284198
|
action: "edit",
|
|
283270
284199
|
kind: "discussion",
|
|
283271
284200
|
projectId: current.value.record.project_id,
|
|
@@ -283281,7 +284210,7 @@ var DiscussionService = class {
|
|
|
283281
284210
|
});
|
|
283282
284211
|
}
|
|
283283
284212
|
async operation(tx, actorId, kind, id, from, to) {
|
|
283284
|
-
await tx.put("operation", (0,
|
|
284213
|
+
await tx.put("operation", (0, import_node_crypto89.randomUUID)(), { actorId, kind, id, from, to, at: new Date(this.now()).toISOString() });
|
|
283285
284214
|
}
|
|
283286
284215
|
};
|
|
283287
284216
|
function pickDiscussionContent(d) {
|
|
@@ -283412,13 +284341,13 @@ function renderProjectContext(input) {
|
|
|
283412
284341
|
const dir = PROJECT_DISCUSSIONS_DIR;
|
|
283413
284342
|
const files = {};
|
|
283414
284343
|
const width = (n) => Math.max(2, String(n).length);
|
|
283415
|
-
const
|
|
284344
|
+
const pad3 = (i, n) => String(i + 1).padStart(width(n), "0");
|
|
283416
284345
|
const mine = new Set(input.discussions.flatMap((row) => row.value.record.topics.map((t) => `${row.value.record.project_id}\0${t.topic_id}`)));
|
|
283417
|
-
const discussionPaths = input.discussions.map((row, i) => `${dir}/\u6211\u7684\u8BA8\u8BBA/${
|
|
284346
|
+
const discussionPaths = input.discussions.map((row, i) => `${dir}/\u6211\u7684\u8BA8\u8BBA/${pad3(i, input.discussions.length)}-${row.value.discussedAt.slice(0, 10)}-${fileSegment(row.value.record.title, "\u672A\u547D\u540D\u8BA8\u8BBA")}.md`);
|
|
283418
284347
|
input.discussions.forEach((row, i) => {
|
|
283419
284348
|
files[discussionPaths[i]] = [`# ${row.value.record.title}`, "", ...discussionBody(input, row)].join("\n");
|
|
283420
284349
|
});
|
|
283421
|
-
const topicPaths = input.topics.map((t, i) => `${dir}/\u8BAE\u9898/${
|
|
284350
|
+
const topicPaths = input.topics.map((t, i) => `${dir}/\u8BAE\u9898/${pad3(i, input.topics.length)}-${fileSegment(t.value.title, "\u672A\u547D\u540D\u8BAE\u9898")}.md`);
|
|
283422
284351
|
input.topics.forEach((t, i) => {
|
|
283423
284352
|
files[topicPaths[i]] = [`# \u8BAE\u9898\uFF1A${t.value.title}`, "", decisionLegend, "", ...topicBody(input, t, "##")].join("\n");
|
|
283424
284353
|
});
|
|
@@ -283581,7 +284510,7 @@ var DiscussionContext = class {
|
|
|
283581
284510
|
};
|
|
283582
284511
|
|
|
283583
284512
|
// ../server/src/domains/discussions/worker.ts
|
|
283584
|
-
var
|
|
284513
|
+
var import_node_crypto90 = require("node:crypto");
|
|
283585
284514
|
var DISCUSSION_IDLE_MS = 15 * 6e4;
|
|
283586
284515
|
var DISCUSSION_MAX_CORRECTIONS = 3;
|
|
283587
284516
|
var DISCUSSION_LEASE_MS = 2 * 6e4;
|
|
@@ -283607,7 +284536,7 @@ var DiscussionWorker = class {
|
|
|
283607
284536
|
if (await this.isReplying(sessionId)) return false;
|
|
283608
284537
|
const cutoff = eligibleCutoff(await this.service.chat.listMessages(sessionId), this.service.now());
|
|
283609
284538
|
if (!cutoff) return false;
|
|
283610
|
-
const owner = (0,
|
|
284539
|
+
const owner = (0, import_node_crypto90.randomUUID)();
|
|
283611
284540
|
const claimed = await this.service.store.transaction(async (tx) => {
|
|
283612
284541
|
const old = (await tx.get("job", sessionId))?.value;
|
|
283613
284542
|
if (old?.status === "running" && (old.leaseUntil ?? 0) > this.service.now()) return null;
|
|
@@ -284033,7 +284962,7 @@ init_zod();
|
|
|
284033
284962
|
init_discussions();
|
|
284034
284963
|
init_router();
|
|
284035
284964
|
init_uncategorized_project();
|
|
284036
|
-
var
|
|
284965
|
+
var edit2 = external_exports.object({ revision: external_exports.number().int().positive(), content: external_exports.unknown() }).strict();
|
|
284037
284966
|
var removal = external_exports.object({ revision: external_exports.number().int().positive(), reason: external_exports.string() }).strict();
|
|
284038
284967
|
function paging(query) {
|
|
284039
284968
|
const parsed = external_exports.object({
|
|
@@ -284122,7 +285051,7 @@ function discussionsDomain(options) {
|
|
|
284122
285051
|
router.patch("/api/chat-sessions/:id/discussion", wrap(async (req) => {
|
|
284123
285052
|
await human(req);
|
|
284124
285053
|
const { service, session } = await sessionAccess(req);
|
|
284125
|
-
const body2 =
|
|
285054
|
+
const body2 = edit2.parse(req.body);
|
|
284126
285055
|
return { status: 200, body: await service.editDiscussion(session.id, body2.revision, body2.content, req.auth.actor) };
|
|
284127
285056
|
}));
|
|
284128
285057
|
router.post("/api/chat-sessions/:id/discussion/retry", wrap(async (req) => {
|
|
@@ -284184,7 +285113,7 @@ function discussionsDomain(options) {
|
|
|
284184
285113
|
await human(req);
|
|
284185
285114
|
const service = await options.serviceFor(req.auth.companyId);
|
|
284186
285115
|
await service.project(req.params.id);
|
|
284187
|
-
const body2 =
|
|
285116
|
+
const body2 = edit2.extend({ relatedRevisions: external_exports.record(external_exports.number().int().positive()).optional() }).parse(req.body);
|
|
284188
285117
|
return { status: 200, body: await service.editDecision(req.params.id, req.params.decisionId, body2.revision, body2.content, req.auth.actor, body2.relatedRevisions) };
|
|
284189
285118
|
}));
|
|
284190
285119
|
router.get("/api/chat-sessions/:id/project-context", wrap(async (req) => {
|
|
@@ -284367,9 +285296,9 @@ function createDiscussionRuntime(options) {
|
|
|
284367
285296
|
}
|
|
284368
285297
|
|
|
284369
285298
|
// ../server/src/domains/discussions/store.ts
|
|
284370
|
-
var
|
|
284371
|
-
var
|
|
284372
|
-
var
|
|
285299
|
+
var import_node_crypto91 = require("node:crypto");
|
|
285300
|
+
var import_promises18 = require("node:fs/promises");
|
|
285301
|
+
var import_node_path30 = require("node:path");
|
|
284373
285302
|
var key = (kind, id) => JSON.stringify([kind, id]);
|
|
284374
285303
|
function contains(value2, match) {
|
|
284375
285304
|
if (match !== null && typeof match === "object" && !Array.isArray(match)) {
|
|
@@ -284390,7 +285319,7 @@ var MemoryDiscussionStore = class _MemoryDiscussionStore {
|
|
|
284390
285319
|
static async open(filename) {
|
|
284391
285320
|
const store = new _MemoryDiscussionStore(filename);
|
|
284392
285321
|
try {
|
|
284393
|
-
store.rows = JSON.parse(await (0,
|
|
285322
|
+
store.rows = JSON.parse(await (0, import_promises18.readFile)(filename, "utf8"));
|
|
284394
285323
|
} catch (error2) {
|
|
284395
285324
|
if (error2.code !== "ENOENT") throw error2;
|
|
284396
285325
|
}
|
|
@@ -284442,10 +285371,10 @@ var MemoryDiscussionStore = class _MemoryDiscussionStore {
|
|
|
284442
285371
|
const result = await run(tx);
|
|
284443
285372
|
if (changed) {
|
|
284444
285373
|
if (this.filename) {
|
|
284445
|
-
await (0,
|
|
284446
|
-
const temp = `${this.filename}.${(0,
|
|
284447
|
-
await (0,
|
|
284448
|
-
await (0,
|
|
285374
|
+
await (0, import_promises18.mkdir)((0, import_node_path30.dirname)(this.filename), { recursive: true });
|
|
285375
|
+
const temp = `${this.filename}.${(0, import_node_crypto91.randomUUID)()}.tmp`;
|
|
285376
|
+
await (0, import_promises18.writeFile)(temp, JSON.stringify(next), "utf8");
|
|
285377
|
+
await (0, import_promises18.rename)(temp, this.filename);
|
|
284449
285378
|
}
|
|
284450
285379
|
this.rows = next;
|
|
284451
285380
|
}
|
|
@@ -284536,6 +285465,225 @@ var PostgresDiscussionStore = class _PostgresDiscussionStore {
|
|
|
284536
285465
|
}
|
|
284537
285466
|
};
|
|
284538
285467
|
|
|
285468
|
+
// ../cli/src/todo-wiring.ts
|
|
285469
|
+
init_src();
|
|
285470
|
+
init_router();
|
|
285471
|
+
init_service10();
|
|
285472
|
+
init_routes11();
|
|
285473
|
+
init_reminders();
|
|
285474
|
+
init_flag();
|
|
285475
|
+
function createTodoRuntime(options) {
|
|
285476
|
+
const enabled = options.enabled ?? (() => personalTodoEnabledFromEnv());
|
|
285477
|
+
const cache = /* @__PURE__ */ new Map();
|
|
285478
|
+
const serviceFor = (companyId) => {
|
|
285479
|
+
const id = companyId ?? options.defaultCompanyId();
|
|
285480
|
+
let value2 = cache.get(id);
|
|
285481
|
+
if (!value2) {
|
|
285482
|
+
value2 = options.store(id).then((store) => new TodoService({ store, timeZone: () => options.timeZone(id) }));
|
|
285483
|
+
cache.set(id, value2);
|
|
285484
|
+
void value2.catch(() => cache.delete(id));
|
|
285485
|
+
}
|
|
285486
|
+
return value2;
|
|
285487
|
+
};
|
|
285488
|
+
const resolveCaller = async (actorId, companyId) => {
|
|
285489
|
+
if (isHumanActorId(actorId)) return { principal: actorId, actor: actorId };
|
|
285490
|
+
const human = await options.boundHuman(actorId, companyId ?? options.defaultCompanyId());
|
|
285491
|
+
if (!human) throw new ApiError(403, "TODO_NO_OWNER", "\u4E2A\u4EBA\u5F85\u529E\u53EA\u80FD\u7531\u771F\u4EBA\u6216\u771F\u4EBA\u7684\u52A9\u7406\u8BB0\uFF1A\u8FD9\u4E2A agent \u6CA1\u6709\u7ED1\u5B9A\u4EFB\u4F55\u771F\u4EBA\u3002");
|
|
285492
|
+
return { principal: human, hand: actorId, actor: actorId };
|
|
285493
|
+
};
|
|
285494
|
+
const register = todosDomain({ serviceFor, resolveCaller, enabled });
|
|
285495
|
+
const scanner = new TodoReminderScanner({
|
|
285496
|
+
companies: options.companies,
|
|
285497
|
+
todos: options.store,
|
|
285498
|
+
notifications: options.notifications,
|
|
285499
|
+
timeZone: options.timeZone,
|
|
285500
|
+
enabled,
|
|
285501
|
+
warn: options.warn,
|
|
285502
|
+
...options.onReminders ? { onInserted: options.onReminders } : {}
|
|
285503
|
+
});
|
|
285504
|
+
return {
|
|
285505
|
+
register,
|
|
285506
|
+
serviceFor,
|
|
285507
|
+
resolveCaller,
|
|
285508
|
+
scanner,
|
|
285509
|
+
start: () => scanner.start(),
|
|
285510
|
+
stop: () => scanner.stop()
|
|
285511
|
+
};
|
|
285512
|
+
}
|
|
285513
|
+
|
|
285514
|
+
// ../cli/src/serve.ts
|
|
285515
|
+
init_store3();
|
|
285516
|
+
|
|
285517
|
+
// ../storage/src/postgres-todos.ts
|
|
285518
|
+
init_pg_ident();
|
|
285519
|
+
init_schema_ddl_lock();
|
|
285520
|
+
var PostgresTodoStore = class _PostgresTodoStore {
|
|
285521
|
+
constructor(pool, schema) {
|
|
285522
|
+
this.pool = pool;
|
|
285523
|
+
this.s = quoteIdent2(schema);
|
|
285524
|
+
}
|
|
285525
|
+
s;
|
|
285526
|
+
static async open(pool, schema) {
|
|
285527
|
+
const store = new _PostgresTodoStore(pool, schema);
|
|
285528
|
+
await withSchemaDdlLock(pool, schema, async () => {
|
|
285529
|
+
await pool.query(`CREATE SCHEMA IF NOT EXISTS ${store.s}`);
|
|
285530
|
+
await pool.query(`CREATE TABLE IF NOT EXISTS ${store.s}.todos (
|
|
285531
|
+
id text PRIMARY KEY,
|
|
285532
|
+
title text NOT NULL,
|
|
285533
|
+
note text,
|
|
285534
|
+
creator_actor_id text NOT NULL,
|
|
285535
|
+
assignee_actor_id text NOT NULL,
|
|
285536
|
+
recorded_by_actor_id text NOT NULL,
|
|
285537
|
+
due_date text NOT NULL,
|
|
285538
|
+
due_time text,
|
|
285539
|
+
start_date text,
|
|
285540
|
+
start_time text,
|
|
285541
|
+
status text NOT NULL CHECK (status IN ('open','done','cancelled')),
|
|
285542
|
+
done_at timestamptz,
|
|
285543
|
+
cancelled_at timestamptz,
|
|
285544
|
+
source_chat_session_id text,
|
|
285545
|
+
linked_workorder_id text,
|
|
285546
|
+
created_at timestamptz NOT NULL,
|
|
285547
|
+
updated_at timestamptz NOT NULL
|
|
285548
|
+
)`);
|
|
285549
|
+
await pool.query(`CREATE INDEX IF NOT EXISTS todos_assignee_status_due_idx ON ${store.s}.todos (assignee_actor_id, status, due_date)`);
|
|
285550
|
+
await pool.query(`CREATE INDEX IF NOT EXISTS todos_creator_status_due_idx ON ${store.s}.todos (creator_actor_id, status, due_date)`);
|
|
285551
|
+
await pool.query(`CREATE INDEX IF NOT EXISTS todos_open_due_idx ON ${store.s}.todos (due_date) WHERE status = 'open'`);
|
|
285552
|
+
await pool.query(`CREATE INDEX IF NOT EXISTS todos_open_start_idx ON ${store.s}.todos (start_date) WHERE status = 'open' AND start_date IS NOT NULL`);
|
|
285553
|
+
await pool.query(`CREATE TABLE IF NOT EXISTS ${store.s}.todo_changes (
|
|
285554
|
+
id text PRIMARY KEY,
|
|
285555
|
+
todo_id text NOT NULL REFERENCES ${store.s}.todos(id) ON DELETE CASCADE,
|
|
285556
|
+
actor_id text NOT NULL,
|
|
285557
|
+
hand_actor_id text,
|
|
285558
|
+
at timestamptz NOT NULL,
|
|
285559
|
+
field text NOT NULL,
|
|
285560
|
+
old_value text,
|
|
285561
|
+
new_value text,
|
|
285562
|
+
reason text
|
|
285563
|
+
)`);
|
|
285564
|
+
await pool.query(`CREATE INDEX IF NOT EXISTS todo_changes_todo_at_idx ON ${store.s}.todo_changes (todo_id, at, id)`);
|
|
285565
|
+
});
|
|
285566
|
+
return store;
|
|
285567
|
+
}
|
|
285568
|
+
async tx(run) {
|
|
285569
|
+
const client = await this.pool.connect();
|
|
285570
|
+
try {
|
|
285571
|
+
await client.query("BEGIN");
|
|
285572
|
+
const result = await run(client);
|
|
285573
|
+
await client.query("COMMIT");
|
|
285574
|
+
return result;
|
|
285575
|
+
} catch (error2) {
|
|
285576
|
+
await client.query("ROLLBACK");
|
|
285577
|
+
throw error2;
|
|
285578
|
+
} finally {
|
|
285579
|
+
client.release();
|
|
285580
|
+
}
|
|
285581
|
+
}
|
|
285582
|
+
async insertChanges(client, changes) {
|
|
285583
|
+
for (const c of changes) {
|
|
285584
|
+
await client.query(
|
|
285585
|
+
`INSERT INTO ${this.s}.todo_changes (id,todo_id,actor_id,hand_actor_id,at,field,old_value,new_value,reason)
|
|
285586
|
+
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9)`,
|
|
285587
|
+
[c.id, c.todoId, c.actorId, c.handActorId ?? null, c.at, c.field, c.oldValue ?? null, c.newValue ?? null, c.reason ?? null]
|
|
285588
|
+
);
|
|
285589
|
+
}
|
|
285590
|
+
}
|
|
285591
|
+
async create(todo, changes) {
|
|
285592
|
+
return this.tx(async (client) => {
|
|
285593
|
+
const r = await client.query(`INSERT INTO ${this.s}.todos (id,title,note,creator_actor_id,assignee_actor_id,recorded_by_actor_id,
|
|
285594
|
+
due_date,due_time,status,done_at,cancelled_at,source_chat_session_id,linked_workorder_id,created_at,updated_at,start_date,start_time)
|
|
285595
|
+
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17) RETURNING *`, rowValues(todo));
|
|
285596
|
+
await this.insertChanges(client, changes);
|
|
285597
|
+
return fromRow3(r.rows[0]);
|
|
285598
|
+
});
|
|
285599
|
+
}
|
|
285600
|
+
async get(id) {
|
|
285601
|
+
const r = await this.pool.query(`SELECT * FROM ${this.s}.todos WHERE id=$1`, [id]);
|
|
285602
|
+
return r.rows[0] ? fromRow3(r.rows[0]) : null;
|
|
285603
|
+
}
|
|
285604
|
+
async update(next, expectedUpdatedAt, changes) {
|
|
285605
|
+
return this.tx(async (client) => {
|
|
285606
|
+
const r = await client.query(`UPDATE ${this.s}.todos SET title=$2,note=$3,creator_actor_id=$4,assignee_actor_id=$5,
|
|
285607
|
+
recorded_by_actor_id=$6,due_date=$7,due_time=$8,status=$9,done_at=$10,cancelled_at=$11,source_chat_session_id=$12,
|
|
285608
|
+
linked_workorder_id=$13,created_at=$14,updated_at=$15,start_date=$16,start_time=$17
|
|
285609
|
+
WHERE id=$1 AND updated_at=$18::timestamptz RETURNING *`, [...rowValues(next), expectedUpdatedAt]);
|
|
285610
|
+
if (!r.rows[0]) return null;
|
|
285611
|
+
await this.insertChanges(client, changes);
|
|
285612
|
+
return fromRow3(r.rows[0]);
|
|
285613
|
+
});
|
|
285614
|
+
}
|
|
285615
|
+
async listInvolving(actorId, statuses2) {
|
|
285616
|
+
const r = await this.pool.query(`SELECT * FROM ${this.s}.todos
|
|
285617
|
+
WHERE (creator_actor_id=$1 OR assignee_actor_id=$1) AND status = ANY($2::text[])
|
|
285618
|
+
ORDER BY due_date, COALESCE(due_time,'99:99'), created_at, id`, [actorId, [...statuses2]]);
|
|
285619
|
+
return r.rows.map(fromRow3);
|
|
285620
|
+
}
|
|
285621
|
+
async listOpenReminderCandidates(fromDay, toDay) {
|
|
285622
|
+
const r = await this.pool.query(`SELECT * FROM ${this.s}.todos
|
|
285623
|
+
WHERE status='open' AND (due_date BETWEEN $1 AND $2 OR start_date BETWEEN $1 AND $2)
|
|
285624
|
+
ORDER BY due_date, COALESCE(due_time,'99:99'), created_at, id`, [fromDay, toDay]);
|
|
285625
|
+
return r.rows.map(fromRow3);
|
|
285626
|
+
}
|
|
285627
|
+
async listChanges(todoId) {
|
|
285628
|
+
const r = await this.pool.query(`SELECT * FROM ${this.s}.todo_changes WHERE todo_id=$1 ORDER BY at, id`, [todoId]);
|
|
285629
|
+
return r.rows.map((row) => {
|
|
285630
|
+
const c = { id: row.id, todoId: row.todo_id, actorId: row.actor_id, at: iso8(row.at), field: row.field };
|
|
285631
|
+
if (row.hand_actor_id) c.handActorId = row.hand_actor_id;
|
|
285632
|
+
if (row.old_value !== null) c.oldValue = row.old_value;
|
|
285633
|
+
if (row.new_value !== null) c.newValue = row.new_value;
|
|
285634
|
+
if (row.reason !== null) c.reason = row.reason;
|
|
285635
|
+
return c;
|
|
285636
|
+
});
|
|
285637
|
+
}
|
|
285638
|
+
};
|
|
285639
|
+
var iso8 = (v2) => v2 instanceof Date ? v2.toISOString() : typeof v2 === "string" ? new Date(v2).toISOString() : void 0;
|
|
285640
|
+
function rowValues(t) {
|
|
285641
|
+
return [
|
|
285642
|
+
t.id,
|
|
285643
|
+
t.title,
|
|
285644
|
+
t.note ?? null,
|
|
285645
|
+
t.creatorActorId,
|
|
285646
|
+
t.assigneeActorId,
|
|
285647
|
+
t.recordedByActorId,
|
|
285648
|
+
t.dueDate,
|
|
285649
|
+
t.dueTime ?? null,
|
|
285650
|
+
t.status,
|
|
285651
|
+
t.doneAt ?? null,
|
|
285652
|
+
t.cancelledAt ?? null,
|
|
285653
|
+
t.sourceChatSessionId ?? null,
|
|
285654
|
+
t.linkedWorkorderId ?? null,
|
|
285655
|
+
t.createdAt,
|
|
285656
|
+
t.updatedAt,
|
|
285657
|
+
t.startDate ?? null,
|
|
285658
|
+
t.startTime ?? null
|
|
285659
|
+
];
|
|
285660
|
+
}
|
|
285661
|
+
function fromRow3(row) {
|
|
285662
|
+
const t = {
|
|
285663
|
+
id: row["id"],
|
|
285664
|
+
title: row["title"],
|
|
285665
|
+
creatorActorId: row["creator_actor_id"],
|
|
285666
|
+
assigneeActorId: row["assignee_actor_id"],
|
|
285667
|
+
recordedByActorId: row["recorded_by_actor_id"],
|
|
285668
|
+
dueDate: row["due_date"],
|
|
285669
|
+
status: row["status"],
|
|
285670
|
+
createdAt: iso8(row["created_at"]),
|
|
285671
|
+
updatedAt: iso8(row["updated_at"])
|
|
285672
|
+
};
|
|
285673
|
+
const opt = [
|
|
285674
|
+
["note", row["note"]],
|
|
285675
|
+
["dueTime", row["due_time"]],
|
|
285676
|
+
["startDate", row["start_date"]],
|
|
285677
|
+
["startTime", row["start_time"]],
|
|
285678
|
+
["doneAt", iso8(row["done_at"])],
|
|
285679
|
+
["cancelledAt", iso8(row["cancelled_at"])],
|
|
285680
|
+
["sourceChatSessionId", row["source_chat_session_id"]],
|
|
285681
|
+
["linkedWorkorderId", row["linked_workorder_id"]]
|
|
285682
|
+
];
|
|
285683
|
+
for (const [k2, v2] of opt) if (v2 !== void 0 && v2 !== null) t[k2] = v2;
|
|
285684
|
+
return t;
|
|
285685
|
+
}
|
|
285686
|
+
|
|
284539
285687
|
// ../cli/src/rebuild-artifact-projections-per-company.ts
|
|
284540
285688
|
init_src11();
|
|
284541
285689
|
var DEFAULT_LOGGER = {
|
|
@@ -284592,7 +285740,7 @@ init_src4();
|
|
|
284592
285740
|
init_chat_exit();
|
|
284593
285741
|
|
|
284594
285742
|
// ../cli/src/chat-task-header.ts
|
|
284595
|
-
var
|
|
285743
|
+
var import_node_crypto92 = require("node:crypto");
|
|
284596
285744
|
init_src11();
|
|
284597
285745
|
init_src();
|
|
284598
285746
|
var BRAINSTORM_LEGACY_LINE = "\u8BF7\u76F4\u63A5\u56DE\u7B54\u7528\u6237\u95EE\u9898\u3002\u9664\u975E\u7528\u6237\u660E\u786E\u8981\u6C42\u5199\u5165\u7CFB\u7EDF\uFF0C\u5426\u5219\u4E0D\u8981\u521B\u5EFA\u6216\u4FEE\u6539 artifact\u3002";
|
|
@@ -284653,7 +285801,7 @@ function buildChatTurnPrompts(input) {
|
|
|
284653
285801
|
};
|
|
284654
285802
|
}
|
|
284655
285803
|
function chatSystemPromptFingerprint(systemPrompt) {
|
|
284656
|
-
return (0,
|
|
285804
|
+
return (0, import_node_crypto92.createHash)("sha256").update(systemPrompt ?? "").digest("hex").slice(0, 16);
|
|
284657
285805
|
}
|
|
284658
285806
|
|
|
284659
285807
|
// ../cli/src/chat-task-md.ts
|
|
@@ -285507,7 +286655,7 @@ function oasisWrapperScript() {
|
|
|
285507
286655
|
const repoRoot = (0, import_node_url7.fileURLToPath)(new URL("../../../", __esm_import_meta_url));
|
|
285508
286656
|
const tsx = path29.join(repoRoot, "node_modules/.bin/tsx");
|
|
285509
286657
|
const main = path29.join(repoRoot, "packages/cli/src/main.ts");
|
|
285510
|
-
const key2 = (0,
|
|
286658
|
+
const key2 = (0, import_node_crypto93.createHash)("sha256").update(repoRoot).digest("hex").slice(0, 12);
|
|
285511
286659
|
const uid = typeof process.getuid === "function" ? process.getuid() : "na";
|
|
285512
286660
|
const stable = path29.join(os9.tmpdir(), `oasis-cli-wrapper-${uid}-${key2}`);
|
|
285513
286661
|
let dir;
|
|
@@ -285727,6 +286875,14 @@ function consoleLinksFromEnv(rawUrl, rawRoutes) {
|
|
|
285727
286875
|
}
|
|
285728
286876
|
async function startServe(opts) {
|
|
285729
286877
|
const serverStartedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
286878
|
+
let defaultTimeZone;
|
|
286879
|
+
try {
|
|
286880
|
+
defaultTimeZone = defaultTimeZoneFromEnv(process.env[DEFAULT_TIME_ZONE_ENV]);
|
|
286881
|
+
console.log(`[serve] \u90E8\u7F72\u9ED8\u8BA4\u65F6\u533A=${defaultTimeZone}\uFF08${DEFAULT_TIME_ZONE_ENV}\uFF1B\u7EC4\u7EC7\u6CA1\u914D\u65F6\u533A\u65F6\u4F7F\u7528\uFF09`);
|
|
286882
|
+
} catch (err) {
|
|
286883
|
+
console.error(`[serve] ${err.message}`);
|
|
286884
|
+
throw err;
|
|
286885
|
+
}
|
|
285730
286886
|
fs36.mkdirSync(opts.dir, { recursive: true });
|
|
285731
286887
|
const serverHeartbeatFile = path29.join(opts.dir, "serve-heartbeat.json");
|
|
285732
286888
|
let previousServerHeartbeatAt;
|
|
@@ -285919,7 +287075,7 @@ async function startServe(opts) {
|
|
|
285919
287075
|
if (!hub) return Promise.resolve({ ok: false, reason: "\u672C\u8FDB\u7A0B\u6CA1\u6709\u8282\u70B9\u7F51\u5173" });
|
|
285920
287076
|
const online = hub.connectedDaemons().some((d) => d.daemonId === nodeId);
|
|
285921
287077
|
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" });
|
|
285922
|
-
const requestId = (0,
|
|
287078
|
+
const requestId = (0, import_node_crypto93.randomUUID)();
|
|
285923
287079
|
const task = new Promise((resolve11) => {
|
|
285924
287080
|
const timer = setTimeout(() => {
|
|
285925
287081
|
modelRefreshWaiters.delete(requestId);
|
|
@@ -285993,6 +287149,8 @@ async function startServe(opts) {
|
|
|
285993
287149
|
// 租户闸(ADR-0164 §5):`POST /api/bindings` 据它拦「把本公司员工绑到别家公司的机器上」。
|
|
285994
287150
|
// 闭包读当前 nodeStore(下方 PG 分支会重赋值),与 `listBindingModelIds` 同一写法。
|
|
285995
287151
|
resolveNodeTenancy: async (nodeId) => nodeStore.getNode(nodeId),
|
|
287152
|
+
// 变量到期按组织的生效时区算日界(PRD v1.2 §7)。`companies` 在下方才建好——本箭头只在派单 / 请求时跑,那时已就绪。
|
|
287153
|
+
companyTimeZone: (companyId) => companies.service.effectiveTimeZoneOf(companyId),
|
|
285996
287154
|
store: registryStore,
|
|
285997
287155
|
oplog,
|
|
285998
287156
|
kernel: defaultCompanyKernel,
|
|
@@ -286766,7 +287924,7 @@ async function startServe(opts) {
|
|
|
286766
287924
|
const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
286767
287925
|
if (buf || session.runId) {
|
|
286768
287926
|
await turnStore.appendMessage({
|
|
286769
|
-
id: (0,
|
|
287927
|
+
id: (0, import_node_crypto93.randomUUID)(),
|
|
286770
287928
|
sessionId: chatSessionId,
|
|
286771
287929
|
role: "assistant",
|
|
286772
287930
|
content: buf,
|
|
@@ -286812,7 +287970,7 @@ async function startServe(opts) {
|
|
|
286812
287970
|
chatTargets: {
|
|
286813
287971
|
inspect: inspectChatTarget,
|
|
286814
287972
|
createTargetSession: async ({ companyId, agentId, ownerHumanActorId, title }) => {
|
|
286815
|
-
const sessionId = (0,
|
|
287973
|
+
const sessionId = (0, import_node_crypto93.randomUUID)();
|
|
286816
287974
|
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
286817
287975
|
const binding = await registryStore.getBinding(agentId).catch(() => null);
|
|
286818
287976
|
await (await chatStoreFor(companyId)).createSession({
|
|
@@ -286928,7 +288086,26 @@ async function startServe(opts) {
|
|
|
286928
288086
|
secret: jwtSecret ?? "oasis-dev-secret",
|
|
286929
288087
|
onAuthFailure: (reason) => console.warn(`[org-model] agent credential auth failure: ${reason}`)
|
|
286930
288088
|
});
|
|
286931
|
-
const companies = createCompaniesDomain({
|
|
288089
|
+
const companies = createCompaniesDomain({
|
|
288090
|
+
store: controlPlaneStore,
|
|
288091
|
+
blobs,
|
|
288092
|
+
sender: mailSender,
|
|
288093
|
+
consoleUrl,
|
|
288094
|
+
resolveActorsCtx: actors.resolveCtx,
|
|
288095
|
+
listInFlightAssignments,
|
|
288096
|
+
agentCredentials,
|
|
288097
|
+
defaultTimeZone,
|
|
288098
|
+
// 注销的邮箱验证门禁(设置页 PRD §4.3):票据由 auth 域签发与校验。auth 要拿 companies.service
|
|
288099
|
+
// 建号,只能建在后面——这里包一层闭包,请求时才解引用,不撞 TDZ。
|
|
288100
|
+
verifyAccountDeletionTicket: (accountId, ticket) => auth.verifyAccountDeletionTicket(accountId, ticket),
|
|
288101
|
+
// 改成员昵称时同步其懒创建助理的名字(设置页 PRD §3.1)。解析器在下方才装好、只在请求时调用;
|
|
288102
|
+
// 还没装好(启动期,没有请求)就当作没有绑定,只改真人档案。
|
|
288103
|
+
assistantOfHuman: async (companyId, humanActorId) => {
|
|
288104
|
+
const ctx = await resolveAssistantsCtxLazy(companyId);
|
|
288105
|
+
const bond = ctx ? await ctx.service.getByHuman(humanActorId) : null;
|
|
288106
|
+
return bond ? { agentActorId: bond.agentActorId, origin: bond.origin } : null;
|
|
288107
|
+
}
|
|
288108
|
+
});
|
|
286932
288109
|
const auth = createAuth({
|
|
286933
288110
|
store: controlPlaneStore,
|
|
286934
288111
|
sender: mailSender,
|
|
@@ -287954,7 +289131,7 @@ async function startServe(opts) {
|
|
|
287954
289131
|
onQuotaExhausted: (t) => {
|
|
287955
289132
|
const daemon = hub?.connectedDaemons().find((d) => d.daemonId === t.nodeId);
|
|
287956
289133
|
if (!daemon?.meta.supportsQuotaRefresh) return;
|
|
287957
|
-
hub?.dispatch(t.nodeId, { type: "refresh_quotas", requestId: (0,
|
|
289134
|
+
hub?.dispatch(t.nodeId, { type: "refresh_quotas", requestId: (0, import_node_crypto93.randomUUID)() });
|
|
287958
289135
|
},
|
|
287959
289136
|
actorName: async (actorId) => (await (await actors.resolveCtx(companyId)).service.getActor(actorId).catch(() => null))?.name ?? null
|
|
287960
289137
|
});
|
|
@@ -288069,6 +289246,30 @@ async function startServe(opts) {
|
|
|
288069
289246
|
isDelegationChild: async (sessionId, companyId) => Boolean(await (await delegationStoreFor(companyId)).getByChildSession(sessionId)),
|
|
288070
289247
|
warn: (error2) => console.warn(`[discussions] ${String(error2)}`)
|
|
288071
289248
|
});
|
|
289249
|
+
const todoStores = /* @__PURE__ */ new Map();
|
|
289250
|
+
const todoRuntime = createTodoRuntime({
|
|
289251
|
+
companies: async () => (await controlPlaneStore.listCompanies()).filter((c) => c.status === "active").map((c) => c.id),
|
|
289252
|
+
store: (companyId) => {
|
|
289253
|
+
let store = todoStores.get(companyId);
|
|
289254
|
+
if (!store) {
|
|
289255
|
+
store = pgPool ? PostgresTodoStore.open(pgPool, engineSchemaFor(companyId)) : MemoryTodoStore.open(path29.join(opts.dir, "companies", companyEngineDirName(companyId), "todos.json"));
|
|
289256
|
+
todoStores.set(companyId, store);
|
|
289257
|
+
void store.catch(() => todoStores.delete(companyId));
|
|
289258
|
+
}
|
|
289259
|
+
return store;
|
|
289260
|
+
},
|
|
289261
|
+
timeZone: (companyId) => companies.service.effectiveTimeZoneOf(companyId),
|
|
289262
|
+
boundHuman: async (agentId, companyId) => (await (await resolveAssistantsCtx(companyId)).service.getByAgent(agentId))?.humanActorId ?? null,
|
|
289263
|
+
notifications: (companyId) => notificationStoreFor(companyId),
|
|
289264
|
+
onReminders: (companyId, records) => {
|
|
289265
|
+
pushNotifier?.notify(companyId, records);
|
|
289266
|
+
const recipients = [...new Set(records.map((r) => r.recipient))];
|
|
289267
|
+
console.warn(`[todos] ${companyId} \u5230\u671F\u63D0\u9192 ${records.length} \u6761 \u2192 ${recipients.join(",")}`);
|
|
289268
|
+
auditSink.notifyNotificationsChanged(recipients);
|
|
289269
|
+
},
|
|
289270
|
+
defaultCompanyId: () => defaultCompanyId,
|
|
289271
|
+
warn: (error2) => console.warn(`[todos] ${String(error2)}`)
|
|
289272
|
+
});
|
|
288072
289273
|
let notificationLedgerWorker;
|
|
288073
289274
|
let pushNotifier;
|
|
288074
289275
|
let notificationLedgerTimer;
|
|
@@ -288279,7 +289480,7 @@ async function startServe(opts) {
|
|
|
288279
289480
|
}));
|
|
288280
289481
|
}
|
|
288281
289482
|
const limits = { wallClockMs: wallClockForKind("planner") };
|
|
288282
|
-
const artifactId = `artifact:planner:${(0,
|
|
289483
|
+
const artifactId = `artifact:planner:${(0, import_node_crypto93.randomUUID)()}`;
|
|
288283
289484
|
const handle = await chatRemoteAdapter.spawn({
|
|
288284
289485
|
actor: planner.id,
|
|
288285
289486
|
// companyId 同协调者:planner 用的就是默认公司的 actors 服务,漏签会让它一调公司域端点就 404。
|
|
@@ -288321,6 +289522,7 @@ async function startServe(opts) {
|
|
|
288321
289522
|
companies.register,
|
|
288322
289523
|
projectsDomain2.register,
|
|
288323
289524
|
discussionRuntime.register,
|
|
289525
|
+
todoRuntime.register,
|
|
288324
289526
|
typesDomain({
|
|
288325
289527
|
admin: typesAdmin,
|
|
288326
289528
|
resolveAdmin: async (companyId) => {
|
|
@@ -289201,10 +290403,10 @@ async function startServe(opts) {
|
|
|
289201
290403
|
if (isDeletedActor(dispatchTarget)) {
|
|
289202
290404
|
throw new ApiError(409, ACTOR_DELETED_ERROR_CODE, ACTOR_DELETED_CHAT_MESSAGE);
|
|
289203
290405
|
}
|
|
289204
|
-
const runtimeSessionId = sessionId ?? (requestDispatchId ? deterministicUuid(retargetClaimedDispatch ? `chat-runtime:${requestDispatchId}:retry:${(0,
|
|
290406
|
+
const runtimeSessionId = sessionId ?? (requestDispatchId ? deterministicUuid(retargetClaimedDispatch ? `chat-runtime:${requestDispatchId}:retry:${(0, import_node_crypto93.randomUUID)()}` : `chat-runtime:${requestDispatchId}`) : (0, import_node_crypto93.randomUUID)());
|
|
289205
290407
|
const resumeRuntimeSession = Boolean(sessionId);
|
|
289206
|
-
const traceRunId = requestDispatchId ? stableChatTraceRunId(requestDispatchId) : `chat-run:${(0,
|
|
289207
|
-
const artifactId = requestDispatchId ? `artifact:chat:${deterministicUuid(`chat-artifact:${requestDispatchId}`)}` : `artifact:chat:${(0,
|
|
290408
|
+
const traceRunId = requestDispatchId ? stableChatTraceRunId(requestDispatchId) : `chat-run:${(0, import_node_crypto93.randomUUID)()}`;
|
|
290409
|
+
const artifactId = requestDispatchId ? `artifact:chat:${deterministicUuid(`chat-artifact:${requestDispatchId}`)}` : `artifact:chat:${(0, import_node_crypto93.randomUUID)()}`;
|
|
289208
290410
|
let stableDispatch = requestDispatchId ? await resolveStableChatDispatch({ store: await traceStoreFor(runCompanyId), runId: traceRunId }) : null;
|
|
289209
290411
|
const retargetClaim = Boolean(retargetClaimedDispatch && stableDispatch && allocatedTurn);
|
|
289210
290412
|
if (stableDispatch && !stableDispatch.shouldDispatch && !retargetClaim) {
|
|
@@ -289961,6 +291163,7 @@ async function startServe(opts) {
|
|
|
289961
291163
|
notifications: auditSink.notifications
|
|
289962
291164
|
});
|
|
289963
291165
|
discussionRuntime.start();
|
|
291166
|
+
todoRuntime.start();
|
|
289964
291167
|
projectsDomain2.service.setProjectCreatedHandler(async (project) => {
|
|
289965
291168
|
if (!server.knowledgeGovernance) return;
|
|
289966
291169
|
await server.knowledgeGovernance.initializeProjectSpace({
|
|
@@ -290867,7 +292070,7 @@ async function startServe(opts) {
|
|
|
290867
292070
|
console.log(`[new-engine] dispatchWork ${workId} \u662F human work\u2014\u2014\u4E0D\u6D3E runtime\uFF0C\u7B49\u5F85\u4EBA\u5DE5\u5904\u7406`);
|
|
290868
292071
|
return;
|
|
290869
292072
|
}
|
|
290870
|
-
const ledgerId = opts2?.protocolRecovery?.dispatchId ?? `dispatch:${(0,
|
|
292073
|
+
const ledgerId = opts2?.protocolRecovery?.dispatchId ?? `dispatch:${(0, import_node_crypto93.randomUUID)()}`;
|
|
290871
292074
|
try {
|
|
290872
292075
|
const inserted = await (await dispatchLedgerFor(companyId)).insertOpen({
|
|
290873
292076
|
id: ledgerId,
|
|
@@ -290967,7 +292170,7 @@ async function startServe(opts) {
|
|
|
290967
292170
|
const kernelModel = newKernel.model;
|
|
290968
292171
|
const art = kernelModel.artifacts.get(nodeId);
|
|
290969
292172
|
const revWid = art?.workspace ?? "";
|
|
290970
|
-
const ledgerId = `dispatch:${(0,
|
|
292173
|
+
const ledgerId = `dispatch:${(0, import_node_crypto93.randomUUID)()}`;
|
|
290971
292174
|
try {
|
|
290972
292175
|
await (await dispatchLedgerFor(companyId)).insertOpen({
|
|
290973
292176
|
id: ledgerId,
|
|
@@ -291338,7 +292541,7 @@ async function startServe(opts) {
|
|
|
291338
292541
|
resolveSupplementalContext: server.knowledgeGovernance ? async ({ actorId, artifactId, workOrderId, action, part, runtimeKind, taskMarkdown }) => {
|
|
291339
292542
|
try {
|
|
291340
292543
|
const governance = server.knowledgeGovernance;
|
|
291341
|
-
const taskFingerprint = (0,
|
|
292544
|
+
const taskFingerprint = (0, import_node_crypto93.createHash)("sha256").update(JSON.stringify({ artifactId, workOrderId, action, part: part ?? null, taskMarkdown })).digest("hex");
|
|
291342
292545
|
const requestContext = {
|
|
291343
292546
|
organizationId: companyId,
|
|
291344
292547
|
actorId,
|
|
@@ -291811,8 +293014,8 @@ async function startServe(opts) {
|
|
|
291811
293014
|
const quotaStarvationMs = opts.sla?.quotaStarvationMs ?? 6 * 36e5;
|
|
291812
293015
|
const nodeIdleFallbackMs = opts.sla?.nodeIdleFallbackMs ?? opts.sla?.reviewStallMs ?? (Number(process.env["OASIS_SLA_NODE_IDLE_FALLBACK_MS"]) || 2 * 36e5);
|
|
291813
293016
|
console.log(`[sla] \u8282\u70B9\u9759\u6B62\u515C\u5E95\u9608\u503C nodeIdleFallbackMs=${nodeIdleFallbackMs}ms\uFF08${Math.round(nodeIdleFallbackMs / 6e4)} \u5206\u949F\uFF09`);
|
|
291814
|
-
const fmtSince = (
|
|
291815
|
-
const min2 = Math.floor(Math.max(0, now - Date.parse(
|
|
293017
|
+
const fmtSince = (iso9, now) => {
|
|
293018
|
+
const min2 = Math.floor(Math.max(0, now - Date.parse(iso9)) / 6e4);
|
|
291816
293019
|
if (!Number.isFinite(min2)) return "\u521A\u624D";
|
|
291817
293020
|
if (min2 < 1) return "\u4E0D\u5230 1 \u5206\u949F\u524D";
|
|
291818
293021
|
if (min2 < 60) return `${min2} \u5206\u949F\u524D`;
|
|
@@ -292815,6 +294018,7 @@ ${nodeFault}` : "");
|
|
|
292815
294018
|
})
|
|
292816
294019
|
]);
|
|
292817
294020
|
await discussionRuntime.stop();
|
|
294021
|
+
todoRuntime.stop();
|
|
292818
294022
|
for (const timer of dispatchTimers) clearInterval(timer);
|
|
292819
294023
|
clearInterval(slaTimer);
|
|
292820
294024
|
escalationDeliveryWorker.stop();
|
|
@@ -293841,9 +295045,9 @@ function readCodexQuota(binary, signal, timeoutMs = 15e3) {
|
|
|
293841
295045
|
|
|
293842
295046
|
// ../cli/src/daemon/quota/claude.ts
|
|
293843
295047
|
var import_node_child_process18 = require("node:child_process");
|
|
293844
|
-
var
|
|
295048
|
+
var import_promises19 = require("node:fs/promises");
|
|
293845
295049
|
var import_node_os12 = require("node:os");
|
|
293846
|
-
var
|
|
295050
|
+
var import_node_path31 = require("node:path");
|
|
293847
295051
|
var import_node_util5 = require("node:util");
|
|
293848
295052
|
var exec = (0, import_node_util5.promisify)(import_node_child_process18.execFile);
|
|
293849
295053
|
var USAGE_URL = "https://api.anthropic.com/api/oauth/usage";
|
|
@@ -293862,9 +295066,9 @@ async function credentials(env, signal) {
|
|
|
293862
295066
|
}
|
|
293863
295067
|
}
|
|
293864
295068
|
if (!raw) {
|
|
293865
|
-
const file = (0,
|
|
293866
|
-
if ((await (0,
|
|
293867
|
-
raw = await (0,
|
|
295069
|
+
const file = (0, import_node_path31.join)(env.CLAUDE_CONFIG_DIR || (0, import_node_path31.join)((0, import_node_os12.homedir)(), ".claude"), ".credentials.json");
|
|
295070
|
+
if ((await (0, import_promises19.stat)(file)).size > 256 * 1024) return void 0;
|
|
295071
|
+
raw = await (0, import_promises19.readFile)(file, { encoding: "utf8", ...signal ? { signal } : {} });
|
|
293868
295072
|
}
|
|
293869
295073
|
const oauth = object6(object6(JSON.parse(raw)).claudeAiOauth);
|
|
293870
295074
|
if (typeof oauth.expiresAt === "number" && oauth.expiresAt <= Date.now()) return void 0;
|
|
@@ -293933,18 +295137,18 @@ async function readClaudeQuota(binary, signal, deps = {}) {
|
|
|
293933
295137
|
}
|
|
293934
295138
|
|
|
293935
295139
|
// ../cli/src/daemon/quota/shared-cache.ts
|
|
293936
|
-
var
|
|
295140
|
+
var import_node_crypto94 = require("node:crypto");
|
|
293937
295141
|
var import_node_fs25 = require("node:fs");
|
|
293938
295142
|
var import_node_os13 = require("node:os");
|
|
293939
|
-
var
|
|
295143
|
+
var import_node_path32 = require("node:path");
|
|
293940
295144
|
init_src();
|
|
293941
295145
|
function profileOf(kind, env) {
|
|
293942
|
-
if (kind === "codex") return `codex:${env.CODEX_HOME || (0,
|
|
293943
|
-
if (env.CLAUDE_CODE_OAUTH_TOKEN) return `claude-token:${(0,
|
|
293944
|
-
return `claude:${env.CLAUDE_CONFIG_DIR || (0,
|
|
295146
|
+
if (kind === "codex") return `codex:${env.CODEX_HOME || (0, import_node_path32.join)((0, import_node_os13.homedir)(), ".codex")}`;
|
|
295147
|
+
if (env.CLAUDE_CODE_OAUTH_TOKEN) return `claude-token:${(0, import_node_crypto94.createHash)("sha256").update(env.CLAUDE_CODE_OAUTH_TOKEN).digest("hex")}`;
|
|
295148
|
+
return `claude:${env.CLAUDE_CONFIG_DIR || (0, import_node_path32.join)((0, import_node_os13.homedir)(), ".claude")}`;
|
|
293945
295149
|
}
|
|
293946
295150
|
function fileQuotaCache(dir, env = process.env) {
|
|
293947
|
-
const file = (kind) => (0,
|
|
295151
|
+
const file = (kind) => (0, import_node_path32.join)(dir, `${kind}-${(0, import_node_crypto94.createHash)("sha256").update(profileOf(kind, env)).digest("hex").slice(0, 16)}.json`);
|
|
293948
295152
|
return {
|
|
293949
295153
|
get(kind) {
|
|
293950
295154
|
try {
|
|
@@ -294126,7 +295330,7 @@ var RuntimeQuotaMonitor = class _RuntimeQuotaMonitor {
|
|
|
294126
295330
|
init_wrapper();
|
|
294127
295331
|
init_src();
|
|
294128
295332
|
var import_node_os14 = require("node:os");
|
|
294129
|
-
var
|
|
295333
|
+
var import_node_crypto95 = require("node:crypto");
|
|
294130
295334
|
init_src8();
|
|
294131
295335
|
init_src2();
|
|
294132
295336
|
|
|
@@ -294192,7 +295396,7 @@ function detectRuntimes() {
|
|
|
294192
295396
|
|
|
294193
295397
|
// ../cli/src/daemon/workdir-handler.ts
|
|
294194
295398
|
var import_node_fs26 = __toESM(require("node:fs"), 1);
|
|
294195
|
-
var
|
|
295399
|
+
var import_node_path33 = __toESM(require("node:path"), 1);
|
|
294196
295400
|
init_src2();
|
|
294197
295401
|
init_src();
|
|
294198
295402
|
var WORKDIR_READ_MAX_BYTES = 2 * 1024 * 1024;
|
|
@@ -294213,10 +295417,10 @@ function isSensitiveSegment(segment) {
|
|
|
294213
295417
|
}
|
|
294214
295418
|
function relPathIsSensitive(rel) {
|
|
294215
295419
|
if (!rel) return false;
|
|
294216
|
-
return rel.split(
|
|
295420
|
+
return rel.split(import_node_path33.default.sep).some((seg) => seg.length > 0 && isSensitiveSegment(seg));
|
|
294217
295421
|
}
|
|
294218
295422
|
function withinBase(p2, base) {
|
|
294219
|
-
return p2 === base || p2.startsWith(base +
|
|
295423
|
+
return p2 === base || p2.startsWith(base + import_node_path33.default.sep);
|
|
294220
295424
|
}
|
|
294221
295425
|
function normalizeRel(raw) {
|
|
294222
295426
|
const trimmed = (raw ?? "").trim();
|
|
@@ -294233,7 +295437,7 @@ async function trustedCanonicalContainer(req, logicalBase, dirKind) {
|
|
|
294233
295437
|
} catch {
|
|
294234
295438
|
return null;
|
|
294235
295439
|
}
|
|
294236
|
-
return isLegacy ?
|
|
295440
|
+
return isLegacy ? import_node_path33.default.join(trustedRootReal, "oasis-chat-sessions") : import_node_path33.default.join(trustedRootReal, "sessions", dirKind);
|
|
294237
295441
|
}
|
|
294238
295442
|
async function resolveWithinWorkdir(req) {
|
|
294239
295443
|
const dirKind = sessionDirKind(req.runtimeKind);
|
|
@@ -294251,11 +295455,11 @@ async function resolveWithinWorkdir(req) {
|
|
|
294251
295455
|
} catch {
|
|
294252
295456
|
return { ok: false, code: "NOT_FOUND" };
|
|
294253
295457
|
}
|
|
294254
|
-
if (
|
|
295458
|
+
if (import_node_path33.default.dirname(base) !== canonicalContainer) return { ok: false, code: "PATH_ESCAPE" };
|
|
294255
295459
|
const rel = normalizeRel(req.path);
|
|
294256
|
-
const requested =
|
|
295460
|
+
const requested = import_node_path33.default.resolve(base, rel);
|
|
294257
295461
|
if (!withinBase(requested, base)) return { ok: false, code: "PATH_ESCAPE" };
|
|
294258
|
-
const cleanRel = base === requested ? "" :
|
|
295462
|
+
const cleanRel = base === requested ? "" : import_node_path33.default.relative(base, requested);
|
|
294259
295463
|
if (relPathIsSensitive(cleanRel)) return { ok: false, code: "SENSITIVE" };
|
|
294260
295464
|
let real;
|
|
294261
295465
|
try {
|
|
@@ -294265,7 +295469,7 @@ async function resolveWithinWorkdir(req) {
|
|
|
294265
295469
|
return { ok: false, code: "PATH_ESCAPE" };
|
|
294266
295470
|
}
|
|
294267
295471
|
if (!withinBase(real, base)) return { ok: false, code: "PATH_ESCAPE" };
|
|
294268
|
-
const realRel = base === real ? "" :
|
|
295472
|
+
const realRel = base === real ? "" : import_node_path33.default.relative(base, real);
|
|
294269
295473
|
if (relPathIsSensitive(realRel)) return { ok: false, code: "SENSITIVE" };
|
|
294270
295474
|
return { ok: true, base, real };
|
|
294271
295475
|
}
|
|
@@ -294301,7 +295505,7 @@ async function handleWorkdirList(req) {
|
|
|
294301
295505
|
const slice = truncated ? visible.slice(0, WORKDIR_LIST_MAX_ENTRIES) : visible;
|
|
294302
295506
|
const entries = [];
|
|
294303
295507
|
for (const d of slice) {
|
|
294304
|
-
const abs =
|
|
295508
|
+
const abs = import_node_path33.default.join(anchor, d.name);
|
|
294305
295509
|
try {
|
|
294306
295510
|
const st = await import_node_fs26.default.promises.lstat(abs);
|
|
294307
295511
|
if (st.isSymbolicLink()) continue;
|
|
@@ -294368,7 +295572,7 @@ async function verifyOpenedFd(fh, base, fallback) {
|
|
|
294368
295572
|
const fdReal = await fdCanonicalPath(fh);
|
|
294369
295573
|
if (fdReal === null) return { anchor: fallback };
|
|
294370
295574
|
if (!withinBase(fdReal, base)) return { error: { ok: false, code: "PATH_ESCAPE" } };
|
|
294371
|
-
const fdRel = base === fdReal ? "" :
|
|
295575
|
+
const fdRel = base === fdReal ? "" : import_node_path33.default.relative(base, fdReal);
|
|
294372
295576
|
if (relPathIsSensitive(fdRel)) return { error: { ok: false, code: "SENSITIVE" } };
|
|
294373
295577
|
return { anchor: `/proc/self/fd/${fh.fd}` };
|
|
294374
295578
|
}
|
|
@@ -294462,7 +295666,7 @@ function looksBinary(bytes2) {
|
|
|
294462
295666
|
function contentTypeFor(absPath, bytes2) {
|
|
294463
295667
|
const sniffed = sniffContentType(bytes2);
|
|
294464
295668
|
if (sniffed) return sniffed;
|
|
294465
|
-
const ext =
|
|
295669
|
+
const ext = import_node_path33.default.extname(absPath).toLowerCase();
|
|
294466
295670
|
if (EXT_CONTENT_TYPE[ext]) return EXT_CONTENT_TYPE[ext];
|
|
294467
295671
|
return looksBinary(bytes2) ? "application/octet-stream" : "text/plain; charset=utf-8";
|
|
294468
295672
|
}
|
|
@@ -295045,7 +296249,7 @@ var DaemonWsClient = class {
|
|
|
295045
296249
|
*/
|
|
295046
296250
|
async queryArtifactStates(artifactIds, timeoutMs = 15e3) {
|
|
295047
296251
|
if (artifactIds.length === 0) return {};
|
|
295048
|
-
const requestId = (0,
|
|
296252
|
+
const requestId = (0, import_node_crypto95.randomUUID)();
|
|
295049
296253
|
return new Promise((resolve11, reject) => {
|
|
295050
296254
|
const timer = setTimeout(() => {
|
|
295051
296255
|
this.gcPending.delete(requestId);
|
|
@@ -295225,17 +296429,17 @@ var RuntimeRouterAdapter = class {
|
|
|
295225
296429
|
// ../cli/src/daemon/reap-claude-projects.ts
|
|
295226
296430
|
var import_node_fs27 = __toESM(require("node:fs"), 1);
|
|
295227
296431
|
var import_node_os15 = __toESM(require("node:os"), 1);
|
|
295228
|
-
var
|
|
296432
|
+
var import_node_path34 = __toESM(require("node:path"), 1);
|
|
295229
296433
|
function claudeProjectSlug(cwd) {
|
|
295230
296434
|
return cwd.replace(/[^a-zA-Z0-9]/g, "-");
|
|
295231
296435
|
}
|
|
295232
296436
|
function claudeProjectsRoot() {
|
|
295233
|
-
const configDir = process.env["CLAUDE_CONFIG_DIR"] ||
|
|
295234
|
-
return
|
|
296437
|
+
const configDir = process.env["CLAUDE_CONFIG_DIR"] || import_node_path34.default.join(import_node_os15.default.homedir(), ".claude");
|
|
296438
|
+
return import_node_path34.default.join(configDir, "projects");
|
|
295235
296439
|
}
|
|
295236
296440
|
function reapClaudeProjects(workdir, runtimeKind) {
|
|
295237
296441
|
if (runtimeKind !== "claude" && runtimeKind !== "claude-code") return;
|
|
295238
|
-
const dir =
|
|
296442
|
+
const dir = import_node_path34.default.join(claudeProjectsRoot(), claudeProjectSlug(workdir));
|
|
295239
296443
|
if (!import_node_fs27.default.existsSync(dir)) return;
|
|
295240
296444
|
try {
|
|
295241
296445
|
import_node_fs27.default.rmSync(dir, { recursive: true, force: true });
|
|
@@ -295244,7 +296448,7 @@ function reapClaudeProjects(workdir, runtimeKind) {
|
|
|
295244
296448
|
}
|
|
295245
296449
|
function measureClaudeProjects(workdir, runtimeKind) {
|
|
295246
296450
|
if (runtimeKind !== "claude" && runtimeKind !== "claude-code") return 0;
|
|
295247
|
-
const dir =
|
|
296451
|
+
const dir = import_node_path34.default.join(claudeProjectsRoot(), claudeProjectSlug(workdir));
|
|
295248
296452
|
return dirSizeBytes2(dir);
|
|
295249
296453
|
}
|
|
295250
296454
|
function dirSizeBytes2(dir) {
|
|
@@ -295256,7 +296460,7 @@ function dirSizeBytes2(dir) {
|
|
|
295256
296460
|
return 0;
|
|
295257
296461
|
}
|
|
295258
296462
|
for (const e of entries) {
|
|
295259
|
-
const p2 =
|
|
296463
|
+
const p2 = import_node_path34.default.join(dir, e.name);
|
|
295260
296464
|
if (e.isSymbolicLink()) continue;
|
|
295261
296465
|
if (e.isDirectory()) {
|
|
295262
296466
|
total += dirSizeBytes2(p2);
|
|
@@ -295273,7 +296477,7 @@ function dirSizeBytes2(dir) {
|
|
|
295273
296477
|
// ../cli/src/node.ts
|
|
295274
296478
|
init_src2();
|
|
295275
296479
|
var import_node_os16 = __toESM(require("node:os"), 1);
|
|
295276
|
-
var
|
|
296480
|
+
var import_node_path35 = __toESM(require("node:path"), 1);
|
|
295277
296481
|
var idleFor = (runtimeKind) => CODE_DEFAULT_POLICY.resolve({ executor: "agent", scenario: "runtime-idle", runtimeKind }).idleTimeoutMs ?? 0;
|
|
295278
296482
|
var RESILIENCE = {
|
|
295279
296483
|
codex: { idleTimeoutMs: idleFor("codex") }
|
|
@@ -295345,7 +296549,7 @@ async function startNode(opts) {
|
|
|
295345
296549
|
const client = new DaemonWsClient(opts.serverUrl, opts.nodeId, sessions, adapters, opts.token, runtimes, opts.nodeName, opts.reportRuntimes ?? false, true, opts.onUpdate, opts.daemonVersion, {
|
|
295346
296550
|
...opts.daemonPkg ? { daemonPkg: opts.daemonPkg } : {},
|
|
295347
296551
|
// 同一个 OS 用户下的所有实例(~/.oasis/instances/*)共用一份额度采集结果:同账号 5 分钟只问一次上游。
|
|
295348
|
-
quotaCacheDir:
|
|
296552
|
+
quotaCacheDir: import_node_path35.default.join(import_node_os16.default.homedir(), ".oasis", "quota-cache"),
|
|
295349
296553
|
// chat 文件浏览 handler 用它定位会话目录;production 不传 = 与 adapter 同款默认根(~/.oasis/work)。
|
|
295350
296554
|
...opts.workRoot !== void 0 ? { workRoot: opts.workRoot } : {},
|
|
295351
296555
|
...opts.spawnSessionProcess ? { spawnSessionProcess: opts.spawnSessionProcess } : {},
|
|
@@ -295464,7 +296668,7 @@ function forwardSignal(child, sig, killGroup = (pgid, signal) => {
|
|
|
295464
296668
|
// ../cli/src/daemon/machine-id.ts
|
|
295465
296669
|
var import_node_child_process20 = require("node:child_process");
|
|
295466
296670
|
var import_node_fs28 = require("node:fs");
|
|
295467
|
-
var
|
|
296671
|
+
var import_node_crypto96 = require("node:crypto");
|
|
295468
296672
|
var import_node_os17 = require("node:os");
|
|
295469
296673
|
function linuxMachineId() {
|
|
295470
296674
|
for (const p2 of ["/etc/machine-id", "/var/lib/dbus/machine-id"]) {
|
|
@@ -295530,7 +296734,7 @@ var defaultSources = {
|
|
|
295530
296734
|
function resolveNodeId(sources = {}) {
|
|
295531
296735
|
const s2 = { ...defaultSources, ...sources };
|
|
295532
296736
|
const material = `${s2.machineFingerprint()}:${s2.osUser()}`;
|
|
295533
|
-
const digest = (0,
|
|
296737
|
+
const digest = (0, import_node_crypto96.createHash)("sha256").update(material).digest("hex").slice(0, 12);
|
|
295534
296738
|
return `node-${digest}`;
|
|
295535
296739
|
}
|
|
295536
296740
|
|
|
@@ -297211,6 +298415,84 @@ var COMMAND_DECLS = {
|
|
|
297211
298415
|
],
|
|
297212
298416
|
examples: ["oasis var rm STALE_KEY --scope project --project oasis", "oasis var rm --id var_1234 --yes"]
|
|
297213
298417
|
},
|
|
298418
|
+
// —— 个人待办(ADR 0635):人对助理说「帮我记一下」→ 助理用这组命令记、改、勾掉。发起人 / 承接人由服务端按调用者
|
|
298419
|
+
// 填(agent 调 = 它绑定的那个真人),命令行不收。开关 OASIS_PERSONAL_TODO=off 时服务端 404。 ——
|
|
298420
|
+
todo: {
|
|
298421
|
+
group: "\u4E2A\u4EBA\u5F85\u529E",
|
|
298422
|
+
usage: "oasis todo <add|list|show|edit|done|cancel|reopen> ...",
|
|
298423
|
+
description: "\u4E2A\u4EBA\u5F85\u529E\uFF1A\u66FF\u4F60\u7ED1\u5B9A\u7684\u90A3\u4E2A\u771F\u4EBA\u8BB0\u4E0B\u6709\u622A\u6B62\u65E5\u7684\u4E8B\uFF0C\u5230\u671F\u524D\u4E00\u5929 09:00\u3001\u5F53\u5929 09:00 \u7CFB\u7EDF\u4F1A\u63D0\u9192 TA\uFF08\u8BBE\u4E86\u5F00\u59CB\u65E5\u7684\uFF0C\u5F00\u59CB\u5F53\u5929 09:00 \u4E5F\u63D0\u9192\u4E00\u6B21\uFF09\u3002\u6BCF\u6761\u8F93\u51FA\u7B2C\u4E00\u884C\u662F\u300C\u4ECA\u5929\uFF1AYYYY-MM-DD \u5468X\uFF08\u65F6\u533A\uFF09\u300D\u2014\u2014\u6362\u7B97\u300C\u8FD9\u5468\u4E94\u300D\u300C\u6708\u5E95\u300D\u4E00\u5F8B\u4EE5\u5B83\u4E3A\u51C6\u3002**\u6CA1\u6709 `oasis todo` \u547D\u4EE4\u6267\u884C\u6210\u529F\uFF0C\u5C31\u4E0D\u80FD\u8BF4\u8BB0\u4E0B\u4E86\u3002**",
|
|
298424
|
+
subCommands: ["todo add", "todo list", "todo show", "todo edit", "todo done", "todo cancel", "todo reopen"],
|
|
298425
|
+
examples: [
|
|
298426
|
+
'oasis todo add --title "\u4EA4 Q3 \u590D\u76D8\u62A5\u544A" --note "\u738B\u603B\u8981\uFF0C\u5468\u4F1A\u524D\u8FC7\u4E00\u904D" --due 2026-10-09',
|
|
298427
|
+
"oasis todo list",
|
|
298428
|
+
"oasis todo show td_3f9a1c2b",
|
|
298429
|
+
'oasis todo edit td_3f9a1c2b --due 2026-10-12 --reason "\u6392\u671F\u8C03\u6574"',
|
|
298430
|
+
"oasis todo done td_3f9a1c2b"
|
|
298431
|
+
]
|
|
298432
|
+
},
|
|
298433
|
+
"todo add": {
|
|
298434
|
+
group: "\u4E2A\u4EBA\u5F85\u529E",
|
|
298435
|
+
usage: "oasis todo add --title <\u4E00\u53E5\u8BDD\uFF0C\u52A8\u8BCD\u5F00\u5934> [--note <\u8C01\u8981\u3001\u4E3A\u4EC0\u4E48\u3001\u539F\u8BDD\u8981\u70B9>] [--start YYYY-MM-DD [--start-time HH:mm]] --due YYYY-MM-DD [--time HH:mm]",
|
|
298436
|
+
description: "\u8BB0\u4E00\u6761\u5F85\u529E\u3002--due / --start \u53EA\u6536\u4E0D\u5E26\u65F6\u533A\u7684\u65E5\u671F\uFF08\u7EC4\u7EC7\u65F6\u533A\u91CC\u7684\u90A3\u4E00\u5929\uFF09\uFF0C\u975E\u6CD5\u65E5\u671F\u5F53\u573A\u62A5\u9519\uFF1B\u6CA1\u8BF4\u51E0\u70B9\u5C31\u522B\u7ED9 --time\uFF1B\u7528\u6237\u6CA1\u8BF4\u4EC0\u4E48\u65F6\u5019\u5F00\u59CB\u5C31\u522B\u7ED9 --start\uFF08\u4E0D\u8FFD\u95EE\u3001\u4E0D\u731C\uFF09\uFF0C\u5F00\u59CB\u4E0D\u80FD\u665A\u4E8E\u622A\u6B62\u3002\u6765\u6E90\u5BF9\u8BDD\u81EA\u52A8\u53D6 $OASIS_CHAT_SESSION_ID\uFF08\u63D0\u9192\u70B9\u5F00\u4F1A\u8DF3\u56DE\u8FD9\u91CC\uFF09\u3002\u6210\u529F\u8F93\u51FA\u300C\u8BB0\u4E0B\u4E86\uFF1A<\u6807\u9898>\uFF0C\u622A\u6B62 X \u6708 X \u65E5\uFF08\u5468X\uFF09\u300D\u3002",
|
|
298437
|
+
flags: [
|
|
298438
|
+
{ name: "title", desc: "\u6807\u9898\uFF1A\u4E00\u53E5\u8BDD\u3001\u52A8\u8BCD\u5F00\u5934", required: true, own: true },
|
|
298439
|
+
{ name: "note", desc: "\u5907\u6CE8\uFF1A\u8C01\u8981\u3001\u4E3A\u4EC0\u4E48\u8981\u3001\u539F\u8BDD\u91CC\u7684\u5173\u952E\u4FE1\u606F", own: true },
|
|
298440
|
+
{ name: "due", desc: "\u622A\u6B62\u65E5 YYYY-MM-DD\uFF08\u4E0D\u5E26\u65F6\u533A\uFF09", required: true, own: true },
|
|
298441
|
+
{ name: "time", desc: "\u622A\u6B62\u65F6\u523B HH:mm\uFF0824 \u5C0F\u65F6\u5236\uFF1B\u6CA1\u8BF4\u5C31\u4E0D\u7ED9\uFF09", own: true },
|
|
298442
|
+
{ name: "start", desc: "\u5F00\u59CB\u65E5 YYYY-MM-DD\uFF08\u7528\u6237\u8BF4\u4E86\u300C\u54EA\u5929\u5F00\u59CB\u5F04\u300D\u624D\u7ED9\uFF09", own: true },
|
|
298443
|
+
{ name: "start-time", desc: "\u5F00\u59CB\u65F6\u523B HH:mm\uFF08\u914D --start\uFF09", own: true }
|
|
298444
|
+
],
|
|
298445
|
+
examples: ['oasis todo add --title "\u4EA4 Q3 \u590D\u76D8\u62A5\u544A" --due 2026-10-09 --time 18:00']
|
|
298446
|
+
},
|
|
298447
|
+
"todo list": {
|
|
298448
|
+
group: "\u4E2A\u4EBA\u5F85\u529E",
|
|
298449
|
+
usage: "oasis todo list [--all]",
|
|
298450
|
+
description: "\u5217\u51FA\u5F85\u529E\uFF0C\u6309\u622A\u6B62\u65E5\u6392\u5E8F\uFF0C\u8FC7\u671F\u7684\u6807\u300C\u5DF2\u8FC7\u671F\u300D\uFF1B\u8BBE\u4E86\u5F00\u59CB\u65E5\u7684\u663E\u793A\u300CX \u6708 X \u65E5\u5F00\u59CB \u2192 X \u6708 X \u65E5\u622A\u6B62\u300D\u3002\u9ED8\u8BA4\u53EA\u5217\u672A\u5B8C\u6210\u7684\uFF1B--all \u8FDE\u5DF2\u5B8C\u6210\u3001\u5DF2\u53D6\u6D88\u7684\u4E00\u8D77\u5217\u3002",
|
|
298451
|
+
flags: [{ name: "all", desc: "\u8FDE\u5DF2\u5B8C\u6210 / \u5DF2\u53D6\u6D88\u7684\u4E00\u8D77\u5217", boolean: true, own: true }]
|
|
298452
|
+
},
|
|
298453
|
+
"todo show": {
|
|
298454
|
+
group: "\u4E2A\u4EBA\u5F85\u529E",
|
|
298455
|
+
usage: "oasis todo show <id>",
|
|
298456
|
+
description: "\u770B\u4E00\u6761\u5F85\u529E\u7684\u5168\u8C8C\uFF1A\u6807\u9898\u3001\u5F00\u59CB \u2192 \u622A\u6B62\u3001\u72B6\u6001\u3001\u5907\u6CE8\u5168\u6587\uFF0C\u4EE5\u53CA\u53D8\u66F4\u8BB0\u5F55\uFF08\u65F6\u95F4\u3001\u8C01\u6539\u7684 / \u7ECF\u624B agent\u3001\u5B57\u6BB5\u3001\u65E7\u503C \u2192 \u65B0\u503C\u3001\u539F\u56E0\uFF0C\u65B0\u7684\u5728\u524D\uFF09\u3002\u6539\u5907\u6CE8\u524D\u5148\u7528\u5B83\u8BFB\u51FA\u5F53\u524D\u5907\u6CE8\u5168\u6587\uFF1B\u7528\u6237\u95EE\u300C\u4E4B\u524D\u5199\u7684\u662F\u4EC0\u4E48\u300D\u4E5F\u67E5\u8FD9\u91CC\u3002",
|
|
298457
|
+
positional: [{ name: "<id>", required: true, desc: "\u5F85\u529E id\uFF08oasis todo list \u7B2C\u4E00\u5217\uFF09" }],
|
|
298458
|
+
examples: ["oasis todo show td_3f9a1c2b"]
|
|
298459
|
+
},
|
|
298460
|
+
"todo edit": {
|
|
298461
|
+
group: "\u4E2A\u4EBA\u5F85\u529E",
|
|
298462
|
+
usage: "oasis todo edit <id> [--title \u2026] [--note \u2026] [--start YYYY-MM-DD|none] [--start-time HH:mm|none] [--due YYYY-MM-DD] [--time HH:mm|none] [--workorder <\u5DE5\u5355 id>|none] [--reason \u2026]",
|
|
298463
|
+
description: '\u6539\u4E00\u6761\u5F85\u529E\u7684\u5B57\u6BB5\uFF0C\u7ED9\u4E86\u54EA\u4E2A\u6539\u54EA\u4E2A\uFF1B\u6BCF\u6539\u4E00\u4E2A\u5B57\u6BB5\u90FD\u7559\u4E00\u6761\u8BB0\u5F55\uFF08\u65E7\u503C\u3001\u65B0\u503C\u3001\u539F\u56E0\uFF09\u3002\u6539\u671F\u8981\u5199\u539F\u56E0\uFF1A\u7528\u6237\u6CA1\u8BF4\u5C31\u95EE\u4E00\u53E5\uFF0C\u7528\u6237\u8BF4\u4E0D\u7528\u5C31\u4E0D\u5199\uFF0C\u522B\u7F16\u3002--start none\uFF08\u8FDE\u540C\u5F00\u59CB\u65F6\u523B\uFF09/ --start-time none / --time none / --workorder none \u6E05\u7A7A\uFF0C--note "" \u6E05\u7A7A\u5907\u6CE8\u3002',
|
|
298464
|
+
positional: [{ name: "<id>", required: true, desc: "\u5F85\u529E id\uFF08oasis todo list \u7B2C\u4E00\u5217\uFF09" }],
|
|
298465
|
+
flags: [
|
|
298466
|
+
{ name: "title", desc: "\u65B0\u6807\u9898", own: true },
|
|
298467
|
+
{ name: "note", desc: "\u65B0\u5907\u6CE8\uFF08\u7A7A\u4E32 = \u6E05\u7A7A\uFF09", own: true },
|
|
298468
|
+
{ name: "start", desc: "\u65B0\u5F00\u59CB\u65E5 YYYY-MM-DD\uFF1Bnone = \u6E05\u7A7A\uFF08\u8FDE\u540C\u5F00\u59CB\u65F6\u523B\uFF09", own: true },
|
|
298469
|
+
{ name: "start-time", desc: "\u65B0\u5F00\u59CB\u65F6\u523B HH:mm\uFF1Bnone = \u6E05\u7A7A", own: true },
|
|
298470
|
+
{ name: "due", desc: "\u65B0\u622A\u6B62\u65E5 YYYY-MM-DD", own: true },
|
|
298471
|
+
{ name: "time", desc: "\u65B0\u622A\u6B62\u65F6\u523B HH:mm\uFF1Bnone = \u6E05\u7A7A", own: true },
|
|
298472
|
+
{ name: "workorder", desc: "\u5173\u8054\u7684\u5DE5\u5355 id\uFF08\u300C\u8FD9\u4EF6\u4F60\u5E2E\u6211\u505A\u4E86\u5427\u300D\u5EFA\u5355\u540E\u6302\u4E0A\uFF09\uFF1Bnone = \u6E05\u7A7A", own: true },
|
|
298473
|
+
{ name: "reason", desc: "\u4E3A\u4EC0\u4E48\u6539\uFF08\u6539\u671F\u65F6\u8981\u5199\uFF1B\u7528\u6237\u8BF4\u4E0D\u7528\u5C31\u4E0D\u5199\uFF09", own: true }
|
|
298474
|
+
],
|
|
298475
|
+
examples: ['oasis todo edit td_3f9a1c2b --due 2026-10-12 --reason "\u5BA2\u6237\u5EF6\u671F\u4E00\u5468"']
|
|
298476
|
+
},
|
|
298477
|
+
"todo done": {
|
|
298478
|
+
group: "\u4E2A\u4EBA\u5F85\u529E",
|
|
298479
|
+
usage: "oasis todo done <id>",
|
|
298480
|
+
description: "\u6807\u8BB0\u5B8C\u6210\u3002\u5339\u914D\u5230\u591A\u6761\u65F6\u5148\u95EE\u7528\u6237\u662F\u54EA\u6761\uFF0C\u522B\u731C\u3002",
|
|
298481
|
+
positional: [{ name: "<id>", required: true, desc: "\u5F85\u529E id" }]
|
|
298482
|
+
},
|
|
298483
|
+
"todo cancel": {
|
|
298484
|
+
group: "\u4E2A\u4EBA\u5F85\u529E",
|
|
298485
|
+
usage: "oasis todo cancel <id> [--reason \u2026]",
|
|
298486
|
+
description: "\u53D6\u6D88\uFF08\u4E0D\u7528\u505A\u4E86\uFF09\u3002\u53EA\u6539\u72B6\u6001\u3001\u4E0D\u5220\u9664\uFF0C--all \u5217\u8868\u91CC\u8FD8\u770B\u5F97\u5230\u3002",
|
|
298487
|
+
positional: [{ name: "<id>", required: true, desc: "\u5F85\u529E id" }],
|
|
298488
|
+
flags: [{ name: "reason", desc: "\u4E3A\u4EC0\u4E48\u4E0D\u7528\u505A\u4E86", own: true }]
|
|
298489
|
+
},
|
|
298490
|
+
"todo reopen": {
|
|
298491
|
+
group: "\u4E2A\u4EBA\u5F85\u529E",
|
|
298492
|
+
usage: "oasis todo reopen <id>",
|
|
298493
|
+
description: "\u628A\u5DF2\u5B8C\u6210 / \u5DF2\u53D6\u6D88\u7684\u5F85\u529E\u91CD\u65B0\u6253\u5F00\u3002",
|
|
298494
|
+
positional: [{ name: "<id>", required: true, desc: "\u5F85\u529E id" }]
|
|
298495
|
+
},
|
|
297214
298496
|
// —— 技能:组织技能库的 CLI 面(Web 上是「管理 > 技能」那一页)。
|
|
297215
298497
|
// agent 把自己写好的一个技能目录沉淀进公司,并决定它对谁生效。 ——
|
|
297216
298498
|
skill: {
|
|
@@ -297300,21 +298582,21 @@ function formatCommandHelp(decl) {
|
|
|
297300
298582
|
const posNames = (decl.positional ?? []).map((p2) => p2.name);
|
|
297301
298583
|
const flagNames = (decl.flags ?? []).map((f2) => `--${f2.name}`);
|
|
297302
298584
|
const allNames = [...posNames, ...flagNames];
|
|
297303
|
-
const
|
|
298585
|
+
const pad3 = allNames.length > 0 ? Math.max(...allNames.map((n) => n.length)) + 2 : 0;
|
|
297304
298586
|
const reqPos = (decl.positional ?? []).filter((p2) => p2.required);
|
|
297305
298587
|
const reqFlags = (decl.flags ?? []).filter((f2) => f2.required);
|
|
297306
298588
|
if (reqPos.length > 0 || reqFlags.length > 0) {
|
|
297307
298589
|
lines.push("\u5FC5\u586B\uFF1A");
|
|
297308
|
-
for (const p2 of reqPos) lines.push(` ${p2.name.padEnd(
|
|
297309
|
-
for (const f2 of reqFlags) lines.push(` --${f2.name.padEnd(
|
|
298590
|
+
for (const p2 of reqPos) lines.push(` ${p2.name.padEnd(pad3)} ${p2.desc}`);
|
|
298591
|
+
for (const f2 of reqFlags) lines.push(` --${f2.name.padEnd(pad3 - 2)} ${f2.desc}`);
|
|
297310
298592
|
lines.push("");
|
|
297311
298593
|
}
|
|
297312
298594
|
const optPos = (decl.positional ?? []).filter((p2) => !p2.required);
|
|
297313
298595
|
const optFlags = (decl.flags ?? []).filter((f2) => !f2.required);
|
|
297314
298596
|
if (optPos.length > 0 || optFlags.length > 0) {
|
|
297315
298597
|
lines.push("\u53EF\u9009\uFF1A");
|
|
297316
|
-
for (const p2 of optPos) lines.push(` ${p2.name.padEnd(
|
|
297317
|
-
for (const f2 of optFlags) lines.push(` --${f2.name.padEnd(
|
|
298598
|
+
for (const p2 of optPos) lines.push(` ${p2.name.padEnd(pad3)} ${p2.desc}`);
|
|
298599
|
+
for (const f2 of optFlags) lines.push(` --${f2.name.padEnd(pad3 - 2)} ${f2.desc}`);
|
|
297318
298600
|
lines.push("");
|
|
297319
298601
|
}
|
|
297320
298602
|
lines.push(`\u8BF4\u660E\uFF1A${decl.description}`);
|
|
@@ -297341,6 +298623,7 @@ var GROUP_ORDER = [
|
|
|
297341
298623
|
"\u957F\u671F\u8BB0\u5FC6\uFF08ADR-0084/0102\uFF09",
|
|
297342
298624
|
"\u77E5\u8BC6\u5E93",
|
|
297343
298625
|
"\u59D4\u6D3E\u4E13\u5BB6",
|
|
298626
|
+
"\u4E2A\u4EBA\u5F85\u529E",
|
|
297344
298627
|
"\u751F\u547D\u5468\u671F",
|
|
297345
298628
|
"\u89D2\u8272 & \u4EBA\u5458",
|
|
297346
298629
|
"\u8BFB\u4EA7\u7269",
|
|
@@ -297405,13 +298688,13 @@ function ownFlagsFromDecl(command2) {
|
|
|
297405
298688
|
}
|
|
297406
298689
|
|
|
297407
298690
|
// ../cli/src/connector-effect-runner.ts
|
|
297408
|
-
var
|
|
298691
|
+
var import_node_crypto97 = require("node:crypto");
|
|
297409
298692
|
var import_node_child_process21 = require("node:child_process");
|
|
297410
298693
|
init_src8();
|
|
297411
298694
|
function stableKey(effect) {
|
|
297412
298695
|
const keyFields = Object.fromEntries(Object.entries(effect.keyFields).sort(([a], [b2]) => a.localeCompare(b2)));
|
|
297413
298696
|
const canonical2 = JSON.stringify({ kind: effect.kind, target: effect.target, keyFields });
|
|
297414
|
-
return `sha256:${(0,
|
|
298697
|
+
return `sha256:${(0, import_node_crypto97.createHash)("sha256").update(canonical2).digest("hex")}`;
|
|
297415
298698
|
}
|
|
297416
298699
|
async function runConnectorEffect(connector, toolArgs, deps) {
|
|
297417
298700
|
const effect = connector.describeExternalEffect?.(toolArgs) ?? null;
|
|
@@ -297630,8 +298913,8 @@ function formatSize(size) {
|
|
|
297630
298913
|
if (size < 1024 * 1024) return `${(size / 1024).toFixed(1)}KB`;
|
|
297631
298914
|
return `${(size / 1024 / 1024).toFixed(1)}MB`;
|
|
297632
298915
|
}
|
|
297633
|
-
function formatTime(
|
|
297634
|
-
return /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}/.test(
|
|
298916
|
+
function formatTime(iso9) {
|
|
298917
|
+
return /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}/.test(iso9) ? `${iso9.slice(5, 10)} ${iso9.slice(11, 16)}` : iso9;
|
|
297635
298918
|
}
|
|
297636
298919
|
function displayName2(name) {
|
|
297637
298920
|
const cut = name.lastIndexOf("/");
|
|
@@ -297980,7 +299263,7 @@ async function waitForCommandAuthorization(base, headers, draftId, fallback) {
|
|
|
297980
299263
|
const timeoutMs = resolveAuthWaitMs();
|
|
297981
299264
|
const controller = new AbortController();
|
|
297982
299265
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
297983
|
-
const waiterId = (0,
|
|
299266
|
+
const waiterId = (0, import_node_crypto98.randomUUID)();
|
|
297984
299267
|
process.stderr.write(
|
|
297985
299268
|
`\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
|
|
297986
299269
|
`
|
|
@@ -298064,7 +299347,7 @@ async function waitForCommandAuthorization(base, headers, draftId, fallback) {
|
|
|
298064
299347
|
}
|
|
298065
299348
|
}
|
|
298066
299349
|
}
|
|
298067
|
-
var CLI_VERSION = "2.2.
|
|
299350
|
+
var CLI_VERSION = "2.2.107" ? "2.2.107" : "dev";
|
|
298068
299351
|
function apiHeaders(token2, company) {
|
|
298069
299352
|
const headers = {
|
|
298070
299353
|
authorization: `Bearer ${token2}`,
|
|
@@ -298154,7 +299437,7 @@ function fieldsFromFlags(flags, ownFlags) {
|
|
|
298154
299437
|
}
|
|
298155
299438
|
return Object.keys(fields).length > 0 ? fields : void 0;
|
|
298156
299439
|
}
|
|
298157
|
-
function buildStageOp(cmd, flags, positional,
|
|
299440
|
+
function buildStageOp(cmd, flags, positional, readFile13 = (file) => fs44.readFileSync(file, "utf8")) {
|
|
298158
299441
|
switch (cmd) {
|
|
298159
299442
|
case "link":
|
|
298160
299443
|
return {
|
|
@@ -298176,7 +299459,7 @@ function buildStageOp(cmd, flags, positional, readFile12 = (file) => fs44.readFi
|
|
|
298176
299459
|
...flags.get("title") !== void 0 ? { title: flags.get("title") } : {},
|
|
298177
299460
|
...(flags.get("brief") ?? flags.get("description")) !== void 0 ? { description: flags.get("brief") ?? flags.get("description") } : {},
|
|
298178
299461
|
...flags.get("input") !== void 0 ? { inputs: flags.get("input").split(",").map((to) => ({ to: to.trim() })) } : {},
|
|
298179
|
-
...partsFile !== void 0 ? { parts: JSON.parse(
|
|
299462
|
+
...partsFile !== void 0 ? { parts: JSON.parse(readFile13(partsFile)) } : {},
|
|
298180
299463
|
...fields !== void 0 ? { fields } : {}
|
|
298181
299464
|
};
|
|
298182
299465
|
}
|
|
@@ -298430,7 +299713,7 @@ async function runCli(argv, println = console.log, progressln = console.error) {
|
|
|
298430
299713
|
const store = createNodeTokenStore(path39.join(dir, "node-tokens.json"));
|
|
298431
299714
|
const sub = positional[0];
|
|
298432
299715
|
if (sub === "issue") {
|
|
298433
|
-
const id = flags.get("id") ?? `node-${(0,
|
|
299716
|
+
const id = flags.get("id") ?? `node-${(0, import_node_crypto98.randomUUID)()}`;
|
|
298434
299717
|
const token3 = store.issue(id);
|
|
298435
299718
|
println(token3);
|
|
298436
299719
|
process.stderr.write(
|
|
@@ -299582,7 +300865,7 @@ ${t.ref} ${t.name} [\u5267\u672C=${t.playbookRef}]`);
|
|
|
299582
300865
|
if (!name) throw new Error("\u9879\u76EE\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A");
|
|
299583
300866
|
const goal = flags.get("goal")?.trim();
|
|
299584
300867
|
const slug5 = flags.get("slug");
|
|
299585
|
-
const id = slug5 !== void 0 ? projectSlug(slug5) : projectIdFromUuid((0,
|
|
300868
|
+
const id = slug5 !== void 0 ? projectSlug(slug5) : projectIdFromUuid((0, import_node_crypto98.randomUUID)());
|
|
299586
300869
|
const result = await api.request("POST", "/api/projects", {
|
|
299587
300870
|
...id ? { id } : {},
|
|
299588
300871
|
name,
|
|
@@ -300434,6 +301717,141 @@ ${res.warning}`);
|
|
|
300434
301717
|
oasis var rm <key> --scope \u2026 | oasis var rm --id <\u8BB0\u5F55 id> [--yes]
|
|
300435
301718
|
\u540E\u4E09\u4E2A\u662F\u7BA1\u7406\u9762\uFF0C\u4EC5\u9650\u4EBA\u7C7B operator token\u3002`);
|
|
300436
301719
|
}
|
|
301720
|
+
case "todo": {
|
|
301721
|
+
const sub = positional[0];
|
|
301722
|
+
const due = (t) => formatTodoSpan(t);
|
|
301723
|
+
const call = async (method, url, body2) => {
|
|
301724
|
+
try {
|
|
301725
|
+
return await api.request(method, url, body2);
|
|
301726
|
+
} catch (e) {
|
|
301727
|
+
if (e instanceof ApiRequestError && e.status === 404 && e.body?.error?.code === "NOT_FOUND") {
|
|
301728
|
+
throw new Error("\u4E2A\u4EBA\u5F85\u529E\u6CA1\u6709\u5F00\u542F\uFF08\u670D\u52A1\u7AEF OASIS_PERSONAL_TODO=off\uFF09\uFF0C\u8FD9\u6761\u6CA1\u6709\u8BB0\u4E0B\u3002");
|
|
301729
|
+
}
|
|
301730
|
+
throw e;
|
|
301731
|
+
}
|
|
301732
|
+
};
|
|
301733
|
+
const checkDay = (v2, flag) => {
|
|
301734
|
+
if (!isValidDay(v2)) throw new Error(`--${flag} \u53EA\u6536\u4E0D\u5E26\u65F6\u533A\u7684\u65E5\u671F YYYY-MM-DD\uFF08\u4F8B\uFF1A2026-10-09\uFF09\uFF0C\u6536\u5230\uFF1A${v2}`);
|
|
301735
|
+
return v2;
|
|
301736
|
+
};
|
|
301737
|
+
const checkTime = (v2, flag = "time") => {
|
|
301738
|
+
if (!isValidTodoTime(v2)) throw new Error(`--${flag} \u53EA\u6536 24 \u5C0F\u65F6\u5236 HH:mm\uFF08\u4F8B\uFF1A18:00\uFF09\uFF0C\u6536\u5230\uFF1A${v2}`);
|
|
301739
|
+
return v2;
|
|
301740
|
+
};
|
|
301741
|
+
const idOf = () => needPos(positional, 1, `oasis todo ${sub} <id>`);
|
|
301742
|
+
const todoPath = (id, tail = "") => `/api/todos/${encodeURIComponent(id)}${tail}`;
|
|
301743
|
+
if (sub === "add") {
|
|
301744
|
+
const title = need(flags, "title");
|
|
301745
|
+
const dueDate = checkDay(need(flags, "due"), "due");
|
|
301746
|
+
const time3 = flags.get("time");
|
|
301747
|
+
const note = flags.get("note");
|
|
301748
|
+
const start = flags.get("start");
|
|
301749
|
+
const startTime = flags.get("start-time");
|
|
301750
|
+
if (startTime !== void 0 && start === void 0) throw new Error("--start-time \u8981\u914D --start\uFF08\u5148\u8BF4\u54EA\u5929\u5F00\u59CB\uFF09");
|
|
301751
|
+
if (start !== void 0 && start > dueDate && isValidDay(start)) throw new Error(`--start ${start} \u665A\u4E8E --due ${dueDate}\uFF1A\u5F00\u59CB\u4E0D\u80FD\u665A\u4E8E\u622A\u6B62`);
|
|
301752
|
+
const sourceChatSessionId = process.env["OASIS_CHAT_SESSION_ID"];
|
|
301753
|
+
const r = await call("POST", "/api/todos", {
|
|
301754
|
+
title,
|
|
301755
|
+
dueDate,
|
|
301756
|
+
...time3 !== void 0 ? { dueTime: checkTime(time3) } : {},
|
|
301757
|
+
...start !== void 0 ? { startDate: checkDay(start, "start") } : {},
|
|
301758
|
+
...startTime !== void 0 ? { startTime: checkTime(startTime, "start-time") } : {},
|
|
301759
|
+
...note ? { note } : {},
|
|
301760
|
+
...sourceChatSessionId ? { sourceChatSessionId } : {}
|
|
301761
|
+
});
|
|
301762
|
+
println(r.todayLine);
|
|
301763
|
+
println(`\u8BB0\u4E0B\u4E86\uFF1A${r.todo.title}\uFF0C${due(r.todo)}`);
|
|
301764
|
+
println(`id\uFF1A${r.todo.id}`);
|
|
301765
|
+
break;
|
|
301766
|
+
}
|
|
301767
|
+
if (sub === "list") {
|
|
301768
|
+
const all2 = flags.get("all") === "true";
|
|
301769
|
+
const r = await call("GET", `/api/todos${all2 ? "?all=1" : ""}`);
|
|
301770
|
+
println(r.todayLine);
|
|
301771
|
+
if (r.items.length === 0) {
|
|
301772
|
+
println(all2 ? "\u6CA1\u6709\u5F85\u529E\u3002" : "\u6CA1\u6709\u672A\u5B8C\u6210\u7684\u5F85\u529E\u3002");
|
|
301773
|
+
break;
|
|
301774
|
+
}
|
|
301775
|
+
for (const t of r.items) {
|
|
301776
|
+
const tag = t.status === "done" ? " [\u5DF2\u5B8C\u6210]" : t.status === "cancelled" ? " [\u5DF2\u53D6\u6D88]" : t.dueDate < r.today.date ? " [\u5DF2\u8FC7\u671F]" : "";
|
|
301777
|
+
const when = t.startDate ? formatTodoSpan(t) : formatTodoDue(t.dueDate, t.dueTime);
|
|
301778
|
+
println(`${t.id} ${when} ${t.title}${tag}`);
|
|
301779
|
+
}
|
|
301780
|
+
break;
|
|
301781
|
+
}
|
|
301782
|
+
if (sub === "show") {
|
|
301783
|
+
const id = idOf();
|
|
301784
|
+
const [one2, day] = await Promise.all([
|
|
301785
|
+
call("GET", todoPath(id)),
|
|
301786
|
+
call("GET", "/api/todos")
|
|
301787
|
+
]);
|
|
301788
|
+
const t = one2.todo;
|
|
301789
|
+
const statusText = t.status === "done" ? "\u5DF2\u5B8C\u6210" : t.status === "cancelled" ? "\u5DF2\u53D6\u6D88" : t.dueDate < day.today.date ? "\u672A\u5B8C\u6210\uFF08\u5DF2\u8FC7\u671F\uFF09" : "\u672A\u5B8C\u6210";
|
|
301790
|
+
println(day.todayLine);
|
|
301791
|
+
println(`${t.id} ${t.title}`);
|
|
301792
|
+
println(`\u65F6\u95F4\uFF1A${due(t)}`);
|
|
301793
|
+
println(`\u72B6\u6001\uFF1A${statusText}`);
|
|
301794
|
+
if (t.linkedWorkorderId) println(`\u5DE5\u5355\uFF1A${t.linkedWorkorderId}`);
|
|
301795
|
+
println("\u5907\u6CE8\uFF1A");
|
|
301796
|
+
println(t.note ? t.note : "\uFF08\u65E0\uFF09");
|
|
301797
|
+
const FIELD = {
|
|
301798
|
+
created: "\u8BB0\u4E0B",
|
|
301799
|
+
status: "\u72B6\u6001",
|
|
301800
|
+
title: "\u6807\u9898",
|
|
301801
|
+
note: "\u5907\u6CE8",
|
|
301802
|
+
startDate: "\u5F00\u59CB\u65E5",
|
|
301803
|
+
startTime: "\u5F00\u59CB\u65F6\u523B",
|
|
301804
|
+
dueDate: "\u622A\u6B62\u65E5",
|
|
301805
|
+
dueTime: "\u622A\u6B62\u65F6\u523B",
|
|
301806
|
+
linkedWorkorderId: "\u5DE5\u5355"
|
|
301807
|
+
};
|
|
301808
|
+
const STATUS = { open: "\u672A\u5B8C\u6210", done: "\u5DF2\u5B8C\u6210", cancelled: "\u5DF2\u53D6\u6D88" };
|
|
301809
|
+
const val = (field, v2) => v2 === void 0 || v2 === "" ? "\uFF08\u7A7A\uFF09" : field === "status" ? STATUS[v2] ?? v2 : v2;
|
|
301810
|
+
const fmtAt = (iso9) => new Intl.DateTimeFormat("sv-SE", {
|
|
301811
|
+
timeZone: day.today.timeZone,
|
|
301812
|
+
year: "numeric",
|
|
301813
|
+
month: "2-digit",
|
|
301814
|
+
day: "2-digit",
|
|
301815
|
+
hour: "2-digit",
|
|
301816
|
+
minute: "2-digit",
|
|
301817
|
+
hour12: false
|
|
301818
|
+
}).format(new Date(iso9));
|
|
301819
|
+
const changes = [...one2.changes].sort((a, b2) => b2.at.localeCompare(a.at));
|
|
301820
|
+
println(`\u53D8\u66F4\u8BB0\u5F55\uFF08${changes.length} \u6761\uFF0C\u65B0\u7684\u5728\u524D\uFF09\uFF1A`);
|
|
301821
|
+
for (const c of changes) {
|
|
301822
|
+
const who = c.handActorId ? `${c.actorId}\uFF08\u7ECF\u624B ${c.handActorId}\uFF09` : c.actorId;
|
|
301823
|
+
const what = c.field === "created" ? `\u8BB0\u4E0B\uFF1A${c.newValue ?? ""}` : `${FIELD[c.field] ?? c.field}\uFF1A${val(c.field, c.oldValue)} \u2192 ${val(c.field, c.newValue)}`;
|
|
301824
|
+
println(`- ${fmtAt(c.at)} ${who} ${what}${c.reason ? ` \u539F\u56E0\uFF1A${c.reason}` : ""}`);
|
|
301825
|
+
}
|
|
301826
|
+
break;
|
|
301827
|
+
}
|
|
301828
|
+
if (sub === "edit") {
|
|
301829
|
+
const id = idOf();
|
|
301830
|
+
const body2 = {};
|
|
301831
|
+
if (flags.has("title")) body2["title"] = flags.get("title");
|
|
301832
|
+
if (flags.has("note")) body2["note"] = flags.get("note") === "" ? null : flags.get("note");
|
|
301833
|
+
if (flags.has("due")) body2["dueDate"] = checkDay(flags.get("due"), "due");
|
|
301834
|
+
if (flags.has("time")) body2["dueTime"] = flags.get("time") === "none" ? null : checkTime(flags.get("time"));
|
|
301835
|
+
if (flags.has("start")) body2["startDate"] = flags.get("start") === "none" ? null : checkDay(flags.get("start"), "start");
|
|
301836
|
+
if (flags.has("start-time")) body2["startTime"] = flags.get("start-time") === "none" ? null : checkTime(flags.get("start-time"), "start-time");
|
|
301837
|
+
if (flags.has("workorder")) body2["linkedWorkorderId"] = flags.get("workorder") === "none" ? null : flags.get("workorder");
|
|
301838
|
+
if (Object.keys(body2).length === 0) throw new Error("\u6CA1\u6709\u8981\u6539\u7684\u5B57\u6BB5\uFF1A\u7ED9 --title / --note / --start / --start-time / --due / --time / --workorder \u91CC\u7684\u81F3\u5C11\u4E00\u4E2A");
|
|
301839
|
+
if (flags.get("reason")) body2["reason"] = flags.get("reason");
|
|
301840
|
+
const r = await call("PATCH", todoPath(id), body2);
|
|
301841
|
+
println(r.todayLine);
|
|
301842
|
+
println(`\u5DF2\u6539\uFF1A${r.todo.title}\uFF0C${due(r.todo)}`);
|
|
301843
|
+
break;
|
|
301844
|
+
}
|
|
301845
|
+
if (sub === "done" || sub === "cancel" || sub === "reopen") {
|
|
301846
|
+
const id = idOf();
|
|
301847
|
+
const reason = sub === "cancel" ? flags.get("reason") : void 0;
|
|
301848
|
+
const r = await call("POST", todoPath(id, `/${sub}`), reason ? { reason } : {});
|
|
301849
|
+
println(r.todayLine);
|
|
301850
|
+
println(`${sub === "done" ? "\u5DF2\u5B8C\u6210" : sub === "cancel" ? "\u5DF2\u53D6\u6D88" : "\u5DF2\u91CD\u65B0\u6253\u5F00"}\uFF1A${r.todo.title}\uFF0C${due(r.todo)}`);
|
|
301851
|
+
break;
|
|
301852
|
+
}
|
|
301853
|
+
throw new Error("\u7528\u6CD5: oasis todo <add|list|show|edit|done|cancel|reopen> \u2026\uFF08oasis todo --help \u770B\u8BE6\u60C5\uFF09");
|
|
301854
|
+
}
|
|
300437
301855
|
case "skill": {
|
|
300438
301856
|
const sub = positional[0];
|
|
300439
301857
|
const asJson2 = flags.get("json") === "true";
|
|
@@ -301577,8 +302995,8 @@ var LOG_RETAIN_DAYS = 30;
|
|
|
301577
302995
|
var LOG_RETAIN_MAX_FILES = 10;
|
|
301578
302996
|
var ROTATED_SUFFIX = /^\d{8}-\d{6}(-\d+)?$/;
|
|
301579
302997
|
function stampOf(now) {
|
|
301580
|
-
const
|
|
301581
|
-
return `${
|
|
302998
|
+
const iso9 = now.toISOString();
|
|
302999
|
+
return `${iso9.slice(0, 10).replace(/-/g, "")}-${iso9.slice(11, 19).replace(/:/g, "")}`;
|
|
301582
303000
|
}
|
|
301583
303001
|
function rotateLogIfNeeded(file, opts = {}) {
|
|
301584
303002
|
const maxBytes = opts.maxBytes ?? LOG_ROTATE_MAX_BYTES;
|
|
@@ -301971,13 +303389,13 @@ async function exchangeEnrollToken(o) {
|
|
|
301971
303389
|
}
|
|
301972
303390
|
|
|
301973
303391
|
// src/install.ts
|
|
301974
|
-
var
|
|
303392
|
+
var import_node_crypto99 = require("node:crypto");
|
|
301975
303393
|
var fs50 = __toESM(require("node:fs"));
|
|
301976
303394
|
var path45 = __toESM(require("node:path"));
|
|
301977
303395
|
function versionLabel(sourceFile, pkgVersion, npmPrefixDir, pkgName = LEGACY_PKG_NAME) {
|
|
301978
303396
|
const tag = pkgName === LEGACY_PKG_NAME ? "" : `+pkg.${pkgName.replace(/[^A-Za-z0-9-]/g, "-")}`;
|
|
301979
303397
|
if (isFromNpmPrefix(sourceFile, npmPrefixDir)) return `${pkgVersion}${tag}`;
|
|
301980
|
-
const digest = (0,
|
|
303398
|
+
const digest = (0, import_node_crypto99.createHash)("sha256").update(fs50.readFileSync(sourceFile)).digest("hex").slice(0, 8);
|
|
301981
303399
|
return tag ? `${pkgVersion}${tag}.local.${digest}` : `${pkgVersion}+local.${digest}`;
|
|
301982
303400
|
}
|
|
301983
303401
|
function isFromNpmPrefix(sourceFile, npmPrefixDir) {
|
|
@@ -302100,7 +303518,7 @@ function shimScript() {
|
|
|
302100
303518
|
}
|
|
302101
303519
|
|
|
302102
303520
|
// src/index.ts
|
|
302103
|
-
var PKG_VERSION = true ? "2.2.
|
|
303521
|
+
var PKG_VERSION = true ? "2.2.107" : "dev";
|
|
302104
303522
|
var LOCAL_BIN = localBin();
|
|
302105
303523
|
var NPM_PREFIX = npmPrefix();
|
|
302106
303524
|
var INSTANCE = DEFAULT_INSTANCE;
|
|
@@ -302408,7 +303826,7 @@ function newInstanceName() {
|
|
|
302408
303826
|
const existing = new Set(listInstances());
|
|
302409
303827
|
if (!existing.has(DEFAULT_INSTANCE)) return DEFAULT_INSTANCE;
|
|
302410
303828
|
for (; ; ) {
|
|
302411
|
-
const n = `inst-${(0,
|
|
303829
|
+
const n = `inst-${(0, import_node_crypto100.randomBytes)(3).toString("hex")}`;
|
|
302412
303830
|
if (!existing.has(n)) return n;
|
|
302413
303831
|
}
|
|
302414
303832
|
}
|