oasis_test 0.1.104 → 0.1.105
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 +261 -75
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -4440,6 +4440,14 @@ function classify(actorId) {
|
|
|
4440
4440
|
if (actorId.startsWith("actor:human:")) return "human";
|
|
4441
4441
|
return "unknown";
|
|
4442
4442
|
}
|
|
4443
|
+
function pickReminderStep(cadence2, elapsedMs) {
|
|
4444
|
+
let hit = null;
|
|
4445
|
+
for (let i = 0; i < cadence2.length; i++) {
|
|
4446
|
+
const s2 = cadence2[i];
|
|
4447
|
+
if (elapsedMs >= s2.atMs) hit = { step: s2, index: i };
|
|
4448
|
+
}
|
|
4449
|
+
return hit;
|
|
4450
|
+
}
|
|
4443
4451
|
function mergeConfig(cfg) {
|
|
4444
4452
|
return {
|
|
4445
4453
|
version: cfg?.version ?? "code-default-v1",
|
|
@@ -16307,7 +16315,11 @@ function previewIntervention(model, plan, config2) {
|
|
|
16307
16315
|
if (lifecycleOf(fork, a.id) !== "active") continue;
|
|
16308
16316
|
for (const e of a.inputs) {
|
|
16309
16317
|
if (lifecycleOf(fork, e.to) === "sealed:cancelled") {
|
|
16310
|
-
|
|
16318
|
+
const consumerWs = fork.artifacts.get(a.id)?.workspace;
|
|
16319
|
+
const cancelledWs = fork.artifacts.get(e.to)?.workspace;
|
|
16320
|
+
violations.push(
|
|
16321
|
+
`\u4F9D\u8D56\u5E9F\u5F03\u8282\u70B9: ${a.id}${consumerWs ? `\uFF08${consumerWs}\uFF09` : ""} \u2192 ${e.to}${cancelledWs ? `\uFF08${cancelledWs}\uFF09` : ""}\uFF08cancelled \u4E0D\u53EF\u88AB\u4F9D\u8D56\uFF09`
|
|
16322
|
+
);
|
|
16311
16323
|
}
|
|
16312
16324
|
}
|
|
16313
16325
|
}
|
|
@@ -16581,26 +16593,26 @@ var init_kernel_bridge = __esm({
|
|
|
16581
16593
|
convergenceUnified: this.model.convergenceUnified,
|
|
16582
16594
|
disabledActors: this.model.disabledActors
|
|
16583
16595
|
});
|
|
16584
|
-
for (const [draftId,
|
|
16585
|
-
const anchorFromPlan =
|
|
16586
|
-
const anchorId =
|
|
16587
|
-
const cardWs =
|
|
16596
|
+
for (const [draftId, card2] of this.draftCards) {
|
|
16597
|
+
const anchorFromPlan = card2.plan?.ops.find((o) => "artifactId" in o && o.artifactId) ?? card2.plan?.ops.find((o) => "id" in o && o.id);
|
|
16598
|
+
const anchorId = card2.anchor ?? (anchorFromPlan ? anchorFromPlan.artifactId ?? anchorFromPlan.id : void 0) ?? "";
|
|
16599
|
+
const cardWs = card2.plan?.workspace ?? this.model.artifacts.get(anchorId)?.workspace ?? card2.anchor ?? "";
|
|
16588
16600
|
fresh.pendingReviews.set(draftId, {
|
|
16589
16601
|
draftId,
|
|
16590
|
-
plan:
|
|
16591
|
-
changeClass:
|
|
16592
|
-
nonMonotonicOps:
|
|
16593
|
-
proposedBy:
|
|
16594
|
-
origin:
|
|
16602
|
+
plan: card2.plan ?? { workspace: cardWs, reason: "", ops: [] },
|
|
16603
|
+
changeClass: card2.changeClass ?? "B",
|
|
16604
|
+
nonMonotonicOps: card2.nonMonotonicOps ?? [],
|
|
16605
|
+
proposedBy: card2.proposedBy,
|
|
16606
|
+
origin: card2.origin ?? null,
|
|
16595
16607
|
workspace: cardWs,
|
|
16596
16608
|
advisory: [],
|
|
16597
16609
|
downstreamClosure: [],
|
|
16598
16610
|
at: "",
|
|
16599
16611
|
// ★ anchor 也兜底到 plan ops 的产物 id——inbox change-confirm 用 r.anchor 找「anchor owner 的
|
|
16600
16612
|
// 人类上级」(leadOf(r.anchor));graph-edit 卡之前恒空、boss 收不到卡(collab-inbox-audit 实测)。
|
|
16601
|
-
anchor: anchorId ||
|
|
16602
|
-
kind:
|
|
16603
|
-
...
|
|
16613
|
+
anchor: anchorId || card2.anchor || "",
|
|
16614
|
+
kind: card2.kind,
|
|
16615
|
+
...card2.command ? { command: { command: card2.command, args: card2.commandArgs ?? {}, effectLabel: card2.effectLabel ?? "" } } : {}
|
|
16604
16616
|
});
|
|
16605
16617
|
}
|
|
16606
16618
|
Object.assign(this.model, fresh);
|
|
@@ -16698,8 +16710,8 @@ var init_kernel_bridge = __esm({
|
|
|
16698
16710
|
typeName: a.type
|
|
16699
16711
|
};
|
|
16700
16712
|
}
|
|
16701
|
-
cancelCascadeEdges(
|
|
16702
|
-
return
|
|
16713
|
+
cancelCascadeEdges(id) {
|
|
16714
|
+
return edgesTouching(this.model, id).map((e) => ({ from: e.artifactId, to: e.to }));
|
|
16703
16715
|
}
|
|
16704
16716
|
/* ═══════════════════════ 写方法 ═══════════════════════ */
|
|
16705
16717
|
// ── 建节点 ──
|
|
@@ -17435,6 +17447,13 @@ var init_kernel_bridge = __esm({
|
|
|
17435
17447
|
}
|
|
17436
17448
|
async seal(args) {
|
|
17437
17449
|
const wid = this.wo(args.artifactId);
|
|
17450
|
+
if (args.reason === "cancelled") {
|
|
17451
|
+
const preserve = args.preserveEdgesAmong;
|
|
17452
|
+
for (const e of edgesTouching(this.model, args.artifactId)) {
|
|
17453
|
+
if (preserve && preserve.has(e.artifactId) && preserve.has(e.to)) continue;
|
|
17454
|
+
await this.unlinkInput({ artifactId: e.artifactId, to: e.to, actor: args.actor });
|
|
17455
|
+
}
|
|
17456
|
+
}
|
|
17438
17457
|
await this.commit({
|
|
17439
17458
|
companyId: "",
|
|
17440
17459
|
workorderId: wid,
|
|
@@ -17630,10 +17649,10 @@ var init_kernel_bridge = __esm({
|
|
|
17630
17649
|
async proposeCommandAuthorization(args) {
|
|
17631
17650
|
const originNorm = args.origin ?? null;
|
|
17632
17651
|
const argsJson = JSON.stringify(args.args ?? {});
|
|
17633
|
-
for (const [id,
|
|
17634
|
-
if (
|
|
17635
|
-
if ((
|
|
17636
|
-
if (JSON.stringify(
|
|
17652
|
+
for (const [id, card2] of this.draftCards) {
|
|
17653
|
+
if (card2.kind !== "command" || card2.command !== args.command) continue;
|
|
17654
|
+
if ((card2.origin ?? null) !== originNorm) continue;
|
|
17655
|
+
if (JSON.stringify(card2.commandArgs ?? {}) !== argsJson) continue;
|
|
17637
17656
|
await this.refreshModel();
|
|
17638
17657
|
return { draftId: id };
|
|
17639
17658
|
}
|
|
@@ -17651,23 +17670,23 @@ var init_kernel_bridge = __esm({
|
|
|
17651
17670
|
return { draftId };
|
|
17652
17671
|
}
|
|
17653
17672
|
async applyAuthorizedCommand(args) {
|
|
17654
|
-
const
|
|
17655
|
-
if (!
|
|
17673
|
+
const card2 = this.draftCards.get(args.draftId);
|
|
17674
|
+
if (!card2 || card2.kind !== "command" || !card2.command) {
|
|
17656
17675
|
throw new Error(`\u4E0D\u662F\u547D\u4EE4\u6388\u6743\u8BF7\u6C42\u6216\u5DF2\u5904\u7406\uFF1A${args.draftId}`);
|
|
17657
17676
|
}
|
|
17658
|
-
const artifactId =
|
|
17659
|
-
if (
|
|
17677
|
+
const artifactId = card2.anchor;
|
|
17678
|
+
if (card2.command === "forceConclude") {
|
|
17660
17679
|
await this.forceConclude({
|
|
17661
17680
|
artifactId,
|
|
17662
17681
|
actor: args.actor,
|
|
17663
|
-
reason: typeof
|
|
17682
|
+
reason: typeof card2.commandArgs?.["reason"] === "string" ? card2.commandArgs["reason"] : "\u7BA1\u7406\u8005\u8BF7\u6C42\u3001\u4EBA\u5DF2\u6388\u6743"
|
|
17664
17683
|
});
|
|
17665
|
-
} else if (
|
|
17666
|
-
const escalationId = typeof
|
|
17684
|
+
} else if (card2.command === "resolveEscalation") {
|
|
17685
|
+
const escalationId = typeof card2.commandArgs?.["escalationId"] === "string" ? card2.commandArgs["escalationId"] : void 0;
|
|
17667
17686
|
if (!escalationId) {
|
|
17668
17687
|
throw new Error(`resolveEscalation \u6388\u6743\u5361\u7F3A escalationId\uFF1A${args.draftId}`);
|
|
17669
17688
|
}
|
|
17670
|
-
const reason = typeof
|
|
17689
|
+
const reason = typeof card2.commandArgs?.["reason"] === "string" ? card2.commandArgs["reason"] : void 0;
|
|
17671
17690
|
await this.resolveEscalation({
|
|
17672
17691
|
artifactId,
|
|
17673
17692
|
actor: args.actor,
|
|
@@ -17675,23 +17694,39 @@ var init_kernel_bridge = __esm({
|
|
|
17675
17694
|
...reason !== void 0 ? { reason } : {}
|
|
17676
17695
|
});
|
|
17677
17696
|
} else {
|
|
17678
|
-
throw new Error(`\u547D\u4EE4\u6388\u6743\uFF1A\u6682\u4E0D\u652F\u6301\u6267\u884C ${
|
|
17697
|
+
throw new Error(`\u547D\u4EE4\u6388\u6743\uFF1A\u6682\u4E0D\u652F\u6301\u6267\u884C ${card2.command}`);
|
|
17679
17698
|
}
|
|
17680
17699
|
this.draftCards.delete(args.draftId);
|
|
17681
17700
|
await this.refreshModel();
|
|
17682
|
-
return { command:
|
|
17701
|
+
return { command: card2.command, artifactId };
|
|
17683
17702
|
}
|
|
17684
17703
|
async rejectIntervention(args) {
|
|
17685
17704
|
this.draftCards.delete(args.draftId);
|
|
17686
17705
|
await this.refreshModel();
|
|
17687
17706
|
}
|
|
17707
|
+
/**
|
|
17708
|
+
* 有效 workspace:优先 plan.workspace,缺省时从首个带 workspace 的 spawn op 兜底(与
|
|
17709
|
+
* applyIntervention 里 wid 的兜底同源,见下方 line ~1453)。
|
|
17710
|
+
* ★ 诊断 9f589b81 §② B:建单方案(buildDynamicWorkorderPlan)曾漏传顶层 plan.workspace,导致
|
|
17711
|
+
* preview 的 workspace 过滤短路、拿全公司读模型跑终态校验——别家工单里一条僵尸边就能拒掉无关建单
|
|
17712
|
+
* (事故半径=全组织)。planner 已补 plan.workspace(根治),此兜底再保一层:只要 plan 里有带
|
|
17713
|
+
* workspace 的 spawn op,就绝不静默 fallback 到全公司。两者皆缺才回退全模型(如纯 seal/unlink 单节点
|
|
17714
|
+
* 改图,此时 wo() 反查也能定位,全局校验只是更宽、不误伤建单)。
|
|
17715
|
+
*/
|
|
17716
|
+
effectiveWorkspace(plan) {
|
|
17717
|
+
if (plan.workspace) return plan.workspace;
|
|
17718
|
+
const spawn8 = plan.ops.find(
|
|
17719
|
+
(o) => o.action === "spawn" && o.workspace
|
|
17720
|
+
);
|
|
17721
|
+
return spawn8?.workspace;
|
|
17722
|
+
}
|
|
17688
17723
|
async previewIntervention(plan) {
|
|
17689
|
-
const ws = plan
|
|
17724
|
+
const ws = this.effectiveWorkspace(plan);
|
|
17690
17725
|
const scopedModel = ws ? filterReadModelByWorkspace(this.model, ws) : this.model;
|
|
17691
17726
|
return previewIntervention(scopedModel, plan, { schema: this.schema, roleIndex: this.roleIndex });
|
|
17692
17727
|
}
|
|
17693
17728
|
async applyIntervention(plan, _baseSeqs, _actor) {
|
|
17694
|
-
const ws = plan
|
|
17729
|
+
const ws = this.effectiveWorkspace(plan);
|
|
17695
17730
|
const scopedModel = ws ? filterReadModelByWorkspace(this.model, ws) : this.model;
|
|
17696
17731
|
plan = resolveInterventionRefs(scopedModel, plan, this.schema);
|
|
17697
17732
|
const preview2 = await this.previewIntervention(plan);
|
|
@@ -18237,9 +18272,9 @@ var init_crypto = __esm({
|
|
|
18237
18272
|
function buildTextCard(text, opts) {
|
|
18238
18273
|
const elements = [{ tag: "div", text: { tag: "lark_md", content: text || " " } }];
|
|
18239
18274
|
if (opts?.footer) elements.push({ tag: "note", elements: [{ tag: "lark_md", content: opts.footer }] });
|
|
18240
|
-
const
|
|
18241
|
-
if (opts?.header)
|
|
18242
|
-
return
|
|
18275
|
+
const card2 = { config: { wide_screen_mode: true, update_multi: true }, elements };
|
|
18276
|
+
if (opts?.header) card2["header"] = { title: { tag: "plain_text", content: opts.header } };
|
|
18277
|
+
return card2;
|
|
18243
18278
|
}
|
|
18244
18279
|
var BASE, FeishuApiClient;
|
|
18245
18280
|
var init_api = __esm({
|
|
@@ -18318,26 +18353,26 @@ var init_api = __esm({
|
|
|
18318
18353
|
};
|
|
18319
18354
|
}
|
|
18320
18355
|
/** 发一张 interactive 卡片,返回 message_id(后续 patch 同一条消息实现流式更新)。 */
|
|
18321
|
-
async sendCard(chatId,
|
|
18356
|
+
async sendCard(chatId, card2) {
|
|
18322
18357
|
const token = await this.tenantAccessToken();
|
|
18323
18358
|
const res = await this.fetchImpl(`${this.base}/open-apis/im/v1/messages?receive_id_type=chat_id`, {
|
|
18324
18359
|
method: "POST",
|
|
18325
18360
|
headers: { "content-type": "application/json; charset=utf-8", authorization: `Bearer ${token}` },
|
|
18326
|
-
body: JSON.stringify({ receive_id: chatId, msg_type: "interactive", content: JSON.stringify(
|
|
18361
|
+
body: JSON.stringify({ receive_id: chatId, msg_type: "interactive", content: JSON.stringify(card2) })
|
|
18327
18362
|
});
|
|
18328
18363
|
const body = await res.json();
|
|
18329
18364
|
if (body.code !== 0) throw new Error(`feishu send card failed: code=${body.code} msg=${body.msg ?? ""}`);
|
|
18330
18365
|
return { messageId: body.data?.message_id ?? "" };
|
|
18331
18366
|
}
|
|
18332
18367
|
/** 就地更新一张已发出的 interactive 卡片(流式回复靠反复 patch 同一条消息)。 */
|
|
18333
|
-
async patchCard(messageId,
|
|
18368
|
+
async patchCard(messageId, card2) {
|
|
18334
18369
|
const token = await this.tenantAccessToken();
|
|
18335
18370
|
const res = await this.fetchImpl(
|
|
18336
18371
|
`${this.base}/open-apis/im/v1/messages/${encodeURIComponent(messageId)}`,
|
|
18337
18372
|
{
|
|
18338
18373
|
method: "PATCH",
|
|
18339
18374
|
headers: { "content-type": "application/json; charset=utf-8", authorization: `Bearer ${token}` },
|
|
18340
|
-
body: JSON.stringify({ content: JSON.stringify(
|
|
18375
|
+
body: JSON.stringify({ content: JSON.stringify(card2) })
|
|
18341
18376
|
}
|
|
18342
18377
|
);
|
|
18343
18378
|
const body = await res.json();
|
|
@@ -18780,11 +18815,11 @@ var init_service = __esm({
|
|
|
18780
18815
|
this.dirty = false;
|
|
18781
18816
|
const snapshot = this.buf;
|
|
18782
18817
|
try {
|
|
18783
|
-
const
|
|
18818
|
+
const card2 = buildTextCard(snapshot, { footer: "\u25CF \u751F\u6210\u4E2D\u2026" });
|
|
18784
18819
|
if (!this.messageId) {
|
|
18785
|
-
this.messageId = (await this.client.sendCard(this.chatId,
|
|
18820
|
+
this.messageId = (await this.client.sendCard(this.chatId, card2)).messageId;
|
|
18786
18821
|
} else {
|
|
18787
|
-
await this.client.patchCard(this.messageId,
|
|
18822
|
+
await this.client.patchCard(this.messageId, card2);
|
|
18788
18823
|
}
|
|
18789
18824
|
} catch (e) {
|
|
18790
18825
|
this.log(`feishu card stream tick failed: ${errMsg(e)}`);
|
|
@@ -18798,10 +18833,10 @@ var init_service = __esm({
|
|
|
18798
18833
|
clearInterval(this.timer);
|
|
18799
18834
|
this.timer = null;
|
|
18800
18835
|
}
|
|
18801
|
-
const
|
|
18836
|
+
const card2 = buildTextCard(this.buf || "\uFF08\u65E0\u8F93\u51FA\uFF09");
|
|
18802
18837
|
try {
|
|
18803
|
-
if (!this.messageId) await this.client.sendCard(this.chatId,
|
|
18804
|
-
else await this.client.patchCard(this.messageId,
|
|
18838
|
+
if (!this.messageId) await this.client.sendCard(this.chatId, card2);
|
|
18839
|
+
else await this.client.patchCard(this.messageId, card2);
|
|
18805
18840
|
} catch (e) {
|
|
18806
18841
|
this.log(`feishu card finalize failed: ${errMsg(e)}`);
|
|
18807
18842
|
}
|
|
@@ -18812,10 +18847,10 @@ var init_service = __esm({
|
|
|
18812
18847
|
clearInterval(this.timer);
|
|
18813
18848
|
this.timer = null;
|
|
18814
18849
|
}
|
|
18815
|
-
const
|
|
18850
|
+
const card2 = buildTextCard(`${this.buf ? this.buf + "\n\n" : ""}\u26A0\uFE0F ${message}`);
|
|
18816
18851
|
try {
|
|
18817
|
-
if (!this.messageId) await this.client.sendCard(this.chatId,
|
|
18818
|
-
else await this.client.patchCard(this.messageId,
|
|
18852
|
+
if (!this.messageId) await this.client.sendCard(this.chatId, card2);
|
|
18853
|
+
else await this.client.patchCard(this.messageId, card2);
|
|
18819
18854
|
} catch (e) {
|
|
18820
18855
|
this.log(`feishu card error-finalize failed: ${errMsg(e)}`);
|
|
18821
18856
|
}
|
|
@@ -127601,14 +127636,14 @@ var require_lib4 = __commonJS({
|
|
|
127601
127636
|
});
|
|
127602
127637
|
}
|
|
127603
127638
|
};
|
|
127604
|
-
function appendErrorFooter(
|
|
127605
|
-
const cardObj =
|
|
127639
|
+
function appendErrorFooter(card2) {
|
|
127640
|
+
const cardObj = card2;
|
|
127606
127641
|
const elements = Array.isArray(cardObj === null || cardObj === void 0 ? void 0 : cardObj.elements) ? [...cardObj.elements] : [];
|
|
127607
127642
|
elements.push({
|
|
127608
127643
|
tag: "note",
|
|
127609
127644
|
elements: [{ tag: "plain_text", content: "\u26A0\uFE0F \u751F\u6210\u4E2D\u65AD" }]
|
|
127610
127645
|
});
|
|
127611
|
-
return Object.assign(Object.assign({},
|
|
127646
|
+
return Object.assign(Object.assign({}, card2), { elements });
|
|
127612
127647
|
}
|
|
127613
127648
|
var CardStreamController = class {
|
|
127614
127649
|
constructor(sender, to, idType, opts, initial) {
|
|
@@ -128377,13 +128412,13 @@ ${block}
|
|
|
128377
128412
|
});
|
|
128378
128413
|
}
|
|
128379
128414
|
// ─── card ─────────────────────────────────────────────
|
|
128380
|
-
sendCard(to, idType,
|
|
128415
|
+
sendCard(to, idType, card2, opts) {
|
|
128381
128416
|
return __awaiter(this, void 0, void 0, function* () {
|
|
128382
128417
|
const id = yield this.sendOneWithFallback({
|
|
128383
128418
|
to,
|
|
128384
128419
|
idType,
|
|
128385
128420
|
msgType: "interactive",
|
|
128386
|
-
content:
|
|
128421
|
+
content: card2,
|
|
128387
128422
|
replyTo: opts.replyTo,
|
|
128388
128423
|
replyInThread: opts.replyInThread
|
|
128389
128424
|
});
|
|
@@ -128495,11 +128530,11 @@ ${block}
|
|
|
128495
128530
|
* and the public `channel.updateCard()` low-level API. Not suitable for
|
|
128496
128531
|
* text streaming (use native cardkit streaming below for that).
|
|
128497
128532
|
*/
|
|
128498
|
-
patchCard(messageId,
|
|
128533
|
+
patchCard(messageId, card2) {
|
|
128499
128534
|
return __awaiter(this, void 0, void 0, function* () {
|
|
128500
128535
|
yield this.client.im.v1.message.patch({
|
|
128501
128536
|
path: { message_id: messageId },
|
|
128502
|
-
data: { content: JSON.stringify(
|
|
128537
|
+
data: { content: JSON.stringify(card2) }
|
|
128503
128538
|
});
|
|
128504
128539
|
});
|
|
128505
128540
|
}
|
|
@@ -130050,9 +130085,9 @@ ${lines.join("\n")}
|
|
|
130050
130085
|
});
|
|
130051
130086
|
}
|
|
130052
130087
|
// ─── low-level ─────────────────────────────────────────
|
|
130053
|
-
updateCard(messageId,
|
|
130088
|
+
updateCard(messageId, card2) {
|
|
130054
130089
|
return __awaiter(this, void 0, void 0, function* () {
|
|
130055
|
-
yield this.sender.patchCard(messageId,
|
|
130090
|
+
yield this.sender.patchCard(messageId, card2);
|
|
130056
130091
|
});
|
|
130057
130092
|
}
|
|
130058
130093
|
/**
|
|
@@ -149291,7 +149326,7 @@ async function buildDynamicWorkorderPlan(input) {
|
|
|
149291
149326
|
}
|
|
149292
149327
|
}
|
|
149293
149328
|
const plan = withClosureReport(
|
|
149294
|
-
{ reason: `\u52A8\u6001\u89C4\u5212\u5DE5\u5355\uFF1A${displayTitle}`, ops },
|
|
149329
|
+
{ reason: `\u52A8\u6001\u89C4\u5212\u5DE5\u5355\uFF1A${displayTitle}`, ops, workspace: input.workspace },
|
|
149295
149330
|
{ draftedBy: input.actor }
|
|
149296
149331
|
);
|
|
149297
149332
|
const closureOp = plan.ops.find(
|
|
@@ -179739,6 +179774,126 @@ var init_inbox_chat = __esm({
|
|
|
179739
179774
|
}
|
|
179740
179775
|
});
|
|
179741
179776
|
|
|
179777
|
+
// ../server/src/domains/collab/waiting-inbox.ts
|
|
179778
|
+
function card(kind, row, severity, since, summary) {
|
|
179779
|
+
return {
|
|
179780
|
+
kind,
|
|
179781
|
+
...row.artifactId ? { artifactId: row.artifactId } : {},
|
|
179782
|
+
workspace: row.workorderId,
|
|
179783
|
+
...row.title ? { title: row.title } : {},
|
|
179784
|
+
since,
|
|
179785
|
+
actionRequired: true,
|
|
179786
|
+
summary,
|
|
179787
|
+
// info 档只提示不算 overdue;warn/urgent 置 overdue(前端红点/排序)。
|
|
179788
|
+
...severity === "info" ? {} : { overdue: true }
|
|
179789
|
+
};
|
|
179790
|
+
}
|
|
179791
|
+
function buildWaitingInbox(reviews, works, policy, nowIso, me) {
|
|
179792
|
+
const now = Date.parse(nowIso);
|
|
179793
|
+
const out = [];
|
|
179794
|
+
const consider = (rows, scenario, kind) => {
|
|
179795
|
+
for (const r of rows) {
|
|
179796
|
+
if (r.actorId !== me) continue;
|
|
179797
|
+
const start = r.startedAt || r.createdAt;
|
|
179798
|
+
if (r.status === "dead") {
|
|
179799
|
+
out.push(card(kind, r, "urgent", start, `\u4F60\u7684${KIND_LABEL[kind]}\u5DF2\u4E2D\u6B62\uFF0C\u9700\u8981\u4F60\u4ECB\u5165\u91CD\u5F00`));
|
|
179800
|
+
continue;
|
|
179801
|
+
}
|
|
179802
|
+
if (r.status !== "running") continue;
|
|
179803
|
+
if (classify(me) !== "human") continue;
|
|
179804
|
+
const action = policy.resolve({ executor: "human", scenario }).timeoutAction;
|
|
179805
|
+
if (action.kind !== "remind") continue;
|
|
179806
|
+
const elapsed = Number.isFinite(now) ? now - Date.parse(start) : NaN;
|
|
179807
|
+
if (!Number.isFinite(elapsed)) continue;
|
|
179808
|
+
const picked = pickReminderStep(action.cadence, elapsed);
|
|
179809
|
+
if (!picked) continue;
|
|
179810
|
+
const mins = Math.round(elapsed / 6e4);
|
|
179811
|
+
out.push(card(kind, r, picked.step.severity, start, `\u6709\u4E00\u9879${KIND_LABEL[kind]}\u5728\u7B49\u4F60\uFF0C\u5DF2 ${mins} \u5206\u949F\u672A\u52A8`));
|
|
179812
|
+
}
|
|
179813
|
+
};
|
|
179814
|
+
consider(reviews, "review", "review-waiting");
|
|
179815
|
+
consider(works, "work", "work-waiting");
|
|
179816
|
+
return out;
|
|
179817
|
+
}
|
|
179818
|
+
function waitingWorkspacesFor(model, me) {
|
|
179819
|
+
const out = /* @__PURE__ */ new Set();
|
|
179820
|
+
for (const a of model.artifacts.values()) {
|
|
179821
|
+
if (lifecycleOf(model, a.id) !== "active") continue;
|
|
179822
|
+
if (a.owner === me) {
|
|
179823
|
+
out.add(a.workspace);
|
|
179824
|
+
continue;
|
|
179825
|
+
}
|
|
179826
|
+
if (pendingConcludeAttempt(model, a.id)?.gate?.eligible.includes(me)) out.add(a.workspace);
|
|
179827
|
+
}
|
|
179828
|
+
return out;
|
|
179829
|
+
}
|
|
179830
|
+
function collectWaitingRows(snapshots2, me) {
|
|
179831
|
+
const reviews = [];
|
|
179832
|
+
const works = [];
|
|
179833
|
+
const latestBy = (map, row) => {
|
|
179834
|
+
const prev = map.get(row.nodeId);
|
|
179835
|
+
if (!prev || row.createdAt > prev.createdAt) map.set(row.nodeId, row);
|
|
179836
|
+
};
|
|
179837
|
+
for (const snap of snapshots2) {
|
|
179838
|
+
const nodeTitle = new Map(snap.nodes.map((n) => [n.id, n.title]));
|
|
179839
|
+
const cancelled = new Set(snap.nodes.filter((n) => n.cancelledAt).map((n) => n.id));
|
|
179840
|
+
const outputCountOf = (workId) => snap.artifacts.reduce((n, a) => a.workId === workId ? n + 1 : n, 0);
|
|
179841
|
+
const latestReview = /* @__PURE__ */ new Map();
|
|
179842
|
+
for (const r of snap.reviews) {
|
|
179843
|
+
if (r.reviewerActorId !== me || cancelled.has(r.nodeId)) continue;
|
|
179844
|
+
latestBy(latestReview, r);
|
|
179845
|
+
}
|
|
179846
|
+
for (const r of latestReview.values()) {
|
|
179847
|
+
const st = reviewState(r);
|
|
179848
|
+
if (st !== "running" && st !== "dead") continue;
|
|
179849
|
+
reviews.push({
|
|
179850
|
+
id: r.id,
|
|
179851
|
+
workorderId: snap.workorder.id,
|
|
179852
|
+
artifactId: r.nodeId,
|
|
179853
|
+
actorId: r.reviewerActorId,
|
|
179854
|
+
...nodeTitle.get(r.nodeId) ? { title: nodeTitle.get(r.nodeId) } : {},
|
|
179855
|
+
createdAt: r.createdAt,
|
|
179856
|
+
startedAt: r.startedAt,
|
|
179857
|
+
status: st
|
|
179858
|
+
});
|
|
179859
|
+
}
|
|
179860
|
+
const latestMain = /* @__PURE__ */ new Map();
|
|
179861
|
+
const latestReply = /* @__PURE__ */ new Map();
|
|
179862
|
+
for (const w2 of snap.works) {
|
|
179863
|
+
if (w2.assigneeActorId !== me || cancelled.has(w2.nodeId)) continue;
|
|
179864
|
+
latestBy(w2.replyToIssueId ? latestReply : latestMain, w2);
|
|
179865
|
+
}
|
|
179866
|
+
for (const w2 of [...latestMain.values(), ...latestReply.values()]) {
|
|
179867
|
+
const st = workState(w2, hasOutput(w2, outputCountOf(w2.id)));
|
|
179868
|
+
if (st !== "running" && st !== "dead") continue;
|
|
179869
|
+
works.push({
|
|
179870
|
+
id: w2.id,
|
|
179871
|
+
workorderId: snap.workorder.id,
|
|
179872
|
+
artifactId: w2.nodeId,
|
|
179873
|
+
actorId: w2.assigneeActorId,
|
|
179874
|
+
...nodeTitle.get(w2.nodeId) ? { title: nodeTitle.get(w2.nodeId) } : {},
|
|
179875
|
+
createdAt: w2.createdAt,
|
|
179876
|
+
startedAt: w2.startedAt,
|
|
179877
|
+
status: st
|
|
179878
|
+
});
|
|
179879
|
+
}
|
|
179880
|
+
}
|
|
179881
|
+
return { reviews, works };
|
|
179882
|
+
}
|
|
179883
|
+
var KIND_LABEL;
|
|
179884
|
+
var init_waiting_inbox = __esm({
|
|
179885
|
+
"../server/src/domains/collab/waiting-inbox.ts"() {
|
|
179886
|
+
"use strict";
|
|
179887
|
+
init_src4();
|
|
179888
|
+
init_src3();
|
|
179889
|
+
init_src2();
|
|
179890
|
+
KIND_LABEL = {
|
|
179891
|
+
"review-waiting": "\u8BC4\u5BA1",
|
|
179892
|
+
"work-waiting": "\u5904\u7406"
|
|
179893
|
+
};
|
|
179894
|
+
}
|
|
179895
|
+
});
|
|
179896
|
+
|
|
179742
179897
|
// ../server/src/domains/collab/audit.ts
|
|
179743
179898
|
function toAuditEntry(op) {
|
|
179744
179899
|
return {
|
|
@@ -179747,7 +179902,7 @@ function toAuditEntry(op) {
|
|
|
179747
179902
|
actor: op.actor,
|
|
179748
179903
|
op: op.kind,
|
|
179749
179904
|
artifactId: op.artifactId,
|
|
179750
|
-
summary: `${
|
|
179905
|
+
summary: `${KIND_LABEL2[op.kind] ?? op.kind} \xB7 ${op.artifactId}`
|
|
179751
179906
|
};
|
|
179752
179907
|
}
|
|
179753
179908
|
function eventToAuditEntry(rec) {
|
|
@@ -179759,7 +179914,7 @@ function eventToAuditEntry(rec) {
|
|
|
179759
179914
|
actor: rec.actorId,
|
|
179760
179915
|
op: ev.kind,
|
|
179761
179916
|
artifactId,
|
|
179762
|
-
summary: `${
|
|
179917
|
+
summary: `${KIND_LABEL2[ev.kind] ?? ev.kind}${artifactId ? ` \xB7 ${artifactId}` : ""}`
|
|
179763
179918
|
};
|
|
179764
179919
|
}
|
|
179765
179920
|
function enrichAudit(entry, model, titleOf) {
|
|
@@ -179835,12 +179990,12 @@ async function buildAudit(source, q = {}, model) {
|
|
|
179835
179990
|
}
|
|
179836
179991
|
return { items, cursor: truncated ? lastCursor : null };
|
|
179837
179992
|
}
|
|
179838
|
-
var
|
|
179993
|
+
var KIND_LABEL2;
|
|
179839
179994
|
var init_audit = __esm({
|
|
179840
179995
|
"../server/src/domains/collab/audit.ts"() {
|
|
179841
179996
|
"use strict";
|
|
179842
179997
|
init_node_state();
|
|
179843
|
-
|
|
179998
|
+
KIND_LABEL2 = {
|
|
179844
179999
|
// 新引擎事件 kind
|
|
179845
180000
|
"plan.update_spec": "\u6539\u4EFB\u52A1",
|
|
179846
180001
|
"plan.add_node": "\u52A0\u8282\u70B9",
|
|
@@ -180947,7 +181102,7 @@ function collabDomain(opts) {
|
|
|
180947
181102
|
return { status: 200, body: { dispatched: !already } };
|
|
180948
181103
|
});
|
|
180949
181104
|
router.get("/api/inbox", async (req) => {
|
|
180950
|
-
const { kernel, registry: registry2 } = await resolveCtx(req.auth.companyId);
|
|
181105
|
+
const { kernel, registry: registry2, engineStore } = await resolveCtx(req.auth.companyId);
|
|
180951
181106
|
const me = req.auth.actor;
|
|
180952
181107
|
const [leadOf, resolveActor, markers] = await Promise.all([
|
|
180953
181108
|
buildLeadResolver(registry2),
|
|
@@ -180960,7 +181115,18 @@ function collabDomain(opts) {
|
|
|
180960
181115
|
const inboxSlaMs = opts.sla?.humanMs ?? 24 * 36e5;
|
|
180961
181116
|
const kernelItems = buildInbox(kernel.model, me, leadOf, resolveActor, markers, inboxSlaMs, (/* @__PURE__ */ new Date()).toISOString());
|
|
180962
181117
|
const chatItems = opts.chatSession && opts.readMarkers ? await buildChatInbox(opts.chatSession, markers, me, resolveActor) : [];
|
|
180963
|
-
|
|
181118
|
+
let waitingItems = [];
|
|
181119
|
+
if (engineStore) {
|
|
181120
|
+
const snaps = (await Promise.all(
|
|
181121
|
+
[...waitingWorkspacesFor(kernel.model, me)].map(
|
|
181122
|
+
(wid) => engineStore.transaction((tx) => tx.loadWorkorder(wid))
|
|
181123
|
+
)
|
|
181124
|
+
)).filter((s2) => s2 !== null);
|
|
181125
|
+
const { reviews, works } = collectWaitingRows(snaps, me);
|
|
181126
|
+
const policy = opts.policy?.() ?? CODE_DEFAULT_POLICY;
|
|
181127
|
+
waitingItems = buildWaitingInbox(reviews, works, policy, (/* @__PURE__ */ new Date()).toISOString(), me);
|
|
181128
|
+
}
|
|
181129
|
+
return { status: 200, body: { items: mergeInbox(kernelItems, [...chatItems, ...waitingItems]) } };
|
|
180964
181130
|
});
|
|
180965
181131
|
const companyOf = (req) => req.auth.companyId ?? "company:default";
|
|
180966
181132
|
const noTagStore = { status: 501, body: { error: { code: "not_implemented", message: "\u672C\u90E8\u7F72\u672A\u542F\u7528\u5DE5\u5355\u6807\u7B7E" } } };
|
|
@@ -181200,6 +181366,8 @@ var init_collab = __esm({
|
|
|
181200
181366
|
init_workorder_detail();
|
|
181201
181367
|
init_inbox();
|
|
181202
181368
|
init_inbox_chat();
|
|
181369
|
+
init_waiting_inbox();
|
|
181370
|
+
init_src2();
|
|
181203
181371
|
init_audit();
|
|
181204
181372
|
init_dashboard();
|
|
181205
181373
|
init_workorder_metrics();
|
|
@@ -194540,6 +194708,8 @@ async function startServe(opts) {
|
|
|
194540
194708
|
// 工单标签词表(组织级受控、旁账,与 playbook-overrides 同款侧存)。
|
|
194541
194709
|
tags: workorderTagStore,
|
|
194542
194710
|
...opts.sla ? { sla: opts.sla } : {},
|
|
194711
|
+
// ADR 0147:waiting 投影的 human 阶梯从策略中心取;getter 保证随 SIGHUP/reload 热载而变。
|
|
194712
|
+
policy: () => activeTimeoutPolicy,
|
|
194543
194713
|
resolveEngine: (cid) => getEngine(cid ?? defaultCompanyId)
|
|
194544
194714
|
}),
|
|
194545
194715
|
trace.register,
|
|
@@ -201889,7 +202059,7 @@ function syncRuntimeAssets(candidateRoots, binDir) {
|
|
|
201889
202059
|
}
|
|
201890
202060
|
|
|
201891
202061
|
// src/index.ts
|
|
201892
|
-
var PKG_VERSION = true ? "0.1.
|
|
202062
|
+
var PKG_VERSION = true ? "0.1.105" : "dev";
|
|
201893
202063
|
var OASIS_DIR = path26.join(os10.homedir(), ".oasis");
|
|
201894
202064
|
var CONFIG_FILE = path26.join(OASIS_DIR, "node-config.json");
|
|
201895
202065
|
var PID_FILE = path26.join(OASIS_DIR, "node.pid");
|
|
@@ -201992,8 +202162,10 @@ function setupAutostart() {
|
|
|
201992
202162
|
].join("\n"));
|
|
201993
202163
|
try {
|
|
201994
202164
|
(0, import_node_child_process17.execSync)("systemctl --user daemon-reload && systemctl --user enable --now oasis-node", { stdio: "ignore" });
|
|
202165
|
+
return true;
|
|
201995
202166
|
} catch {
|
|
201996
202167
|
}
|
|
202168
|
+
return false;
|
|
201997
202169
|
} else if (process.platform === "darwin") {
|
|
201998
202170
|
const plist = path26.join(os10.homedir(), "Library", "LaunchAgents", "com.oasis.node.plist");
|
|
201999
202171
|
fs33.mkdirSync(path26.dirname(plist), { recursive: true });
|
|
@@ -202009,9 +202181,12 @@ function setupAutostart() {
|
|
|
202009
202181
|
</dict></plist>`);
|
|
202010
202182
|
try {
|
|
202011
202183
|
(0, import_node_child_process17.execSync)(`launchctl load "${plist}"`, { stdio: "ignore" });
|
|
202184
|
+
return true;
|
|
202012
202185
|
} catch {
|
|
202013
202186
|
}
|
|
202187
|
+
return false;
|
|
202014
202188
|
}
|
|
202189
|
+
return false;
|
|
202015
202190
|
}
|
|
202016
202191
|
function spawnDaemon() {
|
|
202017
202192
|
const log3 = fs33.openSync(LOG_FILE, "a");
|
|
@@ -202020,9 +202195,7 @@ function spawnDaemon() {
|
|
|
202020
202195
|
stdio: ["ignore", log3, log3]
|
|
202021
202196
|
});
|
|
202022
202197
|
child.unref();
|
|
202023
|
-
|
|
202024
|
-
fs33.writeFileSync(PID_FILE, String(pid));
|
|
202025
|
-
return pid;
|
|
202198
|
+
return child.pid ?? 0;
|
|
202026
202199
|
}
|
|
202027
202200
|
function stopDaemon() {
|
|
202028
202201
|
const pid = readPid();
|
|
@@ -202094,12 +202267,21 @@ void (async () => {
|
|
|
202094
202267
|
console.error("[oasis] no config \u2014 run `oasis daemon start` first");
|
|
202095
202268
|
process.exit(1);
|
|
202096
202269
|
}
|
|
202097
|
-
|
|
202098
|
-
|
|
202099
|
-
|
|
202100
|
-
|
|
202270
|
+
try {
|
|
202271
|
+
const fd = fs33.openSync(PID_FILE, "wx");
|
|
202272
|
+
fs33.writeSync(fd, String(process.pid));
|
|
202273
|
+
fs33.closeSync(fd);
|
|
202274
|
+
} catch {
|
|
202275
|
+
const alivePid = readPid();
|
|
202276
|
+
if (alivePid && alivePid !== process.pid && isRunning2(alivePid)) {
|
|
202277
|
+
console.error(`[oasis] daemon already running (PID ${alivePid}) \u2014 exiting duplicate`);
|
|
202278
|
+
process.exit(0);
|
|
202279
|
+
}
|
|
202280
|
+
try {
|
|
202281
|
+
fs33.writeFileSync(PID_FILE, String(process.pid));
|
|
202282
|
+
} catch {
|
|
202283
|
+
}
|
|
202101
202284
|
}
|
|
202102
|
-
fs33.writeFileSync(PID_FILE, String(process.pid));
|
|
202103
202285
|
const cleanup = () => {
|
|
202104
202286
|
try {
|
|
202105
202287
|
fs33.unlinkSync(PID_FILE);
|
|
@@ -202193,9 +202375,13 @@ void (async () => {
|
|
|
202193
202375
|
saveConfig({ serverUrl, token, nodeId, ...name ? { name } : {}, reportRuntimesOnNextStart: true });
|
|
202194
202376
|
installBinary();
|
|
202195
202377
|
stopDaemon();
|
|
202196
|
-
setupAutostart();
|
|
202197
|
-
|
|
202198
|
-
|
|
202378
|
+
const tookOver = setupAutostart();
|
|
202379
|
+
if (!tookOver) {
|
|
202380
|
+
const pid = spawnDaemon();
|
|
202381
|
+
console.log(`\u2713 daemon started (PID ${pid})${nameChanged ? ` [name updated: ${prev.name} \u2192 ${name}]` : ""}`);
|
|
202382
|
+
} else {
|
|
202383
|
+
console.log(`\u2713 daemon started via systemd (oasis-node.service)${nameChanged ? ` [name updated: ${prev.name} \u2192 ${name}]` : ""}`);
|
|
202384
|
+
}
|
|
202199
202385
|
console.log(` logs: tail -f ${LOG_FILE}`);
|
|
202200
202386
|
if (!process.env["PATH"]?.includes(path26.dirname(LOCAL_BIN)))
|
|
202201
202387
|
console.log(` add to PATH: echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc && source ~/.bashrc`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oasis_test",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.105",
|
|
4
4
|
"description": "Oasis node daemon + CLI — background daemon, auto-start, full server CLI",
|
|
5
5
|
"bin": {
|
|
6
6
|
"oasis": "./dist/index.js"
|
|
@@ -26,6 +26,6 @@
|
|
|
26
26
|
"node": ">=20"
|
|
27
27
|
},
|
|
28
28
|
"oasisRelease": {
|
|
29
|
-
"sourceHead": "
|
|
29
|
+
"sourceHead": "60d88fd92311e481e7bbfe922d75db13a3483643"
|
|
30
30
|
}
|
|
31
31
|
}
|