oasis_test_v2 2.2.17 → 2.2.19
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 +497 -63
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -5737,6 +5737,26 @@ CREATE TABLE IF NOT EXISTS ${q2}.event_handler_log (
|
|
|
5737
5737
|
PRIMARY KEY (event_seq, handler_name)
|
|
5738
5738
|
);
|
|
5739
5739
|
|
|
5740
|
+
-- \u5F85\u4EBA\u786E\u8BA4\u7684 intervention \u8349\u6848\u5361\uFF08\u547D\u4EE4\u6388\u6743\u5361 / \u6539\u56FE\u5361\uFF09\u3002
|
|
5741
|
+
--
|
|
5742
|
+
-- \u4E3A\u4EC0\u4E48\u8981\u843D\u5E93\uFF082026-09-11 \u5B9E\u5F55\uFF09\uFF1A\u65E7\u5F15\u64CE\u628A\u8D77\u8349\u8BB0\u6210\u4E00\u6761 propose_intervention op \u8FDB oplog\uFF0C
|
|
5743
|
+
-- \u91CD\u542F replay \u5C31 fold \u56DE pendingReviews\uFF1B\u51B3\u7B56 0130 \u9000\u5F79 oplog \u65F6\u8FD9\u4E00\u6BB5\u53EA\u642C\u4E86\u5185\u5B58 Map\uFF0C
|
|
5744
|
+
-- \u6CE8\u91CA\u8FD8\u5199\u7740\u300C\u77ED\u751F\u547D\u5468\u671F\u3001\u91CD\u542F\u4E22\u53EF\u63A5\u53D7\u300D\u3002\u4F46\u8FD9\u5F20\u5361\u7684\u8BED\u4E49\u662F**\u7B49\u4E00\u4E2A\u771F\u4EBA\u6765\u70B9**\uFF0C\u5BFF\u547D\u7531\u4EBA\u51B3\u5B9A\uFF0C
|
|
5745
|
+
-- \u4E0D\u7531\u8FDB\u7A0B\u51B3\u5B9A\u3002v2 \u4E0A 31 \u5C0F\u65F6\u91CD\u542F\u4E86 158 \u6B21\uFF08\u22485 \u6B21/\u5C0F\u65F6\uFF09\uFF0C\u5B9E\u6D4B\u4E00\u5F20\u5361\u8D77\u8349 24 \u79D2\u540E\u5C31\u88AB\u91CD\u542F\u62B9\u6389\uFF0C
|
|
5746
|
+
-- \u534F\u8C03\u8005\u5374\u4ECD\u5728\u5BF9\u8BDD\u91CC\u8BA9\u4EBA\u300C\u53BB\u6536\u4EF6\u7BB1\u627E\u90A3\u5F20\u5361\u300D\u2014\u2014\u804A\u5929\u9875\u548C\u6536\u4EF6\u7BB1\u8BFB\u7684\u662F\u540C\u4E00\u4EFD\u5185\u5B58\uFF0C\u4E00\u8D77\u53D8\u7A7A\u3002
|
|
5747
|
+
--
|
|
5748
|
+
-- card \u5217\u7528 jsonb \u6574\u5B58\uFF1A\u5361\u4F53\u7684\u5F62\u72B6\u5F52 core\uFF08KernelBridge.draftCards\uFF09\u7BA1\uFF0C\u5F15\u64CE\u53EA\u8D1F\u8D23\u5B58\u53D6\uFF0C
|
|
5749
|
+
-- \u4E0D\u8BA4\u91CC\u9762\u7684\u4E1A\u52A1\u5B57\u6BB5\u2014\u2014\u5426\u5219\u6BCF\u52A0\u4E00\u4E2A\u5B57\u6BB5\u90FD\u8981\u52A8 DDL\uFF0C\u800C\u5F15\u64CE\u4E0D\u8BE5\u77E5\u9053 InterventionPlan \u662F\u4EC0\u4E48\u3002
|
|
5750
|
+
-- \u7D22\u5F15\u4F4D\u53EA\u7559\u6392\u969C\u8981\u7528\u7684\u90A3\u4E24\u5217\u3002\u4E0D\u52A0 workorder_id \u5916\u952E\uFF1A\u5361\u53EF\u4EE5\u6307\u5411\u4E00\u4E2A\u521A\u88AB\u4F5C\u5E9F\u7684\u8282\u70B9\uFF0C
|
|
5751
|
+
-- \u5916\u952E\u4F1A\u8BA9\u300C\u8D77\u8349\u300D\u8FD9\u4E00\u6B65\u76F4\u63A5\u5931\u8D25\uFF0C\u6BD4\u7559\u4E00\u6761\u5B64\u513F\u5361\u7CDF\u5F97\u591A\u3002
|
|
5752
|
+
CREATE TABLE IF NOT EXISTS ${q2}.intervention_drafts (
|
|
5753
|
+
draft_id text PRIMARY KEY,
|
|
5754
|
+
workorder_id text,
|
|
5755
|
+
created_at timestamptz NOT NULL,
|
|
5756
|
+
card jsonb NOT NULL
|
|
5757
|
+
);
|
|
5758
|
+
CREATE INDEX IF NOT EXISTS intervention_drafts_wo_idx ON ${q2}.intervention_drafts (workorder_id);
|
|
5759
|
+
|
|
5740
5760
|
-- \u2500\u2500 \u8FC1\u79FB\uFF1A\u65E2\u6709\u90E8\u7F72\u7684\u5217\u589E\u91CF\uFF08CREATE TABLE IF NOT EXISTS \u4E0D\u52A0\u5217\uFF0C\u8FD9\u91CC\u8865\uFF09\u2500\u2500
|
|
5741
5761
|
-- \u2605 review_requirements.source \u6269\u4E3A\u56DB\u503C\uFF08+'closure'\uFF09\uFF1A\u7ED3\u6848\u4EBA\u95F8\u7531 scan \u5728\u6536\u53E3\u90A3\u4E00\u523B\u5199\u5165\uFF0C\u4E0E manual \u5206\u5BB6\u3002
|
|
5742
5762
|
-- \u5199\u6CD5\u4E0E\u4E0B\u65B9 works_lane_check \u540C\u6B3E\uFF08\u5148\u5220\u540E\u52A0\uFF0C\u6210\u5BF9\u5E42\u7B49\uFF09\u3002
|
|
@@ -11278,6 +11298,38 @@ var init_store_postgres = __esm({
|
|
|
11278
11298
|
createdAt: iso(r.createdAt)
|
|
11279
11299
|
}));
|
|
11280
11300
|
}
|
|
11301
|
+
/* ── intervention 草案卡(见 store.ts 的接口注释)。与上面两口钟同类:直连 pool 的窄读写,
|
|
11302
|
+
标识符位一律经 quoteIdent——带连字符的公司 schema 裸拼会 syntax error。 ── */
|
|
11303
|
+
async listInterventionDrafts() {
|
|
11304
|
+
const res = await this.pool.query(
|
|
11305
|
+
`SELECT draft_id AS "draftId", workorder_id AS "workorderId", created_at AS "createdAt", card
|
|
11306
|
+
FROM ${quoteIdent(this.schema)}.intervention_drafts
|
|
11307
|
+
ORDER BY created_at`
|
|
11308
|
+
);
|
|
11309
|
+
return res.rows.map((r) => ({
|
|
11310
|
+
draftId: r.draftId,
|
|
11311
|
+
workorderId: r.workorderId ?? null,
|
|
11312
|
+
createdAt: iso(r.createdAt),
|
|
11313
|
+
card: r.card
|
|
11314
|
+
}));
|
|
11315
|
+
}
|
|
11316
|
+
async saveInterventionDraft(record8) {
|
|
11317
|
+
await this.pool.query(
|
|
11318
|
+
`INSERT INTO ${quoteIdent(this.schema)}.intervention_drafts (draft_id, workorder_id, created_at, card)
|
|
11319
|
+
VALUES ($1, $2, $3::timestamptz, $4::jsonb)
|
|
11320
|
+
ON CONFLICT (draft_id) DO UPDATE
|
|
11321
|
+
SET workorder_id = EXCLUDED.workorder_id,
|
|
11322
|
+
created_at = EXCLUDED.created_at,
|
|
11323
|
+
card = EXCLUDED.card`,
|
|
11324
|
+
[record8.draftId, record8.workorderId, record8.createdAt, JSON.stringify(record8.card ?? null)]
|
|
11325
|
+
);
|
|
11326
|
+
}
|
|
11327
|
+
async deleteInterventionDraft(draftId) {
|
|
11328
|
+
await this.pool.query(
|
|
11329
|
+
`DELETE FROM ${quoteIdent(this.schema)}.intervention_drafts WHERE draft_id = $1`,
|
|
11330
|
+
[draftId]
|
|
11331
|
+
);
|
|
11332
|
+
}
|
|
11281
11333
|
};
|
|
11282
11334
|
PgTx = class {
|
|
11283
11335
|
constructor(c, s2) {
|
|
@@ -15588,7 +15640,7 @@ ${m2.spec.split("\n").map((l) => ` > ${l}`).join("\n")}`);
|
|
|
15588
15640
|
`- \u7F3A\u4E00\u4E2A**\u8FD8\u4E0D\u5B58\u5728\u7684\u524D\u7F6E** \u2192 \`oasis gap\` \u4EA4\u4E0A\u53BB\uFF0C**\u522B\u786C\u7F16**\uFF1B\u5DF2\u505A\u5B8C\u7684\u90E8\u5206\u7167\u5E38 \`propose\`\uFF0C\u4F46\u8FD9\u4E00\u8F6E \`conclude\` \u4F1A\u88AB\u62D2\uFF0C\u63D0\u4EA4\u5B8C\u5373\u6536\u5DE5\u2014\u2014\u524D\u7F6E\u5C31\u7EEA\u540E\u7CFB\u7EDF\u4F1A\u5E26\u7740\u89E3\u6CD5\u8BF4\u660E\u91CD\u65B0\u5524\u8D77\u4F60\u3002`,
|
|
15589
15641
|
`- \u5BF9**\u4E0A\u6E38**\u6709\u610F\u89C1\u2014\u2014\u6709\u7591\u95EE\u3001\u8981\u5B83\u6539\u3001\u5224\u5B83\u6CA1\u8FBE\u6807 \u2192 \`oasis annotate <\u4E0A\u6E38id> --body "<\u8BF4\u6E05\u695A>"\` \u540E**\u6536\u5DE5**\u3002\u5199\u7ED9\u4E0A\u6E38\u7684\u8BC4\u8BBA\u81EA\u52A8\u5E26\u963B\u585E\u529B\uFF1A**\u5B83\u7B54\u590D\u524D\u4E0D\u80FD\u6536\u5C3E**\uFF0C\u7B54\u590D\u540E\u7CFB\u7EDF\u91CD\u6D3E\u4F60\u3002`,
|
|
15590
15642
|
...args.part === void 0 ? [`- \u6D3B\u592A\u5927 / \u53EF\u5E76\u884C \u2192 \`oasis add-revision\` \u62C6\u6210\u5B50\u90E8\u4EF6\u6D3E\u51FA\u53BB\uFF0C\u522B\u4E00\u4EBA\u4E00\u4F1A\u8BDD\u786C\u625B\u3002`] : [],
|
|
15591
|
-
...batchedContinuation && args.part === void 0 ? [`- \u957F\u4EFB\u52A1\u5DF2\u5141\u8BB8\u5206\u6279\u7EED\u8DD1\uFF1A\u4E00\u6279\u6709\u8FDB\u5C55\u4F46\u6574\u4F53\u672A\u5B8C\u6210\u65F6\uFF0C\u6309\u300C\u600E\u4E48\u63D0\u4EA4\u300D\u91CC\u7684 propose \u547D\u4EE4\u8FFD\u52A0 \`--checkpoint --continue\`\uFF0Creason \u5199\u6E05\u672C\u6279\u5B8C\u6210\u4E86\u4EC0\u4E48\u3001\u5269\u4EC0\u4E48\u3001\u4E0B\u6279\u4ECE\u54EA\u7EE7\u7EED\uFF0C\u7136\u540E\u6536\u5DE5\uFF1B\u7CFB\u7EDF\u4F1A\u6D3E\u53D1\u4E0B\u4E00\u8F6E\u6B63\u5F0F session\u3002\u5168\u90E8\u5B8C\u6210\u65F6\u7167\u5E38 propose \u540E \`oasis conclude ${artifactId}\`\u3002`] : [],
|
|
15643
|
+
...batchedContinuation && args.part === void 0 ? [`- \u957F\u4EFB\u52A1\u5DF2\u5141\u8BB8\u5206\u6279\u7EED\u8DD1\uFF1A\u4E00\u6279\u6709\u8FDB\u5C55\u4F46\u6574\u4F53\u672A\u5B8C\u6210\u65F6\uFF0C\u6309\u300C\u600E\u4E48\u63D0\u4EA4\u300D\u91CC\u7684 propose \u547D\u4EE4\u8FFD\u52A0 \`--checkpoint --continue\`\uFF0Creason \u5199\u6E05\u672C\u6279\u5B8C\u6210\u4E86\u4EC0\u4E48\u3001\u5269\u4EC0\u4E48\u3001\u4E0B\u6279\u4ECE\u54EA\u7EE7\u7EED\uFF0C\u7136\u540E\u6536\u5DE5\uFF1B\u7CFB\u7EDF\u4F1A\u6D3E\u53D1\u4E0B\u4E00\u8F6E\u6B63\u5F0F session\u3002\u5168\u90E8\u5B8C\u6210\u65F6\u7167\u5E38 propose \u540E \`oasis conclude ${artifactId} --note "<\u4EA4\u4ED8\u7ED3\u8BBA>"\`\u3002`] : [],
|
|
15592
15644
|
`- \u5199\u5165\u53EA\u8D70 \`oasis propose\`\uFF0C\u771F\u6B63\u5B8C\u6574\u4E86\u624D \`oasis conclude\`\uFF1B\u5361\u6CA1\u5361\u4F4F\u3001\u8FDB\u5EA6\u90FD\u662F\u7CFB\u7EDF\u7B97\u7684\uFF0C\u522B\u81EA\u5DF1\u7EF4\u62A4\u3002`,
|
|
15593
15645
|
`- \u4F46**\u7B80\u5355\u3001\u81EA\u8DB3\u3001\u4E0D\u4F9D\u8D56\u672A\u5B9A\u51B3\u7B56\u7684\u4EFB\u52A1**\uFF08\u5982\u6539\u4E2A\u80CC\u666F\u8272\uFF09\u2192 \u76F4\u63A5\u505A\uFF0C\u5224\u65AD\u6743\u5728\u4F60\u3002`,
|
|
15594
15646
|
...typeDef?.recommendedInputs && typeDef.recommendedInputs.length > 0 ? [`- \u672C\u7C7B\u578B\u5E38\u89C1\u4E0A\u6E38\u4F9D\u8D56\uFF08\u63A8\u8350\uFF0C\u975E\u5F3A\u5236\uFF09\uFF1A${typeDef.recommendedInputs.join("\u3001")}\u2014\u2014\u4F9D\u8D56\u5176\u4E2D\u67D0\u4E2A\u800C\u5B83\u8FD8\u6CA1\u6709\uFF0C\u6309\u4E0A\u9762 gap \u89C4\u5219\u62A5\u7F3A\u53E3\u3002`] : []
|
|
@@ -19353,8 +19405,14 @@ var init_kernel_bridge = __esm({
|
|
|
19353
19405
|
/** 下一轮刷新是否顺带重扫一小片"不脏"的工单。只由 `refreshModel({ resync: true })`(读模型时钟)置位。 */
|
|
19354
19406
|
resyncRequested = false;
|
|
19355
19407
|
/**
|
|
19356
|
-
* intervention
|
|
19357
|
-
*
|
|
19408
|
+
* intervention 待授权卡。内存 map 是**读路径的缓存**,真源在库里(`intervention_drafts` 表,
|
|
19409
|
+
* 见 engine/schema.ts)——`open()` 启动时 rehydrate,propose 写库,apply/reject 删库。
|
|
19410
|
+
*
|
|
19411
|
+
* 旧引擎把起草记成一条 `propose_intervention` op 进 oplog,重启 replay 就 fold 回 pendingReviews;
|
|
19412
|
+
* 决策 0130 退役 oplog 时这一段只搬了内存 Map,注释写着「短生命周期、重启丢可接受」。
|
|
19413
|
+
* 2026-09-11 实录证伪了这句:v2 上 31 小时重启 158 次,一张卡起草 24 秒后就被抹掉,
|
|
19414
|
+
* 而协调者仍在对话里让人「去收件箱找那张卡」——聊天页和收件箱读的是同一份 `pendingReviews`,
|
|
19415
|
+
* 一起变空。这张卡的寿命由**等它的那个人**决定,不由进程决定,所以必须落库。
|
|
19358
19416
|
*/
|
|
19359
19417
|
draftCards = /* @__PURE__ */ new Map();
|
|
19360
19418
|
model;
|
|
@@ -19374,6 +19432,14 @@ var init_kernel_bridge = __esm({
|
|
|
19374
19432
|
for (const record8 of records) kernel.markWorkorderDirty(record8.workorderId);
|
|
19375
19433
|
});
|
|
19376
19434
|
bus.onApplied((wid) => kernel.markWorkorderDirty(wid));
|
|
19435
|
+
try {
|
|
19436
|
+
for (const rec of await store.listInterventionDrafts()) {
|
|
19437
|
+
const card2 = rec.card;
|
|
19438
|
+
kernel.draftCards.set(rec.draftId, { ...card2, at: card2?.at || rec.createdAt });
|
|
19439
|
+
}
|
|
19440
|
+
} catch (err) {
|
|
19441
|
+
console.warn(`[kernel-bridge] open \u6062\u590D\u5F85\u6388\u6743\u5361\u5931\u8D25\uFF08\u672C\u6B21\u91CD\u542F\u7684\u5B58\u91CF\u5361\u4F1A\u4E22\uFF09\uFF1A${String(err)}`);
|
|
19442
|
+
}
|
|
19377
19443
|
try {
|
|
19378
19444
|
const all2 = await store.transaction((tx) => tx.listAllWorkorders());
|
|
19379
19445
|
for (const id of all2) kernel.trackedWorkorders.add(id);
|
|
@@ -19384,6 +19450,39 @@ var init_kernel_bridge = __esm({
|
|
|
19384
19450
|
return kernel;
|
|
19385
19451
|
}
|
|
19386
19452
|
/* ─────────────────────── 内部工具 ─────────────────────── */
|
|
19453
|
+
/**
|
|
19454
|
+
* 起草落库。**写失败不阻断起草**——卡已经在内存里、已经显示给人了,这时候抛错会让
|
|
19455
|
+
* `oasis force-conclude` 整条命令失败,比"这张卡撑不过下次重启"糟得多。退化成本次改动之前的行为。
|
|
19456
|
+
*/
|
|
19457
|
+
async persistDraftCard(draftId, card2) {
|
|
19458
|
+
try {
|
|
19459
|
+
await this.store.saveInterventionDraft({
|
|
19460
|
+
draftId,
|
|
19461
|
+
workorderId: this.workorderOfCard(card2),
|
|
19462
|
+
createdAt: card2.at,
|
|
19463
|
+
card: card2
|
|
19464
|
+
});
|
|
19465
|
+
} catch (err) {
|
|
19466
|
+
console.warn(`[kernel-bridge] \u5F85\u6388\u6743\u5361\u843D\u5E93\u5931\u8D25 ${draftId}\uFF08\u91CD\u542F\u540E\u4F1A\u4E22\uFF09\uFF1A${String(err)}`);
|
|
19467
|
+
}
|
|
19468
|
+
}
|
|
19469
|
+
/** 卡已终局(人点了确认或驳回)→ 删库。失败只记日志:内存已出队,残留行会在下次 rehydrate 后
|
|
19470
|
+
* 被 apply/reject 的「卡不存在」分支挡掉,不会让已执行的命令被再执行一次。 */
|
|
19471
|
+
async forgetDraftCard(draftId) {
|
|
19472
|
+
try {
|
|
19473
|
+
await this.store.deleteInterventionDraft(draftId);
|
|
19474
|
+
} catch (err) {
|
|
19475
|
+
console.warn(`[kernel-bridge] \u5F85\u6388\u6743\u5361\u5220\u5E93\u5931\u8D25 ${draftId}\uFF1A${String(err)}`);
|
|
19476
|
+
}
|
|
19477
|
+
}
|
|
19478
|
+
/** 卡挂在哪张工单下(排障列用,允许为空)。锚点可能指向一个模型里已经没有的产物。 */
|
|
19479
|
+
workorderOfCard(card2) {
|
|
19480
|
+
const fromPlan = card2.plan?.workspace;
|
|
19481
|
+
if (fromPlan) return fromPlan;
|
|
19482
|
+
const anchor = card2.anchor;
|
|
19483
|
+
if (!anchor) return null;
|
|
19484
|
+
return this.model.artifacts.get(anchor)?.workspace ?? null;
|
|
19485
|
+
}
|
|
19387
19486
|
/** artifactId → 所属 workorderId(从 model 查)。 */
|
|
19388
19487
|
wo(artifactId) {
|
|
19389
19488
|
const a = this.model.artifacts.get(artifactId);
|
|
@@ -19554,7 +19653,8 @@ var init_kernel_bridge = __esm({
|
|
|
19554
19653
|
workspace: cardWs,
|
|
19555
19654
|
advisory: [],
|
|
19556
19655
|
downstreamClosure: [],
|
|
19557
|
-
|
|
19656
|
+
// 真实起草时刻。曾经恒为 "":收件箱那行因此时间列印 "-"、排序键空串最小、恒沉到列表最后一行。
|
|
19657
|
+
at: card2.at ?? "",
|
|
19558
19658
|
// ★ anchor 也兜底到 plan ops 的产物 id——inbox change-confirm 用 r.anchor 找「anchor owner 的
|
|
19559
19659
|
// 人类上级」(leadOf(r.anchor));graph-edit 卡之前恒空、boss 收不到卡(collab-inbox-audit 实测)。
|
|
19560
19660
|
anchor: anchorId || card2.anchor || "",
|
|
@@ -21007,30 +21107,33 @@ var init_kernel_bridge = __esm({
|
|
|
21007
21107
|
async proposeIntervention(plan, actor, opts) {
|
|
21008
21108
|
const preview2 = await previewIntervention(this.model, plan, { schema: this.schema, roleIndex: this.roleIndex });
|
|
21009
21109
|
const draftId = `draft:${(0, import_node_crypto3.randomUUID)()}`;
|
|
21010
|
-
|
|
21110
|
+
const card2 = {
|
|
21011
21111
|
kind: "graph-edit",
|
|
21012
21112
|
plan,
|
|
21013
21113
|
proposedBy: actor,
|
|
21014
21114
|
origin: opts?.origin,
|
|
21015
21115
|
parentMessageId: opts?.parentMessageId,
|
|
21016
21116
|
changeClass: preview2.changeClass,
|
|
21017
|
-
nonMonotonicOps: preview2.nonMonotonicOps
|
|
21018
|
-
|
|
21117
|
+
nonMonotonicOps: preview2.nonMonotonicOps,
|
|
21118
|
+
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
21119
|
+
};
|
|
21120
|
+
this.draftCards.set(draftId, card2);
|
|
21121
|
+
await this.persistDraftCard(draftId, card2);
|
|
21019
21122
|
await this.refreshModel();
|
|
21020
21123
|
return { draftId, changeClass: preview2.changeClass, nonMonotonicOps: preview2.nonMonotonicOps };
|
|
21021
21124
|
}
|
|
21022
21125
|
async proposeCommandAuthorization(args) {
|
|
21023
21126
|
const originNorm = args.origin ?? null;
|
|
21024
21127
|
const argsJson = JSON.stringify(args.args ?? {});
|
|
21025
|
-
for (const [id,
|
|
21026
|
-
if (
|
|
21027
|
-
if ((
|
|
21028
|
-
if (JSON.stringify(
|
|
21128
|
+
for (const [id, card3] of this.draftCards) {
|
|
21129
|
+
if (card3.kind !== "command" || card3.command !== args.command) continue;
|
|
21130
|
+
if ((card3.origin ?? null) !== originNorm) continue;
|
|
21131
|
+
if (JSON.stringify(card3.commandArgs ?? {}) !== argsJson) continue;
|
|
21029
21132
|
await this.refreshModel();
|
|
21030
21133
|
return { draftId: id };
|
|
21031
21134
|
}
|
|
21032
21135
|
const draftId = `draft:${(0, import_node_crypto3.randomUUID)()}`;
|
|
21033
|
-
|
|
21136
|
+
const card2 = {
|
|
21034
21137
|
kind: "command",
|
|
21035
21138
|
command: args.command,
|
|
21036
21139
|
commandArgs: args.args,
|
|
@@ -21038,8 +21141,11 @@ var init_kernel_bridge = __esm({
|
|
|
21038
21141
|
anchor: args.artifactId,
|
|
21039
21142
|
proposedBy: args.actor,
|
|
21040
21143
|
origin: args.origin,
|
|
21041
|
-
parentMessageId: args.parentMessageId
|
|
21042
|
-
|
|
21144
|
+
parentMessageId: args.parentMessageId,
|
|
21145
|
+
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
21146
|
+
};
|
|
21147
|
+
this.draftCards.set(draftId, card2);
|
|
21148
|
+
await this.persistDraftCard(draftId, card2);
|
|
21043
21149
|
await this.refreshModel();
|
|
21044
21150
|
return { draftId };
|
|
21045
21151
|
}
|
|
@@ -21068,11 +21174,13 @@ var init_kernel_bridge = __esm({
|
|
|
21068
21174
|
throw new Error(`\u547D\u4EE4\u6388\u6743\uFF1A\u6682\u4E0D\u652F\u6301\u6267\u884C ${card2.command}`);
|
|
21069
21175
|
}
|
|
21070
21176
|
this.draftCards.delete(args.draftId);
|
|
21177
|
+
await this.forgetDraftCard(args.draftId);
|
|
21071
21178
|
await this.refreshModel();
|
|
21072
21179
|
return { command: card2.command, artifactId };
|
|
21073
21180
|
}
|
|
21074
21181
|
async rejectIntervention(args) {
|
|
21075
21182
|
this.draftCards.delete(args.draftId);
|
|
21183
|
+
await this.forgetDraftCard(args.draftId);
|
|
21076
21184
|
await this.refreshModel();
|
|
21077
21185
|
}
|
|
21078
21186
|
/**
|
|
@@ -21383,6 +21491,7 @@ var init_kernel_bridge = __esm({
|
|
|
21383
21491
|
}
|
|
21384
21492
|
if (typeof plan.resolvesProposal === "string") {
|
|
21385
21493
|
this.draftCards.delete(plan.resolvesProposal);
|
|
21494
|
+
await this.forgetDraftCard(plan.resolvesProposal);
|
|
21386
21495
|
await this.refreshModel();
|
|
21387
21496
|
}
|
|
21388
21497
|
return {
|
|
@@ -22814,7 +22923,7 @@ function normalizeClaudeStreamLine(line) {
|
|
|
22814
22923
|
for (const block of content3) {
|
|
22815
22924
|
switch (block["type"]) {
|
|
22816
22925
|
case "text":
|
|
22817
|
-
out.push({ kind: "message", payload: { text: block["text"] } });
|
|
22926
|
+
if (type === "assistant") out.push({ kind: "message", payload: { text: block["text"] } });
|
|
22818
22927
|
break;
|
|
22819
22928
|
case "thinking":
|
|
22820
22929
|
out.push({ kind: "thought", payload: { text: block["thinking"] } });
|
|
@@ -23014,6 +23123,8 @@ var init_claude_code = __esm({
|
|
|
23014
23123
|
// 同上
|
|
23015
23124
|
["--verbose", "boolean"],
|
|
23016
23125
|
// 与 --output-format stream-json 配对;单独无意义、成对是重复
|
|
23126
|
+
["--replay-user-messages", "boolean"],
|
|
23127
|
+
// Input consumption receipts are adapter-owned.
|
|
23017
23128
|
["--include-partial-messages", "boolean"]
|
|
23018
23129
|
// 同上
|
|
23019
23130
|
]);
|
|
@@ -23102,7 +23213,7 @@ var init_claude_code = __esm({
|
|
|
23102
23213
|
// 据此喂 onOutput 实现 chat 逐字流式(同时 telemetry 仍由整条 assistant 消息归一)。
|
|
23103
23214
|
...this.opts.streamJson ? ["--output-format", "stream-json", "--verbose", "--include-partial-messages"] : [],
|
|
23104
23215
|
// ADR-0093:stream-json 输入模式——让 claude 逐条从 stdin 读 user 消息(支持多轮追加)。
|
|
23105
|
-
...appendMode ? ["--input-format", "stream-json"] : [],
|
|
23216
|
+
...appendMode ? ["--input-format", "stream-json", "--replay-user-messages"] : [],
|
|
23106
23217
|
...job.model ?? this.opts.model ? ["--model", job.model ?? this.opts.model] : [],
|
|
23107
23218
|
// ADR「agent CLI 启动参数员工级可配置化」:员工配置 job.extraArgs(在前)+ opts.extraArgs(静态默认,在后),
|
|
23108
23219
|
// 过 CLAUDE_BLOCKED_FLAGS 拦截打破协议契约的 flag(剔除 + warn),追加到 argv 末尾。
|
|
@@ -23170,10 +23281,11 @@ var init_claude_code = __esm({
|
|
|
23170
23281
|
pendingClose = null;
|
|
23171
23282
|
}
|
|
23172
23283
|
};
|
|
23173
|
-
const
|
|
23284
|
+
const pendingInputReceipts = /* @__PURE__ */ new Map();
|
|
23285
|
+
const writeUserMessage = (text5, uuid2) => {
|
|
23174
23286
|
try {
|
|
23175
23287
|
child.stdin.write(
|
|
23176
|
-
JSON.stringify({ type: "user", message: { role: "user", content: [{ type: "text", text: text5 }] } }) + "\n"
|
|
23288
|
+
JSON.stringify({ type: "user", ...uuid2 ? { uuid: uuid2 } : {}, message: { role: "user", content: [{ type: "text", text: text5 }] } }) + "\n"
|
|
23177
23289
|
);
|
|
23178
23290
|
writes++;
|
|
23179
23291
|
cancelPendingClose();
|
|
@@ -23248,6 +23360,22 @@ var init_claude_code = __esm({
|
|
|
23248
23360
|
out.write(line + "\n");
|
|
23249
23361
|
try {
|
|
23250
23362
|
const p2 = JSON.parse(line);
|
|
23363
|
+
if (p2["type"] === "user" && p2["isReplay"] === true && !p2["parent_tool_use_id"] && typeof p2["uuid"] === "string") {
|
|
23364
|
+
const key = pendingInputReceipts.get(p2["uuid"]);
|
|
23365
|
+
if (key) {
|
|
23366
|
+
pendingInputReceipts.delete(p2["uuid"]);
|
|
23367
|
+
diag("input_consumed", { key, uuid: p2["uuid"] });
|
|
23368
|
+
for (const cb of liveEventCbs) cb({
|
|
23369
|
+
protocolVersion: 2,
|
|
23370
|
+
streamId: `claude-live:${id}`,
|
|
23371
|
+
turnId: id,
|
|
23372
|
+
itemId: `input:${p2["uuid"]}`,
|
|
23373
|
+
itemType: "control",
|
|
23374
|
+
operation: "completed",
|
|
23375
|
+
payload: { code: "input_consumed", clientMessageKey: key }
|
|
23376
|
+
});
|
|
23377
|
+
}
|
|
23378
|
+
}
|
|
23251
23379
|
if (p2["type"] === "result") {
|
|
23252
23380
|
lastResult = p2;
|
|
23253
23381
|
results++;
|
|
@@ -23423,6 +23551,9 @@ var init_claude_code = __esm({
|
|
|
23423
23551
|
}
|
|
23424
23552
|
};
|
|
23425
23553
|
function doAppend(input) {
|
|
23554
|
+
if (input.requireConsumptionReceipt && (!input.clientMessageKey || !appendMode)) {
|
|
23555
|
+
return Promise.resolve({ accepted: false, reason: "consumption-unsupported" });
|
|
23556
|
+
}
|
|
23426
23557
|
if (!appendMode) {
|
|
23427
23558
|
diag("append_rejected", { reason: "unsupported", writes, results });
|
|
23428
23559
|
return Promise.resolve({ accepted: false, reason: "unsupported", ...input.interrupt ? { interrupt: "unsupported" } : {} });
|
|
@@ -23436,9 +23567,12 @@ var init_claude_code = __esm({
|
|
|
23436
23567
|
const outgoing = report.failed.length ? appendMaterializeWarning(input.text, report) : input.text;
|
|
23437
23568
|
if (input.interrupt) writeInterrupt();
|
|
23438
23569
|
diag("append_accepted", { writes, results, interrupt: !!input.interrupt, chars: input.text.length });
|
|
23439
|
-
const
|
|
23570
|
+
const receiptId = input.requireConsumptionReceipt ? (0, import_node_crypto8.randomUUID)() : void 0;
|
|
23571
|
+
if (receiptId) pendingInputReceipts.set(receiptId, input.clientMessageKey);
|
|
23572
|
+
const ok3 = writeUserMessage(outgoing, receiptId);
|
|
23573
|
+
if (!ok3 && receiptId) pendingInputReceipts.delete(receiptId);
|
|
23440
23574
|
if (!ok3) return Promise.resolve({ accepted: false, reason: "rejected", ...hasFiles ? { files: report } : {}, ...input.interrupt ? { interrupt: "unknown" } : {} });
|
|
23441
|
-
return Promise.resolve({ accepted: true, ...hasFiles ? { files: report } : {}, interrupt: input.interrupt ? "interrupted" : "queued_at_boundary" });
|
|
23575
|
+
return Promise.resolve({ accepted: true, ...receiptId ? { consumption: "pending" } : {}, ...hasFiles ? { files: report } : {}, interrupt: input.interrupt ? "interrupted" : "queued_at_boundary" });
|
|
23442
23576
|
}
|
|
23443
23577
|
}
|
|
23444
23578
|
};
|
|
@@ -24918,6 +25052,7 @@ async function runProtocolSession(job, cfg) {
|
|
|
24918
25052
|
return !closing && started && !exited;
|
|
24919
25053
|
},
|
|
24920
25054
|
appendInput(input) {
|
|
25055
|
+
if (input.requireConsumptionReceipt) return Promise.resolve({ accepted: false, reason: "consumption-unsupported" });
|
|
24921
25056
|
appendChain = appendChain.then(async () => {
|
|
24922
25057
|
if (exited || closing) return { accepted: false, reason: "session-closing" };
|
|
24923
25058
|
const files = materializeFiles(dir, input.files, input.binaryFiles);
|
|
@@ -26743,6 +26878,7 @@ ${task}` : task;
|
|
|
26743
26878
|
}
|
|
26744
26879
|
};
|
|
26745
26880
|
function doAppend(input) {
|
|
26881
|
+
if (input.requireConsumptionReceipt) return Promise.resolve({ accepted: false, reason: "consumption-unsupported" });
|
|
26746
26882
|
if (exited || closingForExit) return Promise.resolve({ accepted: false, reason: "session-closing" });
|
|
26747
26883
|
const report = materializeFiles(dir, input.files, input.binaryFiles);
|
|
26748
26884
|
const queued = report.failed.length ? { ...input, text: appendMaterializeWarning(input.text, report) } : input;
|
|
@@ -28398,6 +28534,18 @@ var init_normalizer = __esm({
|
|
|
28398
28534
|
onLiveEvent(event) {
|
|
28399
28535
|
this.turnId = event.turnId || this.turnId;
|
|
28400
28536
|
const payload = event.payload && typeof event.payload === "object" && !Array.isArray(event.payload) ? event.payload : {};
|
|
28537
|
+
if (event.itemType === "control" && payload.code === "input_consumed" && typeof payload.clientMessageKey === "string") {
|
|
28538
|
+
this.closeOpen("completed");
|
|
28539
|
+
this.emitItem({
|
|
28540
|
+
key: providerItemKey(this.providerName, event.itemId),
|
|
28541
|
+
kind: "control",
|
|
28542
|
+
role: "system",
|
|
28543
|
+
origin: "live",
|
|
28544
|
+
opShape: { op: "set_status", status: "completed" },
|
|
28545
|
+
attrs: { code: "input_consumed", clientMessageKey: payload.clientMessageKey }
|
|
28546
|
+
});
|
|
28547
|
+
return;
|
|
28548
|
+
}
|
|
28401
28549
|
if (event.operation === "turn_completed" || event.operation === "turn_failed") {
|
|
28402
28550
|
this.turnFinished(event.operation === "turn_failed" ? "failed" : "completed");
|
|
28403
28551
|
return;
|
|
@@ -28813,7 +28961,7 @@ var init_chat_item_ledger = __esm({
|
|
|
28813
28961
|
const payload = { role: "user", text: text5 };
|
|
28814
28962
|
if (attachments?.length) payload.attachments = attachments;
|
|
28815
28963
|
if (clientKeys?.length) payload.clientSubmitIds = clientKeys;
|
|
28816
|
-
this.insert({
|
|
28964
|
+
return this.insert({
|
|
28817
28965
|
kind: "text",
|
|
28818
28966
|
role: "user",
|
|
28819
28967
|
status: "completed",
|
|
@@ -28963,10 +29111,10 @@ var init_chat_item_ledger = __esm({
|
|
|
28963
29111
|
* 返回落下的那一行(`null` = 本段有输出、或还没有 assistant 行可归属,不需要注解),
|
|
28964
29112
|
* 调用方据它把这条推上 v3 流——不推的话它只在下一次快照才出现。
|
|
28965
29113
|
*/
|
|
28966
|
-
closeSegmentBeforeUserInput() {
|
|
29114
|
+
closeSegmentBeforeUserInput(allowUnboundSegment = false) {
|
|
28967
29115
|
this.closeStreamingRows("completed");
|
|
28968
29116
|
if (this.segmentEndEmitted) return null;
|
|
28969
|
-
if (this.segmentItemCount !== 0 || !this.messageId) return null;
|
|
29117
|
+
if (this.segmentItemCount !== 0 || !this.messageId && !allowUnboundSegment) return null;
|
|
28970
29118
|
const id = this.insertSegmentEnd();
|
|
28971
29119
|
this.segmentEndEmitted = true;
|
|
28972
29120
|
const row = this.rows.get(id);
|
|
@@ -159948,7 +160096,8 @@ var init_live_chat = __esm({
|
|
|
159948
160096
|
v3Seq: 0,
|
|
159949
160097
|
v3Buffer: [],
|
|
159950
160098
|
v3Subscribers: prev?.recovering ? prev.v3Subscribers : /* @__PURE__ */ new Set(),
|
|
159951
|
-
v3Items: /* @__PURE__ */ new Map()
|
|
160099
|
+
v3Items: /* @__PURE__ */ new Map(),
|
|
160100
|
+
inputReceipts: /* @__PURE__ */ new Map()
|
|
159952
160101
|
};
|
|
159953
160102
|
this.turns.set(chatSessionId, turn);
|
|
159954
160103
|
this.flushPendingUserItems(chatSessionId);
|
|
@@ -160002,6 +160151,8 @@ var init_live_chat = __esm({
|
|
|
160002
160151
|
};
|
|
160003
160152
|
},
|
|
160004
160153
|
finish: (status) => {
|
|
160154
|
+
for (const receipt of turn.inputReceipts.values()) receipt.abandon();
|
|
160155
|
+
turn.inputReceipts.clear();
|
|
160005
160156
|
try {
|
|
160006
160157
|
turn.items?.finish(status === "error" ? "failed" : "completed");
|
|
160007
160158
|
} catch {
|
|
@@ -160063,6 +160214,11 @@ var init_live_chat = __esm({
|
|
|
160063
160214
|
* 账本坏掉不影响对话;v3 emit 抛异常也不影响 v2 通路与账本落盘——两条独立通路。
|
|
160064
160215
|
*/
|
|
160065
160216
|
applyNormalizedEvent(turn, event) {
|
|
160217
|
+
if (event.type === "item" && event.kind === "control" && event.attrs?.code === "input_consumed") {
|
|
160218
|
+
const key = event.attrs.clientMessageKey;
|
|
160219
|
+
if (key) turn.inputReceipts.get(key)?.consume();
|
|
160220
|
+
return;
|
|
160221
|
+
}
|
|
160066
160222
|
let outcome = null;
|
|
160067
160223
|
try {
|
|
160068
160224
|
outcome = turn.items?.apply(event) ?? null;
|
|
@@ -160586,7 +160742,7 @@ var init_live_chat = __esm({
|
|
|
160586
160742
|
if (turn.recovering) return say({ accepted: false, reason: "recovering" }, { recovering: true });
|
|
160587
160743
|
const fn = turn.handle.appendInput;
|
|
160588
160744
|
if (typeof fn !== "function") return say({ accepted: false, reason: "unsupported" });
|
|
160589
|
-
const pendingItemId = !opts?.system && opts?.clientMessageKey ? `oasis-user:${opts.clientMessageKey}` : void 0;
|
|
160745
|
+
const pendingItemId = !opts?.requireConsumptionReceipt && !opts?.system && opts?.clientMessageKey ? `oasis-user:${opts.clientMessageKey}` : void 0;
|
|
160590
160746
|
const pendingAttachments = opts?.attachments?.map((a) => ({
|
|
160591
160747
|
name: a.name,
|
|
160592
160748
|
...a.blobRef ? { blobRef: a.blobRef } : {},
|
|
@@ -160617,17 +160773,75 @@ var init_live_chat = __esm({
|
|
|
160617
160773
|
payload: { role: "user" }
|
|
160618
160774
|
});
|
|
160619
160775
|
};
|
|
160776
|
+
let confirmed2 = false;
|
|
160777
|
+
let consumedItemId;
|
|
160778
|
+
let receiptPromise;
|
|
160779
|
+
const receiptKey = opts?.requireConsumptionReceipt && !opts.system ? opts.clientMessageKey : void 0;
|
|
160780
|
+
if (opts?.requireConsumptionReceipt && !opts.system && !receiptKey) {
|
|
160781
|
+
return say({ accepted: false, reason: "consumption-unsupported" });
|
|
160782
|
+
}
|
|
160783
|
+
if (receiptKey) {
|
|
160784
|
+
const existing = turn.inputReceipts.get(receiptKey);
|
|
160785
|
+
if (existing) {
|
|
160786
|
+
const consumed = await existing.result;
|
|
160787
|
+
await turn.items?.drain();
|
|
160788
|
+
return consumed && existing.itemId && turn.items?.ordFor(existing.itemId) !== void 0 ? { accepted: true } : { accepted: false, reason: "unconfirmed" };
|
|
160789
|
+
}
|
|
160790
|
+
let resolveReceipt;
|
|
160791
|
+
receiptPromise = new Promise((resolve10) => {
|
|
160792
|
+
resolveReceipt = resolve10;
|
|
160793
|
+
});
|
|
160794
|
+
turn.inputReceipts.set(receiptKey, {
|
|
160795
|
+
get itemId() {
|
|
160796
|
+
return consumedItemId;
|
|
160797
|
+
},
|
|
160798
|
+
result: receiptPromise,
|
|
160799
|
+
consume: () => {
|
|
160800
|
+
if (confirmed2 || turn.status !== "running") return;
|
|
160801
|
+
confirmed2 = true;
|
|
160802
|
+
consumedItemId = this.commitUserInput(turn, text5, opts);
|
|
160803
|
+
resolveReceipt(true);
|
|
160804
|
+
},
|
|
160805
|
+
abandon: () => {
|
|
160806
|
+
resolveReceipt(false);
|
|
160807
|
+
}
|
|
160808
|
+
});
|
|
160809
|
+
}
|
|
160810
|
+
const clearReceipt = () => {
|
|
160811
|
+
if (!receiptKey) return;
|
|
160812
|
+
turn.inputReceipts.get(receiptKey)?.abandon();
|
|
160813
|
+
turn.inputReceipts.delete(receiptKey);
|
|
160814
|
+
};
|
|
160620
160815
|
let res;
|
|
160621
160816
|
try {
|
|
160622
160817
|
res = await fn.call(turn.handle, {
|
|
160623
160818
|
text: text5,
|
|
160819
|
+
...receiptKey ? { requireConsumptionReceipt: true } : {},
|
|
160624
160820
|
...opts?.clientMessageKey ? { clientMessageKey: opts.clientMessageKey } : {},
|
|
160625
160821
|
...opts?.files && Object.keys(opts.files).length ? { files: opts.files } : {},
|
|
160626
160822
|
...opts?.binaryFiles && Object.keys(opts.binaryFiles).length ? { binaryFiles: opts.binaryFiles } : {}
|
|
160627
160823
|
});
|
|
160628
160824
|
} catch (e) {
|
|
160825
|
+
if (!receiptKey) clearReceipt();
|
|
160629
160826
|
failPending();
|
|
160630
|
-
|
|
160827
|
+
if (confirmed2) await turn.items?.drain();
|
|
160828
|
+
confirmed2 = confirmed2 && !!consumedItemId && turn.items?.ordFor(consumedItemId) !== void 0;
|
|
160829
|
+
return say({ accepted: confirmed2, ...!confirmed2 ? { reason: receiptKey ? "unconfirmed" : "rejected" } : {} }, { err: String(e) });
|
|
160830
|
+
}
|
|
160831
|
+
if (receiptPromise) {
|
|
160832
|
+
const notSent = ["unsupported", "consumption-unsupported", "session-closing", "no-live-turn", "recovering"];
|
|
160833
|
+
if (!confirmed2 && !res.accepted && notSent.includes(res.reason ?? "")) {
|
|
160834
|
+
clearReceipt();
|
|
160835
|
+
failPending();
|
|
160836
|
+
return say(res);
|
|
160837
|
+
}
|
|
160838
|
+
if (!await receiptPromise) {
|
|
160839
|
+
clearReceipt();
|
|
160840
|
+
failPending();
|
|
160841
|
+
return say({ accepted: false, reason: "unconfirmed" });
|
|
160842
|
+
}
|
|
160843
|
+
await turn.items?.drain();
|
|
160844
|
+
return say(!consumedItemId || turn.items?.ordFor(consumedItemId) === void 0 ? { accepted: false, reason: "unconfirmed" } : { accepted: true });
|
|
160631
160845
|
}
|
|
160632
160846
|
if (!res.accepted) {
|
|
160633
160847
|
failPending();
|
|
@@ -160638,6 +160852,10 @@ var init_live_chat = __esm({
|
|
|
160638
160852
|
failPending();
|
|
160639
160853
|
return say({ accepted: false, reason: "turn-finished" }, { turnStatus: turn.status, replaced: this.turns.get(chatSessionId) !== turn });
|
|
160640
160854
|
}
|
|
160855
|
+
this.commitUserInput(turn, text5, opts);
|
|
160856
|
+
return { accepted: true };
|
|
160857
|
+
}
|
|
160858
|
+
commitUserInput(turn, text5, opts) {
|
|
160641
160859
|
const shown = opts?.displayText ?? text5;
|
|
160642
160860
|
const userPart = {
|
|
160643
160861
|
type: "user",
|
|
@@ -160646,7 +160864,7 @@ var init_live_chat = __esm({
|
|
|
160646
160864
|
};
|
|
160647
160865
|
const segmentEnd = (() => {
|
|
160648
160866
|
try {
|
|
160649
|
-
return turn.items?.closeSegmentBeforeUserInput() ?? null;
|
|
160867
|
+
return turn.items?.closeSegmentBeforeUserInput(!!opts?.requireConsumptionReceipt && !!turn.onUserInput) ?? null;
|
|
160650
160868
|
} catch {
|
|
160651
160869
|
return null;
|
|
160652
160870
|
}
|
|
@@ -160662,8 +160880,9 @@ var init_live_chat = __esm({
|
|
|
160662
160880
|
payload: { code: "segment_end", note: SEGMENT_END_NOTE }
|
|
160663
160881
|
});
|
|
160664
160882
|
}
|
|
160883
|
+
let userItemId;
|
|
160665
160884
|
try {
|
|
160666
|
-
turn.items?.recordUserInput(shown, opts?.attachments, opts?.clientKeys);
|
|
160885
|
+
userItemId = turn.items?.recordUserInput(shown, opts?.attachments, opts?.clientKeys);
|
|
160667
160886
|
} catch {
|
|
160668
160887
|
}
|
|
160669
160888
|
const withSeq = { ...userPart, seq: ++turn.seq };
|
|
@@ -160697,7 +160916,7 @@ var init_live_chat = __esm({
|
|
|
160697
160916
|
turn.onUserInput?.(shown, opts?.attachments);
|
|
160698
160917
|
} catch {
|
|
160699
160918
|
}
|
|
160700
|
-
return
|
|
160919
|
+
return userItemId;
|
|
160701
160920
|
}
|
|
160702
160921
|
/** 反查该会话当前驻留那一轮的 runId(无进行中/grace 轮,或该轮无 runId 时 undefined)。
|
|
160703
160922
|
* 建单草案 submit 发生在这一轮内:用它给草案盖上「产出轮次」标记,供 friday 重进对话页把每版
|
|
@@ -160843,10 +161062,10 @@ var init_chat_attachment_files = __esm({
|
|
|
160843
161062
|
});
|
|
160844
161063
|
|
|
160845
161064
|
// ../server/src/domains/chat-sessions/append-now.ts
|
|
160846
|
-
async function appendNowThroughQueue(chatSessionId, text5, deps, clientKey, attachments) {
|
|
161065
|
+
async function appendNowThroughQueue(chatSessionId, text5, deps, clientKey, attachments, retainLocallyOnFailure = false) {
|
|
160847
161066
|
const newId = deps.newId ?? import_node_crypto20.randomUUID;
|
|
160848
161067
|
const now = deps.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
160849
|
-
await deps.store.enqueuePendingMessage({
|
|
161068
|
+
const submitted = await deps.store.enqueuePendingMessage({
|
|
160850
161069
|
id: newId(),
|
|
160851
161070
|
chatSessionId,
|
|
160852
161071
|
text: text5,
|
|
@@ -160879,10 +161098,19 @@ async function appendNowThroughQueue(chatSessionId, text5, deps, clientKey, atta
|
|
|
160879
161098
|
...displayText !== merged ? { displayText } : {},
|
|
160880
161099
|
...attachmentRefs.length ? { attachments: attachmentRefs } : {}
|
|
160881
161100
|
});
|
|
160882
|
-
const DEFINITELY_NOT_DELIVERED = /* @__PURE__ */ new Set(["unsupported", "no-live-turn", "session-closing", "turn-finished", "recovering"]);
|
|
161101
|
+
const DEFINITELY_NOT_DELIVERED = /* @__PURE__ */ new Set(["unsupported", "no-live-turn", "session-closing", "turn-finished", "recovering", "consumption-unsupported"]);
|
|
160883
161102
|
const nextState = res.accepted ? "delivered" : DEFINITELY_NOT_DELIVERED.has(res.reason ?? "") ? "queued" : "unconfirmed";
|
|
160884
|
-
|
|
160885
|
-
|
|
161103
|
+
const returnToClient = retainLocallyOnFailure && !!clientKey && nextState === "queued";
|
|
161104
|
+
if (returnToClient && deps.store.markPendingMessages) {
|
|
161105
|
+
await deps.store.markPendingMessages(chatSessionId, [submitted.id], "cancelled", "client-retained");
|
|
161106
|
+
await deps.store.markPendingMessages(chatSessionId, ids2.filter((id) => id !== submitted.id), nextState, res.reason);
|
|
161107
|
+
} else {
|
|
161108
|
+
const transition = deps.store.markPendingMessages?.(chatSessionId, ids2, nextState, res.reason);
|
|
161109
|
+
if (retainLocallyOnFailure) await transition;
|
|
161110
|
+
else await transition?.catch(() => void 0);
|
|
161111
|
+
if (returnToClient) await deps.store.removePendingMessage(chatSessionId, submitted.id);
|
|
161112
|
+
}
|
|
161113
|
+
return { ...res, queued: !returnToClient, delivered: merged, batch, ...prepared.paths.length ? { attachmentPaths: prepared.paths } : {} };
|
|
160886
161114
|
}
|
|
160887
161115
|
var import_node_crypto20;
|
|
160888
161116
|
var init_append_now = __esm({
|
|
@@ -203944,7 +204172,7 @@ async function startOasisServer(opts) {
|
|
|
203944
204172
|
}
|
|
203945
204173
|
return void 0;
|
|
203946
204174
|
}
|
|
203947
|
-
const appendNowThroughQueue2 = async (sid, text5, clientKey, attachments, perCompanyStore) => {
|
|
204175
|
+
const appendNowThroughQueue2 = async (sid, text5, clientKey, attachments, perCompanyStore, retainLocallyOnFailure = false) => {
|
|
203948
204176
|
if (perCompanyStore === null) {
|
|
203949
204177
|
throw new Error(
|
|
203950
204178
|
`appendNowThroughQueue: per-company chat store unresolved (sid=${sid})`
|
|
@@ -203958,7 +204186,7 @@ async function startOasisServer(opts) {
|
|
|
203958
204186
|
store,
|
|
203959
204187
|
// ADR-0166 D9.1:附件与正文**同一次**送出——拆开就等于让 agent 拿着「见附件」而
|
|
203960
204188
|
// 附件不存在的描述去干活。`files` 空时这次调用与从前逐字相同。
|
|
203961
|
-
deliver: (merged, clientMessageKey, extra) => liveChat.append(sid, merged, { clientMessageKey, ...extra }),
|
|
204189
|
+
deliver: (merged, clientMessageKey, extra) => liveChat.append(sid, merged, { clientMessageKey, ...extra, requireConsumptionReceipt: true }),
|
|
203962
204190
|
// **先查资产柜再查事实柜**——chat 附件是 `uploadChatAttachment` 存进**资产柜**的
|
|
203963
204191
|
// (serve 那侧 `assets.put`),两个柜是**物理隔离**的(「资产柜与事实柜分开」)。
|
|
203964
204192
|
// 只查 `opts.blobs` 必然取不到,于是每张图都被报成「附件没能取回来」。
|
|
@@ -203973,8 +204201,8 @@ async function startOasisServer(opts) {
|
|
|
203973
204201
|
}
|
|
203974
204202
|
throw new Error(`blob ${blobRef} \u4E24\u4E2A\u67DC\u91CC\u90FD\u6CA1\u6709`);
|
|
203975
204203
|
}
|
|
203976
|
-
}, clientKey, attachments);
|
|
203977
|
-
return { accepted: r.accepted, ...r.reason ? { reason: r.reason } : {}, queued:
|
|
204204
|
+
}, clientKey, attachments, retainLocallyOnFailure);
|
|
204205
|
+
return { accepted: r.accepted, ...r.reason ? { reason: r.reason } : {}, queued: r.queued };
|
|
203978
204206
|
};
|
|
203979
204207
|
const GRAPH_EDIT_SUMMARY_MAX = 60;
|
|
203980
204208
|
const truncateSummary = (s2) => {
|
|
@@ -206131,9 +206359,11 @@ async function startOasisServer(opts) {
|
|
|
206131
206359
|
let text5 = "";
|
|
206132
206360
|
let clientKey;
|
|
206133
206361
|
let insertAttachments = [];
|
|
206362
|
+
let retainLocallyOnFailure = false;
|
|
206134
206363
|
try {
|
|
206135
206364
|
const b2 = JSON.parse(rawBody);
|
|
206136
206365
|
text5 = String(b2.text ?? "").trim();
|
|
206366
|
+
retainLocallyOnFailure = b2.retainLocallyOnFailure === true;
|
|
206137
206367
|
if (typeof b2.clientKey === "string" && b2.clientKey) clientKey = b2.clientKey;
|
|
206138
206368
|
insertAttachments = (Array.isArray(b2.attachments) ? b2.attachments : []).filter((a) => !!a && typeof a === "object" && typeof a["name"] === "string" && (typeof a["text"] === "string" || typeof a["blobRef"] === "string")).map((a) => ({
|
|
206139
206369
|
name: a["name"],
|
|
@@ -206147,7 +206377,7 @@ async function startOasisServer(opts) {
|
|
|
206147
206377
|
res.writeHead(400, { "content-type": "application/json" }).end(JSON.stringify({ error: "EMPTY_TEXT" }));
|
|
206148
206378
|
return;
|
|
206149
206379
|
}
|
|
206150
|
-
const result = await appendNowThroughQueue2(sid, text5, clientKey, insertAttachments, perCompanyStore);
|
|
206380
|
+
const result = await appendNowThroughQueue2(sid, text5, clientKey, insertAttachments, perCompanyStore, retainLocallyOnFailure);
|
|
206151
206381
|
res.writeHead(result.accepted ? 200 : 409, { "content-type": "application/json" }).end(JSON.stringify(result));
|
|
206152
206382
|
return;
|
|
206153
206383
|
}
|
|
@@ -218337,6 +218567,10 @@ var init_daemon_hub = __esm({
|
|
|
218337
218567
|
this.onHandshakeRejected?.(rejection);
|
|
218338
218568
|
cb(false, code2, message);
|
|
218339
218569
|
}
|
|
218570
|
+
/** Ask the running session: an upgrade leaves existing sessions alive. */
|
|
218571
|
+
supportsInputConsumptionReceipts(dispatchId) {
|
|
218572
|
+
return this.hasSession(dispatchId) && this.sessionMeta.get(dispatchId)?.supportsInputConsumptionReceipts === true;
|
|
218573
|
+
}
|
|
218340
218574
|
dispatch(daemonId, msg) {
|
|
218341
218575
|
const daemon = this.daemons.get(daemonId);
|
|
218342
218576
|
if (!daemon) return false;
|
|
@@ -218406,6 +218640,7 @@ var init_daemon_hub = __esm({
|
|
|
218406
218640
|
nodeId,
|
|
218407
218641
|
sessionId: msg.sessionId,
|
|
218408
218642
|
connectedAt: Date.now(),
|
|
218643
|
+
supportsInputConsumptionReceipts: msg.supportsInputConsumptionReceipts === true,
|
|
218409
218644
|
...msg.jobArtifactId ? { jobArtifactId: msg.jobArtifactId } : {}
|
|
218410
218645
|
});
|
|
218411
218646
|
for (const l of this.sessionConnectListeners) l({ dispatchId, sessionId: msg.sessionId, nodeId });
|
|
@@ -221047,7 +221282,7 @@ async function actorStats(actorId, opts = {}) {
|
|
|
221047
221282
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
221048
221283
|
const from = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1e3).toISOString();
|
|
221049
221284
|
const to = now.toISOString();
|
|
221050
|
-
const weeklyUsage = opts.usage?.listRuns ? summarizeWeeklyRuns(await listWeeklyRuns(opts.usage, actorId, from, to)) : summarizeWeeklyUsage(opts.usage?.queryUsageStats ? await opts.usage.queryUsageStats({
|
|
221285
|
+
const weeklyUsage = opts.usage?.listRuns ? summarizeWeeklyRuns(await listWeeklyRuns(opts.usage, actorId, from, to, opts.artifactIds)) : summarizeWeeklyUsage(!opts.artifactIds && opts.usage?.queryUsageStats ? await opts.usage.queryUsageStats({
|
|
221051
221286
|
actorIds: [actorId],
|
|
221052
221287
|
from,
|
|
221053
221288
|
to,
|
|
@@ -221055,6 +221290,8 @@ async function actorStats(actorId, opts = {}) {
|
|
|
221055
221290
|
}) : []);
|
|
221056
221291
|
return {
|
|
221057
221292
|
actorId,
|
|
221293
|
+
usageAvailable: !!(opts.usage?.listRuns || !opts.artifactIds && opts.usage?.queryUsageStats),
|
|
221294
|
+
...opts.model ? { participatingTaskCount: participatingTaskCount(opts.model, actorId) } : {},
|
|
221058
221295
|
tokenWeek: weeklyUsage.tokenWeek,
|
|
221059
221296
|
tokenWeekBreakdown: weeklyUsage.tokenWeekBreakdown,
|
|
221060
221297
|
costWeekUsdMicros: weeklyUsage.costWeekUsdMicros,
|
|
@@ -221064,12 +221301,12 @@ async function actorStats(actorId, opts = {}) {
|
|
|
221064
221301
|
unpricedModels: weeklyUsage.unpricedModels
|
|
221065
221302
|
};
|
|
221066
221303
|
}
|
|
221067
|
-
async function listWeeklyRuns(trace, actorId, from, to) {
|
|
221304
|
+
async function listWeeklyRuns(trace, actorId, from, to, artifactIds) {
|
|
221068
221305
|
const out = [];
|
|
221069
221306
|
let cursor;
|
|
221070
221307
|
do {
|
|
221071
221308
|
const page = await trace.listRuns({ actorId, from, to, limit: 500, ...cursor ? { cursor } : {} });
|
|
221072
|
-
out.push(...page.items);
|
|
221309
|
+
out.push(...page.items.filter((run) => !artifactIds || run.artifactId != null && artifactIds.has(run.artifactId)));
|
|
221073
221310
|
cursor = page.nextCursor ?? void 0;
|
|
221074
221311
|
} while (cursor);
|
|
221075
221312
|
return out;
|
|
@@ -221080,6 +221317,13 @@ function summarizeWeeklyRuns(runs) {
|
|
|
221080
221317
|
function summarizeWeeklyUsage(rows) {
|
|
221081
221318
|
return summarize2(rows.map((row) => ({ model: row.effectiveModel, usage: row })));
|
|
221082
221319
|
}
|
|
221320
|
+
function participatingTaskCount(model, actorId) {
|
|
221321
|
+
const workorders = /* @__PURE__ */ new Set();
|
|
221322
|
+
for (const artifact of model.artifacts.values()) {
|
|
221323
|
+
if (artifact.owner === actorId) workorders.add(artifact.workspace);
|
|
221324
|
+
}
|
|
221325
|
+
return workorders.size;
|
|
221326
|
+
}
|
|
221083
221327
|
var init_stats = __esm({
|
|
221084
221328
|
"../server/src/domains/actors/stats.ts"() {
|
|
221085
221329
|
"use strict";
|
|
@@ -222415,9 +222659,16 @@ function actorsDomain(opts) {
|
|
|
222415
222659
|
throw new ApiError(400, "BAD_REQUEST", "\u4F20 enabled\uFF08\u5F00\u5173\uFF09/ appliedToAll\uFF08\u5168\u5458\u751F\u6548\uFF09/ name\xB7description\uFF08\u66F4\u65B0\u5143\u6570\u636E\uFF09");
|
|
222416
222660
|
});
|
|
222417
222661
|
router.get("/api/actors/:id/stats", async (req) => {
|
|
222662
|
+
const ctx = await resolveCtx(req.auth.companyId);
|
|
222663
|
+
if (!await ctx.service.getActor(req.params.id)) throw new ApiError(404, "NOT_FOUND", "\u6CA1\u6709\u8FD9\u4E2A\u5458\u5DE5");
|
|
222664
|
+
const model = ctx.getModel?.();
|
|
222418
222665
|
return {
|
|
222419
222666
|
status: 200,
|
|
222420
|
-
body: await actorStats(req.params.id, {
|
|
222667
|
+
body: await actorStats(req.params.id, {
|
|
222668
|
+
usage: req.auth.companyId && !model ? void 0 : opts.trace?.(),
|
|
222669
|
+
model,
|
|
222670
|
+
...req.auth.companyId ? { artifactIds: new Set(model?.artifacts.keys() ?? []) } : {}
|
|
222671
|
+
})
|
|
222421
222672
|
};
|
|
222422
222673
|
});
|
|
222423
222674
|
router.get("/api/actors/:id/running-tasks", async (req) => {
|
|
@@ -222975,6 +223226,7 @@ function createActorsDomain(opts) {
|
|
|
222975
223226
|
const engineStoreOf = (k2) => k2?.getStore?.();
|
|
222976
223227
|
const defaultCtx = {
|
|
222977
223228
|
service: buildService(opts.store, opts.kernel, opts.blobs),
|
|
223229
|
+
...opts.kernel?.model ? { getModel: () => opts.kernel.model } : {},
|
|
222978
223230
|
...opts.oplog !== void 0 ? { oplog: opts.oplog } : {},
|
|
222979
223231
|
...engineStoreOf(opts.kernel) !== void 0 ? { engineStore: engineStoreOf(opts.kernel) } : {},
|
|
222980
223232
|
...opts.blobs !== void 0 ? { blobs: opts.blobs } : {}
|
|
@@ -222988,6 +223240,7 @@ function createActorsDomain(opts) {
|
|
|
222988
223240
|
const blobs = engine.assets ?? engine.blobs;
|
|
222989
223241
|
const ctx = {
|
|
222990
223242
|
service: buildService(engine.registry, engine.kernel, blobs),
|
|
223243
|
+
getModel: () => engine.kernel.model,
|
|
222991
223244
|
oplog: engine.oplog,
|
|
222992
223245
|
...engineStoreOf(engine.kernel) !== void 0 ? { engineStore: engineStoreOf(engine.kernel) } : {},
|
|
222993
223246
|
blobs
|
|
@@ -223173,6 +223426,16 @@ var init_assistant_tier_dispatch = __esm({
|
|
|
223173
223426
|
// ../server/src/domains/projects/routes.ts
|
|
223174
223427
|
function projectsDomain(opts) {
|
|
223175
223428
|
const svc = async (req) => opts.resolveService ? opts.resolveService(req.auth.companyId) : opts.service;
|
|
223429
|
+
const requireProjectManagePermission = async (req, projectId2, action) => {
|
|
223430
|
+
if (!opts.resolveMemberRole) return;
|
|
223431
|
+
if (isUncategorizedProjectId(projectId2)) return;
|
|
223432
|
+
const project = await (await svc(req)).getProject(projectId2);
|
|
223433
|
+
if (!project) throw new ApiError(404, "NOT_FOUND", `\u6CA1\u6709\u8FD9\u4E2A\u9879\u76EE\uFF1A${projectId2}`);
|
|
223434
|
+
if (project.createdBy && project.createdBy.id === req.auth.actor) return;
|
|
223435
|
+
const role = await opts.resolveMemberRole(req.auth.companyId, req.auth.actor);
|
|
223436
|
+
if (role === "owner" || role === "admin") return;
|
|
223437
|
+
throw new ApiError(403, action.code, `\u4F60\u6CA1\u6709${action.verb}\u8BE5\u9879\u76EE\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7EC4\u7EC7\u7BA1\u7406\u5458`);
|
|
223438
|
+
};
|
|
223176
223439
|
return (router) => {
|
|
223177
223440
|
router.post("/api/projects", async (req) => {
|
|
223178
223441
|
const body2 = req.body;
|
|
@@ -223214,6 +223477,7 @@ function projectsDomain(opts) {
|
|
|
223214
223477
|
return { status: 200, body: toApiProject(project) };
|
|
223215
223478
|
});
|
|
223216
223479
|
router.patch("/api/projects/:id", async (req) => {
|
|
223480
|
+
await requireProjectManagePermission(req, req.params.id, { verb: "\u7F16\u8F91", code: "PROJECT_EDIT_FORBIDDEN" });
|
|
223217
223481
|
const body2 = req.body ?? {};
|
|
223218
223482
|
for (const immutable of ["id", "project_id", "projectId", "createdBy", "created_by", "ownerId", "owner_id"]) {
|
|
223219
223483
|
if (Object.prototype.hasOwnProperty.call(body2, immutable)) {
|
|
@@ -223233,6 +223497,7 @@ function projectsDomain(opts) {
|
|
|
223233
223497
|
}
|
|
223234
223498
|
});
|
|
223235
223499
|
router.delete("/api/projects/:id", async (req) => {
|
|
223500
|
+
await requireProjectManagePermission(req, req.params.id, { verb: "\u5220\u9664", code: "PROJECT_DELETE_FORBIDDEN" });
|
|
223236
223501
|
try {
|
|
223237
223502
|
const result = await (await svc(req)).deleteProject(req.params.id);
|
|
223238
223503
|
return {
|
|
@@ -224873,8 +225138,10 @@ function buildWorkorderActivity(input) {
|
|
|
224873
225138
|
] : []
|
|
224874
225139
|
});
|
|
224875
225140
|
}
|
|
225141
|
+
const openedSeq = events.find((rec) => rec.event.kind === "work.create")?.seq;
|
|
225142
|
+
const beforeOpen = (seq) => openedSeq !== void 0 && seq < openedSeq;
|
|
224876
225143
|
const drafts = [
|
|
224877
|
-
...standalone,
|
|
225144
|
+
...standalone.filter((d) => !beforeOpen(d.seq)),
|
|
224878
225145
|
...executionCards,
|
|
224879
225146
|
...visibleReviews.values(),
|
|
224880
225147
|
...issueCards.values(),
|
|
@@ -224950,7 +225217,7 @@ function buildWorkorderActivity(input) {
|
|
|
224950
225217
|
.../* @__PURE__ */ ((r) => r ? { runId: r, traceAvailable: true } : {})(traced ? runIdOfCard(d) : void 0)
|
|
224951
225218
|
};
|
|
224952
225219
|
});
|
|
224953
|
-
cards.push(...reviewRequirementActivity(snap, events, ref2));
|
|
225220
|
+
cards.push(...reviewRequirementActivity(snap, events, ref2).filter((c) => !beforeOpen(c.seq)));
|
|
224954
225221
|
cards.sort((a, b2) => a.updatedAt.localeCompare(b2.updatedAt) || a.seq - b2.seq || a.id.localeCompare(b2.id));
|
|
224955
225222
|
return { workorderId, cards, truncated };
|
|
224956
225223
|
}
|
|
@@ -225620,6 +225887,12 @@ function buildInbox(model, me, leadOf, resolveActor, markers = [], slaMs, nowIso
|
|
|
225620
225887
|
actionRequired: true,
|
|
225621
225888
|
summary: changeConfirmSummary(r),
|
|
225622
225889
|
draftId: r.draftId,
|
|
225890
|
+
// ★ 落点(2026-09-11):带上起草它的那段对话,让前端把这一行跳回**卡真正渲染着的地方**。
|
|
225891
|
+
// 此前这一行恒跳「任务详情 ?tab=activity」,而全仓库渲染待审卡的只有 chat 页与任务页的协调者
|
|
225892
|
+
// 对话(都按 origin=会话 id 查),动态 tab 里一行渲染代码都没有——于是收件箱这条路
|
|
225893
|
+
// 「找得到那一行、却点不到确认键」。origin 缺省(自主会话起草、没人在场)时不带,
|
|
225894
|
+
// 仍回落工单详情。
|
|
225895
|
+
...r.origin ? { chatSessionId: r.origin } : {},
|
|
225623
225896
|
...anchorArt ? { title: nodeLabel(anchorArt) } : {},
|
|
225624
225897
|
detail: `${actorName(r.proposedBy) || "\u7BA1\u7406\u8005"}\uFF1A${r.command?.effectLabel ?? firstSentence(r.plan.reason)}`,
|
|
225625
225898
|
...r.kind !== "command" && opCount > 0 ? { impact: `\u6D89\u53CA ${opCount} \u5904\u6539\u52A8${r.nonMonotonicOps.length > 0 ? " \xB7 \u542B\u9500\u6BC1\u6027" : ""}` } : {},
|
|
@@ -228506,7 +228779,8 @@ function createProjectsDomain(opts) {
|
|
|
228506
228779
|
register: projectsDomain({
|
|
228507
228780
|
service,
|
|
228508
228781
|
...opts.resolveCompany ? { resolveService } : {},
|
|
228509
|
-
...opts.defaultBranchResolver ? { defaultBranchResolver: opts.defaultBranchResolver } : {}
|
|
228782
|
+
...opts.defaultBranchResolver ? { defaultBranchResolver: opts.defaultBranchResolver } : {},
|
|
228783
|
+
...opts.resolveMemberRole ? { resolveMemberRole: opts.resolveMemberRole } : {}
|
|
228510
228784
|
}),
|
|
228511
228785
|
...opts.resolveCompany ? { resolveService } : {}
|
|
228512
228786
|
};
|
|
@@ -239159,6 +239433,9 @@ function routeToSession(hub, nodeId, dispatchId, msg) {
|
|
|
239159
239433
|
function remoteAppendInput(hub, nodeId, dispatchId, entry, input, timeoutMs) {
|
|
239160
239434
|
const unknownIfInterrupting = input.interrupt ? { interrupt: "unknown" } : {};
|
|
239161
239435
|
if (entry.exited) return Promise.resolve({ accepted: false, reason: "session-closing", ...unknownIfInterrupting });
|
|
239436
|
+
if (input.requireConsumptionReceipt && !hub.supportsInputConsumptionReceipts?.(dispatchId)) {
|
|
239437
|
+
return Promise.resolve({ accepted: false, reason: "consumption-unsupported" });
|
|
239438
|
+
}
|
|
239162
239439
|
const requestId = (0, import_node_crypto65.randomUUID)();
|
|
239163
239440
|
const sent = routeToSession(hub, nodeId, dispatchId, { type: "append_input", dispatchId, input, requestId });
|
|
239164
239441
|
if (!sent) return Promise.resolve({ accepted: false, reason: "session-closing", ...unknownIfInterrupting });
|
|
@@ -239166,10 +239443,10 @@ function remoteAppendInput(hub, nodeId, dispatchId, entry, input, timeoutMs) {
|
|
|
239166
239443
|
const timer = setTimeout(() => {
|
|
239167
239444
|
const i = entry.appendWaiters.findIndex((w2) => w2.timer === timer);
|
|
239168
239445
|
if (i >= 0) entry.appendWaiters.splice(i, 1);
|
|
239169
|
-
resolve10({ accepted: false, reason: "unsupported", ...unknownIfInterrupting });
|
|
239446
|
+
resolve10({ accepted: false, reason: input.requireConsumptionReceipt ? "unconfirmed" : "unsupported", ...unknownIfInterrupting });
|
|
239170
239447
|
}, timeoutMs);
|
|
239171
239448
|
timer.unref?.();
|
|
239172
|
-
entry.appendWaiters.push({ requestId, resolve: resolve10, timer });
|
|
239449
|
+
entry.appendWaiters.push({ requestId, requireConsumptionReceipt: input.requireConsumptionReceipt, resolve: resolve10, timer });
|
|
239173
239450
|
});
|
|
239174
239451
|
}
|
|
239175
239452
|
var import_node_crypto65, STASH_TTL_MS, STASH_MAX_FRAMES_PER_ID, STASH_MAX_IDS, DaemonHubAdapter, BindingRouterAdapter, WorkdirBridge;
|
|
@@ -239316,7 +239593,7 @@ var init_daemon_adapter = __esm({
|
|
|
239316
239593
|
entry.exited = info;
|
|
239317
239594
|
for (const w2 of entry.appendWaiters.splice(0)) {
|
|
239318
239595
|
clearTimeout(w2.timer);
|
|
239319
|
-
w2.resolve({ accepted: false, reason: "session-closing" });
|
|
239596
|
+
w2.resolve({ accepted: false, reason: w2.requireConsumptionReceipt ? "unconfirmed" : "session-closing" });
|
|
239320
239597
|
}
|
|
239321
239598
|
if (info.reason === "server-unreachable") this.health?.recordUnreachable(entry.nodeId, info.reason);
|
|
239322
239599
|
else this.health?.recordReachable(entry.nodeId);
|
|
@@ -253204,6 +253481,17 @@ var init_cutover_aware_dispatches = __esm({
|
|
|
253204
253481
|
if (row.state === "frozen") throw new BundleFrozenError("dispatch");
|
|
253205
253482
|
return this.o.cutover.readsCompanySchema(row) ? this.o.owned : this.o.legacy;
|
|
253206
253483
|
}
|
|
253484
|
+
/**
|
|
253485
|
+
* 这家公司的派发台账当前**物理落在哪**:切走了就是它自己的引擎 schema,没切走就是那个
|
|
253486
|
+
* 所有未切公司共用的 legacy 台账。
|
|
253487
|
+
*
|
|
253488
|
+
* 给 {@link FanOutDispatchLedger} 去重用。判据**不在调用方重算**——就是 {@link pick}
|
|
253489
|
+
* 那一条(`cutover.get` + `readsCompanySchema`)。与 `CutoverAwareTraceStore.storageKey` 同构。
|
|
253490
|
+
*/
|
|
253491
|
+
async storageKey() {
|
|
253492
|
+
const row = await this.o.cutover.get(this.o.companyId, "dispatch");
|
|
253493
|
+
return this.o.cutover.readsCompanySchema(row) ? `owned:${this.o.companyId}` : "legacy";
|
|
253494
|
+
}
|
|
253207
253495
|
async insertOpen(rec) {
|
|
253208
253496
|
return (await this.pickWritable()).insertOpen(rec);
|
|
253209
253497
|
}
|
|
@@ -253239,11 +253527,48 @@ var init_cutover_aware_dispatches = __esm({
|
|
|
253239
253527
|
constructor(o) {
|
|
253240
253528
|
this.o = o;
|
|
253241
253529
|
}
|
|
253242
|
-
|
|
253530
|
+
/**
|
|
253531
|
+
* 本次要作用的物理落点清单——**同一个台账只出现一次**。
|
|
253532
|
+
*
|
|
253533
|
+
* 为什么必须去重:`dispatch` 是按 (公司, bundle) 逐个切的,没切走的公司**全部共用同一个
|
|
253534
|
+
* legacy 台账**(读写同一张 `public.dispatches`)。此前 `each` 直接按公司逐家来,于是同一张
|
|
253535
|
+
* 表被访问 N 次(N = 未切走的公司数):
|
|
253536
|
+
*
|
|
253537
|
+
* - **纯读直接出重复行**(`listOpen` / `listByWorkorder` / `findOpenByTarget`)。
|
|
253538
|
+
* 2026-09-11 v2 生产实证(`ws:wo-9f4652cd`):35 家公司、其中 33 家 dispatch 未切走,
|
|
253539
|
+
* `listByWorkorder` 返回 33 份同一条派发,动态卡「执行轨迹」抽屉里同一轮 attempt
|
|
253540
|
+
* 就出现 33 次(`attempts` 由它喂,见 server 的 `activity-trace.ts`)。
|
|
253541
|
+
* - 写侧**没有被放大**,但原因是运气好而不是设计:`markStarted` / `close` 是同值 UPDATE;
|
|
253542
|
+
* `closeStaleNeverStarted` / `closeOpenByTarget` 的 WHERE 带 `ended_at IS NULL`,
|
|
253543
|
+
* 第一遍改完第二遍就匹配不上,返回 0,`reduce` 出来仍是真实值。
|
|
253544
|
+
* - 无论读写,同一条 SQL 都实打实打了 N 遍。
|
|
253545
|
+
*
|
|
253546
|
+
* 去重键由台账自己报,不在这里按 cutover 状态重算(见 `storageKey` 的注释)。也不能按
|
|
253547
|
+
* `ledgerFor` 返回的对象做身份去重:每家各有一个 `CutoverAwareDispatchStore` 包装实例,
|
|
253548
|
+
* N 个不同对象包着同一个 legacy 台账。
|
|
253549
|
+
*/
|
|
253550
|
+
async targets(op) {
|
|
253243
253551
|
const out = [];
|
|
253552
|
+
const seen = /* @__PURE__ */ new Set();
|
|
253244
253553
|
for (const cid of await this.o.listCompanies()) {
|
|
253245
253554
|
try {
|
|
253246
|
-
|
|
253555
|
+
if (this.o.storageKeyFor) {
|
|
253556
|
+
const key = await this.o.storageKeyFor(cid);
|
|
253557
|
+
if (seen.has(key)) continue;
|
|
253558
|
+
seen.add(key);
|
|
253559
|
+
}
|
|
253560
|
+
out.push({ cid, ledger: await this.o.ledgerFor(cid) });
|
|
253561
|
+
} catch (err) {
|
|
253562
|
+
this.o.onError?.(cid, op, err);
|
|
253563
|
+
}
|
|
253564
|
+
}
|
|
253565
|
+
return out;
|
|
253566
|
+
}
|
|
253567
|
+
async each(op, fn) {
|
|
253568
|
+
const out = [];
|
|
253569
|
+
for (const { cid, ledger } of await this.targets(op)) {
|
|
253570
|
+
try {
|
|
253571
|
+
out.push(await fn(ledger));
|
|
253247
253572
|
} catch (err) {
|
|
253248
253573
|
this.o.onError?.(cid, op, err);
|
|
253249
253574
|
}
|
|
@@ -253379,6 +253704,17 @@ var init_cutover_aware_trace = __esm({
|
|
|
253379
253704
|
if (row.state === "frozen") throw new BundleFrozenError("trace");
|
|
253380
253705
|
return this.o.cutover.readsCompanySchema(row) ? this.o.owned : this.o.legacy;
|
|
253381
253706
|
}
|
|
253707
|
+
/**
|
|
253708
|
+
* 这家公司的 trace 当前**物理落在哪**:切走了就是它自己的引擎 schema,没切走就是那个
|
|
253709
|
+
* 所有未切公司共用的 legacy store。
|
|
253710
|
+
*
|
|
253711
|
+
* 给 {@link FanOutTraceStore} 去重用。判据**不在调用方重算**——就是 {@link pick} 那一条
|
|
253712
|
+
* (`cutover.get` + `readsCompanySchema`),照抄一遍就是又造一处会分叉的实现。
|
|
253713
|
+
*/
|
|
253714
|
+
async storageKey() {
|
|
253715
|
+
const row = await this.o.cutover.get(this.o.companyId, "trace");
|
|
253716
|
+
return this.o.cutover.readsCompanySchema(row) ? `owned:${this.o.companyId}` : "legacy";
|
|
253717
|
+
}
|
|
253382
253718
|
// ── run ──────────────────────────────────────────────────────────────────
|
|
253383
253719
|
async createRun(input) {
|
|
253384
253720
|
return (await this.pickWritable()).createRun(input);
|
|
@@ -253496,10 +253832,43 @@ var init_cutover_aware_trace = __esm({
|
|
|
253496
253832
|
constructor(o) {
|
|
253497
253833
|
this.o = o;
|
|
253498
253834
|
}
|
|
253499
|
-
|
|
253835
|
+
/**
|
|
253836
|
+
* 本次要查的物理落点清单——**同一个 store 只出现一次**。
|
|
253837
|
+
*
|
|
253838
|
+
* 为什么必须去重:`trace` 是按 (公司, bundle) 逐个切的,没切走的公司**全部共用同一个
|
|
253839
|
+
* legacy store**(读同一张 `public.agent_runs`)。此前 `union` 直接按公司逐家拼接,于是
|
|
253840
|
+
* 一条 run 在库里只有一行,却被取回 N 份(N = 未切走的公司数)。
|
|
253841
|
+
*
|
|
253842
|
+
* 2026-09-11 v2 生产实证(`ws:wo-9f4652cd`):35 家公司、其中 33 家 trace 未切走,
|
|
253843
|
+
* 动态卡的「执行轨迹」抽屉里同一轮 attempt 出现 **33 次**;`listEvents` 更狠——那一轮
|
|
253844
|
+
* `agent_run_events` 有 1158 行,扇出后返回 ≈3.8 万行,还附带 33 条一模一样的 SQL。
|
|
253845
|
+
* 不是显示层重复,是响应体和查询量一起炸。
|
|
253846
|
+
*
|
|
253847
|
+
* 去重键由 store 自己报,不在这里按 cutover 状态重算(见 `storageKey` 的注释)。
|
|
253848
|
+
* 也不能按 `storeFor` 返回的对象做身份去重:`openCompanyPlane` 给每家各造了一个
|
|
253849
|
+
* `CutoverAwareTraceStore` 包装实例,33 个不同对象包着同一个 legacy store。
|
|
253850
|
+
*/
|
|
253851
|
+
async targets(op) {
|
|
253852
|
+
const out = [];
|
|
253853
|
+
const seen = /* @__PURE__ */ new Set();
|
|
253500
253854
|
for (const cid of await this.o.listCompanies()) {
|
|
253501
253855
|
try {
|
|
253502
|
-
|
|
253856
|
+
if (this.o.storageKeyFor) {
|
|
253857
|
+
const key = await this.o.storageKeyFor(cid);
|
|
253858
|
+
if (seen.has(key)) continue;
|
|
253859
|
+
seen.add(key);
|
|
253860
|
+
}
|
|
253861
|
+
out.push({ cid, store: await this.o.storeFor(cid) });
|
|
253862
|
+
} catch (err) {
|
|
253863
|
+
this.o.onError?.(cid, op, err);
|
|
253864
|
+
}
|
|
253865
|
+
}
|
|
253866
|
+
return out;
|
|
253867
|
+
}
|
|
253868
|
+
async first(op, fn) {
|
|
253869
|
+
for (const { cid, store } of await this.targets(op)) {
|
|
253870
|
+
try {
|
|
253871
|
+
const r = await fn(store);
|
|
253503
253872
|
if (r != null) return r;
|
|
253504
253873
|
} catch (err) {
|
|
253505
253874
|
this.o.onError?.(cid, op, err);
|
|
@@ -253509,20 +253878,26 @@ var init_cutover_aware_trace = __esm({
|
|
|
253509
253878
|
}
|
|
253510
253879
|
async union(op, fn) {
|
|
253511
253880
|
const out = [];
|
|
253512
|
-
for (const cid of await this.
|
|
253881
|
+
for (const { cid, store } of await this.targets(op)) {
|
|
253513
253882
|
try {
|
|
253514
|
-
out.push(...await fn(
|
|
253883
|
+
out.push(...await fn(store));
|
|
253515
253884
|
} catch (err) {
|
|
253516
253885
|
this.o.onError?.(cid, op, err);
|
|
253517
253886
|
}
|
|
253518
253887
|
}
|
|
253519
253888
|
return out;
|
|
253520
253889
|
}
|
|
253521
|
-
/**
|
|
253890
|
+
/**
|
|
253891
|
+
* 这个 run 属于哪一家。写侧要先拿它,别直接写。
|
|
253892
|
+
*
|
|
253893
|
+
* ⚠ 未切走的那批公司共用一张 legacy 表,这里**判不出真正的归属**——它们都「有」这条 run,
|
|
253894
|
+
* 返回的是名单里第一家。去重不改变这个答案(第一家仍是第一家),只是把 N 次重复查询收成一次。
|
|
253895
|
+
* 要真正判准归属,得等 `trace` bundle 切完、每家各有自己的 schema。
|
|
253896
|
+
*/
|
|
253522
253897
|
async companyOfRun(runId) {
|
|
253523
|
-
for (const cid of await this.
|
|
253898
|
+
for (const { cid, store } of await this.targets("companyOfRun")) {
|
|
253524
253899
|
try {
|
|
253525
|
-
if (await
|
|
253900
|
+
if (await store.getRun(runId)) return cid;
|
|
253526
253901
|
} catch (err) {
|
|
253527
253902
|
this.o.onError?.(cid, "companyOfRun", err);
|
|
253528
253903
|
}
|
|
@@ -256328,6 +256703,11 @@ var init_default_company_schema_move = __esm({
|
|
|
256328
256703
|
"chat_sessions",
|
|
256329
256704
|
"event_handler_log",
|
|
256330
256705
|
"events",
|
|
256706
|
+
// 待人确认的 intervention 草案卡(2026-09-11 落库)。与 events/workorders 同族:锚在本公司的
|
|
256707
|
+
// 工单与产物上、不跨公司读,所以**整表搬**。不进 ENGINE_SCHEMA_BUNDLE_TABLES——那份是
|
|
256708
|
+
// legacy 里混着所有公司行的表(dispatches/blobs/trace 一族),只能逐行按归属复制;
|
|
256709
|
+
// 这张表在默认公司 schema 里只有总部自己的卡。
|
|
256710
|
+
"intervention_drafts",
|
|
256331
256711
|
"issue_attachments",
|
|
256332
256712
|
"issue_recipients",
|
|
256333
256713
|
"issue_replies",
|
|
@@ -259405,6 +259785,14 @@ async function startServe(opts) {
|
|
|
259405
259785
|
actorDirectory: registryStore,
|
|
259406
259786
|
// 与 collab 同源;闭包避开下方 listCompanyMembers 声明的 TDZ,实际请求时才读取。
|
|
259407
259787
|
listMembers: (companyId) => listCompanyMembers(companyId),
|
|
259788
|
+
// 改/删项目的门禁判据之一(另一半是项目创建人)——见 domains/projects/routes.ts 的
|
|
259789
|
+
// `requireProjectManagePermission`。同样用闭包避开 listCompanyMembers 的 TDZ。
|
|
259790
|
+
// 成员表按 company_id 有索引、量级几十行,与 `listMembers` 同一次读的成本量级;
|
|
259791
|
+
// 只在 PATCH/DELETE 这两个低频写端点上调,不在任何读热路径上。
|
|
259792
|
+
resolveMemberRole: async (companyId, actorId) => {
|
|
259793
|
+
const members = await listCompanyMembers(companyId);
|
|
259794
|
+
return members.find((m2) => m2.actorId === actorId)?.role;
|
|
259795
|
+
},
|
|
259408
259796
|
resolveActorContext: (actorId) => buildActorContext(actors.service, actorId),
|
|
259409
259797
|
defaultBranchResolver,
|
|
259410
259798
|
// 展示:GET content-locations 给 git 仓补 resolvedDefaultBranch
|
|
@@ -260362,6 +260750,15 @@ async function startServe(opts) {
|
|
|
260362
260750
|
const fanOutTrace = new FanOutTraceStore({
|
|
260363
260751
|
listCompanies: async () => pgPool ? (await controlPlaneStore.listCompanies()).filter((c) => c.status === "active").map((c) => c.id) : [defaultCompanyId],
|
|
260364
260752
|
storeFor: (cid) => traceStoreFor(cid),
|
|
260753
|
+
/**
|
|
260754
|
+
* 去重键:`trace` 未切走的公司全部共用同一个 legacy store,扇出只该查它一次。
|
|
260755
|
+
* 由 store 自己报落点,这里不按 cutover 状态重算(见 FanOutTraceStore.targets 的注释)。
|
|
260756
|
+
* 非 PG / 非 cutover-aware 的路径没有这个方法 ⇒ 退回按公司逐家查,行为不变。
|
|
260757
|
+
*/
|
|
260758
|
+
storageKeyFor: async (cid) => {
|
|
260759
|
+
const s2 = await traceStoreFor(cid);
|
|
260760
|
+
return typeof s2.storageKey === "function" ? s2.storageKey() : cid;
|
|
260761
|
+
},
|
|
260365
260762
|
onError: (cid, op, err) => console.warn(`[trace] ${cid} \u7684 ${op} \u5931\u8D25\uFF08\u5176\u4F59\u516C\u53F8\u7EE7\u7EED\uFF09\uFF1A${String(err)}`)
|
|
260366
260763
|
});
|
|
260367
260764
|
const traceSinkCache = /* @__PURE__ */ new Map();
|
|
@@ -260412,6 +260809,15 @@ async function startServe(opts) {
|
|
|
260412
260809
|
// 只扫 active 的公司:停用公司的台账不该再被兜底扫改写(与本文件其它按公司扇出的地方同口径)。
|
|
260413
260810
|
listCompanies: async () => (await controlPlaneStore.listCompanies()).filter((c) => c.status === "active").map((c) => c.id),
|
|
260414
260811
|
ledgerFor: (cid) => dispatchLedgerFor(cid),
|
|
260812
|
+
/**
|
|
260813
|
+
* 去重键:`dispatch` 未切走的公司全部共用同一张 legacy 台账,扇出只该作用一次。
|
|
260814
|
+
* 由台账自己报落点,这里不按 cutover 状态重算(见 FanOutDispatchLedger.targets 的注释)。
|
|
260815
|
+
* 非 PG / 非 cutover-aware 的路径没有这个方法 ⇒ 退回按公司逐家来,行为不变。
|
|
260816
|
+
*/
|
|
260817
|
+
storageKeyFor: async (cid) => {
|
|
260818
|
+
const l = await dispatchLedgerFor(cid);
|
|
260819
|
+
return typeof l.storageKey === "function" ? l.storageKey() : cid;
|
|
260820
|
+
},
|
|
260415
260821
|
onError: (cid, op, err) => console.warn(`[dispatch-ledger] ${cid} \u7684 ${op} \u5931\u8D25\uFF08\u5176\u4F59\u516C\u53F8\u7EE7\u7EED\uFF09\uFF1A${String(err)}`)
|
|
260416
260822
|
}) : dispatchLedger;
|
|
260417
260823
|
const companyRegistryFor = async (companyId) => pgPool ? (await openCompanyPlane(companyId)).overlay : scopedRegistryFor(companyId);
|
|
@@ -265063,7 +265469,8 @@ var SessionProcessState = class {
|
|
|
265063
265469
|
// 只报 dispatchId 的话 serve 重启后它认不出这是条活会话,会当成野进程 evict 掉。
|
|
265064
265470
|
...this.spec.job.artifactId ? { jobArtifactId: this.spec.job.artifactId } : {},
|
|
265065
265471
|
// ADR 0300 D2:自报支持帧号;新服务端据此回带 ackSeq 的 hello-ack,届时才把 serverSupportsDedup 置真。
|
|
265066
|
-
supportsFrameSeq: true
|
|
265472
|
+
supportsFrameSeq: true,
|
|
265473
|
+
supportsInputConsumptionReceipts: true
|
|
265067
265474
|
});
|
|
265068
265475
|
const toResend = this.serverSupportsDedup ? this.outbox : this.outbox.filter(isKeyFrame);
|
|
265069
265476
|
for (const m2 of toResend) this.rawSend(m2);
|
|
@@ -268370,6 +268777,28 @@ var ASYNC_AUTH_MESSAGE = "\u5DF2\u63D0\u4EA4\u4EBA\u5DE5\u5BA1\u6838\uFF1B\u5148
|
|
|
268370
268777
|
function asyncAuthorizationReturn(data) {
|
|
268371
268778
|
return data !== void 0 ? { message: ASYNC_AUTH_MESSAGE, data } : { message: ASYNC_AUTH_MESSAGE };
|
|
268372
268779
|
}
|
|
268780
|
+
var AUTH_CARD_GONE_MESSAGE = "\u8FD9\u5F20\u5F85\u6388\u6743\u5361\u5DF2\u7ECF\u4E0D\u5728\u5F85\u5904\u7406\u5217\u8868\u91CC\u4E86\u2014\u2014\u53EF\u80FD\u5DF2\u88AB\u4EBA\u5904\u7F6E\uFF0C\u4E5F\u53EF\u80FD\u5DF2\u5931\u6548\u3002**\u522B\u518D\u8BA9\u7528\u6237\u53BB\u6536\u4EF6\u7BB1\u627E\u8FD9\u5F20\u5361**\uFF1A\u5148\u7528\u53EA\u8BFB\u547D\u4EE4\u6838\u5BF9\u5F53\u524D\u72B6\u6001\uFF08\u5982 `oasis status <\u8282\u70B9>`\uFF09\uFF0C\u786E\u8BA4\u8FD9\u4EF6\u4E8B\u6CA1\u751F\u6548\uFF0C\u518D\u91CD\u65B0\u53D1\u8D77\u540C\u4E00\u6761\u547D\u4EE4\u3002";
|
|
268781
|
+
function authorizationGoneReturn(draftId) {
|
|
268782
|
+
return { message: AUTH_CARD_GONE_MESSAGE, data: { outcome: "authorization-gone", draftId } };
|
|
268783
|
+
}
|
|
268784
|
+
async function draftStillPending(base, headers, draftId) {
|
|
268785
|
+
try {
|
|
268786
|
+
const ctrl = new AbortController();
|
|
268787
|
+
const timer = setTimeout(() => ctrl.abort(), 5e3);
|
|
268788
|
+
timer.unref?.();
|
|
268789
|
+
try {
|
|
268790
|
+
const res = await fetch(`${base}/api/view?name=intervention-drafts`, { headers, signal: ctrl.signal });
|
|
268791
|
+
if (!res.ok) return null;
|
|
268792
|
+
const body2 = await res.json();
|
|
268793
|
+
if (!Array.isArray(body2.data)) return null;
|
|
268794
|
+
return body2.data.some((d) => d?.id === draftId);
|
|
268795
|
+
} finally {
|
|
268796
|
+
clearTimeout(timer);
|
|
268797
|
+
}
|
|
268798
|
+
} catch {
|
|
268799
|
+
return null;
|
|
268800
|
+
}
|
|
268801
|
+
}
|
|
268373
268802
|
function renderGraphLines(graph) {
|
|
268374
268803
|
const closureIds = new Set(graph.nodes.filter((n) => n.type === DELIVERY_SUMMARY_ARTIFACT_TYPE).map((n) => n.id));
|
|
268375
268804
|
const out = ["\n\u8282\u70B9\uFF08\u6539\u56FE\u5F15\u7528\u7528\u8FD9\u4E9B id\uFF09:"];
|
|
@@ -268391,6 +268820,10 @@ function resolveAuthWaitMs() {
|
|
|
268391
268820
|
}
|
|
268392
268821
|
async function waitForCommandAuthorization(base, headers, draftId, fallback) {
|
|
268393
268822
|
const asyncFallback = asyncAuthorizationReturn(fallback.data);
|
|
268823
|
+
const giveUp = async () => {
|
|
268824
|
+
const pending = await draftStillPending(base, headers, draftId);
|
|
268825
|
+
return pending === false ? authorizationGoneReturn(draftId) : asyncFallback;
|
|
268826
|
+
};
|
|
268394
268827
|
const timeoutMs = resolveAuthWaitMs();
|
|
268395
268828
|
const controller = new AbortController();
|
|
268396
268829
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
@@ -268448,12 +268881,13 @@ async function waitForCommandAuthorization(base, headers, draftId, fallback) {
|
|
|
268448
268881
|
data: { outcome: "denied", draftId }
|
|
268449
268882
|
};
|
|
268450
268883
|
}
|
|
268451
|
-
return
|
|
268884
|
+
if (p2.status === "gone") return authorizationGoneReturn(draftId);
|
|
268885
|
+
return await giveUp();
|
|
268452
268886
|
}
|
|
268453
268887
|
}
|
|
268454
|
-
return
|
|
268888
|
+
return await giveUp();
|
|
268455
268889
|
} catch {
|
|
268456
|
-
return
|
|
268890
|
+
return await giveUp();
|
|
268457
268891
|
} finally {
|
|
268458
268892
|
clearTimeout(timer);
|
|
268459
268893
|
clearInterval(progress);
|
|
@@ -271958,7 +272392,7 @@ function shimScript() {
|
|
|
271958
272392
|
}
|
|
271959
272393
|
|
|
271960
272394
|
// src/index.ts
|
|
271961
|
-
var PKG_VERSION = true ? "2.2.
|
|
272395
|
+
var PKG_VERSION = true ? "2.2.19" : "dev";
|
|
271962
272396
|
var LOCAL_BIN = localBin();
|
|
271963
272397
|
var NPM_PREFIX = npmPrefix();
|
|
271964
272398
|
var INSTANCE = DEFAULT_INSTANCE;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oasis_test_v2",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.19",
|
|
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": "2b179b35f141bdd0e3785e0cf069d22b76fc8a37"
|
|
30
30
|
}
|
|
31
31
|
}
|