oasis_test_v2 2.2.81 → 2.2.83
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 +1299 -485
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -2950,6 +2950,25 @@ async function fetchResultPackage(base, fetchImpl, runId) {
|
|
|
2950
2950
|
}));
|
|
2951
2951
|
return { artifacts, fileCount: body2.project?.fileCount ?? artifacts.length };
|
|
2952
2952
|
}
|
|
2953
|
+
function toEpochMs(v2) {
|
|
2954
|
+
if (typeof v2 === "number" && Number.isFinite(v2)) return v2;
|
|
2955
|
+
if (typeof v2 === "string" && v2.length > 0) {
|
|
2956
|
+
const ms = Date.parse(v2);
|
|
2957
|
+
return Number.isNaN(ms) ? void 0 : ms;
|
|
2958
|
+
}
|
|
2959
|
+
return void 0;
|
|
2960
|
+
}
|
|
2961
|
+
function runTime(r) {
|
|
2962
|
+
return r.createdAt ?? r.updatedAt ?? Number.NEGATIVE_INFINITY;
|
|
2963
|
+
}
|
|
2964
|
+
function latestSucceededRun(runs) {
|
|
2965
|
+
let best;
|
|
2966
|
+
for (const r of runs) {
|
|
2967
|
+
if (r.status !== "succeeded") continue;
|
|
2968
|
+
if (best === void 0 || runTime(r) > runTime(best)) best = r;
|
|
2969
|
+
}
|
|
2970
|
+
return best;
|
|
2971
|
+
}
|
|
2953
2972
|
async function fetchBoardStatus(base, fetchImpl, artifactId) {
|
|
2954
2973
|
const boardKey = deriveBoardKey(artifactId);
|
|
2955
2974
|
let boardExists = true;
|
|
@@ -2975,10 +2994,20 @@ async function fetchBoardStatus(base, fetchImpl, artifactId) {
|
|
|
2975
2994
|
"GET",
|
|
2976
2995
|
`/api/runs?projectId=${encodeURIComponent(boardKey)}`
|
|
2977
2996
|
);
|
|
2978
|
-
runs = (body2.runs ?? []).map((r) =>
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2997
|
+
runs = (body2.runs ?? []).map((r) => {
|
|
2998
|
+
const run = {
|
|
2999
|
+
runId: String(r["runId"] ?? r["id"] ?? ""),
|
|
3000
|
+
status: String(r["status"] ?? "unknown")
|
|
3001
|
+
};
|
|
3002
|
+
if (typeof r["agentId"] === "string" && r["agentId"].length > 0) run.agentId = r["agentId"];
|
|
3003
|
+
if (typeof r["error"] === "string" && r["error"].trim().length > 0) run.error = r["error"];
|
|
3004
|
+
const createdAt = toEpochMs(r["createdAt"]);
|
|
3005
|
+
if (createdAt !== void 0) run.createdAt = createdAt;
|
|
3006
|
+
const updatedAt = toEpochMs(r["updatedAt"]);
|
|
3007
|
+
if (updatedAt !== void 0) run.updatedAt = updatedAt;
|
|
3008
|
+
return run;
|
|
3009
|
+
});
|
|
3010
|
+
runs.sort((a, b2) => runTime(b2) - runTime(a) || 0);
|
|
2982
3011
|
} catch {
|
|
2983
3012
|
}
|
|
2984
3013
|
}
|
|
@@ -35159,7 +35188,7 @@ var require_websocket = __commonJS({
|
|
|
35159
35188
|
var http2 = require("http");
|
|
35160
35189
|
var net = require("net");
|
|
35161
35190
|
var tls = require("tls");
|
|
35162
|
-
var { randomBytes:
|
|
35191
|
+
var { randomBytes: randomBytes15, createHash: createHash45 } = require("crypto");
|
|
35163
35192
|
var { Duplex, Readable } = require("stream");
|
|
35164
35193
|
var { URL: URL2 } = require("url");
|
|
35165
35194
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
@@ -35697,7 +35726,7 @@ var require_websocket = __commonJS({
|
|
|
35697
35726
|
}
|
|
35698
35727
|
}
|
|
35699
35728
|
const defaultPort = isSecure ? 443 : 80;
|
|
35700
|
-
const key2 =
|
|
35729
|
+
const key2 = randomBytes15(16).toString("base64");
|
|
35701
35730
|
const request2 = isSecure ? https.request : http2.request;
|
|
35702
35731
|
const protocolSet = /* @__PURE__ */ new Set();
|
|
35703
35732
|
let perMessageDeflate;
|
|
@@ -130108,7 +130137,7 @@ var require_utils3 = __commonJS({
|
|
|
130108
130137
|
var nodeCrypto = require("crypto");
|
|
130109
130138
|
module2.exports = {
|
|
130110
130139
|
postgresMd5PasswordHash,
|
|
130111
|
-
randomBytes:
|
|
130140
|
+
randomBytes: randomBytes15,
|
|
130112
130141
|
deriveKey,
|
|
130113
130142
|
sha256: sha2563,
|
|
130114
130143
|
hashByName,
|
|
@@ -130118,7 +130147,7 @@ var require_utils3 = __commonJS({
|
|
|
130118
130147
|
var webCrypto = nodeCrypto.webcrypto || globalThis.crypto;
|
|
130119
130148
|
var subtleCrypto = webCrypto.subtle;
|
|
130120
130149
|
var textEncoder = new TextEncoder();
|
|
130121
|
-
function
|
|
130150
|
+
function randomBytes15(length) {
|
|
130122
130151
|
return webCrypto.getRandomValues(Buffer.alloc(length));
|
|
130123
130152
|
}
|
|
130124
130153
|
async function md5(string7) {
|
|
@@ -208676,11 +208705,17 @@ var init_app_adopt = __esm({
|
|
|
208676
208705
|
});
|
|
208677
208706
|
|
|
208678
208707
|
// ../connectors/src/github/app-manifest.ts
|
|
208708
|
+
function randomAppNameSuffix() {
|
|
208709
|
+
const alphabet = "abcdefghijklmnopqrstuvwxyz0123456789";
|
|
208710
|
+
return Array.from((0, import_node_crypto42.randomBytes)(4), (b2) => alphabet[b2 % alphabet.length]).join("");
|
|
208711
|
+
}
|
|
208679
208712
|
function buildAppManifest(args) {
|
|
208680
208713
|
const base = args.baseUrl.replace(/\/+$/, "");
|
|
208714
|
+
const suffix = args.nameSuffix ?? randomAppNameSuffix();
|
|
208715
|
+
const room = GITHUB_APP_NAME_MAX - args.namePrefix.length - suffix.length - 2;
|
|
208716
|
+
const middle = args.employeeSlug.slice(0, Math.max(0, room)).replace(/-+$/, "");
|
|
208681
208717
|
return {
|
|
208682
|
-
name:
|
|
208683
|
-
// GitHub App 名上限 34 字符
|
|
208718
|
+
name: [args.namePrefix, middle, suffix].filter(Boolean).join("-"),
|
|
208684
208719
|
url: base,
|
|
208685
208720
|
redirect_url: `${base}${args.redirectPath}`,
|
|
208686
208721
|
public: false,
|
|
@@ -208758,10 +208793,11 @@ function checkAppOwnership(conv, want) {
|
|
|
208758
208793
|
}
|
|
208759
208794
|
return null;
|
|
208760
208795
|
}
|
|
208761
|
-
var GITHUB_APP_DEFAULT_PERMISSIONS, GITHUB_APP_PERMISSION_LABELS, PENDING_TTL_MS, REQUIRED_WRITE_PERMISSIONS, PERMISSION_RANK, FORBIDDEN_IMPORT_PERMISSION_KEYS;
|
|
208796
|
+
var import_node_crypto42, GITHUB_APP_DEFAULT_PERMISSIONS, GITHUB_APP_PERMISSION_LABELS, GITHUB_APP_NAME_MAX, PENDING_TTL_MS, REQUIRED_WRITE_PERMISSIONS, PERMISSION_RANK, FORBIDDEN_IMPORT_PERMISSION_KEYS;
|
|
208762
208797
|
var init_app_manifest = __esm({
|
|
208763
208798
|
"../connectors/src/github/app-manifest.ts"() {
|
|
208764
208799
|
"use strict";
|
|
208800
|
+
import_node_crypto42 = require("node:crypto");
|
|
208765
208801
|
GITHUB_APP_DEFAULT_PERMISSIONS = {
|
|
208766
208802
|
contents: "write",
|
|
208767
208803
|
// clone / push
|
|
@@ -208790,6 +208826,7 @@ var init_app_manifest = __esm({
|
|
|
208790
208826
|
{ key: "workflows", label: "\u5DE5\u4F5C\u6D41\u6587\u4EF6\uFF08\u8BFB\u5199\uFF09", desc: "\u4FEE\u6539 .github/workflows \u4E0B\u7684 CI \u914D\u7F6E" },
|
|
208791
208827
|
{ key: "issues", label: "Issue\uFF08\u8BFB\u5199\uFF09", desc: "\u521B\u5EFA\u4E0E\u8BC4\u8BBA Issue" }
|
|
208792
208828
|
];
|
|
208829
|
+
GITHUB_APP_NAME_MAX = 34;
|
|
208793
208830
|
PENDING_TTL_MS = 15 * 60 * 1e3;
|
|
208794
208831
|
REQUIRED_WRITE_PERMISSIONS = ["contents", "pull_requests"];
|
|
208795
208832
|
PERMISSION_RANK = { read: 1, write: 2, admin: 3 };
|
|
@@ -208806,6 +208843,195 @@ var init_app_manifest = __esm({
|
|
|
208806
208843
|
}
|
|
208807
208844
|
});
|
|
208808
208845
|
|
|
208846
|
+
// ../connectors/src/github/app-inventory.ts
|
|
208847
|
+
function permissionVerdict(perms) {
|
|
208848
|
+
const missingRequired = REQUIRED_WRITE.filter((k2) => perms[k2] !== "write" && perms[k2] !== "admin");
|
|
208849
|
+
const excess = excessAppPermissions(perms);
|
|
208850
|
+
return {
|
|
208851
|
+
missingRequired: [...missingRequired],
|
|
208852
|
+
missing: missingAppPermissions(perms),
|
|
208853
|
+
excess,
|
|
208854
|
+
usable: missingRequired.length === 0 && excess.length === 0
|
|
208855
|
+
};
|
|
208856
|
+
}
|
|
208857
|
+
async function listOrgInstalledApps(args, deps = {}) {
|
|
208858
|
+
const d = { ...defaultDeps3, ...deps };
|
|
208859
|
+
let resp;
|
|
208860
|
+
try {
|
|
208861
|
+
resp = await d.fetch(`${GITHUB_API2}/orgs/${encodeURIComponent(args.org)}/installations?per_page=100`, {
|
|
208862
|
+
headers: {
|
|
208863
|
+
authorization: `Bearer ${args.token}`,
|
|
208864
|
+
accept: "application/vnd.github+json",
|
|
208865
|
+
"x-github-api-version": "2022-11-28"
|
|
208866
|
+
}
|
|
208867
|
+
});
|
|
208868
|
+
} catch (e) {
|
|
208869
|
+
return { status: "error", message: String(e) };
|
|
208870
|
+
}
|
|
208871
|
+
if (resp.status === 401 || resp.status === 403) return { status: "needsAuth", httpStatus: resp.status };
|
|
208872
|
+
const body2 = await resp.json().catch(() => ({}));
|
|
208873
|
+
if (!resp.ok) return { status: "error", message: `GitHub \u8FD4\u56DE HTTP ${resp.status} ${String(body2["message"] ?? "")}`.trim() };
|
|
208874
|
+
const list2 = Array.isArray(body2["installations"]) ? body2["installations"] : [];
|
|
208875
|
+
const all2 = list2.flatMap((raw) => {
|
|
208876
|
+
const item = raw;
|
|
208877
|
+
const appId = item["app_id"] === void 0 ? "" : String(item["app_id"]);
|
|
208878
|
+
const installationId = item["id"] === void 0 ? "" : String(item["id"]);
|
|
208879
|
+
if (!appId || !installationId) return [];
|
|
208880
|
+
const rawPerms = item["permissions"];
|
|
208881
|
+
const permissions = {};
|
|
208882
|
+
for (const [k2, v2] of Object.entries(rawPerms ?? {})) if (typeof v2 === "string") permissions[k2] = v2;
|
|
208883
|
+
return [{ appId, slug: String(item["app_slug"] ?? ""), installationId, org: args.org, permissions }];
|
|
208884
|
+
});
|
|
208885
|
+
const owned = await Promise.all(all2.map(async (app) => {
|
|
208886
|
+
if (!app.slug) return app;
|
|
208887
|
+
try {
|
|
208888
|
+
const r = await d.fetch(`${GITHUB_API2}/apps/${encodeURIComponent(app.slug)}`, {
|
|
208889
|
+
headers: {
|
|
208890
|
+
authorization: `Bearer ${args.token}`,
|
|
208891
|
+
accept: "application/vnd.github+json",
|
|
208892
|
+
"x-github-api-version": "2022-11-28"
|
|
208893
|
+
}
|
|
208894
|
+
});
|
|
208895
|
+
if (!r.ok) return app;
|
|
208896
|
+
const meta = await r.json().catch(() => ({}));
|
|
208897
|
+
const login = meta.owner?.login;
|
|
208898
|
+
return login && login.toLowerCase() !== args.org.toLowerCase() ? null : app;
|
|
208899
|
+
} catch {
|
|
208900
|
+
return app;
|
|
208901
|
+
}
|
|
208902
|
+
}));
|
|
208903
|
+
return { status: "ok", apps: owned.filter((a) => a !== null) };
|
|
208904
|
+
}
|
|
208905
|
+
async function uninstallAppInstallation(args, deps = {}) {
|
|
208906
|
+
const d = { ...defaultDeps3, ...deps };
|
|
208907
|
+
const jwt = createAppJwt(args.appId, args.privateKeyPem, d.nowMs());
|
|
208908
|
+
const resp = await d.fetch(`${GITHUB_API2}/app/installations/${encodeURIComponent(args.installationId)}`, {
|
|
208909
|
+
method: "DELETE",
|
|
208910
|
+
headers: {
|
|
208911
|
+
authorization: `Bearer ${jwt}`,
|
|
208912
|
+
accept: "application/vnd.github+json",
|
|
208913
|
+
"x-github-api-version": "2022-11-28"
|
|
208914
|
+
}
|
|
208915
|
+
});
|
|
208916
|
+
if (resp.status === 204 || resp.status === 404) return;
|
|
208917
|
+
const body2 = await resp.json().catch(() => ({}));
|
|
208918
|
+
throw new Error(`github app: uninstall failed HTTP ${resp.status} ${String(body2["message"] ?? "")}`.trim());
|
|
208919
|
+
}
|
|
208920
|
+
function appSettingsUrl(owner, slug6) {
|
|
208921
|
+
const s2 = encodeURIComponent(slug6);
|
|
208922
|
+
return owner.kind === "org" ? `https://github.com/organizations/${encodeURIComponent(owner.login)}/settings/apps/${s2}` : `https://github.com/settings/apps/${s2}`;
|
|
208923
|
+
}
|
|
208924
|
+
function appInstallPageUrl(slug6) {
|
|
208925
|
+
return `https://github.com/apps/${encodeURIComponent(slug6)}/installations/new`;
|
|
208926
|
+
}
|
|
208927
|
+
function appDeleteUrl(owner, slug6) {
|
|
208928
|
+
return `${appSettingsUrl(owner, slug6)}/advanced`;
|
|
208929
|
+
}
|
|
208930
|
+
function ownerMatches(app, owner) {
|
|
208931
|
+
if (owner.kind === "org") {
|
|
208932
|
+
return app.ownerType === "Organization" && app.ownerLogin.toLowerCase() === owner.login.toLowerCase();
|
|
208933
|
+
}
|
|
208934
|
+
if (app.ownerType !== "User") return false;
|
|
208935
|
+
return !owner.login || app.ownerLogin.toLowerCase() === owner.login.toLowerCase();
|
|
208936
|
+
}
|
|
208937
|
+
function buildReuseCandidates(args) {
|
|
208938
|
+
const { owner } = args;
|
|
208939
|
+
const known = new Set(args.oasisApps.map((a2) => a2.appId));
|
|
208940
|
+
const a = args.oasisApps.filter((app) => ownerMatches(app, owner)).map((app) => {
|
|
208941
|
+
const verdict = app.permissions ? permissionVerdict(app.permissions) : null;
|
|
208942
|
+
const selectable = verdict ? verdict.usable : true;
|
|
208943
|
+
const action = !selectable ? "blocked" : app.installationIds.length === 0 ? "install" : "bind";
|
|
208944
|
+
return {
|
|
208945
|
+
kind: "oasis",
|
|
208946
|
+
action,
|
|
208947
|
+
appId: app.appId,
|
|
208948
|
+
slug: app.slug,
|
|
208949
|
+
...app.installationIds[0] ? { installationId: app.installationIds[0] } : {},
|
|
208950
|
+
usedBy: app.usedBy,
|
|
208951
|
+
isOrgDefault: app.isOrgDefault,
|
|
208952
|
+
permissionsUnknown: !verdict,
|
|
208953
|
+
verdict,
|
|
208954
|
+
selectable,
|
|
208955
|
+
settingsUrl: appSettingsUrl(owner, app.slug),
|
|
208956
|
+
permissionsUrl: `${appSettingsUrl(owner, app.slug)}/permissions`,
|
|
208957
|
+
installUrl: appInstallPageUrl(app.slug)
|
|
208958
|
+
};
|
|
208959
|
+
});
|
|
208960
|
+
const b2 = owner.kind === "org" ? args.installed.filter((i) => !known.has(i.appId) && i.org.toLowerCase() === owner.login.toLowerCase()).map((i) => {
|
|
208961
|
+
const verdict = permissionVerdict(i.permissions);
|
|
208962
|
+
return {
|
|
208963
|
+
kind: "installed",
|
|
208964
|
+
action: verdict.usable ? "import" : "blocked",
|
|
208965
|
+
appId: i.appId,
|
|
208966
|
+
slug: i.slug,
|
|
208967
|
+
installationId: i.installationId,
|
|
208968
|
+
usedBy: [],
|
|
208969
|
+
isOrgDefault: false,
|
|
208970
|
+
permissionsUnknown: false,
|
|
208971
|
+
verdict,
|
|
208972
|
+
selectable: verdict.usable,
|
|
208973
|
+
settingsUrl: appSettingsUrl(owner, i.slug),
|
|
208974
|
+
permissionsUrl: `${appSettingsUrl(owner, i.slug)}/permissions`,
|
|
208975
|
+
installUrl: appInstallPageUrl(i.slug)
|
|
208976
|
+
};
|
|
208977
|
+
}) : [];
|
|
208978
|
+
return [...a, ...b2].sort((x2, y) => Number(y.selectable) - Number(x2.selectable));
|
|
208979
|
+
}
|
|
208980
|
+
function buildAppInventory(args) {
|
|
208981
|
+
const rows = /* @__PURE__ */ new Map();
|
|
208982
|
+
const ownerOf = (login, type) => !login ? null : type === "Organization" ? { kind: "org", login } : { kind: "user", login };
|
|
208983
|
+
for (const app of args.oasisApps) {
|
|
208984
|
+
const inUse = app.isOrgDefault || app.usedBy.length > 0;
|
|
208985
|
+
const owner = ownerOf(app.ownerLogin, app.ownerType);
|
|
208986
|
+
rows.set(app.appId, {
|
|
208987
|
+
appId: app.appId,
|
|
208988
|
+
slug: app.slug,
|
|
208989
|
+
ownerLogin: app.ownerLogin,
|
|
208990
|
+
hasKey: true,
|
|
208991
|
+
usedBy: app.usedBy,
|
|
208992
|
+
isOrgDefault: app.isOrgDefault,
|
|
208993
|
+
inUse,
|
|
208994
|
+
installationIds: [...app.installationIds],
|
|
208995
|
+
canUninstall: !inUse && app.installationIds.length > 0,
|
|
208996
|
+
deleteUrl: owner && app.slug ? appDeleteUrl(owner, app.slug) : ""
|
|
208997
|
+
});
|
|
208998
|
+
}
|
|
208999
|
+
for (const i of args.installed) {
|
|
209000
|
+
const prev = rows.get(i.appId);
|
|
209001
|
+
if (prev) {
|
|
209002
|
+
if (!prev.installationIds.includes(i.installationId)) prev.installationIds.push(i.installationId);
|
|
209003
|
+
prev.canUninstall = !prev.inUse && prev.installationIds.length > 0;
|
|
209004
|
+
if (!prev.ownerLogin) prev.ownerLogin = i.org;
|
|
209005
|
+
if (!prev.deleteUrl && prev.slug) prev.deleteUrl = appDeleteUrl({ kind: "org", login: i.org }, prev.slug);
|
|
209006
|
+
continue;
|
|
209007
|
+
}
|
|
209008
|
+
rows.set(i.appId, {
|
|
209009
|
+
appId: i.appId,
|
|
209010
|
+
slug: i.slug,
|
|
209011
|
+
ownerLogin: i.org,
|
|
209012
|
+
hasKey: false,
|
|
209013
|
+
usedBy: [],
|
|
209014
|
+
isOrgDefault: false,
|
|
209015
|
+
inUse: false,
|
|
209016
|
+
installationIds: [i.installationId],
|
|
209017
|
+
canUninstall: false,
|
|
209018
|
+
deleteUrl: i.slug ? appDeleteUrl({ kind: "org", login: i.org }, i.slug) : ""
|
|
209019
|
+
});
|
|
209020
|
+
}
|
|
209021
|
+
return [...rows.values()].sort((x2, y) => Number(x2.inUse) - Number(y.inUse) || x2.slug.localeCompare(y.slug));
|
|
209022
|
+
}
|
|
209023
|
+
var GITHUB_API2, defaultDeps3, REQUIRED_WRITE;
|
|
209024
|
+
var init_app_inventory = __esm({
|
|
209025
|
+
"../connectors/src/github/app-inventory.ts"() {
|
|
209026
|
+
"use strict";
|
|
209027
|
+
init_app_auth();
|
|
209028
|
+
init_app_manifest();
|
|
209029
|
+
GITHUB_API2 = "https://api.github.com";
|
|
209030
|
+
defaultDeps3 = { fetch: (...a) => globalThis.fetch(...a), nowMs: () => Date.now() };
|
|
209031
|
+
REQUIRED_WRITE = ["contents", "pull_requests"];
|
|
209032
|
+
}
|
|
209033
|
+
});
|
|
209034
|
+
|
|
208809
209035
|
// ../connectors/src/registry.ts
|
|
208810
209036
|
function createConnectorBySlug(slug6) {
|
|
208811
209037
|
switch (slug6) {
|
|
@@ -209262,6 +209488,7 @@ var init_src8 = __esm({
|
|
|
209262
209488
|
init_app_auth();
|
|
209263
209489
|
init_app_adopt();
|
|
209264
209490
|
init_app_manifest();
|
|
209491
|
+
init_app_inventory();
|
|
209265
209492
|
init_registry2();
|
|
209266
209493
|
init_provision();
|
|
209267
209494
|
init_prepare_job();
|
|
@@ -209270,6 +209497,118 @@ var init_src8 = __esm({
|
|
|
209270
209497
|
}
|
|
209271
209498
|
});
|
|
209272
209499
|
|
|
209500
|
+
// ../server/src/github-app-inventory.ts
|
|
209501
|
+
async function collectOasisGithubApps(svc) {
|
|
209502
|
+
const rows = (await svc.listVariables()).filter((r) => r.scope === "global" || r.scope === "personal");
|
|
209503
|
+
const agents = await svc.listActors({ kind: "agent", status: "active" });
|
|
209504
|
+
const nameOf2 = new Map(agents.map((a) => [a.id, a.name || a.id]));
|
|
209505
|
+
const plain = (key2, actorId) => rows.find((r) => r.key === key2 && r.actorId === actorId && !r.encrypted)?.maskedValue ?? "";
|
|
209506
|
+
const byAppId = /* @__PURE__ */ new Map();
|
|
209507
|
+
for (const r of rows) {
|
|
209508
|
+
if (r.key !== "GITHUB_APP_ID" || r.encrypted || !r.maskedValue) continue;
|
|
209509
|
+
const e = byAppId.get(r.maskedValue) ?? {
|
|
209510
|
+
slug: "",
|
|
209511
|
+
installationId: "",
|
|
209512
|
+
keyActorId: void 0,
|
|
209513
|
+
usedBy: [],
|
|
209514
|
+
isOrgDefault: false,
|
|
209515
|
+
sources: []
|
|
209516
|
+
};
|
|
209517
|
+
e.sources.push(r.actorId);
|
|
209518
|
+
if (!r.actorId) e.isOrgDefault = true;
|
|
209519
|
+
else if (nameOf2.has(r.actorId) && !e.usedBy.includes(r.actorId)) e.usedBy.push(r.actorId);
|
|
209520
|
+
byAppId.set(r.maskedValue, e);
|
|
209521
|
+
}
|
|
209522
|
+
const out = await Promise.all([...byAppId.entries()].map(async ([appId, e]) => {
|
|
209523
|
+
let pem = null;
|
|
209524
|
+
let keyActorId;
|
|
209525
|
+
for (const src of [...e.sources].sort((a, b2) => Number(Boolean(a)) - Number(Boolean(b2)))) {
|
|
209526
|
+
pem = await svc.revealVariable("GITHUB_APP_PRIVATE_KEY", src).catch(() => null);
|
|
209527
|
+
if (pem) {
|
|
209528
|
+
keyActorId = src;
|
|
209529
|
+
break;
|
|
209530
|
+
}
|
|
209531
|
+
}
|
|
209532
|
+
if (!pem) return null;
|
|
209533
|
+
const slug6 = plain("GITHUB_APP_SLUG", keyActorId);
|
|
209534
|
+
const storedInstallationId = plain("GITHUB_APP_INSTALLATION_ID", keyActorId);
|
|
209535
|
+
const [meta, installs] = await Promise.all([
|
|
209536
|
+
fetchAppSelfMetadata({ appId, privateKeyPem: pem }).catch(() => null),
|
|
209537
|
+
listAppInstallations({ appId, privateKeyPem: pem }).catch(() => null)
|
|
209538
|
+
]);
|
|
209539
|
+
const stored = installs?.find((i) => i.installationId === storedInstallationId) ?? installs?.[0];
|
|
209540
|
+
const permissions = stored && Object.keys(stored.permissions).length > 0 ? stored.permissions : meta?.permissions ?? null;
|
|
209541
|
+
const app = {
|
|
209542
|
+
appId,
|
|
209543
|
+
slug: meta?.slug || slug6,
|
|
209544
|
+
ownerLogin: meta?.ownerLogin ?? "",
|
|
209545
|
+
ownerType: meta?.ownerType ?? "",
|
|
209546
|
+
usedBy: e.usedBy,
|
|
209547
|
+
usedByNames: e.usedBy.map((id) => nameOf2.get(id) ?? id),
|
|
209548
|
+
isOrgDefault: e.isOrgDefault,
|
|
209549
|
+
// 列不出来(私钥失效等)时退回库里记的那一处,卸载时 404 也当成功。
|
|
209550
|
+
installationIds: installs ? installs.map((i) => i.installationId) : storedInstallationId ? [storedInstallationId] : [],
|
|
209551
|
+
permissions,
|
|
209552
|
+
keyActorId
|
|
209553
|
+
};
|
|
209554
|
+
return app;
|
|
209555
|
+
}));
|
|
209556
|
+
return out.filter((a) => a !== null);
|
|
209557
|
+
}
|
|
209558
|
+
async function ghUser(token, path47) {
|
|
209559
|
+
const r = await fetch(`https://api.github.com${path47}`, {
|
|
209560
|
+
headers: {
|
|
209561
|
+
authorization: `Bearer ${token}`,
|
|
209562
|
+
accept: "application/vnd.github+json",
|
|
209563
|
+
"x-github-api-version": "2022-11-28"
|
|
209564
|
+
}
|
|
209565
|
+
});
|
|
209566
|
+
return { status: r.status, body: r.ok ? await r.json().catch(() => null) : null };
|
|
209567
|
+
}
|
|
209568
|
+
async function githubLoginOf(token) {
|
|
209569
|
+
const r = await ghUser(token, "/user").catch(() => null);
|
|
209570
|
+
return r?.body?.login ?? "";
|
|
209571
|
+
}
|
|
209572
|
+
async function listMemberships(token) {
|
|
209573
|
+
const r = await ghUser(
|
|
209574
|
+
token,
|
|
209575
|
+
"/user/memberships/orgs?state=active&per_page=100"
|
|
209576
|
+
);
|
|
209577
|
+
if (!r.body) return null;
|
|
209578
|
+
return r.body.flatMap((m2) => m2.organization?.login ? [{ login: m2.organization.login, role: m2.role ?? "member" }] : []);
|
|
209579
|
+
}
|
|
209580
|
+
async function orgInstalledAppsFor(token, org) {
|
|
209581
|
+
if (!token) return { state: { status: "needsAuth" }, apps: [] };
|
|
209582
|
+
const m2 = await ghUser(token, `/user/memberships/orgs/${encodeURIComponent(org)}`);
|
|
209583
|
+
if (m2.status === 401) return { state: { status: "needsAuth" }, apps: [] };
|
|
209584
|
+
if (m2.body && m2.body.role !== "admin") return { state: { status: "notAdmin" }, apps: [] };
|
|
209585
|
+
if (!m2.body && m2.status === 404) return { state: { status: "notAdmin" }, apps: [] };
|
|
209586
|
+
if (!m2.body) return { state: { status: "needsAuth" }, apps: [] };
|
|
209587
|
+
const r = await listOrgInstalledApps({ token, org });
|
|
209588
|
+
if (r.status === "ok") return { state: { status: "ok" }, apps: r.apps };
|
|
209589
|
+
if (r.status === "needsAuth") return { state: { status: "needsAuth" }, apps: [] };
|
|
209590
|
+
return { state: { status: "error", message: r.message }, apps: [] };
|
|
209591
|
+
}
|
|
209592
|
+
async function pickUserToken(svc) {
|
|
209593
|
+
const rows = await svc.listVariables();
|
|
209594
|
+
const sources = [void 0, ...rows.filter((r) => r.key === "GITHUB_TOKEN" && r.scope === "personal" && r.actorId).map((r) => r.actorId)];
|
|
209595
|
+
const tried = /* @__PURE__ */ new Set();
|
|
209596
|
+
for (const src of sources) {
|
|
209597
|
+
const token = await svc.revealVariable("GITHUB_TOKEN", src).catch(() => null);
|
|
209598
|
+
if (!token || tried.has(token)) continue;
|
|
209599
|
+
tried.add(token);
|
|
209600
|
+
const memberships = await listMemberships(token).catch(() => null);
|
|
209601
|
+
if (memberships) return { token, memberships };
|
|
209602
|
+
}
|
|
209603
|
+
return null;
|
|
209604
|
+
}
|
|
209605
|
+
var init_github_app_inventory = __esm({
|
|
209606
|
+
"../server/src/github-app-inventory.ts"() {
|
|
209607
|
+
"use strict";
|
|
209608
|
+
init_src8();
|
|
209609
|
+
}
|
|
209610
|
+
});
|
|
209611
|
+
|
|
209273
209612
|
// ../server/src/server.ts
|
|
209274
209613
|
function isBundleFrozen(err) {
|
|
209275
209614
|
return typeof err === "object" && err !== null && err.code === "TENANT_BUNDLE_FROZEN";
|
|
@@ -212711,7 +213050,7 @@ async function startOasisServer(opts) {
|
|
|
212711
213050
|
entry = {
|
|
212712
213051
|
// 旧 CLI 未带 waiterId 时给它塞一个服务端本地生成的——它绝不可能出现在 leave 上,
|
|
212713
213052
|
// 也就绝不会误命中 leftWaiterIds、绝不会被别人的 leave 摘掉。行为与旧 CLI 相同。
|
|
212714
|
-
waiterId: clientWaiterId ?? `server:${(0,
|
|
213053
|
+
waiterId: clientWaiterId ?? `server:${(0, import_node_crypto43.randomUUID)()}`,
|
|
212715
213054
|
onResolve,
|
|
212716
213055
|
expiresAt: expiresAt2,
|
|
212717
213056
|
cleanup: () => clearTimeout(expiryTimer),
|
|
@@ -214849,57 +215188,71 @@ ${composed}`;
|
|
|
214849
215188
|
}
|
|
214850
215189
|
if (url.pathname === "/api/connectors/github/app/available" && req.method === "POST") {
|
|
214851
215190
|
try {
|
|
215191
|
+
const { actorId, owner } = JSON.parse(rawBody || "{}");
|
|
214852
215192
|
const svc = await connectorActorsService();
|
|
214853
215193
|
if (!svc) throw new Error("actors service unavailable");
|
|
214854
|
-
const
|
|
214855
|
-
const
|
|
214856
|
-
const
|
|
214857
|
-
|
|
214858
|
-
|
|
214859
|
-
|
|
214860
|
-
|
|
214861
|
-
|
|
214862
|
-
|
|
214863
|
-
|
|
214864
|
-
|
|
214865
|
-
|
|
214866
|
-
|
|
214867
|
-
|
|
214868
|
-
|
|
214869
|
-
|
|
214870
|
-
|
|
214871
|
-
|
|
214872
|
-
|
|
214873
|
-
|
|
214874
|
-
|
|
214875
|
-
|
|
214876
|
-
|
|
214877
|
-
|
|
214878
|
-
})
|
|
215194
|
+
const token = await svc.revealResolvedVariable("GITHUB_TOKEN", actorId);
|
|
215195
|
+
const appOwner = owner?.kind === "org" && owner.login ? { kind: "org", login: owner.login } : { kind: "user", ...token ? { login: await githubLoginOf(token) } : {} };
|
|
215196
|
+
const [oasisApps, installed] = await Promise.all([
|
|
215197
|
+
collectOasisGithubApps(svc),
|
|
215198
|
+
appOwner.kind === "org" ? orgInstalledAppsFor(token, appOwner.login) : Promise.resolve({ state: { status: "ok" }, apps: [] })
|
|
215199
|
+
]);
|
|
215200
|
+
const names = new Map(oasisApps.map((a) => [a.appId, a.usedByNames]));
|
|
215201
|
+
const candidates = buildReuseCandidates({ owner: appOwner, oasisApps, installed: installed.apps }).map((c) => ({ ...c, usedBy: names.get(c.appId) ?? [] }));
|
|
215202
|
+
res.writeHead(200, { "content-type": "application/json" }).end(JSON.stringify({ candidates, installed: installed.state }));
|
|
215203
|
+
} catch (e) {
|
|
215204
|
+
res.writeHead(500, { "content-type": "application/json" }).end(JSON.stringify({ error: String(e) }));
|
|
215205
|
+
}
|
|
215206
|
+
return;
|
|
215207
|
+
}
|
|
215208
|
+
if (url.pathname === "/api/connectors/github/app/inventory" && req.method === "POST") {
|
|
215209
|
+
try {
|
|
215210
|
+
const svc = await connectorActorsService();
|
|
215211
|
+
if (!svc) throw new Error("actors service unavailable");
|
|
215212
|
+
const [oasisApps, picked] = await Promise.all([collectOasisGithubApps(svc), pickUserToken(svc)]);
|
|
215213
|
+
const adminOrgs = picked ? picked.memberships.filter((m2) => m2.role === "admin").map((m2) => m2.login) : [];
|
|
215214
|
+
const perOrg = picked ? await Promise.all(adminOrgs.map((org) => orgInstalledAppsFor(picked.token, org))) : [];
|
|
215215
|
+
const rows = buildAppInventory({ oasisApps, installed: perOrg.flatMap((r) => r.apps) });
|
|
215216
|
+
const names = new Map(oasisApps.map((a) => [a.appId, a.usedByNames]));
|
|
215217
|
+
res.writeHead(200, { "content-type": "application/json" }).end(JSON.stringify({
|
|
215218
|
+
rows: rows.map((r) => ({ ...r, usedBy: names.get(r.appId) ?? [] })),
|
|
215219
|
+
/** 组织里装着的那部分列没列出来:needsAuth = 没有可用的 GitHub 登录;notAdmin = 不是任何组织的管理员。 */
|
|
215220
|
+
installed: !picked ? { status: "needsAuth" } : adminOrgs.length === 0 ? { status: "notAdmin" } : perOrg.find((r) => r.state.status !== "ok")?.state ?? { status: "ok" },
|
|
215221
|
+
orgs: adminOrgs
|
|
215222
|
+
}));
|
|
215223
|
+
} catch (e) {
|
|
215224
|
+
res.writeHead(500, { "content-type": "application/json" }).end(JSON.stringify({ error: String(e) }));
|
|
215225
|
+
}
|
|
215226
|
+
return;
|
|
215227
|
+
}
|
|
215228
|
+
if (url.pathname === "/api/connectors/github/app/uninstall" && req.method === "POST") {
|
|
215229
|
+
try {
|
|
215230
|
+
const { appIds } = JSON.parse(rawBody || "{}");
|
|
215231
|
+
if (!Array.isArray(appIds) || appIds.length === 0 || !appIds.every((x2) => typeof x2 === "string")) {
|
|
215232
|
+
res.writeHead(400, { "content-type": "application/json" }).end(JSON.stringify({ error: "\u8BF7\u5148\u52FE\u9009\u8981\u5378\u8F7D\u7684 App" }));
|
|
215233
|
+
return;
|
|
214879
215234
|
}
|
|
214880
|
-
const
|
|
214881
|
-
|
|
214882
|
-
|
|
214883
|
-
|
|
214884
|
-
|
|
214885
|
-
|
|
214886
|
-
|
|
214887
|
-
|
|
214888
|
-
}
|
|
215235
|
+
const svc = await connectorActorsService();
|
|
215236
|
+
if (!svc) throw new Error("actors service unavailable");
|
|
215237
|
+
const apps = new Map((await collectOasisGithubApps(svc)).map((a) => [a.appId, a]));
|
|
215238
|
+
const results = await Promise.all(appIds.map(async (appId) => {
|
|
215239
|
+
const app = apps.get(appId);
|
|
215240
|
+
if (!app) return { appId, ok: false, error: "Oasis \u6CA1\u6709\u8FD9\u4E2A App \u7684\u79C1\u94A5\uFF0C\u5378\u8F7D\u4E0D\u4E86\uFF0C\u8BF7\u53BB GitHub \u9875\u9762\u5904\u7406" };
|
|
215241
|
+
if (app.isOrgDefault || app.usedBy.length > 0) {
|
|
215242
|
+
return { appId, slug: app.slug, ok: false, error: `\u8FD8\u6709 agent \u5728\u7528\uFF08${app.isOrgDefault ? "\u7EC4\u7EC7\u9ED8\u8BA4" : app.usedByNames.join("\u3001")}\uFF09\uFF0C\u4E0D\u80FD\u5378\u8F7D` };
|
|
215243
|
+
}
|
|
215244
|
+
const pem = await svc.revealVariable("GITHUB_APP_PRIVATE_KEY", app.keyActorId);
|
|
215245
|
+
if (!pem) return { appId, slug: app.slug, ok: false, error: "\u79C1\u94A5\u8BFB\u4E0D\u51FA\u6765\uFF0C\u5378\u8F7D\u4E0D\u4E86" };
|
|
214889
215246
|
try {
|
|
214890
|
-
const
|
|
214891
|
-
|
|
214892
|
-
|
|
214893
|
-
|
|
214894
|
-
|
|
214895
|
-
|
|
214896
|
-
});
|
|
214897
|
-
return { ...base, missing: missingAppPermissions(perms) };
|
|
214898
|
-
} catch {
|
|
214899
|
-
return { ...base, permissionsUnknown: true };
|
|
215247
|
+
for (const installationId of app.installationIds) {
|
|
215248
|
+
await uninstallAppInstallation({ appId, privateKeyPem: pem, installationId });
|
|
215249
|
+
}
|
|
215250
|
+
return { appId, slug: app.slug, ok: true };
|
|
215251
|
+
} catch (e) {
|
|
215252
|
+
return { appId, slug: app.slug, ok: false, error: `GitHub \u62D2\u7EDD\u4E86\u5378\u8F7D\uFF1A${String(e).replace(/^Error:\s*/, "")}` };
|
|
214900
215253
|
}
|
|
214901
215254
|
}));
|
|
214902
|
-
res.writeHead(200, { "content-type": "application/json" }).end(JSON.stringify({
|
|
215255
|
+
res.writeHead(200, { "content-type": "application/json" }).end(JSON.stringify({ results }));
|
|
214903
215256
|
} catch (e) {
|
|
214904
215257
|
res.writeHead(500, { "content-type": "application/json" }).end(JSON.stringify({ error: String(e) }));
|
|
214905
215258
|
}
|
|
@@ -214928,9 +215281,11 @@ ${composed}`;
|
|
|
214928
215281
|
return;
|
|
214929
215282
|
}
|
|
214930
215283
|
const pick3 = (key2) => rows.find((r) => r.key === key2 && r.actorId === srcActor && !r.encrypted)?.maskedValue ?? "";
|
|
214931
|
-
const
|
|
215284
|
+
const storedInstallationId = pick3("GITHUB_APP_INSTALLATION_ID");
|
|
215285
|
+
const live = await listAppInstallations({ appId, privateKeyPem: pem }).catch(() => null);
|
|
215286
|
+
const installationId = live ? (live.find((i) => i.installationId === storedInstallationId) ?? live[0])?.installationId ?? "" : storedInstallationId;
|
|
214932
215287
|
if (!installationId) {
|
|
214933
|
-
res.writeHead(409, { "content-type": "application/json" }).end(JSON.stringify({ error: "\u8FD9\u4E2A App \u8FD8\u6CA1\
|
|
215288
|
+
res.writeHead(409, { "content-type": "application/json" }).end(JSON.stringify({ error: "\u8FD9\u4E2A App \u8FD8\u6CA1\u88C5\u5230\u4EFB\u4F55\u8D26\u53F7\u2014\u2014\u5148\u5728 GitHub \u4E0A\u5B89\u88C5\u5B83\uFF0C\u88C5\u597D\u540E\u518D\u70B9\u8FDE\u63A5" }));
|
|
214934
215289
|
return;
|
|
214935
215290
|
}
|
|
214936
215291
|
const slug6 = pick3("GITHUB_APP_SLUG");
|
|
@@ -214968,7 +215323,7 @@ ${composed}`;
|
|
|
214968
215323
|
const msg = String(e);
|
|
214969
215324
|
bad(
|
|
214970
215325
|
400,
|
|
214971
|
-
/HTTP 401/.test(msg) ? "
|
|
215326
|
+
/HTTP 401/.test(msg) ? "\u8FD9\u4E2A\u79C1\u94A5\u548C\u6240\u9009\u7684 App \u5BF9\u4E0D\u4E0A\u2014\u2014\u8BF7\u786E\u8BA4\u5B83\u662F\u5728\u8FD9\u4E2A App \u7684\u8BBE\u7F6E\u9875\u70B9 Generate a private key \u4E0B\u8F7D\u7684\u90A3\u4E00\u4EFD\uFF08\u624B\u586B App ID \u65F6\u4E5F\u6838\u5BF9\u4E00\u4E0B\u6709\u6CA1\u6709\u6284\u9519\uFF09" : /私钥解析失败/.test(msg) ? msg.replace(/^Error:\s*/, "").replace(/^github app:\s*/, "") : `GitHub \u62D2\u7EDD\u4E86\u8FD9\u5BF9\u51ED\u636E\uFF1A${msg}`
|
|
214972
215327
|
);
|
|
214973
215328
|
return;
|
|
214974
215329
|
}
|
|
@@ -215638,14 +215993,14 @@ async function markDeliveredWithRetry(store, messageId, attempts = 3) {
|
|
|
215638
215993
|
}
|
|
215639
215994
|
return false;
|
|
215640
215995
|
}
|
|
215641
|
-
var http,
|
|
215996
|
+
var http, import_node_crypto43, CONNECTOR_AUTH_SNAPSHOT_TTL_MS, defaultResolveActor, enc, CHAT_OUTPUT_LIMIT, APPEND_TURN_START_WAIT_MS, STREAMING_PATHS, PLANNER_BLOCKING_CODES, WILL_VERBS, GOVERNANCE_COMMANDS, READ_ONLY_COMMANDS, isAgent, isHuman;
|
|
215642
215997
|
var init_server3 = __esm({
|
|
215643
215998
|
"../server/src/server.ts"() {
|
|
215644
215999
|
"use strict";
|
|
215645
216000
|
init_src();
|
|
215646
216001
|
init_file_limits2();
|
|
215647
216002
|
http = __toESM(require("node:http"), 1);
|
|
215648
|
-
|
|
216003
|
+
import_node_crypto43 = require("node:crypto");
|
|
215649
216004
|
init_chat_session();
|
|
215650
216005
|
init_chat_system_message();
|
|
215651
216006
|
init_sealed_node_receipt();
|
|
@@ -215711,6 +216066,7 @@ var init_server3 = __esm({
|
|
|
215711
216066
|
init_child_live_turn();
|
|
215712
216067
|
init_registry_audit_sink();
|
|
215713
216068
|
init_src8();
|
|
216069
|
+
init_github_app_inventory();
|
|
215714
216070
|
init_continuation3();
|
|
215715
216071
|
CONNECTOR_AUTH_SNAPSHOT_TTL_MS = 30 * 60 * 1e3;
|
|
215716
216072
|
defaultResolveActor = (token) => token.startsWith("token:") ? token.slice("token:".length) : null;
|
|
@@ -215825,7 +216181,7 @@ function createNodeTokenStore(file) {
|
|
|
215825
216181
|
return {
|
|
215826
216182
|
issue(nodeId) {
|
|
215827
216183
|
const table = read3();
|
|
215828
|
-
const token = `ont_${(0,
|
|
216184
|
+
const token = `ont_${(0, import_node_crypto44.randomBytes)(24).toString("base64url")}`;
|
|
215829
216185
|
table[token] = nodeId;
|
|
215830
216186
|
write(table);
|
|
215831
216187
|
return token;
|
|
@@ -215885,7 +216241,7 @@ function createEnrollTokenStore(defaultTtlMs = 30 * 60 * 1e3, file) {
|
|
|
215885
216241
|
return {
|
|
215886
216242
|
issue(name, ttlMs = defaultTtlMs, companyId) {
|
|
215887
216243
|
const m2 = prune();
|
|
215888
|
-
const token = `ent_${(0,
|
|
216244
|
+
const token = `ent_${(0, import_node_crypto44.randomBytes)(24).toString("base64url")}`;
|
|
215889
216245
|
const expiresAt2 = Date.now() + ttlMs;
|
|
215890
216246
|
m2.set(token, { name, expiresAt: expiresAt2, ...companyId !== void 0 ? { companyId } : {} });
|
|
215891
216247
|
write(m2);
|
|
@@ -215934,33 +216290,33 @@ function createEnrollTokenStore(defaultTtlMs = 30 * 60 * 1e3, file) {
|
|
|
215934
216290
|
}
|
|
215935
216291
|
};
|
|
215936
216292
|
}
|
|
215937
|
-
var
|
|
216293
|
+
var import_node_crypto44, fs22, path21, SESSION_TOKEN_PREFIX, b64url2, fromB64url, readOrCreateSecret, sign, signatureMatches, isTokenClaims;
|
|
215938
216294
|
var init_tokens = __esm({
|
|
215939
216295
|
"../server/src/tokens.ts"() {
|
|
215940
216296
|
"use strict";
|
|
215941
|
-
|
|
216297
|
+
import_node_crypto44 = require("node:crypto");
|
|
215942
216298
|
fs22 = __toESM(require("node:fs"), 1);
|
|
215943
216299
|
path21 = __toESM(require("node:path"), 1);
|
|
215944
216300
|
SESSION_TOKEN_PREFIX = "oat_v2_";
|
|
215945
216301
|
b64url2 = (value2) => Buffer.from(value2).toString("base64url");
|
|
215946
216302
|
fromB64url = (value2) => Buffer.from(value2, "base64url").toString("utf8");
|
|
215947
216303
|
readOrCreateSecret = (file) => {
|
|
215948
|
-
if (!file) return (0,
|
|
216304
|
+
if (!file) return (0, import_node_crypto44.randomBytes)(32);
|
|
215949
216305
|
try {
|
|
215950
216306
|
const raw = fs22.readFileSync(file, "utf8").trim();
|
|
215951
216307
|
if (raw) return Buffer.from(raw, "base64url");
|
|
215952
216308
|
} catch {
|
|
215953
216309
|
}
|
|
215954
|
-
const secret = (0,
|
|
216310
|
+
const secret = (0, import_node_crypto44.randomBytes)(32);
|
|
215955
216311
|
fs22.mkdirSync(path21.dirname(file), { recursive: true });
|
|
215956
216312
|
fs22.writeFileSync(file, secret.toString("base64url"), { mode: 384 });
|
|
215957
216313
|
return secret;
|
|
215958
216314
|
};
|
|
215959
|
-
sign = (secret, payload2) => (0,
|
|
216315
|
+
sign = (secret, payload2) => (0, import_node_crypto44.createHmac)("sha256", secret).update(payload2).digest("base64url");
|
|
215960
216316
|
signatureMatches = (actual, expected) => {
|
|
215961
216317
|
const a = Buffer.from(actual);
|
|
215962
216318
|
const b2 = Buffer.from(expected);
|
|
215963
|
-
return a.length === b2.length && (0,
|
|
216319
|
+
return a.length === b2.length && (0, import_node_crypto44.timingSafeEqual)(a, b2);
|
|
215964
216320
|
};
|
|
215965
216321
|
isTokenClaims = (value2) => {
|
|
215966
216322
|
if (value2 === null || typeof value2 !== "object") return false;
|
|
@@ -216022,31 +216378,31 @@ function createDataplaneTokenIssuer(opts = {}) {
|
|
|
216022
216378
|
}
|
|
216023
216379
|
};
|
|
216024
216380
|
}
|
|
216025
|
-
var
|
|
216381
|
+
var import_node_crypto45, fs23, path22, PREFIX2, b64url3, fromB64url2, sign2, sigMatches, readOrCreateSecret2, isClaims, isDataplaneToken;
|
|
216026
216382
|
var init_session_dataplane_token = __esm({
|
|
216027
216383
|
"../server/src/session-dataplane-token.ts"() {
|
|
216028
216384
|
"use strict";
|
|
216029
|
-
|
|
216385
|
+
import_node_crypto45 = require("node:crypto");
|
|
216030
216386
|
fs23 = __toESM(require("node:fs"), 1);
|
|
216031
216387
|
path22 = __toESM(require("node:path"), 1);
|
|
216032
216388
|
init_src();
|
|
216033
216389
|
PREFIX2 = "osd_";
|
|
216034
216390
|
b64url3 = (v2) => Buffer.from(v2, "utf8").toString("base64url");
|
|
216035
216391
|
fromB64url2 = (v2) => Buffer.from(v2, "base64url").toString("utf8");
|
|
216036
|
-
sign2 = (secret, payload2) => (0,
|
|
216392
|
+
sign2 = (secret, payload2) => (0, import_node_crypto45.createHmac)("sha256", secret).update(payload2).digest("base64url");
|
|
216037
216393
|
sigMatches = (actual, expected) => {
|
|
216038
216394
|
const a = Buffer.from(actual);
|
|
216039
216395
|
const b2 = Buffer.from(expected);
|
|
216040
|
-
return a.length === b2.length && (0,
|
|
216396
|
+
return a.length === b2.length && (0, import_node_crypto45.timingSafeEqual)(a, b2);
|
|
216041
216397
|
};
|
|
216042
216398
|
readOrCreateSecret2 = (file) => {
|
|
216043
|
-
if (!file) return (0,
|
|
216399
|
+
if (!file) return (0, import_node_crypto45.randomBytes)(32);
|
|
216044
216400
|
try {
|
|
216045
216401
|
const raw = fs23.readFileSync(file, "utf8").trim();
|
|
216046
216402
|
if (raw) return Buffer.from(raw, "base64url");
|
|
216047
216403
|
} catch {
|
|
216048
216404
|
}
|
|
216049
|
-
const secret = (0,
|
|
216405
|
+
const secret = (0, import_node_crypto45.randomBytes)(32);
|
|
216050
216406
|
fs23.mkdirSync(path22.dirname(file), { recursive: true });
|
|
216051
216407
|
fs23.writeFileSync(file, secret.toString("base64url"), { mode: 384 });
|
|
216052
216408
|
return secret;
|
|
@@ -218354,13 +218710,22 @@ function cloneOffboarding(op) {
|
|
|
218354
218710
|
assignmentDecisions: op.assignmentDecisions.map((d) => ({ ...d, toPrincipal: { ...d.toPrincipal } }))
|
|
218355
218711
|
};
|
|
218356
218712
|
}
|
|
218357
|
-
var memberKey, scopedKey, bridgeKey, MemoryControlPlaneStore;
|
|
218713
|
+
var memberKey, scopedKey, bridgeKey, migrationRow, MemoryControlPlaneStore;
|
|
218358
218714
|
var init_memory_control_plane_store = __esm({
|
|
218359
218715
|
"../testkit/src/memory-control-plane-store.ts"() {
|
|
218360
218716
|
"use strict";
|
|
218361
218717
|
memberKey = (companyId, accountId) => `${companyId} ${accountId}`;
|
|
218362
218718
|
scopedKey = (companyId, id) => `${companyId}\0${id}`;
|
|
218363
218719
|
bridgeKey = (companyId, type, id) => `${companyId}\0${type}\0${id}`;
|
|
218720
|
+
migrationRow = (companyId, accountId, roleBefore, roleAfter, audit2) => ({
|
|
218721
|
+
companyId,
|
|
218722
|
+
accountId,
|
|
218723
|
+
roleBefore,
|
|
218724
|
+
roleAfter,
|
|
218725
|
+
evidence: audit2.evidence,
|
|
218726
|
+
...audit2.evidence === "manifest" && audit2.manifestVersion !== void 0 ? { manifestVersion: audit2.manifestVersion } : {},
|
|
218727
|
+
appliedAt: audit2.appliedAt
|
|
218728
|
+
});
|
|
218364
218729
|
MemoryControlPlaneStore = class {
|
|
218365
218730
|
companies = /* @__PURE__ */ new Map();
|
|
218366
218731
|
members = /* @__PURE__ */ new Map();
|
|
@@ -218480,6 +218845,21 @@ var init_memory_control_plane_store = __esm({
|
|
|
218480
218845
|
this.members.delete(key2);
|
|
218481
218846
|
return { ok: true, member: { ...target } };
|
|
218482
218847
|
}
|
|
218848
|
+
async removeMemberAndReleaseOwnedAgents(companyId, accountId, at2) {
|
|
218849
|
+
const target = this.members.get(memberKey(companyId, accountId));
|
|
218850
|
+
if (!target) return { ok: false, reason: "not_found" };
|
|
218851
|
+
if (target.role === "owner") return { ok: false, reason: "owner_protected" };
|
|
218852
|
+
const releasedAgents = [];
|
|
218853
|
+
for (const [key2, e] of this.digitalEmployees) {
|
|
218854
|
+
if (e.companyId !== companyId || e.ownerAccountId !== accountId) continue;
|
|
218855
|
+
const { ownerAccountId: _cleared, ...rest } = e;
|
|
218856
|
+
this.digitalEmployees.set(key2, { ...rest, updatedAt: at2 });
|
|
218857
|
+
releasedAgents.push(e.id);
|
|
218858
|
+
}
|
|
218859
|
+
this.principalBridges.delete(bridgeKey(companyId, "human", accountId));
|
|
218860
|
+
this.members.delete(memberKey(companyId, accountId));
|
|
218861
|
+
return { ok: true, member: { ...target }, releasedAgents };
|
|
218862
|
+
}
|
|
218483
218863
|
async updateMemberRoleIfNotLastOwner(companyId, accountId, role) {
|
|
218484
218864
|
const key2 = memberKey(companyId, accountId);
|
|
218485
218865
|
const target = this.members.get(key2);
|
|
@@ -218506,7 +218886,7 @@ var init_memory_control_plane_store = __esm({
|
|
|
218506
218886
|
return { ok: false, reason: "target_not_listed" };
|
|
218507
218887
|
}
|
|
218508
218888
|
const acc = this.accounts.get(toAccountId);
|
|
218509
|
-
if (acc
|
|
218889
|
+
if (!acc || acc.status !== "active") return { ok: false, reason: "target_inactive" };
|
|
218510
218890
|
const others = [];
|
|
218511
218891
|
for (const m2 of this.members.values()) {
|
|
218512
218892
|
if (m2.companyId === companyId && m2.role === "owner" && m2.accountId !== toAccountId) others.push(m2);
|
|
@@ -218523,6 +218903,37 @@ var init_memory_control_plane_store = __esm({
|
|
|
218523
218903
|
this.members.set(memberKey(companyId, toAccountId), owner);
|
|
218524
218904
|
return { ok: true, owner: { ...owner }, demoted };
|
|
218525
218905
|
}
|
|
218906
|
+
// —— 存量身份映射(ADR D3)——
|
|
218907
|
+
async migrateSoleCompanyOwner(companyId, toAccountId, audit2) {
|
|
218908
|
+
const target = this.members.get(memberKey(companyId, toAccountId));
|
|
218909
|
+
if (!target) return { ok: false, reason: "not_found" };
|
|
218910
|
+
const others = [];
|
|
218911
|
+
for (const m2 of this.members.values()) {
|
|
218912
|
+
if (m2.companyId === companyId && m2.role === "owner" && m2.accountId !== toAccountId) others.push(m2);
|
|
218913
|
+
}
|
|
218914
|
+
if (others.length === 0 && target.role === "owner") {
|
|
218915
|
+
return { ok: true, owner: { ...target }, demoted: [], auditRows: [] };
|
|
218916
|
+
}
|
|
218917
|
+
const auditRows = [];
|
|
218918
|
+
const demoted = others.map((m2) => {
|
|
218919
|
+
const next = { ...m2, role: "admin" };
|
|
218920
|
+
this.members.set(memberKey(companyId, m2.accountId), next);
|
|
218921
|
+
auditRows.push(migrationRow(companyId, m2.accountId, "owner", "admin", audit2));
|
|
218922
|
+
return { ...next };
|
|
218923
|
+
});
|
|
218924
|
+
if (target.role !== "owner") auditRows.push(migrationRow(companyId, toAccountId, target.role, "owner", audit2));
|
|
218925
|
+
const owner = { ...target, role: "owner" };
|
|
218926
|
+
this.members.set(memberKey(companyId, toAccountId), owner);
|
|
218927
|
+
for (const r of auditRows) this.roleMigrations.push({ ...r });
|
|
218928
|
+
return { ok: true, owner: { ...owner }, demoted, auditRows };
|
|
218929
|
+
}
|
|
218930
|
+
async setMemberRoleOnly(companyId, accountId, role) {
|
|
218931
|
+
const key2 = memberKey(companyId, accountId);
|
|
218932
|
+
const cur = this.members.get(key2);
|
|
218933
|
+
if (!cur) return false;
|
|
218934
|
+
this.members.set(key2, { ...cur, role });
|
|
218935
|
+
return true;
|
|
218936
|
+
}
|
|
218526
218937
|
// —— 存量身份映射审计(ADR D3.4):只追加 ——
|
|
218527
218938
|
async appendMemberRoleMigrations(rows) {
|
|
218528
218939
|
for (const r of rows) this.roleMigrations.push({ ...r });
|
|
@@ -218793,11 +219204,11 @@ function onlyHits(pool, q2) {
|
|
|
218793
219204
|
if (!q2.requireMatch || q2.keywords.length === 0) return [...pool];
|
|
218794
219205
|
return pool.filter((r) => memoryMatchScore(r, q2.keywords) > 0);
|
|
218795
219206
|
}
|
|
218796
|
-
var
|
|
219207
|
+
var import_node_crypto46, MemoryActorMemoryStore, toIndexEntry;
|
|
218797
219208
|
var init_memory_actor_memory_store = __esm({
|
|
218798
219209
|
"../testkit/src/memory-actor-memory-store.ts"() {
|
|
218799
219210
|
"use strict";
|
|
218800
|
-
|
|
219211
|
+
import_node_crypto46 = require("node:crypto");
|
|
218801
219212
|
init_src();
|
|
218802
219213
|
MemoryActorMemoryStore = class {
|
|
218803
219214
|
rows = /* @__PURE__ */ new Map();
|
|
@@ -218851,7 +219262,7 @@ var init_memory_actor_memory_store = __esm({
|
|
|
218851
219262
|
async write(input, now) {
|
|
218852
219263
|
if (input.memId === void 0) {
|
|
218853
219264
|
const rec2 = {
|
|
218854
|
-
memId: `mem:${(0,
|
|
219265
|
+
memId: `mem:${(0, import_node_crypto46.randomUUID)()}`,
|
|
218855
219266
|
actorId: input.actorId,
|
|
218856
219267
|
projectId: input.projectId,
|
|
218857
219268
|
keywords: [...input.keywords],
|
|
@@ -220550,13 +220961,13 @@ var init_stats = __esm({
|
|
|
220550
220961
|
|
|
220551
220962
|
// ../server/src/domains/projects/project-id.ts
|
|
220552
220963
|
function randomProjectId() {
|
|
220553
|
-
return projectIdFromUuid((0,
|
|
220964
|
+
return projectIdFromUuid((0, import_node_crypto47.randomUUID)());
|
|
220554
220965
|
}
|
|
220555
|
-
var
|
|
220966
|
+
var import_node_crypto47;
|
|
220556
220967
|
var init_project_id = __esm({
|
|
220557
220968
|
"../server/src/domains/projects/project-id.ts"() {
|
|
220558
220969
|
"use strict";
|
|
220559
|
-
|
|
220970
|
+
import_node_crypto47 = require("node:crypto");
|
|
220560
220971
|
init_src();
|
|
220561
220972
|
}
|
|
220562
220973
|
});
|
|
@@ -222631,12 +223042,12 @@ function applyTurnPatch(t, patch) {
|
|
|
222631
223042
|
...patch.lastError !== void 0 ? { lastError: patch.lastError } : {}
|
|
222632
223043
|
};
|
|
222633
223044
|
}
|
|
222634
|
-
var
|
|
223045
|
+
var import_node_crypto48, fs24, path23, NdjsonOplogStore, DirBlobStore, MUTATORS, FileTypeRegistryStore, FileRoleRegistryStore, FileRegistryStore, FileAssistantBindStore, FileHumanPrefsStore, FileProjectStateStore, FileArtifactStateStore, FileTraceStore, MemoryChatSessionStore, FileChatSessionStore, MemoryChatTurnStore, FileChatTurnStore, MemoryReadMarkerStore, FileReadMarkerStore;
|
|
222635
223046
|
var init_dev_store = __esm({
|
|
222636
223047
|
"../server/src/dev-store.ts"() {
|
|
222637
223048
|
"use strict";
|
|
222638
223049
|
init_src();
|
|
222639
|
-
|
|
223050
|
+
import_node_crypto48 = require("node:crypto");
|
|
222640
223051
|
fs24 = __toESM(require("node:fs"), 1);
|
|
222641
223052
|
path23 = __toESM(require("node:path"), 1);
|
|
222642
223053
|
init_src();
|
|
@@ -222690,7 +223101,7 @@ var init_dev_store = __esm({
|
|
|
222690
223101
|
return path23.join(this.dir, hash3);
|
|
222691
223102
|
}
|
|
222692
223103
|
async put(bytes2) {
|
|
222693
|
-
const hash3 = (0,
|
|
223104
|
+
const hash3 = (0, import_node_crypto48.createHash)("sha256").update(bytes2).digest("hex");
|
|
222694
223105
|
const file = this.fileOf(hash3);
|
|
222695
223106
|
if (!fs24.existsSync(file)) fs24.writeFileSync(file, bytes2);
|
|
222696
223107
|
return hash3;
|
|
@@ -223813,6 +224224,9 @@ var init_control_plane_file_store = __esm({
|
|
|
223813
224224
|
"removeMemberIfNotLastOwner",
|
|
223814
224225
|
"updateMemberRoleIfNotLastOwner",
|
|
223815
224226
|
"setSoleCompanyOwner",
|
|
224227
|
+
"removeMemberAndReleaseOwnedAgents",
|
|
224228
|
+
"migrateSoleCompanyOwner",
|
|
224229
|
+
"setMemberRoleOnly",
|
|
223816
224230
|
"appendMemberRoleMigrations",
|
|
223817
224231
|
"createInvitation",
|
|
223818
224232
|
"updateInvitationStatus",
|
|
@@ -223982,7 +224396,7 @@ var init_company_engine_router = __esm({
|
|
|
223982
224396
|
|
|
223983
224397
|
// ../server/src/skill-market-client.ts
|
|
223984
224398
|
function digestOf2(bytes2) {
|
|
223985
|
-
return `sha256:${(0,
|
|
224399
|
+
return `sha256:${(0, import_node_crypto49.createHash)("sha256").update(bytes2).digest("hex")}`;
|
|
223986
224400
|
}
|
|
223987
224401
|
function createSkillMarketClientFromEnv(env = process.env) {
|
|
223988
224402
|
const base = env["SKILL_MARKET_BASE_URL"];
|
|
@@ -223993,11 +224407,11 @@ function createSkillMarketClientFromEnv(env = process.env) {
|
|
|
223993
224407
|
function sleep4(ms) {
|
|
223994
224408
|
return new Promise((r) => setTimeout(r, ms));
|
|
223995
224409
|
}
|
|
223996
|
-
var
|
|
224410
|
+
var import_node_crypto49, DisabledSkillMarketClient, FakeSkillMarketClient, HttpSkillMarketClient;
|
|
223997
224411
|
var init_skill_market_client = __esm({
|
|
223998
224412
|
"../server/src/skill-market-client.ts"() {
|
|
223999
224413
|
"use strict";
|
|
224000
|
-
|
|
224414
|
+
import_node_crypto49 = require("node:crypto");
|
|
224001
224415
|
init_src();
|
|
224002
224416
|
DisabledSkillMarketClient = class {
|
|
224003
224417
|
async listSkills(_input) {
|
|
@@ -224848,7 +225262,7 @@ async function copySessionOutputs(deps) {
|
|
|
224848
225262
|
continue;
|
|
224849
225263
|
}
|
|
224850
225264
|
const saved = existing?.[file.path];
|
|
224851
|
-
if (saved && savedContentHash(saved) === (0,
|
|
225265
|
+
if (saved && savedContentHash(saved) === (0, import_node_crypto50.createHash)("sha256").update(bytes2).digest("hex")) {
|
|
224852
225266
|
const aligned = { ...saved, size: bytes2.length, mtime: file.mtime };
|
|
224853
225267
|
delete aligned.editedAt;
|
|
224854
225268
|
realigned.push(aligned);
|
|
@@ -224945,11 +225359,11 @@ function createOutputCopyScheduler(deps) {
|
|
|
224945
225359
|
}
|
|
224946
225360
|
};
|
|
224947
225361
|
}
|
|
224948
|
-
var
|
|
225362
|
+
var import_node_crypto50, OUTPUT_COPY_LIMITS;
|
|
224949
225363
|
var init_outputs_copy = __esm({
|
|
224950
225364
|
"../server/src/domains/chat-sessions/outputs-copy.ts"() {
|
|
224951
225365
|
"use strict";
|
|
224952
|
-
|
|
225366
|
+
import_node_crypto50 = require("node:crypto");
|
|
224953
225367
|
init_src();
|
|
224954
225368
|
OUTPUT_COPY_LIMITS = {
|
|
224955
225369
|
maxFileBytes: FILE_CONTENT_MAX_BYTES,
|
|
@@ -225260,38 +225674,17 @@ async function backfillOrgIdentity(deps, opts = {}) {
|
|
|
225260
225674
|
const desc = row.changes.map((c) => `${c.accountId} ${c.roleBefore}\u2192${c.roleAfter}`).join("\uFF0C");
|
|
225261
225675
|
log3(` ${row.companyId}\uFF1A${desc}${opts.apply ? "" : "\uFF08dry-run\uFF09"}`);
|
|
225262
225676
|
if (!opts.apply) continue;
|
|
225263
|
-
const res = await deps.store.setSoleCompanyOwner(row.companyId, target);
|
|
225264
|
-
if (!res.ok) {
|
|
225265
|
-
throw new Error(
|
|
225266
|
-
`${row.companyId} \u6536\u655B\u5230 ${target} \u5931\u8D25\uFF1A${res.reason}\uFF08target_not_listed = \u90A3\u4E2A\u4EBA\u8FD8\u6CA1\u8D70\u5B8C\u65B0\u624B\u6307\u5F15\uFF1Btarget_inactive = \u8D26\u53F7\u5DF2\u505C\u7528\uFF09`
|
|
225267
|
-
);
|
|
225268
|
-
}
|
|
225269
|
-
applied += 1;
|
|
225270
|
-
const at2 = now();
|
|
225271
225677
|
const evidence = row.decision === "manifest" ? "manifest" : "E1";
|
|
225272
|
-
const
|
|
225273
|
-
companyId: row.companyId,
|
|
225274
|
-
accountId: m2.accountId,
|
|
225275
|
-
roleBefore: "owner",
|
|
225276
|
-
roleAfter: "admin",
|
|
225678
|
+
const res = await deps.store.migrateSoleCompanyOwner(row.companyId, target, {
|
|
225277
225679
|
evidence,
|
|
225278
|
-
...opts.manifest?.manifestVersion !== void 0
|
|
225279
|
-
appliedAt:
|
|
225280
|
-
})
|
|
225281
|
-
|
|
225282
|
-
|
|
225283
|
-
rows.push({
|
|
225284
|
-
companyId: row.companyId,
|
|
225285
|
-
accountId: target,
|
|
225286
|
-
roleBefore: promoted.roleBefore,
|
|
225287
|
-
roleAfter: "owner",
|
|
225288
|
-
evidence,
|
|
225289
|
-
...opts.manifest?.manifestVersion !== void 0 && evidence === "manifest" ? { manifestVersion: opts.manifest.manifestVersion } : {},
|
|
225290
|
-
appliedAt: at2
|
|
225291
|
-
});
|
|
225680
|
+
...opts.manifest?.manifestVersion !== void 0 ? { manifestVersion: opts.manifest.manifestVersion } : {},
|
|
225681
|
+
appliedAt: now()
|
|
225682
|
+
});
|
|
225683
|
+
if (!res.ok) {
|
|
225684
|
+
throw new Error(`${row.companyId} \u6536\u655B\u5230 ${target} \u5931\u8D25\uFF1A${res.reason}\uFF08\u90A3\u4E00\u884C\u4E0D\u5728\u8BE5\u7EC4\u7EC7\u7684\u6210\u5458\u8868\u91CC\uFF09`);
|
|
225292
225685
|
}
|
|
225293
|
-
|
|
225294
|
-
auditRows +=
|
|
225686
|
+
applied += 1;
|
|
225687
|
+
auditRows += res.auditRows.length;
|
|
225295
225688
|
}
|
|
225296
225689
|
return { ...inv, applied, auditRows };
|
|
225297
225690
|
}
|
|
@@ -225311,7 +225704,7 @@ async function rollbackOrgIdentity(deps, opts) {
|
|
|
225311
225704
|
plan.push({ companyId: r.companyId, accountId: r.accountId, from: member.role, to: r.roleBefore });
|
|
225312
225705
|
log3(` ${r.companyId} ${r.accountId} ${member.role}\u2192${r.roleBefore}${opts.apply ? "" : "\uFF08dry-run\uFF09"}`);
|
|
225313
225706
|
if (!opts.apply) continue;
|
|
225314
|
-
await deps.store.
|
|
225707
|
+
await deps.store.setMemberRoleOnly(r.companyId, r.accountId, r.roleBefore);
|
|
225315
225708
|
reverted += 1;
|
|
225316
225709
|
}
|
|
225317
225710
|
return { plan, reverted };
|
|
@@ -225355,11 +225748,11 @@ function typeDefError(def, mode) {
|
|
|
225355
225748
|
}
|
|
225356
225749
|
return null;
|
|
225357
225750
|
}
|
|
225358
|
-
var
|
|
225751
|
+
var import_node_crypto51, RESERVED_FIELD_NAMES, ARTIFACT_TYPE_ACCENTS, TYPE_DEF_SCHEMA, TypesAdminService;
|
|
225359
225752
|
var init_types_admin = __esm({
|
|
225360
225753
|
"../server/src/types-admin.ts"() {
|
|
225361
225754
|
"use strict";
|
|
225362
|
-
|
|
225755
|
+
import_node_crypto51 = require("node:crypto");
|
|
225363
225756
|
init_zod();
|
|
225364
225757
|
init_src7();
|
|
225365
225758
|
init_config_audit();
|
|
@@ -225486,7 +225879,7 @@ var init_types_admin = __esm({
|
|
|
225486
225879
|
async trace(change, target, by, detail) {
|
|
225487
225880
|
try {
|
|
225488
225881
|
await this.audit?.({
|
|
225489
|
-
id: `reg_${(0,
|
|
225882
|
+
id: `reg_${(0, import_node_crypto51.randomUUID)()}`,
|
|
225490
225883
|
actor: by ?? SYSTEM_CONFIG_ACTOR,
|
|
225491
225884
|
kind: "registry_change",
|
|
225492
225885
|
target,
|
|
@@ -225634,11 +226027,11 @@ function roleDefError(def, mode) {
|
|
|
225634
226027
|
}
|
|
225635
226028
|
return null;
|
|
225636
226029
|
}
|
|
225637
|
-
var
|
|
226030
|
+
var import_node_crypto52, ACCENTS, ROLE_DEF_SCHEMA, RolesAdminService;
|
|
225638
226031
|
var init_roles_admin = __esm({
|
|
225639
226032
|
"../server/src/roles-admin.ts"() {
|
|
225640
226033
|
"use strict";
|
|
225641
|
-
|
|
226034
|
+
import_node_crypto52 = require("node:crypto");
|
|
225642
226035
|
init_zod();
|
|
225643
226036
|
init_src7();
|
|
225644
226037
|
init_config_audit();
|
|
@@ -225663,7 +226056,7 @@ var init_roles_admin = __esm({
|
|
|
225663
226056
|
async trace(change, target, by, detail) {
|
|
225664
226057
|
try {
|
|
225665
226058
|
await this.deps.audit?.({
|
|
225666
|
-
id: `reg_${(0,
|
|
226059
|
+
id: `reg_${(0, import_node_crypto52.randomUUID)()}`,
|
|
225667
226060
|
actor: by ?? SYSTEM_CONFIG_ACTOR,
|
|
225668
226061
|
kind: "registry_change",
|
|
225669
226062
|
target,
|
|
@@ -228541,8 +228934,8 @@ var init_chat_recovery = __esm({
|
|
|
228541
228934
|
|
|
228542
228935
|
// ../server/src/auth/crypto.ts
|
|
228543
228936
|
function hashPassword(password) {
|
|
228544
|
-
const salt = (0,
|
|
228545
|
-
const dk = (0,
|
|
228937
|
+
const salt = (0, import_node_crypto53.randomBytes)(16);
|
|
228938
|
+
const dk = (0, import_node_crypto53.scryptSync)(password, salt, SCRYPT_KEYLEN, { N: SCRYPT_N, maxmem: 64 * 1024 * 1024 });
|
|
228546
228939
|
return `scrypt$${SCRYPT_N}$${salt.toString("base64url")}$${dk.toString("base64url")}`;
|
|
228547
228940
|
}
|
|
228548
228941
|
function verifyPassword(password, stored) {
|
|
@@ -228559,8 +228952,8 @@ function verifyPassword(password, stored) {
|
|
|
228559
228952
|
return false;
|
|
228560
228953
|
}
|
|
228561
228954
|
if (expected.length === 0) return false;
|
|
228562
|
-
const dk = (0,
|
|
228563
|
-
return dk.length === expected.length && (0,
|
|
228955
|
+
const dk = (0, import_node_crypto53.scryptSync)(password, salt, expected.length, { N, maxmem: 64 * 1024 * 1024 });
|
|
228956
|
+
return dk.length === expected.length && (0, import_node_crypto53.timingSafeEqual)(dk, expected);
|
|
228564
228957
|
}
|
|
228565
228958
|
function b64urlJson(value2) {
|
|
228566
228959
|
return Buffer.from(JSON.stringify(value2)).toString("base64url");
|
|
@@ -228568,17 +228961,17 @@ function b64urlJson(value2) {
|
|
|
228568
228961
|
function signSession(claims, secret) {
|
|
228569
228962
|
const head = b64urlJson({ alg: "HS256", typ: "JWT" });
|
|
228570
228963
|
const body2 = b64urlJson(claims);
|
|
228571
|
-
const sig = (0,
|
|
228964
|
+
const sig = (0, import_node_crypto53.createHmac)("sha256", secret).update(`${head}.${body2}`).digest("base64url");
|
|
228572
228965
|
return `${head}.${body2}.${sig}`;
|
|
228573
228966
|
}
|
|
228574
228967
|
function verifySession(token, secret, nowMs) {
|
|
228575
228968
|
const parts = token.split(".");
|
|
228576
228969
|
if (parts.length !== 3) return null;
|
|
228577
228970
|
const [head, body2, sig] = parts;
|
|
228578
|
-
const expected = (0,
|
|
228971
|
+
const expected = (0, import_node_crypto53.createHmac)("sha256", secret).update(`${head}.${body2}`).digest("base64url");
|
|
228579
228972
|
const got = Buffer.from(sig);
|
|
228580
228973
|
const exp = Buffer.from(expected);
|
|
228581
|
-
if (got.length !== exp.length || !(0,
|
|
228974
|
+
if (got.length !== exp.length || !(0, import_node_crypto53.timingSafeEqual)(got, exp)) return null;
|
|
228582
228975
|
let claims;
|
|
228583
228976
|
try {
|
|
228584
228977
|
claims = JSON.parse(Buffer.from(body2, "base64url").toString("utf8"));
|
|
@@ -228590,21 +228983,21 @@ function verifySession(token, secret, nowMs) {
|
|
|
228590
228983
|
return claims;
|
|
228591
228984
|
}
|
|
228592
228985
|
function generateCode() {
|
|
228593
|
-
return String((0,
|
|
228986
|
+
return String((0, import_node_crypto53.randomInt)(0, 1e6)).padStart(6, "0");
|
|
228594
228987
|
}
|
|
228595
228988
|
function hashCode(code2, secret) {
|
|
228596
|
-
return (0,
|
|
228989
|
+
return (0, import_node_crypto53.createHmac)("sha256", secret).update(`code:${code2}`).digest("base64url");
|
|
228597
228990
|
}
|
|
228598
228991
|
function safeEqualHash(a, b2) {
|
|
228599
228992
|
const ba = Buffer.from(a);
|
|
228600
228993
|
const bb = Buffer.from(b2);
|
|
228601
|
-
return ba.length === bb.length && (0,
|
|
228994
|
+
return ba.length === bb.length && (0, import_node_crypto53.timingSafeEqual)(ba, bb);
|
|
228602
228995
|
}
|
|
228603
|
-
var
|
|
228996
|
+
var import_node_crypto53, SCRYPT_N, SCRYPT_KEYLEN;
|
|
228604
228997
|
var init_crypto2 = __esm({
|
|
228605
228998
|
"../server/src/auth/crypto.ts"() {
|
|
228606
228999
|
"use strict";
|
|
228607
|
-
|
|
229000
|
+
import_node_crypto53 = require("node:crypto");
|
|
228608
229001
|
SCRYPT_N = 16384;
|
|
228609
229002
|
SCRYPT_KEYLEN = 32;
|
|
228610
229003
|
}
|
|
@@ -229988,18 +230381,18 @@ function variableKeyFromEnv(env = process.env) {
|
|
|
229988
230381
|
return buf;
|
|
229989
230382
|
}
|
|
229990
230383
|
if (env.NODE_ENV === "production") throw new Error("OASIS_VAR_KEY is required in production");
|
|
229991
|
-
return (0,
|
|
230384
|
+
return (0, import_node_crypto54.createHash)("sha256").update("oasis-dev-only-variable-key").digest();
|
|
229992
230385
|
}
|
|
229993
230386
|
function dedupe2(ids2) {
|
|
229994
230387
|
return [...new Set(ids2.filter((x2) => typeof x2 === "string" && x2.length > 0))];
|
|
229995
230388
|
}
|
|
229996
|
-
var
|
|
230389
|
+
var import_node_crypto54, REDACTED_MARKER, ActorsService, MASK_TAIL_MIN_LENGTH, mask, changedKeys;
|
|
229997
230390
|
var init_service5 = __esm({
|
|
229998
230391
|
"../server/src/domains/actors/service.ts"() {
|
|
229999
230392
|
"use strict";
|
|
230000
230393
|
init_file_limits2();
|
|
230001
230394
|
init_keyed_mutex();
|
|
230002
|
-
|
|
230395
|
+
import_node_crypto54 = require("node:crypto");
|
|
230003
230396
|
init_skill_fetcher();
|
|
230004
230397
|
init_identity();
|
|
230005
230398
|
init_migrate();
|
|
@@ -230623,7 +231016,7 @@ ${input.description}
|
|
|
230623
231016
|
*/
|
|
230624
231017
|
buildSkillFile(skillId, path47, content3, now) {
|
|
230625
231018
|
const bytes2 = new TextEncoder().encode(content3);
|
|
230626
|
-
const blobHash = (0,
|
|
231019
|
+
const blobHash = (0, import_node_crypto54.createHash)("sha256").update(bytes2).digest("hex");
|
|
230627
231020
|
return { skillId, path: path47, content: content3, blobHash, size: bytes2.length, updatedAt: now };
|
|
230628
231021
|
}
|
|
230629
231022
|
/**
|
|
@@ -231746,15 +232139,15 @@ ${input.description}
|
|
|
231746
232139
|
return hit ? { value: hit.value, ...hit.origin ? { origin: hit.origin } : {} } : null;
|
|
231747
232140
|
}
|
|
231748
232141
|
encrypt(plain) {
|
|
231749
|
-
const iv = (0,
|
|
231750
|
-
const cipher = (0,
|
|
232142
|
+
const iv = (0, import_node_crypto54.randomBytes)(12);
|
|
232143
|
+
const cipher = (0, import_node_crypto54.createCipheriv)("aes-256-gcm", this.opts.variableKey, iv);
|
|
231751
232144
|
const enc3 = Buffer.concat([cipher.update(plain, "utf8"), cipher.final()]);
|
|
231752
232145
|
return [iv.toString("base64"), cipher.getAuthTag().toString("base64"), enc3.toString("base64")].join(".");
|
|
231753
232146
|
}
|
|
231754
232147
|
decrypt(packed) {
|
|
231755
232148
|
const [iv, tag, data] = packed.split(".");
|
|
231756
232149
|
if (!iv || !tag || typeof data !== "string") throw new Error("malformed ciphertext");
|
|
231757
|
-
const decipher = (0,
|
|
232150
|
+
const decipher = (0, import_node_crypto54.createDecipheriv)("aes-256-gcm", this.opts.variableKey, Buffer.from(iv, "base64"));
|
|
231758
232151
|
decipher.setAuthTag(Buffer.from(tag, "base64"));
|
|
231759
232152
|
return Buffer.concat([decipher.update(Buffer.from(data, "base64")), decipher.final()]).toString("utf8");
|
|
231760
232153
|
}
|
|
@@ -232368,7 +232761,7 @@ async function listSkillMetadataForActor(args) {
|
|
|
232368
232761
|
usedDirs.add(dir);
|
|
232369
232762
|
const sorted = [...metas].sort((a, b2) => a.path.localeCompare(b2.path));
|
|
232370
232763
|
let latest = "1970-01-01T00:00:00.000Z";
|
|
232371
|
-
const hasher = (0,
|
|
232764
|
+
const hasher = (0, import_node_crypto55.createHash)("sha256");
|
|
232372
232765
|
for (const m2 of sorted) {
|
|
232373
232766
|
if (m2.updatedAt > latest) latest = m2.updatedAt;
|
|
232374
232767
|
hasher.update(m2.path);
|
|
@@ -232393,11 +232786,11 @@ async function listSkillMetadataForActor(args) {
|
|
|
232393
232786
|
const dir = sanitizeSkillDir(c.name, c.slug);
|
|
232394
232787
|
if (usedDirs.has(dir)) continue;
|
|
232395
232788
|
usedDirs.add(dir);
|
|
232396
|
-
const hasher = (0,
|
|
232789
|
+
const hasher = (0, import_node_crypto55.createHash)("sha256");
|
|
232397
232790
|
for (const p2 of paths) {
|
|
232398
232791
|
hasher.update(p2);
|
|
232399
232792
|
hasher.update("\0");
|
|
232400
|
-
hasher.update((0,
|
|
232793
|
+
hasher.update((0, import_node_crypto55.createHash)("sha256").update(c.files[p2]).digest("hex"));
|
|
232401
232794
|
hasher.update("\0");
|
|
232402
232795
|
}
|
|
232403
232796
|
out.push({
|
|
@@ -232418,11 +232811,11 @@ async function listSkillMetadataForActor(args) {
|
|
|
232418
232811
|
const dir = sanitizeSkillDir(b2.name, b2.id);
|
|
232419
232812
|
if (usedDirs.has(dir)) continue;
|
|
232420
232813
|
usedDirs.add(dir);
|
|
232421
|
-
const hasher = (0,
|
|
232814
|
+
const hasher = (0, import_node_crypto55.createHash)("sha256");
|
|
232422
232815
|
for (const p2 of paths) {
|
|
232423
232816
|
hasher.update(p2);
|
|
232424
232817
|
hasher.update("\0");
|
|
232425
|
-
hasher.update((0,
|
|
232818
|
+
hasher.update((0, import_node_crypto55.createHash)("sha256").update(b2.files[p2]).digest("hex"));
|
|
232426
232819
|
hasher.update("\0");
|
|
232427
232820
|
}
|
|
232428
232821
|
out.push({
|
|
@@ -232442,7 +232835,7 @@ function builtinSkillToFiles(b2) {
|
|
|
232442
232835
|
skillId: `builtin:${b2.id}`,
|
|
232443
232836
|
path: path47,
|
|
232444
232837
|
content: content3,
|
|
232445
|
-
blobHash: (0,
|
|
232838
|
+
blobHash: (0, import_node_crypto55.createHash)("sha256").update(content3).digest("hex"),
|
|
232446
232839
|
size: Buffer.byteLength(content3, "utf8"),
|
|
232447
232840
|
updatedAt: "1970-01-01T00:00:00.000Z"
|
|
232448
232841
|
}));
|
|
@@ -232466,7 +232859,7 @@ function sanitizeSkillDir(name, fallbackId) {
|
|
|
232466
232859
|
if (byName) return byName;
|
|
232467
232860
|
const byId = fallbackId ? fold2(fallbackId) : "";
|
|
232468
232861
|
if (byId) return byId;
|
|
232469
|
-
return `skill-${(0,
|
|
232862
|
+
return `skill-${(0, import_node_crypto55.createHash)("sha256").update(name).digest("hex").slice(0, 8)}`;
|
|
232470
232863
|
}
|
|
232471
232864
|
async function materializeSkillFiles(args) {
|
|
232472
232865
|
const skills = await args.service.listInstalledSkillsForActor(args.actorId);
|
|
@@ -232499,7 +232892,7 @@ function connectorSkillToFiles(c) {
|
|
|
232499
232892
|
skillId: c.id,
|
|
232500
232893
|
path: path47,
|
|
232501
232894
|
content: content3,
|
|
232502
|
-
blobHash: (0,
|
|
232895
|
+
blobHash: (0, import_node_crypto55.createHash)("sha256").update(content3).digest("hex"),
|
|
232503
232896
|
size: Buffer.byteLength(content3, "utf8"),
|
|
232504
232897
|
updatedAt: "1970-01-01T00:00:00.000Z"
|
|
232505
232898
|
}));
|
|
@@ -232516,11 +232909,11 @@ function connectorSkillDisplayRows(connectorSkills, enabledConnectors) {
|
|
|
232516
232909
|
...s2.version !== void 0 ? { version: s2.version } : {}
|
|
232517
232910
|
}));
|
|
232518
232911
|
}
|
|
232519
|
-
var
|
|
232912
|
+
var import_node_crypto55;
|
|
232520
232913
|
var init_skill_materializer = __esm({
|
|
232521
232914
|
"../server/src/domains/actors/skill-materializer.ts"() {
|
|
232522
232915
|
"use strict";
|
|
232523
|
-
|
|
232916
|
+
import_node_crypto55 = require("node:crypto");
|
|
232524
232917
|
}
|
|
232525
232918
|
});
|
|
232526
232919
|
|
|
@@ -232799,6 +233192,12 @@ function actorsDomain(opts) {
|
|
|
232799
233192
|
}
|
|
232800
233193
|
await asForbidden(() => assertMayManageAgent(opts.agentManageGuard, ctx, { id: actor.id, positions: actor.roles }));
|
|
232801
233194
|
};
|
|
233195
|
+
const guardPositionsChange = async (req, existing, nextPositions) => {
|
|
233196
|
+
if (existing.kind !== "agent" || nextPositions === void 0) return;
|
|
233197
|
+
if (isAssistantAgent({ positions: existing.roles }) === isAssistantAgent({ positions: nextPositions })) return;
|
|
233198
|
+
const ctx = { companyId: req.auth.companyId, callerActorId: req.auth.actor };
|
|
233199
|
+
await asForbidden(() => assertMayManageAgent(opts.agentManageGuard, ctx, { id: existing.id, positions: nextPositions }));
|
|
233200
|
+
};
|
|
232802
233201
|
const guardExistingActorWrite = async (req, service, actorId) => {
|
|
232803
233202
|
const existing = await service.getActor(actorId);
|
|
232804
233203
|
if (!existing) throw new ApiError(404, "NOT_FOUND", `\u6CA1\u6709\u8FD9\u4E2A\u5458\u5DE5\uFF1A${actorId}`);
|
|
@@ -232891,6 +233290,7 @@ function actorsDomain(opts) {
|
|
|
232891
233290
|
const positions = positionsFromPayload(b2);
|
|
232892
233291
|
const avatar = avatarRefFromPayload(b2);
|
|
232893
233292
|
const tags = tagsFromPayload(b2);
|
|
233293
|
+
await guardPositionsChange(req, existing, positions);
|
|
232894
233294
|
const {
|
|
232895
233295
|
positions: _positions,
|
|
232896
233296
|
id: _id,
|
|
@@ -234620,7 +235020,7 @@ function createActorsDomain(opts) {
|
|
|
234620
235020
|
...kernel !== void 0 ? { onRolesChanged: (a, r) => kernel.setActorRoles(a, r) } : {},
|
|
234621
235021
|
audit: async (entry) => {
|
|
234622
235022
|
await opts.audit?.({
|
|
234623
|
-
id: `reg_${(0,
|
|
235023
|
+
id: `reg_${(0, import_node_crypto56.randomUUID)()}`,
|
|
234624
235024
|
actor: entry.by,
|
|
234625
235025
|
kind: "registry_change",
|
|
234626
235026
|
target: entry.actorId,
|
|
@@ -234660,11 +235060,11 @@ function createActorsDomain(opts) {
|
|
|
234660
235060
|
register: actorsDomain({ resolveCtx, ...opts.resolveTrace ? { resolveTrace: opts.resolveTrace } : {}, ...opts.trace ? { trace: opts.trace } : {}, ...opts.listBuiltinSkills ? { listBuiltinSkills: opts.listBuiltinSkills } : {}, ...opts.getBuiltinSkills ? { getBuiltinSkills: opts.getBuiltinSkills } : {}, ...opts.getConnectorSkills ? { getConnectorSkills: opts.getConnectorSkills } : {}, ...opts.refreshConnectorSkills ? { refreshConnectorSkills: opts.refreshConnectorSkills } : {}, ...opts.memory ? { memory: opts.memory } : {}, ...opts.resolveDispatchScope ? { resolveDispatchScope: opts.resolveDispatchScope } : {}, ...opts.projectExists ? { projectExists: opts.projectExists } : {}, ...opts.companyMemberRole ? { companyMemberRole: opts.companyMemberRole } : {}, ...opts.credentialAudit ? { credentialAudit: opts.credentialAudit } : {}, ...opts.readCredentialAudit ? { readCredentialAudit: opts.readCredentialAudit } : {}, ...opts.credentialRevealLimits ? { credentialRevealLimits: opts.credentialRevealLimits } : {}, ...opts.skillMarket ? { skillMarket: opts.skillMarket } : {}, ...opts.resolveNodeTenancy ? { resolveNodeTenancy: opts.resolveNodeTenancy } : {}, ...opts.agentManageGuard ? { agentManageGuard: opts.agentManageGuard } : {} })
|
|
234661
235061
|
};
|
|
234662
235062
|
}
|
|
234663
|
-
var
|
|
235063
|
+
var import_node_crypto56;
|
|
234664
235064
|
var init_actors = __esm({
|
|
234665
235065
|
"../server/src/domains/actors/index.ts"() {
|
|
234666
235066
|
"use strict";
|
|
234667
|
-
|
|
235067
|
+
import_node_crypto56 = require("node:crypto");
|
|
234668
235068
|
init_service5();
|
|
234669
235069
|
init_routes3();
|
|
234670
235070
|
init_service5();
|
|
@@ -236353,6 +236753,13 @@ function isPendingActor(id) {
|
|
|
236353
236753
|
function isAgentActor(id) {
|
|
236354
236754
|
return typeof id === "string" && id.startsWith("actor:agent:");
|
|
236355
236755
|
}
|
|
236756
|
+
function isBlockingBackpressure(i) {
|
|
236757
|
+
if (i.kind === "gap" || i.kind === "escalation") return false;
|
|
236758
|
+
if (i.intent === "advisory") return false;
|
|
236759
|
+
const from = i.raisedByNodeId;
|
|
236760
|
+
const about = i.aboutNodeId;
|
|
236761
|
+
return !!from && !!about && from !== about;
|
|
236762
|
+
}
|
|
236356
236763
|
function isDispatchLayerFailure(detail) {
|
|
236357
236764
|
const reason = detail?.reason;
|
|
236358
236765
|
return typeof reason === "string" && reason.startsWith("dispatch ");
|
|
@@ -236577,12 +236984,8 @@ function buildWorkorderActivity(input) {
|
|
|
236577
236984
|
} else if (r.decision === "approved" || r.decision === "completed") h.to = h.to ?? r.decidedAt ?? r.at;
|
|
236578
236985
|
}
|
|
236579
236986
|
for (const i of snap.issues) {
|
|
236580
|
-
if (i
|
|
236581
|
-
|
|
236582
|
-
const from = i.raisedByNodeId;
|
|
236583
|
-
const about = i.aboutNodeId;
|
|
236584
|
-
if (!from || !about || from === about) continue;
|
|
236585
|
-
addHold(from, { kind: "backpressure", from: i.createdAt, to: i.resolvedAt ?? null, upstream: about });
|
|
236987
|
+
if (!isBlockingBackpressure(i)) continue;
|
|
236988
|
+
addHold(i.raisedByNodeId, { kind: "backpressure", from: i.createdAt, to: i.resolvedAt ?? null, upstream: i.aboutNodeId });
|
|
236586
236989
|
}
|
|
236587
236990
|
const HOLD_RANK = { paused: 0, continuationDenied: 1, continuation: 2, backpressure: 3 };
|
|
236588
236991
|
const holdOf2 = (w2) => {
|
|
@@ -236602,11 +237005,50 @@ function buildWorkorderActivity(input) {
|
|
|
236602
237005
|
};
|
|
236603
237006
|
const lastStampOf = (w2) => [w2.createdAt, w2.startedAt, w2.endedAt, w2.deadAt, w2.cancelledAt].filter((t) => !!t).sort().at(-1);
|
|
236604
237007
|
const concludedRootBriefNodeIds = /* @__PURE__ */ new Set();
|
|
237008
|
+
const blockingBackpressure = snap.issues.filter((i) => isBlockingBackpressure(i));
|
|
237009
|
+
const blockingBackpressureIds = new Set(blockingBackpressure.map((i) => i.id));
|
|
237010
|
+
const backpressureRaisedBy = /* @__PURE__ */ new Map();
|
|
237011
|
+
for (const i of [...blockingBackpressure].sort((a, b2) => a.createdAt.localeCompare(b2.createdAt) || a.id.localeCompare(b2.id))) {
|
|
237012
|
+
const from = i.raisedByNodeId;
|
|
237013
|
+
backpressureRaisedBy.set(from, [...backpressureRaisedBy.get(from) ?? [], i]);
|
|
237014
|
+
}
|
|
237015
|
+
const backpressureOnRaiserCard = /* @__PURE__ */ new Set();
|
|
237016
|
+
const backpressureDriving = /* @__PURE__ */ new Map();
|
|
237017
|
+
{
|
|
237018
|
+
const add = (workId, issueId) => {
|
|
237019
|
+
if (!issueId || !blockingBackpressureIds.has(issueId)) return;
|
|
237020
|
+
const list2 = backpressureDriving.get(workId) ?? [];
|
|
237021
|
+
if (!list2.includes(issueId)) list2.push(issueId);
|
|
237022
|
+
backpressureDriving.set(workId, list2);
|
|
237023
|
+
};
|
|
237024
|
+
for (const rec2 of events) {
|
|
237025
|
+
const ev = rec2.event;
|
|
237026
|
+
if (ev.kind !== "work.create" || !ev.workId) continue;
|
|
237027
|
+
for (const r of ev.reasons ?? []) if (r.kind === "issue") add(ev.workId, r.issueId);
|
|
237028
|
+
}
|
|
237029
|
+
for (const w2 of snap.works) for (const id of w2.frozenIssueIds ?? []) add(w2.id, id);
|
|
237030
|
+
}
|
|
237031
|
+
const backpressureTargetName = (nodeId) => nodeId && rootBriefNodeIds.has(nodeId) ? "\u4EFB\u52A1\u8BF4\u660E" : nodeName(nodeId);
|
|
237032
|
+
const backpressureOwnerOf = (nodeId) => {
|
|
237033
|
+
const assignee = nodeId ? nodeById.get(nodeId)?.assigneeActorId : void 0;
|
|
237034
|
+
return assignee && !isPendingActor(assignee) ? assignee : ownerId;
|
|
237035
|
+
};
|
|
237036
|
+
const backpressureRaisersOf = (workId) => {
|
|
237037
|
+
const ids2 = backpressureDriving.get(workId);
|
|
237038
|
+
if (!ids2?.length) return void 0;
|
|
237039
|
+
const authors = [...new Set(ids2.map((id) => issueById.get(id)?.authorActorId).filter((a) => !!a))];
|
|
237040
|
+
return authors.length ? authors.map(nameOf2).join("\u3001") : void 0;
|
|
237041
|
+
};
|
|
236605
237042
|
for (const [nodeId, works] of worksOfNode) {
|
|
236606
237043
|
const interrupts = [...interruptsOfNode.get(nodeId) ?? []].sort((a, b2) => a.at.localeCompare(b2.at) || a.issueId.localeCompare(b2.issueId));
|
|
236607
237044
|
const trips = stopLossOfNode.get(nodeId) ?? [];
|
|
236608
237045
|
const interventions = [...interventionsOfNode.get(nodeId) ?? []].sort();
|
|
236609
237046
|
const humanBetween = (prev, w2) => !!prev && interventions.some((t) => t >= lastStampOf(prev) && t <= w2.createdAt);
|
|
237047
|
+
const upstreamRoundBetween = (prev, w2) => {
|
|
237048
|
+
if (!prev) return false;
|
|
237049
|
+
const ancestors = ancestorsOf(nodeId);
|
|
237050
|
+
return snap.works.some((u) => u.lane !== "reply" && ancestors.has(u.nodeId) && u.createdAt > prev.createdAt && u.createdAt <= w2.createdAt);
|
|
237051
|
+
};
|
|
236610
237052
|
const node2 = nodeById.get(nodeId);
|
|
236611
237053
|
const nodeCancelledAt = node2?.cancelledAt ?? null;
|
|
236612
237054
|
const name = nodeName(nodeId);
|
|
@@ -236618,17 +237060,20 @@ function buildWorkorderActivity(input) {
|
|
|
236618
237060
|
const st = statusOf2(w2);
|
|
236619
237061
|
const nextStart = nextStartOf.get(w2.id) ?? null;
|
|
236620
237062
|
const interrupt = interrupts.find((t) => t.at >= w2.createdAt && (!nextStart || t.at < nextStart));
|
|
237063
|
+
const roundEndedAt = w2.endedAt ?? w2.deadAt ?? w2.cancelledAt;
|
|
237064
|
+
const raisedHere = !w2.conclusion && !interrupt ? (backpressureRaisedBy.get(nodeId) ?? []).filter((i) => i.createdAt >= w2.createdAt && (!nextStart || i.createdAt < nextStart) && (!roundEndedAt || i.createdAt <= roundEndedAt)) : [];
|
|
237065
|
+
const halted = !!interrupt || raisedHere.length > 0;
|
|
236621
237066
|
const tripsHere = trips.filter((t) => t.at >= w2.createdAt && (!nextStart || t.at < nextStart));
|
|
236622
237067
|
const removedHere = !!nodeCancelledAt && nodeCancelledAt >= w2.createdAt && (!next || nodeCancelledAt < next.createdAt);
|
|
236623
237068
|
const reassigned = !!next && next.assigneeActorId !== w2.assigneeActorId;
|
|
236624
237069
|
const killedByPlan = !!(w2.deadAt || w2.cancelledAt) && !!next && (reassigned || (next.nodeVersion ?? 0) > (w2.nodeVersion ?? 0));
|
|
236625
237070
|
const killedAtOfRound = w2.deadAt ?? w2.cancelledAt;
|
|
236626
|
-
const supersededBy = !w2.conclusion && !
|
|
236627
|
-
const failedRound = !w2.conclusion && !
|
|
237071
|
+
const supersededBy = !w2.conclusion && !halted && !removedHere && !killedByPlan && killedAtOfRound && next && !killedByWorkorderPause(w2, killedAtOfRound) ? supersedingUpstreamVersion(nodeId, w2, killedAtOfRound, next) : void 0;
|
|
237072
|
+
const failedRound = !w2.conclusion && !halted && !removedHere && !killedByPlan && !supersededBy && (!!w2.deadAt || !!w2.cancelledAt || st === "failed" || st === "retry" || noOutputRound(w2));
|
|
236628
237073
|
const foldableFailure = failedRound && !(killedAtOfRound && killedByWorkorderPause(w2, killedAtOfRound));
|
|
236629
|
-
const ackedRound = st === "success" && !!w2.upstreamAck && !w2.conclusion && artifacts.length === 0 && !
|
|
236630
|
-
const held = !w2.conclusion && !
|
|
236631
|
-
const handedOverRound = !w2.conclusion && !
|
|
237074
|
+
const ackedRound = st === "success" && !!w2.upstreamAck && !w2.conclusion && artifacts.length === 0 && !halted && !removedHere && !killedByPlan && !supersededBy && !failedRound;
|
|
237075
|
+
const held = !w2.conclusion && !halted && !removedHere && !killedByPlan && !supersededBy && !failedRound && !ackedRound ? holdOf2(w2) : void 0;
|
|
237076
|
+
const handedOverRound = !w2.conclusion && !halted && !removedHere && !killedByPlan && !supersededBy && !failedRound && !held && !ackedRound && st === "success" && !!w2.endedAt && !!next;
|
|
236632
237077
|
const refiredByFuse = tripsHere.some((t) => t.kind === "output_stall");
|
|
236633
237078
|
const brokenByHuman = humanBetween(works[idx - 1], w2) && !refiredByFuse;
|
|
236634
237079
|
if (foldableFailure && fold2 && !brokenByHuman) {
|
|
@@ -236641,7 +237086,7 @@ function buildWorkorderActivity(input) {
|
|
|
236641
237086
|
if (tripsHere.length) fold2.stopLossTrips = [...fold2.stopLossTrips ?? [], ...tripsHere];
|
|
236642
237087
|
continue;
|
|
236643
237088
|
}
|
|
236644
|
-
const absorb2 = fold2 && !brokenByHuman && !!w2.conclusion && fold2.executorId === w2.assigneeActorId ? fold2 : null;
|
|
237089
|
+
const absorb2 = fold2 && !brokenByHuman && !!w2.conclusion && fold2.executorId === w2.assigneeActorId && !upstreamRoundBetween(works[idx - 1], w2) ? fold2 : null;
|
|
236645
237090
|
fold2 = null;
|
|
236646
237091
|
if (handedOverRound && handoverFold && handoverFold.executorId === w2.assigneeActorId) {
|
|
236647
237092
|
handoverFold.traceWorkIds.push(w2.id);
|
|
@@ -236676,6 +237121,7 @@ function buildWorkorderActivity(input) {
|
|
|
236676
237121
|
}
|
|
236677
237122
|
executionCards.push(card2);
|
|
236678
237123
|
cardOfWork.set(w2.id, card2);
|
|
237124
|
+
if (isHumanActorId(card2.executorId) && backpressureDriving.has(w2.id)) card2.humanTrace = true;
|
|
236679
237125
|
if (w2.conclusion) {
|
|
236680
237126
|
card2.phase = "done";
|
|
236681
237127
|
if (rootBriefNodeIds.has(nodeId)) {
|
|
@@ -236691,6 +237137,10 @@ function buildWorkorderActivity(input) {
|
|
|
236691
237137
|
card2.status = awaits ? ACTIVITY_COPY.doneAwaitingReview(name) : ACTIVITY_COPY.done(name);
|
|
236692
237138
|
}
|
|
236693
237139
|
}
|
|
237140
|
+
const bpRaisers = backpressureRaisersOf(w2.id);
|
|
237141
|
+
if (bpRaisers && (card2.status === ACTIVITY_COPY.done(name) || card2.status === ACTIVITY_COPY.goalConfirmed || card2.status === ACTIVITY_COPY.goalRevised)) {
|
|
237142
|
+
card2.status = ACTIVITY_COPY.backpressureAddressed(bpRaisers, backpressureTargetName(nodeId));
|
|
237143
|
+
}
|
|
236694
237144
|
} else if (interrupt) {
|
|
236695
237145
|
card2.phase = "stuck";
|
|
236696
237146
|
card2.segmentOpen = false;
|
|
@@ -236699,6 +237149,18 @@ function buildWorkorderActivity(input) {
|
|
|
236699
237149
|
card2.actions = [{ kind: "open_thread", label: BUTTON.view, target: gapThreadSessionId(interrupt.authorId), variant: "quiet" }];
|
|
236700
237150
|
}
|
|
236701
237151
|
if (interrupt.at > card2.updatedAt) card2.updatedAt = interrupt.at;
|
|
237152
|
+
} else if (raisedHere.length) {
|
|
237153
|
+
card2.phase = "stuck";
|
|
237154
|
+
card2.segmentOpen = false;
|
|
237155
|
+
card2.awaitingHuman = false;
|
|
237156
|
+
const upstreams = [...new Set(raisedHere.map((i) => i.aboutNodeId))];
|
|
237157
|
+
const targets = upstreams.map(backpressureTargetName);
|
|
237158
|
+
const owners = [...new Set(upstreams.map((u) => nameOf2(backpressureOwnerOf(u))))];
|
|
237159
|
+
card2.status = artifacts.length ? ACTIVITY_COPY.backpressureAfterStage(name, targets, owners) : ACTIVITY_COPY.backpressure(nameOf2(card2.executorId), targets, owners);
|
|
237160
|
+
for (const i of raisedHere) {
|
|
237161
|
+
backpressureOnRaiserCard.add(i.id);
|
|
237162
|
+
if (i.createdAt > card2.updatedAt) card2.updatedAt = i.createdAt;
|
|
237163
|
+
}
|
|
236702
237164
|
} else if (supersededBy) {
|
|
236703
237165
|
card2.phase = "stuck";
|
|
236704
237166
|
card2.segmentOpen = false;
|
|
@@ -236861,7 +237323,7 @@ function buildWorkorderActivity(input) {
|
|
|
236861
237323
|
const forcedBy = str5(reasons.find((r) => r.kind === "forced")?.actorId);
|
|
236862
237324
|
const parentWorkId = str5(workById.get(workId)?.parentWorkId);
|
|
236863
237325
|
const reworkOfRejected = !!parentWorkId && workById.get(parentWorkId)?.acceptanceState === "rejected";
|
|
236864
|
-
const status = reasonKinds.has("rework") || reworkOfRejected ? ACTIVITY_COPY.reworking(nodeName(nodeId)) : reasonKinds.has("resumed") ? ACTIVITY_COPY.resumed(nameOf2(d.executorId), nodeName(nodeId)) : reasonKinds.has("spec_changed") ? ACTIVITY_COPY.specChanged(nodeName(nodeId)) : reasonKinds.has("issue") ? ACTIVITY_COPY.issueDriven(nodeName(nodeId)) : forcedBy ? ACTIVITY_COPY.forcedRerun(nameOf2(forcedBy), nodeName(nodeId)) : ACTIVITY_COPY.working(nodeName(nodeId));
|
|
237326
|
+
const status = reasonKinds.has("rework") || reworkOfRejected ? ACTIVITY_COPY.reworking(nodeName(nodeId)) : reasonKinds.has("resumed") ? ACTIVITY_COPY.resumed(nameOf2(d.executorId), nodeName(nodeId)) : reasonKinds.has("spec_changed") ? ACTIVITY_COPY.specChanged(nodeName(nodeId)) : reasonKinds.has("issue") ? backpressureRaisersOf(workId) ? ACTIVITY_COPY.backpressureInProgress(backpressureRaisersOf(workId), backpressureTargetName(nodeId)) : ACTIVITY_COPY.issueDriven(nodeName(nodeId)) : forcedBy ? ACTIVITY_COPY.forcedRerun(nameOf2(forcedBy), nodeName(nodeId)) : ACTIVITY_COPY.working(nodeName(nodeId));
|
|
236865
237327
|
for (const r of reasons) {
|
|
236866
237328
|
if (r.kind !== "issue") continue;
|
|
236867
237329
|
const issueId = str5(r.issueId);
|
|
@@ -236979,6 +237441,7 @@ function buildWorkorderActivity(input) {
|
|
|
236979
237441
|
const raisedFrom = str5(ev.raisedByNodeId);
|
|
236980
237442
|
const isBackpressure = !isEscalation && !isGap && !!raisedFrom && raisedFrom !== nodeId;
|
|
236981
237443
|
if (isBackpressure) backpressureIssueIds.add(issueId);
|
|
237444
|
+
if (isBackpressure && backpressureOnRaiserCard.has(issueId)) break;
|
|
236982
237445
|
const body2 = str5(ev.body) ?? "";
|
|
236983
237446
|
if (isEscalation) {
|
|
236984
237447
|
const linkedGapId = str5(ev.gapId);
|
|
@@ -237033,8 +237496,8 @@ function buildWorkorderActivity(input) {
|
|
|
237033
237496
|
...isBackpressure ? { segmentOpen: false, awaitingHuman: false } : {},
|
|
237034
237497
|
status: isBackpressure ? ACTIVITY_COPY.backpressure(
|
|
237035
237498
|
nameOf2(authorId),
|
|
237036
|
-
|
|
237037
|
-
nameOf2((nodeId ? nodeById.get(nodeId)?.assigneeActorId : void 0) ?? ownerId)
|
|
237499
|
+
[backpressureTargetName(nodeId)],
|
|
237500
|
+
[nameOf2((nodeId ? nodeById.get(nodeId)?.assigneeActorId : void 0) ?? ownerId)]
|
|
237038
237501
|
) : ACTIVITY_COPY.commentRaised(nameOf2(authorId), nameOf2(commentTargetId ?? ownerId), nodeName(nodeId)),
|
|
237039
237502
|
/* **正文一律不上卡**:缺口去缺口线、回压去产物批注、留言去留言线。
|
|
237040
237503
|
此前只有缺口/回压被排除,留言仍是「正文当小状态 + 展开区再印一遍」,
|
|
@@ -237368,7 +237831,7 @@ function buildWorkorderActivity(input) {
|
|
|
237368
237831
|
card2.phaseLabel = PHASE_LABEL.escalationPending;
|
|
237369
237832
|
card2.segmentOpen = true;
|
|
237370
237833
|
card2.awaitingHuman = true;
|
|
237371
|
-
card2.status = ACTIVITY_COPY.backpressureAwaitingOwner(nameOf2(card2.executorId),
|
|
237834
|
+
card2.status = ACTIVITY_COPY.backpressureAwaitingOwner(nameOf2(card2.executorId), backpressureTargetName(card2.nodeId));
|
|
237372
237835
|
card2.actions = [{ kind: "open_issue", label: BUTTON.handle, target: issueId, variant: "primary" }];
|
|
237373
237836
|
}
|
|
237374
237837
|
for (const card2 of executionCards) {
|
|
@@ -237571,7 +238034,7 @@ function buildWorkorderActivity(input) {
|
|
|
237571
238034
|
artifacts: d.artifacts,
|
|
237572
238035
|
actions: d.actions,
|
|
237573
238036
|
...traced && d.traceAvailable ? { traceAvailable: true } : {},
|
|
237574
|
-
...d.traceWorkIds?.length ? { traceWorkIds: d.traceWorkIds, ...traced ? { traceAvailable: true } : {} } : {},
|
|
238037
|
+
...d.traceWorkIds?.length ? { traceWorkIds: d.traceWorkIds, ...traced || d.humanTrace ? { traceAvailable: true } : {} } : {},
|
|
237575
238038
|
.../* @__PURE__ */ ((r) => r ? { runId: r, traceAvailable: true } : {})(traced ? runIdOfCard(d) : void 0)
|
|
237576
238039
|
};
|
|
237577
238040
|
});
|
|
@@ -237828,6 +238291,7 @@ var init_activity2 = __esm({
|
|
|
237828
238291
|
heldByContinuation: (node2) => `\u300A${node2}\u300B\u5DF2\u4EA4\u4ED8\u9636\u6BB5\u6210\u679C\uFF0C\u672C\u6279\u7EED\u8DD1\u989D\u5EA6\u5DF2\u7528\u5B8C\uFF0C\u7B49\u5F85\u6279\u51C6\u7EE7\u7EED\u3002`,
|
|
237829
238292
|
heldByContinuationDenied: (node2) => `\u300A${node2}\u300B\u5DF2\u4EA4\u4ED8\u9636\u6BB5\u6210\u679C\uFF0C\u7EED\u8DD1\u7533\u8BF7\u672A\u83B7\u6279\u51C6\uFF0C\u8282\u70B9\u5DF2\u6682\u505C\uFF0C\u7B49\u5F85\u653E\u884C\u3002`,
|
|
237830
238293
|
heldByWorkorderPause: (node2) => `\u300A${node2}\u300B\u5DF2\u4EA4\u4ED8\u9636\u6BB5\u6210\u679C\uFF0C\u4EFB\u52A1\u5DF2\u6682\u505C\uFF0C\u7B49\u5F85\u6062\u590D\u3002`,
|
|
238294
|
+
/** 只剩「交完稿、这一轮结束之后才补提」的那一档;同一轮里提的见 {@link ACTIVITY_COPY.backpressureAfterStage}(ADR 0623 补章)。 */
|
|
237831
238295
|
heldByBackpressure: (node2, upstreams) => `\u300A${node2}\u300B\u5DF2\u4EA4\u4ED8\uFF0C\u7B49\u5F85${upstreams.map((u) => `\u300A${u}\u300B`).join("\u3001")}\u5904\u7406\u4FEE\u6539\u8981\u6C42\u540E\u518D\u6536\u53E3\u3002`,
|
|
237832
238296
|
/** `works.status=retry`:这一轮没跑成,等引擎重派。谁按的重试由 `plan.node_retry` 补进这句。 */
|
|
237833
238297
|
awaitingRedispatch: (executor, node2) => `${executor} \u8FD9\u4E00\u8F6E\u6CA1\u8DD1\u6210\u300A${node2}\u300B\uFF0C\u7B49\u5F85\u91CD\u6D3E\u3002`,
|
|
@@ -237880,8 +238344,27 @@ var init_activity2 = __esm({
|
|
|
237880
238344
|
(「{X} 遇到处理不了的问题,需要 @{Y} 的协助」)——**别在别处复用**:系统代开的两种止损
|
|
237881
238345
|
上报根本没有人「开口」,套这句话是假话(生产上它已经把 `actor:system` 渲染成了句子的主语)。
|
|
237882
238346
|
①「缺口卡」也删掉(F4):它和执行卡挂的是同一段运行、同一份轨迹,点哪张打开的都一样。 */
|
|
237883
|
-
/**
|
|
237884
|
-
|
|
238347
|
+
/**
|
|
238348
|
+
* 回压(下游对上游提修改要求)——发起人 2026-09-08 认可的措辞。
|
|
238349
|
+
*
|
|
238350
|
+
* 2026-09-23 起它是**提出方那一轮执行卡的结局句**(奕璇定,与缺口 F4 同一做法):提要求这件事就发生在
|
|
238351
|
+
* 那一轮里,不再单独出一张 `issue:` 卡。同一轮对几个上游提了要求时并成一句(《A》、《B》 / @X、@Y)。
|
|
238352
|
+
* 🚨 **之后一个字不改**:要求关掉了也不翻署名、不改写成「已基于…更新了一版」——那是被要求方那张卡的事。
|
|
238353
|
+
*/
|
|
238354
|
+
backpressure: (raiser, upstreams, owners) => `${raiser} \u5BF9${upstreams.map((u) => `\u300A${u}\u300B`).join("\u3001")}\u63D0\u51FA\u4FEE\u6539\u8981\u6C42\uFF0C\u9700\u8981 ${owners.map((o) => `@${o}`).join("\u3001")} \u5904\u7406\u3002`,
|
|
238355
|
+
/**
|
|
238356
|
+
* 同上,但提出方**这一轮先交了阶段成果**(propose 了、没 conclude)、同一轮又提了修改要求(奕璇 2026-09-23 定,
|
|
238357
|
+
* ADR 0623 补章):此前这一档出两张卡——自己那轮「已交付,等待《X》处理修改要求后再收口」+ 一张 `issue:` 回压卡。
|
|
238358
|
+
* 合成这一句:「交了什么」由卡上 / 轨迹里的交付物说,句子说「停在哪、等谁」。之后同样一个字不改。
|
|
238359
|
+
*/
|
|
238360
|
+
backpressureAfterStage: (node2, upstreams, owners) => `\u300A${node2}\u300B\u5DF2\u63D0\u4EA4\u9636\u6BB5\u6210\u679C\uFF0C\u5BF9${upstreams.map((u) => `\u300A${u}\u300B`).join("\u3001")}\u63D0\u51FA\u4FEE\u6539\u8981\u6C42\uFF0C\u9700\u8981 ${owners.map((o) => `@${o}`).join("\u3001")} \u5904\u7406\u3002`,
|
|
238361
|
+
/** 被要求方是 agent、正在按修改要求改的那一轮(取代通用的「正在根据反馈调整」:说清是谁提的)。 */
|
|
238362
|
+
backpressureInProgress: (raisers, node2) => `\u6B63\u5728\u6839\u636E ${raisers} \u7684\u4FEE\u6539\u8981\u6C42\u8C03\u6574\u300A${node2}\u300B\u3002`,
|
|
238363
|
+
/**
|
|
238364
|
+
* 被要求方按修改要求交出了新一版(agent / 真人同一句)。取代「《X》已完成」「已修订目标」——
|
|
238365
|
+
* 此前同一件事还另有一张回压卡收口成「{X} 已基于 {Z} 的留言更新了一版」,一件事三张卡。
|
|
238366
|
+
*/
|
|
238367
|
+
backpressureAddressed: (raisers, node2) => `\u5DF2\u6309 ${raisers} \u7684\u4FEE\u6539\u8981\u6C42\u66F4\u65B0\u300A${node2}\u300B\u3002`,
|
|
237885
238368
|
/**
|
|
237886
238369
|
* 被回压节点的负责人是**真人**时,系统为他开的那一轮(奕璇 2026-09-22 定):这一轮不会自己跑,
|
|
237887
238370
|
* 是在等他动手——不能再说「正在根据反馈调整」(`issueDriven`),那句会让一张没人在动的卡挂成「进行中」。
|
|
@@ -238040,6 +238523,26 @@ function buildWorkorderActivityTrace(input) {
|
|
|
238040
238523
|
if (!briefing) continue;
|
|
238041
238524
|
firstBriefing ??= briefing;
|
|
238042
238525
|
const sources = sourcesOfWork(work, input, briefing);
|
|
238526
|
+
const humanBackpressureRound = isHumanActorId(work.assigneeActorId) && sources.some((src) => {
|
|
238527
|
+
const issue2 = src.kind === "comment" ? snap.issues.find((i) => i.id === src.issueId) : void 0;
|
|
238528
|
+
return !!issue2 && isBlockingBackpressure(issue2);
|
|
238529
|
+
});
|
|
238530
|
+
if (humanBackpressureRound) {
|
|
238531
|
+
const before = previousVersionOf(work, snap);
|
|
238532
|
+
works.push({
|
|
238533
|
+
workId,
|
|
238534
|
+
at: work.createdAt,
|
|
238535
|
+
nodeTitle: briefing.nodeTitle,
|
|
238536
|
+
...briefing.spec ? { spec: briefing.spec } : {},
|
|
238537
|
+
sources,
|
|
238538
|
+
attempts: [],
|
|
238539
|
+
artifacts: [
|
|
238540
|
+
...before ? artifactsOfWork(before, input).map((a) => ({ ...a, name: `${a.name}\uFF08\u6539\u524D\uFF09` })) : [],
|
|
238541
|
+
...artifactsOfWork(work, input).map((a) => ({ ...a, name: `${a.name}\uFF08\u6539\u540E\uFF09` }))
|
|
238542
|
+
]
|
|
238543
|
+
});
|
|
238544
|
+
continue;
|
|
238545
|
+
}
|
|
238043
238546
|
const artifacts = single.attempts.at(-1)?.artifacts ?? artifactsOfWork(work, input);
|
|
238044
238547
|
works.push({
|
|
238045
238548
|
workId,
|
|
@@ -238113,6 +238616,13 @@ function sourcesOfWork(work, input, briefing) {
|
|
|
238113
238616
|
...briefing.spec ? { content: briefing.spec } : {}
|
|
238114
238617
|
}];
|
|
238115
238618
|
}
|
|
238619
|
+
function previousVersionOf(work, snap) {
|
|
238620
|
+
const delivered = new Set(snap.artifacts.map((a) => a.workId));
|
|
238621
|
+
const parentId = work.parentWorkId;
|
|
238622
|
+
const parent = parentId ? snap.works.find((w2) => w2.id === parentId && delivered.has(w2.id)) : void 0;
|
|
238623
|
+
if (parent) return parent;
|
|
238624
|
+
return snap.works.filter((w2) => w2.nodeId === work.nodeId && w2.id !== work.id && w2.createdAt < work.createdAt && delivered.has(w2.id)).sort((a, b2) => a.createdAt.localeCompare(b2.createdAt) || a.id.localeCompare(b2.id)).at(-1);
|
|
238625
|
+
}
|
|
238116
238626
|
function artifactsOfWork(work, input) {
|
|
238117
238627
|
const snap = input.snap;
|
|
238118
238628
|
const workId = work.id;
|
|
@@ -238271,6 +238781,7 @@ var init_activity_trace = __esm({
|
|
|
238271
238781
|
"use strict";
|
|
238272
238782
|
init_src6();
|
|
238273
238783
|
init_review_activity();
|
|
238784
|
+
init_src();
|
|
238274
238785
|
init_activity2();
|
|
238275
238786
|
init_workorder_manager();
|
|
238276
238787
|
init_src7();
|
|
@@ -239182,11 +239693,11 @@ function fromRow(row) {
|
|
|
239182
239693
|
for (const [k2, v2] of opt) if (v2 !== void 0 && v2 !== null) r[k2] = v2;
|
|
239183
239694
|
return r;
|
|
239184
239695
|
}
|
|
239185
|
-
var
|
|
239696
|
+
var import_node_crypto57, import_node_fs16, DEFAULT_PAGE, MAX_PAGE, pageSize, MemoryNotificationStore, ident3, iso2, str2, PostgresNotificationStore;
|
|
239186
239697
|
var init_notification_store = __esm({
|
|
239187
239698
|
"../server/src/domains/collab/notification-store.ts"() {
|
|
239188
239699
|
"use strict";
|
|
239189
|
-
|
|
239700
|
+
import_node_crypto57 = require("node:crypto");
|
|
239190
239701
|
import_node_fs16 = __toESM(require("node:fs"), 1);
|
|
239191
239702
|
DEFAULT_PAGE = 50;
|
|
239192
239703
|
MAX_PAGE = 200;
|
|
@@ -239219,7 +239730,7 @@ var init_notification_store = __esm({
|
|
|
239219
239730
|
async insert(n) {
|
|
239220
239731
|
const existing = this.findLive(n.recipient, n.sourceKey, n.category);
|
|
239221
239732
|
if (existing) return existing;
|
|
239222
|
-
const row = { ...n, id: `ntf:${(0,
|
|
239733
|
+
const row = { ...n, id: `ntf:${(0, import_node_crypto57.randomUUID)()}`, updatedAt: n.enteredAt };
|
|
239223
239734
|
this.rows.set(row.id, row);
|
|
239224
239735
|
this.save();
|
|
239225
239736
|
return row;
|
|
@@ -239352,7 +239863,7 @@ var init_notification_store = __esm({
|
|
|
239352
239863
|
return new _PostgresNotificationStore(sql, schema);
|
|
239353
239864
|
}
|
|
239354
239865
|
async insert(n) {
|
|
239355
|
-
const id = `ntf:${(0,
|
|
239866
|
+
const id = `ntf:${(0, import_node_crypto57.randomUUID)()}`;
|
|
239356
239867
|
const r = await this.sql.query(
|
|
239357
239868
|
`INSERT INTO ${this.t} (id, recipient, category, source_key, kind, workorder_id, node_id, card_id, actor_id,
|
|
239358
239869
|
title, workspace_title, entered_at, updated_at, status, read_at, item)
|
|
@@ -240481,13 +240992,13 @@ function nameKey(name) {
|
|
|
240481
240992
|
function cleanName(name) {
|
|
240482
240993
|
return name.trim().replace(/\s+/g, " ");
|
|
240483
240994
|
}
|
|
240484
|
-
var import_node_fs17, import_node_path21,
|
|
240995
|
+
var import_node_fs17, import_node_path21, import_node_crypto58, SEP, keyOf, prefixOf, MemoryWorkorderTagStore, FileWorkorderTagStore;
|
|
240485
240996
|
var init_tags = __esm({
|
|
240486
240997
|
"../server/src/domains/collab/tags.ts"() {
|
|
240487
240998
|
"use strict";
|
|
240488
240999
|
import_node_fs17 = __toESM(require("node:fs"), 1);
|
|
240489
241000
|
import_node_path21 = __toESM(require("node:path"), 1);
|
|
240490
|
-
|
|
241001
|
+
import_node_crypto58 = __toESM(require("node:crypto"), 1);
|
|
240491
241002
|
SEP = "::";
|
|
240492
241003
|
keyOf = (companyId, id) => `${companyId}${SEP}${id}`;
|
|
240493
241004
|
prefixOf = (companyId) => `${companyId}${SEP}`;
|
|
@@ -240505,7 +241016,7 @@ var init_tags = __esm({
|
|
|
240505
241016
|
if (!name) return null;
|
|
240506
241017
|
if (this.entries(companyId).some((t) => nameKey(t.name) === nameKey(name))) return null;
|
|
240507
241018
|
const tag = {
|
|
240508
|
-
id: `tag-${
|
|
241019
|
+
id: `tag-${import_node_crypto58.default.randomBytes(6).toString("hex")}`,
|
|
240509
241020
|
name,
|
|
240510
241021
|
...input.color?.trim() ? { color: input.color.trim() } : {},
|
|
240511
241022
|
...input.description?.trim() ? { description: input.description.trim() } : {}
|
|
@@ -241894,11 +242405,11 @@ async function isEmployedElsewhere(store, companyId, accountId) {
|
|
|
241894
242405
|
const memberships = await store.listMembershipsForAccount(accountId);
|
|
241895
242406
|
return memberships.some((m2) => m2.companyId !== companyId);
|
|
241896
242407
|
}
|
|
241897
|
-
var
|
|
242408
|
+
var import_node_crypto59, ROLES, INVITABLE_ROLES, INVITATION_TTL_MS, INVITE_LINK_TTL_MS, INVITE_LINK_TOKEN_BYTES, INVITE_LINK_ROLE, SLUG_RE, CompanyError, CompaniesService;
|
|
241898
242409
|
var init_service6 = __esm({
|
|
241899
242410
|
"../server/src/domains/companies/service.ts"() {
|
|
241900
242411
|
"use strict";
|
|
241901
|
-
|
|
242412
|
+
import_node_crypto59 = require("node:crypto");
|
|
241902
242413
|
init_console_url();
|
|
241903
242414
|
ROLES = ["owner", "admin", "member"];
|
|
241904
242415
|
INVITABLE_ROLES = ["admin", "member"];
|
|
@@ -241997,9 +242508,13 @@ var init_service6 = __esm({
|
|
|
241997
242508
|
await this.store.updateCompany(id, { name });
|
|
241998
242509
|
return { ...company, name };
|
|
241999
242510
|
}
|
|
242000
|
-
/**
|
|
242511
|
+
/**
|
|
242512
|
+
* 设置/清除公司头像引用("blob:<哈希>";null = 回到默认首字母标识)。
|
|
242513
|
+
* 权限(本组织 owner/admin)由路由层 `requireOwnerOrAdmin` 强制;这里只守「组织还可用」
|
|
242514
|
+
* ——与本域其余写面同一条判据(D8.2:闸不只长在路由上),解散之后 404 COMPANY_NOT_FOUND。
|
|
242515
|
+
*/
|
|
242001
242516
|
async setAvatar(id, ref2) {
|
|
242002
|
-
const company = await this.
|
|
242517
|
+
const company = await this.requireActiveCompany(id);
|
|
242003
242518
|
await this.store.updateCompany(id, { avatar: ref2 });
|
|
242004
242519
|
const next = ref2 === null ? (({ avatar: _drop, ...rest }) => rest)(company) : { ...company, avatar: ref2 };
|
|
242005
242520
|
return next;
|
|
@@ -242013,7 +242528,7 @@ var init_service6 = __esm({
|
|
|
242013
242528
|
const existing = await this.store.getAccountByEmail(normalized4);
|
|
242014
242529
|
if (existing) return existing;
|
|
242015
242530
|
const account = {
|
|
242016
|
-
id: `actor:human:${(0,
|
|
242531
|
+
id: `actor:human:${(0, import_node_crypto59.randomUUID)()}`,
|
|
242017
242532
|
email: normalized4,
|
|
242018
242533
|
name: name ?? normalized4,
|
|
242019
242534
|
status: "active"
|
|
@@ -242321,8 +242836,8 @@ var init_service6 = __esm({
|
|
|
242321
242836
|
const target = await this.store.getMember(companyId, accountId);
|
|
242322
242837
|
if (!target) throw new CompanyError(404, "NOT_FOUND", `\u4E0D\u662F\u8BE5\u516C\u53F8\u6210\u5458\uFF1A${accountId}`);
|
|
242323
242838
|
if (target.role === "owner") throw this.ownerProtected();
|
|
242324
|
-
const res = await this.store.
|
|
242325
|
-
if (res.ok) return res.member;
|
|
242839
|
+
const res = await this.store.removeMemberAndReleaseOwnedAgents(companyId, accountId, this.now());
|
|
242840
|
+
if (res.ok) return { member: res.member, releasedAgents: res.releasedAgents };
|
|
242326
242841
|
if (res.reason === "not_found") throw new CompanyError(404, "NOT_FOUND", `\u4E0D\u662F\u8BE5\u516C\u53F8\u6210\u5458\uFF1A${accountId}`);
|
|
242327
242842
|
throw this.ownerProtected();
|
|
242328
242843
|
}
|
|
@@ -242411,7 +242926,7 @@ var init_service6 = __esm({
|
|
|
242411
242926
|
}
|
|
242412
242927
|
const nowMs = Date.parse(this.now());
|
|
242413
242928
|
const invitation = {
|
|
242414
|
-
id: `invitation:${(0,
|
|
242929
|
+
id: `invitation:${(0, import_node_crypto59.randomUUID)()}`,
|
|
242415
242930
|
companyId,
|
|
242416
242931
|
email: mail,
|
|
242417
242932
|
role,
|
|
@@ -242542,7 +243057,7 @@ var init_service6 = __esm({
|
|
|
242542
243057
|
const nowMs = Date.parse(this.now());
|
|
242543
243058
|
const link = {
|
|
242544
243059
|
companyId,
|
|
242545
|
-
token: (0,
|
|
243060
|
+
token: (0, import_node_crypto59.randomBytes)(INVITE_LINK_TOKEN_BYTES).toString("base64url"),
|
|
242546
243061
|
role: INVITE_LINK_ROLE,
|
|
242547
243062
|
createdAt: new Date(nowMs).toISOString(),
|
|
242548
243063
|
expiresAt: new Date(nowMs + INVITE_LINK_TTL_MS).toISOString(),
|
|
@@ -242599,7 +243114,7 @@ var init_service6 = __esm({
|
|
|
242599
243114
|
const reusable = existing.find((inv) => !this.isExpired(inv));
|
|
242600
243115
|
if (reusable) return reusable;
|
|
242601
243116
|
const invitation = {
|
|
242602
|
-
id: `invitation:${(0,
|
|
243117
|
+
id: `invitation:${(0, import_node_crypto59.randomUUID)()}`,
|
|
242603
243118
|
companyId: link.companyId,
|
|
242604
243119
|
email: mail,
|
|
242605
243120
|
role: link.role,
|
|
@@ -242645,9 +243160,9 @@ var init_service6 = __esm({
|
|
|
242645
243160
|
* 登录身份查自己那条 membership;不是成员 → 404。
|
|
242646
243161
|
*/
|
|
242647
243162
|
async completeMemberOnboarding(companyId, accountId) {
|
|
242648
|
-
await this.requireCompany(companyId);
|
|
242649
243163
|
const member = await this.store.getMember(companyId, accountId);
|
|
242650
243164
|
if (!member) throw new CompanyError(404, "NOT_FOUND", `\u4E0D\u662F\u8BE5\u516C\u53F8\u6210\u5458\uFF1A${accountId}`);
|
|
243165
|
+
await this.requireActiveCompany(companyId);
|
|
242651
243166
|
if (member.onboardingCompletedAt) return member;
|
|
242652
243167
|
const next = { ...member, onboardingCompletedAt: this.now() };
|
|
242653
243168
|
await this.store.upsertMember(next);
|
|
@@ -242671,9 +243186,9 @@ var init_service6 = __esm({
|
|
|
242671
243186
|
async setMemberOnboardingStep(companyId, accountId, step) {
|
|
242672
243187
|
const trimmed = step?.trim();
|
|
242673
243188
|
if (!trimmed) throw new CompanyError(400, "BAD_REQUEST", "step \u4E0D\u80FD\u4E3A\u7A7A");
|
|
242674
|
-
await this.requireCompany(companyId);
|
|
242675
243189
|
const member = await this.store.getMember(companyId, accountId);
|
|
242676
243190
|
if (!member) throw new CompanyError(404, "NOT_FOUND", `\u4E0D\u662F\u8BE5\u516C\u53F8\u6210\u5458\uFF1A${accountId}`);
|
|
243191
|
+
await this.requireActiveCompany(companyId);
|
|
242677
243192
|
const next = { ...member, onboardingStep: trimmed };
|
|
242678
243193
|
await this.store.upsertMember(next);
|
|
242679
243194
|
return next;
|
|
@@ -242833,11 +243348,11 @@ var init_service6 = __esm({
|
|
|
242833
243348
|
});
|
|
242834
243349
|
|
|
242835
243350
|
// ../server/src/domains/companies/offboarding.ts
|
|
242836
|
-
var
|
|
243351
|
+
var import_node_crypto60, OWNER_PROTECTED_MESSAGE, MemberOffboardingService;
|
|
242837
243352
|
var init_offboarding = __esm({
|
|
242838
243353
|
"../server/src/domains/companies/offboarding.ts"() {
|
|
242839
243354
|
"use strict";
|
|
242840
|
-
|
|
243355
|
+
import_node_crypto60 = require("node:crypto");
|
|
242841
243356
|
init_service6();
|
|
242842
243357
|
OWNER_PROTECTED_MESSAGE = "\u7EC4\u7EC7\u7BA1\u7406\u5458\u4E0D\u53EF\u88AB\u79FB\u9664\uFF0C\u53EA\u80FD\u7531\u672C\u4EBA\u8F6C\u4EA4\u6216\u89E3\u6563\u7EC4\u7EC7";
|
|
242843
243358
|
MemberOffboardingService = class {
|
|
@@ -242846,12 +243361,14 @@ var init_offboarding = __esm({
|
|
|
242846
243361
|
listInFlight;
|
|
242847
243362
|
transferAssignment;
|
|
242848
243363
|
disableActor;
|
|
243364
|
+
restoreActor;
|
|
242849
243365
|
constructor(opts) {
|
|
242850
243366
|
this.store = opts.store;
|
|
242851
243367
|
this.now = opts.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
242852
243368
|
this.listInFlight = opts.listInFlightAssignments;
|
|
242853
243369
|
this.transferAssignment = opts.transferAssignment;
|
|
242854
243370
|
this.disableActor = opts.disableActor;
|
|
243371
|
+
this.restoreActor = opts.restoreActor;
|
|
242855
243372
|
}
|
|
242856
243373
|
/** 该成员是不是公司最后一个 owner(最后一个 owner 立即阻断,先于任何交接讨论)。 */
|
|
242857
243374
|
async isLastOwner(companyId, accountId) {
|
|
@@ -242877,14 +243394,13 @@ var init_offboarding = __esm({
|
|
|
242877
243394
|
*/
|
|
242878
243395
|
async blockersForRemoval(companyId, accountId) {
|
|
242879
243396
|
const blockers = [];
|
|
242880
|
-
const
|
|
243397
|
+
const members = await this.store.listMembers(companyId);
|
|
243398
|
+
const member = members.find((m2) => m2.accountId === accountId);
|
|
242881
243399
|
if (!member) {
|
|
242882
243400
|
return [{ code: "NOT_FOUND", message: `\u4E0D\u662F\u8BE5\u516C\u53F8\u6210\u5458\uFF1A${accountId}` }];
|
|
242883
243401
|
}
|
|
242884
243402
|
if (member.role === "owner") {
|
|
242885
243403
|
blockers.push({ code: "OWNER_PROTECTED", message: OWNER_PROTECTED_MESSAGE });
|
|
242886
|
-
} else if (await this.isLastOwner(companyId, accountId)) {
|
|
242887
|
-
blockers.push({ code: "LAST_OWNER", message: "\u516C\u53F8\u81F3\u5C11\u8981\u7559 1 \u4E2A owner\uFF0C\u4E0D\u80FD\u79FB\u9664\u6700\u540E\u4E00\u4E2A owner" });
|
|
242888
243404
|
}
|
|
242889
243405
|
return blockers;
|
|
242890
243406
|
}
|
|
@@ -242913,7 +243429,7 @@ var init_offboarding = __esm({
|
|
|
242913
243429
|
const { ownedAgents, inFlight } = await this.snapshot(companyId, accountId);
|
|
242914
243430
|
const at2 = this.now();
|
|
242915
243431
|
const started = await this.store.startMemberOffboarding({
|
|
242916
|
-
operationId: `off:${(0,
|
|
243432
|
+
operationId: `off:${(0, import_node_crypto60.randomUUID)()}`,
|
|
242917
243433
|
companyId,
|
|
242918
243434
|
accountId,
|
|
242919
243435
|
initiatedBy,
|
|
@@ -242953,12 +243469,9 @@ var init_offboarding = __esm({
|
|
|
242953
243469
|
if (op.version !== expectedVersion) {
|
|
242954
243470
|
throw new CompanyError(409, "STALE_PLAN", `\u8BA1\u5212\u7248\u672C\u5DF2\u53D8\uFF08\u5F53\u524D ${op.version}\uFF0C\u4F60\u7ED9\u7684\u662F ${expectedVersion}\uFF09\uFF0C\u8BF7\u91CD\u65B0\u53D6\u8BA1\u5212`);
|
|
242955
243471
|
}
|
|
242956
|
-
const
|
|
243472
|
+
const members = await this.store.listMembers(companyId);
|
|
243473
|
+
const target = members.find((m2) => m2.accountId === accountId);
|
|
242957
243474
|
if (target?.role === "owner") throw new CompanyError(403, "OWNER_PROTECTED", OWNER_PROTECTED_MESSAGE);
|
|
242958
|
-
if (await this.isLastOwner(companyId, accountId)) {
|
|
242959
|
-
throw new CompanyError(409, "LAST_OWNER", "\u516C\u53F8\u81F3\u5C11\u8981\u7559 1 \u4E2A owner\uFF0C\u4E0D\u80FD\u79FB\u9664\u6700\u540E\u4E00\u4E2A owner");
|
|
242960
|
-
}
|
|
242961
|
-
const released = await this.releaseOwnedAgents(companyId, accountId);
|
|
242962
243475
|
const remaining = await this.blockersForRemoval(companyId, accountId);
|
|
242963
243476
|
if (remaining.length > 0) {
|
|
242964
243477
|
await this.store.updateMemberOffboardingIfVersion(
|
|
@@ -242970,7 +243483,7 @@ var init_offboarding = __esm({
|
|
|
242970
243483
|
);
|
|
242971
243484
|
throw new CompanyError(409, remaining[0].code, `\u4ECD\u6709\u672A\u4EA4\u63A5\u9879\uFF1A${remaining.map((b2) => b2.message).join("; ")}`);
|
|
242972
243485
|
}
|
|
242973
|
-
await this.applyMemberRemoval(companyId, accountId);
|
|
243486
|
+
const released = await this.applyMemberRemoval(companyId, accountId);
|
|
242974
243487
|
await this.store.updateMemberOffboardingIfVersion(
|
|
242975
243488
|
companyId,
|
|
242976
243489
|
operationId,
|
|
@@ -242981,35 +243494,63 @@ var init_offboarding = __esm({
|
|
|
242981
243494
|
return { status: "removed", transferred: [], left: released };
|
|
242982
243495
|
}
|
|
242983
243496
|
/**
|
|
242984
|
-
*
|
|
242985
|
-
*
|
|
242986
|
-
* 不清就是一个裸 FK 违例);**只清 owner**——不改状态、不撤凭证、不解绑助理(PRD v1.5);
|
|
242987
|
-
* ② 停用花名册里这个人(**还在别家公司在职就不停用**——停用打的是全局那一行);
|
|
242988
|
-
* ③ 删 human principal bridge(对 company_member 是 CASCADE,但文件/内存实现没有级联,
|
|
242989
|
-
* 显式删一次让「桥随主体走」在应用层也成立);
|
|
242990
|
-
* ④ 删成员行(走 `removeMemberIfNotLastOwner`,组织管理员那一位在这里被纵深防御挡住)。
|
|
243497
|
+
* 移除一条成员关系的**全套副作用**,三条移除路径共用(管理员移除他人 `commit`、
|
|
243498
|
+
* 本人退出组织 `DELETE …/members/me`、注销账号 `DELETE /api/accounts/me`)。
|
|
242991
243499
|
*
|
|
242992
|
-
*
|
|
242993
|
-
*
|
|
243500
|
+
* 顺序与原子性(2026-09-23 代码评审打回后重排):
|
|
243501
|
+
* ① 读一遍成员行:不存在 → 404;**已经是组织管理员 → 当场 403,一个副作用都不做**(D5.2)。
|
|
243502
|
+
* ② 停用花名册里这个人(**还在别家公司在职就不停用**——停用打的是全局那一行)。
|
|
243503
|
+
* 这一步必须在③之前:成员行一删,本公司的 scoped registry 就不再认这个 actor,
|
|
243504
|
+
* 停用会静默 no-op,人被移除了却还挂在花名册上(QA D3 修过一次的病)。
|
|
243505
|
+
* ③ **一个事务**做完控制面三件事:锁内复核目标不是组织管理员 → 清名下 agent 的负责人字段
|
|
243506
|
+
* (`digital_employee.owner` 的复合 FK 是 ON DELETE RESTRICT,不清就是裸 FK 违例;
|
|
243507
|
+
* **只清 owner**,不改状态、不撤凭证、不解绑助理,PRD v1.5)→ 删 human principal bridge
|
|
243508
|
+
* → 删成员行(`store.removeMemberAndReleaseOwnedAgents`)。
|
|
243509
|
+
* ④ ③失败(并发转交把这个人升成了组织管理员,A09)→ 把②CAS 还原回去。
|
|
242994
243510
|
*
|
|
242995
|
-
*
|
|
242996
|
-
*
|
|
243511
|
+
* **为什么③非要是一个事务**:以前①②③是「先清负责人、再停用、再删桥,最后才去拿锁删成员行」
|
|
243512
|
+
* 四段独立的写。A09 那条并发(`O` 转交给 `A1` 的同时另一位管理员删 `A1`)走到最后一步才被
|
|
243513
|
+
* `OWNER_PROTECTED` 拒——而此刻 `A1` 名下 Agent 的负责人已经被清空、桥已经被删、人已经被停用。
|
|
243514
|
+
* 请求失败了,破坏却留下了:新上任的组织管理员丢了名下全部 Agent 的归属、还从花名册上消失。
|
|
243515
|
+
* 现在控制面那三件事共一把锁(与转交锁同一组行),失败时一行都没写;跨不进这把锁的只有员工侧
|
|
243516
|
+
* 停用,用 CAS 补偿还原——「停用之后有别人写过这个 actor」就跳过,不撤销他人的合法写(QA R9)。
|
|
242997
243517
|
*/
|
|
242998
243518
|
async applyMemberRemoval(companyId, accountId) {
|
|
242999
|
-
const released = await this.releaseOwnedAgents(companyId, accountId);
|
|
243000
243519
|
const member = await this.store.getMember(companyId, accountId);
|
|
243001
|
-
if (member
|
|
243002
|
-
|
|
243520
|
+
if (!member) throw new CompanyError(404, "NOT_FOUND", `\u4E0D\u662F\u8BE5\u516C\u53F8\u6210\u5458\uFF1A${accountId}`);
|
|
243521
|
+
if (member.role === "owner") throw new CompanyError(403, "OWNER_PROTECTED", OWNER_PROTECTED_MESSAGE);
|
|
243522
|
+
let ticket = null;
|
|
243523
|
+
if (!await isEmployedElsewhere(this.store, companyId, accountId)) {
|
|
243524
|
+
ticket = await this.disableActor?.(companyId, member.actorId) ?? null;
|
|
243003
243525
|
}
|
|
243004
|
-
await this.store.
|
|
243005
|
-
|
|
243526
|
+
const removed = await this.store.removeMemberAndReleaseOwnedAgents(companyId, accountId, this.now()).catch(async (e) => {
|
|
243527
|
+
await this.compensateDisable(companyId, ticket);
|
|
243528
|
+
throw e;
|
|
243529
|
+
});
|
|
243006
243530
|
if (!removed.ok) {
|
|
243531
|
+
await this.compensateDisable(companyId, ticket);
|
|
243007
243532
|
if (removed.reason === "not_found") {
|
|
243008
243533
|
throw new CompanyError(404, "NOT_FOUND", `\u4E0D\u662F\u8BE5\u516C\u53F8\u6210\u5458\uFF1A${accountId}`);
|
|
243009
243534
|
}
|
|
243010
243535
|
throw new CompanyError(403, "OWNER_PROTECTED", OWNER_PROTECTED_MESSAGE);
|
|
243011
243536
|
}
|
|
243012
|
-
return
|
|
243537
|
+
return removed.releasedAgents;
|
|
243538
|
+
}
|
|
243539
|
+
/**
|
|
243540
|
+
* 把②那次停用还原回去。**只还原本次自己造成的那一次**:`restoreActor` 走 CAS,
|
|
243541
|
+
* 停用之后但凡有别人写过这个 actor 就跳过——留下「成员还在 + actor 已停用」这个合法终态
|
|
243542
|
+
* (与员工页 `DELETE /api/actors/:id` 的终态同构),比静默撤销他人的合法停用安全。
|
|
243543
|
+
* 补偿本身失败不改写主错误:调用方要看到的是「为什么没删成」,不是补偿的二级故障。
|
|
243544
|
+
*/
|
|
243545
|
+
async compensateDisable(companyId, ticket) {
|
|
243546
|
+
if (!ticket || !this.restoreActor) return;
|
|
243547
|
+
try {
|
|
243548
|
+
await this.restoreActor(companyId, ticket);
|
|
243549
|
+
} catch (e) {
|
|
243550
|
+
console.error(
|
|
243551
|
+
`[offboarding] restore actor ${ticket.actorId} failed after removal was rejected: ${e instanceof Error ? e.message : String(e)}`
|
|
243552
|
+
);
|
|
243553
|
+
}
|
|
243013
243554
|
}
|
|
243014
243555
|
/**
|
|
243015
243556
|
* 把该成员名下所有 agent 的负责人字段清空,返回被清的 agent id。
|
|
@@ -243098,10 +243639,18 @@ function companiesDomain(opts) {
|
|
|
243098
243639
|
}
|
|
243099
243640
|
return n;
|
|
243100
243641
|
};
|
|
243642
|
+
const requireActiveCompany = async (companyId) => {
|
|
243643
|
+
const company = await service.get(companyId);
|
|
243644
|
+
if (!company || company.status !== "active") {
|
|
243645
|
+
throw new ApiError(404, "COMPANY_NOT_FOUND", `\u7EC4\u7EC7\u4E0D\u5B58\u5728\u6216\u5DF2\u4E0D\u53EF\u7528\uFF1A${companyId}`);
|
|
243646
|
+
}
|
|
243647
|
+
};
|
|
243101
243648
|
const requireOwnerOrAdmin = async (req, companyId) => {
|
|
243102
243649
|
const me = await whoami(req);
|
|
243103
243650
|
const member = await service.getMember(companyId, me.accountId);
|
|
243104
|
-
if (!member
|
|
243651
|
+
if (!member) throw new ApiError(403, "FORBIDDEN", "\u9700\u8981\u8BE5\u516C\u53F8\u7684 owner/admin \u6743\u9650");
|
|
243652
|
+
await requireActiveCompany(companyId);
|
|
243653
|
+
if (member.role !== "owner" && member.role !== "admin") {
|
|
243105
243654
|
throw new ApiError(403, "FORBIDDEN", "\u9700\u8981\u8BE5\u516C\u53F8\u7684 owner/admin \u6743\u9650");
|
|
243106
243655
|
}
|
|
243107
243656
|
};
|
|
@@ -243109,8 +243658,16 @@ function companiesDomain(opts) {
|
|
|
243109
243658
|
const me = await whoami(req);
|
|
243110
243659
|
const member = await service.getMember(companyId, me.accountId);
|
|
243111
243660
|
if (!member) throw new ApiError(403, "NOT_A_MEMBER", "\u4E0D\u662F\u8BE5\u516C\u53F8\u6210\u5458\uFF0C\u8BBF\u95EE\u88AB\u62D2");
|
|
243661
|
+
await requireActiveCompany(companyId);
|
|
243112
243662
|
return me;
|
|
243113
243663
|
};
|
|
243664
|
+
const requireActiveSelfMember = async (req, companyId) => {
|
|
243665
|
+
const me = await whoami(req);
|
|
243666
|
+
const member = await service.getMember(companyId, me.accountId);
|
|
243667
|
+
if (!member) throw new ApiError(404, "NOT_FOUND", `\u4E0D\u662F\u8BE5\u516C\u53F8\u6210\u5458\uFF1A${me.accountId}`);
|
|
243668
|
+
await requireActiveCompany(companyId);
|
|
243669
|
+
return { me, member };
|
|
243670
|
+
};
|
|
243114
243671
|
return (router) => {
|
|
243115
243672
|
router.get("/api/companies", async (req) => {
|
|
243116
243673
|
const me = await whoami(req);
|
|
@@ -243160,13 +243717,17 @@ function companiesDomain(opts) {
|
|
|
243160
243717
|
return { status: 201, body: company };
|
|
243161
243718
|
});
|
|
243162
243719
|
router.post("/api/companies/:id/avatar", async (req) => {
|
|
243720
|
+
const cid = req.params.id;
|
|
243721
|
+
await requireOwnerOrAdmin(req, cid);
|
|
243163
243722
|
if (!blobs) throw new ApiError(501, "NOT_IMPLEMENTED", "blob \u5B58\u50A8\u672A\u63A5\u5165");
|
|
243164
243723
|
const ref2 = await storeImageBlob(blobs, req.body?.data);
|
|
243165
|
-
const company = await service.setAvatar(
|
|
243724
|
+
const company = await service.setAvatar(cid, ref2).catch(mapErr);
|
|
243166
243725
|
return { status: 201, body: { avatar: company.avatar } };
|
|
243167
243726
|
});
|
|
243168
243727
|
router.delete("/api/companies/:id/avatar", async (req) => {
|
|
243169
|
-
|
|
243728
|
+
const cid = req.params.id;
|
|
243729
|
+
await requireOwnerOrAdmin(req, cid);
|
|
243730
|
+
await service.setAvatar(cid, null).catch(mapErr);
|
|
243170
243731
|
return { status: 200, body: { ok: true } };
|
|
243171
243732
|
});
|
|
243172
243733
|
router.get("/api/companies/:id/members", async (req) => {
|
|
@@ -243176,23 +243737,23 @@ function companiesDomain(opts) {
|
|
|
243176
243737
|
return { status: 200, body: { items } };
|
|
243177
243738
|
});
|
|
243178
243739
|
router.get("/api/companies/:id/members/me", async (req) => {
|
|
243179
|
-
const
|
|
243180
|
-
const member = await service.getMember(req.params.id, me.accountId);
|
|
243181
|
-
if (!member) throw new ApiError(404, "NOT_FOUND", `\u4E0D\u662F\u8BE5\u516C\u53F8\u6210\u5458\uFF1A${me.accountId}`);
|
|
243740
|
+
const { member } = await requireActiveSelfMember(req, req.params.id);
|
|
243182
243741
|
return { status: 200, body: member };
|
|
243183
243742
|
});
|
|
243184
243743
|
router.post("/api/companies/:id/members/me/onboarding-complete", async (req) => {
|
|
243185
|
-
const
|
|
243186
|
-
const
|
|
243744
|
+
const cid = req.params.id;
|
|
243745
|
+
const { me } = await requireActiveSelfMember(req, cid);
|
|
243746
|
+
const member = await service.completeMemberOnboarding(cid, me.accountId).catch(mapErr);
|
|
243187
243747
|
return { status: 200, body: member };
|
|
243188
243748
|
});
|
|
243189
243749
|
router.post("/api/companies/:id/members/me/onboarding-step", async (req) => {
|
|
243190
|
-
const
|
|
243750
|
+
const cid = req.params.id;
|
|
243751
|
+
const { me } = await requireActiveSelfMember(req, cid);
|
|
243191
243752
|
const body2 = req.body ?? {};
|
|
243192
243753
|
if (typeof body2.step !== "string") {
|
|
243193
243754
|
throw new ApiError(400, "BAD_REQUEST", "\u7F3A\u5C11 step: string");
|
|
243194
243755
|
}
|
|
243195
|
-
const member = await service.setMemberOnboardingStep(
|
|
243756
|
+
const member = await service.setMemberOnboardingStep(cid, me.accountId, body2.step).catch(mapErr);
|
|
243196
243757
|
return { status: 200, body: member };
|
|
243197
243758
|
});
|
|
243198
243759
|
router.patch("/api/companies/:id/members/:accountId", async (req) => {
|
|
@@ -243232,7 +243793,6 @@ function companiesDomain(opts) {
|
|
|
243232
243793
|
const aid = req.params.accountId;
|
|
243233
243794
|
await requireOwnerOrAdmin(req, cid);
|
|
243234
243795
|
const member = await service.peekRemovableMember(cid, aid).catch(mapErr);
|
|
243235
|
-
if (offboarding) await offboarding.releaseOwnedAgents(cid, aid).catch(mapErr);
|
|
243236
243796
|
let actorsSvc;
|
|
243237
243797
|
let ownedDisableBefore = null;
|
|
243238
243798
|
let disableSeq = 0;
|
|
@@ -243491,18 +244051,18 @@ var init_routes6 = __esm({
|
|
|
243491
244051
|
|
|
243492
244052
|
// ../server/src/domains/companies/agent-credentials.ts
|
|
243493
244053
|
function hashAgentToken(token, secret) {
|
|
243494
|
-
return HASH_PREFIX + (0,
|
|
244054
|
+
return HASH_PREFIX + (0, import_node_crypto61.createHmac)("sha256", secret).update(`agent-token:${token}`).digest("base64url");
|
|
243495
244055
|
}
|
|
243496
244056
|
function safeEqual(a, b2) {
|
|
243497
244057
|
const ba = Buffer.from(a);
|
|
243498
244058
|
const bb = Buffer.from(b2);
|
|
243499
|
-
return ba.length === bb.length && (0,
|
|
244059
|
+
return ba.length === bb.length && (0, import_node_crypto61.timingSafeEqual)(ba, bb);
|
|
243500
244060
|
}
|
|
243501
|
-
var
|
|
244061
|
+
var import_node_crypto61, HASH_PREFIX, TOKEN_PREFIX, AgentCredentialService;
|
|
243502
244062
|
var init_agent_credentials = __esm({
|
|
243503
244063
|
"../server/src/domains/companies/agent-credentials.ts"() {
|
|
243504
244064
|
"use strict";
|
|
243505
|
-
|
|
244065
|
+
import_node_crypto61 = require("node:crypto");
|
|
243506
244066
|
init_service6();
|
|
243507
244067
|
HASH_PREFIX = "ac1$";
|
|
243508
244068
|
TOKEN_PREFIX = "oak_";
|
|
@@ -243527,7 +244087,7 @@ var init_agent_credentials = __esm({
|
|
|
243527
244087
|
if (employee.status !== "active") {
|
|
243528
244088
|
throw new CompanyError(409, "AGENT_LEFT", `\u6570\u5B57\u5458\u5DE5\u5DF2\u79BB\u5F00\uFF0C\u4E0D\u80FD\u7B7E\u53D1\u51ED\u8BC1\uFF1A${agentId}`);
|
|
243529
244089
|
}
|
|
243530
|
-
const token = `${TOKEN_PREFIX}${(0,
|
|
244090
|
+
const token = `${TOKEN_PREFIX}${(0, import_node_crypto61.randomBytes)(32).toString("base64url")}`;
|
|
243531
244091
|
const credential = {
|
|
243532
244092
|
tokenHash: hashAgentToken(token, this.secret),
|
|
243533
244093
|
companyId,
|
|
@@ -243628,9 +244188,30 @@ function createCompaniesDomain(opts) {
|
|
|
243628
244188
|
...opts.resolveActorsCtx !== void 0 ? {
|
|
243629
244189
|
// 未认领转 left 的 agent、以及 commit 移除掉的那位成员,都要把员工侧 ActorRecord
|
|
243630
244190
|
// 一并软停用——否则控制面说「已离开/已移除」、花名册还显示在岗,两个事实源当场分叉。
|
|
244191
|
+
//
|
|
244192
|
+
// 用 `disableActorIfCurrentlyActive` 而不是 `disableActor`,并把 `{before, seq}` 回给
|
|
244193
|
+
// offboarding:只有**真的把这个 actor 从 active 拉到 disabled** 的那一次调用才拿得到
|
|
244194
|
+
// 返回值,也才「拥有」这次状态变更;已被并发请求或员工页先停用的一律 ok:false,
|
|
244195
|
+
// 本次就不 own、移除失败也不补偿(QA R10 的判据,两条移除路径同一套)。
|
|
243631
244196
|
disableActor: async (companyId, actorId) => {
|
|
243632
244197
|
const ctx = await opts.resolveActorsCtx(companyId);
|
|
243633
|
-
await ctx.service.disableActorIfCurrentlyActive(actorId, "system:offboarding");
|
|
244198
|
+
const res = await ctx.service.disableActorIfCurrentlyActive(actorId, "system:offboarding");
|
|
244199
|
+
return res.ok ? { actorId, before: res.before, seq: res.seq } : null;
|
|
244200
|
+
},
|
|
244201
|
+
// 移除最终失败时的补偿:**CAS** 写回停用前那一行。`expectedSeq` 对不上(停用之后
|
|
244202
|
+
// 有任何第三方写过这个 actor)就跳过——不静默撤销他人的合法停用 / 改名(QA R9)。
|
|
244203
|
+
restoreActor: async (companyId, ticket) => {
|
|
244204
|
+
const ctx = await opts.resolveActorsCtx(companyId);
|
|
244205
|
+
const res = await ctx.service.casUpsertActor(
|
|
244206
|
+
{ ...ticket.before, status: "active" },
|
|
244207
|
+
ticket.seq,
|
|
244208
|
+
"system:offboarding"
|
|
244209
|
+
);
|
|
244210
|
+
if (!res.ok) {
|
|
244211
|
+
console.info(
|
|
244212
|
+
`[companies] restore skipped for ${ticket.actorId}: another write intervened after the disable`
|
|
244213
|
+
);
|
|
244214
|
+
}
|
|
243634
244215
|
}
|
|
243635
244216
|
} : {}
|
|
243636
244217
|
});
|
|
@@ -244018,7 +244599,7 @@ function gatewayInstanceSlug(gatewayUrl) {
|
|
|
244018
244599
|
}
|
|
244019
244600
|
function connectInstanceName(gatewayUrl, token, companyId) {
|
|
244020
244601
|
const scope2 = companyId?.trim();
|
|
244021
|
-
const suffix = scope2 ? `c${(0,
|
|
244602
|
+
const suffix = scope2 ? `c${(0, import_node_crypto62.createHash)("sha256").update(`${gatewayUrl}\0${scope2}`).digest("hex").slice(0, 10)}` : token.replace(/[^a-z0-9]/gi, "").slice(-8).toLowerCase() || "enroll";
|
|
244022
244603
|
const base = gatewayInstanceSlug(gatewayUrl);
|
|
244023
244604
|
return base.slice(0, Math.max(1, 64 - suffix.length - 1)) + "-" + suffix;
|
|
244024
244605
|
}
|
|
@@ -244347,12 +244928,12 @@ function buildNpxCmd(p2) {
|
|
|
244347
244928
|
const prefix = daemonNpmPrefix();
|
|
244348
244929
|
return `npm install -g --prefer-online --prefix ${prefix} ${DAEMON_NPM_PACKAGE}@latest && ${prefix}/bin/oasis daemon start --instance ${shellQuote(instanceName)} --server-ws ${shellQuote(p2.gatewayUrl)}${companyPart}${namePart} --pkg ${shellQuote(DAEMON_NPM_PACKAGE)} --upgrade --enroll-token ${shellQuote(p2.token)}`;
|
|
244349
244930
|
}
|
|
244350
|
-
var
|
|
244931
|
+
var import_node_crypto62;
|
|
244351
244932
|
var init_connect_script = __esm({
|
|
244352
244933
|
"../server/src/domains/nodes/connect-script.ts"() {
|
|
244353
244934
|
"use strict";
|
|
244354
244935
|
init_src();
|
|
244355
|
-
|
|
244936
|
+
import_node_crypto62 = require("node:crypto");
|
|
244356
244937
|
}
|
|
244357
244938
|
});
|
|
244358
244939
|
|
|
@@ -244812,7 +245393,7 @@ function nodesDomain(deps) {
|
|
|
244812
245393
|
if (!daemon.meta.adapters.some((kind) => QUOTA_CAPABLE_KINDS.has(kind))) {
|
|
244813
245394
|
return { ok: false, code: "no-quota-runtime", reason: "\u8FD9\u53F0\u673A\u5668\u4E0A\u6CA1\u6709\u4F1A\u4E0A\u62A5\u989D\u5EA6\u7684\u8FD0\u884C\u65F6\uFF08\u53EA\u6709 Claude Code \u548C Codex \u80FD\u67E5\u5230\u8BA2\u9605\u989D\u5EA6\uFF09" };
|
|
244814
245395
|
}
|
|
244815
|
-
const requestId = (0,
|
|
245396
|
+
const requestId = (0, import_node_crypto63.randomUUID)();
|
|
244816
245397
|
const task = new Promise((resolve12) => {
|
|
244817
245398
|
const timer = setTimeout(() => {
|
|
244818
245399
|
quotaRefreshWaiters.delete(requestId);
|
|
@@ -245188,7 +245769,7 @@ function nodesDomain(deps) {
|
|
|
245188
245769
|
}
|
|
245189
245770
|
deps.enrollTokens.setIssuedNodeId(enrollToken, nodeId);
|
|
245190
245771
|
} else {
|
|
245191
|
-
nodeId = `node-${(0,
|
|
245772
|
+
nodeId = `node-${(0, import_node_crypto63.randomUUID)().slice(0, 8)}`;
|
|
245192
245773
|
deps.enrollTokens.setIssuedNodeId(enrollToken, nodeId);
|
|
245193
245774
|
}
|
|
245194
245775
|
const existingNode = await deps.nodeStore.getNode(nodeId);
|
|
@@ -245454,16 +246035,16 @@ function normalizeGatewayUrl(raw) {
|
|
|
245454
246035
|
}
|
|
245455
246036
|
}
|
|
245456
246037
|
function newNodeId() {
|
|
245457
|
-
return "node-" + (0,
|
|
246038
|
+
return "node-" + (0, import_node_crypto63.randomUUID)().replace(/-/g, "").slice(0, 12);
|
|
245458
246039
|
}
|
|
245459
|
-
var
|
|
246040
|
+
var import_node_crypto63, import_node_fs18, import_node_url6, import_node_path22, NODE_NAME_MAX_LENGTH;
|
|
245460
246041
|
var init_routes7 = __esm({
|
|
245461
246042
|
"../server/src/domains/nodes/routes.ts"() {
|
|
245462
246043
|
"use strict";
|
|
245463
246044
|
init_src();
|
|
245464
246045
|
init_faults();
|
|
245465
246046
|
init_runtime_status();
|
|
245466
|
-
|
|
246047
|
+
import_node_crypto63 = require("node:crypto");
|
|
245467
246048
|
import_node_fs18 = require("node:fs");
|
|
245468
246049
|
import_node_url6 = require("node:url");
|
|
245469
246050
|
import_node_path22 = require("node:path");
|
|
@@ -247130,7 +247711,7 @@ function createBundle(root, target, input) {
|
|
|
247130
247711
|
}
|
|
247131
247712
|
}
|
|
247132
247713
|
const bytes2 = fs29.statSync(absBundle).size;
|
|
247133
|
-
const digest = (0,
|
|
247714
|
+
const digest = (0, import_node_crypto64.createHash)("sha256").update(fs29.readFileSync(absBundle)).digest("hex");
|
|
247134
247715
|
const relBase = `inputs/git-bundles/${safeRepo}-${commit.slice(0, 12)}`;
|
|
247135
247716
|
return {
|
|
247136
247717
|
absoluteBundlePath: absBundle,
|
|
@@ -247226,12 +247807,12 @@ function classifyGitError(fallback, err, where) {
|
|
|
247226
247807
|
function oneLine2(msg) {
|
|
247227
247808
|
return msg.split("\n").map((s2) => s2.trim()).filter(Boolean).slice(0, 3).join(" ");
|
|
247228
247809
|
}
|
|
247229
|
-
var import_node_child_process17,
|
|
247810
|
+
var import_node_child_process17, import_node_crypto64, fs29, os8, path26, GitReadonlyBundleError, HEX40, FETCH_TIMEOUT_MS2;
|
|
247230
247811
|
var init_readonly_bundle = __esm({
|
|
247231
247812
|
"../server/src/git/readonly-bundle.ts"() {
|
|
247232
247813
|
"use strict";
|
|
247233
247814
|
import_node_child_process17 = require("node:child_process");
|
|
247234
|
-
|
|
247815
|
+
import_node_crypto64 = require("node:crypto");
|
|
247235
247816
|
fs29 = __toESM(require("node:fs"), 1);
|
|
247236
247817
|
os8 = __toESM(require("node:os"), 1);
|
|
247237
247818
|
path26 = __toESM(require("node:path"), 1);
|
|
@@ -247252,7 +247833,7 @@ var init_readonly_bundle = __esm({
|
|
|
247252
247833
|
// ../server/src/domains/collab/create-seeded-workorder.ts
|
|
247253
247834
|
function makeSeededWorkorderCreator(deps) {
|
|
247254
247835
|
const locks = createKeyedMutex();
|
|
247255
|
-
const genWorkspace = deps.genWorkspace ?? (() => `ws:wo-${(0,
|
|
247836
|
+
const genWorkspace = deps.genWorkspace ?? (() => `ws:wo-${(0, import_node_crypto65.randomUUID)().slice(0, 8)}`);
|
|
247256
247837
|
const create = async (input) => {
|
|
247257
247838
|
const company = input.companyId && deps.resolveCompany ? await deps.resolveCompany(input.companyId) : void 0;
|
|
247258
247839
|
const kernel = company?.kernel ?? deps.kernel;
|
|
@@ -247339,7 +247920,7 @@ function makeSeededWorkorderCreator(deps) {
|
|
|
247339
247920
|
return await finishCreation({ workspace, rootArtifactId: planned.rootArtifactId, spawned: planned.spawned });
|
|
247340
247921
|
};
|
|
247341
247922
|
return async (input) => {
|
|
247342
|
-
const release = await locks.acquire(`${input.companyId ?? ""}\0${input.idempotencyKey ?? (0,
|
|
247923
|
+
const release = await locks.acquire(`${input.companyId ?? ""}\0${input.idempotencyKey ?? (0, import_node_crypto65.randomUUID)()}`);
|
|
247343
247924
|
try {
|
|
247344
247925
|
return await create(input);
|
|
247345
247926
|
} finally {
|
|
@@ -247348,7 +247929,7 @@ function makeSeededWorkorderCreator(deps) {
|
|
|
247348
247929
|
};
|
|
247349
247930
|
}
|
|
247350
247931
|
function workspaceForKey(key2) {
|
|
247351
|
-
return `ws:wo-${(0,
|
|
247932
|
+
return `ws:wo-${(0, import_node_crypto65.createHash)("sha256").update(key2).digest("hex").slice(0, 8)}`;
|
|
247352
247933
|
}
|
|
247353
247934
|
function existingWorkorder(snapshot, workspace, actor) {
|
|
247354
247935
|
if (!snapshot?.nodes.length) return null;
|
|
@@ -247360,11 +247941,11 @@ function existingWorkorder(snapshot, workspace, actor) {
|
|
|
247360
247941
|
spawned: snapshot.nodes.map((node2) => ({ id: node2.id, type: node2.type, owner: node2.assigneeActorId ?? actor }))
|
|
247361
247942
|
};
|
|
247362
247943
|
}
|
|
247363
|
-
var
|
|
247944
|
+
var import_node_crypto65;
|
|
247364
247945
|
var init_create_seeded_workorder = __esm({
|
|
247365
247946
|
"../server/src/domains/collab/create-seeded-workorder.ts"() {
|
|
247366
247947
|
"use strict";
|
|
247367
|
-
|
|
247948
|
+
import_node_crypto65 = require("node:crypto");
|
|
247368
247949
|
init_uncategorized_project();
|
|
247369
247950
|
init_src();
|
|
247370
247951
|
init_planner();
|
|
@@ -248867,12 +249448,12 @@ function stateFromAttempt(attempt, handoff, checkpoint, now, stalledAfterMs, ope
|
|
|
248867
249448
|
if (attempt.status === "no-output") return handoff?.unresolvedIssues.length ? "blocked" : "no_change";
|
|
248868
249449
|
return "failed";
|
|
248869
249450
|
}
|
|
248870
|
-
var
|
|
249451
|
+
var import_node_crypto66, BLOCKING_STATES, HANDOFF_OUTCOMES2, RESUME_EXTERNAL_EFFECT_LIMIT, RESUME_SNAPSHOT_PREFIX, RESUME_SNAPSHOT_SUFFIX, ExecutionContinuityService;
|
|
248871
249452
|
var init_service9 = __esm({
|
|
248872
249453
|
"../server/src/domains/execution-continuity/service.ts"() {
|
|
248873
249454
|
"use strict";
|
|
248874
249455
|
init_src();
|
|
248875
|
-
|
|
249456
|
+
import_node_crypto66 = require("node:crypto");
|
|
248876
249457
|
init_src7();
|
|
248877
249458
|
BLOCKING_STATES = /* @__PURE__ */ new Set(["stalled", "failed", "blocked"]);
|
|
248878
249459
|
HANDOFF_OUTCOMES2 = /* @__PURE__ */ new Set(["succeeded", "no-output", "failed", "cancelled", "timeout", "orphaned"]);
|
|
@@ -249103,7 +249684,7 @@ var init_service9 = __esm({
|
|
|
249103
249684
|
if (typeof expectedHash !== "string" || !this.readBundleFile) return null;
|
|
249104
249685
|
const injectedResume = this.readBundleFile(attempt.id, "execution/RESUME.md");
|
|
249105
249686
|
if (!injectedResume) return null;
|
|
249106
|
-
const actualHash = (0,
|
|
249687
|
+
const actualHash = (0, import_node_crypto66.createHash)("sha256").update(injectedResume).digest("hex");
|
|
249107
249688
|
if (actualHash !== expectedHash) return null;
|
|
249108
249689
|
const recoverySnapshot = parseResumePackSnapshot(injectedResume);
|
|
249109
249690
|
if (!recoverySnapshot || recoverySnapshot.scenario !== "redispatch" || !recoverySnapshot.previousAttempt || recoverySnapshot.node.nodeId !== attempt.nodeId || recoverySnapshot.jobKey !== attempt.jobKey || recoverySnapshot.part !== attempt.part) return null;
|
|
@@ -250285,7 +250866,7 @@ function createChatSessionsDomain(opts) {
|
|
|
250285
250866
|
if (!text7.trim()) throw new ApiError(400, "BAD_REQUEST", "text required");
|
|
250286
250867
|
const now = Date.now();
|
|
250287
250868
|
sweepDrafts(now);
|
|
250288
|
-
const id = `cd_${(0,
|
|
250869
|
+
const id = `cd_${(0, import_node_crypto67.randomUUID)()}`;
|
|
250289
250870
|
drafts.set(id, { text: text7, actor: req.auth.actor, expiresAt: now + DRAFT_TTL_MS });
|
|
250290
250871
|
return { status: 201, body: { id, expiresInMs: DRAFT_TTL_MS } };
|
|
250291
250872
|
});
|
|
@@ -250362,7 +250943,7 @@ function createChatSessionsDomain(opts) {
|
|
|
250362
250943
|
const runtimeId = agentDefault.binding?.nodeId ?? "unknown";
|
|
250363
250944
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
250364
250945
|
const session = {
|
|
250365
|
-
id: (0,
|
|
250946
|
+
id: (0, import_node_crypto67.randomUUID)(),
|
|
250366
250947
|
humanActorId: req.auth.actor,
|
|
250367
250948
|
// 注:这里**刻意不写 companyId**。新会话要不要带公司归属,按 ws:wo-6d588f8e 的 ADR
|
|
250368
250949
|
// (每公司 schema、最终移除表内 company 列)统一定,不在本节点自行发明。
|
|
@@ -250497,7 +251078,7 @@ function createChatSessionsDomain(opts) {
|
|
|
250497
251078
|
if (body2.role !== "user" && body2.role !== "assistant") throw new ApiError(400, "BAD_REQUEST", "role must be user or assistant");
|
|
250498
251079
|
const role = body2.role;
|
|
250499
251080
|
const msg = await store2.appendMessage({
|
|
250500
|
-
id: (0,
|
|
251081
|
+
id: (0, import_node_crypto67.randomUUID)(),
|
|
250501
251082
|
sessionId: req.params.id,
|
|
250502
251083
|
role,
|
|
250503
251084
|
content: role === "user" ? stripInjectedChatContext(body2.content) : body2.content,
|
|
@@ -250539,7 +251120,7 @@ function createChatSessionsDomain(opts) {
|
|
|
250539
251120
|
const known = key2 ? cur.find((x2) => x2.clientKey === key2) : void 0;
|
|
250540
251121
|
if (!known && cur.length >= QUEUE_MAX) throw new ApiError(409, "QUEUE_FULL", `\u961F\u5217\u5DF2\u6EE1\uFF08\u4E0A\u9650 ${QUEUE_MAX} \u6761\uFF09`);
|
|
250541
251122
|
const item = await store2.enqueuePendingMessage({
|
|
250542
|
-
id: (0,
|
|
251123
|
+
id: (0, import_node_crypto67.randomUUID)(),
|
|
250543
251124
|
chatSessionId: sid,
|
|
250544
251125
|
text: text7,
|
|
250545
251126
|
...attachments.length ? { attachments } : {},
|
|
@@ -251392,12 +251973,12 @@ async function legacySendFailureCards(entries, deps) {
|
|
|
251392
251973
|
}
|
|
251393
251974
|
return out;
|
|
251394
251975
|
}
|
|
251395
|
-
var
|
|
251976
|
+
var import_node_crypto67, DEFAULT_SNAPSHOT_ITEMS, INFLIGHT_INSERT_SETTLE_WAIT_MS, MAX_SNAPSHOT_ITEMS, PROJECTED_CARD_LIMIT, SUBMISSION_NOT_DELIVERED_NOTE, SUBMISSION_UNCONFIRMED_NOTE, LEGACY_CARD_LIMIT;
|
|
251396
251977
|
var init_chat_sessions2 = __esm({
|
|
251397
251978
|
"../server/src/domains/chat-sessions/index.ts"() {
|
|
251398
251979
|
"use strict";
|
|
251399
251980
|
init_file_limits2();
|
|
251400
|
-
|
|
251981
|
+
import_node_crypto67 = require("node:crypto");
|
|
251401
251982
|
init_src();
|
|
251402
251983
|
init_chat_session();
|
|
251403
251984
|
init_persistent_files();
|
|
@@ -252857,7 +253438,7 @@ function busyError(chatSessionId, blockedBy) {
|
|
|
252857
253438
|
return `\u76EE\u6807\u4F1A\u8BDD ${chatSessionId} \u6B63\u6709\u4E00\u8F6E\u5728\u8DD1${blockedBy ? `\uFF08${blockedBy}\uFF09` : ""}\u2014\u2014\u672C\u6B21\u89E6\u53D1\u5DF2\u4E22\u5F03\uFF0C\u4E0D\u6392\u961F\u3001\u4E0D\u8865\u8DD1`;
|
|
252858
253439
|
}
|
|
252859
253440
|
function genWebhookToken() {
|
|
252860
|
-
return `owt_${(0,
|
|
253441
|
+
return `owt_${(0, import_node_crypto68.randomBytes)(32).toString("base64url")}`;
|
|
252861
253442
|
}
|
|
252862
253443
|
function validateTitleTemplate(tpl) {
|
|
252863
253444
|
const residue = tpl.replace(DATE_TOKEN, "");
|
|
@@ -252913,11 +253494,11 @@ function appendSourceNote(brief, automation, source, atIso) {
|
|
|
252913
253494
|
---
|
|
252914
253495
|
\u672C\u5DE5\u5355\u7531\u81EA\u52A8\u5316\u300C${automation.name}\u300D\u4E8E ${atIso} \u89E6\u53D1\uFF08\u6765\u6E90\uFF1A${source}\uFF09\u3002\u5F00\u5DE5\u540E\u8BF7\u628A\u5DE5\u5355\u6807\u9898\u6539\u6210\u51C6\u786E\u53CD\u6620\u5B9E\u9645\u5DE5\u4F5C\u7684\u63CF\u8FF0\u3002`;
|
|
252915
253496
|
}
|
|
252916
|
-
var
|
|
253497
|
+
var import_node_crypto68, DATE_TOKEN, AutomationsService, EVENT_RETRY_BASE_MS, EVENT_RETRY_MAX_MS, EVENT_RETRY_MAX_ATTEMPTS, eventAttempts, eventLastAttemptAt, eventLastError, CHAT_REPLY_MAX;
|
|
252917
253498
|
var init_service10 = __esm({
|
|
252918
253499
|
"../server/src/domains/automations/service.ts"() {
|
|
252919
253500
|
"use strict";
|
|
252920
|
-
|
|
253501
|
+
import_node_crypto68 = require("node:crypto");
|
|
252921
253502
|
init_src();
|
|
252922
253503
|
init_registry3();
|
|
252923
253504
|
init_attribution();
|
|
@@ -253731,11 +254312,11 @@ function verifySignature(rawBody, headers, secret) {
|
|
|
253731
254312
|
if (!secret) return "not_required";
|
|
253732
254313
|
const given = header1(headers, "x-hub-signature-256");
|
|
253733
254314
|
if (!given) return "missing";
|
|
253734
|
-
const expected = `sha256=${(0,
|
|
254315
|
+
const expected = `sha256=${(0, import_node_crypto69.createHmac)("sha256", secret).update(rawBody).digest("hex")}`;
|
|
253735
254316
|
const a = Buffer.from(given);
|
|
253736
254317
|
const b2 = Buffer.from(expected);
|
|
253737
254318
|
if (a.length !== b2.length) return "invalid";
|
|
253738
|
-
return (0,
|
|
254319
|
+
return (0, import_node_crypto69.timingSafeEqual)(a, b2) ? "valid" : "invalid";
|
|
253739
254320
|
}
|
|
253740
254321
|
function eventAllowed(filters, envelope) {
|
|
253741
254322
|
if (!filters || filters.length === 0) return true;
|
|
@@ -253765,11 +254346,11 @@ function splitEvent(envelope) {
|
|
|
253765
254346
|
}
|
|
253766
254347
|
return { eventName, actionCandidates: candidates };
|
|
253767
254348
|
}
|
|
253768
|
-
var
|
|
254349
|
+
var import_node_crypto69, MAX_BODY_BYTES, AutomationWebhookService, header1, PROVIDER_PREFIXES;
|
|
253769
254350
|
var init_webhook = __esm({
|
|
253770
254351
|
"../server/src/domains/automations/webhook.ts"() {
|
|
253771
254352
|
"use strict";
|
|
253772
|
-
|
|
254353
|
+
import_node_crypto69 = require("node:crypto");
|
|
253773
254354
|
MAX_BODY_BYTES = 256 * 1024;
|
|
253774
254355
|
AutomationWebhookService = class {
|
|
253775
254356
|
store;
|
|
@@ -254921,7 +255502,7 @@ function playbooksDomain(opts) {
|
|
|
254921
255502
|
opts.overrides.set(companyOf(req), ref2, nodeKey, nextOverride);
|
|
254922
255503
|
try {
|
|
254923
255504
|
await opts.audit?.({
|
|
254924
|
-
id: `reg_${(0,
|
|
255505
|
+
id: `reg_${(0, import_node_crypto70.randomUUID)()}`,
|
|
254925
255506
|
actor: req.auth.actor,
|
|
254926
255507
|
kind: "registry_change",
|
|
254927
255508
|
target: `playbook:${ref2}#${nodeKey}`,
|
|
@@ -254938,11 +255519,11 @@ function playbooksDomain(opts) {
|
|
|
254938
255519
|
});
|
|
254939
255520
|
};
|
|
254940
255521
|
}
|
|
254941
|
-
var
|
|
255522
|
+
var import_node_crypto70;
|
|
254942
255523
|
var init_routes12 = __esm({
|
|
254943
255524
|
"../server/src/domains/playbooks/routes.ts"() {
|
|
254944
255525
|
"use strict";
|
|
254945
|
-
|
|
255526
|
+
import_node_crypto70 = require("node:crypto");
|
|
254946
255527
|
init_router();
|
|
254947
255528
|
init_registry3();
|
|
254948
255529
|
init_planner();
|
|
@@ -255071,17 +255652,17 @@ function completionFingerprint(workspace, members) {
|
|
|
255071
255652
|
workspace,
|
|
255072
255653
|
members: [...members].sort((a, b2) => a.artifactId < b2.artifactId ? -1 : a.artifactId > b2.artifactId ? 1 : 0).map((m2) => ({ artifactId: m2.artifactId, currentRevisionId: m2.currentRevisionId ?? null }))
|
|
255073
255654
|
});
|
|
255074
|
-
return (0,
|
|
255655
|
+
return (0, import_node_crypto71.createHash)("sha256").update(canonical2).digest("hex");
|
|
255075
255656
|
}
|
|
255076
255657
|
function eventConsumptionKey(args) {
|
|
255077
255658
|
const raw = `project-event:${EVENT_KEY_VERSION}:${args.triggerId}:${args.event}:${args.workspace}:${args.fingerprint}`;
|
|
255078
|
-
return raw.length <= 200 ? raw : `project-event:${EVENT_KEY_VERSION}:sha256:${(0,
|
|
255659
|
+
return raw.length <= 200 ? raw : `project-event:${EVENT_KEY_VERSION}:sha256:${(0, import_node_crypto71.createHash)("sha256").update(raw).digest("hex")}`;
|
|
255079
255660
|
}
|
|
255080
|
-
var
|
|
255661
|
+
var import_node_crypto71, EVENT_KEY_VERSION, EMPTY_METRICS, AUTOMATION_EVENT_HANDLERS, ProjectEventPoller;
|
|
255081
255662
|
var init_project_event_poller = __esm({
|
|
255082
255663
|
"../server/src/automations/project-event-poller.ts"() {
|
|
255083
255664
|
"use strict";
|
|
255084
|
-
|
|
255665
|
+
import_node_crypto71 = require("node:crypto");
|
|
255085
255666
|
EVENT_KEY_VERSION = "v1";
|
|
255086
255667
|
EMPTY_METRICS = () => ({
|
|
255087
255668
|
scanDurationMs: 0,
|
|
@@ -255291,7 +255872,7 @@ function queryInputReceipt(hub, nodeId, dispatchId, clientMessageKey, pending, t
|
|
|
255291
255872
|
const viaSession = hub.hasSession?.(dispatchId) === true;
|
|
255292
255873
|
const supported = viaSession ? hub.supportsInputReceiptQuery?.(dispatchId) === true : daemonMetaOf(hub, nodeId)?.supportsInputReceiptQuery === true;
|
|
255293
255874
|
if (!supported) return Promise.resolve({ status: "unknown", reason: "unsupported" });
|
|
255294
|
-
const requestId = (0,
|
|
255875
|
+
const requestId = (0, import_node_crypto72.randomUUID)();
|
|
255295
255876
|
return new Promise((resolve12) => {
|
|
255296
255877
|
const timer = setTimeout(() => {
|
|
255297
255878
|
pending.delete(requestId);
|
|
@@ -255353,7 +255934,7 @@ function sendAppendInput(hub, nodeId, dispatchId, entry, input, timeoutMs, sessi
|
|
|
255353
255934
|
if (input.requireConsumptionReceipt && !hub.supportsInputConsumptionReceipts?.(dispatchId)) {
|
|
255354
255935
|
return Promise.resolve({ accepted: false, reason: "consumption-unsupported" });
|
|
255355
255936
|
}
|
|
255356
|
-
const requestId = (0,
|
|
255937
|
+
const requestId = (0, import_node_crypto72.randomUUID)();
|
|
255357
255938
|
const sent = routeToSession(hub, nodeId, dispatchId, { type: "append_input", dispatchId, input, requestId });
|
|
255358
255939
|
if (!sent) return Promise.resolve({ accepted: false, reason: "session-closing", ...unknownIfInterrupting });
|
|
255359
255940
|
return new Promise((resolve12) => {
|
|
@@ -255366,11 +255947,11 @@ function sendAppendInput(hub, nodeId, dispatchId, entry, input, timeoutMs, sessi
|
|
|
255366
255947
|
entry.appendWaiters.push({ requestId, requireConsumptionReceipt: input.requireConsumptionReceipt, resolve: resolve12, timer });
|
|
255367
255948
|
});
|
|
255368
255949
|
}
|
|
255369
|
-
var
|
|
255950
|
+
var import_node_crypto72, STASH_TTL_MS, STASH_MAX_FRAMES_PER_ID, STASH_MAX_TOTAL_FRAMES, STASH_MAX_IDS, STASH_LOSS_MAX_IDS, STASH_LOSS_TTL_MS, DaemonHubAdapter, BindingRouterAdapter, WorkdirBridge;
|
|
255370
255951
|
var init_daemon_adapter = __esm({
|
|
255371
255952
|
"../server/src/daemon-adapter.ts"() {
|
|
255372
255953
|
"use strict";
|
|
255373
|
-
|
|
255954
|
+
import_node_crypto72 = require("node:crypto");
|
|
255374
255955
|
init_src();
|
|
255375
255956
|
STASH_TTL_MS = 5 * 6e4;
|
|
255376
255957
|
STASH_MAX_FRAMES_PER_ID = 1e4;
|
|
@@ -255810,7 +256391,7 @@ var init_daemon_adapter = __esm({
|
|
|
255810
256391
|
async spawn(job) {
|
|
255811
256392
|
const nodeId = job.binding?.nodeId;
|
|
255812
256393
|
if (!nodeId) throw new Error("DaemonHubAdapter \u9700\u8981 job.binding.nodeId\uFF08\u8DEF\u7531\u9519\u8BEF\uFF09");
|
|
255813
|
-
const dispatchId = job.dispatchId ?? `dispatch:${(0,
|
|
256394
|
+
const dispatchId = job.dispatchId ?? `dispatch:${(0, import_node_crypto72.randomUUID)()}`;
|
|
255814
256395
|
if (job.dispatchId && this.pending.has(dispatchId)) {
|
|
255815
256396
|
return this.recover(dispatchId, nodeId, job.binding?.runtimeKind, job.actor);
|
|
255816
256397
|
}
|
|
@@ -256066,7 +256647,7 @@ var init_daemon_adapter = __esm({
|
|
|
256066
256647
|
return daemon?.meta.supportsWorkdirWalk === true;
|
|
256067
256648
|
}
|
|
256068
256649
|
request(nodeId, buildFrame) {
|
|
256069
|
-
const requestId = (0,
|
|
256650
|
+
const requestId = (0, import_node_crypto72.randomUUID)();
|
|
256070
256651
|
const sent = this.hub.dispatch(nodeId, buildFrame(requestId));
|
|
256071
256652
|
if (!sent) return Promise.resolve({ ok: false, code: "NODE_OFFLINE" });
|
|
256072
256653
|
return new Promise((resolve12) => {
|
|
@@ -256174,13 +256755,13 @@ function classifyPage(page, lastPushedHash, serviceAccount) {
|
|
|
256174
256755
|
if (sha(body2) === lastPushedHash) return { kind: "echo" };
|
|
256175
256756
|
return { kind: "human-edit", content: body2, updatedBy: page.updatedBy };
|
|
256176
256757
|
}
|
|
256177
|
-
var
|
|
256758
|
+
var import_node_crypto73, sha, enc2, dec, MirrorEngine, MemoryMirrorStateStore, MapMirrorIdentities;
|
|
256178
256759
|
var init_engine = __esm({
|
|
256179
256760
|
"../server/src/mirror/engine.ts"() {
|
|
256180
256761
|
"use strict";
|
|
256181
|
-
|
|
256762
|
+
import_node_crypto73 = require("node:crypto");
|
|
256182
256763
|
init_src();
|
|
256183
|
-
sha = (s2) => (0,
|
|
256764
|
+
sha = (s2) => (0, import_node_crypto73.createHash)("sha256").update(s2, "utf8").digest("hex");
|
|
256184
256765
|
enc2 = (s2) => new TextEncoder().encode(s2);
|
|
256185
256766
|
dec = (b2) => new TextDecoder().decode(b2);
|
|
256186
256767
|
MirrorEngine = class {
|
|
@@ -256461,11 +257042,11 @@ function humanExitCause(exit3) {
|
|
|
256461
257042
|
const base = (exit3.reason ? label2[exit3.reason] : void 0) ?? `\u4F1A\u8BDD\u5F02\u5E38\u7ED3\u675F\uFF08${exit3.reason ?? "\u65E0\u9000\u51FA\u4FE1\u606F"}\uFF09`;
|
|
256462
257043
|
return exit3.errorMessage ? `${base}\uFF1A${exit3.errorMessage.slice(0, 200)}` : base;
|
|
256463
257044
|
}
|
|
256464
|
-
var
|
|
257045
|
+
var import_node_crypto74, AUTONOMOUS_ETHOS, CONVERSATIONAL_ETHOS, SHARED_GRAPH_BODY, AUTONOMOUS_RECOVERY_TOOLS, HIGH_RISK_COMMANDS, REJECTED_PROPOSALS_IN_TASK, COORDINATOR_SYSTEM_PROMPT, CONVERSATIONAL_RECOVERY_TOOLS, CONVERSATIONAL_ESCALATION_TOOLS, CONVERSATIONAL_MANAGER_BODY, MACHINE_EXIT_CODES, CoordinatorWorker;
|
|
256465
257046
|
var init_worker = __esm({
|
|
256466
257047
|
"../server/src/coordinator/worker.ts"() {
|
|
256467
257048
|
"use strict";
|
|
256468
|
-
|
|
257049
|
+
import_node_crypto74 = require("node:crypto");
|
|
256469
257050
|
init_src7();
|
|
256470
257051
|
init_identity();
|
|
256471
257052
|
AUTONOMOUS_ETHOS = `\u4F60\u662F\u8FD9\u4E2A\u5DE5\u5355\u7684**\u7BA1\u7406\u8005**\u2014\u2014\u804C\u8D23\u662F\u8BA9\u5B83\u987A\u7545\u8DD1\u5B8C\u3002\u7CFB\u7EDF\u5728\u67D0\u4E2A\u8282\u70B9\u5361\u4F4F\u3001\u673A\u68B0\u5206\u8BCA\u786E\u8BA4"\u9700\u8981\u4F60"\u65F6\u5524\u8D77\u4F60\uFF08\u65E0\u4EBA\u5728\u573A\uFF0C\u4F60\u8FD9\u4E00\u8F6E\u628A\u80FD\u505A\u7684\u505A\u6389\uFF09\u3002\u4F60\u7684\u624B\u6BB5\u5F88\u5BBD\uFF1A
|
|
@@ -256735,7 +257316,7 @@ ${HIGH_RISK_COMMANDS}`;
|
|
|
256735
257316
|
return this.deps.kernel.model.lastSeq.get(artifactId) ?? 0;
|
|
256736
257317
|
}
|
|
256737
257318
|
evaluationKey(kind, artifactId, evidence) {
|
|
256738
|
-
const fingerprint2 = (0,
|
|
257319
|
+
const fingerprint2 = (0, import_node_crypto74.createHash)("sha256").update(JSON.stringify(evidence)).digest("hex");
|
|
256739
257320
|
return `${kind}:${artifactId}:${fingerprint2}`;
|
|
256740
257321
|
}
|
|
256741
257322
|
artifactEvidence(id) {
|
|
@@ -257124,8 +257705,8 @@ ${ctx.nodeFault}
|
|
|
257124
257705
|
const taskWithRejections = rejectedSection ? `${task}
|
|
257125
257706
|
|
|
257126
257707
|
${rejectedSection}` : task;
|
|
257127
|
-
const runtimeSessionId = opts?.resumeSessionId ?? (0,
|
|
257128
|
-
const coordinatorRunId = `coordinate:${(0,
|
|
257708
|
+
const runtimeSessionId = opts?.resumeSessionId ?? (0, import_node_crypto74.randomUUID)();
|
|
257709
|
+
const coordinatorRunId = `coordinate:${(0, import_node_crypto74.randomUUID)()}`;
|
|
257129
257710
|
const taskWithContext = coordinatorContext ? [
|
|
257130
257711
|
taskWithRejections,
|
|
257131
257712
|
``,
|
|
@@ -257169,7 +257750,7 @@ ${rejectedSection}` : task;
|
|
|
257169
257750
|
const startedAtMs = Date.now();
|
|
257170
257751
|
let trajectoryStarted = false;
|
|
257171
257752
|
if (this.deps.trajectory) {
|
|
257172
|
-
const bundleManifest = Object.fromEntries(Object.entries(job.bundle.files).map(([name, content3]) => [name, (0,
|
|
257753
|
+
const bundleManifest = Object.fromEntries(Object.entries(job.bundle.files).map(([name, content3]) => [name, (0, import_node_crypto74.createHash)("sha256").update(content3).digest("hex")]));
|
|
257173
257754
|
const session = {
|
|
257174
257755
|
runId: coordinatorRunId,
|
|
257175
257756
|
runtimeSessionId,
|
|
@@ -257380,11 +257961,11 @@ var init_pg_ident = __esm({
|
|
|
257380
257961
|
});
|
|
257381
257962
|
|
|
257382
257963
|
// ../storage/src/postgres.ts
|
|
257383
|
-
var
|
|
257964
|
+
var import_node_crypto75, ident4, isUniqueViolation, PostgresOplogStore, PostgresBlobStore;
|
|
257384
257965
|
var init_postgres = __esm({
|
|
257385
257966
|
"../storage/src/postgres.ts"() {
|
|
257386
257967
|
"use strict";
|
|
257387
|
-
|
|
257968
|
+
import_node_crypto75 = require("node:crypto");
|
|
257388
257969
|
init_pg_ident();
|
|
257389
257970
|
init_esm();
|
|
257390
257971
|
init_src();
|
|
@@ -257564,7 +258145,7 @@ var init_postgres = __esm({
|
|
|
257564
258145
|
return new _PostgresBlobStore(pool, schema);
|
|
257565
258146
|
}
|
|
257566
258147
|
async put(bytes2) {
|
|
257567
|
-
const hash3 = (0,
|
|
258148
|
+
const hash3 = (0, import_node_crypto75.createHash)("sha256").update(bytes2).digest("hex");
|
|
257568
258149
|
await this.pool.query(
|
|
257569
258150
|
`INSERT INTO ${this.t} (hash, bytes, size, content_type) VALUES ($1, $2, $3, $4) ON CONFLICT (hash) DO NOTHING`,
|
|
257570
258151
|
[hash3, Buffer.from(bytes2), bytes2.byteLength, sniffContentType(bytes2) ?? null]
|
|
@@ -257612,7 +258193,7 @@ function stageAtLeast(stage, min2) {
|
|
|
257612
258193
|
return STAGES.indexOf(stage) >= STAGES.indexOf(min2);
|
|
257613
258194
|
}
|
|
257614
258195
|
function newVariableId() {
|
|
257615
|
-
return `var_${(0,
|
|
258196
|
+
return `var_${(0, import_node_crypto76.randomUUID)()}`;
|
|
257616
258197
|
}
|
|
257617
258198
|
async function declareRecordsAware(db) {
|
|
257618
258199
|
await db.query(`SELECT set_config('${RECORDS_AWARE_SETTING}', 'on', true)`);
|
|
@@ -257968,11 +258549,11 @@ async function listBindingTargetIds(db, s2, kind) {
|
|
|
257968
258549
|
[kind]
|
|
257969
258550
|
)).rows.map((x2) => x2.target_id);
|
|
257970
258551
|
}
|
|
257971
|
-
var
|
|
258552
|
+
var import_node_crypto76, STAGES, RECORDS_AWARE_SETTING, markLockName;
|
|
257972
258553
|
var init_variable_bindings = __esm({
|
|
257973
258554
|
"../storage/src/variable-bindings.ts"() {
|
|
257974
258555
|
"use strict";
|
|
257975
|
-
|
|
258556
|
+
import_node_crypto76 = require("node:crypto");
|
|
257976
258557
|
init_src();
|
|
257977
258558
|
STAGES = ["off", "dual", "read", "records"];
|
|
257978
258559
|
RECORDS_AWARE_SETTING = "oasis.variable_records_aware";
|
|
@@ -260652,7 +261233,7 @@ async function ensureOneOwnerInvariant(pool, s2) {
|
|
|
260652
261233
|
);
|
|
260653
261234
|
}
|
|
260654
261235
|
}
|
|
260655
|
-
var ident8, PostgresControlPlaneStore, rowToDigitalEmployee, rowToAgentCredential, rowToBridge, rowToOffboarding, toIso, rowToCompany, rowToRoleMigration, rowToMember, rowToInvitation, rowToInviteLink, rowToAccount, rowToVerificationCode;
|
|
261236
|
+
var ident8, PostgresControlPlaneStore, rowToDigitalEmployee, rowToAgentCredential, rowToBridge, rowToOffboarding, toIso, rowToCompany, rowToRoleMigration, migrationRow2, rowToMember, rowToInvitation, rowToInviteLink, rowToAccount, rowToVerificationCode;
|
|
260656
261237
|
var init_postgres_control_plane = __esm({
|
|
260657
261238
|
"../storage/src/postgres-control-plane.ts"() {
|
|
260658
261239
|
"use strict";
|
|
@@ -261043,6 +261624,48 @@ var init_postgres_control_plane = __esm({
|
|
|
261043
261624
|
client.release();
|
|
261044
261625
|
}
|
|
261045
261626
|
}
|
|
261627
|
+
async removeMemberAndReleaseOwnedAgents(companyId, accountId, at2) {
|
|
261628
|
+
const client = await this.pool.connect();
|
|
261629
|
+
try {
|
|
261630
|
+
await client.query("BEGIN");
|
|
261631
|
+
const all2 = await client.query(
|
|
261632
|
+
`SELECT company_id, account_id, actor_id, role, display_name, onboarding_completed_at, onboarding_step
|
|
261633
|
+
FROM ${this.s}.company_members WHERE company_id = $1 FOR UPDATE`,
|
|
261634
|
+
[companyId]
|
|
261635
|
+
);
|
|
261636
|
+
const target = all2.rows.map(rowToMember).find((m2) => m2.accountId === accountId);
|
|
261637
|
+
if (!target) {
|
|
261638
|
+
await client.query("ROLLBACK");
|
|
261639
|
+
return { ok: false, reason: "not_found" };
|
|
261640
|
+
}
|
|
261641
|
+
if (target.role === "owner") {
|
|
261642
|
+
await client.query("ROLLBACK");
|
|
261643
|
+
return { ok: false, reason: "owner_protected" };
|
|
261644
|
+
}
|
|
261645
|
+
const released = await client.query(
|
|
261646
|
+
`UPDATE ${this.s}.digital_employees SET owner_account_id = NULL, updated_at = $3
|
|
261647
|
+
WHERE company_id = $1 AND owner_account_id = $2
|
|
261648
|
+
RETURNING id`,
|
|
261649
|
+
[companyId, accountId, at2]
|
|
261650
|
+
);
|
|
261651
|
+
await client.query(
|
|
261652
|
+
`DELETE FROM ${this.s}.principal_bridge WHERE company_id = $1 AND principal_type = 'human' AND principal_id = $2`,
|
|
261653
|
+
[companyId, accountId]
|
|
261654
|
+
);
|
|
261655
|
+
await client.query(
|
|
261656
|
+
`DELETE FROM ${this.s}.company_members WHERE company_id = $1 AND account_id = $2`,
|
|
261657
|
+
[companyId, accountId]
|
|
261658
|
+
);
|
|
261659
|
+
await client.query("COMMIT");
|
|
261660
|
+
return { ok: true, member: target, releasedAgents: released.rows.map((r) => r.id) };
|
|
261661
|
+
} catch (e) {
|
|
261662
|
+
await client.query("ROLLBACK").catch(() => {
|
|
261663
|
+
});
|
|
261664
|
+
throw e;
|
|
261665
|
+
} finally {
|
|
261666
|
+
client.release();
|
|
261667
|
+
}
|
|
261668
|
+
}
|
|
261046
261669
|
async updateMemberRoleIfNotLastOwner(companyId, accountId, role) {
|
|
261047
261670
|
const client = await this.pool.connect();
|
|
261048
261671
|
try {
|
|
@@ -261111,7 +261734,7 @@ var init_postgres_control_plane = __esm({
|
|
|
261111
261734
|
`SELECT status FROM ${this.s}.accounts WHERE id = $1`,
|
|
261112
261735
|
[toAccountId]
|
|
261113
261736
|
);
|
|
261114
|
-
if (acc.rows[0]
|
|
261737
|
+
if (!acc.rows[0] || acc.rows[0].status !== "active") {
|
|
261115
261738
|
await client.query("ROLLBACK");
|
|
261116
261739
|
return { ok: false, reason: "target_inactive" };
|
|
261117
261740
|
}
|
|
@@ -261148,6 +261771,73 @@ var init_postgres_control_plane = __esm({
|
|
|
261148
261771
|
client.release();
|
|
261149
261772
|
}
|
|
261150
261773
|
}
|
|
261774
|
+
// —— 存量身份映射(ADR D3)——
|
|
261775
|
+
async migrateSoleCompanyOwner(companyId, toAccountId, audit2) {
|
|
261776
|
+
const client = await this.pool.connect();
|
|
261777
|
+
try {
|
|
261778
|
+
await client.query("BEGIN");
|
|
261779
|
+
const all2 = await client.query(
|
|
261780
|
+
`SELECT company_id, account_id, actor_id, role, display_name, onboarding_completed_at, onboarding_step
|
|
261781
|
+
FROM ${this.s}.company_members WHERE company_id = $1 FOR UPDATE`,
|
|
261782
|
+
[companyId]
|
|
261783
|
+
);
|
|
261784
|
+
const rows = all2.rows.map(rowToMember);
|
|
261785
|
+
const target = rows.find((m2) => m2.accountId === toAccountId);
|
|
261786
|
+
if (!target) {
|
|
261787
|
+
await client.query("ROLLBACK");
|
|
261788
|
+
return { ok: false, reason: "not_found" };
|
|
261789
|
+
}
|
|
261790
|
+
const others = rows.filter((m2) => m2.role === "owner" && m2.accountId !== toAccountId);
|
|
261791
|
+
if (others.length === 0 && target.role === "owner") {
|
|
261792
|
+
await client.query("COMMIT");
|
|
261793
|
+
return { ok: true, owner: target, demoted: [], auditRows: [] };
|
|
261794
|
+
}
|
|
261795
|
+
if (others.length > 0) {
|
|
261796
|
+
await client.query(
|
|
261797
|
+
`UPDATE ${this.s}.company_members SET role = 'admin' WHERE company_id = $1 AND role = 'owner' AND account_id <> $2`,
|
|
261798
|
+
[companyId, toAccountId]
|
|
261799
|
+
);
|
|
261800
|
+
}
|
|
261801
|
+
if (target.role !== "owner") {
|
|
261802
|
+
await client.query(
|
|
261803
|
+
`UPDATE ${this.s}.company_members SET role = 'owner' WHERE company_id = $1 AND account_id = $2`,
|
|
261804
|
+
[companyId, toAccountId]
|
|
261805
|
+
);
|
|
261806
|
+
}
|
|
261807
|
+
const auditRows = [
|
|
261808
|
+
...others.map((m2) => migrationRow2(companyId, m2.accountId, "owner", "admin", audit2)),
|
|
261809
|
+
...target.role !== "owner" ? [migrationRow2(companyId, toAccountId, target.role, "owner", audit2)] : []
|
|
261810
|
+
];
|
|
261811
|
+
for (const r of auditRows) {
|
|
261812
|
+
await client.query(
|
|
261813
|
+
`INSERT INTO ${this.s}.company_member_role_migrations
|
|
261814
|
+
(company_id, account_id, role_before, role_after, evidence, manifest_version, applied_at)
|
|
261815
|
+
VALUES ($1,$2,$3,$4,$5,$6,$7)`,
|
|
261816
|
+
[r.companyId, r.accountId, r.roleBefore, r.roleAfter, r.evidence, r.manifestVersion ?? null, r.appliedAt]
|
|
261817
|
+
);
|
|
261818
|
+
}
|
|
261819
|
+
await client.query("COMMIT");
|
|
261820
|
+
return {
|
|
261821
|
+
ok: true,
|
|
261822
|
+
owner: { ...target, role: "owner" },
|
|
261823
|
+
demoted: others.map((m2) => ({ ...m2, role: "admin" })),
|
|
261824
|
+
auditRows
|
|
261825
|
+
};
|
|
261826
|
+
} catch (e) {
|
|
261827
|
+
await client.query("ROLLBACK").catch(() => {
|
|
261828
|
+
});
|
|
261829
|
+
throw e;
|
|
261830
|
+
} finally {
|
|
261831
|
+
client.release();
|
|
261832
|
+
}
|
|
261833
|
+
}
|
|
261834
|
+
async setMemberRoleOnly(companyId, accountId, role) {
|
|
261835
|
+
const r = await this.pool.query(
|
|
261836
|
+
`UPDATE ${this.s}.company_members SET role = $3 WHERE company_id = $1 AND account_id = $2`,
|
|
261837
|
+
[companyId, accountId, role]
|
|
261838
|
+
);
|
|
261839
|
+
return (r.rowCount ?? 0) > 0;
|
|
261840
|
+
}
|
|
261151
261841
|
// —— 存量身份映射审计(ADR D3.4)——
|
|
261152
261842
|
async appendMemberRoleMigrations(rows) {
|
|
261153
261843
|
if (rows.length === 0) return;
|
|
@@ -261661,6 +262351,15 @@ var init_postgres_control_plane = __esm({
|
|
|
261661
262351
|
...row.manifest_version != null ? { manifestVersion: row.manifest_version } : {},
|
|
261662
262352
|
appliedAt: toIso(row.applied_at)
|
|
261663
262353
|
});
|
|
262354
|
+
migrationRow2 = (companyId, accountId, roleBefore, roleAfter, audit2) => ({
|
|
262355
|
+
companyId,
|
|
262356
|
+
accountId,
|
|
262357
|
+
roleBefore,
|
|
262358
|
+
roleAfter,
|
|
262359
|
+
evidence: audit2.evidence,
|
|
262360
|
+
...audit2.evidence === "manifest" && audit2.manifestVersion !== void 0 ? { manifestVersion: audit2.manifestVersion } : {},
|
|
262361
|
+
appliedAt: audit2.appliedAt
|
|
262362
|
+
});
|
|
261664
262363
|
rowToMember = (row) => ({
|
|
261665
262364
|
companyId: row.company_id,
|
|
261666
262365
|
accountId: row.account_id,
|
|
@@ -267916,11 +268615,11 @@ var init_postgres_delegations = __esm({
|
|
|
267916
268615
|
});
|
|
267917
268616
|
|
|
267918
268617
|
// ../storage/src/postgres-nodes.ts
|
|
267919
|
-
var
|
|
268618
|
+
var import_node_crypto77, ident13, PostgresNodeStore, PostgresNodeTokenStore, rowToNode, rowToFault, rowToQuota, rowToRuntime;
|
|
267920
268619
|
var init_postgres_nodes = __esm({
|
|
267921
268620
|
"../storage/src/postgres-nodes.ts"() {
|
|
267922
268621
|
"use strict";
|
|
267923
|
-
|
|
268622
|
+
import_node_crypto77 = require("node:crypto");
|
|
267924
268623
|
init_pg_ident();
|
|
267925
268624
|
init_esm();
|
|
267926
268625
|
ident13 = (s2) => {
|
|
@@ -268270,7 +268969,7 @@ var init_postgres_nodes = __esm({
|
|
|
268270
268969
|
return store;
|
|
268271
268970
|
}
|
|
268272
268971
|
issue(nodeId) {
|
|
268273
|
-
const token = `ont_${(0,
|
|
268972
|
+
const token = `ont_${(0, import_node_crypto77.randomBytes)(24).toString("base64url")}`;
|
|
268274
268973
|
this.cache.set(token, nodeId);
|
|
268275
268974
|
void this.pool.query(`INSERT INTO ${this.s}.node_tokens (token,node_id) VALUES ($1,$2)`, [token, nodeId]);
|
|
268276
268975
|
return token;
|
|
@@ -268572,11 +269271,11 @@ var init_postgres_type_registry = __esm({
|
|
|
268572
269271
|
});
|
|
268573
269272
|
|
|
268574
269273
|
// ../storage/src/postgres-actor-memory.ts
|
|
268575
|
-
var
|
|
269274
|
+
var import_node_crypto78, matchClause, ident15, PostgresActorMemoryStore, rowToIndexEntry, rowToRecord;
|
|
268576
269275
|
var init_postgres_actor_memory = __esm({
|
|
268577
269276
|
"../storage/src/postgres-actor-memory.ts"() {
|
|
268578
269277
|
"use strict";
|
|
268579
|
-
|
|
269278
|
+
import_node_crypto78 = require("node:crypto");
|
|
268580
269279
|
init_pg_ident();
|
|
268581
269280
|
init_src();
|
|
268582
269281
|
matchClause = (q2) => q2.requireMatch && q2.keywords.length > 0 ? " WHERE m > 0" : "";
|
|
@@ -268786,7 +269485,7 @@ var init_postgres_actor_memory = __esm({
|
|
|
268786
269485
|
}
|
|
268787
269486
|
async write(input, now) {
|
|
268788
269487
|
if (input.memId === void 0) {
|
|
268789
|
-
const memId = `mem:${(0,
|
|
269488
|
+
const memId = `mem:${(0, import_node_crypto78.randomUUID)()}`;
|
|
268790
269489
|
const r2 = await this.pool.query(
|
|
268791
269490
|
`INSERT INTO ${this.s}.actor_memories
|
|
268792
269491
|
(mem_id, actor_id, project_id, keywords, content, version, created_at, updated_at, accessed_at, source_artifact_id, source_session_id)
|
|
@@ -270357,14 +271056,14 @@ function companySchemaName(companyId) {
|
|
|
270357
271056
|
if (typeof companyId !== "string" || !companyId.trim()) {
|
|
270358
271057
|
throw new Error("company schema mapping \u9700\u8981\u975E\u7A7A companyId\uFF08fail-closed\uFF1A\u4E0D\u56DE\u9000\u9ED8\u8BA4\u516C\u53F8\uFF09");
|
|
270359
271058
|
}
|
|
270360
|
-
const hex = (0,
|
|
271059
|
+
const hex = (0, import_node_crypto79.createHash)("sha256").update(companyId, "utf8").digest("hex");
|
|
270361
271060
|
return `${COMPANY_SCHEMA_PREFIX}${hex.slice(0, DIGEST_HEX_LEN)}`;
|
|
270362
271061
|
}
|
|
270363
|
-
var
|
|
271062
|
+
var import_node_crypto79, COMPANY_SCHEMA_PREFIX, DIGEST_HEX_LEN, SchemaMappingConflictError, TenantStorageLocationStore;
|
|
270364
271063
|
var init_tenant_schema_mapping = __esm({
|
|
270365
271064
|
"../storage/src/tenant-schema-mapping.ts"() {
|
|
270366
271065
|
"use strict";
|
|
270367
|
-
|
|
271066
|
+
import_node_crypto79 = require("node:crypto");
|
|
270368
271067
|
init_esm();
|
|
270369
271068
|
init_pg_ident();
|
|
270370
271069
|
COMPANY_SCHEMA_PREFIX = "c_";
|
|
@@ -270438,7 +271137,7 @@ var init_tenant_schema_mapping = __esm({
|
|
|
270438
271137
|
|
|
270439
271138
|
// ../storage/src/company-data-plane-schema.ts
|
|
270440
271139
|
function canonicalTypeDefHash(def) {
|
|
270441
|
-
return `sha256:${(0,
|
|
271140
|
+
return `sha256:${(0, import_node_crypto80.createHash)("sha256").update(JSON.stringify(def), "utf8").digest("hex")}`;
|
|
270442
271141
|
}
|
|
270443
271142
|
function defaultArtifactTypeTemplate() {
|
|
270444
271143
|
return [
|
|
@@ -270620,11 +271319,11 @@ async function seedDefaultArtifactTypes(pool, schema, templates = defaultArtifac
|
|
|
270620
271319
|
}
|
|
270621
271320
|
return { inserted };
|
|
270622
271321
|
}
|
|
270623
|
-
var
|
|
271322
|
+
var import_node_crypto80, DEFAULT_ARTIFACT_TYPE_TEMPLATE_VERSION;
|
|
270624
271323
|
var init_company_data_plane_schema = __esm({
|
|
270625
271324
|
"../storage/src/company-data-plane-schema.ts"() {
|
|
270626
271325
|
"use strict";
|
|
270627
|
-
|
|
271326
|
+
import_node_crypto80 = require("node:crypto");
|
|
270628
271327
|
init_esm();
|
|
270629
271328
|
init_pg_ident();
|
|
270630
271329
|
DEFAULT_ARTIFACT_TYPE_TEMPLATE_VERSION = "4c368e5c-types-v1";
|
|
@@ -270703,11 +271402,11 @@ function rowToFile2(row) {
|
|
|
270703
271402
|
updatedAt: new Date(row.updated_at).toISOString()
|
|
270704
271403
|
};
|
|
270705
271404
|
}
|
|
270706
|
-
var
|
|
271405
|
+
var import_node_crypto81, COMPANY_CONFLICT_MSG, CompanyIdentifierConflictError, CompanyOwnedRegistryStore;
|
|
270707
271406
|
var init_company_owned_registry_store = __esm({
|
|
270708
271407
|
"../storage/src/company-owned-registry-store.ts"() {
|
|
270709
271408
|
"use strict";
|
|
270710
|
-
|
|
271409
|
+
import_node_crypto81 = require("node:crypto");
|
|
270711
271410
|
init_esm();
|
|
270712
271411
|
init_src();
|
|
270713
271412
|
init_pg_ident();
|
|
@@ -271092,7 +271791,7 @@ var init_company_owned_registry_store = __esm({
|
|
|
271092
271791
|
enabled: skill.enabled,
|
|
271093
271792
|
files: files.map((f2) => ({ path: f2.path, blobHash: f2.blobHash }))
|
|
271094
271793
|
});
|
|
271095
|
-
return (0,
|
|
271794
|
+
return (0, import_node_crypto81.createHash)("sha256").update(body2).digest("hex");
|
|
271096
271795
|
}
|
|
271097
271796
|
};
|
|
271098
271797
|
}
|
|
@@ -273902,7 +274601,7 @@ function sourceSetConservation(input) {
|
|
|
273902
274601
|
return input.sourceFinal === input.copied + input.approvedRuntimeConversion + input.approvedArchive + input.approvedDiscard;
|
|
273903
274602
|
}
|
|
273904
274603
|
function payloadChecksum(value2) {
|
|
273905
|
-
return (0,
|
|
274604
|
+
return (0, import_node_crypto82.createHash)("sha256").update(JSON.stringify(value2)).digest("hex");
|
|
273906
274605
|
}
|
|
273907
274606
|
async function copyWorkorderDraftsIdempotent(pool, companyId, companySchema, manifestId, opts) {
|
|
273908
274607
|
const cs = quoteIdent2(companySchema);
|
|
@@ -274294,11 +274993,11 @@ async function copyTraceFamilyIdempotent(pool, companyId, companySchema, manifes
|
|
|
274294
274993
|
sequences
|
|
274295
274994
|
};
|
|
274296
274995
|
}
|
|
274297
|
-
var
|
|
274996
|
+
var import_node_crypto82, MissingInstallerActorsError, TypeCatalogNotCoveredError, ORG_REGISTRY_TABLES, TRACE_FAMILY;
|
|
274298
274997
|
var init_tenant_migration_operator = __esm({
|
|
274299
274998
|
"../storage/src/tenant-migration-operator.ts"() {
|
|
274300
274999
|
"use strict";
|
|
274301
|
-
|
|
275000
|
+
import_node_crypto82 = require("node:crypto");
|
|
274302
275001
|
init_esm();
|
|
274303
275002
|
init_pg_ident();
|
|
274304
275003
|
init_tenancy_attribution();
|
|
@@ -274534,8 +275233,8 @@ var init_tenant_new_company_provision = __esm({
|
|
|
274534
275233
|
// ../storage/src/knowledge-snapshot-crypto.ts
|
|
274535
275234
|
function sealSnapshot(snapshot, key2) {
|
|
274536
275235
|
if (snapshot.content.startsWith(PREFIX3)) return structuredClone(snapshot);
|
|
274537
|
-
const iv = (0,
|
|
274538
|
-
const cipher = (0,
|
|
275236
|
+
const iv = (0, import_node_crypto83.randomBytes)(12);
|
|
275237
|
+
const cipher = (0, import_node_crypto83.createCipheriv)("aes-256-gcm", bytes(key2), iv);
|
|
274539
275238
|
cipher.setAAD(aad2(snapshot));
|
|
274540
275239
|
const encrypted = Buffer.concat([cipher.update(snapshot.content, "utf8"), cipher.final()]);
|
|
274541
275240
|
return { ...structuredClone(snapshot), content: `${PREFIX3}${iv.toString("base64url")}.${cipher.getAuthTag().toString("base64url")}.${encrypted.toString("base64url")}` };
|
|
@@ -274545,7 +275244,7 @@ function openSnapshot(snapshot, key2) {
|
|
|
274545
275244
|
const packed = snapshot.content.slice(PREFIX3.length).split(".");
|
|
274546
275245
|
if (packed.length !== 3 || packed.some((part) => !part)) throw new Error(`knowledge snapshot ${snapshot.ref} ciphertext is malformed`);
|
|
274547
275246
|
const [iv, tag, data] = packed;
|
|
274548
|
-
const decipher = (0,
|
|
275247
|
+
const decipher = (0, import_node_crypto83.createDecipheriv)("aes-256-gcm", bytes(key2), Buffer.from(iv, "base64url"));
|
|
274549
275248
|
decipher.setAAD(aad2(snapshot));
|
|
274550
275249
|
decipher.setAuthTag(Buffer.from(tag, "base64url"));
|
|
274551
275250
|
return {
|
|
@@ -274553,11 +275252,11 @@ function openSnapshot(snapshot, key2) {
|
|
|
274553
275252
|
content: Buffer.concat([decipher.update(Buffer.from(data, "base64url")), decipher.final()]).toString("utf8")
|
|
274554
275253
|
};
|
|
274555
275254
|
}
|
|
274556
|
-
var
|
|
275255
|
+
var import_node_crypto83, PREFIX3, bytes, aad2;
|
|
274557
275256
|
var init_knowledge_snapshot_crypto = __esm({
|
|
274558
275257
|
"../storage/src/knowledge-snapshot-crypto.ts"() {
|
|
274559
275258
|
"use strict";
|
|
274560
|
-
|
|
275259
|
+
import_node_crypto83 = require("node:crypto");
|
|
274561
275260
|
PREFIX3 = "oasis-knowledge:v1:";
|
|
274562
275261
|
bytes = (key2) => {
|
|
274563
275262
|
const value2 = Buffer.from(key2);
|
|
@@ -275449,7 +276148,7 @@ function reportedCost(v2) {
|
|
|
275449
276148
|
}
|
|
275450
276149
|
function newUsageBackfillManifestId(now = /* @__PURE__ */ new Date()) {
|
|
275451
276150
|
const stamp = now.toISOString().replace(/[-:]/g, "").replace(/\.\d+Z$/, "Z");
|
|
275452
|
-
return `ulb-${stamp}-${(0,
|
|
276151
|
+
return `ulb-${stamp}-${(0, import_node_crypto84.randomBytes)(3).toString("hex")}`;
|
|
275453
276152
|
}
|
|
275454
276153
|
async function backfillUsageLedger(ledger, opts) {
|
|
275455
276154
|
if (!opts.dryRun && !opts.manifestId) throw new Error("execute \u9700\u8981 manifestId");
|
|
@@ -275998,11 +276697,11 @@ async function audit(c, s2, manifestId, runId, field, before, after, createdAt)
|
|
|
275998
276697
|
[manifestId, runId, field, before == null ? null : JSON.stringify(before), after == null ? null : JSON.stringify(after), createdAt]
|
|
275999
276698
|
);
|
|
276000
276699
|
}
|
|
276001
|
-
var
|
|
276700
|
+
var import_node_crypto84, BUCKETS, ENDED_SQL, START_EVIDENCE_SQL, CHAT_RUN_SQL, ALLOWED_MODEL_EVIDENCE_TIERS, emptyStep, MODEL_BACKFILL_SOURCE, fourOf, sameUsage, ChatRunLookup;
|
|
276002
276701
|
var init_usage_ledger_backfill = __esm({
|
|
276003
276702
|
"../storage/src/usage-ledger-backfill.ts"() {
|
|
276004
276703
|
"use strict";
|
|
276005
|
-
|
|
276704
|
+
import_node_crypto84 = require("node:crypto");
|
|
276006
276705
|
init_src();
|
|
276007
276706
|
init_pg_ident();
|
|
276008
276707
|
init_postgres_trace();
|
|
@@ -276581,31 +277280,64 @@ var init_connector_tool_versions = __esm({
|
|
|
276581
277280
|
});
|
|
276582
277281
|
|
|
276583
277282
|
// ../server/src/design/board-watch.ts
|
|
276584
|
-
function
|
|
276585
|
-
if (
|
|
276586
|
-
if (
|
|
276587
|
-
|
|
276588
|
-
if (
|
|
276589
|
-
|
|
276590
|
-
|
|
276591
|
-
|
|
276592
|
-
|
|
277283
|
+
function parseOdTime(v2) {
|
|
277284
|
+
if (typeof v2 === "number") return Number.isFinite(v2) ? v2 : null;
|
|
277285
|
+
if (typeof v2 !== "string" || v2.trim().length === 0) return null;
|
|
277286
|
+
const s2 = v2.trim();
|
|
277287
|
+
if (/^\d+(\.\d+)?$/.test(s2)) return Number(s2);
|
|
277288
|
+
const t = Date.parse(s2);
|
|
277289
|
+
return Number.isFinite(t) ? t : null;
|
|
277290
|
+
}
|
|
277291
|
+
function nonEmpty2(v2) {
|
|
277292
|
+
return typeof v2 === "string" && v2.trim().length > 0 ? v2 : null;
|
|
277293
|
+
}
|
|
277294
|
+
function roundOfMessage(m2, conversationId = null) {
|
|
277295
|
+
if (m2["role"] !== "assistant") return null;
|
|
277296
|
+
const status = nonEmpty2(m2["runStatus"]);
|
|
277297
|
+
if (status === null || !TERMINAL_RUN_STATUS.has(status)) return null;
|
|
277298
|
+
const endedAt = parseOdTime(m2["endedAt"]);
|
|
277299
|
+
if (endedAt === null) return null;
|
|
277300
|
+
const runId = nonEmpty2(m2["runId"]);
|
|
277301
|
+
const messageId = nonEmpty2(m2["id"]);
|
|
277302
|
+
if (runId === null && messageId === null) return null;
|
|
277303
|
+
const files = Array.isArray(m2["producedFiles"]) ? m2["producedFiles"] : [];
|
|
277304
|
+
const producedFiles = files.map((f2) => typeof f2 === "string" ? f2 : f2 && typeof f2 === "object" ? nonEmpty2(f2["path"]) ?? nonEmpty2(f2["name"]) : null).filter((s2) => s2 !== null);
|
|
277305
|
+
const { error: error2, errorCode } = messageError(m2, status);
|
|
277306
|
+
return {
|
|
277307
|
+
key: runId ?? `msg:${messageId}`,
|
|
277308
|
+
conversationId,
|
|
277309
|
+
runId,
|
|
277310
|
+
status,
|
|
277311
|
+
agentId: nonEmpty2(m2["agentId"]),
|
|
277312
|
+
endedAt,
|
|
277313
|
+
producedFiles,
|
|
277314
|
+
error: error2,
|
|
277315
|
+
errorCode
|
|
277316
|
+
};
|
|
277317
|
+
}
|
|
277318
|
+
function messageError(m2, status) {
|
|
277319
|
+
const events = Array.isArray(m2["events"]) ? m2["events"] : [];
|
|
277320
|
+
for (let i = events.length - 1; i >= 0; i--) {
|
|
277321
|
+
const e = events[i];
|
|
277322
|
+
if (!e || typeof e !== "object") continue;
|
|
277323
|
+
const ev = e;
|
|
277324
|
+
if (ev["kind"] !== "status" || ev["label"] !== "error") continue;
|
|
277325
|
+
const detail = nonEmpty2(ev["detail"]);
|
|
277326
|
+
if (detail !== null) return { error: detail, errorCode: nonEmpty2(ev["code"]) };
|
|
277327
|
+
}
|
|
277328
|
+
if (status !== "succeeded") {
|
|
277329
|
+
const content3 = nonEmpty2(m2["content"]);
|
|
277330
|
+
if (content3 !== null) return { error: content3, errorCode: null };
|
|
277331
|
+
}
|
|
277332
|
+
return { error: null, errorCode: null };
|
|
276593
277333
|
}
|
|
276594
|
-
var
|
|
277334
|
+
var RUN_MARKER_PREFIX, boardWatchRunMarker, parseRunMarker, SINCE_MARKER_PREFIX, boardWatchSinceMarker, parseSinceMarker, TERMINAL_RUN_STATUS, MAX_REASON_CHARS, MAX_LISTED_FILES, BoardWatcher;
|
|
276595
277335
|
var init_board_watch = __esm({
|
|
276596
277336
|
"../server/src/design/board-watch.ts"() {
|
|
276597
277337
|
"use strict";
|
|
276598
277338
|
init_src7();
|
|
276599
|
-
MARKER_PREFIX = "[od-board-watch mtime:";
|
|
276600
|
-
boardWatchMarker = (mtimeMs) => `${MARKER_PREFIX}${mtimeMs}]`;
|
|
276601
|
-
parseMarker = (body2) => {
|
|
276602
|
-
const i = body2.indexOf(MARKER_PREFIX);
|
|
276603
|
-
if (i < 0) return null;
|
|
276604
|
-
const n = Number.parseInt(body2.slice(i + MARKER_PREFIX.length), 10);
|
|
276605
|
-
return Number.isFinite(n) ? n : null;
|
|
276606
|
-
};
|
|
276607
277339
|
RUN_MARKER_PREFIX = "[od-board-watch run:";
|
|
276608
|
-
boardWatchRunMarker = (
|
|
277340
|
+
boardWatchRunMarker = (roundKey) => `${RUN_MARKER_PREFIX}${roundKey}]`;
|
|
276609
277341
|
parseRunMarker = (body2) => {
|
|
276610
277342
|
const i = body2.indexOf(RUN_MARKER_PREFIX);
|
|
276611
277343
|
if (i < 0) return null;
|
|
@@ -276614,113 +277346,183 @@ var init_board_watch = __esm({
|
|
|
276614
277346
|
const id = body2.slice(i + RUN_MARKER_PREFIX.length, j);
|
|
276615
277347
|
return id.length > 0 ? id : null;
|
|
276616
277348
|
};
|
|
277349
|
+
SINCE_MARKER_PREFIX = "[od-board-watch since:";
|
|
277350
|
+
boardWatchSinceMarker = (sinceMs) => `${SINCE_MARKER_PREFIX}${sinceMs}]`;
|
|
277351
|
+
parseSinceMarker = (body2) => {
|
|
277352
|
+
const i = body2.indexOf(SINCE_MARKER_PREFIX);
|
|
277353
|
+
if (i < 0) return null;
|
|
277354
|
+
const n = Number.parseInt(body2.slice(i + SINCE_MARKER_PREFIX.length), 10);
|
|
277355
|
+
return Number.isFinite(n) ? n : null;
|
|
277356
|
+
};
|
|
276617
277357
|
TERMINAL_RUN_STATUS = /* @__PURE__ */ new Set(["succeeded", "failed", "canceled", "cancelled"]);
|
|
277358
|
+
MAX_REASON_CHARS = 500;
|
|
277359
|
+
MAX_LISTED_FILES = 10;
|
|
276618
277360
|
BoardWatcher = class {
|
|
276619
277361
|
constructor(deps) {
|
|
276620
277362
|
this.deps = deps;
|
|
276621
|
-
|
|
276622
|
-
|
|
277363
|
+
if (!deps.kernel && !(deps.listCompanies && deps.kernelFor)) throw new Error("BoardWatcher \u9700\u8981 kernel\uFF0C\u6216 listCompanies + kernelFor");
|
|
277364
|
+
}
|
|
277365
|
+
/** `<公司>\0<artifactId>` → 本进程第一次读成功时钉住的起算点(还没写过带 since 的信时用),免得在第一封信之前随时间往后漂。 */
|
|
277366
|
+
pinnedSince = /* @__PURE__ */ new Map();
|
|
277367
|
+
/** `<公司>\0<boardKey>\0<conversationId>` → 本进程上次把这个对话的轮次处理完时它的 updatedAt。 */
|
|
277368
|
+
seenConvAt = /* @__PURE__ */ new Map();
|
|
277369
|
+
/** 公司 → 上次记下的失败原文(同样的错只记一次;成功一轮就清掉)。 */
|
|
277370
|
+
companyLastError = /* @__PURE__ */ new Map();
|
|
277371
|
+
async odGet(path47) {
|
|
276623
277372
|
const fetchImpl = this.deps.fetchImpl ?? fetch;
|
|
276624
|
-
return fetchImpl(`${this.deps.odBase}${path47}`, this.deps.odToken ? { headers: { authorization: `Bearer ${this.deps.odToken}` } } : void 0);
|
|
276625
|
-
}
|
|
276626
|
-
/** 查一块板的交付物(排 task-context/、只算带 artifactManifest 的)。404/网络错 → null(板不存在)。 */
|
|
276627
|
-
async boardFiles(boardKey) {
|
|
276628
277373
|
try {
|
|
276629
|
-
const res = await this.
|
|
276630
|
-
if (
|
|
276631
|
-
|
|
276632
|
-
|
|
276633
|
-
|
|
276634
|
-
|
|
277374
|
+
const res = await fetchImpl(`${this.deps.odBase}${path47}`, this.deps.odToken ? { headers: { authorization: `Bearer ${this.deps.odToken}` } } : void 0);
|
|
277375
|
+
if (res.status === 401 || res.status === 403) return { kind: "denied", status: res.status };
|
|
277376
|
+
if (res.status === 404) return { kind: "missing" };
|
|
277377
|
+
if (!res.ok) return { kind: "error", detail: `HTTP ${res.status}` };
|
|
277378
|
+
return { kind: "ok", value: await res.json() };
|
|
277379
|
+
} catch (err) {
|
|
277380
|
+
return { kind: "error", detail: String(err) };
|
|
276635
277381
|
}
|
|
276636
277382
|
}
|
|
276637
277383
|
/**
|
|
276638
|
-
*
|
|
276639
|
-
*
|
|
276640
|
-
*
|
|
277384
|
+
* 列出一块板上结束时间可能晚于 since 的轮次(跨对话;顺序不重要,调用方按 endedAt 排)。
|
|
277385
|
+
*
|
|
277386
|
+
* 省流:od 的 assistant 消息带整段 events 与 content,每分钟把每个对话的 /messages 全拉一遍,轮次多的板
|
|
277387
|
+
* 一分钟就是几 MB。所以先用 /conversations 列表里的 updatedAt / latestRun.endedAt(取较大)筛:
|
|
277388
|
+
* - 不晚于 since → 这个对话里不可能有要写信的轮次,跳过;
|
|
277389
|
+
* - 和本进程上次看完时一样 → 没变,跳过(seenConvAt,serve 重启即清空,退回只按 since 筛,run marker 去重兜着)。
|
|
277390
|
+
* 两个时间都没有的对话照拉,不猜。返回每个拉过的对话的 updatedAt,由 tick 在它的轮次都写完信后记进 seenConvAt。
|
|
276641
277391
|
*/
|
|
276642
|
-
async
|
|
276643
|
-
|
|
276644
|
-
|
|
276645
|
-
|
|
276646
|
-
|
|
276647
|
-
|
|
276648
|
-
|
|
276649
|
-
|
|
276650
|
-
|
|
277392
|
+
async boardRounds(company, boardKey, since) {
|
|
277393
|
+
const base = `/api/projects/${encodeURIComponent(boardKey)}/conversations`;
|
|
277394
|
+
const convs = await this.odGet(base);
|
|
277395
|
+
if (convs.kind !== "ok") return convs;
|
|
277396
|
+
const rounds = [];
|
|
277397
|
+
const fetched = /* @__PURE__ */ new Map();
|
|
277398
|
+
for (const c of convs.value.conversations ?? []) {
|
|
277399
|
+
const cid = nonEmpty2(c["id"]);
|
|
277400
|
+
if (cid === null) continue;
|
|
277401
|
+
const latestRun = c["latestRun"] && typeof c["latestRun"] === "object" ? c["latestRun"] : {};
|
|
277402
|
+
const times = [parseOdTime(c["updatedAt"]), parseOdTime(latestRun["endedAt"])].filter((t) => t !== null);
|
|
277403
|
+
const convAt = times.length > 0 ? Math.max(...times) : null;
|
|
277404
|
+
if (convAt !== null && (convAt <= since || this.seenConvAt.get(`${company}\0${boardKey}\0${cid}`) === convAt)) continue;
|
|
277405
|
+
const msgs = await this.odGet(`${base}/${encodeURIComponent(cid)}/messages`);
|
|
277406
|
+
if (msgs.kind === "missing") continue;
|
|
277407
|
+
if (msgs.kind !== "ok") return msgs;
|
|
277408
|
+
fetched.set(cid, convAt);
|
|
277409
|
+
for (const m2 of msgs.value.messages ?? []) {
|
|
277410
|
+
if (!m2 || typeof m2 !== "object") continue;
|
|
277411
|
+
const r = roundOfMessage(m2, cid);
|
|
277412
|
+
if (r !== null) rounds.push(r);
|
|
277413
|
+
}
|
|
277414
|
+
}
|
|
277415
|
+
return { kind: "ok", value: { rounds, fetched } };
|
|
277416
|
+
}
|
|
277417
|
+
/** 失败轮消息上没有错误原文时,去 `/api/runs` 按 runId 找 od 记的 error;找不到(含 od 重启过)→ null。 */
|
|
277418
|
+
async runErrorFromRegistry(boardKey, runId) {
|
|
277419
|
+
const res = await this.odGet(`/api/runs?projectId=${encodeURIComponent(boardKey)}`);
|
|
277420
|
+
if (res.kind !== "ok") return null;
|
|
277421
|
+
const hit = (res.value.runs ?? []).find((r) => String(r["runId"] ?? r["id"] ?? "") === runId);
|
|
277422
|
+
return hit ? nonEmpty2(hit["error"]) : null;
|
|
276651
277423
|
}
|
|
276652
277424
|
async tick(now = Date.now()) {
|
|
276653
|
-
const {
|
|
276654
|
-
const
|
|
277425
|
+
const { log: log3 } = this.deps;
|
|
277426
|
+
const denied = [];
|
|
277427
|
+
const { listCompanies, kernelFor } = this.deps;
|
|
277428
|
+
if (listCompanies && kernelFor) {
|
|
277429
|
+
for (const companyId of await listCompanies()) {
|
|
277430
|
+
try {
|
|
277431
|
+
await this.tickCompany(companyId, await kernelFor(companyId), now, denied);
|
|
277432
|
+
this.companyLastError.delete(companyId);
|
|
277433
|
+
} catch (err) {
|
|
277434
|
+
const msg = String(err);
|
|
277435
|
+
if (this.companyLastError.get(companyId) === msg) continue;
|
|
277436
|
+
this.companyLastError.set(companyId, msg);
|
|
277437
|
+
log3?.(`[board-watch] [${companyId}] \u8FD9\u4E00\u8F6E\u6CA1\u5DE1\u6210\uFF08\u5176\u4F59\u516C\u53F8\u7EE7\u7EED\uFF09\uFF1A${msg}`);
|
|
277438
|
+
}
|
|
277439
|
+
}
|
|
277440
|
+
} else {
|
|
277441
|
+
await this.tickCompany("", this.deps.kernel, now, denied);
|
|
277442
|
+
}
|
|
277443
|
+
if (denied.length > 0) {
|
|
277444
|
+
const codes = [...new Set(denied.map((d) => d.status))].join("/");
|
|
277445
|
+
const eg = denied[0];
|
|
277446
|
+
log3?.(
|
|
277447
|
+
`[board-watch] od \u62D2\u7EDD\u4E86\u5DE1\u68C0\u8BF7\u6C42\uFF08HTTP ${codes}\uFF0C${denied.length} \u5757\u677F\uFF0C\u5982 ${eg.company ? `[${eg.company}] ` : ""}${eg.boardKey}\uFF09\uFF1A${this.deps.odToken ? "\u5E26\u4E86 OASIS_OPEN_DESIGN_TOKEN \u4F46 od \u4E0D\u8BA4\uFF0C\u6838\u5BF9\u5B83\u4E0E od \u7684 OD_API_TOKEN \u662F\u5426\u4E00\u81F4" : "\u6CA1\u914D OASIS_OPEN_DESIGN_TOKEN\uFF0Cod \u8981\u4EE4\u724C"}\u3002\u8FD9\u4E9B\u677F\u672C\u8F6E\u6CA1\u770B\u6210`
|
|
277448
|
+
);
|
|
277449
|
+
}
|
|
277450
|
+
}
|
|
277451
|
+
/** 巡一家公司(company 为空串 = 单 kernel 模式);被拒的板记进 denied,由 tick 统一汇总成一行。 */
|
|
277452
|
+
async tickCompany(company, kernel, now, denied) {
|
|
277453
|
+
const { boardKeyOf, log: log3 } = this.deps;
|
|
277454
|
+
const graceMs = this.deps.firstLookGraceMs ?? 10 * 6e4;
|
|
276655
277455
|
const maxPerTick = this.deps.maxLettersPerTick ?? 2;
|
|
276656
277456
|
const actor = this.deps.actor ?? "actor:system";
|
|
277457
|
+
const tag = company ? `[${company}] ` : "";
|
|
276657
277458
|
const model = kernel.model;
|
|
276658
277459
|
let written = 0;
|
|
276659
|
-
for (const a of model.artifacts.values()) {
|
|
276660
|
-
if (a.type !== "design") continue;
|
|
276661
|
-
if (lifecycleOf(model, a.id) !== "active") continue;
|
|
277460
|
+
for (const a of [...model.artifacts.values()]) {
|
|
276662
277461
|
if (written >= maxPerTick) {
|
|
276663
|
-
log3?.(`[board-watch] \u672C\u8F6E\u5199\u4FE1\u5DF2\u8FBE\u4E0A\u9650 ${maxPerTick}\uFF0C\u5176\u4F59\u677F\u4E0B\u8F6E\u518D\u770B`);
|
|
277462
|
+
log3?.(`[board-watch] ${tag}\u672C\u8F6E\u5199\u4FE1\u5DF2\u8FBE\u4E0A\u9650 ${maxPerTick}\uFF0C\u5176\u4F59\u677F\u4E0B\u8F6E\u518D\u770B`);
|
|
276664
277463
|
break;
|
|
276665
277464
|
}
|
|
277465
|
+
if (a.type !== "design") continue;
|
|
277466
|
+
if (lifecycleOf(model, a.id) !== "active") continue;
|
|
276666
277467
|
const boardKey = boardKeyOf(a.id);
|
|
276667
|
-
const
|
|
276668
|
-
|
|
276669
|
-
const
|
|
276670
|
-
|
|
276671
|
-
|
|
276672
|
-
|
|
276673
|
-
|
|
276674
|
-
);
|
|
276675
|
-
const
|
|
276676
|
-
|
|
276677
|
-
)
|
|
276678
|
-
|
|
276679
|
-
|
|
276680
|
-
const candidate = {
|
|
276681
|
-
boardMtime,
|
|
276682
|
-
hasRevision: revisionsOf(model, a.id).length > 0,
|
|
276683
|
-
lastOpAtMs: lastOpAt ? Date.parse(lastOpAt) : null,
|
|
276684
|
-
hasOpenWatchLetter: watchLetters.some((x2) => x2.state === "open"),
|
|
276685
|
-
lastWatchMtime: watchLetters.reduce((mx, x2) => {
|
|
276686
|
-
const m2 = parseMarker(x2.body);
|
|
276687
|
-
return m2 !== null && (mx === null || m2 > mx) ? m2 : mx;
|
|
276688
|
-
}, null),
|
|
276689
|
-
freshTerminalRunId: newestTerminalRun !== null && !letteredRuns.has(newestTerminalRun.runId) ? newestTerminalRun.runId : null
|
|
276690
|
-
};
|
|
276691
|
-
if (!decideBoardLetter(candidate, now, quietMs)) continue;
|
|
276692
|
-
const fmt = (fs52) => fs52.slice(0, 5).map((f2) => `- ${f2.path}\uFF08${f2.kind ?? "?"}\uFF09\xB7 ${f2.mtime ? new Date(f2.mtime).toISOString() : "?"}`).join("\n");
|
|
276693
|
-
let body2;
|
|
276694
|
-
let logLine;
|
|
276695
|
-
if (candidate.freshTerminalRunId !== null) {
|
|
276696
|
-
const status = newestTerminalRun.status;
|
|
276697
|
-
const ok3 = status === "succeeded";
|
|
276698
|
-
const listed = files.length > 0 ? fmt([...files].sort((x2, y) => (y.mtime ?? 0) - (x2.mtime ?? 0))) : "\uFF08\u677F\u4E0A\u6682\u65E0\u4EA4\u4ED8\u7269\uFF09";
|
|
276699
|
-
body2 = [
|
|
276700
|
-
// 两个 marker 都带:run marker 管快路径去重,mtime marker 顺手把慢路径也盖住——
|
|
276701
|
-
// 否则这封信被 resolve 后,慢路径会就**同一批板内容**再写一封(两路去重各管各的)。
|
|
276702
|
-
boardMtime !== null ? `${boardWatchRunMarker(candidate.freshTerminalRunId)} ${boardWatchMarker(boardMtime)}` : boardWatchRunMarker(candidate.freshTerminalRunId),
|
|
276703
|
-
ok3 ? `\u753B\u677F ${boardKey} \u7684\u5F15\u64CE\u8DD1\u5B8C\u4E86\uFF08run ${candidate.freshTerminalRunId.slice(0, 8)} \u7EC8\u6001=${status}\uFF09\uFF0C\u8D27\u5728\u677F\u4E0A\u7B49\u4F60\u6536\uFF1A` : `\u753B\u677F ${boardKey} \u7684\u5F15\u64CE\u8FD9\u4E00\u8F6E**\u6CA1\u8DD1\u6210**\uFF08run ${candidate.freshTerminalRunId.slice(0, 8)} \u7EC8\u6001=${status}\uFF09\u3002\u677F\u4E0A\u5F53\u524D\u5185\u5BB9\uFF1A`,
|
|
276704
|
-
listed,
|
|
276705
|
-
``,
|
|
276706
|
-
ok3 ? `\u53D6\u8D27\u6838\u5BF9\uFF1A\`oasis design status ${a.id} --pull\` \u2192 \u5BF9\u7740 DESIGN_BRIEF.md \u4E0E inputs/ \u9010\u5B57\u6BB5\u6838\uFF08\u6570\u636E\u5BF9\u4E0D\u5BF9\u3001\u72B6\u6001\u5168\u4E0D\u5168\u3001\u6709\u6CA1\u6709\u7F16\u9020\uFF09\u3002\u591F\u597D\u5C31 \`oasis propose ${a.id} --from-dir <\u76EE\u5F55> --reason "<\u8FD9\u7248\u505A\u4E86\u4EC0\u4E48>"\`\uFF1B\u8981\u6539\u5C31\u56DE\u677F\u4E0A\u518D\u6765\u4E00\u8F6E \`oasis design chat ${a.id} --turn continue --message "<\u8981\u6539\u4EC0\u4E48>" --async\`\uFF08\u26D4 \u522B\u628A --pull \u4E0B\u6765\u7684\u6587\u4EF6\u5728\u672C\u5730\u624B\u6539\u540E propose\uFF09\u3002` : `\u5148 \`oasis design status ${a.id}\` \u770B\u677F\u4E0A\u6709\u6CA1\u6709\u53EF\u7528\u7684\u4E0A\u4E00\u7248\uFF1A\u6709\u5C31\u7167\u5E38\u53D6\u8D27\u6838\u5BF9\uFF1B\u6CA1\u6709\u5C31\u628A\u9700\u6C42\u4E0E\u771F\u5B9E\u6570\u636E\u9489\u5F97\u66F4\u6B7B\u540E\u91CD\u8D77\u4E00\u8F6E \`oasis design chat ${a.id} --message "<\u2026>" --async\`\uFF0C\u4ECD\u4E0D\u884C\u7528 \`oasis gap ${a.id} --desc "<\u5361\u5728\u54EA>"\` \u5192\u6CE1\u7ED9\u4EBA\u3002`
|
|
276707
|
-
].join("\n");
|
|
276708
|
-
logLine = `[board-watch] ${a.id} \u2190 \u677F ${boardKey} \u5F15\u64CE\u6536\u5C3E\uFF08run ${candidate.freshTerminalRunId.slice(0, 8)} ${status}\uFF09\u2192 \u5DF2\u5199\u4FE1\u5524 owner`;
|
|
276709
|
-
} else {
|
|
276710
|
-
const newest = files.filter((f2) => f2.mtime !== null && candidate.lastOpAtMs !== null && f2.mtime > candidate.lastOpAtMs).sort((x2, y) => (y.mtime ?? 0) - (x2.mtime ?? 0));
|
|
276711
|
-
body2 = [
|
|
276712
|
-
boardWatchMarker(boardMtime),
|
|
276713
|
-
`\u753B\u677F ${boardKey} \u4E0A\u6709 Oasis \u4E4B\u5916\u7684\u65B0\u52A8\u9759\uFF08\u4EBA\u5728\u677F\u4E0A\u5BF9\u8BDD/\u6539\u7A3F\uFF0C\u6216\u5F15\u64CE\u4EA7\u4E86\u6CA1\u4EBA\u6536\u7684\u65B0\u7248\uFF09\uFF0C\u6BD4\u672C\u4EA7\u7269\u6700\u8FD1\u4E00\u6B21\u64CD\u4F5C\uFF08${lastOpAt ?? "?"}\uFF09\u65B0\u3001\u4E14\u5DF2\u9759\u9ED8 ${Math.round(quietMs / 6e4)} \u5206\u949F\uFF1A`,
|
|
276714
|
-
fmt(newest.length > 0 ? newest : files),
|
|
276715
|
-
``,
|
|
276716
|
-
`\u8BF7\u53D6\u8D27\u6838\u5BF9\uFF1A\`oasis design status ${a.id} --pull\` \u2192 \u5185\u5BB9\u5408\u610F\u5C31 \`oasis propose ${a.id} --from-dir <\u76EE\u5F55> --reason "<\u6536\u5F55\u677F\u4E0A\u4EBA\u5DE5\u8FED\u4EE3>"\` \u6536\u5F55\u4E3A\u65B0\u7248\u672C\uFF1B\u4E0D\u5408\u610F/\u4E0D\u5FC5\u6536\u5F55\uFF0C\u56DE\u5E16\u8BF4\u660E\u540E\u6309 wontfix \u5904\u7406\u5373\u53EF\uFF08\u540C\u4E00\u7248\u4E0D\u4F1A\u518D\u6765\u4FE1\uFF09\u3002`
|
|
276717
|
-
].join("\n");
|
|
276718
|
-
logLine = `[board-watch] ${a.id} \u2190 \u677F ${boardKey} \u6709\u65B0\u5185\u5BB9\uFF08mtime=${new Date(boardMtime).toISOString()}\uFF09\u2192 \u5DF2\u5199\u4FE1\u5524 owner`;
|
|
277468
|
+
const pinKey = `${company}\0${a.id}`;
|
|
277469
|
+
const watchLetters = annotationsOf(model, a.id).filter((x2) => x2.author === actor && x2.body.includes("[od-board-watch "));
|
|
277470
|
+
const lettered = new Set(watchLetters.map((x2) => parseRunMarker(x2.body)).filter((s2) => s2 !== null));
|
|
277471
|
+
const recordedSince = watchLetters.reduce((mn, x2) => {
|
|
277472
|
+
const s2 = parseSinceMarker(x2.body);
|
|
277473
|
+
return s2 !== null && (mn === null || s2 < mn) ? s2 : mn;
|
|
277474
|
+
}, null);
|
|
277475
|
+
const since = recordedSince ?? this.pinnedSince.get(pinKey) ?? now - graceMs;
|
|
277476
|
+
const read3 = await this.boardRounds(company, boardKey, since);
|
|
277477
|
+
if (read3.kind === "missing") continue;
|
|
277478
|
+
if (read3.kind === "denied") {
|
|
277479
|
+
denied.push({ company, boardKey, status: read3.status });
|
|
277480
|
+
continue;
|
|
276719
277481
|
}
|
|
276720
|
-
|
|
276721
|
-
|
|
276722
|
-
|
|
277482
|
+
if (read3.kind === "error") {
|
|
277483
|
+
log3?.(`[board-watch] ${tag}\u8BFB\u753B\u677F ${boardKey} \u5931\u8D25\uFF08${read3.detail}\uFF09\uFF0C\u672C\u8F6E\u8DF3\u8FC7`);
|
|
277484
|
+
continue;
|
|
277485
|
+
}
|
|
277486
|
+
if (recordedSince === null && !this.pinnedSince.has(pinKey)) this.pinnedSince.set(pinKey, since);
|
|
277487
|
+
const fresh = read3.value.rounds.filter((r) => r.endedAt > since && !lettered.has(r.key)).sort((x2, y) => x2.endedAt - y.endedAt);
|
|
277488
|
+
const seen = /* @__PURE__ */ new Set();
|
|
277489
|
+
for (const r of fresh) {
|
|
277490
|
+
if (written >= maxPerTick) break;
|
|
277491
|
+
if (seen.has(r.key)) continue;
|
|
277492
|
+
seen.add(r.key);
|
|
277493
|
+
const ok3 = r.status === "succeeded";
|
|
277494
|
+
const reason = ok3 ? null : r.error ?? (r.runId !== null ? await this.runErrorFromRegistry(boardKey, r.runId) : null);
|
|
277495
|
+
await kernel.annotate({ artifactId: a.id, actor, body: this.letterBody(a.id, boardKey, r, since, reason), kind: "comment" });
|
|
277496
|
+
written++;
|
|
277497
|
+
log3?.(`[board-watch] ${tag}${a.id} \u2190 \u677F ${boardKey} \u4E00\u8F6E\u5BF9\u8BDD\u7ED3\u675F\uFF08${r.key.slice(0, 12)} ${r.status}${r.agentId ? ` ${r.agentId}` : ""}\uFF09\u2192 \u5DF2\u5199\u4FE1\u5524 owner`);
|
|
277498
|
+
}
|
|
277499
|
+
const pending = new Set(fresh.filter((r) => !seen.has(r.key)).map((r) => r.conversationId));
|
|
277500
|
+
for (const [cid, convAt] of read3.value.fetched) {
|
|
277501
|
+
if (convAt !== null && !pending.has(cid)) this.seenConvAt.set(`${company}\0${boardKey}\0${cid}`, convAt);
|
|
277502
|
+
}
|
|
277503
|
+
}
|
|
277504
|
+
}
|
|
277505
|
+
letterBody(artifactId, boardKey, r, since, reason) {
|
|
277506
|
+
const marker = `${boardWatchRunMarker(r.key)} ${boardWatchSinceMarker(since)}`;
|
|
277507
|
+
const round = `${r.runId !== null ? `run ${r.runId.slice(0, 8)}` : `\u6D88\u606F ${r.key.slice(4, 12)}`}\uFF0C\u5F15\u64CE=${r.agentId ?? "?"}\uFF0C\u7ED3\u675F\u4E8E ${new Date(r.endedAt).toISOString()}`;
|
|
277508
|
+
if (r.status === "succeeded") {
|
|
277509
|
+
const files = r.producedFiles.length > 0 ? [...r.producedFiles.slice(0, MAX_LISTED_FILES).map((f2) => `- ${f2}`), ...r.producedFiles.length > MAX_LISTED_FILES ? [`- \u2026\u53E6 ${r.producedFiles.length - MAX_LISTED_FILES} \u4E2A`] : []].join("\n") : "\uFF08\u8FD9\u4E00\u8F6E\u6CA1\u6709\u767B\u8BB0\u4EA7\u51FA\u6587\u4EF6\uFF09";
|
|
277510
|
+
return [
|
|
277511
|
+
marker,
|
|
277512
|
+
`\u753B\u677F ${boardKey} \u4E0A\u6709\u4E00\u8F6E\u5BF9\u8BDD\u8DD1\u5B8C\u4E86\uFF08${round}\uFF09\uFF0C\u8FD9\u4E00\u8F6E\u4EA7\u51FA\uFF1A`,
|
|
277513
|
+
files,
|
|
277514
|
+
``,
|
|
277515
|
+
`\u53D6\u8D27\u6838\u5BF9\uFF1A\`oasis design status ${artifactId} --pull\` \u2192 \u5BF9\u7740 DESIGN_BRIEF.md \u4E0E inputs/ \u9010\u5B57\u6BB5\u6838\uFF08\u6570\u636E\u5BF9\u4E0D\u5BF9\u3001\u72B6\u6001\u5168\u4E0D\u5168\u3001\u6709\u6CA1\u6709\u7F16\u9020\uFF09\u3002\u591F\u597D\u5C31 \`oasis propose ${artifactId} --from-dir <\u76EE\u5F55> --reason "<\u8FD9\u7248\u505A\u4E86\u4EC0\u4E48>"\`\uFF1B\u8981\u6539\u5C31\u56DE\u677F\u4E0A\u518D\u6765\u4E00\u8F6E \`oasis design chat ${artifactId} --turn continue --message "<\u8981\u6539\u4EC0\u4E48>" --async\`\uFF08\u26D4 \u522B\u628A --pull \u4E0B\u6765\u7684\u6587\u4EF6\u5728\u672C\u5730\u624B\u6539\u540E propose\uFF09\u3002\u8FD9\u4E00\u8F6E\u82E5\u662F\u4EBA\u76F4\u63A5\u5728\u677F\u4E0A\u804A\u51FA\u6765\u7684\u3001\u5185\u5BB9\u4E0D\u5FC5\u6536\u5F55\uFF0C\u56DE\u5E16\u8BF4\u660E\u540E\u6309 wontfix \u5904\u7406\u5373\u53EF\uFF08\u540C\u4E00\u8F6E\u4E0D\u4F1A\u518D\u6765\u4FE1\uFF09\u3002`
|
|
277516
|
+
].join("\n");
|
|
276723
277517
|
}
|
|
277518
|
+
const quoted = reason === null ? null : reason.length > MAX_REASON_CHARS ? `${reason.slice(0, MAX_REASON_CHARS)}\u2026` : reason;
|
|
277519
|
+
return [
|
|
277520
|
+
marker,
|
|
277521
|
+
`\u753B\u677F ${boardKey} \u4E0A\u6709\u4E00\u8F6E\u5BF9\u8BDD**\u6CA1\u8DD1\u6210**\uFF08\u7EC8\u6001=${r.status}\uFF0C${round}\uFF09\u3002`,
|
|
277522
|
+
quoted !== null ? `od \u8BB0\u7684\u539F\u56E0\uFF08\u539F\u6587\uFF09\uFF1A${quoted}${r.errorCode !== null ? `\uFF08\u9519\u8BEF\u7801 ${r.errorCode}\uFF09` : ""}` : `od \u6CA1\u6709\u8BB0\u5F55\u8FD9\u4E00\u8F6E\u7684\u5931\u8D25\u539F\u56E0\u3002`,
|
|
277523
|
+
``,
|
|
277524
|
+
`\u5148 \`oasis design status ${artifactId}\` \u770B\u677F\u4E0A\u6709\u6CA1\u6709\u53EF\u7528\u7684\u4E0A\u4E00\u7248\uFF1A\u6709\u5C31\u7167\u5E38\u53D6\u8D27\u6838\u5BF9\u3002\u8981\u91CD\u8DD1\u5C31\u81EA\u5DF1\u5224\u65AD\uFF1A\u50CF\u662F\u989D\u5EA6/\u9650\u6D41\u5C31\u7B49\u6062\u590D\u540E\u518D\u6765\uFF0C\u6216\u6362\u4E2A\u5F15\u64CE \`oasis design chat ${artifactId} --agent <\u5F15\u64CE> --message "<\u2026>" --async\`\uFF1B\u50CF\u662F\u9700\u6C42/\u6570\u636E\u95EE\u9898\u5C31\u628A\u5B83\u4EEC\u9489\u5F97\u66F4\u6B7B\u540E\u91CD\u8D77\u4E00\u8F6E\uFF1B\u4ECD\u4E0D\u884C\u7528 \`oasis gap ${artifactId} --desc "<\u5361\u5728\u54EA>"\` \u5192\u6CE1\u7ED9\u4EBA\u3002`
|
|
277525
|
+
].join("\n");
|
|
276724
277526
|
}
|
|
276725
277527
|
};
|
|
276726
277528
|
}
|
|
@@ -277602,8 +278404,8 @@ __export(src_exports2, {
|
|
|
277602
278404
|
bindWorkorderProject: () => bindWorkorderProject,
|
|
277603
278405
|
bindingResolverFromRegistry: () => bindingResolverFromRegistry,
|
|
277604
278406
|
bindingRuntimeState: () => bindingRuntimeState,
|
|
277605
|
-
boardWatchMarker: () => boardWatchMarker,
|
|
277606
278407
|
boardWatchRunMarker: () => boardWatchRunMarker,
|
|
278408
|
+
boardWatchSinceMarker: () => boardWatchSinceMarker,
|
|
277607
278409
|
broadcastMessageId: () => broadcastMessageId,
|
|
277608
278410
|
broadcastMessageText: () => broadcastMessageText,
|
|
277609
278411
|
bucketRuntimeRuns: () => bucketRuntimeRuns,
|
|
@@ -277707,7 +278509,6 @@ __export(src_exports2, {
|
|
|
277707
278509
|
cronNext: () => cronNext,
|
|
277708
278510
|
cronNextN: () => cronNextN,
|
|
277709
278511
|
deadlineClockTick: () => deadlineClockTick,
|
|
277710
|
-
decideBoardLetter: () => decideBoardLetter,
|
|
277711
278512
|
defaultAvatarRefOf: () => defaultAvatarRefOf,
|
|
277712
278513
|
delegationArtifactsView: () => delegationArtifactsView,
|
|
277713
278514
|
delegationBundleAdditions: () => delegationBundleAdditions,
|
|
@@ -277858,6 +278659,7 @@ __export(src_exports2, {
|
|
|
277858
278659
|
parseConnectorSkillId: () => parseConnectorSkillId,
|
|
277859
278660
|
parseKnowledgeAnswerOutput: () => parseKnowledgeAnswerOutput,
|
|
277860
278661
|
parseKnowledgePlan: () => parseKnowledgePlan,
|
|
278662
|
+
parseOdTime: () => parseOdTime,
|
|
277861
278663
|
parseReadScope: () => parseReadScope,
|
|
277862
278664
|
parseSkillFrontmatter: () => parseSkillFrontmatter,
|
|
277863
278665
|
parseSymrefHead: () => parseSymrefHead,
|
|
@@ -277947,6 +278749,7 @@ __export(src_exports2, {
|
|
|
277947
278749
|
retireCdGateInTypeStore: () => retireCdGateInTypeStore,
|
|
277948
278750
|
rolesDomain: () => rolesDomain,
|
|
277949
278751
|
rollbackOrgIdentity: () => rollbackOrgIdentity,
|
|
278752
|
+
roundOfMessage: () => roundOfMessage,
|
|
277950
278753
|
routeFusedSignal: () => routeFusedSignal,
|
|
277951
278754
|
runtimeConnectionStatus: () => runtimeConnectionStatus,
|
|
277952
278755
|
runtimeDriftBlock: () => runtimeDriftBlock,
|
|
@@ -278512,14 +279315,14 @@ init_src();
|
|
|
278512
279315
|
var os16 = __toESM(require("node:os"));
|
|
278513
279316
|
var path46 = __toESM(require("node:path"));
|
|
278514
279317
|
var import_node_child_process26 = require("node:child_process");
|
|
278515
|
-
var
|
|
279318
|
+
var import_node_crypto95 = require("node:crypto");
|
|
278516
279319
|
|
|
278517
279320
|
// ../cli/src/cli.ts
|
|
278518
279321
|
init_src();
|
|
278519
279322
|
var fs44 = __toESM(require("node:fs"), 1);
|
|
278520
279323
|
var os13 = __toESM(require("node:os"), 1);
|
|
278521
279324
|
var path39 = __toESM(require("node:path"), 1);
|
|
278522
|
-
var
|
|
279325
|
+
var import_node_crypto93 = require("node:crypto");
|
|
278523
279326
|
|
|
278524
279327
|
// ../cli/src/serve.ts
|
|
278525
279328
|
init_src11();
|
|
@@ -278531,11 +279334,11 @@ var fs36 = __toESM(require("node:fs"), 1);
|
|
|
278531
279334
|
var os9 = __toESM(require("node:os"), 1);
|
|
278532
279335
|
var path30 = __toESM(require("node:path"), 1);
|
|
278533
279336
|
var import_node_child_process18 = require("node:child_process");
|
|
278534
|
-
var
|
|
279337
|
+
var import_node_crypto89 = require("node:crypto");
|
|
278535
279338
|
var import_node_url7 = require("node:url");
|
|
278536
279339
|
|
|
278537
279340
|
// ../cli/src/artifact-discovery-source.ts
|
|
278538
|
-
var
|
|
279341
|
+
var import_node_crypto85 = require("node:crypto");
|
|
278539
279342
|
init_src7();
|
|
278540
279343
|
var ArtifactDiscoverySourceUnreadableError = class extends Error {
|
|
278541
279344
|
constructor(message) {
|
|
@@ -278565,7 +279368,7 @@ async function resolveArtifactDiscoverySourceContent(blobs, input) {
|
|
|
278565
279368
|
throw new ArtifactDiscoverySourceUnreadableError(`Artifact Revision ${input.revisionId} \u7684 contentKind \u4E0D\u53D7\u652F\u6301\uFF1A${String(input.contentKind)}`);
|
|
278566
279369
|
}
|
|
278567
279370
|
const rootBytes = await blobs.get(input.contentRef);
|
|
278568
|
-
const sourceFingerprint = (0,
|
|
279371
|
+
const sourceFingerprint = (0, import_node_crypto85.createHash)("sha256").update(rootBytes).digest("hex");
|
|
278569
279372
|
if (input.contentKind === "inline-blob") {
|
|
278570
279373
|
const sourceContent = decodeText3(rootBytes);
|
|
278571
279374
|
if (sourceContent === null) {
|
|
@@ -278589,7 +279392,7 @@ ${entry.text}`).join("\n\n"),
|
|
|
278589
279392
|
}
|
|
278590
279393
|
|
|
278591
279394
|
// ../server/src/domains/discussions/service.ts
|
|
278592
|
-
var
|
|
279395
|
+
var import_node_crypto86 = require("node:crypto");
|
|
278593
279396
|
init_zod();
|
|
278594
279397
|
init_discussions();
|
|
278595
279398
|
init_router();
|
|
@@ -278651,7 +279454,7 @@ function remapTopics(topics, removed) {
|
|
|
278651
279454
|
return [...out].map(([topic_id, summary]) => ({ topic_id, summary }));
|
|
278652
279455
|
}
|
|
278653
279456
|
var entryId = (projectId2, id) => JSON.stringify([projectId2, id]);
|
|
278654
|
-
var hash2 = (s2) => (0,
|
|
279457
|
+
var hash2 = (s2) => (0, import_node_crypto86.createHash)("sha256").update(s2).digest("hex").slice(0, 24);
|
|
278655
279458
|
var canonical = (s2) => s2.normalize("NFKC").trim().toLocaleLowerCase();
|
|
278656
279459
|
function decisionFingerprint(d) {
|
|
278657
279460
|
return hash2(JSON.stringify([d.statement, d.rationale, d.alternatives]));
|
|
@@ -278871,7 +279674,7 @@ var DiscussionService = class {
|
|
|
278871
279674
|
throw new ApiError(409, "DISCUSSION_CONFLICT", "\u9879\u76EE\u8BAE\u9898\u6216\u51B3\u7B56\u5DF2\u53D8\u5316\uFF0C\u8BF7\u8BFB\u53D6\u6700\u65B0\u5185\u5BB9\u540E\u4FEE\u6B63");
|
|
278872
279675
|
}
|
|
278873
279676
|
}
|
|
278874
|
-
const operation = (value2) => tx.put("operation", (0,
|
|
279677
|
+
const operation = (value2) => tx.put("operation", (0, import_node_crypto86.randomUUID)(), {
|
|
278875
279678
|
...value2,
|
|
278876
279679
|
projectId: projectId2,
|
|
278877
279680
|
actorId: ctx.actorId,
|
|
@@ -278888,7 +279691,7 @@ var DiscussionService = class {
|
|
|
278888
279691
|
if (id.startsWith("new:")) {
|
|
278889
279692
|
if (BUG_TOPIC.test(t.title.trim())) invalid("topics.title", `\u300C${t.title}\u300D\u662F\u5355\u4E2A Bug\uFF1A\u4FEE\u590D\u60C5\u51B5\u5199\u8FDB\u8BA8\u8BBA\u8BB0\u5F55\uFF0C\u5B9A\u51FA\u7684\u89C4\u5219\u6302\u5230\u5BF9\u5E94\u529F\u80FD\u8BAE\u9898\u4E0B\uFF0C\u4E0D\u6309 Bug \u53F7\u5EFA\u8BAE\u9898`);
|
|
278890
279693
|
const existing = [...topicMap.values()].find((x2) => canonical(x2.title) === canonical(t.title));
|
|
278891
|
-
id = existing?.topicId ?? `topic_${(0,
|
|
279694
|
+
id = existing?.topicId ?? `topic_${(0, import_node_crypto86.randomUUID)()}`;
|
|
278892
279695
|
if (!existing) createdTopics.add(id);
|
|
278893
279696
|
} else if (!topicMap.has(id)) invalid("topics.topic_id", `\u8BAE\u9898 ${id} \u4E0D\u5B58\u5728\uFF1B\u65B0\u8BAE\u9898\u4F7F\u7528 new: \u524D\u7F00`);
|
|
278894
279697
|
topicAliases.set(t.topic_id, id);
|
|
@@ -278940,7 +279743,7 @@ var DiscussionService = class {
|
|
|
278940
279743
|
if (id.startsWith("new:")) {
|
|
278941
279744
|
const candidateKey = JSON.stringify([topicId, canonical(d.record.statement)]);
|
|
278942
279745
|
const existing = [...decisionMap.values()].find((x2) => x2.topicId === topicId && canonical(x2.record.statement) === canonical(d.record.statement));
|
|
278943
|
-
id = existing?.decisionId ?? candidateIds.get(candidateKey) ?? `decision_${(0,
|
|
279746
|
+
id = existing?.decisionId ?? candidateIds.get(candidateKey) ?? `decision_${(0, import_node_crypto86.randomUUID)()}`;
|
|
278944
279747
|
candidateIds.set(candidateKey, id);
|
|
278945
279748
|
} else if (!decisionMap.has(id)) invalid("decision_id", `\u51B3\u7B56 ${id} \u4E0D\u5B58\u5728\uFF1B\u65B0\u51B3\u7B56\u4F7F\u7528 new: \u524D\u7F00`);
|
|
278946
279749
|
decisionAliases.set(d.decision_id, id);
|
|
@@ -279202,7 +280005,7 @@ var DiscussionService = class {
|
|
|
279202
280005
|
...row.value.confirmation ? { confirmation: { ...row.value.confirmation, fingerprint: decisionFingerprint(record9) } } : {}
|
|
279203
280006
|
};
|
|
279204
280007
|
await tx.put("decision", row.id, value2);
|
|
279205
|
-
await tx.put("operation", (0,
|
|
280008
|
+
await tx.put("operation", (0, import_node_crypto86.randomUUID)(), {
|
|
279206
280009
|
action: "edit",
|
|
279207
280010
|
kind: "decision",
|
|
279208
280011
|
projectId: projectId2,
|
|
@@ -279266,7 +280069,7 @@ var DiscussionService = class {
|
|
|
279266
280069
|
if (!current || current.revision !== row.revision) throw new ApiError(409, "DISCUSSION_CONFLICT", `\u8BA8\u8BBA ${row.id} \u5DF2\u88AB\u4FEE\u6539\uFF0C\u8BF7\u8BFB\u53D6\u6700\u65B0\u5185\u5BB9\u540E\u91CD\u8BD5`);
|
|
279267
280070
|
const summary = given.get(row.id);
|
|
279268
280071
|
await tx.put("discussion", row.id, { ...current.value, record: { ...current.value.record, summary } });
|
|
279269
|
-
await tx.put("operation", (0,
|
|
280072
|
+
await tx.put("operation", (0, import_node_crypto86.randomUUID)(), {
|
|
279270
280073
|
action: "edit",
|
|
279271
280074
|
kind: "discussion",
|
|
279272
280075
|
projectId: current.value.record.project_id,
|
|
@@ -279282,7 +280085,7 @@ var DiscussionService = class {
|
|
|
279282
280085
|
});
|
|
279283
280086
|
}
|
|
279284
280087
|
async operation(tx, actorId, kind, id, from, to) {
|
|
279285
|
-
await tx.put("operation", (0,
|
|
280088
|
+
await tx.put("operation", (0, import_node_crypto86.randomUUID)(), { actorId, kind, id, from, to, at: new Date(this.now()).toISOString() });
|
|
279286
280089
|
}
|
|
279287
280090
|
};
|
|
279288
280091
|
function pickDiscussionContent(d) {
|
|
@@ -279582,7 +280385,7 @@ var DiscussionContext = class {
|
|
|
279582
280385
|
};
|
|
279583
280386
|
|
|
279584
280387
|
// ../server/src/domains/discussions/worker.ts
|
|
279585
|
-
var
|
|
280388
|
+
var import_node_crypto87 = require("node:crypto");
|
|
279586
280389
|
var DISCUSSION_IDLE_MS = 15 * 6e4;
|
|
279587
280390
|
var DISCUSSION_MAX_CORRECTIONS = 3;
|
|
279588
280391
|
var DISCUSSION_LEASE_MS = 2 * 6e4;
|
|
@@ -279608,7 +280411,7 @@ var DiscussionWorker = class {
|
|
|
279608
280411
|
if (await this.isReplying(sessionId)) return false;
|
|
279609
280412
|
const cutoff = eligibleCutoff(await this.service.chat.listMessages(sessionId), this.service.now());
|
|
279610
280413
|
if (!cutoff) return false;
|
|
279611
|
-
const owner = (0,
|
|
280414
|
+
const owner = (0, import_node_crypto87.randomUUID)();
|
|
279612
280415
|
const claimed = await this.service.store.transaction(async (tx) => {
|
|
279613
280416
|
const old = (await tx.get("job", sessionId))?.value;
|
|
279614
280417
|
if (old?.status === "running" && (old.leaseUntil ?? 0) > this.service.now()) return null;
|
|
@@ -280330,7 +281133,7 @@ function createDiscussionRuntime(options) {
|
|
|
280330
281133
|
}
|
|
280331
281134
|
|
|
280332
281135
|
// ../server/src/domains/discussions/store.ts
|
|
280333
|
-
var
|
|
281136
|
+
var import_node_crypto88 = require("node:crypto");
|
|
280334
281137
|
var import_promises17 = require("node:fs/promises");
|
|
280335
281138
|
var import_node_path27 = require("node:path");
|
|
280336
281139
|
var key = (kind, id) => JSON.stringify([kind, id]);
|
|
@@ -280375,7 +281178,7 @@ var MemoryDiscussionStore = class _MemoryDiscussionStore {
|
|
|
280375
281178
|
if (changed) {
|
|
280376
281179
|
if (this.filename) {
|
|
280377
281180
|
await (0, import_promises17.mkdir)((0, import_node_path27.dirname)(this.filename), { recursive: true });
|
|
280378
|
-
const temp = `${this.filename}.${(0,
|
|
281181
|
+
const temp = `${this.filename}.${(0, import_node_crypto88.randomUUID)()}.tmp`;
|
|
280379
281182
|
await (0, import_promises17.writeFile)(temp, JSON.stringify(next), "utf8");
|
|
280380
281183
|
await (0, import_promises17.rename)(temp, this.filename);
|
|
280381
281184
|
}
|
|
@@ -281324,7 +282127,7 @@ function oasisWrapperScript() {
|
|
|
281324
282127
|
const repoRoot = (0, import_node_url7.fileURLToPath)(new URL("../../../", __esm_import_meta_url));
|
|
281325
282128
|
const tsx = path30.join(repoRoot, "node_modules/.bin/tsx");
|
|
281326
282129
|
const main = path30.join(repoRoot, "packages/cli/src/main.ts");
|
|
281327
|
-
const key2 = (0,
|
|
282130
|
+
const key2 = (0, import_node_crypto89.createHash)("sha256").update(repoRoot).digest("hex").slice(0, 12);
|
|
281328
282131
|
const uid = typeof process.getuid === "function" ? process.getuid() : "na";
|
|
281329
282132
|
const stable = path30.join(os9.tmpdir(), `oasis-cli-wrapper-${uid}-${key2}`);
|
|
281330
282133
|
let dir;
|
|
@@ -281717,7 +282520,7 @@ async function startServe(opts) {
|
|
|
281717
282520
|
if (!hub) return Promise.resolve({ ok: false, reason: "\u672C\u8FDB\u7A0B\u6CA1\u6709\u8282\u70B9\u7F51\u5173" });
|
|
281718
282521
|
const online = hub.connectedDaemons().some((d) => d.daemonId === nodeId);
|
|
281719
282522
|
if (!online) return Promise.resolve({ ok: false, reason: "\u8282\u70B9\u5F53\u524D\u4E0D\u5728\u7EBF\uFF0C\u7528\u7684\u662F\u5B83\u4E0A\u6B21\u62A5\u7684\u6E05\u5355" });
|
|
281720
|
-
const requestId = (0,
|
|
282523
|
+
const requestId = (0, import_node_crypto89.randomUUID)();
|
|
281721
282524
|
const task = new Promise((resolve12) => {
|
|
281722
282525
|
const timer = setTimeout(() => {
|
|
281723
282526
|
modelRefreshWaiters.delete(requestId);
|
|
@@ -282546,7 +283349,7 @@ async function startServe(opts) {
|
|
|
282546
283349
|
const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
282547
283350
|
if (buf || session.runId) {
|
|
282548
283351
|
await turnStore.appendMessage({
|
|
282549
|
-
id: (0,
|
|
283352
|
+
id: (0, import_node_crypto89.randomUUID)(),
|
|
282550
283353
|
sessionId: chatSessionId,
|
|
282551
283354
|
role: "assistant",
|
|
282552
283355
|
content: buf,
|
|
@@ -282592,7 +283395,7 @@ async function startServe(opts) {
|
|
|
282592
283395
|
chatTargets: {
|
|
282593
283396
|
inspect: inspectChatTarget,
|
|
282594
283397
|
createTargetSession: async ({ companyId, agentId, ownerHumanActorId, title }) => {
|
|
282595
|
-
const sessionId = (0,
|
|
283398
|
+
const sessionId = (0, import_node_crypto89.randomUUID)();
|
|
282596
283399
|
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
282597
283400
|
const binding = await registryStore.getBinding(agentId).catch(() => null);
|
|
282598
283401
|
await (await chatStoreFor(companyId)).createSession({
|
|
@@ -283994,7 +284797,7 @@ async function startServe(opts) {
|
|
|
283994
284797
|
}));
|
|
283995
284798
|
}
|
|
283996
284799
|
const limits = { wallClockMs: wallClockForKind("planner") };
|
|
283997
|
-
const artifactId = `artifact:planner:${(0,
|
|
284800
|
+
const artifactId = `artifact:planner:${(0, import_node_crypto89.randomUUID)()}`;
|
|
283998
284801
|
const handle = await chatRemoteAdapter.spawn({
|
|
283999
284802
|
actor: planner.id,
|
|
284000
284803
|
// companyId 同协调者:planner 用的就是默认公司的 actors 服务,漏签会让它一调公司域端点就 404。
|
|
@@ -284915,10 +285718,10 @@ async function startServe(opts) {
|
|
|
284915
285718
|
if (isDeletedActor(dispatchTarget)) {
|
|
284916
285719
|
throw new ApiError(409, ACTOR_DELETED_ERROR_CODE, ACTOR_DELETED_CHAT_MESSAGE);
|
|
284917
285720
|
}
|
|
284918
|
-
const runtimeSessionId = sessionId ?? (requestDispatchId ? deterministicUuid(`chat-runtime:${requestDispatchId}`) : (0,
|
|
285721
|
+
const runtimeSessionId = sessionId ?? (requestDispatchId ? deterministicUuid(`chat-runtime:${requestDispatchId}`) : (0, import_node_crypto89.randomUUID)());
|
|
284919
285722
|
const resumeRuntimeSession = Boolean(sessionId);
|
|
284920
|
-
const traceRunId = requestDispatchId ? stableChatTraceRunId(requestDispatchId) : `chat-run:${(0,
|
|
284921
|
-
const artifactId = requestDispatchId ? `artifact:chat:${deterministicUuid(`chat-artifact:${requestDispatchId}`)}` : `artifact:chat:${(0,
|
|
285723
|
+
const traceRunId = requestDispatchId ? stableChatTraceRunId(requestDispatchId) : `chat-run:${(0, import_node_crypto89.randomUUID)()}`;
|
|
285724
|
+
const artifactId = requestDispatchId ? `artifact:chat:${deterministicUuid(`chat-artifact:${requestDispatchId}`)}` : `artifact:chat:${(0, import_node_crypto89.randomUUID)()}`;
|
|
284922
285725
|
let stableDispatch = requestDispatchId ? await resolveStableChatDispatch({ store: await traceStoreFor(runCompanyId), runId: traceRunId }) : null;
|
|
284923
285726
|
if (stableDispatch && !stableDispatch.shouldDispatch) {
|
|
284924
285727
|
if (isHumanSubmitDispatchId(requestDispatchId)) {
|
|
@@ -286376,7 +287179,7 @@ async function startServe(opts) {
|
|
|
286376
287179
|
console.log(`[new-engine] dispatchWork ${workId} \u662F human work\u2014\u2014\u4E0D\u6D3E runtime\uFF0C\u7B49\u5F85\u4EBA\u5DE5\u5904\u7406`);
|
|
286377
287180
|
return;
|
|
286378
287181
|
}
|
|
286379
|
-
const ledgerId = opts2?.protocolRecovery?.dispatchId ?? `dispatch:${(0,
|
|
287182
|
+
const ledgerId = opts2?.protocolRecovery?.dispatchId ?? `dispatch:${(0, import_node_crypto89.randomUUID)()}`;
|
|
286380
287183
|
try {
|
|
286381
287184
|
const inserted = await (await dispatchLedgerFor(companyId)).insertOpen({
|
|
286382
287185
|
id: ledgerId,
|
|
@@ -286476,7 +287279,7 @@ async function startServe(opts) {
|
|
|
286476
287279
|
const kernelModel = newKernel.model;
|
|
286477
287280
|
const art = kernelModel.artifacts.get(nodeId);
|
|
286478
287281
|
const revWid = art?.workspace ?? "";
|
|
286479
|
-
const ledgerId = `dispatch:${(0,
|
|
287282
|
+
const ledgerId = `dispatch:${(0, import_node_crypto89.randomUUID)()}`;
|
|
286480
287283
|
try {
|
|
286481
287284
|
await (await dispatchLedgerFor(companyId)).insertOpen({
|
|
286482
287285
|
id: ledgerId,
|
|
@@ -286870,7 +287673,7 @@ async function startServe(opts) {
|
|
|
286870
287673
|
resolveSupplementalContext: server.knowledgeGovernance ? async ({ actorId, artifactId, workOrderId, action, part, runtimeKind, taskMarkdown }) => {
|
|
286871
287674
|
try {
|
|
286872
287675
|
const governance = server.knowledgeGovernance;
|
|
286873
|
-
const taskFingerprint = (0,
|
|
287676
|
+
const taskFingerprint = (0, import_node_crypto89.createHash)("sha256").update(JSON.stringify({ artifactId, workOrderId, action, part: part ?? null, taskMarkdown })).digest("hex");
|
|
286874
287677
|
const requestContext = {
|
|
286875
287678
|
organizationId: companyId,
|
|
286876
287679
|
actorId,
|
|
@@ -288333,7 +289136,12 @@ ${nodeFault}` : "");
|
|
|
288333
289136
|
const odBase = (process.env["OASIS_OPEN_DESIGN_URL"] ?? "http://127.0.0.1:7457").replace(/\/$/, "");
|
|
288334
289137
|
const odToken = process.env["OASIS_OPEN_DESIGN_TOKEN"]?.trim() || void 0;
|
|
288335
289138
|
const boardWatcher = new BoardWatcher({
|
|
288336
|
-
|
|
289139
|
+
listCompanies: async () => {
|
|
289140
|
+
if (!chatStoreRouter) return [defaultCompanyId];
|
|
289141
|
+
const active = (await controlPlaneStore.listCompanies()).filter((c) => c.status === "active").map((c) => c.id);
|
|
289142
|
+
return [defaultCompanyId, ...active.filter((id) => id !== defaultCompanyId)];
|
|
289143
|
+
},
|
|
289144
|
+
kernelFor: async (companyId) => (await getEngine(companyId)).kernel,
|
|
288337
289145
|
odBase,
|
|
288338
289146
|
...odToken ? { odToken } : {},
|
|
288339
289147
|
boardKeyOf: deriveBoardKey,
|
|
@@ -288342,7 +289150,7 @@ ${nodeFault}` : "");
|
|
|
288342
289150
|
boardWatchTimer = setInterval(() => {
|
|
288343
289151
|
void boardWatcher.tick().catch((err) => console.error(`[board-watch] tick \u5931\u8D25: ${String(err)}`));
|
|
288344
289152
|
}, 6e4);
|
|
288345
|
-
console.log(`[serve] \u753B\u677F\u76D1\u89C6\u5668\u5DF2\u542F\u7528\uFF08od=${odBase}${odToken ? "\uFF0C\u5E26\u4EE4\u724C" : ""}\uFF0C\
|
|
289153
|
+
console.log(`[serve] \u753B\u677F\u76D1\u89C6\u5668\u5DF2\u542F\u7528\uFF08od=${odBase}${odToken ? "\uFF0C\u5E26\u4EE4\u724C" : ""}\uFF0C\u5DE1\u6240\u6709\u516C\u53F8\uFF0C\u6BCF\u7ED3\u675F\u4E00\u8F6E\u5BF9\u8BDD\u5199\u4E00\u5C01\u4FE1\uFF0C\u6BCF\u8F6E\u6BCF\u5BB6\u516C\u53F8\u4E0A\u9650 2 \u5C01\uFF1BOASIS_BOARD_WATCH=0 \u53EF\u5173\uFF09`);
|
|
288346
289154
|
} else {
|
|
288347
289155
|
console.log(`[serve] \u753B\u677F\u76D1\u89C6\u5668\u5DF2\u88AB OASIS_BOARD_WATCH=${boardWatchFlag} \u663E\u5F0F\u5173\u95ED`);
|
|
288348
289156
|
}
|
|
@@ -289589,7 +290397,7 @@ var RuntimeQuotaMonitor = class {
|
|
|
289589
290397
|
init_wrapper();
|
|
289590
290398
|
init_src();
|
|
289591
290399
|
var import_node_os11 = require("node:os");
|
|
289592
|
-
var
|
|
290400
|
+
var import_node_crypto90 = require("node:crypto");
|
|
289593
290401
|
init_src8();
|
|
289594
290402
|
init_src2();
|
|
289595
290403
|
|
|
@@ -290493,7 +291301,7 @@ var DaemonWsClient = class {
|
|
|
290493
291301
|
*/
|
|
290494
291302
|
async queryArtifactStates(artifactIds, timeoutMs = 15e3) {
|
|
290495
291303
|
if (artifactIds.length === 0) return {};
|
|
290496
|
-
const requestId = (0,
|
|
291304
|
+
const requestId = (0, import_node_crypto90.randomUUID)();
|
|
290497
291305
|
return new Promise((resolve12, reject) => {
|
|
290498
291306
|
const timer = setTimeout(() => {
|
|
290499
291307
|
this.gcPending.delete(requestId);
|
|
@@ -290907,7 +291715,7 @@ function forwardSignal(child, sig, killGroup = (pgid, signal) => {
|
|
|
290907
291715
|
// ../cli/src/daemon/machine-id.ts
|
|
290908
291716
|
var import_node_child_process23 = require("node:child_process");
|
|
290909
291717
|
var import_node_fs24 = require("node:fs");
|
|
290910
|
-
var
|
|
291718
|
+
var import_node_crypto91 = require("node:crypto");
|
|
290911
291719
|
var import_node_os14 = require("node:os");
|
|
290912
291720
|
function linuxMachineId() {
|
|
290913
291721
|
for (const p2 of ["/etc/machine-id", "/var/lib/dbus/machine-id"]) {
|
|
@@ -290973,7 +291781,7 @@ var defaultSources = {
|
|
|
290973
291781
|
function resolveNodeId(sources = {}) {
|
|
290974
291782
|
const s2 = { ...defaultSources, ...sources };
|
|
290975
291783
|
const material = `${s2.machineFingerprint()}:${s2.osUser()}`;
|
|
290976
|
-
const digest = (0,
|
|
291784
|
+
const digest = (0, import_node_crypto91.createHash)("sha256").update(material).digest("hex").slice(0, 12);
|
|
290977
291785
|
return `node-${digest}`;
|
|
290978
291786
|
}
|
|
290979
291787
|
|
|
@@ -292845,13 +293653,13 @@ function ownFlagsFromDecl(command2) {
|
|
|
292845
293653
|
}
|
|
292846
293654
|
|
|
292847
293655
|
// ../cli/src/connector-effect-runner.ts
|
|
292848
|
-
var
|
|
293656
|
+
var import_node_crypto92 = require("node:crypto");
|
|
292849
293657
|
var import_node_child_process24 = require("node:child_process");
|
|
292850
293658
|
init_src8();
|
|
292851
293659
|
function stableKey(effect) {
|
|
292852
293660
|
const keyFields = Object.fromEntries(Object.entries(effect.keyFields).sort(([a], [b2]) => a.localeCompare(b2)));
|
|
292853
293661
|
const canonical2 = JSON.stringify({ kind: effect.kind, target: effect.target, keyFields });
|
|
292854
|
-
return `sha256:${(0,
|
|
293662
|
+
return `sha256:${(0, import_node_crypto92.createHash)("sha256").update(canonical2).digest("hex")}`;
|
|
292855
293663
|
}
|
|
292856
293664
|
async function runConnectorEffect(connector, toolArgs, deps) {
|
|
292857
293665
|
const effect = connector.describeExternalEffect?.(toolArgs) ?? null;
|
|
@@ -293406,7 +294214,7 @@ async function waitForCommandAuthorization(base, headers, draftId, fallback) {
|
|
|
293406
294214
|
const timeoutMs = resolveAuthWaitMs();
|
|
293407
294215
|
const controller = new AbortController();
|
|
293408
294216
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
293409
|
-
const waiterId = (0,
|
|
294217
|
+
const waiterId = (0, import_node_crypto93.randomUUID)();
|
|
293410
294218
|
process.stderr.write(
|
|
293411
294219
|
`\u7B49\u5F85\u4EBA\u5DE5\u6388\u6743\u4E2D\u2026\u2026\u6700\u591A ${Math.round(timeoutMs / 1e3)} \u79D2\uFF0C\u8D85\u65F6\u4F1A\u81EA\u52A8\u8F6C\u4E3A\u5F85\u5BA1\uFF1B\u8FD9\u4E0D\u662F\u9519\u8BEF\uFF0C\u8BF7\u52FF\u91CD\u8BD5\u540C\u4E00\u6761\u547D\u4EE4\u3002
|
|
293412
294220
|
`
|
|
@@ -293490,7 +294298,7 @@ async function waitForCommandAuthorization(base, headers, draftId, fallback) {
|
|
|
293490
294298
|
}
|
|
293491
294299
|
}
|
|
293492
294300
|
}
|
|
293493
|
-
var CLI_VERSION = "2.2.
|
|
294301
|
+
var CLI_VERSION = "2.2.83" ? "2.2.83" : "dev";
|
|
293494
294302
|
function apiHeaders(token, company) {
|
|
293495
294303
|
const headers = {
|
|
293496
294304
|
authorization: `Bearer ${token}`,
|
|
@@ -293856,7 +294664,7 @@ async function runCli(argv, println = console.log, progressln = console.error) {
|
|
|
293856
294664
|
const store = createNodeTokenStore(path39.join(dir, "node-tokens.json"));
|
|
293857
294665
|
const sub = positional[0];
|
|
293858
294666
|
if (sub === "issue") {
|
|
293859
|
-
const id = flags.get("id") ?? `node-${(0,
|
|
294667
|
+
const id = flags.get("id") ?? `node-${(0, import_node_crypto93.randomUUID)()}`;
|
|
293860
294668
|
const token2 = store.issue(id);
|
|
293861
294669
|
println(token2);
|
|
293862
294670
|
process.stderr.write(
|
|
@@ -295006,7 +295814,7 @@ ${t.ref} ${t.name} [\u5267\u672C=${t.playbookRef}]`);
|
|
|
295006
295814
|
if (!name) throw new Error("\u9879\u76EE\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A");
|
|
295007
295815
|
const goal = flags.get("goal")?.trim();
|
|
295008
295816
|
const slug6 = flags.get("slug");
|
|
295009
|
-
const id = slug6 !== void 0 ? projectSlug(slug6) : projectIdFromUuid((0,
|
|
295817
|
+
const id = slug6 !== void 0 ? projectSlug(slug6) : projectIdFromUuid((0, import_node_crypto93.randomUUID)());
|
|
295010
295818
|
const result = await api.request("POST", "/api/projects", {
|
|
295011
295819
|
...id ? { id } : {},
|
|
295012
295820
|
name,
|
|
@@ -295287,7 +296095,13 @@ ${res.warning}`);
|
|
|
295287
296095
|
if (live.length > 0) {
|
|
295288
296096
|
for (const r of live) println(`[design] \u5F15\u64CE\u5728\u8DD1\uFF1Arun ${r.runId.slice(0, 8)} \u72B6\u6001=${r.status}\u2014\u2014\u522B\u518D\u8D77\u65B0\u8F6E\uFF1B\u8FC7\u51E0\u5206\u949F\u518D status\uFF0C\u6216\u672C\u8F6E\u6536\u5DE5\u7B49\u91CD\u6D3E\u3002`);
|
|
295289
296097
|
} else if (st.runs.length > 0) {
|
|
295290
|
-
for (const r of st.runs.slice(0, 3))
|
|
296098
|
+
for (const r of st.runs.slice(0, 3)) {
|
|
296099
|
+
println(`[design] \u8FD1\u671F run\uFF1A${r.runId.slice(0, 8)} \u7EC8\u6001=${r.status}${r.agentId ? ` \u5F15\u64CE=${r.agentId}` : ""}`);
|
|
296100
|
+
if (r.status === "failed" && r.error) {
|
|
296101
|
+
const reason = r.error.length > 300 ? `${r.error.slice(0, 300)}\u2026` : r.error;
|
|
296102
|
+
println(`[design] \u5931\u8D25\u539F\u56E0\uFF08od \u539F\u6587\uFF09\uFF1A${reason}`);
|
|
296103
|
+
}
|
|
296104
|
+
}
|
|
295291
296105
|
} else {
|
|
295292
296106
|
println(`[design] \u65E0\u5728\u4E16 run \u8BB0\u5F55\uFF08od \u91CD\u542F\u540E\u4E3A\u7A7A\uFF0C\u5C5E\u6B63\u5E38\uFF09\u2014\u2014\u770B\u4E0B\u9762\u677F\u4E0A\u4EA7\u7269\u5373\u6301\u4E45\u771F\u76F8\u3002`);
|
|
295293
296107
|
}
|
|
@@ -295299,7 +296113,7 @@ ${res.warning}`);
|
|
|
295299
296113
|
for (const a of st.artifacts) println(` - ${a.path}\uFF08${a.kind ?? "?"}\uFF09status=${a.status ?? "?"}${a.mtime ? ` \xB7 ${new Date(a.mtime).toISOString()}` : ""}`);
|
|
295300
296114
|
if (flags.get("pull") === "true") {
|
|
295301
296115
|
const odPublic = (flags.get("od-public-url") ?? process.env["OASIS_OPEN_DESIGN_PUBLIC_URL"] ?? "https://design.open-friday.com").replace(/\/$/, "");
|
|
295302
|
-
const { dir: dir2, entry } = await harvestBoard(odBase, odFetch, odPublic, os13.tmpdir(), st.boardKey, st.runs
|
|
296116
|
+
const { dir: dir2, entry } = await harvestBoard(odBase, odFetch, odPublic, os13.tmpdir(), st.boardKey, latestSucceededRun(st.runs)?.runId ?? "status-pull");
|
|
295303
296117
|
println(`[design] \u5DF2\u62C9\u5230\u672C\u5730\uFF1A${dir2}\uFF08\u5165\u53E3 ${entry}\uFF09`);
|
|
295304
296118
|
println(`[design] \u8BFB\u5B8C\u6EE1\u610F\u5373\u4EA4\u7A3F\uFF1Aoasis propose ${artifactId} --from-dir ${dir2} --reason "<\u8FD9\u7248\u505A\u4E86\u4EC0\u4E48>"`);
|
|
295305
296119
|
} else {
|
|
@@ -297271,13 +298085,13 @@ function runtimeAssetSourceRoots(input) {
|
|
|
297271
298085
|
}
|
|
297272
298086
|
|
|
297273
298087
|
// src/install.ts
|
|
297274
|
-
var
|
|
298088
|
+
var import_node_crypto94 = require("node:crypto");
|
|
297275
298089
|
var fs50 = __toESM(require("node:fs"));
|
|
297276
298090
|
var path45 = __toESM(require("node:path"));
|
|
297277
298091
|
function versionLabel(sourceFile, pkgVersion, npmPrefixDir, pkgName = LEGACY_PKG_NAME) {
|
|
297278
298092
|
const tag = pkgName === LEGACY_PKG_NAME ? "" : `+pkg.${pkgName.replace(/[^A-Za-z0-9-]/g, "-")}`;
|
|
297279
298093
|
if (isFromNpmPrefix(sourceFile, npmPrefixDir)) return `${pkgVersion}${tag}`;
|
|
297280
|
-
const digest = (0,
|
|
298094
|
+
const digest = (0, import_node_crypto94.createHash)("sha256").update(fs50.readFileSync(sourceFile)).digest("hex").slice(0, 8);
|
|
297281
298095
|
return tag ? `${pkgVersion}${tag}.local.${digest}` : `${pkgVersion}+local.${digest}`;
|
|
297282
298096
|
}
|
|
297283
298097
|
function isFromNpmPrefix(sourceFile, npmPrefixDir) {
|
|
@@ -297400,7 +298214,7 @@ function shimScript() {
|
|
|
297400
298214
|
}
|
|
297401
298215
|
|
|
297402
298216
|
// src/index.ts
|
|
297403
|
-
var PKG_VERSION = true ? "2.2.
|
|
298217
|
+
var PKG_VERSION = true ? "2.2.83" : "dev";
|
|
297404
298218
|
var LOCAL_BIN = localBin();
|
|
297405
298219
|
var NPM_PREFIX = npmPrefix();
|
|
297406
298220
|
var INSTANCE = DEFAULT_INSTANCE;
|
|
@@ -297708,7 +298522,7 @@ function newInstanceName() {
|
|
|
297708
298522
|
const existing = new Set(listInstances());
|
|
297709
298523
|
if (!existing.has(DEFAULT_INSTANCE)) return DEFAULT_INSTANCE;
|
|
297710
298524
|
for (; ; ) {
|
|
297711
|
-
const n = `inst-${(0,
|
|
298525
|
+
const n = `inst-${(0, import_node_crypto95.randomBytes)(3).toString("hex")}`;
|
|
297712
298526
|
if (!existing.has(n)) return n;
|
|
297713
298527
|
}
|
|
297714
298528
|
}
|