oasis_test_v2 2.2.119 → 2.2.121
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 +907 -131
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1569,6 +1569,21 @@ function todoAssignees(todo) {
|
|
|
1569
1569
|
function isTodoParty(todo, actorId) {
|
|
1570
1570
|
return todo.creatorActorId === actorId || todoAssignees(todo).includes(actorId);
|
|
1571
1571
|
}
|
|
1572
|
+
function isTodoDelegated(todo) {
|
|
1573
|
+
return !todoAssignees(todo).includes(todo.creatorActorId);
|
|
1574
|
+
}
|
|
1575
|
+
function isTodoUnsent(todo) {
|
|
1576
|
+
return isTodoDelegated(todo) && !todo.sentAt;
|
|
1577
|
+
}
|
|
1578
|
+
function canReadTodo(todo, actorId) {
|
|
1579
|
+
return !isTodoUnsent(todo) || todo.creatorActorId === actorId;
|
|
1580
|
+
}
|
|
1581
|
+
function canWriteTodo(todo, actorId) {
|
|
1582
|
+
return isTodoUnsent(todo) ? todo.creatorActorId === actorId : isTodoParty(todo, actorId);
|
|
1583
|
+
}
|
|
1584
|
+
function isTodoAssignedToByOther(todo, actorId) {
|
|
1585
|
+
return isTodoDelegated(todo) && todoAssignees(todo).includes(actorId);
|
|
1586
|
+
}
|
|
1572
1587
|
function isValidTodoTime(time4) {
|
|
1573
1588
|
const m4 = /^(\d{2}):(\d{2})$/.exec(time4);
|
|
1574
1589
|
return !!m4 && Number(m4[1]) <= 23 && Number(m4[2]) <= 59;
|
|
@@ -1609,11 +1624,12 @@ function compareTodos(a5, b6) {
|
|
|
1609
1624
|
if (a5.createdAt !== b6.createdAt) return a5.createdAt < b6.createdAt ? -1 : 1;
|
|
1610
1625
|
return a5.id < b6.id ? -1 : a5.id > b6.id ? 1 : 0;
|
|
1611
1626
|
}
|
|
1612
|
-
var WEEKDAY_LABEL;
|
|
1627
|
+
var TODO_STATUSES, WEEKDAY_LABEL;
|
|
1613
1628
|
var init_todos = __esm({
|
|
1614
1629
|
"../contract/src/todos.ts"() {
|
|
1615
1630
|
"use strict";
|
|
1616
1631
|
init_time_zone();
|
|
1632
|
+
TODO_STATUSES = ["draft", "open", "done", "cancelled"];
|
|
1617
1633
|
WEEKDAY_LABEL = ["\u5468\u65E5", "\u5468\u4E00", "\u5468\u4E8C", "\u5468\u4E09", "\u5468\u56DB", "\u5468\u4E94", "\u5468\u516D"];
|
|
1618
1634
|
}
|
|
1619
1635
|
});
|
|
@@ -138818,7 +138834,7 @@ ${block}
|
|
|
138818
138834
|
}
|
|
138819
138835
|
return out;
|
|
138820
138836
|
}
|
|
138821
|
-
var
|
|
138837
|
+
var DEFAULT_BATCH2 = {
|
|
138822
138838
|
delayMs: 600,
|
|
138823
138839
|
longThresholdChars: 1e3,
|
|
138824
138840
|
longDelayMs: 2e3,
|
|
@@ -138837,11 +138853,11 @@ ${block}
|
|
|
138837
138853
|
var _a2, _b, _c5, _d, _e5, _f, _g;
|
|
138838
138854
|
const t = (_b = (_a2 = cfg === null || cfg === void 0 ? void 0 : cfg.batch) === null || _a2 === void 0 ? void 0 : _a2.text) !== null && _b !== void 0 ? _b : {};
|
|
138839
138855
|
return {
|
|
138840
|
-
delayMs: (_c5 = t.delayMs) !== null && _c5 !== void 0 ? _c5 :
|
|
138841
|
-
longThresholdChars: (_d = t.longThresholdChars) !== null && _d !== void 0 ? _d :
|
|
138842
|
-
longDelayMs: (_e5 = t.longDelayMs) !== null && _e5 !== void 0 ? _e5 :
|
|
138843
|
-
maxMessages: (_f = t.maxMessages) !== null && _f !== void 0 ? _f :
|
|
138844
|
-
maxChars: (_g = t.maxChars) !== null && _g !== void 0 ? _g :
|
|
138856
|
+
delayMs: (_c5 = t.delayMs) !== null && _c5 !== void 0 ? _c5 : DEFAULT_BATCH2.delayMs,
|
|
138857
|
+
longThresholdChars: (_d = t.longThresholdChars) !== null && _d !== void 0 ? _d : DEFAULT_BATCH2.longThresholdChars,
|
|
138858
|
+
longDelayMs: (_e5 = t.longDelayMs) !== null && _e5 !== void 0 ? _e5 : DEFAULT_BATCH2.longDelayMs,
|
|
138859
|
+
maxMessages: (_f = t.maxMessages) !== null && _f !== void 0 ? _f : DEFAULT_BATCH2.maxMessages,
|
|
138860
|
+
maxChars: (_g = t.maxChars) !== null && _g !== void 0 ? _g : DEFAULT_BATCH2.maxChars
|
|
138845
138861
|
};
|
|
138846
138862
|
}
|
|
138847
138863
|
var SeenCache = class {
|
|
@@ -180598,9 +180614,9 @@ var init_live_chat = __esm({
|
|
|
180598
180614
|
* `chat_messages` 不补:二期页面只从 `chat_items` 出历史,agent 也已经读到,不需要再捎带。
|
|
180599
180615
|
*/
|
|
180600
180616
|
recordLateConsumedInput(turn, text7, opts, ord) {
|
|
180601
|
-
const
|
|
180617
|
+
const shown2 = opts?.displayText ?? text7;
|
|
180602
180618
|
try {
|
|
180603
|
-
return turn.items?.recordUserInput(
|
|
180619
|
+
return turn.items?.recordUserInput(shown2, opts?.attachments, opts?.clientKeys, {
|
|
180604
180620
|
...ord !== void 0 ? { ord } : {},
|
|
180605
180621
|
// ADR 0615:认领那个乐观气泡(问出「读到了」的这一档,气泡此前没被撤掉,正好就地转成真行)。
|
|
180606
180622
|
...opts?.submittedClientKey ? { clientSubmitId: opts.submittedClientKey } : {}
|
|
@@ -180610,10 +180626,10 @@ var init_live_chat = __esm({
|
|
|
180610
180626
|
}
|
|
180611
180627
|
}
|
|
180612
180628
|
commitUserInput(turn, text7, opts) {
|
|
180613
|
-
const
|
|
180629
|
+
const shown2 = opts?.displayText ?? text7;
|
|
180614
180630
|
const userPart = {
|
|
180615
180631
|
type: "user",
|
|
180616
|
-
text:
|
|
180632
|
+
text: shown2,
|
|
180617
180633
|
...opts?.attachments?.length ? { attachments: opts.attachments } : {}
|
|
180618
180634
|
};
|
|
180619
180635
|
const segmentEnd = (() => {
|
|
@@ -180637,7 +180653,7 @@ var init_live_chat = __esm({
|
|
|
180637
180653
|
let userItemId;
|
|
180638
180654
|
const adopt = opts?.submittedClientKey ? { clientSubmitId: opts.submittedClientKey } : void 0;
|
|
180639
180655
|
try {
|
|
180640
|
-
userItemId = turn.items?.recordUserInput(
|
|
180656
|
+
userItemId = turn.items?.recordUserInput(shown2, opts?.attachments, opts?.clientKeys, adopt);
|
|
180641
180657
|
} catch {
|
|
180642
180658
|
}
|
|
180643
180659
|
const withSeq = { ...userPart, seq: ++turn.seq };
|
|
@@ -180664,12 +180680,12 @@ var init_live_chat = __esm({
|
|
|
180664
180680
|
operation: "completed",
|
|
180665
180681
|
payload: {
|
|
180666
180682
|
role: "user",
|
|
180667
|
-
text:
|
|
180683
|
+
text: shown2,
|
|
180668
180684
|
...liveAttachments?.length ? { attachments: liveAttachments } : {}
|
|
180669
180685
|
}
|
|
180670
180686
|
});
|
|
180671
180687
|
try {
|
|
180672
|
-
turn.onUserInput?.(
|
|
180688
|
+
turn.onUserInput?.(shown2, opts?.attachments);
|
|
180673
180689
|
} catch {
|
|
180674
180690
|
}
|
|
180675
180691
|
return userItemId;
|
|
@@ -184464,7 +184480,7 @@ function buildEscalationChatContext(input) {
|
|
|
184464
184480
|
manual: "\u4EBA\u5DE5\u4E0A\u62A5\uFF08\u6709\u4EBA\u7528 oasis escalate \u63D0\u7684\uFF09"
|
|
184465
184481
|
};
|
|
184466
184482
|
const others = snap.issues.filter((row) => row.kind === "escalation" && !row.resolvedAt && row.id !== issue2.id).sort((a5, b6) => String(a5.createdAt).localeCompare(String(b6.createdAt)));
|
|
184467
|
-
const
|
|
184483
|
+
const shown2 = others.slice(0, OTHER_OPEN_LIMIT);
|
|
184468
184484
|
const lines = [
|
|
184469
184485
|
"\u3010\u8FD9\u6761\u4F1A\u8BDD\u662F\u4EBA\u4ECE\u4E00\u6761\u4E0A\u62A5\uFF08\u5347\u7EA7\u5361\uFF09\u70B9\u8FDB\u6765\u7684\u2014\u2014\u4F60\u662F\u8FD9\u5F20\u4EFB\u52A1\u7684\u534F\u8C03\u8005\uFF0C\u4EBA\u662F\u6765\u627E\u4F60\u4E00\u8D77\u5904\u7F6E\u8FD9\u6761\u4E0A\u62A5\u7684\u3002",
|
|
184470
184486
|
"\u4EE5\u4E0B\u662F\u8FD9\u6761\u4E0A\u62A5\u6B64\u523B\u7684\u4E8B\u5B9E\uFF0C\u4E0E\u4EBA\u5728\u754C\u9762\u4E0A\u770B\u5230\u7684\u90A3\u6BB5\u5F00\u573A\u767D\u540C\u6E90\u3002\u522B\u53CD\u95EE\u300C\u4F60\u8BF4\u7684\u662F\u54EA\u4EF6\u4E8B\u300D\uFF1B\u8981\u66F4\u7EC6\u7684\u73B0\u72B6\u81EA\u5DF1\u7528 `oasis status` / `oasis content <id>` \u73B0\u67E5\u56FE\u3002\u3011",
|
|
@@ -184489,8 +184505,8 @@ function buildEscalationChatContext(input) {
|
|
|
184489
184505
|
lines.push(
|
|
184490
184506
|
"",
|
|
184491
184507
|
others.length ? `\u8FD9\u5F20\u4EFB\u52A1\u4E0A\u8FD8\u5F00\u7740\u53E6\u5916 ${others.length} \u6761\u4E0A\u62A5\uFF1A` : "\u8FD9\u5F20\u4EFB\u52A1\u4E0A\u6CA1\u6709\u522B\u7684\u672A\u5173\u4E0A\u62A5\u3002",
|
|
184492
|
-
...
|
|
184493
|
-
...others.length >
|
|
184508
|
+
...shown2.map((row) => ` \xB7 ${row.id}${row.aboutNodeId ? `\uFF08\u8282\u70B9 ${row.aboutNodeId}\uFF09` : ""}\uFF1A${oneLine(row.body)}`),
|
|
184509
|
+
...others.length > shown2.length ? [` \xB7 \uFF08\u53E6\u6709 ${others.length - shown2.length} \u6761\u6CA1\u5217\u51FA\u6765\uFF0C\u7528 \`oasis status\` \u770B\u5168\uFF09`] : [],
|
|
184494
184510
|
"",
|
|
184495
184511
|
'\u5904\u7F6E\u5B8C\u8FD9\u6761\u4E0A\u62A5\uFF0C\u5728\u672C\u4F1A\u8BDD\u91CC\u8DD1 `oasis resolve-escalation --reason "<\u7ED3\u8BBA>"` \u5373\u53EF\u2014\u2014\u4F1A\u8BDD\u5DF2\u7ECF\u7ED1\u7740\u8FD9\u6761\u4E0A\u62A5\uFF0C\u4E0D\u7528\u5E26 id\uFF08\u5B83\u4F1A\u8F6C\u6210\u4E00\u5F20\u5F85\u4EBA\u786E\u8BA4\u7684\u5361\uFF0C\u4E0D\u662F\u7ACB\u523B\u751F\u6548\uFF09\u3002',
|
|
184496
184512
|
...kind === "output_stall" && node2 ? [`\u96F6\u4EA7\u51FA\u6B62\u635F\u540C\u65F6\u6682\u505C\u4E86\u6D3E\u53D1\uFF0C\u786E\u8BA4\u6839\u56E0\u5904\u7406\u6389\u4E4B\u540E\u8FD8\u8981 \`oasis release ${node2.id}\` \u624D\u4F1A\u91CD\u65B0\u6D3E\u3002`] : [],
|
|
@@ -214604,13 +214620,13 @@ async function startOasisServer(opts) {
|
|
|
214604
214620
|
...clientAttached ? { clientAttached } : {}
|
|
214605
214621
|
}, clientKey, attachments, retainLocallyOnFailure, resend ? { resend: true } : void 0);
|
|
214606
214622
|
if ((r5.insertStatus === "uncertain" || r5.orphanedReturn) && clientKey) {
|
|
214607
|
-
const
|
|
214623
|
+
const shown2 = r5.batch.map((m4) => m4.text).filter(Boolean).join("\n\n") || text7;
|
|
214608
214624
|
await landUndeliveredInsert({
|
|
214609
214625
|
store,
|
|
214610
214626
|
itemStore,
|
|
214611
214627
|
chatSessionId: sid,
|
|
214612
214628
|
clientKey,
|
|
214613
|
-
text:
|
|
214629
|
+
text: shown2,
|
|
214614
214630
|
attachments: attachments ?? [],
|
|
214615
214631
|
note: r5.orphanedReturn ? INSERT_RETURNED_NOTE : INSERT_UNCERTAIN_NOTE
|
|
214616
214632
|
});
|
|
@@ -244306,6 +244322,10 @@ var init_notification_store = __esm({
|
|
|
244306
244322
|
this.save();
|
|
244307
244323
|
return row;
|
|
244308
244324
|
}
|
|
244325
|
+
async findBySource(recipient, sourceKey) {
|
|
244326
|
+
const hits = [...this.rows.values()].filter((r5) => r5.recipient === recipient && r5.sourceKey === sourceKey).sort(newerFirst);
|
|
244327
|
+
return hits[0] ?? null;
|
|
244328
|
+
}
|
|
244309
244329
|
async listPending() {
|
|
244310
244330
|
return [...this.rows.values()].filter((r5) => r5.status === "pending");
|
|
244311
244331
|
}
|
|
@@ -244470,6 +244490,13 @@ var init_notification_store = __esm({
|
|
|
244470
244490
|
if (!e5.rows[0]) throw new Error(`notification insert conflicted but no live row: ${n3.recipient} ${n3.sourceKey}`);
|
|
244471
244491
|
return fromRow(e5.rows[0]);
|
|
244472
244492
|
}
|
|
244493
|
+
async findBySource(recipient, sourceKey) {
|
|
244494
|
+
const r5 = await this.sql.query(
|
|
244495
|
+
`SELECT * FROM ${this.t} WHERE recipient = $1 AND source_key = $2 ORDER BY entered_at DESC, id DESC LIMIT 1`,
|
|
244496
|
+
[recipient, sourceKey]
|
|
244497
|
+
);
|
|
244498
|
+
return r5.rows[0] ? fromRow(r5.rows[0]) : null;
|
|
244499
|
+
}
|
|
244473
244500
|
async listPending() {
|
|
244474
244501
|
const r5 = await this.sql.query(`SELECT * FROM ${this.t} WHERE status = 'pending'`);
|
|
244475
244502
|
return r5.rows.map(fromRow);
|
|
@@ -253045,10 +253072,10 @@ function mergedPushPayload(first, queued, companyId) {
|
|
|
253045
253072
|
const all2 = [first, ...queued];
|
|
253046
253073
|
const latest = all2[all2.length - 1];
|
|
253047
253074
|
const others = all2.slice(0, -1).map((r5) => r5.title.trim()).filter(Boolean);
|
|
253048
|
-
const
|
|
253075
|
+
const shown2 = others.slice(-OTHERS_LIMIT);
|
|
253049
253076
|
const task = latest.workspaceTitle?.trim() || first.workspaceTitle?.trim() || OASIS;
|
|
253050
253077
|
const lines = [latest.title.trim() || OASIS];
|
|
253051
|
-
if (
|
|
253078
|
+
if (shown2.length > 0) lines.push(`\u53E6\u6709\uFF1A${shown2.join("\u3001")}${others.length > shown2.length ? " \u7B49" : ""}`);
|
|
253052
253079
|
return {
|
|
253053
253080
|
title: `${task} \xB7 ${all2.length} \u6761\u5F85\u5904\u7406`,
|
|
253054
253081
|
body: lines.join("\n"),
|
|
@@ -257647,14 +257674,57 @@ var init_flag = __esm({
|
|
|
257647
257674
|
}
|
|
257648
257675
|
});
|
|
257649
257676
|
|
|
257650
|
-
// ../server/src/domains/todos/
|
|
257651
|
-
function
|
|
257652
|
-
if (
|
|
257653
|
-
|
|
257677
|
+
// ../server/src/domains/todos/notices.ts
|
|
257678
|
+
function shown(field, v2, nameOf2) {
|
|
257679
|
+
if (v2 === void 0 || v2 === "") return "\uFF08\u7A7A\uFF09";
|
|
257680
|
+
if (field === "dueDate" || field === "startDate") return formatTodoDue(v2);
|
|
257681
|
+
if (field === "assignee") return nameOf2(v2);
|
|
257682
|
+
return clip4(v2);
|
|
257683
|
+
}
|
|
257684
|
+
function assignedTitle(who, todo) {
|
|
257685
|
+
return `${who} \u6D3E\u7ED9\u4F60\uFF1A${todo.title}\uFF0C${formatTodoSpan(todo)}`;
|
|
257686
|
+
}
|
|
257687
|
+
function unseenTitle(assigneeName, todo) {
|
|
257688
|
+
return `${assigneeName} \u8FD8\u6CA1\u770B\u8FC7\u8FD9\u6761\uFF1A${todo.title}\uFF0C\u660E\u5929\u622A\u6B62`;
|
|
257689
|
+
}
|
|
257690
|
+
function changedTitle(who, todo, changes, nameOf2) {
|
|
257691
|
+
const parts = changes.map((c5) => `${FIELD_LABEL[c5.field] ?? c5.field} ${shown(c5.field, c5.oldValue, nameOf2)} \u2192 ${shown(c5.field, c5.newValue, nameOf2)}`);
|
|
257692
|
+
const reason = changes.find((c5) => c5.reason)?.reason;
|
|
257693
|
+
return `${who} \u6539\u4E86\u300C${todo.title}\u300D\uFF1A${parts.join("\uFF1B")}${reason ? `\uFF1B\u539F\u56E0\uFF1A${clip4(reason)}` : ""}`;
|
|
257694
|
+
}
|
|
257695
|
+
function statusTitle(who, todo, kind, reason) {
|
|
257696
|
+
const verb = kind === "todo-done" ? "\u5B8C\u6210\u4E86" : kind === "todo-reopened" ? "\u91CD\u65B0\u6253\u5F00\u4E86" : "\u53D6\u6D88\u4E86";
|
|
257697
|
+
return `${who} ${verb}\u300C${todo.title}\u300D${reason ? `\uFF1B\u539F\u56E0\uFF1A${clip4(reason)}` : ""}`;
|
|
257698
|
+
}
|
|
257699
|
+
var VALUE_MAX, FIELD_LABEL, clip4, todoAssignedSourceKey, todoChangeSourceKey, todoUnseenSourceKey;
|
|
257700
|
+
var init_notices = __esm({
|
|
257701
|
+
"../server/src/domains/todos/notices.ts"() {
|
|
257702
|
+
"use strict";
|
|
257703
|
+
init_src();
|
|
257704
|
+
VALUE_MAX = 40;
|
|
257705
|
+
FIELD_LABEL = {
|
|
257706
|
+
title: "\u6807\u9898",
|
|
257707
|
+
note: "\u5907\u6CE8",
|
|
257708
|
+
startDate: "\u5F00\u59CB\u65E5",
|
|
257709
|
+
startTime: "\u5F00\u59CB\u65F6\u523B",
|
|
257710
|
+
dueDate: "\u622A\u6B62\u65E5",
|
|
257711
|
+
dueTime: "\u622A\u6B62\u65F6\u523B",
|
|
257712
|
+
linkedWorkorderId: "\u5173\u8054\u5DE5\u5355",
|
|
257713
|
+
assignee: "\u627F\u63A5\u4EBA"
|
|
257714
|
+
};
|
|
257715
|
+
clip4 = (v2) => v2.length > VALUE_MAX ? `${v2.slice(0, VALUE_MAX)}\u2026` : v2;
|
|
257716
|
+
todoAssignedSourceKey = (todoId) => `todo:${todoId}@assigned`;
|
|
257717
|
+
todoChangeSourceKey = (todoId, changeId) => `todo:${todoId}@change:${changeId}`;
|
|
257718
|
+
todoUnseenSourceKey = (todo) => `todo:${todo.id}@unseen:${todo.dueDate}`;
|
|
257654
257719
|
}
|
|
257720
|
+
});
|
|
257721
|
+
|
|
257722
|
+
// ../server/src/domains/todos/service.ts
|
|
257723
|
+
function canSeeTodo(todo, caller) {
|
|
257724
|
+
return canReadTodo(todo, caller.principal);
|
|
257655
257725
|
}
|
|
257656
|
-
function
|
|
257657
|
-
return
|
|
257726
|
+
function canChangeTodo(todo, caller) {
|
|
257727
|
+
return canWriteTodo(todo, caller.principal);
|
|
257658
257728
|
}
|
|
257659
257729
|
function newTodoId() {
|
|
257660
257730
|
return `td_${(0, import_node_crypto71.randomBytes)(4).toString("hex")}`;
|
|
@@ -257675,16 +257745,18 @@ function assertStartBeforeDue(t) {
|
|
|
257675
257745
|
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`);
|
|
257676
257746
|
}
|
|
257677
257747
|
}
|
|
257678
|
-
var import_node_crypto71, TITLE_MAX, NOTE_MAX, REASON_MAX, clean2, TodoService;
|
|
257748
|
+
var import_node_crypto71, TITLE_MAX, NOTE_MAX, REASON_MAX, LIST_MAX, clean2, TodoService;
|
|
257679
257749
|
var init_service10 = __esm({
|
|
257680
257750
|
"../server/src/domains/todos/service.ts"() {
|
|
257681
257751
|
"use strict";
|
|
257682
257752
|
import_node_crypto71 = require("node:crypto");
|
|
257683
257753
|
init_src();
|
|
257684
257754
|
init_router();
|
|
257755
|
+
init_notices();
|
|
257685
257756
|
TITLE_MAX = 200;
|
|
257686
257757
|
NOTE_MAX = 4e3;
|
|
257687
257758
|
REASON_MAX = 500;
|
|
257759
|
+
LIST_MAX = 500;
|
|
257688
257760
|
clean2 = (v2) => {
|
|
257689
257761
|
const t = v2?.trim();
|
|
257690
257762
|
return t ? t : void 0;
|
|
@@ -257701,7 +257773,71 @@ var init_service10 = __esm({
|
|
|
257701
257773
|
}
|
|
257702
257774
|
async respond(todo) {
|
|
257703
257775
|
const today = await this.today();
|
|
257704
|
-
return { today, todayLine: formatTodayLine(today), todo };
|
|
257776
|
+
return { today, todayLine: formatTodayLine(today), todo, names: await this.namesFor([todo]) };
|
|
257777
|
+
}
|
|
257778
|
+
async people() {
|
|
257779
|
+
return await this.deps.people?.() ?? [];
|
|
257780
|
+
}
|
|
257781
|
+
/** 列表 / 单条里出现的发起人、承接人的显示名。 */
|
|
257782
|
+
async namesFor(todos, people) {
|
|
257783
|
+
const ids2 = new Set(todos.flatMap((t) => [t.creatorActorId, ...todoAssignees(t)]));
|
|
257784
|
+
const out = {};
|
|
257785
|
+
for (const p4 of people ?? await this.people()) if (ids2.has(p4.actorId)) out[p4.actorId] = p4.name;
|
|
257786
|
+
return out;
|
|
257787
|
+
}
|
|
257788
|
+
/**
|
|
257789
|
+
* 把「人」解析成本公司唯一一个真人(ADR 0640):`me` / `我` = 调用者代表的真人;actorId 必须是本公司成员;
|
|
257790
|
+
* 名字先比全名(昵称、账号名、邮箱、邮箱 @ 前那段,不分大小写),没有再比「包含」——**只认唯一一个**,
|
|
257791
|
+
* 一个都没有或不止一个都报错、列出候选,不替人挑。
|
|
257792
|
+
*/
|
|
257793
|
+
async resolvePerson(raw, caller, what = "\u627F\u63A5\u4EBA") {
|
|
257794
|
+
const input = raw.trim();
|
|
257795
|
+
if (!input) throw new ApiError(400, "TODO_INVALID", `${what}\u4E0D\u80FD\u4E3A\u7A7A`);
|
|
257796
|
+
if (input === "me" || input === "\u6211") return caller.principal;
|
|
257797
|
+
const people = await this.people();
|
|
257798
|
+
if (input.startsWith("actor:")) {
|
|
257799
|
+
if (input === caller.principal) return input;
|
|
257800
|
+
if (people.some((p4) => p4.actorId === input)) return input;
|
|
257801
|
+
throw new ApiError(400, "TODO_PERSON_NOT_MEMBER", `${what} ${input} \u4E0D\u662F\u672C\u516C\u53F8\u7684\u771F\u4EBA\u6210\u5458`);
|
|
257802
|
+
}
|
|
257803
|
+
const key2 = input.toLowerCase();
|
|
257804
|
+
const names = (p4) => [p4.name, ...p4.aliases ?? []].map((n3) => n3.trim().toLowerCase()).filter(Boolean);
|
|
257805
|
+
let hits = people.filter((p4) => names(p4).includes(key2));
|
|
257806
|
+
if (hits.length === 0) hits = people.filter((p4) => names(p4).some((n3) => n3.includes(key2)));
|
|
257807
|
+
const unique4 = [...new Map(hits.map((p4) => [p4.actorId, p4])).values()];
|
|
257808
|
+
if (unique4.length === 1) return unique4[0].actorId;
|
|
257809
|
+
if (unique4.length === 0) throw new ApiError(400, "TODO_PERSON_NOT_FOUND", `\u672C\u516C\u53F8\u6CA1\u6709\u53EB\u300C${input}\u300D\u7684\u6210\u5458\uFF08${what}\uFF09\u3002\u7528 actorId \u6307\u5B9A\uFF0C\u6216\u6362\u4E2A\u5199\u6CD5\u3002`);
|
|
257810
|
+
const list3 = unique4.map((p4) => `${p4.name}\uFF08${p4.actorId}\uFF09`).join("\u3001");
|
|
257811
|
+
throw new ApiError(400, "TODO_PERSON_AMBIGUOUS", `\u300C${input}\u300D\u5BF9\u5F97\u4E0A\u4E0D\u6B62\u4E00\u4E2A\u4EBA\uFF1A${list3}\u3002\u8BF7\u7528 actorId \u6307\u5B9A${what}\u3002`);
|
|
257812
|
+
}
|
|
257813
|
+
/** 给另一方(或承接人)发通知;失败只告警。 */
|
|
257814
|
+
async notice(todo, actor, recipients, kind, sourceKey, title, at2) {
|
|
257815
|
+
if (!this.deps.notify || recipients.length === 0) return;
|
|
257816
|
+
const records = recipients.map((recipient) => ({
|
|
257817
|
+
recipient,
|
|
257818
|
+
category: "todo",
|
|
257819
|
+
sourceKey,
|
|
257820
|
+
kind,
|
|
257821
|
+
title,
|
|
257822
|
+
enteredAt: at2,
|
|
257823
|
+
actorId: actor,
|
|
257824
|
+
// 来源对话是发起人那边的:只有发起人点了能跳回去;给承接人的不带(带了也打不开)。
|
|
257825
|
+
...recipient === todo.creatorActorId && todo.sourceChatSessionId ? { chatSessionId: todo.sourceChatSessionId } : {}
|
|
257826
|
+
}));
|
|
257827
|
+
try {
|
|
257828
|
+
await this.deps.notify(records);
|
|
257829
|
+
} catch (error3) {
|
|
257830
|
+
this.deps.warn?.(new Error(`\u5F85\u529E ${todo.id} \u901A\u77E5\u6CA1\u53D1\u51FA\u53BB\uFF1A${String(error3)}`));
|
|
257831
|
+
}
|
|
257832
|
+
}
|
|
257833
|
+
/** 「另一方」:调用者是发起人 → 承接人们;是承接人 → 发起人。只在派给别人、且已经发出的待办上有。 */
|
|
257834
|
+
counterparts(todo, caller) {
|
|
257835
|
+
if (!isTodoDelegated(todo) || isTodoUnsent(todo)) return [];
|
|
257836
|
+
const parties = [todo.creatorActorId, ...todoAssignees(todo)];
|
|
257837
|
+
return [...new Set(parties)].filter((p4) => p4 !== caller.principal);
|
|
257838
|
+
}
|
|
257839
|
+
async nameOf(id) {
|
|
257840
|
+
return (await this.people()).find((p4) => p4.actorId === id)?.name ?? id;
|
|
257705
257841
|
}
|
|
257706
257842
|
change(todoId, caller, at2, field, oldValue, newValue, reason) {
|
|
257707
257843
|
return {
|
|
@@ -257731,8 +257867,10 @@ var init_service10 = __esm({
|
|
|
257731
257867
|
}
|
|
257732
257868
|
assertStartBeforeDue({ ...input });
|
|
257733
257869
|
const creator = caller.principal;
|
|
257734
|
-
const assignee = caller
|
|
257735
|
-
|
|
257870
|
+
const assignee = input.assignee !== void 0 ? await this.resolvePerson(input.assignee, caller) : creator;
|
|
257871
|
+
const delegated = assignee !== creator;
|
|
257872
|
+
const sourceChatSessionId = clean2(input.sourceChatSessionId);
|
|
257873
|
+
const sourceRunId = delegated && sourceChatSessionId ? this.deps.runOf?.(sourceChatSessionId) : void 0;
|
|
257736
257874
|
const at2 = new Date(this.nowMs()).toISOString();
|
|
257737
257875
|
const todo = {
|
|
257738
257876
|
id: newTodoId(),
|
|
@@ -257745,27 +257883,93 @@ var init_service10 = __esm({
|
|
|
257745
257883
|
...input.dueTime ? { dueTime: input.dueTime } : {},
|
|
257746
257884
|
...input.startDate ? { startDate: input.startDate } : {},
|
|
257747
257885
|
...input.startTime ? { startTime: input.startTime } : {},
|
|
257748
|
-
status: "open",
|
|
257749
|
-
...
|
|
257886
|
+
status: delegated ? "draft" : "open",
|
|
257887
|
+
...sourceChatSessionId ? { sourceChatSessionId } : {},
|
|
257888
|
+
...sourceRunId ? { sourceRunId } : {},
|
|
257750
257889
|
createdAt: at2,
|
|
257751
257890
|
updatedAt: at2
|
|
257752
257891
|
};
|
|
257753
257892
|
const saved = await this.deps.store.create(todo, [this.change(todo.id, caller, at2, "created", void 0, title)]);
|
|
257754
257893
|
return this.respond(saved);
|
|
257755
257894
|
}
|
|
257756
|
-
|
|
257757
|
-
|
|
257758
|
-
|
|
257895
|
+
/**
|
|
257896
|
+
* 列表(ADR 0640):筛选都不给 = 「我承接的、未完成的」(与 0635 相同)。人可以写 actorId、成员名或 `me`;
|
|
257897
|
+
* 从没发出过的草案只列给发起人(存储层与 `canReadTodo` 配对的那条条件)。
|
|
257898
|
+
*/
|
|
257899
|
+
async list(caller, query = {}) {
|
|
257900
|
+
const statuses2 = query.all ? TODO_STATUSES : query.statuses?.length ? query.statuses : ["open"];
|
|
257901
|
+
for (const st of statuses2) if (!TODO_STATUSES.includes(st)) throw new ApiError(400, "TODO_INVALID", `status \u53EA\u6536 ${TODO_STATUSES.join(" / ")}\uFF0C\u6536\u5230\uFF1A${st}`);
|
|
257902
|
+
if (query.dueFrom !== void 0) assertDay(query.dueFrom, "dueFrom");
|
|
257903
|
+
if (query.dueTo !== void 0) assertDay(query.dueTo, "dueTo");
|
|
257904
|
+
const assignee = query.assignee !== void 0 ? await this.resolvePerson(query.assignee, caller) : void 0;
|
|
257905
|
+
const creator = query.creator !== void 0 ? await this.resolvePerson(query.creator, caller, "\u53D1\u8D77\u4EBA") : void 0;
|
|
257906
|
+
const mine = assignee === void 0 && creator === void 0 && !query.everyone;
|
|
257907
|
+
const q4 = clean2(query.q);
|
|
257908
|
+
const items = await this.deps.store.search({
|
|
257909
|
+
statuses: statuses2,
|
|
257910
|
+
...mine ? { assignee: caller.principal } : assignee ? { assignee } : {},
|
|
257911
|
+
...creator ? { creator } : {},
|
|
257912
|
+
...query.dueFrom ? { dueFrom: query.dueFrom } : {},
|
|
257913
|
+
...query.dueTo ? { dueTo: query.dueTo } : {},
|
|
257914
|
+
...q4 ? { q: q4 } : {},
|
|
257915
|
+
...clean2(query.chatSessionId) ? { chatSessionId: clean2(query.chatSessionId) } : {},
|
|
257916
|
+
viewer: caller.principal,
|
|
257917
|
+
limit: LIST_MAX
|
|
257918
|
+
});
|
|
257919
|
+
const visible = items.filter((t) => canSeeTodo(t, caller));
|
|
257759
257920
|
const today = await this.today();
|
|
257760
|
-
return { today, todayLine: formatTodayLine(today), items };
|
|
257921
|
+
return { today, todayLine: formatTodayLine(today), items: visible, names: await this.namesFor(visible) };
|
|
257761
257922
|
}
|
|
257762
|
-
/**
|
|
257923
|
+
/**
|
|
257924
|
+
* 读一条并校验读权限。不存在 404;从没发出过的草案对发起人以外的人也是 404(不透露有这么一条)。
|
|
257925
|
+
*/
|
|
257763
257926
|
async get(caller, id) {
|
|
257764
257927
|
const todo = await this.deps.store.get(id);
|
|
257765
|
-
if (!todo) throw new ApiError(404, "TODO_NOT_FOUND", `\u5F85\u529E ${id} \u4E0D\u5B58\u5728`);
|
|
257766
|
-
if (!canAccessTodo(todo, caller)) throw new ApiError(403, "TODO_FORBIDDEN", "\u65E0\u6743\u67E5\u770B\u6216\u4FEE\u6539\u8FD9\u6761\u5F85\u529E");
|
|
257928
|
+
if (!todo || !canSeeTodo(todo, caller)) throw new ApiError(404, "TODO_NOT_FOUND", `\u5F85\u529E ${id} \u4E0D\u5B58\u5728`);
|
|
257767
257929
|
return todo;
|
|
257768
257930
|
}
|
|
257931
|
+
/** 读一条并校验改权限:读得到但不是当事人 403(任务书口径「其他人 403」)。 */
|
|
257932
|
+
async getForChange(caller, id) {
|
|
257933
|
+
const todo = await this.get(caller, id);
|
|
257934
|
+
if (!canChangeTodo(todo, caller)) throw new ApiError(403, "TODO_FORBIDDEN", "\u53EA\u6709\u53D1\u8D77\u4EBA\u6216\u627F\u63A5\u4EBA\u80FD\u6539\u8FD9\u6761\u5F85\u529E");
|
|
257935
|
+
return todo;
|
|
257936
|
+
}
|
|
257937
|
+
/**
|
|
257938
|
+
* `oasis todo show`:单条 + 全部变更记录。承接人(派给别人的、已发出的)第一次看时记下 `firstViewedAt`
|
|
257939
|
+
* (「对方还没看过」提醒用,ADR 0640);发起人、第三人看不算。
|
|
257940
|
+
*/
|
|
257941
|
+
async view(caller, id) {
|
|
257942
|
+
let todo = await this.get(caller, id);
|
|
257943
|
+
if (!todo.firstViewedAt && !isTodoUnsent(todo) && isTodoAssignedToByOther(todo, caller.principal)) {
|
|
257944
|
+
todo = await this.deps.store.markFirstViewed(todo.id, new Date(this.nowMs()).toISOString()) ?? todo;
|
|
257945
|
+
}
|
|
257946
|
+
return { todo, changes: await this.deps.store.listChanges(id), names: await this.namesFor([todo]) };
|
|
257947
|
+
}
|
|
257948
|
+
/**
|
|
257949
|
+
* 发出(ADR 0640):草案 → open,记 `sentAt`,通知承接人「X 派给你:…」。
|
|
257950
|
+
* **只有发起人本人**能发——经助理(agent)调用一律 403:「先出草案、人点发出」就是为了不让助理替人发出去。
|
|
257951
|
+
* 已经发出过的再点一次原样返回(连点 / 刷新后重点不报错、不重发通知)。
|
|
257952
|
+
*/
|
|
257953
|
+
async send(caller, id) {
|
|
257954
|
+
const before = await this.get(caller, id);
|
|
257955
|
+
if (before.creatorActorId !== caller.principal) throw new ApiError(403, "TODO_FORBIDDEN", "\u53EA\u6709\u53D1\u8D77\u4EBA\u80FD\u53D1\u51FA\u8FD9\u6761\u5F85\u529E");
|
|
257956
|
+
if (caller.hand) throw new ApiError(403, "TODO_SEND_HUMAN_ONLY", "\u6D3E\u7ED9\u522B\u4EBA\u7684\u5F85\u529E\u53EA\u80FD\u7531\u53D1\u8D77\u4EBA\u672C\u4EBA\u5728\u8349\u6848\u5361\u4E0A\u70B9\u300C\u53D1\u51FA\u300D\uFF0C\u52A9\u7406\u4E0D\u80FD\u4EE3\u53D1\u3002");
|
|
257957
|
+
if (before.sentAt) return this.respond(before);
|
|
257958
|
+
if (before.status !== "draft") throw new ApiError(409, "TODO_NOT_DRAFT", "\u8FD9\u6761\u5F85\u529E\u4E0D\u662F\u8349\u6848\uFF08\u53EF\u80FD\u5DF2\u53D6\u6D88\uFF09\uFF0C\u4E0D\u80FD\u53D1\u51FA");
|
|
257959
|
+
const at2 = new Date(this.nowMs()).toISOString();
|
|
257960
|
+
const next = { ...before, status: "open", sentAt: at2, updatedAt: at2, recordedByActorId: caller.actor };
|
|
257961
|
+
const out = await this.save(caller, before, next, [this.change(id, caller, at2, "sent", void 0, before.assigneeActorId)]);
|
|
257962
|
+
await this.notice(
|
|
257963
|
+
out.todo,
|
|
257964
|
+
caller.principal,
|
|
257965
|
+
todoAssignees(out.todo),
|
|
257966
|
+
"todo-assigned",
|
|
257967
|
+
todoAssignedSourceKey(id),
|
|
257968
|
+
assignedTitle(await this.nameOf(caller.principal), out.todo),
|
|
257969
|
+
at2
|
|
257970
|
+
);
|
|
257971
|
+
return out;
|
|
257972
|
+
}
|
|
257769
257973
|
async save(caller, before, next, changes) {
|
|
257770
257974
|
if (changes.length === 0) return this.respond(before);
|
|
257771
257975
|
const saved = await this.deps.store.update(next, before.updatedAt, changes);
|
|
@@ -257773,7 +257977,7 @@ var init_service10 = __esm({
|
|
|
257773
257977
|
return this.respond(saved);
|
|
257774
257978
|
}
|
|
257775
257979
|
async edit(caller, id, input) {
|
|
257776
|
-
const before = await this.
|
|
257980
|
+
const before = await this.getForChange(caller, id);
|
|
257777
257981
|
const reason = clean2(input.reason);
|
|
257778
257982
|
if (reason && reason.length > REASON_MAX) throw new ApiError(400, "TODO_INVALID", `reason \u4E0D\u80FD\u8D85\u8FC7 ${REASON_MAX} \u5B57`);
|
|
257779
257983
|
const at2 = new Date(this.nowMs()).toISOString();
|
|
@@ -257819,29 +258023,75 @@ var init_service10 = __esm({
|
|
|
257819
258023
|
set("dueTime", input.dueTime ?? void 0);
|
|
257820
258024
|
}
|
|
257821
258025
|
if (input.linkedWorkorderId !== void 0) set("linkedWorkorderId", clean2(input.linkedWorkorderId));
|
|
258026
|
+
if (input.assignee !== void 0) {
|
|
258027
|
+
if (!isTodoUnsent(before)) throw new ApiError(400, "TODO_ASSIGNEE_LOCKED", "\u5DF2\u7ECF\u53D1\u51FA\u7684\u5F85\u529E\u4E0D\u80FD\u6362\u627F\u63A5\u4EBA\uFF1A\u53D6\u6D88\u8FD9\u6761\uFF08\u5E26\u539F\u56E0\uFF09\uFF0C\u518D\u91CD\u65B0\u6D3E\u4E00\u6761\u3002");
|
|
258028
|
+
const assignee = await this.resolvePerson(input.assignee, caller);
|
|
258029
|
+
if (assignee === before.creatorActorId) throw new ApiError(400, "TODO_INVALID", "\u8349\u6848\u4E0D\u80FD\u6539\u6210\u6D3E\u7ED9\u81EA\u5DF1\uFF1A\u53D6\u6D88\u8FD9\u6761\u8349\u6848\uFF0C\u518D\u7ED9\u81EA\u5DF1\u8BB0\u4E00\u6761\u3002");
|
|
258030
|
+
if (assignee !== before.assigneeActorId) {
|
|
258031
|
+
next.assigneeActorId = assignee;
|
|
258032
|
+
changes.push(this.change(id, caller, at2, "assignee", before.assigneeActorId, assignee, reason));
|
|
258033
|
+
}
|
|
258034
|
+
}
|
|
257822
258035
|
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");
|
|
257823
258036
|
assertStartBeforeDue(next);
|
|
258037
|
+
if (!reason && isTodoAssignedToByOther(before, caller.principal) && changes.some((c5) => c5.field === "dueDate" || c5.field === "dueTime")) {
|
|
258038
|
+
throw new ApiError(400, "TODO_REASON_REQUIRED", "\u8FD9\u6761\u662F\u522B\u4EBA\u6D3E\u7ED9\u4F60\u7684\uFF1A\u6539\u622A\u6B62\u8981\u5199\u539F\u56E0\uFF08--reason\uFF09\uFF0C\u53D1\u8D77\u4EBA\u4F1A\u6536\u5230\u901A\u77E5\u3002");
|
|
258039
|
+
}
|
|
257824
258040
|
if (changes.length > 0) {
|
|
257825
258041
|
next.updatedAt = at2;
|
|
257826
258042
|
next.recordedByActorId = caller.actor;
|
|
257827
258043
|
}
|
|
257828
|
-
|
|
258044
|
+
const out = await this.save(caller, before, next, changes);
|
|
258045
|
+
if (changes.length > 0) {
|
|
258046
|
+
const people = await this.people();
|
|
258047
|
+
const nameOf2 = (a5) => people.find((p4) => p4.actorId === a5)?.name ?? a5;
|
|
258048
|
+
await this.notice(
|
|
258049
|
+
out.todo,
|
|
258050
|
+
caller.principal,
|
|
258051
|
+
this.counterparts(out.todo, caller),
|
|
258052
|
+
"todo-changed",
|
|
258053
|
+
todoChangeSourceKey(id, changes[0].id),
|
|
258054
|
+
changedTitle(nameOf2(caller.principal), out.todo, changes, nameOf2),
|
|
258055
|
+
at2
|
|
258056
|
+
);
|
|
258057
|
+
}
|
|
258058
|
+
return out;
|
|
257829
258059
|
}
|
|
257830
|
-
|
|
257831
|
-
|
|
258060
|
+
/**
|
|
258061
|
+
* 完成 / 取消 / 重新打开。草案(从没发出过的):不能完成;取消了也仍只有发起人看得到;重新打开回到草案、不会因此发出去。
|
|
258062
|
+
* 别人派给我的,取消必须带原因(ADR 0640 D9)。派给别人且已发出的,动完通知另一方。
|
|
258063
|
+
*/
|
|
258064
|
+
async setStatus(caller, id, requested, reason) {
|
|
258065
|
+
const before = await this.getForChange(caller, id);
|
|
257832
258066
|
const why = clean2(reason);
|
|
257833
258067
|
if (why && why.length > REASON_MAX) throw new ApiError(400, "TODO_INVALID", `reason \u4E0D\u80FD\u8D85\u8FC7 ${REASON_MAX} \u5B57`);
|
|
258068
|
+
const unsent = isTodoUnsent(before);
|
|
258069
|
+
if (unsent && requested === "done") throw new ApiError(400, "TODO_NOT_SENT", "\u8FD9\u6761\u8FD8\u662F\u8349\u6848\uFF08\u6CA1\u53D1\u51FA\uFF09\uFF0C\u4E0D\u80FD\u6807\u5B8C\u6210\uFF1A\u5148\u5728\u8349\u6848\u5361\u4E0A\u70B9\u300C\u53D1\u51FA\u300D\uFF0C\u6216\u53D6\u6D88\u5B83\u3002");
|
|
258070
|
+
if (before.status === "draft" && requested === "open") throw new ApiError(400, "TODO_NOT_SENT", "\u8FD9\u6761\u662F\u8349\u6848\uFF1A\u8981\u751F\u6548\u8BF7\u53D1\u8D77\u4EBA\u5728\u8349\u6848\u5361\u4E0A\u70B9\u300C\u53D1\u51FA\u300D\u3002");
|
|
258071
|
+
const status = unsent && requested === "open" ? "draft" : requested;
|
|
257834
258072
|
if (before.status === status) return this.respond(before);
|
|
258073
|
+
if (status === "cancelled" && !why && isTodoAssignedToByOther(before, caller.principal)) {
|
|
258074
|
+
throw new ApiError(400, "TODO_REASON_REQUIRED", "\u8FD9\u6761\u662F\u522B\u4EBA\u6D3E\u7ED9\u4F60\u7684\uFF1A\u53D6\u6D88\u8981\u5199\u539F\u56E0\uFF08--reason\uFF09\uFF0C\u53D1\u8D77\u4EBA\u4F1A\u6536\u5230\u901A\u77E5\u3002");
|
|
258075
|
+
}
|
|
257835
258076
|
const at2 = new Date(this.nowMs()).toISOString();
|
|
257836
258077
|
const next = { ...before, status, updatedAt: at2, recordedByActorId: caller.actor };
|
|
257837
258078
|
delete next.doneAt;
|
|
257838
258079
|
delete next.cancelledAt;
|
|
257839
258080
|
if (status === "done") next.doneAt = at2;
|
|
257840
258081
|
if (status === "cancelled") next.cancelledAt = at2;
|
|
257841
|
-
|
|
257842
|
-
|
|
257843
|
-
|
|
257844
|
-
|
|
258082
|
+
const change = this.change(id, caller, at2, "status", before.status, status, why);
|
|
258083
|
+
const out = await this.save(caller, before, next, [change]);
|
|
258084
|
+
const kind = status === "done" ? "todo-done" : status === "cancelled" ? "todo-cancelled" : "todo-reopened";
|
|
258085
|
+
await this.notice(
|
|
258086
|
+
out.todo,
|
|
258087
|
+
caller.principal,
|
|
258088
|
+
this.counterparts(out.todo, caller),
|
|
258089
|
+
kind,
|
|
258090
|
+
todoChangeSourceKey(id, change.id),
|
|
258091
|
+
statusTitle(await this.nameOf(caller.principal), out.todo, kind, why),
|
|
258092
|
+
at2
|
|
258093
|
+
);
|
|
258094
|
+
return out;
|
|
257845
258095
|
}
|
|
257846
258096
|
};
|
|
257847
258097
|
}
|
|
@@ -257905,15 +258155,29 @@ var init_store3 = __esm({
|
|
|
257905
258155
|
return this.write((rows) => {
|
|
257906
258156
|
const current = rows.todos[next.id];
|
|
257907
258157
|
if (!current || current.updatedAt !== expectedUpdatedAt) return null;
|
|
257908
|
-
|
|
258158
|
+
const firstViewedAt = current.firstViewedAt ?? next.firstViewedAt;
|
|
258159
|
+
rows.todos[next.id] = structuredClone({ ...next, ...firstViewedAt ? { firstViewedAt } : {} });
|
|
257909
258160
|
rows.changes.push(...structuredClone(changes));
|
|
257910
|
-
return next;
|
|
258161
|
+
return rows.todos[next.id];
|
|
257911
258162
|
});
|
|
257912
258163
|
}
|
|
257913
258164
|
async listInvolving(actorId, statuses2) {
|
|
257914
258165
|
await this.tail;
|
|
257915
258166
|
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));
|
|
257916
258167
|
}
|
|
258168
|
+
async search(f6) {
|
|
258169
|
+
await this.tail;
|
|
258170
|
+
const q4 = f6.q?.toLowerCase();
|
|
258171
|
+
return Object.values(this.rows.todos).filter((t) => f6.statuses.includes(t.status) && (!f6.assignee || todoAssignees(t).includes(f6.assignee)) && (!f6.creator || t.creatorActorId === f6.creator) && (!f6.dueFrom || t.dueDate >= f6.dueFrom) && (!f6.dueTo || t.dueDate <= f6.dueTo) && (!f6.chatSessionId || t.sourceChatSessionId === f6.chatSessionId) && (!q4 || t.title.toLowerCase().includes(q4) || (t.note ?? "").toLowerCase().includes(q4)) && canReadTodo(t, f6.viewer)).sort(compareTodos).slice(0, f6.limit).map((t) => structuredClone(t));
|
|
258172
|
+
}
|
|
258173
|
+
markFirstViewed(id, at2) {
|
|
258174
|
+
return this.write((rows) => {
|
|
258175
|
+
const t = rows.todos[id];
|
|
258176
|
+
if (!t) return null;
|
|
258177
|
+
t.firstViewedAt ??= at2;
|
|
258178
|
+
return t;
|
|
258179
|
+
}).then((r5) => r5 ?? this.get(id));
|
|
258180
|
+
}
|
|
257917
258181
|
async listOpenReminderCandidates(fromDay, toDay) {
|
|
257918
258182
|
await this.tail;
|
|
257919
258183
|
const within = (day) => day !== void 0 && day >= fromDay && day <= toDay;
|
|
@@ -257943,18 +258207,32 @@ function todosDomain(options) {
|
|
|
257943
258207
|
const sourceSession = (req, fromBody) => req.auth.dispatch?.chatSessionId ?? fromBody;
|
|
257944
258208
|
return (router) => {
|
|
257945
258209
|
router.get("/api/todos", wrap(async (req, service, caller) => {
|
|
257946
|
-
const
|
|
257947
|
-
|
|
258210
|
+
const q4 = req.query;
|
|
258211
|
+
const flag = (k6) => ["1", "true"].includes((q4.get(k6) ?? "").toLowerCase());
|
|
258212
|
+
const one2 = (k6) => q4.get(k6) ?? void 0;
|
|
258213
|
+
const statuses2 = q4.getAll("status").flatMap((v2) => v2.split(",")).map((v2) => v2.trim()).filter(Boolean);
|
|
258214
|
+
return {
|
|
258215
|
+
status: 200,
|
|
258216
|
+
body: await service.list(caller, {
|
|
258217
|
+
all: flag("all"),
|
|
258218
|
+
everyone: flag("everyone"),
|
|
258219
|
+
...statuses2.length ? { statuses: statuses2 } : {},
|
|
258220
|
+
...one2("assignee") !== void 0 ? { assignee: one2("assignee") } : {},
|
|
258221
|
+
...one2("creator") !== void 0 ? { creator: one2("creator") } : {},
|
|
258222
|
+
...one2("dueFrom") !== void 0 ? { dueFrom: one2("dueFrom") } : {},
|
|
258223
|
+
...one2("dueTo") !== void 0 ? { dueTo: one2("dueTo") } : {},
|
|
258224
|
+
...one2("q") !== void 0 ? { q: one2("q") } : {},
|
|
258225
|
+
...one2("chatSessionId") !== void 0 ? { chatSessionId: one2("chatSessionId") } : {}
|
|
258226
|
+
})
|
|
258227
|
+
};
|
|
257948
258228
|
}));
|
|
257949
258229
|
router.post("/api/todos", wrap(async (req, service, caller) => {
|
|
257950
258230
|
const body2 = create.parse(req.body ?? {});
|
|
257951
258231
|
const sourceChatSessionId = sourceSession(req, body2.sourceChatSessionId);
|
|
257952
258232
|
return { status: 201, body: await service.create(caller, { ...body2, ...sourceChatSessionId ? { sourceChatSessionId } : {} }) };
|
|
257953
258233
|
}));
|
|
257954
|
-
router.get("/api/todos/:id", wrap(async (req, service, caller) => {
|
|
257955
|
-
|
|
257956
|
-
return { status: 200, body: { todo, changes: await service.history(caller, todo.id) } };
|
|
257957
|
-
}));
|
|
258234
|
+
router.get("/api/todos/:id", wrap(async (req, service, caller) => ({ status: 200, body: await service.view(caller, req.params.id) })));
|
|
258235
|
+
router.post("/api/todos/:id/send", wrap(async (req, service, caller) => ({ status: 200, body: await service.send(caller, req.params.id) })));
|
|
257958
258236
|
router.patch("/api/todos/:id", wrap(async (req, service, caller) => {
|
|
257959
258237
|
const body2 = edit.parse(req.body ?? {});
|
|
257960
258238
|
return { status: 200, body: await service.edit(caller, req.params.id, body2) };
|
|
@@ -257975,6 +258253,7 @@ var init_routes11 = __esm({
|
|
|
257975
258253
|
init_zod();
|
|
257976
258254
|
init_router();
|
|
257977
258255
|
create = external_exports.object({
|
|
258256
|
+
assignee: external_exports.string().optional(),
|
|
257978
258257
|
title: external_exports.string(),
|
|
257979
258258
|
note: external_exports.string().optional(),
|
|
257980
258259
|
dueDate: external_exports.string(),
|
|
@@ -257991,6 +258270,7 @@ var init_routes11 = __esm({
|
|
|
257991
258270
|
startDate: external_exports.string().nullable().optional(),
|
|
257992
258271
|
startTime: external_exports.string().nullable().optional(),
|
|
257993
258272
|
linkedWorkorderId: external_exports.string().nullable().optional(),
|
|
258273
|
+
assignee: external_exports.string().optional(),
|
|
257994
258274
|
reason: external_exports.string().optional()
|
|
257995
258275
|
}).strict();
|
|
257996
258276
|
statusBody = external_exports.object({ reason: external_exports.string().optional() }).strict();
|
|
@@ -258029,6 +258309,7 @@ var init_reminders = __esm({
|
|
|
258029
258309
|
"../server/src/domains/todos/reminders.ts"() {
|
|
258030
258310
|
"use strict";
|
|
258031
258311
|
init_src();
|
|
258312
|
+
init_notices();
|
|
258032
258313
|
TODO_REMINDER_TIME = "09:00";
|
|
258033
258314
|
TODO_REMINDER_SCAN_MS = 6e4;
|
|
258034
258315
|
TODO_REMINDER_TITLE = {
|
|
@@ -258086,16 +258367,48 @@ var init_reminders = __esm({
|
|
|
258086
258367
|
kind: r5.kind,
|
|
258087
258368
|
title: TODO_REMINDER_TITLE[r5.kind](todo.title),
|
|
258088
258369
|
enteredAt,
|
|
258089
|
-
...todo.sourceChatSessionId ? { chatSessionId: todo.sourceChatSessionId } : {}
|
|
258370
|
+
...todo.sourceChatSessionId && recipient === todo.creatorActorId ? { chatSessionId: todo.sourceChatSessionId } : {}
|
|
258090
258371
|
});
|
|
258091
258372
|
this.seen.add(key2);
|
|
258092
258373
|
if (row.enteredAt === enteredAt) fresh.push(row);
|
|
258093
258374
|
}
|
|
258375
|
+
if (r5.kind === "todo-due-1d") {
|
|
258376
|
+
const row = await this.unseen(companyId, ledger, todo, enteredAt);
|
|
258377
|
+
if (row) fresh.push(row);
|
|
258378
|
+
}
|
|
258094
258379
|
}
|
|
258095
258380
|
}
|
|
258096
258381
|
if (fresh.length > 0) this.deps.onInserted?.(companyId, fresh);
|
|
258097
258382
|
return fresh.length;
|
|
258098
258383
|
}
|
|
258384
|
+
/** 「对方还没看过」:三条都成立才发给发起人(见文件头)。返回这一拍新写的那条。 */
|
|
258385
|
+
async unseen(companyId, ledger, todo, enteredAt) {
|
|
258386
|
+
if (!isTodoDelegated(todo) || !todo.sentAt || todo.firstViewedAt) return void 0;
|
|
258387
|
+
const sourceKey = todoUnseenSourceKey(todo);
|
|
258388
|
+
const key2 = JSON.stringify([companyId, todo.creatorActorId, sourceKey]);
|
|
258389
|
+
if (this.seen.has(key2)) return void 0;
|
|
258390
|
+
const assignees = todoAssignees(todo);
|
|
258391
|
+
for (const a5 of assignees) {
|
|
258392
|
+
const assigned = await ledger.findBySource(a5, todoAssignedSourceKey(todo.id));
|
|
258393
|
+
if (!assigned || assigned.readAt) {
|
|
258394
|
+
this.seen.add(key2);
|
|
258395
|
+
return void 0;
|
|
258396
|
+
}
|
|
258397
|
+
}
|
|
258398
|
+
const names = await Promise.all(assignees.map((a5) => this.deps.nameOf?.(companyId, a5) ?? Promise.resolve(a5)));
|
|
258399
|
+
const row = await ledger.insert({
|
|
258400
|
+
recipient: todo.creatorActorId,
|
|
258401
|
+
category: "todo",
|
|
258402
|
+
sourceKey,
|
|
258403
|
+
kind: "todo-unseen",
|
|
258404
|
+
title: unseenTitle(names.join("\u3001"), todo),
|
|
258405
|
+
enteredAt,
|
|
258406
|
+
...assignees[0] ? { actorId: assignees[0] } : {},
|
|
258407
|
+
...todo.sourceChatSessionId ? { chatSessionId: todo.sourceChatSessionId } : {}
|
|
258408
|
+
});
|
|
258409
|
+
this.seen.add(key2);
|
|
258410
|
+
return row.enteredAt === enteredAt ? row : void 0;
|
|
258411
|
+
}
|
|
258099
258412
|
/** 首拍延后一点(默认 10 秒,与通知对账器同款):等 serve 把推送、台账都装好再扫。 */
|
|
258100
258413
|
start(intervalMs = TODO_REMINDER_SCAN_MS, firstDelayMs = 1e4) {
|
|
258101
258414
|
if (this.timer) return;
|
|
@@ -258123,6 +258436,7 @@ var init_todos2 = __esm({
|
|
|
258123
258436
|
init_store3();
|
|
258124
258437
|
init_routes11();
|
|
258125
258438
|
init_reminders();
|
|
258439
|
+
init_notices();
|
|
258126
258440
|
}
|
|
258127
258441
|
});
|
|
258128
258442
|
|
|
@@ -279920,7 +280234,7 @@ async function drainToBuffer(body2) {
|
|
|
279920
280234
|
for await (const chunk of body2) parts.push(chunk);
|
|
279921
280235
|
return new Uint8Array(Buffer.concat(parts));
|
|
279922
280236
|
}
|
|
279923
|
-
var import_node_crypto87, fs36, BLOB_NAME2, ExternalizedBlobStore, ObjectBlobStore;
|
|
280237
|
+
var import_node_crypto87, fs36, BLOB_NAME2, MIGRATION_SELECTORS, ExternalizedBlobStore, ObjectBlobStore;
|
|
279924
280238
|
var init_externalized_blobs = __esm({
|
|
279925
280239
|
"../storage/src/externalized-blobs.ts"() {
|
|
279926
280240
|
"use strict";
|
|
@@ -279930,6 +280244,12 @@ var init_externalized_blobs = __esm({
|
|
|
279930
280244
|
init_blob_object_backend();
|
|
279931
280245
|
init_postgres();
|
|
279932
280246
|
BLOB_NAME2 = /^[0-9a-f]{64}$/;
|
|
280247
|
+
MIGRATION_SELECTORS = {
|
|
280248
|
+
pg: `location = 'pg'`,
|
|
280249
|
+
ext: `location = 'ext'`,
|
|
280250
|
+
"ext-with-bytes": `location = 'ext' AND bytes IS NOT NULL`,
|
|
280251
|
+
internalize: `location = 'ext' OR bytes IS NULL`
|
|
280252
|
+
};
|
|
279933
280253
|
ExternalizedBlobStore = class _ExternalizedBlobStore {
|
|
279934
280254
|
constructor(pool, t, namespace, backend, opts) {
|
|
279935
280255
|
this.pool = pool;
|
|
@@ -280137,13 +280457,49 @@ var init_externalized_blobs = __esm({
|
|
|
280137
280457
|
}
|
|
280138
280458
|
/** 列出待处理的 hash(分批、按 hash 升序,便于中断续跑)。 */
|
|
280139
280459
|
async listHashes(where, after, limit) {
|
|
280140
|
-
const cond = where === "pg" ? `location = 'pg'` : where === "ext" ? `location = 'ext'` : `location = 'ext' AND bytes IS NOT NULL`;
|
|
280141
280460
|
const res = await this.pool.query(
|
|
280142
|
-
`SELECT hash FROM ${this.t} WHERE ${
|
|
280461
|
+
`SELECT hash FROM ${this.t} WHERE (${MIGRATION_SELECTORS[where]}) AND hash > $1 ORDER BY hash LIMIT $2`,
|
|
280143
280462
|
[after, limit]
|
|
280144
280463
|
);
|
|
280145
280464
|
return res.rows.map((r5) => r5.hash);
|
|
280146
280465
|
}
|
|
280466
|
+
/** 待处理的行数与字节数(`oasis blobs … --dry-run` 与进度分母)。 */
|
|
280467
|
+
async pendingStats(where) {
|
|
280468
|
+
const res = await this.pool.query(
|
|
280469
|
+
`SELECT count(*)::bigint AS rows, coalesce(sum(size), 0)::bigint AS bytes FROM ${this.t} WHERE ${MIGRATION_SELECTORS[where]}`
|
|
280470
|
+
);
|
|
280471
|
+
const r5 = res.rows[0] ?? {};
|
|
280472
|
+
return { rows: Number(r5.rows ?? 0), bytes: Number(r5.bytes ?? 0) };
|
|
280473
|
+
}
|
|
280474
|
+
/**
|
|
280475
|
+
* 清空一行的 bytea(§6.2 第 6 步 `--purge-pg-bytes` 的单行原语):**先确认对象在后端、大小与行一致**才清——
|
|
280476
|
+
* bytea 是清掉前最后一份副本,对象丢了(误删、恢复不全)时宁可留着。对象缺失 / 大小不符、或核对本身出错
|
|
280477
|
+
* (S3 超时 / 403 / 5xx、fs I/O 错)一律抛错,bytea 不动。可重复执行:已清过或已不是 `ext` 的行跳过。
|
|
280478
|
+
* 返回本行清掉的字节数(行 `size`);跳过返回 0。
|
|
280479
|
+
*/
|
|
280480
|
+
async purgePgBytesOne(hash3) {
|
|
280481
|
+
const res = await this.pool.query(
|
|
280482
|
+
`SELECT size FROM ${this.t} WHERE hash = $1 AND location = 'ext' AND bytes IS NOT NULL`,
|
|
280483
|
+
[hash3]
|
|
280484
|
+
);
|
|
280485
|
+
const row = res.rows[0];
|
|
280486
|
+
if (!row) return 0;
|
|
280487
|
+
const size = Number(row.size);
|
|
280488
|
+
let head;
|
|
280489
|
+
try {
|
|
280490
|
+
head = await this.backend.head(this.key(hash3));
|
|
280491
|
+
} catch (err) {
|
|
280492
|
+
throw new Error("\u6838\u5BF9\u5BF9\u8C61\u51FA\u9519\uFF0Cbytea \u4FDD\u7559", { cause: err });
|
|
280493
|
+
}
|
|
280494
|
+
if (!head || head.size !== size) {
|
|
280495
|
+
throw new Error(`\u5BF9\u8C61\u4E0D\u5728\u540E\u7AEF\u6216\u5927\u5C0F\u4E0E\u884C\u4E0D\u7B26\uFF08\u884C ${size} B\uFF0C\u5BF9\u8C61 ${head ? `${head.size} B` : "\u4E0D\u5B58\u5728"}\uFF09\uFF0Cbytea \u4FDD\u7559`);
|
|
280496
|
+
}
|
|
280497
|
+
const upd = await this.pool.query(
|
|
280498
|
+
`UPDATE ${this.t} SET bytes = NULL WHERE hash = $1 AND location = 'ext' AND bytes IS NOT NULL`,
|
|
280499
|
+
[hash3]
|
|
280500
|
+
);
|
|
280501
|
+
return (upd.rowCount ?? 0) > 0 ? size : 0;
|
|
280502
|
+
}
|
|
280147
280503
|
/** 观察期后清空已外部化行的 bytea(§6.2 第 6 步),一批一条语句。返回本批清掉的行数。 */
|
|
280148
280504
|
async purgePgBytes(limit) {
|
|
280149
280505
|
const res = await this.pool.query(
|
|
@@ -320180,7 +320536,7 @@ var s3_object_backend_exports = {};
|
|
|
320180
320536
|
__export(s3_object_backend_exports, {
|
|
320181
320537
|
S3ObjectBackend: () => S3ObjectBackend
|
|
320182
320538
|
});
|
|
320183
|
-
var fs37, import_client_s3, import_lib_storage, import_s3_request_presigner, MULTIPART_THRESHOLD, isNotFound, S3ObjectBackend;
|
|
320539
|
+
var fs37, import_client_s3, import_lib_storage, import_s3_request_presigner, MULTIPART_THRESHOLD, MULTIPART_PART_SIZE, MULTIPART_QUEUE_SIZE, isNotFound, S3ObjectBackend;
|
|
320184
320540
|
var init_s3_object_backend = __esm({
|
|
320185
320541
|
"../storage/src/s3-object-backend.ts"() {
|
|
320186
320542
|
"use strict";
|
|
@@ -320191,6 +320547,8 @@ var init_s3_object_backend = __esm({
|
|
|
320191
320547
|
init_blob_object_backend();
|
|
320192
320548
|
init_blob_backend_config();
|
|
320193
320549
|
MULTIPART_THRESHOLD = 16 * 1024 * 1024;
|
|
320550
|
+
MULTIPART_PART_SIZE = 8 * 1024 * 1024;
|
|
320551
|
+
MULTIPART_QUEUE_SIZE = 2;
|
|
320194
320552
|
isNotFound = (err) => {
|
|
320195
320553
|
const e5 = err;
|
|
320196
320554
|
return e5?.name === "NotFound" || e5?.name === "NoSuchKey" || e5?.$metadata?.httpStatusCode === 404;
|
|
@@ -320289,8 +320647,8 @@ var init_s3_object_backend = __esm({
|
|
|
320289
320647
|
await new import_lib_storage.Upload({
|
|
320290
320648
|
client: this.client,
|
|
320291
320649
|
params: { Bucket: this.bucket, Key, Body: fs37.createReadStream(staged.file), ContentType, ChecksumAlgorithm: "SHA256" },
|
|
320292
|
-
partSize:
|
|
320293
|
-
queueSize:
|
|
320650
|
+
partSize: MULTIPART_PART_SIZE,
|
|
320651
|
+
queueSize: MULTIPART_QUEUE_SIZE,
|
|
320294
320652
|
leavePartsOnError: false
|
|
320295
320653
|
}).done();
|
|
320296
320654
|
}
|
|
@@ -320476,6 +320834,91 @@ var init_blob_backend_config = __esm({
|
|
|
320476
320834
|
}
|
|
320477
320835
|
});
|
|
320478
320836
|
|
|
320837
|
+
// ../storage/src/blob-migration.ts
|
|
320838
|
+
async function migrateBlobs(store, op2, opts) {
|
|
320839
|
+
const selector = SELECTOR[op2];
|
|
320840
|
+
const pending = await store.pendingStats(selector);
|
|
320841
|
+
const report = {
|
|
320842
|
+
op: op2,
|
|
320843
|
+
dryRun: opts.dryRun === true,
|
|
320844
|
+
interrupted: false,
|
|
320845
|
+
batches: 0,
|
|
320846
|
+
candidateRows: pending.rows,
|
|
320847
|
+
candidateBytes: pending.bytes,
|
|
320848
|
+
rows: 0,
|
|
320849
|
+
bytes: 0,
|
|
320850
|
+
failed: 0,
|
|
320851
|
+
failures: [],
|
|
320852
|
+
counts: { pg: 0, ext: 0, extWithBytes: 0 }
|
|
320853
|
+
};
|
|
320854
|
+
const fail = (hash3, err) => {
|
|
320855
|
+
report.failed++;
|
|
320856
|
+
if (report.failures.length < MAX_FAILURES_KEPT) {
|
|
320857
|
+
const cause = err instanceof Error && err.cause instanceof Error ? `\uFF1A${err.cause.message}` : "";
|
|
320858
|
+
report.failures.push({ hash: hash3, error: `${err instanceof Error ? err.message : String(err)}${cause}` });
|
|
320859
|
+
}
|
|
320860
|
+
};
|
|
320861
|
+
const stop = () => opts.shouldStop?.() === true;
|
|
320862
|
+
const sleep7 = opts.sleep ?? defaultSleep2;
|
|
320863
|
+
const batch = Math.max(1, Math.floor(opts.batch));
|
|
320864
|
+
if (!report.dryRun) {
|
|
320865
|
+
let after = "";
|
|
320866
|
+
for (; ; ) {
|
|
320867
|
+
if (stop()) {
|
|
320868
|
+
report.interrupted = true;
|
|
320869
|
+
break;
|
|
320870
|
+
}
|
|
320871
|
+
const hashes = await store.listHashes(selector, after, batch);
|
|
320872
|
+
if (hashes.length === 0) break;
|
|
320873
|
+
for (const hash3 of hashes) {
|
|
320874
|
+
if (stop()) {
|
|
320875
|
+
report.interrupted = true;
|
|
320876
|
+
break;
|
|
320877
|
+
}
|
|
320878
|
+
try {
|
|
320879
|
+
const n3 = op2 === "externalize" ? await store.externalizeOne(hash3) : op2 === "internalize" ? await store.internalizeOne(hash3) : await store.purgePgBytesOne(hash3);
|
|
320880
|
+
report.rows++;
|
|
320881
|
+
report.bytes += n3;
|
|
320882
|
+
} catch (err) {
|
|
320883
|
+
fail(hash3, err);
|
|
320884
|
+
}
|
|
320885
|
+
after = hash3;
|
|
320886
|
+
}
|
|
320887
|
+
report.batches++;
|
|
320888
|
+
opts.onProgress?.(progressOf(report));
|
|
320889
|
+
if (report.interrupted || hashes.length < batch) break;
|
|
320890
|
+
if (opts.pauseMs > 0) await sleep7(opts.pauseMs);
|
|
320891
|
+
}
|
|
320892
|
+
}
|
|
320893
|
+
report.counts = await store.locationCounts();
|
|
320894
|
+
return report;
|
|
320895
|
+
}
|
|
320896
|
+
function progressOf(r5) {
|
|
320897
|
+
return { batches: r5.batches, candidateRows: r5.candidateRows, candidateBytes: r5.candidateBytes, rows: r5.rows, bytes: r5.bytes, failed: r5.failed };
|
|
320898
|
+
}
|
|
320899
|
+
async function listBlobSchemas(pool) {
|
|
320900
|
+
const res = await pool.query(
|
|
320901
|
+
`SELECT table_schema AS s FROM information_schema.tables
|
|
320902
|
+
WHERE table_name = 'blobs' AND table_type = 'BASE TABLE'
|
|
320903
|
+
AND table_schema NOT IN ('pg_catalog', 'information_schema')
|
|
320904
|
+
ORDER BY table_schema`
|
|
320905
|
+
);
|
|
320906
|
+
return res.rows.map((r5) => r5.s);
|
|
320907
|
+
}
|
|
320908
|
+
var SELECTOR, MAX_FAILURES_KEPT, defaultSleep2;
|
|
320909
|
+
var init_blob_migration = __esm({
|
|
320910
|
+
"../storage/src/blob-migration.ts"() {
|
|
320911
|
+
"use strict";
|
|
320912
|
+
SELECTOR = {
|
|
320913
|
+
externalize: "pg",
|
|
320914
|
+
"purge-pg-bytes": "ext-with-bytes",
|
|
320915
|
+
internalize: "internalize"
|
|
320916
|
+
};
|
|
320917
|
+
MAX_FAILURES_KEPT = 50;
|
|
320918
|
+
defaultSleep2 = (ms) => new Promise((r5) => setTimeout(r5, ms));
|
|
320919
|
+
}
|
|
320920
|
+
});
|
|
320921
|
+
|
|
320479
320922
|
// ../storage/src/index.ts
|
|
320480
320923
|
var src_exports = {};
|
|
320481
320924
|
__export(src_exports, {
|
|
@@ -320608,10 +321051,12 @@ __export(src_exports, {
|
|
|
320608
321051
|
inventoryZeroTenantTables: () => inventoryZeroTenantTables,
|
|
320609
321052
|
isUniqueViolation: () => isUniqueViolation2,
|
|
320610
321053
|
legacyTurnId: () => legacyTurnId,
|
|
321054
|
+
listBlobSchemas: () => listBlobSchemas,
|
|
320611
321055
|
listChatItemsSchemas: () => listChatItemsSchemas,
|
|
320612
321056
|
listTenancyCompanies: () => listTenancyCompanies,
|
|
320613
321057
|
loadKnownCompanies: () => loadKnownCompanies,
|
|
320614
321058
|
maxGate: () => maxGate,
|
|
321059
|
+
migrateBlobs: () => migrateBlobs,
|
|
320615
321060
|
missingTypeNames: () => missingTypeNames,
|
|
320616
321061
|
moveDefaultCompanySchema: () => moveDefaultCompanySchema,
|
|
320617
321062
|
moveTenancyRows: () => moveTenancyRows,
|
|
@@ -320702,6 +321147,7 @@ var init_src10 = __esm({
|
|
|
320702
321147
|
init_blob_object_backend();
|
|
320703
321148
|
init_externalized_blobs();
|
|
320704
321149
|
init_blob_backend_config();
|
|
321150
|
+
init_blob_migration();
|
|
320705
321151
|
}
|
|
320706
321152
|
});
|
|
320707
321153
|
|
|
@@ -322240,10 +322686,10 @@ __export(src_exports2, {
|
|
|
322240
322686
|
assertBindingWritePermission: () => assertBindingWritePermission,
|
|
322241
322687
|
assertCompanyManager: () => assertCompanyManager,
|
|
322242
322688
|
assertCreatableVariable: () => assertCreatableVariable,
|
|
322243
|
-
assertFirstVersionAssignee: () => assertFirstVersionAssignee,
|
|
322244
322689
|
assertMayCreateAgent: () => assertMayCreateAgent,
|
|
322245
322690
|
assertMayManageAgent: () => assertMayManageAgent,
|
|
322246
322691
|
assertMaySelfOrManage: () => assertMaySelfOrManage,
|
|
322692
|
+
assignedTitle: () => assignedTitle,
|
|
322247
322693
|
assistantBoundToMember: () => assistantBoundToMember,
|
|
322248
322694
|
assistantNameFor: () => assistantNameFor,
|
|
322249
322695
|
assistantRowRecovery: () => assistantRowRecovery,
|
|
@@ -322281,9 +322727,11 @@ __export(src_exports2, {
|
|
|
322281
322727
|
buildWorkorderMetrics: () => buildWorkorderMetrics,
|
|
322282
322728
|
buildWorkorderSummaries: () => buildWorkorderSummaries,
|
|
322283
322729
|
builtinSkillToFiles: () => builtinSkillToFiles,
|
|
322284
|
-
canAccessTodo: () => canAccessTodo,
|
|
322285
322730
|
canAnnounceRuntimeSwitch: () => canAnnounceRuntimeSwitch,
|
|
322731
|
+
canChangeTodo: () => canChangeTodo,
|
|
322286
322732
|
canRetryAllocation: () => canRetryAllocation,
|
|
322733
|
+
canSeeTodo: () => canSeeTodo,
|
|
322734
|
+
changedTitle: () => changedTitle,
|
|
322287
322735
|
chatBroadcastEnabledFromEnv: () => chatBroadcastEnabledFromEnv,
|
|
322288
322736
|
chatDelegationEnabledFromEnv: () => chatDelegationEnabledFromEnv,
|
|
322289
322737
|
chatDispatchScope: () => chatDispatchScope,
|
|
@@ -322658,6 +323106,7 @@ __export(src_exports2, {
|
|
|
322658
323106
|
stableChatTraceRunId: () => stableChatTraceRunId,
|
|
322659
323107
|
stableJson: () => stableJson2,
|
|
322660
323108
|
startOasisServer: () => startOasisServer,
|
|
323109
|
+
statusTitle: () => statusTitle,
|
|
322661
323110
|
stopDispatchesForDeletedActor: () => stopDispatchesForDeletedActor,
|
|
322662
323111
|
stripRetiredCdBotFromDrafts: () => stripRetiredCdBotFromDrafts,
|
|
322663
323112
|
subagentRunEventFromLive: () => subagentRunEventFromLive,
|
|
@@ -322675,7 +323124,10 @@ __export(src_exports2, {
|
|
|
322675
323124
|
toBundleFiles: () => toBundleFiles,
|
|
322676
323125
|
toChatDispatchRequest: () => toChatDispatchRequest,
|
|
322677
323126
|
toYamlDoubleQuoted: () => toYamlDoubleQuoted,
|
|
323127
|
+
todoAssignedSourceKey: () => todoAssignedSourceKey,
|
|
323128
|
+
todoChangeSourceKey: () => todoChangeSourceKey,
|
|
322678
323129
|
todoReminderSourceKey: () => todoReminderSourceKey,
|
|
323130
|
+
todoUnseenSourceKey: () => todoUnseenSourceKey,
|
|
322679
323131
|
todosDomain: () => todosDomain,
|
|
322680
323132
|
touchKey: () => touchKey,
|
|
322681
323133
|
traceDomain: () => traceDomain,
|
|
@@ -322684,6 +323136,7 @@ __export(src_exports2, {
|
|
|
322684
323136
|
trustedDelegationInvocationId: () => trustedDelegationInvocationId,
|
|
322685
323137
|
trustedKnowledgeInvocationId: () => trustedKnowledgeInvocationId,
|
|
322686
323138
|
typesDomain: () => typesDomain,
|
|
323139
|
+
unseenTitle: () => unseenTitle,
|
|
322687
323140
|
upgradeDefaultFieldDefs: () => upgradeDefaultFieldDefs,
|
|
322688
323141
|
validateCron: () => validateCron,
|
|
322689
323142
|
validateKnowledgeAnswer: () => validateKnowledgeAnswer,
|
|
@@ -323213,6 +323666,146 @@ var init_usage_ledger_backfill_command = __esm({
|
|
|
323213
323666
|
}
|
|
323214
323667
|
});
|
|
323215
323668
|
|
|
323669
|
+
// ../cli/src/blobs-command.ts
|
|
323670
|
+
var blobs_command_exports = {};
|
|
323671
|
+
__export(blobs_command_exports, {
|
|
323672
|
+
BLOBS_USAGE: () => BLOBS_USAGE,
|
|
323673
|
+
BlobsArgError: () => BlobsArgError,
|
|
323674
|
+
parseBlobsArgs: () => parseBlobsArgs,
|
|
323675
|
+
runBlobs: () => runBlobs
|
|
323676
|
+
});
|
|
323677
|
+
function parseBlobsArgs(positional, flags) {
|
|
323678
|
+
const on = (k6) => flags.has(k6) && flags.get(k6) !== "false";
|
|
323679
|
+
const sub = positional[0];
|
|
323680
|
+
if (sub !== "externalize" && sub !== "internalize") throw new BlobsArgError("\u5B50\u547D\u4EE4\u5FC5\u987B\u662F externalize \u6216 internalize");
|
|
323681
|
+
if (on("purge-pg-bytes") && sub !== "externalize") throw new BlobsArgError("--purge-pg-bytes \u53EA\u914D externalize");
|
|
323682
|
+
const op2 = on("purge-pg-bytes") ? "purge-pg-bytes" : sub;
|
|
323683
|
+
const schema = flags.get("schema");
|
|
323684
|
+
const all2 = on("all-schemas");
|
|
323685
|
+
if (schema !== void 0 && all2) throw new BlobsArgError("--schema \u4E0E --all-schemas \u53EA\u80FD\u9009\u4E00\u4E2A");
|
|
323686
|
+
if (schema === void 0 && !all2) throw new BlobsArgError("\u5FC5\u987B\u6307\u5B9A --schema <schema> \u6216 --all-schemas");
|
|
323687
|
+
if (schema !== void 0 && (schema === "" || schema === "true")) throw new BlobsArgError("--schema \u9700\u8981 schema \u540D\uFF08\u5982 company_oasis-prod\u3001public\uFF09");
|
|
323688
|
+
const int2 = (k6, dflt, min2) => {
|
|
323689
|
+
const raw = flags.get(k6);
|
|
323690
|
+
if (raw === void 0) return dflt;
|
|
323691
|
+
const n3 = Number(raw);
|
|
323692
|
+
if (!Number.isInteger(n3) || n3 < min2) throw new BlobsArgError(`--${k6} \u9700\u8981\u4E0D\u5C0F\u4E8E ${min2} \u7684\u6574\u6570`);
|
|
323693
|
+
return n3;
|
|
323694
|
+
};
|
|
323695
|
+
return {
|
|
323696
|
+
op: op2,
|
|
323697
|
+
scope: schema !== void 0 ? { schema } : { all: true },
|
|
323698
|
+
batch: int2("batch", DEFAULT_BATCH[op2], 1),
|
|
323699
|
+
pauseMs: int2("pause-ms", DEFAULT_PAUSE_MS, 0),
|
|
323700
|
+
dryRun: on("dry-run")
|
|
323701
|
+
};
|
|
323702
|
+
}
|
|
323703
|
+
async function runBlobs(positional, flags, io) {
|
|
323704
|
+
let args;
|
|
323705
|
+
try {
|
|
323706
|
+
args = parseBlobsArgs(positional, flags);
|
|
323707
|
+
} catch (err) {
|
|
323708
|
+
if (!(err instanceof BlobsArgError)) throw err;
|
|
323709
|
+
io.err(`${err.message}
|
|
323710
|
+
${BLOBS_USAGE}`);
|
|
323711
|
+
return 2;
|
|
323712
|
+
}
|
|
323713
|
+
const tag = `[blobs ${args.op}]`;
|
|
323714
|
+
const pgDsn = io.env["OASIS_PG_DSN"] ?? io.env["DATABASE_URL"];
|
|
323715
|
+
if (!pgDsn) {
|
|
323716
|
+
io.err(`${tag} \u9700\u8981 OASIS_PG_DSN\uFF08\u6216 DATABASE_URL\uFF09\u2014\u2014\u8BF7\u4EE5 serve \u7684\u73AF\u5883\u6267\u884C\u672C\u547D\u4EE4\u3002`);
|
|
323717
|
+
return 2;
|
|
323718
|
+
}
|
|
323719
|
+
const storage = await Promise.resolve().then(() => (init_src10(), src_exports));
|
|
323720
|
+
let config2;
|
|
323721
|
+
try {
|
|
323722
|
+
config2 = storage.readBlobBackendConfig(io.env, { hasPg: true, dataDir: io.dir });
|
|
323723
|
+
} catch (err) {
|
|
323724
|
+
io.err(`${tag} \u5BF9\u8C61\u540E\u7AEF\u914D\u7F6E\u6709\u8BEF\uFF1A${err instanceof Error ? err.message : String(err)}`);
|
|
323725
|
+
return 2;
|
|
323726
|
+
}
|
|
323727
|
+
if (config2.kind === "pg") {
|
|
323728
|
+
io.err(`${tag} \u5F53\u524D OASIS_BLOB_BACKEND=pg\uFF08\u6216\u672A\u8BBE\uFF09\uFF1A\u672C\u547D\u4EE4\u8981\u4E0E serve \u540C\u4E00\u4E2A\u5BF9\u8C61\u540E\u7AEF\uFF08fs / s3\uFF09\u3002` + (args.op === "internalize" ? "\u56DE\u6EDA\u987B\u5728\u5207\u56DE pg \u4E4B\u524D\u3001\u4ECD\u662F fs / s3 \u914D\u7F6E\u65F6\u6267\u884C\uFF08ADR 0638 \xA76.3\uFF09\u3002" : ""));
|
|
323729
|
+
return 2;
|
|
323730
|
+
}
|
|
323731
|
+
if (args.op === "purge-pg-bytes" && config2.dualWrite && !args.dryRun) {
|
|
323732
|
+
io.err(`${tag} OASIS_BLOB_PG_DUAL_WRITE=on\uFF1A\u89C2\u5BDF\u671F\u8FD8\u6CA1\u7ED3\u675F\u3002\u5148\u5173\u53CC\u5199\u5E76\u91CD\u542F serve\uFF0C\u518D\u6E05 bytea\uFF08ADR 0638 \xA76.2 \u7B2C 6 \u6B65\uFF09\u3002`);
|
|
323733
|
+
return 2;
|
|
323734
|
+
}
|
|
323735
|
+
if (args.op === "internalize" && !config2.dualWrite) {
|
|
323736
|
+
io.out(`${tag} \u63D0\u793A\uFF1AOASIS_BLOB_PG_DUAL_WRITE \u672A\u5F00\u3002\u56DE\u6EDA\u671F\u95F4 serve \u65B0\u5199\u5165\u7684\u6587\u4EF6\u53EA\u5728\u5BF9\u8C61\u540E\u7AEF\uFF0C\u5207\u56DE pg \u540E\u4F1A\u8BFB\u4E0D\u5230\uFF1B\u5EFA\u8BAE\u5148\u5F00\u53CC\u5199\u5E76\u91CD\u542F serve\uFF0C\u518D\u8DD1\u672C\u547D\u4EE4\uFF08\u89C1 docs/oasis-dev-storage.md \xA72.5.4\uFF09\u3002`);
|
|
323737
|
+
}
|
|
323738
|
+
const pool = storage.createPgPool(pgDsn);
|
|
323739
|
+
try {
|
|
323740
|
+
const existing = await storage.listBlobSchemas(pool);
|
|
323741
|
+
let schemas;
|
|
323742
|
+
if ("schema" in args.scope) {
|
|
323743
|
+
if (!existing.includes(args.scope.schema)) {
|
|
323744
|
+
io.err(`${tag} schema ${args.scope.schema} \u6CA1\u6709 blobs \u8868\u3002\u6709 blobs \u8868\u7684 schema\uFF1A${existing.join(" ") || "\uFF08\u65E0\uFF09"}`);
|
|
323745
|
+
return 2;
|
|
323746
|
+
}
|
|
323747
|
+
schemas = [args.scope.schema];
|
|
323748
|
+
} else {
|
|
323749
|
+
schemas = existing;
|
|
323750
|
+
}
|
|
323751
|
+
const backend = await storage.createObjectBackend(config2);
|
|
323752
|
+
if (!backend) throw new Error("\u5BF9\u8C61\u540E\u7AEF\u88C5\u914D\u5931\u8D25");
|
|
323753
|
+
io.out(`${tag} \u540E\u7AEF ${storage.describeBlobBackend(config2)}\uFF1B${schemas.length} \u4E2A schema\uFF1A${schemas.join(" ")}\uFF1B\u6BCF\u6279 ${args.batch} \u884C\u3001\u6279\u95F4 ${args.pauseMs}ms${args.dryRun ? "\uFF1Bdry-run\uFF08\u4E00\u884C\u4E0D\u52A8\uFF09" : ""}`);
|
|
323754
|
+
const total = { rows: 0, bytes: 0, failed: 0 };
|
|
323755
|
+
for (const schema of schemas) {
|
|
323756
|
+
const store = await storage.ExternalizedBlobStore.open(pool, schema, backend, { dualWrite: config2.dualWrite });
|
|
323757
|
+
const r5 = await storage.migrateBlobs(store, args.op, {
|
|
323758
|
+
batch: args.batch,
|
|
323759
|
+
pauseMs: args.pauseMs,
|
|
323760
|
+
dryRun: args.dryRun,
|
|
323761
|
+
...io.shouldStop ? { shouldStop: io.shouldStop } : {},
|
|
323762
|
+
...io.sleep ? { sleep: io.sleep } : {},
|
|
323763
|
+
onProgress: (p4) => io.out(`${tag} ${schema} \u7B2C ${p4.batches} \u6279\uFF1A\u5DF2\u5904\u7406 ${p4.rows}/${p4.candidateRows} \u884C\u3001${fmtBytes(p4.bytes)}/${fmtBytes(p4.candidateBytes)}\uFF0C\u5931\u8D25 ${p4.failed}`)
|
|
323764
|
+
});
|
|
323765
|
+
const c5 = r5.counts;
|
|
323766
|
+
const tail = `\uFF08location\uFF1Apg ${c5.pg}\u3001ext ${c5.ext}\uFF0C\u5176\u4E2D bytea \u672A\u6E05 ${c5.extWithBytes}\uFF09`;
|
|
323767
|
+
if (r5.dryRun) {
|
|
323768
|
+
io.out(`${tag} ${schema} dry-run\uFF1A\u5F85\u5904\u7406 ${r5.candidateRows} \u884C\u3001${fmtBytes(r5.candidateBytes)}${tail}`);
|
|
323769
|
+
} else {
|
|
323770
|
+
io.out(`${tag} ${schema} ${r5.interrupted ? "\u5DF2\u4E2D\u65AD" : "\u5B8C\u6210"}\uFF1A\u5904\u7406 ${r5.rows} \u884C\u3001${fmtBytes(r5.bytes)}\uFF0C\u5931\u8D25 ${r5.failed}${tail}`);
|
|
323771
|
+
for (const f6 of r5.failures) io.out(` \u2717 ${f6.hash}\uFF1A${f6.error}`);
|
|
323772
|
+
if (r5.failed > r5.failures.length) io.out(` \u2026\u53E6\u6709 ${r5.failed - r5.failures.length} \u6761\u5931\u8D25\u672A\u5217\u51FA`);
|
|
323773
|
+
}
|
|
323774
|
+
total.rows += r5.rows;
|
|
323775
|
+
total.bytes += r5.bytes;
|
|
323776
|
+
total.failed += r5.failed;
|
|
323777
|
+
if (r5.interrupted) {
|
|
323778
|
+
io.err(`${tag} \u5DF2\u4E2D\u65AD\uFF1A\u5DF2\u5904\u7406\u7684\u884C\u4E0D\u4F1A\u91CD\u505A\uFF0C\u91CD\u8DD1\u540C\u4E00\u6761\u547D\u4EE4\u4ECE\u5269\u4E0B\u7684\u63A5\u7740\u505A\u3002`);
|
|
323779
|
+
return 130;
|
|
323780
|
+
}
|
|
323781
|
+
}
|
|
323782
|
+
if (!args.dryRun) {
|
|
323783
|
+
io.out(`${tag} \u5408\u8BA1\uFF1A\u5904\u7406 ${total.rows} \u884C\u3001${fmtBytes(total.bytes)}\uFF0C\u5931\u8D25 ${total.failed}\u3002` + (total.failed > 0 ? "\u5931\u8D25\u7684\u884C\u4FDD\u6301\u539F\u72B6\uFF0C\u6392\u67E5\u540E\u91CD\u8DD1\u540C\u4E00\u547D\u4EE4\u53EA\u91CD\u8BD5\u5B83\u4EEC\u3002" : ""));
|
|
323784
|
+
}
|
|
323785
|
+
return total.failed > 0 ? 1 : 0;
|
|
323786
|
+
} finally {
|
|
323787
|
+
await pool.end().catch(() => void 0);
|
|
323788
|
+
}
|
|
323789
|
+
}
|
|
323790
|
+
var BLOBS_USAGE, BlobsArgError, DEFAULT_BATCH, DEFAULT_PAUSE_MS, MB, fmtBytes;
|
|
323791
|
+
var init_blobs_command = __esm({
|
|
323792
|
+
"../cli/src/blobs-command.ts"() {
|
|
323793
|
+
"use strict";
|
|
323794
|
+
BLOBS_USAGE = [
|
|
323795
|
+
"\u7528\u6CD5\uFF1A",
|
|
323796
|
+
" oasis blobs externalize (--schema <s> | --all-schemas) [--batch 50] [--pause-ms 200] [--dry-run]",
|
|
323797
|
+
" oasis blobs externalize --purge-pg-bytes (--schema <s> | --all-schemas) [--batch 500] [--pause-ms 200] [--dry-run]",
|
|
323798
|
+
" oasis blobs internalize (--schema <s> | --all-schemas) [--batch 50] [--pause-ms 200] [--dry-run]"
|
|
323799
|
+
].join("\n");
|
|
323800
|
+
BlobsArgError = class extends Error {
|
|
323801
|
+
};
|
|
323802
|
+
DEFAULT_BATCH = { externalize: 50, "purge-pg-bytes": 500, internalize: 50 };
|
|
323803
|
+
DEFAULT_PAUSE_MS = 200;
|
|
323804
|
+
MB = 1024 * 1024;
|
|
323805
|
+
fmtBytes = (n3) => n3 >= MB ? `${(n3 / MB).toFixed(1)} MiB` : `${n3} B`;
|
|
323806
|
+
}
|
|
323807
|
+
});
|
|
323808
|
+
|
|
323216
323809
|
// src/index.ts
|
|
323217
323810
|
var fs55 = __toESM(require("node:fs"));
|
|
323218
323811
|
init_src();
|
|
@@ -325320,7 +325913,24 @@ function createTodoRuntime(options) {
|
|
|
325320
325913
|
const id = companyId ?? options.defaultCompanyId();
|
|
325321
325914
|
let value2 = cache5.get(id);
|
|
325322
325915
|
if (!value2) {
|
|
325323
|
-
value2 = options.store(id).then((store) => new TodoService({
|
|
325916
|
+
value2 = options.store(id).then((store) => new TodoService({
|
|
325917
|
+
store,
|
|
325918
|
+
timeZone: () => options.timeZone(id),
|
|
325919
|
+
...options.people ? { people: () => options.people(id) } : {},
|
|
325920
|
+
...options.runOf ? { runOf: options.runOf } : {},
|
|
325921
|
+
// 派给别人的待办的告知(ADR 0640):与到期提醒同一条路——直接 insert 进台账 `todo` 类,新写的推送 + 刷铃铛。
|
|
325922
|
+
notify: async (records) => {
|
|
325923
|
+
const ledger = await options.notifications(id);
|
|
325924
|
+
if (!ledger) return;
|
|
325925
|
+
const fresh = [];
|
|
325926
|
+
for (const r5 of records) {
|
|
325927
|
+
const row = await ledger.insert(r5);
|
|
325928
|
+
if (row.enteredAt === r5.enteredAt) fresh.push(row);
|
|
325929
|
+
}
|
|
325930
|
+
if (fresh.length > 0) options.onReminders?.(id, fresh);
|
|
325931
|
+
},
|
|
325932
|
+
warn: options.warn
|
|
325933
|
+
}));
|
|
325324
325934
|
cache5.set(id, value2);
|
|
325325
325935
|
void value2.catch(() => cache5.delete(id));
|
|
325326
325936
|
}
|
|
@@ -325338,6 +325948,7 @@ function createTodoRuntime(options) {
|
|
|
325338
325948
|
todos: options.store,
|
|
325339
325949
|
notifications: options.notifications,
|
|
325340
325950
|
timeZone: options.timeZone,
|
|
325951
|
+
...options.people ? { nameOf: async (companyId, actorId) => (await options.people(companyId)).find((p4) => p4.actorId === actorId)?.name ?? actorId } : {},
|
|
325341
325952
|
enabled,
|
|
325342
325953
|
warn: options.warn,
|
|
325343
325954
|
...options.onReminders ? { onInserted: options.onReminders } : {}
|
|
@@ -325686,6 +326297,7 @@ function createConnectorRenewalRuntime(options) {
|
|
|
325686
326297
|
init_store3();
|
|
325687
326298
|
|
|
325688
326299
|
// ../storage/src/postgres-todos.ts
|
|
326300
|
+
init_src();
|
|
325689
326301
|
init_pg_ident();
|
|
325690
326302
|
init_schema_ddl_lock();
|
|
325691
326303
|
var PostgresTodoStore = class _PostgresTodoStore {
|
|
@@ -325709,7 +326321,7 @@ var PostgresTodoStore = class _PostgresTodoStore {
|
|
|
325709
326321
|
due_time text,
|
|
325710
326322
|
start_date text,
|
|
325711
326323
|
start_time text,
|
|
325712
|
-
status text NOT NULL CHECK (status IN (
|
|
326324
|
+
status text NOT NULL CONSTRAINT todos_status_check CHECK (status IN (${STATUS_LIST})),
|
|
325713
326325
|
done_at timestamptz,
|
|
325714
326326
|
cancelled_at timestamptz,
|
|
325715
326327
|
source_chat_session_id text,
|
|
@@ -325717,6 +326329,17 @@ var PostgresTodoStore = class _PostgresTodoStore {
|
|
|
325717
326329
|
created_at timestamptz NOT NULL,
|
|
325718
326330
|
updated_at timestamptz NOT NULL
|
|
325719
326331
|
)`);
|
|
326332
|
+
await pool.query(`ALTER TABLE ${store.s}.todos ADD COLUMN IF NOT EXISTS sent_at timestamptz`);
|
|
326333
|
+
await pool.query(`ALTER TABLE ${store.s}.todos ADD COLUMN IF NOT EXISTS first_viewed_at timestamptz`);
|
|
326334
|
+
await pool.query(`ALTER TABLE ${store.s}.todos ADD COLUMN IF NOT EXISTS source_run_id text`);
|
|
326335
|
+
const check2 = await pool.query(`SELECT pg_get_constraintdef(c.oid) AS def FROM pg_constraint c
|
|
326336
|
+
JOIN pg_class t ON t.oid = c.conrelid JOIN pg_namespace n ON n.oid = t.relnamespace
|
|
326337
|
+
WHERE n.nspname = $1 AND t.relname = 'todos' AND c.conname = 'todos_status_check'`, [schema]);
|
|
326338
|
+
const def = check2.rows[0]?.def;
|
|
326339
|
+
if (!def || !def.includes("'draft'")) {
|
|
326340
|
+
await pool.query(`ALTER TABLE ${store.s}.todos DROP CONSTRAINT IF EXISTS todos_status_check`);
|
|
326341
|
+
await pool.query(`ALTER TABLE ${store.s}.todos ADD CONSTRAINT todos_status_check CHECK (status IN (${STATUS_LIST}))`);
|
|
326342
|
+
}
|
|
325720
326343
|
await pool.query(`CREATE INDEX IF NOT EXISTS todos_assignee_status_due_idx ON ${store.s}.todos (assignee_actor_id, status, due_date)`);
|
|
325721
326344
|
await pool.query(`CREATE INDEX IF NOT EXISTS todos_creator_status_due_idx ON ${store.s}.todos (creator_actor_id, status, due_date)`);
|
|
325722
326345
|
await pool.query(`CREATE INDEX IF NOT EXISTS todos_open_due_idx ON ${store.s}.todos (due_date) WHERE status = 'open'`);
|
|
@@ -325762,8 +326385,9 @@ var PostgresTodoStore = class _PostgresTodoStore {
|
|
|
325762
326385
|
async create(todo, changes) {
|
|
325763
326386
|
return this.tx(async (client) => {
|
|
325764
326387
|
const r5 = await client.query(`INSERT INTO ${this.s}.todos (id,title,note,creator_actor_id,assignee_actor_id,recorded_by_actor_id,
|
|
325765
|
-
due_date,due_time,status,done_at,cancelled_at,source_chat_session_id,linked_workorder_id,created_at,updated_at,start_date,start_time
|
|
325766
|
-
|
|
326388
|
+
due_date,due_time,status,done_at,cancelled_at,source_chat_session_id,linked_workorder_id,created_at,updated_at,start_date,start_time,
|
|
326389
|
+
sent_at,first_viewed_at,source_run_id)
|
|
326390
|
+
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20) RETURNING *`, rowValues(todo));
|
|
325767
326391
|
await this.insertChanges(client, changes);
|
|
325768
326392
|
return fromRow3(r5.rows[0]);
|
|
325769
326393
|
});
|
|
@@ -325776,8 +326400,9 @@ var PostgresTodoStore = class _PostgresTodoStore {
|
|
|
325776
326400
|
return this.tx(async (client) => {
|
|
325777
326401
|
const r5 = await client.query(`UPDATE ${this.s}.todos SET title=$2,note=$3,creator_actor_id=$4,assignee_actor_id=$5,
|
|
325778
326402
|
recorded_by_actor_id=$6,due_date=$7,due_time=$8,status=$9,done_at=$10,cancelled_at=$11,source_chat_session_id=$12,
|
|
325779
|
-
linked_workorder_id=$13,created_at=$14,updated_at=$15,start_date=$16,start_time=$17
|
|
325780
|
-
|
|
326403
|
+
linked_workorder_id=$13,created_at=$14,updated_at=$15,start_date=$16,start_time=$17,
|
|
326404
|
+
sent_at=$18,first_viewed_at=COALESCE(first_viewed_at,$19),source_run_id=$20
|
|
326405
|
+
WHERE id=$1 AND updated_at=$21::timestamptz RETURNING *`, [...rowValues(next), expectedUpdatedAt]);
|
|
325781
326406
|
if (!r5.rows[0]) return null;
|
|
325782
326407
|
await this.insertChanges(client, changes);
|
|
325783
326408
|
return fromRow3(r5.rows[0]);
|
|
@@ -325789,6 +326414,31 @@ var PostgresTodoStore = class _PostgresTodoStore {
|
|
|
325789
326414
|
ORDER BY due_date, COALESCE(due_time,'99:99'), created_at, id`, [actorId, [...statuses2]]);
|
|
325790
326415
|
return r5.rows.map(fromRow3);
|
|
325791
326416
|
}
|
|
326417
|
+
async search(f6) {
|
|
326418
|
+
const where = ["status = ANY($1::text[])"];
|
|
326419
|
+
const args = [[...f6.statuses]];
|
|
326420
|
+
const arg = (v2) => {
|
|
326421
|
+
args.push(v2);
|
|
326422
|
+
return `$${args.length}`;
|
|
326423
|
+
};
|
|
326424
|
+
if (f6.assignee) where.push(`assignee_actor_id = ${arg(f6.assignee)}`);
|
|
326425
|
+
if (f6.creator) where.push(`creator_actor_id = ${arg(f6.creator)}`);
|
|
326426
|
+
if (f6.dueFrom) where.push(`due_date >= ${arg(f6.dueFrom)}`);
|
|
326427
|
+
if (f6.dueTo) where.push(`due_date <= ${arg(f6.dueTo)}`);
|
|
326428
|
+
if (f6.chatSessionId) where.push(`source_chat_session_id = ${arg(f6.chatSessionId)}`);
|
|
326429
|
+
if (f6.q) {
|
|
326430
|
+
const like = arg(`%${f6.q.replace(/[\\%_]/g, (c5) => `\\${c5}`)}%`);
|
|
326431
|
+
where.push(`(title ILIKE ${like} OR COALESCE(note,'') ILIKE ${like})`);
|
|
326432
|
+
}
|
|
326433
|
+
where.push(`NOT (creator_actor_id <> assignee_actor_id AND sent_at IS NULL AND creator_actor_id <> ${arg(f6.viewer)})`);
|
|
326434
|
+
const r5 = await this.pool.query(`SELECT * FROM ${this.s}.todos WHERE ${where.join(" AND ")}
|
|
326435
|
+
ORDER BY due_date, COALESCE(due_time,'99:99'), created_at, id LIMIT ${arg(f6.limit)}`, args);
|
|
326436
|
+
return r5.rows.map(fromRow3);
|
|
326437
|
+
}
|
|
326438
|
+
async markFirstViewed(id, at2) {
|
|
326439
|
+
await this.pool.query(`UPDATE ${this.s}.todos SET first_viewed_at=$2 WHERE id=$1 AND first_viewed_at IS NULL`, [id, at2]);
|
|
326440
|
+
return this.get(id);
|
|
326441
|
+
}
|
|
325792
326442
|
async listOpenReminderCandidates(fromDay, toDay) {
|
|
325793
326443
|
const r5 = await this.pool.query(`SELECT * FROM ${this.s}.todos
|
|
325794
326444
|
WHERE status='open' AND (due_date BETWEEN $1 AND $2 OR start_date BETWEEN $1 AND $2)
|
|
@@ -325807,6 +326457,7 @@ var PostgresTodoStore = class _PostgresTodoStore {
|
|
|
325807
326457
|
});
|
|
325808
326458
|
}
|
|
325809
326459
|
};
|
|
326460
|
+
var STATUS_LIST = TODO_STATUSES.map((v2) => `'${v2}'`).join(",");
|
|
325810
326461
|
var iso8 = (v2) => v2 instanceof Date ? v2.toISOString() : typeof v2 === "string" ? new Date(v2).toISOString() : void 0;
|
|
325811
326462
|
function rowValues(t) {
|
|
325812
326463
|
return [
|
|
@@ -325826,7 +326477,10 @@ function rowValues(t) {
|
|
|
325826
326477
|
t.createdAt,
|
|
325827
326478
|
t.updatedAt,
|
|
325828
326479
|
t.startDate ?? null,
|
|
325829
|
-
t.startTime ?? null
|
|
326480
|
+
t.startTime ?? null,
|
|
326481
|
+
t.sentAt ?? null,
|
|
326482
|
+
t.firstViewedAt ?? null,
|
|
326483
|
+
t.sourceRunId ?? null
|
|
325830
326484
|
];
|
|
325831
326485
|
}
|
|
325832
326486
|
function fromRow3(row) {
|
|
@@ -325849,7 +326503,10 @@ function fromRow3(row) {
|
|
|
325849
326503
|
["doneAt", iso8(row["done_at"])],
|
|
325850
326504
|
["cancelledAt", iso8(row["cancelled_at"])],
|
|
325851
326505
|
["sourceChatSessionId", row["source_chat_session_id"]],
|
|
325852
|
-
["linkedWorkorderId", row["linked_workorder_id"]]
|
|
326506
|
+
["linkedWorkorderId", row["linked_workorder_id"]],
|
|
326507
|
+
["sentAt", iso8(row["sent_at"])],
|
|
326508
|
+
["firstViewedAt", iso8(row["first_viewed_at"])],
|
|
326509
|
+
["sourceRunId", row["source_run_id"]]
|
|
325853
326510
|
];
|
|
325854
326511
|
for (const [k6, v2] of opt) if (v2 !== void 0 && v2 !== null) t[k6] = v2;
|
|
325855
326512
|
return t;
|
|
@@ -329449,10 +330106,17 @@ async function startServe(opts) {
|
|
|
329449
330106
|
timeZone: (companyId) => companies.service.effectiveTimeZoneOf(companyId),
|
|
329450
330107
|
boundHuman: async (agentId, companyId) => (await (await resolveAssistantsCtx(companyId)).service.getByAgent(agentId))?.humanActorId ?? null,
|
|
329451
330108
|
notifications: (companyId) => notificationStoreFor(companyId),
|
|
330109
|
+
// 派给别人(ADR 0640):承接人只能是本公司走完新手指引的真人成员(与组织成员页同一份名单)。
|
|
330110
|
+
people: async (companyId) => (await companies.service.listMemberViews(companyId)).map((m4) => ({
|
|
330111
|
+
actorId: m4.actorId,
|
|
330112
|
+
name: m4.displayName?.trim() || m4.name?.trim() || m4.email || m4.actorId,
|
|
330113
|
+
aliases: [m4.name, m4.email, m4.email?.split("@")[0]].filter((v2) => !!v2 && !!v2.trim())
|
|
330114
|
+
})),
|
|
330115
|
+
runOf: (chatSessionId) => liveChat.runFor(chatSessionId),
|
|
329452
330116
|
onReminders: (companyId, records) => {
|
|
329453
330117
|
pushNotifier?.notify(companyId, records);
|
|
329454
330118
|
const recipients = [...new Set(records.map((r5) => r5.recipient))];
|
|
329455
|
-
console.warn(`[todos] ${companyId} \
|
|
330119
|
+
console.warn(`[todos] ${companyId} \u5F85\u529E\u901A\u77E5 ${records.length} \u6761 \u2192 ${recipients.join(",")}`);
|
|
329456
330120
|
auditSink.notifyNotificationsChanged(recipients);
|
|
329457
330121
|
},
|
|
329458
330122
|
defaultCompanyId: () => defaultCompanyId,
|
|
@@ -337190,6 +337854,46 @@ var COMMAND_DECLS = {
|
|
|
337190
337854
|
"oasis usage-ledger-backfill --all --verify"
|
|
337191
337855
|
]
|
|
337192
337856
|
},
|
|
337857
|
+
blobs: {
|
|
337858
|
+
group: "\u57FA\u7840\u8BBE\u65BD",
|
|
337859
|
+
usage: "oasis blobs <externalize|internalize> (--schema <s> | --all-schemas) ...",
|
|
337860
|
+
description: "\u4E8B\u5B9E\u67DC bytea \u8FC1\u51FA / \u6E05\u7A7A / \u56DE\u6EDA\uFF08ADR 0638 \xA76.2\u3001\xA76.3\uFF09\u3002\u4EE5 serve \u7684\u73AF\u5883\u5728\u90E8\u7F72\u673A\u4E0A\u6267\u884C\uFF0C\u5BF9\u8C61\u540E\u7AEF\u4E0E serve \u540C\u4E00\u5957\u88C5\u914D\u3002",
|
|
337861
|
+
subCommands: ["blobs externalize", "blobs internalize"]
|
|
337862
|
+
},
|
|
337863
|
+
"blobs externalize": {
|
|
337864
|
+
group: "\u57FA\u7840\u8BBE\u65BD",
|
|
337865
|
+
usage: "oasis blobs externalize [--purge-pg-bytes] (--schema <s> | --all-schemas) [--batch 50] [--pause-ms 200] [--dry-run]",
|
|
337866
|
+
description: "\u628A location='pg' \u7684\u884C\u9010\u4E2A\u5199\u8FDB\u5BF9\u8C61\u540E\u7AEF\uFF08\u8BFB\u56DE\u6821\u9A8C sha256 \u540E\u6539 location='ext'\uFF0C\u4FDD\u7559 bytea\uFF09\uFF1B\u5E26 --purge-pg-bytes \u65F6\u6539\u4E3A\u5206\u6279\u6E05\u7A7A\u5DF2\u5916\u90E8\u5316\u884C\u7684 bytea\uFF08\u5148\u6838\u5BF9\u5BF9\u8C61\u5728\u4E14\u5927\u5C0F\u4E00\u81F4\uFF09\u3002\u5206\u6279\u3001\u6279\u95F4\u9650\u901F\u3001\u6BCF\u6279\u8F93\u51FA\u8FDB\u5EA6\uFF1BCtrl-C \u5904\u7406\u5B8C\u5F53\u524D\u4E00\u884C\u518D\u505C\uFF0C\u91CD\u8DD1\u540C\u4E00\u547D\u4EE4\u7EED\u8DD1\u3002\u9000\u51FA\u7801\uFF1A0 \u5B8C\u6210\u30011 \u6709\u884C\u5931\u8D25\u30012 \u53C2\u6570/\u73AF\u5883\u9519\u8BEF\u3001130 \u88AB\u4E2D\u65AD\u3002",
|
|
337867
|
+
flags: [
|
|
337868
|
+
{ name: "schema", desc: "\u53EA\u5904\u7406\u8FD9\u4E2A schema\uFF08\u5982 company_oasis-prod\u3001public\uFF09\uFF1B\u987B\u5DF2\u6709 blobs \u8868" },
|
|
337869
|
+
{ name: "all-schemas", desc: "\u6240\u6709\u6709 blobs \u8868\u7684 schema\uFF0C\u542B\u5171\u4EAB schema public", boolean: true },
|
|
337870
|
+
{ name: "purge-pg-bytes", desc: "\u6E05\u7A7A\u5DF2\u5916\u90E8\u5316\u884C\u7684 bytea\uFF08\u89C2\u5BDF\u671F\u7ED3\u675F\u3001\u5173\u53CC\u5199\u5E76\u91CD\u542F serve \u4E4B\u540E\uFF1B\u53CC\u5199\u5F00\u7740\u65F6\u62D2\u7EDD\uFF09", boolean: true },
|
|
337871
|
+
{ name: "batch", desc: "\u6BCF\u6279\u884C\u6570\uFF08\u7F3A\u7701 50\uFF1B--purge-pg-bytes \u7F3A\u7701 500\uFF09" },
|
|
337872
|
+
{ name: "pause-ms", desc: "\u6279\u95F4\u505C\u987F\u6BEB\u79D2\u6570\uFF08\u7F3A\u7701 200\uFF09" },
|
|
337873
|
+
{ name: "dry-run", desc: "\u53EA\u62A5\u6BCF\u4E2A schema \u5F85\u5904\u7406\u7684\u884C\u6570\u548C\u5B57\u8282\u6570\uFF0C\u4E00\u884C\u4E0D\u52A8", boolean: true }
|
|
337874
|
+
],
|
|
337875
|
+
examples: [
|
|
337876
|
+
"oasis blobs externalize --all-schemas --dry-run",
|
|
337877
|
+
"oasis blobs externalize --schema company_oasis-prod --batch 50",
|
|
337878
|
+
"oasis blobs externalize --purge-pg-bytes --all-schemas"
|
|
337879
|
+
]
|
|
337880
|
+
},
|
|
337881
|
+
"blobs internalize": {
|
|
337882
|
+
group: "\u57FA\u7840\u8BBE\u65BD",
|
|
337883
|
+
usage: "oasis blobs internalize (--schema <s> | --all-schemas) [--batch 50] [--pause-ms 200] [--dry-run]",
|
|
337884
|
+
description: "\u56DE\u6EDA\uFF1A\u628A\u5BF9\u8C61\u5199\u56DE bytea\uFF08\u6821\u9A8C sha256\uFF09\u5E76\u6539 location='pg'\u3002\u987B\u5728\u5207\u56DE OASIS_BLOB_BACKEND=pg \u4E4B\u524D\u3001\u4ECD\u662F fs / s3 \u914D\u7F6E\u65F6\u6267\u884C\uFF1B\u5EFA\u8BAE\u5148\u5F00\u53CC\u5199\u5E76\u91CD\u542F serve\u3002\u5206\u6279\u3001\u9650\u901F\u3001\u8FDB\u5EA6\u3001\u53EF\u4E2D\u65AD\u7EED\u8DD1\uFF0C\u9000\u51FA\u7801\u540C externalize\u3002",
|
|
337885
|
+
flags: [
|
|
337886
|
+
{ name: "schema", desc: "\u53EA\u5904\u7406\u8FD9\u4E2A schema\uFF1B\u987B\u5DF2\u6709 blobs \u8868" },
|
|
337887
|
+
{ name: "all-schemas", desc: "\u6240\u6709\u6709 blobs \u8868\u7684 schema\uFF0C\u542B\u5171\u4EAB schema public", boolean: true },
|
|
337888
|
+
{ name: "batch", desc: "\u6BCF\u6279\u884C\u6570\uFF08\u7F3A\u7701 50\uFF09" },
|
|
337889
|
+
{ name: "pause-ms", desc: "\u6279\u95F4\u505C\u987F\u6BEB\u79D2\u6570\uFF08\u7F3A\u7701 200\uFF09" },
|
|
337890
|
+
{ name: "dry-run", desc: "\u53EA\u62A5\u5F85\u5199\u56DE\u7684\u884C\u6570\u548C\u5B57\u8282\u6570\uFF0C\u4E00\u884C\u4E0D\u52A8", boolean: true }
|
|
337891
|
+
],
|
|
337892
|
+
examples: [
|
|
337893
|
+
"oasis blobs internalize --all-schemas --dry-run",
|
|
337894
|
+
"oasis blobs internalize --all-schemas"
|
|
337895
|
+
]
|
|
337896
|
+
},
|
|
337193
337897
|
kb: {
|
|
337194
337898
|
group: "\u77E5\u8BC6\u5E93",
|
|
337195
337899
|
usage: "oasis kb <ask|ingest|status|maintain|lint> ...",
|
|
@@ -338683,16 +339387,19 @@ var COMMAND_DECLS = {
|
|
|
338683
339387
|
],
|
|
338684
339388
|
examples: ["oasis var rm STALE_KEY --scope project --project oasis", "oasis var rm --id var_1234 --yes"]
|
|
338685
339389
|
},
|
|
338686
|
-
// —— 个人待办(ADR 0635):人对助理说「帮我记一下」→
|
|
338687
|
-
// 填(agent 调 =
|
|
339390
|
+
// —— 个人待办(ADR 0635):人对助理说「帮我记一下」→ 助理用这组命令记、改、勾掉。发起人由服务端按调用者
|
|
339391
|
+
// 填(agent 调 = 它绑定的那个真人),命令行不收;派给别人用 --to(ADR 0640,先成草案、人点发出才生效)。
|
|
339392
|
+
// 开关 OASIS_PERSONAL_TODO=off 时服务端 404。 ——
|
|
338688
339393
|
todo: {
|
|
338689
339394
|
group: "\u4E2A\u4EBA\u5F85\u529E",
|
|
338690
339395
|
usage: "oasis todo <add|list|show|edit|done|cancel|reopen> ...",
|
|
338691
|
-
description: "\
|
|
339396
|
+
description: "\u5F85\u529E\uFF1A\u66FF\u4F60\u7ED1\u5B9A\u7684\u90A3\u4E2A\u771F\u4EBA\u8BB0\u4E0B\u6709\u622A\u6B62\u65E5\u7684\u5DE5\u4F5C\uFF0C\u6216\u6D3E\u7ED9\u672C\u516C\u53F8\u7684\u540C\u4E8B\uFF08--to\uFF0C\u5148\u6210\u8349\u6848\u3001TA \u5728\u5361\u4E0A\u70B9\u300C\u53D1\u51FA\u300D\u624D\u751F\u6548\uFF09\uFF1B\u5230\u671F\u524D\u4E00\u5929 09:00\u3001\u5F53\u5929 09:00 \u7CFB\u7EDF\u4F1A\u63D0\u9192\u627F\u63A5\u4EBA\uFF08\u8BBE\u4E86\u5F00\u59CB\u65E5\u7684\uFF0C\u5F00\u59CB\u5F53\u5929 09:00 \u4E5F\u63D0\u9192\u4E00\u6B21\uFF09\u3002\u5168\u516C\u53F8\u7684\u5F85\u529E\u90FD\u80FD\u67E5\uFF08list --assignee / --creator / --everyone / --q\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**",
|
|
338692
339397
|
subCommands: ["todo add", "todo list", "todo show", "todo edit", "todo done", "todo cancel", "todo reopen"],
|
|
338693
339398
|
examples: [
|
|
338694
339399
|
'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',
|
|
339400
|
+
'oasis todo add --to \u5955\u7487 --title "\u6574\u7406\u7ADE\u54C1\u62A5\u4EF7" --due 2026-10-15',
|
|
338695
339401
|
"oasis todo list",
|
|
339402
|
+
"oasis todo list --assignee \u5955\u7487",
|
|
338696
339403
|
"oasis todo show td_3f9a1c2b",
|
|
338697
339404
|
'oasis todo edit td_3f9a1c2b --due 2026-10-12 --reason "\u6392\u671F\u8C03\u6574"',
|
|
338698
339405
|
"oasis todo done td_3f9a1c2b"
|
|
@@ -338700,9 +339407,10 @@ var COMMAND_DECLS = {
|
|
|
338700
339407
|
},
|
|
338701
339408
|
"todo add": {
|
|
338702
339409
|
group: "\u4E2A\u4EBA\u5F85\u529E",
|
|
338703
|
-
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]",
|
|
338704
|
-
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",
|
|
339410
|
+
usage: "oasis todo add [--to <\u4EBA>] --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]",
|
|
339411
|
+
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\u7ED9\u81EA\u5DF1\u8BB0\uFF1A\u6210\u529F\u8F93\u51FA\u300C\u8BB0\u4E0B\u4E86\uFF1A<\u6807\u9898>\uFF0C\u622A\u6B62 X \u6708 X \u65E5\uFF08\u5468X\uFF09\u300D\u3002--to \u6D3E\u7ED9\u522B\u4EBA\uFF1A\u53EA\u5B58\u6210**\u8349\u6848**\uFF0C\u8F93\u51FA\u300C\u8349\u6848\uFF08\u8FD8\u6CA1\u53D1\u51FA\uFF09\uFF1A\u6D3E\u7ED9 X\uFF1A\u2026\u300D\uFF0C\u5BF9\u8BDD\u91CC\u51FA\u4E00\u5F20\u8349\u6848\u5361\uFF0C\u7528\u6237\u70B9\u300C\u53D1\u51FA\u300D\u624D\u751F\u6548\u3001\u5BF9\u65B9\u624D\u6536\u5230\u901A\u77E5\u2014\u2014\u4F60\u4E0D\u80FD\u66FF TA \u53D1\u51FA\u3002--to \u8BA4 actorId \u6216\u540D\u5B57\uFF0C\u5BF9\u4E0D\u4E0A\u6216\u5BF9\u4E0A\u4E0D\u6B62\u4E00\u4E2A\u76F4\u63A5\u62A5\u9519\uFF0C\u522B\u731C\uFF0C\u95EE\u7528\u6237\u662F\u54EA\u4F4D\u3002",
|
|
338705
339412
|
flags: [
|
|
339413
|
+
{ name: "to", desc: "\u6D3E\u7ED9\u8C01\uFF1A\u672C\u516C\u53F8\u771F\u4EBA\u7684 actorId \u6216\u540D\u5B57\uFF08\u4E0D\u7ED9 = \u7ED9\u81EA\u5DF1\u8BB0\uFF09", own: true },
|
|
338706
339414
|
{ name: "title", desc: "\u6807\u9898\uFF1A\u4E00\u53E5\u8BDD\u3001\u52A8\u8BCD\u5F00\u5934", required: true, own: true },
|
|
338707
339415
|
{ name: "note", desc: "\u5907\u6CE8\uFF1A\u8C01\u8981\u3001\u4E3A\u4EC0\u4E48\u8981\u3001\u539F\u8BDD\u91CC\u7684\u5173\u952E\u4FE1\u606F", own: true },
|
|
338708
339416
|
{ name: "due", desc: "\u622A\u6B62\u65E5 YYYY-MM-DD\uFF08\u4E0D\u5E26\u65F6\u533A\uFF09", required: true, own: true },
|
|
@@ -338710,25 +339418,35 @@ var COMMAND_DECLS = {
|
|
|
338710
339418
|
{ 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 },
|
|
338711
339419
|
{ name: "start-time", desc: "\u5F00\u59CB\u65F6\u523B HH:mm\uFF08\u914D --start\uFF09", own: true }
|
|
338712
339420
|
],
|
|
338713
|
-
examples: ['oasis todo add --title "\u4EA4 Q3 \u590D\u76D8\u62A5\u544A" --due 2026-10-09 --time 18:00']
|
|
339421
|
+
examples: ['oasis todo add --title "\u4EA4 Q3 \u590D\u76D8\u62A5\u544A" --due 2026-10-09 --time 18:00', 'oasis todo add --to \u5955\u7487 --title "\u6574\u7406\u7ADE\u54C1\u62A5\u4EF7" --due 2026-10-15']
|
|
338714
339422
|
},
|
|
338715
339423
|
"todo list": {
|
|
338716
339424
|
group: "\u4E2A\u4EBA\u5F85\u529E",
|
|
338717
|
-
usage: "oasis todo list [--all]",
|
|
338718
|
-
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\
|
|
338719
|
-
flags: [
|
|
339425
|
+
usage: "oasis todo list [--assignee <\u4EBA>] [--creator <\u4EBA>] [--everyone] [--q <\u5173\u952E\u8BCD>] [--due-from YYYY-MM-DD] [--due-to YYYY-MM-DD] [--status <s,\u2026>] [--all]",
|
|
339426
|
+
description: "\u5217\u51FA\u5F85\u529E\uFF0C\u6309\u622A\u6B62\u65E5\u6392\u5E8F\uFF0C\u6BCF\u884C\u5E26\u627F\u63A5\u4EBA\u548C\u53D1\u8D77\u4EBA\uFF0C\u8FC7\u671F\u7684\u6807\u300C\u5DF2\u8FC7\u671F\u300D\u3001\u6CA1\u53D1\u51FA\u7684\u8349\u6848\u6807\u300C\u8349\u6848\xB7\u672A\u53D1\u51FA\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\u4EC0\u4E48\u90FD\u4E0D\u7ED9 = \u6211\u627F\u63A5\u7684\u3001\u672A\u5B8C\u6210\u7684\u3002\u5168\u516C\u53F8\u7684\u5F85\u529E\u90FD\u80FD\u67E5\uFF1A--assignee / --creator \u6309\u4EBA\uFF08actorId\u3001\u540D\u5B57\u6216 me\uFF09\uFF0C--everyone \u4E0D\u6309\u4EBA\uFF0C--q \u641C\u6807\u9898\u548C\u5907\u6CE8\uFF0C--due-from / --due-to \u622A\u6B62\u65E5\u8303\u56F4\uFF08\u542B\u4E24\u7AEF\uFF09\u3002\u522B\u4EBA\u7684\u8349\u6848\u6C38\u8FDC\u67E5\u4E0D\u5230\u3002",
|
|
339427
|
+
flags: [
|
|
339428
|
+
{ name: "assignee", desc: "\u627F\u63A5\u4EBA\uFF08actorId\u3001\u540D\u5B57\u6216 me\uFF09", own: true },
|
|
339429
|
+
{ name: "creator", desc: "\u53D1\u8D77\u4EBA\uFF08actorId\u3001\u540D\u5B57\u6216 me\uFF09", own: true },
|
|
339430
|
+
{ name: "everyone", desc: "\u4E0D\u6309\u4EBA\u7B5B\uFF0C\u5168\u516C\u53F8", boolean: true, own: true },
|
|
339431
|
+
{ name: "q", desc: "\u5173\u952E\u8BCD\uFF1A\u6807\u9898\u6216\u5907\u6CE8\u91CC\u5305\u542B", own: true },
|
|
339432
|
+
{ name: "due-from", desc: "\u622A\u6B62\u65E5\u4E0D\u65E9\u4E8E YYYY-MM-DD", own: true },
|
|
339433
|
+
{ name: "due-to", desc: "\u622A\u6B62\u65E5\u4E0D\u665A\u4E8E YYYY-MM-DD", own: true },
|
|
339434
|
+
{ name: "status", desc: "\u72B6\u6001\uFF0C\u53EF\u591A\u9009\u9017\u53F7\u5206\u9694\uFF1Adraft / open / done / cancelled\uFF08\u9ED8\u8BA4 open\uFF09", own: true },
|
|
339435
|
+
{ name: "all", desc: "\u56DB\u79CD\u72B6\u6001\u90FD\u5217\uFF08\u542B\u5DF2\u5B8C\u6210 / \u5DF2\u53D6\u6D88\uFF1B\u8349\u6848\u53EA\u5217\u81EA\u5DF1\u53D1\u8D77\u7684\uFF09", boolean: true, own: true }
|
|
339436
|
+
],
|
|
339437
|
+
examples: ["oasis todo list --assignee \u5955\u7487", "oasis todo list --everyone --due-from 2026-10-12 --due-to 2026-10-18", "oasis todo list --everyone --q \u62A5\u4EF7 --all", "oasis todo list --creator me"]
|
|
338720
339438
|
},
|
|
338721
339439
|
"todo show": {
|
|
338722
339440
|
group: "\u4E2A\u4EBA\u5F85\u529E",
|
|
338723
339441
|
usage: "oasis todo show <id>",
|
|
338724
|
-
description: "\u770B\u4E00\u6761\u5F85\u529E\u7684\u5168\u8C8C\uFF1A\u6807\u9898\u3001\u5F00\u59CB \u2192 \u622A\u6B62\u3001\u72B6\u6001\u3001\u5907\u6CE8\u5168\u6587\uFF0C\u4EE5\u53CA\u53D8\u66F4\u8BB0\u5F55\uFF08\u65F6\u95F4\u3001\u8C01\u6539\u7684 / \u7ECF\u624B agent\u3001\u5B57\u6BB5\u3001\u65E7\u503C \u2192 \u65B0\u503C\u3001\u539F\u56E0\uFF0C\u65B0\u7684\u5728\u524D\uFF09\u3002\u6539\u5907\u6CE8\u524D\u5148\u7528\u5B83\u8BFB\u51FA\u5F53\u524D\u5907\u6CE8\u5168\u6587\uFF1B\u7528\u6237\u95EE\u300C\u4E4B\u524D\u5199\u7684\u662F\u4EC0\u4E48\u300D\u4E5F\u67E5\u8FD9\u91CC\u3002",
|
|
339442
|
+
description: "\u770B\u4E00\u6761\u5F85\u529E\u7684\u5168\u8C8C\uFF1A\u6807\u9898\u3001\u5F00\u59CB \u2192 \u622A\u6B62\u3001\u72B6\u6001\u3001\u53D1\u8D77\u4EBA\u3001\u627F\u63A5\u4EBA\uFF08\u6D3E\u7ED9\u522B\u4EBA\u7684\u8FD8\u6709\u53D1\u51FA\u65F6\u95F4\u3001\u627F\u63A5\u4EBA\u9996\u6B21\u67E5\u770B\u65F6\u95F4\uFF09\u3001\u5907\u6CE8\u5168\u6587\uFF0C\u4EE5\u53CA\u53D8\u66F4\u8BB0\u5F55\uFF08\u65F6\u95F4\u3001\u8C01\u6539\u7684 / \u7ECF\u624B agent\u3001\u5B57\u6BB5\u3001\u65E7\u503C \u2192 \u65B0\u503C\u3001\u539F\u56E0\uFF0C\u65B0\u7684\u5728\u524D\uFF09\u3002\u6539\u5907\u6CE8\u524D\u5148\u7528\u5B83\u8BFB\u51FA\u5F53\u524D\u5907\u6CE8\u5168\u6587\uFF1B\u7528\u6237\u95EE\u300C\u4E4B\u524D\u5199\u7684\u662F\u4EC0\u4E48\u300D\u4E5F\u67E5\u8FD9\u91CC\u3002\u672C\u516C\u53F8\u8C01\u7684\u5F85\u529E\u90FD\u80FD\u770B\uFF08\u522B\u4EBA\u7684\u8349\u6848\u9664\u5916\uFF09\uFF1B\u627F\u63A5\u4EBA\u7B2C\u4E00\u6B21\u770B\u4F1A\u88AB\u8BB0\u4E0B\u3002",
|
|
338725
339443
|
positional: [{ name: "<id>", required: true, desc: "\u5F85\u529E id\uFF08oasis todo list \u7B2C\u4E00\u5217\uFF09" }],
|
|
338726
339444
|
examples: ["oasis todo show td_3f9a1c2b"]
|
|
338727
339445
|
},
|
|
338728
339446
|
"todo edit": {
|
|
338729
339447
|
group: "\u4E2A\u4EBA\u5F85\u529E",
|
|
338730
|
-
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]",
|
|
338731
|
-
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',
|
|
339448
|
+
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] [--to <\u4EBA>] [--reason \u2026]",
|
|
339449
|
+
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\u53EA\u6709\u53D1\u8D77\u4EBA\u548C\u627F\u63A5\u4EBA\u80FD\u6539\uFF1B\u6D3E\u7ED9\u522B\u4EBA\u4E14\u5DF2\u53D1\u51FA\u7684\uFF0C\u6539\u4E86\u4F1A\u901A\u77E5\u53E6\u4E00\u65B9\u3002\u6539\u671F\u8981\u5199\u539F\u56E0\uFF1A\u7528\u6237\u6CA1\u8BF4\u5C31\u95EE\u4E00\u53E5\uFF1B**\u522B\u4EBA\u6D3E\u7ED9\u4F60\u7684\u6539\u622A\u6B62\u5FC5\u987B\u5E26 --reason**\uFF08\u4E0D\u5E26\u76F4\u63A5\u62A5\u9519\uFF09\uFF0C\u81EA\u5DF1\u8BB0\u7684\u7528\u6237\u8BF4\u4E0D\u7528\u5C31\u4E0D\u5199\uFF0C\u522B\u7F16\u3002--to \u53EA\u80FD\u5728\u8FD8\u6CA1\u53D1\u51FA\u7684\u8349\u6848\u4E0A\u6362\u627F\u63A5\u4EBA\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',
|
|
338732
339450
|
positional: [{ name: "<id>", required: true, desc: "\u5F85\u529E id\uFF08oasis todo list \u7B2C\u4E00\u5217\uFF09" }],
|
|
338733
339451
|
flags: [
|
|
338734
339452
|
{ name: "title", desc: "\u65B0\u6807\u9898", own: true },
|
|
@@ -338738,28 +339456,31 @@ var COMMAND_DECLS = {
|
|
|
338738
339456
|
{ name: "due", desc: "\u65B0\u622A\u6B62\u65E5 YYYY-MM-DD", own: true },
|
|
338739
339457
|
{ name: "time", desc: "\u65B0\u622A\u6B62\u65F6\u523B HH:mm\uFF1Bnone = \u6E05\u7A7A", own: true },
|
|
338740
339458
|
{ 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 },
|
|
338741
|
-
{ name: "
|
|
339459
|
+
{ name: "to", desc: "\u6362\u627F\u63A5\u4EBA\uFF08\u53EA\u9650\u8FD8\u6CA1\u53D1\u51FA\u7684\u8349\u6848\uFF09", own: true },
|
|
339460
|
+
{ name: "reason", desc: "\u4E3A\u4EC0\u4E48\u6539\uFF08\u6539\u671F\u65F6\u8981\u5199\uFF1B\u522B\u4EBA\u6D3E\u7ED9\u4F60\u7684\u6539\u622A\u6B62\u5FC5\u987B\u5199\uFF09", own: true }
|
|
338742
339461
|
],
|
|
338743
339462
|
examples: ['oasis todo edit td_3f9a1c2b --due 2026-10-12 --reason "\u5BA2\u6237\u5EF6\u671F\u4E00\u5468"']
|
|
338744
339463
|
},
|
|
338745
339464
|
"todo done": {
|
|
338746
339465
|
group: "\u4E2A\u4EBA\u5F85\u529E",
|
|
338747
|
-
usage: "oasis todo done <id>",
|
|
338748
|
-
description: "\u6807\u8BB0\u5B8C\u6210\u3002\u5339\u914D\u5230\u591A\u6761\u65F6\u5148\u95EE\u7528\u6237\u662F\u54EA\u6761\uFF0C\u522B\u731C\u3002",
|
|
338749
|
-
positional: [{ name: "<id>", required: true, desc: "\u5F85\u529E id" }]
|
|
339466
|
+
usage: "oasis todo done <id> [--reason \u2026]",
|
|
339467
|
+
description: "\u6807\u8BB0\u5B8C\u6210\u3002\u5339\u914D\u5230\u591A\u6761\u65F6\u5148\u95EE\u7528\u6237\u662F\u54EA\u6761\uFF0C\u522B\u731C\u3002\u6D3E\u7ED9\u522B\u4EBA\u4E14\u5DF2\u53D1\u51FA\u7684\uFF0C\u5B8C\u6210\u540E\u901A\u77E5\u53E6\u4E00\u65B9\u3002",
|
|
339468
|
+
positional: [{ name: "<id>", required: true, desc: "\u5F85\u529E id" }],
|
|
339469
|
+
flags: [{ name: "reason", desc: "\u5907\u6CE8\u4E00\u53E5\uFF08\u53EF\u9009\uFF09", own: true }]
|
|
338750
339470
|
},
|
|
338751
339471
|
"todo cancel": {
|
|
338752
339472
|
group: "\u4E2A\u4EBA\u5F85\u529E",
|
|
338753
339473
|
usage: "oasis todo cancel <id> [--reason \u2026]",
|
|
338754
|
-
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",
|
|
339474
|
+
description: "\u53D6\u6D88\uFF08\u4E0D\u7528\u505A\u4E86\uFF09\u3002\u53EA\u6539\u72B6\u6001\u3001\u4E0D\u5220\u9664\uFF08\u5F85\u529E\u6C38\u4E0D\u5220\u9664\uFF09\uFF0C--all \u5217\u8868\u548C show \u91CC\u90FD\u8FD8\u770B\u5F97\u5230\u3002\u53D1\u8D77\u4EBA\u3001\u627F\u63A5\u4EBA\u90FD\u80FD\u53D6\u6D88\uFF0C\u6D3E\u7ED9\u522B\u4EBA\u4E14\u5DF2\u53D1\u51FA\u7684\u4F1A\u901A\u77E5\u53E6\u4E00\u65B9\uFF1B**\u522B\u4EBA\u6D3E\u7ED9\u4F60\u7684\u53D6\u6D88\u5FC5\u987B\u5E26 --reason**\u3002",
|
|
338755
339475
|
positional: [{ name: "<id>", required: true, desc: "\u5F85\u529E id" }],
|
|
338756
|
-
flags: [{ name: "reason", desc: "\u4E3A\u4EC0\u4E48\u4E0D\u7528\u505A\u4E86", own: true }]
|
|
339476
|
+
flags: [{ name: "reason", desc: "\u4E3A\u4EC0\u4E48\u4E0D\u7528\u505A\u4E86\uFF08\u522B\u4EBA\u6D3E\u7ED9\u4F60\u7684\u5FC5\u987B\u5199\uFF09", own: true }]
|
|
338757
339477
|
},
|
|
338758
339478
|
"todo reopen": {
|
|
338759
339479
|
group: "\u4E2A\u4EBA\u5F85\u529E",
|
|
338760
|
-
usage: "oasis todo reopen <id>",
|
|
338761
|
-
description: "\u628A\u5DF2\u5B8C\u6210 / \u5DF2\u53D6\u6D88\u7684\u5F85\u529E\u91CD\u65B0\u6253\u5F00\u3002",
|
|
338762
|
-
positional: [{ name: "<id>", required: true, desc: "\u5F85\u529E id" }]
|
|
339480
|
+
usage: "oasis todo reopen <id> [--reason \u2026]",
|
|
339481
|
+
description: "\u628A\u5DF2\u5B8C\u6210 / \u5DF2\u53D6\u6D88\u7684\u5F85\u529E\u91CD\u65B0\u6253\u5F00\uFF08\u53D1\u8D77\u4EBA\u89C9\u5F97\u6CA1\u505A\u5B8C\u4E5F\u7528\u5B83\uFF09\u3002\u6D3E\u7ED9\u522B\u4EBA\u4E14\u5DF2\u53D1\u51FA\u7684\uFF0C\u4F1A\u901A\u77E5\u53E6\u4E00\u65B9\u3002\u8349\u6848\u53D6\u6D88\u540E\u91CD\u5F00\u4ECD\u662F\u8349\u6848\uFF0C\u4E0D\u4F1A\u56E0\u6B64\u53D1\u51FA\u3002",
|
|
339482
|
+
positional: [{ name: "<id>", required: true, desc: "\u5F85\u529E id" }],
|
|
339483
|
+
flags: [{ name: "reason", desc: "\u4E3A\u4EC0\u4E48\u91CD\u5F00\uFF08\u53EF\u9009\uFF09", own: true }]
|
|
338763
339484
|
},
|
|
338764
339485
|
// —— 技能:组织技能库的 CLI 面(Web 上是「管理 > 技能」那一页)。
|
|
338765
339486
|
// agent 把自己写好的一个技能目录沉淀进公司,并决定它对谁生效。 ——
|
|
@@ -339086,7 +339807,7 @@ function formatProjectDecisions(projectId2, view, query) {
|
|
|
339086
339807
|
"\u5DF2\u786E\u8BA4 = \u5B9A\u4E86\u8981\u8FD9\u4E48\u505A\uFF0C\u4E0D\u4EE3\u8868\u5DF2\u7ECF\u4E0A\u7EBF\uFF1B\u6807\u300C\u5DF2\u4E0A\u7EBF\u300D\u7684\u624D\u662F\u73B0\u5728\u7CFB\u7EDF\u91CC\u7684\u6837\u5B50\u3002",
|
|
339087
339808
|
""
|
|
339088
339809
|
];
|
|
339089
|
-
let
|
|
339810
|
+
let shown2 = 0;
|
|
339090
339811
|
for (const t of topics) {
|
|
339091
339812
|
const rows = view.decisions.filter((d5) => d5.value.topicId === t.value.topicId).filter((d5) => {
|
|
339092
339813
|
if (state2 ? !stateMatches(d5.value, state2, query.now) : !["accepted", "proposed"].includes(d5.value.record.state)) return false;
|
|
@@ -339100,7 +339821,7 @@ function formatProjectDecisions(projectId2, view, query) {
|
|
|
339100
339821
|
if (!rows.length) lines.push("\uFF08\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u51B3\u7B56\uFF09");
|
|
339101
339822
|
for (const d5 of rows) {
|
|
339102
339823
|
const r5 = d5.value.record;
|
|
339103
|
-
|
|
339824
|
+
shown2 += 1;
|
|
339104
339825
|
lines.push(`- [${label(d5.value, query.now)}] ${r5.statement} \uFF08\u66F4\u65B0 ${r5.updated_at.slice(0, 10)}\uFF0C${d5.value.decisionId}\uFF09`);
|
|
339105
339826
|
if (!detail) continue;
|
|
339106
339827
|
lines.push(` \u539F\u56E0\uFF1A${r5.rationale || "\u672A\u8BF4\u660E"}`, ` \u786E\u8BA4\u4EBA\uFF1A${r5.confirmer ?? "\u672A\u786E\u8BA4"}`);
|
|
@@ -339111,7 +339832,7 @@ function formatProjectDecisions(projectId2, view, query) {
|
|
|
339111
339832
|
}
|
|
339112
339833
|
lines.push("");
|
|
339113
339834
|
}
|
|
339114
|
-
if (!
|
|
339835
|
+
if (!shown2 && !detail) lines.push("\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u51B3\u7B56\u3002");
|
|
339115
339836
|
return lines;
|
|
339116
339837
|
}
|
|
339117
339838
|
function writeContextSnapshot(root5, snapshot) {
|
|
@@ -339511,10 +340232,10 @@ function renderGraphLines(graph) {
|
|
|
339511
340232
|
const systemNote = closureIds.has(n3.id) ? " [\u672C\u5355\u672B\u7AEF\xB7\u7CFB\u7EDF\u7EF4\u62A4\uFF0C\u8FDE\u7EBF\u4E0E\u4EFB\u52A1\u4E66\u90FD\u4E0D\u7528\u4F60\u7BA1]" : "";
|
|
339512
340233
|
out.push(` type=${n3.type}${n3.stage ? ` \u9636\u6BB5=${n3.stage}` : ""}${n3.blocked ? " [\u5361\u4F4F]" : ""}${n3.unresolvedEscalations ? ` [\u4E0A\u62A5 ${n3.unresolvedEscalations}]` : ""} owner=${n3.owner?.name ?? n3.owner?.id ?? "?"}${n3.label ? ` ${n3.label}` : ""}${systemNote}`);
|
|
339513
340234
|
}
|
|
339514
|
-
const
|
|
340235
|
+
const shown2 = graph.edges.filter((e5) => !closureIds.has(e5.from));
|
|
339515
340236
|
const folded = [...closureIds].filter((id) => graph.edges.some((e5) => e5.from === id));
|
|
339516
|
-
out.push(
|
|
339517
|
-
for (const e5 of
|
|
340237
|
+
out.push(shown2.length > 0 || folded.length > 0 ? "\n\u4F9D\u8D56\u8FB9\uFF08\u6D88\u8D39\u8005 \u2192 \u4E0A\u6E38\uFF09:" : "\n\u4F9D\u8D56\u8FB9\uFF1A\uFF08\u65E0\uFF09");
|
|
340238
|
+
for (const e5 of shown2) out.push(` ${e5.from} \u2192 ${e5.to}${e5.required === false ? "\uFF08\u53EF\u9009\uFF09" : ""}`);
|
|
339518
340239
|
for (const id of folded) out.push(` ${id} \u2192 \uFF08\u672C\u5355\u5168\u90E8\u4E1A\u52A1\u4EA7\u7269\xB7\u7CFB\u7EDF\u7EF4\u62A4\uFF09`);
|
|
339519
340240
|
return out;
|
|
339520
340241
|
}
|
|
@@ -339615,7 +340336,7 @@ async function waitForCommandAuthorization(base, headers, draftId, fallback2) {
|
|
|
339615
340336
|
}
|
|
339616
340337
|
}
|
|
339617
340338
|
}
|
|
339618
|
-
var CLI_VERSION = "2.2.
|
|
340339
|
+
var CLI_VERSION = "2.2.121" ? "2.2.121" : "dev";
|
|
339619
340340
|
function apiHeaders(token2, company) {
|
|
339620
340341
|
const headers = {
|
|
339621
340342
|
authorization: `Bearer ${token2}`,
|
|
@@ -339977,6 +340698,31 @@ async function runCli(argv, println = console.log, progressln = console.error) {
|
|
|
339977
340698
|
});
|
|
339978
340699
|
return;
|
|
339979
340700
|
}
|
|
340701
|
+
if (command6 === "blobs") {
|
|
340702
|
+
const { runBlobs: runBlobs2 } = await Promise.resolve().then(() => (init_blobs_command(), blobs_command_exports));
|
|
340703
|
+
let stopRequested = false;
|
|
340704
|
+
const onSignal = () => {
|
|
340705
|
+
if (stopRequested) process.exit(130);
|
|
340706
|
+
stopRequested = true;
|
|
340707
|
+
process.stderr.write("[blobs] \u6536\u5230\u4E2D\u65AD\uFF1A\u5904\u7406\u5B8C\u5F53\u524D\u8FD9\u4E00\u884C\u540E\u505C\u6B62\uFF08\u518D\u6309\u4E00\u6B21\u7ACB\u5373\u9000\u51FA\uFF09\n");
|
|
340708
|
+
};
|
|
340709
|
+
process.on("SIGINT", onSignal);
|
|
340710
|
+
process.on("SIGTERM", onSignal);
|
|
340711
|
+
try {
|
|
340712
|
+
process.exitCode = await runBlobs2(positional, flags, {
|
|
340713
|
+
out: (line2) => println(line2),
|
|
340714
|
+
err: (line2) => process.stderr.write(`${line2}
|
|
340715
|
+
`),
|
|
340716
|
+
env: process.env,
|
|
340717
|
+
dir,
|
|
340718
|
+
shouldStop: () => stopRequested
|
|
340719
|
+
});
|
|
340720
|
+
} finally {
|
|
340721
|
+
process.off("SIGINT", onSignal);
|
|
340722
|
+
process.off("SIGTERM", onSignal);
|
|
340723
|
+
}
|
|
340724
|
+
return;
|
|
340725
|
+
}
|
|
339980
340726
|
if (command6 === "node-token") {
|
|
339981
340727
|
const store = createNodeTokenStore(path42.join(dir, "node-tokens.json"));
|
|
339982
340728
|
const sub = positional[0];
|
|
@@ -341987,6 +342733,7 @@ ${res.warning}`);
|
|
|
341987
342733
|
}
|
|
341988
342734
|
case "todo": {
|
|
341989
342735
|
const sub = positional[0];
|
|
342736
|
+
const nameIn = (names) => (id) => names?.[id] ?? id;
|
|
341990
342737
|
const due = (t) => formatTodoSpan(t);
|
|
341991
342738
|
const call = async (method, url, body2) => {
|
|
341992
342739
|
try {
|
|
@@ -342009,6 +342756,8 @@ ${res.warning}`);
|
|
|
342009
342756
|
const idOf = () => needPos(positional, 1, `oasis todo ${sub} <id>`);
|
|
342010
342757
|
const todoPath = (id, tail = "") => `/api/todos/${encodeURIComponent(id)}${tail}`;
|
|
342011
342758
|
if (sub === "add") {
|
|
342759
|
+
const to = flags.get("to");
|
|
342760
|
+
if (to !== void 0 && !to.trim()) throw new Error("--to \u8981\u5199\u6D3E\u7ED9\u8C01\uFF08actorId \u6216\u540D\u5B57\uFF09");
|
|
342012
342761
|
const title = need(flags, "title");
|
|
342013
342762
|
const dueDate = checkDay(need(flags, "due"), "due");
|
|
342014
342763
|
const time4 = flags.get("time");
|
|
@@ -342019,6 +342768,7 @@ ${res.warning}`);
|
|
|
342019
342768
|
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`);
|
|
342020
342769
|
const sourceChatSessionId = process.env["OASIS_CHAT_SESSION_ID"];
|
|
342021
342770
|
const r5 = await call("POST", "/api/todos", {
|
|
342771
|
+
...to !== void 0 ? { assignee: to } : {},
|
|
342022
342772
|
title,
|
|
342023
342773
|
dueDate,
|
|
342024
342774
|
...time4 !== void 0 ? { dueTime: checkTime(time4) } : {},
|
|
@@ -342028,22 +342778,39 @@ ${res.warning}`);
|
|
|
342028
342778
|
...sourceChatSessionId ? { sourceChatSessionId } : {}
|
|
342029
342779
|
});
|
|
342030
342780
|
println(r5.todayLine);
|
|
342781
|
+
if (r5.todo.status === "draft") {
|
|
342782
|
+
println(`\u8349\u6848\uFF08\u8FD8\u6CA1\u53D1\u51FA\uFF09\uFF1A\u6D3E\u7ED9 ${nameIn(r5.names)(r5.todo.assigneeActorId)}\uFF1A${r5.todo.title}\uFF0C${due(r5.todo)}`);
|
|
342783
|
+
println(`id\uFF1A${r5.todo.id}`);
|
|
342784
|
+
println("\u5BF9\u8BDD\u91CC\u5DF2\u51FA\u8349\u6848\u5361\uFF1A\u8BF7\u7528\u6237\u6838\u5BF9\u540E\u70B9\u300C\u53D1\u51FA\u300D\u3002\u53D1\u51FA\u524D\u5BF9\u65B9\u770B\u4E0D\u5230\u3001\u4E5F\u6536\u4E0D\u5230\u901A\u77E5\uFF1B\u8981\u6539\u5C31 oasis todo edit \u8FD9\u6761\u8349\u6848\u3002");
|
|
342785
|
+
break;
|
|
342786
|
+
}
|
|
342031
342787
|
println(`\u8BB0\u4E0B\u4E86\uFF1A${r5.todo.title}\uFF0C${due(r5.todo)}`);
|
|
342032
342788
|
println(`id\uFF1A${r5.todo.id}`);
|
|
342033
342789
|
break;
|
|
342034
342790
|
}
|
|
342035
342791
|
if (sub === "list") {
|
|
342792
|
+
const qs = new URLSearchParams();
|
|
342036
342793
|
const all2 = flags.get("all") === "true";
|
|
342037
|
-
|
|
342794
|
+
if (all2) qs.set("all", "1");
|
|
342795
|
+
if (flags.get("everyone") === "true") qs.set("everyone", "1");
|
|
342796
|
+
for (const [flag, key2] of [["assignee", "assignee"], ["creator", "creator"], ["q", "q"], ["status", "status"]]) {
|
|
342797
|
+
const v2 = flags.get(flag);
|
|
342798
|
+
if (v2 !== void 0) qs.set(key2, v2);
|
|
342799
|
+
}
|
|
342800
|
+
if (flags.has("due-from")) qs.set("dueFrom", checkDay(flags.get("due-from"), "due-from"));
|
|
342801
|
+
if (flags.has("due-to")) qs.set("dueTo", checkDay(flags.get("due-to"), "due-to"));
|
|
342802
|
+
const query = qs.toString();
|
|
342803
|
+
const r5 = await call("GET", `/api/todos${query ? `?${query}` : ""}`);
|
|
342038
342804
|
println(r5.todayLine);
|
|
342039
342805
|
if (r5.items.length === 0) {
|
|
342040
|
-
println(all2 ? "\u6CA1\u6709\u5F85\u529E\u3002" : "\u6CA1\u6709\u672A\u5B8C\u6210\u7684\u5F85\u529E\u3002");
|
|
342806
|
+
println(query && query !== "all=1" ? "\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u5F85\u529E\u3002" : all2 ? "\u6CA1\u6709\u5F85\u529E\u3002" : "\u6CA1\u6709\u672A\u5B8C\u6210\u7684\u5F85\u529E\u3002");
|
|
342041
342807
|
break;
|
|
342042
342808
|
}
|
|
342809
|
+
const nm = nameIn(r5.names);
|
|
342043
342810
|
for (const t of r5.items) {
|
|
342044
|
-
const tag = t.status === "done" ? " [\u5DF2\u5B8C\u6210]" : t.status === "cancelled" ? " [\u5DF2\u53D6\u6D88]" : t.dueDate < r5.today.date ? " [\u5DF2\u8FC7\u671F]" : "";
|
|
342811
|
+
const tag = t.status === "draft" ? " [\u8349\u6848\xB7\u672A\u53D1\u51FA]" : t.status === "done" ? " [\u5DF2\u5B8C\u6210]" : t.status === "cancelled" ? " [\u5DF2\u53D6\u6D88]" : t.dueDate < r5.today.date ? " [\u5DF2\u8FC7\u671F]" : "";
|
|
342045
342812
|
const when = t.startDate ? formatTodoSpan(t) : formatTodoDue(t.dueDate, t.dueTime);
|
|
342046
|
-
println(`${t.id} ${when} ${t.title}${tag}`);
|
|
342813
|
+
println(`${t.id} ${when} ${t.title} \u627F\u63A5\uFF1A${nm(t.assigneeActorId)} \u53D1\u8D77\uFF1A${nm(t.creatorActorId)}${tag}`);
|
|
342047
342814
|
}
|
|
342048
342815
|
break;
|
|
342049
342816
|
}
|
|
@@ -342054,11 +342821,27 @@ ${res.warning}`);
|
|
|
342054
342821
|
call("GET", "/api/todos")
|
|
342055
342822
|
]);
|
|
342056
342823
|
const t = one2.todo;
|
|
342057
|
-
const
|
|
342824
|
+
const nm = nameIn(one2.names);
|
|
342825
|
+
const statusText = t.status === "draft" ? "\u8349\u6848\uFF08\u8FD8\u6CA1\u53D1\u51FA\uFF09" : t.status === "done" ? "\u5DF2\u5B8C\u6210" : t.status === "cancelled" ? "\u5DF2\u53D6\u6D88" : t.dueDate < day.today.date ? "\u672A\u5B8C\u6210\uFF08\u5DF2\u8FC7\u671F\uFF09" : "\u672A\u5B8C\u6210";
|
|
342058
342826
|
println(day.todayLine);
|
|
342059
342827
|
println(`${t.id} ${t.title}`);
|
|
342060
342828
|
println(`\u65F6\u95F4\uFF1A${due(t)}`);
|
|
342061
342829
|
println(`\u72B6\u6001\uFF1A${statusText}`);
|
|
342830
|
+
println(`\u53D1\u8D77\u4EBA\uFF1A${nm(t.creatorActorId)}`);
|
|
342831
|
+
println(`\u627F\u63A5\u4EBA\uFF1A${nm(t.assigneeActorId)}`);
|
|
342832
|
+
const fmtAt = (iso9) => new Intl.DateTimeFormat("sv-SE", {
|
|
342833
|
+
timeZone: day.today.timeZone,
|
|
342834
|
+
year: "numeric",
|
|
342835
|
+
month: "2-digit",
|
|
342836
|
+
day: "2-digit",
|
|
342837
|
+
hour: "2-digit",
|
|
342838
|
+
minute: "2-digit",
|
|
342839
|
+
hour12: false
|
|
342840
|
+
}).format(new Date(iso9));
|
|
342841
|
+
if (t.creatorActorId !== t.assigneeActorId) {
|
|
342842
|
+
println(`\u53D1\u51FA\u65F6\u95F4\uFF1A${t.sentAt ? fmtAt(t.sentAt) : "\uFF08\u8FD8\u6CA1\u53D1\u51FA\uFF09"}`);
|
|
342843
|
+
println(`\u627F\u63A5\u4EBA\u9996\u6B21\u67E5\u770B\uFF1A${t.firstViewedAt ? fmtAt(t.firstViewedAt) : "\uFF08\u8FD8\u6CA1\u770B\u8FC7\uFF09"}`);
|
|
342844
|
+
}
|
|
342062
342845
|
if (t.linkedWorkorderId) println(`\u5DE5\u5355\uFF1A${t.linkedWorkorderId}`);
|
|
342063
342846
|
println("\u5907\u6CE8\uFF1A");
|
|
342064
342847
|
println(t.note ? t.note : "\uFF08\u65E0\uFF09");
|
|
@@ -342071,24 +342854,16 @@ ${res.warning}`);
|
|
|
342071
342854
|
startTime: "\u5F00\u59CB\u65F6\u523B",
|
|
342072
342855
|
dueDate: "\u622A\u6B62\u65E5",
|
|
342073
342856
|
dueTime: "\u622A\u6B62\u65F6\u523B",
|
|
342074
|
-
linkedWorkorderId: "\u5DE5\u5355"
|
|
342857
|
+
linkedWorkorderId: "\u5DE5\u5355",
|
|
342858
|
+
assignee: "\u627F\u63A5\u4EBA"
|
|
342075
342859
|
};
|
|
342076
|
-
const STATUS = { open: "\u672A\u5B8C\u6210", done: "\u5DF2\u5B8C\u6210", cancelled: "\u5DF2\u53D6\u6D88" };
|
|
342077
|
-
const val = (field, v2) => v2 === void 0 || v2 === "" ? "\uFF08\u7A7A\uFF09" : field === "status" ? STATUS[v2] ?? v2 : v2;
|
|
342078
|
-
const fmtAt = (iso9) => new Intl.DateTimeFormat("sv-SE", {
|
|
342079
|
-
timeZone: day.today.timeZone,
|
|
342080
|
-
year: "numeric",
|
|
342081
|
-
month: "2-digit",
|
|
342082
|
-
day: "2-digit",
|
|
342083
|
-
hour: "2-digit",
|
|
342084
|
-
minute: "2-digit",
|
|
342085
|
-
hour12: false
|
|
342086
|
-
}).format(new Date(iso9));
|
|
342860
|
+
const STATUS = { draft: "\u8349\u6848", open: "\u672A\u5B8C\u6210", done: "\u5DF2\u5B8C\u6210", cancelled: "\u5DF2\u53D6\u6D88" };
|
|
342861
|
+
const val = (field, v2) => v2 === void 0 || v2 === "" ? "\uFF08\u7A7A\uFF09" : field === "status" ? STATUS[v2] ?? v2 : field === "assignee" ? nm(v2) : v2;
|
|
342087
342862
|
const changes = [...one2.changes].sort((a5, b6) => b6.at.localeCompare(a5.at));
|
|
342088
342863
|
println(`\u53D8\u66F4\u8BB0\u5F55\uFF08${changes.length} \u6761\uFF0C\u65B0\u7684\u5728\u524D\uFF09\uFF1A`);
|
|
342089
342864
|
for (const c5 of changes) {
|
|
342090
|
-
const who = c5.handActorId ? `${c5.actorId}\uFF08\u7ECF\u624B ${c5.handActorId}\uFF09` : c5.actorId;
|
|
342091
|
-
const what = c5.field === "created" ? `\u8BB0\u4E0B\uFF1A${c5.newValue ?? ""}` : `${FIELD[c5.field] ?? c5.field}\uFF1A${val(c5.field, c5.oldValue)} \u2192 ${val(c5.field, c5.newValue)}`;
|
|
342865
|
+
const who = c5.handActorId ? `${nm(c5.actorId)}\uFF08\u7ECF\u624B ${c5.handActorId}\uFF09` : nm(c5.actorId);
|
|
342866
|
+
const what = c5.field === "created" ? `\u8BB0\u4E0B\uFF1A${c5.newValue ?? ""}` : c5.field === "sent" ? `\u53D1\u51FA\uFF1A\u6D3E\u7ED9 ${nm(c5.newValue ?? "")}` : `${FIELD[c5.field] ?? c5.field}\uFF1A${val(c5.field, c5.oldValue)} \u2192 ${val(c5.field, c5.newValue)}`;
|
|
342092
342867
|
println(`- ${fmtAt(c5.at)} ${who} ${what}${c5.reason ? ` \u539F\u56E0\uFF1A${c5.reason}` : ""}`);
|
|
342093
342868
|
}
|
|
342094
342869
|
break;
|
|
@@ -342103,7 +342878,8 @@ ${res.warning}`);
|
|
|
342103
342878
|
if (flags.has("start")) body2["startDate"] = flags.get("start") === "none" ? null : checkDay(flags.get("start"), "start");
|
|
342104
342879
|
if (flags.has("start-time")) body2["startTime"] = flags.get("start-time") === "none" ? null : checkTime(flags.get("start-time"), "start-time");
|
|
342105
342880
|
if (flags.has("workorder")) body2["linkedWorkorderId"] = flags.get("workorder") === "none" ? null : flags.get("workorder");
|
|
342106
|
-
if (
|
|
342881
|
+
if (flags.has("to")) body2["assignee"] = flags.get("to");
|
|
342882
|
+
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 / --to \u91CC\u7684\u81F3\u5C11\u4E00\u4E2A");
|
|
342107
342883
|
if (flags.get("reason")) body2["reason"] = flags.get("reason");
|
|
342108
342884
|
const r5 = await call("PATCH", todoPath(id), body2);
|
|
342109
342885
|
println(r5.todayLine);
|
|
@@ -342112,7 +342888,7 @@ ${res.warning}`);
|
|
|
342112
342888
|
}
|
|
342113
342889
|
if (sub === "done" || sub === "cancel" || sub === "reopen") {
|
|
342114
342890
|
const id = idOf();
|
|
342115
|
-
const reason =
|
|
342891
|
+
const reason = flags.get("reason");
|
|
342116
342892
|
const r5 = await call("POST", todoPath(id, `/${sub}`), reason ? { reason } : {});
|
|
342117
342893
|
println(r5.todayLine);
|
|
342118
342894
|
println(`${sub === "done" ? "\u5DF2\u5B8C\u6210" : sub === "cancel" ? "\u5DF2\u53D6\u6D88" : "\u5DF2\u91CD\u65B0\u6253\u5F00"}\uFF1A${r5.todo.title}\uFF0C${due(r5.todo)}`);
|
|
@@ -342943,10 +343719,10 @@ ${res.warning}`);
|
|
|
342943
343719
|
println(`\u4F9D\u8D56: ${v2.artifact.inputs.length === 0 ? "\u65E0" : v2.artifact.inputs.map((e5) => `${e5.to}@${e5.pinned ?? "\u672A\u5C31\u7EEA"}${e5.required ? "[required]" : ""}`).join(" ")}`);
|
|
342944
343720
|
println(`\u5185\u5BB9: ${kind} \u2190 \u53D6\u6B63\u6587\u7528 \`oasis content ${id} [path]\`\uFF08current head\uFF09\uFF0F\`oasis content <revisionId>\`\uFF08\u6307\u5B9A\u7248\u672C\uFF09`);
|
|
342945
343721
|
const REV_LIMIT = 50;
|
|
342946
|
-
const
|
|
342947
|
-
println(`\u7248\u672C(${v2.revisions.length})${
|
|
342948
|
-
if (
|
|
342949
|
-
for (const r5 of
|
|
343722
|
+
const shown2 = v2.revisions.length > REV_LIMIT ? v2.revisions.slice(-REV_LIMIT) : v2.revisions;
|
|
343723
|
+
println(`\u7248\u672C(${v2.revisions.length})${shown2.length < v2.revisions.length ? `\u2014\u2014\u53EA\u5217\u6700\u8FD1 ${REV_LIMIT} \u6761` : ""}\uFF1A`);
|
|
343724
|
+
if (shown2.length === 0) println(` \uFF08\u65E0\uFF09`);
|
|
343725
|
+
for (const r5 of shown2) {
|
|
342950
343726
|
const marks = [
|
|
342951
343727
|
r5.id === v2.artifact.currentRev ? "\u2190 current head" : "",
|
|
342952
343728
|
r5.id === v2.concludedHead ? "\u2190 \u5DF2\u4EA4\u4ED8" : ""
|
|
@@ -343019,11 +343795,11 @@ ${res.warning}`);
|
|
|
343019
343795
|
case "ls": {
|
|
343020
343796
|
const wsFilter = flags.get("workspace");
|
|
343021
343797
|
const rows = await api.view("ls");
|
|
343022
|
-
const
|
|
343023
|
-
for (const a5 of
|
|
343798
|
+
const shown2 = wsFilter ? rows.filter((a5) => a5.workspace === wsFilter) : rows;
|
|
343799
|
+
for (const a5 of shown2) {
|
|
343024
343800
|
println(`${a5.id} ws=${a5.workspace ?? "\u2205"} type=${a5.type} owner=${a5.owner} head=${a5.currentRev ?? "\u2205"} queue=${a5.queue} [${a5.mark}]`);
|
|
343025
343801
|
}
|
|
343026
|
-
if (wsFilter &&
|
|
343802
|
+
if (wsFilter && shown2.length === 0) println(`\uFF08${wsFilter} \u4E0B\u6CA1\u6709\u4EA7\u7269\u2014\u2014\u5DE5\u5355 id \u7528 \`oasis workorders\` \u67E5\uFF09`);
|
|
343027
343803
|
else if (!wsFilter && rows.length > 30) println(`\u2014\u2014 \u5171 ${rows.length} \u4E2A\u4EA7\u7269\uFF08\u5168\u5E93\u62C9\u5E73\uFF09\u3002\u6309\u5DE5\u5355\u770B\u7528 \`oasis ls --workspace <ws:id>\`\uFF0C\u5DE5\u5355\u6E05\u5355\u7528 \`oasis workorders\`\u3002`);
|
|
343028
343804
|
break;
|
|
343029
343805
|
}
|
|
@@ -343793,7 +344569,7 @@ function shimScript() {
|
|
|
343793
344569
|
}
|
|
343794
344570
|
|
|
343795
344571
|
// src/index.ts
|
|
343796
|
-
var PKG_VERSION = true ? "2.2.
|
|
344572
|
+
var PKG_VERSION = true ? "2.2.121" : "dev";
|
|
343797
344573
|
var LOCAL_BIN = localBin();
|
|
343798
344574
|
var NPM_PREFIX = npmPrefix();
|
|
343799
344575
|
var INSTANCE = DEFAULT_INSTANCE;
|