oasis_test_v2 2.2.104 → 2.2.106
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 +1846 -392
- 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;
|
|
@@ -1118,12 +1124,12 @@ function sanitizeRuntimeQuotas(value2, now = Date.now()) {
|
|
|
1118
1124
|
}
|
|
1119
1125
|
return result;
|
|
1120
1126
|
}
|
|
1121
|
-
var
|
|
1127
|
+
var RUNTIME_QUOTA_REUSE_MS, RUNTIME_QUOTA_STALE_MS, RUNTIME_QUOTA_REFRESH_MIN_GAP_MS, statuses;
|
|
1122
1128
|
var init_runtime_quota = __esm({
|
|
1123
1129
|
"../contract/src/runtime-quota.ts"() {
|
|
1124
1130
|
"use strict";
|
|
1125
|
-
|
|
1126
|
-
RUNTIME_QUOTA_STALE_MS =
|
|
1131
|
+
RUNTIME_QUOTA_REUSE_MS = 10 * 6e4;
|
|
1132
|
+
RUNTIME_QUOTA_STALE_MS = 60 * 6e4;
|
|
1127
1133
|
RUNTIME_QUOTA_REFRESH_MIN_GAP_MS = 3e4;
|
|
1128
1134
|
statuses = /* @__PURE__ */ new Set(["ok", "unavailable", "unauthenticated", "unsupported", "error", "rate_limited"]);
|
|
1129
1135
|
}
|
|
@@ -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: createHash46 } = 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;
|
|
@@ -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) {
|
|
@@ -142037,6 +142176,21 @@ var init_store_postgres = __esm({
|
|
|
142037
142176
|
createdAt: iso(r.createdAt)
|
|
142038
142177
|
}));
|
|
142039
142178
|
}
|
|
142179
|
+
async listLiveNodeAssignees(workorderId) {
|
|
142180
|
+
const res = await this.pool.query(
|
|
142181
|
+
`SELECT n.assignee_actor_id AS "assigneeActorId",
|
|
142182
|
+
n.continuation_budget AS "continuationBudget"
|
|
142183
|
+
FROM ${quoteIdent(this.schema)}.workflow_nodes n
|
|
142184
|
+
JOIN ${quoteIdent(this.schema)}.workorders w ON w.id = n.workorder_id
|
|
142185
|
+
WHERE n.workorder_id = $1 AND w.lifecycle = 'active'
|
|
142186
|
+
AND n.cancelled_at IS NULL AND n.assignee_actor_id IS NOT NULL`,
|
|
142187
|
+
[workorderId]
|
|
142188
|
+
);
|
|
142189
|
+
return res.rows.map((r) => ({
|
|
142190
|
+
assigneeActorId: r.assigneeActorId,
|
|
142191
|
+
continuationBudget: r.continuationBudget ?? null
|
|
142192
|
+
}));
|
|
142193
|
+
}
|
|
142040
142194
|
/* ── intervention 草案卡(见 store.ts 的接口注释)。与上面两口钟同类:直连 pool 的窄读写,
|
|
142041
142195
|
标识符位一律经 quoteIdent——带连字符的公司 schema 裸拼会 syntax error。 ── */
|
|
142042
142196
|
async listInterventionDrafts() {
|
|
@@ -144386,7 +144540,7 @@ function emptySnapshotPlaceholder(record10) {
|
|
|
144386
144540
|
reviews: []
|
|
144387
144541
|
};
|
|
144388
144542
|
}
|
|
144389
|
-
var SYSTEM_ACTOR, NOOP_IO, SYSTEM_CLOCK, HandlerRegistry, DEFAULT_STUCK_APPLIED_RECOVERY_MS, SETTLE_FOREIGN_PROGRESS_FALLBACK_MS, EVENT_RETRY_DELAY_MS, EngineBus, ApplyFailure, sleep3;
|
|
144543
|
+
var SYSTEM_ACTOR, POLICY_MISSING, SCAN_POLICY_ATTEMPTS, NOOP_IO, SYSTEM_CLOCK, HandlerRegistry, DEFAULT_STUCK_APPLIED_RECOVERY_MS, SETTLE_FOREIGN_PROGRESS_FALLBACK_MS, EVENT_RETRY_DELAY_MS, EngineBus, ApplyFailure, sleep3;
|
|
144390
144544
|
var init_bus = __esm({
|
|
144391
144545
|
"../engine/src/bus.ts"() {
|
|
144392
144546
|
"use strict";
|
|
@@ -144400,6 +144554,8 @@ var init_bus = __esm({
|
|
|
144400
144554
|
init_protocol_recovery();
|
|
144401
144555
|
init_continuation();
|
|
144402
144556
|
SYSTEM_ACTOR = "actor:system:engine";
|
|
144557
|
+
POLICY_MISSING = Symbol("continuation-policy-missing");
|
|
144558
|
+
SCAN_POLICY_ATTEMPTS = 3;
|
|
144403
144559
|
NOOP_IO = {
|
|
144404
144560
|
async dispatchWork() {
|
|
144405
144561
|
},
|
|
@@ -145086,6 +145242,38 @@ var init_bus = __esm({
|
|
|
145086
145242
|
* ★ 只在调度器(run)内调用,其他代码不得调。
|
|
145087
145243
|
*/
|
|
145088
145244
|
async scan(workorderId) {
|
|
145245
|
+
for (let attempt = 1; ; attempt++) {
|
|
145246
|
+
const policies = await this.prefetchContinuationPolicies(workorderId);
|
|
145247
|
+
const result = await this.scanOnce(workorderId, policies);
|
|
145248
|
+
if (result !== POLICY_MISSING) return result;
|
|
145249
|
+
if (attempt >= SCAN_POLICY_ATTEMPTS) {
|
|
145250
|
+
console.warn(`[bus] scan ${workorderId}: \u8FDE\u7EED ${attempt} \u6B21\u9501\u5185\u51FA\u73B0\u672A\u9884\u8BFB\u8BBE\u7F6E\u7684\u8D1F\u8D23\u4EBA\uFF0C\u672C\u8F6E\u4E0D\u5224\u65AD`);
|
|
145251
|
+
return { emitted: 0, terminated: false };
|
|
145252
|
+
}
|
|
145253
|
+
}
|
|
145254
|
+
}
|
|
145255
|
+
/**
|
|
145256
|
+
* 事务外预读员工分批执行设置(v2 连接池耗尽,工单 fa17f92a)。
|
|
145257
|
+
*
|
|
145258
|
+
* 读设置要经 `io.continuationPolicy` 向**同一个池**借连接;放在 scan 持锁事务里读,事务那条连接
|
|
145259
|
+
* 一直空等,多家公司同时全扫就全卡在「拿着一条、等第二条」上,直到借连接超时,网页请求一起 503。
|
|
145260
|
+
* 所以先不持任何连接读完、放回池子,再进事务。设置的时效与原来相同——原来那次读本就走另一条
|
|
145261
|
+
* 连接、不在事务快照里。
|
|
145262
|
+
*
|
|
145263
|
+
* 预读范围是锁内跳过条件的超集:额度已冻结(待审/已拒)的节点锁内也不读,这里同样跳过;
|
|
145264
|
+
* 额度是否用完要看 works,窄读拿不到,统统预读。锁内判断仍以锁内读到的状态为准。
|
|
145265
|
+
*/
|
|
145266
|
+
async prefetchContinuationPolicies(workorderId) {
|
|
145267
|
+
const policies = /* @__PURE__ */ new Map();
|
|
145268
|
+
if (!this.io.continuationPolicy) return policies;
|
|
145269
|
+
for (const node2 of await this.store.listLiveNodeAssignees(workorderId)) {
|
|
145270
|
+
const decision = node2.continuationBudget?.request?.decision;
|
|
145271
|
+
if (decision === "pending" || decision === "denied" || policies.has(node2.assigneeActorId)) continue;
|
|
145272
|
+
policies.set(node2.assigneeActorId, await this.io.continuationPolicy(node2.assigneeActorId));
|
|
145273
|
+
}
|
|
145274
|
+
return policies;
|
|
145275
|
+
}
|
|
145276
|
+
async scanOnce(workorderId, prefetched) {
|
|
145089
145277
|
let wrote = false;
|
|
145090
145278
|
let settledAt = null;
|
|
145091
145279
|
const result = await this.store.transaction(async (tx) => {
|
|
@@ -145102,7 +145290,11 @@ var init_bus = __esm({
|
|
|
145102
145290
|
const budget = node2.continuationBudget;
|
|
145103
145291
|
if (budget && (!continuationExhausted(state, node2) || budget.request?.decision === "pending" || budget.request?.decision === "denied")) continue;
|
|
145104
145292
|
if (node2.assigneeActorId && !continuationPolicies.has(node2.assigneeActorId)) {
|
|
145105
|
-
|
|
145293
|
+
if (!prefetched.has(node2.assigneeActorId)) {
|
|
145294
|
+
settledAt = null;
|
|
145295
|
+
return POLICY_MISSING;
|
|
145296
|
+
}
|
|
145297
|
+
const policy = prefetched.get(node2.assigneeActorId) ?? null;
|
|
145106
145298
|
if (policy && (!Number.isSafeInteger(policy.maxRounds) || policy.maxRounds < 1 || policy.maxRounds > 100)) {
|
|
145107
145299
|
throw new Error(`invalid continuation round limit for ${node2.assigneeActorId}`);
|
|
145108
145300
|
}
|
|
@@ -145131,6 +145323,7 @@ var init_bus = __esm({
|
|
|
145131
145323
|
wrote = state.mutations.length > 0 || allEvents.length > 0;
|
|
145132
145324
|
return { emitted: allEvents.length, terminated };
|
|
145133
145325
|
});
|
|
145326
|
+
if (result === POLICY_MISSING) return result;
|
|
145134
145327
|
if (settledAt !== null) {
|
|
145135
145328
|
const prev = this.scanProgress.get(workorderId);
|
|
145136
145329
|
this.scanProgress.set(workorderId, {
|
|
@@ -153343,14 +153536,14 @@ var init_kernel_bridge = __esm({
|
|
|
153343
153536
|
fresh.add(id);
|
|
153344
153537
|
}
|
|
153345
153538
|
}
|
|
153346
|
-
const
|
|
153539
|
+
const clean3 = this.resyncRequested ? ids2.filter((id) => !fresh.has(id)) : [];
|
|
153347
153540
|
this.resyncRequested = false;
|
|
153348
|
-
if (
|
|
153349
|
-
const slice = Math.min(_EngineKernel.REFRESH_RESYNC_SLICE,
|
|
153541
|
+
if (clean3.length > 0) {
|
|
153542
|
+
const slice = Math.min(_EngineKernel.REFRESH_RESYNC_SLICE, clean3.length);
|
|
153350
153543
|
for (let i = 0; i < slice; i++) {
|
|
153351
|
-
toLoad.push(
|
|
153544
|
+
toLoad.push(clean3[(this.resyncCursor + i) % clean3.length]);
|
|
153352
153545
|
}
|
|
153353
|
-
this.resyncCursor = (this.resyncCursor + slice) %
|
|
153546
|
+
this.resyncCursor = (this.resyncCursor + slice) % clean3.length;
|
|
153354
153547
|
}
|
|
153355
153548
|
const claimed = toLoad.filter((id) => this.dirtyWorkorders.delete(id));
|
|
153356
153549
|
let loaded;
|
|
@@ -175481,7 +175674,11 @@ var init_assistants = __esm({
|
|
|
175481
175674
|
return p2?.autoAssignAssistant !== false;
|
|
175482
175675
|
}
|
|
175483
175676
|
/* ---------- 懒创建(原子 + 幂等 + 探针 + opt-out) ---------- */
|
|
175484
|
-
|
|
175677
|
+
/**
|
|
175678
|
+
* @param preferred 调用方(入职向导「我的助理」)指定的那台运行时。只是**偏好**:在本公司在线运行时里
|
|
175679
|
+
* 找得到就用它建,找不到(下线了 / 不是本公司的 / 乱填)就当没给,照常按负载挑——见 {@link pickAssistantRuntime}。
|
|
175680
|
+
*/
|
|
175681
|
+
async ensureFor(humanId, by = humanId, preferred) {
|
|
175485
175682
|
const pre = await this.opts.bindStore.getByHuman(humanId);
|
|
175486
175683
|
if (pre) return { agentId: pre.agentActorId, created: false, source: "existing" };
|
|
175487
175684
|
if (!await this.isAutoAssignOn(humanId)) {
|
|
@@ -175509,7 +175706,7 @@ var init_assistants = __esm({
|
|
|
175509
175706
|
return { agentId: restored.agentActorId, created: false, source: "existing" };
|
|
175510
175707
|
}
|
|
175511
175708
|
}
|
|
175512
|
-
const agentId = await this._createLocked(humanId, by, "lazy-create");
|
|
175709
|
+
const agentId = await this._createLocked(humanId, by, "lazy-create", preferred);
|
|
175513
175710
|
return { agentId, created: true, source: "lazy-created" };
|
|
175514
175711
|
});
|
|
175515
175712
|
}
|
|
@@ -175763,11 +175960,11 @@ var init_assistants = __esm({
|
|
|
175763
175960
|
}
|
|
175764
175961
|
}
|
|
175765
175962
|
/* ---------- 私有:创建流水线(不加锁;调用方须已持 withHumanLock) ---------- */
|
|
175766
|
-
async _createLocked(humanId, by, origin) {
|
|
175963
|
+
async _createLocked(humanId, by, origin, preferred) {
|
|
175767
175964
|
const human = await this.opts.registry.getActor(humanId);
|
|
175768
175965
|
if (!human) throw new AssistantLazyCreateError("human-not-found");
|
|
175769
175966
|
if (human.kind !== "human" || human.status !== "active") throw new AssistantLazyCreateError("human-inactive");
|
|
175770
|
-
const runtime = await this.pickAssistantRuntime();
|
|
175967
|
+
const runtime = await this.pickAssistantRuntime(preferred);
|
|
175771
175968
|
if (!runtime) throw new AssistantLazyCreateError("no-runtime");
|
|
175772
175969
|
const agentId = `actor:agent:asst-${slug4(human.name)}-${short6()}`;
|
|
175773
175970
|
await this.opts.actors.upsertActor({ id: agentId, kind: "agent", name: `${human.name}\u7684\u52A9\u7406`, status: "active", roles: ["assistant"] }, by);
|
|
@@ -175806,7 +176003,18 @@ var init_assistants = __esm({
|
|
|
175806
176003
|
return companyId ? { companyId } : void 0;
|
|
175807
176004
|
}
|
|
175808
176005
|
/* ---------- runtime 挑选(ADR §3.3.a):负载均衡 + 幂等 tie-break ---------- */
|
|
175809
|
-
|
|
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) {
|
|
175810
176018
|
const runtimes = (await this.opts.listRuntimes(void 0, this.scope())).filter((r) => r.status === "online");
|
|
175811
176019
|
if (runtimes.length === 0) return null;
|
|
175812
176020
|
let defaultKind = DEFAULT_ASSISTANT_RUNTIME_KIND;
|
|
@@ -175817,8 +176025,12 @@ var init_assistants = __esm({
|
|
|
175817
176025
|
break;
|
|
175818
176026
|
}
|
|
175819
176027
|
}
|
|
175820
|
-
|
|
175821
|
-
|
|
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;
|
|
175822
176034
|
const bindings = (await this.opts.registry.listBindings()).filter((b2) => b2.status === "active");
|
|
175823
176035
|
const load = (r) => bindings.filter((b2) => b2.nodeId === r.nodeId && b2.runtimeKind === r.kind).length;
|
|
175824
176036
|
return candidates.slice().sort((a, b2) => {
|
|
@@ -177262,7 +177474,7 @@ function buildWorkorderDraftDetail(draft, resolveActor, spawnReviewers, resolveR
|
|
|
177262
177474
|
const hasDeliverySummary = spawns.some((op) => op.type === DELIVERY_SUMMARY_ARTIFACT_TYPE);
|
|
177263
177475
|
const nodes = spawns.map((op) => {
|
|
177264
177476
|
const rows = spawnReviewers ? draft.plan.ops.filter((o) => o.action === "edit" && o.artifactId === op.id && o.reviewers !== void 0).reduce(
|
|
177265
|
-
(current,
|
|
177477
|
+
(current, edit3) => applyReviewerList({ current, next: edit3.reviewers }),
|
|
177266
177478
|
[...spawnReviewers(op.type, op.reviewers ?? [], { reviewersFinal: op.reviewersFinal === true })]
|
|
177267
177479
|
) : [];
|
|
177268
177480
|
const pv = rows.length > 0 ? reviewerPreviewOfRows(rows.map((r) => ({ actor: r.reviewerActorId, source: r.source, reviewGroup: r.reviewGroup }))) : null;
|
|
@@ -188359,16 +188571,16 @@ function parse2(options) {
|
|
|
188359
188571
|
);
|
|
188360
188572
|
const parser = {
|
|
188361
188573
|
constructs: constructs2,
|
|
188362
|
-
content:
|
|
188574
|
+
content: create2(content),
|
|
188363
188575
|
defined: [],
|
|
188364
|
-
document:
|
|
188365
|
-
flow:
|
|
188576
|
+
document: create2(document2),
|
|
188577
|
+
flow: create2(flow),
|
|
188366
188578
|
lazy: {},
|
|
188367
|
-
string:
|
|
188368
|
-
text:
|
|
188579
|
+
string: create2(string3),
|
|
188580
|
+
text: create2(text)
|
|
188369
188581
|
};
|
|
188370
188582
|
return parser;
|
|
188371
|
-
function
|
|
188583
|
+
function create2(initial) {
|
|
188372
188584
|
return creator;
|
|
188373
188585
|
function creator(from) {
|
|
188374
188586
|
return createTokenizer(parser, initial, from);
|
|
@@ -188812,10 +189024,10 @@ function compiler(options) {
|
|
|
188812
189024
|
events[start][1]._spread = listSpread;
|
|
188813
189025
|
return length;
|
|
188814
189026
|
}
|
|
188815
|
-
function opener(
|
|
189027
|
+
function opener(create2, and) {
|
|
188816
189028
|
return open3;
|
|
188817
189029
|
function open3(token2) {
|
|
188818
|
-
enter.call(this,
|
|
189030
|
+
enter.call(this, create2(token2), token2);
|
|
188819
189031
|
if (and) and.call(this, token2);
|
|
188820
189032
|
}
|
|
188821
189033
|
}
|
|
@@ -212906,10 +213118,10 @@ async function startOasisServer(opts) {
|
|
|
212906
213118
|
...fp(p2)
|
|
212907
213119
|
}))
|
|
212908
213120
|
] : [];
|
|
212909
|
-
const { randomUUID:
|
|
213121
|
+
const { randomUUID: randomUUID50 } = await import("node:crypto");
|
|
212910
213122
|
try {
|
|
212911
213123
|
await store.enqueuePendingMessage({
|
|
212912
|
-
id:
|
|
213124
|
+
id: randomUUID50(),
|
|
212913
213125
|
chatSessionId: input.chatSessionId,
|
|
212914
213126
|
text: input.text,
|
|
212915
213127
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -212942,11 +213154,11 @@ async function startOasisServer(opts) {
|
|
|
212942
213154
|
...f2?.mtime ? { srcMtime: f2.mtime } : {}
|
|
212943
213155
|
};
|
|
212944
213156
|
});
|
|
212945
|
-
const { randomUUID:
|
|
213157
|
+
const { randomUUID: randomUUID50 } = await import("node:crypto");
|
|
212946
213158
|
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
212947
213159
|
try {
|
|
212948
213160
|
await store.enqueuePendingMessage({
|
|
212949
|
-
id:
|
|
213161
|
+
id: randomUUID50(),
|
|
212950
213162
|
chatSessionId: input.chatSessionId,
|
|
212951
213163
|
text: "",
|
|
212952
213164
|
createdAt: nowIso,
|
|
@@ -213246,6 +213458,11 @@ async function startOasisServer(opts) {
|
|
|
213246
213458
|
return;
|
|
213247
213459
|
}
|
|
213248
213460
|
const url = new URL(req.url ?? "/", "http://localhost");
|
|
213461
|
+
if (url.pathname === "/healthz" && url.searchParams.get("deep") === "1") {
|
|
213462
|
+
const db = opts.deepHealth ? await opts.deepHealth() : { ok: true, db: "none" };
|
|
213463
|
+
res.writeHead(db.ok ? 200 : 503, { "content-type": "application/json" }).end(JSON.stringify({ ok: db.ok, ...getBuildInfo(), db }));
|
|
213464
|
+
return;
|
|
213465
|
+
}
|
|
213249
213466
|
if (url.pathname === "/healthz") {
|
|
213250
213467
|
res.writeHead(200, { "content-type": "application/json" }).end(JSON.stringify({ ok: true, ...getBuildInfo() }));
|
|
213251
213468
|
return;
|
|
@@ -214416,7 +214633,7 @@ async function startOasisServer(opts) {
|
|
|
214416
214633
|
const openRoom = async () => {
|
|
214417
214634
|
let chatSessionId2;
|
|
214418
214635
|
if (chatStore) {
|
|
214419
|
-
const { randomUUID:
|
|
214636
|
+
const { randomUUID: randomUUID50 } = await import("node:crypto");
|
|
214420
214637
|
const known = discussSessions.get(itemKey);
|
|
214421
214638
|
const knownSession = known ? await chatStore.getSession(known) : null;
|
|
214422
214639
|
if (knownSession && knownSession.workspace === ctx.workspace && knownSession.humanActorId === ctx.ownerId && (!body2.escalationId || knownSession.escalationId === body2.escalationId)) chatSessionId2 = known;
|
|
@@ -214425,7 +214642,7 @@ async function startOasisServer(opts) {
|
|
|
214425
214642
|
chatSessionId2 = existing[0]?.id;
|
|
214426
214643
|
}
|
|
214427
214644
|
if (!chatSessionId2) {
|
|
214428
|
-
chatSessionId2 =
|
|
214645
|
+
chatSessionId2 = randomUUID50();
|
|
214429
214646
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
214430
214647
|
const title = `\u89E3\u51B3\uFF1A${ctx.seed.slice(ctx.seed.indexOf("\uFF1A") + 1, ctx.seed.indexOf("\uFF1A") + 25) || "\u5DE5\u5355\u5361\u70B9"}`;
|
|
214431
214648
|
const reg0 = (await resolveEngine(currentCompanyId).catch(() => null))?.registry ?? opts.registry;
|
|
@@ -215631,7 +215848,7 @@ ${composed}`;
|
|
|
215631
215848
|
if (rejectedLedger.failures === 0 && retriedRow) {
|
|
215632
215849
|
turnPersisted = true;
|
|
215633
215850
|
} else if (rejectedLedger.failures === 0) {
|
|
215634
|
-
const { randomUUID:
|
|
215851
|
+
const { randomUUID: randomUUID50 } = await import("node:crypto");
|
|
215635
215852
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
215636
215853
|
const rejectedAttachments = effectiveAttachments.map((a) => ({
|
|
215637
215854
|
name: a.name,
|
|
@@ -215639,7 +215856,7 @@ ${composed}`;
|
|
|
215639
215856
|
...a.contentType !== void 0 ? { contentType: a.contentType } : {}
|
|
215640
215857
|
}));
|
|
215641
215858
|
await chatStore.appendMessage({
|
|
215642
|
-
id:
|
|
215859
|
+
id: randomUUID50(),
|
|
215643
215860
|
sessionId: persistTarget.id,
|
|
215644
215861
|
role: "user",
|
|
215645
215862
|
content: persistedUserMessage,
|
|
@@ -215724,14 +215941,14 @@ ${composed}`;
|
|
|
215724
215941
|
runtimeSessionId: session.nativeSessionId ?? session.id
|
|
215725
215942
|
}).catch(() => void 0);
|
|
215726
215943
|
}
|
|
215727
|
-
const { randomUUID:
|
|
215944
|
+
const { randomUUID: randomUUID50 } = await import("node:crypto");
|
|
215728
215945
|
const persistAttachments = effectiveAttachments.map((a) => ({
|
|
215729
215946
|
name: a.name,
|
|
215730
215947
|
...a.blobRef !== void 0 ? { blobRef: a.blobRef } : {},
|
|
215731
215948
|
...a.contentType !== void 0 ? { contentType: a.contentType } : {}
|
|
215732
215949
|
}));
|
|
215733
215950
|
if (!retriedRow) await chatStore.appendMessage({
|
|
215734
|
-
id:
|
|
215951
|
+
id: randomUUID50(),
|
|
215735
215952
|
sessionId: persistTarget.id,
|
|
215736
215953
|
role: "user",
|
|
215737
215954
|
content: persistedUserMessage,
|
|
@@ -216383,8 +216600,8 @@ ${composed}`;
|
|
|
216383
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}` }));
|
|
216384
216601
|
return;
|
|
216385
216602
|
}
|
|
216386
|
-
const { randomUUID:
|
|
216387
|
-
const state =
|
|
216603
|
+
const { randomUUID: randomUUID50 } = await import("node:crypto");
|
|
216604
|
+
const state = randomUUID50();
|
|
216388
216605
|
const nameSlug = (actorName || actorId?.split(":").pop() || owner?.login || "bot").toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-|-$/g, "").slice(0, 24) || "bot";
|
|
216389
216606
|
const nameSuffix = await chooseAppNameSuffix(
|
|
216390
216607
|
{ employeeSlug: nameSlug, namePrefix: "oasis" },
|
|
@@ -220114,6 +220331,10 @@ var init_memory_control_plane_store = __esm({
|
|
|
220114
220331
|
}
|
|
220115
220332
|
if (patch.status !== void 0) c.status = patch.status;
|
|
220116
220333
|
if (patch.onboardingVariant !== void 0) c.onboardingVariant = patch.onboardingVariant;
|
|
220334
|
+
if (patch.timeZone !== void 0) {
|
|
220335
|
+
if (patch.timeZone === null) delete c.timeZone;
|
|
220336
|
+
else c.timeZone = patch.timeZone;
|
|
220337
|
+
}
|
|
220117
220338
|
if (patch.dissolvedAt !== void 0) {
|
|
220118
220339
|
if (patch.dissolvedAt === null) delete c.dissolvedAt;
|
|
220119
220340
|
else c.dissolvedAt = patch.dissolvedAt;
|
|
@@ -220757,12 +220978,12 @@ function isUncategorizedProjectId(projectId2) {
|
|
|
220757
220978
|
function latestUncategorizedActivityAt(candidates) {
|
|
220758
220979
|
let bestIso = UNCATEGORIZED_UNKNOWN_TIME;
|
|
220759
220980
|
let bestMs = Date.parse(UNCATEGORIZED_UNKNOWN_TIME);
|
|
220760
|
-
for (const
|
|
220761
|
-
if (!
|
|
220762
|
-
const ms = Date.parse(
|
|
220981
|
+
for (const iso9 of candidates) {
|
|
220982
|
+
if (!iso9) continue;
|
|
220983
|
+
const ms = Date.parse(iso9);
|
|
220763
220984
|
if (Number.isNaN(ms) || ms <= bestMs) continue;
|
|
220764
220985
|
bestMs = ms;
|
|
220765
|
-
bestIso =
|
|
220986
|
+
bestIso = iso9;
|
|
220766
220987
|
}
|
|
220767
220988
|
return bestIso;
|
|
220768
220989
|
}
|
|
@@ -221535,9 +221756,9 @@ function deriveRounds(runs) {
|
|
|
221535
221756
|
}
|
|
221536
221757
|
return rounds.sort((a, b2) => Date.parse(a.startedAt) - Date.parse(b2.startedAt) || a.key.localeCompare(b2.key));
|
|
221537
221758
|
}
|
|
221538
|
-
function inWindow(
|
|
221539
|
-
if (!
|
|
221540
|
-
const ms = Date.parse(
|
|
221759
|
+
function inWindow(iso9, fromMs, toMs) {
|
|
221760
|
+
if (!iso9) return false;
|
|
221761
|
+
const ms = Date.parse(iso9);
|
|
221541
221762
|
return Number.isFinite(ms) && ms >= fromMs && ms <= toMs;
|
|
221542
221763
|
}
|
|
221543
221764
|
function computeFacts(input) {
|
|
@@ -231669,40 +231890,21 @@ var init_migrate = __esm({
|
|
|
231669
231890
|
});
|
|
231670
231891
|
|
|
231671
231892
|
// ../server/src/domains/actors/variable-expiry.ts
|
|
231672
|
-
function zoneOffsetMs(ms, timeZone) {
|
|
231673
|
-
const parts = new Intl.DateTimeFormat("en-US", {
|
|
231674
|
-
timeZone,
|
|
231675
|
-
hour12: false,
|
|
231676
|
-
year: "numeric",
|
|
231677
|
-
month: "2-digit",
|
|
231678
|
-
day: "2-digit",
|
|
231679
|
-
hour: "2-digit",
|
|
231680
|
-
minute: "2-digit",
|
|
231681
|
-
second: "2-digit"
|
|
231682
|
-
}).formatToParts(new Date(ms));
|
|
231683
|
-
const get = (type) => Number(parts.find((p2) => p2.type === type)?.value ?? "0");
|
|
231684
|
-
const asIfUtc = Date.UTC(get("year"), get("month") - 1, get("day"), get("hour") % 24, get("minute"), get("second"));
|
|
231685
|
-
return asIfUtc - ms;
|
|
231686
|
-
}
|
|
231687
|
-
function zonedStartOfDayMs(dateStr, timeZone) {
|
|
231688
|
-
const utcMidnight = Date.parse(`${dateStr}T00:00:00Z`);
|
|
231689
|
-
const firstGuess = utcMidnight - zoneOffsetMs(utcMidnight, timeZone);
|
|
231690
|
-
const corrected = utcMidnight - zoneOffsetMs(firstGuess, timeZone);
|
|
231691
|
-
return corrected;
|
|
231692
|
-
}
|
|
231693
231893
|
function isVariableExpired(expiresAt2, nowMs, timeZone = DEFAULT_VARIABLE_TIME_ZONE) {
|
|
231694
231894
|
if (!expiresAt2) return false;
|
|
231695
231895
|
const t = Date.parse(expiresAt2);
|
|
231696
231896
|
if (Number.isNaN(t)) return false;
|
|
231697
231897
|
const d = new Date(t);
|
|
231698
231898
|
const dateStr = `${d.getUTCFullYear()}-${pad(d.getUTCMonth() + 1)}-${pad(d.getUTCDate())}`;
|
|
231899
|
+
if (!isValidDay(dateStr)) return false;
|
|
231699
231900
|
return nowMs >= zonedStartOfDayMs(dateStr, timeZone);
|
|
231700
231901
|
}
|
|
231701
231902
|
var DEFAULT_VARIABLE_TIME_ZONE, pad;
|
|
231702
231903
|
var init_variable_expiry = __esm({
|
|
231703
231904
|
"../server/src/domains/actors/variable-expiry.ts"() {
|
|
231704
231905
|
"use strict";
|
|
231705
|
-
|
|
231906
|
+
init_src();
|
|
231907
|
+
DEFAULT_VARIABLE_TIME_ZONE = DEFAULT_TIME_ZONE;
|
|
231706
231908
|
pad = (n) => String(n).padStart(2, "0");
|
|
231707
231909
|
}
|
|
231708
231910
|
});
|
|
@@ -233241,6 +233443,19 @@ ${input.description}
|
|
|
233241
233443
|
if (rows.some((r) => r.key === key2)) return true;
|
|
233242
233444
|
return this.variableRecordsEnabled() && (await this.opts.store.listVariableRecords()).some((r) => r.key === key2);
|
|
233243
233445
|
}
|
|
233446
|
+
/**
|
|
233447
|
+
* 变量到期按哪个时区算日界:本组织的生效时区(PRD v1.2 §7「按组织时区,未设置时按默认」)。
|
|
233448
|
+
* 读失败回落 Asia/Shanghai 并告警——宁可按默认日界判,也不让一次控制面抖动把整次派单打挂。
|
|
233449
|
+
*/
|
|
233450
|
+
async variableTimeZone() {
|
|
233451
|
+
if (!this.opts.timeZone) return DEFAULT_VARIABLE_TIME_ZONE;
|
|
233452
|
+
try {
|
|
233453
|
+
return await this.opts.timeZone();
|
|
233454
|
+
} catch (err) {
|
|
233455
|
+
console.warn(`[variables] \u8BFB\u7EC4\u7EC7\u65F6\u533A\u5931\u8D25\uFF0C\u6309 ${DEFAULT_VARIABLE_TIME_ZONE} \u5224\u5230\u671F\uFF1A${err.message}`);
|
|
233456
|
+
return DEFAULT_VARIABLE_TIME_ZONE;
|
|
233457
|
+
}
|
|
233458
|
+
}
|
|
233244
233459
|
async resolveActorEnv(actorId) {
|
|
233245
233460
|
const cfg = await this.opts.store.latestConfig(actorId);
|
|
233246
233461
|
const enabledConnectors = await this.effectiveEnabledConnectors(actorId, cfg);
|
|
@@ -233260,12 +233475,13 @@ ${input.description}
|
|
|
233260
233475
|
const decode2 = (ct) => ct.startsWith("plain:") ? ct.slice(6) : this.decrypt(ct);
|
|
233261
233476
|
const expiredWinner = /* @__PURE__ */ new Map();
|
|
233262
233477
|
const nowMs = Date.now();
|
|
233478
|
+
const timeZone = await this.variableTimeZone();
|
|
233263
233479
|
for (const row of rows) {
|
|
233264
233480
|
if (row.scope !== "global") continue;
|
|
233265
233481
|
if (row.actorId) continue;
|
|
233266
233482
|
if (!row.connectorId || enabledConnectors.has(row.connectorId)) {
|
|
233267
233483
|
env[row.key] = decode2(row.valueEncrypted);
|
|
233268
|
-
expiredWinner.set(row.key, isVariableExpired(row.expiresAt, nowMs));
|
|
233484
|
+
expiredWinner.set(row.key, isVariableExpired(row.expiresAt, nowMs, timeZone));
|
|
233269
233485
|
}
|
|
233270
233486
|
}
|
|
233271
233487
|
for (const row of rows) {
|
|
@@ -233273,7 +233489,7 @@ ${input.description}
|
|
|
233273
233489
|
if (row.actorId && row.actorId !== actorId) continue;
|
|
233274
233490
|
if (!row.connectorId || enabledConnectors.has(row.connectorId)) {
|
|
233275
233491
|
env[row.key] = decode2(row.valueEncrypted);
|
|
233276
|
-
expiredWinner.set(row.key, isVariableExpired(row.expiresAt, nowMs));
|
|
233492
|
+
expiredWinner.set(row.key, isVariableExpired(row.expiresAt, nowMs, timeZone));
|
|
233277
233493
|
}
|
|
233278
233494
|
}
|
|
233279
233495
|
for (const [key2, expired] of expiredWinner) if (expired) delete env[key2];
|
|
@@ -233317,13 +233533,14 @@ ${input.description}
|
|
|
233317
233533
|
if (!prev || rank[row.binding.kind] > rank[prev.binding.kind]) best.set(row.key, row);
|
|
233318
233534
|
}
|
|
233319
233535
|
const nowMs = Date.now();
|
|
233536
|
+
const timeZone = await this.variableTimeZone();
|
|
233320
233537
|
const out = [];
|
|
233321
233538
|
for (const row of best.values()) {
|
|
233322
233539
|
if (!isInjectableVariableName(row.key)) {
|
|
233323
233540
|
skipUninjectable(row.key);
|
|
233324
233541
|
continue;
|
|
233325
233542
|
}
|
|
233326
|
-
if (isVariableExpired(row.expiresAt, nowMs)) continue;
|
|
233543
|
+
if (isVariableExpired(row.expiresAt, nowMs, timeZone)) continue;
|
|
233327
233544
|
out.push(row);
|
|
233328
233545
|
}
|
|
233329
233546
|
return out;
|
|
@@ -233500,6 +233717,7 @@ ${input.description}
|
|
|
233500
233717
|
const merged = /* @__PURE__ */ new Map();
|
|
233501
233718
|
const expiredWinner = /* @__PURE__ */ new Map();
|
|
233502
233719
|
const nowMs = Date.now();
|
|
233720
|
+
const timeZone = await this.variableTimeZone();
|
|
233503
233721
|
const gated = (row) => !row.connectorId || enabledConnectors.has(row.connectorId);
|
|
233504
233722
|
const put3 = (row) => {
|
|
233505
233723
|
if (!gated(row)) return;
|
|
@@ -233513,7 +233731,7 @@ ${input.description}
|
|
|
233513
233731
|
deliveryMode: row.deliveryMode ?? "env",
|
|
233514
233732
|
origin: { ...row.actorId !== void 0 ? { actorId: row.actorId } : {}, ...row.projectId !== void 0 ? { projectId: row.projectId } : {} }
|
|
233515
233733
|
});
|
|
233516
|
-
expiredWinner.set(row.key, isVariableExpired(row.expiresAt, nowMs));
|
|
233734
|
+
expiredWinner.set(row.key, isVariableExpired(row.expiresAt, nowMs, timeZone));
|
|
233517
233735
|
};
|
|
233518
233736
|
for (const row of rows) {
|
|
233519
233737
|
if (row.scope === "global" && !row.actorId) put3(row);
|
|
@@ -234452,10 +234670,10 @@ function normalizeExpiresAt(raw) {
|
|
|
234452
234670
|
if (Number.isNaN(t)) throw new ApiError(400, "BAD_REQUEST", `expiresAt \u4E0D\u662F\u5408\u6CD5\u65E5\u671F\uFF1A${raw}`);
|
|
234453
234671
|
return new Date(t).toISOString();
|
|
234454
234672
|
}
|
|
234455
|
-
function assertCreatableVariable(key2, expiresAt2, nowMs = Date.now()) {
|
|
234673
|
+
function assertCreatableVariable(key2, expiresAt2, nowMs = Date.now(), timeZone = DEFAULT_VARIABLE_TIME_ZONE) {
|
|
234456
234674
|
const problem = variableNameProblem(key2);
|
|
234457
234675
|
if (problem) throw new ApiError(400, problem.code, problem.message);
|
|
234458
|
-
if (expiresAt2 && isVariableExpired(expiresAt2, nowMs)) {
|
|
234676
|
+
if (expiresAt2 && isVariableExpired(expiresAt2, nowMs, timeZone)) {
|
|
234459
234677
|
throw new ApiError(400, "VARIABLE_EXPIRY_NOT_FUTURE", "\u65B0\u5EFA\u53D8\u91CF\u7684\u5230\u671F\u65F6\u95F4\u987B\u665A\u4E8E\u4ECA\u5929");
|
|
234460
234678
|
}
|
|
234461
234679
|
}
|
|
@@ -235010,7 +235228,7 @@ function actorsDomain(opts) {
|
|
|
235010
235228
|
const { service } = await resolveCtx(req.auth.companyId);
|
|
235011
235229
|
const b2 = req.body;
|
|
235012
235230
|
if (typeof b2?.key !== "string" || !b2.key) throw new ApiError(400, "BAD_REQUEST", "\u7F3A\u5C11 key");
|
|
235013
|
-
const
|
|
235231
|
+
const create2 = parseCreateFlag(b2.create);
|
|
235014
235232
|
const legacyOpts = { replace: parseReplaceFlag(b2.replace), displaced: [] };
|
|
235015
235233
|
const expiresAt2 = normalizeExpiresAt(b2.expiresAt);
|
|
235016
235234
|
const audienceMeta = parseAudienceMeta(b2);
|
|
@@ -235064,9 +235282,9 @@ function actorsDomain(opts) {
|
|
|
235064
235282
|
by: req.auth.actor,
|
|
235065
235283
|
expiresAt: expiresAt2
|
|
235066
235284
|
};
|
|
235067
|
-
if (
|
|
235285
|
+
if (create2) {
|
|
235068
235286
|
if (b2.value === void 0 || b2.value === "") throw new ApiError(400, "BAD_REQUEST", "\u65B0\u5EFA\u53D8\u91CF\u5FC5\u987B\u63D0\u4F9B\u53D8\u91CF\u503C");
|
|
235069
|
-
assertCreatableVariable(b2.key, expiresAt2);
|
|
235287
|
+
assertCreatableVariable(b2.key, expiresAt2, Date.now(), await service.variableTimeZone());
|
|
235070
235288
|
const outcome = await service.createVariable({ ...input, value: b2.value }, legacyOpts).catch(rethrowBindingConflict);
|
|
235071
235289
|
if (outcome === "exists") throw await variableExistsError(service, b2.key, selector);
|
|
235072
235290
|
} else {
|
|
@@ -235203,7 +235421,7 @@ function actorsDomain(opts) {
|
|
|
235203
235421
|
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");
|
|
235204
235422
|
}
|
|
235205
235423
|
const expiresAt2 = normalizeExpiresAt(b2.expiresAt);
|
|
235206
|
-
assertCreatableVariable(b2.key, expiresAt2);
|
|
235424
|
+
assertCreatableVariable(b2.key, expiresAt2, Date.now(), await service.variableTimeZone());
|
|
235207
235425
|
const bindings = parseBindingTargets(b2.bindings, "bindings");
|
|
235208
235426
|
const replace2 = parseBindingTargets(b2.replace, "replace");
|
|
235209
235427
|
const connectorId = await connectorOwner(service, b2.key);
|
|
@@ -235294,9 +235512,9 @@ function actorsDomain(opts) {
|
|
|
235294
235512
|
const actorId = req.params.id;
|
|
235295
235513
|
const b2 = req.body;
|
|
235296
235514
|
if (typeof b2?.key !== "string" || !b2.key) throw new ApiError(400, "BAD_REQUEST", "\u7F3A\u5C11 key");
|
|
235297
|
-
const
|
|
235515
|
+
const create2 = parseCreateFlag(b2.create);
|
|
235298
235516
|
const legacyOpts = { replace: parseReplaceFlag(b2.replace), displaced: [] };
|
|
235299
|
-
if (
|
|
235517
|
+
if (create2) {
|
|
235300
235518
|
const owner = await service.getActor(actorId);
|
|
235301
235519
|
if (!owner) throw new ApiError(404, "NOT_FOUND", `\u6CA1\u6709\u8FD9\u4E2A Agent\uFF1A${actorId}`);
|
|
235302
235520
|
if (owner.kind !== "agent") throw new ApiError(400, "BAD_REQUEST", "\u4E2A\u4EBA\u53D8\u91CF\u53EA\u80FD\u5EFA\u5728 Agent \u4E0A");
|
|
@@ -235312,8 +235530,8 @@ function actorsDomain(opts) {
|
|
|
235312
235530
|
"\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"
|
|
235313
235531
|
);
|
|
235314
235532
|
}
|
|
235315
|
-
if (
|
|
235316
|
-
if (
|
|
235533
|
+
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");
|
|
235534
|
+
if (create2) assertCreatableVariable(b2.key, expiresAt2, Date.now(), await service.variableTimeZone());
|
|
235317
235535
|
if (b2.value === void 0 || b2.value === "") return { status: 200, body: { ok: true } };
|
|
235318
235536
|
assertInjectableVariableName(b2.key);
|
|
235319
235537
|
if (b2.connectorId === void 0) {
|
|
@@ -235341,7 +235559,7 @@ function actorsDomain(opts) {
|
|
|
235341
235559
|
by: req.auth.actor,
|
|
235342
235560
|
expiresAt: expiresAt2
|
|
235343
235561
|
};
|
|
235344
|
-
if (
|
|
235562
|
+
if (create2) {
|
|
235345
235563
|
const outcome = await service.createVariable(input, legacyOpts).catch(rethrowBindingConflict);
|
|
235346
235564
|
if (outcome === "exists") throw await variableExistsError(service, b2.key, { actorId });
|
|
235347
235565
|
} else {
|
|
@@ -236372,6 +236590,7 @@ function createActorsDomain(opts) {
|
|
|
236372
236590
|
...opts.listSharedSkillFiles !== void 0 ? { listSharedSkillFiles: opts.listSharedSkillFiles } : {},
|
|
236373
236591
|
...opts.isInstalledSkillAvailable !== void 0 ? { isInstalledSkillAvailable: opts.isInstalledSkillAvailable } : {},
|
|
236374
236592
|
...opts.listBindingModelIds !== void 0 ? { listBindingModelIds: opts.listBindingModelIds } : {},
|
|
236593
|
+
...opts.companyTimeZone !== void 0 ? { timeZone: () => opts.companyTimeZone(companyOf()) } : {},
|
|
236375
236594
|
// 服务内部的变量写入(连接器授权)抢占记录时由服务自己记审计(ADR 0578 评审 N-3),与路由同一个旁账。
|
|
236376
236595
|
...opts.credentialAudit !== void 0 ? { credentialAudit: (r) => opts.credentialAudit({ ...r, companyId: companyOf() }) } : {},
|
|
236377
236596
|
...kernel !== void 0 ? { onRolesChanged: (a, r) => kernel.setActorRoles(a, r) } : {},
|
|
@@ -236496,7 +236715,9 @@ function assistantsDomain(opts) {
|
|
|
236496
236715
|
const humanId = req.params.humanId;
|
|
236497
236716
|
try {
|
|
236498
236717
|
await service.assertWritePermission(req.auth.actor, humanId);
|
|
236499
|
-
const
|
|
236718
|
+
const b2 = req.body ?? {};
|
|
236719
|
+
const preferred = typeof b2.nodeId === "string" && b2.nodeId && typeof b2.runtimeKind === "string" && b2.runtimeKind ? { nodeId: b2.nodeId, runtimeKind: b2.runtimeKind } : void 0;
|
|
236720
|
+
const r = await service.ensureFor(humanId, req.auth.actor, preferred);
|
|
236500
236721
|
return { status: 201, body: { agentId: r.agentId, source: r.source } };
|
|
236501
236722
|
} catch (e) {
|
|
236502
236723
|
toApiError2(e);
|
|
@@ -241564,7 +241785,8 @@ function fromRow(row) {
|
|
|
241564
241785
|
["result", str2(row["result"])],
|
|
241565
241786
|
["invalidReason", str2(row["invalid_reason"])],
|
|
241566
241787
|
["readAt", iso2(row["read_at"])],
|
|
241567
|
-
["item", row["item"] ?? void 0]
|
|
241788
|
+
["item", row["item"] ?? void 0],
|
|
241789
|
+
["chatSessionId", str2(row["chat_session_id"])]
|
|
241568
241790
|
];
|
|
241569
241791
|
for (const [k2, v2] of opt) if (v2 !== void 0 && v2 !== null) r[k2] = v2;
|
|
241570
241792
|
return r;
|
|
@@ -241730,6 +241952,7 @@ var init_notification_store = __esm({
|
|
|
241730
241952
|
read_at timestamptz,
|
|
241731
241953
|
item jsonb
|
|
241732
241954
|
)`);
|
|
241955
|
+
await sql.query(`ALTER TABLE "${s2}".notifications ADD COLUMN IF NOT EXISTS chat_session_id text`);
|
|
241733
241956
|
await sql.query(`CREATE UNIQUE INDEX IF NOT EXISTS notifications_pending_source_uq
|
|
241734
241957
|
ON "${s2}".notifications (recipient, source_key) WHERE status = 'pending'`);
|
|
241735
241958
|
await sql.query(`CREATE UNIQUE INDEX IF NOT EXISTS notifications_notice_source_uq
|
|
@@ -241742,8 +241965,8 @@ var init_notification_store = __esm({
|
|
|
241742
241965
|
const id = `ntf:${(0, import_node_crypto58.randomUUID)()}`;
|
|
241743
241966
|
const r = await this.sql.query(
|
|
241744
241967
|
`INSERT INTO ${this.t} (id, recipient, category, source_key, kind, workorder_id, node_id, card_id, actor_id,
|
|
241745
|
-
title, workspace_title, entered_at, updated_at, status, read_at, item)
|
|
241746
|
-
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$12,$13,$14,$15)
|
|
241968
|
+
title, workspace_title, entered_at, updated_at, status, read_at, item, chat_session_id)
|
|
241969
|
+
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$12,$13,$14,$15,$16)
|
|
241747
241970
|
ON CONFLICT DO NOTHING
|
|
241748
241971
|
RETURNING *`,
|
|
241749
241972
|
[
|
|
@@ -241761,7 +241984,8 @@ var init_notification_store = __esm({
|
|
|
241761
241984
|
n.enteredAt,
|
|
241762
241985
|
n.status ?? null,
|
|
241763
241986
|
n.readAt ?? null,
|
|
241764
|
-
n.item ? JSON.stringify(n.item) : null
|
|
241987
|
+
n.item ? JSON.stringify(n.item) : null,
|
|
241988
|
+
n.chatSessionId ?? null
|
|
241765
241989
|
]
|
|
241766
241990
|
);
|
|
241767
241991
|
if (r.rows[0]) return fromRow(r.rows[0]);
|
|
@@ -242413,11 +242637,11 @@ function parseUsageQuery(raw, now) {
|
|
|
242413
242637
|
let timeZone = "UTC";
|
|
242414
242638
|
if (raw.timeZone !== void 0 && raw.timeZone !== null && raw.timeZone !== "") {
|
|
242415
242639
|
if (typeof raw.timeZone !== "string") throw new UsageQueryError("timeZone \u5FC5\u987B\u662F IANA \u65F6\u533A\u540D");
|
|
242416
|
-
timeZone =
|
|
242640
|
+
timeZone = canonicalTimeZone2(raw.timeZone.trim());
|
|
242417
242641
|
}
|
|
242418
242642
|
return { range, asOf: new Date(asOfMs).toISOString(), timeZone };
|
|
242419
242643
|
}
|
|
242420
|
-
function
|
|
242644
|
+
function canonicalTimeZone2(tz) {
|
|
242421
242645
|
if (!tz) throw new UsageQueryError("timeZone \u5FC5\u987B\u662F IANA \u65F6\u533A\u540D");
|
|
242422
242646
|
try {
|
|
242423
242647
|
return new Intl.DateTimeFormat("en-US", { timeZone: tz }).resolvedOptions().timeZone;
|
|
@@ -242936,10 +243160,10 @@ var init_tags = __esm({
|
|
|
242936
243160
|
return [...new Set(ids2.map((s2) => String(s2).trim()).filter(Boolean))].filter((id) => known.has(id));
|
|
242937
243161
|
}
|
|
242938
243162
|
ensureByName(companyId, name) {
|
|
242939
|
-
const
|
|
242940
|
-
if (!
|
|
242941
|
-
const hit = this.entries(companyId).find((t) => nameKey(t.name) === nameKey(
|
|
242942
|
-
return hit ?? this.create(companyId, { name:
|
|
243163
|
+
const clean3 = cleanName(name ?? "");
|
|
243164
|
+
if (!clean3) return null;
|
|
243165
|
+
const hit = this.entries(companyId).find((t) => nameKey(t.name) === nameKey(clean3));
|
|
243166
|
+
return hit ?? this.create(companyId, { name: clean3 });
|
|
242943
243167
|
}
|
|
242944
243168
|
/** 子类落盘钩子(内存实现为空)。 */
|
|
242945
243169
|
persist() {
|
|
@@ -244324,6 +244548,11 @@ var init_projects = __esm({
|
|
|
244324
244548
|
});
|
|
244325
244549
|
|
|
244326
244550
|
// ../server/src/domains/companies/service.ts
|
|
244551
|
+
function assertProfileNameLength(value2, label2) {
|
|
244552
|
+
if (profileNameLength(value2) > PROFILE_NAME_MAX) {
|
|
244553
|
+
throw new CompanyError(400, "NAME_TOO_LONG", `${label2}\u6700\u591A ${PROFILE_NAME_MAX} \u4E2A\u5B57\u7B26`);
|
|
244554
|
+
}
|
|
244555
|
+
}
|
|
244327
244556
|
function normalizeEmail(raw) {
|
|
244328
244557
|
const v2 = raw?.trim().toLowerCase() ?? "";
|
|
244329
244558
|
return v2.length > 0 ? v2 : void 0;
|
|
@@ -244337,6 +244566,7 @@ var init_service6 = __esm({
|
|
|
244337
244566
|
"../server/src/domains/companies/service.ts"() {
|
|
244338
244567
|
"use strict";
|
|
244339
244568
|
import_node_crypto60 = require("node:crypto");
|
|
244569
|
+
init_src();
|
|
244340
244570
|
init_console_url();
|
|
244341
244571
|
ROLES = ["owner", "admin", "member"];
|
|
244342
244572
|
INVITABLE_ROLES = ["admin", "member"];
|
|
@@ -244358,8 +244588,11 @@ var init_service6 = __esm({
|
|
|
244358
244588
|
now;
|
|
244359
244589
|
sender;
|
|
244360
244590
|
consoleUrl;
|
|
244591
|
+
/** 部署默认时区,见 {@link CompaniesServiceOptions.defaultTimeZone}。 */
|
|
244592
|
+
defaultTimeZone;
|
|
244361
244593
|
constructor(opts) {
|
|
244362
244594
|
this.store = opts.store;
|
|
244595
|
+
this.defaultTimeZone = opts.defaultTimeZone ?? DEFAULT_TIME_ZONE;
|
|
244363
244596
|
this.now = opts.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
244364
244597
|
this.sender = opts.sender;
|
|
244365
244598
|
this.consoleUrl = opts.consoleUrl;
|
|
@@ -244425,12 +244658,47 @@ var init_service6 = __esm({
|
|
|
244425
244658
|
await this.store.updateCompany(companyId, { onboardingVariant: variant });
|
|
244426
244659
|
return { ...company, onboardingVariant: variant };
|
|
244427
244660
|
}
|
|
244661
|
+
/** 给成员看的公司:存的字段 + 实际生效的时区(含部署默认值回落)+ 部署默认时区。 */
|
|
244662
|
+
view(company) {
|
|
244663
|
+
return { ...company, effectiveTimeZone: effectiveTimeZone(company, this.defaultTimeZone), defaultTimeZone: this.defaultTimeZone };
|
|
244664
|
+
}
|
|
244665
|
+
/**
|
|
244666
|
+
* 这家组织实际生效的时区。组织不存在、或控制面读失败时回落部署默认值并告警——
|
|
244667
|
+
* 调用方是变量到期这类「必须给出一个答案」的判定,读不到组织行不该让派单整个失败。
|
|
244668
|
+
*/
|
|
244669
|
+
async effectiveTimeZoneOf(companyId) {
|
|
244670
|
+
if (!companyId) return this.defaultTimeZone;
|
|
244671
|
+
try {
|
|
244672
|
+
return effectiveTimeZone(await this.store.getCompany(companyId), this.defaultTimeZone);
|
|
244673
|
+
} catch (err) {
|
|
244674
|
+
console.warn(`[companies] \u8BFB\u7EC4\u7EC7 ${companyId} \u7684\u65F6\u533A\u5931\u8D25\uFF0C\u6309\u90E8\u7F72\u9ED8\u8BA4 ${this.defaultTimeZone}\uFF1A${err.message}`);
|
|
244675
|
+
return this.defaultTimeZone;
|
|
244676
|
+
}
|
|
244677
|
+
}
|
|
244678
|
+
/**
|
|
244679
|
+
* 设置组织时区(IANA 名,存规范写法);`null` = 清空,回到部署默认值。非法名 400。
|
|
244680
|
+
* 权限(owner/admin)由路由层强制;这里守「组织还可用」(D8.2)。
|
|
244681
|
+
*/
|
|
244682
|
+
async setTimeZone(companyId, timeZone) {
|
|
244683
|
+
const canonical2 = timeZone === null ? null : canonicalTimeZone(timeZone);
|
|
244684
|
+
if (timeZone !== null && !canonical2) {
|
|
244685
|
+
throw new CompanyError(400, "INVALID_TIME_ZONE", `timeZone \u4E0D\u662F\u5408\u6CD5\u7684 IANA \u65F6\u533A\u540D\uFF1A${JSON.stringify(timeZone)}`);
|
|
244686
|
+
}
|
|
244687
|
+
const company = await this.requireActiveCompany(companyId);
|
|
244688
|
+
await this.store.updateCompany(companyId, { timeZone: canonical2 });
|
|
244689
|
+
if (canonical2 === null) {
|
|
244690
|
+
const { timeZone: _drop, ...rest } = company;
|
|
244691
|
+
return rest;
|
|
244692
|
+
}
|
|
244693
|
+
return { ...company, timeZone: canonical2 };
|
|
244694
|
+
}
|
|
244428
244695
|
/**
|
|
244429
244696
|
* 改团队名称。**只改 name,不动 slug**——slug 是路由键(company:<slug> 与引擎 schema co_<slug>
|
|
244430
244697
|
* 的一部分,`create` 里注释「建成不可改」),改它会让所有历史链接失效。
|
|
244431
244698
|
* 校验(非空 / trim)在路由层做完了,这里假设 name 已经是非空 trim 过的字符串。
|
|
244432
244699
|
*/
|
|
244433
244700
|
async renameCompany(id, name) {
|
|
244701
|
+
assertProfileNameLength(name, "\u56E2\u961F\u7A7A\u95F4\u540D\u79F0");
|
|
244434
244702
|
const company = await this.requireCompany(id);
|
|
244435
244703
|
await this.store.updateCompany(id, { name });
|
|
244436
244704
|
return { ...company, name };
|
|
@@ -244549,6 +244817,7 @@ var init_service6 = __esm({
|
|
|
244549
244817
|
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");
|
|
244550
244818
|
const name = input.name?.trim() ?? "";
|
|
244551
244819
|
if (!name) throw new CompanyError(400, "BAD_REQUEST", "\u7F3A\u5C11 name");
|
|
244820
|
+
assertProfileNameLength(name, "\u56E2\u961F\u7A7A\u95F4\u540D\u79F0");
|
|
244552
244821
|
if (await this.store.getCompanyBySlug(slug5)) throw new CompanyError(409, "SLUG_TAKEN", `slug \u5DF2\u88AB\u5360\u7528\uFF1A${slug5}`);
|
|
244553
244822
|
const company = {
|
|
244554
244823
|
id: `company:${slug5}`,
|
|
@@ -244741,6 +245010,7 @@ var init_service6 = __esm({
|
|
|
244741
245010
|
async setMemberDisplayName(companyId, accountId, displayName3, callerAccountId) {
|
|
244742
245011
|
const trimmed = displayName3.trim();
|
|
244743
245012
|
if (!trimmed) throw new CompanyError(400, "BAD_REQUEST", "displayName \u4E0D\u80FD\u4E3A\u7A7A");
|
|
245013
|
+
assertProfileNameLength(trimmed, "\u540D\u5B57");
|
|
244744
245014
|
await this.requireCompany(companyId);
|
|
244745
245015
|
const editingSomeoneElse = callerAccountId !== accountId;
|
|
244746
245016
|
const res = await this.store.updateMemberDisplayName(companyId, accountId, trimmed, {
|
|
@@ -245628,7 +245898,7 @@ function isCompanyCrossTenantPath(pathname) {
|
|
|
245628
245898
|
return COMPANY_CROSS_TENANT_PREFIXES.some((p2) => pathname === p2 || pathname.startsWith(`${p2}/`));
|
|
245629
245899
|
}
|
|
245630
245900
|
function companiesDomain(opts) {
|
|
245631
|
-
const { service, currentUser, blobs, resolveActorsCtx, offboarding, agentCredentials } = opts;
|
|
245901
|
+
const { service, currentUser, blobs, resolveActorsCtx, offboarding, agentCredentials, verifyAccountDeletionTicket, assistantOfHuman } = opts;
|
|
245632
245902
|
const mapErr = (e) => {
|
|
245633
245903
|
if (e instanceof CompanyError) throw new ApiError(e.status, e.code, e.message, e.details);
|
|
245634
245904
|
throw e;
|
|
@@ -245648,8 +245918,13 @@ function companiesDomain(opts) {
|
|
|
245648
245918
|
if (!name) return;
|
|
245649
245919
|
const { service: actorsSvc } = await resolveActorsCtx(member.companyId);
|
|
245650
245920
|
const existing = await actorsSvc.getActor(member.actorId);
|
|
245651
|
-
if (
|
|
245652
|
-
await
|
|
245921
|
+
if (existing && existing.name !== name) await actorsSvc.upsertActor({ ...existing, name }, by);
|
|
245922
|
+
const bond = assistantOfHuman ? await assistantOfHuman(member.companyId, member.actorId) : null;
|
|
245923
|
+
if (!bond || bond.origin !== "lazy-create") return;
|
|
245924
|
+
const assistant = await actorsSvc.getActor(bond.agentActorId);
|
|
245925
|
+
const assistantName = assistantNameFor(name);
|
|
245926
|
+
if (!assistant || assistant.name === assistantName) return;
|
|
245927
|
+
await actorsSvc.upsertActor({ ...assistant, name: assistantName }, by);
|
|
245653
245928
|
};
|
|
245654
245929
|
const requireIfMatch = (req) => {
|
|
245655
245930
|
const raw = req.raw.headers["if-match"];
|
|
@@ -245693,13 +245968,13 @@ function companiesDomain(opts) {
|
|
|
245693
245968
|
router.get("/api/companies", async (req) => {
|
|
245694
245969
|
const me = await whoami(req);
|
|
245695
245970
|
const items = await service.listForUser(me.accountId);
|
|
245696
|
-
return { status: 200, body: { items } };
|
|
245971
|
+
return { status: 200, body: { items: items.map((c) => service.view(c)) } };
|
|
245697
245972
|
});
|
|
245698
245973
|
router.get("/api/companies/:id", async (req) => {
|
|
245699
245974
|
const cid = req.params.id;
|
|
245700
245975
|
const me = await whoami(req);
|
|
245701
245976
|
const company = await service.get(cid);
|
|
245702
|
-
if (company && await service.getMember(cid, me.accountId)) return { status: 200, body: company };
|
|
245977
|
+
if (company && await service.getMember(cid, me.accountId)) return { status: 200, body: service.view(company) };
|
|
245703
245978
|
if (company && await service.hasPendingInvitation(cid, me.email)) {
|
|
245704
245979
|
return { status: 200, body: { id: company.id, name: company.name } };
|
|
245705
245980
|
}
|
|
@@ -245710,8 +245985,9 @@ function companiesDomain(opts) {
|
|
|
245710
245985
|
const b2 = req.body ?? {};
|
|
245711
245986
|
const hasName = b2.name !== void 0;
|
|
245712
245987
|
const hasVariant = b2.onboardingVariant !== void 0;
|
|
245713
|
-
|
|
245714
|
-
|
|
245988
|
+
const hasTimeZone = b2.timeZone !== void 0;
|
|
245989
|
+
if (!hasName && !hasVariant && !hasTimeZone) {
|
|
245990
|
+
throw new ApiError(400, "BAD_REQUEST", "\u7F3A\u5C11\u53EF\u66F4\u65B0\u5B57\u6BB5\uFF08name / onboardingVariant / timeZone\uFF09");
|
|
245715
245991
|
}
|
|
245716
245992
|
let trimmedName;
|
|
245717
245993
|
if (hasName) {
|
|
@@ -245723,6 +245999,9 @@ function companiesDomain(opts) {
|
|
|
245723
245999
|
if (hasVariant && b2.onboardingVariant !== "A" && b2.onboardingVariant !== "B") {
|
|
245724
246000
|
throw new ApiError(400, "BAD_REQUEST", `onboardingVariant \u987B\u4E3A "A" | "B"`);
|
|
245725
246001
|
}
|
|
246002
|
+
if (hasTimeZone && b2.timeZone !== null && !isValidTimeZone(b2.timeZone)) {
|
|
246003
|
+
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)}`);
|
|
246004
|
+
}
|
|
245726
246005
|
await requireOwnerOrAdmin(req, cid);
|
|
245727
246006
|
let company;
|
|
245728
246007
|
if (trimmedName !== void 0) {
|
|
@@ -245731,7 +246010,10 @@ function companiesDomain(opts) {
|
|
|
245731
246010
|
if (hasVariant) {
|
|
245732
246011
|
company = await service.setOnboardingVariant(cid, b2.onboardingVariant).catch(mapErr);
|
|
245733
246012
|
}
|
|
245734
|
-
|
|
246013
|
+
if (hasTimeZone) {
|
|
246014
|
+
company = await service.setTimeZone(cid, b2.timeZone).catch(mapErr);
|
|
246015
|
+
}
|
|
246016
|
+
return { status: 200, body: service.view(company) };
|
|
245735
246017
|
});
|
|
245736
246018
|
router.post("/api/companies", async (req) => {
|
|
245737
246019
|
const b2 = req.body ?? {};
|
|
@@ -245883,6 +246165,16 @@ function companiesDomain(opts) {
|
|
|
245883
246165
|
router.delete("/api/accounts/me", async (req) => {
|
|
245884
246166
|
const off = requireOffboarding();
|
|
245885
246167
|
const me = await whoami(req);
|
|
246168
|
+
if (!verifyAccountDeletionTicket) {
|
|
246169
|
+
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");
|
|
246170
|
+
}
|
|
246171
|
+
const ticket = req.body?.ticket;
|
|
246172
|
+
if (typeof ticket !== "string" || !ticket) {
|
|
246173
|
+
throw new ApiError(403, "DELETION_VERIFICATION_REQUIRED", "\u6CE8\u9500\u524D\u9700\u8981\u5148\u5B8C\u6210\u90AE\u7BB1\u9A8C\u8BC1\u7801\u9A8C\u8BC1");
|
|
246174
|
+
}
|
|
246175
|
+
if (!await verifyAccountDeletionTicket(me.accountId, ticket)) {
|
|
246176
|
+
throw new ApiError(403, "DELETION_VERIFICATION_INVALID", "\u90AE\u7BB1\u9A8C\u8BC1\u5DF2\u5931\u6548\uFF0C\u8BF7\u91CD\u65B0\u83B7\u53D6\u9A8C\u8BC1\u7801");
|
|
246177
|
+
}
|
|
245886
246178
|
const { soloOwned, memberships } = await service.peekAccountDeletion(me.accountId).catch(mapErr);
|
|
245887
246179
|
for (const c of soloOwned) {
|
|
245888
246180
|
await service.dissolveSoloCompanyOnAccountDeletion(c.id, me.accountId).catch(mapErr);
|
|
@@ -246081,14 +246373,16 @@ function companiesDomain(opts) {
|
|
|
246081
246373
|
});
|
|
246082
246374
|
};
|
|
246083
246375
|
}
|
|
246084
|
-
var COMPANY_CROSS_TENANT_PREFIXES;
|
|
246376
|
+
var COMPANY_CROSS_TENANT_PREFIXES, assistantNameFor;
|
|
246085
246377
|
var init_routes6 = __esm({
|
|
246086
246378
|
"../server/src/domains/companies/routes.ts"() {
|
|
246087
246379
|
"use strict";
|
|
246380
|
+
init_src();
|
|
246088
246381
|
init_router();
|
|
246089
246382
|
init_service6();
|
|
246090
246383
|
init_image_upload();
|
|
246091
246384
|
COMPANY_CROSS_TENANT_PREFIXES = ["/api/companies", "/api/invitations", "/api/invite-links", "/api/accounts"];
|
|
246385
|
+
assistantNameFor = (humanName) => `${humanName}\u7684\u52A9\u7406`;
|
|
246092
246386
|
}
|
|
246093
246387
|
});
|
|
246094
246388
|
|
|
@@ -246214,13 +246508,35 @@ var init_agent_credentials = __esm({
|
|
|
246214
246508
|
}
|
|
246215
246509
|
});
|
|
246216
246510
|
|
|
246511
|
+
// ../server/src/domains/companies/time-zone.ts
|
|
246512
|
+
function defaultTimeZoneFromEnv(raw) {
|
|
246513
|
+
const v2 = raw?.trim();
|
|
246514
|
+
if (!v2) return DEFAULT_TIME_ZONE;
|
|
246515
|
+
const canonical2 = canonicalTimeZone(v2);
|
|
246516
|
+
if (!canonical2) {
|
|
246517
|
+
throw new Error(
|
|
246518
|
+
`${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`
|
|
246519
|
+
);
|
|
246520
|
+
}
|
|
246521
|
+
return canonical2;
|
|
246522
|
+
}
|
|
246523
|
+
var DEFAULT_TIME_ZONE_ENV;
|
|
246524
|
+
var init_time_zone2 = __esm({
|
|
246525
|
+
"../server/src/domains/companies/time-zone.ts"() {
|
|
246526
|
+
"use strict";
|
|
246527
|
+
init_src();
|
|
246528
|
+
DEFAULT_TIME_ZONE_ENV = "OASIS_DEFAULT_TIMEZONE";
|
|
246529
|
+
}
|
|
246530
|
+
});
|
|
246531
|
+
|
|
246217
246532
|
// ../server/src/domains/companies/index.ts
|
|
246218
246533
|
function createCompaniesDomain(opts) {
|
|
246219
246534
|
const service = new CompaniesService({
|
|
246220
246535
|
store: opts.store,
|
|
246221
246536
|
...opts.now !== void 0 ? { now: opts.now } : {},
|
|
246222
246537
|
...opts.sender !== void 0 ? { sender: opts.sender } : {},
|
|
246223
|
-
...opts.consoleUrl !== void 0 ? { consoleUrl: opts.consoleUrl } : {}
|
|
246538
|
+
...opts.consoleUrl !== void 0 ? { consoleUrl: opts.consoleUrl } : {},
|
|
246539
|
+
...opts.defaultTimeZone !== void 0 ? { defaultTimeZone: opts.defaultTimeZone } : {}
|
|
246224
246540
|
});
|
|
246225
246541
|
const currentUser = opts.currentUser ?? makeCurrentUser(opts.store);
|
|
246226
246542
|
const offboarding = new MemberOffboardingService({
|
|
@@ -246266,8 +246582,10 @@ function createCompaniesDomain(opts) {
|
|
|
246266
246582
|
offboarding,
|
|
246267
246583
|
currentUser,
|
|
246268
246584
|
...opts.agentCredentials !== void 0 ? { agentCredentials: opts.agentCredentials } : {},
|
|
246585
|
+
...opts.verifyAccountDeletionTicket !== void 0 ? { verifyAccountDeletionTicket: opts.verifyAccountDeletionTicket } : {},
|
|
246269
246586
|
...opts.blobs !== void 0 ? { blobs: opts.blobs } : {},
|
|
246270
|
-
...opts.resolveActorsCtx !== void 0 ? { resolveActorsCtx: opts.resolveActorsCtx } : {}
|
|
246587
|
+
...opts.resolveActorsCtx !== void 0 ? { resolveActorsCtx: opts.resolveActorsCtx } : {},
|
|
246588
|
+
...opts.assistantOfHuman !== void 0 ? { assistantOfHuman: opts.assistantOfHuman } : {}
|
|
246271
246589
|
}),
|
|
246272
246590
|
currentUser
|
|
246273
246591
|
};
|
|
@@ -246289,6 +246607,7 @@ var init_companies = __esm({
|
|
|
246289
246607
|
init_agent_credentials();
|
|
246290
246608
|
init_routes6();
|
|
246291
246609
|
init_migrate();
|
|
246610
|
+
init_time_zone2();
|
|
246292
246611
|
}
|
|
246293
246612
|
});
|
|
246294
246613
|
|
|
@@ -246306,6 +246625,14 @@ function parseCookies(header) {
|
|
|
246306
246625
|
function looksLikeEmail(s2) {
|
|
246307
246626
|
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(s2);
|
|
246308
246627
|
}
|
|
246628
|
+
function meetsChangePasswordPolicy(pw) {
|
|
246629
|
+
if (pw.length < 8) return false;
|
|
246630
|
+
let classes = 0;
|
|
246631
|
+
if (/[A-Za-z]/.test(pw)) classes++;
|
|
246632
|
+
if (/\d/.test(pw)) classes++;
|
|
246633
|
+
if (/[^A-Za-z0-9]/.test(pw)) classes++;
|
|
246634
|
+
return classes >= 2;
|
|
246635
|
+
}
|
|
246309
246636
|
function maskEmail(email2) {
|
|
246310
246637
|
const at2 = email2.indexOf("@");
|
|
246311
246638
|
if (at2 <= 0) return "***";
|
|
@@ -246319,7 +246646,9 @@ function createAuth(opts) {
|
|
|
246319
246646
|
const maxAttempts = opts.maxCodeAttempts ?? 5;
|
|
246320
246647
|
const resendThrottleMs = opts.resendThrottleMs ?? 60 * 1e3;
|
|
246321
246648
|
const riskFailureThreshold = opts.riskFailureThreshold ?? 3;
|
|
246649
|
+
const deletionTicketTtlMs = opts.deletionTicketTtlMs ?? 10 * 60 * 1e3;
|
|
246322
246650
|
const { store, sender, jwtSecret } = opts;
|
|
246651
|
+
const deletionTicketSecret = `${jwtSecret}\0account-deletion-ticket`;
|
|
246323
246652
|
const passwordFailures = /* @__PURE__ */ new Map();
|
|
246324
246653
|
const sessionCookie = (accountId, tokenVersion) => {
|
|
246325
246654
|
const t = now();
|
|
@@ -246339,38 +246668,46 @@ function createAuth(opts) {
|
|
|
246339
246668
|
const tokenVersion = sec?.tokenVersion ?? 0;
|
|
246340
246669
|
return { status: 200, body: account, setCookie: sessionCookie(account.id, tokenVersion) };
|
|
246341
246670
|
};
|
|
246342
|
-
const
|
|
246343
|
-
|
|
246344
|
-
const
|
|
246345
|
-
|
|
246671
|
+
const codeKey = (email2, purpose = "login") => purpose === "login" ? email2 : `${purpose} ${email2}`;
|
|
246672
|
+
const sendCodeDetailed = async (email2, purpose = "login") => {
|
|
246673
|
+
const key2 = codeKey(email2, purpose);
|
|
246674
|
+
const existing = await store.getVerificationCode(key2);
|
|
246675
|
+
const createdAt = existing ? Date.parse(existing.createdAt) : Number.NaN;
|
|
246676
|
+
if (existing && createdAt > now() - resendThrottleMs) {
|
|
246677
|
+
return { sent: false, retryAfterMs: createdAt + resendThrottleMs - now() };
|
|
246678
|
+
}
|
|
246346
246679
|
const code2 = generateCode();
|
|
246347
246680
|
const t = now();
|
|
246348
246681
|
await store.putVerificationCode({
|
|
246349
|
-
email:
|
|
246682
|
+
email: key2,
|
|
246350
246683
|
codeHash: hashCode(code2, jwtSecret),
|
|
246351
246684
|
createdAt: new Date(t).toISOString(),
|
|
246352
246685
|
expiresAt: new Date(t + codeTtlMs).toISOString(),
|
|
246353
246686
|
attempts: 0
|
|
246354
246687
|
});
|
|
246355
246688
|
try {
|
|
246356
|
-
await sender.sendCode(email2, code2);
|
|
246689
|
+
if (purpose === "login") await sender.sendCode(email2, code2);
|
|
246690
|
+
else await sender.sendCode(email2, code2, purpose);
|
|
246357
246691
|
} catch (e) {
|
|
246358
246692
|
console.error(`[auth] \u9A8C\u8BC1\u7801\u53D1\u9001\u5931\u8D25 ${maskEmail(email2)}: ${e instanceof Error ? e.message : String(e)}`);
|
|
246359
246693
|
}
|
|
246694
|
+
return { sent: true, retryAfterMs: resendThrottleMs };
|
|
246360
246695
|
};
|
|
246361
|
-
const
|
|
246362
|
-
|
|
246696
|
+
const sendCode = async (email2, purpose = "login") => (await sendCodeDetailed(email2, purpose)).sent;
|
|
246697
|
+
const verifyEmailCode = async (email2, code2, purpose = "login") => {
|
|
246698
|
+
const key2 = codeKey(email2, purpose);
|
|
246699
|
+
const rec2 = email2 ? await store.getVerificationCode(key2) : null;
|
|
246363
246700
|
if (!rec2) return "invalid";
|
|
246364
246701
|
if (Date.parse(rec2.expiresAt) <= now()) {
|
|
246365
|
-
await store.deleteVerificationCode(
|
|
246702
|
+
await store.deleteVerificationCode(key2);
|
|
246366
246703
|
return "expired";
|
|
246367
246704
|
}
|
|
246368
|
-
if (rec2.attempts >= maxAttempts) return "
|
|
246705
|
+
if (rec2.attempts >= maxAttempts) return "locked";
|
|
246369
246706
|
if (!code2 || !safeEqualHash(rec2.codeHash, hashCode(code2, jwtSecret))) {
|
|
246370
|
-
await store.incrementCodeAttempts(
|
|
246707
|
+
await store.incrementCodeAttempts(key2);
|
|
246371
246708
|
return "invalid";
|
|
246372
246709
|
}
|
|
246373
|
-
await store.deleteVerificationCode(
|
|
246710
|
+
await store.deleteVerificationCode(key2);
|
|
246374
246711
|
return "ok";
|
|
246375
246712
|
};
|
|
246376
246713
|
const currentAccount = async (headers) => {
|
|
@@ -246388,6 +246725,15 @@ function createAuth(opts) {
|
|
|
246388
246725
|
async sessionAccountId(headers) {
|
|
246389
246726
|
return (await currentAccount(headers))?.id ?? null;
|
|
246390
246727
|
},
|
|
246728
|
+
async verifyAccountDeletionTicket(accountId, ticket) {
|
|
246729
|
+
if (!ticket) return false;
|
|
246730
|
+
const claims = verifySession(ticket, deletionTicketSecret, now());
|
|
246731
|
+
if (!claims || claims.sub !== accountId) return false;
|
|
246732
|
+
const sec = await store.getAccountSecret(accountId);
|
|
246733
|
+
if (!sec || sec.tokenVersion !== claims.tokenVersion) return false;
|
|
246734
|
+
const account = await store.getAccount(accountId);
|
|
246735
|
+
return Boolean(account && mayHoldSession(account));
|
|
246736
|
+
},
|
|
246391
246737
|
async handle(method, pathname, rawBody, headers) {
|
|
246392
246738
|
const route2 = pathname.replace(/^\/api\/auth\//, "");
|
|
246393
246739
|
if (method === "GET" && route2 === "me") {
|
|
@@ -246491,6 +246837,59 @@ function createAuth(opts) {
|
|
|
246491
246837
|
await store.setAccountPassword(account.id, hashPassword(password));
|
|
246492
246838
|
return { status: 200, body: { ok: true } };
|
|
246493
246839
|
}
|
|
246840
|
+
if (route2 === "change-password/request-code") {
|
|
246841
|
+
const account = await currentAccount(headers);
|
|
246842
|
+
if (!account) return { status: 401, body: { error: { code: "UNAUTHENTICATED", message: "\u672A\u767B\u5F55" } } };
|
|
246843
|
+
const email2 = account.email.trim().toLowerCase();
|
|
246844
|
+
const { sent, retryAfterMs: retryAfterMs2 } = await sendCodeDetailed(email2, "change-password");
|
|
246845
|
+
return {
|
|
246846
|
+
status: 202,
|
|
246847
|
+
body: { ok: true, maskedEmail: maskEmail(email2), resent: sent, retryAfterSeconds: Math.max(0, Math.ceil(retryAfterMs2 / 1e3)) }
|
|
246848
|
+
};
|
|
246849
|
+
}
|
|
246850
|
+
if (route2 === "change-password") {
|
|
246851
|
+
const account = await currentAccount(headers);
|
|
246852
|
+
if (!account) return { status: 401, body: { error: { code: "UNAUTHENTICATED", message: "\u672A\u767B\u5F55" } } };
|
|
246853
|
+
const code2 = typeof parsed.code === "string" ? parsed.code.trim() : "";
|
|
246854
|
+
const password = typeof parsed.password === "string" ? parsed.password : "";
|
|
246855
|
+
if (!meetsChangePasswordPolicy(password)) {
|
|
246856
|
+
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" } } };
|
|
246857
|
+
}
|
|
246858
|
+
if (!/^\d{6}$/.test(code2)) {
|
|
246859
|
+
return { status: 400, body: { error: { code: "BAD_CODE_FORMAT", message: "\u8BF7\u8F93\u5165 6 \u4F4D\u6570\u5B57\u9A8C\u8BC1\u7801" } } };
|
|
246860
|
+
}
|
|
246861
|
+
const verdict = await verifyEmailCode(account.email.trim().toLowerCase(), code2, "change-password");
|
|
246862
|
+
if (verdict !== "ok") {
|
|
246863
|
+
return { status: 401, body: { error: { code: "INVALID_CODE", message: "\u9A8C\u8BC1\u7801\u5931\u6548\uFF0C\u8BF7\u91CD\u65B0\u83B7\u53D6", reason: verdict } } };
|
|
246864
|
+
}
|
|
246865
|
+
await store.setAccountPassword(account.id, hashPassword(password));
|
|
246866
|
+
return { status: 200, body: { ok: true } };
|
|
246867
|
+
}
|
|
246868
|
+
if (route2 === "account-deletion/request-code") {
|
|
246869
|
+
const account = await currentAccount(headers);
|
|
246870
|
+
if (!account) return { status: 401, body: { error: { code: "UNAUTHENTICATED", message: "\u672A\u767B\u5F55" } } };
|
|
246871
|
+
const email2 = account.email.trim().toLowerCase();
|
|
246872
|
+
const sent = await sendCode(email2, "account-deletion");
|
|
246873
|
+
return { status: 202, body: { ok: true, maskedEmail: maskEmail(email2), resent: sent } };
|
|
246874
|
+
}
|
|
246875
|
+
if (route2 === "account-deletion/verify-code") {
|
|
246876
|
+
const account = await currentAccount(headers);
|
|
246877
|
+
if (!account) return { status: 401, body: { error: { code: "UNAUTHENTICATED", message: "\u672A\u767B\u5F55" } } };
|
|
246878
|
+
const code2 = typeof parsed.code === "string" ? parsed.code.trim() : "";
|
|
246879
|
+
if (!/^\d{6}$/.test(code2)) {
|
|
246880
|
+
return { status: 400, body: { error: { code: "BAD_CODE_FORMAT", message: "\u8BF7\u8F93\u5165 6 \u4F4D\u6570\u5B57\u9A8C\u8BC1\u7801" } } };
|
|
246881
|
+
}
|
|
246882
|
+
const verdict = await verifyEmailCode(account.email.trim().toLowerCase(), code2, "account-deletion");
|
|
246883
|
+
if (verdict !== "ok") {
|
|
246884
|
+
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";
|
|
246885
|
+
return { status: 401, body: { error: { code: "INVALID_CODE", message, reason: verdict } } };
|
|
246886
|
+
}
|
|
246887
|
+
const sec = await store.getAccountSecret(account.id);
|
|
246888
|
+
const t = now();
|
|
246889
|
+
const exp = t + deletionTicketTtlMs;
|
|
246890
|
+
const ticket = signSession({ sub: account.id, tokenVersion: sec?.tokenVersion ?? 0, iat: t, exp }, deletionTicketSecret);
|
|
246891
|
+
return { status: 200, body: { ticket, expiresAt: new Date(exp).toISOString() } };
|
|
246892
|
+
}
|
|
246494
246893
|
if (route2 === "logout") {
|
|
246495
246894
|
return { status: 200, body: { ok: true }, setCookie: clearCookie() };
|
|
246496
246895
|
}
|
|
@@ -246515,8 +246914,8 @@ var init_auth = __esm({
|
|
|
246515
246914
|
// ../server/src/auth/sender.ts
|
|
246516
246915
|
function consoleSender() {
|
|
246517
246916
|
return {
|
|
246518
|
-
async sendCode(email2, code2) {
|
|
246519
|
-
console.log(`[auth] \u9A8C\u8BC1\u7801 \u2192 ${email2}: ${code2}`);
|
|
246917
|
+
async sendCode(email2, code2, purpose) {
|
|
246918
|
+
console.log(`[auth] ${purpose && purpose !== "login" ? CODE_PURPOSE_LABEL[purpose] : "\u9A8C\u8BC1\u7801"} \u2192 ${email2}: ${code2}`);
|
|
246520
246919
|
},
|
|
246521
246920
|
async sendInvitation(email2, opts) {
|
|
246522
246921
|
console.log(
|
|
@@ -246528,15 +246927,17 @@ function consoleSender() {
|
|
|
246528
246927
|
function resendSender(opts) {
|
|
246529
246928
|
const doFetch = opts.fetchImpl ?? fetch;
|
|
246530
246929
|
return {
|
|
246531
|
-
async sendCode(email2, code2) {
|
|
246930
|
+
async sendCode(email2, code2, purpose) {
|
|
246931
|
+
const deletion = purpose === "account-deletion";
|
|
246932
|
+
const label2 = CODE_PURPOSE_LABEL[purpose ?? "login"];
|
|
246532
246933
|
const res = await doFetch("https://api.resend.com/emails", {
|
|
246533
246934
|
method: "POST",
|
|
246534
246935
|
headers: { authorization: `Bearer ${opts.apiKey}`, "content-type": "application/json" },
|
|
246535
246936
|
body: JSON.stringify({
|
|
246536
246937
|
from: opts.from,
|
|
246537
246938
|
to: [email2],
|
|
246538
|
-
subject:
|
|
246539
|
-
html: `<div style="font-family:sans-serif;max-width:400px;margin:0 auto"><h2
|
|
246939
|
+
subject: `\u4F60\u7684 Oasis ${label2}`,
|
|
246940
|
+
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>`)
|
|
246540
246941
|
})
|
|
246541
246942
|
});
|
|
246542
246943
|
if (!res.ok) {
|
|
@@ -246563,9 +246964,15 @@ function resendSender(opts) {
|
|
|
246563
246964
|
}
|
|
246564
246965
|
};
|
|
246565
246966
|
}
|
|
246967
|
+
var CODE_PURPOSE_LABEL;
|
|
246566
246968
|
var init_sender = __esm({
|
|
246567
246969
|
"../server/src/auth/sender.ts"() {
|
|
246568
246970
|
"use strict";
|
|
246971
|
+
CODE_PURPOSE_LABEL = {
|
|
246972
|
+
login: "\u767B\u5F55\u9A8C\u8BC1\u7801",
|
|
246973
|
+
"account-deletion": "\u6CE8\u9500\u8D26\u53F7\u9A8C\u8BC1\u7801",
|
|
246974
|
+
"change-password": "\u4FEE\u6539\u5BC6\u7801\u9A8C\u8BC1\u7801"
|
|
246975
|
+
};
|
|
246569
246976
|
}
|
|
246570
246977
|
});
|
|
246571
246978
|
|
|
@@ -246611,9 +247018,15 @@ function faultAfterFailure(previous3, input, now) {
|
|
|
246611
247018
|
}
|
|
246612
247019
|
return { ...base, nextProbeAt: new Date(now + probeIntervalMs(attempts)).toISOString() };
|
|
246613
247020
|
}
|
|
246614
|
-
function quotaClearsFault(fault,
|
|
247021
|
+
function quotaClearsFault(fault, quota, now = Date.now()) {
|
|
246615
247022
|
if (RUNTIME_FAULT_RECOVERY[fault.reason] !== "readonly-probe") return false;
|
|
246616
|
-
|
|
247023
|
+
if (quota?.status !== "ok") return false;
|
|
247024
|
+
const exhaustedUntilFuture = quota.windows.some((w2) => {
|
|
247025
|
+
if (w2.usedPercent < 100 || !w2.resetsAt) return false;
|
|
247026
|
+
const resetsAt = Date.parse(w2.resetsAt);
|
|
247027
|
+
return Number.isFinite(resetsAt) && resetsAt > now;
|
|
247028
|
+
});
|
|
247029
|
+
return exhaustedUntilFuture || fault.awaitingManual;
|
|
246617
247030
|
}
|
|
246618
247031
|
function describeFault(fault, now) {
|
|
246619
247032
|
const head = `${fault.nodeId} \xB7 ${fault.runtimeKind} \u6545\u969C\uFF08${fault.reason}${fault.detail ? `\uFF1A${fault.detail}` : ""}\uFF09`;
|
|
@@ -247645,7 +248058,7 @@ function nodesDomain(deps) {
|
|
|
247645
248058
|
void (async () => {
|
|
247646
248059
|
for (const q2 of quotas) {
|
|
247647
248060
|
const existing = faultByTarget.get(faultKey(daemonId, q2.kind));
|
|
247648
|
-
if (!existing || !quotaClearsFault(existing, q2
|
|
248061
|
+
if (!existing || !quotaClearsFault(existing, q2)) continue;
|
|
247649
248062
|
await nodeStore.clearRuntimeFault(daemonId, q2.kind);
|
|
247650
248063
|
faultByTarget.delete(faultKey(daemonId, q2.kind));
|
|
247651
248064
|
console.log(`[nodes] \u53EA\u8BFB\u91C7\u96C6\u56DE ok\uFF0C\u81EA\u52A8\u89E3\u9664\u6545\u969C\uFF1A${daemonId} \xB7 ${q2.kind}\uFF08\u539F\u56E0 ${existing.reason}\uFF09`);
|
|
@@ -248405,13 +248818,20 @@ function atCapacity(node2) {
|
|
|
248405
248818
|
if (limit === null || limit === void 0) return false;
|
|
248406
248819
|
return node2.activeRunCount >= limit;
|
|
248407
248820
|
}
|
|
248408
|
-
function quotaDerateFactor(quota) {
|
|
248409
|
-
if (!quota || quota.status !== "ok"
|
|
248410
|
-
const
|
|
248821
|
+
function quotaDerateFactor(quota, now = Date.now()) {
|
|
248822
|
+
if (!quota || quota.status !== "ok") return { factor: 1 };
|
|
248823
|
+
const windows = quota.windows.filter((w2) => windowStillCurrent(w2, now));
|
|
248824
|
+
if (windows.length === 0) return { factor: 1 };
|
|
248825
|
+
const worst = Math.max(...windows.map((w2) => w2.usedPercent));
|
|
248411
248826
|
if (worst <= RUNTIME_QUOTA_DERATE_THRESHOLD_PERCENT) return { factor: 1, worstUsedPercent: worst };
|
|
248412
248827
|
const remaining = Math.max(0, 100 - worst);
|
|
248413
248828
|
return { factor: remaining / (100 - RUNTIME_QUOTA_DERATE_THRESHOLD_PERCENT), worstUsedPercent: worst };
|
|
248414
248829
|
}
|
|
248830
|
+
function windowStillCurrent(window3, now) {
|
|
248831
|
+
if (!window3.resetsAt) return true;
|
|
248832
|
+
const resetsAt = Date.parse(window3.resetsAt);
|
|
248833
|
+
return !Number.isFinite(resetsAt) || resetsAt > now;
|
|
248834
|
+
}
|
|
248415
248835
|
function faultFromQuota(target, quota, now) {
|
|
248416
248836
|
if (!quota) return null;
|
|
248417
248837
|
const base = { nodeId: target.nodeId, runtimeKind: target.runtimeKind, markedAt: quota.checkedAt, attempts: 0 };
|
|
@@ -248419,7 +248839,7 @@ function faultFromQuota(target, quota, now) {
|
|
|
248419
248839
|
return { ...base, reason: "unauthenticated", awaitingManual: true, detail: "\u8FD0\u884C\u65F6\u767B\u5F55\u5DF2\u5931\u6548\uFF0C\u9700\u8981\u5728\u8BE5\u673A\u5668\u4E0A\u91CD\u65B0\u767B\u5F55" };
|
|
248420
248840
|
}
|
|
248421
248841
|
if (quota.status !== "ok") return null;
|
|
248422
|
-
const exhausted = quota.windows.filter((w2) => w2.usedPercent >= 100);
|
|
248842
|
+
const exhausted = quota.windows.filter((w2) => w2.usedPercent >= 100 && windowStillCurrent(w2, now));
|
|
248423
248843
|
if (exhausted.length === 0) return null;
|
|
248424
248844
|
const resets = exhausted.map((w2) => w2.resetsAt).filter((v2) => Boolean(v2)).sort();
|
|
248425
248845
|
const latest = resets.at(-1);
|
|
@@ -248503,7 +248923,7 @@ function allocateRuntime(input, now = Date.now()) {
|
|
|
248503
248923
|
const rank = (candidate) => {
|
|
248504
248924
|
const node2 = input.nodes.get(candidate.nodeId);
|
|
248505
248925
|
const idleness = idlenessOf(node2);
|
|
248506
|
-
const { factor, worstUsedPercent } = quotaDerateFactor(input.quotas?.get(runtimeTargetKey(candidate)));
|
|
248926
|
+
const { factor, worstUsedPercent } = quotaDerateFactor(input.quotas?.get(runtimeTargetKey(candidate)), now);
|
|
248507
248927
|
return {
|
|
248508
248928
|
candidate,
|
|
248509
248929
|
nodeName: node2.displayName?.trim() || candidate.nodeId,
|
|
@@ -248748,6 +249168,7 @@ function createRuntimeAllocator(ports) {
|
|
|
248748
249168
|
}, now);
|
|
248749
249169
|
await ports.saveFault(fault);
|
|
248750
249170
|
log3(`[runtime-alloc] ${describeFault(fault, now)}`);
|
|
249171
|
+
if (reason === "quota-exhausted" && !previous3) ports.onQuotaExhausted?.(target);
|
|
248751
249172
|
return { chained, fault };
|
|
248752
249173
|
} catch (err) {
|
|
248753
249174
|
log3(`[runtime-alloc] \u6545\u969C\u843D\u5E93\u5931\u8D25\uFF08\u6362\u5019\u9009\u7167\u5E38\uFF09${target.nodeId}\xB7${target.runtimeKind}\uFF1A${String(err)}`);
|
|
@@ -249848,7 +250269,7 @@ var init_notification_reconciler = __esm({
|
|
|
249848
250269
|
if (!store) return 0;
|
|
249849
250270
|
const members = new Set(ctx.humans);
|
|
249850
250271
|
const titleOf = workspaceTitleMap(model);
|
|
249851
|
-
const fresh = (
|
|
250272
|
+
const fresh = (iso9) => nowMs - Date.parse(iso9) <= TASK_NOTICE_FRESH_MS;
|
|
249852
250273
|
let sent = 0;
|
|
249853
250274
|
const emit = async (workorderId, kind, rec2, trigger) => {
|
|
249854
250275
|
const recipients = taskNoticeRecipients(model, workorderId, await loadSnapshot2(workorderId), members, trigger);
|
|
@@ -250070,6 +250491,7 @@ function pushThrottleOptionsFromEnv(env = process.env) {
|
|
|
250070
250491
|
};
|
|
250071
250492
|
}
|
|
250072
250493
|
function shouldPush(record10) {
|
|
250494
|
+
if (record10.category === "todo") return !record10.readAt;
|
|
250073
250495
|
if (record10.category !== "action") return false;
|
|
250074
250496
|
if (record10.readAt) return false;
|
|
250075
250497
|
return record10.status === "pending";
|
|
@@ -250385,7 +250807,7 @@ var init_push_notifier = __esm({
|
|
|
250385
250807
|
function makeSeededWorkorderCreator(deps) {
|
|
250386
250808
|
const locks = createKeyedMutex();
|
|
250387
250809
|
const genWorkspace = deps.genWorkspace ?? (() => `ws:wo-${(0, import_node_crypto66.randomUUID)().slice(0, 8)}`);
|
|
250388
|
-
const
|
|
250810
|
+
const create2 = async (input) => {
|
|
250389
250811
|
const company = input.companyId && deps.resolveCompany ? await deps.resolveCompany(input.companyId) : void 0;
|
|
250390
250812
|
const kernel = company?.kernel ?? deps.kernel;
|
|
250391
250813
|
const blobs = company?.blobs ?? deps.blobs;
|
|
@@ -250473,7 +250895,7 @@ function makeSeededWorkorderCreator(deps) {
|
|
|
250473
250895
|
return async (input) => {
|
|
250474
250896
|
const release = await locks.acquire(`${input.companyId ?? ""}\0${input.idempotencyKey ?? (0, import_node_crypto66.randomUUID)()}`);
|
|
250475
250897
|
try {
|
|
250476
|
-
return await
|
|
250898
|
+
return await create2(input);
|
|
250477
250899
|
} finally {
|
|
250478
250900
|
release();
|
|
250479
250901
|
}
|
|
@@ -254690,6 +255112,496 @@ var init_agent_default_runtime_store = __esm({
|
|
|
254690
255112
|
}
|
|
254691
255113
|
});
|
|
254692
255114
|
|
|
255115
|
+
// ../server/src/domains/todos/flag.ts
|
|
255116
|
+
function personalTodoEnabledFromEnv(env = process.env) {
|
|
255117
|
+
const raw = (env["OASIS_PERSONAL_TODO"] ?? "").trim().toLowerCase();
|
|
255118
|
+
return !(raw === "off" || raw === "0" || raw === "false");
|
|
255119
|
+
}
|
|
255120
|
+
var init_flag = __esm({
|
|
255121
|
+
"../server/src/domains/todos/flag.ts"() {
|
|
255122
|
+
"use strict";
|
|
255123
|
+
}
|
|
255124
|
+
});
|
|
255125
|
+
|
|
255126
|
+
// ../server/src/domains/todos/service.ts
|
|
255127
|
+
function assertFirstVersionAssignee(creator, assignee) {
|
|
255128
|
+
if (creator !== assignee) {
|
|
255129
|
+
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");
|
|
255130
|
+
}
|
|
255131
|
+
}
|
|
255132
|
+
function canAccessTodo(todo, caller) {
|
|
255133
|
+
return isTodoParty(todo, caller.principal);
|
|
255134
|
+
}
|
|
255135
|
+
function newTodoId() {
|
|
255136
|
+
return `td_${(0, import_node_crypto69.randomBytes)(4).toString("hex")}`;
|
|
255137
|
+
}
|
|
255138
|
+
function assertDay(day, what = "\u622A\u6B62\u65E5") {
|
|
255139
|
+
if (typeof day !== "string" || !isValidDay(day)) {
|
|
255140
|
+
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)}`);
|
|
255141
|
+
}
|
|
255142
|
+
}
|
|
255143
|
+
function assertTime(time3, what = "\u622A\u6B62\u65F6\u523B") {
|
|
255144
|
+
if (typeof time3 !== "string" || !isValidTodoTime(time3)) {
|
|
255145
|
+
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)}`);
|
|
255146
|
+
}
|
|
255147
|
+
}
|
|
255148
|
+
function assertStartBeforeDue(t) {
|
|
255149
|
+
if (!isTodoStartBeforeDue(t)) {
|
|
255150
|
+
const fmt = (d, h) => `${d}${h ? ` ${h}` : ""}`;
|
|
255151
|
+
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`);
|
|
255152
|
+
}
|
|
255153
|
+
}
|
|
255154
|
+
var import_node_crypto69, TITLE_MAX, NOTE_MAX, REASON_MAX, clean2, TodoService;
|
|
255155
|
+
var init_service10 = __esm({
|
|
255156
|
+
"../server/src/domains/todos/service.ts"() {
|
|
255157
|
+
"use strict";
|
|
255158
|
+
import_node_crypto69 = require("node:crypto");
|
|
255159
|
+
init_src();
|
|
255160
|
+
init_router();
|
|
255161
|
+
TITLE_MAX = 200;
|
|
255162
|
+
NOTE_MAX = 4e3;
|
|
255163
|
+
REASON_MAX = 500;
|
|
255164
|
+
clean2 = (v2) => {
|
|
255165
|
+
const t = v2?.trim();
|
|
255166
|
+
return t ? t : void 0;
|
|
255167
|
+
};
|
|
255168
|
+
TodoService = class {
|
|
255169
|
+
constructor(deps) {
|
|
255170
|
+
this.deps = deps;
|
|
255171
|
+
}
|
|
255172
|
+
nowMs() {
|
|
255173
|
+
return this.deps.now?.() ?? Date.now();
|
|
255174
|
+
}
|
|
255175
|
+
async today() {
|
|
255176
|
+
return todoToday(await this.deps.timeZone(), this.nowMs());
|
|
255177
|
+
}
|
|
255178
|
+
async respond(todo) {
|
|
255179
|
+
const today = await this.today();
|
|
255180
|
+
return { today, todayLine: formatTodayLine(today), todo };
|
|
255181
|
+
}
|
|
255182
|
+
change(todoId, caller, at2, field, oldValue, newValue, reason) {
|
|
255183
|
+
return {
|
|
255184
|
+
id: `tdc_${(0, import_node_crypto69.randomUUID)()}`,
|
|
255185
|
+
todoId,
|
|
255186
|
+
actorId: caller.principal,
|
|
255187
|
+
at: at2,
|
|
255188
|
+
field,
|
|
255189
|
+
...caller.hand ? { handActorId: caller.hand } : {},
|
|
255190
|
+
...oldValue !== void 0 ? { oldValue } : {},
|
|
255191
|
+
...newValue !== void 0 ? { newValue } : {},
|
|
255192
|
+
...reason ? { reason } : {}
|
|
255193
|
+
};
|
|
255194
|
+
}
|
|
255195
|
+
async create(caller, input) {
|
|
255196
|
+
const title = clean2(input.title);
|
|
255197
|
+
if (!title) throw new ApiError(400, "TODO_INVALID", "title \u4E0D\u80FD\u4E3A\u7A7A");
|
|
255198
|
+
if (title.length > TITLE_MAX) throw new ApiError(400, "TODO_INVALID", `title \u4E0D\u80FD\u8D85\u8FC7 ${TITLE_MAX} \u5B57`);
|
|
255199
|
+
const note = clean2(input.note);
|
|
255200
|
+
if (note && note.length > NOTE_MAX) throw new ApiError(400, "TODO_INVALID", `note \u4E0D\u80FD\u8D85\u8FC7 ${NOTE_MAX} \u5B57`);
|
|
255201
|
+
assertDay(input.dueDate);
|
|
255202
|
+
if (input.dueTime !== void 0) assertTime(input.dueTime);
|
|
255203
|
+
if (input.startDate !== void 0) assertDay(input.startDate, "\u5F00\u59CB\u65E5");
|
|
255204
|
+
if (input.startTime !== void 0) {
|
|
255205
|
+
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");
|
|
255206
|
+
assertTime(input.startTime, "\u5F00\u59CB\u65F6\u523B");
|
|
255207
|
+
}
|
|
255208
|
+
assertStartBeforeDue({ ...input });
|
|
255209
|
+
const creator = caller.principal;
|
|
255210
|
+
const assignee = caller.principal;
|
|
255211
|
+
assertFirstVersionAssignee(creator, assignee);
|
|
255212
|
+
const at2 = new Date(this.nowMs()).toISOString();
|
|
255213
|
+
const todo = {
|
|
255214
|
+
id: newTodoId(),
|
|
255215
|
+
title,
|
|
255216
|
+
...note ? { note } : {},
|
|
255217
|
+
creatorActorId: creator,
|
|
255218
|
+
assigneeActorId: assignee,
|
|
255219
|
+
recordedByActorId: caller.actor,
|
|
255220
|
+
dueDate: input.dueDate,
|
|
255221
|
+
...input.dueTime ? { dueTime: input.dueTime } : {},
|
|
255222
|
+
...input.startDate ? { startDate: input.startDate } : {},
|
|
255223
|
+
...input.startTime ? { startTime: input.startTime } : {},
|
|
255224
|
+
status: "open",
|
|
255225
|
+
...clean2(input.sourceChatSessionId) ? { sourceChatSessionId: clean2(input.sourceChatSessionId) } : {},
|
|
255226
|
+
createdAt: at2,
|
|
255227
|
+
updatedAt: at2
|
|
255228
|
+
};
|
|
255229
|
+
const saved = await this.deps.store.create(todo, [this.change(todo.id, caller, at2, "created", void 0, title)]);
|
|
255230
|
+
return this.respond(saved);
|
|
255231
|
+
}
|
|
255232
|
+
async list(caller, opts = {}) {
|
|
255233
|
+
const statuses2 = opts.all ? ["open", "done", "cancelled"] : ["open"];
|
|
255234
|
+
const items = (await this.deps.store.listInvolving(caller.principal, statuses2)).filter((t) => canAccessTodo(t, caller));
|
|
255235
|
+
const today = await this.today();
|
|
255236
|
+
return { today, todayLine: formatTodayLine(today), items };
|
|
255237
|
+
}
|
|
255238
|
+
/** 读一条并校验权限:不存在与无权限分开报(无权限 403——任务书口径「其他人 403」)。 */
|
|
255239
|
+
async get(caller, id) {
|
|
255240
|
+
const todo = await this.deps.store.get(id);
|
|
255241
|
+
if (!todo) throw new ApiError(404, "TODO_NOT_FOUND", `\u5F85\u529E ${id} \u4E0D\u5B58\u5728`);
|
|
255242
|
+
if (!canAccessTodo(todo, caller)) throw new ApiError(403, "TODO_FORBIDDEN", "\u65E0\u6743\u67E5\u770B\u6216\u4FEE\u6539\u8FD9\u6761\u5F85\u529E");
|
|
255243
|
+
return todo;
|
|
255244
|
+
}
|
|
255245
|
+
async save(caller, before, next, changes) {
|
|
255246
|
+
if (changes.length === 0) return this.respond(before);
|
|
255247
|
+
const saved = await this.deps.store.update(next, before.updatedAt, changes);
|
|
255248
|
+
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");
|
|
255249
|
+
return this.respond(saved);
|
|
255250
|
+
}
|
|
255251
|
+
async edit(caller, id, input) {
|
|
255252
|
+
const before = await this.get(caller, id);
|
|
255253
|
+
const reason = clean2(input.reason);
|
|
255254
|
+
if (reason && reason.length > REASON_MAX) throw new ApiError(400, "TODO_INVALID", `reason \u4E0D\u80FD\u8D85\u8FC7 ${REASON_MAX} \u5B57`);
|
|
255255
|
+
const at2 = new Date(this.nowMs()).toISOString();
|
|
255256
|
+
const next = { ...before };
|
|
255257
|
+
const changes = [];
|
|
255258
|
+
const set = (field, value2) => {
|
|
255259
|
+
const old = before[field];
|
|
255260
|
+
if (old === value2) return;
|
|
255261
|
+
if (value2 === void 0) delete next[field];
|
|
255262
|
+
else next[field] = value2;
|
|
255263
|
+
changes.push(this.change(id, caller, at2, field, old, value2, reason));
|
|
255264
|
+
};
|
|
255265
|
+
if (input.title !== void 0) {
|
|
255266
|
+
const title = clean2(input.title);
|
|
255267
|
+
if (!title) throw new ApiError(400, "TODO_INVALID", "title \u4E0D\u80FD\u6E05\u7A7A");
|
|
255268
|
+
if (title.length > TITLE_MAX) throw new ApiError(400, "TODO_INVALID", `title \u4E0D\u80FD\u8D85\u8FC7 ${TITLE_MAX} \u5B57`);
|
|
255269
|
+
set("title", title);
|
|
255270
|
+
}
|
|
255271
|
+
if (input.note !== void 0) {
|
|
255272
|
+
const note = clean2(input.note);
|
|
255273
|
+
if (note && note.length > NOTE_MAX) throw new ApiError(400, "TODO_INVALID", `note \u4E0D\u80FD\u8D85\u8FC7 ${NOTE_MAX} \u5B57`);
|
|
255274
|
+
set("note", note);
|
|
255275
|
+
}
|
|
255276
|
+
if (input.startDate !== void 0) {
|
|
255277
|
+
if (input.startDate === null) {
|
|
255278
|
+
set("startDate", void 0);
|
|
255279
|
+
if (input.startTime === void 0) set("startTime", void 0);
|
|
255280
|
+
} else {
|
|
255281
|
+
assertDay(input.startDate, "\u5F00\u59CB\u65E5");
|
|
255282
|
+
set("startDate", input.startDate);
|
|
255283
|
+
}
|
|
255284
|
+
}
|
|
255285
|
+
if (input.startTime !== void 0) {
|
|
255286
|
+
if (input.startTime !== null) assertTime(input.startTime, "\u5F00\u59CB\u65F6\u523B");
|
|
255287
|
+
set("startTime", input.startTime ?? void 0);
|
|
255288
|
+
}
|
|
255289
|
+
if (input.dueDate !== void 0) {
|
|
255290
|
+
assertDay(input.dueDate);
|
|
255291
|
+
set("dueDate", input.dueDate);
|
|
255292
|
+
}
|
|
255293
|
+
if (input.dueTime !== void 0) {
|
|
255294
|
+
if (input.dueTime !== null) assertTime(input.dueTime);
|
|
255295
|
+
set("dueTime", input.dueTime ?? void 0);
|
|
255296
|
+
}
|
|
255297
|
+
if (input.linkedWorkorderId !== void 0) set("linkedWorkorderId", clean2(input.linkedWorkorderId));
|
|
255298
|
+
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");
|
|
255299
|
+
assertStartBeforeDue(next);
|
|
255300
|
+
if (changes.length > 0) {
|
|
255301
|
+
next.updatedAt = at2;
|
|
255302
|
+
next.recordedByActorId = caller.actor;
|
|
255303
|
+
}
|
|
255304
|
+
return this.save(caller, before, next, changes);
|
|
255305
|
+
}
|
|
255306
|
+
async setStatus(caller, id, status, reason) {
|
|
255307
|
+
const before = await this.get(caller, id);
|
|
255308
|
+
const why = clean2(reason);
|
|
255309
|
+
if (why && why.length > REASON_MAX) throw new ApiError(400, "TODO_INVALID", `reason \u4E0D\u80FD\u8D85\u8FC7 ${REASON_MAX} \u5B57`);
|
|
255310
|
+
if (before.status === status) return this.respond(before);
|
|
255311
|
+
const at2 = new Date(this.nowMs()).toISOString();
|
|
255312
|
+
const next = { ...before, status, updatedAt: at2, recordedByActorId: caller.actor };
|
|
255313
|
+
delete next.doneAt;
|
|
255314
|
+
delete next.cancelledAt;
|
|
255315
|
+
if (status === "done") next.doneAt = at2;
|
|
255316
|
+
if (status === "cancelled") next.cancelledAt = at2;
|
|
255317
|
+
return this.save(caller, before, next, [this.change(id, caller, at2, "status", before.status, status, why)]);
|
|
255318
|
+
}
|
|
255319
|
+
history(caller, id) {
|
|
255320
|
+
return this.get(caller, id).then(() => this.deps.store.listChanges(id));
|
|
255321
|
+
}
|
|
255322
|
+
};
|
|
255323
|
+
}
|
|
255324
|
+
});
|
|
255325
|
+
|
|
255326
|
+
// ../server/src/domains/todos/store.ts
|
|
255327
|
+
var import_node_crypto70, import_promises15, import_node_path25, MemoryTodoStore;
|
|
255328
|
+
var init_store3 = __esm({
|
|
255329
|
+
"../server/src/domains/todos/store.ts"() {
|
|
255330
|
+
"use strict";
|
|
255331
|
+
import_node_crypto70 = require("node:crypto");
|
|
255332
|
+
import_promises15 = require("node:fs/promises");
|
|
255333
|
+
import_node_path25 = require("node:path");
|
|
255334
|
+
init_src();
|
|
255335
|
+
MemoryTodoStore = class _MemoryTodoStore {
|
|
255336
|
+
constructor(filename) {
|
|
255337
|
+
this.filename = filename;
|
|
255338
|
+
}
|
|
255339
|
+
rows = { todos: {}, changes: [] };
|
|
255340
|
+
tail = Promise.resolve();
|
|
255341
|
+
static async open(filename) {
|
|
255342
|
+
const store = new _MemoryTodoStore(filename);
|
|
255343
|
+
try {
|
|
255344
|
+
store.rows = JSON.parse(await (0, import_promises15.readFile)(filename, "utf8"));
|
|
255345
|
+
} catch (error2) {
|
|
255346
|
+
if (error2.code !== "ENOENT") throw error2;
|
|
255347
|
+
}
|
|
255348
|
+
return store;
|
|
255349
|
+
}
|
|
255350
|
+
write(run) {
|
|
255351
|
+
const pending = this.tail.then(async () => {
|
|
255352
|
+
const next = structuredClone(this.rows);
|
|
255353
|
+
const result = run(next);
|
|
255354
|
+
if (result === null) return null;
|
|
255355
|
+
if (this.filename) {
|
|
255356
|
+
await (0, import_promises15.mkdir)((0, import_node_path25.dirname)(this.filename), { recursive: true });
|
|
255357
|
+
const temp = `${this.filename}.${(0, import_node_crypto70.randomUUID)()}.tmp`;
|
|
255358
|
+
await (0, import_promises15.writeFile)(temp, JSON.stringify(next), "utf8");
|
|
255359
|
+
await (0, import_promises15.rename)(temp, this.filename);
|
|
255360
|
+
}
|
|
255361
|
+
this.rows = next;
|
|
255362
|
+
return structuredClone(result);
|
|
255363
|
+
});
|
|
255364
|
+
this.tail = pending.catch(() => void 0);
|
|
255365
|
+
return pending;
|
|
255366
|
+
}
|
|
255367
|
+
async create(todo, changes) {
|
|
255368
|
+
const saved = await this.write((next) => {
|
|
255369
|
+
if (next.todos[todo.id]) throw new Error(`todo ${todo.id} already exists`);
|
|
255370
|
+
next.todos[todo.id] = structuredClone(todo);
|
|
255371
|
+
next.changes.push(...structuredClone(changes));
|
|
255372
|
+
return todo;
|
|
255373
|
+
});
|
|
255374
|
+
return saved;
|
|
255375
|
+
}
|
|
255376
|
+
async get(id) {
|
|
255377
|
+
await this.tail;
|
|
255378
|
+
return structuredClone(this.rows.todos[id] ?? null);
|
|
255379
|
+
}
|
|
255380
|
+
update(next, expectedUpdatedAt, changes) {
|
|
255381
|
+
return this.write((rows) => {
|
|
255382
|
+
const current = rows.todos[next.id];
|
|
255383
|
+
if (!current || current.updatedAt !== expectedUpdatedAt) return null;
|
|
255384
|
+
rows.todos[next.id] = structuredClone(next);
|
|
255385
|
+
rows.changes.push(...structuredClone(changes));
|
|
255386
|
+
return next;
|
|
255387
|
+
});
|
|
255388
|
+
}
|
|
255389
|
+
async listInvolving(actorId, statuses2) {
|
|
255390
|
+
await this.tail;
|
|
255391
|
+
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));
|
|
255392
|
+
}
|
|
255393
|
+
async listOpenReminderCandidates(fromDay, toDay) {
|
|
255394
|
+
await this.tail;
|
|
255395
|
+
const within = (day) => day !== void 0 && day >= fromDay && day <= toDay;
|
|
255396
|
+
return Object.values(this.rows.todos).filter((t) => t.status === "open" && (within(t.dueDate) || within(t.startDate))).sort(compareTodos).map((t) => structuredClone(t));
|
|
255397
|
+
}
|
|
255398
|
+
async listChanges(todoId) {
|
|
255399
|
+
await this.tail;
|
|
255400
|
+
return this.rows.changes.filter((c) => c.todoId === todoId).map((c) => structuredClone(c));
|
|
255401
|
+
}
|
|
255402
|
+
};
|
|
255403
|
+
}
|
|
255404
|
+
});
|
|
255405
|
+
|
|
255406
|
+
// ../server/src/domains/todos/routes.ts
|
|
255407
|
+
function todosDomain(options) {
|
|
255408
|
+
const wrap = (fn) => async (req) => {
|
|
255409
|
+
if (!options.enabled()) throw new ApiError(404, "NOT_FOUND", "\u4E2A\u4EBA\u5F85\u529E\u672A\u5F00\u542F");
|
|
255410
|
+
try {
|
|
255411
|
+
const service = await options.serviceFor(req.auth.companyId);
|
|
255412
|
+
const caller = await options.resolveCaller(req.auth.actor, req.auth.companyId);
|
|
255413
|
+
return await fn(req, service, caller);
|
|
255414
|
+
} catch (e) {
|
|
255415
|
+
if (e instanceof ZodError) throw new ApiError(400, "TODO_INVALID", e.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; "));
|
|
255416
|
+
throw e;
|
|
255417
|
+
}
|
|
255418
|
+
};
|
|
255419
|
+
const sourceSession = (req, fromBody) => req.auth.dispatch?.chatSessionId ?? fromBody;
|
|
255420
|
+
return (router) => {
|
|
255421
|
+
router.get("/api/todos", wrap(async (req, service, caller) => {
|
|
255422
|
+
const all2 = ["1", "true"].includes((req.query.get("all") ?? "").toLowerCase());
|
|
255423
|
+
return { status: 200, body: await service.list(caller, { all: all2 }) };
|
|
255424
|
+
}));
|
|
255425
|
+
router.post("/api/todos", wrap(async (req, service, caller) => {
|
|
255426
|
+
const body2 = create.parse(req.body ?? {});
|
|
255427
|
+
const sourceChatSessionId = sourceSession(req, body2.sourceChatSessionId);
|
|
255428
|
+
return { status: 201, body: await service.create(caller, { ...body2, ...sourceChatSessionId ? { sourceChatSessionId } : {} }) };
|
|
255429
|
+
}));
|
|
255430
|
+
router.get("/api/todos/:id", wrap(async (req, service, caller) => {
|
|
255431
|
+
const todo = await service.get(caller, req.params.id);
|
|
255432
|
+
return { status: 200, body: { todo, changes: await service.history(caller, todo.id) } };
|
|
255433
|
+
}));
|
|
255434
|
+
router.patch("/api/todos/:id", wrap(async (req, service, caller) => {
|
|
255435
|
+
const body2 = edit.parse(req.body ?? {});
|
|
255436
|
+
return { status: 200, body: await service.edit(caller, req.params.id, body2) };
|
|
255437
|
+
}));
|
|
255438
|
+
const status = (path47, to) => router.post(`/api/todos/:id/${path47}`, wrap(async (req, service, caller) => {
|
|
255439
|
+
const body2 = statusBody.parse(req.body ?? {});
|
|
255440
|
+
return { status: 200, body: await service.setStatus(caller, req.params.id, to, body2.reason) };
|
|
255441
|
+
}));
|
|
255442
|
+
status("done", "done");
|
|
255443
|
+
status("cancel", "cancelled");
|
|
255444
|
+
status("reopen", "open");
|
|
255445
|
+
};
|
|
255446
|
+
}
|
|
255447
|
+
var create, edit, statusBody;
|
|
255448
|
+
var init_routes11 = __esm({
|
|
255449
|
+
"../server/src/domains/todos/routes.ts"() {
|
|
255450
|
+
"use strict";
|
|
255451
|
+
init_zod();
|
|
255452
|
+
init_router();
|
|
255453
|
+
create = external_exports.object({
|
|
255454
|
+
title: external_exports.string(),
|
|
255455
|
+
note: external_exports.string().optional(),
|
|
255456
|
+
dueDate: external_exports.string(),
|
|
255457
|
+
dueTime: external_exports.string().optional(),
|
|
255458
|
+
startDate: external_exports.string().optional(),
|
|
255459
|
+
startTime: external_exports.string().optional(),
|
|
255460
|
+
sourceChatSessionId: external_exports.string().optional()
|
|
255461
|
+
}).strict();
|
|
255462
|
+
edit = external_exports.object({
|
|
255463
|
+
title: external_exports.string().optional(),
|
|
255464
|
+
note: external_exports.string().nullable().optional(),
|
|
255465
|
+
dueDate: external_exports.string().optional(),
|
|
255466
|
+
dueTime: external_exports.string().nullable().optional(),
|
|
255467
|
+
startDate: external_exports.string().nullable().optional(),
|
|
255468
|
+
startTime: external_exports.string().nullable().optional(),
|
|
255469
|
+
linkedWorkorderId: external_exports.string().nullable().optional(),
|
|
255470
|
+
reason: external_exports.string().optional()
|
|
255471
|
+
}).strict();
|
|
255472
|
+
statusBody = external_exports.object({ reason: external_exports.string().optional() }).strict();
|
|
255473
|
+
}
|
|
255474
|
+
});
|
|
255475
|
+
|
|
255476
|
+
// ../server/src/domains/todos/reminders.ts
|
|
255477
|
+
function todoReminderSourceKey(todo, kind) {
|
|
255478
|
+
if (kind === "todo-start") return `todo:${todo.id}@start:${todo.startDate}`;
|
|
255479
|
+
return `todo:${todo.id}@${kind === "todo-due-1d" ? "due-1d" : "due"}:${todo.dueDate}`;
|
|
255480
|
+
}
|
|
255481
|
+
function dueReminders(todo, timeZone, nowMs) {
|
|
255482
|
+
if (todo.status !== "open") return [];
|
|
255483
|
+
const created = Date.parse(todo.createdAt);
|
|
255484
|
+
const dayBefore = zonedDateTimeToUtcMs(shiftDay(todo.dueDate, -1), TODO_REMINDER_TIME, timeZone);
|
|
255485
|
+
const onDay = zonedDateTimeToUtcMs(todo.dueDate, TODO_REMINDER_TIME, timeZone);
|
|
255486
|
+
const dayEnd = zonedStartOfDayMs(shiftDay(todo.dueDate, 1), timeZone);
|
|
255487
|
+
const out = [];
|
|
255488
|
+
if (nowMs >= dayBefore && nowMs < onDay && created <= dayBefore) {
|
|
255489
|
+
out.push({ kind: "todo-due-1d", sourceKey: todoReminderSourceKey(todo, "todo-due-1d"), fireAt: dayBefore });
|
|
255490
|
+
}
|
|
255491
|
+
if (nowMs >= onDay && nowMs < dayEnd && created <= onDay) {
|
|
255492
|
+
out.push({ kind: "todo-due", sourceKey: todoReminderSourceKey(todo, "todo-due"), fireAt: onDay });
|
|
255493
|
+
}
|
|
255494
|
+
if (todo.startDate && todo.startDate !== todo.dueDate) {
|
|
255495
|
+
const startAt = zonedDateTimeToUtcMs(todo.startDate, TODO_REMINDER_TIME, timeZone);
|
|
255496
|
+
const startEnd = zonedStartOfDayMs(shiftDay(todo.startDate, 1), timeZone);
|
|
255497
|
+
if (nowMs >= startAt && nowMs < startEnd && created <= startAt) {
|
|
255498
|
+
out.push({ kind: "todo-start", sourceKey: todoReminderSourceKey(todo, "todo-start"), fireAt: startAt });
|
|
255499
|
+
}
|
|
255500
|
+
}
|
|
255501
|
+
return out;
|
|
255502
|
+
}
|
|
255503
|
+
var TODO_REMINDER_TIME, TODO_REMINDER_SCAN_MS, TODO_REMINDER_TITLE, TodoReminderScanner;
|
|
255504
|
+
var init_reminders = __esm({
|
|
255505
|
+
"../server/src/domains/todos/reminders.ts"() {
|
|
255506
|
+
"use strict";
|
|
255507
|
+
init_src();
|
|
255508
|
+
TODO_REMINDER_TIME = "09:00";
|
|
255509
|
+
TODO_REMINDER_SCAN_MS = 6e4;
|
|
255510
|
+
TODO_REMINDER_TITLE = {
|
|
255511
|
+
"todo-due-1d": (title) => `\u5F85\u529E\u660E\u5929\u5230\u671F\uFF1A${title}`,
|
|
255512
|
+
"todo-due": (title) => `\u5F85\u529E\u4ECA\u5929\u5230\u671F\uFF1A${title}`,
|
|
255513
|
+
"todo-start": (title) => `\u5F85\u529E\u4ECA\u5929\u5F00\u59CB\uFF1A${title}`
|
|
255514
|
+
};
|
|
255515
|
+
TodoReminderScanner = class {
|
|
255516
|
+
constructor(deps) {
|
|
255517
|
+
this.deps = deps;
|
|
255518
|
+
}
|
|
255519
|
+
timer;
|
|
255520
|
+
first;
|
|
255521
|
+
scanning = false;
|
|
255522
|
+
/** 本进程已经确认在台账里的 (公司, 收件人, 来源键):省掉每拍对同一条的重复 insert。重启后靠台账唯一约束兜底。 */
|
|
255523
|
+
seen = /* @__PURE__ */ new Set();
|
|
255524
|
+
/** 扫一遍所有公司。防重入:上一拍没扫完,这一拍直接跳过。返回本拍新写入的条数。 */
|
|
255525
|
+
async sweep() {
|
|
255526
|
+
if (this.scanning || !this.deps.enabled()) return 0;
|
|
255527
|
+
this.scanning = true;
|
|
255528
|
+
let inserted = 0;
|
|
255529
|
+
try {
|
|
255530
|
+
for (const companyId of await this.deps.companies()) {
|
|
255531
|
+
try {
|
|
255532
|
+
inserted += await this.sweepCompany(companyId);
|
|
255533
|
+
} catch (error2) {
|
|
255534
|
+
this.deps.warn(new Error(`\u5F85\u529E\u63D0\u9192 company=${companyId}: ${String(error2)}`));
|
|
255535
|
+
}
|
|
255536
|
+
}
|
|
255537
|
+
} catch (error2) {
|
|
255538
|
+
this.deps.warn(error2);
|
|
255539
|
+
} finally {
|
|
255540
|
+
this.scanning = false;
|
|
255541
|
+
}
|
|
255542
|
+
return inserted;
|
|
255543
|
+
}
|
|
255544
|
+
async sweepCompany(companyId) {
|
|
255545
|
+
const ledger = await this.deps.notifications(companyId);
|
|
255546
|
+
if (!ledger) return 0;
|
|
255547
|
+
const nowMs = this.deps.now?.() ?? Date.now();
|
|
255548
|
+
const timeZone = await this.deps.timeZone(companyId);
|
|
255549
|
+
const today = zonedToday(timeZone, nowMs).date;
|
|
255550
|
+
const candidates = await (await this.deps.todos(companyId)).listOpenReminderCandidates(today, shiftDay(today, 1));
|
|
255551
|
+
const enteredAt = new Date(nowMs).toISOString();
|
|
255552
|
+
const fresh = [];
|
|
255553
|
+
for (const todo of candidates) {
|
|
255554
|
+
for (const r of dueReminders(todo, timeZone, nowMs)) {
|
|
255555
|
+
for (const recipient of todoAssignees(todo)) {
|
|
255556
|
+
const key2 = JSON.stringify([companyId, recipient, r.sourceKey]);
|
|
255557
|
+
if (this.seen.has(key2)) continue;
|
|
255558
|
+
const row = await ledger.insert({
|
|
255559
|
+
recipient,
|
|
255560
|
+
category: "todo",
|
|
255561
|
+
sourceKey: r.sourceKey,
|
|
255562
|
+
kind: r.kind,
|
|
255563
|
+
title: TODO_REMINDER_TITLE[r.kind](todo.title),
|
|
255564
|
+
enteredAt,
|
|
255565
|
+
...todo.sourceChatSessionId ? { chatSessionId: todo.sourceChatSessionId } : {}
|
|
255566
|
+
});
|
|
255567
|
+
this.seen.add(key2);
|
|
255568
|
+
if (row.enteredAt === enteredAt) fresh.push(row);
|
|
255569
|
+
}
|
|
255570
|
+
}
|
|
255571
|
+
}
|
|
255572
|
+
if (fresh.length > 0) this.deps.onInserted?.(companyId, fresh);
|
|
255573
|
+
return fresh.length;
|
|
255574
|
+
}
|
|
255575
|
+
/** 首拍延后一点(默认 10 秒,与通知对账器同款):等 serve 把推送、台账都装好再扫。 */
|
|
255576
|
+
start(intervalMs = TODO_REMINDER_SCAN_MS, firstDelayMs = 1e4) {
|
|
255577
|
+
if (this.timer) return;
|
|
255578
|
+
this.timer = setInterval(() => void this.sweep(), intervalMs);
|
|
255579
|
+
this.timer.unref?.();
|
|
255580
|
+
this.first = setTimeout(() => void this.sweep(), firstDelayMs);
|
|
255581
|
+
this.first.unref?.();
|
|
255582
|
+
}
|
|
255583
|
+
stop() {
|
|
255584
|
+
if (this.timer) clearInterval(this.timer);
|
|
255585
|
+
if (this.first) clearTimeout(this.first);
|
|
255586
|
+
this.timer = void 0;
|
|
255587
|
+
this.first = void 0;
|
|
255588
|
+
}
|
|
255589
|
+
};
|
|
255590
|
+
}
|
|
255591
|
+
});
|
|
255592
|
+
|
|
255593
|
+
// ../server/src/domains/todos/index.ts
|
|
255594
|
+
var init_todos2 = __esm({
|
|
255595
|
+
"../server/src/domains/todos/index.ts"() {
|
|
255596
|
+
"use strict";
|
|
255597
|
+
init_flag();
|
|
255598
|
+
init_service10();
|
|
255599
|
+
init_store3();
|
|
255600
|
+
init_routes11();
|
|
255601
|
+
init_reminders();
|
|
255602
|
+
}
|
|
255603
|
+
});
|
|
255604
|
+
|
|
254693
255605
|
// ../server/src/domains/playbooks/registry.ts
|
|
254694
255606
|
function deriveGraph(structure, filerReviews) {
|
|
254695
255607
|
const idOf = (n) => `${n.type}:${n.title}`;
|
|
@@ -256055,7 +256967,7 @@ function busyError(chatSessionId, blockedBy) {
|
|
|
256055
256967
|
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`;
|
|
256056
256968
|
}
|
|
256057
256969
|
function genWebhookToken() {
|
|
256058
|
-
return `owt_${(0,
|
|
256970
|
+
return `owt_${(0, import_node_crypto71.randomBytes)(32).toString("base64url")}`;
|
|
256059
256971
|
}
|
|
256060
256972
|
function validateTitleTemplate(tpl) {
|
|
256061
256973
|
const residue = tpl.replace(DATE_TOKEN, "");
|
|
@@ -256111,11 +257023,11 @@ function appendSourceNote(brief, automation, source, atIso) {
|
|
|
256111
257023
|
---
|
|
256112
257024
|
\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`;
|
|
256113
257025
|
}
|
|
256114
|
-
var
|
|
256115
|
-
var
|
|
257026
|
+
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;
|
|
257027
|
+
var init_service11 = __esm({
|
|
256116
257028
|
"../server/src/domains/automations/service.ts"() {
|
|
256117
257029
|
"use strict";
|
|
256118
|
-
|
|
257030
|
+
import_node_crypto71 = require("node:crypto");
|
|
256119
257031
|
init_src();
|
|
256120
257032
|
init_registry3();
|
|
256121
257033
|
init_attribution();
|
|
@@ -256929,11 +257841,11 @@ function verifySignature(rawBody, headers, secret) {
|
|
|
256929
257841
|
if (!secret) return "not_required";
|
|
256930
257842
|
const given = header1(headers, "x-hub-signature-256");
|
|
256931
257843
|
if (!given) return "missing";
|
|
256932
|
-
const expected = `sha256=${(0,
|
|
257844
|
+
const expected = `sha256=${(0, import_node_crypto72.createHmac)("sha256", secret).update(rawBody).digest("hex")}`;
|
|
256933
257845
|
const a = Buffer.from(given);
|
|
256934
257846
|
const b2 = Buffer.from(expected);
|
|
256935
257847
|
if (a.length !== b2.length) return "invalid";
|
|
256936
|
-
return (0,
|
|
257848
|
+
return (0, import_node_crypto72.timingSafeEqual)(a, b2) ? "valid" : "invalid";
|
|
256937
257849
|
}
|
|
256938
257850
|
function eventAllowed(filters, envelope) {
|
|
256939
257851
|
if (!filters || filters.length === 0) return true;
|
|
@@ -256963,11 +257875,11 @@ function splitEvent(envelope) {
|
|
|
256963
257875
|
}
|
|
256964
257876
|
return { eventName, actionCandidates: candidates };
|
|
256965
257877
|
}
|
|
256966
|
-
var
|
|
257878
|
+
var import_node_crypto72, MAX_BODY_BYTES, AutomationWebhookService, header1, PROVIDER_PREFIXES;
|
|
256967
257879
|
var init_webhook = __esm({
|
|
256968
257880
|
"../server/src/domains/automations/webhook.ts"() {
|
|
256969
257881
|
"use strict";
|
|
256970
|
-
|
|
257882
|
+
import_node_crypto72 = require("node:crypto");
|
|
256971
257883
|
MAX_BODY_BYTES = 256 * 1024;
|
|
256972
257884
|
AutomationWebhookService = class {
|
|
256973
257885
|
store;
|
|
@@ -257841,13 +258753,13 @@ function automationsDomain(opts) {
|
|
|
257841
258753
|
};
|
|
257842
258754
|
}
|
|
257843
258755
|
var RECENT_LIMIT2, TARGET_ISSUE_MESSAGE;
|
|
257844
|
-
var
|
|
258756
|
+
var init_routes12 = __esm({
|
|
257845
258757
|
"../server/src/domains/automations/routes.ts"() {
|
|
257846
258758
|
"use strict";
|
|
257847
258759
|
init_src();
|
|
257848
258760
|
init_templates();
|
|
257849
258761
|
init_router();
|
|
257850
|
-
|
|
258762
|
+
init_service11();
|
|
257851
258763
|
init_projection2();
|
|
257852
258764
|
init_scheduler();
|
|
257853
258765
|
init_registry3();
|
|
@@ -257962,11 +258874,11 @@ function createAutomationsDomain(opts) {
|
|
|
257962
258874
|
var init_automations = __esm({
|
|
257963
258875
|
"../server/src/domains/automations/index.ts"() {
|
|
257964
258876
|
"use strict";
|
|
257965
|
-
|
|
258877
|
+
init_service11();
|
|
257966
258878
|
init_webhook();
|
|
257967
|
-
|
|
257968
|
-
|
|
257969
|
-
|
|
258879
|
+
init_routes12();
|
|
258880
|
+
init_service11();
|
|
258881
|
+
init_routes12();
|
|
257970
258882
|
init_projection2();
|
|
257971
258883
|
init_webhook();
|
|
257972
258884
|
init_attribution();
|
|
@@ -258119,7 +259031,7 @@ function playbooksDomain(opts) {
|
|
|
258119
259031
|
opts.overrides.set(companyOf(req), ref2, nodeKey, nextOverride);
|
|
258120
259032
|
try {
|
|
258121
259033
|
await opts.audit?.({
|
|
258122
|
-
id: `reg_${(0,
|
|
259034
|
+
id: `reg_${(0, import_node_crypto73.randomUUID)()}`,
|
|
258123
259035
|
actor: req.auth.actor,
|
|
258124
259036
|
kind: "registry_change",
|
|
258125
259037
|
target: `playbook:${ref2}#${nodeKey}`,
|
|
@@ -258136,11 +259048,11 @@ function playbooksDomain(opts) {
|
|
|
258136
259048
|
});
|
|
258137
259049
|
};
|
|
258138
259050
|
}
|
|
258139
|
-
var
|
|
258140
|
-
var
|
|
259051
|
+
var import_node_crypto73;
|
|
259052
|
+
var init_routes13 = __esm({
|
|
258141
259053
|
"../server/src/domains/playbooks/routes.ts"() {
|
|
258142
259054
|
"use strict";
|
|
258143
|
-
|
|
259055
|
+
import_node_crypto73 = require("node:crypto");
|
|
258144
259056
|
init_router();
|
|
258145
259057
|
init_registry3();
|
|
258146
259058
|
init_planner();
|
|
@@ -258159,12 +259071,12 @@ function normalize(patch) {
|
|
|
258159
259071
|
...reviewers !== void 0 ? { reviewers: [...new Set(reviewers.map((r) => r.trim()).filter(Boolean))] } : {}
|
|
258160
259072
|
};
|
|
258161
259073
|
}
|
|
258162
|
-
var import_node_fs22,
|
|
259074
|
+
var import_node_fs22, import_node_path26, SEP3, keyOf2, prefixOf2, MemoryPlaybookOverrideStore, FilePlaybookOverrideStore;
|
|
258163
259075
|
var init_overrides = __esm({
|
|
258164
259076
|
"../server/src/domains/playbooks/overrides.ts"() {
|
|
258165
259077
|
"use strict";
|
|
258166
259078
|
import_node_fs22 = __toESM(require("node:fs"), 1);
|
|
258167
|
-
|
|
259079
|
+
import_node_path26 = __toESM(require("node:path"), 1);
|
|
258168
259080
|
SEP3 = "::";
|
|
258169
259081
|
keyOf2 = (companyId, ref2, nodeKey) => `${companyId}${SEP3}${ref2}${SEP3}${nodeKey}`;
|
|
258170
259082
|
prefixOf2 = (companyId, ref2) => `${companyId}${SEP3}${ref2}${SEP3}`;
|
|
@@ -258220,7 +259132,7 @@ var init_overrides = __esm({
|
|
|
258220
259132
|
}
|
|
258221
259133
|
persist() {
|
|
258222
259134
|
try {
|
|
258223
|
-
import_node_fs22.default.mkdirSync(
|
|
259135
|
+
import_node_fs22.default.mkdirSync(import_node_path26.default.dirname(this.file), { recursive: true });
|
|
258224
259136
|
const tmp = `${this.file}.tmp`;
|
|
258225
259137
|
import_node_fs22.default.writeFileSync(tmp, JSON.stringify(Object.fromEntries(this.map), null, 2));
|
|
258226
259138
|
import_node_fs22.default.renameSync(tmp, this.file);
|
|
@@ -258256,9 +259168,9 @@ function createPlaybooksDomain(opts) {
|
|
|
258256
259168
|
var init_playbooks = __esm({
|
|
258257
259169
|
"../server/src/domains/playbooks/index.ts"() {
|
|
258258
259170
|
"use strict";
|
|
258259
|
-
|
|
259171
|
+
init_routes13();
|
|
258260
259172
|
init_registry3();
|
|
258261
|
-
|
|
259173
|
+
init_routes13();
|
|
258262
259174
|
init_overrides();
|
|
258263
259175
|
}
|
|
258264
259176
|
});
|
|
@@ -258269,17 +259181,17 @@ function completionFingerprint(workspace, members) {
|
|
|
258269
259181
|
workspace,
|
|
258270
259182
|
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 }))
|
|
258271
259183
|
});
|
|
258272
|
-
return (0,
|
|
259184
|
+
return (0, import_node_crypto74.createHash)("sha256").update(canonical2).digest("hex");
|
|
258273
259185
|
}
|
|
258274
259186
|
function eventConsumptionKey(args) {
|
|
258275
259187
|
const raw = `project-event:${EVENT_KEY_VERSION}:${args.triggerId}:${args.event}:${args.workspace}:${args.fingerprint}`;
|
|
258276
|
-
return raw.length <= 200 ? raw : `project-event:${EVENT_KEY_VERSION}:sha256:${(0,
|
|
259188
|
+
return raw.length <= 200 ? raw : `project-event:${EVENT_KEY_VERSION}:sha256:${(0, import_node_crypto74.createHash)("sha256").update(raw).digest("hex")}`;
|
|
258277
259189
|
}
|
|
258278
|
-
var
|
|
259190
|
+
var import_node_crypto74, EVENT_KEY_VERSION, EMPTY_METRICS, AUTOMATION_EVENT_HANDLERS, ProjectEventPoller;
|
|
258279
259191
|
var init_project_event_poller = __esm({
|
|
258280
259192
|
"../server/src/automations/project-event-poller.ts"() {
|
|
258281
259193
|
"use strict";
|
|
258282
|
-
|
|
259194
|
+
import_node_crypto74 = require("node:crypto");
|
|
258283
259195
|
EVENT_KEY_VERSION = "v1";
|
|
258284
259196
|
EMPTY_METRICS = () => ({
|
|
258285
259197
|
scanDurationMs: 0,
|
|
@@ -258489,7 +259401,7 @@ function queryInputReceipt(hub, nodeId, dispatchId, clientMessageKey, pending, t
|
|
|
258489
259401
|
const viaSession = hub.hasSession?.(dispatchId) === true;
|
|
258490
259402
|
const supported = viaSession ? hub.supportsInputReceiptQuery?.(dispatchId) === true : daemonMetaOf(hub, nodeId)?.supportsInputReceiptQuery === true;
|
|
258491
259403
|
if (!supported) return Promise.resolve({ status: "unknown", reason: "unsupported" });
|
|
258492
|
-
const requestId = (0,
|
|
259404
|
+
const requestId = (0, import_node_crypto75.randomUUID)();
|
|
258493
259405
|
return new Promise((resolve11) => {
|
|
258494
259406
|
const timer = setTimeout(() => {
|
|
258495
259407
|
pending.delete(requestId);
|
|
@@ -258551,7 +259463,7 @@ function sendAppendInput(hub, nodeId, dispatchId, entry, input, timeoutMs, sessi
|
|
|
258551
259463
|
if (input.requireConsumptionReceipt && !hub.supportsInputConsumptionReceipts?.(dispatchId)) {
|
|
258552
259464
|
return Promise.resolve({ accepted: false, reason: "consumption-unsupported" });
|
|
258553
259465
|
}
|
|
258554
|
-
const requestId = (0,
|
|
259466
|
+
const requestId = (0, import_node_crypto75.randomUUID)();
|
|
258555
259467
|
const sent = routeToSession(hub, nodeId, dispatchId, { type: "append_input", dispatchId, input, requestId });
|
|
258556
259468
|
if (!sent) return Promise.resolve({ accepted: false, reason: "session-closing", ...unknownIfInterrupting });
|
|
258557
259469
|
return new Promise((resolve11) => {
|
|
@@ -258564,11 +259476,11 @@ function sendAppendInput(hub, nodeId, dispatchId, entry, input, timeoutMs, sessi
|
|
|
258564
259476
|
entry.appendWaiters.push({ requestId, requireConsumptionReceipt: input.requireConsumptionReceipt, resolve: resolve11, timer });
|
|
258565
259477
|
});
|
|
258566
259478
|
}
|
|
258567
|
-
var
|
|
259479
|
+
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;
|
|
258568
259480
|
var init_daemon_adapter = __esm({
|
|
258569
259481
|
"../server/src/daemon-adapter.ts"() {
|
|
258570
259482
|
"use strict";
|
|
258571
|
-
|
|
259483
|
+
import_node_crypto75 = require("node:crypto");
|
|
258572
259484
|
init_src();
|
|
258573
259485
|
STASH_TTL_MS = 5 * 6e4;
|
|
258574
259486
|
STASH_MAX_FRAMES_PER_ID = 1e4;
|
|
@@ -259027,7 +259939,7 @@ var init_daemon_adapter = __esm({
|
|
|
259027
259939
|
async spawn(job) {
|
|
259028
259940
|
const nodeId = job.binding?.nodeId;
|
|
259029
259941
|
if (!nodeId) throw new Error("DaemonHubAdapter \u9700\u8981 job.binding.nodeId\uFF08\u8DEF\u7531\u9519\u8BEF\uFF09");
|
|
259030
|
-
const dispatchId = job.dispatchId ?? `dispatch:${(0,
|
|
259942
|
+
const dispatchId = job.dispatchId ?? `dispatch:${(0, import_node_crypto75.randomUUID)()}`;
|
|
259031
259943
|
if (job.dispatchId && this.pending.has(dispatchId)) {
|
|
259032
259944
|
return this.recover(dispatchId, nodeId, job.binding?.runtimeKind, job.actor);
|
|
259033
259945
|
}
|
|
@@ -259284,7 +260196,7 @@ var init_daemon_adapter = __esm({
|
|
|
259284
260196
|
return daemon?.meta.supportsWorkdirWalk === true;
|
|
259285
260197
|
}
|
|
259286
260198
|
request(nodeId, buildFrame) {
|
|
259287
|
-
const requestId = (0,
|
|
260199
|
+
const requestId = (0, import_node_crypto75.randomUUID)();
|
|
259288
260200
|
const sent = this.hub.dispatch(nodeId, buildFrame(requestId));
|
|
259289
260201
|
if (!sent) return Promise.resolve({ ok: false, code: "NODE_OFFLINE" });
|
|
259290
260202
|
return new Promise((resolve11) => {
|
|
@@ -259342,12 +260254,12 @@ var init_dispatch_fence = __esm({
|
|
|
259342
260254
|
});
|
|
259343
260255
|
|
|
259344
260256
|
// ../server/src/side-map.ts
|
|
259345
|
-
var import_node_fs23,
|
|
260257
|
+
var import_node_fs23, import_node_path27, FileSideMap;
|
|
259346
260258
|
var init_side_map = __esm({
|
|
259347
260259
|
"../server/src/side-map.ts"() {
|
|
259348
260260
|
"use strict";
|
|
259349
260261
|
import_node_fs23 = __toESM(require("node:fs"), 1);
|
|
259350
|
-
|
|
260262
|
+
import_node_path27 = __toESM(require("node:path"), 1);
|
|
259351
260263
|
FileSideMap = class {
|
|
259352
260264
|
constructor(file) {
|
|
259353
260265
|
this.file = file;
|
|
@@ -259374,7 +260286,7 @@ var init_side_map = __esm({
|
|
|
259374
260286
|
}
|
|
259375
260287
|
persist() {
|
|
259376
260288
|
try {
|
|
259377
|
-
import_node_fs23.default.mkdirSync(
|
|
260289
|
+
import_node_fs23.default.mkdirSync(import_node_path27.default.dirname(this.file), { recursive: true });
|
|
259378
260290
|
const tmp = `${this.file}.tmp`;
|
|
259379
260291
|
import_node_fs23.default.writeFileSync(tmp, JSON.stringify(Object.fromEntries(this.map), null, 2));
|
|
259380
260292
|
import_node_fs23.default.renameSync(tmp, this.file);
|
|
@@ -259392,13 +260304,13 @@ function classifyPage(page, lastPushedHash, serviceAccount) {
|
|
|
259392
260304
|
if (sha(body2) === lastPushedHash) return { kind: "echo" };
|
|
259393
260305
|
return { kind: "human-edit", content: body2, updatedBy: page.updatedBy };
|
|
259394
260306
|
}
|
|
259395
|
-
var
|
|
260307
|
+
var import_node_crypto76, sha, enc2, dec, MirrorEngine, MemoryMirrorStateStore, MapMirrorIdentities;
|
|
259396
260308
|
var init_engine = __esm({
|
|
259397
260309
|
"../server/src/mirror/engine.ts"() {
|
|
259398
260310
|
"use strict";
|
|
259399
|
-
|
|
260311
|
+
import_node_crypto76 = require("node:crypto");
|
|
259400
260312
|
init_src();
|
|
259401
|
-
sha = (s2) => (0,
|
|
260313
|
+
sha = (s2) => (0, import_node_crypto76.createHash)("sha256").update(s2, "utf8").digest("hex");
|
|
259402
260314
|
enc2 = (s2) => new TextEncoder().encode(s2);
|
|
259403
260315
|
dec = (b2) => new TextDecoder().decode(b2);
|
|
259404
260316
|
MirrorEngine = class {
|
|
@@ -259679,11 +260591,11 @@ function humanExitCause(exit3) {
|
|
|
259679
260591
|
const base = (exit3.reason ? label2[exit3.reason] : void 0) ?? `\u4F1A\u8BDD\u5F02\u5E38\u7ED3\u675F\uFF08${exit3.reason ?? "\u65E0\u9000\u51FA\u4FE1\u606F"}\uFF09`;
|
|
259680
260592
|
return exit3.errorMessage ? `${base}\uFF1A${exit3.errorMessage.slice(0, 200)}` : base;
|
|
259681
260593
|
}
|
|
259682
|
-
var
|
|
260594
|
+
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;
|
|
259683
260595
|
var init_worker = __esm({
|
|
259684
260596
|
"../server/src/coordinator/worker.ts"() {
|
|
259685
260597
|
"use strict";
|
|
259686
|
-
|
|
260598
|
+
import_node_crypto77 = require("node:crypto");
|
|
259687
260599
|
init_src7();
|
|
259688
260600
|
init_identity();
|
|
259689
260601
|
init_escalation_kind();
|
|
@@ -259956,7 +260868,7 @@ ${HIGH_RISK_COMMANDS}`;
|
|
|
259956
260868
|
return this.deps.kernel.model.lastSeq.get(artifactId) ?? 0;
|
|
259957
260869
|
}
|
|
259958
260870
|
evaluationKey(kind, artifactId, evidence) {
|
|
259959
|
-
const fingerprint2 = (0,
|
|
260871
|
+
const fingerprint2 = (0, import_node_crypto77.createHash)("sha256").update(JSON.stringify(evidence)).digest("hex");
|
|
259960
260872
|
return `${kind}:${artifactId}:${fingerprint2}`;
|
|
259961
260873
|
}
|
|
259962
260874
|
artifactEvidence(id) {
|
|
@@ -260347,8 +261259,8 @@ ${ctx.nodeFault}
|
|
|
260347
261259
|
const taskWithRejections = rejectedSection ? `${task}
|
|
260348
261260
|
|
|
260349
261261
|
${rejectedSection}` : task;
|
|
260350
|
-
const runtimeSessionId = opts?.resumeSessionId ?? (0,
|
|
260351
|
-
const coordinatorRunId = `coordinate:${(0,
|
|
261262
|
+
const runtimeSessionId = opts?.resumeSessionId ?? (0, import_node_crypto77.randomUUID)();
|
|
261263
|
+
const coordinatorRunId = `coordinate:${(0, import_node_crypto77.randomUUID)()}`;
|
|
260352
261264
|
const taskWithContext = coordinatorContext ? [
|
|
260353
261265
|
taskWithRejections,
|
|
260354
261266
|
``,
|
|
@@ -260392,7 +261304,7 @@ ${rejectedSection}` : task;
|
|
|
260392
261304
|
const startedAtMs = Date.now();
|
|
260393
261305
|
let trajectoryStarted = false;
|
|
260394
261306
|
if (this.deps.trajectory) {
|
|
260395
|
-
const bundleManifest = Object.fromEntries(Object.entries(job.bundle.files).map(([name, content3]) => [name, (0,
|
|
261307
|
+
const bundleManifest = Object.fromEntries(Object.entries(job.bundle.files).map(([name, content3]) => [name, (0, import_node_crypto77.createHash)("sha256").update(content3).digest("hex")]));
|
|
260396
261308
|
const session = {
|
|
260397
261309
|
runId: coordinatorRunId,
|
|
260398
261310
|
runtimeSessionId,
|
|
@@ -260603,11 +261515,11 @@ var init_pg_ident = __esm({
|
|
|
260603
261515
|
});
|
|
260604
261516
|
|
|
260605
261517
|
// ../storage/src/postgres.ts
|
|
260606
|
-
var
|
|
261518
|
+
var import_node_crypto78, ident5, isUniqueViolation, PostgresOplogStore, PostgresBlobStore;
|
|
260607
261519
|
var init_postgres = __esm({
|
|
260608
261520
|
"../storage/src/postgres.ts"() {
|
|
260609
261521
|
"use strict";
|
|
260610
|
-
|
|
261522
|
+
import_node_crypto78 = require("node:crypto");
|
|
260611
261523
|
init_pg_ident();
|
|
260612
261524
|
init_esm();
|
|
260613
261525
|
init_src();
|
|
@@ -260787,7 +261699,7 @@ var init_postgres = __esm({
|
|
|
260787
261699
|
return new _PostgresBlobStore(pool, schema);
|
|
260788
261700
|
}
|
|
260789
261701
|
async put(bytes2) {
|
|
260790
|
-
const hash3 = (0,
|
|
261702
|
+
const hash3 = (0, import_node_crypto78.createHash)("sha256").update(bytes2).digest("hex");
|
|
260791
261703
|
await this.pool.query(
|
|
260792
261704
|
`INSERT INTO ${this.t} (hash, bytes, size, content_type) VALUES ($1, $2, $3, $4) ON CONFLICT (hash) DO NOTHING`,
|
|
260793
261705
|
[hash3, Buffer.from(bytes2), bytes2.byteLength, sniffContentType(bytes2) ?? null]
|
|
@@ -260835,7 +261747,7 @@ function stageAtLeast(stage, min2) {
|
|
|
260835
261747
|
return STAGES.indexOf(stage) >= STAGES.indexOf(min2);
|
|
260836
261748
|
}
|
|
260837
261749
|
function newVariableId() {
|
|
260838
|
-
return `var_${(0,
|
|
261750
|
+
return `var_${(0, import_node_crypto79.randomUUID)()}`;
|
|
260839
261751
|
}
|
|
260840
261752
|
async function declareRecordsAware(db) {
|
|
260841
261753
|
await db.query(`SELECT set_config('${RECORDS_AWARE_SETTING}', 'on', true)`);
|
|
@@ -261191,11 +262103,11 @@ async function listBindingTargetIds(db, s2, kind) {
|
|
|
261191
262103
|
[kind]
|
|
261192
262104
|
)).rows.map((x2) => x2.target_id);
|
|
261193
262105
|
}
|
|
261194
|
-
var
|
|
262106
|
+
var import_node_crypto79, STAGES, RECORDS_AWARE_SETTING, markLockName;
|
|
261195
262107
|
var init_variable_bindings = __esm({
|
|
261196
262108
|
"../storage/src/variable-bindings.ts"() {
|
|
261197
262109
|
"use strict";
|
|
261198
|
-
|
|
262110
|
+
import_node_crypto79 = require("node:crypto");
|
|
261199
262111
|
init_src();
|
|
261200
262112
|
STAGES = ["off", "dual", "read", "records"];
|
|
261201
262113
|
RECORDS_AWARE_SETTING = "oasis.variable_records_aware";
|
|
@@ -263845,6 +264757,32 @@ function createPgPool(dsn, opts) {
|
|
|
263845
264757
|
connectionTimeoutMillis: opts?.connectionTimeoutMillis ?? 5e3
|
|
263846
264758
|
});
|
|
263847
264759
|
}
|
|
264760
|
+
async function probePgPool(pool, timeoutMs = 2e3) {
|
|
264761
|
+
const startedAt = Date.now();
|
|
264762
|
+
const stats = () => ({ max: pool.options.max, total: pool.totalCount, idle: pool.idleCount, waiting: pool.waitingCount });
|
|
264763
|
+
const attempt = (async () => {
|
|
264764
|
+
const client = await pool.connect();
|
|
264765
|
+
try {
|
|
264766
|
+
await client.query("SELECT 1");
|
|
264767
|
+
} finally {
|
|
264768
|
+
client.release();
|
|
264769
|
+
}
|
|
264770
|
+
})();
|
|
264771
|
+
let timer;
|
|
264772
|
+
const timeout = new Promise((_2, reject) => {
|
|
264773
|
+
timer = setTimeout(() => reject(new Error(`\u501F\u8FDE\u63A5\u8D85\u8FC7 ${timeoutMs}ms`)), timeoutMs);
|
|
264774
|
+
});
|
|
264775
|
+
try {
|
|
264776
|
+
await Promise.race([attempt, timeout]);
|
|
264777
|
+
return { ok: true, ms: Date.now() - startedAt, pool: stats() };
|
|
264778
|
+
} catch (err) {
|
|
264779
|
+
attempt.catch(() => {
|
|
264780
|
+
});
|
|
264781
|
+
return { ok: false, ms: Date.now() - startedAt, error: err instanceof Error ? err.message : String(err), pool: stats() };
|
|
264782
|
+
} finally {
|
|
264783
|
+
clearTimeout(timer);
|
|
264784
|
+
}
|
|
264785
|
+
}
|
|
263848
264786
|
async function dropSchemaIfExists(dsn, schema) {
|
|
263849
264787
|
const pool = createPgPool(dsn, { max: 1 });
|
|
263850
264788
|
try {
|
|
@@ -263921,9 +264859,11 @@ var init_postgres_control_plane = __esm({
|
|
|
263921
264859
|
avatar text, -- "blob:<hash>"\uFF0C\u7A7A=\u9ED8\u8BA4
|
|
263922
264860
|
status text NOT NULL, -- active | suspended
|
|
263923
264861
|
created_at timestamptz NOT NULL,
|
|
263924
|
-
onboarding_variant text
|
|
264862
|
+
onboarding_variant text, -- \u767B\u5F55\u540E\u52A9\u7406\u5F15\u5BFC\u53D8\u4F53 A|B\uFF1BNULL=\u7F3A\u7701\u89C6\u4E3A A
|
|
264863
|
+
time_zone text -- \u7EC4\u7EC7\u65F6\u533A IANA \u540D\uFF1BNULL=\u6309\u90E8\u7F72\u9ED8\u8BA4\u503C
|
|
263925
264864
|
)`);
|
|
263926
264865
|
await pool.query(`ALTER TABLE "${s2}".companies ADD COLUMN IF NOT EXISTS onboarding_variant text`);
|
|
264866
|
+
await pool.query(`ALTER TABLE "${s2}".companies ADD COLUMN IF NOT EXISTS time_zone text`);
|
|
263927
264867
|
await pool.query(`ALTER TABLE "${s2}".companies ADD COLUMN IF NOT EXISTS dissolved_at timestamptz`);
|
|
263928
264868
|
await pool.query(`ALTER TABLE "${s2}".companies ADD COLUMN IF NOT EXISTS dissolved_by text`);
|
|
263929
264869
|
await pool.query(`
|
|
@@ -264132,8 +265072,8 @@ var init_postgres_control_plane = __esm({
|
|
|
264132
265072
|
// —— 公司 ——
|
|
264133
265073
|
async createCompany(c) {
|
|
264134
265074
|
await this.pool.query(
|
|
264135
|
-
`INSERT INTO ${this.s}.companies (id, slug, name, avatar, status, created_at, onboarding_variant) VALUES ($1,$2,$3,$4,$5,$6,$7)`,
|
|
264136
|
-
[c.id, c.slug, c.name, c.avatar ?? null, c.status, c.createdAt, c.onboardingVariant ?? null]
|
|
265075
|
+
`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)`,
|
|
265076
|
+
[c.id, c.slug, c.name, c.avatar ?? null, c.status, c.createdAt, c.onboardingVariant ?? null, c.timeZone ?? null]
|
|
264137
265077
|
);
|
|
264138
265078
|
}
|
|
264139
265079
|
async getCompany(id) {
|
|
@@ -264167,6 +265107,10 @@ var init_postgres_control_plane = __esm({
|
|
|
264167
265107
|
args.push(patch.onboardingVariant);
|
|
264168
265108
|
sets.push(`onboarding_variant = $${args.length}`);
|
|
264169
265109
|
}
|
|
265110
|
+
if (patch.timeZone !== void 0) {
|
|
265111
|
+
args.push(patch.timeZone);
|
|
265112
|
+
sets.push(`time_zone = $${args.length}`);
|
|
265113
|
+
}
|
|
264170
265114
|
if (patch.dissolvedAt !== void 0) {
|
|
264171
265115
|
args.push(patch.dissolvedAt);
|
|
264172
265116
|
sets.push(`dissolved_at = $${args.length}`);
|
|
@@ -265175,6 +266119,7 @@ var init_postgres_control_plane = __esm({
|
|
|
265175
266119
|
status: row.status,
|
|
265176
266120
|
createdAt: new Date(row.created_at).toISOString(),
|
|
265177
266121
|
...row.onboarding_variant ? { onboardingVariant: row.onboarding_variant } : {},
|
|
266122
|
+
...row.time_zone ? { timeZone: row.time_zone } : {},
|
|
265178
266123
|
// 解散痕迹(组织三层身份 ADR D9.2):两列一起有、一起空。普通运维停用不写它们。
|
|
265179
266124
|
...row.dissolved_at != null ? { dissolvedAt: toIso(row.dissolved_at) } : {},
|
|
265180
266125
|
...row.dissolved_by != null ? { dissolvedBy: row.dissolved_by } : {}
|
|
@@ -271472,11 +272417,11 @@ var init_postgres_delegations = __esm({
|
|
|
271472
272417
|
});
|
|
271473
272418
|
|
|
271474
272419
|
// ../storage/src/postgres-nodes.ts
|
|
271475
|
-
var
|
|
272420
|
+
var import_node_crypto80, ident14, PostgresNodeStore, PostgresNodeTokenStore, rowToNode, rowToFault, rowToQuota, rowToRuntime;
|
|
271476
272421
|
var init_postgres_nodes = __esm({
|
|
271477
272422
|
"../storage/src/postgres-nodes.ts"() {
|
|
271478
272423
|
"use strict";
|
|
271479
|
-
|
|
272424
|
+
import_node_crypto80 = require("node:crypto");
|
|
271480
272425
|
init_pg_ident();
|
|
271481
272426
|
init_esm();
|
|
271482
272427
|
ident14 = (s2) => {
|
|
@@ -271830,7 +272775,7 @@ var init_postgres_nodes = __esm({
|
|
|
271830
272775
|
return store;
|
|
271831
272776
|
}
|
|
271832
272777
|
issue(nodeId) {
|
|
271833
|
-
const token2 = `ont_${(0,
|
|
272778
|
+
const token2 = `ont_${(0, import_node_crypto80.randomBytes)(24).toString("base64url")}`;
|
|
271834
272779
|
this.cache.set(token2, nodeId);
|
|
271835
272780
|
void this.pool.query(`INSERT INTO ${this.s}.node_tokens (token,node_id) VALUES ($1,$2)`, [token2, nodeId]);
|
|
271836
272781
|
return token2;
|
|
@@ -272132,11 +273077,11 @@ var init_postgres_type_registry = __esm({
|
|
|
272132
273077
|
});
|
|
272133
273078
|
|
|
272134
273079
|
// ../storage/src/postgres-actor-memory.ts
|
|
272135
|
-
var
|
|
273080
|
+
var import_node_crypto81, matchClause, ident16, PostgresActorMemoryStore, rowToIndexEntry, rowToRecord;
|
|
272136
273081
|
var init_postgres_actor_memory = __esm({
|
|
272137
273082
|
"../storage/src/postgres-actor-memory.ts"() {
|
|
272138
273083
|
"use strict";
|
|
272139
|
-
|
|
273084
|
+
import_node_crypto81 = require("node:crypto");
|
|
272140
273085
|
init_pg_ident();
|
|
272141
273086
|
init_src();
|
|
272142
273087
|
matchClause = (q2) => q2.requireMatch && q2.keywords.length > 0 ? " WHERE m > 0" : "";
|
|
@@ -272346,7 +273291,7 @@ var init_postgres_actor_memory = __esm({
|
|
|
272346
273291
|
}
|
|
272347
273292
|
async write(input, now) {
|
|
272348
273293
|
if (input.memId === void 0) {
|
|
272349
|
-
const memId = `mem:${(0,
|
|
273294
|
+
const memId = `mem:${(0, import_node_crypto81.randomUUID)()}`;
|
|
272350
273295
|
const r2 = await this.pool.query(
|
|
272351
273296
|
`INSERT INTO ${this.s}.actor_memories
|
|
272352
273297
|
(mem_id, actor_id, project_id, keywords, content, version, created_at, updated_at, accessed_at, source_artifact_id, source_session_id)
|
|
@@ -273917,14 +274862,14 @@ function companySchemaName(companyId) {
|
|
|
273917
274862
|
if (typeof companyId !== "string" || !companyId.trim()) {
|
|
273918
274863
|
throw new Error("company schema mapping \u9700\u8981\u975E\u7A7A companyId\uFF08fail-closed\uFF1A\u4E0D\u56DE\u9000\u9ED8\u8BA4\u516C\u53F8\uFF09");
|
|
273919
274864
|
}
|
|
273920
|
-
const hex = (0,
|
|
274865
|
+
const hex = (0, import_node_crypto82.createHash)("sha256").update(companyId, "utf8").digest("hex");
|
|
273921
274866
|
return `${COMPANY_SCHEMA_PREFIX}${hex.slice(0, DIGEST_HEX_LEN)}`;
|
|
273922
274867
|
}
|
|
273923
|
-
var
|
|
274868
|
+
var import_node_crypto82, COMPANY_SCHEMA_PREFIX, DIGEST_HEX_LEN, SchemaMappingConflictError, TenantStorageLocationStore;
|
|
273924
274869
|
var init_tenant_schema_mapping = __esm({
|
|
273925
274870
|
"../storage/src/tenant-schema-mapping.ts"() {
|
|
273926
274871
|
"use strict";
|
|
273927
|
-
|
|
274872
|
+
import_node_crypto82 = require("node:crypto");
|
|
273928
274873
|
init_esm();
|
|
273929
274874
|
init_pg_ident();
|
|
273930
274875
|
COMPANY_SCHEMA_PREFIX = "c_";
|
|
@@ -273998,7 +274943,7 @@ var init_tenant_schema_mapping = __esm({
|
|
|
273998
274943
|
|
|
273999
274944
|
// ../storage/src/company-data-plane-schema.ts
|
|
274000
274945
|
function canonicalTypeDefHash(def) {
|
|
274001
|
-
return `sha256:${(0,
|
|
274946
|
+
return `sha256:${(0, import_node_crypto83.createHash)("sha256").update(JSON.stringify(def), "utf8").digest("hex")}`;
|
|
274002
274947
|
}
|
|
274003
274948
|
function defaultArtifactTypeTemplate() {
|
|
274004
274949
|
return [
|
|
@@ -274180,11 +275125,11 @@ async function seedDefaultArtifactTypes(pool, schema, templates = defaultArtifac
|
|
|
274180
275125
|
}
|
|
274181
275126
|
return { inserted };
|
|
274182
275127
|
}
|
|
274183
|
-
var
|
|
275128
|
+
var import_node_crypto83, DEFAULT_ARTIFACT_TYPE_TEMPLATE_VERSION;
|
|
274184
275129
|
var init_company_data_plane_schema = __esm({
|
|
274185
275130
|
"../storage/src/company-data-plane-schema.ts"() {
|
|
274186
275131
|
"use strict";
|
|
274187
|
-
|
|
275132
|
+
import_node_crypto83 = require("node:crypto");
|
|
274188
275133
|
init_esm();
|
|
274189
275134
|
init_pg_ident();
|
|
274190
275135
|
DEFAULT_ARTIFACT_TYPE_TEMPLATE_VERSION = "4c368e5c-types-v1";
|
|
@@ -274263,11 +275208,11 @@ function rowToFile2(row) {
|
|
|
274263
275208
|
updatedAt: new Date(row.updated_at).toISOString()
|
|
274264
275209
|
};
|
|
274265
275210
|
}
|
|
274266
|
-
var
|
|
275211
|
+
var import_node_crypto84, COMPANY_CONFLICT_MSG, CompanyIdentifierConflictError, CompanyOwnedRegistryStore;
|
|
274267
275212
|
var init_company_owned_registry_store = __esm({
|
|
274268
275213
|
"../storage/src/company-owned-registry-store.ts"() {
|
|
274269
275214
|
"use strict";
|
|
274270
|
-
|
|
275215
|
+
import_node_crypto84 = require("node:crypto");
|
|
274271
275216
|
init_esm();
|
|
274272
275217
|
init_src();
|
|
274273
275218
|
init_pg_ident();
|
|
@@ -274652,7 +275597,7 @@ var init_company_owned_registry_store = __esm({
|
|
|
274652
275597
|
enabled: skill.enabled,
|
|
274653
275598
|
files: files.map((f2) => ({ path: f2.path, blobHash: f2.blobHash }))
|
|
274654
275599
|
});
|
|
274655
|
-
return (0,
|
|
275600
|
+
return (0, import_node_crypto84.createHash)("sha256").update(body2).digest("hex");
|
|
274656
275601
|
}
|
|
274657
275602
|
};
|
|
274658
275603
|
}
|
|
@@ -277462,7 +278407,7 @@ function sourceSetConservation(input) {
|
|
|
277462
278407
|
return input.sourceFinal === input.copied + input.approvedRuntimeConversion + input.approvedArchive + input.approvedDiscard;
|
|
277463
278408
|
}
|
|
277464
278409
|
function payloadChecksum(value2) {
|
|
277465
|
-
return (0,
|
|
278410
|
+
return (0, import_node_crypto85.createHash)("sha256").update(JSON.stringify(value2)).digest("hex");
|
|
277466
278411
|
}
|
|
277467
278412
|
async function copyWorkorderDraftsIdempotent(pool, companyId, companySchema, manifestId, opts) {
|
|
277468
278413
|
const cs = quoteIdent2(companySchema);
|
|
@@ -277854,11 +278799,11 @@ async function copyTraceFamilyIdempotent(pool, companyId, companySchema, manifes
|
|
|
277854
278799
|
sequences
|
|
277855
278800
|
};
|
|
277856
278801
|
}
|
|
277857
|
-
var
|
|
278802
|
+
var import_node_crypto85, MissingInstallerActorsError, TypeCatalogNotCoveredError, ORG_REGISTRY_TABLES, TRACE_FAMILY;
|
|
277858
278803
|
var init_tenant_migration_operator = __esm({
|
|
277859
278804
|
"../storage/src/tenant-migration-operator.ts"() {
|
|
277860
278805
|
"use strict";
|
|
277861
|
-
|
|
278806
|
+
import_node_crypto85 = require("node:crypto");
|
|
277862
278807
|
init_esm();
|
|
277863
278808
|
init_pg_ident();
|
|
277864
278809
|
init_tenancy_attribution();
|
|
@@ -278094,8 +279039,8 @@ var init_tenant_new_company_provision = __esm({
|
|
|
278094
279039
|
// ../storage/src/knowledge-snapshot-crypto.ts
|
|
278095
279040
|
function sealSnapshot(snapshot, key2) {
|
|
278096
279041
|
if (snapshot.content.startsWith(PREFIX3)) return structuredClone(snapshot);
|
|
278097
|
-
const iv = (0,
|
|
278098
|
-
const cipher = (0,
|
|
279042
|
+
const iv = (0, import_node_crypto86.randomBytes)(12);
|
|
279043
|
+
const cipher = (0, import_node_crypto86.createCipheriv)("aes-256-gcm", bytes(key2), iv);
|
|
278099
279044
|
cipher.setAAD(aad2(snapshot));
|
|
278100
279045
|
const encrypted = Buffer.concat([cipher.update(snapshot.content, "utf8"), cipher.final()]);
|
|
278101
279046
|
return { ...structuredClone(snapshot), content: `${PREFIX3}${iv.toString("base64url")}.${cipher.getAuthTag().toString("base64url")}.${encrypted.toString("base64url")}` };
|
|
@@ -278105,7 +279050,7 @@ function openSnapshot(snapshot, key2) {
|
|
|
278105
279050
|
const packed = snapshot.content.slice(PREFIX3.length).split(".");
|
|
278106
279051
|
if (packed.length !== 3 || packed.some((part) => !part)) throw new Error(`knowledge snapshot ${snapshot.ref} ciphertext is malformed`);
|
|
278107
279052
|
const [iv, tag, data] = packed;
|
|
278108
|
-
const decipher = (0,
|
|
279053
|
+
const decipher = (0, import_node_crypto86.createDecipheriv)("aes-256-gcm", bytes(key2), Buffer.from(iv, "base64url"));
|
|
278109
279054
|
decipher.setAAD(aad2(snapshot));
|
|
278110
279055
|
decipher.setAuthTag(Buffer.from(tag, "base64url"));
|
|
278111
279056
|
return {
|
|
@@ -278113,11 +279058,11 @@ function openSnapshot(snapshot, key2) {
|
|
|
278113
279058
|
content: Buffer.concat([decipher.update(Buffer.from(data, "base64url")), decipher.final()]).toString("utf8")
|
|
278114
279059
|
};
|
|
278115
279060
|
}
|
|
278116
|
-
var
|
|
279061
|
+
var import_node_crypto86, PREFIX3, bytes, aad2;
|
|
278117
279062
|
var init_knowledge_snapshot_crypto = __esm({
|
|
278118
279063
|
"../storage/src/knowledge-snapshot-crypto.ts"() {
|
|
278119
279064
|
"use strict";
|
|
278120
|
-
|
|
279065
|
+
import_node_crypto86 = require("node:crypto");
|
|
278121
279066
|
PREFIX3 = "oasis-knowledge:v1:";
|
|
278122
279067
|
bytes = (key2) => {
|
|
278123
279068
|
const value2 = Buffer.from(key2);
|
|
@@ -278866,6 +279811,9 @@ var init_default_company_schema_move = __esm({
|
|
|
278866
279811
|
"review_requirements",
|
|
278867
279812
|
"review_view",
|
|
278868
279813
|
"reviews",
|
|
279814
|
+
// 个人待办与它的变更记录(2026-10-08 落库,ADR 0635):每行锚在本公司成员与会话上,整表搬(与 discussion_entries 同理)。
|
|
279815
|
+
"todo_changes",
|
|
279816
|
+
"todos",
|
|
278869
279817
|
"work_artifacts",
|
|
278870
279818
|
"work_inputs",
|
|
278871
279819
|
"work_order_files",
|
|
@@ -279012,7 +279960,7 @@ function reportedCost(v2) {
|
|
|
279012
279960
|
}
|
|
279013
279961
|
function newUsageBackfillManifestId(now = /* @__PURE__ */ new Date()) {
|
|
279014
279962
|
const stamp = now.toISOString().replace(/[-:]/g, "").replace(/\.\d+Z$/, "Z");
|
|
279015
|
-
return `ulb-${stamp}-${(0,
|
|
279963
|
+
return `ulb-${stamp}-${(0, import_node_crypto87.randomBytes)(3).toString("hex")}`;
|
|
279016
279964
|
}
|
|
279017
279965
|
async function backfillUsageLedger(ledger, opts) {
|
|
279018
279966
|
if (!opts.dryRun && !opts.manifestId) throw new Error("execute \u9700\u8981 manifestId");
|
|
@@ -279561,11 +280509,11 @@ async function audit(c, s2, manifestId, runId, field, before, after, createdAt)
|
|
|
279561
280509
|
[manifestId, runId, field, before == null ? null : JSON.stringify(before), after == null ? null : JSON.stringify(after), createdAt]
|
|
279562
280510
|
);
|
|
279563
280511
|
}
|
|
279564
|
-
var
|
|
280512
|
+
var import_node_crypto87, BUCKETS, ENDED_SQL, START_EVIDENCE_SQL, CHAT_RUN_SQL, ALLOWED_MODEL_EVIDENCE_TIERS, emptyStep, MODEL_BACKFILL_SOURCE, fourOf, sameUsage, ChatRunLookup;
|
|
279565
280513
|
var init_usage_ledger_backfill = __esm({
|
|
279566
280514
|
"../storage/src/usage-ledger-backfill.ts"() {
|
|
279567
280515
|
"use strict";
|
|
279568
|
-
|
|
280516
|
+
import_node_crypto87 = require("node:crypto");
|
|
279569
280517
|
init_src();
|
|
279570
280518
|
init_pg_ident();
|
|
279571
280519
|
init_postgres_trace();
|
|
@@ -279789,6 +280737,7 @@ __export(src_exports, {
|
|
|
279789
280737
|
payloadChecksum: () => payloadChecksum,
|
|
279790
280738
|
pinChatSessionsToAgentDefault: () => pinChatSessionsToAgentDefault,
|
|
279791
280739
|
planSessionOrd: () => planSessionOrd,
|
|
280740
|
+
probePgPool: () => probePgPool,
|
|
279792
280741
|
provisionCompanyDataPlaneSchema: () => provisionCompanyDataPlaneSchema,
|
|
279793
280742
|
provisionNewCompanyDataPlane: () => provisionNewCompanyDataPlane,
|
|
279794
280743
|
quoteIdent: () => quoteIdent2,
|
|
@@ -279949,26 +280898,26 @@ var init_cutover_aware_workorder_drafts = __esm({
|
|
|
279949
280898
|
|
|
279950
280899
|
// ../server/src/governance/builtin-skills.ts
|
|
279951
280900
|
async function collectDir(root, dir, out) {
|
|
279952
|
-
const entries = await (0,
|
|
280901
|
+
const entries = await (0, import_promises16.readdir)(dir, { withFileTypes: true });
|
|
279953
280902
|
for (const e of entries) {
|
|
279954
|
-
const abs = (0,
|
|
280903
|
+
const abs = (0, import_node_path28.join)(dir, e.name);
|
|
279955
280904
|
if (e.isDirectory()) {
|
|
279956
280905
|
await collectDir(root, abs, out);
|
|
279957
280906
|
} else if (e.isFile()) {
|
|
279958
|
-
const info = await (0,
|
|
280907
|
+
const info = await (0, import_promises16.stat)(abs);
|
|
279959
280908
|
if (info.size > MAX_FILE_BYTES2) {
|
|
279960
280909
|
console.warn(`[builtin-skills] skip oversized file (${info.size}B): ${abs}`);
|
|
279961
280910
|
continue;
|
|
279962
280911
|
}
|
|
279963
|
-
const rel = (0,
|
|
279964
|
-
out[rel] = await (0,
|
|
280912
|
+
const rel = (0, import_node_path28.relative)(root, abs).split(/[\\/]/).join("/");
|
|
280913
|
+
out[rel] = await (0, import_promises16.readFile)(abs, "utf8");
|
|
279965
280914
|
}
|
|
279966
280915
|
}
|
|
279967
280916
|
}
|
|
279968
280917
|
async function loadBuiltinSkills(skillsDir) {
|
|
279969
280918
|
let dirents;
|
|
279970
280919
|
try {
|
|
279971
|
-
dirents = await (0,
|
|
280920
|
+
dirents = await (0, import_promises16.readdir)(skillsDir, { withFileTypes: true });
|
|
279972
280921
|
} catch {
|
|
279973
280922
|
return [];
|
|
279974
280923
|
}
|
|
@@ -279976,7 +280925,7 @@ async function loadBuiltinSkills(skillsDir) {
|
|
|
279976
280925
|
for (const d of dirents) {
|
|
279977
280926
|
if (!d.isDirectory()) continue;
|
|
279978
280927
|
const slug5 = d.name;
|
|
279979
|
-
const skillDir = (0,
|
|
280928
|
+
const skillDir = (0, import_node_path28.join)(skillsDir, slug5);
|
|
279980
280929
|
const files = {};
|
|
279981
280930
|
try {
|
|
279982
280931
|
await collectDir(skillDir, skillDir, files);
|
|
@@ -280005,7 +280954,8 @@ function materializeBuiltinSkills(builtins, skillsDirPrefix) {
|
|
|
280005
280954
|
return out;
|
|
280006
280955
|
}
|
|
280007
280956
|
function applyBuiltinSkillVariants(builtins, opts) {
|
|
280008
|
-
|
|
280957
|
+
const personalTodoEnabled = opts.personalTodoEnabled ?? personalTodoEnabledFromEnv();
|
|
280958
|
+
return builtins.filter((skill) => skill.id !== PERSONAL_TODO_SKILL_ID || personalTodoEnabled).map((skill) => {
|
|
280009
280959
|
const variant = skill.files[BUILTIN_SKILL_DELEGATION_VARIANT];
|
|
280010
280960
|
if (variant === void 0) return skill;
|
|
280011
280961
|
const files = { ...skill.files };
|
|
@@ -280016,16 +280966,18 @@ function applyBuiltinSkillVariants(builtins, opts) {
|
|
|
280016
280966
|
return { ...skill, name: name || skill.id, description, files };
|
|
280017
280967
|
});
|
|
280018
280968
|
}
|
|
280019
|
-
var
|
|
280969
|
+
var import_promises16, import_node_path28, MAX_FILE_BYTES2, BUILTIN_SKILL_DELEGATION_VARIANT, PERSONAL_TODO_SKILL_ID;
|
|
280020
280970
|
var init_builtin_skills = __esm({
|
|
280021
280971
|
"../server/src/governance/builtin-skills.ts"() {
|
|
280022
280972
|
"use strict";
|
|
280023
|
-
|
|
280024
|
-
|
|
280973
|
+
import_promises16 = require("node:fs/promises");
|
|
280974
|
+
import_node_path28 = require("node:path");
|
|
280025
280975
|
init_skill_fetcher();
|
|
280026
280976
|
init_skill_materializer();
|
|
280977
|
+
init_flag();
|
|
280027
280978
|
MAX_FILE_BYTES2 = 1 << 20;
|
|
280028
280979
|
BUILTIN_SKILL_DELEGATION_VARIANT = "SKILL.delegation.md";
|
|
280980
|
+
PERSONAL_TODO_SKILL_ID = "personal-todo";
|
|
280029
280981
|
}
|
|
280030
280982
|
});
|
|
280031
280983
|
|
|
@@ -280053,7 +281005,7 @@ var init_chat_builtin_skills = __esm({
|
|
|
280053
281005
|
|
|
280054
281006
|
// ../server/src/governance/connector-tool-versions.ts
|
|
280055
281007
|
function connectorToolVersionsFile(dataDir) {
|
|
280056
|
-
return (0,
|
|
281008
|
+
return (0, import_node_path29.join)(dataDir, "connector-tools", "versions.json");
|
|
280057
281009
|
}
|
|
280058
281010
|
function registryBase() {
|
|
280059
281011
|
const raw = process.env["npm_config_registry"] || process.env["NPM_CONFIG_REGISTRY"] || "https://registry.npmjs.org";
|
|
@@ -280072,7 +281024,7 @@ async function fetchLatestNpmVersion(pkg) {
|
|
|
280072
281024
|
}
|
|
280073
281025
|
async function readRegisteredToolVersions(dataDir) {
|
|
280074
281026
|
try {
|
|
280075
|
-
const raw = JSON.parse(await (0,
|
|
281027
|
+
const raw = JSON.parse(await (0, import_promises17.readFile)(connectorToolVersionsFile(dataDir), "utf8"));
|
|
280076
281028
|
if (!raw || typeof raw !== "object") return {};
|
|
280077
281029
|
const out = {};
|
|
280078
281030
|
for (const [k2, v2] of Object.entries(raw)) {
|
|
@@ -280085,11 +281037,11 @@ async function readRegisteredToolVersions(dataDir) {
|
|
|
280085
281037
|
}
|
|
280086
281038
|
async function writeRegisteredToolVersions(dataDir, versions) {
|
|
280087
281039
|
const file = connectorToolVersionsFile(dataDir);
|
|
280088
|
-
await (0,
|
|
281040
|
+
await (0, import_promises17.mkdir)((0, import_node_path29.join)(dataDir, "connector-tools"), { recursive: true });
|
|
280089
281041
|
const tmp = `${file}.${process.pid}.tmp`;
|
|
280090
|
-
await (0,
|
|
281042
|
+
await (0, import_promises17.writeFile)(tmp, `${JSON.stringify(versions, null, 2)}
|
|
280091
281043
|
`, "utf8");
|
|
280092
|
-
await (0,
|
|
281044
|
+
await (0, import_promises17.rename)(tmp, file);
|
|
280093
281045
|
}
|
|
280094
281046
|
async function refreshConnectorToolVersions(opts) {
|
|
280095
281047
|
const fetchLatest = opts.fetchLatest ?? fetchLatestNpmVersion;
|
|
@@ -280132,12 +281084,12 @@ function pickToolVersions(registered, tools) {
|
|
|
280132
281084
|
}
|
|
280133
281085
|
return out;
|
|
280134
281086
|
}
|
|
280135
|
-
var
|
|
281087
|
+
var import_promises17, import_node_path29, NPM_PROBE_TIMEOUT_MS;
|
|
280136
281088
|
var init_connector_tool_versions = __esm({
|
|
280137
281089
|
"../server/src/governance/connector-tool-versions.ts"() {
|
|
280138
281090
|
"use strict";
|
|
280139
|
-
|
|
280140
|
-
|
|
281091
|
+
import_promises17 = require("node:fs/promises");
|
|
281092
|
+
import_node_path29 = require("node:path");
|
|
280141
281093
|
init_src8();
|
|
280142
281094
|
NPM_PROBE_TIMEOUT_MS = 3e3;
|
|
280143
281095
|
}
|
|
@@ -281230,6 +282182,7 @@ __export(src_exports2, {
|
|
|
281230
282182
|
DEFAULT_PUSH_THROTTLE_MS: () => DEFAULT_PUSH_THROTTLE_MS,
|
|
281231
282183
|
DEFAULT_SIMPLE_QUERY_MAX_CHARS: () => DEFAULT_SIMPLE_QUERY_MAX_CHARS,
|
|
281232
282184
|
DEFAULT_TERMINAL_MAX_AGE_MS: () => DEFAULT_TERMINAL_MAX_AGE_MS,
|
|
282185
|
+
DEFAULT_TIME_ZONE_ENV: () => DEFAULT_TIME_ZONE_ENV,
|
|
281233
282186
|
DELIVERY_REPAIR_BATCH: () => DELIVERY_REPAIR_BATCH,
|
|
281234
282187
|
DENY_ALL_TRACE_READ: () => DENY_ALL_TRACE_READ,
|
|
281235
282188
|
DISPATCH_DROP_BACKOFF_MS: () => DISPATCH_DROP_BACKOFF_MS,
|
|
@@ -281313,6 +282266,7 @@ __export(src_exports2, {
|
|
|
281313
282266
|
MemoryProjectStateStore: () => MemoryProjectStateStore,
|
|
281314
282267
|
MemoryPushSubscriptionStore: () => MemoryPushSubscriptionStore,
|
|
281315
282268
|
MemoryReadMarkerStore: () => MemoryReadMarkerStore,
|
|
282269
|
+
MemoryTodoStore: () => MemoryTodoStore,
|
|
281316
282270
|
MemoryWorkorderDraftPlannerIssuesStore: () => MemoryWorkorderDraftPlannerIssuesStore,
|
|
281317
282271
|
MemoryWorkorderTagStore: () => MemoryWorkorderTagStore,
|
|
281318
282272
|
MemoryWriteConflictError: () => MemoryWriteConflictError,
|
|
@@ -281331,6 +282285,7 @@ __export(src_exports2, {
|
|
|
281331
282285
|
OWNER_PROTECTED_PROFILE_MESSAGE: () => OWNER_PROTECTED_PROFILE_MESSAGE,
|
|
281332
282286
|
PARENT_CONVERSATION_PATH: () => PARENT_CONVERSATION_PATH,
|
|
281333
282287
|
PARENT_CONVERSATION_RECENT_TURNS: () => PARENT_CONVERSATION_RECENT_TURNS,
|
|
282288
|
+
PERSONAL_TODO_SKILL_ID: () => PERSONAL_TODO_SKILL_ID,
|
|
281334
282289
|
PostgresNotificationStore: () => PostgresNotificationStore,
|
|
281335
282290
|
PostgresPushSubscriptionStore: () => PostgresPushSubscriptionStore,
|
|
281336
282291
|
PostgresWorkorderDraftPlannerIssuesStore: () => PostgresWorkorderDraftPlannerIssuesStore,
|
|
@@ -281361,7 +282316,12 @@ __export(src_exports2, {
|
|
|
281361
282316
|
STATUS_MARKER: () => STATUS_MARKER,
|
|
281362
282317
|
SessionRuntimeOverrideError: () => SessionRuntimeOverrideError,
|
|
281363
282318
|
SkillFetchHttpError: () => SkillFetchHttpError,
|
|
282319
|
+
TODO_REMINDER_SCAN_MS: () => TODO_REMINDER_SCAN_MS,
|
|
282320
|
+
TODO_REMINDER_TIME: () => TODO_REMINDER_TIME,
|
|
282321
|
+
TODO_REMINDER_TITLE: () => TODO_REMINDER_TITLE,
|
|
281364
282322
|
TenancyVisibilityInputError: () => TenancyVisibilityInputError,
|
|
282323
|
+
TodoReminderScanner: () => TodoReminderScanner,
|
|
282324
|
+
TodoService: () => TodoService,
|
|
281365
282325
|
TraceService: () => TraceService,
|
|
281366
282326
|
TraceStoreSink: () => TraceStoreSink,
|
|
281367
282327
|
TypesAdminService: () => TypesAdminService,
|
|
@@ -281387,10 +282347,12 @@ __export(src_exports2, {
|
|
|
281387
282347
|
assertBindingWritePermission: () => assertBindingWritePermission,
|
|
281388
282348
|
assertCompanyManager: () => assertCompanyManager,
|
|
281389
282349
|
assertCreatableVariable: () => assertCreatableVariable,
|
|
282350
|
+
assertFirstVersionAssignee: () => assertFirstVersionAssignee,
|
|
281390
282351
|
assertMayCreateAgent: () => assertMayCreateAgent,
|
|
281391
282352
|
assertMayManageAgent: () => assertMayManageAgent,
|
|
281392
282353
|
assertMaySelfOrManage: () => assertMaySelfOrManage,
|
|
281393
282354
|
assistantBoundToMember: () => assistantBoundToMember,
|
|
282355
|
+
assistantNameFor: () => assistantNameFor,
|
|
281394
282356
|
assistantRowRecovery: () => assistantRowRecovery,
|
|
281395
282357
|
assistantsDomain: () => assistantsDomain,
|
|
281396
282358
|
atCapacity: () => atCapacity,
|
|
@@ -281426,6 +282388,7 @@ __export(src_exports2, {
|
|
|
281426
282388
|
buildWorkorderMetrics: () => buildWorkorderMetrics,
|
|
281427
282389
|
buildWorkorderSummaries: () => buildWorkorderSummaries,
|
|
281428
282390
|
builtinSkillToFiles: () => builtinSkillToFiles,
|
|
282391
|
+
canAccessTodo: () => canAccessTodo,
|
|
281429
282392
|
canAnnounceRuntimeSwitch: () => canAnnounceRuntimeSwitch,
|
|
281430
282393
|
canRetryAllocation: () => canRetryAllocation,
|
|
281431
282394
|
chatBroadcastEnabledFromEnv: () => chatBroadcastEnabledFromEnv,
|
|
@@ -281511,6 +282474,7 @@ __export(src_exports2, {
|
|
|
281511
282474
|
decideArrival: () => decideArrival,
|
|
281512
282475
|
decideFlush: () => decideFlush,
|
|
281513
282476
|
defaultAvatarRefOf: () => defaultAvatarRefOf,
|
|
282477
|
+
defaultTimeZoneFromEnv: () => defaultTimeZoneFromEnv,
|
|
281514
282478
|
delegationArtifactsView: () => delegationArtifactsView,
|
|
281515
282479
|
delegationBundleAdditions: () => delegationBundleAdditions,
|
|
281516
282480
|
delegationDirName: () => delegationDirName,
|
|
@@ -281535,6 +282499,7 @@ __export(src_exports2, {
|
|
|
281535
282499
|
dispatchIntentMarker: () => dispatchIntentMarker,
|
|
281536
282500
|
displayCostUsdMicros: () => displayCostUsdMicros,
|
|
281537
282501
|
dropUnchangedOutputs: () => dropUnchangedOutputs,
|
|
282502
|
+
dueReminders: () => dueReminders,
|
|
281538
282503
|
employeeHref: () => employeeHref,
|
|
281539
282504
|
encryptPushMessage: () => encryptPushMessage,
|
|
281540
282505
|
ensureCompanyActors: () => ensureCompanyActors,
|
|
@@ -281670,6 +282635,7 @@ __export(src_exports2, {
|
|
|
281670
282635
|
parseWriteScope: () => parseWriteScope,
|
|
281671
282636
|
parseZhizengzengMarkdown: () => parseZhizengzengMarkdown,
|
|
281672
282637
|
participatingTaskCount: () => participatingTaskCount,
|
|
282638
|
+
personalTodoEnabledFromEnv: () => personalTodoEnabledFromEnv,
|
|
281673
282639
|
pickToolVersions: () => pickToolVersions,
|
|
281674
282640
|
placeholderRuntimeSessionFlag: () => placeholderRuntimeSessionFlag,
|
|
281675
282641
|
planChatContinuation: () => planChatContinuation,
|
|
@@ -281811,6 +282777,8 @@ __export(src_exports2, {
|
|
|
281811
282777
|
toBundleFiles: () => toBundleFiles,
|
|
281812
282778
|
toChatDispatchRequest: () => toChatDispatchRequest,
|
|
281813
282779
|
toYamlDoubleQuoted: () => toYamlDoubleQuoted,
|
|
282780
|
+
todoReminderSourceKey: () => todoReminderSourceKey,
|
|
282781
|
+
todosDomain: () => todosDomain,
|
|
281814
282782
|
touchKey: () => touchKey,
|
|
281815
282783
|
traceDomain: () => traceDomain,
|
|
281816
282784
|
traceReadAllows: () => traceReadAllows,
|
|
@@ -281939,6 +282907,7 @@ var init_src11 = __esm({
|
|
|
281939
282907
|
init_agent_default_runtime_store();
|
|
281940
282908
|
init_knowledge2();
|
|
281941
282909
|
init_delegations();
|
|
282910
|
+
init_todos2();
|
|
281942
282911
|
init_automations();
|
|
281943
282912
|
init_automations();
|
|
281944
282913
|
init_playbooks();
|
|
@@ -282350,14 +283319,14 @@ init_src();
|
|
|
282350
283319
|
var os16 = __toESM(require("node:os"));
|
|
282351
283320
|
var path46 = __toESM(require("node:path"));
|
|
282352
283321
|
var import_node_child_process23 = require("node:child_process");
|
|
282353
|
-
var
|
|
283322
|
+
var import_node_crypto100 = require("node:crypto");
|
|
282354
283323
|
|
|
282355
283324
|
// ../cli/src/cli.ts
|
|
282356
283325
|
init_src();
|
|
282357
283326
|
var fs44 = __toESM(require("node:fs"), 1);
|
|
282358
283327
|
var os13 = __toESM(require("node:os"), 1);
|
|
282359
283328
|
var path39 = __toESM(require("node:path"), 1);
|
|
282360
|
-
var
|
|
283329
|
+
var import_node_crypto98 = require("node:crypto");
|
|
282361
283330
|
|
|
282362
283331
|
// ../cli/src/serve.ts
|
|
282363
283332
|
init_src11();
|
|
@@ -282370,11 +283339,11 @@ var fs36 = __toESM(require("node:fs"), 1);
|
|
|
282370
283339
|
var os9 = __toESM(require("node:os"), 1);
|
|
282371
283340
|
var path29 = __toESM(require("node:path"), 1);
|
|
282372
283341
|
var import_node_child_process15 = require("node:child_process");
|
|
282373
|
-
var
|
|
283342
|
+
var import_node_crypto93 = require("node:crypto");
|
|
282374
283343
|
var import_node_url7 = require("node:url");
|
|
282375
283344
|
|
|
282376
283345
|
// ../cli/src/artifact-discovery-source.ts
|
|
282377
|
-
var
|
|
283346
|
+
var import_node_crypto88 = require("node:crypto");
|
|
282378
283347
|
init_src7();
|
|
282379
283348
|
var ArtifactDiscoverySourceUnreadableError = class extends Error {
|
|
282380
283349
|
constructor(message) {
|
|
@@ -282404,7 +283373,7 @@ async function resolveArtifactDiscoverySourceContent(blobs, input) {
|
|
|
282404
283373
|
throw new ArtifactDiscoverySourceUnreadableError(`Artifact Revision ${input.revisionId} \u7684 contentKind \u4E0D\u53D7\u652F\u6301\uFF1A${String(input.contentKind)}`);
|
|
282405
283374
|
}
|
|
282406
283375
|
const rootBytes = await blobs.get(input.contentRef);
|
|
282407
|
-
const sourceFingerprint = (0,
|
|
283376
|
+
const sourceFingerprint = (0, import_node_crypto88.createHash)("sha256").update(rootBytes).digest("hex");
|
|
282408
283377
|
if (input.contentKind === "inline-blob") {
|
|
282409
283378
|
const sourceContent = decodeText3(rootBytes);
|
|
282410
283379
|
if (sourceContent === null) {
|
|
@@ -282428,7 +283397,7 @@ ${entry.text}`).join("\n\n"),
|
|
|
282428
283397
|
}
|
|
282429
283398
|
|
|
282430
283399
|
// ../server/src/domains/discussions/service.ts
|
|
282431
|
-
var
|
|
283400
|
+
var import_node_crypto89 = require("node:crypto");
|
|
282432
283401
|
init_zod();
|
|
282433
283402
|
init_discussions();
|
|
282434
283403
|
init_router();
|
|
@@ -282497,7 +283466,7 @@ var decisionOption = (row) => ({
|
|
|
282497
283466
|
state: row.value.record.state,
|
|
282498
283467
|
revision: row.revision
|
|
282499
283468
|
});
|
|
282500
|
-
var hash2 = (s2) => (0,
|
|
283469
|
+
var hash2 = (s2) => (0, import_node_crypto89.createHash)("sha256").update(s2).digest("hex").slice(0, 24);
|
|
282501
283470
|
var canonical = (s2) => s2.normalize("NFKC").trim().toLocaleLowerCase();
|
|
282502
283471
|
function decisionFingerprint(d) {
|
|
282503
283472
|
return hash2(JSON.stringify([d.statement, d.rationale, d.alternatives]));
|
|
@@ -282770,7 +283739,7 @@ var DiscussionService = class {
|
|
|
282770
283739
|
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");
|
|
282771
283740
|
}
|
|
282772
283741
|
}
|
|
282773
|
-
const operation = (value2) => tx.put("operation", (0,
|
|
283742
|
+
const operation = (value2) => tx.put("operation", (0, import_node_crypto89.randomUUID)(), {
|
|
282774
283743
|
...value2,
|
|
282775
283744
|
projectId: projectId2,
|
|
282776
283745
|
actorId: ctx.actorId,
|
|
@@ -282787,7 +283756,7 @@ var DiscussionService = class {
|
|
|
282787
283756
|
if (id.startsWith("new:")) {
|
|
282788
283757
|
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`);
|
|
282789
283758
|
const existing = [...topicMap.values()].find((x2) => canonical(x2.title) === canonical(t.title));
|
|
282790
|
-
id = existing?.topicId ?? `topic_${(0,
|
|
283759
|
+
id = existing?.topicId ?? `topic_${(0, import_node_crypto89.randomUUID)()}`;
|
|
282791
283760
|
if (!existing) createdTopics.add(id);
|
|
282792
283761
|
} else if (!topicMap.has(id)) invalid("topics.topic_id", `\u8BAE\u9898 ${id} \u4E0D\u5B58\u5728\uFF1B\u65B0\u8BAE\u9898\u4F7F\u7528 new: \u524D\u7F00`);
|
|
282793
283762
|
topicAliases.set(t.topic_id, id);
|
|
@@ -282839,7 +283808,7 @@ var DiscussionService = class {
|
|
|
282839
283808
|
if (id.startsWith("new:")) {
|
|
282840
283809
|
const candidateKey = JSON.stringify([topicId, canonical(d.record.statement)]);
|
|
282841
283810
|
const existing = [...decisionMap.values()].find((x2) => x2.topicId === topicId && canonical(x2.record.statement) === canonical(d.record.statement));
|
|
282842
|
-
id = existing?.decisionId ?? candidateIds.get(candidateKey) ?? `decision_${(0,
|
|
283811
|
+
id = existing?.decisionId ?? candidateIds.get(candidateKey) ?? `decision_${(0, import_node_crypto89.randomUUID)()}`;
|
|
282843
283812
|
candidateIds.set(candidateKey, id);
|
|
282844
283813
|
} else if (!decisionMap.has(id)) invalid("decision_id", `\u51B3\u7B56 ${id} \u4E0D\u5B58\u5728\uFF1B\u65B0\u51B3\u7B56\u4F7F\u7528 new: \u524D\u7F00`);
|
|
282845
283814
|
decisionAliases.set(d.decision_id, id);
|
|
@@ -282963,15 +283932,15 @@ var DiscussionService = class {
|
|
|
282963
283932
|
});
|
|
282964
283933
|
}
|
|
282965
283934
|
async editTopic(projectId2, topicId, revision, raw, actorId) {
|
|
282966
|
-
const
|
|
283935
|
+
const edit3 = external_exports.object({ title: nonempty, summary: text6.optional() }).strict().parse(raw);
|
|
282967
283936
|
return this.store.transaction(async (tx) => {
|
|
282968
283937
|
const key2 = entryId(projectId2, topicId);
|
|
282969
283938
|
const old = await tx.get("topic", key2);
|
|
282970
283939
|
if (!old) throw new ApiError(404, "NOT_FOUND", "\u8BAE\u9898\u4E0D\u5B58\u5728");
|
|
282971
283940
|
assertRevision(old.revision, revision);
|
|
282972
|
-
const summary = (
|
|
282973
|
-
if (old.value.title ===
|
|
282974
|
-
const result = await tx.put("topic", key2, { ...old.value, title:
|
|
283941
|
+
const summary = (edit3.summary ?? old.value.summary ?? "").trim();
|
|
283942
|
+
if (old.value.title === edit3.title && (old.value.summary ?? "") === summary) return old;
|
|
283943
|
+
const result = await tx.put("topic", key2, { ...old.value, title: edit3.title, summary, updated_at: new Date(this.now()).toISOString() });
|
|
282975
283944
|
await this.operation(tx, actorId, "topic", key2, old.revision, result.revision);
|
|
282976
283945
|
return result;
|
|
282977
283946
|
});
|
|
@@ -283101,7 +284070,7 @@ var DiscussionService = class {
|
|
|
283101
284070
|
...row.value.confirmation ? { confirmation: { ...row.value.confirmation, fingerprint: decisionFingerprint(record10) } } : {}
|
|
283102
284071
|
};
|
|
283103
284072
|
await tx.put("decision", row.id, value2);
|
|
283104
|
-
await tx.put("operation", (0,
|
|
284073
|
+
await tx.put("operation", (0, import_node_crypto89.randomUUID)(), {
|
|
283105
284074
|
action: "edit",
|
|
283106
284075
|
kind: "decision",
|
|
283107
284076
|
projectId: projectId2,
|
|
@@ -283165,7 +284134,7 @@ var DiscussionService = class {
|
|
|
283165
284134
|
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`);
|
|
283166
284135
|
const summary = given.get(row.id);
|
|
283167
284136
|
await tx.put("discussion", row.id, { ...current.value, record: { ...current.value.record, summary } });
|
|
283168
|
-
await tx.put("operation", (0,
|
|
284137
|
+
await tx.put("operation", (0, import_node_crypto89.randomUUID)(), {
|
|
283169
284138
|
action: "edit",
|
|
283170
284139
|
kind: "discussion",
|
|
283171
284140
|
projectId: current.value.record.project_id,
|
|
@@ -283181,7 +284150,7 @@ var DiscussionService = class {
|
|
|
283181
284150
|
});
|
|
283182
284151
|
}
|
|
283183
284152
|
async operation(tx, actorId, kind, id, from, to) {
|
|
283184
|
-
await tx.put("operation", (0,
|
|
284153
|
+
await tx.put("operation", (0, import_node_crypto89.randomUUID)(), { actorId, kind, id, from, to, at: new Date(this.now()).toISOString() });
|
|
283185
284154
|
}
|
|
283186
284155
|
};
|
|
283187
284156
|
function pickDiscussionContent(d) {
|
|
@@ -283312,13 +284281,13 @@ function renderProjectContext(input) {
|
|
|
283312
284281
|
const dir = PROJECT_DISCUSSIONS_DIR;
|
|
283313
284282
|
const files = {};
|
|
283314
284283
|
const width = (n) => Math.max(2, String(n).length);
|
|
283315
|
-
const
|
|
284284
|
+
const pad3 = (i, n) => String(i + 1).padStart(width(n), "0");
|
|
283316
284285
|
const mine = new Set(input.discussions.flatMap((row) => row.value.record.topics.map((t) => `${row.value.record.project_id}\0${t.topic_id}`)));
|
|
283317
|
-
const discussionPaths = input.discussions.map((row, i) => `${dir}/\u6211\u7684\u8BA8\u8BBA/${
|
|
284286
|
+
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`);
|
|
283318
284287
|
input.discussions.forEach((row, i) => {
|
|
283319
284288
|
files[discussionPaths[i]] = [`# ${row.value.record.title}`, "", ...discussionBody(input, row)].join("\n");
|
|
283320
284289
|
});
|
|
283321
|
-
const topicPaths = input.topics.map((t, i) => `${dir}/\u8BAE\u9898/${
|
|
284290
|
+
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`);
|
|
283322
284291
|
input.topics.forEach((t, i) => {
|
|
283323
284292
|
files[topicPaths[i]] = [`# \u8BAE\u9898\uFF1A${t.value.title}`, "", decisionLegend, "", ...topicBody(input, t, "##")].join("\n");
|
|
283324
284293
|
});
|
|
@@ -283481,7 +284450,7 @@ var DiscussionContext = class {
|
|
|
283481
284450
|
};
|
|
283482
284451
|
|
|
283483
284452
|
// ../server/src/domains/discussions/worker.ts
|
|
283484
|
-
var
|
|
284453
|
+
var import_node_crypto90 = require("node:crypto");
|
|
283485
284454
|
var DISCUSSION_IDLE_MS = 15 * 6e4;
|
|
283486
284455
|
var DISCUSSION_MAX_CORRECTIONS = 3;
|
|
283487
284456
|
var DISCUSSION_LEASE_MS = 2 * 6e4;
|
|
@@ -283507,7 +284476,7 @@ var DiscussionWorker = class {
|
|
|
283507
284476
|
if (await this.isReplying(sessionId)) return false;
|
|
283508
284477
|
const cutoff = eligibleCutoff(await this.service.chat.listMessages(sessionId), this.service.now());
|
|
283509
284478
|
if (!cutoff) return false;
|
|
283510
|
-
const owner = (0,
|
|
284479
|
+
const owner = (0, import_node_crypto90.randomUUID)();
|
|
283511
284480
|
const claimed = await this.service.store.transaction(async (tx) => {
|
|
283512
284481
|
const old = (await tx.get("job", sessionId))?.value;
|
|
283513
284482
|
if (old?.status === "running" && (old.leaseUntil ?? 0) > this.service.now()) return null;
|
|
@@ -283933,7 +284902,7 @@ init_zod();
|
|
|
283933
284902
|
init_discussions();
|
|
283934
284903
|
init_router();
|
|
283935
284904
|
init_uncategorized_project();
|
|
283936
|
-
var
|
|
284905
|
+
var edit2 = external_exports.object({ revision: external_exports.number().int().positive(), content: external_exports.unknown() }).strict();
|
|
283937
284906
|
var removal = external_exports.object({ revision: external_exports.number().int().positive(), reason: external_exports.string() }).strict();
|
|
283938
284907
|
function paging(query) {
|
|
283939
284908
|
const parsed = external_exports.object({
|
|
@@ -284022,7 +284991,7 @@ function discussionsDomain(options) {
|
|
|
284022
284991
|
router.patch("/api/chat-sessions/:id/discussion", wrap(async (req) => {
|
|
284023
284992
|
await human(req);
|
|
284024
284993
|
const { service, session } = await sessionAccess(req);
|
|
284025
|
-
const body2 =
|
|
284994
|
+
const body2 = edit2.parse(req.body);
|
|
284026
284995
|
return { status: 200, body: await service.editDiscussion(session.id, body2.revision, body2.content, req.auth.actor) };
|
|
284027
284996
|
}));
|
|
284028
284997
|
router.post("/api/chat-sessions/:id/discussion/retry", wrap(async (req) => {
|
|
@@ -284084,7 +285053,7 @@ function discussionsDomain(options) {
|
|
|
284084
285053
|
await human(req);
|
|
284085
285054
|
const service = await options.serviceFor(req.auth.companyId);
|
|
284086
285055
|
await service.project(req.params.id);
|
|
284087
|
-
const body2 =
|
|
285056
|
+
const body2 = edit2.extend({ relatedRevisions: external_exports.record(external_exports.number().int().positive()).optional() }).parse(req.body);
|
|
284088
285057
|
return { status: 200, body: await service.editDecision(req.params.id, req.params.decisionId, body2.revision, body2.content, req.auth.actor, body2.relatedRevisions) };
|
|
284089
285058
|
}));
|
|
284090
285059
|
router.get("/api/chat-sessions/:id/project-context", wrap(async (req) => {
|
|
@@ -284267,9 +285236,9 @@ function createDiscussionRuntime(options) {
|
|
|
284267
285236
|
}
|
|
284268
285237
|
|
|
284269
285238
|
// ../server/src/domains/discussions/store.ts
|
|
284270
|
-
var
|
|
284271
|
-
var
|
|
284272
|
-
var
|
|
285239
|
+
var import_node_crypto91 = require("node:crypto");
|
|
285240
|
+
var import_promises18 = require("node:fs/promises");
|
|
285241
|
+
var import_node_path30 = require("node:path");
|
|
284273
285242
|
var key = (kind, id) => JSON.stringify([kind, id]);
|
|
284274
285243
|
function contains(value2, match) {
|
|
284275
285244
|
if (match !== null && typeof match === "object" && !Array.isArray(match)) {
|
|
@@ -284290,7 +285259,7 @@ var MemoryDiscussionStore = class _MemoryDiscussionStore {
|
|
|
284290
285259
|
static async open(filename) {
|
|
284291
285260
|
const store = new _MemoryDiscussionStore(filename);
|
|
284292
285261
|
try {
|
|
284293
|
-
store.rows = JSON.parse(await (0,
|
|
285262
|
+
store.rows = JSON.parse(await (0, import_promises18.readFile)(filename, "utf8"));
|
|
284294
285263
|
} catch (error2) {
|
|
284295
285264
|
if (error2.code !== "ENOENT") throw error2;
|
|
284296
285265
|
}
|
|
@@ -284342,10 +285311,10 @@ var MemoryDiscussionStore = class _MemoryDiscussionStore {
|
|
|
284342
285311
|
const result = await run(tx);
|
|
284343
285312
|
if (changed) {
|
|
284344
285313
|
if (this.filename) {
|
|
284345
|
-
await (0,
|
|
284346
|
-
const temp = `${this.filename}.${(0,
|
|
284347
|
-
await (0,
|
|
284348
|
-
await (0,
|
|
285314
|
+
await (0, import_promises18.mkdir)((0, import_node_path30.dirname)(this.filename), { recursive: true });
|
|
285315
|
+
const temp = `${this.filename}.${(0, import_node_crypto91.randomUUID)()}.tmp`;
|
|
285316
|
+
await (0, import_promises18.writeFile)(temp, JSON.stringify(next), "utf8");
|
|
285317
|
+
await (0, import_promises18.rename)(temp, this.filename);
|
|
284349
285318
|
}
|
|
284350
285319
|
this.rows = next;
|
|
284351
285320
|
}
|
|
@@ -284436,6 +285405,225 @@ var PostgresDiscussionStore = class _PostgresDiscussionStore {
|
|
|
284436
285405
|
}
|
|
284437
285406
|
};
|
|
284438
285407
|
|
|
285408
|
+
// ../cli/src/todo-wiring.ts
|
|
285409
|
+
init_src();
|
|
285410
|
+
init_router();
|
|
285411
|
+
init_service10();
|
|
285412
|
+
init_routes11();
|
|
285413
|
+
init_reminders();
|
|
285414
|
+
init_flag();
|
|
285415
|
+
function createTodoRuntime(options) {
|
|
285416
|
+
const enabled = options.enabled ?? (() => personalTodoEnabledFromEnv());
|
|
285417
|
+
const cache = /* @__PURE__ */ new Map();
|
|
285418
|
+
const serviceFor = (companyId) => {
|
|
285419
|
+
const id = companyId ?? options.defaultCompanyId();
|
|
285420
|
+
let value2 = cache.get(id);
|
|
285421
|
+
if (!value2) {
|
|
285422
|
+
value2 = options.store(id).then((store) => new TodoService({ store, timeZone: () => options.timeZone(id) }));
|
|
285423
|
+
cache.set(id, value2);
|
|
285424
|
+
void value2.catch(() => cache.delete(id));
|
|
285425
|
+
}
|
|
285426
|
+
return value2;
|
|
285427
|
+
};
|
|
285428
|
+
const resolveCaller = async (actorId, companyId) => {
|
|
285429
|
+
if (isHumanActorId(actorId)) return { principal: actorId, actor: actorId };
|
|
285430
|
+
const human = await options.boundHuman(actorId, companyId ?? options.defaultCompanyId());
|
|
285431
|
+
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");
|
|
285432
|
+
return { principal: human, hand: actorId, actor: actorId };
|
|
285433
|
+
};
|
|
285434
|
+
const register = todosDomain({ serviceFor, resolveCaller, enabled });
|
|
285435
|
+
const scanner = new TodoReminderScanner({
|
|
285436
|
+
companies: options.companies,
|
|
285437
|
+
todos: options.store,
|
|
285438
|
+
notifications: options.notifications,
|
|
285439
|
+
timeZone: options.timeZone,
|
|
285440
|
+
enabled,
|
|
285441
|
+
warn: options.warn,
|
|
285442
|
+
...options.onReminders ? { onInserted: options.onReminders } : {}
|
|
285443
|
+
});
|
|
285444
|
+
return {
|
|
285445
|
+
register,
|
|
285446
|
+
serviceFor,
|
|
285447
|
+
resolveCaller,
|
|
285448
|
+
scanner,
|
|
285449
|
+
start: () => scanner.start(),
|
|
285450
|
+
stop: () => scanner.stop()
|
|
285451
|
+
};
|
|
285452
|
+
}
|
|
285453
|
+
|
|
285454
|
+
// ../cli/src/serve.ts
|
|
285455
|
+
init_store3();
|
|
285456
|
+
|
|
285457
|
+
// ../storage/src/postgres-todos.ts
|
|
285458
|
+
init_pg_ident();
|
|
285459
|
+
init_schema_ddl_lock();
|
|
285460
|
+
var PostgresTodoStore = class _PostgresTodoStore {
|
|
285461
|
+
constructor(pool, schema) {
|
|
285462
|
+
this.pool = pool;
|
|
285463
|
+
this.s = quoteIdent2(schema);
|
|
285464
|
+
}
|
|
285465
|
+
s;
|
|
285466
|
+
static async open(pool, schema) {
|
|
285467
|
+
const store = new _PostgresTodoStore(pool, schema);
|
|
285468
|
+
await withSchemaDdlLock(pool, schema, async () => {
|
|
285469
|
+
await pool.query(`CREATE SCHEMA IF NOT EXISTS ${store.s}`);
|
|
285470
|
+
await pool.query(`CREATE TABLE IF NOT EXISTS ${store.s}.todos (
|
|
285471
|
+
id text PRIMARY KEY,
|
|
285472
|
+
title text NOT NULL,
|
|
285473
|
+
note text,
|
|
285474
|
+
creator_actor_id text NOT NULL,
|
|
285475
|
+
assignee_actor_id text NOT NULL,
|
|
285476
|
+
recorded_by_actor_id text NOT NULL,
|
|
285477
|
+
due_date text NOT NULL,
|
|
285478
|
+
due_time text,
|
|
285479
|
+
start_date text,
|
|
285480
|
+
start_time text,
|
|
285481
|
+
status text NOT NULL CHECK (status IN ('open','done','cancelled')),
|
|
285482
|
+
done_at timestamptz,
|
|
285483
|
+
cancelled_at timestamptz,
|
|
285484
|
+
source_chat_session_id text,
|
|
285485
|
+
linked_workorder_id text,
|
|
285486
|
+
created_at timestamptz NOT NULL,
|
|
285487
|
+
updated_at timestamptz NOT NULL
|
|
285488
|
+
)`);
|
|
285489
|
+
await pool.query(`CREATE INDEX IF NOT EXISTS todos_assignee_status_due_idx ON ${store.s}.todos (assignee_actor_id, status, due_date)`);
|
|
285490
|
+
await pool.query(`CREATE INDEX IF NOT EXISTS todos_creator_status_due_idx ON ${store.s}.todos (creator_actor_id, status, due_date)`);
|
|
285491
|
+
await pool.query(`CREATE INDEX IF NOT EXISTS todos_open_due_idx ON ${store.s}.todos (due_date) WHERE status = 'open'`);
|
|
285492
|
+
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`);
|
|
285493
|
+
await pool.query(`CREATE TABLE IF NOT EXISTS ${store.s}.todo_changes (
|
|
285494
|
+
id text PRIMARY KEY,
|
|
285495
|
+
todo_id text NOT NULL REFERENCES ${store.s}.todos(id) ON DELETE CASCADE,
|
|
285496
|
+
actor_id text NOT NULL,
|
|
285497
|
+
hand_actor_id text,
|
|
285498
|
+
at timestamptz NOT NULL,
|
|
285499
|
+
field text NOT NULL,
|
|
285500
|
+
old_value text,
|
|
285501
|
+
new_value text,
|
|
285502
|
+
reason text
|
|
285503
|
+
)`);
|
|
285504
|
+
await pool.query(`CREATE INDEX IF NOT EXISTS todo_changes_todo_at_idx ON ${store.s}.todo_changes (todo_id, at, id)`);
|
|
285505
|
+
});
|
|
285506
|
+
return store;
|
|
285507
|
+
}
|
|
285508
|
+
async tx(run) {
|
|
285509
|
+
const client = await this.pool.connect();
|
|
285510
|
+
try {
|
|
285511
|
+
await client.query("BEGIN");
|
|
285512
|
+
const result = await run(client);
|
|
285513
|
+
await client.query("COMMIT");
|
|
285514
|
+
return result;
|
|
285515
|
+
} catch (error2) {
|
|
285516
|
+
await client.query("ROLLBACK");
|
|
285517
|
+
throw error2;
|
|
285518
|
+
} finally {
|
|
285519
|
+
client.release();
|
|
285520
|
+
}
|
|
285521
|
+
}
|
|
285522
|
+
async insertChanges(client, changes) {
|
|
285523
|
+
for (const c of changes) {
|
|
285524
|
+
await client.query(
|
|
285525
|
+
`INSERT INTO ${this.s}.todo_changes (id,todo_id,actor_id,hand_actor_id,at,field,old_value,new_value,reason)
|
|
285526
|
+
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9)`,
|
|
285527
|
+
[c.id, c.todoId, c.actorId, c.handActorId ?? null, c.at, c.field, c.oldValue ?? null, c.newValue ?? null, c.reason ?? null]
|
|
285528
|
+
);
|
|
285529
|
+
}
|
|
285530
|
+
}
|
|
285531
|
+
async create(todo, changes) {
|
|
285532
|
+
return this.tx(async (client) => {
|
|
285533
|
+
const r = await client.query(`INSERT INTO ${this.s}.todos (id,title,note,creator_actor_id,assignee_actor_id,recorded_by_actor_id,
|
|
285534
|
+
due_date,due_time,status,done_at,cancelled_at,source_chat_session_id,linked_workorder_id,created_at,updated_at,start_date,start_time)
|
|
285535
|
+
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17) RETURNING *`, rowValues(todo));
|
|
285536
|
+
await this.insertChanges(client, changes);
|
|
285537
|
+
return fromRow3(r.rows[0]);
|
|
285538
|
+
});
|
|
285539
|
+
}
|
|
285540
|
+
async get(id) {
|
|
285541
|
+
const r = await this.pool.query(`SELECT * FROM ${this.s}.todos WHERE id=$1`, [id]);
|
|
285542
|
+
return r.rows[0] ? fromRow3(r.rows[0]) : null;
|
|
285543
|
+
}
|
|
285544
|
+
async update(next, expectedUpdatedAt, changes) {
|
|
285545
|
+
return this.tx(async (client) => {
|
|
285546
|
+
const r = await client.query(`UPDATE ${this.s}.todos SET title=$2,note=$3,creator_actor_id=$4,assignee_actor_id=$5,
|
|
285547
|
+
recorded_by_actor_id=$6,due_date=$7,due_time=$8,status=$9,done_at=$10,cancelled_at=$11,source_chat_session_id=$12,
|
|
285548
|
+
linked_workorder_id=$13,created_at=$14,updated_at=$15,start_date=$16,start_time=$17
|
|
285549
|
+
WHERE id=$1 AND updated_at=$18::timestamptz RETURNING *`, [...rowValues(next), expectedUpdatedAt]);
|
|
285550
|
+
if (!r.rows[0]) return null;
|
|
285551
|
+
await this.insertChanges(client, changes);
|
|
285552
|
+
return fromRow3(r.rows[0]);
|
|
285553
|
+
});
|
|
285554
|
+
}
|
|
285555
|
+
async listInvolving(actorId, statuses2) {
|
|
285556
|
+
const r = await this.pool.query(`SELECT * FROM ${this.s}.todos
|
|
285557
|
+
WHERE (creator_actor_id=$1 OR assignee_actor_id=$1) AND status = ANY($2::text[])
|
|
285558
|
+
ORDER BY due_date, COALESCE(due_time,'99:99'), created_at, id`, [actorId, [...statuses2]]);
|
|
285559
|
+
return r.rows.map(fromRow3);
|
|
285560
|
+
}
|
|
285561
|
+
async listOpenReminderCandidates(fromDay, toDay) {
|
|
285562
|
+
const r = await this.pool.query(`SELECT * FROM ${this.s}.todos
|
|
285563
|
+
WHERE status='open' AND (due_date BETWEEN $1 AND $2 OR start_date BETWEEN $1 AND $2)
|
|
285564
|
+
ORDER BY due_date, COALESCE(due_time,'99:99'), created_at, id`, [fromDay, toDay]);
|
|
285565
|
+
return r.rows.map(fromRow3);
|
|
285566
|
+
}
|
|
285567
|
+
async listChanges(todoId) {
|
|
285568
|
+
const r = await this.pool.query(`SELECT * FROM ${this.s}.todo_changes WHERE todo_id=$1 ORDER BY at, id`, [todoId]);
|
|
285569
|
+
return r.rows.map((row) => {
|
|
285570
|
+
const c = { id: row.id, todoId: row.todo_id, actorId: row.actor_id, at: iso8(row.at), field: row.field };
|
|
285571
|
+
if (row.hand_actor_id) c.handActorId = row.hand_actor_id;
|
|
285572
|
+
if (row.old_value !== null) c.oldValue = row.old_value;
|
|
285573
|
+
if (row.new_value !== null) c.newValue = row.new_value;
|
|
285574
|
+
if (row.reason !== null) c.reason = row.reason;
|
|
285575
|
+
return c;
|
|
285576
|
+
});
|
|
285577
|
+
}
|
|
285578
|
+
};
|
|
285579
|
+
var iso8 = (v2) => v2 instanceof Date ? v2.toISOString() : typeof v2 === "string" ? new Date(v2).toISOString() : void 0;
|
|
285580
|
+
function rowValues(t) {
|
|
285581
|
+
return [
|
|
285582
|
+
t.id,
|
|
285583
|
+
t.title,
|
|
285584
|
+
t.note ?? null,
|
|
285585
|
+
t.creatorActorId,
|
|
285586
|
+
t.assigneeActorId,
|
|
285587
|
+
t.recordedByActorId,
|
|
285588
|
+
t.dueDate,
|
|
285589
|
+
t.dueTime ?? null,
|
|
285590
|
+
t.status,
|
|
285591
|
+
t.doneAt ?? null,
|
|
285592
|
+
t.cancelledAt ?? null,
|
|
285593
|
+
t.sourceChatSessionId ?? null,
|
|
285594
|
+
t.linkedWorkorderId ?? null,
|
|
285595
|
+
t.createdAt,
|
|
285596
|
+
t.updatedAt,
|
|
285597
|
+
t.startDate ?? null,
|
|
285598
|
+
t.startTime ?? null
|
|
285599
|
+
];
|
|
285600
|
+
}
|
|
285601
|
+
function fromRow3(row) {
|
|
285602
|
+
const t = {
|
|
285603
|
+
id: row["id"],
|
|
285604
|
+
title: row["title"],
|
|
285605
|
+
creatorActorId: row["creator_actor_id"],
|
|
285606
|
+
assigneeActorId: row["assignee_actor_id"],
|
|
285607
|
+
recordedByActorId: row["recorded_by_actor_id"],
|
|
285608
|
+
dueDate: row["due_date"],
|
|
285609
|
+
status: row["status"],
|
|
285610
|
+
createdAt: iso8(row["created_at"]),
|
|
285611
|
+
updatedAt: iso8(row["updated_at"])
|
|
285612
|
+
};
|
|
285613
|
+
const opt = [
|
|
285614
|
+
["note", row["note"]],
|
|
285615
|
+
["dueTime", row["due_time"]],
|
|
285616
|
+
["startDate", row["start_date"]],
|
|
285617
|
+
["startTime", row["start_time"]],
|
|
285618
|
+
["doneAt", iso8(row["done_at"])],
|
|
285619
|
+
["cancelledAt", iso8(row["cancelled_at"])],
|
|
285620
|
+
["sourceChatSessionId", row["source_chat_session_id"]],
|
|
285621
|
+
["linkedWorkorderId", row["linked_workorder_id"]]
|
|
285622
|
+
];
|
|
285623
|
+
for (const [k2, v2] of opt) if (v2 !== void 0 && v2 !== null) t[k2] = v2;
|
|
285624
|
+
return t;
|
|
285625
|
+
}
|
|
285626
|
+
|
|
284439
285627
|
// ../cli/src/rebuild-artifact-projections-per-company.ts
|
|
284440
285628
|
init_src11();
|
|
284441
285629
|
var DEFAULT_LOGGER = {
|
|
@@ -284492,7 +285680,7 @@ init_src4();
|
|
|
284492
285680
|
init_chat_exit();
|
|
284493
285681
|
|
|
284494
285682
|
// ../cli/src/chat-task-header.ts
|
|
284495
|
-
var
|
|
285683
|
+
var import_node_crypto92 = require("node:crypto");
|
|
284496
285684
|
init_src11();
|
|
284497
285685
|
init_src();
|
|
284498
285686
|
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";
|
|
@@ -284553,7 +285741,7 @@ function buildChatTurnPrompts(input) {
|
|
|
284553
285741
|
};
|
|
284554
285742
|
}
|
|
284555
285743
|
function chatSystemPromptFingerprint(systemPrompt) {
|
|
284556
|
-
return (0,
|
|
285744
|
+
return (0, import_node_crypto92.createHash)("sha256").update(systemPrompt ?? "").digest("hex").slice(0, 16);
|
|
284557
285745
|
}
|
|
284558
285746
|
|
|
284559
285747
|
// ../cli/src/chat-task-md.ts
|
|
@@ -285407,7 +286595,7 @@ function oasisWrapperScript() {
|
|
|
285407
286595
|
const repoRoot = (0, import_node_url7.fileURLToPath)(new URL("../../../", __esm_import_meta_url));
|
|
285408
286596
|
const tsx = path29.join(repoRoot, "node_modules/.bin/tsx");
|
|
285409
286597
|
const main = path29.join(repoRoot, "packages/cli/src/main.ts");
|
|
285410
|
-
const key2 = (0,
|
|
286598
|
+
const key2 = (0, import_node_crypto93.createHash)("sha256").update(repoRoot).digest("hex").slice(0, 12);
|
|
285411
286599
|
const uid = typeof process.getuid === "function" ? process.getuid() : "na";
|
|
285412
286600
|
const stable = path29.join(os9.tmpdir(), `oasis-cli-wrapper-${uid}-${key2}`);
|
|
285413
286601
|
let dir;
|
|
@@ -285627,6 +286815,14 @@ function consoleLinksFromEnv(rawUrl, rawRoutes) {
|
|
|
285627
286815
|
}
|
|
285628
286816
|
async function startServe(opts) {
|
|
285629
286817
|
const serverStartedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
286818
|
+
let defaultTimeZone;
|
|
286819
|
+
try {
|
|
286820
|
+
defaultTimeZone = defaultTimeZoneFromEnv(process.env[DEFAULT_TIME_ZONE_ENV]);
|
|
286821
|
+
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`);
|
|
286822
|
+
} catch (err) {
|
|
286823
|
+
console.error(`[serve] ${err.message}`);
|
|
286824
|
+
throw err;
|
|
286825
|
+
}
|
|
285630
286826
|
fs36.mkdirSync(opts.dir, { recursive: true });
|
|
285631
286827
|
const serverHeartbeatFile = path29.join(opts.dir, "serve-heartbeat.json");
|
|
285632
286828
|
let previousServerHeartbeatAt;
|
|
@@ -285819,7 +287015,7 @@ async function startServe(opts) {
|
|
|
285819
287015
|
if (!hub) return Promise.resolve({ ok: false, reason: "\u672C\u8FDB\u7A0B\u6CA1\u6709\u8282\u70B9\u7F51\u5173" });
|
|
285820
287016
|
const online = hub.connectedDaemons().some((d) => d.daemonId === nodeId);
|
|
285821
287017
|
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" });
|
|
285822
|
-
const requestId = (0,
|
|
287018
|
+
const requestId = (0, import_node_crypto93.randomUUID)();
|
|
285823
287019
|
const task = new Promise((resolve11) => {
|
|
285824
287020
|
const timer = setTimeout(() => {
|
|
285825
287021
|
modelRefreshWaiters.delete(requestId);
|
|
@@ -285893,6 +287089,8 @@ async function startServe(opts) {
|
|
|
285893
287089
|
// 租户闸(ADR-0164 §5):`POST /api/bindings` 据它拦「把本公司员工绑到别家公司的机器上」。
|
|
285894
287090
|
// 闭包读当前 nodeStore(下方 PG 分支会重赋值),与 `listBindingModelIds` 同一写法。
|
|
285895
287091
|
resolveNodeTenancy: async (nodeId) => nodeStore.getNode(nodeId),
|
|
287092
|
+
// 变量到期按组织的生效时区算日界(PRD v1.2 §7)。`companies` 在下方才建好——本箭头只在派单 / 请求时跑,那时已就绪。
|
|
287093
|
+
companyTimeZone: (companyId) => companies.service.effectiveTimeZoneOf(companyId),
|
|
285896
287094
|
store: registryStore,
|
|
285897
287095
|
oplog,
|
|
285898
287096
|
kernel: defaultCompanyKernel,
|
|
@@ -286666,7 +287864,7 @@ async function startServe(opts) {
|
|
|
286666
287864
|
const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
286667
287865
|
if (buf || session.runId) {
|
|
286668
287866
|
await turnStore.appendMessage({
|
|
286669
|
-
id: (0,
|
|
287867
|
+
id: (0, import_node_crypto93.randomUUID)(),
|
|
286670
287868
|
sessionId: chatSessionId,
|
|
286671
287869
|
role: "assistant",
|
|
286672
287870
|
content: buf,
|
|
@@ -286712,7 +287910,7 @@ async function startServe(opts) {
|
|
|
286712
287910
|
chatTargets: {
|
|
286713
287911
|
inspect: inspectChatTarget,
|
|
286714
287912
|
createTargetSession: async ({ companyId, agentId, ownerHumanActorId, title }) => {
|
|
286715
|
-
const sessionId = (0,
|
|
287913
|
+
const sessionId = (0, import_node_crypto93.randomUUID)();
|
|
286716
287914
|
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
286717
287915
|
const binding = await registryStore.getBinding(agentId).catch(() => null);
|
|
286718
287916
|
await (await chatStoreFor(companyId)).createSession({
|
|
@@ -286828,7 +288026,26 @@ async function startServe(opts) {
|
|
|
286828
288026
|
secret: jwtSecret ?? "oasis-dev-secret",
|
|
286829
288027
|
onAuthFailure: (reason) => console.warn(`[org-model] agent credential auth failure: ${reason}`)
|
|
286830
288028
|
});
|
|
286831
|
-
const companies = createCompaniesDomain({
|
|
288029
|
+
const companies = createCompaniesDomain({
|
|
288030
|
+
store: controlPlaneStore,
|
|
288031
|
+
blobs,
|
|
288032
|
+
sender: mailSender,
|
|
288033
|
+
consoleUrl,
|
|
288034
|
+
resolveActorsCtx: actors.resolveCtx,
|
|
288035
|
+
listInFlightAssignments,
|
|
288036
|
+
agentCredentials,
|
|
288037
|
+
defaultTimeZone,
|
|
288038
|
+
// 注销的邮箱验证门禁(设置页 PRD §4.3):票据由 auth 域签发与校验。auth 要拿 companies.service
|
|
288039
|
+
// 建号,只能建在后面——这里包一层闭包,请求时才解引用,不撞 TDZ。
|
|
288040
|
+
verifyAccountDeletionTicket: (accountId, ticket) => auth.verifyAccountDeletionTicket(accountId, ticket),
|
|
288041
|
+
// 改成员昵称时同步其懒创建助理的名字(设置页 PRD §3.1)。解析器在下方才装好、只在请求时调用;
|
|
288042
|
+
// 还没装好(启动期,没有请求)就当作没有绑定,只改真人档案。
|
|
288043
|
+
assistantOfHuman: async (companyId, humanActorId) => {
|
|
288044
|
+
const ctx = await resolveAssistantsCtxLazy(companyId);
|
|
288045
|
+
const bond = ctx ? await ctx.service.getByHuman(humanActorId) : null;
|
|
288046
|
+
return bond ? { agentActorId: bond.agentActorId, origin: bond.origin } : null;
|
|
288047
|
+
}
|
|
288048
|
+
});
|
|
286832
288049
|
const auth = createAuth({
|
|
286833
288050
|
store: controlPlaneStore,
|
|
286834
288051
|
sender: mailSender,
|
|
@@ -287849,6 +289066,13 @@ async function startServe(opts) {
|
|
|
287849
289066
|
clearFault: async (t) => {
|
|
287850
289067
|
await nodeStore.clearRuntimeFault(t.nodeId, t.runtimeKind);
|
|
287851
289068
|
},
|
|
289069
|
+
/* ADR 0633:撞限流 → 叫那台机器现去问一遍额度。只发给自报能重采的节点;结果帧没人等,
|
|
289070
|
+
serve 那边按不认识的 requestId 丢掉,新数据照旧走 runtime_quotas 落库;用满了才解除落库故障、改按重置时刻挡。 */
|
|
289071
|
+
onQuotaExhausted: (t) => {
|
|
289072
|
+
const daemon = hub?.connectedDaemons().find((d) => d.daemonId === t.nodeId);
|
|
289073
|
+
if (!daemon?.meta.supportsQuotaRefresh) return;
|
|
289074
|
+
hub?.dispatch(t.nodeId, { type: "refresh_quotas", requestId: (0, import_node_crypto93.randomUUID)() });
|
|
289075
|
+
},
|
|
287852
289076
|
actorName: async (actorId) => (await (await actors.resolveCtx(companyId)).service.getActor(actorId).catch(() => null))?.name ?? null
|
|
287853
289077
|
});
|
|
287854
289078
|
runtimeAllocators.set(companyId, allocator);
|
|
@@ -287962,6 +289186,30 @@ async function startServe(opts) {
|
|
|
287962
289186
|
isDelegationChild: async (sessionId, companyId) => Boolean(await (await delegationStoreFor(companyId)).getByChildSession(sessionId)),
|
|
287963
289187
|
warn: (error2) => console.warn(`[discussions] ${String(error2)}`)
|
|
287964
289188
|
});
|
|
289189
|
+
const todoStores = /* @__PURE__ */ new Map();
|
|
289190
|
+
const todoRuntime = createTodoRuntime({
|
|
289191
|
+
companies: async () => (await controlPlaneStore.listCompanies()).filter((c) => c.status === "active").map((c) => c.id),
|
|
289192
|
+
store: (companyId) => {
|
|
289193
|
+
let store = todoStores.get(companyId);
|
|
289194
|
+
if (!store) {
|
|
289195
|
+
store = pgPool ? PostgresTodoStore.open(pgPool, engineSchemaFor(companyId)) : MemoryTodoStore.open(path29.join(opts.dir, "companies", companyEngineDirName(companyId), "todos.json"));
|
|
289196
|
+
todoStores.set(companyId, store);
|
|
289197
|
+
void store.catch(() => todoStores.delete(companyId));
|
|
289198
|
+
}
|
|
289199
|
+
return store;
|
|
289200
|
+
},
|
|
289201
|
+
timeZone: (companyId) => companies.service.effectiveTimeZoneOf(companyId),
|
|
289202
|
+
boundHuman: async (agentId, companyId) => (await (await resolveAssistantsCtx(companyId)).service.getByAgent(agentId))?.humanActorId ?? null,
|
|
289203
|
+
notifications: (companyId) => notificationStoreFor(companyId),
|
|
289204
|
+
onReminders: (companyId, records) => {
|
|
289205
|
+
pushNotifier?.notify(companyId, records);
|
|
289206
|
+
const recipients = [...new Set(records.map((r) => r.recipient))];
|
|
289207
|
+
console.warn(`[todos] ${companyId} \u5230\u671F\u63D0\u9192 ${records.length} \u6761 \u2192 ${recipients.join(",")}`);
|
|
289208
|
+
auditSink.notifyNotificationsChanged(recipients);
|
|
289209
|
+
},
|
|
289210
|
+
defaultCompanyId: () => defaultCompanyId,
|
|
289211
|
+
warn: (error2) => console.warn(`[todos] ${String(error2)}`)
|
|
289212
|
+
});
|
|
287965
289213
|
let notificationLedgerWorker;
|
|
287966
289214
|
let pushNotifier;
|
|
287967
289215
|
let notificationLedgerTimer;
|
|
@@ -288067,6 +289315,7 @@ async function startServe(opts) {
|
|
|
288067
289315
|
blobs: engine.blobs,
|
|
288068
289316
|
// 自动化 webhook 公开入口(ADR 0156 D4):token 即凭证,归属从触发器行反推。
|
|
288069
289317
|
automationWebhook: (token2, rawBody, headers) => automations.webhook.handle(token2, rawBody, headers),
|
|
289318
|
+
...pgPool ? { deepHealth: () => probePgPool(pgPool) } : {},
|
|
288070
289319
|
...engine.assets ? { assets: engine.assets } : {},
|
|
288071
289320
|
// ★ 新引擎 store:blob GC 从 work_artifacts 扫根(事实源=实体表,oplog 已退役)。
|
|
288072
289321
|
engineStore: engine.kernel.getStore?.(),
|
|
@@ -288171,7 +289420,7 @@ async function startServe(opts) {
|
|
|
288171
289420
|
}));
|
|
288172
289421
|
}
|
|
288173
289422
|
const limits = { wallClockMs: wallClockForKind("planner") };
|
|
288174
|
-
const artifactId = `artifact:planner:${(0,
|
|
289423
|
+
const artifactId = `artifact:planner:${(0, import_node_crypto93.randomUUID)()}`;
|
|
288175
289424
|
const handle = await chatRemoteAdapter.spawn({
|
|
288176
289425
|
actor: planner.id,
|
|
288177
289426
|
// companyId 同协调者:planner 用的就是默认公司的 actors 服务,漏签会让它一调公司域端点就 404。
|
|
@@ -288213,6 +289462,7 @@ async function startServe(opts) {
|
|
|
288213
289462
|
companies.register,
|
|
288214
289463
|
projectsDomain2.register,
|
|
288215
289464
|
discussionRuntime.register,
|
|
289465
|
+
todoRuntime.register,
|
|
288216
289466
|
typesDomain({
|
|
288217
289467
|
admin: typesAdmin,
|
|
288218
289468
|
resolveAdmin: async (companyId) => {
|
|
@@ -289093,10 +290343,10 @@ async function startServe(opts) {
|
|
|
289093
290343
|
if (isDeletedActor(dispatchTarget)) {
|
|
289094
290344
|
throw new ApiError(409, ACTOR_DELETED_ERROR_CODE, ACTOR_DELETED_CHAT_MESSAGE);
|
|
289095
290345
|
}
|
|
289096
|
-
const runtimeSessionId = sessionId ?? (requestDispatchId ? deterministicUuid(retargetClaimedDispatch ? `chat-runtime:${requestDispatchId}:retry:${(0,
|
|
290346
|
+
const runtimeSessionId = sessionId ?? (requestDispatchId ? deterministicUuid(retargetClaimedDispatch ? `chat-runtime:${requestDispatchId}:retry:${(0, import_node_crypto93.randomUUID)()}` : `chat-runtime:${requestDispatchId}`) : (0, import_node_crypto93.randomUUID)());
|
|
289097
290347
|
const resumeRuntimeSession = Boolean(sessionId);
|
|
289098
|
-
const traceRunId = requestDispatchId ? stableChatTraceRunId(requestDispatchId) : `chat-run:${(0,
|
|
289099
|
-
const artifactId = requestDispatchId ? `artifact:chat:${deterministicUuid(`chat-artifact:${requestDispatchId}`)}` : `artifact:chat:${(0,
|
|
290348
|
+
const traceRunId = requestDispatchId ? stableChatTraceRunId(requestDispatchId) : `chat-run:${(0, import_node_crypto93.randomUUID)()}`;
|
|
290349
|
+
const artifactId = requestDispatchId ? `artifact:chat:${deterministicUuid(`chat-artifact:${requestDispatchId}`)}` : `artifact:chat:${(0, import_node_crypto93.randomUUID)()}`;
|
|
289100
290350
|
let stableDispatch = requestDispatchId ? await resolveStableChatDispatch({ store: await traceStoreFor(runCompanyId), runId: traceRunId }) : null;
|
|
289101
290351
|
const retargetClaim = Boolean(retargetClaimedDispatch && stableDispatch && allocatedTurn);
|
|
289102
290352
|
if (stableDispatch && !stableDispatch.shouldDispatch && !retargetClaim) {
|
|
@@ -289853,6 +291103,7 @@ async function startServe(opts) {
|
|
|
289853
291103
|
notifications: auditSink.notifications
|
|
289854
291104
|
});
|
|
289855
291105
|
discussionRuntime.start();
|
|
291106
|
+
todoRuntime.start();
|
|
289856
291107
|
projectsDomain2.service.setProjectCreatedHandler(async (project) => {
|
|
289857
291108
|
if (!server.knowledgeGovernance) return;
|
|
289858
291109
|
await server.knowledgeGovernance.initializeProjectSpace({
|
|
@@ -290759,7 +292010,7 @@ async function startServe(opts) {
|
|
|
290759
292010
|
console.log(`[new-engine] dispatchWork ${workId} \u662F human work\u2014\u2014\u4E0D\u6D3E runtime\uFF0C\u7B49\u5F85\u4EBA\u5DE5\u5904\u7406`);
|
|
290760
292011
|
return;
|
|
290761
292012
|
}
|
|
290762
|
-
const ledgerId = opts2?.protocolRecovery?.dispatchId ?? `dispatch:${(0,
|
|
292013
|
+
const ledgerId = opts2?.protocolRecovery?.dispatchId ?? `dispatch:${(0, import_node_crypto93.randomUUID)()}`;
|
|
290763
292014
|
try {
|
|
290764
292015
|
const inserted = await (await dispatchLedgerFor(companyId)).insertOpen({
|
|
290765
292016
|
id: ledgerId,
|
|
@@ -290859,7 +292110,7 @@ async function startServe(opts) {
|
|
|
290859
292110
|
const kernelModel = newKernel.model;
|
|
290860
292111
|
const art = kernelModel.artifacts.get(nodeId);
|
|
290861
292112
|
const revWid = art?.workspace ?? "";
|
|
290862
|
-
const ledgerId = `dispatch:${(0,
|
|
292113
|
+
const ledgerId = `dispatch:${(0, import_node_crypto93.randomUUID)()}`;
|
|
290863
292114
|
try {
|
|
290864
292115
|
await (await dispatchLedgerFor(companyId)).insertOpen({
|
|
290865
292116
|
id: ledgerId,
|
|
@@ -291230,7 +292481,7 @@ async function startServe(opts) {
|
|
|
291230
292481
|
resolveSupplementalContext: server.knowledgeGovernance ? async ({ actorId, artifactId, workOrderId, action, part, runtimeKind, taskMarkdown }) => {
|
|
291231
292482
|
try {
|
|
291232
292483
|
const governance = server.knowledgeGovernance;
|
|
291233
|
-
const taskFingerprint = (0,
|
|
292484
|
+
const taskFingerprint = (0, import_node_crypto93.createHash)("sha256").update(JSON.stringify({ artifactId, workOrderId, action, part: part ?? null, taskMarkdown })).digest("hex");
|
|
291234
292485
|
const requestContext = {
|
|
291235
292486
|
organizationId: companyId,
|
|
291236
292487
|
actorId,
|
|
@@ -291703,8 +292954,8 @@ async function startServe(opts) {
|
|
|
291703
292954
|
const quotaStarvationMs = opts.sla?.quotaStarvationMs ?? 6 * 36e5;
|
|
291704
292955
|
const nodeIdleFallbackMs = opts.sla?.nodeIdleFallbackMs ?? opts.sla?.reviewStallMs ?? (Number(process.env["OASIS_SLA_NODE_IDLE_FALLBACK_MS"]) || 2 * 36e5);
|
|
291705
292956
|
console.log(`[sla] \u8282\u70B9\u9759\u6B62\u515C\u5E95\u9608\u503C nodeIdleFallbackMs=${nodeIdleFallbackMs}ms\uFF08${Math.round(nodeIdleFallbackMs / 6e4)} \u5206\u949F\uFF09`);
|
|
291706
|
-
const fmtSince = (
|
|
291707
|
-
const min2 = Math.floor(Math.max(0, now - Date.parse(
|
|
292957
|
+
const fmtSince = (iso9, now) => {
|
|
292958
|
+
const min2 = Math.floor(Math.max(0, now - Date.parse(iso9)) / 6e4);
|
|
291708
292959
|
if (!Number.isFinite(min2)) return "\u521A\u624D";
|
|
291709
292960
|
if (min2 < 1) return "\u4E0D\u5230 1 \u5206\u949F\u524D";
|
|
291710
292961
|
if (min2 < 60) return `${min2} \u5206\u949F\u524D`;
|
|
@@ -292707,6 +293958,7 @@ ${nodeFault}` : "");
|
|
|
292707
293958
|
})
|
|
292708
293959
|
]);
|
|
292709
293960
|
await discussionRuntime.stop();
|
|
293961
|
+
todoRuntime.stop();
|
|
292710
293962
|
for (const timer of dispatchTimers) clearInterval(timer);
|
|
292711
293963
|
clearInterval(slaTimer);
|
|
292712
293964
|
escalationDeliveryWorker.stop();
|
|
@@ -293733,9 +294985,9 @@ function readCodexQuota(binary, signal, timeoutMs = 15e3) {
|
|
|
293733
294985
|
|
|
293734
294986
|
// ../cli/src/daemon/quota/claude.ts
|
|
293735
294987
|
var import_node_child_process18 = require("node:child_process");
|
|
293736
|
-
var
|
|
294988
|
+
var import_promises19 = require("node:fs/promises");
|
|
293737
294989
|
var import_node_os12 = require("node:os");
|
|
293738
|
-
var
|
|
294990
|
+
var import_node_path31 = require("node:path");
|
|
293739
294991
|
var import_node_util5 = require("node:util");
|
|
293740
294992
|
var exec = (0, import_node_util5.promisify)(import_node_child_process18.execFile);
|
|
293741
294993
|
var USAGE_URL = "https://api.anthropic.com/api/oauth/usage";
|
|
@@ -293754,9 +295006,9 @@ async function credentials(env, signal) {
|
|
|
293754
295006
|
}
|
|
293755
295007
|
}
|
|
293756
295008
|
if (!raw) {
|
|
293757
|
-
const file = (0,
|
|
293758
|
-
if ((await (0,
|
|
293759
|
-
raw = await (0,
|
|
295009
|
+
const file = (0, import_node_path31.join)(env.CLAUDE_CONFIG_DIR || (0, import_node_path31.join)((0, import_node_os12.homedir)(), ".claude"), ".credentials.json");
|
|
295010
|
+
if ((await (0, import_promises19.stat)(file)).size > 256 * 1024) return void 0;
|
|
295011
|
+
raw = await (0, import_promises19.readFile)(file, { encoding: "utf8", ...signal ? { signal } : {} });
|
|
293760
295012
|
}
|
|
293761
295013
|
const oauth = object6(object6(JSON.parse(raw)).claudeAiOauth);
|
|
293762
295014
|
if (typeof oauth.expiresAt === "number" && oauth.expiresAt <= Date.now()) return void 0;
|
|
@@ -293825,18 +295077,18 @@ async function readClaudeQuota(binary, signal, deps = {}) {
|
|
|
293825
295077
|
}
|
|
293826
295078
|
|
|
293827
295079
|
// ../cli/src/daemon/quota/shared-cache.ts
|
|
293828
|
-
var
|
|
295080
|
+
var import_node_crypto94 = require("node:crypto");
|
|
293829
295081
|
var import_node_fs25 = require("node:fs");
|
|
293830
295082
|
var import_node_os13 = require("node:os");
|
|
293831
|
-
var
|
|
295083
|
+
var import_node_path32 = require("node:path");
|
|
293832
295084
|
init_src();
|
|
293833
295085
|
function profileOf(kind, env) {
|
|
293834
|
-
if (kind === "codex") return `codex:${env.CODEX_HOME || (0,
|
|
293835
|
-
if (env.CLAUDE_CODE_OAUTH_TOKEN) return `claude-token:${(0,
|
|
293836
|
-
return `claude:${env.CLAUDE_CONFIG_DIR || (0,
|
|
295086
|
+
if (kind === "codex") return `codex:${env.CODEX_HOME || (0, import_node_path32.join)((0, import_node_os13.homedir)(), ".codex")}`;
|
|
295087
|
+
if (env.CLAUDE_CODE_OAUTH_TOKEN) return `claude-token:${(0, import_node_crypto94.createHash)("sha256").update(env.CLAUDE_CODE_OAUTH_TOKEN).digest("hex")}`;
|
|
295088
|
+
return `claude:${env.CLAUDE_CONFIG_DIR || (0, import_node_path32.join)((0, import_node_os13.homedir)(), ".claude")}`;
|
|
293837
295089
|
}
|
|
293838
295090
|
function fileQuotaCache(dir, env = process.env) {
|
|
293839
|
-
const file = (kind) => (0,
|
|
295091
|
+
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`);
|
|
293840
295092
|
return {
|
|
293841
295093
|
get(kind) {
|
|
293842
295094
|
try {
|
|
@@ -293857,49 +295109,71 @@ function fileQuotaCache(dir, env = process.env) {
|
|
|
293857
295109
|
(0, import_node_fs25.renameSync)(tmp, target);
|
|
293858
295110
|
} catch {
|
|
293859
295111
|
}
|
|
295112
|
+
},
|
|
295113
|
+
claim(kind, ttlMs) {
|
|
295114
|
+
const lock = `${file(kind)}.lock`;
|
|
295115
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
295116
|
+
try {
|
|
295117
|
+
(0, import_node_fs25.mkdirSync)(dir, { recursive: true, mode: 448 });
|
|
295118
|
+
(0, import_node_fs25.writeFileSync)(lock, String(process.pid), { flag: "wx", mode: 384 });
|
|
295119
|
+
return true;
|
|
295120
|
+
} catch (err) {
|
|
295121
|
+
if (err.code !== "EEXIST") return true;
|
|
295122
|
+
try {
|
|
295123
|
+
if (Date.now() - (0, import_node_fs25.statSync)(lock).mtimeMs < ttlMs) return false;
|
|
295124
|
+
(0, import_node_fs25.unlinkSync)(lock);
|
|
295125
|
+
} catch {
|
|
295126
|
+
}
|
|
295127
|
+
}
|
|
295128
|
+
}
|
|
295129
|
+
return false;
|
|
295130
|
+
},
|
|
295131
|
+
release(kind) {
|
|
295132
|
+
try {
|
|
295133
|
+
(0, import_node_fs25.unlinkSync)(`${file(kind)}.lock`);
|
|
295134
|
+
} catch {
|
|
295135
|
+
}
|
|
293860
295136
|
}
|
|
293861
295137
|
};
|
|
293862
295138
|
}
|
|
293863
295139
|
|
|
293864
295140
|
// ../cli/src/daemon/quota/monitor.ts
|
|
295141
|
+
var CLAIM_TTL_MS = 3e4;
|
|
295142
|
+
var PEER_POLL_MS = 500;
|
|
293865
295143
|
var read2 = (runtime, signal) => runtime.kind === "codex" ? readCodexQuota(runtime.binary ?? "codex", signal) : readClaudeQuota(runtime.binary ?? "claude", signal, { version: runtime.version });
|
|
293866
295144
|
var RuntimeQuotaMonitor = class _RuntimeQuotaMonitor {
|
|
293867
|
-
constructor(runtimes, send, reader = read2,
|
|
295145
|
+
constructor(runtimes, send, reader = read2, reuseMs = RUNTIME_QUOTA_REUSE_MS, minGapMs = RUNTIME_QUOTA_REFRESH_MIN_GAP_MS, shared = null) {
|
|
293868
295146
|
this.runtimes = runtimes;
|
|
293869
295147
|
this.send = send;
|
|
293870
295148
|
this.reader = reader;
|
|
293871
|
-
this.
|
|
295149
|
+
this.reuseMs = reuseMs;
|
|
293872
295150
|
this.minGapMs = minGapMs;
|
|
293873
295151
|
this.shared = shared;
|
|
293874
295152
|
}
|
|
293875
295153
|
cache = [];
|
|
293876
295154
|
collectedAt;
|
|
293877
295155
|
pending;
|
|
293878
|
-
timer;
|
|
293879
295156
|
abort = new AbortController();
|
|
293880
295157
|
stopped = false;
|
|
293881
295158
|
/** daemon 用的那一份:同机同账号的其它 daemon 刚采过就直接用它的结果(见 shared-cache.ts)。 */
|
|
293882
295159
|
static forNode(runtimes, send, sharedDir) {
|
|
293883
|
-
return new _RuntimeQuotaMonitor(runtimes, send, read2,
|
|
295160
|
+
return new _RuntimeQuotaMonitor(runtimes, send, read2, RUNTIME_QUOTA_REUSE_MS, RUNTIME_QUOTA_REFRESH_MIN_GAP_MS, sharedDir ? fileQuotaCache(sharedDir) : null);
|
|
293884
295161
|
}
|
|
293885
295162
|
connected() {
|
|
293886
295163
|
if (this.stopped) return;
|
|
293887
295164
|
if (this.cache.length) this.send(this.cache);
|
|
293888
|
-
if (!this.timer) this.timer = setInterval(() => {
|
|
293889
|
-
void this.refresh();
|
|
293890
|
-
}, this.intervalMs);
|
|
293891
295165
|
void this.refresh();
|
|
293892
295166
|
}
|
|
293893
295167
|
stop() {
|
|
293894
295168
|
this.stopped = true;
|
|
293895
|
-
if (this.timer) clearInterval(this.timer);
|
|
293896
295169
|
this.abort.abort();
|
|
293897
295170
|
}
|
|
295171
|
+
/** 连接时那一次:复用期内采过(自己或同账号的别的 daemon)就不再问上游。 */
|
|
293898
295172
|
refresh() {
|
|
293899
295173
|
if (this.stopped) return Promise.resolve();
|
|
293900
295174
|
if (this.pending) return this.pending;
|
|
293901
|
-
if (this.collectedAt !== void 0 && Date.now() - this.collectedAt < this.
|
|
293902
|
-
this.pending = this.collect(this.
|
|
295175
|
+
if (this.collectedAt !== void 0 && Date.now() - this.collectedAt < this.reuseMs) return Promise.resolve();
|
|
295176
|
+
this.pending = this.collect(this.reuseMs).finally(() => {
|
|
293903
295177
|
this.pending = void 0;
|
|
293904
295178
|
});
|
|
293905
295179
|
return this.pending;
|
|
@@ -293907,7 +295181,7 @@ var RuntimeQuotaMonitor = class _RuntimeQuotaMonitor {
|
|
|
293907
295181
|
/**
|
|
293908
295182
|
* 人点了页面上的「刷新」(服务端下发 `refresh_quotas`,ADR 0620):**现在就去问上游**。
|
|
293909
295183
|
*
|
|
293910
|
-
* 与 {@link refresh} 的唯一区别就是**不看那
|
|
295184
|
+
* 与 {@link refresh} 的唯一区别就是**不看那 10 分钟复用期**——那条是连接时防重复的闸,
|
|
293911
295185
|
* 对一个正盯着页面等结果的人没有任何意义。换上的是一条窄得多的闸:
|
|
293912
295186
|
* {@link RUNTIME_QUOTA_REFRESH_MIN_GAP_MS}(30 秒)。连点被它挡下,且挡下时**如实说**
|
|
293913
295187
|
* 「刚在 N 秒前采过」,不假装采了一次(发起人方申的定则:会静默降级的动作必须回报走了哪条路)。
|
|
@@ -293939,6 +295213,16 @@ var RuntimeQuotaMonitor = class _RuntimeQuotaMonitor {
|
|
|
293939
295213
|
for (const r of this.runtimes) if (r.kind === "codex" || r.kind === "claude-code") kinds.push(r.kind);
|
|
293940
295214
|
return kinds;
|
|
293941
295215
|
}
|
|
295216
|
+
/** 等持锁的那个 daemon 把结果写进共享缓存;等不到(它挂了 / 采失败不外传)就回 undefined,自己去问。 */
|
|
295217
|
+
async awaitPeer(kind) {
|
|
295218
|
+
const since = Date.now();
|
|
295219
|
+
while (!this.stopped && Date.now() - since < CLAIM_TTL_MS) {
|
|
295220
|
+
await new Promise((r) => setTimeout(r, PEER_POLL_MS));
|
|
295221
|
+
const peer = this.shared?.get(kind);
|
|
295222
|
+
if (peer && Date.parse(peer.checkedAt) >= since - PEER_POLL_MS) return peer;
|
|
295223
|
+
}
|
|
295224
|
+
return void 0;
|
|
295225
|
+
}
|
|
293942
295226
|
/** `maxAgeMs`:同机其它 daemon 采到的结果在这个时长内就直接用,不再去问上游。 */
|
|
293943
295227
|
async collect(maxAgeMs) {
|
|
293944
295228
|
const result = [];
|
|
@@ -293956,6 +295240,15 @@ var RuntimeQuotaMonitor = class _RuntimeQuotaMonitor {
|
|
|
293956
295240
|
result.push({ ...peer, kind });
|
|
293957
295241
|
continue;
|
|
293958
295242
|
}
|
|
295243
|
+
const held = this.shared?.claim ? this.shared.claim(kind, CLAIM_TTL_MS) : false;
|
|
295244
|
+
if (this.shared?.claim && !held) {
|
|
295245
|
+
const theirs = await this.awaitPeer(kind);
|
|
295246
|
+
if (this.stopped) return;
|
|
295247
|
+
if (theirs) {
|
|
295248
|
+
result.push({ ...theirs, kind });
|
|
295249
|
+
continue;
|
|
295250
|
+
}
|
|
295251
|
+
}
|
|
293959
295252
|
let quota;
|
|
293960
295253
|
try {
|
|
293961
295254
|
quota = await this.reader(runtime, this.abort.signal);
|
|
@@ -293963,6 +295256,7 @@ var RuntimeQuotaMonitor = class _RuntimeQuotaMonitor {
|
|
|
293963
295256
|
quota = { status: "error", windows: [], checkedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
293964
295257
|
}
|
|
293965
295258
|
if (quota.status === "ok" || quota.status === "rate_limited") this.shared?.put(kind, quota);
|
|
295259
|
+
if (held) this.shared?.release?.(kind);
|
|
293966
295260
|
result.push({ ...quota, kind });
|
|
293967
295261
|
}
|
|
293968
295262
|
if (this.stopped) return;
|
|
@@ -293976,7 +295270,7 @@ var RuntimeQuotaMonitor = class _RuntimeQuotaMonitor {
|
|
|
293976
295270
|
init_wrapper();
|
|
293977
295271
|
init_src();
|
|
293978
295272
|
var import_node_os14 = require("node:os");
|
|
293979
|
-
var
|
|
295273
|
+
var import_node_crypto95 = require("node:crypto");
|
|
293980
295274
|
init_src8();
|
|
293981
295275
|
init_src2();
|
|
293982
295276
|
|
|
@@ -294042,7 +295336,7 @@ function detectRuntimes() {
|
|
|
294042
295336
|
|
|
294043
295337
|
// ../cli/src/daemon/workdir-handler.ts
|
|
294044
295338
|
var import_node_fs26 = __toESM(require("node:fs"), 1);
|
|
294045
|
-
var
|
|
295339
|
+
var import_node_path33 = __toESM(require("node:path"), 1);
|
|
294046
295340
|
init_src2();
|
|
294047
295341
|
init_src();
|
|
294048
295342
|
var WORKDIR_READ_MAX_BYTES = 2 * 1024 * 1024;
|
|
@@ -294063,10 +295357,10 @@ function isSensitiveSegment(segment) {
|
|
|
294063
295357
|
}
|
|
294064
295358
|
function relPathIsSensitive(rel) {
|
|
294065
295359
|
if (!rel) return false;
|
|
294066
|
-
return rel.split(
|
|
295360
|
+
return rel.split(import_node_path33.default.sep).some((seg) => seg.length > 0 && isSensitiveSegment(seg));
|
|
294067
295361
|
}
|
|
294068
295362
|
function withinBase(p2, base) {
|
|
294069
|
-
return p2 === base || p2.startsWith(base +
|
|
295363
|
+
return p2 === base || p2.startsWith(base + import_node_path33.default.sep);
|
|
294070
295364
|
}
|
|
294071
295365
|
function normalizeRel(raw) {
|
|
294072
295366
|
const trimmed = (raw ?? "").trim();
|
|
@@ -294083,7 +295377,7 @@ async function trustedCanonicalContainer(req, logicalBase, dirKind) {
|
|
|
294083
295377
|
} catch {
|
|
294084
295378
|
return null;
|
|
294085
295379
|
}
|
|
294086
|
-
return isLegacy ?
|
|
295380
|
+
return isLegacy ? import_node_path33.default.join(trustedRootReal, "oasis-chat-sessions") : import_node_path33.default.join(trustedRootReal, "sessions", dirKind);
|
|
294087
295381
|
}
|
|
294088
295382
|
async function resolveWithinWorkdir(req) {
|
|
294089
295383
|
const dirKind = sessionDirKind(req.runtimeKind);
|
|
@@ -294101,11 +295395,11 @@ async function resolveWithinWorkdir(req) {
|
|
|
294101
295395
|
} catch {
|
|
294102
295396
|
return { ok: false, code: "NOT_FOUND" };
|
|
294103
295397
|
}
|
|
294104
|
-
if (
|
|
295398
|
+
if (import_node_path33.default.dirname(base) !== canonicalContainer) return { ok: false, code: "PATH_ESCAPE" };
|
|
294105
295399
|
const rel = normalizeRel(req.path);
|
|
294106
|
-
const requested =
|
|
295400
|
+
const requested = import_node_path33.default.resolve(base, rel);
|
|
294107
295401
|
if (!withinBase(requested, base)) return { ok: false, code: "PATH_ESCAPE" };
|
|
294108
|
-
const cleanRel = base === requested ? "" :
|
|
295402
|
+
const cleanRel = base === requested ? "" : import_node_path33.default.relative(base, requested);
|
|
294109
295403
|
if (relPathIsSensitive(cleanRel)) return { ok: false, code: "SENSITIVE" };
|
|
294110
295404
|
let real;
|
|
294111
295405
|
try {
|
|
@@ -294115,7 +295409,7 @@ async function resolveWithinWorkdir(req) {
|
|
|
294115
295409
|
return { ok: false, code: "PATH_ESCAPE" };
|
|
294116
295410
|
}
|
|
294117
295411
|
if (!withinBase(real, base)) return { ok: false, code: "PATH_ESCAPE" };
|
|
294118
|
-
const realRel = base === real ? "" :
|
|
295412
|
+
const realRel = base === real ? "" : import_node_path33.default.relative(base, real);
|
|
294119
295413
|
if (relPathIsSensitive(realRel)) return { ok: false, code: "SENSITIVE" };
|
|
294120
295414
|
return { ok: true, base, real };
|
|
294121
295415
|
}
|
|
@@ -294151,7 +295445,7 @@ async function handleWorkdirList(req) {
|
|
|
294151
295445
|
const slice = truncated ? visible.slice(0, WORKDIR_LIST_MAX_ENTRIES) : visible;
|
|
294152
295446
|
const entries = [];
|
|
294153
295447
|
for (const d of slice) {
|
|
294154
|
-
const abs =
|
|
295448
|
+
const abs = import_node_path33.default.join(anchor, d.name);
|
|
294155
295449
|
try {
|
|
294156
295450
|
const st = await import_node_fs26.default.promises.lstat(abs);
|
|
294157
295451
|
if (st.isSymbolicLink()) continue;
|
|
@@ -294218,7 +295512,7 @@ async function verifyOpenedFd(fh, base, fallback) {
|
|
|
294218
295512
|
const fdReal = await fdCanonicalPath(fh);
|
|
294219
295513
|
if (fdReal === null) return { anchor: fallback };
|
|
294220
295514
|
if (!withinBase(fdReal, base)) return { error: { ok: false, code: "PATH_ESCAPE" } };
|
|
294221
|
-
const fdRel = base === fdReal ? "" :
|
|
295515
|
+
const fdRel = base === fdReal ? "" : import_node_path33.default.relative(base, fdReal);
|
|
294222
295516
|
if (relPathIsSensitive(fdRel)) return { error: { ok: false, code: "SENSITIVE" } };
|
|
294223
295517
|
return { anchor: `/proc/self/fd/${fh.fd}` };
|
|
294224
295518
|
}
|
|
@@ -294312,7 +295606,7 @@ function looksBinary(bytes2) {
|
|
|
294312
295606
|
function contentTypeFor(absPath, bytes2) {
|
|
294313
295607
|
const sniffed = sniffContentType(bytes2);
|
|
294314
295608
|
if (sniffed) return sniffed;
|
|
294315
|
-
const ext =
|
|
295609
|
+
const ext = import_node_path33.default.extname(absPath).toLowerCase();
|
|
294316
295610
|
if (EXT_CONTENT_TYPE[ext]) return EXT_CONTENT_TYPE[ext];
|
|
294317
295611
|
return looksBinary(bytes2) ? "application/octet-stream" : "text/plain; charset=utf-8";
|
|
294318
295612
|
}
|
|
@@ -294895,7 +296189,7 @@ var DaemonWsClient = class {
|
|
|
294895
296189
|
*/
|
|
294896
296190
|
async queryArtifactStates(artifactIds, timeoutMs = 15e3) {
|
|
294897
296191
|
if (artifactIds.length === 0) return {};
|
|
294898
|
-
const requestId = (0,
|
|
296192
|
+
const requestId = (0, import_node_crypto95.randomUUID)();
|
|
294899
296193
|
return new Promise((resolve11, reject) => {
|
|
294900
296194
|
const timer = setTimeout(() => {
|
|
294901
296195
|
this.gcPending.delete(requestId);
|
|
@@ -295075,17 +296369,17 @@ var RuntimeRouterAdapter = class {
|
|
|
295075
296369
|
// ../cli/src/daemon/reap-claude-projects.ts
|
|
295076
296370
|
var import_node_fs27 = __toESM(require("node:fs"), 1);
|
|
295077
296371
|
var import_node_os15 = __toESM(require("node:os"), 1);
|
|
295078
|
-
var
|
|
296372
|
+
var import_node_path34 = __toESM(require("node:path"), 1);
|
|
295079
296373
|
function claudeProjectSlug(cwd) {
|
|
295080
296374
|
return cwd.replace(/[^a-zA-Z0-9]/g, "-");
|
|
295081
296375
|
}
|
|
295082
296376
|
function claudeProjectsRoot() {
|
|
295083
|
-
const configDir = process.env["CLAUDE_CONFIG_DIR"] ||
|
|
295084
|
-
return
|
|
296377
|
+
const configDir = process.env["CLAUDE_CONFIG_DIR"] || import_node_path34.default.join(import_node_os15.default.homedir(), ".claude");
|
|
296378
|
+
return import_node_path34.default.join(configDir, "projects");
|
|
295085
296379
|
}
|
|
295086
296380
|
function reapClaudeProjects(workdir, runtimeKind) {
|
|
295087
296381
|
if (runtimeKind !== "claude" && runtimeKind !== "claude-code") return;
|
|
295088
|
-
const dir =
|
|
296382
|
+
const dir = import_node_path34.default.join(claudeProjectsRoot(), claudeProjectSlug(workdir));
|
|
295089
296383
|
if (!import_node_fs27.default.existsSync(dir)) return;
|
|
295090
296384
|
try {
|
|
295091
296385
|
import_node_fs27.default.rmSync(dir, { recursive: true, force: true });
|
|
@@ -295094,7 +296388,7 @@ function reapClaudeProjects(workdir, runtimeKind) {
|
|
|
295094
296388
|
}
|
|
295095
296389
|
function measureClaudeProjects(workdir, runtimeKind) {
|
|
295096
296390
|
if (runtimeKind !== "claude" && runtimeKind !== "claude-code") return 0;
|
|
295097
|
-
const dir =
|
|
296391
|
+
const dir = import_node_path34.default.join(claudeProjectsRoot(), claudeProjectSlug(workdir));
|
|
295098
296392
|
return dirSizeBytes2(dir);
|
|
295099
296393
|
}
|
|
295100
296394
|
function dirSizeBytes2(dir) {
|
|
@@ -295106,7 +296400,7 @@ function dirSizeBytes2(dir) {
|
|
|
295106
296400
|
return 0;
|
|
295107
296401
|
}
|
|
295108
296402
|
for (const e of entries) {
|
|
295109
|
-
const p2 =
|
|
296403
|
+
const p2 = import_node_path34.default.join(dir, e.name);
|
|
295110
296404
|
if (e.isSymbolicLink()) continue;
|
|
295111
296405
|
if (e.isDirectory()) {
|
|
295112
296406
|
total += dirSizeBytes2(p2);
|
|
@@ -295123,7 +296417,7 @@ function dirSizeBytes2(dir) {
|
|
|
295123
296417
|
// ../cli/src/node.ts
|
|
295124
296418
|
init_src2();
|
|
295125
296419
|
var import_node_os16 = __toESM(require("node:os"), 1);
|
|
295126
|
-
var
|
|
296420
|
+
var import_node_path35 = __toESM(require("node:path"), 1);
|
|
295127
296421
|
var idleFor = (runtimeKind) => CODE_DEFAULT_POLICY.resolve({ executor: "agent", scenario: "runtime-idle", runtimeKind }).idleTimeoutMs ?? 0;
|
|
295128
296422
|
var RESILIENCE = {
|
|
295129
296423
|
codex: { idleTimeoutMs: idleFor("codex") }
|
|
@@ -295195,7 +296489,7 @@ async function startNode(opts) {
|
|
|
295195
296489
|
const client = new DaemonWsClient(opts.serverUrl, opts.nodeId, sessions, adapters, opts.token, runtimes, opts.nodeName, opts.reportRuntimes ?? false, true, opts.onUpdate, opts.daemonVersion, {
|
|
295196
296490
|
...opts.daemonPkg ? { daemonPkg: opts.daemonPkg } : {},
|
|
295197
296491
|
// 同一个 OS 用户下的所有实例(~/.oasis/instances/*)共用一份额度采集结果:同账号 5 分钟只问一次上游。
|
|
295198
|
-
quotaCacheDir:
|
|
296492
|
+
quotaCacheDir: import_node_path35.default.join(import_node_os16.default.homedir(), ".oasis", "quota-cache"),
|
|
295199
296493
|
// chat 文件浏览 handler 用它定位会话目录;production 不传 = 与 adapter 同款默认根(~/.oasis/work)。
|
|
295200
296494
|
...opts.workRoot !== void 0 ? { workRoot: opts.workRoot } : {},
|
|
295201
296495
|
...opts.spawnSessionProcess ? { spawnSessionProcess: opts.spawnSessionProcess } : {},
|
|
@@ -295314,7 +296608,7 @@ function forwardSignal(child, sig, killGroup = (pgid, signal) => {
|
|
|
295314
296608
|
// ../cli/src/daemon/machine-id.ts
|
|
295315
296609
|
var import_node_child_process20 = require("node:child_process");
|
|
295316
296610
|
var import_node_fs28 = require("node:fs");
|
|
295317
|
-
var
|
|
296611
|
+
var import_node_crypto96 = require("node:crypto");
|
|
295318
296612
|
var import_node_os17 = require("node:os");
|
|
295319
296613
|
function linuxMachineId() {
|
|
295320
296614
|
for (const p2 of ["/etc/machine-id", "/var/lib/dbus/machine-id"]) {
|
|
@@ -295380,7 +296674,7 @@ var defaultSources = {
|
|
|
295380
296674
|
function resolveNodeId(sources = {}) {
|
|
295381
296675
|
const s2 = { ...defaultSources, ...sources };
|
|
295382
296676
|
const material = `${s2.machineFingerprint()}:${s2.osUser()}`;
|
|
295383
|
-
const digest = (0,
|
|
296677
|
+
const digest = (0, import_node_crypto96.createHash)("sha256").update(material).digest("hex").slice(0, 12);
|
|
295384
296678
|
return `node-${digest}`;
|
|
295385
296679
|
}
|
|
295386
296680
|
|
|
@@ -297061,6 +298355,76 @@ var COMMAND_DECLS = {
|
|
|
297061
298355
|
],
|
|
297062
298356
|
examples: ["oasis var rm STALE_KEY --scope project --project oasis", "oasis var rm --id var_1234 --yes"]
|
|
297063
298357
|
},
|
|
298358
|
+
// —— 个人待办(ADR 0635):人对助理说「帮我记一下」→ 助理用这组命令记、改、勾掉。发起人 / 承接人由服务端按调用者
|
|
298359
|
+
// 填(agent 调 = 它绑定的那个真人),命令行不收。开关 OASIS_PERSONAL_TODO=off 时服务端 404。 ——
|
|
298360
|
+
todo: {
|
|
298361
|
+
group: "\u4E2A\u4EBA\u5F85\u529E",
|
|
298362
|
+
usage: "oasis todo <add|list|edit|done|cancel|reopen> ...",
|
|
298363
|
+
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**",
|
|
298364
|
+
subCommands: ["todo add", "todo list", "todo edit", "todo done", "todo cancel", "todo reopen"],
|
|
298365
|
+
examples: [
|
|
298366
|
+
'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',
|
|
298367
|
+
"oasis todo list",
|
|
298368
|
+
'oasis todo edit td_3f9a1c2b --due 2026-10-12 --reason "\u6392\u671F\u8C03\u6574"',
|
|
298369
|
+
"oasis todo done td_3f9a1c2b"
|
|
298370
|
+
]
|
|
298371
|
+
},
|
|
298372
|
+
"todo add": {
|
|
298373
|
+
group: "\u4E2A\u4EBA\u5F85\u529E",
|
|
298374
|
+
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]",
|
|
298375
|
+
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",
|
|
298376
|
+
flags: [
|
|
298377
|
+
{ name: "title", desc: "\u6807\u9898\uFF1A\u4E00\u53E5\u8BDD\u3001\u52A8\u8BCD\u5F00\u5934", required: true, own: true },
|
|
298378
|
+
{ name: "note", desc: "\u5907\u6CE8\uFF1A\u8C01\u8981\u3001\u4E3A\u4EC0\u4E48\u8981\u3001\u539F\u8BDD\u91CC\u7684\u5173\u952E\u4FE1\u606F", own: true },
|
|
298379
|
+
{ name: "due", desc: "\u622A\u6B62\u65E5 YYYY-MM-DD\uFF08\u4E0D\u5E26\u65F6\u533A\uFF09", required: true, own: true },
|
|
298380
|
+
{ name: "time", desc: "\u622A\u6B62\u65F6\u523B HH:mm\uFF0824 \u5C0F\u65F6\u5236\uFF1B\u6CA1\u8BF4\u5C31\u4E0D\u7ED9\uFF09", own: true },
|
|
298381
|
+
{ 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 },
|
|
298382
|
+
{ name: "start-time", desc: "\u5F00\u59CB\u65F6\u523B HH:mm\uFF08\u914D --start\uFF09", own: true }
|
|
298383
|
+
],
|
|
298384
|
+
examples: ['oasis todo add --title "\u4EA4 Q3 \u590D\u76D8\u62A5\u544A" --due 2026-10-09 --time 18:00']
|
|
298385
|
+
},
|
|
298386
|
+
"todo list": {
|
|
298387
|
+
group: "\u4E2A\u4EBA\u5F85\u529E",
|
|
298388
|
+
usage: "oasis todo list [--all]",
|
|
298389
|
+
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",
|
|
298390
|
+
flags: [{ name: "all", desc: "\u8FDE\u5DF2\u5B8C\u6210 / \u5DF2\u53D6\u6D88\u7684\u4E00\u8D77\u5217", boolean: true, own: true }]
|
|
298391
|
+
},
|
|
298392
|
+
"todo edit": {
|
|
298393
|
+
group: "\u4E2A\u4EBA\u5F85\u529E",
|
|
298394
|
+
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]",
|
|
298395
|
+
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',
|
|
298396
|
+
positional: [{ name: "<id>", required: true, desc: "\u5F85\u529E id\uFF08oasis todo list \u7B2C\u4E00\u5217\uFF09" }],
|
|
298397
|
+
flags: [
|
|
298398
|
+
{ name: "title", desc: "\u65B0\u6807\u9898", own: true },
|
|
298399
|
+
{ name: "note", desc: "\u65B0\u5907\u6CE8\uFF08\u7A7A\u4E32 = \u6E05\u7A7A\uFF09", own: true },
|
|
298400
|
+
{ name: "start", desc: "\u65B0\u5F00\u59CB\u65E5 YYYY-MM-DD\uFF1Bnone = \u6E05\u7A7A\uFF08\u8FDE\u540C\u5F00\u59CB\u65F6\u523B\uFF09", own: true },
|
|
298401
|
+
{ name: "start-time", desc: "\u65B0\u5F00\u59CB\u65F6\u523B HH:mm\uFF1Bnone = \u6E05\u7A7A", own: true },
|
|
298402
|
+
{ name: "due", desc: "\u65B0\u622A\u6B62\u65E5 YYYY-MM-DD", own: true },
|
|
298403
|
+
{ name: "time", desc: "\u65B0\u622A\u6B62\u65F6\u523B HH:mm\uFF1Bnone = \u6E05\u7A7A", own: true },
|
|
298404
|
+
{ 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 },
|
|
298405
|
+
{ 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 }
|
|
298406
|
+
],
|
|
298407
|
+
examples: ['oasis todo edit td_3f9a1c2b --due 2026-10-12 --reason "\u5BA2\u6237\u5EF6\u671F\u4E00\u5468"']
|
|
298408
|
+
},
|
|
298409
|
+
"todo done": {
|
|
298410
|
+
group: "\u4E2A\u4EBA\u5F85\u529E",
|
|
298411
|
+
usage: "oasis todo done <id>",
|
|
298412
|
+
description: "\u6807\u8BB0\u5B8C\u6210\u3002\u5339\u914D\u5230\u591A\u6761\u65F6\u5148\u95EE\u7528\u6237\u662F\u54EA\u6761\uFF0C\u522B\u731C\u3002",
|
|
298413
|
+
positional: [{ name: "<id>", required: true, desc: "\u5F85\u529E id" }]
|
|
298414
|
+
},
|
|
298415
|
+
"todo cancel": {
|
|
298416
|
+
group: "\u4E2A\u4EBA\u5F85\u529E",
|
|
298417
|
+
usage: "oasis todo cancel <id> [--reason \u2026]",
|
|
298418
|
+
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",
|
|
298419
|
+
positional: [{ name: "<id>", required: true, desc: "\u5F85\u529E id" }],
|
|
298420
|
+
flags: [{ name: "reason", desc: "\u4E3A\u4EC0\u4E48\u4E0D\u7528\u505A\u4E86", own: true }]
|
|
298421
|
+
},
|
|
298422
|
+
"todo reopen": {
|
|
298423
|
+
group: "\u4E2A\u4EBA\u5F85\u529E",
|
|
298424
|
+
usage: "oasis todo reopen <id>",
|
|
298425
|
+
description: "\u628A\u5DF2\u5B8C\u6210 / \u5DF2\u53D6\u6D88\u7684\u5F85\u529E\u91CD\u65B0\u6253\u5F00\u3002",
|
|
298426
|
+
positional: [{ name: "<id>", required: true, desc: "\u5F85\u529E id" }]
|
|
298427
|
+
},
|
|
297064
298428
|
// —— 技能:组织技能库的 CLI 面(Web 上是「管理 > 技能」那一页)。
|
|
297065
298429
|
// agent 把自己写好的一个技能目录沉淀进公司,并决定它对谁生效。 ——
|
|
297066
298430
|
skill: {
|
|
@@ -297150,21 +298514,21 @@ function formatCommandHelp(decl) {
|
|
|
297150
298514
|
const posNames = (decl.positional ?? []).map((p2) => p2.name);
|
|
297151
298515
|
const flagNames = (decl.flags ?? []).map((f2) => `--${f2.name}`);
|
|
297152
298516
|
const allNames = [...posNames, ...flagNames];
|
|
297153
|
-
const
|
|
298517
|
+
const pad3 = allNames.length > 0 ? Math.max(...allNames.map((n) => n.length)) + 2 : 0;
|
|
297154
298518
|
const reqPos = (decl.positional ?? []).filter((p2) => p2.required);
|
|
297155
298519
|
const reqFlags = (decl.flags ?? []).filter((f2) => f2.required);
|
|
297156
298520
|
if (reqPos.length > 0 || reqFlags.length > 0) {
|
|
297157
298521
|
lines.push("\u5FC5\u586B\uFF1A");
|
|
297158
|
-
for (const p2 of reqPos) lines.push(` ${p2.name.padEnd(
|
|
297159
|
-
for (const f2 of reqFlags) lines.push(` --${f2.name.padEnd(
|
|
298522
|
+
for (const p2 of reqPos) lines.push(` ${p2.name.padEnd(pad3)} ${p2.desc}`);
|
|
298523
|
+
for (const f2 of reqFlags) lines.push(` --${f2.name.padEnd(pad3 - 2)} ${f2.desc}`);
|
|
297160
298524
|
lines.push("");
|
|
297161
298525
|
}
|
|
297162
298526
|
const optPos = (decl.positional ?? []).filter((p2) => !p2.required);
|
|
297163
298527
|
const optFlags = (decl.flags ?? []).filter((f2) => !f2.required);
|
|
297164
298528
|
if (optPos.length > 0 || optFlags.length > 0) {
|
|
297165
298529
|
lines.push("\u53EF\u9009\uFF1A");
|
|
297166
|
-
for (const p2 of optPos) lines.push(` ${p2.name.padEnd(
|
|
297167
|
-
for (const f2 of optFlags) lines.push(` --${f2.name.padEnd(
|
|
298530
|
+
for (const p2 of optPos) lines.push(` ${p2.name.padEnd(pad3)} ${p2.desc}`);
|
|
298531
|
+
for (const f2 of optFlags) lines.push(` --${f2.name.padEnd(pad3 - 2)} ${f2.desc}`);
|
|
297168
298532
|
lines.push("");
|
|
297169
298533
|
}
|
|
297170
298534
|
lines.push(`\u8BF4\u660E\uFF1A${decl.description}`);
|
|
@@ -297191,6 +298555,7 @@ var GROUP_ORDER = [
|
|
|
297191
298555
|
"\u957F\u671F\u8BB0\u5FC6\uFF08ADR-0084/0102\uFF09",
|
|
297192
298556
|
"\u77E5\u8BC6\u5E93",
|
|
297193
298557
|
"\u59D4\u6D3E\u4E13\u5BB6",
|
|
298558
|
+
"\u4E2A\u4EBA\u5F85\u529E",
|
|
297194
298559
|
"\u751F\u547D\u5468\u671F",
|
|
297195
298560
|
"\u89D2\u8272 & \u4EBA\u5458",
|
|
297196
298561
|
"\u8BFB\u4EA7\u7269",
|
|
@@ -297255,13 +298620,13 @@ function ownFlagsFromDecl(command2) {
|
|
|
297255
298620
|
}
|
|
297256
298621
|
|
|
297257
298622
|
// ../cli/src/connector-effect-runner.ts
|
|
297258
|
-
var
|
|
298623
|
+
var import_node_crypto97 = require("node:crypto");
|
|
297259
298624
|
var import_node_child_process21 = require("node:child_process");
|
|
297260
298625
|
init_src8();
|
|
297261
298626
|
function stableKey(effect) {
|
|
297262
298627
|
const keyFields = Object.fromEntries(Object.entries(effect.keyFields).sort(([a], [b2]) => a.localeCompare(b2)));
|
|
297263
298628
|
const canonical2 = JSON.stringify({ kind: effect.kind, target: effect.target, keyFields });
|
|
297264
|
-
return `sha256:${(0,
|
|
298629
|
+
return `sha256:${(0, import_node_crypto97.createHash)("sha256").update(canonical2).digest("hex")}`;
|
|
297265
298630
|
}
|
|
297266
298631
|
async function runConnectorEffect(connector, toolArgs, deps) {
|
|
297267
298632
|
const effect = connector.describeExternalEffect?.(toolArgs) ?? null;
|
|
@@ -297480,8 +298845,8 @@ function formatSize(size) {
|
|
|
297480
298845
|
if (size < 1024 * 1024) return `${(size / 1024).toFixed(1)}KB`;
|
|
297481
298846
|
return `${(size / 1024 / 1024).toFixed(1)}MB`;
|
|
297482
298847
|
}
|
|
297483
|
-
function formatTime(
|
|
297484
|
-
return /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}/.test(
|
|
298848
|
+
function formatTime(iso9) {
|
|
298849
|
+
return /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}/.test(iso9) ? `${iso9.slice(5, 10)} ${iso9.slice(11, 16)}` : iso9;
|
|
297485
298850
|
}
|
|
297486
298851
|
function displayName2(name) {
|
|
297487
298852
|
const cut = name.lastIndexOf("/");
|
|
@@ -297830,7 +299195,7 @@ async function waitForCommandAuthorization(base, headers, draftId, fallback) {
|
|
|
297830
299195
|
const timeoutMs = resolveAuthWaitMs();
|
|
297831
299196
|
const controller = new AbortController();
|
|
297832
299197
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
297833
|
-
const waiterId = (0,
|
|
299198
|
+
const waiterId = (0, import_node_crypto98.randomUUID)();
|
|
297834
299199
|
process.stderr.write(
|
|
297835
299200
|
`\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
|
|
297836
299201
|
`
|
|
@@ -297914,7 +299279,7 @@ async function waitForCommandAuthorization(base, headers, draftId, fallback) {
|
|
|
297914
299279
|
}
|
|
297915
299280
|
}
|
|
297916
299281
|
}
|
|
297917
|
-
var CLI_VERSION = "2.2.
|
|
299282
|
+
var CLI_VERSION = "2.2.106" ? "2.2.106" : "dev";
|
|
297918
299283
|
function apiHeaders(token2, company) {
|
|
297919
299284
|
const headers = {
|
|
297920
299285
|
authorization: `Bearer ${token2}`,
|
|
@@ -298004,7 +299369,7 @@ function fieldsFromFlags(flags, ownFlags) {
|
|
|
298004
299369
|
}
|
|
298005
299370
|
return Object.keys(fields).length > 0 ? fields : void 0;
|
|
298006
299371
|
}
|
|
298007
|
-
function buildStageOp(cmd, flags, positional,
|
|
299372
|
+
function buildStageOp(cmd, flags, positional, readFile13 = (file) => fs44.readFileSync(file, "utf8")) {
|
|
298008
299373
|
switch (cmd) {
|
|
298009
299374
|
case "link":
|
|
298010
299375
|
return {
|
|
@@ -298026,7 +299391,7 @@ function buildStageOp(cmd, flags, positional, readFile12 = (file) => fs44.readFi
|
|
|
298026
299391
|
...flags.get("title") !== void 0 ? { title: flags.get("title") } : {},
|
|
298027
299392
|
...(flags.get("brief") ?? flags.get("description")) !== void 0 ? { description: flags.get("brief") ?? flags.get("description") } : {},
|
|
298028
299393
|
...flags.get("input") !== void 0 ? { inputs: flags.get("input").split(",").map((to) => ({ to: to.trim() })) } : {},
|
|
298029
|
-
...partsFile !== void 0 ? { parts: JSON.parse(
|
|
299394
|
+
...partsFile !== void 0 ? { parts: JSON.parse(readFile13(partsFile)) } : {},
|
|
298030
299395
|
...fields !== void 0 ? { fields } : {}
|
|
298031
299396
|
};
|
|
298032
299397
|
}
|
|
@@ -298280,7 +299645,7 @@ async function runCli(argv, println = console.log, progressln = console.error) {
|
|
|
298280
299645
|
const store = createNodeTokenStore(path39.join(dir, "node-tokens.json"));
|
|
298281
299646
|
const sub = positional[0];
|
|
298282
299647
|
if (sub === "issue") {
|
|
298283
|
-
const id = flags.get("id") ?? `node-${(0,
|
|
299648
|
+
const id = flags.get("id") ?? `node-${(0, import_node_crypto98.randomUUID)()}`;
|
|
298284
299649
|
const token3 = store.issue(id);
|
|
298285
299650
|
println(token3);
|
|
298286
299651
|
process.stderr.write(
|
|
@@ -299432,7 +300797,7 @@ ${t.ref} ${t.name} [\u5267\u672C=${t.playbookRef}]`);
|
|
|
299432
300797
|
if (!name) throw new Error("\u9879\u76EE\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A");
|
|
299433
300798
|
const goal = flags.get("goal")?.trim();
|
|
299434
300799
|
const slug5 = flags.get("slug");
|
|
299435
|
-
const id = slug5 !== void 0 ? projectSlug(slug5) : projectIdFromUuid((0,
|
|
300800
|
+
const id = slug5 !== void 0 ? projectSlug(slug5) : projectIdFromUuid((0, import_node_crypto98.randomUUID)());
|
|
299436
300801
|
const result = await api.request("POST", "/api/projects", {
|
|
299437
300802
|
...id ? { id } : {},
|
|
299438
300803
|
name,
|
|
@@ -300284,6 +301649,95 @@ ${res.warning}`);
|
|
|
300284
301649
|
oasis var rm <key> --scope \u2026 | oasis var rm --id <\u8BB0\u5F55 id> [--yes]
|
|
300285
301650
|
\u540E\u4E09\u4E2A\u662F\u7BA1\u7406\u9762\uFF0C\u4EC5\u9650\u4EBA\u7C7B operator token\u3002`);
|
|
300286
301651
|
}
|
|
301652
|
+
case "todo": {
|
|
301653
|
+
const sub = positional[0];
|
|
301654
|
+
const due = (t) => formatTodoSpan(t);
|
|
301655
|
+
const call = async (method, url, body2) => {
|
|
301656
|
+
try {
|
|
301657
|
+
return await api.request(method, url, body2);
|
|
301658
|
+
} catch (e) {
|
|
301659
|
+
if (e instanceof ApiRequestError && e.status === 404 && e.body?.error?.code === "NOT_FOUND") {
|
|
301660
|
+
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");
|
|
301661
|
+
}
|
|
301662
|
+
throw e;
|
|
301663
|
+
}
|
|
301664
|
+
};
|
|
301665
|
+
const checkDay = (v2, flag) => {
|
|
301666
|
+
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}`);
|
|
301667
|
+
return v2;
|
|
301668
|
+
};
|
|
301669
|
+
const checkTime = (v2, flag = "time") => {
|
|
301670
|
+
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}`);
|
|
301671
|
+
return v2;
|
|
301672
|
+
};
|
|
301673
|
+
const idOf = () => needPos(positional, 1, `oasis todo ${sub} <id>`);
|
|
301674
|
+
const todoPath = (id, tail = "") => `/api/todos/${encodeURIComponent(id)}${tail}`;
|
|
301675
|
+
if (sub === "add") {
|
|
301676
|
+
const title = need(flags, "title");
|
|
301677
|
+
const dueDate = checkDay(need(flags, "due"), "due");
|
|
301678
|
+
const time3 = flags.get("time");
|
|
301679
|
+
const note = flags.get("note");
|
|
301680
|
+
const start = flags.get("start");
|
|
301681
|
+
const startTime = flags.get("start-time");
|
|
301682
|
+
if (startTime !== void 0 && start === void 0) throw new Error("--start-time \u8981\u914D --start\uFF08\u5148\u8BF4\u54EA\u5929\u5F00\u59CB\uFF09");
|
|
301683
|
+
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`);
|
|
301684
|
+
const sourceChatSessionId = process.env["OASIS_CHAT_SESSION_ID"];
|
|
301685
|
+
const r = await call("POST", "/api/todos", {
|
|
301686
|
+
title,
|
|
301687
|
+
dueDate,
|
|
301688
|
+
...time3 !== void 0 ? { dueTime: checkTime(time3) } : {},
|
|
301689
|
+
...start !== void 0 ? { startDate: checkDay(start, "start") } : {},
|
|
301690
|
+
...startTime !== void 0 ? { startTime: checkTime(startTime, "start-time") } : {},
|
|
301691
|
+
...note ? { note } : {},
|
|
301692
|
+
...sourceChatSessionId ? { sourceChatSessionId } : {}
|
|
301693
|
+
});
|
|
301694
|
+
println(r.todayLine);
|
|
301695
|
+
println(`\u8BB0\u4E0B\u4E86\uFF1A${r.todo.title}\uFF0C${due(r.todo)}`);
|
|
301696
|
+
println(`id\uFF1A${r.todo.id}`);
|
|
301697
|
+
break;
|
|
301698
|
+
}
|
|
301699
|
+
if (sub === "list") {
|
|
301700
|
+
const all2 = flags.get("all") === "true";
|
|
301701
|
+
const r = await call("GET", `/api/todos${all2 ? "?all=1" : ""}`);
|
|
301702
|
+
println(r.todayLine);
|
|
301703
|
+
if (r.items.length === 0) {
|
|
301704
|
+
println(all2 ? "\u6CA1\u6709\u5F85\u529E\u3002" : "\u6CA1\u6709\u672A\u5B8C\u6210\u7684\u5F85\u529E\u3002");
|
|
301705
|
+
break;
|
|
301706
|
+
}
|
|
301707
|
+
for (const t of r.items) {
|
|
301708
|
+
const tag = t.status === "done" ? " [\u5DF2\u5B8C\u6210]" : t.status === "cancelled" ? " [\u5DF2\u53D6\u6D88]" : t.dueDate < r.today.date ? " [\u5DF2\u8FC7\u671F]" : "";
|
|
301709
|
+
const when = t.startDate ? formatTodoSpan(t) : formatTodoDue(t.dueDate, t.dueTime);
|
|
301710
|
+
println(`${t.id} ${when} ${t.title}${tag}`);
|
|
301711
|
+
}
|
|
301712
|
+
break;
|
|
301713
|
+
}
|
|
301714
|
+
if (sub === "edit") {
|
|
301715
|
+
const id = idOf();
|
|
301716
|
+
const body2 = {};
|
|
301717
|
+
if (flags.has("title")) body2["title"] = flags.get("title");
|
|
301718
|
+
if (flags.has("note")) body2["note"] = flags.get("note") === "" ? null : flags.get("note");
|
|
301719
|
+
if (flags.has("due")) body2["dueDate"] = checkDay(flags.get("due"), "due");
|
|
301720
|
+
if (flags.has("time")) body2["dueTime"] = flags.get("time") === "none" ? null : checkTime(flags.get("time"));
|
|
301721
|
+
if (flags.has("start")) body2["startDate"] = flags.get("start") === "none" ? null : checkDay(flags.get("start"), "start");
|
|
301722
|
+
if (flags.has("start-time")) body2["startTime"] = flags.get("start-time") === "none" ? null : checkTime(flags.get("start-time"), "start-time");
|
|
301723
|
+
if (flags.has("workorder")) body2["linkedWorkorderId"] = flags.get("workorder") === "none" ? null : flags.get("workorder");
|
|
301724
|
+
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");
|
|
301725
|
+
if (flags.get("reason")) body2["reason"] = flags.get("reason");
|
|
301726
|
+
const r = await call("PATCH", todoPath(id), body2);
|
|
301727
|
+
println(r.todayLine);
|
|
301728
|
+
println(`\u5DF2\u6539\uFF1A${r.todo.title}\uFF0C${due(r.todo)}`);
|
|
301729
|
+
break;
|
|
301730
|
+
}
|
|
301731
|
+
if (sub === "done" || sub === "cancel" || sub === "reopen") {
|
|
301732
|
+
const id = idOf();
|
|
301733
|
+
const reason = sub === "cancel" ? flags.get("reason") : void 0;
|
|
301734
|
+
const r = await call("POST", todoPath(id, `/${sub}`), reason ? { reason } : {});
|
|
301735
|
+
println(r.todayLine);
|
|
301736
|
+
println(`${sub === "done" ? "\u5DF2\u5B8C\u6210" : sub === "cancel" ? "\u5DF2\u53D6\u6D88" : "\u5DF2\u91CD\u65B0\u6253\u5F00"}\uFF1A${r.todo.title}\uFF0C${due(r.todo)}`);
|
|
301737
|
+
break;
|
|
301738
|
+
}
|
|
301739
|
+
throw new Error("\u7528\u6CD5: oasis todo <add|list|edit|done|cancel|reopen> \u2026\uFF08oasis todo --help \u770B\u8BE6\u60C5\uFF09");
|
|
301740
|
+
}
|
|
300287
301741
|
case "skill": {
|
|
300288
301742
|
const sub = positional[0];
|
|
300289
301743
|
const asJson2 = flags.get("json") === "true";
|
|
@@ -301427,8 +302881,8 @@ var LOG_RETAIN_DAYS = 30;
|
|
|
301427
302881
|
var LOG_RETAIN_MAX_FILES = 10;
|
|
301428
302882
|
var ROTATED_SUFFIX = /^\d{8}-\d{6}(-\d+)?$/;
|
|
301429
302883
|
function stampOf(now) {
|
|
301430
|
-
const
|
|
301431
|
-
return `${
|
|
302884
|
+
const iso9 = now.toISOString();
|
|
302885
|
+
return `${iso9.slice(0, 10).replace(/-/g, "")}-${iso9.slice(11, 19).replace(/:/g, "")}`;
|
|
301432
302886
|
}
|
|
301433
302887
|
function rotateLogIfNeeded(file, opts = {}) {
|
|
301434
302888
|
const maxBytes = opts.maxBytes ?? LOG_ROTATE_MAX_BYTES;
|
|
@@ -301821,13 +303275,13 @@ async function exchangeEnrollToken(o) {
|
|
|
301821
303275
|
}
|
|
301822
303276
|
|
|
301823
303277
|
// src/install.ts
|
|
301824
|
-
var
|
|
303278
|
+
var import_node_crypto99 = require("node:crypto");
|
|
301825
303279
|
var fs50 = __toESM(require("node:fs"));
|
|
301826
303280
|
var path45 = __toESM(require("node:path"));
|
|
301827
303281
|
function versionLabel(sourceFile, pkgVersion, npmPrefixDir, pkgName = LEGACY_PKG_NAME) {
|
|
301828
303282
|
const tag = pkgName === LEGACY_PKG_NAME ? "" : `+pkg.${pkgName.replace(/[^A-Za-z0-9-]/g, "-")}`;
|
|
301829
303283
|
if (isFromNpmPrefix(sourceFile, npmPrefixDir)) return `${pkgVersion}${tag}`;
|
|
301830
|
-
const digest = (0,
|
|
303284
|
+
const digest = (0, import_node_crypto99.createHash)("sha256").update(fs50.readFileSync(sourceFile)).digest("hex").slice(0, 8);
|
|
301831
303285
|
return tag ? `${pkgVersion}${tag}.local.${digest}` : `${pkgVersion}+local.${digest}`;
|
|
301832
303286
|
}
|
|
301833
303287
|
function isFromNpmPrefix(sourceFile, npmPrefixDir) {
|
|
@@ -301950,7 +303404,7 @@ function shimScript() {
|
|
|
301950
303404
|
}
|
|
301951
303405
|
|
|
301952
303406
|
// src/index.ts
|
|
301953
|
-
var PKG_VERSION = true ? "2.2.
|
|
303407
|
+
var PKG_VERSION = true ? "2.2.106" : "dev";
|
|
301954
303408
|
var LOCAL_BIN = localBin();
|
|
301955
303409
|
var NPM_PREFIX = npmPrefix();
|
|
301956
303410
|
var INSTANCE = DEFAULT_INSTANCE;
|
|
@@ -302258,7 +303712,7 @@ function newInstanceName() {
|
|
|
302258
303712
|
const existing = new Set(listInstances());
|
|
302259
303713
|
if (!existing.has(DEFAULT_INSTANCE)) return DEFAULT_INSTANCE;
|
|
302260
303714
|
for (; ; ) {
|
|
302261
|
-
const n = `inst-${(0,
|
|
303715
|
+
const n = `inst-${(0, import_node_crypto100.randomBytes)(3).toString("hex")}`;
|
|
302262
303716
|
if (!existing.has(n)) return n;
|
|
302263
303717
|
}
|
|
302264
303718
|
}
|