oasis_test_v2 2.2.13 → 2.2.14
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 +93 -17
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -203682,6 +203682,14 @@ async function runView(kernel, oplog, engineStore, blobs, name, artifactId, para
|
|
|
203682
203682
|
throw new Error(`\u672A\u77E5\u89C6\u56FE: ${name}`);
|
|
203683
203683
|
}
|
|
203684
203684
|
}
|
|
203685
|
+
function resolveListenTarget(env, pid, port) {
|
|
203686
|
+
const count2 = Number(env["LISTEN_FDS"] ?? "0");
|
|
203687
|
+
const listenPid = env["LISTEN_PID"];
|
|
203688
|
+
if (Number.isFinite(count2) && count2 >= 1 && (!listenPid || listenPid === String(pid))) {
|
|
203689
|
+
return { fd: 3 };
|
|
203690
|
+
}
|
|
203691
|
+
return { port: port ?? 0, host: "0.0.0.0" };
|
|
203692
|
+
}
|
|
203685
203693
|
async function startOasisServer(opts) {
|
|
203686
203694
|
const resolveActor = opts.resolveActor ?? defaultResolveActor;
|
|
203687
203695
|
const defaultDraftPlannerIssuesStore = new MemoryWorkorderDraftPlannerIssuesStore();
|
|
@@ -207700,7 +207708,7 @@ ${composed}`;
|
|
|
207700
207708
|
});
|
|
207701
207709
|
httpServer.keepAliveTimeout = 65e3;
|
|
207702
207710
|
httpServer.headersTimeout = 66e3;
|
|
207703
|
-
await new Promise((resolve10) => httpServer.listen(
|
|
207711
|
+
await new Promise((resolve10) => httpServer.listen(resolveListenTarget(process.env, process.pid, opts.port), resolve10));
|
|
207704
207712
|
const address = httpServer.address();
|
|
207705
207713
|
if (address === null || typeof address === "string") throw new Error("listen failed");
|
|
207706
207714
|
const baseUrl = `http://127.0.0.1:${address.port}`;
|
|
@@ -207719,14 +207727,41 @@ ${composed}`;
|
|
|
207719
207727
|
* 委派域没装配时返回 null,调用方照常。
|
|
207720
207728
|
*/
|
|
207721
207729
|
settleDelegationFromSweep: (childSessionId, reason, companyId, opts2) => delegationService?.settleFromSweep(childSessionId, reason, companyId, opts2) ?? Promise.resolve(null),
|
|
207722
|
-
|
|
207730
|
+
/**
|
|
207731
|
+
* @param opts.drainMs **优雅停机预算**(毫秒)。缺省 0 = 老行为:立刻掐断所有连接后关闭。
|
|
207732
|
+
*
|
|
207733
|
+
* 给了预算就改成「排空」:先 `close()` 停收新连接、`closeIdleConnections()` 放掉空闲的
|
|
207734
|
+
* keep-alive,**在途请求让它跑完**;预算到点还没走完的(SSE 这类长连接本来就不会自己结束)
|
|
207735
|
+
* 再 `closeAllConnections()` 强断。前端的流有重连(`hydrateAndAttach`),被强断能自愈;
|
|
207736
|
+
* 普通请求跑到一半被掐则是实打实的失败,所以要给它们这几百毫秒。
|
|
207737
|
+
*
|
|
207738
|
+
* 生产上这条由 `oasis serve` 的 SIGTERM 处理器传(见 cli.ts)——现在 systemd 是硬杀
|
|
207739
|
+
* (journal: `code=exited, status=143`),在途请求当场断。
|
|
207740
|
+
*/
|
|
207741
|
+
close: async (opts2) => {
|
|
207723
207742
|
if (broadcastTimer) clearInterval(broadcastTimer);
|
|
207724
207743
|
if (pendingSystemNoticesRecoveryTimer) clearInterval(pendingSystemNoticesRecoveryTimer);
|
|
207725
207744
|
await knowledgeDomain?.close();
|
|
207726
207745
|
channelWsSupervisor?.stop();
|
|
207746
|
+
const drainMs = opts2?.drainMs ?? 0;
|
|
207727
207747
|
await new Promise((resolve10, reject) => {
|
|
207728
|
-
|
|
207729
|
-
|
|
207748
|
+
let sweep;
|
|
207749
|
+
let force;
|
|
207750
|
+
httpServer.close((err) => {
|
|
207751
|
+
if (sweep) clearInterval(sweep);
|
|
207752
|
+
if (force) clearTimeout(force);
|
|
207753
|
+
if (err) reject(err);
|
|
207754
|
+
else resolve10();
|
|
207755
|
+
});
|
|
207756
|
+
if (drainMs > 0) {
|
|
207757
|
+
httpServer.closeIdleConnections();
|
|
207758
|
+
sweep = setInterval(() => httpServer.closeIdleConnections(), 100);
|
|
207759
|
+
sweep.unref?.();
|
|
207760
|
+
force = setTimeout(() => httpServer.closeAllConnections(), drainMs);
|
|
207761
|
+
force.unref?.();
|
|
207762
|
+
} else {
|
|
207763
|
+
httpServer.closeAllConnections();
|
|
207764
|
+
}
|
|
207730
207765
|
});
|
|
207731
207766
|
}
|
|
207732
207767
|
};
|
|
@@ -210837,6 +210872,18 @@ var init_projection = __esm({
|
|
|
210837
210872
|
function isUncategorizedProjectId(projectId2) {
|
|
210838
210873
|
return projectId2 === UNCATEGORIZED_PROJECT_ID;
|
|
210839
210874
|
}
|
|
210875
|
+
function latestUncategorizedActivityAt(candidates) {
|
|
210876
|
+
let bestIso = UNCATEGORIZED_UNKNOWN_TIME;
|
|
210877
|
+
let bestMs = Date.parse(UNCATEGORIZED_UNKNOWN_TIME);
|
|
210878
|
+
for (const iso6 of candidates) {
|
|
210879
|
+
if (!iso6) continue;
|
|
210880
|
+
const ms = Date.parse(iso6);
|
|
210881
|
+
if (Number.isNaN(ms) || ms <= bestMs) continue;
|
|
210882
|
+
bestMs = ms;
|
|
210883
|
+
bestIso = iso6;
|
|
210884
|
+
}
|
|
210885
|
+
return bestIso;
|
|
210886
|
+
}
|
|
210840
210887
|
async function bindWorkorderProject(deps) {
|
|
210841
210888
|
const { workOrderId, projectId: projectId2 } = deps;
|
|
210842
210889
|
if (!projectId2) return null;
|
|
@@ -211472,6 +211519,10 @@ var init_service4 = __esm({
|
|
|
211472
211519
|
async buildUncategorizedProject() {
|
|
211473
211520
|
const workorders = await this.listProjectWorkorders(UNCATEGORIZED_PROJECT_ID);
|
|
211474
211521
|
const artifactList = await this.aggregateUncategorizedArtifacts();
|
|
211522
|
+
const updatedAt = latestUncategorizedActivityAt([
|
|
211523
|
+
...workorders.map((workorder) => workorder.updatedAt),
|
|
211524
|
+
...artifactList.artifacts.map((artifact) => artifact.updatedAt)
|
|
211525
|
+
]);
|
|
211475
211526
|
return {
|
|
211476
211527
|
id: UNCATEGORIZED_PROJECT_ID,
|
|
211477
211528
|
name: UNCATEGORIZED_PROJECT_NAME,
|
|
@@ -211484,7 +211535,7 @@ var init_service4 = __esm({
|
|
|
211484
211535
|
// 出 null 保持「取不到就 null」的域内红线,也不把一个不存在的 actor id 塞进契约。
|
|
211485
211536
|
createdBy: null,
|
|
211486
211537
|
createdAt: UNCATEGORIZED_UNKNOWN_TIME,
|
|
211487
|
-
updatedAt
|
|
211538
|
+
updatedAt
|
|
211488
211539
|
};
|
|
211489
211540
|
}
|
|
211490
211541
|
async aggregateUncategorizedArtifacts() {
|
|
@@ -223362,8 +223413,12 @@ function toApiProject(project) {
|
|
|
223362
223413
|
// - 取不到创建人 → `null`(老的手建项目 / 无分类虚拟卡),前端显示「—」;
|
|
223363
223414
|
// - 有 id 但名册解析不到 → 对象在、`name`/`avatar` 为 `null`(**不回落 id 尾段**)。
|
|
223364
223415
|
created_by: project.createdBy ? toApiProjectActorRef(project.createdBy) : null,
|
|
223365
|
-
//
|
|
223366
|
-
//
|
|
223416
|
+
// 「时间不可知」哨兵(`UNCATEGORIZED_UNKNOWN_TIME`)→ `null`,前端见 null 显示「—」而不是
|
|
223417
|
+
// 一串远古时间。**只有无分类虚拟卡会命中**,真项目不受影响(建项目时两个字段都写真时间戳)。
|
|
223418
|
+
// 命中的两种情形(2026-09-10 起):
|
|
223419
|
+
// · `created_at`:恒命中——桶不存在「被创建」这回事;
|
|
223420
|
+
// · `updated_at`:只在桶里空无一物时命中;桶里有工单/产物时是真时间(见 service.ts
|
|
223421
|
+
// `buildUncategorizedProject` 与 `latestUncategorizedActivityAt`)。
|
|
223367
223422
|
created_at: project.createdAt === UNCATEGORIZED_UNKNOWN_TIME ? null : project.createdAt,
|
|
223368
223423
|
updated_at: project.updatedAt === UNCATEGORIZED_UNKNOWN_TIME ? null : project.updatedAt
|
|
223369
223424
|
};
|
|
@@ -234856,6 +234911,12 @@ function payloadStr(payload, key) {
|
|
|
234856
234911
|
}
|
|
234857
234912
|
return "";
|
|
234858
234913
|
}
|
|
234914
|
+
function workorderGoal(title, prefix, suffix) {
|
|
234915
|
+
const subject = Array.from(title.replace(/\s+/g, " ").trim());
|
|
234916
|
+
const budget = 50 - Array.from(prefix + suffix).length;
|
|
234917
|
+
const shortTitle = subject.length > budget ? `${subject.slice(0, budget - 1).join("")}\u2026` : subject.join("");
|
|
234918
|
+
return `${prefix}${shortTitle}${suffix}`;
|
|
234919
|
+
}
|
|
234859
234920
|
function buildPlan(structure, title, ctx, opts = {}) {
|
|
234860
234921
|
const nodeOwners = payloadNodeOwners(ctx.payload);
|
|
234861
234922
|
const nodeReviewers = payloadNodeReviewers(ctx.payload);
|
|
@@ -234915,9 +234976,7 @@ function bugFixResolve(ctx) {
|
|
|
234915
234976
|
artifactType: "diagnosis",
|
|
234916
234977
|
title,
|
|
234917
234978
|
brief,
|
|
234918
|
-
|
|
234919
|
-
// 但字段本身在内核里有设计意图(workorderSpec 读它),故填上而非留空。
|
|
234920
|
-
goal: title,
|
|
234979
|
+
goal: workorderGoal(title, "\u4FEE\u590D\u300C", "\u300D\uFF0C\u9A8C\u8BC1\u6240\u62A5\u73B0\u8C61\u4E0D\u518D\u51FA\u73B0\u3002"),
|
|
234921
234980
|
...manager ? { manager } : {},
|
|
234922
234981
|
acceptanceCriteria: ["\u6309\u63CF\u8FF0\u91CC\u7684\u590D\u73B0\u65B9\u5F0F\u9A8C\u8BC1\uFF1A\u6240\u62A5\u73B0\u8C61\u4E0D\u518D\u51FA\u73B0", "\u6539\u52A8\u6CA1\u6709\u660E\u663E\u6253\u574F\u76F4\u63A5\u76F8\u90BB\u7684\u8DEF\u5F84"],
|
|
234923
234982
|
plan
|
|
@@ -234948,7 +235007,7 @@ function adoptExternalResolve(ctx) {
|
|
|
234948
235007
|
artifactType: "research",
|
|
234949
235008
|
title,
|
|
234950
235009
|
brief,
|
|
234951
|
-
goal: title,
|
|
235010
|
+
goal: workorderGoal(title, "\u56F4\u7ED5\u300C", "\u300D\u501F\u9274\u5916\u90E8\u65B9\u6848\uFF0C\u5B8C\u6210\u843D\u5730\u5E76\u9A8C\u8BC1\u6548\u679C\u3002"),
|
|
234952
235011
|
...manager ? { manager } : {},
|
|
234953
235012
|
acceptanceCriteria: [
|
|
234954
235013
|
"\u843D\u5730\u65B9\u6848\u9010\u6761\u8BF4\u660E\u4E86\u4E3A\u4EC0\u4E48\u4E0D\u76F4\u63A5\u91C7\u7528\u5DF2\u77E5\u89E3\u6CD5\uFF0C\u5E76\u5199\u660E\u6211\u4EEC\u65B9\u6848\u7684\u4EE3\u4EF7",
|
|
@@ -234979,7 +235038,7 @@ function simpleTaskResolve(ctx) {
|
|
|
234979
235038
|
artifactType: "research",
|
|
234980
235039
|
title,
|
|
234981
235040
|
brief,
|
|
234982
|
-
goal: title,
|
|
235041
|
+
goal: workorderGoal(title, "\u5B8C\u6210\u300C", "\u300D\uFF0C\u4EA4\u4ED8\u53D1\u8D77\u4EBA\u53EF\u76F4\u63A5\u4F7F\u7528\u7684\u7ED3\u679C\u3002"),
|
|
234983
235042
|
...manager ? { manager } : {},
|
|
234984
235043
|
plan
|
|
234985
235044
|
};
|
|
@@ -264088,7 +264147,8 @@ ${nodeFault}` : "");
|
|
|
264088
264147
|
baseUrl: server.baseUrl,
|
|
264089
264148
|
operatorToken,
|
|
264090
264149
|
__coordinatorSpawnProbe: coordinatorSpawnProbe,
|
|
264091
|
-
close
|
|
264150
|
+
/** @param opts.drainMs 优雅停机排空预算,原样透传给 HTTP 层(见 server.ts 的 close)。缺省 = 老行为。 */
|
|
264151
|
+
close: async (opts2) => {
|
|
264092
264152
|
for (const timer of dispatchTimers) clearInterval(timer);
|
|
264093
264153
|
clearInterval(slaTimer);
|
|
264094
264154
|
escalationDeliveryWorker.stop();
|
|
@@ -264107,7 +264167,7 @@ ${nodeFault}` : "");
|
|
|
264107
264167
|
if (boardWatchTimer) clearInterval(boardWatchTimer);
|
|
264108
264168
|
clearInterval(serverHeartbeatTimer);
|
|
264109
264169
|
hub?.close();
|
|
264110
|
-
await server.close();
|
|
264170
|
+
await server.close(opts2 ?? {});
|
|
264111
264171
|
if (pgPool) await pgPool.end().catch(() => {
|
|
264112
264172
|
});
|
|
264113
264173
|
releaseServeLock(lock);
|
|
@@ -268326,9 +268386,25 @@ async function runCli(argv, println = console.log, progressln = console.error) {
|
|
|
268326
268386
|
println(`oasis serve \u5C31\u7EEA\uFF1Ahttp://0.0.0.0:${port2}\uFF08\u672C\u673A\u8BBF\u95EE\u7528 http://127.0.0.1:${port2}\uFF09`);
|
|
268327
268387
|
println(`operator token \u5DF2\u5199\u5165 ${path35.join(dir, "operator-token")}\uFF08\u672C\u673A CLI \u81EA\u52A8\u8BFB\u53D6\uFF09`);
|
|
268328
268388
|
if (flags.get("dispatch") === "true") println(`\u8C03\u5EA6\u5FAA\u73AF\u5DF2\u542F\u52A8\uFF08claude-code adapter\uFF09`);
|
|
268329
|
-
|
|
268389
|
+
const drainMs = Number(process.env["OASIS_SHUTDOWN_DRAIN_MS"] ?? "3000");
|
|
268390
|
+
const shutdownBudgetMs = drainMs + 5e3;
|
|
268391
|
+
await new Promise((resolve10) => {
|
|
268392
|
+
let stopping = false;
|
|
268393
|
+
const stop = (signal) => {
|
|
268394
|
+
if (stopping) return;
|
|
268395
|
+
stopping = true;
|
|
268396
|
+
println(`[serve] \u6536\u5230 ${signal}\uFF0C\u5F00\u59CB\u4F18\u96C5\u505C\u673A\uFF08\u6392\u7A7A\u9884\u7B97 ${drainMs}ms\uFF09\u2026`);
|
|
268397
|
+
const hardExit = setTimeout(() => {
|
|
268398
|
+
println(`[serve] \u505C\u673A\u603B\u9884\u7B97 ${shutdownBudgetMs}ms \u7528\u5C3D\uFF0C\u5F3A\u5236\u9000\u51FA`);
|
|
268399
|
+
process.exit(0);
|
|
268400
|
+
}, shutdownBudgetMs);
|
|
268401
|
+
hardExit.unref?.();
|
|
268402
|
+
void handle.close({ drainMs }).then(() => println("[serve] \u5DF2\u4F18\u96C5\u505C\u673A")).catch((err) => println(`[serve] \u505C\u673A\u8FC7\u7A0B\u51FA\u9519\uFF08\u7167\u5E38\u9000\u51FA\uFF09\uFF1A${String(err)}`)).finally(() => resolve10());
|
|
268403
|
+
};
|
|
268404
|
+
process.once("SIGTERM", () => stop("SIGTERM"));
|
|
268405
|
+
process.once("SIGINT", () => stop("SIGINT"));
|
|
268330
268406
|
});
|
|
268331
|
-
|
|
268407
|
+
process.exit(0);
|
|
268332
268408
|
}
|
|
268333
268409
|
const base = flags.get("server") ?? process.env["OASIS_SERVER"] ?? "http://127.0.0.1:7320";
|
|
268334
268410
|
const tokenFile = path35.join(dir, "operator-token");
|
|
@@ -271356,7 +271432,7 @@ function shimScript() {
|
|
|
271356
271432
|
}
|
|
271357
271433
|
|
|
271358
271434
|
// src/index.ts
|
|
271359
|
-
var PKG_VERSION = true ? "2.2.
|
|
271435
|
+
var PKG_VERSION = true ? "2.2.14" : "dev";
|
|
271360
271436
|
var LOCAL_BIN = localBin();
|
|
271361
271437
|
var NPM_PREFIX = npmPrefix();
|
|
271362
271438
|
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.14",
|
|
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": "c6b9e871786ca57b2d1b01293c368ed043db700f"
|
|
30
30
|
}
|
|
31
31
|
}
|