@eve-horizon/cli 0.2.20 → 0.2.22
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 +2328 -424
- package/package.json +7 -7
package/dist/index.js
CHANGED
|
@@ -9811,8 +9811,8 @@ var require_sync = __commonJS({
|
|
|
9811
9811
|
}
|
|
9812
9812
|
return x;
|
|
9813
9813
|
};
|
|
9814
|
-
var defaultReadPackageSync = function defaultReadPackageSync2(
|
|
9815
|
-
var body =
|
|
9814
|
+
var defaultReadPackageSync = function defaultReadPackageSync2(readFileSync21, pkgfile) {
|
|
9815
|
+
var body = readFileSync21(pkgfile);
|
|
9816
9816
|
try {
|
|
9817
9817
|
var pkg = JSON.parse(body);
|
|
9818
9818
|
return pkg;
|
|
@@ -9832,7 +9832,7 @@ var require_sync = __commonJS({
|
|
|
9832
9832
|
}
|
|
9833
9833
|
var opts = normalizeOptions(x, options);
|
|
9834
9834
|
var isFile = opts.isFile || defaultIsFile;
|
|
9835
|
-
var
|
|
9835
|
+
var readFileSync21 = opts.readFileSync || fs4.readFileSync;
|
|
9836
9836
|
var isDirectory = opts.isDirectory || defaultIsDir;
|
|
9837
9837
|
var realpathSync = opts.realpathSync || defaultRealpathSync;
|
|
9838
9838
|
var readPackageSync = opts.readPackageSync || defaultReadPackageSync;
|
|
@@ -9889,7 +9889,7 @@ var require_sync = __commonJS({
|
|
|
9889
9889
|
if (!isFile(pkgfile)) {
|
|
9890
9890
|
return loadpkg(path6.dirname(dir));
|
|
9891
9891
|
}
|
|
9892
|
-
var pkg = readPackageSync(
|
|
9892
|
+
var pkg = readPackageSync(readFileSync21, pkgfile);
|
|
9893
9893
|
if (pkg && opts.packageFilter) {
|
|
9894
9894
|
pkg = opts.packageFilter(
|
|
9895
9895
|
pkg,
|
|
@@ -9903,7 +9903,7 @@ var require_sync = __commonJS({
|
|
|
9903
9903
|
var pkgfile = path6.join(maybeRealpathSync(realpathSync, x2, opts), "/package.json");
|
|
9904
9904
|
if (isFile(pkgfile)) {
|
|
9905
9905
|
try {
|
|
9906
|
-
var pkg = readPackageSync(
|
|
9906
|
+
var pkg = readPackageSync(readFileSync21, pkgfile);
|
|
9907
9907
|
} catch (e) {
|
|
9908
9908
|
}
|
|
9909
9909
|
if (pkg && opts.packageFilter) {
|
|
@@ -13197,8 +13197,8 @@ var require_utils3 = __commonJS({
|
|
|
13197
13197
|
const connectOptions = url;
|
|
13198
13198
|
const protocol = getProtocol(connectOptions === null || connectOptions === void 0 ? void 0 : connectOptions.protocol);
|
|
13199
13199
|
Object.assign(attributes, Object.assign({}, extractConnectionAttributeOrLog(url, semantic_conventions_1.SEMATTRS_MESSAGING_PROTOCOL, protocol, "protocol")));
|
|
13200
|
-
const
|
|
13201
|
-
Object.assign(attributes, Object.assign({}, extractConnectionAttributeOrLog(url, semantic_conventions_1.SEMATTRS_NET_PEER_NAME,
|
|
13200
|
+
const hostname2 = getHostname(connectOptions === null || connectOptions === void 0 ? void 0 : connectOptions.hostname);
|
|
13201
|
+
Object.assign(attributes, Object.assign({}, extractConnectionAttributeOrLog(url, semantic_conventions_1.SEMATTRS_NET_PEER_NAME, hostname2, "hostname")));
|
|
13202
13202
|
const port = getPort(connectOptions.port, protocol);
|
|
13203
13203
|
Object.assign(attributes, Object.assign({}, extractConnectionAttributeOrLog(url, semantic_conventions_1.SEMATTRS_NET_PEER_PORT, port, "port")));
|
|
13204
13204
|
} else {
|
|
@@ -13208,8 +13208,8 @@ var require_utils3 = __commonJS({
|
|
|
13208
13208
|
const urlParts = new URL(censoredUrl);
|
|
13209
13209
|
const protocol = getProtocol(urlParts.protocol);
|
|
13210
13210
|
Object.assign(attributes, Object.assign({}, extractConnectionAttributeOrLog(censoredUrl, semantic_conventions_1.SEMATTRS_MESSAGING_PROTOCOL, protocol, "protocol")));
|
|
13211
|
-
const
|
|
13212
|
-
Object.assign(attributes, Object.assign({}, extractConnectionAttributeOrLog(censoredUrl, semantic_conventions_1.SEMATTRS_NET_PEER_NAME,
|
|
13211
|
+
const hostname2 = getHostname(urlParts.hostname);
|
|
13212
|
+
Object.assign(attributes, Object.assign({}, extractConnectionAttributeOrLog(censoredUrl, semantic_conventions_1.SEMATTRS_NET_PEER_NAME, hostname2, "hostname")));
|
|
13213
13213
|
const port = getPort(urlParts.port ? parseInt(urlParts.port) : void 0, protocol);
|
|
13214
13214
|
Object.assign(attributes, Object.assign({}, extractConnectionAttributeOrLog(censoredUrl, semantic_conventions_1.SEMATTRS_NET_PEER_PORT, port, "port")));
|
|
13215
13215
|
} catch (err) {
|
|
@@ -19754,7 +19754,7 @@ var require_OpenTelemetryBunyanStream = __commonJS({
|
|
|
19754
19754
|
msg,
|
|
19755
19755
|
v,
|
|
19756
19756
|
// eslint-disable-line @typescript-eslint/no-unused-vars
|
|
19757
|
-
hostname,
|
|
19757
|
+
hostname: hostname2,
|
|
19758
19758
|
// eslint-disable-line @typescript-eslint/no-unused-vars
|
|
19759
19759
|
pid,
|
|
19760
19760
|
// eslint-disable-line @typescript-eslint/no-unused-vars
|
|
@@ -21171,9 +21171,9 @@ var require_instrumentation9 = __commonJS({
|
|
|
21171
21171
|
*/
|
|
21172
21172
|
_getPatchLookupFunction(original) {
|
|
21173
21173
|
const plugin = this;
|
|
21174
|
-
return function patchedLookup(
|
|
21175
|
-
if (utils.isIgnored(
|
|
21176
|
-
return original.apply(this, [
|
|
21174
|
+
return function patchedLookup(hostname2, ...args) {
|
|
21175
|
+
if (utils.isIgnored(hostname2, plugin.getConfig().ignoreHostnames, (e) => api_1.diag.error("caught ignoreHostname error: ", e))) {
|
|
21176
|
+
return original.apply(this, [hostname2, ...args]);
|
|
21177
21177
|
}
|
|
21178
21178
|
const argsCount = args.length;
|
|
21179
21179
|
api_1.diag.debug("wrap lookup callback function and starts span");
|
|
@@ -21184,7 +21184,7 @@ var require_instrumentation9 = __commonJS({
|
|
|
21184
21184
|
const originalCallback = args[argsCount - 1];
|
|
21185
21185
|
if (typeof originalCallback === "function") {
|
|
21186
21186
|
args[argsCount - 1] = plugin._wrapLookupCallback(originalCallback, span);
|
|
21187
|
-
return (0, instrumentation_1.safeExecuteInTheMiddle)(() => original.apply(this, [
|
|
21187
|
+
return (0, instrumentation_1.safeExecuteInTheMiddle)(() => original.apply(this, [hostname2, ...args]), (error) => {
|
|
21188
21188
|
if (error != null) {
|
|
21189
21189
|
utils.setError(error, span);
|
|
21190
21190
|
span.end();
|
|
@@ -21192,7 +21192,7 @@ var require_instrumentation9 = __commonJS({
|
|
|
21192
21192
|
});
|
|
21193
21193
|
} else {
|
|
21194
21194
|
const promise = (0, instrumentation_1.safeExecuteInTheMiddle)(() => original.apply(this, [
|
|
21195
|
-
|
|
21195
|
+
hostname2,
|
|
21196
21196
|
...args
|
|
21197
21197
|
]), (error) => {
|
|
21198
21198
|
if (error != null) {
|
|
@@ -28558,8 +28558,8 @@ var require_utils14 = __commonJS({
|
|
|
28558
28558
|
if (!pathname && optionsParsed.path) {
|
|
28559
28559
|
pathname = url.parse(optionsParsed.path).pathname || "/";
|
|
28560
28560
|
}
|
|
28561
|
-
const
|
|
28562
|
-
origin = `${optionsParsed.protocol || "http:"}//${
|
|
28561
|
+
const hostname2 = optionsParsed.host || (optionsParsed.port != null ? `${optionsParsed.hostname}${optionsParsed.port}` : optionsParsed.hostname);
|
|
28562
|
+
origin = `${optionsParsed.protocol || "http:"}//${hostname2}`;
|
|
28563
28563
|
}
|
|
28564
28564
|
const method = optionsParsed.method ? optionsParsed.method.toUpperCase() : "GET";
|
|
28565
28565
|
return { origin, pathname, method, optionsParsed };
|
|
@@ -28579,7 +28579,7 @@ var require_utils14 = __commonJS({
|
|
|
28579
28579
|
return { hostname: requestOptions.hostname, port: requestOptions.port };
|
|
28580
28580
|
}
|
|
28581
28581
|
const matches = ((_a = requestOptions.host) === null || _a === void 0 ? void 0 : _a.match(/^([^:/ ]+)(:\d{1,5})?/)) || null;
|
|
28582
|
-
const
|
|
28582
|
+
const hostname2 = requestOptions.hostname || (matches === null ? "localhost" : matches[1]);
|
|
28583
28583
|
let port = requestOptions.port;
|
|
28584
28584
|
if (!port) {
|
|
28585
28585
|
if (matches && matches[2]) {
|
|
@@ -28588,12 +28588,12 @@ var require_utils14 = __commonJS({
|
|
|
28588
28588
|
port = requestOptions.protocol === "https:" ? "443" : "80";
|
|
28589
28589
|
}
|
|
28590
28590
|
}
|
|
28591
|
-
return { hostname, port };
|
|
28591
|
+
return { hostname: hostname2, port };
|
|
28592
28592
|
};
|
|
28593
28593
|
exports2.extractHostnameAndPort = extractHostnameAndPort;
|
|
28594
28594
|
var getOutgoingRequestAttributes = (requestOptions, options, semconvStability) => {
|
|
28595
28595
|
var _a, _b;
|
|
28596
|
-
const
|
|
28596
|
+
const hostname2 = options.hostname;
|
|
28597
28597
|
const port = options.port;
|
|
28598
28598
|
const method = (_a = requestOptions.method) !== null && _a !== void 0 ? _a : "GET";
|
|
28599
28599
|
const normalizedMethod = normalizeMethod(method);
|
|
@@ -28604,13 +28604,13 @@ var require_utils14 = __commonJS({
|
|
|
28604
28604
|
[semantic_conventions_1.SEMATTRS_HTTP_URL]: urlFull,
|
|
28605
28605
|
[semantic_conventions_1.SEMATTRS_HTTP_METHOD]: method,
|
|
28606
28606
|
[semantic_conventions_1.SEMATTRS_HTTP_TARGET]: requestOptions.path || "/",
|
|
28607
|
-
[semantic_conventions_1.SEMATTRS_NET_PEER_NAME]:
|
|
28608
|
-
[semantic_conventions_1.SEMATTRS_HTTP_HOST]: (_b = headers.host) !== null && _b !== void 0 ? _b : `${
|
|
28607
|
+
[semantic_conventions_1.SEMATTRS_NET_PEER_NAME]: hostname2,
|
|
28608
|
+
[semantic_conventions_1.SEMATTRS_HTTP_HOST]: (_b = headers.host) !== null && _b !== void 0 ? _b : `${hostname2}:${port}`
|
|
28609
28609
|
};
|
|
28610
28610
|
const newAttributes = {
|
|
28611
28611
|
// Required attributes
|
|
28612
28612
|
[semantic_conventions_1.ATTR_HTTP_REQUEST_METHOD]: normalizedMethod,
|
|
28613
|
-
[semantic_conventions_1.ATTR_SERVER_ADDRESS]:
|
|
28613
|
+
[semantic_conventions_1.ATTR_SERVER_ADDRESS]: hostname2,
|
|
28614
28614
|
[semantic_conventions_1.ATTR_SERVER_PORT]: Number(port),
|
|
28615
28615
|
[semantic_conventions_1.ATTR_URL_FULL]: urlFull
|
|
28616
28616
|
// leaving out protocol version, it is not yet negotiated
|
|
@@ -28785,7 +28785,7 @@ var require_utils14 = __commonJS({
|
|
|
28785
28785
|
const httpVersion = request.httpVersion;
|
|
28786
28786
|
const requestUrl = request.url ? url.parse(request.url) : null;
|
|
28787
28787
|
const host = (requestUrl === null || requestUrl === void 0 ? void 0 : requestUrl.host) || headers.host;
|
|
28788
|
-
const
|
|
28788
|
+
const hostname2 = (requestUrl === null || requestUrl === void 0 ? void 0 : requestUrl.hostname) || (host === null || host === void 0 ? void 0 : host.replace(/^(.*)(:[0-9]{1,5})/, "$1")) || "localhost";
|
|
28789
28789
|
const method = request.method;
|
|
28790
28790
|
const normalizedMethod = normalizeMethod(method);
|
|
28791
28791
|
const serverAddress = getServerAddress(request, options.component);
|
|
@@ -28815,7 +28815,7 @@ var require_utils14 = __commonJS({
|
|
|
28815
28815
|
const oldAttributes = {
|
|
28816
28816
|
[semantic_conventions_1.SEMATTRS_HTTP_URL]: (0, exports2.getAbsoluteUrl)(requestUrl, headers, `${options.component}:`),
|
|
28817
28817
|
[semantic_conventions_1.SEMATTRS_HTTP_HOST]: host,
|
|
28818
|
-
[semantic_conventions_1.SEMATTRS_NET_HOST_NAME]:
|
|
28818
|
+
[semantic_conventions_1.SEMATTRS_NET_HOST_NAME]: hostname2,
|
|
28819
28819
|
[semantic_conventions_1.SEMATTRS_HTTP_METHOD]: method,
|
|
28820
28820
|
[semantic_conventions_1.SEMATTRS_HTTP_SCHEME]: options.component
|
|
28821
28821
|
};
|
|
@@ -29368,11 +29368,11 @@ var require_http = __commonJS({
|
|
|
29368
29368
|
}, true)) {
|
|
29369
29369
|
return original.apply(this, [optionsParsed, ...args]);
|
|
29370
29370
|
}
|
|
29371
|
-
const { hostname, port } = (0, utils_1.extractHostnameAndPort)(optionsParsed);
|
|
29371
|
+
const { hostname: hostname2, port } = (0, utils_1.extractHostnameAndPort)(optionsParsed);
|
|
29372
29372
|
const attributes = (0, utils_1.getOutgoingRequestAttributes)(optionsParsed, {
|
|
29373
29373
|
component,
|
|
29374
29374
|
port,
|
|
29375
|
-
hostname,
|
|
29375
|
+
hostname: hostname2,
|
|
29376
29376
|
hookAttributes: instrumentation._callStartSpanHook(optionsParsed, instrumentation.getConfig().startOutgoingSpanHook)
|
|
29377
29377
|
}, instrumentation._semconvStability);
|
|
29378
29378
|
const startTime = (0, core_1.hrTime)();
|
|
@@ -36012,7 +36012,7 @@ var require_log_sending_utils = __commonJS({
|
|
|
36012
36012
|
// depends on the user using the OpenTelemetry HostDetector and
|
|
36013
36013
|
// ProcessDetector.
|
|
36014
36014
|
// https://getpino.io/#/docs/api?id=opt-base
|
|
36015
|
-
hostname,
|
|
36015
|
+
hostname: hostname2,
|
|
36016
36016
|
// eslint-disable-line @typescript-eslint/no-unused-vars
|
|
36017
36017
|
pid,
|
|
36018
36018
|
// eslint-disable-line @typescript-eslint/no-unused-vars
|
|
@@ -39634,7 +39634,7 @@ var require_AlibabaCloudEcsDetector = __commonJS({
|
|
|
39634
39634
|
/** Gets identity and host info and returns them as attribs. Empty object if fails */
|
|
39635
39635
|
async _getAttributes(_config) {
|
|
39636
39636
|
const { "owner-account-id": accountId, "instance-id": instanceId, "instance-type": instanceType, "region-id": region, "zone-id": availabilityZone } = await this._fetchIdentity();
|
|
39637
|
-
const
|
|
39637
|
+
const hostname2 = await this._fetchHost();
|
|
39638
39638
|
return {
|
|
39639
39639
|
[semantic_conventions_1.SEMRESATTRS_CLOUD_PROVIDER]: semantic_conventions_1.CLOUDPROVIDERVALUES_ALIBABA_CLOUD,
|
|
39640
39640
|
[semantic_conventions_1.SEMRESATTRS_CLOUD_PLATFORM]: semantic_conventions_1.CLOUDPLATFORMVALUES_ALIBABA_CLOUD_ECS,
|
|
@@ -39643,7 +39643,7 @@ var require_AlibabaCloudEcsDetector = __commonJS({
|
|
|
39643
39643
|
[semantic_conventions_1.SEMRESATTRS_CLOUD_AVAILABILITY_ZONE]: availabilityZone,
|
|
39644
39644
|
[semantic_conventions_1.SEMRESATTRS_HOST_ID]: instanceId,
|
|
39645
39645
|
[semantic_conventions_1.SEMRESATTRS_HOST_TYPE]: instanceType,
|
|
39646
|
-
[semantic_conventions_1.SEMRESATTRS_HOST_NAME]:
|
|
39646
|
+
[semantic_conventions_1.SEMRESATTRS_HOST_NAME]: hostname2
|
|
39647
39647
|
};
|
|
39648
39648
|
}
|
|
39649
39649
|
/**
|
|
@@ -39888,7 +39888,7 @@ var require_AwsEc2DetectorSync = __commonJS({
|
|
|
39888
39888
|
try {
|
|
39889
39889
|
const token = await this._fetchToken();
|
|
39890
39890
|
const { accountId, instanceId, instanceType, region, availabilityZone } = await this._fetchIdentity(token);
|
|
39891
|
-
const
|
|
39891
|
+
const hostname2 = await this._fetchHost(token);
|
|
39892
39892
|
return {
|
|
39893
39893
|
[semconv_1.ATTR_CLOUD_PROVIDER]: semconv_1.CLOUD_PROVIDER_VALUE_AWS,
|
|
39894
39894
|
[semconv_1.ATTR_CLOUD_PLATFORM]: semconv_1.CLOUD_PLATFORM_VALUE_AWS_EC2,
|
|
@@ -39897,7 +39897,7 @@ var require_AwsEc2DetectorSync = __commonJS({
|
|
|
39897
39897
|
[semconv_1.ATTR_CLOUD_AVAILABILITY_ZONE]: availabilityZone,
|
|
39898
39898
|
[semconv_1.ATTR_HOST_ID]: instanceId,
|
|
39899
39899
|
[semconv_1.ATTR_HOST_TYPE]: instanceType,
|
|
39900
|
-
[semconv_1.ATTR_HOST_NAME]:
|
|
39900
|
+
[semconv_1.ATTR_HOST_NAME]: hostname2
|
|
39901
39901
|
};
|
|
39902
39902
|
} catch (_a) {
|
|
39903
39903
|
return {};
|
|
@@ -47946,7 +47946,7 @@ var require_GcpDetector = __commonJS({
|
|
|
47946
47946
|
api_1.diag.debug("GcpDetector failed: GCP Metadata unavailable.");
|
|
47947
47947
|
return {};
|
|
47948
47948
|
}
|
|
47949
|
-
const [projectId, instanceId, zoneId, clusterName,
|
|
47949
|
+
const [projectId, instanceId, zoneId, clusterName, hostname2] = await Promise.all([
|
|
47950
47950
|
this._getProjectId(),
|
|
47951
47951
|
this._getInstanceId(),
|
|
47952
47952
|
this._getZone(),
|
|
@@ -47956,7 +47956,7 @@ var require_GcpDetector = __commonJS({
|
|
|
47956
47956
|
const attributes = {};
|
|
47957
47957
|
attributes[semantic_conventions_1.SEMRESATTRS_CLOUD_ACCOUNT_ID] = projectId;
|
|
47958
47958
|
attributes[semantic_conventions_1.SEMRESATTRS_HOST_ID] = instanceId;
|
|
47959
|
-
attributes[semantic_conventions_1.SEMRESATTRS_HOST_NAME] =
|
|
47959
|
+
attributes[semantic_conventions_1.SEMRESATTRS_HOST_NAME] = hostname2;
|
|
47960
47960
|
attributes[semantic_conventions_1.SEMRESATTRS_CLOUD_AVAILABILITY_ZONE] = zoneId;
|
|
47961
47961
|
attributes[semantic_conventions_1.SEMRESATTRS_CLOUD_PROVIDER] = semantic_conventions_1.CLOUDPROVIDERVALUES_GCP;
|
|
47962
47962
|
if ((0, core_2.getEnv)().KUBERNETES_SERVICE_HOST)
|
|
@@ -48734,6 +48734,23 @@ function resolveContext(flags, credentials) {
|
|
|
48734
48734
|
profileSource
|
|
48735
48735
|
};
|
|
48736
48736
|
}
|
|
48737
|
+
function resolveContextForProfile(profileName, profile, credentials) {
|
|
48738
|
+
const apiUrl = profile.api_url || DEFAULT_API_URL;
|
|
48739
|
+
const authKey = toAuthKey(apiUrl);
|
|
48740
|
+
const tokenEntry = credentials.tokens[authKey] || credentials.profiles?.[profileName];
|
|
48741
|
+
return {
|
|
48742
|
+
apiUrl,
|
|
48743
|
+
orgId: profile.org_id,
|
|
48744
|
+
projectId: profile.project_id,
|
|
48745
|
+
profileName,
|
|
48746
|
+
profile,
|
|
48747
|
+
authKey,
|
|
48748
|
+
token: tokenEntry?.access_token,
|
|
48749
|
+
refreshToken: tokenEntry?.refresh_token,
|
|
48750
|
+
expiresAt: tokenEntry?.expires_at,
|
|
48751
|
+
profileSource: "local"
|
|
48752
|
+
};
|
|
48753
|
+
}
|
|
48737
48754
|
function normalizeRepoProfiles(parsed) {
|
|
48738
48755
|
if (!parsed || typeof parsed !== "object") {
|
|
48739
48756
|
return { profiles: {} };
|
|
@@ -48884,6 +48901,20 @@ var HELP = {
|
|
|
48884
48901
|
"eve project sync --path ./custom-manifest.yaml"
|
|
48885
48902
|
]
|
|
48886
48903
|
},
|
|
48904
|
+
status: {
|
|
48905
|
+
description: "Show deployment status across all profiles with revision info, service URLs, and deploy age",
|
|
48906
|
+
usage: "eve project status [--profile <name>] [--env <name>] [--json]",
|
|
48907
|
+
options: [
|
|
48908
|
+
"--profile <name> Show only this profile",
|
|
48909
|
+
"--env <name> Show only this environment",
|
|
48910
|
+
"--json Machine-readable JSON output"
|
|
48911
|
+
],
|
|
48912
|
+
examples: [
|
|
48913
|
+
"eve project status",
|
|
48914
|
+
"eve project status --profile staging",
|
|
48915
|
+
"eve project status --env sandbox --json"
|
|
48916
|
+
]
|
|
48917
|
+
},
|
|
48887
48918
|
members: {
|
|
48888
48919
|
description: "Manage project members (list, add, remove)",
|
|
48889
48920
|
usage: "eve project members [list|add|remove] [options]",
|
|
@@ -49619,34 +49650,63 @@ for cloud deployments. Credentials are stored globally per API URL.`,
|
|
|
49619
49650
|
subcommands: {
|
|
49620
49651
|
can: {
|
|
49621
49652
|
description: "Check if a principal can perform an action",
|
|
49622
|
-
usage: "eve access can --org <org_id> --user <
|
|
49653
|
+
usage: "eve access can --org <org_id> (--user <id>|--service-principal <id>|--group <id>) --permission <perm> [--project <project_id>] [--resource-type <type> --resource <id> --action <read|write|admin>]",
|
|
49623
49654
|
options: [
|
|
49624
49655
|
"--org <org_id> Org scope (uses profile default if omitted)",
|
|
49625
|
-
"--user <user_id> User to check (mutually exclusive with --service-principal)",
|
|
49626
|
-
"--service-principal <sp_id> Service principal to check (mutually exclusive with --user)",
|
|
49656
|
+
"--user <user_id> User to check (mutually exclusive with --service-principal/--group)",
|
|
49657
|
+
"--service-principal <sp_id> Service principal to check (mutually exclusive with --user/--group)",
|
|
49658
|
+
"--group <group_id> Group to check directly (mutually exclusive with --user/--service-principal)",
|
|
49627
49659
|
"--permission <perm> Permission to check (e.g., chat:write, jobs:admin)",
|
|
49628
|
-
"--project <project_id> Optional project scope for the check"
|
|
49660
|
+
"--project <project_id> Optional project scope for the check",
|
|
49661
|
+
"--resource-type <type> Optional resource type: orgfs|orgdocs|envdb",
|
|
49662
|
+
"--resource <id> Optional resource id/path (required when --resource-type used)",
|
|
49663
|
+
"--action <action> Optional action: read|write|admin"
|
|
49629
49664
|
],
|
|
49630
49665
|
examples: [
|
|
49631
49666
|
"eve access can --org org_xxx --user user_abc --permission chat:write",
|
|
49632
49667
|
"eve access can --org org_xxx --user user_abc --project proj_xxx --permission jobs:admin",
|
|
49633
|
-
"eve access can --org org_xxx --service-principal sp_xxx --permission jobs:read"
|
|
49668
|
+
"eve access can --org org_xxx --service-principal sp_xxx --permission jobs:read",
|
|
49669
|
+
"eve access can --org org_xxx --user user_abc --permission orgfs:read --resource-type orgfs --resource /groups/pm/spec.md --action read"
|
|
49634
49670
|
]
|
|
49635
49671
|
},
|
|
49636
49672
|
explain: {
|
|
49637
49673
|
description: "Explain the permission resolution chain",
|
|
49638
|
-
usage: "eve access explain --org <org_id> --user <
|
|
49674
|
+
usage: "eve access explain --org <org_id> (--user <id>|--service-principal <id>|--group <id>) --permission <perm> [--project <project_id>] [--resource-type <type> --resource <id> --action <read|write|admin>]",
|
|
49639
49675
|
options: [
|
|
49640
49676
|
"--org <org_id> Org scope (uses profile default if omitted)",
|
|
49641
|
-
"--user <user_id> User to explain (mutually exclusive with --service-principal)",
|
|
49642
|
-
"--service-principal <sp_id> Service principal to explain (mutually exclusive with --user)",
|
|
49677
|
+
"--user <user_id> User to explain (mutually exclusive with --service-principal/--group)",
|
|
49678
|
+
"--service-principal <sp_id> Service principal to explain (mutually exclusive with --user/--group)",
|
|
49679
|
+
"--group <group_id> Group to explain directly (mutually exclusive with --user/--service-principal)",
|
|
49643
49680
|
"--permission <perm> Permission to explain (e.g., chat:write, jobs:admin)",
|
|
49644
|
-
"--project <project_id> Optional project scope for the explanation"
|
|
49681
|
+
"--project <project_id> Optional project scope for the explanation",
|
|
49682
|
+
"--resource-type <type> Optional resource type: orgfs|orgdocs|envdb",
|
|
49683
|
+
"--resource <id> Optional resource id/path (required when --resource-type used)",
|
|
49684
|
+
"--action <action> Optional action: read|write|admin"
|
|
49645
49685
|
],
|
|
49646
49686
|
examples: [
|
|
49647
49687
|
"eve access explain --org org_xxx --user user_abc --permission jobs:admin",
|
|
49648
49688
|
"eve access explain --org org_xxx --user user_abc --project proj_xxx --permission jobs:admin",
|
|
49649
|
-
"eve access explain --org org_xxx --service-principal sp_xxx --permission jobs:read"
|
|
49689
|
+
"eve access explain --org org_xxx --service-principal sp_xxx --permission jobs:read",
|
|
49690
|
+
"eve access explain --org org_xxx --user user_abc --permission orgfs:read --resource-type orgfs --resource /groups/pm/spec.md --action read"
|
|
49691
|
+
]
|
|
49692
|
+
},
|
|
49693
|
+
groups: {
|
|
49694
|
+
description: "Manage access groups and members",
|
|
49695
|
+
usage: "eve access groups <create|list|show|update|delete|members> [args]",
|
|
49696
|
+
examples: [
|
|
49697
|
+
'eve access groups create "Product Management" --org org_xxx --slug pm-team',
|
|
49698
|
+
"eve access groups list --org org_xxx",
|
|
49699
|
+
"eve access groups members add pm-team --org org_xxx --user user_abc",
|
|
49700
|
+
"eve access groups members list pm-team --org org_xxx"
|
|
49701
|
+
]
|
|
49702
|
+
},
|
|
49703
|
+
memberships: {
|
|
49704
|
+
description: "Inspect memberships, effective bindings, and effective scopes for a principal",
|
|
49705
|
+
usage: "eve access memberships --org <org_id> (--user <id>|--service-principal <id>|--group <id>)",
|
|
49706
|
+
examples: [
|
|
49707
|
+
"eve access memberships --org org_xxx --user user_abc",
|
|
49708
|
+
"eve access memberships --org org_xxx --service-principal sp_abc",
|
|
49709
|
+
"eve access memberships --org org_xxx --group grp_abc"
|
|
49650
49710
|
]
|
|
49651
49711
|
},
|
|
49652
49712
|
validate: {
|
|
@@ -49904,10 +49964,15 @@ for cloud deployments. Credentials are stored globally per API URL.`,
|
|
|
49904
49964
|
examples: ["eve db schema --env staging"]
|
|
49905
49965
|
},
|
|
49906
49966
|
rls: {
|
|
49907
|
-
description: "Show RLS policies
|
|
49908
|
-
usage: "eve db rls --env <name> [--project <id>]",
|
|
49909
|
-
options: [
|
|
49910
|
-
|
|
49967
|
+
description: "Show RLS policies or scaffold helper SQL",
|
|
49968
|
+
usage: "eve db rls --env <name> [--project <id>] | eve db rls init --with-groups [--out <path>] [--force]",
|
|
49969
|
+
options: [
|
|
49970
|
+
"--env <name> Environment name (required for inspect mode)",
|
|
49971
|
+
"--with-groups Generate app.current_group_ids()/app.has_group() helper SQL (init mode)",
|
|
49972
|
+
"--out <path> Output file for init mode (default: db/rls/helpers.sql)",
|
|
49973
|
+
"--force Overwrite output file when it already exists"
|
|
49974
|
+
],
|
|
49975
|
+
examples: ["eve db rls --env staging", "eve db rls init --with-groups"]
|
|
49911
49976
|
},
|
|
49912
49977
|
sql: {
|
|
49913
49978
|
description: "Run parameterized SQL as the calling user",
|
|
@@ -50663,6 +50728,33 @@ eve-new-project-setup skill to complete configuration.`,
|
|
|
50663
50728
|
'eve docs query --org org_xxx --where "metadata.feature_status in draft,review"'
|
|
50664
50729
|
]
|
|
50665
50730
|
},
|
|
50731
|
+
fs: {
|
|
50732
|
+
description: "Manage org filesystem sync links, events, and diagnostics.",
|
|
50733
|
+
usage: "eve fs sync <subcommand> [options]",
|
|
50734
|
+
subcommands: {
|
|
50735
|
+
sync: {
|
|
50736
|
+
description: "Org filesystem sync operations",
|
|
50737
|
+
usage: "eve fs sync <init|status|logs|pause|resume|disconnect|mode|conflicts|resolve|doctor> [options]",
|
|
50738
|
+
options: [
|
|
50739
|
+
"init: --org <id> --local <path> [--mode two-way|push-only|pull-only]",
|
|
50740
|
+
"status: --org <id>",
|
|
50741
|
+
"logs: --org <id> [--after <seq>] [--limit <n>] [--follow]",
|
|
50742
|
+
"pause|resume|disconnect: --org <id> [--link <link_id>]",
|
|
50743
|
+
"mode: --org <id> --set <two-way|push-only|pull-only> [--link <link_id>]",
|
|
50744
|
+
"conflicts: --org <id> [--open-only]",
|
|
50745
|
+
"resolve: --org <id> --conflict <id> --strategy <pick-remote|pick-local|manual>",
|
|
50746
|
+
"doctor: --org <id>"
|
|
50747
|
+
]
|
|
50748
|
+
}
|
|
50749
|
+
},
|
|
50750
|
+
examples: [
|
|
50751
|
+
"eve fs sync init --org org_xxx --local ~/Eve/acme --mode two-way",
|
|
50752
|
+
"eve fs sync status --org org_xxx",
|
|
50753
|
+
"eve fs sync logs --org org_xxx --follow",
|
|
50754
|
+
"eve fs sync mode --org org_xxx --set pull-only",
|
|
50755
|
+
"eve fs sync doctor --org org_xxx"
|
|
50756
|
+
]
|
|
50757
|
+
},
|
|
50666
50758
|
resources: {
|
|
50667
50759
|
description: "Resolve resource URIs into content snapshots.",
|
|
50668
50760
|
usage: "eve resources <subcommand> [options]",
|
|
@@ -50951,6 +51043,7 @@ function showMainHelp() {
|
|
|
50951
51043
|
console.log(" workflow Inspect manifest workflows (list, show)");
|
|
50952
51044
|
console.log(" event Emit and inspect events (app integration)");
|
|
50953
51045
|
console.log(" docs Manage org documents");
|
|
51046
|
+
console.log(" fs Manage org filesystem sync");
|
|
50954
51047
|
console.log(" resources Resolve org/job resources");
|
|
50955
51048
|
console.log(" secrets Manage secrets (project/org/user scope)");
|
|
50956
51049
|
console.log(" harness Inspect harnesses and auth status");
|
|
@@ -51666,8 +51759,201 @@ async function handleProject(subcommand, positionals, flags, context2) {
|
|
|
51666
51759
|
}
|
|
51667
51760
|
return;
|
|
51668
51761
|
}
|
|
51762
|
+
case "status":
|
|
51763
|
+
return handleStatus(flags, context2, json);
|
|
51669
51764
|
default:
|
|
51670
|
-
throw new Error("Usage: eve project <ensure|list|get|spend|update|sync|members|bootstrap>");
|
|
51765
|
+
throw new Error("Usage: eve project <ensure|list|get|spend|update|sync|members|bootstrap|status>");
|
|
51766
|
+
}
|
|
51767
|
+
}
|
|
51768
|
+
async function handleStatus(flags, currentContext, json) {
|
|
51769
|
+
const repoProfiles = loadRepoProfiles();
|
|
51770
|
+
const credentials = loadCredentials();
|
|
51771
|
+
const profileFilter = getStringFlag(flags, ["profile"]);
|
|
51772
|
+
const envFilter = getStringFlag(flags, ["env"]);
|
|
51773
|
+
const profileEntries = Object.entries(repoProfiles.profiles);
|
|
51774
|
+
if (profileEntries.length === 0) {
|
|
51775
|
+
throw new Error(
|
|
51776
|
+
"No profiles configured. Use `eve profile create <name> --api-url <url> --project <id>` to add one."
|
|
51777
|
+
);
|
|
51778
|
+
}
|
|
51779
|
+
const results = [];
|
|
51780
|
+
for (const [name, profile] of profileEntries) {
|
|
51781
|
+
if (profileFilter && name !== profileFilter) continue;
|
|
51782
|
+
const active = name === repoProfiles.activeProfile;
|
|
51783
|
+
const ctx = resolveContextForProfile(name, profile, credentials);
|
|
51784
|
+
if (!ctx.projectId) {
|
|
51785
|
+
results.push({ name, active, api_url: ctx.apiUrl, error: "No project_id configured" });
|
|
51786
|
+
continue;
|
|
51787
|
+
}
|
|
51788
|
+
if (!ctx.token) {
|
|
51789
|
+
results.push({
|
|
51790
|
+
name,
|
|
51791
|
+
active,
|
|
51792
|
+
api_url: ctx.apiUrl,
|
|
51793
|
+
project_id: ctx.projectId,
|
|
51794
|
+
error: "Not authenticated (run: eve auth login --profile " + name + ")"
|
|
51795
|
+
});
|
|
51796
|
+
continue;
|
|
51797
|
+
}
|
|
51798
|
+
try {
|
|
51799
|
+
const result = await fetchProfileStatus(ctx, envFilter);
|
|
51800
|
+
results.push({ name, active, ...result });
|
|
51801
|
+
} catch (err) {
|
|
51802
|
+
results.push({
|
|
51803
|
+
name,
|
|
51804
|
+
active,
|
|
51805
|
+
api_url: ctx.apiUrl,
|
|
51806
|
+
project_id: ctx.projectId,
|
|
51807
|
+
error: err instanceof Error ? err.message : String(err)
|
|
51808
|
+
});
|
|
51809
|
+
}
|
|
51810
|
+
}
|
|
51811
|
+
if (json) {
|
|
51812
|
+
outputJson({ profiles: results }, json);
|
|
51813
|
+
return;
|
|
51814
|
+
}
|
|
51815
|
+
formatStatusOutput(results);
|
|
51816
|
+
}
|
|
51817
|
+
async function fetchProfileStatus(ctx, envFilter) {
|
|
51818
|
+
const [project, releasesResponse] = await Promise.all([
|
|
51819
|
+
requestJson(ctx, `/projects/${ctx.projectId}`),
|
|
51820
|
+
requestJson(ctx, `/projects/${ctx.projectId}/releases?limit=50`).catch(() => ({ data: [] }))
|
|
51821
|
+
]);
|
|
51822
|
+
const releasesById = new Map(releasesResponse.data.map((r) => [r.id, r]));
|
|
51823
|
+
const envResponse = await requestJson(ctx, `/projects/${ctx.projectId}/envs?limit=50`);
|
|
51824
|
+
const domain = inferDomain(ctx.apiUrl);
|
|
51825
|
+
const environments = [];
|
|
51826
|
+
for (const env of envResponse.data) {
|
|
51827
|
+
if (envFilter && env.name !== envFilter) continue;
|
|
51828
|
+
const status = env.suspended_at ? "suspended" : "active";
|
|
51829
|
+
let release = null;
|
|
51830
|
+
if (env.current_release_id) {
|
|
51831
|
+
const r = releasesById.get(env.current_release_id);
|
|
51832
|
+
if (r) {
|
|
51833
|
+
release = {
|
|
51834
|
+
git_sha: r.git_sha,
|
|
51835
|
+
version: r.version,
|
|
51836
|
+
tag: r.tag,
|
|
51837
|
+
deployed_at: r.created_at,
|
|
51838
|
+
created_by: r.created_by
|
|
51839
|
+
};
|
|
51840
|
+
}
|
|
51841
|
+
}
|
|
51842
|
+
if (env.suspended_at) {
|
|
51843
|
+
environments.push({
|
|
51844
|
+
name: env.name,
|
|
51845
|
+
type: env.type,
|
|
51846
|
+
status,
|
|
51847
|
+
namespace: env.namespace,
|
|
51848
|
+
release,
|
|
51849
|
+
services: []
|
|
51850
|
+
});
|
|
51851
|
+
continue;
|
|
51852
|
+
}
|
|
51853
|
+
let services = [];
|
|
51854
|
+
try {
|
|
51855
|
+
const diagnose = await requestJson(ctx, `/projects/${ctx.projectId}/envs/${env.name}/diagnose`);
|
|
51856
|
+
services = buildStatusServices(diagnose.pods, diagnose.namespace ?? env.namespace, domain);
|
|
51857
|
+
} catch {
|
|
51858
|
+
}
|
|
51859
|
+
environments.push({
|
|
51860
|
+
name: env.name,
|
|
51861
|
+
type: env.type,
|
|
51862
|
+
status,
|
|
51863
|
+
namespace: env.namespace,
|
|
51864
|
+
release,
|
|
51865
|
+
services
|
|
51866
|
+
});
|
|
51867
|
+
}
|
|
51868
|
+
return {
|
|
51869
|
+
api_url: ctx.apiUrl,
|
|
51870
|
+
project_id: project.id,
|
|
51871
|
+
project_name: project.name,
|
|
51872
|
+
environments
|
|
51873
|
+
};
|
|
51874
|
+
}
|
|
51875
|
+
function buildStatusServices(pods, namespace, domain) {
|
|
51876
|
+
const services = /* @__PURE__ */ new Map();
|
|
51877
|
+
for (const pod of pods) {
|
|
51878
|
+
const component = pod.labels["eve.component"] || pod.labels["app.kubernetes.io/name"] || pod.labels["app"] || pod.labels["component"] || "unknown";
|
|
51879
|
+
const existing = services.get(component) ?? { ready: 0, total: 0, phases: /* @__PURE__ */ new Set() };
|
|
51880
|
+
existing.total += 1;
|
|
51881
|
+
if (pod.ready) existing.ready += 1;
|
|
51882
|
+
existing.phases.add(pod.phase);
|
|
51883
|
+
services.set(component, existing);
|
|
51884
|
+
}
|
|
51885
|
+
return Array.from(services.entries()).sort(([a], [b]) => a.localeCompare(b)).map(([name, info]) => {
|
|
51886
|
+
const allDone = info.phases.size > 0 && [...info.phases].every((p) => p === "Succeeded" || p === "Failed");
|
|
51887
|
+
const status = allDone ? "completed" : info.ready === info.total ? "ready" : "not-ready";
|
|
51888
|
+
const url = !allDone && namespace && domain ? buildServiceUrl(name, namespace, domain) : null;
|
|
51889
|
+
return {
|
|
51890
|
+
name,
|
|
51891
|
+
pods_ready: info.ready,
|
|
51892
|
+
pods_total: info.total,
|
|
51893
|
+
status,
|
|
51894
|
+
url
|
|
51895
|
+
};
|
|
51896
|
+
});
|
|
51897
|
+
}
|
|
51898
|
+
function inferDomain(apiUrl) {
|
|
51899
|
+
try {
|
|
51900
|
+
const host = new URL(apiUrl).hostname;
|
|
51901
|
+
if (host.startsWith("api.eve.")) return host.slice("api.eve.".length);
|
|
51902
|
+
if (host.startsWith("api.")) return host.slice("api.".length);
|
|
51903
|
+
return null;
|
|
51904
|
+
} catch {
|
|
51905
|
+
return null;
|
|
51906
|
+
}
|
|
51907
|
+
}
|
|
51908
|
+
function buildServiceUrl(component, namespace, domain) {
|
|
51909
|
+
const slug = namespace.startsWith("eve-") ? namespace.slice(4) : namespace;
|
|
51910
|
+
const secure = !domain.includes("lvh.me") && !domain.includes("localhost");
|
|
51911
|
+
return `${secure ? "https" : "http"}://${component}.${slug}.${domain}`;
|
|
51912
|
+
}
|
|
51913
|
+
function formatStatusOutput(results) {
|
|
51914
|
+
for (let i = 0; i < results.length; i++) {
|
|
51915
|
+
const r = results[i];
|
|
51916
|
+
if (i > 0) console.log("");
|
|
51917
|
+
const marker = r.active ? " (active)" : "";
|
|
51918
|
+
console.log(`${r.name}${marker} ${r.api_url}`);
|
|
51919
|
+
if (r.error) {
|
|
51920
|
+
console.log(` error: ${r.error}`);
|
|
51921
|
+
continue;
|
|
51922
|
+
}
|
|
51923
|
+
const label = r.project_name ? `${r.project_id} (${r.project_name})` : r.project_id;
|
|
51924
|
+
console.log(` project: ${label}`);
|
|
51925
|
+
if (!r.environments || r.environments.length === 0) {
|
|
51926
|
+
console.log(" (no environments)");
|
|
51927
|
+
continue;
|
|
51928
|
+
}
|
|
51929
|
+
for (const env of r.environments) {
|
|
51930
|
+
console.log("");
|
|
51931
|
+
console.log(` ${env.name} ${env.status} ${env.type}`);
|
|
51932
|
+
if (env.release) {
|
|
51933
|
+
const sha = env.release.git_sha.substring(0, 8);
|
|
51934
|
+
const age = formatAge(env.release.deployed_at);
|
|
51935
|
+
const ver = env.release.tag ?? env.release.version ?? "";
|
|
51936
|
+
const verPart = ver ? ` ${ver}` : "";
|
|
51937
|
+
console.log(` revision: ${sha}${verPart} deployed ${age}`);
|
|
51938
|
+
}
|
|
51939
|
+
if (env.services.length === 0) {
|
|
51940
|
+
if (env.status === "suspended") {
|
|
51941
|
+
console.log(" (suspended)");
|
|
51942
|
+
} else {
|
|
51943
|
+
console.log(" (no services)");
|
|
51944
|
+
}
|
|
51945
|
+
continue;
|
|
51946
|
+
}
|
|
51947
|
+
const nameW = Math.max(...env.services.map((s) => s.name.length));
|
|
51948
|
+
const podsW = Math.max(...env.services.map((s) => `${s.pods_ready}/${s.pods_total}`.length));
|
|
51949
|
+
for (const svc of env.services) {
|
|
51950
|
+
const pods = `${svc.pods_ready}/${svc.pods_total}`;
|
|
51951
|
+
const urlPart = svc.url ? ` ${svc.url}` : "";
|
|
51952
|
+
console.log(
|
|
51953
|
+
` ${padRight(svc.name, nameW)} ${padRight(pods, podsW)} ${padRight(svc.status, 9)}${urlPart}`
|
|
51954
|
+
);
|
|
51955
|
+
}
|
|
51956
|
+
}
|
|
51671
51957
|
}
|
|
51672
51958
|
}
|
|
51673
51959
|
function parseSinceValue2(since) {
|
|
@@ -51697,6 +51983,21 @@ function parseSinceValue2(since) {
|
|
|
51697
51983
|
}
|
|
51698
51984
|
return now.toISOString();
|
|
51699
51985
|
}
|
|
51986
|
+
function formatAge(isoDate) {
|
|
51987
|
+
const ms = Date.now() - new Date(isoDate).getTime();
|
|
51988
|
+
if (ms < 0) return "just now";
|
|
51989
|
+
const secs = Math.floor(ms / 1e3);
|
|
51990
|
+
if (secs < 60) return `${secs}s ago`;
|
|
51991
|
+
const mins = Math.floor(secs / 60);
|
|
51992
|
+
if (mins < 60) return `${mins}m ago`;
|
|
51993
|
+
const hours = Math.floor(mins / 60);
|
|
51994
|
+
if (hours < 24) return `${hours}h ago`;
|
|
51995
|
+
const days = Math.floor(hours / 24);
|
|
51996
|
+
return `${days}d ago`;
|
|
51997
|
+
}
|
|
51998
|
+
function padRight(str, width) {
|
|
51999
|
+
return str.length >= width ? str : str + " ".repeat(width - str.length);
|
|
52000
|
+
}
|
|
51700
52001
|
function buildQuery2(params) {
|
|
51701
52002
|
const search = new URLSearchParams();
|
|
51702
52003
|
Object.entries(params).forEach(([key, value]) => {
|
|
@@ -55834,6 +56135,8 @@ var configSchema = external_exports.object({
|
|
|
55834
56135
|
EVE_GITHUB_TOKEN: external_exports.string().optional(),
|
|
55835
56136
|
EVE_SLACK_SIGNING_SECRET: external_exports.string().optional(),
|
|
55836
56137
|
EVE_INTERNAL_API_KEY: external_exports.string().optional(),
|
|
56138
|
+
EVE_ORG_FS_LINK_TOKEN_SECRET: external_exports.string().optional(),
|
|
56139
|
+
EVE_ORG_FS_LINK_TOKEN_TTL_SECONDS: external_exports.coerce.number().int().min(60).default(900),
|
|
55837
56140
|
EVE_SECRETS_MASTER_KEY: external_exports.string().optional(),
|
|
55838
56141
|
EVE_DEFAULT_DOMAIN: external_exports.string().optional(),
|
|
55839
56142
|
// Cluster-level default domain for Ingress (e.g., lvh.me, apps.example.com)
|
|
@@ -56961,56 +57264,179 @@ var AccessRoleResponseSchema = external_exports.object({
|
|
|
56961
57264
|
updated_at: external_exports.string()
|
|
56962
57265
|
});
|
|
56963
57266
|
var AccessRoleListResponseSchema = createApiListResponseSchema(AccessRoleResponseSchema);
|
|
57267
|
+
var AccessPrincipalTypeSchema = external_exports.enum(["user", "service_principal", "group"]);
|
|
57268
|
+
var AccessGroupMemberPrincipalTypeSchema = external_exports.enum(["user", "service_principal"]);
|
|
57269
|
+
var AccessScopePrefixesSchema = external_exports.object({
|
|
57270
|
+
allow_prefixes: external_exports.array(external_exports.string()).optional(),
|
|
57271
|
+
read_only_prefixes: external_exports.array(external_exports.string()).optional()
|
|
57272
|
+
}).strict();
|
|
57273
|
+
var AccessScopeEnvDbSchema = external_exports.object({
|
|
57274
|
+
schemas: external_exports.array(external_exports.string()).optional(),
|
|
57275
|
+
tables: external_exports.array(external_exports.string()).optional()
|
|
57276
|
+
}).strict();
|
|
57277
|
+
var AccessBindingScopeSchema = external_exports.object({
|
|
57278
|
+
orgfs: AccessScopePrefixesSchema.optional(),
|
|
57279
|
+
orgdocs: AccessScopePrefixesSchema.optional(),
|
|
57280
|
+
envdb: AccessScopeEnvDbSchema.optional()
|
|
57281
|
+
}).strict();
|
|
56964
57282
|
var CreateAccessBindingRequestSchema = external_exports.object({
|
|
56965
57283
|
role_name: external_exports.string().min(1),
|
|
56966
|
-
principal_type:
|
|
57284
|
+
principal_type: AccessPrincipalTypeSchema,
|
|
56967
57285
|
principal_id: external_exports.string().min(1),
|
|
56968
|
-
project_id: external_exports.string().optional()
|
|
57286
|
+
project_id: external_exports.string().optional(),
|
|
57287
|
+
scope_json: AccessBindingScopeSchema.optional()
|
|
56969
57288
|
});
|
|
56970
57289
|
var AccessBindingResponseSchema = external_exports.object({
|
|
56971
57290
|
id: external_exports.string(),
|
|
56972
57291
|
role_id: external_exports.string(),
|
|
56973
57292
|
role_name: external_exports.string(),
|
|
56974
|
-
principal_type:
|
|
57293
|
+
principal_type: AccessPrincipalTypeSchema,
|
|
56975
57294
|
principal_id: external_exports.string(),
|
|
56976
57295
|
project_id: external_exports.string().nullable(),
|
|
57296
|
+
scope_json: AccessBindingScopeSchema.nullable().optional(),
|
|
56977
57297
|
created_by: external_exports.string().nullable(),
|
|
56978
57298
|
created_at: external_exports.string()
|
|
56979
57299
|
});
|
|
56980
57300
|
var AccessBindingListResponseSchema = createApiListResponseSchema(AccessBindingResponseSchema);
|
|
57301
|
+
var CreateAccessGroupRequestSchema = external_exports.object({
|
|
57302
|
+
name: external_exports.string().min(1).max(100),
|
|
57303
|
+
slug: external_exports.string().min(1).max(100).regex(/^[a-z0-9][a-z0-9-_]*$/).optional(),
|
|
57304
|
+
description: external_exports.string().max(500).optional()
|
|
57305
|
+
});
|
|
57306
|
+
var UpdateAccessGroupRequestSchema = external_exports.object({
|
|
57307
|
+
name: external_exports.string().min(1).max(100).optional(),
|
|
57308
|
+
slug: external_exports.string().min(1).max(100).regex(/^[a-z0-9][a-z0-9-_]*$/).optional(),
|
|
57309
|
+
description: external_exports.string().max(500).nullable().optional()
|
|
57310
|
+
}).refine((value) => Object.keys(value).length > 0, {
|
|
57311
|
+
message: "At least one field is required"
|
|
57312
|
+
});
|
|
57313
|
+
var AccessGroupResponseSchema = external_exports.object({
|
|
57314
|
+
id: external_exports.string(),
|
|
57315
|
+
org_id: external_exports.string(),
|
|
57316
|
+
name: external_exports.string(),
|
|
57317
|
+
slug: external_exports.string(),
|
|
57318
|
+
description: external_exports.string().nullable(),
|
|
57319
|
+
created_by: external_exports.string().nullable(),
|
|
57320
|
+
created_at: external_exports.string(),
|
|
57321
|
+
updated_at: external_exports.string()
|
|
57322
|
+
});
|
|
57323
|
+
var AccessGroupListResponseSchema = createApiListResponseSchema(AccessGroupResponseSchema);
|
|
57324
|
+
var CreateAccessGroupMemberRequestSchema = external_exports.object({
|
|
57325
|
+
principal_type: AccessGroupMemberPrincipalTypeSchema,
|
|
57326
|
+
principal_id: external_exports.string().min(1)
|
|
57327
|
+
});
|
|
57328
|
+
var AccessGroupMemberResponseSchema = external_exports.object({
|
|
57329
|
+
group_id: external_exports.string(),
|
|
57330
|
+
principal_type: AccessGroupMemberPrincipalTypeSchema,
|
|
57331
|
+
principal_id: external_exports.string(),
|
|
57332
|
+
added_by: external_exports.string().nullable(),
|
|
57333
|
+
created_at: external_exports.string()
|
|
57334
|
+
});
|
|
57335
|
+
var AccessGroupMemberListResponseSchema = createApiListResponseSchema(AccessGroupMemberResponseSchema);
|
|
56981
57336
|
var AccessCanResponseSchema = external_exports.object({
|
|
56982
57337
|
allowed: external_exports.boolean(),
|
|
56983
|
-
source: external_exports.string()
|
|
57338
|
+
source: external_exports.string(),
|
|
57339
|
+
resource: external_exports.object({
|
|
57340
|
+
type: external_exports.enum(["orgfs", "orgdocs", "envdb"]),
|
|
57341
|
+
id: external_exports.string(),
|
|
57342
|
+
action: external_exports.enum(["read", "write", "admin"]),
|
|
57343
|
+
scope_required: external_exports.boolean(),
|
|
57344
|
+
scope_matched: external_exports.boolean()
|
|
57345
|
+
}).optional()
|
|
56984
57346
|
});
|
|
56985
57347
|
var AccessExplainGrantSchema = external_exports.object({
|
|
56986
57348
|
source: external_exports.string(),
|
|
56987
57349
|
role: external_exports.string().optional(),
|
|
56988
57350
|
permissions: external_exports.array(external_exports.string()),
|
|
56989
|
-
has_permission: external_exports.boolean()
|
|
57351
|
+
has_permission: external_exports.boolean(),
|
|
57352
|
+
scope_json: AccessBindingScopeSchema.nullable().optional(),
|
|
57353
|
+
scope_match: external_exports.boolean().optional(),
|
|
57354
|
+
scope_reason: external_exports.string().optional()
|
|
56990
57355
|
});
|
|
56991
57356
|
var AccessExplainResponseSchema = external_exports.object({
|
|
56992
57357
|
permission: external_exports.string(),
|
|
56993
57358
|
result: external_exports.enum(["ALLOWED", "DENIED"]),
|
|
56994
57359
|
grants: external_exports.array(AccessExplainGrantSchema),
|
|
56995
|
-
missing_reason: external_exports.string().optional()
|
|
57360
|
+
missing_reason: external_exports.string().optional(),
|
|
57361
|
+
resource: external_exports.object({
|
|
57362
|
+
type: external_exports.enum(["orgfs", "orgdocs", "envdb"]),
|
|
57363
|
+
id: external_exports.string(),
|
|
57364
|
+
action: external_exports.enum(["read", "write", "admin"]),
|
|
57365
|
+
scope_required: external_exports.boolean(),
|
|
57366
|
+
scope_matched: external_exports.boolean()
|
|
57367
|
+
}).optional()
|
|
57368
|
+
});
|
|
57369
|
+
var AccessMembershipBaseSchema = external_exports.object({
|
|
57370
|
+
org_role: external_exports.enum(["owner", "admin", "member"]).nullable(),
|
|
57371
|
+
project_roles: external_exports.array(external_exports.object({
|
|
57372
|
+
project_id: external_exports.string(),
|
|
57373
|
+
role: external_exports.enum(["owner", "admin", "member"])
|
|
57374
|
+
})),
|
|
57375
|
+
token_scopes: external_exports.array(external_exports.string())
|
|
57376
|
+
});
|
|
57377
|
+
var AccessGroupSummarySchema = external_exports.object({
|
|
57378
|
+
id: external_exports.string(),
|
|
57379
|
+
slug: external_exports.string(),
|
|
57380
|
+
name: external_exports.string()
|
|
57381
|
+
});
|
|
57382
|
+
var AccessResolvedBindingSchema = AccessBindingResponseSchema.extend({
|
|
57383
|
+
role_permissions: external_exports.array(external_exports.string()),
|
|
57384
|
+
matched_via: external_exports.enum(["direct", "group"]).optional(),
|
|
57385
|
+
matched_group_id: external_exports.string().nullable().optional(),
|
|
57386
|
+
matched_group_slug: external_exports.string().nullable().optional()
|
|
57387
|
+
});
|
|
57388
|
+
var AccessEffectiveScopeSummarySchema = external_exports.object({
|
|
57389
|
+
orgfs: external_exports.object({
|
|
57390
|
+
allow_prefixes: external_exports.array(external_exports.string()),
|
|
57391
|
+
read_only_prefixes: external_exports.array(external_exports.string())
|
|
57392
|
+
}),
|
|
57393
|
+
orgdocs: external_exports.object({
|
|
57394
|
+
allow_prefixes: external_exports.array(external_exports.string()),
|
|
57395
|
+
read_only_prefixes: external_exports.array(external_exports.string())
|
|
57396
|
+
}),
|
|
57397
|
+
envdb: external_exports.object({
|
|
57398
|
+
schemas: external_exports.array(external_exports.string()),
|
|
57399
|
+
tables: external_exports.array(external_exports.string())
|
|
57400
|
+
})
|
|
57401
|
+
});
|
|
57402
|
+
var AccessPrincipalMembershipsResponseSchema = external_exports.object({
|
|
57403
|
+
org_id: external_exports.string(),
|
|
57404
|
+
principal_type: AccessPrincipalTypeSchema,
|
|
57405
|
+
principal_id: external_exports.string(),
|
|
57406
|
+
base: AccessMembershipBaseSchema,
|
|
57407
|
+
groups: external_exports.array(AccessGroupSummarySchema),
|
|
57408
|
+
direct_bindings: external_exports.array(AccessBindingResponseSchema),
|
|
57409
|
+
effective_bindings: external_exports.array(AccessResolvedBindingSchema),
|
|
57410
|
+
effective_permissions: external_exports.array(external_exports.string()),
|
|
57411
|
+
effective_scopes: AccessEffectiveScopeSummarySchema
|
|
56996
57412
|
});
|
|
56997
57413
|
var AccessYamlRoleSchema = external_exports.object({
|
|
56998
57414
|
scope: external_exports.enum(["org", "project"]),
|
|
56999
57415
|
description: external_exports.string().optional(),
|
|
57000
57416
|
permissions: external_exports.array(external_exports.string()).min(1)
|
|
57001
57417
|
});
|
|
57418
|
+
var AccessYamlGroupMemberSchema = external_exports.object({
|
|
57419
|
+
type: AccessGroupMemberPrincipalTypeSchema,
|
|
57420
|
+
id: external_exports.string().min(1)
|
|
57421
|
+
});
|
|
57422
|
+
var AccessYamlGroupSchema = external_exports.object({
|
|
57423
|
+
name: external_exports.string().min(1).max(100).optional(),
|
|
57424
|
+
description: external_exports.string().max(500).optional(),
|
|
57425
|
+
members: external_exports.array(AccessYamlGroupMemberSchema).optional()
|
|
57426
|
+
});
|
|
57002
57427
|
var AccessYamlBindingSchema = external_exports.object({
|
|
57003
|
-
scope: external_exports.enum(["org", "project"]),
|
|
57004
57428
|
project_id: external_exports.string().optional(),
|
|
57005
57429
|
subject: external_exports.object({
|
|
57006
|
-
type:
|
|
57430
|
+
type: AccessPrincipalTypeSchema,
|
|
57007
57431
|
id: external_exports.string()
|
|
57008
57432
|
}),
|
|
57009
|
-
roles: external_exports.array(external_exports.string()).min(1)
|
|
57433
|
+
roles: external_exports.array(external_exports.string()).min(1),
|
|
57434
|
+
scope: AccessBindingScopeSchema.optional()
|
|
57010
57435
|
});
|
|
57011
57436
|
var AccessYamlSchema = external_exports.object({
|
|
57012
|
-
version: external_exports.literal(
|
|
57437
|
+
version: external_exports.literal(2),
|
|
57013
57438
|
access: external_exports.object({
|
|
57439
|
+
groups: external_exports.record(external_exports.string().regex(/^[a-z0-9][a-z0-9-_]*$/), AccessYamlGroupSchema).optional(),
|
|
57014
57440
|
roles: external_exports.record(external_exports.string(), AccessYamlRoleSchema).optional(),
|
|
57015
57441
|
bindings: external_exports.array(AccessYamlBindingSchema).optional()
|
|
57016
57442
|
})
|
|
@@ -57561,8 +57987,21 @@ var DbRlsTableSchema = external_exports.object({
|
|
|
57561
57987
|
rls_enabled: external_exports.boolean(),
|
|
57562
57988
|
policies: external_exports.array(DbPolicySchema)
|
|
57563
57989
|
});
|
|
57990
|
+
var DbRlsDiagnosticsContextSchema = external_exports.object({
|
|
57991
|
+
user_id: external_exports.string().nullable(),
|
|
57992
|
+
principal_type: external_exports.enum(["user", "service_principal"]).nullable(),
|
|
57993
|
+
org_id: external_exports.string().nullable(),
|
|
57994
|
+
project_id: external_exports.string().nullable(),
|
|
57995
|
+
env_name: external_exports.string().nullable(),
|
|
57996
|
+
group_ids: external_exports.array(external_exports.string()),
|
|
57997
|
+
permissions: external_exports.array(external_exports.string())
|
|
57998
|
+
});
|
|
57999
|
+
var DbRlsDiagnosticsSchema = external_exports.object({
|
|
58000
|
+
context: DbRlsDiagnosticsContextSchema
|
|
58001
|
+
});
|
|
57564
58002
|
var DbRlsResponseSchema = external_exports.object({
|
|
57565
|
-
tables: external_exports.array(DbRlsTableSchema)
|
|
58003
|
+
tables: external_exports.array(DbRlsTableSchema),
|
|
58004
|
+
diagnostics: DbRlsDiagnosticsSchema
|
|
57566
58005
|
});
|
|
57567
58006
|
var DbSqlRequestSchema = external_exports.object({
|
|
57568
58007
|
sql: external_exports.string().min(1),
|
|
@@ -58363,6 +58802,186 @@ var OrgDocumentQueryResponseSchema = external_exports.object({
|
|
|
58363
58802
|
})
|
|
58364
58803
|
});
|
|
58365
58804
|
|
|
58805
|
+
// ../shared/dist/schemas/org-fs-sync.js
|
|
58806
|
+
var OrgFsSyncModeSchema = external_exports.enum(["two_way", "push_only", "pull_only"]);
|
|
58807
|
+
var OrgFsLinkStatusSchema = external_exports.enum(["active", "paused", "revoked"]);
|
|
58808
|
+
var OrgFsDeviceStatusSchema = external_exports.enum(["active", "revoked"]);
|
|
58809
|
+
var OrgFsEventSourceSideSchema = external_exports.enum(["local", "remote", "system"]);
|
|
58810
|
+
var OrgFsOwnerPrincipalTypeSchema = external_exports.enum(["user", "service_principal", "system"]);
|
|
58811
|
+
var OrgFsLinkScopeSchema = external_exports.object({
|
|
58812
|
+
allow_prefixes: external_exports.array(external_exports.string().min(1)),
|
|
58813
|
+
read_only_prefixes: external_exports.array(external_exports.string().min(1)).optional()
|
|
58814
|
+
}).passthrough();
|
|
58815
|
+
var OrgFsDeviceSchema = external_exports.object({
|
|
58816
|
+
id: external_exports.string(),
|
|
58817
|
+
org_id: external_exports.string(),
|
|
58818
|
+
device_name: external_exports.string(),
|
|
58819
|
+
platform: external_exports.string().nullable(),
|
|
58820
|
+
client_version: external_exports.string().nullable(),
|
|
58821
|
+
public_key: external_exports.string(),
|
|
58822
|
+
status: OrgFsDeviceStatusSchema,
|
|
58823
|
+
last_seen_at: external_exports.string().nullable(),
|
|
58824
|
+
created_at: external_exports.string(),
|
|
58825
|
+
updated_at: external_exports.string()
|
|
58826
|
+
});
|
|
58827
|
+
var OrgFsEnrollmentSchema = external_exports.object({
|
|
58828
|
+
token: external_exports.string(),
|
|
58829
|
+
expires_at: external_exports.string(),
|
|
58830
|
+
gateway_url: external_exports.string().url()
|
|
58831
|
+
});
|
|
58832
|
+
var OrgFsEnrollDeviceRequestSchema = external_exports.object({
|
|
58833
|
+
device_name: external_exports.string().min(1),
|
|
58834
|
+
platform: external_exports.string().optional(),
|
|
58835
|
+
client_version: external_exports.string().optional(),
|
|
58836
|
+
public_key: external_exports.string().optional()
|
|
58837
|
+
});
|
|
58838
|
+
var OrgFsEnrollDeviceResponseSchema = external_exports.object({
|
|
58839
|
+
device: OrgFsDeviceSchema,
|
|
58840
|
+
enrollment: OrgFsEnrollmentSchema
|
|
58841
|
+
});
|
|
58842
|
+
var OrgFsLinkSchema = external_exports.object({
|
|
58843
|
+
id: external_exports.string(),
|
|
58844
|
+
org_id: external_exports.string(),
|
|
58845
|
+
device_id: external_exports.string(),
|
|
58846
|
+
owner_principal_type: OrgFsOwnerPrincipalTypeSchema,
|
|
58847
|
+
owner_principal_id: external_exports.string().nullable(),
|
|
58848
|
+
mode: OrgFsSyncModeSchema,
|
|
58849
|
+
status: OrgFsLinkStatusSchema,
|
|
58850
|
+
local_path: external_exports.string(),
|
|
58851
|
+
remote_path: external_exports.string(),
|
|
58852
|
+
scope_json: OrgFsLinkScopeSchema,
|
|
58853
|
+
includes: external_exports.array(external_exports.string()),
|
|
58854
|
+
excludes: external_exports.array(external_exports.string()),
|
|
58855
|
+
last_cursor: external_exports.number().int().nonnegative(),
|
|
58856
|
+
lag_ms: external_exports.number().int().nonnegative().nullable().optional(),
|
|
58857
|
+
backlog: external_exports.number().int().nonnegative().optional(),
|
|
58858
|
+
last_synced_at: external_exports.string().nullable(),
|
|
58859
|
+
last_heartbeat_at: external_exports.string().nullable(),
|
|
58860
|
+
updated_at: external_exports.string(),
|
|
58861
|
+
created_at: external_exports.string()
|
|
58862
|
+
});
|
|
58863
|
+
var OrgFsCreateLinkRequestSchema = external_exports.object({
|
|
58864
|
+
device_id: external_exports.string().min(1),
|
|
58865
|
+
mode: OrgFsSyncModeSchema.default("two_way"),
|
|
58866
|
+
local_path: external_exports.string().min(1),
|
|
58867
|
+
remote_path: external_exports.string().min(1).default("/"),
|
|
58868
|
+
allow_prefixes: external_exports.array(external_exports.string().min(1)).min(1).optional(),
|
|
58869
|
+
includes: external_exports.array(external_exports.string()).optional(),
|
|
58870
|
+
excludes: external_exports.array(external_exports.string()).optional()
|
|
58871
|
+
});
|
|
58872
|
+
var OrgFsLinkGatewayTokenSchema = external_exports.object({
|
|
58873
|
+
token: external_exports.string(),
|
|
58874
|
+
expires_at: external_exports.string(),
|
|
58875
|
+
header: external_exports.string().default("x-eve-internal-token"),
|
|
58876
|
+
link_id: external_exports.string(),
|
|
58877
|
+
mode: OrgFsSyncModeSchema,
|
|
58878
|
+
allow_prefixes: external_exports.array(external_exports.string())
|
|
58879
|
+
});
|
|
58880
|
+
var OrgFsCreateLinkResponseSchema = external_exports.object({
|
|
58881
|
+
link: OrgFsLinkSchema,
|
|
58882
|
+
runtime: external_exports.object({
|
|
58883
|
+
sync_engine: external_exports.literal("syncthing"),
|
|
58884
|
+
profile: external_exports.string(),
|
|
58885
|
+
gateway: OrgFsLinkGatewayTokenSchema
|
|
58886
|
+
})
|
|
58887
|
+
});
|
|
58888
|
+
var OrgFsRotateLinkTokenResponseSchema = external_exports.object({
|
|
58889
|
+
gateway: OrgFsLinkGatewayTokenSchema
|
|
58890
|
+
});
|
|
58891
|
+
var OrgFsListLinksResponseSchema = external_exports.object({
|
|
58892
|
+
data: external_exports.array(OrgFsLinkSchema)
|
|
58893
|
+
});
|
|
58894
|
+
var OrgFsUpdateLinkRequestSchema = external_exports.object({
|
|
58895
|
+
mode: OrgFsSyncModeSchema.optional(),
|
|
58896
|
+
status: OrgFsLinkStatusSchema.optional(),
|
|
58897
|
+
allow_prefixes: external_exports.array(external_exports.string().min(1)).min(1).optional(),
|
|
58898
|
+
includes: external_exports.array(external_exports.string()).optional(),
|
|
58899
|
+
excludes: external_exports.array(external_exports.string()).optional()
|
|
58900
|
+
}).refine((value) => Object.keys(value).length > 0, {
|
|
58901
|
+
message: "At least one field is required"
|
|
58902
|
+
});
|
|
58903
|
+
var OrgFsDeleteLinkResponseSchema = external_exports.object({
|
|
58904
|
+
success: external_exports.boolean()
|
|
58905
|
+
});
|
|
58906
|
+
var OrgFsStatusResponseSchema = external_exports.object({
|
|
58907
|
+
org_id: external_exports.string(),
|
|
58908
|
+
gateway: external_exports.object({
|
|
58909
|
+
status: external_exports.enum(["healthy", "degraded", "offline"]),
|
|
58910
|
+
last_heartbeat_at: external_exports.string().nullable()
|
|
58911
|
+
}),
|
|
58912
|
+
links: external_exports.object({
|
|
58913
|
+
active: external_exports.number().int().nonnegative(),
|
|
58914
|
+
paused: external_exports.number().int().nonnegative(),
|
|
58915
|
+
revoked: external_exports.number().int().nonnegative()
|
|
58916
|
+
}),
|
|
58917
|
+
events: external_exports.object({
|
|
58918
|
+
latest_seq: external_exports.number().int().nonnegative()
|
|
58919
|
+
})
|
|
58920
|
+
});
|
|
58921
|
+
var OrgFsEventSchema = external_exports.object({
|
|
58922
|
+
seq: external_exports.number().int().nonnegative(),
|
|
58923
|
+
event_id: external_exports.string(),
|
|
58924
|
+
org_id: external_exports.string(),
|
|
58925
|
+
link_id: external_exports.string().nullable().optional(),
|
|
58926
|
+
device_id: external_exports.string().nullable().optional(),
|
|
58927
|
+
event_type: external_exports.string(),
|
|
58928
|
+
path: external_exports.string(),
|
|
58929
|
+
content_hash: external_exports.string().nullable().optional(),
|
|
58930
|
+
size_bytes: external_exports.number().int().nonnegative().nullable().optional(),
|
|
58931
|
+
source_side: OrgFsEventSourceSideSchema,
|
|
58932
|
+
metadata: external_exports.record(external_exports.unknown()).optional(),
|
|
58933
|
+
created_at: external_exports.string()
|
|
58934
|
+
});
|
|
58935
|
+
var OrgFsEventListResponseSchema = external_exports.object({
|
|
58936
|
+
data: external_exports.array(OrgFsEventSchema),
|
|
58937
|
+
pagination: external_exports.object({
|
|
58938
|
+
limit: external_exports.number().int().positive(),
|
|
58939
|
+
next_after_seq: external_exports.number().int().nonnegative().nullable()
|
|
58940
|
+
})
|
|
58941
|
+
});
|
|
58942
|
+
var OrgFsConflictSchema = external_exports.object({
|
|
58943
|
+
id: external_exports.string(),
|
|
58944
|
+
org_id: external_exports.string(),
|
|
58945
|
+
link_id: external_exports.string().nullable(),
|
|
58946
|
+
path: external_exports.string(),
|
|
58947
|
+
local_hash: external_exports.string().nullable(),
|
|
58948
|
+
remote_hash: external_exports.string().nullable(),
|
|
58949
|
+
status: external_exports.enum(["open", "resolved"]),
|
|
58950
|
+
resolution: external_exports.enum(["pick_local", "pick_remote", "manual"]).nullable(),
|
|
58951
|
+
resolved_by: external_exports.string().nullable(),
|
|
58952
|
+
resolved_at: external_exports.string().nullable(),
|
|
58953
|
+
created_at: external_exports.string()
|
|
58954
|
+
});
|
|
58955
|
+
var OrgFsListConflictsResponseSchema = external_exports.object({
|
|
58956
|
+
data: external_exports.array(OrgFsConflictSchema)
|
|
58957
|
+
});
|
|
58958
|
+
var OrgFsResolveConflictRequestSchema = external_exports.object({
|
|
58959
|
+
strategy: external_exports.enum(["pick_local", "pick_remote", "manual"]),
|
|
58960
|
+
merged_content: external_exports.string().optional()
|
|
58961
|
+
});
|
|
58962
|
+
var OrgFsResolveConflictResponseSchema = external_exports.object({
|
|
58963
|
+
conflict: OrgFsConflictSchema
|
|
58964
|
+
});
|
|
58965
|
+
var OrgFsInternalIngestEventRequestSchema = external_exports.object({
|
|
58966
|
+
event_id: external_exports.string(),
|
|
58967
|
+
link_id: external_exports.string().optional(),
|
|
58968
|
+
device_id: external_exports.string().optional(),
|
|
58969
|
+
event_type: external_exports.string(),
|
|
58970
|
+
path: external_exports.string(),
|
|
58971
|
+
content_hash: external_exports.string().optional(),
|
|
58972
|
+
size_bytes: external_exports.number().int().nonnegative().optional(),
|
|
58973
|
+
source_side: OrgFsEventSourceSideSchema,
|
|
58974
|
+
metadata: external_exports.record(external_exports.unknown()).optional()
|
|
58975
|
+
});
|
|
58976
|
+
var OrgFsInternalHeartbeatRequestSchema = external_exports.object({
|
|
58977
|
+
cursor: external_exports.number().int().nonnegative().optional(),
|
|
58978
|
+
backlog: external_exports.number().int().nonnegative().optional(),
|
|
58979
|
+
lag_ms: external_exports.number().int().nonnegative().optional()
|
|
58980
|
+
});
|
|
58981
|
+
var OrgFsInternalMetricsRequestSchema = external_exports.object({
|
|
58982
|
+
metrics: external_exports.record(external_exports.unknown())
|
|
58983
|
+
});
|
|
58984
|
+
|
|
58366
58985
|
// ../shared/dist/schemas/resource.js
|
|
58367
58986
|
var ResolveResourcesRequestSchema = external_exports.object({
|
|
58368
58987
|
uris: external_exports.array(external_exports.string().min(1)),
|
|
@@ -60767,6 +61386,14 @@ var ALL_PERMISSIONS = [
|
|
|
60767
61386
|
// Env DB
|
|
60768
61387
|
"envdb:read",
|
|
60769
61388
|
"envdb:write",
|
|
61389
|
+
// Org filesystem data plane
|
|
61390
|
+
"orgfs:read",
|
|
61391
|
+
"orgfs:write",
|
|
61392
|
+
"orgfs:admin",
|
|
61393
|
+
// Org document data plane
|
|
61394
|
+
"orgdocs:read",
|
|
61395
|
+
"orgdocs:write",
|
|
61396
|
+
"orgdocs:admin",
|
|
60770
61397
|
// Secrets
|
|
60771
61398
|
"secrets:read",
|
|
60772
61399
|
"secrets:write",
|
|
@@ -61688,11 +62315,11 @@ function formatJobsTable(jobs) {
|
|
|
61688
62315
|
const phaseWidth = Math.max(5, ...jobs.map((j) => j.phase.length));
|
|
61689
62316
|
const titleWidth = Math.min(50, Math.max(5, ...jobs.map((j) => j.title.length)));
|
|
61690
62317
|
const header = [
|
|
61691
|
-
|
|
61692
|
-
|
|
61693
|
-
|
|
61694
|
-
|
|
61695
|
-
|
|
62318
|
+
padRight2("ID", idWidth),
|
|
62319
|
+
padRight2("P", 2),
|
|
62320
|
+
padRight2("Phase", phaseWidth),
|
|
62321
|
+
padRight2("Type", 8),
|
|
62322
|
+
padRight2("Title", titleWidth),
|
|
61696
62323
|
"Assignee"
|
|
61697
62324
|
].join(" ");
|
|
61698
62325
|
console.log(header);
|
|
@@ -61700,11 +62327,11 @@ function formatJobsTable(jobs) {
|
|
|
61700
62327
|
for (const job of jobs) {
|
|
61701
62328
|
const title = job.title.length > titleWidth ? job.title.slice(0, titleWidth - 3) + "..." : job.title;
|
|
61702
62329
|
const row = [
|
|
61703
|
-
|
|
61704
|
-
|
|
61705
|
-
|
|
61706
|
-
|
|
61707
|
-
|
|
62330
|
+
padRight2(job.id, idWidth),
|
|
62331
|
+
padRight2(`P${job.priority}`, 2),
|
|
62332
|
+
padRight2(job.phase, phaseWidth),
|
|
62333
|
+
padRight2(job.issue_type, 8),
|
|
62334
|
+
padRight2(title, titleWidth),
|
|
61708
62335
|
job.assignee ?? "-"
|
|
61709
62336
|
].join(" ");
|
|
61710
62337
|
console.log(row);
|
|
@@ -63344,7 +63971,7 @@ function formatDuration(startStr, endStr) {
|
|
|
63344
63971
|
return "unknown";
|
|
63345
63972
|
}
|
|
63346
63973
|
}
|
|
63347
|
-
function
|
|
63974
|
+
function padRight2(str, width) {
|
|
63348
63975
|
if (str.length >= width) return str;
|
|
63349
63976
|
return str + " ".repeat(width - str.length);
|
|
63350
63977
|
}
|
|
@@ -63938,11 +64565,11 @@ Permissions (${data.permissions.length}):`);
|
|
|
63938
64565
|
}
|
|
63939
64566
|
if (status) {
|
|
63940
64567
|
if (status.completed) {
|
|
63941
|
-
|
|
64568
|
+
console.log("Bootstrap already completed. Attempting server-side recovery flow.");
|
|
63942
64569
|
}
|
|
63943
|
-
if (!status.requires_token && status.window_open) {
|
|
64570
|
+
if (!status.completed && !status.requires_token && status.window_open) {
|
|
63944
64571
|
console.log(`Bootstrap window open (${status.mode} mode). Token not required.`);
|
|
63945
|
-
} else if (status.requires_token && !token) {
|
|
64572
|
+
} else if (!status.completed && status.requires_token && !token) {
|
|
63946
64573
|
throw new Error("Bootstrap token required. Use --token <token> or set EVE_BOOTSTRAP_TOKEN");
|
|
63947
64574
|
}
|
|
63948
64575
|
} else if (!token) {
|
|
@@ -64977,10 +65604,10 @@ function renderDiscoveredModels(response) {
|
|
|
64977
65604
|
${response.models.length} model(s) discovered`);
|
|
64978
65605
|
}
|
|
64979
65606
|
function formatRow2(columns, widths) {
|
|
64980
|
-
const cells = columns.map((value, idx) => ` ${
|
|
65607
|
+
const cells = columns.map((value, idx) => ` ${padRight3(value, widths[idx])} `);
|
|
64981
65608
|
return `|${cells.join("|")}|`;
|
|
64982
65609
|
}
|
|
64983
|
-
function
|
|
65610
|
+
function padRight3(value, width) {
|
|
64984
65611
|
return value.length >= width ? value : `${value}${" ".repeat(width - value.length)}`;
|
|
64985
65612
|
}
|
|
64986
65613
|
|
|
@@ -65195,7 +65822,7 @@ async function handleSystem(subcommand, positionals, flags, context2) {
|
|
|
65195
65822
|
const json = Boolean(flags.json);
|
|
65196
65823
|
switch (subcommand) {
|
|
65197
65824
|
case "status":
|
|
65198
|
-
return
|
|
65825
|
+
return handleStatus2(context2, json);
|
|
65199
65826
|
case "health":
|
|
65200
65827
|
return handleHealth(context2, json);
|
|
65201
65828
|
case "jobs":
|
|
@@ -65218,7 +65845,7 @@ async function handleSystem(subcommand, positionals, flags, context2) {
|
|
|
65218
65845
|
throw new Error("Usage: eve system <status|health|jobs|envs|logs|pods|events|config|settings|orchestrator>");
|
|
65219
65846
|
}
|
|
65220
65847
|
}
|
|
65221
|
-
async function
|
|
65848
|
+
async function handleStatus2(context2, json) {
|
|
65222
65849
|
try {
|
|
65223
65850
|
const status = await requestJson(context2, "/system/status");
|
|
65224
65851
|
if (json) {
|
|
@@ -65584,11 +66211,11 @@ function formatJobsTable2(jobs) {
|
|
|
65584
66211
|
const phaseWidth = Math.max(5, ...jobs.map((j) => j.phase.length));
|
|
65585
66212
|
const titleWidth = Math.min(40, Math.max(5, ...jobs.map((j) => j.title.length)));
|
|
65586
66213
|
const header = [
|
|
65587
|
-
|
|
65588
|
-
|
|
65589
|
-
|
|
65590
|
-
|
|
65591
|
-
|
|
66214
|
+
padRight4("Job ID", idWidth),
|
|
66215
|
+
padRight4("Project", projectWidth),
|
|
66216
|
+
padRight4("Phase", phaseWidth),
|
|
66217
|
+
padRight4("P", 2),
|
|
66218
|
+
padRight4("Title", titleWidth),
|
|
65592
66219
|
"Assignee"
|
|
65593
66220
|
].join(" ");
|
|
65594
66221
|
console.log(header);
|
|
@@ -65596,11 +66223,11 @@ function formatJobsTable2(jobs) {
|
|
|
65596
66223
|
for (const job of jobs) {
|
|
65597
66224
|
const title = job.title.length > titleWidth ? job.title.slice(0, titleWidth - 3) + "..." : job.title;
|
|
65598
66225
|
const row = [
|
|
65599
|
-
|
|
65600
|
-
|
|
65601
|
-
|
|
65602
|
-
|
|
65603
|
-
|
|
66226
|
+
padRight4(job.id, idWidth),
|
|
66227
|
+
padRight4(job.project_id, projectWidth),
|
|
66228
|
+
padRight4(job.phase, phaseWidth),
|
|
66229
|
+
padRight4(`P${job.priority}`, 2),
|
|
66230
|
+
padRight4(title, titleWidth),
|
|
65604
66231
|
job.assignee ?? "-"
|
|
65605
66232
|
].join(" ");
|
|
65606
66233
|
console.log(row);
|
|
@@ -65619,21 +66246,21 @@ function formatEnvsTable(envs) {
|
|
|
65619
66246
|
const namespaceWidth = Math.max(9, ...envs.map((e) => (e.namespace ?? "-").length));
|
|
65620
66247
|
const releaseWidth = Math.max(7, ...envs.map((e) => (e.current_release ?? "-").length));
|
|
65621
66248
|
const header = [
|
|
65622
|
-
|
|
65623
|
-
|
|
65624
|
-
|
|
65625
|
-
|
|
65626
|
-
|
|
66249
|
+
padRight4("Project", projectWidth),
|
|
66250
|
+
padRight4("Environment", nameWidth),
|
|
66251
|
+
padRight4("Type", typeWidth),
|
|
66252
|
+
padRight4("Namespace", namespaceWidth),
|
|
66253
|
+
padRight4("Release", releaseWidth)
|
|
65627
66254
|
].join(" ");
|
|
65628
66255
|
console.log(header);
|
|
65629
66256
|
console.log("-".repeat(header.length));
|
|
65630
66257
|
for (const env of envs) {
|
|
65631
66258
|
const row = [
|
|
65632
|
-
|
|
65633
|
-
|
|
65634
|
-
|
|
65635
|
-
|
|
65636
|
-
|
|
66259
|
+
padRight4(env.project_id, projectWidth),
|
|
66260
|
+
padRight4(env.name, nameWidth),
|
|
66261
|
+
padRight4(env.type, typeWidth),
|
|
66262
|
+
padRight4(env.namespace ?? "-", namespaceWidth),
|
|
66263
|
+
padRight4(env.current_release ?? "-", releaseWidth)
|
|
65637
66264
|
].join(" ");
|
|
65638
66265
|
console.log(row);
|
|
65639
66266
|
}
|
|
@@ -65652,12 +66279,12 @@ function formatPodsTable(pods) {
|
|
|
65652
66279
|
const restartsWidth = Math.max(8, ...pods.map((p) => String(p.restarts).length));
|
|
65653
66280
|
const ageWidth = Math.max(3, ...pods.map((p) => p.age.length));
|
|
65654
66281
|
const header = [
|
|
65655
|
-
|
|
65656
|
-
|
|
65657
|
-
|
|
65658
|
-
|
|
65659
|
-
|
|
65660
|
-
|
|
66282
|
+
padRight4("Name", nameWidth),
|
|
66283
|
+
padRight4("Namespace", nsWidth),
|
|
66284
|
+
padRight4("Phase", phaseWidth),
|
|
66285
|
+
padRight4("Ready", readyWidth),
|
|
66286
|
+
padRight4("Restarts", restartsWidth),
|
|
66287
|
+
padRight4("Age", ageWidth),
|
|
65661
66288
|
"Component",
|
|
65662
66289
|
"Org",
|
|
65663
66290
|
"Project",
|
|
@@ -65667,20 +66294,20 @@ function formatPodsTable(pods) {
|
|
|
65667
66294
|
console.log("-".repeat(header.length));
|
|
65668
66295
|
for (const pod of pods) {
|
|
65669
66296
|
console.log([
|
|
65670
|
-
|
|
65671
|
-
|
|
65672
|
-
|
|
65673
|
-
|
|
65674
|
-
|
|
65675
|
-
|
|
65676
|
-
|
|
65677
|
-
|
|
65678
|
-
|
|
65679
|
-
|
|
66297
|
+
padRight4(pod.name, nameWidth),
|
|
66298
|
+
padRight4(pod.namespace, nsWidth),
|
|
66299
|
+
padRight4(pod.phase, phaseWidth),
|
|
66300
|
+
padRight4(pod.ready ? "yes" : "no", readyWidth),
|
|
66301
|
+
padRight4(String(pod.restarts), restartsWidth),
|
|
66302
|
+
padRight4(pod.age, ageWidth),
|
|
66303
|
+
padRight4(pod.component ?? "-", 10),
|
|
66304
|
+
padRight4(pod.orgId ?? "-", 10),
|
|
66305
|
+
padRight4(pod.projectId ?? "-", 10),
|
|
66306
|
+
padRight4(pod.env ?? "-", 10)
|
|
65680
66307
|
].join(" "));
|
|
65681
66308
|
}
|
|
65682
66309
|
}
|
|
65683
|
-
function
|
|
66310
|
+
function padRight4(str, width) {
|
|
65684
66311
|
if (str.length >= width) return str;
|
|
65685
66312
|
return str + " ".repeat(width - str.length);
|
|
65686
66313
|
}
|
|
@@ -65897,6 +66524,8 @@ function stripFilePath(filePath) {
|
|
|
65897
66524
|
}
|
|
65898
66525
|
|
|
65899
66526
|
// src/commands/env.ts
|
|
66527
|
+
var import_node_fs7 = require("node:fs");
|
|
66528
|
+
var import_node_path7 = require("node:path");
|
|
65900
66529
|
var readline2 = __toESM(require("node:readline/promises"));
|
|
65901
66530
|
async function handleEnv(subcommand, positionals, flags, context2) {
|
|
65902
66531
|
const json = Boolean(flags.json);
|
|
@@ -66048,12 +66677,47 @@ async function handleDeploy(positionals, flags, context2, json) {
|
|
|
66048
66677
|
if (!json) {
|
|
66049
66678
|
console.log(`Deploying commit ${gitSha.substring(0, 8)} to ${envName}...`);
|
|
66050
66679
|
}
|
|
66051
|
-
|
|
66052
|
-
|
|
66053
|
-
|
|
66054
|
-
|
|
66055
|
-
|
|
66056
|
-
|
|
66680
|
+
let manifestHash;
|
|
66681
|
+
if (repoDir) {
|
|
66682
|
+
const manifestPath = (0, import_node_path7.join)(repoDir, ".eve", "manifest.yaml");
|
|
66683
|
+
if ((0, import_node_fs7.existsSync)(manifestPath)) {
|
|
66684
|
+
const manifestYaml = (0, import_node_fs7.readFileSync)(manifestPath, "utf-8");
|
|
66685
|
+
const branch = getGitBranch(repoDir);
|
|
66686
|
+
const syncResponse = await requestJson(
|
|
66687
|
+
context2,
|
|
66688
|
+
`/projects/${projectId}/manifest`,
|
|
66689
|
+
{
|
|
66690
|
+
method: "POST",
|
|
66691
|
+
body: {
|
|
66692
|
+
yaml: manifestYaml,
|
|
66693
|
+
git_sha: gitSha,
|
|
66694
|
+
branch
|
|
66695
|
+
}
|
|
66696
|
+
}
|
|
66697
|
+
);
|
|
66698
|
+
manifestHash = syncResponse.manifest_hash;
|
|
66699
|
+
if (!json) {
|
|
66700
|
+
console.log(`Synced manifest ${manifestHash.substring(0, 8)}...`);
|
|
66701
|
+
}
|
|
66702
|
+
} else {
|
|
66703
|
+
const manifest = await requestJson(
|
|
66704
|
+
context2,
|
|
66705
|
+
`/projects/${projectId}/manifest`
|
|
66706
|
+
);
|
|
66707
|
+
manifestHash = manifest.manifest_hash;
|
|
66708
|
+
if (!json) {
|
|
66709
|
+
console.log(`Using manifest ${manifestHash.substring(0, 8)}...`);
|
|
66710
|
+
}
|
|
66711
|
+
}
|
|
66712
|
+
} else {
|
|
66713
|
+
const manifest = await requestJson(
|
|
66714
|
+
context2,
|
|
66715
|
+
`/projects/${projectId}/manifest`
|
|
66716
|
+
);
|
|
66717
|
+
manifestHash = manifest.manifest_hash;
|
|
66718
|
+
if (!json) {
|
|
66719
|
+
console.log(`Using manifest ${manifestHash.substring(0, 8)}...`);
|
|
66720
|
+
}
|
|
66057
66721
|
}
|
|
66058
66722
|
const direct = Boolean(flags.direct);
|
|
66059
66723
|
let inputs;
|
|
@@ -66074,7 +66738,7 @@ Example: --inputs '{"release_id":"rel_xxx","smoke_test":false}'`
|
|
|
66074
66738
|
const imageTag = getStringFlag(flags, ["image-tag", "image_tag", "imageTag"]);
|
|
66075
66739
|
const body = {
|
|
66076
66740
|
git_sha: gitSha,
|
|
66077
|
-
manifest_hash:
|
|
66741
|
+
manifest_hash: manifestHash
|
|
66078
66742
|
};
|
|
66079
66743
|
if (direct) {
|
|
66080
66744
|
body.direct = true;
|
|
@@ -66351,9 +67015,9 @@ function formatEnvironmentsTable(environments) {
|
|
|
66351
67015
|
const typeWidth = Math.max(4, ...environments.map((e) => e.type.length));
|
|
66352
67016
|
const namespaceWidth = Math.max(9, ...environments.map((e) => e.namespace?.length ?? 0));
|
|
66353
67017
|
const header = [
|
|
66354
|
-
|
|
66355
|
-
|
|
66356
|
-
|
|
67018
|
+
padRight5("Name", nameWidth),
|
|
67019
|
+
padRight5("Type", typeWidth),
|
|
67020
|
+
padRight5("Namespace", namespaceWidth),
|
|
66357
67021
|
"Current Release"
|
|
66358
67022
|
].join(" ");
|
|
66359
67023
|
console.log(header);
|
|
@@ -66361,9 +67025,9 @@ function formatEnvironmentsTable(environments) {
|
|
|
66361
67025
|
for (const env of environments) {
|
|
66362
67026
|
const releaseDisplay = env.current_release_id ? env.current_release_id.substring(0, 12) + "..." : "-";
|
|
66363
67027
|
const row = [
|
|
66364
|
-
|
|
66365
|
-
|
|
66366
|
-
|
|
67028
|
+
padRight5(env.name, nameWidth),
|
|
67029
|
+
padRight5(env.type, typeWidth),
|
|
67030
|
+
padRight5(env.namespace || "-", namespaceWidth),
|
|
66367
67031
|
releaseDisplay
|
|
66368
67032
|
].join(" ");
|
|
66369
67033
|
console.log(row);
|
|
@@ -66455,21 +67119,21 @@ function formatEnvServices(report, services) {
|
|
|
66455
67119
|
const restartsWidth = Math.max(8, ...services.map((s) => String(s.restarts).length));
|
|
66456
67120
|
const phasesWidth = Math.max(6, ...services.map((s) => s.phases.join(", ").length));
|
|
66457
67121
|
const header = [
|
|
66458
|
-
|
|
66459
|
-
|
|
66460
|
-
|
|
66461
|
-
|
|
66462
|
-
|
|
67122
|
+
padRight5("Service", nameWidth),
|
|
67123
|
+
padRight5("Pods", totalWidth),
|
|
67124
|
+
padRight5("Ready", readyWidth),
|
|
67125
|
+
padRight5("Restarts", restartsWidth),
|
|
67126
|
+
padRight5("Phases", phasesWidth)
|
|
66463
67127
|
].join(" ");
|
|
66464
67128
|
console.log(header);
|
|
66465
67129
|
console.log("-".repeat(header.length));
|
|
66466
67130
|
for (const service of services) {
|
|
66467
67131
|
console.log([
|
|
66468
|
-
|
|
66469
|
-
|
|
66470
|
-
|
|
66471
|
-
|
|
66472
|
-
|
|
67132
|
+
padRight5(service.name, nameWidth),
|
|
67133
|
+
padRight5(String(service.pods_total), totalWidth),
|
|
67134
|
+
padRight5(String(service.pods_ready), readyWidth),
|
|
67135
|
+
padRight5(String(service.restarts), restartsWidth),
|
|
67136
|
+
padRight5(service.phases.join(", "), phasesWidth)
|
|
66473
67137
|
].join(" "));
|
|
66474
67138
|
}
|
|
66475
67139
|
}
|
|
@@ -66479,8 +67143,8 @@ function formatEnvServices(report, services) {
|
|
|
66479
67143
|
const nameWidth = Math.max(4, ...report.deployments.map((d) => d.name.length));
|
|
66480
67144
|
const readyWidth = Math.max(5, ...report.deployments.map((d) => `${d.available_replicas}/${d.desired_replicas}`.length));
|
|
66481
67145
|
const header = [
|
|
66482
|
-
|
|
66483
|
-
|
|
67146
|
+
padRight5("Name", nameWidth),
|
|
67147
|
+
padRight5("Ready", readyWidth),
|
|
66484
67148
|
"Status"
|
|
66485
67149
|
].join(" ");
|
|
66486
67150
|
console.log(header);
|
|
@@ -66489,8 +67153,8 @@ function formatEnvServices(report, services) {
|
|
|
66489
67153
|
const readiness = `${deployment.available_replicas}/${deployment.desired_replicas}`;
|
|
66490
67154
|
const status = deployment.ready ? "ready" : "not-ready";
|
|
66491
67155
|
console.log([
|
|
66492
|
-
|
|
66493
|
-
|
|
67156
|
+
padRight5(deployment.name, nameWidth),
|
|
67157
|
+
padRight5(readiness, readyWidth),
|
|
66494
67158
|
status
|
|
66495
67159
|
].join(" "));
|
|
66496
67160
|
}
|
|
@@ -66519,8 +67183,8 @@ function formatEnvDiagnose(report) {
|
|
|
66519
67183
|
const nameWidth = Math.max(4, ...report.deployments.map((d) => d.name.length));
|
|
66520
67184
|
const readyWidth = Math.max(5, ...report.deployments.map((d) => `${d.available_replicas}/${d.desired_replicas}`.length));
|
|
66521
67185
|
const header = [
|
|
66522
|
-
|
|
66523
|
-
|
|
67186
|
+
padRight5("Name", nameWidth),
|
|
67187
|
+
padRight5("Ready", readyWidth),
|
|
66524
67188
|
"Status"
|
|
66525
67189
|
].join(" ");
|
|
66526
67190
|
console.log(header);
|
|
@@ -66529,8 +67193,8 @@ function formatEnvDiagnose(report) {
|
|
|
66529
67193
|
const readiness = `${deployment.available_replicas}/${deployment.desired_replicas}`;
|
|
66530
67194
|
const status = deployment.ready ? "ready" : "not-ready";
|
|
66531
67195
|
console.log([
|
|
66532
|
-
|
|
66533
|
-
|
|
67196
|
+
padRight5(deployment.name, nameWidth),
|
|
67197
|
+
padRight5(readiness, readyWidth),
|
|
66534
67198
|
status
|
|
66535
67199
|
].join(" "));
|
|
66536
67200
|
}
|
|
@@ -66542,9 +67206,9 @@ function formatEnvDiagnose(report) {
|
|
|
66542
67206
|
const phaseWidth = Math.max(5, ...report.pods.map((p) => p.phase.length));
|
|
66543
67207
|
const restartsWidth = Math.max(8, ...report.pods.map((p) => String(p.restarts).length));
|
|
66544
67208
|
const header = [
|
|
66545
|
-
|
|
66546
|
-
|
|
66547
|
-
|
|
67209
|
+
padRight5("Name", nameWidth),
|
|
67210
|
+
padRight5("Phase", phaseWidth),
|
|
67211
|
+
padRight5("Restarts", restartsWidth),
|
|
66548
67212
|
"Ready",
|
|
66549
67213
|
"Age"
|
|
66550
67214
|
].join(" ");
|
|
@@ -66552,9 +67216,9 @@ function formatEnvDiagnose(report) {
|
|
|
66552
67216
|
console.log("-".repeat(header.length));
|
|
66553
67217
|
for (const pod of report.pods) {
|
|
66554
67218
|
console.log([
|
|
66555
|
-
|
|
66556
|
-
|
|
66557
|
-
|
|
67219
|
+
padRight5(pod.name, nameWidth),
|
|
67220
|
+
padRight5(pod.phase, phaseWidth),
|
|
67221
|
+
padRight5(String(pod.restarts), restartsWidth),
|
|
66558
67222
|
pod.ready ? "yes" : "no",
|
|
66559
67223
|
pod.age
|
|
66560
67224
|
].join(" "));
|
|
@@ -66654,7 +67318,7 @@ function formatDate2(dateStr) {
|
|
|
66654
67318
|
return dateStr;
|
|
66655
67319
|
}
|
|
66656
67320
|
}
|
|
66657
|
-
function
|
|
67321
|
+
function padRight5(str, width) {
|
|
66658
67322
|
if (str.length >= width) return str;
|
|
66659
67323
|
return str + " ".repeat(width - str.length);
|
|
66660
67324
|
}
|
|
@@ -67552,8 +68216,8 @@ function formatLifecycleMeta2(phase, meta) {
|
|
|
67552
68216
|
}
|
|
67553
68217
|
|
|
67554
68218
|
// src/commands/api.ts
|
|
67555
|
-
var
|
|
67556
|
-
var
|
|
68219
|
+
var import_node_fs8 = require("node:fs");
|
|
68220
|
+
var import_node_path8 = require("node:path");
|
|
67557
68221
|
var import_node_child_process6 = require("node:child_process");
|
|
67558
68222
|
var import_node_os4 = require("node:os");
|
|
67559
68223
|
async function handleApi(subcommand, positionals, flags, context2) {
|
|
@@ -67672,7 +68336,7 @@ async function handleExamples(positionals, flags, context2, jsonOutput) {
|
|
|
67672
68336
|
async function handleGenerate(positionals, flags, jsonOutput) {
|
|
67673
68337
|
const outDir = getStringFlag(flags, ["out"]) ?? positionals[0];
|
|
67674
68338
|
const repoRoot = resolveRepoRoot();
|
|
67675
|
-
const outputDir = outDir ? (0,
|
|
68339
|
+
const outputDir = outDir ? (0, import_node_path8.resolve)(repoRoot, outDir) : (0, import_node_path8.resolve)(repoRoot, "docs/system");
|
|
67676
68340
|
runOpenApiExport(repoRoot, outputDir);
|
|
67677
68341
|
outputJson({ ok: true, output_dir: outputDir }, jsonOutput, `OpenAPI exported to ${outputDir}`);
|
|
67678
68342
|
}
|
|
@@ -67680,13 +68344,13 @@ async function handleDiff(positionals, flags, jsonOutput) {
|
|
|
67680
68344
|
const exitCode = Boolean(flags["exit-code"]);
|
|
67681
68345
|
const repoRoot = resolveRepoRoot();
|
|
67682
68346
|
const expectedDir = getStringFlag(flags, ["out"]) ?? positionals[0];
|
|
67683
|
-
const targetDir = expectedDir ? (0,
|
|
67684
|
-
const tempDir = (0,
|
|
68347
|
+
const targetDir = expectedDir ? (0, import_node_path8.resolve)(repoRoot, expectedDir) : (0, import_node_path8.resolve)(repoRoot, "docs/system");
|
|
68348
|
+
const tempDir = (0, import_node_fs8.mkdtempSync)((0, import_node_path8.join)((0, import_node_os4.tmpdir)(), "eve-openapi-"));
|
|
67685
68349
|
try {
|
|
67686
68350
|
runOpenApiExport(repoRoot, tempDir);
|
|
67687
|
-
const actualPath = (0,
|
|
67688
|
-
const expectedPath = (0,
|
|
67689
|
-
if (!(0,
|
|
68351
|
+
const actualPath = (0, import_node_path8.resolve)(tempDir, "openapi.yaml");
|
|
68352
|
+
const expectedPath = (0, import_node_path8.resolve)(targetDir, "openapi.yaml");
|
|
68353
|
+
if (!(0, import_node_fs8.existsSync)(expectedPath)) {
|
|
67690
68354
|
throw new Error(`Missing expected OpenAPI spec at ${expectedPath}`);
|
|
67691
68355
|
}
|
|
67692
68356
|
const diff = (0, import_node_child_process6.spawnSync)("diff", ["-u", expectedPath, actualPath], { stdio: "inherit" });
|
|
@@ -67696,7 +68360,7 @@ async function handleDiff(positionals, flags, jsonOutput) {
|
|
|
67696
68360
|
}
|
|
67697
68361
|
outputJson({ ok: !hasDiff }, jsonOutput, hasDiff ? "OpenAPI spec drift detected" : "OpenAPI spec matches");
|
|
67698
68362
|
} finally {
|
|
67699
|
-
(0,
|
|
68363
|
+
(0, import_node_fs8.rmSync)(tempDir, { recursive: true, force: true });
|
|
67700
68364
|
}
|
|
67701
68365
|
}
|
|
67702
68366
|
async function handleCall(positionals, flags, context2) {
|
|
@@ -67985,10 +68649,10 @@ function stripTrailingSlash(url) {
|
|
|
67985
68649
|
function resolveRepoRoot() {
|
|
67986
68650
|
let current = process.cwd();
|
|
67987
68651
|
while (true) {
|
|
67988
|
-
if ((0,
|
|
68652
|
+
if ((0, import_node_fs8.existsSync)((0, import_node_path8.resolve)(current, "pnpm-workspace.yaml"))) {
|
|
67989
68653
|
return current;
|
|
67990
68654
|
}
|
|
67991
|
-
const parent = (0,
|
|
68655
|
+
const parent = (0, import_node_path8.dirname)(current);
|
|
67992
68656
|
if (parent === current) {
|
|
67993
68657
|
break;
|
|
67994
68658
|
}
|
|
@@ -67997,9 +68661,9 @@ function resolveRepoRoot() {
|
|
|
67997
68661
|
throw new Error("Unable to locate repo root (pnpm-workspace.yaml not found).");
|
|
67998
68662
|
}
|
|
67999
68663
|
function runOpenApiExport(repoRoot, outputDir) {
|
|
68000
|
-
const scriptPath = (0,
|
|
68001
|
-
if (!(0,
|
|
68002
|
-
const build = (0, import_node_child_process6.spawnSync)("pnpm", ["-C", (0,
|
|
68664
|
+
const scriptPath = (0, import_node_path8.resolve)(repoRoot, "apps/api/dist/scripts/export-openapi.js");
|
|
68665
|
+
if (!(0, import_node_fs8.existsSync)(scriptPath)) {
|
|
68666
|
+
const build = (0, import_node_child_process6.spawnSync)("pnpm", ["-C", (0, import_node_path8.resolve)(repoRoot, "apps/api"), "build"], { stdio: "inherit" });
|
|
68003
68667
|
if (build.status !== 0) {
|
|
68004
68668
|
throw new Error("Failed to build API before exporting OpenAPI spec");
|
|
68005
68669
|
}
|
|
@@ -68035,14 +68699,14 @@ function resolveJsonInput(value) {
|
|
|
68035
68699
|
}
|
|
68036
68700
|
function resolveTextInput(value) {
|
|
68037
68701
|
if (value.startsWith("@")) {
|
|
68038
|
-
const filePath = (0,
|
|
68039
|
-
return (0,
|
|
68702
|
+
const filePath = (0, import_node_path8.resolve)(value.slice(1));
|
|
68703
|
+
return (0, import_node_fs8.readFileSync)(filePath, "utf-8");
|
|
68040
68704
|
}
|
|
68041
68705
|
if (value.trim().startsWith("{") || value.trim().startsWith("[")) {
|
|
68042
68706
|
return value;
|
|
68043
68707
|
}
|
|
68044
|
-
if ((0,
|
|
68045
|
-
return (0,
|
|
68708
|
+
if ((0, import_node_fs8.existsSync)(value)) {
|
|
68709
|
+
return (0, import_node_fs8.readFileSync)((0, import_node_path8.resolve)(value), "utf-8");
|
|
68046
68710
|
}
|
|
68047
68711
|
return value;
|
|
68048
68712
|
}
|
|
@@ -68085,8 +68749,8 @@ function buildCurlCommand(options) {
|
|
|
68085
68749
|
}
|
|
68086
68750
|
|
|
68087
68751
|
// src/commands/db.ts
|
|
68088
|
-
var
|
|
68089
|
-
var
|
|
68752
|
+
var import_node_fs9 = require("node:fs");
|
|
68753
|
+
var import_node_path9 = require("node:path");
|
|
68090
68754
|
var MIGRATION_REGEX = /^(\d{14})_([a-z0-9_]+)\.sql$/;
|
|
68091
68755
|
async function handleDb(subcommand, positionals, flags, context2) {
|
|
68092
68756
|
const jsonOutput = Boolean(flags.json);
|
|
@@ -68104,7 +68768,7 @@ async function handleDb(subcommand, positionals, flags, context2) {
|
|
|
68104
68768
|
case "new":
|
|
68105
68769
|
return handleNew(positionals, flags);
|
|
68106
68770
|
case "status":
|
|
68107
|
-
return
|
|
68771
|
+
return handleStatus3(positionals, flags, context2, jsonOutput);
|
|
68108
68772
|
case "rotate-credentials":
|
|
68109
68773
|
return handleRotateCredentials(positionals, flags, context2, jsonOutput);
|
|
68110
68774
|
case "scale":
|
|
@@ -68113,7 +68777,7 @@ async function handleDb(subcommand, positionals, flags, context2) {
|
|
|
68113
68777
|
return handleDestroy(positionals, flags, context2, jsonOutput);
|
|
68114
68778
|
default:
|
|
68115
68779
|
throw new Error(
|
|
68116
|
-
"Usage: eve db <command> [options]\n\nCommands:\n schema --env <name> Show DB schema info\n rls --env <name> Show RLS policies and tables\n sql --env <name> --sql <stmt> Run parameterized SQL\n migrate --env <name> [--path <dir>] Apply pending migrations\n migrations --env <name> List applied migrations\n new <description> Create new migration file\n status --env <name> Show managed DB status\n rotate-credentials --env <name> Rotate managed DB credentials\n scale --env <name> --class <cls> Scale managed DB class\n destroy --env <name> --force Destroy managed DB"
|
|
68780
|
+
"Usage: eve db <command> [options]\n\nCommands:\n schema --env <name> Show DB schema info\n rls --env <name> Show RLS policies and tables\n rls init --with-groups Scaffold group-aware RLS helper SQL\n sql --env <name> --sql <stmt> Run parameterized SQL\n migrate --env <name> [--path <dir>] Apply pending migrations\n migrations --env <name> List applied migrations\n new <description> Create new migration file\n status --env <name> Show managed DB status\n rotate-credentials --env <name> Rotate managed DB credentials\n scale --env <name> --class <cls> Scale managed DB class\n destroy --env <name> --force Destroy managed DB"
|
|
68117
68781
|
);
|
|
68118
68782
|
}
|
|
68119
68783
|
}
|
|
@@ -68123,9 +68787,109 @@ async function handleSchema(positionals, flags, context2, jsonOutput) {
|
|
|
68123
68787
|
outputJson(response, jsonOutput);
|
|
68124
68788
|
}
|
|
68125
68789
|
async function handleRls(positionals, flags, context2, jsonOutput) {
|
|
68790
|
+
if (positionals[0] === "init") {
|
|
68791
|
+
return handleRlsInit(flags, jsonOutput);
|
|
68792
|
+
}
|
|
68126
68793
|
const { projectId, envName } = resolveProjectEnv(positionals, flags, context2);
|
|
68127
68794
|
const response = await requestJson(context2, `/projects/${projectId}/envs/${envName}/db/rls`);
|
|
68128
|
-
|
|
68795
|
+
if (jsonOutput) {
|
|
68796
|
+
outputJson(response, true);
|
|
68797
|
+
return;
|
|
68798
|
+
}
|
|
68799
|
+
printRlsResponse(response);
|
|
68800
|
+
}
|
|
68801
|
+
function handleRlsInit(flags, jsonOutput) {
|
|
68802
|
+
const withGroups = toBoolean(flags["with-groups"]) ?? false;
|
|
68803
|
+
const force = toBoolean(flags.force) ?? false;
|
|
68804
|
+
if (!withGroups) {
|
|
68805
|
+
throw new Error("Usage: eve db rls init --with-groups [--out <path>] [--force]");
|
|
68806
|
+
}
|
|
68807
|
+
const outPath = getStringFlag(flags, ["out"]) ?? "db/rls/helpers.sql";
|
|
68808
|
+
const fullPath = (0, import_node_path9.resolve)(outPath);
|
|
68809
|
+
if ((0, import_node_fs9.existsSync)(fullPath) && !force) {
|
|
68810
|
+
throw new Error(`RLS helper file already exists: ${fullPath}
|
|
68811
|
+
Use --force to overwrite.`);
|
|
68812
|
+
}
|
|
68813
|
+
(0, import_node_fs9.mkdirSync)((0, import_node_path9.dirname)(fullPath), { recursive: true });
|
|
68814
|
+
(0, import_node_fs9.writeFileSync)(fullPath, renderRlsHelperTemplate());
|
|
68815
|
+
const payload = {
|
|
68816
|
+
path: fullPath,
|
|
68817
|
+
with_groups: true
|
|
68818
|
+
};
|
|
68819
|
+
outputJson(payload, jsonOutput, `Created group-aware RLS helpers at ${fullPath}`);
|
|
68820
|
+
}
|
|
68821
|
+
function renderRlsHelperTemplate() {
|
|
68822
|
+
return `-- Eve RLS helpers generated by "eve db rls init --with-groups"
|
|
68823
|
+
-- Usage:
|
|
68824
|
+
-- 1. Apply this SQL in your target environment DB.
|
|
68825
|
+
-- 2. Reference app.current_user_id()/app.current_group_ids()/app.has_group() in policies.
|
|
68826
|
+
--
|
|
68827
|
+
-- Example:
|
|
68828
|
+
-- CREATE POLICY notes_group_read
|
|
68829
|
+
-- ON notes
|
|
68830
|
+
-- FOR SELECT
|
|
68831
|
+
-- USING (group_id = ANY(app.current_group_ids()));
|
|
68832
|
+
|
|
68833
|
+
CREATE SCHEMA IF NOT EXISTS app;
|
|
68834
|
+
|
|
68835
|
+
CREATE OR REPLACE FUNCTION app.current_user_id()
|
|
68836
|
+
RETURNS text
|
|
68837
|
+
LANGUAGE sql
|
|
68838
|
+
STABLE
|
|
68839
|
+
AS $$
|
|
68840
|
+
SELECT NULLIF(current_setting('app.user_id', true), '');
|
|
68841
|
+
$$;
|
|
68842
|
+
|
|
68843
|
+
CREATE OR REPLACE FUNCTION app.current_group_ids()
|
|
68844
|
+
RETURNS text[]
|
|
68845
|
+
LANGUAGE sql
|
|
68846
|
+
STABLE
|
|
68847
|
+
AS $$
|
|
68848
|
+
WITH raw AS (
|
|
68849
|
+
SELECT NULLIF(current_setting('app.group_ids', true), '') AS value
|
|
68850
|
+
)
|
|
68851
|
+
SELECT COALESCE(
|
|
68852
|
+
ARRAY(
|
|
68853
|
+
SELECT jsonb_array_elements_text(COALESCE(raw.value::jsonb, '[]'::jsonb))
|
|
68854
|
+
FROM raw
|
|
68855
|
+
),
|
|
68856
|
+
ARRAY[]::text[]
|
|
68857
|
+
);
|
|
68858
|
+
$$;
|
|
68859
|
+
|
|
68860
|
+
CREATE OR REPLACE FUNCTION app.has_group(group_id text)
|
|
68861
|
+
RETURNS boolean
|
|
68862
|
+
LANGUAGE sql
|
|
68863
|
+
STABLE
|
|
68864
|
+
AS $$
|
|
68865
|
+
SELECT group_id = ANY(app.current_group_ids());
|
|
68866
|
+
$$;
|
|
68867
|
+
`;
|
|
68868
|
+
}
|
|
68869
|
+
function printRlsResponse(response) {
|
|
68870
|
+
const diagnostics = response.diagnostics?.context;
|
|
68871
|
+
if (diagnostics) {
|
|
68872
|
+
const groups = diagnostics.group_ids ?? [];
|
|
68873
|
+
const permissions = diagnostics.permissions ?? [];
|
|
68874
|
+
console.log("Context:");
|
|
68875
|
+
console.log(` Principal: ${diagnostics.principal_type ?? "unknown"} ${diagnostics.user_id ?? "(none)"}`);
|
|
68876
|
+
console.log(` Org: ${diagnostics.org_id ?? "(none)"}`);
|
|
68877
|
+
console.log(` Project: ${diagnostics.project_id ?? "(none)"}`);
|
|
68878
|
+
console.log(` Env: ${diagnostics.env_name ?? "(none)"}`);
|
|
68879
|
+
console.log(` Groups (${groups.length}): ${groups.length > 0 ? groups.join(", ") : "(none)"}`);
|
|
68880
|
+
console.log(` Permissions (${permissions.length}): ${permissions.length > 0 ? permissions.join(", ") : "(none)"}`);
|
|
68881
|
+
console.log("");
|
|
68882
|
+
}
|
|
68883
|
+
const tables = response.tables ?? [];
|
|
68884
|
+
if (tables.length === 0) {
|
|
68885
|
+
console.log("No user tables/views found.");
|
|
68886
|
+
return;
|
|
68887
|
+
}
|
|
68888
|
+
console.log(`RLS tables (${tables.length}):`);
|
|
68889
|
+
for (const table of tables) {
|
|
68890
|
+
const state = table.rls_enabled ? "enabled" : "disabled";
|
|
68891
|
+
console.log(` - ${table.schema}.${table.name} (${state}, ${table.policies.length} policies)`);
|
|
68892
|
+
}
|
|
68129
68893
|
}
|
|
68130
68894
|
async function handleSql(positionals, flags, context2, jsonOutput) {
|
|
68131
68895
|
const projectId = getStringFlag(flags, ["project"]) ?? context2.projectId;
|
|
@@ -68137,7 +68901,7 @@ async function handleSql(positionals, flags, context2, jsonOutput) {
|
|
|
68137
68901
|
const sqlPositionals = envFromFlag ? positionals : positionals.slice(1);
|
|
68138
68902
|
const sqlInput = getStringFlag(flags, ["sql"]) ?? sqlPositionals.join(" ");
|
|
68139
68903
|
const fileInput = getStringFlag(flags, ["file"]);
|
|
68140
|
-
const sqlText = fileInput ? (0,
|
|
68904
|
+
const sqlText = fileInput ? (0, import_node_fs9.readFileSync)((0, import_node_path9.resolve)(fileInput), "utf-8") : sqlInput;
|
|
68141
68905
|
if (!sqlText) {
|
|
68142
68906
|
throw new Error("Usage: eve db sql --env <name> --sql <statement> [--params <json>] [--write]");
|
|
68143
68907
|
}
|
|
@@ -68176,11 +68940,11 @@ function parseJson(value, label) {
|
|
|
68176
68940
|
async function handleMigrate(positionals, flags, context2, jsonOutput) {
|
|
68177
68941
|
const { projectId, envName } = resolveProjectEnv(positionals, flags, context2);
|
|
68178
68942
|
const migrationsPath = getStringFlag(flags, ["path"]) ?? "db/migrations";
|
|
68179
|
-
const fullPath = (0,
|
|
68180
|
-
if (!(0,
|
|
68943
|
+
const fullPath = (0, import_node_path9.resolve)(migrationsPath);
|
|
68944
|
+
if (!(0, import_node_fs9.existsSync)(fullPath)) {
|
|
68181
68945
|
throw new Error(`Migrations directory not found: ${fullPath}`);
|
|
68182
68946
|
}
|
|
68183
|
-
const files = (0,
|
|
68947
|
+
const files = (0, import_node_fs9.readdirSync)(fullPath).filter((f) => f.endsWith(".sql")).sort();
|
|
68184
68948
|
if (files.length === 0) {
|
|
68185
68949
|
console.log("No migration files found");
|
|
68186
68950
|
return;
|
|
@@ -68196,7 +68960,7 @@ Example: 20260128100000_create_users.sql`
|
|
|
68196
68960
|
}
|
|
68197
68961
|
const migrations = files.map((file) => ({
|
|
68198
68962
|
name: file,
|
|
68199
|
-
sql: (0,
|
|
68963
|
+
sql: (0, import_node_fs9.readFileSync)((0, import_node_path9.join)(fullPath, file), "utf-8")
|
|
68200
68964
|
}));
|
|
68201
68965
|
console.log(`Found ${migrations.length} migration files`);
|
|
68202
68966
|
const response = await requestJson(context2, `/projects/${projectId}/envs/${envName}/db/migrate`, {
|
|
@@ -68258,12 +69022,12 @@ function handleNew(positionals, flags) {
|
|
|
68258
69022
|
].join("");
|
|
68259
69023
|
const filename = `${timestamp}_${normalizedDescription}.sql`;
|
|
68260
69024
|
const migrationsPath = getStringFlag(flags, ["path"]) ?? "db/migrations";
|
|
68261
|
-
const fullPath = (0,
|
|
68262
|
-
if (!(0,
|
|
68263
|
-
(0,
|
|
69025
|
+
const fullPath = (0, import_node_path9.resolve)(migrationsPath);
|
|
69026
|
+
if (!(0, import_node_fs9.existsSync)(fullPath)) {
|
|
69027
|
+
(0, import_node_fs9.mkdirSync)(fullPath, { recursive: true });
|
|
68264
69028
|
}
|
|
68265
|
-
const filePath = (0,
|
|
68266
|
-
if ((0,
|
|
69029
|
+
const filePath = (0, import_node_path9.join)(fullPath, filename);
|
|
69030
|
+
if ((0, import_node_fs9.existsSync)(filePath)) {
|
|
68267
69031
|
throw new Error(`Migration file already exists: ${filePath}`);
|
|
68268
69032
|
}
|
|
68269
69033
|
const template = `-- Migration: ${normalizedDescription}
|
|
@@ -68272,10 +69036,10 @@ function handleNew(positionals, flags) {
|
|
|
68272
69036
|
-- Write your SQL migration here
|
|
68273
69037
|
|
|
68274
69038
|
`;
|
|
68275
|
-
(0,
|
|
69039
|
+
(0, import_node_fs9.writeFileSync)(filePath, template);
|
|
68276
69040
|
console.log(`Created: ${filePath}`);
|
|
68277
69041
|
}
|
|
68278
|
-
async function
|
|
69042
|
+
async function handleStatus3(positionals, flags, context2, jsonOutput) {
|
|
68279
69043
|
const { projectId, envName } = resolveProjectEnv(positionals, flags, context2);
|
|
68280
69044
|
const response = await requestJson(context2, `/projects/${projectId}/envs/${envName}/db/managed`);
|
|
68281
69045
|
if (jsonOutput) {
|
|
@@ -68509,24 +69273,24 @@ function formatEventsTable(events) {
|
|
|
68509
69273
|
const sourceWidth = Math.max(6, ...events.map((e) => e.source.length));
|
|
68510
69274
|
const statusWidth = Math.max(6, ...events.map((e) => e.status.length));
|
|
68511
69275
|
const header = [
|
|
68512
|
-
|
|
68513
|
-
|
|
68514
|
-
|
|
68515
|
-
|
|
68516
|
-
|
|
68517
|
-
|
|
69276
|
+
padRight6("ID", idWidth),
|
|
69277
|
+
padRight6("Type", typeWidth),
|
|
69278
|
+
padRight6("Source", sourceWidth),
|
|
69279
|
+
padRight6("Status", statusWidth),
|
|
69280
|
+
padRight6("Env", 12),
|
|
69281
|
+
padRight6("Branch", 20),
|
|
68518
69282
|
"Created"
|
|
68519
69283
|
].join(" ");
|
|
68520
69284
|
console.log(header);
|
|
68521
69285
|
console.log("-".repeat(header.length));
|
|
68522
69286
|
for (const event of events) {
|
|
68523
69287
|
const row = [
|
|
68524
|
-
|
|
68525
|
-
|
|
68526
|
-
|
|
68527
|
-
|
|
68528
|
-
|
|
68529
|
-
|
|
69288
|
+
padRight6(event.id, idWidth),
|
|
69289
|
+
padRight6(event.type, typeWidth),
|
|
69290
|
+
padRight6(event.source, sourceWidth),
|
|
69291
|
+
padRight6(event.status, statusWidth),
|
|
69292
|
+
padRight6(event.env_name || "-", 12),
|
|
69293
|
+
padRight6(event.ref_branch || "-", 20),
|
|
68530
69294
|
formatDate3(event.created_at)
|
|
68531
69295
|
].join(" ");
|
|
68532
69296
|
console.log(row);
|
|
@@ -68579,7 +69343,7 @@ function formatDate3(dateStr) {
|
|
|
68579
69343
|
return dateStr;
|
|
68580
69344
|
}
|
|
68581
69345
|
}
|
|
68582
|
-
function
|
|
69346
|
+
function padRight6(str, width) {
|
|
68583
69347
|
if (str.length >= width) return str;
|
|
68584
69348
|
return str + " ".repeat(width - str.length);
|
|
68585
69349
|
}
|
|
@@ -69391,11 +70155,11 @@ async function fetchGitHubKeys2(username) {
|
|
|
69391
70155
|
|
|
69392
70156
|
// src/commands/agents.ts
|
|
69393
70157
|
var import_node_child_process8 = require("node:child_process");
|
|
69394
|
-
var
|
|
69395
|
-
var
|
|
70158
|
+
var import_node_fs10 = require("node:fs");
|
|
70159
|
+
var import_node_path10 = require("node:path");
|
|
69396
70160
|
var import_yaml3 = require("yaml");
|
|
69397
70161
|
function readYamlFile(filePath) {
|
|
69398
|
-
const raw = (0,
|
|
70162
|
+
const raw = (0, import_node_fs10.readFileSync)(filePath, "utf-8");
|
|
69399
70163
|
const parsed = (0, import_yaml3.parse)(raw);
|
|
69400
70164
|
if (!parsed || typeof parsed !== "object") {
|
|
69401
70165
|
throw new Error(`Invalid YAML in ${filePath}`);
|
|
@@ -69407,9 +70171,9 @@ function resolveAgentsConfigPaths(repoRoot, manifest) {
|
|
|
69407
70171
|
const agentsBlock = xEve["agents"] || {};
|
|
69408
70172
|
const chatBlock = xEve["chat"] || {};
|
|
69409
70173
|
const manifestChat = manifest["chat"] || {};
|
|
69410
|
-
const agentsPath = (0,
|
|
69411
|
-
const teamsPath = (0,
|
|
69412
|
-
const chatPath = (0,
|
|
70174
|
+
const agentsPath = (0, import_node_path10.resolve)(repoRoot, pickString(agentsBlock.config_path) ?? "agents/agents.yaml");
|
|
70175
|
+
const teamsPath = (0, import_node_path10.resolve)(repoRoot, pickString(agentsBlock.teams_path) ?? "agents/teams.yaml");
|
|
70176
|
+
const chatPath = (0, import_node_path10.resolve)(
|
|
69413
70177
|
repoRoot,
|
|
69414
70178
|
pickString(chatBlock.config_path) ?? pickString(manifestChat.config_path) ?? "agents/chat.yaml"
|
|
69415
70179
|
);
|
|
@@ -69419,7 +70183,7 @@ function pickString(value) {
|
|
|
69419
70183
|
return typeof value === "string" && value.trim().length > 0 ? value : void 0;
|
|
69420
70184
|
}
|
|
69421
70185
|
function ensureFileExists(path6, label) {
|
|
69422
|
-
if (!(0,
|
|
70186
|
+
if (!(0, import_node_fs10.existsSync)(path6)) {
|
|
69423
70187
|
throw new Error(`Missing ${label} at ${path6}. Update manifest config_path or add the file.`);
|
|
69424
70188
|
}
|
|
69425
70189
|
return path6;
|
|
@@ -69434,9 +70198,9 @@ function isLocalApiUrl(apiUrl) {
|
|
|
69434
70198
|
}
|
|
69435
70199
|
}
|
|
69436
70200
|
function loadAgentsConfig(repoRoot) {
|
|
69437
|
-
const eveDir = (0,
|
|
69438
|
-
const manifestPath = (0,
|
|
69439
|
-
if ((0,
|
|
70201
|
+
const eveDir = (0, import_node_path10.join)(repoRoot, ".eve");
|
|
70202
|
+
const manifestPath = (0, import_node_path10.join)(eveDir, "manifest.yaml");
|
|
70203
|
+
if ((0, import_node_fs10.existsSync)(manifestPath)) {
|
|
69440
70204
|
const manifest = readYamlFile(manifestPath);
|
|
69441
70205
|
const xEve = manifest["x-eve"] || manifest["x_eve"] || {};
|
|
69442
70206
|
const policy = xEve["agents"] || null;
|
|
@@ -69486,16 +70250,16 @@ async function resolvePacksAndMerge(repoRoot, manifest, projectSlug) {
|
|
|
69486
70250
|
}
|
|
69487
70251
|
}
|
|
69488
70252
|
const configPaths = resolveAgentsConfigPaths(repoRoot, manifest);
|
|
69489
|
-
if ((0,
|
|
69490
|
-
const projectAgents = (0, import_yaml3.parse)((0,
|
|
70253
|
+
if ((0, import_node_fs10.existsSync)(configPaths.agentsPath)) {
|
|
70254
|
+
const projectAgents = (0, import_yaml3.parse)((0, import_node_fs10.readFileSync)(configPaths.agentsPath, "utf-8")) ?? {};
|
|
69491
70255
|
mergedAgents = mergeMapConfig(mergedAgents, projectAgents);
|
|
69492
70256
|
}
|
|
69493
|
-
if ((0,
|
|
69494
|
-
const projectTeams = (0, import_yaml3.parse)((0,
|
|
70257
|
+
if ((0, import_node_fs10.existsSync)(configPaths.teamsPath)) {
|
|
70258
|
+
const projectTeams = (0, import_yaml3.parse)((0, import_node_fs10.readFileSync)(configPaths.teamsPath, "utf-8")) ?? {};
|
|
69495
70259
|
mergedTeams = mergeMapConfig(mergedTeams, projectTeams);
|
|
69496
70260
|
}
|
|
69497
|
-
if ((0,
|
|
69498
|
-
const projectChat = (0, import_yaml3.parse)((0,
|
|
70261
|
+
if ((0, import_node_fs10.existsSync)(configPaths.chatPath)) {
|
|
70262
|
+
const projectChat = (0, import_yaml3.parse)((0, import_node_fs10.readFileSync)(configPaths.chatPath, "utf-8")) ?? {};
|
|
69499
70263
|
mergedChat = mergeChatConfig(
|
|
69500
70264
|
mergedChat,
|
|
69501
70265
|
projectChat
|
|
@@ -69524,10 +70288,10 @@ async function resolvePacksAndMerge(repoRoot, manifest, projectSlug) {
|
|
|
69524
70288
|
chat_hash: simpleHash(JSON.stringify(mergedChat))
|
|
69525
70289
|
}
|
|
69526
70290
|
};
|
|
69527
|
-
const eveDir = (0,
|
|
69528
|
-
(0,
|
|
69529
|
-
const lockfilePath = (0,
|
|
69530
|
-
(0,
|
|
70291
|
+
const eveDir = (0, import_node_path10.join)(repoRoot, ".eve");
|
|
70292
|
+
(0, import_node_fs10.mkdirSync)(eveDir, { recursive: true });
|
|
70293
|
+
const lockfilePath = (0, import_node_path10.join)(eveDir, "packs.lock.yaml");
|
|
70294
|
+
(0, import_node_fs10.writeFileSync)(lockfilePath, (0, import_yaml3.stringify)(lockfile), "utf-8");
|
|
69531
70295
|
console.log(` \u2713 Lockfile written: .eve/packs.lock.yaml`);
|
|
69532
70296
|
const packRefs = resolvedPacks.map((p) => ({ id: p.id, source: p.source, ref: p.ref }));
|
|
69533
70297
|
return {
|
|
@@ -69600,7 +70364,7 @@ async function handleAgents(subcommand, positionals, flags, context2) {
|
|
|
69600
70364
|
const command = subcommand ?? "config";
|
|
69601
70365
|
const json = Boolean(flags.json);
|
|
69602
70366
|
const includeHarnesses = !(getBooleanFlag(flags, ["no-harnesses"]) ?? false);
|
|
69603
|
-
const repoRoot = (0,
|
|
70367
|
+
const repoRoot = (0, import_node_path10.resolve)(getStringFlag(flags, ["repo-dir", "repo_dir", "dir", "path"]) ?? process.cwd());
|
|
69604
70368
|
switch (command) {
|
|
69605
70369
|
case "config": {
|
|
69606
70370
|
const result = loadAgentsConfig(repoRoot);
|
|
@@ -69669,8 +70433,8 @@ async function handleAgents(subcommand, positionals, flags, context2) {
|
|
|
69669
70433
|
if (dirty && !allowDirty) {
|
|
69670
70434
|
throw new Error("Working tree is dirty. Commit changes or pass --allow-dirty to sync anyway.");
|
|
69671
70435
|
}
|
|
69672
|
-
const manifestPath = (0,
|
|
69673
|
-
if (!(0,
|
|
70436
|
+
const manifestPath = (0, import_node_path10.join)(repoRoot, ".eve", "manifest.yaml");
|
|
70437
|
+
if (!(0, import_node_fs10.existsSync)(manifestPath)) {
|
|
69674
70438
|
throw new Error(`Missing manifest at ${manifestPath}. Expected .eve/manifest.yaml.`);
|
|
69675
70439
|
}
|
|
69676
70440
|
const manifest = readYamlFile(manifestPath);
|
|
@@ -69699,9 +70463,9 @@ async function handleAgents(subcommand, positionals, flags, context2) {
|
|
|
69699
70463
|
packRefs = packResult.packRefs;
|
|
69700
70464
|
} else {
|
|
69701
70465
|
const configPaths = resolveAgentsConfigPaths(repoRoot, manifest);
|
|
69702
|
-
agentsYaml = (0,
|
|
69703
|
-
teamsYaml = (0,
|
|
69704
|
-
chatYaml = (0,
|
|
70466
|
+
agentsYaml = (0, import_node_fs10.readFileSync)(ensureFileExists(configPaths.agentsPath, "agents config"), "utf-8");
|
|
70467
|
+
teamsYaml = (0, import_node_fs10.readFileSync)(ensureFileExists(configPaths.teamsPath, "teams config"), "utf-8");
|
|
70468
|
+
chatYaml = (0, import_node_fs10.readFileSync)(ensureFileExists(configPaths.chatPath, "chat config"), "utf-8");
|
|
69705
70469
|
}
|
|
69706
70470
|
let gitSha;
|
|
69707
70471
|
let branch;
|
|
@@ -69784,10 +70548,10 @@ function formatAgentRuntimeStatus(response, orgId) {
|
|
|
69784
70548
|
const ageWidth = Math.max(3, ...response.pods.map((pod) => formatAgeSeconds(pod.last_heartbeat_at).length));
|
|
69785
70549
|
console.log("");
|
|
69786
70550
|
const header = [
|
|
69787
|
-
|
|
69788
|
-
|
|
69789
|
-
|
|
69790
|
-
|
|
70551
|
+
padRight7("Pod", nameWidth),
|
|
70552
|
+
padRight7("Status", statusWidth),
|
|
70553
|
+
padRight7("Capacity", capacityWidth),
|
|
70554
|
+
padRight7("Age", ageWidth),
|
|
69791
70555
|
"Last Heartbeat"
|
|
69792
70556
|
].join(" ");
|
|
69793
70557
|
console.log(header);
|
|
@@ -69795,15 +70559,15 @@ function formatAgentRuntimeStatus(response, orgId) {
|
|
|
69795
70559
|
for (const pod of response.pods) {
|
|
69796
70560
|
const age = formatAgeSeconds(pod.last_heartbeat_at);
|
|
69797
70561
|
console.log([
|
|
69798
|
-
|
|
69799
|
-
|
|
69800
|
-
|
|
69801
|
-
|
|
70562
|
+
padRight7(pod.pod_name, nameWidth),
|
|
70563
|
+
padRight7(pod.status, statusWidth),
|
|
70564
|
+
padRight7(String(pod.capacity), capacityWidth),
|
|
70565
|
+
padRight7(age, ageWidth),
|
|
69802
70566
|
pod.last_heartbeat_at
|
|
69803
70567
|
].join(" "));
|
|
69804
70568
|
}
|
|
69805
70569
|
}
|
|
69806
|
-
function
|
|
70570
|
+
function padRight7(value, width) {
|
|
69807
70571
|
return value.length >= width ? value : `${value}${" ".repeat(width - value.length)}`;
|
|
69808
70572
|
}
|
|
69809
70573
|
function formatAgeSeconds(isoDate) {
|
|
@@ -70044,8 +70808,8 @@ function ensureSkillsSymlink2(projectRoot) {
|
|
|
70044
70808
|
}
|
|
70045
70809
|
|
|
70046
70810
|
// src/commands/release.ts
|
|
70047
|
-
var
|
|
70048
|
-
var
|
|
70811
|
+
var import_node_fs11 = require("node:fs");
|
|
70812
|
+
var import_node_path11 = require("node:path");
|
|
70049
70813
|
async function handleRelease2(subcommand, positionals, flags, context2) {
|
|
70050
70814
|
const json = Boolean(flags.json);
|
|
70051
70815
|
switch (subcommand) {
|
|
@@ -70057,9 +70821,9 @@ async function handleRelease2(subcommand, positionals, flags, context2) {
|
|
|
70057
70821
|
let projectId = typeof flags.project === "string" ? flags.project : context2.projectId;
|
|
70058
70822
|
if (!projectId) {
|
|
70059
70823
|
const dir = typeof flags.dir === "string" ? flags.dir : process.cwd();
|
|
70060
|
-
const manifestPath = (0,
|
|
70824
|
+
const manifestPath = (0, import_node_path11.join)(dir, ".eve", "manifest.yaml");
|
|
70061
70825
|
try {
|
|
70062
|
-
const yaml = (0,
|
|
70826
|
+
const yaml = (0, import_node_fs11.readFileSync)(manifestPath, "utf-8");
|
|
70063
70827
|
const projectMatch = yaml.match(/^project:\s*(\S+)/m);
|
|
70064
70828
|
if (projectMatch) {
|
|
70065
70829
|
projectId = projectMatch[1];
|
|
@@ -70108,8 +70872,8 @@ Make sure the release exists and the tag is correct.`
|
|
|
70108
70872
|
}
|
|
70109
70873
|
|
|
70110
70874
|
// src/commands/manifest.ts
|
|
70111
|
-
var
|
|
70112
|
-
var
|
|
70875
|
+
var import_node_fs12 = require("node:fs");
|
|
70876
|
+
var import_node_path12 = require("node:path");
|
|
70113
70877
|
async function handleManifest(subcommand, positionals, flags, context2) {
|
|
70114
70878
|
const json = Boolean(flags.json);
|
|
70115
70879
|
switch (subcommand) {
|
|
@@ -70119,11 +70883,11 @@ async function handleManifest(subcommand, positionals, flags, context2) {
|
|
|
70119
70883
|
const validateSecretsFlag = flags["validate-secrets"] ?? flags.validate_secrets;
|
|
70120
70884
|
const validateSecrets = toBoolean(validateSecretsFlag) ?? false;
|
|
70121
70885
|
const dir = typeof flags.dir === "string" ? flags.dir : process.cwd();
|
|
70122
|
-
const manifestPath = getStringFlag(flags, ["path"]) ?? (0,
|
|
70886
|
+
const manifestPath = getStringFlag(flags, ["path"]) ?? (0, import_node_path12.join)(dir, ".eve", "manifest.yaml");
|
|
70123
70887
|
let manifestYaml;
|
|
70124
70888
|
if (!useLatest) {
|
|
70125
70889
|
try {
|
|
70126
|
-
manifestYaml = (0,
|
|
70890
|
+
manifestYaml = (0, import_node_fs12.readFileSync)(manifestPath, "utf-8");
|
|
70127
70891
|
} catch (error) {
|
|
70128
70892
|
throw new Error(`Failed to read manifest at ${manifestPath}: ${error.message}`);
|
|
70129
70893
|
}
|
|
@@ -70191,11 +70955,11 @@ async function handleManifest(subcommand, positionals, flags, context2) {
|
|
|
70191
70955
|
}
|
|
70192
70956
|
|
|
70193
70957
|
// src/commands/packs.ts
|
|
70194
|
-
var
|
|
70195
|
-
var
|
|
70958
|
+
var import_node_fs13 = require("node:fs");
|
|
70959
|
+
var import_node_path13 = require("node:path");
|
|
70196
70960
|
var import_yaml4 = require("yaml");
|
|
70197
70961
|
async function handlePacks(subcommand, _rest, flags, _context) {
|
|
70198
|
-
const repoRoot = (0,
|
|
70962
|
+
const repoRoot = (0, import_node_path13.resolve)(getStringFlag(flags, ["repo-dir", "repo_dir", "dir", "path"]) ?? process.cwd());
|
|
70199
70963
|
switch (subcommand) {
|
|
70200
70964
|
case "status": {
|
|
70201
70965
|
printPacksStatus(repoRoot);
|
|
@@ -70211,14 +70975,14 @@ async function handlePacks(subcommand, _rest, flags, _context) {
|
|
|
70211
70975
|
}
|
|
70212
70976
|
}
|
|
70213
70977
|
function printPacksStatus(repoRoot) {
|
|
70214
|
-
const lockfilePath = (0,
|
|
70215
|
-
const manifestPath = (0,
|
|
70216
|
-
if (!(0,
|
|
70978
|
+
const lockfilePath = (0, import_node_path13.join)(repoRoot, ".eve", "packs.lock.yaml");
|
|
70979
|
+
const manifestPath = (0, import_node_path13.join)(repoRoot, ".eve", "manifest.yaml");
|
|
70980
|
+
if (!(0, import_node_fs13.existsSync)(lockfilePath)) {
|
|
70217
70981
|
console.log("No lockfile found at .eve/packs.lock.yaml");
|
|
70218
70982
|
console.log('Run "eve agents sync" to resolve packs and generate the lockfile.');
|
|
70219
70983
|
return;
|
|
70220
70984
|
}
|
|
70221
|
-
const lockRaw = (0,
|
|
70985
|
+
const lockRaw = (0, import_node_fs13.readFileSync)(lockfilePath, "utf-8");
|
|
70222
70986
|
const lock = (0, import_yaml4.parse)(lockRaw);
|
|
70223
70987
|
if (!lock || !lock.packs) {
|
|
70224
70988
|
console.log("Lockfile is empty or malformed.");
|
|
@@ -70234,16 +70998,16 @@ function printPacksStatus(repoRoot) {
|
|
|
70234
70998
|
const idWidth = Math.max(4, ...lock.packs.map((p) => p.id.length));
|
|
70235
70999
|
const sourceWidth = Math.max(6, ...lock.packs.map((p) => p.source.length));
|
|
70236
71000
|
const header = [
|
|
70237
|
-
|
|
70238
|
-
|
|
71001
|
+
padRight8("Pack", idWidth),
|
|
71002
|
+
padRight8("Source", sourceWidth),
|
|
70239
71003
|
"Ref"
|
|
70240
71004
|
].join(" ");
|
|
70241
71005
|
console.log(header);
|
|
70242
71006
|
console.log("-".repeat(header.length + 12));
|
|
70243
71007
|
for (const pack of lock.packs) {
|
|
70244
71008
|
console.log([
|
|
70245
|
-
|
|
70246
|
-
|
|
71009
|
+
padRight8(pack.id, idWidth),
|
|
71010
|
+
padRight8(pack.source, sourceWidth),
|
|
70247
71011
|
pack.ref.substring(0, 12)
|
|
70248
71012
|
].join(" "));
|
|
70249
71013
|
}
|
|
@@ -70253,8 +71017,8 @@ function printPacksStatus(repoRoot) {
|
|
|
70253
71017
|
console.log(` Agents: ${lock.effective.agents_count}`);
|
|
70254
71018
|
console.log(` Teams: ${lock.effective.teams_count}`);
|
|
70255
71019
|
console.log(` Routes: ${lock.effective.routes_count}`);
|
|
70256
|
-
if ((0,
|
|
70257
|
-
const manifestRaw = (0,
|
|
71020
|
+
if ((0, import_node_fs13.existsSync)(manifestPath)) {
|
|
71021
|
+
const manifestRaw = (0, import_node_fs13.readFileSync)(manifestPath, "utf-8");
|
|
70258
71022
|
const manifest = (0, import_yaml4.parse)(manifestRaw);
|
|
70259
71023
|
if (manifest) {
|
|
70260
71024
|
const xEve = manifest["x-eve"] ?? manifest["x_eve"] ?? {};
|
|
@@ -70299,12 +71063,12 @@ function detectDrift(lock, manifestPacks) {
|
|
|
70299
71063
|
}
|
|
70300
71064
|
function printPacksResolve(repoRoot, dryRun) {
|
|
70301
71065
|
if (dryRun) {
|
|
70302
|
-
const lockfilePath = (0,
|
|
70303
|
-
const manifestPath = (0,
|
|
70304
|
-
if (!(0,
|
|
71066
|
+
const lockfilePath = (0, import_node_path13.join)(repoRoot, ".eve", "packs.lock.yaml");
|
|
71067
|
+
const manifestPath = (0, import_node_path13.join)(repoRoot, ".eve", "manifest.yaml");
|
|
71068
|
+
if (!(0, import_node_fs13.existsSync)(manifestPath)) {
|
|
70305
71069
|
throw new Error("No manifest found at .eve/manifest.yaml");
|
|
70306
71070
|
}
|
|
70307
|
-
const manifestRaw = (0,
|
|
71071
|
+
const manifestRaw = (0, import_node_fs13.readFileSync)(manifestPath, "utf-8");
|
|
70308
71072
|
const manifest = (0, import_yaml4.parse)(manifestRaw);
|
|
70309
71073
|
if (!manifest) {
|
|
70310
71074
|
throw new Error("Manifest is empty or malformed.");
|
|
@@ -70322,8 +71086,8 @@ function printPacksResolve(repoRoot, dryRun) {
|
|
|
70322
71086
|
const refShort = mp.ref ? mp.ref.substring(0, 12) : "(local)";
|
|
70323
71087
|
console.log(` - ${mp.source} @ ${refShort}`);
|
|
70324
71088
|
}
|
|
70325
|
-
if ((0,
|
|
70326
|
-
const lockRaw = (0,
|
|
71089
|
+
if ((0, import_node_fs13.existsSync)(lockfilePath)) {
|
|
71090
|
+
const lockRaw = (0, import_node_fs13.readFileSync)(lockfilePath, "utf-8");
|
|
70327
71091
|
const lock = (0, import_yaml4.parse)(lockRaw);
|
|
70328
71092
|
if (lock?.packs) {
|
|
70329
71093
|
const drift = detectDrift(lock, manifestPacks);
|
|
@@ -70352,7 +71116,7 @@ function printPacksResolve(repoRoot, dryRun) {
|
|
|
70352
71116
|
console.log("");
|
|
70353
71117
|
console.log("This will resolve packs, merge configs, write the lockfile, and sync to the API.");
|
|
70354
71118
|
}
|
|
70355
|
-
function
|
|
71119
|
+
function padRight8(value, width) {
|
|
70356
71120
|
return value.length >= width ? value : `${value}${" ".repeat(width - value.length)}`;
|
|
70357
71121
|
}
|
|
70358
71122
|
|
|
@@ -71178,8 +71942,8 @@ Cursor: ${result.cursor}`);
|
|
|
71178
71942
|
}
|
|
71179
71943
|
|
|
71180
71944
|
// src/commands/migrate.ts
|
|
71181
|
-
var
|
|
71182
|
-
var
|
|
71945
|
+
var import_node_fs14 = require("node:fs");
|
|
71946
|
+
var import_node_path14 = require("node:path");
|
|
71183
71947
|
var import_yaml5 = require("yaml");
|
|
71184
71948
|
async function handleMigrate2(subcommand, _rest, _flags) {
|
|
71185
71949
|
switch (subcommand) {
|
|
@@ -71199,12 +71963,12 @@ async function migrateSkillsToPacks() {
|
|
|
71199
71963
|
if (!repoRoot) {
|
|
71200
71964
|
throw new Error("Not in a git repository. Run this from your project root.");
|
|
71201
71965
|
}
|
|
71202
|
-
const skillsTxtPath = (0,
|
|
71203
|
-
if (!(0,
|
|
71966
|
+
const skillsTxtPath = (0, import_node_path14.join)(repoRoot, "skills.txt");
|
|
71967
|
+
if (!(0, import_node_fs14.existsSync)(skillsTxtPath)) {
|
|
71204
71968
|
console.log("No skills.txt found at repository root. Nothing to migrate.");
|
|
71205
71969
|
return;
|
|
71206
71970
|
}
|
|
71207
|
-
const content = (0,
|
|
71971
|
+
const content = (0, import_node_fs14.readFileSync)(skillsTxtPath, "utf-8");
|
|
71208
71972
|
const lines = content.split("\n");
|
|
71209
71973
|
const localSources = [];
|
|
71210
71974
|
const remoteSources = [];
|
|
@@ -71313,9 +72077,9 @@ async function handleList8(flags, context2, json) {
|
|
|
71313
72077
|
const nameWidth = Math.max(12, ...response.managed.map((m) => m.display_name.length));
|
|
71314
72078
|
const providerWidth = Math.max(8, ...response.managed.map((m) => m.inference_provider.length));
|
|
71315
72079
|
const header = [
|
|
71316
|
-
|
|
71317
|
-
|
|
71318
|
-
|
|
72080
|
+
padRight9("Model Spec", specWidth),
|
|
72081
|
+
padRight9("Display Name", nameWidth),
|
|
72082
|
+
padRight9("Provider", providerWidth),
|
|
71319
72083
|
"Capabilities"
|
|
71320
72084
|
].join(" ");
|
|
71321
72085
|
console.log(header);
|
|
@@ -71326,9 +72090,9 @@ async function handleList8(flags, context2, json) {
|
|
|
71326
72090
|
if (model.capabilities.tool_calling) caps.push("tools");
|
|
71327
72091
|
if (model.capabilities.reasoning) caps.push("reason");
|
|
71328
72092
|
const row = [
|
|
71329
|
-
|
|
71330
|
-
|
|
71331
|
-
|
|
72093
|
+
padRight9(model.model_spec, specWidth),
|
|
72094
|
+
padRight9(model.display_name, nameWidth),
|
|
72095
|
+
padRight9(model.inference_provider, providerWidth),
|
|
71332
72096
|
caps.join(", ")
|
|
71333
72097
|
].join(" ");
|
|
71334
72098
|
console.log(row);
|
|
@@ -71338,16 +72102,95 @@ async function handleList8(flags, context2, json) {
|
|
|
71338
72102
|
console.log("");
|
|
71339
72103
|
console.log('Usage: Set harness_options.model to the model spec (e.g. "managed/deepseek-r1")');
|
|
71340
72104
|
}
|
|
71341
|
-
function
|
|
72105
|
+
function padRight9(str, width) {
|
|
71342
72106
|
if (str.length >= width) return str;
|
|
71343
72107
|
return str + " ".repeat(width - str.length);
|
|
71344
72108
|
}
|
|
71345
72109
|
|
|
71346
72110
|
// src/commands/access.ts
|
|
71347
|
-
var
|
|
71348
|
-
var
|
|
72111
|
+
var import_node_fs15 = require("node:fs");
|
|
72112
|
+
var import_node_path15 = require("node:path");
|
|
71349
72113
|
var readline3 = __toESM(require("node:readline/promises"));
|
|
71350
72114
|
var import_yaml6 = require("yaml");
|
|
72115
|
+
function resolvePrincipalSelection(flags, options) {
|
|
72116
|
+
const userId = getStringFlag(flags, ["user"]);
|
|
72117
|
+
const spId = getStringFlag(flags, ["service-principal", "sp"]);
|
|
72118
|
+
const groupId = options?.allowGroup ? getStringFlag(flags, ["group"]) : void 0;
|
|
72119
|
+
const selected = [
|
|
72120
|
+
userId ? "user" : null,
|
|
72121
|
+
spId ? "service_principal" : null,
|
|
72122
|
+
groupId ? "group" : null
|
|
72123
|
+
].filter(Boolean);
|
|
72124
|
+
if (selected.length === 0) {
|
|
72125
|
+
const groupHint = options?.allowGroup ? " or --group <group_id>" : "";
|
|
72126
|
+
throw new Error(`--user <user_id> or --service-principal <sp_id>${groupHint} is required`);
|
|
72127
|
+
}
|
|
72128
|
+
if (selected.length > 1) {
|
|
72129
|
+
throw new Error("Specify exactly one principal selector: --user, --service-principal, or --group");
|
|
72130
|
+
}
|
|
72131
|
+
if (userId) {
|
|
72132
|
+
return { principalType: "user", principalId: userId };
|
|
72133
|
+
}
|
|
72134
|
+
if (spId) {
|
|
72135
|
+
return { principalType: "service_principal", principalId: spId };
|
|
72136
|
+
}
|
|
72137
|
+
return { principalType: "group", principalId: groupId };
|
|
72138
|
+
}
|
|
72139
|
+
function parseScopeJsonFlag(flags) {
|
|
72140
|
+
const raw = getStringFlag(flags, ["scope-json"]);
|
|
72141
|
+
if (!raw) {
|
|
72142
|
+
return void 0;
|
|
72143
|
+
}
|
|
72144
|
+
try {
|
|
72145
|
+
const parsed = JSON.parse(raw);
|
|
72146
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
72147
|
+
throw new Error("must be a JSON object");
|
|
72148
|
+
}
|
|
72149
|
+
return parsed;
|
|
72150
|
+
} catch (error) {
|
|
72151
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
72152
|
+
throw new Error(`Invalid --scope-json: ${message}`);
|
|
72153
|
+
}
|
|
72154
|
+
}
|
|
72155
|
+
function normalizeBindingScope(scope) {
|
|
72156
|
+
if (!scope) {
|
|
72157
|
+
return void 0;
|
|
72158
|
+
}
|
|
72159
|
+
const normalized = {};
|
|
72160
|
+
if (scope.orgfs) {
|
|
72161
|
+
const allow = [...new Set(scope.orgfs.allow_prefixes ?? [])].sort();
|
|
72162
|
+
const readOnly = [...new Set(scope.orgfs.read_only_prefixes ?? [])].sort();
|
|
72163
|
+
if (allow.length > 0 || readOnly.length > 0) {
|
|
72164
|
+
normalized.orgfs = {};
|
|
72165
|
+
if (allow.length > 0) normalized.orgfs.allow_prefixes = allow;
|
|
72166
|
+
if (readOnly.length > 0) normalized.orgfs.read_only_prefixes = readOnly;
|
|
72167
|
+
}
|
|
72168
|
+
}
|
|
72169
|
+
if (scope.orgdocs) {
|
|
72170
|
+
const allow = [...new Set(scope.orgdocs.allow_prefixes ?? [])].sort();
|
|
72171
|
+
const readOnly = [...new Set(scope.orgdocs.read_only_prefixes ?? [])].sort();
|
|
72172
|
+
if (allow.length > 0 || readOnly.length > 0) {
|
|
72173
|
+
normalized.orgdocs = {};
|
|
72174
|
+
if (allow.length > 0) normalized.orgdocs.allow_prefixes = allow;
|
|
72175
|
+
if (readOnly.length > 0) normalized.orgdocs.read_only_prefixes = readOnly;
|
|
72176
|
+
}
|
|
72177
|
+
}
|
|
72178
|
+
if (scope.envdb) {
|
|
72179
|
+
const schemas = [...new Set(scope.envdb.schemas ?? [])].sort();
|
|
72180
|
+
const tables = [...new Set(scope.envdb.tables ?? [])].sort();
|
|
72181
|
+
if (schemas.length > 0 || tables.length > 0) {
|
|
72182
|
+
normalized.envdb = {};
|
|
72183
|
+
if (schemas.length > 0) normalized.envdb.schemas = schemas;
|
|
72184
|
+
if (tables.length > 0) normalized.envdb.tables = tables;
|
|
72185
|
+
}
|
|
72186
|
+
}
|
|
72187
|
+
return Object.keys(normalized).length > 0 ? normalized : void 0;
|
|
72188
|
+
}
|
|
72189
|
+
function scopeEquals(left, right) {
|
|
72190
|
+
const normalizedLeft = normalizeBindingScope(left);
|
|
72191
|
+
const normalizedRight = normalizeBindingScope(right);
|
|
72192
|
+
return JSON.stringify(normalizedLeft ?? null) === JSON.stringify(normalizedRight ?? null);
|
|
72193
|
+
}
|
|
71351
72194
|
async function handleAccess(subcommand, rest, flags, context2) {
|
|
71352
72195
|
const json = Boolean(flags.json);
|
|
71353
72196
|
switch (subcommand) {
|
|
@@ -71363,6 +72206,10 @@ async function handleAccess(subcommand, rest, flags, context2) {
|
|
|
71363
72206
|
return handleUnbind(flags, context2, json);
|
|
71364
72207
|
case "bindings":
|
|
71365
72208
|
return handleBindings(rest[0], flags, context2, json);
|
|
72209
|
+
case "groups":
|
|
72210
|
+
return handleGroups(rest[0], rest.slice(1), flags, context2, json);
|
|
72211
|
+
case "memberships":
|
|
72212
|
+
return handleMemberships(flags, context2, json);
|
|
71366
72213
|
case "validate":
|
|
71367
72214
|
return handleValidate(flags, json);
|
|
71368
72215
|
case "plan":
|
|
@@ -71371,38 +72218,44 @@ async function handleAccess(subcommand, rest, flags, context2) {
|
|
|
71371
72218
|
return handleSync(flags, context2, json);
|
|
71372
72219
|
default:
|
|
71373
72220
|
throw new Error(
|
|
71374
|
-
"Usage: eve access <subcommand> [flags]\n\nCommands:\n can Check if a principal can perform an action\n explain Explain permission resolution chain\n roles Manage custom access roles (create|list|show|update|delete)\n bind Bind a custom role to a principal\n unbind Remove a role binding from a principal\n bindings List access bindings\n validate Validate an .eve/access.yaml file\n plan Show changes needed to sync access.yaml to an org\n sync Apply access.yaml to an org (create/update/prune)"
|
|
72221
|
+
"Usage: eve access <subcommand> [flags]\n\nCommands:\n can Check if a principal can perform an action\n explain Explain permission resolution chain\n roles Manage custom access roles (create|list|show|update|delete)\n bind Bind a custom role to a principal\n unbind Remove a role binding from a principal\n bindings List access bindings\n groups Manage access groups and members\n memberships Inspect principal memberships and effective scopes\n validate Validate an .eve/access.yaml file\n plan Show changes needed to sync access.yaml to an org\n sync Apply access.yaml to an org (create/update/prune)"
|
|
71375
72222
|
);
|
|
71376
72223
|
}
|
|
71377
72224
|
}
|
|
71378
72225
|
async function handleCan(flags, context2, json) {
|
|
71379
72226
|
const orgId = getStringFlag(flags, ["org"]) ?? context2.orgId;
|
|
71380
|
-
const userId = getStringFlag(flags, ["user"]);
|
|
71381
|
-
const spId = getStringFlag(flags, ["service-principal", "sp"]);
|
|
71382
72227
|
const projectId = getStringFlag(flags, ["project"]) ?? context2.projectId;
|
|
71383
72228
|
const permission = getStringFlag(flags, ["permission"]);
|
|
72229
|
+
const resourceType = getStringFlag(flags, ["resource-type"]);
|
|
72230
|
+
const resourceId = getStringFlag(flags, ["resource", "resource-id"]);
|
|
72231
|
+
const action = getStringFlag(flags, ["action"]);
|
|
71384
72232
|
if (!orgId) {
|
|
71385
72233
|
throw new Error("--org is required (or set a default org in your profile)");
|
|
71386
72234
|
}
|
|
71387
72235
|
if (!permission) {
|
|
71388
72236
|
throw new Error("--permission is required");
|
|
71389
72237
|
}
|
|
71390
|
-
|
|
71391
|
-
|
|
71392
|
-
|
|
71393
|
-
if (userId && spId) {
|
|
71394
|
-
throw new Error("Specify either --user or --service-principal, not both");
|
|
72238
|
+
const principal = resolvePrincipalSelection(flags, { allowGroup: true });
|
|
72239
|
+
if ((resourceType || action) && !resourceId) {
|
|
72240
|
+
throw new Error("--resource is required when --resource-type or --action is provided");
|
|
71395
72241
|
}
|
|
71396
|
-
const principalType = userId ? "user" : "service_principal";
|
|
71397
|
-
const principalId = userId ?? spId;
|
|
71398
72242
|
const params = new URLSearchParams({
|
|
71399
|
-
principal_type: principalType,
|
|
71400
|
-
principal_id: principalId,
|
|
72243
|
+
principal_type: principal.principalType,
|
|
72244
|
+
principal_id: principal.principalId,
|
|
71401
72245
|
permission
|
|
71402
72246
|
});
|
|
71403
72247
|
if (projectId) {
|
|
71404
72248
|
params.set("project_id", projectId);
|
|
71405
72249
|
}
|
|
72250
|
+
if (resourceType) {
|
|
72251
|
+
params.set("resource_type", resourceType);
|
|
72252
|
+
}
|
|
72253
|
+
if (resourceId) {
|
|
72254
|
+
params.set("resource_id", resourceId);
|
|
72255
|
+
}
|
|
72256
|
+
if (action) {
|
|
72257
|
+
params.set("action", action);
|
|
72258
|
+
}
|
|
71406
72259
|
const response = await requestJson(
|
|
71407
72260
|
context2,
|
|
71408
72261
|
`/orgs/${orgId}/access/can?${params.toString()}`
|
|
@@ -71413,35 +72266,47 @@ async function handleCan(flags, context2, json) {
|
|
|
71413
72266
|
}
|
|
71414
72267
|
const label = response.allowed ? "ALLOWED" : "DENIED";
|
|
71415
72268
|
console.log(`${label} (source: ${response.source})`);
|
|
72269
|
+
if (response.resource) {
|
|
72270
|
+
const resourceStatus = response.resource.scope_matched ? "scope match" : "scope denied";
|
|
72271
|
+
console.log(
|
|
72272
|
+
`Resource: ${response.resource.type}:${response.resource.id} [${response.resource.action}] (${resourceStatus})`
|
|
72273
|
+
);
|
|
72274
|
+
}
|
|
71416
72275
|
}
|
|
71417
72276
|
async function handleExplain(flags, context2, json) {
|
|
71418
72277
|
const orgId = getStringFlag(flags, ["org"]) ?? context2.orgId;
|
|
71419
|
-
const userId = getStringFlag(flags, ["user"]);
|
|
71420
|
-
const spId = getStringFlag(flags, ["service-principal", "sp"]);
|
|
71421
72278
|
const projectId = getStringFlag(flags, ["project"]) ?? context2.projectId;
|
|
71422
72279
|
const permission = getStringFlag(flags, ["permission"]);
|
|
72280
|
+
const resourceType = getStringFlag(flags, ["resource-type"]);
|
|
72281
|
+
const resourceId = getStringFlag(flags, ["resource", "resource-id"]);
|
|
72282
|
+
const action = getStringFlag(flags, ["action"]);
|
|
71423
72283
|
if (!orgId) {
|
|
71424
72284
|
throw new Error("--org is required (or set a default org in your profile)");
|
|
71425
72285
|
}
|
|
71426
72286
|
if (!permission) {
|
|
71427
72287
|
throw new Error("--permission is required");
|
|
71428
72288
|
}
|
|
71429
|
-
|
|
71430
|
-
|
|
71431
|
-
|
|
71432
|
-
if (userId && spId) {
|
|
71433
|
-
throw new Error("Specify either --user or --service-principal, not both");
|
|
72289
|
+
const principal = resolvePrincipalSelection(flags, { allowGroup: true });
|
|
72290
|
+
if ((resourceType || action) && !resourceId) {
|
|
72291
|
+
throw new Error("--resource is required when --resource-type or --action is provided");
|
|
71434
72292
|
}
|
|
71435
|
-
const principalType = userId ? "user" : "service_principal";
|
|
71436
|
-
const principalId = userId ?? spId;
|
|
71437
72293
|
const params = new URLSearchParams({
|
|
71438
|
-
principal_type: principalType,
|
|
71439
|
-
principal_id: principalId,
|
|
72294
|
+
principal_type: principal.principalType,
|
|
72295
|
+
principal_id: principal.principalId,
|
|
71440
72296
|
permission
|
|
71441
72297
|
});
|
|
71442
72298
|
if (projectId) {
|
|
71443
72299
|
params.set("project_id", projectId);
|
|
71444
72300
|
}
|
|
72301
|
+
if (resourceType) {
|
|
72302
|
+
params.set("resource_type", resourceType);
|
|
72303
|
+
}
|
|
72304
|
+
if (resourceId) {
|
|
72305
|
+
params.set("resource_id", resourceId);
|
|
72306
|
+
}
|
|
72307
|
+
if (action) {
|
|
72308
|
+
params.set("action", action);
|
|
72309
|
+
}
|
|
71445
72310
|
const response = await requestJson(
|
|
71446
72311
|
context2,
|
|
71447
72312
|
`/orgs/${orgId}/access/explain?${params.toString()}`
|
|
@@ -71452,13 +72317,20 @@ async function handleExplain(flags, context2, json) {
|
|
|
71452
72317
|
}
|
|
71453
72318
|
console.log(`Permission: ${response.permission}`);
|
|
71454
72319
|
console.log(`Result: ${response.result}`);
|
|
72320
|
+
if (response.resource) {
|
|
72321
|
+
const resourceStatus = response.resource.scope_matched ? "scope match" : "scope denied";
|
|
72322
|
+
console.log(
|
|
72323
|
+
`Resource: ${response.resource.type}:${response.resource.id} [${response.resource.action}] (${resourceStatus})`
|
|
72324
|
+
);
|
|
72325
|
+
}
|
|
71455
72326
|
if (response.grants.length > 0) {
|
|
71456
72327
|
console.log("Grants found:");
|
|
71457
72328
|
for (const grant of response.grants) {
|
|
71458
72329
|
const roleLabel = grant.role ? `: ${grant.role}` : "";
|
|
71459
72330
|
const permCount = grant.permissions.length;
|
|
71460
72331
|
const status = grant.has_permission ? "has permission" : `missing ${response.permission}`;
|
|
71461
|
-
|
|
72332
|
+
const scopeSuffix = grant.scope_match === void 0 ? "" : grant.scope_match ? " [scope:match]" : ` [scope:deny${grant.scope_reason ? `: ${grant.scope_reason}` : ""}]`;
|
|
72333
|
+
console.log(` - ${grant.source}${roleLabel} -> [${permCount} permissions] (${status})${scopeSuffix}`);
|
|
71462
72334
|
}
|
|
71463
72335
|
} else {
|
|
71464
72336
|
console.log("Grants found: none");
|
|
@@ -71638,32 +72510,27 @@ async function handleRoles(action, positionals, flags, context2, json) {
|
|
|
71638
72510
|
}
|
|
71639
72511
|
async function handleBind(flags, context2, json) {
|
|
71640
72512
|
const orgId = getStringFlag(flags, ["org"]) ?? context2.orgId;
|
|
71641
|
-
const userId = getStringFlag(flags, ["user"]);
|
|
71642
|
-
const spId = getStringFlag(flags, ["service-principal", "sp"]);
|
|
71643
72513
|
const projectId = getStringFlag(flags, ["project"]) ?? context2.projectId;
|
|
71644
72514
|
const roleName = getStringFlag(flags, ["role"]);
|
|
72515
|
+
const scopeJson = parseScopeJsonFlag(flags);
|
|
71645
72516
|
if (!orgId) {
|
|
71646
72517
|
throw new Error("--org is required (or set a default org in your profile)");
|
|
71647
72518
|
}
|
|
71648
72519
|
if (!roleName) {
|
|
71649
72520
|
throw new Error("--role <role_name> is required");
|
|
71650
72521
|
}
|
|
71651
|
-
|
|
71652
|
-
throw new Error("--user <user_id> or --service-principal <sp_id> is required");
|
|
71653
|
-
}
|
|
71654
|
-
if (userId && spId) {
|
|
71655
|
-
throw new Error("Specify either --user or --service-principal, not both");
|
|
71656
|
-
}
|
|
71657
|
-
const principalType = userId ? "user" : "service_principal";
|
|
71658
|
-
const principalId = userId ?? spId;
|
|
72522
|
+
const principal = resolvePrincipalSelection(flags, { allowGroup: true });
|
|
71659
72523
|
const body = {
|
|
71660
72524
|
role_name: roleName,
|
|
71661
|
-
principal_type: principalType,
|
|
71662
|
-
principal_id: principalId
|
|
72525
|
+
principal_type: principal.principalType,
|
|
72526
|
+
principal_id: principal.principalId
|
|
71663
72527
|
};
|
|
71664
72528
|
if (projectId) {
|
|
71665
72529
|
body.project_id = projectId;
|
|
71666
72530
|
}
|
|
72531
|
+
if (scopeJson) {
|
|
72532
|
+
body.scope_json = scopeJson;
|
|
72533
|
+
}
|
|
71667
72534
|
const response = await requestJson(
|
|
71668
72535
|
context2,
|
|
71669
72536
|
`/orgs/${orgId}/access/bindings`,
|
|
@@ -71674,12 +72541,10 @@ async function handleBind(flags, context2, json) {
|
|
|
71674
72541
|
return;
|
|
71675
72542
|
}
|
|
71676
72543
|
const scopeLabel = response.project_id ? `project ${response.project_id}` : `org ${orgId}`;
|
|
71677
|
-
console.log(`Bound role '${response.role_name}' to ${principalType} ${principalId} on ${scopeLabel}`);
|
|
72544
|
+
console.log(`Bound role '${response.role_name}' to ${principal.principalType} ${principal.principalId} on ${scopeLabel}`);
|
|
71678
72545
|
}
|
|
71679
72546
|
async function handleUnbind(flags, context2, json) {
|
|
71680
72547
|
const orgId = getStringFlag(flags, ["org"]) ?? context2.orgId;
|
|
71681
|
-
const userId = getStringFlag(flags, ["user"]);
|
|
71682
|
-
const spId = getStringFlag(flags, ["service-principal", "sp"]);
|
|
71683
72548
|
const projectId = getStringFlag(flags, ["project"]) ?? context2.projectId;
|
|
71684
72549
|
const roleName = getStringFlag(flags, ["role"]);
|
|
71685
72550
|
if (!orgId) {
|
|
@@ -71688,17 +72553,10 @@ async function handleUnbind(flags, context2, json) {
|
|
|
71688
72553
|
if (!roleName) {
|
|
71689
72554
|
throw new Error("--role <role_name> is required");
|
|
71690
72555
|
}
|
|
71691
|
-
|
|
71692
|
-
throw new Error("--user <user_id> or --service-principal <sp_id> is required");
|
|
71693
|
-
}
|
|
71694
|
-
if (userId && spId) {
|
|
71695
|
-
throw new Error("Specify either --user or --service-principal, not both");
|
|
71696
|
-
}
|
|
71697
|
-
const principalType = userId ? "user" : "service_principal";
|
|
71698
|
-
const principalId = userId ?? spId;
|
|
72556
|
+
const principal = resolvePrincipalSelection(flags, { allowGroup: true });
|
|
71699
72557
|
const params = new URLSearchParams({
|
|
71700
|
-
principal_type: principalType,
|
|
71701
|
-
principal_id: principalId
|
|
72558
|
+
principal_type: principal.principalType,
|
|
72559
|
+
principal_id: principal.principalId
|
|
71702
72560
|
});
|
|
71703
72561
|
if (projectId) {
|
|
71704
72562
|
params.set("project_id", projectId);
|
|
@@ -71710,14 +72568,14 @@ async function handleUnbind(flags, context2, json) {
|
|
|
71710
72568
|
const bindings = unwrapListResponse(bindingsResponse);
|
|
71711
72569
|
const matching = bindings.find((b) => {
|
|
71712
72570
|
if (b.role_name !== roleName) return false;
|
|
71713
|
-
if (b.principal_type !== principalType) return false;
|
|
71714
|
-
if (b.principal_id !== principalId) return false;
|
|
72571
|
+
if (b.principal_type !== principal.principalType) return false;
|
|
72572
|
+
if (b.principal_id !== principal.principalId) return false;
|
|
71715
72573
|
if (projectId) return b.project_id === projectId;
|
|
71716
72574
|
return b.project_id === null;
|
|
71717
72575
|
});
|
|
71718
72576
|
if (!matching) {
|
|
71719
72577
|
throw new Error(
|
|
71720
|
-
`No binding found for role '${roleName}' on ${principalType} ${principalId}` + (projectId ? ` in project ${projectId}` : " at org level")
|
|
72578
|
+
`No binding found for role '${roleName}' on ${principal.principalType} ${principal.principalId}` + (projectId ? ` in project ${projectId}` : " at org level")
|
|
71721
72579
|
);
|
|
71722
72580
|
}
|
|
71723
72581
|
await requestJson(
|
|
@@ -71730,7 +72588,7 @@ async function handleUnbind(flags, context2, json) {
|
|
|
71730
72588
|
return;
|
|
71731
72589
|
}
|
|
71732
72590
|
const scopeLabel = projectId ? `project ${projectId}` : `org ${orgId}`;
|
|
71733
|
-
console.log(`Unbound role '${roleName}' from ${principalType} ${principalId} on ${scopeLabel}`);
|
|
72591
|
+
console.log(`Unbound role '${roleName}' from ${principal.principalType} ${principal.principalId} on ${scopeLabel}`);
|
|
71734
72592
|
}
|
|
71735
72593
|
async function handleBindings(action, flags, context2, json) {
|
|
71736
72594
|
if (action && action !== "list") {
|
|
@@ -71762,16 +72620,262 @@ async function handleBindings(action, flags, context2, json) {
|
|
|
71762
72620
|
console.log(`${b.role_name} -> ${b.principal_type} ${b.principal_id} (${scope})`);
|
|
71763
72621
|
}
|
|
71764
72622
|
}
|
|
72623
|
+
async function handleGroups(action, positionals, flags, context2, json) {
|
|
72624
|
+
const orgId = getStringFlag(flags, ["org"]) ?? context2.orgId;
|
|
72625
|
+
if (!orgId) {
|
|
72626
|
+
throw new Error("--org is required (or set a default org in your profile)");
|
|
72627
|
+
}
|
|
72628
|
+
if (action === "members") {
|
|
72629
|
+
return handleGroupMembers(positionals[0], positionals.slice(1), flags, context2, json);
|
|
72630
|
+
}
|
|
72631
|
+
switch (action) {
|
|
72632
|
+
case "create": {
|
|
72633
|
+
const name = positionals[0] ?? getStringFlag(flags, ["name"]);
|
|
72634
|
+
const slug = getStringFlag(flags, ["slug"]);
|
|
72635
|
+
const description = getStringFlag(flags, ["description"]);
|
|
72636
|
+
if (!name) {
|
|
72637
|
+
throw new Error("Usage: eve access groups create <name> --org <org_id> [--slug <slug>] [--description <text>]");
|
|
72638
|
+
}
|
|
72639
|
+
const response = await requestJson(context2, `/orgs/${orgId}/access/groups`, {
|
|
72640
|
+
method: "POST",
|
|
72641
|
+
body: { name, slug, description }
|
|
72642
|
+
});
|
|
72643
|
+
if (json) {
|
|
72644
|
+
outputJson(response, json);
|
|
72645
|
+
return;
|
|
72646
|
+
}
|
|
72647
|
+
console.log(`Created group '${response.name}' (${response.id})`);
|
|
72648
|
+
console.log(` Slug: ${response.slug}`);
|
|
72649
|
+
if (response.description) {
|
|
72650
|
+
console.log(` Description: ${response.description}`);
|
|
72651
|
+
}
|
|
72652
|
+
return;
|
|
72653
|
+
}
|
|
72654
|
+
case "list": {
|
|
72655
|
+
const listResponse = await requestJson(
|
|
72656
|
+
context2,
|
|
72657
|
+
`/orgs/${orgId}/access/groups`
|
|
72658
|
+
);
|
|
72659
|
+
const groups = unwrapListResponse(listResponse);
|
|
72660
|
+
if (json) {
|
|
72661
|
+
outputJson({ data: groups }, json);
|
|
72662
|
+
return;
|
|
72663
|
+
}
|
|
72664
|
+
if (groups.length === 0) {
|
|
72665
|
+
console.log("No access groups found.");
|
|
72666
|
+
return;
|
|
72667
|
+
}
|
|
72668
|
+
for (const group of groups) {
|
|
72669
|
+
const desc = group.description ? ` - ${group.description}` : "";
|
|
72670
|
+
console.log(`${group.slug} (${group.id})${desc}`);
|
|
72671
|
+
}
|
|
72672
|
+
return;
|
|
72673
|
+
}
|
|
72674
|
+
case "show": {
|
|
72675
|
+
const group = positionals[0] ?? getStringFlag(flags, ["group"]);
|
|
72676
|
+
if (!group) {
|
|
72677
|
+
throw new Error("Usage: eve access groups show <group_id_or_slug> --org <org_id>");
|
|
72678
|
+
}
|
|
72679
|
+
const response = await requestJson(
|
|
72680
|
+
context2,
|
|
72681
|
+
`/orgs/${orgId}/access/groups/${encodeURIComponent(group)}`
|
|
72682
|
+
);
|
|
72683
|
+
if (json) {
|
|
72684
|
+
outputJson(response, json);
|
|
72685
|
+
return;
|
|
72686
|
+
}
|
|
72687
|
+
console.log(`Name: ${response.name}`);
|
|
72688
|
+
console.log(`ID: ${response.id}`);
|
|
72689
|
+
console.log(`Slug: ${response.slug}`);
|
|
72690
|
+
if (response.description) {
|
|
72691
|
+
console.log(`Description: ${response.description}`);
|
|
72692
|
+
}
|
|
72693
|
+
console.log(`Created: ${response.created_at}`);
|
|
72694
|
+
console.log(`Updated: ${response.updated_at}`);
|
|
72695
|
+
return;
|
|
72696
|
+
}
|
|
72697
|
+
case "update": {
|
|
72698
|
+
const group = positionals[0] ?? getStringFlag(flags, ["group"]);
|
|
72699
|
+
if (!group) {
|
|
72700
|
+
throw new Error("Usage: eve access groups update <group_id_or_slug> --org <org_id> [--name <name>] [--slug <slug>] [--description <text>]");
|
|
72701
|
+
}
|
|
72702
|
+
const name = getStringFlag(flags, ["name"]);
|
|
72703
|
+
const slug = getStringFlag(flags, ["slug"]);
|
|
72704
|
+
const description = getStringFlag(flags, ["description"]);
|
|
72705
|
+
if (name === void 0 && slug === void 0 && description === void 0) {
|
|
72706
|
+
throw new Error("Nothing to update. Use --name, --slug, or --description");
|
|
72707
|
+
}
|
|
72708
|
+
const response = await requestJson(
|
|
72709
|
+
context2,
|
|
72710
|
+
`/orgs/${orgId}/access/groups/${encodeURIComponent(group)}`,
|
|
72711
|
+
{
|
|
72712
|
+
method: "PATCH",
|
|
72713
|
+
body: {
|
|
72714
|
+
name,
|
|
72715
|
+
slug,
|
|
72716
|
+
description
|
|
72717
|
+
}
|
|
72718
|
+
}
|
|
72719
|
+
);
|
|
72720
|
+
if (json) {
|
|
72721
|
+
outputJson(response, json);
|
|
72722
|
+
return;
|
|
72723
|
+
}
|
|
72724
|
+
console.log(`Updated group '${response.name}' (${response.id})`);
|
|
72725
|
+
console.log(` Slug: ${response.slug}`);
|
|
72726
|
+
if (response.description) {
|
|
72727
|
+
console.log(` Description: ${response.description}`);
|
|
72728
|
+
}
|
|
72729
|
+
return;
|
|
72730
|
+
}
|
|
72731
|
+
case "delete": {
|
|
72732
|
+
const group = positionals[0] ?? getStringFlag(flags, ["group"]);
|
|
72733
|
+
if (!group) {
|
|
72734
|
+
throw new Error("Usage: eve access groups delete <group_id_or_slug> --org <org_id>");
|
|
72735
|
+
}
|
|
72736
|
+
await requestJson(context2, `/orgs/${orgId}/access/groups/${encodeURIComponent(group)}`, {
|
|
72737
|
+
method: "DELETE"
|
|
72738
|
+
});
|
|
72739
|
+
if (json) {
|
|
72740
|
+
outputJson({ deleted: true, group }, json);
|
|
72741
|
+
return;
|
|
72742
|
+
}
|
|
72743
|
+
console.log(`Deleted group '${group}'`);
|
|
72744
|
+
return;
|
|
72745
|
+
}
|
|
72746
|
+
default:
|
|
72747
|
+
throw new Error(
|
|
72748
|
+
'Usage: eve access groups <create|list|show|update|delete|members> [args] [flags]\n\nExamples:\n eve access groups create "Product Management" --org org_xxx\n eve access groups list --org org_xxx\n eve access groups members list pm-team --org org_xxx'
|
|
72749
|
+
);
|
|
72750
|
+
}
|
|
72751
|
+
}
|
|
72752
|
+
async function handleGroupMembers(action, positionals, flags, context2, json) {
|
|
72753
|
+
const orgId = getStringFlag(flags, ["org"]) ?? context2.orgId;
|
|
72754
|
+
if (!orgId) {
|
|
72755
|
+
throw new Error("--org is required (or set a default org in your profile)");
|
|
72756
|
+
}
|
|
72757
|
+
switch (action) {
|
|
72758
|
+
case "add": {
|
|
72759
|
+
const group = positionals[0] ?? getStringFlag(flags, ["group"]);
|
|
72760
|
+
if (!group) {
|
|
72761
|
+
throw new Error("Usage: eve access groups members add <group> --org <org_id> (--user <user_id> | --service-principal <sp_id>)");
|
|
72762
|
+
}
|
|
72763
|
+
const principal = resolvePrincipalSelection(flags);
|
|
72764
|
+
const response = await requestJson(
|
|
72765
|
+
context2,
|
|
72766
|
+
`/orgs/${orgId}/access/groups/${encodeURIComponent(group)}/members`,
|
|
72767
|
+
{
|
|
72768
|
+
method: "POST",
|
|
72769
|
+
body: {
|
|
72770
|
+
principal_type: principal.principalType,
|
|
72771
|
+
principal_id: principal.principalId
|
|
72772
|
+
}
|
|
72773
|
+
}
|
|
72774
|
+
);
|
|
72775
|
+
if (json) {
|
|
72776
|
+
outputJson(response, json);
|
|
72777
|
+
return;
|
|
72778
|
+
}
|
|
72779
|
+
console.log(`Added ${response.principal_type} ${response.principal_id} to group ${group}`);
|
|
72780
|
+
return;
|
|
72781
|
+
}
|
|
72782
|
+
case "list": {
|
|
72783
|
+
const group = positionals[0] ?? getStringFlag(flags, ["group"]);
|
|
72784
|
+
if (!group) {
|
|
72785
|
+
throw new Error("Usage: eve access groups members list <group> --org <org_id>");
|
|
72786
|
+
}
|
|
72787
|
+
const membersResponse = await requestJson(
|
|
72788
|
+
context2,
|
|
72789
|
+
`/orgs/${orgId}/access/groups/${encodeURIComponent(group)}/members`
|
|
72790
|
+
);
|
|
72791
|
+
const members = unwrapListResponse(membersResponse);
|
|
72792
|
+
if (json) {
|
|
72793
|
+
outputJson({ data: members }, json);
|
|
72794
|
+
return;
|
|
72795
|
+
}
|
|
72796
|
+
if (members.length === 0) {
|
|
72797
|
+
console.log("No group members found.");
|
|
72798
|
+
return;
|
|
72799
|
+
}
|
|
72800
|
+
for (const member of members) {
|
|
72801
|
+
console.log(`${member.principal_type} ${member.principal_id}`);
|
|
72802
|
+
}
|
|
72803
|
+
return;
|
|
72804
|
+
}
|
|
72805
|
+
case "remove": {
|
|
72806
|
+
const group = positionals[0] ?? getStringFlag(flags, ["group"]);
|
|
72807
|
+
if (!group) {
|
|
72808
|
+
throw new Error("Usage: eve access groups members remove <group> --org <org_id> (--user <user_id> | --service-principal <sp_id>)");
|
|
72809
|
+
}
|
|
72810
|
+
const principal = resolvePrincipalSelection(flags);
|
|
72811
|
+
await requestJson(
|
|
72812
|
+
context2,
|
|
72813
|
+
`/orgs/${orgId}/access/groups/${encodeURIComponent(group)}/members/${principal.principalType}/${principal.principalId}`,
|
|
72814
|
+
{ method: "DELETE" }
|
|
72815
|
+
);
|
|
72816
|
+
if (json) {
|
|
72817
|
+
outputJson({ removed: true, group, principal: principal.principalId }, json);
|
|
72818
|
+
return;
|
|
72819
|
+
}
|
|
72820
|
+
console.log(`Removed ${principal.principalType} ${principal.principalId} from group ${group}`);
|
|
72821
|
+
return;
|
|
72822
|
+
}
|
|
72823
|
+
default:
|
|
72824
|
+
throw new Error(
|
|
72825
|
+
"Usage: eve access groups members <add|list|remove> <group> --org <org_id> [--user <id> | --service-principal <id>]"
|
|
72826
|
+
);
|
|
72827
|
+
}
|
|
72828
|
+
}
|
|
72829
|
+
async function handleMemberships(flags, context2, json) {
|
|
72830
|
+
const orgId = getStringFlag(flags, ["org"]) ?? context2.orgId;
|
|
72831
|
+
if (!orgId) {
|
|
72832
|
+
throw new Error("--org is required (or set a default org in your profile)");
|
|
72833
|
+
}
|
|
72834
|
+
const principal = resolvePrincipalSelection(flags, { allowGroup: true });
|
|
72835
|
+
const response = await requestJson(
|
|
72836
|
+
context2,
|
|
72837
|
+
`/orgs/${orgId}/access/principals/${principal.principalType}/${principal.principalId}/memberships`
|
|
72838
|
+
);
|
|
72839
|
+
if (json) {
|
|
72840
|
+
outputJson(response, json);
|
|
72841
|
+
return;
|
|
72842
|
+
}
|
|
72843
|
+
console.log(`Principal: ${response.principal_type} ${response.principal_id}`);
|
|
72844
|
+
if (response.base.org_role) {
|
|
72845
|
+
console.log(`Org role: ${response.base.org_role}`);
|
|
72846
|
+
}
|
|
72847
|
+
if (response.base.project_roles.length > 0) {
|
|
72848
|
+
console.log(`Project roles: ${response.base.project_roles.length}`);
|
|
72849
|
+
}
|
|
72850
|
+
if (response.groups.length > 0) {
|
|
72851
|
+
console.log(`Groups: ${response.groups.map((group) => group.slug).join(", ")}`);
|
|
72852
|
+
} else {
|
|
72853
|
+
console.log("Groups: none");
|
|
72854
|
+
}
|
|
72855
|
+
console.log(`Effective permissions: ${response.effective_permissions.length}`);
|
|
72856
|
+
if (response.effective_scopes.orgfs.allow_prefixes.length > 0) {
|
|
72857
|
+
console.log(`orgfs allow: ${response.effective_scopes.orgfs.allow_prefixes.join(", ")}`);
|
|
72858
|
+
}
|
|
72859
|
+
if (response.effective_scopes.orgdocs.allow_prefixes.length > 0) {
|
|
72860
|
+
console.log(`orgdocs allow: ${response.effective_scopes.orgdocs.allow_prefixes.join(", ")}`);
|
|
72861
|
+
}
|
|
72862
|
+
if (response.effective_scopes.envdb.schemas.length > 0 || response.effective_scopes.envdb.tables.length > 0) {
|
|
72863
|
+
const schemas = response.effective_scopes.envdb.schemas.join(", ") || "-";
|
|
72864
|
+
const tables = response.effective_scopes.envdb.tables.join(", ") || "-";
|
|
72865
|
+
console.log(`envdb schemas: ${schemas}`);
|
|
72866
|
+
console.log(`envdb tables: ${tables}`);
|
|
72867
|
+
}
|
|
72868
|
+
}
|
|
71765
72869
|
var DEFAULT_ACCESS_YAML = ".eve/access.yaml";
|
|
71766
72870
|
function resolveFilePath(flags) {
|
|
71767
72871
|
const filePath = getStringFlag(flags, ["file", "f"]) ?? DEFAULT_ACCESS_YAML;
|
|
71768
|
-
return (0,
|
|
72872
|
+
return (0, import_node_path15.resolve)(process.cwd(), filePath);
|
|
71769
72873
|
}
|
|
71770
72874
|
function loadAccessYaml(filePath) {
|
|
71771
|
-
if (!(0,
|
|
72875
|
+
if (!(0, import_node_fs15.existsSync)(filePath)) {
|
|
71772
72876
|
throw new Error(`File not found: ${filePath}`);
|
|
71773
72877
|
}
|
|
71774
|
-
const raw = (0,
|
|
72878
|
+
const raw = (0, import_node_fs15.readFileSync)(filePath, "utf-8");
|
|
71775
72879
|
let parsed;
|
|
71776
72880
|
try {
|
|
71777
72881
|
parsed = (0, import_yaml6.parse)(raw);
|
|
@@ -71789,10 +72893,62 @@ ${issues.join("\n")}`);
|
|
|
71789
72893
|
}
|
|
71790
72894
|
return result.data;
|
|
71791
72895
|
}
|
|
72896
|
+
function permissionScopeType(permission) {
|
|
72897
|
+
if (permission.startsWith("orgfs:")) return "orgfs";
|
|
72898
|
+
if (permission.startsWith("orgdocs:")) return "orgdocs";
|
|
72899
|
+
if (permission.startsWith("envdb:")) return "envdb";
|
|
72900
|
+
return null;
|
|
72901
|
+
}
|
|
72902
|
+
function hasPrefixScope(scope, resourceType, requireWritable) {
|
|
72903
|
+
const resourceScope = scope?.[resourceType];
|
|
72904
|
+
if (!resourceScope) {
|
|
72905
|
+
return false;
|
|
72906
|
+
}
|
|
72907
|
+
const allowCount = resourceScope.allow_prefixes?.length ?? 0;
|
|
72908
|
+
const readOnlyCount = resourceScope.read_only_prefixes?.length ?? 0;
|
|
72909
|
+
if (requireWritable) {
|
|
72910
|
+
return allowCount > 0;
|
|
72911
|
+
}
|
|
72912
|
+
return allowCount > 0 || readOnlyCount > 0;
|
|
72913
|
+
}
|
|
72914
|
+
function hasEnvDbScope(scope) {
|
|
72915
|
+
const envdb = scope?.envdb;
|
|
72916
|
+
if (!envdb) {
|
|
72917
|
+
return false;
|
|
72918
|
+
}
|
|
72919
|
+
return (envdb.schemas?.length ?? 0) > 0 || (envdb.tables?.length ?? 0) > 0;
|
|
72920
|
+
}
|
|
72921
|
+
function groupDefaultName(slug) {
|
|
72922
|
+
return slug.split("-").filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
|
|
72923
|
+
}
|
|
72924
|
+
function declaredMemberKey(member) {
|
|
72925
|
+
return `${member.type}:${member.id}`;
|
|
72926
|
+
}
|
|
72927
|
+
function apiMemberKey(member) {
|
|
72928
|
+
return `${member.principal_type}:${member.principal_id}`;
|
|
72929
|
+
}
|
|
72930
|
+
function bindingIdentityKey(roleName, principalType, principalId, projectId) {
|
|
72931
|
+
const scope = projectId ?? "org";
|
|
72932
|
+
return `${roleName}|${principalType}|${principalId}|${scope}`;
|
|
72933
|
+
}
|
|
72934
|
+
function bindingMatchKey(roleName, principalType, principalId, projectId, scope) {
|
|
72935
|
+
const normalizedScope = normalizeBindingScope(scope);
|
|
72936
|
+
return `${bindingIdentityKey(roleName, principalType, principalId, projectId)}|${JSON.stringify(normalizedScope ?? null)}`;
|
|
72937
|
+
}
|
|
72938
|
+
function formatBindingScope(scope) {
|
|
72939
|
+
const normalized = normalizeBindingScope(scope);
|
|
72940
|
+
if (!normalized) {
|
|
72941
|
+
return "(none)";
|
|
72942
|
+
}
|
|
72943
|
+
return JSON.stringify(normalized);
|
|
72944
|
+
}
|
|
71792
72945
|
function semanticValidate(yaml) {
|
|
71793
72946
|
const errors = [];
|
|
71794
|
-
const
|
|
71795
|
-
|
|
72947
|
+
const roles = yaml.access.roles ?? {};
|
|
72948
|
+
const groups = yaml.access.groups ?? {};
|
|
72949
|
+
const roleNames = new Set(Object.keys(roles));
|
|
72950
|
+
const groupSlugs = new Set(Object.keys(groups));
|
|
72951
|
+
for (const [name, role] of Object.entries(roles)) {
|
|
71796
72952
|
for (const perm of role.permissions) {
|
|
71797
72953
|
if (!PERMISSION_SET.has(perm)) {
|
|
71798
72954
|
errors.push({
|
|
@@ -71802,6 +72958,23 @@ function semanticValidate(yaml) {
|
|
|
71802
72958
|
}
|
|
71803
72959
|
}
|
|
71804
72960
|
}
|
|
72961
|
+
for (const [slug, group] of Object.entries(groups)) {
|
|
72962
|
+
const seenMembers = /* @__PURE__ */ new Set();
|
|
72963
|
+
const members = group.members ?? [];
|
|
72964
|
+
for (let i = 0; i < members.length; i++) {
|
|
72965
|
+
const member = members[i];
|
|
72966
|
+
const key = declaredMemberKey(member);
|
|
72967
|
+
if (seenMembers.has(key)) {
|
|
72968
|
+
errors.push({
|
|
72969
|
+
path: `access.groups.${slug}.members[${i}]`,
|
|
72970
|
+
message: `Duplicate group member '${key}'`
|
|
72971
|
+
});
|
|
72972
|
+
continue;
|
|
72973
|
+
}
|
|
72974
|
+
seenMembers.add(key);
|
|
72975
|
+
}
|
|
72976
|
+
}
|
|
72977
|
+
const seenBindingKeys = /* @__PURE__ */ new Set();
|
|
71805
72978
|
const bindings = yaml.access.bindings ?? [];
|
|
71806
72979
|
for (let i = 0; i < bindings.length; i++) {
|
|
71807
72980
|
const binding = bindings[i];
|
|
@@ -71813,18 +72986,73 @@ function semanticValidate(yaml) {
|
|
|
71813
72986
|
});
|
|
71814
72987
|
}
|
|
71815
72988
|
}
|
|
71816
|
-
if (binding.
|
|
72989
|
+
if (binding.project_id !== void 0 && binding.project_id.trim() === "") {
|
|
72990
|
+
errors.push({
|
|
72991
|
+
path: `access.bindings[${i}].project_id`,
|
|
72992
|
+
message: "project_id cannot be empty when provided"
|
|
72993
|
+
});
|
|
72994
|
+
}
|
|
72995
|
+
if (binding.subject.type === "group" && !groupSlugs.has(binding.subject.id)) {
|
|
72996
|
+
errors.push({
|
|
72997
|
+
path: `access.bindings[${i}].subject.id`,
|
|
72998
|
+
message: `Group '${binding.subject.id}' is not defined in access.groups`
|
|
72999
|
+
});
|
|
73000
|
+
}
|
|
73001
|
+
const normalizedScope = normalizeBindingScope(binding.scope);
|
|
73002
|
+
const requiredScopeTypes = /* @__PURE__ */ new Set();
|
|
73003
|
+
let needsWritableOrgFsScope = false;
|
|
73004
|
+
let needsWritableOrgDocsScope = false;
|
|
73005
|
+
for (const roleName of binding.roles) {
|
|
73006
|
+
const role = roles[roleName];
|
|
73007
|
+
if (!role) continue;
|
|
73008
|
+
for (const permission of role.permissions) {
|
|
73009
|
+
const scopeType = permissionScopeType(permission);
|
|
73010
|
+
if (scopeType) {
|
|
73011
|
+
requiredScopeTypes.add(scopeType);
|
|
73012
|
+
}
|
|
73013
|
+
if (permission === "orgfs:write" || permission === "orgfs:admin") {
|
|
73014
|
+
needsWritableOrgFsScope = true;
|
|
73015
|
+
}
|
|
73016
|
+
if (permission === "orgdocs:write" || permission === "orgdocs:admin") {
|
|
73017
|
+
needsWritableOrgDocsScope = true;
|
|
73018
|
+
}
|
|
73019
|
+
}
|
|
73020
|
+
}
|
|
73021
|
+
if (requiredScopeTypes.has("orgfs") && !hasPrefixScope(normalizedScope, "orgfs", needsWritableOrgFsScope)) {
|
|
73022
|
+
errors.push({
|
|
73023
|
+
path: `access.bindings[${i}].scope`,
|
|
73024
|
+
message: needsWritableOrgFsScope ? "Binding includes orgfs write/admin permissions but scope.orgfs.allow_prefixes is missing" : "Binding includes orgfs permissions but scope.orgfs prefixes are missing"
|
|
73025
|
+
});
|
|
73026
|
+
}
|
|
73027
|
+
if (requiredScopeTypes.has("orgdocs") && !hasPrefixScope(normalizedScope, "orgdocs", needsWritableOrgDocsScope)) {
|
|
71817
73028
|
errors.push({
|
|
71818
|
-
path: `access.bindings[${i}]`,
|
|
71819
|
-
message: "
|
|
73029
|
+
path: `access.bindings[${i}].scope`,
|
|
73030
|
+
message: needsWritableOrgDocsScope ? "Binding includes orgdocs write/admin permissions but scope.orgdocs.allow_prefixes is missing" : "Binding includes orgdocs permissions but scope.orgdocs prefixes are missing"
|
|
71820
73031
|
});
|
|
71821
73032
|
}
|
|
71822
|
-
if (
|
|
73033
|
+
if (requiredScopeTypes.has("envdb") && !hasEnvDbScope(normalizedScope)) {
|
|
71823
73034
|
errors.push({
|
|
71824
|
-
path: `access.bindings[${i}]`,
|
|
71825
|
-
message: "
|
|
73035
|
+
path: `access.bindings[${i}].scope`,
|
|
73036
|
+
message: "Binding includes envdb permissions but scope.envdb.schemas/tables is missing"
|
|
71826
73037
|
});
|
|
71827
73038
|
}
|
|
73039
|
+
for (const roleName of binding.roles) {
|
|
73040
|
+
const dedupeKey = bindingMatchKey(
|
|
73041
|
+
roleName,
|
|
73042
|
+
binding.subject.type,
|
|
73043
|
+
binding.subject.id,
|
|
73044
|
+
binding.project_id ?? null,
|
|
73045
|
+
normalizedScope
|
|
73046
|
+
);
|
|
73047
|
+
if (seenBindingKeys.has(dedupeKey)) {
|
|
73048
|
+
errors.push({
|
|
73049
|
+
path: `access.bindings[${i}]`,
|
|
73050
|
+
message: `Duplicate binding tuple for role '${roleName}' and subject '${binding.subject.type}:${binding.subject.id}'`
|
|
73051
|
+
});
|
|
73052
|
+
} else {
|
|
73053
|
+
seenBindingKeys.add(dedupeKey);
|
|
73054
|
+
}
|
|
73055
|
+
}
|
|
71828
73056
|
}
|
|
71829
73057
|
return errors;
|
|
71830
73058
|
}
|
|
@@ -71837,7 +73065,9 @@ async function handleValidate(flags, json) {
|
|
|
71837
73065
|
valid: errors.length === 0,
|
|
71838
73066
|
file: filePath,
|
|
71839
73067
|
errors,
|
|
73068
|
+
groups: Object.keys(yaml.access.groups ?? {}).length,
|
|
71840
73069
|
roles: Object.keys(yaml.access.roles ?? {}).length,
|
|
73070
|
+
members: Object.values(yaml.access.groups ?? {}).reduce((acc, group) => acc + (group.members?.length ?? 0), 0),
|
|
71841
73071
|
bindings: (yaml.access.bindings ?? []).length
|
|
71842
73072
|
}, json);
|
|
71843
73073
|
return;
|
|
@@ -71850,28 +73080,124 @@ async function handleValidate(flags, json) {
|
|
|
71850
73080
|
}
|
|
71851
73081
|
process.exit(1);
|
|
71852
73082
|
}
|
|
73083
|
+
const groupCount = Object.keys(yaml.access.groups ?? {}).length;
|
|
71853
73084
|
const roleCount = Object.keys(yaml.access.roles ?? {}).length;
|
|
73085
|
+
const memberCount = Object.values(yaml.access.groups ?? {}).reduce((acc, group) => acc + (group.members?.length ?? 0), 0);
|
|
71854
73086
|
const bindingCount = (yaml.access.bindings ?? []).length;
|
|
71855
|
-
console.log(`Valid (${roleCount} roles, ${bindingCount} bindings)`);
|
|
73087
|
+
console.log(`Valid (${groupCount} groups, ${memberCount} members, ${roleCount} roles, ${bindingCount} bindings)`);
|
|
71856
73088
|
}
|
|
71857
|
-
function
|
|
71858
|
-
|
|
71859
|
-
|
|
73089
|
+
function resolveGroupPrincipalId(groupRef, groupsById, groupsBySlug) {
|
|
73090
|
+
if (groupsById.has(groupRef)) {
|
|
73091
|
+
return groupRef;
|
|
73092
|
+
}
|
|
73093
|
+
return groupsBySlug.get(groupRef)?.id ?? null;
|
|
71860
73094
|
}
|
|
71861
73095
|
async function computePlan(yaml, orgId, context2) {
|
|
71862
|
-
const [apiRolesResponse, apiBindingsResponse] = await Promise.all([
|
|
73096
|
+
const [apiGroupsResponse, apiRolesResponse, apiBindingsResponse] = await Promise.all([
|
|
73097
|
+
requestJson(context2, `/orgs/${orgId}/access/groups`),
|
|
71863
73098
|
requestJson(context2, `/orgs/${orgId}/access/roles`),
|
|
71864
73099
|
requestJson(context2, `/orgs/${orgId}/access/bindings`)
|
|
71865
73100
|
]);
|
|
73101
|
+
const apiGroups = unwrapListResponse(apiGroupsResponse);
|
|
71866
73102
|
const apiRoles = unwrapListResponse(apiRolesResponse);
|
|
71867
73103
|
const apiBindings = unwrapListResponse(apiBindingsResponse);
|
|
73104
|
+
const groupMemberEntries = await Promise.all(
|
|
73105
|
+
apiGroups.map(async (group) => {
|
|
73106
|
+
const membersResponse = await requestJson(
|
|
73107
|
+
context2,
|
|
73108
|
+
`/orgs/${orgId}/access/groups/${encodeURIComponent(group.id)}/members`
|
|
73109
|
+
);
|
|
73110
|
+
return [group.id, unwrapListResponse(membersResponse)];
|
|
73111
|
+
})
|
|
73112
|
+
);
|
|
73113
|
+
const membersByGroupId = new Map(
|
|
73114
|
+
groupMemberEntries.map(([groupId, members]) => [groupId, members])
|
|
73115
|
+
);
|
|
73116
|
+
const groupsBySlug = new Map(apiGroups.map((group) => [group.slug, group]));
|
|
73117
|
+
const groupsById = new Map(apiGroups.map((group) => [group.id, group]));
|
|
71868
73118
|
const rolesByName = new Map(apiRoles.map((r) => [r.name, r]));
|
|
71869
73119
|
const plan = {
|
|
73120
|
+
groups: [],
|
|
73121
|
+
group_members: [],
|
|
71870
73122
|
roles: [],
|
|
71871
73123
|
bindings: [],
|
|
73124
|
+
unchanged_groups: 0,
|
|
73125
|
+
unchanged_group_members: 0,
|
|
71872
73126
|
unchanged_roles: 0,
|
|
71873
73127
|
unchanged_bindings: 0
|
|
71874
73128
|
};
|
|
73129
|
+
const declaredGroupSlugs = /* @__PURE__ */ new Set();
|
|
73130
|
+
for (const [slug, declaredGroup] of Object.entries(yaml.access.groups ?? {})) {
|
|
73131
|
+
declaredGroupSlugs.add(slug);
|
|
73132
|
+
const existing = groupsBySlug.get(slug);
|
|
73133
|
+
const desiredMembers = declaredGroup.members ?? [];
|
|
73134
|
+
if (!existing) {
|
|
73135
|
+
plan.groups.push({ action: "create", slug, group: declaredGroup });
|
|
73136
|
+
for (const member of desiredMembers) {
|
|
73137
|
+
plan.group_members.push({
|
|
73138
|
+
action: "add",
|
|
73139
|
+
groupSlug: slug,
|
|
73140
|
+
member
|
|
73141
|
+
});
|
|
73142
|
+
}
|
|
73143
|
+
continue;
|
|
73144
|
+
}
|
|
73145
|
+
const changes = [];
|
|
73146
|
+
const desiredName = declaredGroup.name ?? groupDefaultName(slug);
|
|
73147
|
+
const desiredDescription = declaredGroup.description ?? null;
|
|
73148
|
+
if (desiredName !== existing.name) {
|
|
73149
|
+
changes.push(`name: "${existing.name}" -> "${desiredName}"`);
|
|
73150
|
+
}
|
|
73151
|
+
if (desiredDescription !== (existing.description ?? null)) {
|
|
73152
|
+
changes.push(`description: "${existing.description ?? "(none)"}" -> "${desiredDescription ?? "(none)"}"`);
|
|
73153
|
+
}
|
|
73154
|
+
if (changes.length > 0) {
|
|
73155
|
+
plan.groups.push({
|
|
73156
|
+
action: "update",
|
|
73157
|
+
slug,
|
|
73158
|
+
id: existing.id,
|
|
73159
|
+
group: declaredGroup,
|
|
73160
|
+
changes
|
|
73161
|
+
});
|
|
73162
|
+
} else {
|
|
73163
|
+
plan.unchanged_groups++;
|
|
73164
|
+
}
|
|
73165
|
+
const existingMembers = membersByGroupId.get(existing.id) ?? [];
|
|
73166
|
+
const existingMemberKeys = new Set(existingMembers.map(apiMemberKey));
|
|
73167
|
+
const desiredMemberKeys = new Set(desiredMembers.map(declaredMemberKey));
|
|
73168
|
+
for (const member of desiredMembers) {
|
|
73169
|
+
const key = declaredMemberKey(member);
|
|
73170
|
+
if (existingMemberKeys.has(key)) {
|
|
73171
|
+
plan.unchanged_group_members++;
|
|
73172
|
+
} else {
|
|
73173
|
+
plan.group_members.push({
|
|
73174
|
+
action: "add",
|
|
73175
|
+
groupSlug: slug,
|
|
73176
|
+
member
|
|
73177
|
+
});
|
|
73178
|
+
}
|
|
73179
|
+
}
|
|
73180
|
+
for (const member of existingMembers) {
|
|
73181
|
+
const key = apiMemberKey(member);
|
|
73182
|
+
if (!desiredMemberKeys.has(key)) {
|
|
73183
|
+
plan.group_members.push({
|
|
73184
|
+
action: "remove",
|
|
73185
|
+
groupSlug: slug,
|
|
73186
|
+
groupId: existing.id,
|
|
73187
|
+
member
|
|
73188
|
+
});
|
|
73189
|
+
}
|
|
73190
|
+
}
|
|
73191
|
+
}
|
|
73192
|
+
for (const apiGroup of apiGroups) {
|
|
73193
|
+
if (!declaredGroupSlugs.has(apiGroup.slug)) {
|
|
73194
|
+
plan.groups.push({
|
|
73195
|
+
action: "prune",
|
|
73196
|
+
slug: apiGroup.slug,
|
|
73197
|
+
id: apiGroup.id
|
|
73198
|
+
});
|
|
73199
|
+
}
|
|
73200
|
+
}
|
|
71875
73201
|
const declaredRoleNames = /* @__PURE__ */ new Set();
|
|
71876
73202
|
for (const [name, declaredRole] of Object.entries(yaml.access.roles ?? {})) {
|
|
71877
73203
|
declaredRoleNames.add(name);
|
|
@@ -71908,49 +73234,146 @@ async function computePlan(yaml, orgId, context2) {
|
|
|
71908
73234
|
plan.roles.push({ action: "prune", name: apiRole.name, id: apiRole.id });
|
|
71909
73235
|
}
|
|
71910
73236
|
}
|
|
71911
|
-
const
|
|
73237
|
+
const existingBindingByMatchKey = /* @__PURE__ */ new Map();
|
|
73238
|
+
const existingBindingByIdentityKey = /* @__PURE__ */ new Map();
|
|
71912
73239
|
for (const ab of apiBindings) {
|
|
71913
|
-
const
|
|
71914
|
-
|
|
73240
|
+
const identityKey = bindingIdentityKey(ab.role_name, ab.principal_type, ab.principal_id, ab.project_id);
|
|
73241
|
+
existingBindingByIdentityKey.set(identityKey, ab);
|
|
73242
|
+
const matchKey = bindingMatchKey(
|
|
73243
|
+
ab.role_name,
|
|
73244
|
+
ab.principal_type,
|
|
73245
|
+
ab.principal_id,
|
|
73246
|
+
ab.project_id,
|
|
73247
|
+
ab.scope_json
|
|
73248
|
+
);
|
|
73249
|
+
existingBindingByMatchKey.set(matchKey, ab);
|
|
71915
73250
|
}
|
|
71916
|
-
const
|
|
73251
|
+
const matchedApiBindingIds = /* @__PURE__ */ new Set();
|
|
73252
|
+
const groupsMarkedForPrune = new Set(
|
|
73253
|
+
plan.groups.filter((group) => group.action === "prune").map((group) => group.id)
|
|
73254
|
+
);
|
|
71917
73255
|
for (const declaredBinding of yaml.access.bindings ?? []) {
|
|
71918
|
-
|
|
71919
|
-
|
|
71920
|
-
|
|
73256
|
+
const normalizedDeclaredScope = normalizeBindingScope(declaredBinding.scope);
|
|
73257
|
+
const principalType = declaredBinding.subject.type;
|
|
73258
|
+
let principalIdHint = declaredBinding.subject.id;
|
|
73259
|
+
if (principalType === "group") {
|
|
73260
|
+
const resolvedGroupId = resolveGroupPrincipalId(declaredBinding.subject.id, groupsById, groupsBySlug);
|
|
73261
|
+
if (resolvedGroupId) {
|
|
73262
|
+
principalIdHint = resolvedGroupId;
|
|
73263
|
+
}
|
|
73264
|
+
}
|
|
73265
|
+
for (const roleName of [...new Set(declaredBinding.roles)]) {
|
|
73266
|
+
const identityKey = bindingIdentityKey(
|
|
71921
73267
|
roleName,
|
|
71922
|
-
|
|
71923
|
-
|
|
71924
|
-
|
|
73268
|
+
principalType,
|
|
73269
|
+
principalIdHint,
|
|
73270
|
+
declaredBinding.project_id ?? null
|
|
71925
73271
|
);
|
|
71926
|
-
|
|
71927
|
-
|
|
73272
|
+
const matchKey = bindingMatchKey(
|
|
73273
|
+
roleName,
|
|
73274
|
+
principalType,
|
|
73275
|
+
principalIdHint,
|
|
73276
|
+
declaredBinding.project_id ?? null,
|
|
73277
|
+
normalizedDeclaredScope
|
|
73278
|
+
);
|
|
73279
|
+
const exactMatch = existingBindingByMatchKey.get(matchKey);
|
|
73280
|
+
if (exactMatch) {
|
|
73281
|
+
matchedApiBindingIds.add(exactMatch.id);
|
|
71928
73282
|
plan.unchanged_bindings++;
|
|
71929
|
-
|
|
71930
|
-
plan.bindings.push({ action: "create", binding: declaredBinding, roleName });
|
|
73283
|
+
continue;
|
|
71931
73284
|
}
|
|
73285
|
+
const identityMatch = existingBindingByIdentityKey.get(identityKey);
|
|
73286
|
+
if (identityMatch) {
|
|
73287
|
+
matchedApiBindingIds.add(identityMatch.id);
|
|
73288
|
+
const changes = [];
|
|
73289
|
+
if (!scopeEquals(identityMatch.scope_json, normalizedDeclaredScope)) {
|
|
73290
|
+
changes.push(
|
|
73291
|
+
`scope: ${formatBindingScope(identityMatch.scope_json)} -> ${formatBindingScope(normalizedDeclaredScope)}`
|
|
73292
|
+
);
|
|
73293
|
+
}
|
|
73294
|
+
plan.bindings.push({
|
|
73295
|
+
action: "replace",
|
|
73296
|
+
existing: identityMatch,
|
|
73297
|
+
binding: declaredBinding,
|
|
73298
|
+
roleName,
|
|
73299
|
+
principalIdHint,
|
|
73300
|
+
changes
|
|
73301
|
+
});
|
|
73302
|
+
continue;
|
|
73303
|
+
}
|
|
73304
|
+
plan.bindings.push({
|
|
73305
|
+
action: "create",
|
|
73306
|
+
binding: declaredBinding,
|
|
73307
|
+
roleName,
|
|
73308
|
+
principalIdHint
|
|
73309
|
+
});
|
|
71932
73310
|
}
|
|
71933
73311
|
}
|
|
71934
|
-
for (const
|
|
71935
|
-
if (
|
|
71936
|
-
|
|
73312
|
+
for (const ab of apiBindings) {
|
|
73313
|
+
if (matchedApiBindingIds.has(ab.id)) {
|
|
73314
|
+
continue;
|
|
71937
73315
|
}
|
|
73316
|
+
if (ab.principal_type === "group" && groupsMarkedForPrune.has(ab.principal_id)) {
|
|
73317
|
+
continue;
|
|
73318
|
+
}
|
|
73319
|
+
plan.bindings.push({ action: "prune", binding: ab });
|
|
71938
73320
|
}
|
|
71939
73321
|
return plan;
|
|
71940
73322
|
}
|
|
71941
73323
|
function hasChanges(plan, prune) {
|
|
73324
|
+
const groupChanges = plan.groups.filter(
|
|
73325
|
+
(g) => g.action === "create" || g.action === "update" || g.action === "prune" && prune
|
|
73326
|
+
);
|
|
73327
|
+
const memberChanges = plan.group_members.filter(
|
|
73328
|
+
(m) => m.action === "add" || m.action === "remove"
|
|
73329
|
+
);
|
|
71942
73330
|
const roleChanges = plan.roles.filter(
|
|
71943
73331
|
(r) => r.action === "create" || r.action === "update" || r.action === "prune" && prune
|
|
71944
73332
|
);
|
|
71945
73333
|
const bindingChanges = plan.bindings.filter(
|
|
71946
|
-
(b) => b.action === "create" || b.action === "prune" && prune
|
|
73334
|
+
(b) => b.action === "create" || b.action === "replace" || b.action === "prune" && prune
|
|
71947
73335
|
);
|
|
71948
|
-
return roleChanges.length > 0 || bindingChanges.length > 0;
|
|
73336
|
+
return groupChanges.length > 0 || memberChanges.length > 0 || roleChanges.length > 0 || bindingChanges.length > 0;
|
|
71949
73337
|
}
|
|
71950
73338
|
function printPlan(plan, orgId, prune) {
|
|
71951
73339
|
console.log(`
|
|
71952
73340
|
Access Plan for ${orgId}:
|
|
71953
73341
|
`);
|
|
73342
|
+
const groupCreates = plan.groups.filter((g) => g.action === "create");
|
|
73343
|
+
const groupUpdates = plan.groups.filter((g) => g.action === "update");
|
|
73344
|
+
const groupPrunes = plan.groups.filter((g) => g.action === "prune");
|
|
73345
|
+
if (groupCreates.length > 0 || groupUpdates.length > 0 || groupPrunes.length > 0) {
|
|
73346
|
+
console.log("Groups:");
|
|
73347
|
+
for (const group of groupCreates) {
|
|
73348
|
+
const name = group.group.name ?? groupDefaultName(group.slug);
|
|
73349
|
+
console.log(` + CREATE ${group.slug} (${name})`);
|
|
73350
|
+
}
|
|
73351
|
+
for (const group of groupUpdates) {
|
|
73352
|
+
console.log(` ~ UPDATE ${group.slug}: ${group.changes.join("; ")}`);
|
|
73353
|
+
}
|
|
73354
|
+
if (groupPrunes.length > 0) {
|
|
73355
|
+
if (prune) {
|
|
73356
|
+
for (const group of groupPrunes) {
|
|
73357
|
+
console.log(` - DELETE ${group.slug} (${group.id})`);
|
|
73358
|
+
}
|
|
73359
|
+
} else {
|
|
73360
|
+
console.log(` ? Undeclared (not pruned): ${groupPrunes.map((group) => group.slug).join(", ")}`);
|
|
73361
|
+
}
|
|
73362
|
+
}
|
|
73363
|
+
console.log("");
|
|
73364
|
+
}
|
|
73365
|
+
const memberAdds = plan.group_members.filter((m) => m.action === "add");
|
|
73366
|
+
const memberRemoves = plan.group_members.filter((m) => m.action === "remove");
|
|
73367
|
+
if (memberAdds.length > 0 || memberRemoves.length > 0) {
|
|
73368
|
+
console.log("Group Memberships:");
|
|
73369
|
+
for (const member of memberAdds) {
|
|
73370
|
+
console.log(` + ADD ${member.member.type}:${member.member.id} -> ${member.groupSlug}`);
|
|
73371
|
+
}
|
|
73372
|
+
for (const member of memberRemoves) {
|
|
73373
|
+
console.log(` - REMOVE ${member.member.principal_type}:${member.member.principal_id} -> ${member.groupSlug}`);
|
|
73374
|
+
}
|
|
73375
|
+
console.log("");
|
|
73376
|
+
}
|
|
71954
73377
|
const roleCreates = plan.roles.filter((r) => r.action === "create");
|
|
71955
73378
|
const roleUpdates = plan.roles.filter((r) => r.action === "update");
|
|
71956
73379
|
const rolePrunes = plan.roles.filter((r) => r.action === "prune");
|
|
@@ -71974,12 +73397,21 @@ Access Plan for ${orgId}:
|
|
|
71974
73397
|
console.log("");
|
|
71975
73398
|
}
|
|
71976
73399
|
const bindingCreates = plan.bindings.filter((b) => b.action === "create");
|
|
73400
|
+
const bindingReplaces = plan.bindings.filter((b) => b.action === "replace");
|
|
71977
73401
|
const bindingPrunes = plan.bindings.filter((b) => b.action === "prune");
|
|
71978
|
-
if (bindingCreates.length > 0 || bindingPrunes.length > 0) {
|
|
73402
|
+
if (bindingCreates.length > 0 || bindingReplaces.length > 0 || bindingPrunes.length > 0) {
|
|
71979
73403
|
console.log("Bindings:");
|
|
71980
73404
|
for (const b of bindingCreates) {
|
|
71981
|
-
const scopeLabel = b.binding.
|
|
71982
|
-
console.log(
|
|
73405
|
+
const scopeLabel = b.binding.project_id ? `project: ${b.binding.project_id}` : "org-wide";
|
|
73406
|
+
console.log(
|
|
73407
|
+
` + BIND ${b.roleName} -> ${b.binding.subject.type}:${b.binding.subject.id} (${scopeLabel}, scope=${formatBindingScope(b.binding.scope)})`
|
|
73408
|
+
);
|
|
73409
|
+
}
|
|
73410
|
+
for (const b of bindingReplaces) {
|
|
73411
|
+
const scopeLabel = b.binding.project_id ? `project: ${b.binding.project_id}` : "org-wide";
|
|
73412
|
+
console.log(
|
|
73413
|
+
` ~ REPLACE ${b.roleName} -> ${b.binding.subject.type}:${b.binding.subject.id} (${scopeLabel}): ${b.changes.join("; ")}`
|
|
73414
|
+
);
|
|
71983
73415
|
}
|
|
71984
73416
|
if (bindingPrunes.length > 0) {
|
|
71985
73417
|
if (prune) {
|
|
@@ -71993,9 +73425,11 @@ Access Plan for ${orgId}:
|
|
|
71993
73425
|
}
|
|
71994
73426
|
console.log("");
|
|
71995
73427
|
}
|
|
71996
|
-
const totalUnchanged = plan.unchanged_roles + plan.unchanged_bindings;
|
|
73428
|
+
const totalUnchanged = plan.unchanged_groups + plan.unchanged_group_members + plan.unchanged_roles + plan.unchanged_bindings;
|
|
71997
73429
|
if (totalUnchanged > 0) {
|
|
71998
|
-
console.log(
|
|
73430
|
+
console.log(
|
|
73431
|
+
`Unchanged: ${plan.unchanged_groups} group(s), ${plan.unchanged_group_members} member(s), ${plan.unchanged_roles} role(s), ${plan.unchanged_bindings} binding(s)`
|
|
73432
|
+
);
|
|
71999
73433
|
}
|
|
72000
73434
|
if (!hasChanges(plan, prune)) {
|
|
72001
73435
|
console.log("No changes needed.");
|
|
@@ -72004,6 +73438,52 @@ Access Plan for ${orgId}:
|
|
|
72004
73438
|
function planToJson(plan, orgId) {
|
|
72005
73439
|
return {
|
|
72006
73440
|
org_id: orgId,
|
|
73441
|
+
groups: {
|
|
73442
|
+
create: plan.groups.filter((group) => group.action === "create").map((group) => {
|
|
73443
|
+
const create = group;
|
|
73444
|
+
return {
|
|
73445
|
+
slug: create.slug,
|
|
73446
|
+
name: create.group.name ?? groupDefaultName(create.slug),
|
|
73447
|
+
description: create.group.description ?? null
|
|
73448
|
+
};
|
|
73449
|
+
}),
|
|
73450
|
+
update: plan.groups.filter((group) => group.action === "update").map((group) => {
|
|
73451
|
+
const update = group;
|
|
73452
|
+
return {
|
|
73453
|
+
slug: update.slug,
|
|
73454
|
+
id: update.id,
|
|
73455
|
+
changes: update.changes
|
|
73456
|
+
};
|
|
73457
|
+
}),
|
|
73458
|
+
prune: plan.groups.filter((group) => group.action === "prune").map((group) => {
|
|
73459
|
+
const prune = group;
|
|
73460
|
+
return {
|
|
73461
|
+
slug: prune.slug,
|
|
73462
|
+
id: prune.id
|
|
73463
|
+
};
|
|
73464
|
+
}),
|
|
73465
|
+
unchanged: plan.unchanged_groups
|
|
73466
|
+
},
|
|
73467
|
+
group_members: {
|
|
73468
|
+
add: plan.group_members.filter((member) => member.action === "add").map((member) => {
|
|
73469
|
+
const add = member;
|
|
73470
|
+
return {
|
|
73471
|
+
group_slug: add.groupSlug,
|
|
73472
|
+
principal_type: add.member.type,
|
|
73473
|
+
principal_id: add.member.id
|
|
73474
|
+
};
|
|
73475
|
+
}),
|
|
73476
|
+
remove: plan.group_members.filter((member) => member.action === "remove").map((member) => {
|
|
73477
|
+
const remove = member;
|
|
73478
|
+
return {
|
|
73479
|
+
group_slug: remove.groupSlug,
|
|
73480
|
+
group_id: remove.groupId,
|
|
73481
|
+
principal_type: remove.member.principal_type,
|
|
73482
|
+
principal_id: remove.member.principal_id
|
|
73483
|
+
};
|
|
73484
|
+
}),
|
|
73485
|
+
unchanged: plan.unchanged_group_members
|
|
73486
|
+
},
|
|
72007
73487
|
roles: {
|
|
72008
73488
|
create: plan.roles.filter((r) => r.action === "create").map((r) => {
|
|
72009
73489
|
const cr = r;
|
|
@@ -72026,10 +73506,22 @@ function planToJson(plan, orgId) {
|
|
|
72026
73506
|
role: cb.roleName,
|
|
72027
73507
|
subject_type: cb.binding.subject.type,
|
|
72028
73508
|
subject_id: cb.binding.subject.id,
|
|
72029
|
-
scope: cb.binding.scope,
|
|
73509
|
+
scope: normalizeBindingScope(cb.binding.scope) ?? null,
|
|
72030
73510
|
project_id: cb.binding.project_id
|
|
72031
73511
|
};
|
|
72032
73512
|
}),
|
|
73513
|
+
replace: plan.bindings.filter((b) => b.action === "replace").map((b) => {
|
|
73514
|
+
const rb = b;
|
|
73515
|
+
return {
|
|
73516
|
+
id: rb.existing.id,
|
|
73517
|
+
role: rb.roleName,
|
|
73518
|
+
subject_type: rb.binding.subject.type,
|
|
73519
|
+
subject_id: rb.binding.subject.id,
|
|
73520
|
+
scope: normalizeBindingScope(rb.binding.scope) ?? null,
|
|
73521
|
+
project_id: rb.binding.project_id,
|
|
73522
|
+
changes: rb.changes
|
|
73523
|
+
};
|
|
73524
|
+
}),
|
|
72033
73525
|
prune: plan.bindings.filter((b) => b.action === "prune").map((b) => {
|
|
72034
73526
|
const pb = b;
|
|
72035
73527
|
return {
|
|
@@ -72064,6 +73556,26 @@ ${lines.join("\n")}`);
|
|
|
72064
73556
|
}
|
|
72065
73557
|
printPlan(plan, orgId, false);
|
|
72066
73558
|
}
|
|
73559
|
+
async function fetchOrgGroups(orgId, context2) {
|
|
73560
|
+
const groupsResponse = await requestJson(
|
|
73561
|
+
context2,
|
|
73562
|
+
`/orgs/${orgId}/access/groups`
|
|
73563
|
+
);
|
|
73564
|
+
return unwrapListResponse(groupsResponse);
|
|
73565
|
+
}
|
|
73566
|
+
function resolveBindingPrincipalIdForApply(principalType, principalIdHint, groupIdsBySlug, groupIds) {
|
|
73567
|
+
if (principalType !== "group") {
|
|
73568
|
+
return principalIdHint;
|
|
73569
|
+
}
|
|
73570
|
+
if (groupIds.has(principalIdHint)) {
|
|
73571
|
+
return principalIdHint;
|
|
73572
|
+
}
|
|
73573
|
+
const fromSlug = groupIdsBySlug.get(principalIdHint);
|
|
73574
|
+
if (fromSlug) {
|
|
73575
|
+
return fromSlug;
|
|
73576
|
+
}
|
|
73577
|
+
throw new Error(`Group '${principalIdHint}' does not exist in the target org`);
|
|
73578
|
+
}
|
|
72067
73579
|
async function handleSync(flags, context2, json) {
|
|
72068
73580
|
const orgId = getStringFlag(flags, ["org"]) ?? context2.orgId;
|
|
72069
73581
|
if (!orgId) {
|
|
@@ -72103,10 +73615,16 @@ ${lines.join("\n")}`);
|
|
|
72103
73615
|
}
|
|
72104
73616
|
}
|
|
72105
73617
|
const applied = {
|
|
73618
|
+
groups_created: 0,
|
|
73619
|
+
groups_updated: 0,
|
|
73620
|
+
groups_deleted: 0,
|
|
73621
|
+
group_members_added: 0,
|
|
73622
|
+
group_members_removed: 0,
|
|
72106
73623
|
roles_created: 0,
|
|
72107
73624
|
roles_updated: 0,
|
|
72108
73625
|
roles_deleted: 0,
|
|
72109
73626
|
bindings_created: 0,
|
|
73627
|
+
bindings_replaced: 0,
|
|
72110
73628
|
bindings_deleted: 0
|
|
72111
73629
|
};
|
|
72112
73630
|
for (const ra of plan.roles) {
|
|
@@ -72146,25 +73664,123 @@ ${lines.join("\n")}`);
|
|
|
72146
73664
|
if (!json) console.log(` ~ Updated role '${ra.name}'`);
|
|
72147
73665
|
}
|
|
72148
73666
|
}
|
|
72149
|
-
for (const
|
|
72150
|
-
if (
|
|
72151
|
-
const
|
|
72152
|
-
|
|
72153
|
-
|
|
72154
|
-
|
|
73667
|
+
for (const ga of plan.groups) {
|
|
73668
|
+
if (ga.action === "create") {
|
|
73669
|
+
const payload = {
|
|
73670
|
+
name: ga.group.name ?? groupDefaultName(ga.slug),
|
|
73671
|
+
slug: ga.slug,
|
|
73672
|
+
description: ga.group.description
|
|
73673
|
+
};
|
|
73674
|
+
await requestJson(
|
|
73675
|
+
context2,
|
|
73676
|
+
`/orgs/${orgId}/access/groups`,
|
|
73677
|
+
{
|
|
73678
|
+
method: "POST",
|
|
73679
|
+
body: payload
|
|
73680
|
+
}
|
|
73681
|
+
);
|
|
73682
|
+
applied.groups_created++;
|
|
73683
|
+
if (!json) console.log(` + Created group '${ga.slug}'`);
|
|
73684
|
+
continue;
|
|
73685
|
+
}
|
|
73686
|
+
if (ga.action === "update") {
|
|
73687
|
+
const payload = {
|
|
73688
|
+
name: ga.group.name ?? groupDefaultName(ga.slug),
|
|
73689
|
+
description: ga.group.description ?? null
|
|
72155
73690
|
};
|
|
72156
|
-
|
|
72157
|
-
|
|
73691
|
+
await requestJson(
|
|
73692
|
+
context2,
|
|
73693
|
+
`/orgs/${orgId}/access/groups/${encodeURIComponent(ga.id)}`,
|
|
73694
|
+
{
|
|
73695
|
+
method: "PATCH",
|
|
73696
|
+
body: payload
|
|
73697
|
+
}
|
|
73698
|
+
);
|
|
73699
|
+
applied.groups_updated++;
|
|
73700
|
+
if (!json) console.log(` ~ Updated group '${ga.slug}'`);
|
|
73701
|
+
}
|
|
73702
|
+
}
|
|
73703
|
+
const groupsAfterCreateUpdate = await fetchOrgGroups(orgId, context2);
|
|
73704
|
+
const groupIdsBySlug = new Map(groupsAfterCreateUpdate.map((group) => [group.slug, group.id]));
|
|
73705
|
+
const groupIds = new Set(groupsAfterCreateUpdate.map((group) => group.id));
|
|
73706
|
+
for (const ma of plan.group_members) {
|
|
73707
|
+
if (ma.action === "add") {
|
|
73708
|
+
const groupId2 = groupIdsBySlug.get(ma.groupSlug);
|
|
73709
|
+
if (!groupId2) {
|
|
73710
|
+
throw new Error(`Cannot add member: group '${ma.groupSlug}' does not exist in org '${orgId}'`);
|
|
72158
73711
|
}
|
|
72159
73712
|
await requestJson(
|
|
72160
73713
|
context2,
|
|
72161
|
-
`/orgs/${orgId}/access/
|
|
72162
|
-
{
|
|
73714
|
+
`/orgs/${orgId}/access/groups/${encodeURIComponent(groupId2)}/members`,
|
|
73715
|
+
{
|
|
73716
|
+
method: "POST",
|
|
73717
|
+
body: {
|
|
73718
|
+
principal_type: ma.member.type,
|
|
73719
|
+
principal_id: ma.member.id
|
|
73720
|
+
}
|
|
73721
|
+
}
|
|
73722
|
+
);
|
|
73723
|
+
applied.group_members_added++;
|
|
73724
|
+
if (!json) console.log(` + Added ${ma.member.type}:${ma.member.id} to group '${ma.groupSlug}'`);
|
|
73725
|
+
continue;
|
|
73726
|
+
}
|
|
73727
|
+
const groupId = groupIdsBySlug.get(ma.groupSlug) ?? ma.groupId;
|
|
73728
|
+
await requestJson(
|
|
73729
|
+
context2,
|
|
73730
|
+
`/orgs/${orgId}/access/groups/${encodeURIComponent(groupId)}/members/${ma.member.principal_type}/${encodeURIComponent(ma.member.principal_id)}`,
|
|
73731
|
+
{ method: "DELETE" }
|
|
73732
|
+
);
|
|
73733
|
+
applied.group_members_removed++;
|
|
73734
|
+
if (!json) console.log(` - Removed ${ma.member.principal_type}:${ma.member.principal_id} from group '${ma.groupSlug}'`);
|
|
73735
|
+
}
|
|
73736
|
+
for (const ba of plan.bindings) {
|
|
73737
|
+
if (ba.action !== "create" && ba.action !== "replace") {
|
|
73738
|
+
continue;
|
|
73739
|
+
}
|
|
73740
|
+
const principalId = resolveBindingPrincipalIdForApply(
|
|
73741
|
+
ba.binding.subject.type,
|
|
73742
|
+
ba.principalIdHint,
|
|
73743
|
+
groupIdsBySlug,
|
|
73744
|
+
groupIds
|
|
73745
|
+
);
|
|
73746
|
+
if (ba.action === "replace") {
|
|
73747
|
+
await requestJson(
|
|
73748
|
+
context2,
|
|
73749
|
+
`/orgs/${orgId}/access/bindings/${ba.existing.id}`,
|
|
73750
|
+
{ method: "DELETE" }
|
|
72163
73751
|
);
|
|
73752
|
+
}
|
|
73753
|
+
const body = {
|
|
73754
|
+
role_name: ba.roleName,
|
|
73755
|
+
principal_type: ba.binding.subject.type,
|
|
73756
|
+
principal_id: principalId
|
|
73757
|
+
};
|
|
73758
|
+
if (ba.binding.project_id) {
|
|
73759
|
+
body.project_id = ba.binding.project_id;
|
|
73760
|
+
}
|
|
73761
|
+
const normalizedScope = normalizeBindingScope(ba.binding.scope);
|
|
73762
|
+
if (normalizedScope) {
|
|
73763
|
+
body.scope_json = normalizedScope;
|
|
73764
|
+
}
|
|
73765
|
+
await requestJson(
|
|
73766
|
+
context2,
|
|
73767
|
+
`/orgs/${orgId}/access/bindings`,
|
|
73768
|
+
{ method: "POST", body }
|
|
73769
|
+
);
|
|
73770
|
+
const scopeLabel = ba.binding.project_id ? `project: ${ba.binding.project_id}` : "org-wide";
|
|
73771
|
+
if (ba.action === "create") {
|
|
72164
73772
|
applied.bindings_created++;
|
|
72165
73773
|
if (!json) {
|
|
72166
|
-
|
|
72167
|
-
|
|
73774
|
+
console.log(
|
|
73775
|
+
` + Bound ${ba.roleName} -> ${ba.binding.subject.type}:${principalId} (${scopeLabel}, scope=${formatBindingScope(ba.binding.scope)})`
|
|
73776
|
+
);
|
|
73777
|
+
}
|
|
73778
|
+
} else {
|
|
73779
|
+
applied.bindings_replaced++;
|
|
73780
|
+
if (!json) {
|
|
73781
|
+
console.log(
|
|
73782
|
+
` ~ Rebound ${ba.roleName} -> ${ba.binding.subject.type}:${principalId} (${scopeLabel}, scope=${formatBindingScope(ba.binding.scope)})`
|
|
73783
|
+
);
|
|
72168
73784
|
}
|
|
72169
73785
|
}
|
|
72170
73786
|
}
|
|
@@ -72183,6 +73799,17 @@ ${lines.join("\n")}`);
|
|
|
72183
73799
|
}
|
|
72184
73800
|
}
|
|
72185
73801
|
}
|
|
73802
|
+
for (const ga of plan.groups) {
|
|
73803
|
+
if (ga.action === "prune") {
|
|
73804
|
+
await requestJson(
|
|
73805
|
+
context2,
|
|
73806
|
+
`/orgs/${orgId}/access/groups/${encodeURIComponent(ga.id)}`,
|
|
73807
|
+
{ method: "DELETE" }
|
|
73808
|
+
);
|
|
73809
|
+
applied.groups_deleted++;
|
|
73810
|
+
if (!json) console.log(` - Deleted group '${ga.slug}'`);
|
|
73811
|
+
}
|
|
73812
|
+
}
|
|
72186
73813
|
for (const ra of plan.roles) {
|
|
72187
73814
|
if (ra.action === "prune") {
|
|
72188
73815
|
await requestJson(
|
|
@@ -72200,18 +73827,24 @@ ${lines.join("\n")}`);
|
|
|
72200
73827
|
return;
|
|
72201
73828
|
}
|
|
72202
73829
|
const parts = [];
|
|
73830
|
+
if (applied.groups_created > 0) parts.push(`${applied.groups_created} group(s) created`);
|
|
73831
|
+
if (applied.groups_updated > 0) parts.push(`${applied.groups_updated} group(s) updated`);
|
|
73832
|
+
if (applied.groups_deleted > 0) parts.push(`${applied.groups_deleted} group(s) deleted`);
|
|
73833
|
+
if (applied.group_members_added > 0) parts.push(`${applied.group_members_added} group member(s) added`);
|
|
73834
|
+
if (applied.group_members_removed > 0) parts.push(`${applied.group_members_removed} group member(s) removed`);
|
|
72203
73835
|
if (applied.roles_created > 0) parts.push(`${applied.roles_created} role(s) created`);
|
|
72204
73836
|
if (applied.roles_updated > 0) parts.push(`${applied.roles_updated} role(s) updated`);
|
|
72205
73837
|
if (applied.roles_deleted > 0) parts.push(`${applied.roles_deleted} role(s) deleted`);
|
|
72206
73838
|
if (applied.bindings_created > 0) parts.push(`${applied.bindings_created} binding(s) created`);
|
|
73839
|
+
if (applied.bindings_replaced > 0) parts.push(`${applied.bindings_replaced} binding(s) replaced`);
|
|
72207
73840
|
if (applied.bindings_deleted > 0) parts.push(`${applied.bindings_deleted} binding(s) deleted`);
|
|
72208
73841
|
console.log(`
|
|
72209
73842
|
Sync complete: ${parts.join(", ")}`);
|
|
72210
73843
|
}
|
|
72211
73844
|
|
|
72212
73845
|
// src/commands/docs.ts
|
|
72213
|
-
var
|
|
72214
|
-
var
|
|
73846
|
+
var import_node_fs16 = require("node:fs");
|
|
73847
|
+
var import_node_path16 = require("node:path");
|
|
72215
73848
|
function encodeDocPathParam(path6) {
|
|
72216
73849
|
const trimmed = path6.startsWith("/") ? path6.slice(1) : path6;
|
|
72217
73850
|
return encodeURIComponent(trimmed);
|
|
@@ -72270,9 +73903,9 @@ async function handleDocs(subcommand, positionals, flags, context2) {
|
|
|
72270
73903
|
const filePath = getStringFlag(flags, ["file"]);
|
|
72271
73904
|
const useStdin = flags.stdin === true || flags.stdin === "true";
|
|
72272
73905
|
if (filePath) {
|
|
72273
|
-
content = (0,
|
|
73906
|
+
content = (0, import_node_fs16.readFileSync)((0, import_node_path16.resolve)(filePath), "utf-8");
|
|
72274
73907
|
} else if (useStdin) {
|
|
72275
|
-
content = (0,
|
|
73908
|
+
content = (0, import_node_fs16.readFileSync)(0, "utf-8");
|
|
72276
73909
|
} else {
|
|
72277
73910
|
throw new Error("Provide --file <path> or --stdin to supply document content");
|
|
72278
73911
|
}
|
|
@@ -72721,6 +74354,9 @@ function formatDuration2(seconds) {
|
|
|
72721
74354
|
function pad(label, value, width = 12) {
|
|
72722
74355
|
return ` ${label.padEnd(width)}${value}`;
|
|
72723
74356
|
}
|
|
74357
|
+
function parseAvgDurationSeconds(stats) {
|
|
74358
|
+
return stats.avg_duration_seconds ?? stats.avg_duration_s ?? 0;
|
|
74359
|
+
}
|
|
72724
74360
|
async function analyticsSummary(flags, context2, orgId) {
|
|
72725
74361
|
const json = Boolean(flags.json);
|
|
72726
74362
|
const window2 = getStringFlag(flags, ["window"]) ?? "7d";
|
|
@@ -72747,7 +74383,7 @@ async function analyticsSummary(flags, context2, orgId) {
|
|
|
72747
74383
|
console.log("Pipelines");
|
|
72748
74384
|
console.log(pad("Runs:", pipelines.runs));
|
|
72749
74385
|
console.log(pad("Success Rate:", `${pipelines.success_rate.toFixed(1)}%`));
|
|
72750
|
-
console.log(pad("Avg Duration:", formatDuration2(pipelines
|
|
74386
|
+
console.log(pad("Avg Duration:", formatDuration2(parseAvgDurationSeconds(pipelines))));
|
|
72751
74387
|
console.log("");
|
|
72752
74388
|
console.log("Environments");
|
|
72753
74389
|
console.log(pad("Total:", environments.total));
|
|
@@ -72766,17 +74402,15 @@ async function analyticsJobs(flags, context2, orgId) {
|
|
|
72766
74402
|
outputJson(data, true);
|
|
72767
74403
|
return;
|
|
72768
74404
|
}
|
|
72769
|
-
console.log(`Job Analytics (${
|
|
74405
|
+
console.log(`Job Analytics (${window2} window)`);
|
|
72770
74406
|
console.log("\u2550".repeat(36));
|
|
72771
|
-
|
|
72772
|
-
|
|
72773
|
-
|
|
72774
|
-
|
|
72775
|
-
|
|
72776
|
-
|
|
72777
|
-
|
|
72778
|
-
console.log(` ${job.id} ${job.phase}${duration}${desc}`);
|
|
72779
|
-
}
|
|
74407
|
+
console.log(pad("As of:", data.as_of));
|
|
74408
|
+
console.log("");
|
|
74409
|
+
console.log("Jobs");
|
|
74410
|
+
console.log(pad("Created:", data.created));
|
|
74411
|
+
console.log(pad("Completed:", data.completed));
|
|
74412
|
+
console.log(pad("Failed:", data.failed));
|
|
74413
|
+
console.log(pad("Active:", data.active));
|
|
72780
74414
|
}
|
|
72781
74415
|
async function analyticsPipelines(flags, context2, orgId) {
|
|
72782
74416
|
const json = Boolean(flags.json);
|
|
@@ -72789,22 +74423,14 @@ async function analyticsPipelines(flags, context2, orgId) {
|
|
|
72789
74423
|
outputJson(data, true);
|
|
72790
74424
|
return;
|
|
72791
74425
|
}
|
|
72792
|
-
console.log(`Pipeline Analytics (${
|
|
74426
|
+
console.log(`Pipeline Analytics (${window2} window)`);
|
|
72793
74427
|
console.log("\u2550".repeat(36));
|
|
72794
|
-
|
|
72795
|
-
|
|
72796
|
-
|
|
72797
|
-
|
|
72798
|
-
|
|
72799
|
-
|
|
72800
|
-
console.log(pad("Runs:", p.runs, 16));
|
|
72801
|
-
console.log(pad("Success Rate:", `${p.success_rate.toFixed(1)}%`, 16));
|
|
72802
|
-
console.log(pad("Avg Duration:", formatDuration2(p.avg_duration_seconds), 16));
|
|
72803
|
-
if (p.last_run_at) {
|
|
72804
|
-
console.log(pad("Last Run:", p.last_run_at, 16));
|
|
72805
|
-
}
|
|
72806
|
-
console.log("");
|
|
72807
|
-
}
|
|
74428
|
+
console.log(pad("As of:", data.as_of));
|
|
74429
|
+
console.log("");
|
|
74430
|
+
console.log("Pipelines");
|
|
74431
|
+
console.log(pad("Runs:", data.runs));
|
|
74432
|
+
console.log(pad("Success Rate:", `${data.success_rate.toFixed(1)}%`));
|
|
74433
|
+
console.log(pad("Avg Duration:", formatDuration2(parseAvgDurationSeconds(data))));
|
|
72808
74434
|
}
|
|
72809
74435
|
async function analyticsEnvHealth(flags, context2, orgId) {
|
|
72810
74436
|
const json = Boolean(flags.json);
|
|
@@ -72818,15 +74444,12 @@ async function analyticsEnvHealth(flags, context2, orgId) {
|
|
|
72818
74444
|
}
|
|
72819
74445
|
console.log("Environment Health");
|
|
72820
74446
|
console.log("\u2550".repeat(36));
|
|
72821
|
-
|
|
72822
|
-
|
|
72823
|
-
|
|
72824
|
-
|
|
72825
|
-
|
|
72826
|
-
|
|
72827
|
-
const pods = env.pod_count != null ? ` pods: ${env.pod_count}` : "";
|
|
72828
|
-
console.log(` ${env.name} [${env.status}]${pods}${lastDeploy}`);
|
|
72829
|
-
}
|
|
74447
|
+
console.log("");
|
|
74448
|
+
console.log(pad("As of:", data.as_of));
|
|
74449
|
+
console.log(pad("Total:", data.total));
|
|
74450
|
+
console.log(pad("Healthy:", data.healthy));
|
|
74451
|
+
console.log(pad("Degraded:", data.degraded));
|
|
74452
|
+
console.log(pad("Unknown:", data.unknown));
|
|
72830
74453
|
}
|
|
72831
74454
|
async function handleAnalytics(subcommand, _positionals, flags, context2) {
|
|
72832
74455
|
const orgId = getStringFlag(flags, ["org", "org-id", "org_id"]) ?? context2.orgId;
|
|
@@ -72844,7 +74467,7 @@ async function handleAnalytics(subcommand, _positionals, flags, context2) {
|
|
|
72844
74467
|
return analyticsEnvHealth(flags, context2, orgId);
|
|
72845
74468
|
default:
|
|
72846
74469
|
throw new Error(
|
|
72847
|
-
"Usage: eve analytics <summary|jobs|pipelines|env-health>\n\n summary Org-wide activity summary\n jobs Job
|
|
74470
|
+
"Usage: eve analytics <summary|jobs|pipelines|env-health>\n\n summary Org-wide activity summary\n jobs Job counters for the window\n pipelines Pipeline success rates and durations\n env-health Current environment health snapshot"
|
|
72848
74471
|
);
|
|
72849
74472
|
}
|
|
72850
74473
|
}
|
|
@@ -73217,6 +74840,284 @@ async function handleOllama(subcommand, positionals, flags, context2) {
|
|
|
73217
74840
|
}
|
|
73218
74841
|
}
|
|
73219
74842
|
|
|
74843
|
+
// src/commands/fs.ts
|
|
74844
|
+
var import_promises = require("node:fs/promises");
|
|
74845
|
+
var import_node_fs17 = require("node:fs");
|
|
74846
|
+
var import_node_os5 = require("node:os");
|
|
74847
|
+
function getOrgOrThrow(flags, context2) {
|
|
74848
|
+
const orgId = getStringFlag(flags, ["org", "org-id", "org_id"]) ?? context2.orgId;
|
|
74849
|
+
if (!orgId) {
|
|
74850
|
+
throw new Error("Missing org id. Provide --org or set a profile default.");
|
|
74851
|
+
}
|
|
74852
|
+
return orgId;
|
|
74853
|
+
}
|
|
74854
|
+
function parseModeFlag(value) {
|
|
74855
|
+
const raw = (value ?? "two-way").trim().toLowerCase();
|
|
74856
|
+
if (raw === "two-way" || raw === "two_way") return "two_way";
|
|
74857
|
+
if (raw === "push-only" || raw === "push_only") return "push_only";
|
|
74858
|
+
if (raw === "pull-only" || raw === "pull_only") return "pull_only";
|
|
74859
|
+
throw new Error(`Invalid mode: ${value}. Use two-way, push-only, or pull-only.`);
|
|
74860
|
+
}
|
|
74861
|
+
function parseStrategyFlag(value) {
|
|
74862
|
+
const raw = (value ?? "").trim().toLowerCase();
|
|
74863
|
+
if (raw === "pick-local" || raw === "pick_local") return "pick_local";
|
|
74864
|
+
if (raw === "pick-remote" || raw === "pick_remote") return "pick_remote";
|
|
74865
|
+
if (raw === "manual") return "manual";
|
|
74866
|
+
throw new Error(`Invalid strategy: ${value}. Use pick-local, pick-remote, or manual.`);
|
|
74867
|
+
}
|
|
74868
|
+
function parseGlobList(value) {
|
|
74869
|
+
if (!value) return void 0;
|
|
74870
|
+
return value.split(",").map((item) => item.trim()).filter(Boolean);
|
|
74871
|
+
}
|
|
74872
|
+
async function resolveLinkId(context2, orgId, flags) {
|
|
74873
|
+
const explicit = getStringFlag(flags, ["link", "link-id", "link_id"]);
|
|
74874
|
+
const links = await requestJson(context2, `/orgs/${orgId}/fs/links`);
|
|
74875
|
+
if (explicit) {
|
|
74876
|
+
const found = links.data.find((item) => item.id === explicit);
|
|
74877
|
+
if (!found) {
|
|
74878
|
+
throw new Error(`Link not found: ${explicit}`);
|
|
74879
|
+
}
|
|
74880
|
+
return found.id;
|
|
74881
|
+
}
|
|
74882
|
+
if (links.data.length === 0) {
|
|
74883
|
+
throw new Error("No sync links found. Run: eve fs sync init --org <org> --local <path>");
|
|
74884
|
+
}
|
|
74885
|
+
return links.data[0].id;
|
|
74886
|
+
}
|
|
74887
|
+
async function streamFsEvents(context2, orgId, afterSeq) {
|
|
74888
|
+
const headers = {
|
|
74889
|
+
Accept: "text/event-stream"
|
|
74890
|
+
};
|
|
74891
|
+
if (context2.token) {
|
|
74892
|
+
headers.Authorization = `Bearer ${context2.token}`;
|
|
74893
|
+
}
|
|
74894
|
+
const response = await fetch(`${context2.apiUrl}/orgs/${orgId}/fs/events/stream?after_seq=${afterSeq}`, {
|
|
74895
|
+
method: "GET",
|
|
74896
|
+
headers
|
|
74897
|
+
});
|
|
74898
|
+
if (!response.ok || !response.body) {
|
|
74899
|
+
const body = await response.text();
|
|
74900
|
+
throw new Error(`HTTP ${response.status}: ${body}`);
|
|
74901
|
+
}
|
|
74902
|
+
const reader = response.body.getReader();
|
|
74903
|
+
const decoder = new TextDecoder();
|
|
74904
|
+
let buffer = "";
|
|
74905
|
+
let currentEvent = "";
|
|
74906
|
+
let currentData = "";
|
|
74907
|
+
while (true) {
|
|
74908
|
+
const { done, value } = await reader.read();
|
|
74909
|
+
if (done) break;
|
|
74910
|
+
buffer += decoder.decode(value, { stream: true });
|
|
74911
|
+
const events = buffer.split("\n\n");
|
|
74912
|
+
buffer = events.pop() ?? "";
|
|
74913
|
+
for (const eventBlock of events) {
|
|
74914
|
+
const lines = eventBlock.split("\n");
|
|
74915
|
+
for (const line of lines) {
|
|
74916
|
+
if (line.startsWith("event:")) {
|
|
74917
|
+
currentEvent = line.slice(6).trim();
|
|
74918
|
+
} else if (line.startsWith("data:")) {
|
|
74919
|
+
currentData += `${line.slice(5).trim()}
|
|
74920
|
+
`;
|
|
74921
|
+
}
|
|
74922
|
+
}
|
|
74923
|
+
if (currentData) {
|
|
74924
|
+
const payload = currentData.trim();
|
|
74925
|
+
if (currentEvent === "fs_event") {
|
|
74926
|
+
try {
|
|
74927
|
+
const parsed = JSON.parse(payload);
|
|
74928
|
+
console.log(`[${parsed.seq}] ${parsed.event_type} ${parsed.path} (${parsed.source_side}) ${parsed.created_at}`);
|
|
74929
|
+
} catch {
|
|
74930
|
+
console.log(payload);
|
|
74931
|
+
}
|
|
74932
|
+
} else if (currentEvent === "error") {
|
|
74933
|
+
console.error(payload);
|
|
74934
|
+
}
|
|
74935
|
+
}
|
|
74936
|
+
currentEvent = "";
|
|
74937
|
+
currentData = "";
|
|
74938
|
+
}
|
|
74939
|
+
}
|
|
74940
|
+
}
|
|
74941
|
+
async function handleSync2(action, positionals, flags, context2) {
|
|
74942
|
+
const json = Boolean(flags.json);
|
|
74943
|
+
const orgId = getOrgOrThrow(flags, context2);
|
|
74944
|
+
switch (action) {
|
|
74945
|
+
case "init": {
|
|
74946
|
+
const localPath = getStringFlag(flags, ["local", "path"]);
|
|
74947
|
+
if (!localPath) {
|
|
74948
|
+
throw new Error("Usage: eve fs sync init --org <org_id> --local <path> [--mode two-way]");
|
|
74949
|
+
}
|
|
74950
|
+
const mode = parseModeFlag(getStringFlag(flags, ["mode"]));
|
|
74951
|
+
const includes = parseGlobList(getStringFlag(flags, ["include", "includes"]));
|
|
74952
|
+
const excludes = parseGlobList(getStringFlag(flags, ["exclude", "excludes"]));
|
|
74953
|
+
const publicKey = getStringFlag(flags, ["public-key", "public_key"]);
|
|
74954
|
+
const enroll = await requestJson(context2, `/orgs/${orgId}/fs/devices/enroll`, {
|
|
74955
|
+
method: "POST",
|
|
74956
|
+
body: {
|
|
74957
|
+
device_name: getStringFlag(flags, ["device-name", "device_name"]) ?? (0, import_node_os5.hostname)(),
|
|
74958
|
+
platform: process.platform,
|
|
74959
|
+
client_version: "dev",
|
|
74960
|
+
...publicKey ? { public_key: publicKey } : {}
|
|
74961
|
+
}
|
|
74962
|
+
});
|
|
74963
|
+
const link = await requestJson(context2, `/orgs/${orgId}/fs/links`, {
|
|
74964
|
+
method: "POST",
|
|
74965
|
+
body: {
|
|
74966
|
+
device_id: enroll.device.id,
|
|
74967
|
+
mode,
|
|
74968
|
+
local_path: localPath,
|
|
74969
|
+
remote_path: getStringFlag(flags, ["remote-path", "remote_path"]) ?? "/",
|
|
74970
|
+
...includes ? { includes } : {},
|
|
74971
|
+
...excludes ? { excludes } : {}
|
|
74972
|
+
}
|
|
74973
|
+
});
|
|
74974
|
+
outputJson({
|
|
74975
|
+
device: enroll.device,
|
|
74976
|
+
enrollment: enroll.enrollment,
|
|
74977
|
+
link: link.link,
|
|
74978
|
+
runtime: link.runtime
|
|
74979
|
+
}, json, `Sync initialized for ${orgId}`);
|
|
74980
|
+
return;
|
|
74981
|
+
}
|
|
74982
|
+
case "status": {
|
|
74983
|
+
const [status, links] = await Promise.all([
|
|
74984
|
+
requestJson(context2, `/orgs/${orgId}/fs/status`),
|
|
74985
|
+
requestJson(context2, `/orgs/${orgId}/fs/links`)
|
|
74986
|
+
]);
|
|
74987
|
+
if (json) {
|
|
74988
|
+
outputJson({ ...status, links_detail: links.data }, true);
|
|
74989
|
+
return;
|
|
74990
|
+
}
|
|
74991
|
+
console.log(`Org: ${orgId}`);
|
|
74992
|
+
console.log(`Gateway: ${status.gateway.status}`);
|
|
74993
|
+
if (status.gateway.last_heartbeat_at) console.log(`Last heartbeat: ${status.gateway.last_heartbeat_at}`);
|
|
74994
|
+
console.log(`Links: active=${status.links.active} paused=${status.links.paused} revoked=${status.links.revoked}`);
|
|
74995
|
+
console.log(`Latest seq: ${status.events.latest_seq}`);
|
|
74996
|
+
if (links.data.length > 0) {
|
|
74997
|
+
console.log("");
|
|
74998
|
+
for (const link of links.data) {
|
|
74999
|
+
console.log(`${link.id} ${link.mode} ${link.status} cursor=${link.last_cursor} lag_ms=${link.lag_ms ?? "n/a"} backlog=${link.backlog ?? 0}`);
|
|
75000
|
+
}
|
|
75001
|
+
}
|
|
75002
|
+
return;
|
|
75003
|
+
}
|
|
75004
|
+
case "logs": {
|
|
75005
|
+
const afterSeq = Number(getStringFlag(flags, ["after", "after-seq", "after_seq"]) ?? "0");
|
|
75006
|
+
const limit = Number(getStringFlag(flags, ["limit"]) ?? "200");
|
|
75007
|
+
const follow = flags.follow === true || flags.follow === "true";
|
|
75008
|
+
if (follow) {
|
|
75009
|
+
await streamFsEvents(context2, orgId, Number.isFinite(afterSeq) ? afterSeq : 0);
|
|
75010
|
+
return;
|
|
75011
|
+
}
|
|
75012
|
+
const events = await requestJson(
|
|
75013
|
+
context2,
|
|
75014
|
+
`/orgs/${orgId}/fs/events?after_seq=${Number.isFinite(afterSeq) ? afterSeq : 0}&limit=${Number.isFinite(limit) ? limit : 200}`
|
|
75015
|
+
);
|
|
75016
|
+
outputJson(events, json);
|
|
75017
|
+
return;
|
|
75018
|
+
}
|
|
75019
|
+
case "pause":
|
|
75020
|
+
case "resume":
|
|
75021
|
+
case "disconnect": {
|
|
75022
|
+
const linkId = await resolveLinkId(context2, orgId, flags);
|
|
75023
|
+
const nextStatus = action === "pause" ? "paused" : action === "resume" ? "active" : "revoked";
|
|
75024
|
+
const updated = await requestJson(context2, `/orgs/${orgId}/fs/links/${linkId}`, {
|
|
75025
|
+
method: "PATCH",
|
|
75026
|
+
body: { status: nextStatus }
|
|
75027
|
+
});
|
|
75028
|
+
outputJson(updated, json, `Link ${linkId} ${nextStatus}`);
|
|
75029
|
+
return;
|
|
75030
|
+
}
|
|
75031
|
+
case "mode": {
|
|
75032
|
+
const modeValue = getStringFlag(flags, ["set", "mode"]);
|
|
75033
|
+
if (!modeValue) {
|
|
75034
|
+
throw new Error("Usage: eve fs sync mode --org <org_id> --set <two-way|push-only|pull-only>");
|
|
75035
|
+
}
|
|
75036
|
+
const linkId = await resolveLinkId(context2, orgId, flags);
|
|
75037
|
+
const updated = await requestJson(context2, `/orgs/${orgId}/fs/links/${linkId}`, {
|
|
75038
|
+
method: "PATCH",
|
|
75039
|
+
body: { mode: parseModeFlag(modeValue) }
|
|
75040
|
+
});
|
|
75041
|
+
outputJson(updated, json, `Link ${linkId} mode updated`);
|
|
75042
|
+
return;
|
|
75043
|
+
}
|
|
75044
|
+
case "conflicts": {
|
|
75045
|
+
const openOnly = flags["open-only"] === true || flags["open_only"] === true || flags["open-only"] === "true" || flags["open_only"] === "true";
|
|
75046
|
+
const result = await requestJson(
|
|
75047
|
+
context2,
|
|
75048
|
+
`/orgs/${orgId}/fs/conflicts${openOnly ? "?open_only=true" : ""}`
|
|
75049
|
+
);
|
|
75050
|
+
outputJson(result, json);
|
|
75051
|
+
return;
|
|
75052
|
+
}
|
|
75053
|
+
case "resolve": {
|
|
75054
|
+
const conflictId = getStringFlag(flags, ["conflict", "conflict-id", "conflict_id"]) ?? positionals[0];
|
|
75055
|
+
if (!conflictId) {
|
|
75056
|
+
throw new Error("Usage: eve fs sync resolve --org <org_id> --conflict <conflict_id> --strategy <pick-remote|pick-local|manual>");
|
|
75057
|
+
}
|
|
75058
|
+
const strategy = parseStrategyFlag(getStringFlag(flags, ["strategy"]));
|
|
75059
|
+
const mergedContent = getStringFlag(flags, ["merged-content", "merged_content"]);
|
|
75060
|
+
const result = await requestJson(context2, `/orgs/${orgId}/fs/conflicts/${conflictId}/resolve`, {
|
|
75061
|
+
method: "POST",
|
|
75062
|
+
body: {
|
|
75063
|
+
strategy,
|
|
75064
|
+
...mergedContent ? { merged_content: mergedContent } : {}
|
|
75065
|
+
}
|
|
75066
|
+
});
|
|
75067
|
+
outputJson(result, json, `Conflict ${conflictId} resolved`);
|
|
75068
|
+
return;
|
|
75069
|
+
}
|
|
75070
|
+
case "doctor": {
|
|
75071
|
+
const status = await requestJson(context2, `/orgs/${orgId}/fs/status`);
|
|
75072
|
+
const links = await requestJson(context2, `/orgs/${orgId}/fs/links`);
|
|
75073
|
+
const health = {
|
|
75074
|
+
auth: "ok",
|
|
75075
|
+
gateway_status: status.gateway.status,
|
|
75076
|
+
links: links.data.length,
|
|
75077
|
+
active_links: links.data.filter((item) => item.status === "active").length,
|
|
75078
|
+
cursor_drift: 0,
|
|
75079
|
+
local_path_checks: []
|
|
75080
|
+
};
|
|
75081
|
+
if (links.data.length > 0) {
|
|
75082
|
+
const minCursor = links.data.reduce((min, item) => Math.min(min, item.last_cursor), Number.POSITIVE_INFINITY);
|
|
75083
|
+
const cursorBase = Number.isFinite(minCursor) ? minCursor : 0;
|
|
75084
|
+
health.cursor_drift = Math.max(0, status.events.latest_seq - cursorBase);
|
|
75085
|
+
}
|
|
75086
|
+
for (const link of links.data) {
|
|
75087
|
+
let writable = false;
|
|
75088
|
+
try {
|
|
75089
|
+
await (0, import_promises.access)(link.local_path, import_node_fs17.constants.R_OK | import_node_fs17.constants.W_OK);
|
|
75090
|
+
writable = true;
|
|
75091
|
+
} catch {
|
|
75092
|
+
writable = false;
|
|
75093
|
+
}
|
|
75094
|
+
health.local_path_checks.push({
|
|
75095
|
+
link_id: link.id,
|
|
75096
|
+
local_path: link.local_path,
|
|
75097
|
+
writable
|
|
75098
|
+
});
|
|
75099
|
+
}
|
|
75100
|
+
outputJson(health, json, `FS sync doctor completed for ${orgId}`);
|
|
75101
|
+
return;
|
|
75102
|
+
}
|
|
75103
|
+
default:
|
|
75104
|
+
throw new Error(
|
|
75105
|
+
"Usage: eve fs sync <init|status|logs|pause|resume|disconnect|mode|conflicts|resolve|doctor>\n\n init --org <org> --local <path> [--mode two-way|push-only|pull-only]\n status --org <org>\n logs --org <org> [--after N] [--limit N] [--follow]\n pause --org <org> [--link <link_id>]\n resume --org <org> [--link <link_id>]\n disconnect --org <org> [--link <link_id>]\n mode --org <org> --set <two-way|push-only|pull-only> [--link <link_id>]\n conflicts --org <org> [--open-only]\n resolve --org <org> --conflict <id> --strategy <pick-remote|pick-local|manual>\n doctor --org <org>"
|
|
75106
|
+
);
|
|
75107
|
+
}
|
|
75108
|
+
}
|
|
75109
|
+
async function handleFs(subcommand, positionals, flags, context2) {
|
|
75110
|
+
switch (subcommand) {
|
|
75111
|
+
case "sync": {
|
|
75112
|
+
const action = positionals[0];
|
|
75113
|
+
await handleSync2(action, positionals.slice(1), flags, context2);
|
|
75114
|
+
return;
|
|
75115
|
+
}
|
|
75116
|
+
default:
|
|
75117
|
+
throw new Error("Usage: eve fs sync <init|status|logs|pause|resume|disconnect|mode|conflicts|resolve|doctor>");
|
|
75118
|
+
}
|
|
75119
|
+
}
|
|
75120
|
+
|
|
73220
75121
|
// src/index.ts
|
|
73221
75122
|
async function main() {
|
|
73222
75123
|
const { flags, positionals } = parseArgs(process.argv.slice(2));
|
|
@@ -73343,6 +75244,9 @@ async function main() {
|
|
|
73343
75244
|
case "ollama":
|
|
73344
75245
|
await handleOllama(subcommand, rest, flags, context2);
|
|
73345
75246
|
return;
|
|
75247
|
+
case "fs":
|
|
75248
|
+
await handleFs(subcommand, rest, flags, context2);
|
|
75249
|
+
return;
|
|
73346
75250
|
default:
|
|
73347
75251
|
showMainHelp();
|
|
73348
75252
|
}
|