oasis_test_v2 2.2.36 → 2.2.37
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 +310 -116
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -5645,7 +5645,6 @@ CREATE TABLE IF NOT EXISTS ${q2}.workorders (
|
|
|
5645
5645
|
paused_reason text,
|
|
5646
5646
|
done_at timestamptz,
|
|
5647
5647
|
structural_version integer NOT NULL DEFAULT 0,
|
|
5648
|
-
row_version integer NOT NULL DEFAULT 0,
|
|
5649
5648
|
created_at timestamptz NOT NULL,
|
|
5650
5649
|
created_by text NOT NULL,
|
|
5651
5650
|
updated_at timestamptz NOT NULL
|
|
@@ -5660,7 +5659,6 @@ CREATE TABLE IF NOT EXISTS ${q2}.workflow_nodes (
|
|
|
5660
5659
|
spec text,
|
|
5661
5660
|
version integer NOT NULL DEFAULT 0,
|
|
5662
5661
|
assignee_actor_id text,
|
|
5663
|
-
assignee_role text,
|
|
5664
5662
|
latest_work_id text,
|
|
5665
5663
|
latest_proposed_work_id text,
|
|
5666
5664
|
latest_accept_id text,
|
|
@@ -5670,7 +5668,6 @@ CREATE TABLE IF NOT EXISTS ${q2}.workflow_nodes (
|
|
|
5670
5668
|
cancelled_at timestamptz,
|
|
5671
5669
|
-- \u5C01\u5B58\u539F\u56E0\uFF08accepted/cancelled/frozen\uFF09\u3002NULL = \u5B58\u91CF\u884C\uFF0C\u8BFB\u6A21\u578B\u6309 cancelled \u515C\u5E95\u3002
|
|
5672
5670
|
seal_reason text,
|
|
5673
|
-
row_version integer NOT NULL DEFAULT 0,
|
|
5674
5671
|
created_at timestamptz NOT NULL,
|
|
5675
5672
|
updated_at timestamptz NOT NULL
|
|
5676
5673
|
);
|
|
@@ -5684,7 +5681,6 @@ CREATE TABLE IF NOT EXISTS ${q2}.workflow_edges (
|
|
|
5684
5681
|
kind text NOT NULL CHECK (kind IN ('data','order')),
|
|
5685
5682
|
required boolean NOT NULL DEFAULT true,
|
|
5686
5683
|
pinned_work_id text,
|
|
5687
|
-
consumed_work_id text,
|
|
5688
5684
|
PRIMARY KEY (from_node_id, to_node_id)
|
|
5689
5685
|
);
|
|
5690
5686
|
CREATE INDEX IF NOT EXISTS edges_to_idx ON ${q2}.workflow_edges (to_node_id);
|
|
@@ -5886,7 +5882,6 @@ CREATE TABLE IF NOT EXISTS ${q2}.events (
|
|
|
5886
5882
|
origin text NOT NULL CHECK (origin IN ('command','apply','effect')),
|
|
5887
5883
|
dedup_key text,
|
|
5888
5884
|
status text NOT NULL CHECK (status IN ('pending','applied','done','failed')),
|
|
5889
|
-
attempts integer NOT NULL DEFAULT 0,
|
|
5890
5885
|
available_at timestamptz,
|
|
5891
5886
|
failed_reason text,
|
|
5892
5887
|
created_at timestamptz NOT NULL,
|
|
@@ -6077,6 +6072,31 @@ BEGIN
|
|
|
6077
6072
|
END;
|
|
6078
6073
|
END $$;
|
|
6079
6074
|
|
|
6075
|
+
-- ADR 0564\uFF1A\u9000\u5F79\u672A\u6D88\u8D39\u7684\u8BA1\u6570\u5668\u548C\u5355\u5411\u526F\u672C\uFF1B\u5386\u53F2 events.payload \u539F\u6587\u4E0D\u6539\u3002
|
|
6076
|
+
-- \u90E8\u7F72\u524D\u5907\u4EFD\u5B58\u91CF\u5E93\uFF08\u542B\u975E\u7A7A consumed_work_id / assignee_role\uFF09\u3002\u6309\u5217\u9694\u79BB\u6E05\u7406\uFF0C
|
|
6077
|
+
-- \u5916\u90E8\u4F9D\u8D56\u53EA\u63A8\u8FDF\u8BE5\u5217\uFF0C\u4E0D CASCADE\u3001\u4E0D\u963B\u65AD\u542F\u52A8\uFF08\u6CBF\u7528 ADR 0512 \u7684\u53EF\u7528\u6027\u7EA6\u675F\uFF09\u3002
|
|
6078
|
+
-- \u81EA\u6709 node_view \u5DF2\u5728\u4E0A\u65B9\u5220\u9664\uFF0C\u540E\u7EED ENGINE_VIEWS \u6309\u65B0\u5217\u96C6\u91CD\u5EFA\uFF1B\u4ECD\u88AB\u4FDD\u7559\u7684\u65E7
|
|
6079
|
+
-- workorder_view \u6309\u5916\u90E8\u4F9D\u8D56\u5904\u7406\uFF0C\u4E0D\u80FD\u4E3A\u672C\u6B21\u9000\u5F79\u7834\u574F ADR 0512 \u7684\u5386\u53F2\u503C\u4FDD\u7559\u3002
|
|
6080
|
+
DO $$
|
|
6081
|
+
DECLARE obsolete record;
|
|
6082
|
+
BEGIN
|
|
6083
|
+
FOR obsolete IN SELECT * FROM (VALUES
|
|
6084
|
+
('workorders', 'row_version'),
|
|
6085
|
+
('workflow_nodes', 'row_version'),
|
|
6086
|
+
('workflow_nodes', 'assignee_role'),
|
|
6087
|
+
('workflow_edges', 'consumed_work_id'),
|
|
6088
|
+
('events', 'attempts')
|
|
6089
|
+
) AS retired(table_name, column_name) LOOP
|
|
6090
|
+
BEGIN
|
|
6091
|
+
EXECUTE format('ALTER TABLE %I.%I DROP COLUMN IF EXISTS %I',
|
|
6092
|
+
${lit}, obsolete.table_name, obsolete.column_name);
|
|
6093
|
+
EXCEPTION WHEN dependent_objects_still_exist THEN
|
|
6094
|
+
RAISE WARNING 'Retaining retired engine field %.%.%: external dependencies require reconciliation (ADR 0564)',
|
|
6095
|
+
${lit}, obsolete.table_name, obsolete.column_name;
|
|
6096
|
+
END;
|
|
6097
|
+
END LOOP;
|
|
6098
|
+
END $$;
|
|
6099
|
+
|
|
6080
6100
|
-- \u8C03\u5EA6\u5668\u5B8C\u7ED3\u6807\u8BB0\uFF08mark_done/unmark_done \u843D\u70B9\uFF0C2026-08-12\uFF09\u3002
|
|
6081
6101
|
ALTER TABLE ${q2}.workorders ADD COLUMN IF NOT EXISTS done_at timestamptz;
|
|
6082
6102
|
-- \u2605 \u5DE5\u5355\u7EA7\u5C01\u5B58\u6574\u4F53\u79FB\u9664\uFF08ADR 0137\uFF09\uFF1Alifecycle \u53EA\u5269 draft/active\uFF0Cseal_reason \u5217\u5220\u9664\u3002
|
|
@@ -11329,7 +11349,6 @@ function toRecord(r) {
|
|
|
11329
11349
|
origin: r.origin,
|
|
11330
11350
|
dedupKey: r.dedup_key ?? null,
|
|
11331
11351
|
status: r.status,
|
|
11332
|
-
attempts: Number(r.attempts ?? 0),
|
|
11333
11352
|
availableAt: iso(r.available_at),
|
|
11334
11353
|
failedReason: r.failed_reason ?? null,
|
|
11335
11354
|
createdAt: iso(r.created_at),
|
|
@@ -11558,7 +11577,6 @@ var init_store_postgres = __esm({
|
|
|
11558
11577
|
pausedReason: r.paused_reason,
|
|
11559
11578
|
doneAt: iso(r.done_at),
|
|
11560
11579
|
structuralVersion: r.structural_version,
|
|
11561
|
-
rowVersion: r.row_version,
|
|
11562
11580
|
createdAt: iso(r.created_at),
|
|
11563
11581
|
createdBy: r.created_by,
|
|
11564
11582
|
updatedAt: iso(r.updated_at)
|
|
@@ -11571,7 +11589,6 @@ var init_store_postgres = __esm({
|
|
|
11571
11589
|
spec: n.spec,
|
|
11572
11590
|
version: n.version ?? 0,
|
|
11573
11591
|
assigneeActorId: n.assignee_actor_id,
|
|
11574
|
-
assigneeRole: n.assignee_role,
|
|
11575
11592
|
latestWorkId: n.latest_work_id,
|
|
11576
11593
|
latestProposedWorkId: n.latest_proposed_work_id ?? null,
|
|
11577
11594
|
latestAcceptId: n.latest_accept_id,
|
|
@@ -11581,7 +11598,6 @@ var init_store_postgres = __esm({
|
|
|
11581
11598
|
sealReason: n.seal_reason ?? null,
|
|
11582
11599
|
fields: n.fields ?? void 0,
|
|
11583
11600
|
continuationBudget: n.continuation_budget ?? null,
|
|
11584
|
-
rowVersion: n.row_version,
|
|
11585
11601
|
createdAt: iso(n.created_at),
|
|
11586
11602
|
updatedAt: iso(n.updated_at)
|
|
11587
11603
|
})),
|
|
@@ -11591,8 +11607,7 @@ var init_store_postgres = __esm({
|
|
|
11591
11607
|
toNodeId: e.to_node_id,
|
|
11592
11608
|
kind: e.kind,
|
|
11593
11609
|
required: e.required,
|
|
11594
|
-
pinnedWorkId: e.pinned_work_id
|
|
11595
|
-
consumedWorkId: e.consumed_work_id
|
|
11610
|
+
pinnedWorkId: e.pinned_work_id
|
|
11596
11611
|
})),
|
|
11597
11612
|
requirements: reqs.rows.map((q2) => ({
|
|
11598
11613
|
nodeId: q2.node_id,
|
|
@@ -11731,8 +11746,8 @@ var init_store_postgres = __esm({
|
|
|
11731
11746
|
await this.c.query(
|
|
11732
11747
|
`INSERT INTO ${this.s}.workorders
|
|
11733
11748
|
(id,company_id,title,owner_actor_id,lifecycle,dispatch_paused,paused_by,paused_reason,
|
|
11734
|
-
done_at,structural_version,
|
|
11735
|
-
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13
|
|
11749
|
+
done_at,structural_version,created_at,created_by,updated_at)
|
|
11750
|
+
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13)
|
|
11736
11751
|
ON CONFLICT (id) DO NOTHING`,
|
|
11737
11752
|
[
|
|
11738
11753
|
r.id,
|
|
@@ -11745,7 +11760,6 @@ var init_store_postgres = __esm({
|
|
|
11745
11760
|
r.pausedReason,
|
|
11746
11761
|
r.doneAt,
|
|
11747
11762
|
r.structuralVersion,
|
|
11748
|
-
r.rowVersion,
|
|
11749
11763
|
r.createdAt,
|
|
11750
11764
|
r.createdBy,
|
|
11751
11765
|
r.updatedAt
|
|
@@ -11760,10 +11774,10 @@ var init_store_postgres = __esm({
|
|
|
11760
11774
|
const n = m2.row;
|
|
11761
11775
|
await this.c.query(
|
|
11762
11776
|
`INSERT INTO ${this.s}.workflow_nodes
|
|
11763
|
-
(id,workorder_id,type,title,spec,version,assignee_actor_id,
|
|
11777
|
+
(id,workorder_id,type,title,spec,version,assignee_actor_id,
|
|
11764
11778
|
latest_work_id,latest_proposed_work_id,latest_accept_id,is_final_output,
|
|
11765
|
-
fields,cancelled_at,seal_reason,
|
|
11766
|
-
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17
|
|
11779
|
+
fields,cancelled_at,seal_reason,created_at,updated_at,continuation_budget)
|
|
11780
|
+
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17)
|
|
11767
11781
|
ON CONFLICT (id) DO NOTHING`,
|
|
11768
11782
|
[
|
|
11769
11783
|
n.id,
|
|
@@ -11773,7 +11787,6 @@ var init_store_postgres = __esm({
|
|
|
11773
11787
|
n.spec,
|
|
11774
11788
|
n.version,
|
|
11775
11789
|
n.assigneeActorId,
|
|
11776
|
-
n.assigneeRole,
|
|
11777
11790
|
n.latestWorkId,
|
|
11778
11791
|
n.latestProposedWorkId,
|
|
11779
11792
|
n.latestAcceptId,
|
|
@@ -11781,7 +11794,6 @@ var init_store_postgres = __esm({
|
|
|
11781
11794
|
n.fields ? JSON.stringify(n.fields) : null,
|
|
11782
11795
|
n.cancelledAt,
|
|
11783
11796
|
n.sealReason ?? null,
|
|
11784
|
-
n.rowVersion,
|
|
11785
11797
|
n.createdAt,
|
|
11786
11798
|
n.updatedAt,
|
|
11787
11799
|
n.continuationBudget ? JSON.stringify(n.continuationBudget) : null
|
|
@@ -11796,9 +11808,9 @@ var init_store_postgres = __esm({
|
|
|
11796
11808
|
const e = m2.row;
|
|
11797
11809
|
await this.c.query(
|
|
11798
11810
|
`INSERT INTO ${this.s}.workflow_edges
|
|
11799
|
-
(workorder_id,from_node_id,to_node_id,kind,required,pinned_work_id
|
|
11800
|
-
VALUES ($1,$2,$3,$4,$5,$6
|
|
11801
|
-
[e.workorderId, e.fromNodeId, e.toNodeId, e.kind, e.required, e.pinnedWorkId
|
|
11811
|
+
(workorder_id,from_node_id,to_node_id,kind,required,pinned_work_id)
|
|
11812
|
+
VALUES ($1,$2,$3,$4,$5,$6) ON CONFLICT (from_node_id,to_node_id) DO NOTHING`,
|
|
11813
|
+
[e.workorderId, e.fromNodeId, e.toNodeId, e.kind, e.required, e.pinnedWorkId]
|
|
11802
11814
|
);
|
|
11803
11815
|
break;
|
|
11804
11816
|
}
|
|
@@ -12017,8 +12029,8 @@ var init_store_postgres = __esm({
|
|
|
12017
12029
|
const res = await this.c.query(
|
|
12018
12030
|
`INSERT INTO ${this.s}.events
|
|
12019
12031
|
(company_id,workorder_id,node_id,work_id,actor_id,hand_actor_id,kind,payload,caused_by_seq,
|
|
12020
|
-
origin,dedup_key,status,
|
|
12021
|
-
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,'pending'
|
|
12032
|
+
origin,dedup_key,status,created_at)
|
|
12033
|
+
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,'pending',$12)
|
|
12022
12034
|
ON CONFLICT (workorder_id, dedup_key) WHERE dedup_key IS NOT NULL DO NOTHING
|
|
12023
12035
|
RETURNING seq`,
|
|
12024
12036
|
[
|
|
@@ -12203,13 +12215,11 @@ function newNode(id, workorderId, at, version2) {
|
|
|
12203
12215
|
spec: null,
|
|
12204
12216
|
version: version2,
|
|
12205
12217
|
assigneeActorId: null,
|
|
12206
|
-
assigneeRole: null,
|
|
12207
12218
|
latestWorkId: null,
|
|
12208
12219
|
latestProposedWorkId: null,
|
|
12209
12220
|
latestAcceptId: null,
|
|
12210
12221
|
isFinalOutput: false,
|
|
12211
12222
|
cancelledAt: null,
|
|
12212
|
-
rowVersion: 0,
|
|
12213
12223
|
createdAt: at,
|
|
12214
12224
|
updatedAt: at
|
|
12215
12225
|
};
|
|
@@ -12280,7 +12290,6 @@ var init_plan = __esm({
|
|
|
12280
12290
|
title: e.title,
|
|
12281
12291
|
spec: e.spec,
|
|
12282
12292
|
assigneeActorId: e.assigneeActorId,
|
|
12283
|
-
assigneeRole: e.assigneeRole,
|
|
12284
12293
|
isFinalOutput: e.isFinalOutput,
|
|
12285
12294
|
...e.fields ? { fields: e.fields } : {}
|
|
12286
12295
|
});
|
|
@@ -12332,8 +12341,7 @@ var init_plan = __esm({
|
|
|
12332
12341
|
toNodeId: e.toNodeId,
|
|
12333
12342
|
kind: e.edgeKind,
|
|
12334
12343
|
required: e.required,
|
|
12335
|
-
pinnedWorkId: upstream?.latestAcceptId ?? null
|
|
12336
|
-
consumedWorkId: null
|
|
12344
|
+
pinnedWorkId: upstream?.latestAcceptId ?? null
|
|
12337
12345
|
});
|
|
12338
12346
|
const dn = state.node(e.toNodeId);
|
|
12339
12347
|
if (dn) state.updateNode(e.toNodeId, { version: dn.version + 1 });
|
|
@@ -12362,7 +12370,6 @@ var init_plan = __esm({
|
|
|
12362
12370
|
}
|
|
12363
12371
|
state.updateNode(e.nodeId, {
|
|
12364
12372
|
assigneeActorId: e.assigneeActorId,
|
|
12365
|
-
assigneeRole: e.assigneeRole,
|
|
12366
12373
|
...changed && !settled ? { version: node2.version + 1 } : {},
|
|
12367
12374
|
updatedAt: ctx.at
|
|
12368
12375
|
});
|
|
@@ -12458,7 +12465,6 @@ var init_plan = __esm({
|
|
|
12458
12465
|
title: spec.title,
|
|
12459
12466
|
spec: spec.spec,
|
|
12460
12467
|
assigneeActorId: spec.assigneeActorId,
|
|
12461
|
-
assigneeRole: spec.assigneeRole,
|
|
12462
12468
|
isFinalOutput: spec.isFinalOutput,
|
|
12463
12469
|
reviewers: spec.reviewers,
|
|
12464
12470
|
...spec.fields ? { fields: spec.fields } : {}
|
|
@@ -12528,7 +12534,6 @@ var init_workorder = __esm({
|
|
|
12528
12534
|
pausedReason: null,
|
|
12529
12535
|
doneAt: null,
|
|
12530
12536
|
structuralVersion: 0,
|
|
12531
|
-
rowVersion: 0,
|
|
12532
12537
|
createdAt: ctx.at,
|
|
12533
12538
|
createdBy: ctx.actorId,
|
|
12534
12539
|
updatedAt: ctx.at
|
|
@@ -12543,7 +12548,7 @@ var init_workorder = __esm({
|
|
|
12543
12548
|
([key]) => Object.hasOwn(state.workorder, key)
|
|
12544
12549
|
));
|
|
12545
12550
|
if (Object.keys(patch).length === 0) return;
|
|
12546
|
-
state.updateWorkorder({ ...patch, updatedAt: ctx.at
|
|
12551
|
+
state.updateWorkorder({ ...patch, updatedAt: ctx.at });
|
|
12547
12552
|
}
|
|
12548
12553
|
};
|
|
12549
12554
|
workorderPause = {
|
|
@@ -13347,11 +13352,6 @@ var init_review = __esm({
|
|
|
13347
13352
|
for (const r of state.openReviewsOf(e.workId)) {
|
|
13348
13353
|
state.updateReview(r.id, { cancelledAt: ctx.at, status: "dead" });
|
|
13349
13354
|
}
|
|
13350
|
-
const inputs = state.workInputsOf(e.workId);
|
|
13351
|
-
for (const edge of state.edgesInto(w2.nodeId)) {
|
|
13352
|
-
const real = inputs.find((i) => i.upstreamNodeId === edge.fromNodeId);
|
|
13353
|
-
state.updateEdge(edge.fromNodeId, edge.toNodeId, { consumedWorkId: real?.upstreamWorkId ?? edge.pinnedWorkId });
|
|
13354
|
-
}
|
|
13355
13355
|
for (const edge of state.edgesFrom(w2.nodeId)) {
|
|
13356
13356
|
state.updateEdge(edge.fromNodeId, edge.toNodeId, { pinnedWorkId: e.workId });
|
|
13357
13357
|
}
|
|
@@ -13614,7 +13614,6 @@ function emptySnapshotPlaceholder(record8) {
|
|
|
13614
13614
|
pausedReason: null,
|
|
13615
13615
|
doneAt: null,
|
|
13616
13616
|
structuralVersion: 0,
|
|
13617
|
-
rowVersion: 0,
|
|
13618
13617
|
createdAt: "",
|
|
13619
13618
|
createdBy: "",
|
|
13620
13619
|
updatedAt: ""
|
|
@@ -20236,7 +20235,6 @@ var init_kernel_bridge = __esm({
|
|
|
20236
20235
|
title: args.title ?? args.description ?? args.type,
|
|
20237
20236
|
spec: args.description ?? null,
|
|
20238
20237
|
assigneeActorId: owner,
|
|
20239
|
-
assigneeRole: null,
|
|
20240
20238
|
isFinalOutput: args.isFinalOutput ?? false,
|
|
20241
20239
|
// ★ docType(projects 域的具体文档类型)随节点 fields 落库(同 reviewRoles 的做法,jsonb 免加列);
|
|
20242
20240
|
// bridge 投影时从 fields 剥出成 artifact.docType、不混进用户自定义字段。
|
|
@@ -21101,8 +21099,7 @@ var init_kernel_bridge = __esm({
|
|
|
21101
21099
|
kind: "plan.assign_actor",
|
|
21102
21100
|
workorderId: wid,
|
|
21103
21101
|
nodeId: args.artifactId,
|
|
21104
|
-
assigneeActorId: args.owner
|
|
21105
|
-
assigneeRole: null
|
|
21102
|
+
assigneeActorId: args.owner
|
|
21106
21103
|
}
|
|
21107
21104
|
});
|
|
21108
21105
|
}
|
|
@@ -21628,7 +21625,6 @@ var init_kernel_bridge = __esm({
|
|
|
21628
21625
|
title: op.title ?? op.type,
|
|
21629
21626
|
spec: op.description ?? null,
|
|
21630
21627
|
assigneeActorId: spawnOwner,
|
|
21631
|
-
assigneeRole: null,
|
|
21632
21628
|
isFinalOutput: op.isFinalOutput ?? false,
|
|
21633
21629
|
...allReviewers.length > 0 ? { reviewers: allReviewers } : {},
|
|
21634
21630
|
...mergedFields ? { fields: mergedFields } : {}
|
|
@@ -21675,7 +21671,7 @@ var init_kernel_bridge = __esm({
|
|
|
21675
21671
|
break;
|
|
21676
21672
|
}
|
|
21677
21673
|
case "assign":
|
|
21678
|
-
await enqueue({ kind: "plan.assign_actor", workorderId: woFor(op.artifactId), nodeId: op.artifactId, assigneeActorId: op.owner
|
|
21674
|
+
await enqueue({ kind: "plan.assign_actor", workorderId: woFor(op.artifactId), nodeId: op.artifactId, assigneeActorId: op.owner });
|
|
21679
21675
|
applied++;
|
|
21680
21676
|
break;
|
|
21681
21677
|
case "seal":
|
|
@@ -31180,6 +31176,9 @@ var init_chat_turn_gate = __esm({
|
|
|
31180
31176
|
function isDeletedActor(actor) {
|
|
31181
31177
|
return actor?.status === "disabled";
|
|
31182
31178
|
}
|
|
31179
|
+
function hideDeleted(rows) {
|
|
31180
|
+
return rows.filter((row) => row.status !== "disabled");
|
|
31181
|
+
}
|
|
31183
31182
|
var ACTOR_DELETED_CHAT_MESSAGE, ACTOR_DELETED_ERROR_CODE, ActorAlreadyDeletedError;
|
|
31184
31183
|
var init_deletion = __esm({
|
|
31185
31184
|
"../server/src/domains/actors/deletion.ts"() {
|
|
@@ -210253,6 +210252,11 @@ var init_memory_registry_store = __esm({
|
|
|
210253
210252
|
...v2.updatedBy ? { updatedBy: v2.updatedBy } : {}
|
|
210254
210253
|
});
|
|
210255
210254
|
}
|
|
210255
|
+
async insertVariable(v2) {
|
|
210256
|
+
if (this.variables.has(this._varKey(v2.key, v2.actorId, v2.projectId))) return false;
|
|
210257
|
+
await this.putVariable(v2);
|
|
210258
|
+
return true;
|
|
210259
|
+
}
|
|
210256
210260
|
async touchVariableUsage(key, actorId, projectId2, when) {
|
|
210257
210261
|
const mk = this._varKey(key, actorId, projectId2);
|
|
210258
210262
|
const ex = this.variables.get(mk);
|
|
@@ -216681,6 +216685,9 @@ var init_company_scoped_registry = __esm({
|
|
|
216681
216685
|
async putVariable(...args) {
|
|
216682
216686
|
return this.base.putVariable(...args);
|
|
216683
216687
|
}
|
|
216688
|
+
async insertVariable(...args) {
|
|
216689
|
+
return this.base.insertVariable(...args);
|
|
216690
|
+
}
|
|
216684
216691
|
async patchVariableValue(...args) {
|
|
216685
216692
|
return this.base.patchVariableValue(...args);
|
|
216686
216693
|
}
|
|
@@ -221846,6 +221853,9 @@ function computeEffectiveEntries(config2, connections, connectors) {
|
|
|
221846
221853
|
}
|
|
221847
221854
|
return out;
|
|
221848
221855
|
}
|
|
221856
|
+
function personalConnectionPairs(vars) {
|
|
221857
|
+
return vars.flatMap((v2) => v2.scope === "personal" && v2.actorId && v2.connectorId ? [{ actorId: v2.actorId, connectorId: v2.connectorId }] : []);
|
|
221858
|
+
}
|
|
221849
221859
|
function variableKeyFromEnv(env = process.env) {
|
|
221850
221860
|
const hex = env.OASIS_VAR_KEY;
|
|
221851
221861
|
if (hex) {
|
|
@@ -222587,35 +222597,43 @@ ${input.description}
|
|
|
222587
222597
|
}
|
|
222588
222598
|
}
|
|
222589
222599
|
/**
|
|
222590
|
-
*
|
|
222591
|
-
*
|
|
222592
|
-
*
|
|
222600
|
+
* 管理页连接器列表的「N 个 Agent 已连接」:每个连接器上**建立过 Agent 层连接**的 Agent
|
|
222601
|
+
* (判据见 {@link personalConnectionPairs},与类型详情页的行、组织页 tab 同一份)。
|
|
222602
|
+
*
|
|
222603
|
+
* 口径与原型帧 `1496:5390` / `1551:767` 对齐:卡片上的数 = 点进去那一页的行数——
|
|
222604
|
+
* 开关关着的、凭据不全或解不开的都是一行,也都算一个;从没连过的不算。
|
|
222605
|
+
*
|
|
222606
|
+
* 两处刻意的范围:
|
|
222607
|
+
* · 人群 = 花名册(`GET /api/actors?kind=agent`)那一群:**已删除的 Agent 不算**——详情页压根列不出他们,
|
|
222608
|
+
* 算进来就是「卡片 5、点进去 4」。
|
|
222609
|
+
* · 不以连接器表为界:2026-09-09 起连接器类型对所有组织默认可用、个人授权又不碰组织行,
|
|
222610
|
+
* 连接器表**天然是空的**(二期生产 09-15 实测 `items: []`)。此前只对表里有行的连接器聚合,
|
|
222611
|
+
* 卡片恒为「暂无连接的 Agent」、点进去却有好几位。没有组织行的连接器单列在
|
|
222612
|
+
* `connectedActorIdsByConnector` 里,**不**编一条 Connector 记录塞进 `items`(没有的 name/mode 不造)。
|
|
222613
|
+
*
|
|
222614
|
+
* 这里**不再**按 `effective` 数(此前的「对谁生效」口径):那是注入闸,含组织默认与旧 connectorIds 两档,
|
|
222615
|
+
* 数出来的人与详情行、组织页 tab 都对不上。注入闸本身(`computeEffectiveEntries`)不动。
|
|
222593
222616
|
*/
|
|
222594
222617
|
async listConnectorsWithAssignments() {
|
|
222595
|
-
const [connectors, agents] = await Promise.all([
|
|
222618
|
+
const [connectors, agents, vars] = await Promise.all([
|
|
222596
222619
|
this.opts.store.listConnectors(),
|
|
222597
|
-
this.opts.store.listActors({ kind: "agent" })
|
|
222620
|
+
this.opts.store.listActors({ kind: "agent" }),
|
|
222621
|
+
this.opts.store.listVariables()
|
|
222598
222622
|
]);
|
|
222599
|
-
const
|
|
222600
|
-
const configs = this.opts.store.latestConfigs ? await this.opts.store.latestConfigs(agentIds) : new Map(await Promise.all(agentIds.map(async (id) => [id, await this.opts.store.latestConfig(id)])));
|
|
222601
|
-
const allConns = this.opts.store.listAllActorConnectorConnections ? await this.opts.store.listAllActorConnectorConnections() : (await Promise.all(agentIds.map((id) => this.opts.store.listActorConnectorConnections(id)))).flat();
|
|
222602
|
-
const connsByActor = /* @__PURE__ */ new Map();
|
|
222603
|
-
for (const c of allConns) {
|
|
222604
|
-
const arr = connsByActor.get(c.actorId) ?? [];
|
|
222605
|
-
arr.push(c);
|
|
222606
|
-
connsByActor.set(c.actorId, arr);
|
|
222607
|
-
}
|
|
222623
|
+
const roster = new Set(hideDeleted(agents).map((a) => a.id));
|
|
222608
222624
|
const byConn = /* @__PURE__ */ new Map();
|
|
222609
|
-
for (const
|
|
222610
|
-
|
|
222611
|
-
|
|
222612
|
-
|
|
222613
|
-
|
|
222614
|
-
|
|
222615
|
-
|
|
222616
|
-
|
|
222617
|
-
|
|
222618
|
-
|
|
222625
|
+
for (const { actorId, connectorId } of personalConnectionPairs(vars)) {
|
|
222626
|
+
if (!roster.has(actorId)) continue;
|
|
222627
|
+
const set = byConn.get(connectorId) ?? /* @__PURE__ */ new Set();
|
|
222628
|
+
set.add(actorId);
|
|
222629
|
+
byConn.set(connectorId, set);
|
|
222630
|
+
}
|
|
222631
|
+
const connectedActorIdsByConnector = {};
|
|
222632
|
+
for (const [connectorId, set] of byConn) connectedActorIdsByConnector[connectorId] = [...set];
|
|
222633
|
+
return {
|
|
222634
|
+
items: connectors.map((c) => ({ ...c, connectedActorIds: connectedActorIdsByConnector[c.id] ?? [] })),
|
|
222635
|
+
connectedActorIdsByConnector
|
|
222636
|
+
};
|
|
222619
222637
|
}
|
|
222620
222638
|
/** 该员工最新配置里启用的 connector id 集合——与 resolveActorEnv 同一闸门(connectorIds 成员资格)。 */
|
|
222621
222639
|
async activeConnectorIdsForActor(actorId, cfg) {
|
|
@@ -222712,17 +222730,94 @@ ${input.description}
|
|
|
222712
222730
|
]);
|
|
222713
222731
|
const globalConnected = connectors.filter((c) => c.status === "connected").map((c) => c.id);
|
|
222714
222732
|
const actorConnected = [...new Set(
|
|
222715
|
-
vars.filter((
|
|
222733
|
+
personalConnectionPairs(vars).filter((p2) => p2.actorId === actorId).map((p2) => p2.connectorId)
|
|
222716
222734
|
)];
|
|
222717
222735
|
const effective = await this.effectiveConnectorEntries(actorId, config2, connectors);
|
|
222736
|
+
const { ready, assessed, undecryptable } = this.connectorCredentialReadiness(actorId, vars);
|
|
222737
|
+
const credentialReady = [...ready];
|
|
222738
|
+
const credentialUndecryptable = [...undecryptable];
|
|
222739
|
+
const credentialMissing = actorConnected.filter(
|
|
222740
|
+
(id) => undecryptable.has(id) || assessed.has(id) && !ready.has(id)
|
|
222741
|
+
);
|
|
222742
|
+
return { connections, globalConnected, actorConnected, effective, credentialReady, credentialMissing, credentialUndecryptable };
|
|
222743
|
+
}
|
|
222744
|
+
/**
|
|
222745
|
+
* 这名员工每个连接器的凭据齐不齐——**派单那条路的等价判定**:
|
|
222746
|
+
* ① `collectAllConnectorCredentials`(派单与会话中途续期共用的那个函数)现在就收得齐;或
|
|
222747
|
+
* ② 连接器声明了续期能力,且续期材料里 required 的几项都在(`orgDefault` 的可回落组织级,
|
|
222748
|
+
* 与 `readRefreshMaterials` 同口径)——`resolveActorEnv` 注入前会先跑
|
|
222749
|
+
* `refreshEnabledConnectorCredentials`,把短命凭据铸出来再收。
|
|
222750
|
+
* GitHub App 就是这一类:组织级连接只存 App 材料、token 每次派单现铸(server.ts 的 manifest
|
|
222751
|
+
* 回调刻意不存组织级 token)。只看 ① 会把它一刀切报成「凭据不全」。
|
|
222752
|
+
*
|
|
222753
|
+
* 续期**会不会成功**(私钥被吊销、App 被卸载、飞书 refresh_token 过期、平台不可达 / 限流)这里判不了——
|
|
222754
|
+
* 要真打一次平台才知道,PRD「不能获取时不伪造」,所以不算异常。
|
|
222755
|
+
* `assessed` = 本服务判得了的连接器(注册表里有的)。
|
|
222756
|
+
*
|
|
222757
|
+
* **解不开的密文**(变量密钥换过、坏行)不能当「没有」处理,要记成那个连接器的异常证据(`undecryptable`)。
|
|
222758
|
+
* 派单那条路(serve.ts `buildActorProvision` → `resolveActorProvisionEntries`;`resolveActorEnv` 同规则)
|
|
222759
|
+
* 对「无 connectorId 的行 + 启用中连接器的行」**逐行**解密,任何一行解不开就抛,dispatcher 记 spawn-failed
|
|
222760
|
+
* ——整单派不出去,不是只少一个连接器:
|
|
222761
|
+
* · 不回落同 key 的组织值(个人行存在就解个人行,解不开就抛;续期读材料的 `revealResolvedVariable` 同理);
|
|
222762
|
+
* · 不跳过可选项(用户 token、只在服务端用的 refresh_token 也逐行解);
|
|
222763
|
+
* · 续期读材料撞上坏行 → 该连接器本轮不续(best-effort catch),坏行原样留着,下一步解密照样抛。
|
|
222764
|
+
* 所以这里若把坏行当「没有」再回落组织值、或因为它可选就放过,界面会说凭据齐全而派单整单失败
|
|
222765
|
+
* (2026-09-15 验收时补的回归:connector-connection-consistency.test.ts「解不开的密文」一组)。
|
|
222766
|
+
* 反过来**不改运行时**:派单遇坏行就失败是既有的身份策略,不为了显示去动它。
|
|
222767
|
+
*
|
|
222768
|
+
* 归属:行上有 `connectorId` 就归它;没有(密钥页手录的那种)就归「声明了这个变量名的连接器」——
|
|
222769
|
+
* 与这里收凭据时不看 `connectorId`、只按变量名取值是同一口径。归属不到任何连接器的坏行(如组织级
|
|
222770
|
+
* OPENAI_API_KEY)一样会让派单失败,但它不是哪条连接的事,不拿它把无关连接器标坏。
|
|
222771
|
+
* 此前(更早)这里直接抛,整个 `GET /api/actors/:id/connectors` 500;现在接口照样可读。
|
|
222772
|
+
*/
|
|
222773
|
+
connectorCredentialReadiness(actorId, vars) {
|
|
222774
|
+
const connectors = createAllConnectors();
|
|
222775
|
+
const declaredBy = /* @__PURE__ */ new Map();
|
|
222776
|
+
for (const connector of connectors) {
|
|
222777
|
+
for (const s2 of [...connector.credentialSources, ...connector.refreshCredentialSources ?? []]) {
|
|
222778
|
+
for (const key of [s2.from, ...s2.fromAny ?? []]) {
|
|
222779
|
+
const slugs = declaredBy.get(key) ?? [];
|
|
222780
|
+
if (!slugs.includes(connector.config.slug)) declaredBy.set(key, [...slugs, connector.config.slug]);
|
|
222781
|
+
}
|
|
222782
|
+
}
|
|
222783
|
+
}
|
|
222784
|
+
const undecryptable = /* @__PURE__ */ new Set();
|
|
222785
|
+
const decode2 = (v2) => {
|
|
222786
|
+
try {
|
|
222787
|
+
return this.decodeCiphertext(v2.valueEncrypted);
|
|
222788
|
+
} catch {
|
|
222789
|
+
for (const slug6 of v2.connectorId ? [v2.connectorId] : declaredBy.get(v2.key) ?? []) undecryptable.add(slug6);
|
|
222790
|
+
return void 0;
|
|
222791
|
+
}
|
|
222792
|
+
};
|
|
222718
222793
|
const flat = {};
|
|
222719
|
-
|
|
222720
|
-
for (const v2 of vars)
|
|
222721
|
-
|
|
222794
|
+
const own3 = {};
|
|
222795
|
+
for (const v2 of vars) {
|
|
222796
|
+
if (v2.scope !== "global" || v2.actorId) continue;
|
|
222797
|
+
const value2 = decode2(v2);
|
|
222798
|
+
if (value2 !== void 0) flat[v2.key] = value2;
|
|
222799
|
+
}
|
|
222800
|
+
for (const v2 of vars) {
|
|
222801
|
+
if (v2.scope !== "personal" || v2.actorId && v2.actorId !== actorId) continue;
|
|
222802
|
+
const value2 = decode2(v2);
|
|
222803
|
+
if (value2 === void 0) continue;
|
|
222804
|
+
flat[v2.key] = value2;
|
|
222805
|
+
if (v2.actorId === actorId) own3[v2.key] = value2;
|
|
222806
|
+
}
|
|
222807
|
+
const ready = new Set(collectAllConnectorCredentials({
|
|
222722
222808
|
vars: flat,
|
|
222723
222809
|
actorName: flat["GIT_AUTHOR_NAME"] ?? actorId.split(":").pop() ?? "oasis-agent"
|
|
222724
|
-
}).map((c) => c.slug);
|
|
222725
|
-
|
|
222810
|
+
}).map((c) => c.slug));
|
|
222811
|
+
const assessed = /* @__PURE__ */ new Set();
|
|
222812
|
+
for (const connector of connectors) {
|
|
222813
|
+
const slug6 = connector.config.slug;
|
|
222814
|
+
assessed.add(slug6);
|
|
222815
|
+
if (ready.has(slug6) || !connector.refreshCredentials) continue;
|
|
222816
|
+
const materials = (connector.refreshCredentialSources ?? []).filter((s2) => s2.required);
|
|
222817
|
+
if (materials.length > 0 && materials.every((s2) => Boolean((s2.orgDefault ? flat : own3)[s2.from]))) ready.add(slug6);
|
|
222818
|
+
}
|
|
222819
|
+
for (const slug6 of undecryptable) ready.delete(slug6);
|
|
222820
|
+
return { ready, assessed, undecryptable };
|
|
222726
222821
|
}
|
|
222727
222822
|
/**
|
|
222728
222823
|
* 该员工每个连接器的「有效启用」集合(变量/技能注入闸门):
|
|
@@ -222815,6 +222910,23 @@ ${input.description}
|
|
|
222815
222910
|
if (v2.value === void 0 || v2.value === "") {
|
|
222816
222911
|
return;
|
|
222817
222912
|
}
|
|
222913
|
+
await this.opts.store.putVariable(this.toStoredVariableRow(v2, v2.value));
|
|
222914
|
+
}
|
|
222915
|
+
/**
|
|
222916
|
+
* **新建**一条变量(决策 0565):这一行(组织变量按 key、个人变量按 key + actorId、项目变量按 key + projectId)
|
|
222917
|
+
* 已经存在就返回 `"exists"`、什么都不写——不像 `putVariable` 那样悄悄覆盖。
|
|
222918
|
+
*
|
|
222919
|
+
* 「管理页新建组织变量」「Agent 详情新建个人变量」都走这里:同一组织第二条同名组织变量、同一 Agent
|
|
222920
|
+
* 第二条同名个人变量在存储层当场被挡下;不同 Agent 的同名个人变量、以及个人变量与同名组织变量
|
|
222921
|
+
* 是不同的唯一键,照常共存。值必填(新建出一条没有值的空壳没有意义)。
|
|
222922
|
+
*/
|
|
222923
|
+
async createVariable(v2) {
|
|
222924
|
+
if (!v2.value) throw new ApiError(400, "BAD_REQUEST", "\u65B0\u5EFA\u53D8\u91CF\u5FC5\u987B\u63D0\u4F9B\u53D8\u91CF\u503C");
|
|
222925
|
+
const inserted = await this.opts.store.insertVariable(this.toStoredVariableRow(v2, v2.value));
|
|
222926
|
+
return inserted ? "created" : "exists";
|
|
222927
|
+
}
|
|
222928
|
+
/** `putVariable` / `createVariable` 共用:校验 + 加密 + 摊成存储行。两条写路径的落行口径必须逐字一致。 */
|
|
222929
|
+
toStoredVariableRow(v2, value2) {
|
|
222818
222930
|
if (v2.deliveryMode === void 0 && v2.connectorId === void 0) {
|
|
222819
222931
|
throw new ApiError(
|
|
222820
222932
|
400,
|
|
@@ -222822,7 +222934,7 @@ ${input.description}
|
|
|
222822
222934
|
"\u5199\u53D8\u91CF\u5FC5\u987B\u663E\u5F0F\u63D0\u4F9B deliveryMode\uFF08env | ref | broker\uFF09\u2014\u2014\u6295\u9012\u6863\u51B3\u5B9A\u660E\u6587\u662F\u5426\u8FDB agent env\uFF0C\u4E0D\u8BBE\u7F3A\u7701"
|
|
222823
222935
|
);
|
|
222824
222936
|
}
|
|
222825
|
-
|
|
222937
|
+
return {
|
|
222826
222938
|
key: v2.key,
|
|
222827
222939
|
// 展示名(子 PRD《密钥管理》§2)。没传就不传下去——存储层按「不动」处理,不抹既有名字。
|
|
222828
222940
|
...v2.name !== void 0 && v2.name !== "" ? { name: v2.name } : {},
|
|
@@ -222833,7 +222945,7 @@ ${input.description}
|
|
|
222833
222945
|
...v2.overrides !== void 0 ? { overrides: v2.overrides } : {},
|
|
222834
222946
|
// 非连接器写入到此 deliveryMode 必非空(上面已拦);连接器写入沿用 env(其值经 sensitiveVars 剔除,不进 env)。
|
|
222835
222947
|
deliveryMode: v2.deliveryMode ?? "env",
|
|
222836
|
-
valueEncrypted: v2.encrypted === false ? `plain:${
|
|
222948
|
+
valueEncrypted: v2.encrypted === false ? `plain:${value2}` : this.encrypt(value2),
|
|
222837
222949
|
updatedAt: this.now(),
|
|
222838
222950
|
/* 创建者 / 创建时间 / 更新者:**由服务端落,不接受调用方自报**。
|
|
222839
222951
|
createdBy/createdAt 两格存储层按「第一次落行才写」处理(COALESCE 旧值),所以这里每次都传,
|
|
@@ -222846,7 +222958,7 @@ ${input.description}
|
|
|
222846
222958
|
// 决策 0556:发给谁只对全局行有意义;个人档 / 项目档一律不带(存储层 COALESCE:不带 = 不动)。
|
|
222847
222959
|
...v2.scope === "global" && v2.audience !== void 0 ? { audience: v2.audience } : {},
|
|
222848
222960
|
...v2.scope === "global" && v2.enabledActorIds !== void 0 ? { enabledActorIds: dedupe(v2.enabledActorIds) } : {}
|
|
222849
|
-
}
|
|
222961
|
+
};
|
|
222850
222962
|
}
|
|
222851
222963
|
/**
|
|
222852
222964
|
* 只改一行变量的元数据、不碰值(决策 0556)。
|
|
@@ -222906,15 +223018,18 @@ ${input.description}
|
|
|
222906
223018
|
/** 前端/接口可见的列表。
|
|
222907
223019
|
* - actorId 指定时:返回全局 + 该员工个人变量,按 key 去重(个人覆盖全局);
|
|
222908
223020
|
* 个人变量如覆盖同名全局则 overrides 字段填 key 名,告知前端。
|
|
223021
|
+
* `opts.includeShadowed`(决策 0565):**不去重**——被同名个人变量覆盖的那条组织变量也带上,
|
|
223022
|
+
* Agent 详情要把「组织变量」与「个人变量」分开摆,覆盖关系由调用方按同名个人行判。
|
|
223023
|
+
* 发给谁(audience)的过滤仍由存储层那一条查询做,这里不另判。
|
|
222909
223024
|
* - 不指定时:返回全部(管理员视图,不去重)。
|
|
222910
223025
|
*/
|
|
222911
|
-
async listVariables(actorId) {
|
|
223026
|
+
async listVariables(actorId, opts) {
|
|
222912
223027
|
const rows = await this.opts.store.listVariables(actorId);
|
|
222913
223028
|
let source = rows;
|
|
222914
223029
|
if (actorId) {
|
|
222915
223030
|
const personalKeys = new Set(rows.filter((r) => r.actorId).map((r) => r.key));
|
|
222916
223031
|
const globalKeys = new Set(rows.filter((r) => !r.actorId).map((r) => r.key));
|
|
222917
|
-
source = rows.filter((r) => r.actorId !== void 0 || !personalKeys.has(r.key));
|
|
223032
|
+
if (!opts?.includeShadowed) source = rows.filter((r) => r.actorId !== void 0 || !personalKeys.has(r.key));
|
|
222918
223033
|
source = source.map(
|
|
222919
223034
|
(r) => r.actorId && globalKeys.has(r.key) && !r.overrides ? { ...r, overrides: r.key } : r
|
|
222920
223035
|
);
|
|
@@ -222956,11 +223071,19 @@ ${input.description}
|
|
|
222956
223071
|
* 或行是 2026-09-10 之前落的(那时还没有 created_by 这一格)。
|
|
222957
223072
|
*/
|
|
222958
223073
|
async variableCreatedBy(key, selector = {}) {
|
|
223074
|
+
return (await this.variableRowMeta(key, selector))?.createdBy;
|
|
223075
|
+
}
|
|
223076
|
+
/** 按存储唯一键 (key, actorId?, projectId?) 找那一行的元数据(**不解密**)。没有这一行返回 undefined。 */
|
|
223077
|
+
async variableRowMeta(key, selector = {}) {
|
|
222959
223078
|
const rows = await this.opts.store.listVariables();
|
|
222960
223079
|
const hit = rows.find(
|
|
222961
223080
|
(r) => r.key === key && (r.actorId ?? "") === (selector.actorId ?? "") && (r.projectId ?? "") === (selector.projectId ?? "")
|
|
222962
223081
|
);
|
|
222963
|
-
return
|
|
223082
|
+
if (!hit) return void 0;
|
|
223083
|
+
return {
|
|
223084
|
+
...hit.createdBy !== void 0 ? { createdBy: hit.createdBy } : {},
|
|
223085
|
+
...hit.connectorId !== void 0 ? { connectorId: hit.connectorId } : {}
|
|
223086
|
+
};
|
|
222964
223087
|
}
|
|
222965
223088
|
async revealVariable(key, actorId) {
|
|
222966
223089
|
const ct = await this.opts.store.getVariableCiphertext(key, actorId);
|
|
@@ -224316,7 +224439,8 @@ function actorsDomain(opts) {
|
|
|
224316
224439
|
});
|
|
224317
224440
|
router.get("/api/connectors", async (req) => {
|
|
224318
224441
|
const { service } = await resolveCtx(req.auth.companyId);
|
|
224319
|
-
|
|
224442
|
+
const { items, connectedActorIdsByConnector } = await service.listConnectorsWithAssignments();
|
|
224443
|
+
return { status: 200, body: { items, connectedActorIdsByConnector } };
|
|
224320
224444
|
});
|
|
224321
224445
|
router.post("/api/connectors", async (req) => {
|
|
224322
224446
|
const { service } = await resolveCtx(req.auth.companyId);
|
|
@@ -224367,9 +224491,39 @@ function actorsDomain(opts) {
|
|
|
224367
224491
|
throw new ApiError(
|
|
224368
224492
|
403,
|
|
224369
224493
|
"SECRET_NOT_OWNED",
|
|
224370
|
-
"\u8FD9\
|
|
224494
|
+
"\u8FD9\u6761\u53D8\u91CF\u7531\u522B\u4EBA\u521B\u5EFA\uFF0C\u53EA\u6709\u521B\u5EFA\u8005\u672C\u4EBA\u6216\u7EC4\u7EC7\u7BA1\u7406\u8005\u53EF\u4EE5\u4FEE\u6539 / \u5220\u9664"
|
|
224371
224495
|
);
|
|
224372
224496
|
};
|
|
224497
|
+
const variableExistsError = async (service, key, selector) => {
|
|
224498
|
+
const meta = await service.variableRowMeta(key, selector).catch(() => void 0);
|
|
224499
|
+
if (meta?.connectorId) {
|
|
224500
|
+
return new ApiError(
|
|
224501
|
+
409,
|
|
224502
|
+
"VARIABLE_ALREADY_EXISTS",
|
|
224503
|
+
`\u53D8\u91CF\u540D ${key} \u5DF2\u88AB\u8FDE\u63A5\u5668\u300C${meta.connectorId}\u300D\u7684\u51ED\u636E\u5360\u7528\uFF1B\u8FDE\u63A5\u5668\u51ED\u636E\u8BF7\u901A\u8FC7\u8FDE\u63A5\u5668\u6388\u6743\u6D41\u7A0B\u7EF4\u62A4`
|
|
224504
|
+
);
|
|
224505
|
+
}
|
|
224506
|
+
if (selector.actorId) {
|
|
224507
|
+
return new ApiError(
|
|
224508
|
+
409,
|
|
224509
|
+
"VARIABLE_ALREADY_EXISTS",
|
|
224510
|
+
`\u8FD9\u4F4D Agent \u5DF2\u7ECF\u6709\u53EB ${key} \u7684\u4E2A\u4EBA\u53D8\u91CF\u4E86\u2014\u2014\u540C\u4E00 Agent \u540C\u4E00\u4E2A\u53D8\u91CF\u540D\u53EA\u80FD\u6709\u4E00\u6761\u4E2A\u4EBA\u53D8\u91CF\uFF0C\u8981\u6539\u8BF7\u7F16\u8F91\u90A3\u4E00\u6761`
|
|
224511
|
+
);
|
|
224512
|
+
}
|
|
224513
|
+
if (selector.projectId) {
|
|
224514
|
+
return new ApiError(409, "VARIABLE_ALREADY_EXISTS", `\u9879\u76EE ${selector.projectId} \u5DF2\u7ECF\u6709\u53EB ${key} \u7684\u9879\u76EE\u53D8\u91CF\u4E86`);
|
|
224515
|
+
}
|
|
224516
|
+
return new ApiError(
|
|
224517
|
+
409,
|
|
224518
|
+
"VARIABLE_ALREADY_EXISTS",
|
|
224519
|
+
`\u7EC4\u7EC7\u91CC\u5DF2\u7ECF\u6709\u53EB ${key} \u7684\u7EC4\u7EC7\u53D8\u91CF\u4E86\u2014\u2014\u540C\u4E00\u4E2A\u53D8\u91CF\u540D\u5728\u7EC4\u7EC7\u91CC\u53EA\u80FD\u6709\u4E00\u6761\u7EC4\u7EC7\u53D8\u91CF\uFF0C\u8981\u6539\u8BF7\u7F16\u8F91\u90A3\u4E00\u6761`
|
|
224520
|
+
);
|
|
224521
|
+
};
|
|
224522
|
+
const parseCreateFlag = (raw) => {
|
|
224523
|
+
if (raw === void 0 || raw === false) return false;
|
|
224524
|
+
if (raw === true) return true;
|
|
224525
|
+
throw new ApiError(400, "BAD_REQUEST", "create \u53EA\u80FD\u662F\u5E03\u5C14\u503C true / false");
|
|
224526
|
+
};
|
|
224373
224527
|
const auditVariableChange = async (req, kind, variableKey, targetScope) => {
|
|
224374
224528
|
await opts.credentialAudit?.({
|
|
224375
224529
|
kind,
|
|
@@ -224391,6 +224545,7 @@ function actorsDomain(opts) {
|
|
|
224391
224545
|
const { service } = await resolveCtx(req.auth.companyId);
|
|
224392
224546
|
const b2 = req.body;
|
|
224393
224547
|
if (!b2?.key) throw new ApiError(400, "BAD_REQUEST", "\u7F3A\u5C11 key");
|
|
224548
|
+
const create = parseCreateFlag(b2.create);
|
|
224394
224549
|
const expiresAt2 = normalizeExpiresAt(b2.expiresAt);
|
|
224395
224550
|
const audienceMeta = parseAudienceMeta(b2);
|
|
224396
224551
|
if ((audienceMeta.audience !== void 0 || audienceMeta.enabledActorIds !== void 0) && b2.scope !== "global") {
|
|
@@ -224407,7 +224562,7 @@ function actorsDomain(opts) {
|
|
|
224407
224562
|
if (scope === "project" && !b2.projectId) {
|
|
224408
224563
|
throw new ApiError(400, "BAD_REQUEST", "scope=project \u5FC5\u987B\u63D0\u4F9B projectId");
|
|
224409
224564
|
}
|
|
224410
|
-
if (scope === "project" && opts.projectExists && !await opts.projectExists(b2.projectId)) {
|
|
224565
|
+
if (scope === "project" && opts.projectExists && !await opts.projectExists(b2.projectId, req.auth.companyId)) {
|
|
224411
224566
|
throw new ApiError(400, "BAD_REQUEST", `\u9879\u76EE\u4E0D\u5B58\u5728\uFF1A${b2.projectId}\uFF08scope=project \u53D8\u91CF\u7684 projectId \u5FC5\u987B\u662F\u771F\u5B9E\u9879\u76EE\uFF09`);
|
|
224412
224567
|
}
|
|
224413
224568
|
if (b2.deliveryMode !== void 0 && b2.deliveryMode !== "env" && b2.deliveryMode !== "ref" && b2.deliveryMode !== "broker") {
|
|
@@ -224427,11 +224582,9 @@ function actorsDomain(opts) {
|
|
|
224427
224582
|
"personal \u53D8\u91CF\u8BF7\u8D70 POST /api/actors/:id/variables\uFF08\u672C\u7AEF\u70B9\u65E0 actorId\uFF0C\u5199\u5165\u4F1A\u843D\u4E0B\u65E0\u5F52\u5C5E\u7684\u7578\u5F62\u884C\uFF09"
|
|
224428
224583
|
);
|
|
224429
224584
|
}
|
|
224430
|
-
|
|
224431
|
-
|
|
224432
|
-
await service.putVariable({
|
|
224585
|
+
const selector = scope === "project" ? { projectId: b2.projectId } : {};
|
|
224586
|
+
const input = {
|
|
224433
224587
|
key: b2.key,
|
|
224434
|
-
value: b2.value,
|
|
224435
224588
|
scope,
|
|
224436
224589
|
// 展示名(子 PRD《密钥管理》§2「名称」);不传 = 不改既有名字。
|
|
224437
224590
|
...typeof b2.name === "string" && b2.name.trim() ? { name: b2.name.trim() } : {},
|
|
@@ -224444,7 +224597,16 @@ function actorsDomain(opts) {
|
|
|
224444
224597
|
// 创建者/更新者取**当前登录人**,不接受 body 传入——自报的「谁建的」等于没有这一格。
|
|
224445
224598
|
by: req.auth.actor,
|
|
224446
224599
|
expiresAt: expiresAt2
|
|
224447
|
-
}
|
|
224600
|
+
};
|
|
224601
|
+
if (create) {
|
|
224602
|
+
if (b2.value === void 0 || b2.value === "") throw new ApiError(400, "BAD_REQUEST", "\u65B0\u5EFA\u53D8\u91CF\u5FC5\u987B\u63D0\u4F9B\u53D8\u91CF\u503C");
|
|
224603
|
+
const outcome = await service.createVariable({ ...input, value: b2.value });
|
|
224604
|
+
if (outcome === "exists") throw await variableExistsError(service, b2.key, selector);
|
|
224605
|
+
} else {
|
|
224606
|
+
if (b2.value === void 0 || b2.value === "") return { status: 200, body: { ok: true } };
|
|
224607
|
+
await requireSecretOwner(req, service, b2.key, selector);
|
|
224608
|
+
await service.putVariable({ ...input, value: b2.value });
|
|
224609
|
+
}
|
|
224448
224610
|
await auditVariableChange(
|
|
224449
224611
|
req,
|
|
224450
224612
|
"credential_write",
|
|
@@ -224486,7 +224648,8 @@ function actorsDomain(opts) {
|
|
|
224486
224648
|
router.get("/api/actors/:id/variables", async (req) => {
|
|
224487
224649
|
requireVariableManager(req);
|
|
224488
224650
|
const { service } = await resolveCtx(req.auth.companyId);
|
|
224489
|
-
|
|
224651
|
+
const includeShadowed = ["1", "true"].includes(req.query.get("includeShadowed") ?? "");
|
|
224652
|
+
return { status: 200, body: { items: await service.listVariables(req.params.id, includeShadowed ? { includeShadowed } : void 0) } };
|
|
224490
224653
|
});
|
|
224491
224654
|
router.post("/api/actors/:id/variables", async (req) => {
|
|
224492
224655
|
requireVariableManager(req);
|
|
@@ -224494,6 +224657,12 @@ function actorsDomain(opts) {
|
|
|
224494
224657
|
const actorId = req.params.id;
|
|
224495
224658
|
const b2 = req.body;
|
|
224496
224659
|
if (!b2?.key) throw new ApiError(400, "BAD_REQUEST", "\u7F3A\u5C11 key");
|
|
224660
|
+
const create = parseCreateFlag(b2.create);
|
|
224661
|
+
if (create) {
|
|
224662
|
+
const owner = await service.getActor(actorId);
|
|
224663
|
+
if (!owner) throw new ApiError(404, "NOT_FOUND", `\u6CA1\u6709\u8FD9\u4E2A Agent\uFF1A${actorId}`);
|
|
224664
|
+
if (owner.kind !== "agent") throw new ApiError(400, "BAD_REQUEST", "\u4E2A\u4EBA\u53D8\u91CF\u53EA\u80FD\u5EFA\u5728 Agent \u4E0A");
|
|
224665
|
+
}
|
|
224497
224666
|
const expiresAt2 = normalizeExpiresAt(b2.expiresAt);
|
|
224498
224667
|
if (b2.deliveryMode !== void 0 && b2.deliveryMode !== "env" && b2.deliveryMode !== "ref" && b2.deliveryMode !== "broker") {
|
|
224499
224668
|
throw new ApiError(400, "BAD_REQUEST", "deliveryMode \u53EA\u80FD\u662F env\u3001ref \u6216 broker");
|
|
@@ -224505,6 +224674,7 @@ function actorsDomain(opts) {
|
|
|
224505
224674
|
"\u5FC5\u987B\u663E\u5F0F\u63D0\u4F9B deliveryMode\uFF08env | ref | broker\uFF09\u2014\u2014\u6295\u9012\u6863\u51B3\u5B9A\u660E\u6587\u662F\u5426\u8FDB agent env\uFF0C\u4E0D\u8BBE\u7F3A\u7701"
|
|
224506
224675
|
);
|
|
224507
224676
|
}
|
|
224677
|
+
if (create && (b2.value === void 0 || b2.value === "")) throw new ApiError(400, "BAD_REQUEST", "\u65B0\u5EFA\u53D8\u91CF\u5FC5\u987B\u63D0\u4F9B\u53D8\u91CF\u503C");
|
|
224508
224678
|
if (b2.value === void 0 || b2.value === "") return { status: 200, body: { ok: true } };
|
|
224509
224679
|
if (b2.connectorId === void 0) {
|
|
224510
224680
|
const existing = await service.listVariables(actorId);
|
|
@@ -224517,13 +224687,12 @@ function actorsDomain(opts) {
|
|
|
224517
224687
|
);
|
|
224518
224688
|
}
|
|
224519
224689
|
}
|
|
224520
|
-
|
|
224521
|
-
await service.putVariable({
|
|
224690
|
+
const input = {
|
|
224522
224691
|
key: b2.key,
|
|
224523
224692
|
value: b2.value,
|
|
224524
224693
|
actorId,
|
|
224525
224694
|
scope: "personal",
|
|
224526
|
-
//
|
|
224695
|
+
// 展示名(同上)。组织页「新建变量」走的就是这条端点。
|
|
224527
224696
|
...typeof b2.name === "string" && b2.name.trim() ? { name: b2.name.trim() } : {},
|
|
224528
224697
|
...b2.deliveryMode !== void 0 ? { deliveryMode: b2.deliveryMode } : {},
|
|
224529
224698
|
...b2.connectorId !== void 0 ? { connectorId: b2.connectorId } : {},
|
|
@@ -224531,7 +224700,14 @@ function actorsDomain(opts) {
|
|
|
224531
224700
|
...b2.encrypted !== void 0 ? { encrypted: b2.encrypted } : {},
|
|
224532
224701
|
by: req.auth.actor,
|
|
224533
224702
|
expiresAt: expiresAt2
|
|
224534
|
-
}
|
|
224703
|
+
};
|
|
224704
|
+
if (create) {
|
|
224705
|
+
const outcome = await service.createVariable(input);
|
|
224706
|
+
if (outcome === "exists") throw await variableExistsError(service, b2.key, { actorId });
|
|
224707
|
+
} else {
|
|
224708
|
+
await requireSecretOwner(req, service, b2.key, { actorId });
|
|
224709
|
+
await service.putVariable(input);
|
|
224710
|
+
}
|
|
224535
224711
|
await auditVariableChange(req, "credential_write", b2.key, `personal:${actorId}`);
|
|
224536
224712
|
return { status: 201, body: { ok: true } };
|
|
224537
224713
|
});
|
|
@@ -244949,6 +245125,26 @@ var init_postgres = __esm({
|
|
|
244949
245125
|
});
|
|
244950
245126
|
|
|
244951
245127
|
// ../storage/src/postgres-registry.ts
|
|
245128
|
+
function variableInsertParams(v2) {
|
|
245129
|
+
return [
|
|
245130
|
+
v2.key,
|
|
245131
|
+
v2.scope,
|
|
245132
|
+
v2.actorId ?? null,
|
|
245133
|
+
v2.projectId ?? null,
|
|
245134
|
+
v2.connectorId ?? null,
|
|
245135
|
+
v2.overrides ?? null,
|
|
245136
|
+
v2.deliveryMode ?? null,
|
|
245137
|
+
v2.valueEncrypted,
|
|
245138
|
+
v2.updatedAt,
|
|
245139
|
+
v2.expiresAt ?? null,
|
|
245140
|
+
v2.name ?? null,
|
|
245141
|
+
v2.createdBy ?? null,
|
|
245142
|
+
v2.createdAt ?? null,
|
|
245143
|
+
v2.updatedBy ?? null,
|
|
245144
|
+
v2.audience ?? null,
|
|
245145
|
+
v2.enabledActorIds ?? null
|
|
245146
|
+
];
|
|
245147
|
+
}
|
|
244952
245148
|
function rowToVariable(row) {
|
|
244953
245149
|
return {
|
|
244954
245150
|
key: row.key,
|
|
@@ -244976,7 +245172,7 @@ function rowToVariable(row) {
|
|
|
244976
245172
|
...Array.isArray(row.enabled_actor_ids) ? { enabledActorIds: row.enabled_actor_ids } : {}
|
|
244977
245173
|
};
|
|
244978
245174
|
}
|
|
244979
|
-
var ident5, PostgresRegistryStore, rowToActor, rowToConfig, rowToAgentPrefs;
|
|
245175
|
+
var ident5, PostgresRegistryStore, VARIABLE_INSERT_COLUMNS, rowToActor, rowToConfig, rowToAgentPrefs;
|
|
244980
245176
|
var init_postgres_registry = __esm({
|
|
244981
245177
|
"../storage/src/postgres-registry.ts"() {
|
|
244982
245178
|
"use strict";
|
|
@@ -245657,7 +245853,7 @@ var init_postgres_registry = __esm({
|
|
|
245657
245853
|
updated_by 反过来:每次都覆盖。三者与 name 的 COALESCE 方向相反,别照抄。 */
|
|
245658
245854
|
/* audience / enabled_actor_ids(决策 0556)走 COALESCE(**新值**, 旧值):不传 = 不动——
|
|
245659
245855
|
改默认值时手上不带「发给谁」,普通赋值会把「仅指定 Agent」悄悄打回全员生效。 */
|
|
245660
|
-
`INSERT INTO ${this.s}.variables (
|
|
245856
|
+
`INSERT INTO ${this.s}.variables (${VARIABLE_INSERT_COLUMNS})
|
|
245661
245857
|
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16)
|
|
245662
245858
|
ON CONFLICT (key, COALESCE(actor_id, ''), COALESCE(project_id, '')) DO UPDATE
|
|
245663
245859
|
SET scope=$2, actor_id=$3, project_id=$4, connector_id=$5, overrides=$6, delivery_mode=$7, value_encrypted=$8, updated_at=$9, expires_at=$10,
|
|
@@ -245667,25 +245863,17 @@ var init_postgres_registry = __esm({
|
|
|
245667
245863
|
updated_by=$14,
|
|
245668
245864
|
audience=COALESCE($15, ${this.s}.variables.audience),
|
|
245669
245865
|
enabled_actor_ids=COALESCE($16, ${this.s}.variables.enabled_actor_ids)`,
|
|
245670
|
-
|
|
245671
|
-
|
|
245672
|
-
|
|
245673
|
-
|
|
245674
|
-
|
|
245675
|
-
|
|
245676
|
-
|
|
245677
|
-
|
|
245678
|
-
|
|
245679
|
-
v2.updatedAt,
|
|
245680
|
-
v2.expiresAt ?? null,
|
|
245681
|
-
v2.name ?? null,
|
|
245682
|
-
v2.createdBy ?? null,
|
|
245683
|
-
v2.createdAt ?? null,
|
|
245684
|
-
v2.updatedBy ?? null,
|
|
245685
|
-
v2.audience ?? null,
|
|
245686
|
-
v2.enabledActorIds ?? null
|
|
245687
|
-
]
|
|
245866
|
+
variableInsertParams(v2)
|
|
245867
|
+
);
|
|
245868
|
+
}
|
|
245869
|
+
async insertVariable(v2) {
|
|
245870
|
+
const r = await this.pool.query(
|
|
245871
|
+
`INSERT INTO ${this.s}.variables (${VARIABLE_INSERT_COLUMNS})
|
|
245872
|
+
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16)
|
|
245873
|
+
ON CONFLICT (key, COALESCE(actor_id, ''), COALESCE(project_id, '')) DO NOTHING`,
|
|
245874
|
+
variableInsertParams(v2)
|
|
245688
245875
|
);
|
|
245876
|
+
return (r.rowCount ?? 0) > 0;
|
|
245689
245877
|
}
|
|
245690
245878
|
async touchVariableUsage(key, actorId, projectId2, when) {
|
|
245691
245879
|
await this.pool.query(
|
|
@@ -245773,6 +245961,7 @@ var init_postgres_registry = __esm({
|
|
|
245773
245961
|
);
|
|
245774
245962
|
}
|
|
245775
245963
|
};
|
|
245964
|
+
VARIABLE_INSERT_COLUMNS = "key, scope, actor_id, project_id, connector_id, overrides, delivery_mode, value_encrypted, updated_at, expires_at, name, created_by, created_at, updated_by, audience, enabled_actor_ids";
|
|
245776
245965
|
rowToActor = (row) => ({
|
|
245777
245966
|
id: row.id,
|
|
245778
245967
|
kind: row.kind,
|
|
@@ -257049,6 +257238,9 @@ var init_cutover_aware_registry = __esm({
|
|
|
257049
257238
|
async putVariable(...args) {
|
|
257050
257239
|
return (await this.orgStoreForWrite()).putVariable(...args);
|
|
257051
257240
|
}
|
|
257241
|
+
async insertVariable(...args) {
|
|
257242
|
+
return (await this.orgStoreForWrite()).insertVariable(...args);
|
|
257243
|
+
}
|
|
257052
257244
|
async patchVariableValue(...args) {
|
|
257053
257245
|
return (await this.orgStoreForWrite()).patchVariableValue(...args);
|
|
257054
257246
|
}
|
|
@@ -263398,8 +263590,10 @@ async function startServe(opts) {
|
|
|
263398
263590
|
credentialAudit,
|
|
263399
263591
|
readCredentialAudit,
|
|
263400
263592
|
// ADR 0125:写 scope=project 变量时校验 projectId 真实存在(getProject 直查,含临时项目)。
|
|
263401
|
-
//
|
|
263402
|
-
|
|
263593
|
+
// 按请求所属公司查(同 PR #870 的剧本/自动化):此前固定查 projectStateStore(默认公司那一份),
|
|
263594
|
+
// 非默认公司的项目一律报「项目不存在」。未解析出公司 = 默认公司,与 experiments 同一口径。
|
|
263595
|
+
// projectExistsIn 在下方才声明——本箭头只在请求时跑,那时已就绪(同 resolveDispatchScope 惰性模式)。
|
|
263596
|
+
projectExists: async (id, companyId) => projectExistsIn(id, companyId ?? defaultCompanyId),
|
|
263403
263597
|
/* 子 PRD《密钥管理》§1 的权限判据:密钥的写 / 删要认「创建者本人或组织管理者」。
|
|
263404
263598
|
owner 与 admin 都算组织管理者(与组织页 `orgIdentityOf` 同一口径)。
|
|
263405
263599
|
`controlPlaneStore` 在下方才赋值——本箭头只在请求时跑,那时已就绪(同 projectExists 的惰性模式)。
|
|
@@ -276452,7 +276646,7 @@ function shimScript() {
|
|
|
276452
276646
|
}
|
|
276453
276647
|
|
|
276454
276648
|
// src/index.ts
|
|
276455
|
-
var PKG_VERSION = true ? "2.2.
|
|
276649
|
+
var PKG_VERSION = true ? "2.2.37" : "dev";
|
|
276456
276650
|
var LOCAL_BIN = localBin();
|
|
276457
276651
|
var NPM_PREFIX = npmPrefix();
|
|
276458
276652
|
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.37",
|
|
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": "e9498c25c512b5edf75fde28c132f60d079b20a0"
|
|
30
30
|
}
|
|
31
31
|
}
|