oasis_test_v2 2.1.0 → 2.1.1
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 +182 -45
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1391,6 +1391,11 @@ var init_delegation_prompts = __esm({
|
|
|
1391
1391
|
"**\u522B\u628A\u5224\u65AD\u8FC7\u7A0B\u8BF4\u7ED9\u7528\u6237**\uFF08\u4E0D\u62A5\u300C\u6211\u8BC4\u4F30\u4E86\u4E0B\u80FD\u529B\u8FB9\u754C\u300D\u300C\u5019\u9009\u6709 3 \u4E2A\u300D\u300C\u6B63\u5728\u9009\u4EBA\u300D\uFF09\uFF0C",
|
|
1392
1392
|
"\u4E5F**\u522B\u8BA9\u7528\u6237\u81EA\u5DF1\u4ECE\u540D\u5355\u91CC\u6311\u4EBA**\u3002\u4ED6\u53EA\u8BE5\u770B\u5230\uFF1A\u4F60\u7684\u8FFD\u95EE\u3001\u4F60\u5728\u505A\u4EC0\u4E48\u3001\u4EE5\u53CA\u9700\u8981\u4ED6\u786E\u8BA4\u65F6\u7684\u90A3\u5F20\u5361\u3002",
|
|
1393
1393
|
"",
|
|
1394
|
+
"### \u7528\u6237\u76F4\u63A5\u95EE\u300C\u6709\u54EA\u4E9B\u4EBA / agent\u300D\uFF1A\u522B\u8D70\u4E0B\u9762\u8FD9\u5957",
|
|
1395
|
+
"",
|
|
1396
|
+
"\u90A3\u662F\u5728\u95EE\u82B1\u540D\u518C\uFF0C\u4E0D\u662F\u8BA9\u4F60\u5206\u6D41\u3002\u76F4\u63A5 `oasis actors` \u5982\u5B9E\u5217\uFF08**\u542B `(\u65E0\u5C97\u4F4D)` \u7684**\uFF09\u3002",
|
|
1397
|
+
"**\u522B\u62FF `oasis roles` \u7684\u5728\u5C97\u4EBA\u6570\u56DE\u7B54\u8FD9\u4E2A\u95EE\u9898**\u2014\u2014\u5B83\u53EA\u6570\u5C97\u4F4D\u3001\u4E0D\u5217\u4EBA\u3002",
|
|
1398
|
+
"",
|
|
1394
1399
|
"### \u5148\u770B\u76EE\u6807\u6E05\u4E0D\u6E05\u695A",
|
|
1395
1400
|
"",
|
|
1396
1401
|
"\u4E0D\u6E05\u695A\u5C31**\u53EA\u8FFD\u95EE\u3001\u522B\u52A8\u624B**\u2014\u2014\u522B\u628A\u4E00\u4E2A\u6A21\u7CCA\u76EE\u6807\u4E22\u7ED9\u4E13\u5BB6\u6216\u5DE5\u5355\uFF0C\u90A3\u662F\u628A\u4F60\u7684\u4E0D\u786E\u5B9A\u8F6C\u5AC1\u51FA\u53BB\u3002",
|
|
@@ -1403,9 +1408,12 @@ var init_delegation_prompts = __esm({
|
|
|
1403
1408
|
"",
|
|
1404
1409
|
" oasis roles # \u6BCF\u4E2A\u5C97\u4F4D\u8D1F\u8D23\xB7\u8BC4\u5BA1\u54EA\u4E9B\u4EA4\u4ED8\u7269\u3001\u8FD8\u6709\u51E0\u4EBA\u5728\u5C97",
|
|
1405
1410
|
" oasis actors --role <\u5C97\u4F4D> # \u90A3\u4E2A\u5C97\u4F4D\u73B0\u5728\u6709\u8C01\u53EF\u6D3E",
|
|
1411
|
+
" oasis actors # \u5168\u90E8\u5728\u5C97\u7684\u4EBA/agent\uFF08\u672A\u8BBE\u5C97\u4F4D\u7684\u53EA\u6709\u8FD9\u6761\u770B\u5F97\u89C1\uFF09",
|
|
1406
1412
|
"",
|
|
1407
1413
|
"**\u53EA\u8BA4\u660E\u786E\u5199\u4E86\u300C\u8D1F\u8D23 <\u67D0\u7C7B\u4EA4\u4ED8\u7269>\u300D\u7684\u5C97\u4F4D\u3002**\u53EA\u6709\u4E00\u4E2A\u540D\u5B57\u3001\u6CA1\u5199\u8D1F\u8D23\u4EC0\u4E48\u7684\uFF0C",
|
|
1408
1414
|
"\u4E00\u5F8B**\u5F53\u4F5C\u6CA1\u6709\u5BF9\u53E3\u5C97\u4F4D**\u2014\u2014\u90A3\u79CD\u5C97\u4F4D\u6D3E\u8FC7\u53BB\u591A\u534A\u662F\u7A7A\u8F6C\u3002",
|
|
1415
|
+
"**\u4F46\u300C\u6CA1\u6709\u5BF9\u53E3\u5C97\u4F4D\u300D\u2260\u300C\u6CA1\u4EBA\u53EF\u7528\u300D**\uFF1A\u6709\u7684 agent \u6545\u610F\u4E0D\u8BBE\u5C97\u4F4D\uFF08`actors` \u91CC\u663E\u793A `(\u65E0\u5C97\u4F4D)`\uFF09\uFF0C",
|
|
1416
|
+
"\u4E0D\u8FDB\u6309\u5C97\u4F4D\u5206\u6D41\uFF0C\u4F46\u80FD `--to <actorId>` \u70B9\u540D\u6D3E\u3002`roles` \u6570\u51FA 0 \u4EBA**\u4E0D\u7B49\u4E8E**\u6CA1\u6709 agent\u2014\u2014\u5B83\u4E0D\u5217\u4EBA\u3002",
|
|
1409
1417
|
"",
|
|
1410
1418
|
"- **\u6709\u5BF9\u53E3\u5C97\u4F4D + \u6709\u4EBA\u5728\u5C97** \u2192 \u518D\u95EE\u4E00\u53E5\uFF1A**\u8FD9\u6D3B\u8981\u90A3\u4E2A\u5C97\u4F4D\u505A\u5224\u65AD\uFF0C\u8FD8\u662F\u53EA\u8981\u6309\u5DF2\u7ED9\u7684\u5185\u5BB9\u548C\u5DF2\u6709\u7684\u98CE\u683C\u6267\u884C\uFF1F**",
|
|
1411
1419
|
" - \u8981\u51FA\u65B0\u8BBE\u8BA1\u3001\u8981\u4E0B\u7814\u7A76\u7ED3\u8BBA\u3001\u8981\u505A\u6280\u672F\u9009\u578B \u2192 \u5F80 \u2461 \u770B\u662F\u4E0D\u662F\u591A\u4EF6\uFF0C\u7136\u540E\u59D4\u6D3E\u3002",
|
|
@@ -17692,12 +17700,12 @@ function mapIssueKindToAnnotationKind(k2) {
|
|
|
17692
17700
|
return k2 === "change_request" ? "change-request" : "comment";
|
|
17693
17701
|
}
|
|
17694
17702
|
function nodeToArtifact(node2, edges, requirements) {
|
|
17695
|
-
const inputs = edges.
|
|
17703
|
+
const inputs = edges.map((e) => ({
|
|
17696
17704
|
to: e.fromNodeId,
|
|
17697
17705
|
pinned: e.pinnedWorkId ?? null,
|
|
17698
17706
|
required: e.required
|
|
17699
17707
|
}));
|
|
17700
|
-
const nodeReqs = requirements
|
|
17708
|
+
const nodeReqs = requirements;
|
|
17701
17709
|
const reviewers = nodeReqs.length > 0 ? nodeReqs.map((r) => ({
|
|
17702
17710
|
actor: r.reviewerActorId,
|
|
17703
17711
|
source: r.source,
|
|
@@ -17736,9 +17744,8 @@ function nodeToArtifact(node2, edges, requirements) {
|
|
|
17736
17744
|
};
|
|
17737
17745
|
}
|
|
17738
17746
|
function workToRevision(w2, workInputs, artifactFiles) {
|
|
17739
|
-
const inputs = workInputs.filter((i) => i.workId === w2.id);
|
|
17740
17747
|
const basedOn = {};
|
|
17741
|
-
for (const i of
|
|
17748
|
+
for (const i of workInputs) {
|
|
17742
17749
|
basedOn[i.upstreamNodeId] = i.upstreamWorkId;
|
|
17743
17750
|
}
|
|
17744
17751
|
const files = artifactFiles.get(w2.id);
|
|
@@ -17781,7 +17788,7 @@ function issueToAnnotation(issue2, replies, recipients) {
|
|
|
17781
17788
|
target: issue2.aboutWorkId ?? issue2.aboutNodeId ?? "",
|
|
17782
17789
|
span: void 0
|
|
17783
17790
|
};
|
|
17784
|
-
const ownReplies = replies.
|
|
17791
|
+
const ownReplies = replies.slice().sort((a, b2) => a.createdAt < b2.createdAt ? -1 : a.createdAt > b2.createdAt ? 1 : 0);
|
|
17785
17792
|
const thread = ownReplies.map((r, i) => ({
|
|
17786
17793
|
author: r.authorActorId,
|
|
17787
17794
|
ts: r.createdAt,
|
|
@@ -17875,9 +17882,8 @@ function buildGateFromRequirements(reqs) {
|
|
|
17875
17882
|
});
|
|
17876
17883
|
return { requirements: contractReqs, eligible, quorum };
|
|
17877
17884
|
}
|
|
17878
|
-
function workToConcludeAttempt(w2,
|
|
17885
|
+
function workToConcludeAttempt(w2, reqs) {
|
|
17879
17886
|
if (w2.acceptanceState === "draft" || (w2.acceptanceState === null || w2.acceptanceState === "rejected") && w2.status === "success" && w2.conclusion != null) {
|
|
17880
|
-
const reqs = requirements.filter((r) => r.nodeId === w2.nodeId);
|
|
17881
17887
|
if (reqs.length === 0) return null;
|
|
17882
17888
|
return {
|
|
17883
17889
|
head: w2.id,
|
|
@@ -17889,7 +17895,6 @@ function workToConcludeAttempt(w2, requirements, reviews) {
|
|
|
17889
17895
|
};
|
|
17890
17896
|
}
|
|
17891
17897
|
if (w2.acceptanceState === "accepted" && w2.outputVersionNo !== null) {
|
|
17892
|
-
const reqs = requirements.filter((r) => r.nodeId === w2.nodeId);
|
|
17893
17898
|
return {
|
|
17894
17899
|
head: w2.id,
|
|
17895
17900
|
openedOn: w2.id,
|
|
@@ -17901,6 +17906,16 @@ function workToConcludeAttempt(w2, requirements, reviews) {
|
|
|
17901
17906
|
}
|
|
17902
17907
|
return null;
|
|
17903
17908
|
}
|
|
17909
|
+
function groupRows(rows, keyOf3) {
|
|
17910
|
+
const groups = /* @__PURE__ */ new Map();
|
|
17911
|
+
for (const row of rows) {
|
|
17912
|
+
const key = keyOf3(row);
|
|
17913
|
+
const group = groups.get(key);
|
|
17914
|
+
if (group) group.push(row);
|
|
17915
|
+
else groups.set(key, [row]);
|
|
17916
|
+
}
|
|
17917
|
+
return groups;
|
|
17918
|
+
}
|
|
17904
17919
|
function bridgeLoadReadModel(input) {
|
|
17905
17920
|
const { snapshots: snapshots2, reworkWavefront = false, convergenceUnified = false, disabledActors } = input;
|
|
17906
17921
|
const allNodes = [];
|
|
@@ -17930,12 +17945,18 @@ function bridgeLoadReadModel(input) {
|
|
|
17930
17945
|
name: a.name
|
|
17931
17946
|
})));
|
|
17932
17947
|
}
|
|
17948
|
+
const inputsByWork = groupRows(allWorkInputs, (i) => i.workId);
|
|
17949
|
+
const edgesByTarget = groupRows(allEdges, (e) => e.toNodeId);
|
|
17950
|
+
const requirementsByNode = groupRows(allRequirements, (r) => r.nodeId);
|
|
17951
|
+
const repliesByIssue = groupRows(allReplies, (r) => r.issueId);
|
|
17952
|
+
const reviewById = new Map(allReviews.map((r) => [r.id, r]));
|
|
17933
17953
|
const acceptBlockers = /* @__PURE__ */ new Map();
|
|
17934
17954
|
for (const snap of snapshots2) {
|
|
17935
17955
|
let state = null;
|
|
17956
|
+
const snapshotWorks = new Map(snap.works.map((w2) => [w2.id, w2]));
|
|
17936
17957
|
for (const node2 of snap.nodes) {
|
|
17937
17958
|
if (!node2.latestWorkId || node2.latestAcceptId === node2.latestWorkId) continue;
|
|
17938
|
-
const lw =
|
|
17959
|
+
const lw = snapshotWorks.get(node2.latestWorkId);
|
|
17939
17960
|
if (!lw || !lw.endedAt || lw.deadAt) continue;
|
|
17940
17961
|
state ??= new WorkorderState(snap);
|
|
17941
17962
|
const block = acceptBlock(state, lw.id);
|
|
@@ -17952,7 +17973,7 @@ function bridgeLoadReadModel(input) {
|
|
|
17952
17973
|
const workById = /* @__PURE__ */ new Map();
|
|
17953
17974
|
for (const w2 of allWorks) workById.set(w2.id, w2);
|
|
17954
17975
|
for (const node2 of allNodes) {
|
|
17955
|
-
const art = nodeToArtifact(node2,
|
|
17976
|
+
const art = nodeToArtifact(node2, edgesByTarget.get(node2.id) ?? [], requirementsByNode.get(node2.id) ?? []);
|
|
17956
17977
|
const lw = node2.latestWorkId ? workById.get(node2.latestWorkId) : void 0;
|
|
17957
17978
|
if (lw) {
|
|
17958
17979
|
const st = lw.status ?? (lw.retryAt ? "retry" : lw.deadAt ? "dead" : lw.endedAt ? lw.outcome === "failed" ? "failed" : "success" : "running");
|
|
@@ -17976,7 +17997,7 @@ function bridgeLoadReadModel(input) {
|
|
|
17976
17997
|
}
|
|
17977
17998
|
const revisions = /* @__PURE__ */ new Map();
|
|
17978
17999
|
for (const w2 of allWorks) {
|
|
17979
|
-
revisions.set(w2.id, workToRevision(w2,
|
|
18000
|
+
revisions.set(w2.id, workToRevision(w2, inputsByWork.get(w2.id) ?? [], artifactFiles));
|
|
17980
18001
|
}
|
|
17981
18002
|
{
|
|
17982
18003
|
const worksByNode = /* @__PURE__ */ new Map();
|
|
@@ -18007,7 +18028,7 @@ function bridgeLoadReadModel(input) {
|
|
|
18007
18028
|
for (const issue2 of allIssues) {
|
|
18008
18029
|
if (issue2.kind === "gap" || issue2.kind === "escalation") continue;
|
|
18009
18030
|
annotationSeq.set(issue2.id, 0);
|
|
18010
|
-
annotations.set(issue2.id, issueToAnnotation(issue2,
|
|
18031
|
+
annotations.set(issue2.id, issueToAnnotation(issue2, repliesByIssue.get(issue2.id) ?? [], recipientsByIssue.get(issue2.id) ?? []));
|
|
18011
18032
|
}
|
|
18012
18033
|
const reviewVotes = /* @__PURE__ */ new Map();
|
|
18013
18034
|
for (const r of allReviews) {
|
|
@@ -18019,7 +18040,7 @@ function bridgeLoadReadModel(input) {
|
|
|
18019
18040
|
}
|
|
18020
18041
|
const concludeAttempts = /* @__PURE__ */ new Map();
|
|
18021
18042
|
for (const w2 of allWorks) {
|
|
18022
|
-
const attempt = workToConcludeAttempt(w2,
|
|
18043
|
+
const attempt = workToConcludeAttempt(w2, requirementsByNode.get(w2.nodeId) ?? []);
|
|
18023
18044
|
if (!attempt) continue;
|
|
18024
18045
|
const list2 = concludeAttempts.get(w2.nodeId) ?? [];
|
|
18025
18046
|
list2.push(attempt);
|
|
@@ -18038,6 +18059,19 @@ function bridgeLoadReadModel(input) {
|
|
|
18038
18059
|
let seq = 0;
|
|
18039
18060
|
for (const w2 of allWorks) proposeSeq.set(w2.id, seq++);
|
|
18040
18061
|
}
|
|
18062
|
+
const workTimeRanks = allWorks.map((w2) => ({ at: w2.createdAt, rank: (proposeSeq.get(w2.id) ?? -1) + 1 })).sort((a, b2) => a.at < b2.at ? -1 : a.at > b2.at ? 1 : 0);
|
|
18063
|
+
for (let i = 1; i < workTimeRanks.length; i++) {
|
|
18064
|
+
workTimeRanks[i].rank = Math.max(workTimeRanks[i].rank, workTimeRanks[i - 1].rank);
|
|
18065
|
+
}
|
|
18066
|
+
const seqBefore = (at) => {
|
|
18067
|
+
let low = 0, high = workTimeRanks.length;
|
|
18068
|
+
while (low < high) {
|
|
18069
|
+
const mid = Math.floor((low + high) / 2);
|
|
18070
|
+
if (workTimeRanks[mid].at < at) low = mid + 1;
|
|
18071
|
+
else high = mid;
|
|
18072
|
+
}
|
|
18073
|
+
return low === 0 ? 0 : workTimeRanks[low - 1].rank;
|
|
18074
|
+
};
|
|
18041
18075
|
const gaps = /* @__PURE__ */ new Map();
|
|
18042
18076
|
for (const issue2 of allIssues) {
|
|
18043
18077
|
if (issue2.kind !== "gap") continue;
|
|
@@ -18054,14 +18088,7 @@ function bridgeLoadReadModel(input) {
|
|
|
18054
18088
|
if (resolved) {
|
|
18055
18089
|
if (issue2.resolvedNote !== null) gapView.note = issue2.resolvedNote;
|
|
18056
18090
|
gapView.resolvedAt = issue2.resolvedAt;
|
|
18057
|
-
|
|
18058
|
-
for (const w2 of allWorks) {
|
|
18059
|
-
if (w2.createdAt < issue2.resolvedAt) {
|
|
18060
|
-
const s2 = (proposeSeq.get(w2.id) ?? -1) + 1;
|
|
18061
|
-
if (s2 > seqAtResolve) seqAtResolve = s2;
|
|
18062
|
-
}
|
|
18063
|
-
}
|
|
18064
|
-
gapView.resolvedAtSeq = seqAtResolve;
|
|
18091
|
+
gapView.resolvedAtSeq = seqBefore(issue2.resolvedAt);
|
|
18065
18092
|
}
|
|
18066
18093
|
const list2 = gaps.get(nodeId) ?? [];
|
|
18067
18094
|
list2.push(gapView);
|
|
@@ -18098,18 +18125,18 @@ function bridgeLoadReadModel(input) {
|
|
|
18098
18125
|
for (const node2 of allNodes) {
|
|
18099
18126
|
if (!node2.latestWorkId) continue;
|
|
18100
18127
|
if (node2.cancelledAt) continue;
|
|
18101
|
-
const lw =
|
|
18128
|
+
const lw = workById.get(node2.latestWorkId);
|
|
18102
18129
|
if (!lw || !lw.deadAt) {
|
|
18103
|
-
const head = node2.latestProposedWorkId ?
|
|
18130
|
+
const head = node2.latestProposedWorkId ? workById.get(node2.latestProposedWorkId) : void 0;
|
|
18104
18131
|
if (!head || head.deadAt || node2.latestAcceptId === head.id) continue;
|
|
18105
|
-
const reqs =
|
|
18132
|
+
const reqs = requirementsByNode.get(node2.id) ?? [];
|
|
18106
18133
|
if (reqs.length === 0) continue;
|
|
18107
18134
|
let stoppedAt = null;
|
|
18108
18135
|
let deadGroups = 0;
|
|
18109
18136
|
let liveGroups = 0;
|
|
18110
18137
|
for (const g2 of new Set(reqs.map((r) => r.reviewGroup))) {
|
|
18111
18138
|
const req = reqs.find((r2) => r2.reviewGroup === g2);
|
|
18112
|
-
const r = req?.latestReviewId ?
|
|
18139
|
+
const r = req?.latestReviewId ? reviewById.get(req.latestReviewId) : void 0;
|
|
18113
18140
|
if (!r || r.targetWorkId !== head.id) {
|
|
18114
18141
|
liveGroups += 1;
|
|
18115
18142
|
continue;
|
|
@@ -19276,18 +19303,26 @@ var init_kernel_bridge = __esm({
|
|
|
19276
19303
|
typeName: a.type
|
|
19277
19304
|
};
|
|
19278
19305
|
}
|
|
19279
|
-
const typeDef = this.schema.get(a.type);
|
|
19280
|
-
const closureGate = humanGateActorsOf(this.model, artifactId);
|
|
19281
19306
|
const slot = closureSlotOf(this.model, a.workspace);
|
|
19282
19307
|
const isCurrentClosureSlot = (slot.kind === "closure-report" || slot.kind === "sole-artifact") && slot.id === artifactId;
|
|
19283
|
-
const
|
|
19284
|
-
const
|
|
19308
|
+
const notYetSubmitted = a.latestWorkState !== "success";
|
|
19309
|
+
const closureGate = isCurrentClosureSlot && notYetSubmitted ? humanGateActorsOf(this.model, artifactId) : [];
|
|
19310
|
+
if (!isCurrentClosureSlot || !notYetSubmitted || closureGate.length === 0) {
|
|
19311
|
+
return {
|
|
19312
|
+
reviewers: [],
|
|
19313
|
+
quorum: 0,
|
|
19314
|
+
requirements: [],
|
|
19315
|
+
typeName: a.type
|
|
19316
|
+
};
|
|
19317
|
+
}
|
|
19318
|
+
const typeDef = this.schema.get(a.type);
|
|
19285
19319
|
const { reviewers: predicted } = resolveNodeReviewers({
|
|
19286
19320
|
typeName: a.type,
|
|
19287
19321
|
typeDef,
|
|
19288
|
-
|
|
19322
|
+
// reviewRoles=[] 显式覆盖同样传入,避免 resolver 回落到 typeDef 默认角色(0101 语义)。
|
|
19323
|
+
reviewRoles: [],
|
|
19289
19324
|
roleIndex: this.roleIndex,
|
|
19290
|
-
|
|
19325
|
+
closureGate
|
|
19291
19326
|
});
|
|
19292
19327
|
if (predicted.length === 0) {
|
|
19293
19328
|
return {
|
|
@@ -195420,6 +195455,11 @@ var init_store2 = __esm({
|
|
|
195420
195455
|
const r = [...this.rows.values()].find((x2) => x2.childSessionId === childSessionId);
|
|
195421
195456
|
return r ? this.clone(r) : null;
|
|
195422
195457
|
}
|
|
195458
|
+
async listChildSessionIds(candidateIds) {
|
|
195459
|
+
if (candidateIds.length === 0) return [];
|
|
195460
|
+
const want = new Set(candidateIds);
|
|
195461
|
+
return [...this.rows.values()].map((r) => r.childSessionId).filter((id) => want.has(id));
|
|
195462
|
+
}
|
|
195423
195463
|
async getByInvocationId(invocationId) {
|
|
195424
195464
|
const r = [...this.rows.values()].find((x2) => x2.invocationId === invocationId);
|
|
195425
195465
|
return r ? this.clone(r) : null;
|
|
@@ -215209,13 +215249,22 @@ function clientIpOf(req) {
|
|
|
215209
215249
|
if (typeof raw === "string" && raw.trim().length > 0) return raw.split(",")[0].trim();
|
|
215210
215250
|
return req.socket?.remoteAddress ?? "unknown";
|
|
215211
215251
|
}
|
|
215212
|
-
|
|
215252
|
+
function pkgDriftHealDecision(input) {
|
|
215253
|
+
if (!input.nodePkg || input.nodePkg === input.expectedPkg) return "skip";
|
|
215254
|
+
if (input.nowMs - input.lastHealAtMs < PKG_HEAL_COOLDOWN_MS) return "skip";
|
|
215255
|
+
if (input.tries > PKG_HEAL_MAX_TRIES) return "skip";
|
|
215256
|
+
if (input.tries === PKG_HEAL_MAX_TRIES) return "give-up";
|
|
215257
|
+
return "send";
|
|
215258
|
+
}
|
|
215259
|
+
var PKG_HEAL_COOLDOWN_MS, PKG_HEAL_MAX_TRIES, DaemonHub;
|
|
215213
215260
|
var init_daemon_hub = __esm({
|
|
215214
215261
|
"../server/src/daemon-hub.ts"() {
|
|
215215
215262
|
"use strict";
|
|
215216
215263
|
init_wrapper();
|
|
215217
215264
|
init_src();
|
|
215218
215265
|
init_handshake_throttle();
|
|
215266
|
+
PKG_HEAL_COOLDOWN_MS = 10 * 60 * 1e3;
|
|
215267
|
+
PKG_HEAL_MAX_TRIES = 3;
|
|
215219
215268
|
DaemonHub = class _DaemonHub {
|
|
215220
215269
|
daemons = /* @__PURE__ */ new Map();
|
|
215221
215270
|
/** 底层 socket,仅供 sweepLiveness 对半开连接做 terminate(不等 close 握手)用。 */
|
|
@@ -215260,6 +215309,9 @@ var init_daemon_hub = __esm({
|
|
|
215260
215309
|
wss;
|
|
215261
215310
|
ghosts = /* @__PURE__ */ new Map();
|
|
215262
215311
|
lastDisconnectedAt = /* @__PURE__ */ new Map();
|
|
215312
|
+
/** 通道漂移自愈:上次给某节点补发换包指令的时刻(epoch ms)与本进程内已补发次数。 */
|
|
215313
|
+
pkgHealAt = /* @__PURE__ */ new Map();
|
|
215314
|
+
pkgHealTries = /* @__PURE__ */ new Map();
|
|
215263
215315
|
lastReconnectedAt = /* @__PURE__ */ new Map();
|
|
215264
215316
|
static GHOST_TTL_MS = 5 * 60 * 1e3;
|
|
215265
215317
|
pingIntervalMs;
|
|
@@ -215675,6 +215727,37 @@ var init_daemon_hub = __esm({
|
|
|
215675
215727
|
if (sent) console.warn(`[hub] evict \u4F1A\u8BDD dispatch=${dispatchId} reason=${reason}`);
|
|
215676
215728
|
return sent;
|
|
215677
215729
|
}
|
|
215730
|
+
/**
|
|
215731
|
+
* 通道漂移自愈:节点上报的 `daemonPkg` 与本控制面这条线的包不一致时,握手完就补一帧 `update`
|
|
215732
|
+
* 把正确的包名下发过去(ADR 0515)。没有它,迁移要人点两次「更新」——第一次只是把节点升到
|
|
215733
|
+
* "读得懂 pkg"的那一版,第二次才换包。
|
|
215734
|
+
*
|
|
215735
|
+
* 三道闸,缺一会变成重启风暴:
|
|
215736
|
+
* ① 只对**上报了** `daemonPkg` 的节点动手。没上报 = 更老的 bundle,它读不懂这个字段,
|
|
215737
|
+
* 发过去只会在它自己那条线里白重装一遍,纯粹是一次无意义的重启。
|
|
215738
|
+
* ② 每个节点 10 分钟内最多补一次(与节点侧换包冷却同宽)。
|
|
215739
|
+
* ③ 本进程内每个节点最多补 3 次:换包失败的节点会带着旧包名重连,没有这条就是每 10 分钟重启一轮。
|
|
215740
|
+
*/
|
|
215741
|
+
healDaemonPkgDrift(daemon) {
|
|
215742
|
+
const decision = pkgDriftHealDecision({
|
|
215743
|
+
nodePkg: daemon.meta.daemonPkg,
|
|
215744
|
+
expectedPkg: DAEMON_NPM_PACKAGE,
|
|
215745
|
+
lastHealAtMs: this.pkgHealAt.get(daemon.daemonId) ?? 0,
|
|
215746
|
+
tries: this.pkgHealTries.get(daemon.daemonId) ?? 0,
|
|
215747
|
+
nowMs: Date.now()
|
|
215748
|
+
});
|
|
215749
|
+
if (decision === "skip") return;
|
|
215750
|
+
if (decision === "give-up") {
|
|
215751
|
+
this.pkgHealTries.set(daemon.daemonId, PKG_HEAL_MAX_TRIES + 1);
|
|
215752
|
+
console.error(`[hub] \u8282\u70B9 ${daemon.daemonId} \u8FDE\u7EED ${PKG_HEAL_MAX_TRIES} \u6B21\u6CA1\u80FD\u4ECE ${daemon.meta.daemonPkg} \u6362\u5230 ${DAEMON_NPM_PACKAGE}\uFF0C\u505C\u6B62\u81EA\u52A8\u8865\u53D1\u2014\u2014\u53BB\u770B\u5B83\u7684 node.log`);
|
|
215753
|
+
return;
|
|
215754
|
+
}
|
|
215755
|
+
const tries = (this.pkgHealTries.get(daemon.daemonId) ?? 0) + 1;
|
|
215756
|
+
this.pkgHealAt.set(daemon.daemonId, Date.now());
|
|
215757
|
+
this.pkgHealTries.set(daemon.daemonId, tries);
|
|
215758
|
+
console.error(`[hub] \u8282\u70B9 ${daemon.daemonId} \u8FD8\u5728 ${daemon.meta.daemonPkg} \u8FD9\u6761\u7EBF\u4E0A\uFF0C\u672C\u63A7\u5236\u9762\u7528 ${DAEMON_NPM_PACKAGE}\u2014\u2014\u8865\u53D1\u6362\u5305\u6307\u4EE4\uFF08\u7B2C ${tries} \u6B21\uFF09`);
|
|
215759
|
+
daemon.send({ type: "update", pkg: DAEMON_NPM_PACKAGE });
|
|
215760
|
+
}
|
|
215678
215761
|
handleConnection(ws, req) {
|
|
215679
215762
|
const dataplane = req.oasisDataplane;
|
|
215680
215763
|
if (dataplane) {
|
|
@@ -215706,6 +215789,7 @@ var init_daemon_hub = __esm({
|
|
|
215706
215789
|
if (this.lastDisconnectedAt.has(daemonId)) this.lastReconnectedAt.set(daemonId, Date.now());
|
|
215707
215790
|
this.ghosts.delete(daemonId);
|
|
215708
215791
|
Object.assign(daemon.meta, msg.meta);
|
|
215792
|
+
this.healDaemonPkgDrift(daemon);
|
|
215709
215793
|
if (!registered) {
|
|
215710
215794
|
registered = true;
|
|
215711
215795
|
this.lastSeen.set(daemonId, Date.now());
|
|
@@ -220960,6 +221044,16 @@ var init_service6 = __esm({
|
|
|
220960
221044
|
await this.store.updateCompany(companyId, { onboardingVariant: variant });
|
|
220961
221045
|
return { ...company, onboardingVariant: variant };
|
|
220962
221046
|
}
|
|
221047
|
+
/**
|
|
221048
|
+
* 改团队名称。**只改 name,不动 slug**——slug 是路由键(company:<slug> 与引擎 schema co_<slug>
|
|
221049
|
+
* 的一部分,`create` 里注释「建成不可改」),改它会让所有历史链接失效。
|
|
221050
|
+
* 校验(非空 / trim)在路由层做完了,这里假设 name 已经是非空 trim 过的字符串。
|
|
221051
|
+
*/
|
|
221052
|
+
async renameCompany(id, name) {
|
|
221053
|
+
const company = await this.requireCompany(id);
|
|
221054
|
+
await this.store.updateCompany(id, { name });
|
|
221055
|
+
return { ...company, name };
|
|
221056
|
+
}
|
|
220963
221057
|
/** 设置/清除公司头像引用("blob:<哈希>";null = 回到默认首字母标识)。 */
|
|
220964
221058
|
async setAvatar(id, ref2) {
|
|
220965
221059
|
const company = await this.requireCompany(id);
|
|
@@ -221849,14 +221943,29 @@ function companiesDomain(opts) {
|
|
|
221849
221943
|
router.patch("/api/companies/:id", async (req) => {
|
|
221850
221944
|
const cid = req.params.id;
|
|
221851
221945
|
const b2 = req.body ?? {};
|
|
221852
|
-
|
|
221853
|
-
|
|
221946
|
+
const hasName = b2.name !== void 0;
|
|
221947
|
+
const hasVariant = b2.onboardingVariant !== void 0;
|
|
221948
|
+
if (!hasName && !hasVariant) {
|
|
221949
|
+
throw new ApiError(400, "BAD_REQUEST", "\u7F3A\u5C11\u53EF\u66F4\u65B0\u5B57\u6BB5\uFF08name / onboardingVariant\uFF09");
|
|
221854
221950
|
}
|
|
221855
|
-
|
|
221951
|
+
let trimmedName;
|
|
221952
|
+
if (hasName) {
|
|
221953
|
+
if (typeof b2.name !== "string" || !b2.name.trim()) {
|
|
221954
|
+
throw new ApiError(400, "BAD_REQUEST", "name \u987B\u4E3A\u975E\u7A7A\u5B57\u7B26\u4E32");
|
|
221955
|
+
}
|
|
221956
|
+
trimmedName = b2.name.trim();
|
|
221957
|
+
}
|
|
221958
|
+
if (hasVariant && b2.onboardingVariant !== "A" && b2.onboardingVariant !== "B") {
|
|
221856
221959
|
throw new ApiError(400, "BAD_REQUEST", `onboardingVariant \u987B\u4E3A "A" | "B"`);
|
|
221857
221960
|
}
|
|
221858
221961
|
await requireOwnerOrAdmin(req, cid);
|
|
221859
|
-
|
|
221962
|
+
let company;
|
|
221963
|
+
if (trimmedName !== void 0) {
|
|
221964
|
+
company = await service.renameCompany(cid, trimmedName).catch(mapErr);
|
|
221965
|
+
}
|
|
221966
|
+
if (hasVariant) {
|
|
221967
|
+
company = await service.setOnboardingVariant(cid, b2.onboardingVariant).catch(mapErr);
|
|
221968
|
+
}
|
|
221860
221969
|
return { status: 200, body: company };
|
|
221861
221970
|
});
|
|
221862
221971
|
router.post("/api/companies", async (req) => {
|
|
@@ -223954,7 +224063,6 @@ function buildWorkorderActivity(input) {
|
|
|
223954
224063
|
const tail = nodeId.split(":").slice(2).join(":");
|
|
223955
224064
|
return tail || nodeId;
|
|
223956
224065
|
};
|
|
223957
|
-
const deliverableName = (workId, nodeId) => artifactsByWork.get(workId)?.[0]?.name ?? nodeName(nodeId);
|
|
223958
224066
|
const groupCards = /* @__PURE__ */ new Map();
|
|
223959
224067
|
const groupIndexOf = /* @__PURE__ */ new Map();
|
|
223960
224068
|
const cardOfWork = /* @__PURE__ */ new Map();
|
|
@@ -224068,7 +224176,8 @@ function buildWorkorderActivity(input) {
|
|
|
224068
224176
|
const workId = String(ev.workId ?? "");
|
|
224069
224177
|
const d = cardOfWork.get(workId);
|
|
224070
224178
|
if (!d) break;
|
|
224071
|
-
|
|
224179
|
+
const zeroOutput = ev.outcome === "completed" && workById.get(workId)?.status === "failed";
|
|
224180
|
+
if (zeroOutput || ev.outcome === "failed" && isDispatchLayerFailure(ev.detail)) {
|
|
224072
224181
|
cardOfWork.delete(workId);
|
|
224073
224182
|
if (![...cardOfWork.values()].includes(d)) {
|
|
224074
224183
|
for (const [k2, v2] of groupCards) if (v2 === d) groupCards.delete(k2);
|
|
@@ -224109,7 +224218,7 @@ function buildWorkorderActivity(input) {
|
|
|
224109
224218
|
d.artifacts = artifactsByWork.get(workId) ?? d.artifacts;
|
|
224110
224219
|
if (d.nodeId) groupIndexOf.set(d.nodeId, (groupIndexOf.get(d.nodeId) ?? 0) + 1);
|
|
224111
224220
|
const node2 = d.nodeId ? nodeById.get(d.nodeId) : void 0;
|
|
224112
|
-
const name =
|
|
224221
|
+
const name = nodeName(d.nodeId);
|
|
224113
224222
|
if (d.nodeId && rootBriefNodeIds.has(d.nodeId)) {
|
|
224114
224223
|
const isFirstRound = !concludedRootBriefNodeIds.has(d.nodeId);
|
|
224115
224224
|
concludedRootBriefNodeIds.add(d.nodeId);
|
|
@@ -224146,7 +224255,7 @@ function buildWorkorderActivity(input) {
|
|
|
224146
224255
|
if (reviewers.length === 0 && isSystemAccept(by)) break;
|
|
224147
224256
|
const bypassed = reviewers.length > 0 && isSystemAccept(by);
|
|
224148
224257
|
const existing = acceptCards.get(workId);
|
|
224149
|
-
const status = bypassed ? node2?.isFinalOutput ? ACTIVITY_COPY.autoAccepted(nameOf(reviewers[0])) : ACTIVITY_COPY.autoAcceptedNode(
|
|
224258
|
+
const status = bypassed ? node2?.isFinalOutput ? ACTIVITY_COPY.autoAccepted(nameOf(reviewers[0])) : ACTIVITY_COPY.autoAcceptedNode(nodeName(nodeId), nameOf(reviewers[0])) : node2?.isFinalOutput ? ACTIVITY_COPY.accepted : ACTIVITY_COPY.acceptedNode(nodeName(nodeId));
|
|
224150
224259
|
if (existing) {
|
|
224151
224260
|
touch(existing, rec);
|
|
224152
224261
|
existing.executorId = bypassed ? reviewers[0] : by;
|
|
@@ -224177,7 +224286,7 @@ function buildWorkorderActivity(input) {
|
|
|
224177
224286
|
const targetWorkId = String(ev.targetWorkId ?? "");
|
|
224178
224287
|
const reviewerId = str4(ev.reviewerActorId) ?? rec.actorId;
|
|
224179
224288
|
const isAgent2 = ev.reviewerIsAgent === true;
|
|
224180
|
-
const name =
|
|
224289
|
+
const name = nodeName(nodeId);
|
|
224181
224290
|
reviewCards.set(reviewId, {
|
|
224182
224291
|
id: `review:${reviewId}`,
|
|
224183
224292
|
seq: rec.seq,
|
|
@@ -224213,7 +224322,7 @@ function buildWorkorderActivity(input) {
|
|
|
224213
224322
|
d.executorId = str4(ev.reviewerActorId) ?? d.executorId;
|
|
224214
224323
|
d.actions = [];
|
|
224215
224324
|
const nodeId = d.nodeId;
|
|
224216
|
-
const name =
|
|
224325
|
+
const name = nodeName(nodeId);
|
|
224217
224326
|
if (ev.verdict === "approve") {
|
|
224218
224327
|
d.status = ACTIVITY_COPY.reviewApproved(name);
|
|
224219
224328
|
} else {
|
|
@@ -230192,6 +230301,18 @@ function createChatSessionsDomain(opts) {
|
|
|
230192
230301
|
drafts.delete(req.params["id"]);
|
|
230193
230302
|
return { status: 200, body: { text: draft.text } };
|
|
230194
230303
|
});
|
|
230304
|
+
async function markDelegationChildren(sessions, callerCompanyId) {
|
|
230305
|
+
const wiring = opts.delegations;
|
|
230306
|
+
if (!wiring || !wiring.enabled() || sessions.length === 0) return sessions;
|
|
230307
|
+
const companyId = sessions[0]?.companyId ?? callerCompanyId;
|
|
230308
|
+
const ledger = await wiring.storeFor(companyId).catch(() => null);
|
|
230309
|
+
if (!ledger) return sessions;
|
|
230310
|
+
const childIds = new Set(
|
|
230311
|
+
await ledger.listChildSessionIds(sessions.map((s2) => s2.id)).catch(() => [])
|
|
230312
|
+
);
|
|
230313
|
+
if (childIds.size === 0) return sessions;
|
|
230314
|
+
return sessions.map((s2) => childIds.has(s2.id) ? { ...s2, isDelegationChild: true } : s2);
|
|
230315
|
+
}
|
|
230195
230316
|
router.get("/api/chat-sessions", async (req) => {
|
|
230196
230317
|
const store2 = await storeFor(req);
|
|
230197
230318
|
if (req.query?.get("analysis") === "all") {
|
|
@@ -230206,7 +230327,8 @@ function createChatSessionsDomain(opts) {
|
|
|
230206
230327
|
}
|
|
230207
230328
|
const analyzedRunId = req.query?.get("analyzedRunId") ?? void 0;
|
|
230208
230329
|
const sessions = analyzedRunId ? await store2.listSessionsByAnalyzedRun(analyzedRunId) : await store2.listSessions(req.auth.actor);
|
|
230209
|
-
|
|
230330
|
+
const items = await markDelegationChildren(sessions, req.auth.companyId ?? void 0);
|
|
230331
|
+
return { status: 200, body: { items } };
|
|
230210
230332
|
});
|
|
230211
230333
|
router.post("/api/chat-sessions", async (req) => {
|
|
230212
230334
|
const store2 = await storeFor(req);
|
|
@@ -244624,6 +244746,14 @@ var init_postgres_delegations = __esm({
|
|
|
244624
244746
|
);
|
|
244625
244747
|
return r.rows[0] ? toRecord2(r.rows[0]) : null;
|
|
244626
244748
|
}
|
|
244749
|
+
async listChildSessionIds(candidateIds) {
|
|
244750
|
+
if (candidateIds.length === 0) return [];
|
|
244751
|
+
const r = await this.pool.query(
|
|
244752
|
+
`SELECT child_session_id FROM ${this.s}.chat_session_delegations WHERE child_session_id = ANY($1)`,
|
|
244753
|
+
[[...candidateIds]]
|
|
244754
|
+
);
|
|
244755
|
+
return r.rows.map((row) => row.child_session_id);
|
|
244756
|
+
}
|
|
244627
244757
|
async getByInvocationId(invocationId) {
|
|
244628
244758
|
const r = await this.pool.query(
|
|
244629
244759
|
`SELECT * FROM ${this.s}.chat_session_delegations WHERE invocation_id = $1`,
|
|
@@ -265431,10 +265561,16 @@ ${res.warning}`);
|
|
|
265431
265561
|
println(role ? `\u6CA1\u6709${all2 ? "" : "\u5728\u5C97\u7684"} ${role} \u5C97\u4F4D\u5458\u5DE5` : "\u6CA1\u6709\u5458\u5DE5");
|
|
265432
265562
|
break;
|
|
265433
265563
|
}
|
|
265564
|
+
let anyRoleless = false;
|
|
265434
265565
|
for (const a of rows) {
|
|
265435
|
-
const
|
|
265566
|
+
const hasRole = (a.positions ?? []).length > 0;
|
|
265567
|
+
if (!hasRole) anyRoleless = true;
|
|
265568
|
+
const pos = hasRole ? (a.positions ?? []).join(",") : "(\u65E0\u5C97\u4F4D)";
|
|
265436
265569
|
println(`${a.id} ${a.name ?? ""} ${a.kind} ${pos}${a.status === "active" ? "" : ` [${a.status}]`}`);
|
|
265437
265570
|
}
|
|
265571
|
+
if (anyRoleless) {
|
|
265572
|
+
println("\u2014\u2014 \u6807\u300C(\u65E0\u5C97\u4F4D)\u300D\u7684\uFF1A\u4E0D\u4F1A\u88AB\u6309\u5C97\u4F4D\u7684\u81EA\u52A8\u5206\u6D41 / \u6D3E\u5355\u9009\u4E2D\uFF0C\u4F46\u53EF\u4EE5\u70B9\u540D\u6307\u6D3E\uFF08`oasis assign <\u8282\u70B9> --owner <id>`\uFF0C\u6216\u59D4\u6D3E\u65F6 `--to <actorId>`\uFF09\u3002");
|
|
265573
|
+
}
|
|
265438
265574
|
break;
|
|
265439
265575
|
}
|
|
265440
265576
|
// 诊断 1be339c7 ③:单人详情——「这个 id 到底是谁」。协调者要从岗位跳到人时用它,chat agent 想核实
|
|
@@ -265521,6 +265657,7 @@ ${res.warning}`);
|
|
|
265521
265657
|
println(`${r.name} ${r.label} ${flagsText}${uses ? ` ${uses}` : ""}`);
|
|
265522
265658
|
if (r.description) println(` ${r.description}`);
|
|
265523
265659
|
}
|
|
265660
|
+
println("\u2014\u2014 \u672C\u547D\u4EE4\u53EA\u5217\u5C97\u4F4D\u4E0E\u5728\u5C97\u4EBA\u6570\uFF0C\u4E0D\u5217\u5177\u4F53\u7684\u4EBA / agent\u3002\u8981\u770B\u6709\u8C01\u53EF\u6D3E\uFF08\u542B\u672A\u8BBE\u5C97\u4F4D\u7684\uFF09\u7528 `oasis actors`\u3002");
|
|
265524
265661
|
break;
|
|
265525
265662
|
}
|
|
265526
265663
|
case "assign": {
|
|
@@ -266418,7 +266555,7 @@ function shimScript() {
|
|
|
266418
266555
|
}
|
|
266419
266556
|
|
|
266420
266557
|
// src/index.ts
|
|
266421
|
-
var PKG_VERSION = true ? "2.1.
|
|
266558
|
+
var PKG_VERSION = true ? "2.1.1" : "dev";
|
|
266422
266559
|
var LOCAL_BIN = localBin();
|
|
266423
266560
|
var NPM_PREFIX = npmPrefix();
|
|
266424
266561
|
var INSTANCE = DEFAULT_INSTANCE;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oasis_test_v2",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.1",
|
|
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": "75bc8ca411b3af4f39aba67b159c6570f2b35a7a"
|
|
30
30
|
}
|
|
31
31
|
}
|