oasis_test_v2 2.2.12 → 2.2.13
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 +121 -9
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -201815,6 +201815,15 @@ var init_provision = __esm({
|
|
|
201815
201815
|
});
|
|
201816
201816
|
|
|
201817
201817
|
// ../connectors/src/prepare-job.ts
|
|
201818
|
+
function loginShellShadow(commandName) {
|
|
201819
|
+
const home2 = process.env["HOME"];
|
|
201820
|
+
if (!home2) return "";
|
|
201821
|
+
for (const dir of [(0, import_node_path17.join)(home2, ".local", "bin"), (0, import_node_path17.join)(home2, "bin")]) {
|
|
201822
|
+
const candidate = (0, import_node_path17.join)(dir, commandName);
|
|
201823
|
+
if ((0, import_node_fs11.existsSync)(candidate)) return candidate;
|
|
201824
|
+
}
|
|
201825
|
+
return "";
|
|
201826
|
+
}
|
|
201818
201827
|
async function prepareConnectorsForJob(job, deps) {
|
|
201819
201828
|
const creds = job.connectorCreds ?? [];
|
|
201820
201829
|
const remoteWrappers = job.wrapperPaths ?? [];
|
|
@@ -201850,7 +201859,16 @@ async function prepareConnectorsForJob(job, deps) {
|
|
|
201850
201859
|
localWrappers.push(staged);
|
|
201851
201860
|
status.wrapperReady = true;
|
|
201852
201861
|
}
|
|
201853
|
-
|
|
201862
|
+
const shadow = loginShellShadow(connector.commandName);
|
|
201863
|
+
if (shadow) {
|
|
201864
|
+
status.shadowedBy = shadow;
|
|
201865
|
+
log(
|
|
201866
|
+
"[node-connectors]",
|
|
201867
|
+
`\u26A0 ${slug6}: creds + wrapper \u5DF2\u843D\u5728\u672C\u673A\uFF0C\u4F46 **${shadow} \u4F1A\u5728\u767B\u5F55 shell \u91CC\u6321\u4F4F wrapper**\u2014\u2014Ubuntu \u7684 ~/.profile \u628A $HOME/.local/bin \u524D\u7F6E\u5230 PATH \u6700\u524D\u3002agent \u4E00\u65E6\u7528 \`bash -lc\` \u8C03 ${connector.commandName}\uFF0C\u8D70\u5230\u7684\u662F\u90A3\u4E2A\u5BBF\u4E3B\u526F\u672C\u3001\u914D\u7F6E\u76EE\u5F55\u53C8\u88AB\u9694\u79BB\u6210\u7A7A\u7684\uFF0C\u7ED3\u679C\u5C31\u662F\u300C\u672A\u914D\u7F6E\u300D\u3002\u5904\u7406\u529E\u6CD5\uFF1A\u5220\u6389 ${shadow}\uFF08\u8FDE\u63A5\u5668\u81EA\u5E26\u7684\u771F CLI \u5728 ~/.oasis/connector-tools/bin \u4E0B\uFF0C\u4E0D\u53D7\u5F71\u54CD\uFF09\u3002`
|
|
201868
|
+
);
|
|
201869
|
+
} else {
|
|
201870
|
+
log("[node-connectors]", `${slug6}: creds + wrapper \u5DF2\u843D\u5728\u672C\u673A`);
|
|
201871
|
+
}
|
|
201854
201872
|
} catch (err) {
|
|
201855
201873
|
status.error = String(err);
|
|
201856
201874
|
log(
|
|
@@ -206756,6 +206774,52 @@ ${composed}`;
|
|
|
206756
206774
|
}
|
|
206757
206775
|
return;
|
|
206758
206776
|
}
|
|
206777
|
+
if (url.pathname.startsWith("/api/connectors/") && /\/auth\/(begin|rollback|commit)$/.test(url.pathname) && req.method === "POST") {
|
|
206778
|
+
const m2 = url.pathname.match(/^\/api\/connectors\/([^/]+)\/auth\/(begin|rollback|commit)$/);
|
|
206779
|
+
try {
|
|
206780
|
+
if (!m2) throw new Error("bad path");
|
|
206781
|
+
const connectorId = decodeURIComponent(m2[1]);
|
|
206782
|
+
const op = m2[2];
|
|
206783
|
+
const { actorId } = JSON.parse(rawBody || "{}");
|
|
206784
|
+
if (!actorId) {
|
|
206785
|
+
res.writeHead(400).end(JSON.stringify({ error: "actorId required" }));
|
|
206786
|
+
return;
|
|
206787
|
+
}
|
|
206788
|
+
const svc = await connectorActorsService();
|
|
206789
|
+
if (!svc) throw new Error("actors service unavailable");
|
|
206790
|
+
const cacheKey = `${currentCompanyId ?? ""}::${actorId}::${connectorId}`;
|
|
206791
|
+
const now = Date.now();
|
|
206792
|
+
for (const [k2, v2] of connectorAuthSnapshots) {
|
|
206793
|
+
if (now - v2.at > CONNECTOR_AUTH_SNAPSHOT_TTL_MS) connectorAuthSnapshots.delete(k2);
|
|
206794
|
+
}
|
|
206795
|
+
if (op === "begin") {
|
|
206796
|
+
const rows = await svc.snapshotActorConnectorVars(actorId, connectorId);
|
|
206797
|
+
connectorAuthSnapshots.set(cacheKey, { rows, at: now });
|
|
206798
|
+
res.writeHead(200, { "content-type": "application/json" }).end(JSON.stringify({ ok: true, snapshot: rows.length }));
|
|
206799
|
+
return;
|
|
206800
|
+
}
|
|
206801
|
+
if (op === "commit") {
|
|
206802
|
+
connectorAuthSnapshots.delete(cacheKey);
|
|
206803
|
+
res.writeHead(200, { "content-type": "application/json" }).end(JSON.stringify({ ok: true }));
|
|
206804
|
+
return;
|
|
206805
|
+
}
|
|
206806
|
+
const snap = connectorAuthSnapshots.get(cacheKey);
|
|
206807
|
+
if (!snap) {
|
|
206808
|
+
res.writeHead(200, { "content-type": "application/json" }).end(JSON.stringify({ ok: false, reason: "no_snapshot" }));
|
|
206809
|
+
return;
|
|
206810
|
+
}
|
|
206811
|
+
const out = await svc.restoreActorConnectorVars(
|
|
206812
|
+
actorId,
|
|
206813
|
+
connectorId,
|
|
206814
|
+
snap.rows
|
|
206815
|
+
);
|
|
206816
|
+
connectorAuthSnapshots.delete(cacheKey);
|
|
206817
|
+
res.writeHead(200, { "content-type": "application/json" }).end(JSON.stringify({ ok: true, ...out }));
|
|
206818
|
+
} catch (e) {
|
|
206819
|
+
res.writeHead(500).end(JSON.stringify({ error: String(e) }));
|
|
206820
|
+
}
|
|
206821
|
+
return;
|
|
206822
|
+
}
|
|
206759
206823
|
if (req.method === "POST" && /^\/api\/connectors\/[^/]+\/disconnect$/.test(url.pathname)) {
|
|
206760
206824
|
const connId = decodeURIComponent(url.pathname.split("/")[3] ?? "");
|
|
206761
206825
|
const svc = await connectorActorsService();
|
|
@@ -207193,7 +207257,7 @@ ${composed}`;
|
|
|
207193
207257
|
grantedFrom = "installation";
|
|
207194
207258
|
}
|
|
207195
207259
|
}
|
|
207196
|
-
const missing = missingAppPermissions(effective);
|
|
207260
|
+
const missing = missingAppPermissions({ ...meta.permissions, ...effective });
|
|
207197
207261
|
const requestedAll = Object.entries(meta.permissions).filter(([, level]) => Boolean(level)).map(([key, level]) => ({ key, level: String(level) })).sort((a, b2) => a.key.localeCompare(b2.key));
|
|
207198
207262
|
const grantedKeys = new Set(
|
|
207199
207263
|
Object.entries(effective).filter(([, level]) => Boolean(level)).map(([k2]) => k2)
|
|
@@ -207218,13 +207282,19 @@ ${composed}`;
|
|
|
207218
207282
|
*/
|
|
207219
207283
|
otherInstallations: installs.filter((i) => i.installationId !== installationId).map((i) => ({ account: i.account, count: Object.keys(i.permissions).length })),
|
|
207220
207284
|
/**
|
|
207221
|
-
*
|
|
207222
|
-
*
|
|
207223
|
-
*
|
|
207224
|
-
* ⚠ 差集只说明「这一处安装现在给不了」,不等于「人没批」——同一个 App 装多处时
|
|
207225
|
-
* 批准是逐处的(见 `otherInstallations`)。界面别把这层推断说死。
|
|
207285
|
+
* ⚠ 保留只为**兼容老前端**(新卡片不再读它):新口径不分「已授权 / 申请中」,
|
|
207286
|
+
* 见 `detected`。这一格哪天确认没有旧客户端在读了就可以删。
|
|
207226
207287
|
*/
|
|
207227
207288
|
awaitingApproval: requestedAll.filter((r) => !grantedKeys.has(r.key)).map((r) => r.key),
|
|
207289
|
+
/**
|
|
207290
|
+
* **检测到的全部权限**(App 申请的 ∪ 真拿得到的),英文原名 + 级别,按名排序。
|
|
207291
|
+
* 界面就照这一份平铺成一排 chip,不分组、不计数、不解释审批状态。
|
|
207292
|
+
*/
|
|
207293
|
+
detected: [.../* @__PURE__ */ new Set([...requestedAll.map((r) => r.key), ...grantedKeys])].sort((a, b2) => a.localeCompare(b2)).map((key) => ({
|
|
207294
|
+
key,
|
|
207295
|
+
// 真给的级别优先;只在 App 侧见过的才回落成它申请的级别。
|
|
207296
|
+
level: String(effective[key] ?? meta.permissions[key] ?? "")
|
|
207297
|
+
})),
|
|
207228
207298
|
/**
|
|
207229
207299
|
* agent **真正拿得到**的全部权限(优先读 token 自己的权限位),一律用 GitHub 的英文原名 + 级别
|
|
207230
207300
|
* (2026-09-10 发起人:「所有权限都用英文原文,不区分是不是八项权限」)。
|
|
@@ -207661,7 +207731,7 @@ ${composed}`;
|
|
|
207661
207731
|
}
|
|
207662
207732
|
};
|
|
207663
207733
|
}
|
|
207664
|
-
var http, import_node_crypto37, githubAppPending, defaultResolveActor, enc, CHAT_OUTPUT_LIMIT, STREAMING_PATHS, PLANNER_BLOCKING_CODES, WILL_VERBS, GOVERNANCE_COMMANDS, READ_ONLY_COMMANDS, isAgent, isHuman;
|
|
207734
|
+
var http, import_node_crypto37, githubAppPending, connectorAuthSnapshots, CONNECTOR_AUTH_SNAPSHOT_TTL_MS, defaultResolveActor, enc, CHAT_OUTPUT_LIMIT, STREAMING_PATHS, PLANNER_BLOCKING_CODES, WILL_VERBS, GOVERNANCE_COMMANDS, READ_ONLY_COMMANDS, isAgent, isHuman;
|
|
207665
207735
|
var init_server3 = __esm({
|
|
207666
207736
|
"../server/src/server.ts"() {
|
|
207667
207737
|
"use strict";
|
|
@@ -207719,6 +207789,8 @@ var init_server3 = __esm({
|
|
|
207719
207789
|
init_src8();
|
|
207720
207790
|
init_continuation();
|
|
207721
207791
|
githubAppPending = new PendingAppCreations();
|
|
207792
|
+
connectorAuthSnapshots = /* @__PURE__ */ new Map();
|
|
207793
|
+
CONNECTOR_AUTH_SNAPSHOT_TTL_MS = 30 * 60 * 1e3;
|
|
207722
207794
|
defaultResolveActor = (token) => token.startsWith("token:") ? token.slice("token:".length) : null;
|
|
207723
207795
|
enc = (s2) => new TextEncoder().encode(s2);
|
|
207724
207796
|
CHAT_OUTPUT_LIMIT = 16e3;
|
|
@@ -219564,6 +219636,46 @@ ${input.description}
|
|
|
219564
219636
|
listActorConnectorConnections(actorId) {
|
|
219565
219637
|
return this.opts.store.listActorConnectorConnections(actorId);
|
|
219566
219638
|
}
|
|
219639
|
+
/**
|
|
219640
|
+
* 授权流程**开始前**给这名员工在这个连接器下的全部个人变量拍一张快照(原样密文,不解密)。
|
|
219641
|
+
*
|
|
219642
|
+
* 为什么需要它(2026-09-10 发起人:「如果本身已经有连接器身份,如果重新连接没走完,
|
|
219643
|
+
* 则保留原身份不覆盖,之前重连到一半把原来的身份覆盖了」):
|
|
219644
|
+
* 「重新连接」是**边走边落库**的——飞书在「创建应用」那一步就把 `FEISHU_APP_ID` /
|
|
219645
|
+
* `FEISHU_APP_SECRET` 覆盖掉了,GitHub 在 manifest 回调那一步就把 `GITHUB_APP_*` 覆盖掉了,
|
|
219646
|
+
* 而这两步都在「用户完成授权」**之前**。人中途关掉弹窗,旧身份就已经没了。
|
|
219647
|
+
*
|
|
219648
|
+
* 前端此前的回滚只删「这次新增的键」(基线差集),**对已存在的键无能为力**——它拿不到旧值
|
|
219649
|
+
* (读侧永远只给掩码)。所以快照必须在服务端拍、也在服务端写回。
|
|
219650
|
+
*/
|
|
219651
|
+
async snapshotActorConnectorVars(actorId, connectorId) {
|
|
219652
|
+
const rows = await this.opts.store.listVariables(actorId);
|
|
219653
|
+
return rows.filter((v2) => v2.scope === "personal" && v2.actorId === actorId && v2.connectorId === connectorId);
|
|
219654
|
+
}
|
|
219655
|
+
/**
|
|
219656
|
+
* 把快照原样写回:**快照里有的恢复旧值,快照之后新冒出来的键删掉**。
|
|
219657
|
+
*
|
|
219658
|
+
* 密文原样搬运,不经解密再加密——少一次明文落到内存里,也不受密钥轮换影响。
|
|
219659
|
+
* 返回改了几行,调用方好把「回滚做了什么」如实说出来(回滚静默是上一版的毛病)。
|
|
219660
|
+
*/
|
|
219661
|
+
async restoreActorConnectorVars(actorId, connectorId, snapshot) {
|
|
219662
|
+
const keep = new Map(snapshot.map((r) => [r.key, r]));
|
|
219663
|
+
const now = await this.snapshotActorConnectorVars(actorId, connectorId);
|
|
219664
|
+
let removed = 0;
|
|
219665
|
+
for (const row of now) {
|
|
219666
|
+
if (keep.has(row.key)) continue;
|
|
219667
|
+
await this.deleteVariable(row.key, actorId);
|
|
219668
|
+
removed += 1;
|
|
219669
|
+
}
|
|
219670
|
+
let restored = 0;
|
|
219671
|
+
for (const row of keep.values()) {
|
|
219672
|
+
const current = now.find((r) => r.key === row.key);
|
|
219673
|
+
if (current && current.valueEncrypted === row.valueEncrypted) continue;
|
|
219674
|
+
await this.opts.store.putVariable({ ...row, updatedAt: this.now() });
|
|
219675
|
+
restored += 1;
|
|
219676
|
+
}
|
|
219677
|
+
return { restored, removed };
|
|
219678
|
+
}
|
|
219567
219679
|
/**
|
|
219568
219680
|
* 员工连接器面板所需状态:连接记录 + 组织级已连接集合 + 该员工已授权(有个人 connector 变量)集合。
|
|
219569
219681
|
* 前端据此算每个 connector 的 hasRecord / 有效 enabled / connected(actor 或 global)。
|
|
@@ -271244,7 +271356,7 @@ function shimScript() {
|
|
|
271244
271356
|
}
|
|
271245
271357
|
|
|
271246
271358
|
// src/index.ts
|
|
271247
|
-
var PKG_VERSION = true ? "2.2.
|
|
271359
|
+
var PKG_VERSION = true ? "2.2.13" : "dev";
|
|
271248
271360
|
var LOCAL_BIN = localBin();
|
|
271249
271361
|
var NPM_PREFIX = npmPrefix();
|
|
271250
271362
|
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.13",
|
|
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": "b907ec1d1a0ae4a57e7eb938c477f05323b84590"
|
|
30
30
|
}
|
|
31
31
|
}
|