@odla-ai/cli 0.25.20 → 0.25.21
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/README.md +12 -0
- package/dist/bin.cjs +733 -616
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-ONETPJFW.js → chunk-L2NG4UR4.js} +734 -617
- package/dist/chunk-L2NG4UR4.js.map +1 -0
- package/dist/index.cjs +733 -616
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-ONETPJFW.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -142,22 +142,22 @@ function readJsonFile(path) {
|
|
|
142
142
|
return null;
|
|
143
143
|
}
|
|
144
144
|
}
|
|
145
|
-
function writePrivateJson(path,
|
|
146
|
-
writePrivateText(path, `${JSON.stringify(
|
|
145
|
+
function writePrivateJson(path, value2) {
|
|
146
|
+
writePrivateText(path, `${JSON.stringify(value2, null, 2)}
|
|
147
147
|
`);
|
|
148
148
|
}
|
|
149
149
|
function readCredentials(path) {
|
|
150
150
|
if (!(0, import_node_fs.existsSync)(path)) return null;
|
|
151
|
-
let
|
|
151
|
+
let value2;
|
|
152
152
|
try {
|
|
153
|
-
|
|
153
|
+
value2 = JSON.parse((0, import_node_fs.readFileSync)(path, "utf8"));
|
|
154
154
|
} catch {
|
|
155
155
|
throw new Error(`credentials file ${path} is not valid JSON; fix or remove it before provisioning`);
|
|
156
156
|
}
|
|
157
|
-
if (!
|
|
157
|
+
if (!value2 || typeof value2 !== "object" || typeof value2.appId !== "string" || !value2.envs || typeof value2.envs !== "object") {
|
|
158
158
|
throw new Error(`credentials file ${path} has an invalid shape; fix or remove it before provisioning`);
|
|
159
159
|
}
|
|
160
|
-
return
|
|
160
|
+
return value2;
|
|
161
161
|
}
|
|
162
162
|
function mergeCredential(current, update) {
|
|
163
163
|
const next = current ?? {
|
|
@@ -452,8 +452,8 @@ function stillPending(pending, email) {
|
|
|
452
452
|
{ retryable: true }
|
|
453
453
|
);
|
|
454
454
|
}
|
|
455
|
-
function handshakeEmail(
|
|
456
|
-
const email = (
|
|
455
|
+
function handshakeEmail(value2, cached) {
|
|
456
|
+
const email = (value2 ?? import_node_process3.default.env.ODLA_USER_EMAIL ?? cached ?? "").trim().toLowerCase();
|
|
457
457
|
if (email.length > 254 || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
|
|
458
458
|
throw new Error("a fresh odla handshake requires --email <account> or ODLA_USER_EMAIL");
|
|
459
459
|
}
|
|
@@ -477,10 +477,10 @@ function handshakeUrl(platformUrl, userCode) {
|
|
|
477
477
|
url.searchParams.set("code", userCode);
|
|
478
478
|
return url.toString();
|
|
479
479
|
}
|
|
480
|
-
function platformAudience(
|
|
480
|
+
function platformAudience(value2) {
|
|
481
481
|
let url;
|
|
482
482
|
try {
|
|
483
|
-
url = new URL(
|
|
483
|
+
url = new URL(value2);
|
|
484
484
|
} catch {
|
|
485
485
|
throw new Error("platform must be an absolute URL");
|
|
486
486
|
}
|
|
@@ -499,22 +499,22 @@ var import_node_process4 = __toESM(require("process"), 1);
|
|
|
499
499
|
var MAX_BYTES = 64 * 1024;
|
|
500
500
|
async function secretInputValue(options, kind = "credential") {
|
|
501
501
|
if (options.fromEnv && options.stdin) throw new Error("choose exactly one of --from-env or --stdin");
|
|
502
|
-
let
|
|
503
|
-
if (options.fromEnv)
|
|
504
|
-
else if (options.stdin)
|
|
502
|
+
let value2;
|
|
503
|
+
if (options.fromEnv) value2 = import_node_process4.default.env[options.fromEnv];
|
|
504
|
+
else if (options.stdin) value2 = await (options.readStdin ?? (() => readSecretStream(kind)))();
|
|
505
505
|
else throw new Error(`${kind} input required: use --from-env <NAME> or --stdin; values are never accepted as arguments`);
|
|
506
|
-
|
|
507
|
-
if (!
|
|
508
|
-
if (new TextEncoder().encode(
|
|
509
|
-
return
|
|
506
|
+
value2 = value2?.replace(/[\r\n]+$/, "");
|
|
507
|
+
if (!value2) throw new Error(options.fromEnv ? `environment variable ${options.fromEnv} is empty or unset` : `stdin ${kind} is empty`);
|
|
508
|
+
if (new TextEncoder().encode(value2).byteLength > MAX_BYTES) throw new Error(`${kind} exceeds 64 KiB`);
|
|
509
|
+
return value2;
|
|
510
510
|
}
|
|
511
511
|
async function readSecretStream(kind, stream = import_node_process4.default.stdin) {
|
|
512
|
-
let
|
|
512
|
+
let value2 = "";
|
|
513
513
|
for await (const chunk of stream) {
|
|
514
|
-
|
|
515
|
-
if (
|
|
514
|
+
value2 += String(chunk);
|
|
515
|
+
if (value2.length > MAX_BYTES) throw new Error(`${kind} exceeds 64 KiB`);
|
|
516
516
|
}
|
|
517
|
-
return
|
|
517
|
+
return value2;
|
|
518
518
|
}
|
|
519
519
|
|
|
520
520
|
// src/admin-ai-auth.ts
|
|
@@ -549,6 +549,7 @@ function audienceBoundEnvToken(token, platform) {
|
|
|
549
549
|
return token;
|
|
550
550
|
}
|
|
551
551
|
var SCOPE_PURPOSE = {
|
|
552
|
+
"platform:status:read": "read the platform fleet health and deployment snapshot",
|
|
552
553
|
"platform:runbook:write": "add or edit odla's operational runbooks",
|
|
553
554
|
"platform:ai:policy:write": "change System AI model routing",
|
|
554
555
|
"platform:ai:policy:read": "read System AI model routing",
|
|
@@ -652,13 +653,13 @@ function apiError(status, body) {
|
|
|
652
653
|
const message2 = error && typeof error.message === "string" ? error.message : isRecord(body) && typeof body.message === "string" ? body.message : "request failed";
|
|
653
654
|
return `read System AI admin changes failed (${status}): ${message2}`;
|
|
654
655
|
}
|
|
655
|
-
function timestamp(
|
|
656
|
-
if (typeof
|
|
657
|
-
const date = new Date(
|
|
656
|
+
function timestamp(value2) {
|
|
657
|
+
if (typeof value2 !== "number" || !Number.isFinite(value2)) return String(value2 ?? "");
|
|
658
|
+
const date = new Date(value2);
|
|
658
659
|
return Number.isFinite(date.valueOf()) ? date.toISOString() : "";
|
|
659
660
|
}
|
|
660
|
-
function isRecord(
|
|
661
|
-
return Boolean(
|
|
661
|
+
function isRecord(value2) {
|
|
662
|
+
return Boolean(value2) && typeof value2 === "object" && !Array.isArray(value2);
|
|
662
663
|
}
|
|
663
664
|
|
|
664
665
|
// src/admin-ai-policy.ts
|
|
@@ -668,11 +669,11 @@ var SYSTEM_AI_PURPOSES = [
|
|
|
668
669
|
"security.validation",
|
|
669
670
|
"runbook.answer"
|
|
670
671
|
];
|
|
671
|
-
function requireSystemAiPurpose(
|
|
672
|
-
if (!SYSTEM_AI_PURPOSES.includes(
|
|
672
|
+
function requireSystemAiPurpose(value2) {
|
|
673
|
+
if (!SYSTEM_AI_PURPOSES.includes(value2)) {
|
|
673
674
|
throw new Error(`purpose must be one of: ${SYSTEM_AI_PURPOSES.join(", ")}`);
|
|
674
675
|
}
|
|
675
|
-
return
|
|
676
|
+
return value2;
|
|
676
677
|
}
|
|
677
678
|
|
|
678
679
|
// src/admin-ai-usage.ts
|
|
@@ -694,11 +695,11 @@ async function readAdminAiUsage(request2) {
|
|
|
694
695
|
if (request2.json) request2.stdout.log(JSON.stringify(body, null, 2));
|
|
695
696
|
else printUsage(body, request2.stdout);
|
|
696
697
|
}
|
|
697
|
-
function usageLimit(
|
|
698
|
-
if (!Number.isSafeInteger(
|
|
698
|
+
function usageLimit(value2) {
|
|
699
|
+
if (!Number.isSafeInteger(value2) || value2 < 1 || value2 > 500) {
|
|
699
700
|
throw new Error("usage limit must be an integer from 1 to 500");
|
|
700
701
|
}
|
|
701
|
-
return
|
|
702
|
+
return value2;
|
|
702
703
|
}
|
|
703
704
|
function printUsage(body, out) {
|
|
704
705
|
const aggregates = isRecord2(body) && isRecord2(body.aggregates) && Array.isArray(body.aggregates.byStatus) ? body.aggregates.byStatus.filter(isRecord2) : [];
|
|
@@ -734,15 +735,15 @@ when app/env run actor purpose/role route / policy tokens cost status`);
|
|
|
734
735
|
].join(" "));
|
|
735
736
|
}
|
|
736
737
|
}
|
|
737
|
-
function numeric(
|
|
738
|
-
return typeof
|
|
738
|
+
function numeric(value2) {
|
|
739
|
+
return typeof value2 === "number" && Number.isFinite(value2) ? value2 : 0;
|
|
739
740
|
}
|
|
740
|
-
function formatMicrousd(
|
|
741
|
-
return typeof
|
|
741
|
+
function formatMicrousd(value2) {
|
|
742
|
+
return typeof value2 === "number" && Number.isFinite(value2) ? `$${(value2 / 1e6).toFixed(6)}` : "unpriced";
|
|
742
743
|
}
|
|
743
|
-
function timestamp2(
|
|
744
|
-
if (typeof
|
|
745
|
-
const date = new Date(
|
|
744
|
+
function timestamp2(value2) {
|
|
745
|
+
if (typeof value2 !== "number" || !Number.isFinite(value2)) return String(value2 ?? "");
|
|
746
|
+
const date = new Date(value2);
|
|
746
747
|
return Number.isFinite(date.valueOf()) ? date.toISOString() : "";
|
|
747
748
|
}
|
|
748
749
|
async function responseBody2(res) {
|
|
@@ -759,8 +760,8 @@ function apiError2(action, status, body) {
|
|
|
759
760
|
const message2 = error && typeof error.message === "string" ? error.message : isRecord2(body) && typeof body.message === "string" ? body.message : "request failed";
|
|
760
761
|
return `${action} failed (${status}): ${message2}`;
|
|
761
762
|
}
|
|
762
|
-
function isRecord2(
|
|
763
|
-
return Boolean(
|
|
763
|
+
function isRecord2(value2) {
|
|
764
|
+
return Boolean(value2) && typeof value2 === "object" && !Array.isArray(value2);
|
|
764
765
|
}
|
|
765
766
|
|
|
766
767
|
// src/admin-ai.ts
|
|
@@ -805,11 +806,11 @@ async function adminAi(options) {
|
|
|
805
806
|
}
|
|
806
807
|
if (options.action === "credential-set") {
|
|
807
808
|
const provider = requireProvider(options.credentialProvider);
|
|
808
|
-
const
|
|
809
|
+
const value2 = await secretInputValue(options);
|
|
809
810
|
const res2 = await doFetch(`${platform}/registry/platform/ai-credentials/${encodeURIComponent(provider)}`, {
|
|
810
811
|
method: "PUT",
|
|
811
812
|
headers,
|
|
812
|
-
body: JSON.stringify({ value })
|
|
813
|
+
body: JSON.stringify({ value: value2 })
|
|
813
814
|
});
|
|
814
815
|
const body2 = await responseBody3(res2);
|
|
815
816
|
if (!res2.ok) throw new Error(apiError3(`store ${provider} platform credential`, res2.status, body2));
|
|
@@ -909,11 +910,11 @@ async function adminAi(options) {
|
|
|
909
910
|
const policy = isRecord3(response2) && isRecord3(response2.policy) ? response2.policy : isRecord3(response2) ? response2 : {};
|
|
910
911
|
out.log(options.json ? JSON.stringify({ policy }, null, 2) : `updated ${purpose}: ${String(policy.provider ?? "unchanged")}/${String(policy.model ?? "unchanged")}`);
|
|
911
912
|
}
|
|
912
|
-
function requireProvider(
|
|
913
|
-
if (
|
|
913
|
+
function requireProvider(value2) {
|
|
914
|
+
if (value2 !== "anthropic" && value2 !== "openai" && value2 !== "google") {
|
|
914
915
|
throw new Error("provider must be one of: anthropic, openai, google");
|
|
915
916
|
}
|
|
916
|
-
return
|
|
917
|
+
return value2;
|
|
917
918
|
}
|
|
918
919
|
function policyArray(body) {
|
|
919
920
|
if (isRecord3(body) && Array.isArray(body.policies)) return body.policies.filter(isRecord3);
|
|
@@ -924,7 +925,7 @@ function catalogModels(body) {
|
|
|
924
925
|
if (!isRecord3(body) || !isRecord3(body.catalog) || !Array.isArray(body.catalog.models)) {
|
|
925
926
|
throw new Error("platform returned an invalid System AI model catalog");
|
|
926
927
|
}
|
|
927
|
-
return body.catalog.models.filter((
|
|
928
|
+
return body.catalog.models.filter((value2) => isRecord3(value2) && typeof value2.id === "string" && typeof value2.provider === "string");
|
|
928
929
|
}
|
|
929
930
|
async function responseBody3(res) {
|
|
930
931
|
const text = await res.text();
|
|
@@ -940,8 +941,8 @@ function apiError3(action, status, body) {
|
|
|
940
941
|
const message2 = error && typeof error.message === "string" ? error.message : isRecord3(body) && typeof body.message === "string" ? body.message : "request failed";
|
|
941
942
|
return `${action} failed (${status}): ${message2}`;
|
|
942
943
|
}
|
|
943
|
-
function isRecord3(
|
|
944
|
-
return Boolean(
|
|
944
|
+
function isRecord3(value2) {
|
|
945
|
+
return Boolean(value2) && typeof value2 === "object" && !Array.isArray(value2);
|
|
945
946
|
}
|
|
946
947
|
|
|
947
948
|
// src/argv.ts
|
|
@@ -965,10 +966,10 @@ function parseArgv(argv) {
|
|
|
965
966
|
addOption(options, rawName, arg.slice(eq + 1));
|
|
966
967
|
continue;
|
|
967
968
|
}
|
|
968
|
-
const
|
|
969
|
-
if (
|
|
969
|
+
const value2 = argv[i + 1];
|
|
970
|
+
if (value2 !== void 0 && !value2.startsWith("--")) {
|
|
970
971
|
i++;
|
|
971
|
-
addOption(options, rawName,
|
|
972
|
+
addOption(options, rawName, value2);
|
|
972
973
|
} else {
|
|
973
974
|
addOption(options, rawName, true);
|
|
974
975
|
}
|
|
@@ -984,39 +985,39 @@ function assertArgs(parsed, allowedOptions2, maxPositionals) {
|
|
|
984
985
|
throw new Error(`unexpected argument "${parsed.positionals[maxPositionals]}"; run "odla-ai help"`);
|
|
985
986
|
}
|
|
986
987
|
}
|
|
987
|
-
function requiredString(
|
|
988
|
-
const result = stringOpt(
|
|
988
|
+
function requiredString(value2, name) {
|
|
989
|
+
const result = stringOpt(value2);
|
|
989
990
|
if (!result) throw new Error(`${name} is required`);
|
|
990
991
|
return result;
|
|
991
992
|
}
|
|
992
|
-
function stringOpt(
|
|
993
|
-
if (typeof
|
|
994
|
-
if (Array.isArray(
|
|
993
|
+
function stringOpt(value2) {
|
|
994
|
+
if (typeof value2 === "string") return value2;
|
|
995
|
+
if (Array.isArray(value2)) return value2[value2.length - 1];
|
|
995
996
|
return void 0;
|
|
996
997
|
}
|
|
997
|
-
function listOpt(
|
|
998
|
-
if (
|
|
999
|
-
const values = Array.isArray(
|
|
998
|
+
function listOpt(value2) {
|
|
999
|
+
if (value2 === void 0 || typeof value2 === "boolean") return void 0;
|
|
1000
|
+
const values = Array.isArray(value2) ? value2 : [value2];
|
|
1000
1001
|
return values.flatMap((item) => item.split(",")).map((item) => item.trim()).filter(Boolean);
|
|
1001
1002
|
}
|
|
1002
|
-
function boolOpt(
|
|
1003
|
-
if (typeof
|
|
1004
|
-
if (typeof
|
|
1005
|
-
if (
|
|
1003
|
+
function boolOpt(value2) {
|
|
1004
|
+
if (typeof value2 === "boolean") return value2;
|
|
1005
|
+
if (typeof value2 === "string" && (value2 === "true" || value2 === "false")) return value2 === "true";
|
|
1006
|
+
if (value2 === void 0) return void 0;
|
|
1006
1007
|
throw new Error("boolean option must be true or false");
|
|
1007
1008
|
}
|
|
1008
|
-
function numberOpt(
|
|
1009
|
-
if (
|
|
1010
|
-
const raw = stringOpt(
|
|
1009
|
+
function numberOpt(value2, flag) {
|
|
1010
|
+
if (value2 === void 0) return void 0;
|
|
1011
|
+
const raw = stringOpt(value2);
|
|
1011
1012
|
const parsed = raw === void 0 ? Number.NaN : Number(raw);
|
|
1012
1013
|
if (!Number.isSafeInteger(parsed) || parsed < 1) throw new Error(`${flag} requires a positive integer`);
|
|
1013
1014
|
return parsed;
|
|
1014
1015
|
}
|
|
1015
|
-
function addOption(options, name,
|
|
1016
|
+
function addOption(options, name, value2) {
|
|
1016
1017
|
const current = options[name];
|
|
1017
|
-
if (current === void 0) options[name] =
|
|
1018
|
-
else if (Array.isArray(current)) current.push(String(
|
|
1019
|
-
else options[name] = [String(current), String(
|
|
1018
|
+
if (current === void 0) options[name] = value2;
|
|
1019
|
+
else if (Array.isArray(current)) current.push(String(value2));
|
|
1020
|
+
else options[name] = [String(current), String(value2)];
|
|
1020
1021
|
}
|
|
1021
1022
|
|
|
1022
1023
|
// src/operator-context.ts
|
|
@@ -1083,17 +1084,17 @@ function validateProbes(integration, at) {
|
|
|
1083
1084
|
}
|
|
1084
1085
|
}
|
|
1085
1086
|
}
|
|
1086
|
-
function isRecord4(
|
|
1087
|
-
return
|
|
1087
|
+
function isRecord4(value2) {
|
|
1088
|
+
return value2 !== null && typeof value2 === "object" && !Array.isArray(value2);
|
|
1088
1089
|
}
|
|
1089
|
-
function safeText(
|
|
1090
|
-
return typeof
|
|
1090
|
+
function safeText(value2, max) {
|
|
1091
|
+
return typeof value2 === "string" && value2.trim().length > 0 && value2.length <= max && !/[\u0000-\u001f\u007f]/.test(value2);
|
|
1091
1092
|
}
|
|
1092
|
-
function safeProbePath(
|
|
1093
|
-
return typeof
|
|
1093
|
+
function safeProbePath(value2) {
|
|
1094
|
+
return typeof value2 === "string" && /^\/[A-Za-z0-9._~!$&'()*+,;=:@%/-]*$/.test(value2);
|
|
1094
1095
|
}
|
|
1095
|
-
function validId(
|
|
1096
|
-
return typeof
|
|
1096
|
+
function validId(value2) {
|
|
1097
|
+
return typeof value2 === "string" && /^[a-z0-9][a-z0-9-]*$/.test(value2);
|
|
1097
1098
|
}
|
|
1098
1099
|
function unique(values) {
|
|
1099
1100
|
return [...new Set(values.filter(Boolean))];
|
|
@@ -1135,10 +1136,10 @@ async function loadProjectConfig(configPath = "odla.config.mjs") {
|
|
|
1135
1136
|
local
|
|
1136
1137
|
};
|
|
1137
1138
|
}
|
|
1138
|
-
async function resolveDataExport(cfg,
|
|
1139
|
-
if (
|
|
1140
|
-
if (typeof
|
|
1141
|
-
const target = (0, import_node_path4.isAbsolute)(
|
|
1139
|
+
async function resolveDataExport(cfg, value2, names) {
|
|
1140
|
+
if (value2 === void 0 || value2 === null || value2 === false) return void 0;
|
|
1141
|
+
if (typeof value2 !== "string") return value2;
|
|
1142
|
+
const target = (0, import_node_path4.isAbsolute)(value2) ? value2 : (0, import_node_path4.resolve)(cfg.rootDir, value2);
|
|
1142
1143
|
if (target.endsWith(".json")) {
|
|
1143
1144
|
return JSON.parse((0, import_node_fs4.readFileSync)(target, "utf8"));
|
|
1144
1145
|
}
|
|
@@ -1147,7 +1148,7 @@ async function resolveDataExport(cfg, value, names) {
|
|
|
1147
1148
|
if (mod[name] !== void 0) return mod[name];
|
|
1148
1149
|
}
|
|
1149
1150
|
if (mod.default !== void 0) return mod.default;
|
|
1150
|
-
throw new Error(`${
|
|
1151
|
+
throw new Error(`${value2} did not export ${names.join(", ")} or default`);
|
|
1151
1152
|
}
|
|
1152
1153
|
function buildPlan(cfg) {
|
|
1153
1154
|
const integrationSchema = cfg.integrations?.some((integration) => integration.schema) ?? false;
|
|
@@ -1181,9 +1182,9 @@ function calendarServiceConfig(cfg, env) {
|
|
|
1181
1182
|
};
|
|
1182
1183
|
}
|
|
1183
1184
|
function calendarBookingPageUrl(cfg, env) {
|
|
1184
|
-
const
|
|
1185
|
-
if (
|
|
1186
|
-
return new URL(
|
|
1185
|
+
const value2 = cfg.calendar?.google.bookingPageUrl?.[env];
|
|
1186
|
+
if (value2 === void 0 || value2 === null) return value2;
|
|
1187
|
+
return new URL(value2).toString();
|
|
1187
1188
|
}
|
|
1188
1189
|
function rulesFromSchema(schema) {
|
|
1189
1190
|
const entities = serializedEntities(schema);
|
|
@@ -1197,10 +1198,10 @@ function serializedEntities(schema) {
|
|
|
1197
1198
|
if (!entities || typeof entities !== "object" || Array.isArray(entities)) return [];
|
|
1198
1199
|
return Object.keys(entities);
|
|
1199
1200
|
}
|
|
1200
|
-
function envValue(
|
|
1201
|
-
if (!
|
|
1202
|
-
if (
|
|
1203
|
-
return
|
|
1201
|
+
function envValue(value2) {
|
|
1202
|
+
if (!value2) return void 0;
|
|
1203
|
+
if (value2.startsWith("$")) return process.env[value2.slice(1)];
|
|
1204
|
+
return value2;
|
|
1204
1205
|
}
|
|
1205
1206
|
function validateRawConfig(raw, path) {
|
|
1206
1207
|
if (!raw || typeof raw !== "object") throw new Error(`${path} must export an object`);
|
|
@@ -1256,8 +1257,8 @@ function validateCalendarConfig(cfg, envs, services, path) {
|
|
|
1256
1257
|
if (!isRecord5(google.bookingCalendar)) throw new Error(`${path}: calendar.google.bookingCalendar must map env names to one calendar id`);
|
|
1257
1258
|
const unknownBookingEnv = Object.keys(google.bookingCalendar).find((env) => !envs.includes(env));
|
|
1258
1259
|
if (unknownBookingEnv) throw new Error(`${path}: calendar.google.bookingCalendar.${unknownBookingEnv} is not in config envs`);
|
|
1259
|
-
for (const [env,
|
|
1260
|
-
if (!safeText2(
|
|
1260
|
+
for (const [env, value2] of Object.entries(google.bookingCalendar)) {
|
|
1261
|
+
if (!safeText2(value2, 1024)) {
|
|
1261
1262
|
throw new Error(`${path}: calendar.google.bookingCalendar.${env} must be a calendar id`);
|
|
1262
1263
|
}
|
|
1263
1264
|
}
|
|
@@ -1266,8 +1267,8 @@ function validateCalendarConfig(cfg, envs, services, path) {
|
|
|
1266
1267
|
if (!isRecord5(google.bookingPageUrl)) throw new Error(`${path}: calendar.google.bookingPageUrl must map env names to HTTPS URLs or null`);
|
|
1267
1268
|
const unknownBookingEnv = Object.keys(google.bookingPageUrl).find((env) => !envs.includes(env));
|
|
1268
1269
|
if (unknownBookingEnv) throw new Error(`${path}: calendar.google.bookingPageUrl.${unknownBookingEnv} is not in config envs`);
|
|
1269
|
-
for (const [env,
|
|
1270
|
-
if (
|
|
1270
|
+
for (const [env, value2] of Object.entries(google.bookingPageUrl)) {
|
|
1271
|
+
if (value2 !== null && !safeHttpsUrl(value2)) {
|
|
1271
1272
|
throw new Error(`${path}: calendar.google.bookingPageUrl.${env} must be an HTTPS URL without credentials or fragment`);
|
|
1272
1273
|
}
|
|
1273
1274
|
}
|
|
@@ -1286,37 +1287,37 @@ function validateServices(services, path) {
|
|
|
1286
1287
|
}
|
|
1287
1288
|
}
|
|
1288
1289
|
}
|
|
1289
|
-
function assertOnly(
|
|
1290
|
-
const extra = Object.keys(
|
|
1290
|
+
function assertOnly(value2, allowed, label) {
|
|
1291
|
+
const extra = Object.keys(value2).find((key) => !allowed.includes(key));
|
|
1291
1292
|
if (extra) throw new Error(`${label}.${extra} is not supported`);
|
|
1292
1293
|
}
|
|
1293
|
-
function isRecord5(
|
|
1294
|
-
return
|
|
1294
|
+
function isRecord5(value2) {
|
|
1295
|
+
return value2 !== null && typeof value2 === "object" && !Array.isArray(value2);
|
|
1295
1296
|
}
|
|
1296
|
-
function safeText2(
|
|
1297
|
-
return typeof
|
|
1297
|
+
function safeText2(value2, max) {
|
|
1298
|
+
return typeof value2 === "string" && value2.trim().length > 0 && value2.length <= max && !/[\u0000-\u001f\u007f]/.test(value2);
|
|
1298
1299
|
}
|
|
1299
|
-
function safeHttpsUrl(
|
|
1300
|
-
if (typeof
|
|
1300
|
+
function safeHttpsUrl(value2) {
|
|
1301
|
+
if (typeof value2 !== "string" || value2.length > 2048) return false;
|
|
1301
1302
|
try {
|
|
1302
|
-
const url = new URL(
|
|
1303
|
+
const url = new URL(value2);
|
|
1303
1304
|
return url.protocol === "https:" && !url.username && !url.password && !url.hash;
|
|
1304
1305
|
} catch {
|
|
1305
1306
|
return false;
|
|
1306
1307
|
}
|
|
1307
1308
|
}
|
|
1308
|
-
function validId2(
|
|
1309
|
-
return typeof
|
|
1309
|
+
function validId2(value2) {
|
|
1310
|
+
return typeof value2 === "string" && /^[a-z0-9][a-z0-9-]*$/.test(value2);
|
|
1310
1311
|
}
|
|
1311
1312
|
async function loadConfigModule(path) {
|
|
1312
1313
|
if (path.endsWith(".json")) return JSON.parse((0, import_node_fs4.readFileSync)(path, "utf8"));
|
|
1313
1314
|
const mod = await import(`${(0, import_node_url.pathToFileURL)(path).href}?t=${Date.now()}`);
|
|
1314
|
-
const
|
|
1315
|
-
if (typeof
|
|
1316
|
-
return
|
|
1315
|
+
const value2 = mod.default ?? mod.config;
|
|
1316
|
+
if (typeof value2 === "function") return await value2();
|
|
1317
|
+
return value2;
|
|
1317
1318
|
}
|
|
1318
|
-
function trimSlash(
|
|
1319
|
-
return
|
|
1319
|
+
function trimSlash(value2) {
|
|
1320
|
+
return value2.replace(/\/+$/, "");
|
|
1320
1321
|
}
|
|
1321
1322
|
function unique2(values) {
|
|
1322
1323
|
return [...new Set(values.filter(Boolean))];
|
|
@@ -1342,8 +1343,8 @@ function resolveOperatorProfile(parsed) {
|
|
|
1342
1343
|
}
|
|
1343
1344
|
assertOperatorName(name, "context");
|
|
1344
1345
|
const profiles = readOperatorProfiles(file);
|
|
1345
|
-
const
|
|
1346
|
-
if (!
|
|
1346
|
+
const value2 = Object.hasOwn(profiles, name) ? profiles[name] : void 0;
|
|
1347
|
+
if (!value2) {
|
|
1347
1348
|
throw new Error(
|
|
1348
1349
|
`operator context "${name}" not found in ${file}; run "odla-ai context list" or save it first`
|
|
1349
1350
|
);
|
|
@@ -1352,7 +1353,7 @@ function resolveOperatorProfile(parsed) {
|
|
|
1352
1353
|
name,
|
|
1353
1354
|
source: fromFlag ? "flag" : "environment",
|
|
1354
1355
|
file,
|
|
1355
|
-
value
|
|
1356
|
+
value: value2
|
|
1356
1357
|
};
|
|
1357
1358
|
}
|
|
1358
1359
|
function listOperatorProfiles(file = operatorProfileFile()) {
|
|
@@ -1380,8 +1381,8 @@ function operatorCredentialFiles(selection) {
|
|
|
1380
1381
|
scoped: (0, import_node_path5.join)(base, "admin-token.local.json")
|
|
1381
1382
|
};
|
|
1382
1383
|
}
|
|
1383
|
-
function assertOperatorName(
|
|
1384
|
-
if (!/^[a-z0-9][a-z0-9-]*$/.test(
|
|
1384
|
+
function assertOperatorName(value2, label) {
|
|
1385
|
+
if (!/^[a-z0-9][a-z0-9-]*$/.test(value2)) {
|
|
1385
1386
|
throw new Error(
|
|
1386
1387
|
`${label} must contain lowercase letters, numbers, and hyphens`
|
|
1387
1388
|
);
|
|
@@ -1407,22 +1408,22 @@ function readOperatorProfiles(file) {
|
|
|
1407
1408
|
);
|
|
1408
1409
|
}
|
|
1409
1410
|
const profiles = emptyProfiles();
|
|
1410
|
-
for (const [name,
|
|
1411
|
+
for (const [name, value2] of Object.entries(
|
|
1411
1412
|
raw.profiles
|
|
1412
1413
|
)) {
|
|
1413
1414
|
assertOperatorName(name, "context");
|
|
1414
|
-
profiles[name] = validateProfile(
|
|
1415
|
+
profiles[name] = validateProfile(value2, `operator context "${name}"`);
|
|
1415
1416
|
}
|
|
1416
1417
|
return profiles;
|
|
1417
1418
|
}
|
|
1418
1419
|
function emptyProfiles() {
|
|
1419
1420
|
return /* @__PURE__ */ Object.create(null);
|
|
1420
1421
|
}
|
|
1421
|
-
function validateProfile(
|
|
1422
|
-
if (!
|
|
1422
|
+
function validateProfile(value2, label) {
|
|
1423
|
+
if (!value2 || typeof value2 !== "object" || Array.isArray(value2)) {
|
|
1423
1424
|
throw new Error(`${label} has an invalid shape`);
|
|
1424
1425
|
}
|
|
1425
|
-
const unknown = Object.keys(
|
|
1426
|
+
const unknown = Object.keys(value2).filter(
|
|
1426
1427
|
(key) => !["platform", "app", "environment"].includes(key)
|
|
1427
1428
|
);
|
|
1428
1429
|
if (unknown.length > 0) {
|
|
@@ -1430,7 +1431,7 @@ function validateProfile(value, label) {
|
|
|
1430
1431
|
`${label} contains unsupported field(s): ${unknown.sort().join(", ")}; contexts store scope metadata only, never credentials`
|
|
1431
1432
|
);
|
|
1432
1433
|
}
|
|
1433
|
-
const candidate =
|
|
1434
|
+
const candidate = value2;
|
|
1434
1435
|
if (typeof candidate.platform !== "string") {
|
|
1435
1436
|
throw new Error(`${label} needs an absolute platform URL`);
|
|
1436
1437
|
}
|
|
@@ -1445,8 +1446,8 @@ function validateProfile(value, label) {
|
|
|
1445
1446
|
...environment2 ? { environment: environment2 } : {}
|
|
1446
1447
|
};
|
|
1447
1448
|
}
|
|
1448
|
-
function clean(
|
|
1449
|
-
const normalized =
|
|
1449
|
+
function clean(value2) {
|
|
1450
|
+
const normalized = value2?.trim();
|
|
1450
1451
|
return normalized || void 0;
|
|
1451
1452
|
}
|
|
1452
1453
|
|
|
@@ -1539,8 +1540,8 @@ async function resolveOperatorContext(parsed, options = {}) {
|
|
|
1539
1540
|
}
|
|
1540
1541
|
};
|
|
1541
1542
|
}
|
|
1542
|
-
function clean2(
|
|
1543
|
-
const normalized =
|
|
1543
|
+
function clean2(value2) {
|
|
1544
|
+
const normalized = value2?.trim();
|
|
1544
1545
|
return normalized || void 0;
|
|
1545
1546
|
}
|
|
1546
1547
|
|
|
@@ -2251,44 +2252,44 @@ var REPLACEMENTS = [
|
|
|
2251
2252
|
[/\b(ghp|gho|github_pat)_[A-Za-z0-9_]+/g, "$1_[redacted]"],
|
|
2252
2253
|
[/\bAKIA[A-Z0-9]{12,}/g, "AKIA[redacted]"]
|
|
2253
2254
|
];
|
|
2254
|
-
function redactSecrets(
|
|
2255
|
-
let result =
|
|
2255
|
+
function redactSecrets(value2) {
|
|
2256
|
+
let result = value2;
|
|
2256
2257
|
for (const [pattern, replacement] of REPLACEMENTS) result = result.replace(pattern, replacement);
|
|
2257
2258
|
return result;
|
|
2258
2259
|
}
|
|
2259
2260
|
function redactingOutput(output) {
|
|
2260
|
-
const redactArgs = (args) => args.map((
|
|
2261
|
+
const redactArgs = (args) => args.map((value2) => redactOutputValue(value2, /* @__PURE__ */ new WeakMap()));
|
|
2261
2262
|
return {
|
|
2262
2263
|
log: (...args) => output.log(...redactArgs(args)),
|
|
2263
2264
|
error: (...args) => output.error(...redactArgs(args))
|
|
2264
2265
|
};
|
|
2265
2266
|
}
|
|
2266
|
-
function redactOutputValue(
|
|
2267
|
-
if (typeof
|
|
2268
|
-
if (
|
|
2269
|
-
const redacted = new Error(redactSecrets(
|
|
2270
|
-
redacted.name =
|
|
2271
|
-
if (
|
|
2267
|
+
function redactOutputValue(value2, seen) {
|
|
2268
|
+
if (typeof value2 === "string") return redactSecrets(value2);
|
|
2269
|
+
if (value2 instanceof Error) {
|
|
2270
|
+
const redacted = new Error(redactSecrets(value2.message));
|
|
2271
|
+
redacted.name = value2.name;
|
|
2272
|
+
if (value2.stack) redacted.stack = redactSecrets(value2.stack);
|
|
2272
2273
|
return redacted;
|
|
2273
2274
|
}
|
|
2274
|
-
if (!
|
|
2275
|
-
const prior = seen.get(
|
|
2275
|
+
if (!value2 || typeof value2 !== "object") return value2;
|
|
2276
|
+
const prior = seen.get(value2);
|
|
2276
2277
|
if (prior) return prior;
|
|
2277
|
-
if (Array.isArray(
|
|
2278
|
+
if (Array.isArray(value2)) {
|
|
2278
2279
|
const next2 = [];
|
|
2279
|
-
seen.set(
|
|
2280
|
-
for (const item of
|
|
2280
|
+
seen.set(value2, next2);
|
|
2281
|
+
for (const item of value2) next2.push(redactOutputValue(item, seen));
|
|
2281
2282
|
return next2;
|
|
2282
2283
|
}
|
|
2283
|
-
const prototype = Object.getPrototypeOf(
|
|
2284
|
-
if (prototype !== Object.prototype && prototype !== null) return
|
|
2284
|
+
const prototype = Object.getPrototypeOf(value2);
|
|
2285
|
+
if (prototype !== Object.prototype && prototype !== null) return value2;
|
|
2285
2286
|
const next = {};
|
|
2286
|
-
seen.set(
|
|
2287
|
-
for (const [key, item] of Object.entries(
|
|
2287
|
+
seen.set(value2, next);
|
|
2288
|
+
for (const [key, item] of Object.entries(value2)) next[key] = redactOutputValue(item, seen);
|
|
2288
2289
|
return next;
|
|
2289
2290
|
}
|
|
2290
|
-
function looksSecret(
|
|
2291
|
-
return redactSecrets(
|
|
2291
|
+
function looksSecret(value2) {
|
|
2292
|
+
return redactSecrets(value2) !== value2 || value2.includes("-----BEGIN");
|
|
2292
2293
|
}
|
|
2293
2294
|
|
|
2294
2295
|
// src/calendar-http.ts
|
|
@@ -2305,9 +2306,9 @@ async function readCalendarStatus(ctx) {
|
|
|
2305
2306
|
}
|
|
2306
2307
|
async function discoverGoogleCalendars(ctx) {
|
|
2307
2308
|
const raw = await calendarJson(ctx, "/calendars", {});
|
|
2308
|
-
const
|
|
2309
|
-
if (!
|
|
2310
|
-
return
|
|
2309
|
+
const value2 = record(raw);
|
|
2310
|
+
if (!value2 || !Array.isArray(value2.calendars)) throw new Error("calendar discovery returned an invalid response");
|
|
2311
|
+
return value2.calendars.map((item, index) => {
|
|
2311
2312
|
const calendar = record(item);
|
|
2312
2313
|
const id = textField(calendar?.id, 1024);
|
|
2313
2314
|
if (!calendar || !id) throw new Error(`calendar discovery returned an invalid calendar at index ${index}`);
|
|
@@ -2329,10 +2330,10 @@ async function applyCalendarSettings(ctx, bookingPageUrl) {
|
|
|
2329
2330
|
}
|
|
2330
2331
|
async function startCalendarConnection(ctx) {
|
|
2331
2332
|
const raw = await calendarJson(ctx, "/google/connect", { method: "POST", body: "{}" });
|
|
2332
|
-
const
|
|
2333
|
-
const attemptId = textField(
|
|
2334
|
-
const consentUrl = textField(
|
|
2335
|
-
const expiresAt = timestamp3(
|
|
2333
|
+
const value2 = wrapped(raw, "attempt");
|
|
2334
|
+
const attemptId = textField(value2.attemptId, 180);
|
|
2335
|
+
const consentUrl = textField(value2.consentUrl, 4096);
|
|
2336
|
+
const expiresAt = timestamp3(value2.expiresAt);
|
|
2336
2337
|
if (!attemptId || !consentUrl || expiresAt === void 0) throw new Error("calendar connect returned an invalid attempt");
|
|
2337
2338
|
return { attemptId, consentUrl, expiresAt };
|
|
2338
2339
|
}
|
|
@@ -2350,42 +2351,42 @@ async function requestCalendarDisconnect(ctx) {
|
|
|
2350
2351
|
}
|
|
2351
2352
|
function parseCalendarStatus(raw, env) {
|
|
2352
2353
|
const outer = wrapped(raw, "calendar");
|
|
2353
|
-
const
|
|
2354
|
-
const connection = record(
|
|
2355
|
-
const config = record(
|
|
2354
|
+
const value2 = record(outer.attempt) ?? record(outer.status) ?? outer;
|
|
2355
|
+
const connection = record(value2.connection) ?? {};
|
|
2356
|
+
const config = record(value2.config) ?? record(outer.config) ?? {};
|
|
2356
2357
|
const googleConfig = record(config.google) ?? config;
|
|
2357
|
-
const stateValue = calendarState(
|
|
2358
|
+
const stateValue = calendarState(value2.status ?? value2.state ?? connection.status ?? connection.state);
|
|
2358
2359
|
if (!stateValue) {
|
|
2359
2360
|
throw new Error("calendar status returned an invalid connection state");
|
|
2360
2361
|
}
|
|
2361
|
-
const providerValue =
|
|
2362
|
+
const providerValue = value2.provider ?? connection.provider ?? config.provider ?? (config.google ? "google" : void 0);
|
|
2362
2363
|
if (providerValue !== void 0 && providerValue !== null && providerValue !== "google") {
|
|
2363
2364
|
throw new Error("calendar status returned an unsupported provider");
|
|
2364
2365
|
}
|
|
2365
|
-
const accessValue =
|
|
2366
|
+
const accessValue = value2.access ?? connection.access ?? config.access ?? googleConfig.access;
|
|
2366
2367
|
if (accessValue !== void 0 && accessValue !== "book" && accessValue !== "read") {
|
|
2367
2368
|
throw new Error("calendar status returned unsupported access");
|
|
2368
2369
|
}
|
|
2369
|
-
const errorValue = record(
|
|
2370
|
-
const errorCode = textField(
|
|
2371
|
-
const bookingPageValue = Object.hasOwn(
|
|
2372
|
-
const connected = typeof (
|
|
2373
|
-
const bookingCalendarId = textField(
|
|
2370
|
+
const errorValue = record(value2.error) ?? record(connection.error);
|
|
2371
|
+
const errorCode = textField(value2.lastErrorCode, 128);
|
|
2372
|
+
const bookingPageValue = Object.hasOwn(value2, "bookingPageUrl") ? value2.bookingPageUrl : Object.hasOwn(config, "bookingPageUrl") ? config.bookingPageUrl : googleConfig.bookingPageUrl;
|
|
2373
|
+
const connected = typeof (value2.connected ?? connection.connected) === "boolean" ? Boolean(value2.connected ?? connection.connected) : ["healthy", "degraded"].includes(stateValue);
|
|
2374
|
+
const bookingCalendarId = textField(value2.bookingCalendarId ?? config.bookingCalendarId, 1024);
|
|
2374
2375
|
return {
|
|
2375
2376
|
env,
|
|
2376
|
-
enabled: typeof
|
|
2377
|
+
enabled: typeof value2.enabled === "boolean" ? value2.enabled : true,
|
|
2377
2378
|
connected,
|
|
2378
|
-
writable: typeof
|
|
2379
|
+
writable: typeof value2.writable === "boolean" ? value2.writable : stateValue === "healthy",
|
|
2379
2380
|
provider: providerValue === "google" ? "google" : null,
|
|
2380
2381
|
status: stateValue,
|
|
2381
2382
|
...accessValue !== void 0 ? { access: "book" } : {},
|
|
2382
2383
|
...bookingCalendarId ? { bookingCalendarId } : {},
|
|
2383
2384
|
calendars: calendarIds(
|
|
2384
|
-
|
|
2385
|
+
value2.availabilityCalendars ?? config.availabilityCalendars ?? value2.configuredCalendars ?? value2.calendars ?? config.calendars ?? googleConfig.calendars
|
|
2385
2386
|
),
|
|
2386
2387
|
...optionalNullableUrl("bookingPageUrl", bookingPageValue),
|
|
2387
|
-
grantedScopes: stringList(
|
|
2388
|
-
...optionalText("attemptId",
|
|
2388
|
+
grantedScopes: stringList(value2.grantedScopes ?? connection.grantedScopes ?? connection.scopes),
|
|
2389
|
+
...optionalText("attemptId", value2.attemptId ?? connection.attemptId, 180),
|
|
2389
2390
|
...errorValue || errorCode ? { error: {
|
|
2390
2391
|
...textField(errorValue?.code, 128) ? { code: textField(errorValue?.code, 128) } : {},
|
|
2391
2392
|
...textField(errorValue?.message, 500) ? { message: textField(errorValue?.message, 500) } : {},
|
|
@@ -2393,9 +2394,9 @@ function parseCalendarStatus(raw, env) {
|
|
|
2393
2394
|
} } : {}
|
|
2394
2395
|
};
|
|
2395
2396
|
}
|
|
2396
|
-
function calendarState(
|
|
2397
|
-
if (typeof
|
|
2398
|
-
if (CALENDAR_STATES.includes(
|
|
2397
|
+
function calendarState(value2) {
|
|
2398
|
+
if (typeof value2 !== "string") return null;
|
|
2399
|
+
if (CALENDAR_STATES.includes(value2)) return value2;
|
|
2399
2400
|
const legacy = {
|
|
2400
2401
|
disabled: "not_connected",
|
|
2401
2402
|
disconnected: "disconnected",
|
|
@@ -2406,7 +2407,7 @@ function calendarState(value) {
|
|
|
2406
2407
|
ready: "healthy",
|
|
2407
2408
|
error: "failed"
|
|
2408
2409
|
};
|
|
2409
|
-
return legacy[
|
|
2410
|
+
return legacy[value2] ?? null;
|
|
2410
2411
|
}
|
|
2411
2412
|
async function calendarJson(ctx, suffix, init) {
|
|
2412
2413
|
const platform = platformAudience(ctx.platform);
|
|
@@ -2440,50 +2441,50 @@ function wrapped(raw, key) {
|
|
|
2440
2441
|
if (!outer) throw new Error("calendar returned an invalid response");
|
|
2441
2442
|
return record(outer[key]) ?? outer;
|
|
2442
2443
|
}
|
|
2443
|
-
function record(
|
|
2444
|
-
return
|
|
2444
|
+
function record(value2) {
|
|
2445
|
+
return value2 !== null && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
|
|
2445
2446
|
}
|
|
2446
|
-
function textField(
|
|
2447
|
-
return typeof
|
|
2447
|
+
function textField(value2, max) {
|
|
2448
|
+
return typeof value2 === "string" && value2.length > 0 && value2.length <= max && !/[\u0000-\u001f\u007f]/.test(value2) ? value2 : void 0;
|
|
2448
2449
|
}
|
|
2449
|
-
function stringList(
|
|
2450
|
-
return Array.isArray(
|
|
2450
|
+
function stringList(value2) {
|
|
2451
|
+
return Array.isArray(value2) ? [...new Set(value2.filter((item) => !!textField(item, 4096)))] : [];
|
|
2451
2452
|
}
|
|
2452
|
-
function calendarIds(
|
|
2453
|
-
if (!Array.isArray(
|
|
2454
|
-
return [...new Set(
|
|
2453
|
+
function calendarIds(value2) {
|
|
2454
|
+
if (!Array.isArray(value2)) return [];
|
|
2455
|
+
return [...new Set(value2.flatMap((item) => {
|
|
2455
2456
|
if (typeof item === "string") return textField(item, 4096) ? [item] : [];
|
|
2456
2457
|
const calendar = record(item);
|
|
2457
2458
|
const id = textField(calendar?.id, 4096);
|
|
2458
2459
|
return id && calendar?.selected !== false ? [id] : [];
|
|
2459
2460
|
}))];
|
|
2460
2461
|
}
|
|
2461
|
-
function timestamp3(
|
|
2462
|
-
if (typeof
|
|
2463
|
-
if (typeof
|
|
2464
|
-
const parsed = Date.parse(
|
|
2462
|
+
function timestamp3(value2) {
|
|
2463
|
+
if (typeof value2 === "number" && Number.isFinite(value2) && value2 >= 0) return value2;
|
|
2464
|
+
if (typeof value2 === "string") {
|
|
2465
|
+
const parsed = Date.parse(value2);
|
|
2465
2466
|
if (Number.isFinite(parsed)) return parsed;
|
|
2466
2467
|
}
|
|
2467
2468
|
return void 0;
|
|
2468
2469
|
}
|
|
2469
|
-
function optionalText(key,
|
|
2470
|
-
const parsed = textField(
|
|
2470
|
+
function optionalText(key, value2, max) {
|
|
2471
|
+
const parsed = textField(value2, max);
|
|
2471
2472
|
return parsed ? { [key]: parsed } : {};
|
|
2472
2473
|
}
|
|
2473
|
-
function optionalNullableUrl(key,
|
|
2474
|
-
if (
|
|
2475
|
-
const parsed = textField(
|
|
2474
|
+
function optionalNullableUrl(key, value2) {
|
|
2475
|
+
if (value2 === null) return { [key]: null };
|
|
2476
|
+
const parsed = textField(value2, 4096);
|
|
2476
2477
|
return parsed ? { [key]: parsed } : {};
|
|
2477
2478
|
}
|
|
2478
|
-
function identifier(
|
|
2479
|
-
if (typeof
|
|
2480
|
-
return
|
|
2479
|
+
function identifier(value2, name) {
|
|
2480
|
+
if (typeof value2 !== "string" || !/^[A-Za-z0-9][A-Za-z0-9._:-]{0,179}$/.test(value2)) throw new Error(`${name} is invalid`);
|
|
2481
|
+
return value2;
|
|
2481
2482
|
}
|
|
2482
|
-
function credential(
|
|
2483
|
-
if (typeof
|
|
2483
|
+
function credential(value2) {
|
|
2484
|
+
if (typeof value2 !== "string" || value2.length < 8 || value2.length > 8192 || /\s|[\u0000-\u001f\u007f]/.test(value2)) {
|
|
2484
2485
|
throw new Error("calendar requires an odla developer token");
|
|
2485
2486
|
}
|
|
2486
|
-
return
|
|
2487
|
+
return value2;
|
|
2487
2488
|
}
|
|
2488
2489
|
|
|
2489
2490
|
// src/calendar-poll.ts
|
|
@@ -2644,11 +2645,11 @@ async function connectWithContext(ctx, options) {
|
|
|
2644
2645
|
}
|
|
2645
2646
|
throw new Error('Google Calendar consent timed out; run "odla-ai calendar status" and retry connect');
|
|
2646
2647
|
}
|
|
2647
|
-
function trustedCalendarConsentUrl(platform,
|
|
2648
|
+
function trustedCalendarConsentUrl(platform, value2) {
|
|
2648
2649
|
const origin = platformAudience(platform);
|
|
2649
2650
|
let url;
|
|
2650
2651
|
try {
|
|
2651
|
-
url =
|
|
2652
|
+
url = value2.startsWith("/") ? new URL(value2, origin) : new URL(value2);
|
|
2652
2653
|
} catch {
|
|
2653
2654
|
throw new Error("odla.ai returned an invalid calendar consent URL");
|
|
2654
2655
|
}
|
|
@@ -2659,9 +2660,9 @@ function trustedCalendarConsentUrl(platform, value) {
|
|
|
2659
2660
|
}
|
|
2660
2661
|
return url.toString();
|
|
2661
2662
|
}
|
|
2662
|
-
function pollTimeout(
|
|
2663
|
-
if (!Number.isSafeInteger(
|
|
2664
|
-
return
|
|
2663
|
+
function pollTimeout(value2 = 10 * 6e4) {
|
|
2664
|
+
if (!Number.isSafeInteger(value2) || value2 < 1e3 || value2 > 60 * 6e4) throw new Error("calendar poll timeout must be 1000-3600000ms");
|
|
2665
|
+
return value2;
|
|
2665
2666
|
}
|
|
2666
2667
|
function productionConsent(env, yes, action) {
|
|
2667
2668
|
if ((env === "prod" || env === "production") && !yes) throw new Error(`refusing to ${action} for "${env}" without --yes`);
|
|
@@ -2693,6 +2694,7 @@ var CAPABILITIES = {
|
|
|
2693
2694
|
"validate integration contracts offline and smoke-test a provisioned db environment plus anonymous capability routes",
|
|
2694
2695
|
"save and explicitly select non-secret named operator contexts with isolated credential caches; resolve and explain platform, app, environment, and credential provenance without authenticating; then run PM, Discussions, o11y, runbook, and identity operations outside a project checkout",
|
|
2695
2696
|
"read one versioned o11y status envelope spanning application RED, exact Worker versions and Cloudflare colos observed in traffic, current live-sync freshness/load, the protected commit-to-visible canary, collector ingest/scheduler trust, provider-owned runtime metrics, account-scoped Durable Object, D1, and R2 evidence under odla-db, and a bounded machine verdict",
|
|
2697
|
+
"read one canonical platform fleet snapshot over private service bindings, including release identities, probe latency, Cloudflare load/runtime freshness, explicit unknowns, and stable next actions through a read-only capability",
|
|
2696
2698
|
"inspect durable agent wakeups as a versioned JSON envelope and explicitly requeue one dead-lettered job with a scoped environment credential",
|
|
2697
2699
|
"run app-attributed hosted security discovery and independent validation without provider keys",
|
|
2698
2700
|
"connect/revoke source-read-only GitHub sources and drive commit-pinned hosted security jobs without PATs or provider keys",
|
|
@@ -2876,8 +2878,8 @@ function wranglerWarnings(rootDir) {
|
|
|
2876
2878
|
}
|
|
2877
2879
|
const vars = block.vars;
|
|
2878
2880
|
if (vars && typeof vars === "object") {
|
|
2879
|
-
for (const [name,
|
|
2880
|
-
if (name === "ODLA_API_KEY" || name === "ODLA_O11Y_TOKEN" || typeof
|
|
2881
|
+
for (const [name, value2] of Object.entries(vars)) {
|
|
2882
|
+
if (name === "ODLA_API_KEY" || name === "ODLA_O11Y_TOKEN" || typeof value2 === "string" && looksSecret(value2)) {
|
|
2881
2883
|
warnings.push(`wrangler ${label}vars.${name} looks like a secret \u2014 use "odla-ai secrets push" / wrangler secret put, never vars`);
|
|
2882
2884
|
}
|
|
2883
2885
|
}
|
|
@@ -3045,27 +3047,27 @@ function isUniqueAttr(schema, ns, attr) {
|
|
|
3045
3047
|
const definition = entity.attrs[attr];
|
|
3046
3048
|
return isRecord6(definition) && definition.unique === true;
|
|
3047
3049
|
}
|
|
3048
|
-
function normalizeSchema(
|
|
3049
|
-
if (
|
|
3050
|
-
if (!isRecord6(
|
|
3050
|
+
function normalizeSchema(value2) {
|
|
3051
|
+
if (value2 === void 0 || value2 === null) return { entities: {}, links: {} };
|
|
3052
|
+
if (!isRecord6(value2) || !isRecord6(value2.entities)) {
|
|
3051
3053
|
throw new Error("db schema must be a serialized schema object with an entities map");
|
|
3052
3054
|
}
|
|
3053
|
-
if (
|
|
3055
|
+
if (value2.links !== void 0 && !isRecord6(value2.links)) throw new Error("db schema links must be an object");
|
|
3054
3056
|
return {
|
|
3055
|
-
entities: { ...
|
|
3056
|
-
links: { ...
|
|
3057
|
+
entities: { ...value2.entities },
|
|
3058
|
+
links: { ...value2.links ?? {} }
|
|
3057
3059
|
};
|
|
3058
3060
|
}
|
|
3059
3061
|
function mergeMap(target, fragment, label) {
|
|
3060
|
-
for (const [name,
|
|
3061
|
-
if (Object.hasOwn(target, name) && !(0, import_node_util.isDeepStrictEqual)(target[name],
|
|
3062
|
+
for (const [name, value2] of Object.entries(fragment)) {
|
|
3063
|
+
if (Object.hasOwn(target, name) && !(0, import_node_util.isDeepStrictEqual)(target[name], value2)) {
|
|
3062
3064
|
throw new Error(`${label} "${name}" conflicts with an existing definition`);
|
|
3063
3065
|
}
|
|
3064
|
-
target[name] =
|
|
3066
|
+
target[name] = value2;
|
|
3065
3067
|
}
|
|
3066
3068
|
}
|
|
3067
|
-
function isRecord6(
|
|
3068
|
-
return
|
|
3069
|
+
function isRecord6(value2) {
|
|
3070
|
+
return value2 !== null && typeof value2 === "object" && !Array.isArray(value2);
|
|
3069
3071
|
}
|
|
3070
3072
|
|
|
3071
3073
|
// src/doctor.ts
|
|
@@ -3106,9 +3108,9 @@ async function doctor(options) {
|
|
|
3106
3108
|
warnings.push(...integrationWarnings(database.integrations, schema, rules));
|
|
3107
3109
|
if (cfg.services.includes("ai") && !cfg.ai?.provider) warnings.push("ai service is enabled but ai.provider is not set");
|
|
3108
3110
|
if (cfg.auth?.clerk) {
|
|
3109
|
-
for (const [env,
|
|
3110
|
-
if (typeof
|
|
3111
|
-
warnings.push(`auth.clerk.${env} references unset env var ${
|
|
3111
|
+
for (const [env, value2] of Object.entries(cfg.auth.clerk)) {
|
|
3112
|
+
if (typeof value2 === "string" && value2.startsWith("$") && !process.env[value2.slice(1)]) {
|
|
3113
|
+
warnings.push(`auth.clerk.${env} references unset env var ${value2}`);
|
|
3112
3114
|
}
|
|
3113
3115
|
}
|
|
3114
3116
|
}
|
|
@@ -3150,10 +3152,10 @@ function harnessList(parsed) {
|
|
|
3150
3152
|
];
|
|
3151
3153
|
return selected.length ? selected : ["all"];
|
|
3152
3154
|
}
|
|
3153
|
-
function harnessOption(
|
|
3154
|
-
if (
|
|
3155
|
-
if (typeof
|
|
3156
|
-
const raw = Array.isArray(
|
|
3155
|
+
function harnessOption(value2, flag) {
|
|
3156
|
+
if (value2 === void 0) return [];
|
|
3157
|
+
if (typeof value2 === "boolean") throw new Error(`${flag} requires a harness name`);
|
|
3158
|
+
const raw = Array.isArray(value2) ? value2 : [value2];
|
|
3157
3159
|
const parts = raw.flatMap((item) => item.split(","));
|
|
3158
3160
|
if (parts.some((item) => !item.trim())) {
|
|
3159
3161
|
throw new Error(`${flag} requires a harness name`);
|
|
@@ -3381,38 +3383,38 @@ async function secretsSet(options) {
|
|
|
3381
3383
|
if (name.startsWith("$")) {
|
|
3382
3384
|
throw new Error('"$"-prefixed vault names are platform-reserved; for the Clerk secret key use "odla-ai secrets set-clerk-key"');
|
|
3383
3385
|
}
|
|
3384
|
-
const { cfg, tenantId, value, doFetch, out } = await resolveVaultWrite(options);
|
|
3386
|
+
const { cfg, tenantId, value: value2, doFetch, out } = await resolveVaultWrite(options);
|
|
3385
3387
|
const token = await getDeveloperToken(cfg, options, doFetch, out);
|
|
3386
3388
|
try {
|
|
3387
|
-
await (0, import_ai.putSecret)({ endpoint: cfg.dbEndpoint, token, fetch: doFetch }, tenantId, name,
|
|
3389
|
+
await (0, import_ai.putSecret)({ endpoint: cfg.dbEndpoint, token, fetch: doFetch }, tenantId, name, value2);
|
|
3388
3390
|
} catch (err) {
|
|
3389
|
-
throw new Error(scrubValue(err instanceof Error ? err.message : String(err),
|
|
3391
|
+
throw new Error(scrubValue(err instanceof Error ? err.message : String(err), value2));
|
|
3390
3392
|
}
|
|
3391
3393
|
out.log(`${name} stored in the ${tenantId} vault (write-only; the value was never echoed and cannot be read back here)`);
|
|
3392
3394
|
}
|
|
3393
3395
|
async function secretsSetClerkKey(options) {
|
|
3394
|
-
const { cfg, tenantId, value, doFetch, out } = await resolveVaultWrite(options);
|
|
3395
|
-
if (!
|
|
3396
|
-
if (
|
|
3396
|
+
const { cfg, tenantId, value: value2, doFetch, out } = await resolveVaultWrite(options);
|
|
3397
|
+
if (!value2.startsWith("sk_")) throw new Error("the Clerk secret key must start with sk_ (sk_test_\u2026 or sk_live_\u2026)");
|
|
3398
|
+
if (value2.startsWith("sk_test_") && PROD_ENV_NAMES2.has(options.env)) {
|
|
3397
3399
|
throw new Error(`refusing to store an sk_test_ Clerk key for "${options.env}" \u2014 use the production instance's sk_live_ key`);
|
|
3398
3400
|
}
|
|
3399
|
-
if (
|
|
3401
|
+
if (value2.startsWith("sk_live_") && !PROD_ENV_NAMES2.has(options.env) && !options.yes) {
|
|
3400
3402
|
throw new Error(`refusing to store an sk_live_ Clerk key for "${options.env}" without --yes (live users would sync into a non-prod tenant)`);
|
|
3401
3403
|
}
|
|
3402
3404
|
const token = await getDeveloperToken(cfg, options, doFetch, out);
|
|
3403
3405
|
const res = await doFetch(`${cfg.dbEndpoint}/admin/apps/${encodeURIComponent(tenantId)}/clerk-secret`, {
|
|
3404
3406
|
method: "POST",
|
|
3405
3407
|
headers: { authorization: `Bearer ${token}`, "content-type": "application/json" },
|
|
3406
|
-
body: JSON.stringify({ value })
|
|
3408
|
+
body: JSON.stringify({ value: value2 })
|
|
3407
3409
|
});
|
|
3408
3410
|
if (!res.ok) {
|
|
3409
|
-
const text = scrubValue((await res.text().catch(() => "")).slice(0, 300),
|
|
3411
|
+
const text = scrubValue((await res.text().catch(() => "")).slice(0, 300), value2);
|
|
3410
3412
|
throw new Error(`store Clerk secret key failed (${res.status}): ${text || "request failed"}`);
|
|
3411
3413
|
}
|
|
3412
3414
|
out.log(`Clerk secret key stored for ${tenantId} ($clerk_secret, reserved + write-only; the value was never echoed)`);
|
|
3413
3415
|
}
|
|
3414
|
-
function scrubValue(text,
|
|
3415
|
-
return redactSecrets(text).split(
|
|
3416
|
+
function scrubValue(text, value2) {
|
|
3417
|
+
return redactSecrets(text).split(value2).join("[value redacted]");
|
|
3416
3418
|
}
|
|
3417
3419
|
async function resolveVaultWrite(options) {
|
|
3418
3420
|
const out = options.stdout ?? console;
|
|
@@ -3424,8 +3426,8 @@ async function resolveVaultWrite(options) {
|
|
|
3424
3426
|
if (PROD_ENV_NAMES2.has(options.env) && !options.yes) {
|
|
3425
3427
|
throw new Error(`refusing to store a secret for "${options.env}" without --yes`);
|
|
3426
3428
|
}
|
|
3427
|
-
const
|
|
3428
|
-
return { cfg, tenantId: (0, import_apps4.tenantIdFor)(cfg.app.id, options.env), value, doFetch, out };
|
|
3429
|
+
const value2 = await secretInputValue(options, "secret");
|
|
3430
|
+
return { cfg, tenantId: (0, import_apps4.tenantIdFor)(cfg.app.id, options.env), value: value2, doFetch, out };
|
|
3429
3431
|
}
|
|
3430
3432
|
|
|
3431
3433
|
// src/skill.ts
|
|
@@ -3955,24 +3957,24 @@ var CONTROL = /[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/;
|
|
|
3955
3957
|
var HarnessProtocolError = class extends Error {
|
|
3956
3958
|
name = "HarnessProtocolError";
|
|
3957
3959
|
};
|
|
3958
|
-
function record2(
|
|
3959
|
-
return
|
|
3960
|
+
function record2(value2) {
|
|
3961
|
+
return value2 !== null && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
|
|
3960
3962
|
}
|
|
3961
|
-
function boundedText(
|
|
3962
|
-
if (typeof
|
|
3963
|
+
function boundedText(value2, label, max) {
|
|
3964
|
+
if (typeof value2 !== "string" || !value2 || value2.length > max || CONTROL.test(value2)) {
|
|
3963
3965
|
throw new HarnessProtocolError(`${label} must be a non-empty string of at most ${max} characters`);
|
|
3964
3966
|
}
|
|
3965
|
-
return
|
|
3967
|
+
return value2;
|
|
3966
3968
|
}
|
|
3967
3969
|
function parseAgentOutput(line) {
|
|
3968
3970
|
if (Buffer.byteLength(line, "utf8") > 1e6) throw new HarnessProtocolError("agent message exceeds 1 MB");
|
|
3969
|
-
let
|
|
3971
|
+
let value2;
|
|
3970
3972
|
try {
|
|
3971
|
-
|
|
3973
|
+
value2 = JSON.parse(line);
|
|
3972
3974
|
} catch {
|
|
3973
3975
|
throw new HarnessProtocolError("agent emitted invalid JSON");
|
|
3974
3976
|
}
|
|
3975
|
-
const message2 = record2(
|
|
3977
|
+
const message2 = record2(value2);
|
|
3976
3978
|
if (!message2 || message2.protocolVersion !== HARNESS_PROTOCOL_VERSION) {
|
|
3977
3979
|
throw new HarnessProtocolError(`agent protocolVersion must be ${HARNESS_PROTOCOL_VERSION}`);
|
|
3978
3980
|
}
|
|
@@ -4281,7 +4283,7 @@ async function gitOutput(cwd, args, maxBytes) {
|
|
|
4281
4283
|
else stdout.push(chunk);
|
|
4282
4284
|
});
|
|
4283
4285
|
child.stderr.on("data", (chunk) => {
|
|
4284
|
-
if (stderr.reduce((sum,
|
|
4286
|
+
if (stderr.reduce((sum, value2) => sum + value2.byteLength, 0) < 16384) stderr.push(chunk);
|
|
4285
4287
|
});
|
|
4286
4288
|
const code = await new Promise((accept, reject) => {
|
|
4287
4289
|
child.once("error", reject);
|
|
@@ -4302,7 +4304,7 @@ async function gitBlobs(cwd, entries, maxBytes) {
|
|
|
4302
4304
|
else stdout.push(chunk);
|
|
4303
4305
|
});
|
|
4304
4306
|
child.stderr.on("data", (chunk) => {
|
|
4305
|
-
if (stderr.reduce((sum,
|
|
4307
|
+
if (stderr.reduce((sum, value2) => sum + value2.byteLength, 0) < 16384) stderr.push(chunk);
|
|
4306
4308
|
});
|
|
4307
4309
|
child.stdin.end(`${entries.map((entry) => entry.hash).join("\n")}
|
|
4308
4310
|
`);
|
|
@@ -4340,8 +4342,8 @@ async function materializeGitTree(source, commitSha, options = {}) {
|
|
|
4340
4342
|
const maxFiles = options.maxFiles ?? 2e4;
|
|
4341
4343
|
const maxBytes = options.maxBytes ?? 512 * 1024 * 1024;
|
|
4342
4344
|
const inventory = (await gitOutput(sourceDir, ["ls-tree", "-rz", commitSha], 16 * 1024 * 1024)).toString("utf8").split("\0").filter(Boolean);
|
|
4343
|
-
const entries = inventory.flatMap((
|
|
4344
|
-
const match = /^(100644|100755) blob ([0-9a-f]{40,64})\t([\s\S]+)$/.exec(
|
|
4345
|
+
const entries = inventory.flatMap((record8) => {
|
|
4346
|
+
const match = /^(100644|100755) blob ([0-9a-f]{40,64})\t([\s\S]+)$/.exec(record8);
|
|
4345
4347
|
return match && allowedWorkspacePath(match[3]) ? [{ mode: match[1], hash: match[2], path: match[3] }] : [];
|
|
4346
4348
|
});
|
|
4347
4349
|
if (entries.length > maxFiles) throw new Error(`workspace exceeds ${maxFiles} files`);
|
|
@@ -4416,7 +4418,7 @@ async function gitSourceFiles(sourceDir, maxFiles, maxBytes) {
|
|
|
4416
4418
|
else stdout.push(chunk);
|
|
4417
4419
|
});
|
|
4418
4420
|
child.stderr.on("data", (chunk) => {
|
|
4419
|
-
if (stderr.reduce((sum,
|
|
4421
|
+
if (stderr.reduce((sum, value2) => sum + value2.byteLength, 0) < 16384) stderr.push(chunk);
|
|
4420
4422
|
});
|
|
4421
4423
|
const code = await new Promise((accept, reject) => {
|
|
4422
4424
|
child.once("error", reject);
|
|
@@ -4476,7 +4478,7 @@ async function captureGitDiff(root, maxBytes) {
|
|
|
4476
4478
|
else stdout.push(chunk);
|
|
4477
4479
|
});
|
|
4478
4480
|
child.stderr.on("data", (chunk) => {
|
|
4479
|
-
if (stderr.reduce((sum,
|
|
4481
|
+
if (stderr.reduce((sum, value2) => sum + value2.byteLength, 0) < 16384) stderr.push(chunk);
|
|
4480
4482
|
});
|
|
4481
4483
|
const code = await new Promise((accept, reject) => {
|
|
4482
4484
|
child.once("error", reject);
|
|
@@ -4563,34 +4565,34 @@ var CamelError = class extends Error {
|
|
|
4563
4565
|
};
|
|
4564
4566
|
|
|
4565
4567
|
// ../camel/dist/chunk-L5DYU2E2.js
|
|
4566
|
-
function canonicalJson(
|
|
4567
|
-
return JSON.stringify(normalize(
|
|
4568
|
+
function canonicalJson(value2) {
|
|
4569
|
+
return JSON.stringify(normalize(value2));
|
|
4568
4570
|
}
|
|
4569
|
-
async function sha256Hex(
|
|
4570
|
-
const bytes = typeof
|
|
4571
|
+
async function sha256Hex(value2) {
|
|
4572
|
+
const bytes = typeof value2 === "string" ? new TextEncoder().encode(value2) : value2;
|
|
4571
4573
|
const digest = await crypto.subtle.digest("SHA-256", Uint8Array.from(bytes).buffer);
|
|
4572
4574
|
return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
4573
4575
|
}
|
|
4574
|
-
function utf8Length(
|
|
4575
|
-
if (typeof
|
|
4576
|
-
if (
|
|
4576
|
+
function utf8Length(value2) {
|
|
4577
|
+
if (typeof value2 === "string") return new TextEncoder().encode(value2).byteLength;
|
|
4578
|
+
if (value2 instanceof Uint8Array) return value2.byteLength;
|
|
4577
4579
|
try {
|
|
4578
|
-
return new TextEncoder().encode(canonicalJson(
|
|
4580
|
+
return new TextEncoder().encode(canonicalJson(value2)).byteLength;
|
|
4579
4581
|
} catch {
|
|
4580
4582
|
throw new CamelError("conversion_rejected", "Unsafe input could not be canonically measured.");
|
|
4581
4583
|
}
|
|
4582
4584
|
}
|
|
4583
|
-
function normalize(
|
|
4584
|
-
if (
|
|
4585
|
-
if (typeof
|
|
4586
|
-
if (!Number.isFinite(
|
|
4587
|
-
return
|
|
4585
|
+
function normalize(value2) {
|
|
4586
|
+
if (value2 === null || typeof value2 === "string" || typeof value2 === "boolean") return value2;
|
|
4587
|
+
if (typeof value2 === "number") {
|
|
4588
|
+
if (!Number.isFinite(value2)) throw new CamelError("state_conflict", "Canonical JSON rejects non-finite numbers.");
|
|
4589
|
+
return value2;
|
|
4588
4590
|
}
|
|
4589
|
-
if (Array.isArray(
|
|
4590
|
-
if (
|
|
4591
|
-
if (typeof
|
|
4592
|
-
const
|
|
4593
|
-
return Object.fromEntries(Object.keys(
|
|
4591
|
+
if (Array.isArray(value2)) return value2.map(normalize);
|
|
4592
|
+
if (value2 instanceof Uint8Array) return { $bytes: [...value2] };
|
|
4593
|
+
if (typeof value2 === "object") {
|
|
4594
|
+
const record8 = value2;
|
|
4595
|
+
return Object.fromEntries(Object.keys(record8).filter((key) => record8[key] !== void 0).sort().map((key) => [key, normalize(record8[key])]));
|
|
4594
4596
|
}
|
|
4595
4597
|
throw new CamelError("state_conflict", "Canonical JSON rejects unsupported values.");
|
|
4596
4598
|
}
|
|
@@ -4599,10 +4601,10 @@ function canRead(readers, readerId) {
|
|
|
4599
4601
|
}
|
|
4600
4602
|
function dependenciesOf(values, influence = "data") {
|
|
4601
4603
|
const result = [];
|
|
4602
|
-
for (const
|
|
4603
|
-
result.push(...
|
|
4604
|
-
for (const ref of
|
|
4605
|
-
result.push({ ref, influence, promptSafetyAtUse:
|
|
4604
|
+
for (const value2 of values) {
|
|
4605
|
+
result.push(...value2.label.dependencies);
|
|
4606
|
+
for (const ref of value2.label.provenance) {
|
|
4607
|
+
result.push({ ref, influence, promptSafetyAtUse: value2.label.promptSafety });
|
|
4606
4608
|
}
|
|
4607
4609
|
}
|
|
4608
4610
|
const unique3 = /* @__PURE__ */ new Map();
|
|
@@ -4613,32 +4615,32 @@ function dependenciesOf(values, influence = "data") {
|
|
|
4613
4615
|
// ../camel/dist/chunk-S7EVNA2U.js
|
|
4614
4616
|
var camelValueBrand = /* @__PURE__ */ Symbol("@odla-ai/camel/value");
|
|
4615
4617
|
var authenticCamelValues = /* @__PURE__ */ new WeakSet();
|
|
4616
|
-
function isCamelValue(
|
|
4617
|
-
return typeof
|
|
4618
|
+
function isCamelValue(value2) {
|
|
4619
|
+
return typeof value2 === "object" && value2 !== null && authenticCamelValues.has(value2);
|
|
4618
4620
|
}
|
|
4619
|
-
function isSafe(
|
|
4620
|
-
return isCamelValue(
|
|
4621
|
+
function isSafe(value2) {
|
|
4622
|
+
return isCamelValue(value2) && value2.label.promptSafety === "safe";
|
|
4621
4623
|
}
|
|
4622
|
-
function isUnsafe(
|
|
4623
|
-
return isCamelValue(
|
|
4624
|
+
function isUnsafe(value2) {
|
|
4625
|
+
return isCamelValue(value2) && value2.label.promptSafety === "unsafe";
|
|
4624
4626
|
}
|
|
4625
|
-
function createSafeInternal(
|
|
4626
|
-
return createValue(
|
|
4627
|
+
function createSafeInternal(value2, safeBasis, metadata2) {
|
|
4628
|
+
return createValue(value2, {
|
|
4627
4629
|
schemaVersion: 1,
|
|
4628
4630
|
promptSafety: "safe",
|
|
4629
4631
|
safeBasis,
|
|
4630
4632
|
...copyMetadata(metadata2)
|
|
4631
4633
|
});
|
|
4632
4634
|
}
|
|
4633
|
-
function createUnsafeInternal(
|
|
4634
|
-
return createValue(
|
|
4635
|
+
function createUnsafeInternal(value2, metadata2) {
|
|
4636
|
+
return createValue(value2, {
|
|
4635
4637
|
schemaVersion: 1,
|
|
4636
4638
|
promptSafety: "unsafe",
|
|
4637
4639
|
...copyMetadata(metadata2)
|
|
4638
4640
|
});
|
|
4639
4641
|
}
|
|
4640
|
-
function createValue(
|
|
4641
|
-
const result = { value, label: Object.freeze(label) };
|
|
4642
|
+
function createValue(value2, label) {
|
|
4643
|
+
const result = { value: value2, label: Object.freeze(label) };
|
|
4642
4644
|
Object.defineProperty(result, camelValueBrand, { value: label.promptSafety, enumerable: false });
|
|
4643
4645
|
authenticCamelValues.add(result);
|
|
4644
4646
|
return Object.freeze(result);
|
|
@@ -4744,8 +4746,8 @@ async function createCodePortableCheckpoint(input) {
|
|
|
4744
4746
|
const checkpointDigest = `sha256:${await sha256Hex(canonicalJson(fields))}`;
|
|
4745
4747
|
return freeze({ ...fields, patch: input.patch, checkpointDigest });
|
|
4746
4748
|
}
|
|
4747
|
-
async function verifyCodePortableCheckpoint(
|
|
4748
|
-
const input = object(
|
|
4749
|
+
async function verifyCodePortableCheckpoint(value2) {
|
|
4750
|
+
const input = object(value2, "checkpoint");
|
|
4749
4751
|
exact2(input, ["schemaVersion", "baseCommitSha", "patch", "patchDigest", "state", "stateDigest", "checkpointDigest"]);
|
|
4750
4752
|
if (input.schemaVersion !== 1 || typeof input.baseCommitSha !== "string" || typeof input.patch !== "string" || typeof input.patchDigest !== "string" || typeof input.stateDigest !== "string" || typeof input.checkpointDigest !== "string") {
|
|
4751
4753
|
throw invalid2("Portable checkpoint fields are malformed.");
|
|
@@ -4760,8 +4762,8 @@ async function verifyCodePortableCheckpoint(value) {
|
|
|
4760
4762
|
}
|
|
4761
4763
|
return created;
|
|
4762
4764
|
}
|
|
4763
|
-
function normalizeState(
|
|
4764
|
-
const state2 = object(
|
|
4765
|
+
function normalizeState(value2) {
|
|
4766
|
+
const state2 = object(value2, "state");
|
|
4765
4767
|
exact2(state2, [
|
|
4766
4768
|
"planCursor",
|
|
4767
4769
|
"conversationRefs",
|
|
@@ -4819,30 +4821,30 @@ function validateBaseAndPatch(baseCommitSha, patch2) {
|
|
|
4819
4821
|
throw invalid2("Portable checkpoint base or patch is malformed or outside its bounds.");
|
|
4820
4822
|
}
|
|
4821
4823
|
}
|
|
4822
|
-
function strings(
|
|
4823
|
-
if (!Array.isArray(
|
|
4824
|
+
function strings(value2, name, pattern, maximum, sort) {
|
|
4825
|
+
if (!Array.isArray(value2) || value2.length > maximum || value2.some((item) => typeof item !== "string" || !pattern.test(item)) || new Set(value2).size !== value2.length) {
|
|
4824
4826
|
throw invalid2(`Portable checkpoint ${name} is malformed or outside its bounds.`);
|
|
4825
4827
|
}
|
|
4826
|
-
const result = [...
|
|
4828
|
+
const result = [...value2];
|
|
4827
4829
|
return sort ? result.sort() : result;
|
|
4828
4830
|
}
|
|
4829
|
-
function object(
|
|
4830
|
-
if (!
|
|
4831
|
-
return
|
|
4831
|
+
function object(value2, name) {
|
|
4832
|
+
if (!value2 || typeof value2 !== "object" || Array.isArray(value2)) throw invalid2(`Portable ${name} must be an object.`);
|
|
4833
|
+
return value2;
|
|
4832
4834
|
}
|
|
4833
|
-
function exact2(
|
|
4834
|
-
if (Object.keys(
|
|
4835
|
+
function exact2(value2, keys) {
|
|
4836
|
+
if (Object.keys(value2).some((key) => !keys.includes(key)) || keys.some((key) => !(key in value2))) {
|
|
4835
4837
|
throw invalid2("Portable checkpoint contains missing or unsupported fields.");
|
|
4836
4838
|
}
|
|
4837
4839
|
}
|
|
4838
|
-
function freeze(
|
|
4840
|
+
function freeze(value2) {
|
|
4839
4841
|
return Object.freeze({
|
|
4840
|
-
...
|
|
4842
|
+
...value2,
|
|
4841
4843
|
state: Object.freeze({
|
|
4842
|
-
...
|
|
4843
|
-
conversationRefs: Object.freeze([...
|
|
4844
|
-
completedEffects: Object.freeze(
|
|
4845
|
-
unresolvedApprovals: Object.freeze([...
|
|
4844
|
+
...value2.state,
|
|
4845
|
+
conversationRefs: Object.freeze([...value2.state.conversationRefs]),
|
|
4846
|
+
completedEffects: Object.freeze(value2.state.completedEffects.map((item) => Object.freeze({ ...item }))),
|
|
4847
|
+
unresolvedApprovals: Object.freeze([...value2.state.unresolvedApprovals])
|
|
4846
4848
|
})
|
|
4847
4849
|
});
|
|
4848
4850
|
}
|
|
@@ -4933,61 +4935,61 @@ async function createConversionRegistry(config) {
|
|
|
4933
4935
|
if (utf8Length(source.value) > policy.maximumSourceBytes) throw new CamelError("limit_exceeded", "Unsafe conversion input exceeds its byte bound.");
|
|
4934
4936
|
return policy;
|
|
4935
4937
|
};
|
|
4936
|
-
const emit3 = (source, policy,
|
|
4938
|
+
const emit3 = (source, policy, value2) => convert(source, policy, value2, outputCounts);
|
|
4937
4939
|
const operations = Object.freeze({
|
|
4938
|
-
boolean: async (
|
|
4939
|
-
const policy = checked(
|
|
4940
|
-
return emit3(
|
|
4940
|
+
boolean: async (value2, id) => {
|
|
4941
|
+
const policy = checked(value2, id, "boolean");
|
|
4942
|
+
return emit3(value2, policy, requireBoolean(value2.value));
|
|
4941
4943
|
},
|
|
4942
|
-
integer: async (
|
|
4943
|
-
const policy = checked(
|
|
4944
|
-
return emit3(
|
|
4944
|
+
integer: async (value2, id) => {
|
|
4945
|
+
const policy = checked(value2, id, "integer");
|
|
4946
|
+
return emit3(value2, policy, boundedInteger(value2.value, policy.output));
|
|
4945
4947
|
},
|
|
4946
|
-
finiteNumber: async (
|
|
4947
|
-
const policy = checked(
|
|
4948
|
-
return emit3(
|
|
4948
|
+
finiteNumber: async (value2, id) => {
|
|
4949
|
+
const policy = checked(value2, id, "finite_number");
|
|
4950
|
+
return emit3(value2, policy, boundedNumber(value2.value, policy.output));
|
|
4949
4951
|
},
|
|
4950
|
-
enum: async (
|
|
4951
|
-
const policy = checked(
|
|
4952
|
-
return emit3(
|
|
4952
|
+
enum: async (value2, id) => {
|
|
4953
|
+
const policy = checked(value2, id, "enum");
|
|
4954
|
+
return emit3(value2, policy, enumMember(value2.value, policy.output));
|
|
4953
4955
|
},
|
|
4954
|
-
date: async (
|
|
4955
|
-
const policy = checked(
|
|
4956
|
-
return emit3(
|
|
4956
|
+
date: async (value2, id) => {
|
|
4957
|
+
const policy = checked(value2, id, "date");
|
|
4958
|
+
return emit3(value2, policy, canonicalDate(value2.value, policy.output));
|
|
4957
4959
|
},
|
|
4958
|
-
registeredId: async (
|
|
4959
|
-
const policy = checked(
|
|
4960
|
+
registeredId: async (value2, id) => {
|
|
4961
|
+
const policy = checked(value2, id, "registered_id");
|
|
4960
4962
|
const registry = config.registeredIds?.[policy.output.registryId];
|
|
4961
|
-
const output = typeof
|
|
4963
|
+
const output = typeof value2.value === "string" ? registry?.values[value2.value] : void 0;
|
|
4962
4964
|
if (!output) throw new CamelError("conversion_rejected", "Registered-ID conversion rejected the candidate.");
|
|
4963
|
-
return emit3(
|
|
4965
|
+
return emit3(value2, policy, output);
|
|
4964
4966
|
},
|
|
4965
|
-
digest: async (
|
|
4966
|
-
const policy = checked(
|
|
4967
|
-
if (!(
|
|
4968
|
-
return emit3(
|
|
4967
|
+
digest: async (value2, id) => {
|
|
4968
|
+
const policy = checked(value2, id, "digest");
|
|
4969
|
+
if (!(value2.value instanceof Uint8Array)) throw new CamelError("conversion_rejected", "Digest conversion requires bytes.");
|
|
4970
|
+
return emit3(value2, policy, await sha256Hex(value2.value));
|
|
4969
4971
|
},
|
|
4970
|
-
measure: async (
|
|
4971
|
-
const policy = checked(
|
|
4972
|
-
const measured = measure(
|
|
4973
|
-
return emit3(
|
|
4972
|
+
measure: async (value2, metric, id) => {
|
|
4973
|
+
const policy = checked(value2, id, "integer");
|
|
4974
|
+
const measured = measure(value2.value, metric);
|
|
4975
|
+
return emit3(value2, policy, boundedInteger(measured, policy.output));
|
|
4974
4976
|
},
|
|
4975
|
-
test: async (
|
|
4976
|
-
const policy = checked(
|
|
4977
|
+
test: async (value2, predicateId, id) => {
|
|
4978
|
+
const policy = checked(value2, id, "boolean");
|
|
4977
4979
|
const predicate = config.predicates?.[predicateId];
|
|
4978
4980
|
if (!predicate) throw new CamelError("conversion_rejected", "Predicate is not registered.");
|
|
4979
|
-
return emit3(
|
|
4981
|
+
return emit3(value2, policy, evaluatePredicate(value2.value, predicate, config.registeredIds));
|
|
4980
4982
|
}
|
|
4981
4983
|
});
|
|
4982
4984
|
return Object.freeze({ operations, policy: (id) => policies.get(id) ?? missingPolicy() });
|
|
4983
4985
|
}
|
|
4984
|
-
async function convert(source, policy,
|
|
4986
|
+
async function convert(source, policy, value2, counts) {
|
|
4985
4987
|
const sourceKey = sourceIdentity(source);
|
|
4986
4988
|
const countKey = `${policy.conversionId}\0${sourceKey}`;
|
|
4987
4989
|
const count = counts.get(countKey) ?? 0;
|
|
4988
4990
|
if (count >= policy.maximumOutputsPerArtifact) throw new CamelError("limit_exceeded", "Conversion output count exceeds its per-source bound.");
|
|
4989
4991
|
counts.set(countKey, count + 1);
|
|
4990
|
-
return createSafeInternal(
|
|
4992
|
+
return createSafeInternal(value2, "atomic_conversion", {
|
|
4991
4993
|
readers: source.label.readers,
|
|
4992
4994
|
provenance: [...source.label.provenance, { kind: "converter", id: policy.conversionId, digest: policy.digest }],
|
|
4993
4995
|
dependencies: dependenciesOf([source])
|
|
@@ -4999,49 +5001,49 @@ function validatePolicyShape(policy) {
|
|
|
4999
5001
|
const output = policy.output;
|
|
5000
5002
|
if ((output.kind === "integer" || output.kind === "finite_number") && (!Number.isFinite(output.minimum) || !Number.isFinite(output.maximum) || output.minimum > output.maximum)) throw new CamelError("state_conflict", "Numeric conversion bounds are invalid.");
|
|
5001
5003
|
if (output.kind === "finite_number" && (!Number.isSafeInteger(output.maximumDecimalPlaces) || output.maximumDecimalPlaces < 0 || output.maximumDecimalPlaces > 15)) throw new CamelError("state_conflict", "Decimal-place bound is invalid.");
|
|
5002
|
-
if (output.kind === "enum" && (output.values.length === 0 || output.values.some((
|
|
5004
|
+
if (output.kind === "enum" && (output.values.length === 0 || output.values.some((value2) => typeof value2 !== "string" || !value2) || new Set(output.values).size !== output.values.length)) throw new CamelError("state_conflict", "Enum conversion members must be unique and non-empty.");
|
|
5003
5005
|
if (output.kind === "registered_id" && (!output.registryId || !output.registryDigest)) throw new CamelError("state_conflict", "Registered-ID conversion identity is invalid.");
|
|
5004
5006
|
if (output.kind === "date" && output.format !== "date" && output.format !== "rfc3339") throw new CamelError("state_conflict", "Date conversion format is invalid.");
|
|
5005
5007
|
if (output.kind === "digest" && output.algorithm !== "sha256") throw new CamelError("state_conflict", "Digest conversion algorithm is invalid.");
|
|
5006
5008
|
}
|
|
5007
|
-
function requireBoolean(
|
|
5008
|
-
if (typeof
|
|
5009
|
-
return
|
|
5009
|
+
function requireBoolean(value2) {
|
|
5010
|
+
if (typeof value2 !== "boolean") throw new CamelError("conversion_rejected", "Boolean conversion requires a structured boolean.");
|
|
5011
|
+
return value2;
|
|
5010
5012
|
}
|
|
5011
|
-
function boundedInteger(
|
|
5012
|
-
if (spec.kind !== "integer" || typeof
|
|
5013
|
-
return
|
|
5013
|
+
function boundedInteger(value2, spec) {
|
|
5014
|
+
if (spec.kind !== "integer" || typeof value2 !== "number" || !Number.isSafeInteger(value2) || value2 < spec.minimum || value2 > spec.maximum) throw new CamelError("conversion_rejected", "Integer conversion rejected the structured value.");
|
|
5015
|
+
return value2;
|
|
5014
5016
|
}
|
|
5015
|
-
function boundedNumber(
|
|
5016
|
-
if (spec.kind !== "finite_number" || typeof
|
|
5017
|
-
const text = String(
|
|
5017
|
+
function boundedNumber(value2, spec) {
|
|
5018
|
+
if (spec.kind !== "finite_number" || typeof value2 !== "number" || !Number.isFinite(value2) || value2 < spec.minimum || value2 > spec.maximum) throw new CamelError("conversion_rejected", "Finite-number conversion rejected the structured value.");
|
|
5019
|
+
const text = String(value2);
|
|
5018
5020
|
if (/e/i.test(text) || (text.split(".")[1]?.length ?? 0) > spec.maximumDecimalPlaces) throw new CamelError("conversion_rejected", "Finite-number conversion rejected a non-canonical decimal.");
|
|
5019
|
-
return
|
|
5021
|
+
return value2;
|
|
5020
5022
|
}
|
|
5021
|
-
function enumMember(
|
|
5022
|
-
if (spec.kind !== "enum" || typeof
|
|
5023
|
-
const member = spec.caseSensitive ? spec.values.find((item) => item ===
|
|
5023
|
+
function enumMember(value2, spec) {
|
|
5024
|
+
if (spec.kind !== "enum" || typeof value2 !== "string") throw new CamelError("conversion_rejected", "Enum conversion requires a structured string member.");
|
|
5025
|
+
const member = spec.caseSensitive ? spec.values.find((item) => item === value2) : spec.values.find((item) => item.toLocaleLowerCase("en-US") === value2.toLocaleLowerCase("en-US"));
|
|
5024
5026
|
if (member === void 0) throw new CamelError("conversion_rejected", "Enum conversion rejected a non-member.");
|
|
5025
5027
|
return member;
|
|
5026
5028
|
}
|
|
5027
|
-
function canonicalDate(
|
|
5028
|
-
if (spec.kind !== "date" || typeof
|
|
5029
|
+
function canonicalDate(value2, spec) {
|
|
5030
|
+
if (spec.kind !== "date" || typeof value2 !== "string") throw new CamelError("conversion_rejected", "Date conversion requires a canonical structured string.");
|
|
5029
5031
|
const pattern = spec.format === "date" ? /^\d{4}-\d{2}-\d{2}$/ : /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?(?:Z|[+-]\d{2}:\d{2})$/;
|
|
5030
|
-
const instant = Date.parse(spec.format === "date" ? `${
|
|
5031
|
-
if (!pattern.test(
|
|
5032
|
-
if (spec.earliest &&
|
|
5033
|
-
return
|
|
5034
|
-
}
|
|
5035
|
-
function measure(
|
|
5036
|
-
if (metric === "byte_length" && (typeof
|
|
5037
|
-
if (metric === "codepoint_length" && typeof
|
|
5038
|
-
if (metric === "item_count" && Array.isArray(
|
|
5032
|
+
const instant = Date.parse(spec.format === "date" ? `${value2}T00:00:00Z` : value2);
|
|
5033
|
+
if (!pattern.test(value2) || !Number.isFinite(instant) || spec.format === "date" && new Date(instant).toISOString().slice(0, 10) !== value2) throw new CamelError("conversion_rejected", "Date conversion rejected a non-canonical value.");
|
|
5034
|
+
if (spec.earliest && value2 < spec.earliest || spec.latest && value2 > spec.latest) throw new CamelError("conversion_rejected", "Date conversion rejected an out-of-range value.");
|
|
5035
|
+
return value2;
|
|
5036
|
+
}
|
|
5037
|
+
function measure(value2, metric) {
|
|
5038
|
+
if (metric === "byte_length" && (typeof value2 === "string" || value2 instanceof Uint8Array)) return utf8Length(value2);
|
|
5039
|
+
if (metric === "codepoint_length" && typeof value2 === "string") return [...value2].length;
|
|
5040
|
+
if (metric === "item_count" && Array.isArray(value2)) return value2.length;
|
|
5039
5041
|
throw new CamelError("conversion_rejected", "Measurement input does not match the registered metric.");
|
|
5040
5042
|
}
|
|
5041
|
-
function evaluatePredicate(
|
|
5042
|
-
if (predicate.kind === "has_fields") return typeof
|
|
5043
|
-
if (predicate.kind === "registered_id") return typeof
|
|
5044
|
-
const actual =
|
|
5043
|
+
function evaluatePredicate(value2, predicate, registries) {
|
|
5044
|
+
if (predicate.kind === "has_fields") return typeof value2 === "object" && value2 !== null && !Array.isArray(value2) && predicate.fields.every((field) => Object.hasOwn(value2, field));
|
|
5045
|
+
if (predicate.kind === "registered_id") return typeof value2 === "string" && registries?.[predicate.registryId]?.values[value2] !== void 0;
|
|
5046
|
+
const actual = value2 === null ? "null" : Array.isArray(value2) ? "array" : typeof value2;
|
|
5045
5047
|
return actual === predicate.valueType;
|
|
5046
5048
|
}
|
|
5047
5049
|
function sourceIdentity(source) {
|
|
@@ -5064,17 +5066,17 @@ function createCamelIngress(constants2 = []) {
|
|
|
5064
5066
|
byId.set(item.id, item);
|
|
5065
5067
|
}
|
|
5066
5068
|
const ingress = {
|
|
5067
|
-
userInstruction: (
|
|
5068
|
-
systemPolicy: (
|
|
5069
|
+
userInstruction: (value2, input) => createSafeInternal(value2, "user_instruction", metadata("user_instruction", input.id, input.readers)),
|
|
5070
|
+
systemPolicy: (value2, input) => createSafeInternal(value2, "system_policy", metadata("system_policy", input.id, input.readers)),
|
|
5069
5071
|
control: (id) => {
|
|
5070
5072
|
const item = byId.get(id);
|
|
5071
5073
|
if (!item) throw new CamelError("permission_denied", "Unknown control constant.");
|
|
5072
5074
|
return createSafeInternal(item.value, "harness_constant", metadata("harness", id, item.readers));
|
|
5073
5075
|
},
|
|
5074
|
-
external: (
|
|
5075
|
-
quarantinedOutput: (
|
|
5076
|
+
external: (value2, label) => createUnsafeInternal(value2, label),
|
|
5077
|
+
quarantinedOutput: (value2, input) => {
|
|
5076
5078
|
if (!input.runId) throw new CamelError("state_conflict", "Quarantined run IDs must be non-empty.");
|
|
5077
|
-
return createUnsafeInternal(
|
|
5079
|
+
return createUnsafeInternal(value2, {
|
|
5078
5080
|
readers: input.readers,
|
|
5079
5081
|
dependencies: input.dependencies,
|
|
5080
5082
|
provenance: [{ kind: "quarantined_llm", id: input.runId, digest: input.digest }]
|
|
@@ -5083,15 +5085,15 @@ function createCamelIngress(constants2 = []) {
|
|
|
5083
5085
|
};
|
|
5084
5086
|
return Object.freeze(ingress);
|
|
5085
5087
|
}
|
|
5086
|
-
function assertNoUnsafeConstant(
|
|
5087
|
-
if (typeof
|
|
5088
|
-
seen.add(
|
|
5089
|
-
if (isCamelValue(
|
|
5090
|
-
if (isUnsafe(
|
|
5091
|
-
assertNoUnsafeConstant(
|
|
5088
|
+
function assertNoUnsafeConstant(value2, seen = /* @__PURE__ */ new WeakSet()) {
|
|
5089
|
+
if (typeof value2 !== "object" || value2 === null || seen.has(value2)) return;
|
|
5090
|
+
seen.add(value2);
|
|
5091
|
+
if (isCamelValue(value2)) {
|
|
5092
|
+
if (isUnsafe(value2)) throw new CamelError("unsafe_privileged_flow", "Control constants cannot contain Prompt-Unsafe values.");
|
|
5093
|
+
assertNoUnsafeConstant(value2.value, seen);
|
|
5092
5094
|
return;
|
|
5093
5095
|
}
|
|
5094
|
-
for (const child of Object.values(
|
|
5096
|
+
for (const child of Object.values(value2)) assertNoUnsafeConstant(child, seen);
|
|
5095
5097
|
}
|
|
5096
5098
|
function metadata(kind, id, readers) {
|
|
5097
5099
|
if (!id) throw new CamelError("state_conflict", "Provenance IDs must be non-empty.");
|
|
@@ -5122,7 +5124,7 @@ async function evaluate(input, registries, approvals) {
|
|
|
5122
5124
|
if (invalid3) return deny(invalid3);
|
|
5123
5125
|
if (arg.role === "selector" && !isSafe(arg.value)) confined.add(arg.value);
|
|
5124
5126
|
}
|
|
5125
|
-
if (input.controlDependencies.some((
|
|
5127
|
+
if (input.controlDependencies.some((value2) => !isSafe(value2) && !confined.has(value2))) return deny("unsafe_control_dependency");
|
|
5126
5128
|
if (confined.size > 0) {
|
|
5127
5129
|
const fixed = input.tool.unsafeSelectorPolicy?.fixedProviderIds ?? [];
|
|
5128
5130
|
const destinations = Object.values(input.args).filter((arg) => arg.role === "destination");
|
|
@@ -5149,29 +5151,29 @@ async function validateArgument(path, arg, tool, registries) {
|
|
|
5149
5151
|
if (!isSafe(arg.value)) return "unsafe_destination_argument";
|
|
5150
5152
|
if (!isControlOwned(arg.value)) return "destination_not_control_owned";
|
|
5151
5153
|
const registry = registries[arg.registryId];
|
|
5152
|
-
const validValues = registry && registry.values.length > 0 && registry.values.every((
|
|
5154
|
+
const validValues = registry && registry.values.length > 0 && registry.values.every((value2) => typeof value2 === "string" && value2.length > 0) && new Set(registry.values).size === registry.values.length;
|
|
5153
5155
|
if (!registry || !validValues || registry.digest !== arg.registryDigest || await destinationRegistryDigest(registry.values) !== registry.digest || !registry.values.includes(arg.value.value)) return "destination_not_registered";
|
|
5154
5156
|
}
|
|
5155
5157
|
if (arg.role === "selector" && !isSafe(arg.value)) return validateUnsafeSelector(path, arg.value, tool);
|
|
5156
5158
|
return void 0;
|
|
5157
5159
|
}
|
|
5158
|
-
function isControlOwned(
|
|
5159
|
-
return
|
|
5160
|
+
function isControlOwned(value2) {
|
|
5161
|
+
return value2.label.safeBasis === "system_policy" || value2.label.safeBasis === "harness_constant";
|
|
5160
5162
|
}
|
|
5161
5163
|
function copyRegistries(registries) {
|
|
5162
5164
|
return Object.freeze(Object.fromEntries(Object.entries(registries).map(([id, registry]) => [id, Object.freeze({ digest: registry.digest, values: Object.freeze([...registry.values]) })])));
|
|
5163
5165
|
}
|
|
5164
|
-
function validateUnsafeSelector(path,
|
|
5166
|
+
function validateUnsafeSelector(path, value2, tool) {
|
|
5165
5167
|
const policy = tool.unsafeSelectorPolicy;
|
|
5166
5168
|
if (!policy || policy.effect !== tool.effect || !policy.selectorPaths.includes(path)) return "unsafe_selector_not_confined";
|
|
5167
5169
|
if (!policy.fixedDestination || !policy.unsafeOutput || policy.fixedProviderIds.length === 0) return "unsafe_selector_not_confined";
|
|
5168
5170
|
if (![policy.maximumCalls, policy.maximumResultsPerCall, policy.maximumOutputBytes, policy.maximumSelectorBytes].every((bound) => Number.isSafeInteger(bound) && bound > 0)) return "unsafe_selector_not_confined";
|
|
5169
|
-
if (utf8Length(
|
|
5170
|
-
if (typeof
|
|
5171
|
+
if (utf8Length(value2.value) > policy.maximumSelectorBytes) return "unsafe_selector_too_large";
|
|
5172
|
+
if (typeof value2.value === "string" && looksLikeDestination(value2.value)) return "unsafe_selector_is_destination";
|
|
5171
5173
|
return void 0;
|
|
5172
5174
|
}
|
|
5173
|
-
function looksLikeDestination(
|
|
5174
|
-
const text =
|
|
5175
|
+
function looksLikeDestination(value2) {
|
|
5176
|
+
const text = value2.trim();
|
|
5175
5177
|
return /^(?:[a-z][a-z0-9+.-]*:\/\/|\/|\\\\)/i.test(text) || /^[\w.-]+\.[a-z]{2,}(?:[/:]|$)/i.test(text);
|
|
5176
5178
|
}
|
|
5177
5179
|
|
|
@@ -5257,9 +5259,9 @@ var CodeRuntimeReconciler = class {
|
|
|
5257
5259
|
}
|
|
5258
5260
|
}
|
|
5259
5261
|
};
|
|
5260
|
-
function retryableControlFailure(
|
|
5261
|
-
if (!
|
|
5262
|
-
const failure =
|
|
5262
|
+
function retryableControlFailure(value2) {
|
|
5263
|
+
if (!value2 || typeof value2 !== "object") return false;
|
|
5264
|
+
const failure = value2;
|
|
5263
5265
|
if (failure.code === "invalid_response" || typeof failure.status !== "number") return false;
|
|
5264
5266
|
return failure.status === 408 || failure.status === 425 || failure.status === 429 || failure.status >= 500;
|
|
5265
5267
|
}
|
|
@@ -5311,16 +5313,16 @@ function createCodeRuntimeControlClient(options) {
|
|
|
5311
5313
|
if (options.signal?.aborted) throw cause;
|
|
5312
5314
|
throw new CodeRuntimeControlError("Code runtime control plane is unavailable", 503, "transport_unavailable");
|
|
5313
5315
|
}
|
|
5314
|
-
const
|
|
5316
|
+
const value2 = await response2.json().catch(() => null);
|
|
5315
5317
|
if (!response2.ok) {
|
|
5316
|
-
const problem = record3(record3(
|
|
5318
|
+
const problem = record3(record3(value2)?.error);
|
|
5317
5319
|
throw new CodeRuntimeControlError(
|
|
5318
5320
|
typeof problem?.message === "string" ? problem.message : `Code runtime request failed (${response2.status})`,
|
|
5319
5321
|
response2.status,
|
|
5320
5322
|
typeof problem?.code === "string" ? problem.code : void 0
|
|
5321
5323
|
);
|
|
5322
5324
|
}
|
|
5323
|
-
return
|
|
5325
|
+
return value2;
|
|
5324
5326
|
};
|
|
5325
5327
|
return {
|
|
5326
5328
|
heartbeat: async (version, capabilities) => {
|
|
@@ -5335,15 +5337,15 @@ function createCodeRuntimeControlClient(options) {
|
|
|
5335
5337
|
await call2(`/registry/code/runtime/sessions/${validSessionId(sessionId)}/source`, {})
|
|
5336
5338
|
),
|
|
5337
5339
|
infer: async (sessionId, inference) => {
|
|
5338
|
-
const
|
|
5340
|
+
const value2 = record3(await call2(
|
|
5339
5341
|
`/registry/code/runtime/sessions/${validSessionId(sessionId)}/inference`,
|
|
5340
5342
|
inference,
|
|
5341
5343
|
modelRequestTimeoutMs
|
|
5342
5344
|
));
|
|
5343
|
-
if (!
|
|
5345
|
+
if (!value2 || value2.requestId !== inference.requestId || !record3(value2.response) || !record3(value2.receipt)) {
|
|
5344
5346
|
throw new CodeRuntimeControlError("invalid Code inference response", 502, "invalid_response");
|
|
5345
5347
|
}
|
|
5346
|
-
return
|
|
5348
|
+
return value2;
|
|
5347
5349
|
},
|
|
5348
5350
|
review: async (sessionId, review) => parseReview(
|
|
5349
5351
|
await call2(`/registry/code/runtime/sessions/${validSessionId(sessionId)}/review`, review, modelRequestTimeoutMs)
|
|
@@ -5368,8 +5370,8 @@ function createCodeRuntimeControlClient(options) {
|
|
|
5368
5370
|
}
|
|
5369
5371
|
};
|
|
5370
5372
|
}
|
|
5371
|
-
function validatedEndpoint(
|
|
5372
|
-
const endpoint =
|
|
5373
|
+
function validatedEndpoint(value2) {
|
|
5374
|
+
const endpoint = value2.replace(/\/+$/, "");
|
|
5373
5375
|
let url;
|
|
5374
5376
|
try {
|
|
5375
5377
|
url = new URL(endpoint);
|
|
@@ -5382,9 +5384,9 @@ function validatedEndpoint(value) {
|
|
|
5382
5384
|
}
|
|
5383
5385
|
return endpoint;
|
|
5384
5386
|
}
|
|
5385
|
-
function validSessionId(
|
|
5386
|
-
if (!/^csess_[0-9a-f]{32}$/.test(
|
|
5387
|
-
return
|
|
5387
|
+
function validSessionId(value2) {
|
|
5388
|
+
if (!/^csess_[0-9a-f]{32}$/.test(value2)) throw new TypeError("invalid Code session id");
|
|
5389
|
+
return value2;
|
|
5388
5390
|
}
|
|
5389
5391
|
function validateHeartbeat(version, capabilities) {
|
|
5390
5392
|
if (!version.trim() || version.length > 80) throw new TypeError("runtimeVersion is required and at most 80 characters");
|
|
@@ -5397,8 +5399,8 @@ function validateHeartbeat(version, capabilities) {
|
|
|
5397
5399
|
throw new TypeError("runtime resources must be positive integers");
|
|
5398
5400
|
}
|
|
5399
5401
|
}
|
|
5400
|
-
function parseSnapshot(
|
|
5401
|
-
const root = record3(
|
|
5402
|
+
function parseSnapshot(value2) {
|
|
5403
|
+
const root = record3(value2);
|
|
5402
5404
|
const host = record3(root?.host);
|
|
5403
5405
|
if (!host || typeof host.hostId !== "string" || typeof host.runtimeVersion !== "string" || !Number.isSafeInteger(host.lastSeenAt) || host.revokedAt !== null || !Array.isArray(root?.bindings) || root.bindings.length > 1024 || !Array.isArray(root?.commands) || root.commands.length > 64) throw invalid("heartbeat");
|
|
5404
5406
|
const bindingIds = /* @__PURE__ */ new Set();
|
|
@@ -5423,11 +5425,11 @@ function parseSnapshot(value) {
|
|
|
5423
5425
|
});
|
|
5424
5426
|
return { host, bindings, commands };
|
|
5425
5427
|
}
|
|
5426
|
-
async function parseSource(
|
|
5427
|
-
const snapshot = record3(record3(
|
|
5428
|
+
async function parseSource(value2) {
|
|
5429
|
+
const snapshot = record3(record3(value2)?.snapshot);
|
|
5428
5430
|
if (!snapshot || typeof snapshot.repository !== "string" || typeof snapshot.commitSha !== "string" || typeof snapshot.treeDigest !== "string" || !Array.isArray(snapshot.files)) throw invalid("source");
|
|
5429
|
-
const files = snapshot.files.map((
|
|
5430
|
-
const file = record3(
|
|
5431
|
+
const files = snapshot.files.map((value22) => {
|
|
5432
|
+
const file = record3(value22);
|
|
5431
5433
|
if (!file || typeof file.path !== "string" || typeof file.content !== "string") throw invalid("source file");
|
|
5432
5434
|
return { path: file.path, content: file.content };
|
|
5433
5435
|
});
|
|
@@ -5454,19 +5456,19 @@ async function parseSource(value) {
|
|
|
5454
5456
|
if (digest !== snapshot.treeDigest) throw invalid("source digest");
|
|
5455
5457
|
return { ...source, treeDigest: digest, ...references.length ? { references } : {} };
|
|
5456
5458
|
}
|
|
5457
|
-
function parseReview(
|
|
5458
|
-
const review = record3(record3(
|
|
5459
|
+
function parseReview(value2) {
|
|
5460
|
+
const review = record3(record3(value2)?.review);
|
|
5459
5461
|
if (!review || !["approved", "rejected"].includes(String(review.verdict)) || typeof review.reviewDigest !== "string" || !/^sha256:[0-9a-f]{64}$/.test(review.reviewDigest) || typeof review.provider !== "string" || !review.provider || typeof review.model !== "string" || !review.model || !Number.isSafeInteger(review.policyVersion) || Number(review.policyVersion) < 1) throw invalid("review");
|
|
5460
5462
|
return review;
|
|
5461
5463
|
}
|
|
5462
|
-
function parseCandidate(
|
|
5463
|
-
const candidate = record3(record3(
|
|
5464
|
+
function parseCandidate(value2) {
|
|
5465
|
+
const candidate = record3(record3(value2)?.candidate);
|
|
5464
5466
|
if (!candidate || typeof candidate.candidateId !== "string" || !/^ccand_[0-9a-f]{32}$/.test(candidate.candidateId) || !["submitted", "approved", "published", "failed"].includes(String(candidate.status))) {
|
|
5465
5467
|
throw invalid("candidate");
|
|
5466
5468
|
}
|
|
5467
5469
|
return { candidateId: candidate.candidateId, status: candidate.status };
|
|
5468
5470
|
}
|
|
5469
|
-
var record3 = (
|
|
5471
|
+
var record3 = (value2) => value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
|
|
5470
5472
|
var invalid = (part) => new CodeRuntimeControlError(`invalid Code runtime ${part} response`, 502, "invalid_response");
|
|
5471
5473
|
var RESERVED = /* @__PURE__ */ new Set([".git", ".odla", ".wrangler", "node_modules", "dist", "coverage"]);
|
|
5472
5474
|
var SECRET = /^(?:\.env(?:\..+)?|\.dev\.vars|credentials(?:\..+)?\.json|dev-token(?:\..+)?\.json)$/i;
|
|
@@ -5500,8 +5502,8 @@ function validateCodePatch(patch2, maxBytes) {
|
|
|
5500
5502
|
if (!paths.length || new Set(paths).size !== paths.length) throw new TypeError("patch has no diffs or repeats a path");
|
|
5501
5503
|
return paths;
|
|
5502
5504
|
}
|
|
5503
|
-
function validHeaderPath(
|
|
5504
|
-
return
|
|
5505
|
+
function validHeaderPath(value2, path, prefix) {
|
|
5506
|
+
return value2 === "/dev/null" || value2 === `${prefix}/${path}`;
|
|
5505
5507
|
}
|
|
5506
5508
|
function validateRelativePath(path) {
|
|
5507
5509
|
const parts = path.split("/");
|
|
@@ -5647,8 +5649,8 @@ function assertCodeBuildRecipe(recipe2) {
|
|
|
5647
5649
|
throw new TypeError("build recipe is malformed or exceeds its control bounds");
|
|
5648
5650
|
}
|
|
5649
5651
|
}
|
|
5650
|
-
function parseMemory(
|
|
5651
|
-
const match = /^([1-9][0-9]{0,4})([kmg])$/.exec(
|
|
5652
|
+
function parseMemory(value2) {
|
|
5653
|
+
const match = /^([1-9][0-9]{0,4})([kmg])$/.exec(value2.toLowerCase());
|
|
5652
5654
|
if (!match?.[1] || !match[2]) return 0;
|
|
5653
5655
|
const scale = match[2] === "k" ? 1024 : match[2] === "m" ? 1024 ** 2 : 1024 ** 3;
|
|
5654
5656
|
return Number(match[1]) * scale;
|
|
@@ -5883,14 +5885,14 @@ function normalizedRecipe(recipe2) {
|
|
|
5883
5885
|
expectedArtifacts: [...recipe2.expectedArtifacts ?? []].sort((left, right) => left.id.localeCompare(right.id)).map((artifact) => ({ id: artifact.id, path: artifact.path, maximumBytes: artifact.maximumBytes }))
|
|
5884
5886
|
};
|
|
5885
5887
|
}
|
|
5886
|
-
function digestJson(
|
|
5887
|
-
return digestBytes(JSON.stringify(
|
|
5888
|
+
function digestJson(value2) {
|
|
5889
|
+
return digestBytes(JSON.stringify(value2));
|
|
5888
5890
|
}
|
|
5889
|
-
function digestBytes(
|
|
5890
|
-
return `sha256:${(0, import_crypto3.createHash)("sha256").update(
|
|
5891
|
+
function digestBytes(value2) {
|
|
5892
|
+
return `sha256:${(0, import_crypto3.createHash)("sha256").update(value2).digest("hex")}`;
|
|
5891
5893
|
}
|
|
5892
|
-
function integer(
|
|
5893
|
-
return Number.isSafeInteger(
|
|
5894
|
+
function integer(value2, minimum, maximum) {
|
|
5895
|
+
return Number.isSafeInteger(value2) && value2 >= minimum && value2 <= maximum;
|
|
5894
5896
|
}
|
|
5895
5897
|
async function prepareRuntimeCheckpoint(input) {
|
|
5896
5898
|
const patch2 = await input.workspace.patch(256 * 1024);
|
|
@@ -5943,7 +5945,7 @@ async function prepareRuntimeCheckpoint(input) {
|
|
|
5943
5945
|
});
|
|
5944
5946
|
return { checkpoint, verification, review, note };
|
|
5945
5947
|
}
|
|
5946
|
-
var message = (
|
|
5948
|
+
var message = (value2) => (value2 instanceof Error ? value2.message : String(value2)).slice(0, 500);
|
|
5947
5949
|
var CodeRuntimeCheckpointManager = class {
|
|
5948
5950
|
constructor(options) {
|
|
5949
5951
|
this.options = options;
|
|
@@ -6137,7 +6139,7 @@ async function conversionPolicy(id, output) {
|
|
|
6137
6139
|
return { ...definition, digest: await conversionPolicyDigest(definition) };
|
|
6138
6140
|
}
|
|
6139
6141
|
async function registeredPolicy(id, registryId, values) {
|
|
6140
|
-
const mapping = Object.fromEntries(values.map((
|
|
6142
|
+
const mapping = Object.fromEntries(values.map((value2) => [value2, value2]));
|
|
6141
6143
|
return conversionPolicy(id, {
|
|
6142
6144
|
kind: "registered_id",
|
|
6143
6145
|
registryId,
|
|
@@ -6146,7 +6148,7 @@ async function registeredPolicy(id, registryId, values) {
|
|
|
6146
6148
|
}
|
|
6147
6149
|
async function conversionRegistry(policies, values) {
|
|
6148
6150
|
const registeredIds = Object.fromEntries(await Promise.all(Object.entries(values).map(async ([id, entries]) => {
|
|
6149
|
-
const mapping = Object.fromEntries(entries.map((
|
|
6151
|
+
const mapping = Object.fromEntries(entries.map((value2) => [value2, value2]));
|
|
6150
6152
|
return [id, { values: mapping, digest: await registeredIdRegistryDigest(mapping) }];
|
|
6151
6153
|
})));
|
|
6152
6154
|
return createConversionRegistry({ policies, registeredIds });
|
|
@@ -6170,8 +6172,8 @@ async function environment(input, options, tool) {
|
|
|
6170
6172
|
};
|
|
6171
6173
|
return { ingress, policy, fixedArgs, reader: ingress.control("reader"), runId: `${input.request.requestId}:${tool}` };
|
|
6172
6174
|
}
|
|
6173
|
-
function unsafe(base,
|
|
6174
|
-
return base.ingress.quarantinedOutput(
|
|
6175
|
+
function unsafe(base, value2, field) {
|
|
6176
|
+
return base.ingress.quarantinedOutput(value2, {
|
|
6175
6177
|
readers: base.reader.label.readers,
|
|
6176
6178
|
runId: `${base.runId}:${field}`
|
|
6177
6179
|
});
|
|
@@ -6251,14 +6253,14 @@ async function read(context, request2, options, policy) {
|
|
|
6251
6253
|
}
|
|
6252
6254
|
async function patch(context, request2, options, policy) {
|
|
6253
6255
|
exactKeys(request2.input, ["patch"]);
|
|
6254
|
-
const
|
|
6255
|
-
const paths = validateCodePatch(
|
|
6256
|
+
const value2 = stringField(request2.input, "patch");
|
|
6257
|
+
const paths = validateCodePatch(value2, options.maxPatchBytes ?? 256 * 1024);
|
|
6256
6258
|
if (paths.some((path) => options.readOnlyPrefixes?.some((prefix) => path === prefix || path.startsWith(`${prefix}/`)))) {
|
|
6257
6259
|
throw new TypeError("patch targets a read-only reference source");
|
|
6258
6260
|
}
|
|
6259
|
-
const allowed = await policy.patch(policyContext(context, request2, options, { patch:
|
|
6261
|
+
const allowed = await policy.patch(policyContext(context, request2, options, { patch: value2 }));
|
|
6260
6262
|
if (!allowed) return response(request2, false, "tool denied by CaMeL policy");
|
|
6261
|
-
await applyCodePatch(context.workspaceDir,
|
|
6263
|
+
await applyCodePatch(context.workspaceDir, value2, paths);
|
|
6262
6264
|
return response(request2, true, `Applied patch to ${paths.length} file(s).`, { paths });
|
|
6263
6265
|
}
|
|
6264
6266
|
async function recipe(context, request2, options, recipes, policy) {
|
|
@@ -6349,14 +6351,14 @@ function exactKeys(input, allowed) {
|
|
|
6349
6351
|
if (Object.keys(input).some((key) => !allowed.includes(key))) throw new TypeError("tool input contains an unsupported field");
|
|
6350
6352
|
}
|
|
6351
6353
|
function stringField(input, name) {
|
|
6352
|
-
const
|
|
6353
|
-
if (typeof
|
|
6354
|
-
return
|
|
6354
|
+
const value2 = input[name];
|
|
6355
|
+
if (typeof value2 !== "string" || !value2) throw new TypeError(`${name} must be a non-empty string`);
|
|
6356
|
+
return value2;
|
|
6355
6357
|
}
|
|
6356
|
-
function optionalInteger(
|
|
6357
|
-
if (
|
|
6358
|
-
if (!Number.isSafeInteger(
|
|
6359
|
-
return
|
|
6358
|
+
function optionalInteger(value2) {
|
|
6359
|
+
if (value2 === void 0) return void 0;
|
|
6360
|
+
if (!Number.isSafeInteger(value2) || value2 < 1) throw new TypeError("line bounds must be positive integers");
|
|
6361
|
+
return value2;
|
|
6360
6362
|
}
|
|
6361
6363
|
function response(request2, ok, content2, details) {
|
|
6362
6364
|
return { requestId: request2.requestId, ok, content: content2, ...details ? { details } : {} };
|
|
@@ -6402,9 +6404,9 @@ function codeLocalSource(payload) {
|
|
|
6402
6404
|
return source;
|
|
6403
6405
|
}
|
|
6404
6406
|
function codeCheckpointPayload(payload) {
|
|
6405
|
-
const
|
|
6406
|
-
if (!
|
|
6407
|
-
return
|
|
6407
|
+
const value2 = payload.checkpoint;
|
|
6408
|
+
if (!value2 || typeof value2 !== "object" || Array.isArray(value2)) throw new TypeError("resume checkpoint is missing");
|
|
6409
|
+
return value2;
|
|
6408
6410
|
}
|
|
6409
6411
|
function fakeCodeLease(command, metadata2) {
|
|
6410
6412
|
return {
|
|
@@ -6428,7 +6430,7 @@ function fakeCodeLease(command, metadata2) {
|
|
|
6428
6430
|
}
|
|
6429
6431
|
};
|
|
6430
6432
|
}
|
|
6431
|
-
var record22 = (
|
|
6433
|
+
var record22 = (value2) => value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
|
|
6432
6434
|
var SOURCE_LIMITS = { maxFiles: 2e4, maxBytes: 512 * 1024 * 1024 };
|
|
6433
6435
|
async function prepareRuntimeLocalSource(input) {
|
|
6434
6436
|
const { command, descriptor: descriptor2, available, repository, baseCommitSha, resume } = input;
|
|
@@ -6518,24 +6520,24 @@ async function appendCodeRuntimeEvent(control, command, event, refs) {
|
|
|
6518
6520
|
const bounded = event.type === "message" ? { ...event, body: event.body.trim().slice(0, 2e4) || `${event.actor} event` } : event;
|
|
6519
6521
|
await control.appendSessionEvent(command.sessionId, eventId, bounded);
|
|
6520
6522
|
}
|
|
6521
|
-
var digestRuntimeValue = (
|
|
6522
|
-
var runtimeErrorMessage = (
|
|
6523
|
-
var runtimeRecord = (
|
|
6524
|
-
var safeRuntimeJson = (
|
|
6523
|
+
var digestRuntimeValue = (value2) => `sha256:${(0, import_crypto4.createHash)("sha256").update(value2).digest("hex")}`;
|
|
6524
|
+
var runtimeErrorMessage = (value2) => value2 instanceof Error ? value2.message : String(value2);
|
|
6525
|
+
var runtimeRecord = (value2) => value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
|
|
6526
|
+
var safeRuntimeJson = (value2) => {
|
|
6525
6527
|
try {
|
|
6526
|
-
return JSON.stringify(
|
|
6528
|
+
return JSON.stringify(value2).slice(0, 1e4);
|
|
6527
6529
|
} catch {
|
|
6528
6530
|
return "[event]";
|
|
6529
6531
|
}
|
|
6530
6532
|
};
|
|
6531
|
-
function runtimeResultText(
|
|
6532
|
-
const record32 = runtimeRecord(
|
|
6533
|
+
function runtimeResultText(value2) {
|
|
6534
|
+
const record32 = runtimeRecord(value2);
|
|
6533
6535
|
if (record32 && typeof record32.text === "string") return record32.text.slice(0, 2e4);
|
|
6534
6536
|
if (record32 && typeof record32.error === "string") return `Pi failed: ${record32.error.slice(0, 19989)}`;
|
|
6535
6537
|
return null;
|
|
6536
6538
|
}
|
|
6537
|
-
function runtimeResultError(
|
|
6538
|
-
const record32 = runtimeRecord(
|
|
6539
|
+
function runtimeResultError(value2) {
|
|
6540
|
+
const record32 = runtimeRecord(value2);
|
|
6539
6541
|
return record32 && typeof record32.error === "string" && record32.error.trim() ? record32.error.trim().slice(0, 2e3) : null;
|
|
6540
6542
|
}
|
|
6541
6543
|
var CodePiRuntimeEngine = class {
|
|
@@ -6809,14 +6811,14 @@ var CodePiRuntimeEngine = class {
|
|
|
6809
6811
|
this.#active.delete(command.sessionId);
|
|
6810
6812
|
return result;
|
|
6811
6813
|
}
|
|
6812
|
-
async #failure(command, active,
|
|
6813
|
-
active.failure =
|
|
6814
|
+
async #failure(command, active, value2) {
|
|
6815
|
+
active.failure = value2.slice(0, 2e3);
|
|
6814
6816
|
if (active.acknowledged) {
|
|
6815
6817
|
await this.options.control.reportSessionFailure(command.sessionId, active.failure).catch(() => void 0);
|
|
6816
6818
|
}
|
|
6817
6819
|
}
|
|
6818
|
-
async #diagnostic(command, active,
|
|
6819
|
-
const detail =
|
|
6820
|
+
async #diagnostic(command, active, value2) {
|
|
6821
|
+
const detail = value2.trim().slice(0, 2e3) || "Pi runtime failed";
|
|
6820
6822
|
this.options.onDiagnostic?.(detail);
|
|
6821
6823
|
await this.#event(
|
|
6822
6824
|
command,
|
|
@@ -6901,6 +6903,7 @@ Usage:
|
|
|
6901
6903
|
odla-ai context save <name> [--platform <url>] [--app <id>] [--env <name>] [--json]
|
|
6902
6904
|
odla-ai context remove <name> --yes [--json]
|
|
6903
6905
|
odla-ai o11y status [--app <id>] [--context <name>] [--platform https://odla.ai] [--env prod] [--minutes 60] [--json]
|
|
6906
|
+
odla-ai platform status [--context <name>] [--platform https://odla.ai] [--email <odla-account>] [--json]
|
|
6904
6907
|
odla-ai whoami [--context <name>] [--platform https://odla.ai] [--json]
|
|
6905
6908
|
odla-ai runbook ask "<question>" [--app <id>] [--all] [--json]
|
|
6906
6909
|
odla-ai runbook search "<question>" [--app <id>] [--all] [--limit <n>] [--json]
|
|
@@ -7025,6 +7028,8 @@ Commands:
|
|
|
7025
7028
|
canary, collector ingest/scheduler trust, Cloudflare-owned
|
|
7026
7029
|
runtime metrics, and a machine verdict.
|
|
7027
7030
|
--json keeps auth progress on stderr for unattended agents.
|
|
7031
|
+
platform Read canonical fleet health, releases, provider load/freshness,
|
|
7032
|
+
explicit unknowns, and next actions through a read-only grant.
|
|
7028
7033
|
provision Register services, compose integrations, persist credentials, optionally push secrets.
|
|
7029
7034
|
smoke Verify credentials, public-config, composed schema, db aggregate, and integration probes.
|
|
7030
7035
|
skill Same installer; --agent accepts all, claude, codex, cursor,
|
|
@@ -7111,31 +7116,31 @@ async function requestHostedSecurityJson(options, path, init, action) {
|
|
|
7111
7116
|
}
|
|
7112
7117
|
return body;
|
|
7113
7118
|
}
|
|
7114
|
-
function hostedIdentifier(
|
|
7115
|
-
const result = optionalHostedText(
|
|
7119
|
+
function hostedIdentifier(value2, name) {
|
|
7120
|
+
const result = optionalHostedText(value2, name, 180);
|
|
7116
7121
|
if (!result || !/^[A-Za-z0-9][A-Za-z0-9._:-]*$/.test(result)) {
|
|
7117
7122
|
throw new Error(`${name} is invalid`);
|
|
7118
7123
|
}
|
|
7119
7124
|
return result;
|
|
7120
7125
|
}
|
|
7121
|
-
function positivePolicyVersion(
|
|
7122
|
-
if (!Number.isSafeInteger(
|
|
7126
|
+
function positivePolicyVersion(value2, name) {
|
|
7127
|
+
if (!Number.isSafeInteger(value2) || value2 < 1) {
|
|
7123
7128
|
throw new Error(`${name} is invalid`);
|
|
7124
7129
|
}
|
|
7125
|
-
return
|
|
7130
|
+
return value2;
|
|
7126
7131
|
}
|
|
7127
|
-
function optionalHostedText(
|
|
7128
|
-
if (
|
|
7129
|
-
if (typeof
|
|
7132
|
+
function optionalHostedText(value2, name, maxLength) {
|
|
7133
|
+
if (value2 === void 0 || value2 === null || value2 === "") return void 0;
|
|
7134
|
+
if (typeof value2 !== "string" || value2.length > maxLength || /[\u0000-\u001f\u007f]/.test(value2)) {
|
|
7130
7135
|
throw new Error(`${name} is invalid`);
|
|
7131
7136
|
}
|
|
7132
|
-
return
|
|
7137
|
+
return value2;
|
|
7133
7138
|
}
|
|
7134
|
-
function githubRepositoryName(
|
|
7135
|
-
if (typeof
|
|
7139
|
+
function githubRepositoryName(value2) {
|
|
7140
|
+
if (typeof value2 !== "string" || value2.length > 201) {
|
|
7136
7141
|
throw new Error("repository must be owner/name");
|
|
7137
7142
|
}
|
|
7138
|
-
const parts =
|
|
7143
|
+
const parts = value2.split("/");
|
|
7139
7144
|
const owner = parts[0] ?? "";
|
|
7140
7145
|
const name = (parts[1] ?? "").replace(/\.git$/i, "");
|
|
7141
7146
|
if (parts.length !== 2 || !/^[A-Za-z0-9](?:[A-Za-z0-9-]{0,98}[A-Za-z0-9])?$/.test(owner) || !/^[A-Za-z0-9_.-]{1,100}$/.test(name) || name === "." || name === "..") {
|
|
@@ -7143,10 +7148,10 @@ function githubRepositoryName(value) {
|
|
|
7143
7148
|
}
|
|
7144
7149
|
return `${owner}/${name}`;
|
|
7145
7150
|
}
|
|
7146
|
-
function trustedGitHubInstallUrl(
|
|
7151
|
+
function trustedGitHubInstallUrl(value2) {
|
|
7147
7152
|
let url;
|
|
7148
7153
|
try {
|
|
7149
|
-
url = new URL(
|
|
7154
|
+
url = new URL(value2);
|
|
7150
7155
|
} catch {
|
|
7151
7156
|
throw new Error("odla.ai returned an invalid GitHub installation URL");
|
|
7152
7157
|
}
|
|
@@ -7155,17 +7160,17 @@ function trustedGitHubInstallUrl(value) {
|
|
|
7155
7160
|
}
|
|
7156
7161
|
return url.toString();
|
|
7157
7162
|
}
|
|
7158
|
-
function hostedPollInterval(
|
|
7159
|
-
if (!Number.isSafeInteger(
|
|
7163
|
+
function hostedPollInterval(value2 = 2e3) {
|
|
7164
|
+
if (!Number.isSafeInteger(value2) || value2 < 100 || value2 > 3e4) {
|
|
7160
7165
|
throw new Error("poll interval must be 100-30000ms");
|
|
7161
7166
|
}
|
|
7162
|
-
return
|
|
7167
|
+
return value2;
|
|
7163
7168
|
}
|
|
7164
|
-
function hostedPollTimeout(
|
|
7165
|
-
if (!Number.isSafeInteger(
|
|
7169
|
+
function hostedPollTimeout(value2 = 10 * 6e4) {
|
|
7170
|
+
if (!Number.isSafeInteger(value2) || value2 < 1e3 || value2 > 60 * 6e4) {
|
|
7166
7171
|
throw new Error("poll timeout must be 1000-3600000ms");
|
|
7167
7172
|
}
|
|
7168
|
-
return
|
|
7173
|
+
return value2;
|
|
7169
7174
|
}
|
|
7170
7175
|
async function waitForHostedPoll(milliseconds, signal) {
|
|
7171
7176
|
if (signal?.aborted) throw signal.reason ?? new DOMException("aborted", "AbortError");
|
|
@@ -7177,16 +7182,16 @@ async function waitForHostedPoll(milliseconds, signal) {
|
|
|
7177
7182
|
}, { once: true });
|
|
7178
7183
|
});
|
|
7179
7184
|
}
|
|
7180
|
-
function isValidHostedSecurityPlan(
|
|
7181
|
-
if (!
|
|
7185
|
+
function isValidHostedSecurityPlan(value2, env) {
|
|
7186
|
+
if (!value2 || value2.env !== env || !/^sha256:[a-f0-9]{64}$/.test(value2.planDigest) || value2.consentContract !== "odla.hosted-security-consent.v1" || value2.reportProjection !== "odla.hosted-security-report.v1" || value2.redactionContract !== "odla.best-effort-credential-pattern-redaction.v1" || typeof value2.promptBundle !== "string" || value2.promptBundle.length < 1 || value2.promptBundle.length > 100 || typeof value2.ready !== "boolean" || typeof value2.independent !== "boolean" || value2.sourceDisclosure !== "redacted" || value2.targetExecution !== false || !Number.isSafeInteger(value2.reportRetentionDays) || value2.reportRetentionDays < 1) return false;
|
|
7182
7187
|
const validRoute = (route2, purpose) => !!route2 && route2.purpose === purpose && typeof route2.enabled === "boolean" && typeof route2.credentialReady === "boolean" && typeof route2.provider === "string" && route2.provider.length > 0 && route2.provider.length <= 100 && typeof route2.model === "string" && route2.model.length > 0 && route2.model.length <= 200 && Number.isSafeInteger(route2.policyVersion) && route2.policyVersion >= 1 && Number.isSafeInteger(route2.maxCallsPerRun) && route2.maxCallsPerRun >= 1 && Number.isSafeInteger(route2.maxInputBytes) && route2.maxInputBytes >= 1 && Number.isSafeInteger(route2.maxOutputTokens) && route2.maxOutputTokens >= 1;
|
|
7183
|
-
return validRoute(
|
|
7188
|
+
return validRoute(value2.routes?.discovery, "security.discovery") && validRoute(value2.routes?.validation, "security.validation");
|
|
7184
7189
|
}
|
|
7185
|
-
function hostedSecurityCredential(
|
|
7186
|
-
if (typeof
|
|
7190
|
+
function hostedSecurityCredential(value2) {
|
|
7191
|
+
if (typeof value2 !== "string" || value2.length < 8 || value2.length > 8192 || /\s|[\u0000-\u001f\u007f]/.test(value2)) {
|
|
7187
7192
|
throw new Error("Hosted security requires an injected odla developer token");
|
|
7188
7193
|
}
|
|
7189
|
-
return
|
|
7194
|
+
return value2;
|
|
7190
7195
|
}
|
|
7191
7196
|
|
|
7192
7197
|
// src/security-hosted-github.ts
|
|
@@ -7339,17 +7344,17 @@ async function prepareCodeLocalSource(cwd, repository, readHead = readGitHead) {
|
|
|
7339
7344
|
}
|
|
7340
7345
|
}
|
|
7341
7346
|
async function readGitHead(cwd) {
|
|
7342
|
-
const
|
|
7347
|
+
const value2 = await new Promise((accept, reject) => {
|
|
7343
7348
|
(0, import_node_child_process5.execFile)("git", ["rev-parse", "HEAD"], { cwd, encoding: "utf8", maxBuffer: 16384 }, (error, stdout) => {
|
|
7344
7349
|
if (error) reject(new Error("code connect requires a Git checkout with an initial commit"));
|
|
7345
7350
|
else accept(stdout.trim());
|
|
7346
7351
|
});
|
|
7347
7352
|
});
|
|
7348
|
-
if (!/^[0-9a-f]{40}$/.test(
|
|
7349
|
-
return
|
|
7353
|
+
if (!/^[0-9a-f]{40}$/.test(value2)) throw new Error("code connect could not resolve the checkout HEAD commit");
|
|
7354
|
+
return value2;
|
|
7350
7355
|
}
|
|
7351
|
-
function digestText(
|
|
7352
|
-
return `sha256:${(0, import_node_crypto.createHash)("sha256").update(
|
|
7356
|
+
function digestText(value2) {
|
|
7357
|
+
return `sha256:${(0, import_node_crypto.createHash)("sha256").update(value2).digest("hex")}`;
|
|
7353
7358
|
}
|
|
7354
7359
|
|
|
7355
7360
|
// src/code-images.ts
|
|
@@ -7620,8 +7625,8 @@ async function runCodeRuntime(input) {
|
|
|
7620
7625
|
for (const [name, handler] of handlers) process.removeListener(name, handler);
|
|
7621
7626
|
}
|
|
7622
7627
|
}
|
|
7623
|
-
function parseConnection(
|
|
7624
|
-
const root = record4(
|
|
7628
|
+
function parseConnection(value2, appId, appEnv) {
|
|
7629
|
+
const root = record4(value2);
|
|
7625
7630
|
const host = record4(root?.host);
|
|
7626
7631
|
const offer = record4(root?.offer);
|
|
7627
7632
|
const binding = record4(root?.binding);
|
|
@@ -7630,12 +7635,12 @@ function parseConnection(value, appId, appEnv) {
|
|
|
7630
7635
|
}
|
|
7631
7636
|
return root;
|
|
7632
7637
|
}
|
|
7633
|
-
function apiFailure(action, status,
|
|
7634
|
-
const message2 = record4(record4(
|
|
7638
|
+
function apiFailure(action, status, value2) {
|
|
7639
|
+
const message2 = record4(record4(value2)?.error)?.message;
|
|
7635
7640
|
return `${action} failed (${status})${typeof message2 === "string" ? `: ${message2}` : ""}`;
|
|
7636
7641
|
}
|
|
7637
|
-
function record4(
|
|
7638
|
-
return
|
|
7642
|
+
function record4(value2) {
|
|
7643
|
+
return value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
|
|
7639
7644
|
}
|
|
7640
7645
|
|
|
7641
7646
|
// src/code-command.ts
|
|
@@ -7694,8 +7699,8 @@ function developerTokenStatus(context, parsed, now = Date.now()) {
|
|
|
7694
7699
|
cacheStatus
|
|
7695
7700
|
};
|
|
7696
7701
|
}
|
|
7697
|
-
function clean3(
|
|
7698
|
-
const normalized =
|
|
7702
|
+
function clean3(value2) {
|
|
7703
|
+
const normalized = value2?.trim();
|
|
7699
7704
|
return normalized || void 0;
|
|
7700
7705
|
}
|
|
7701
7706
|
|
|
@@ -7844,8 +7849,8 @@ async function request(ctx, method, path, body) {
|
|
|
7844
7849
|
throw new Error(`discuss ${method} ${path} failed: ${data.error ?? `registry returned ${res.status}`}`);
|
|
7845
7850
|
return data;
|
|
7846
7851
|
}
|
|
7847
|
-
function emit(ctx,
|
|
7848
|
-
if (ctx.json) ctx.out.log(JSON.stringify(
|
|
7852
|
+
function emit(ctx, value2, human) {
|
|
7853
|
+
if (ctx.json) ctx.out.log(JSON.stringify(value2, null, 2));
|
|
7849
7854
|
else human();
|
|
7850
7855
|
}
|
|
7851
7856
|
var state = (topic) => topic.resolved ? "resolved" : "open";
|
|
@@ -7890,8 +7895,8 @@ async function discussList(ctx, parsed) {
|
|
|
7890
7895
|
["limit", "limit"],
|
|
7891
7896
|
["offset", "offset"]
|
|
7892
7897
|
]) {
|
|
7893
|
-
const
|
|
7894
|
-
if (
|
|
7898
|
+
const value2 = stringOpt(parsed.options[flag]);
|
|
7899
|
+
if (value2) query.set(param, value2);
|
|
7895
7900
|
}
|
|
7896
7901
|
const qs = query.toString();
|
|
7897
7902
|
const page = await request(ctx, "GET", `/topics${qs ? `?${qs}` : ""}`);
|
|
@@ -8088,11 +8093,11 @@ var MAX_CONSECUTIVE_FAILURES = 5;
|
|
|
8088
8093
|
var MAX_BACKOFF_MS = 3e4;
|
|
8089
8094
|
function numberOpt2(parsed, flag, fallback) {
|
|
8090
8095
|
const raw = stringOpt(parsed.options[flag]);
|
|
8091
|
-
const
|
|
8092
|
-
return Number.isFinite(
|
|
8096
|
+
const value2 = raw == null ? NaN : Number(raw);
|
|
8097
|
+
return Number.isFinite(value2) && value2 > 0 ? value2 : fallback;
|
|
8093
8098
|
}
|
|
8094
|
-
function jsonl(ctx, parsed,
|
|
8095
|
-
if (parsed.options.jsonl === true) ctx.out.log(JSON.stringify({ v: 1, ...
|
|
8099
|
+
function jsonl(ctx, parsed, value2) {
|
|
8100
|
+
if (parsed.options.jsonl === true) ctx.out.log(JSON.stringify({ v: 1, ...value2 }));
|
|
8096
8101
|
}
|
|
8097
8102
|
async function discussWatch(ctx, topicId, parsed) {
|
|
8098
8103
|
if (ctx.json && parsed.options.jsonl === true) throw new Error("--json and --jsonl cannot be combined");
|
|
@@ -8354,13 +8359,13 @@ async function pmRequest(ctx, method, path, body) {
|
|
|
8354
8359
|
function collectFields(parsed, allowClear) {
|
|
8355
8360
|
const out = {};
|
|
8356
8361
|
for (const [flag, spec] of Object.entries(FIELD_MAP)) {
|
|
8357
|
-
const
|
|
8358
|
-
if (
|
|
8359
|
-
if (
|
|
8362
|
+
const value2 = parsed.options[flag];
|
|
8363
|
+
if (value2 === void 0 || value2 === true) continue;
|
|
8364
|
+
if (value2 === false) {
|
|
8360
8365
|
if (allowClear) out[spec.key] = null;
|
|
8361
8366
|
continue;
|
|
8362
8367
|
}
|
|
8363
|
-
const text = stringOpt(
|
|
8368
|
+
const text = stringOpt(value2);
|
|
8364
8369
|
out[spec.key] = spec.num ? Number(text) : text;
|
|
8365
8370
|
}
|
|
8366
8371
|
return out;
|
|
@@ -8381,8 +8386,8 @@ function statusCol(entity, r) {
|
|
|
8381
8386
|
function printRecord(ctx, entity, r) {
|
|
8382
8387
|
ctx.out.log(`${r.id} [${statusCol(entity, r)}] ${r.appId} ${r.title ?? ""}`);
|
|
8383
8388
|
}
|
|
8384
|
-
function emit2(ctx,
|
|
8385
|
-
if (ctx.json) ctx.out.log(JSON.stringify(
|
|
8389
|
+
function emit2(ctx, value2, human) {
|
|
8390
|
+
if (ctx.json) ctx.out.log(JSON.stringify(value2, null, 2));
|
|
8386
8391
|
else human();
|
|
8387
8392
|
}
|
|
8388
8393
|
async function pmList(ctx, entity, parsed) {
|
|
@@ -8428,8 +8433,8 @@ async function pmAdd(ctx, entity, parsed) {
|
|
|
8428
8433
|
emit2(ctx, res, () => ctx.out.log(`created ${entity} ${res.id}`));
|
|
8429
8434
|
}
|
|
8430
8435
|
async function pmGet(ctx, entity, id) {
|
|
8431
|
-
const { record:
|
|
8432
|
-
emit2(ctx,
|
|
8436
|
+
const { record: record8 } = await pmRequest(ctx, "GET", `/${entity}/${encodeURIComponent(id)}`);
|
|
8437
|
+
emit2(ctx, record8, () => printRecord(ctx, entity, record8));
|
|
8433
8438
|
}
|
|
8434
8439
|
async function pmSet(ctx, entity, id, parsed) {
|
|
8435
8440
|
const patch2 = collectEntityFields(entity, parsed, true);
|
|
@@ -8474,9 +8479,9 @@ async function pmHandoff(ctx, parsed) {
|
|
|
8474
8479
|
]);
|
|
8475
8480
|
const handoff = {
|
|
8476
8481
|
appId,
|
|
8477
|
-
unmetGoals: goals.filter((
|
|
8478
|
-
activeTasks: tasks.filter((
|
|
8479
|
-
openBugs: bugs.filter((
|
|
8482
|
+
unmetGoals: goals.filter((record8) => record8.status !== "met"),
|
|
8483
|
+
activeTasks: tasks.filter((record8) => record8.column !== "done"),
|
|
8484
|
+
openBugs: bugs.filter((record8) => record8.status !== "fixed" && record8.status !== "wontfix")
|
|
8480
8485
|
};
|
|
8481
8486
|
const result = {
|
|
8482
8487
|
...handoff,
|
|
@@ -8495,10 +8500,10 @@ async function pmHandoff(ctx, parsed) {
|
|
|
8495
8500
|
]) {
|
|
8496
8501
|
ctx.out.log(`${label}:`);
|
|
8497
8502
|
if (!records.length) ctx.out.log("- (none)");
|
|
8498
|
-
else for (const
|
|
8503
|
+
else for (const record8 of records) printRecord(
|
|
8499
8504
|
ctx,
|
|
8500
8505
|
label === "unmet goals" ? "goal" : label === "active tasks" ? "task" : "bug",
|
|
8501
|
-
|
|
8506
|
+
record8
|
|
8502
8507
|
);
|
|
8503
8508
|
}
|
|
8504
8509
|
});
|
|
@@ -8646,6 +8651,113 @@ async function pmCommand(parsed, deps = {}) {
|
|
|
8646
8651
|
}
|
|
8647
8652
|
}
|
|
8648
8653
|
|
|
8654
|
+
// src/platform-output.ts
|
|
8655
|
+
function printPlatformStatus(status, out) {
|
|
8656
|
+
out.log(`platform ${status.verdict.status} ${status.observedAt}`);
|
|
8657
|
+
out.log(
|
|
8658
|
+
`fleet ${status.summary.healthy}/${status.summary.services} healthy ${status.summary.required} required ${status.summary.unreachable} unreachable ${status.summary.notConfigured} not configured`
|
|
8659
|
+
);
|
|
8660
|
+
out.log(`catalog ${status.catalog.revision}`);
|
|
8661
|
+
out.log(
|
|
8662
|
+
"service required health probe ms version provider age requests errors cpu p99 us wall p99 us"
|
|
8663
|
+
);
|
|
8664
|
+
for (const service of status.services) {
|
|
8665
|
+
const metrics = service.provider.metrics;
|
|
8666
|
+
out.log([
|
|
8667
|
+
service.id,
|
|
8668
|
+
service.required ? "yes" : "no",
|
|
8669
|
+
service.health.status,
|
|
8670
|
+
value(service.health.latencyMs),
|
|
8671
|
+
service.release.observedVersionId ?? "unknown",
|
|
8672
|
+
service.provider.status,
|
|
8673
|
+
age(service.provider.ageMs),
|
|
8674
|
+
value(metrics?.requests),
|
|
8675
|
+
value(metrics?.errors),
|
|
8676
|
+
value(metrics?.cpuTimeP99),
|
|
8677
|
+
value(metrics?.wallTimeP99)
|
|
8678
|
+
].join(" "));
|
|
8679
|
+
}
|
|
8680
|
+
if (status.verdict.reasons.length) {
|
|
8681
|
+
out.log(`reasons ${status.verdict.reasons.join(", ")}`);
|
|
8682
|
+
}
|
|
8683
|
+
for (const action of status.nextActions) {
|
|
8684
|
+
out.log(`next ${action.service} ${action.code} ${action.message}`);
|
|
8685
|
+
}
|
|
8686
|
+
}
|
|
8687
|
+
function value(input) {
|
|
8688
|
+
return input === null || input === void 0 ? "unknown" : String(input);
|
|
8689
|
+
}
|
|
8690
|
+
function age(input) {
|
|
8691
|
+
if (input === null) return "unknown";
|
|
8692
|
+
if (input < 1e3) return `${input}ms`;
|
|
8693
|
+
if (input < 6e4) return `${Math.round(input / 1e3)}s`;
|
|
8694
|
+
return `${Math.round(input / 6e4)}m`;
|
|
8695
|
+
}
|
|
8696
|
+
|
|
8697
|
+
// src/platform-command.ts
|
|
8698
|
+
async function platformCommand(parsed, deps = {}) {
|
|
8699
|
+
assertArgs(
|
|
8700
|
+
parsed,
|
|
8701
|
+
["config", "context", "platform", "token", "email", "open", "json"],
|
|
8702
|
+
2
|
|
8703
|
+
);
|
|
8704
|
+
const action = parsed.positionals[1];
|
|
8705
|
+
if (action !== "status") {
|
|
8706
|
+
throw new Error(
|
|
8707
|
+
`unknown platform action "${action ?? ""}". Try "odla-ai platform status --json".`
|
|
8708
|
+
);
|
|
8709
|
+
}
|
|
8710
|
+
const context = await resolveOperatorContext(parsed, {
|
|
8711
|
+
allowMissingConfig: true
|
|
8712
|
+
});
|
|
8713
|
+
const platform = context.platform.value;
|
|
8714
|
+
const doFetch = deps.fetch ?? fetch;
|
|
8715
|
+
const out = deps.stdout ?? console;
|
|
8716
|
+
const token = await resolveAdminPlatformToken({
|
|
8717
|
+
platform,
|
|
8718
|
+
scope: "platform:status:read",
|
|
8719
|
+
token: stringOpt(parsed.options.token),
|
|
8720
|
+
tokenFile: context.credentials.scopedTokenFile,
|
|
8721
|
+
email: stringOpt(parsed.options.email),
|
|
8722
|
+
open: parsed.options.open === false ? false : parsed.options.open === true ? true : void 0,
|
|
8723
|
+
fetch: doFetch,
|
|
8724
|
+
stdout: out,
|
|
8725
|
+
openApprovalUrl: deps.openUrl,
|
|
8726
|
+
label: "odla CLI (platform fleet status)"
|
|
8727
|
+
});
|
|
8728
|
+
const response2 = await doFetch(`${platform}/registry/platform/status`, {
|
|
8729
|
+
headers: { authorization: `Bearer ${token}` }
|
|
8730
|
+
});
|
|
8731
|
+
const body = await response2.json().catch(() => null);
|
|
8732
|
+
if (!response2.ok) {
|
|
8733
|
+
throw new Error(
|
|
8734
|
+
`read platform status failed (HTTP ${response2.status}): ${apiMessage(body)}`
|
|
8735
|
+
);
|
|
8736
|
+
}
|
|
8737
|
+
if (!isPlatformStatus(body)) {
|
|
8738
|
+
throw new Error("platform returned an invalid odla.platform-status/v1 envelope");
|
|
8739
|
+
}
|
|
8740
|
+
if (parsed.options.json === true) {
|
|
8741
|
+
out.log(JSON.stringify(body, null, 2));
|
|
8742
|
+
} else {
|
|
8743
|
+
printPlatformStatus(body, out);
|
|
8744
|
+
}
|
|
8745
|
+
}
|
|
8746
|
+
function isPlatformStatus(value2) {
|
|
8747
|
+
if (!record5(value2) || value2.schemaVersion !== "odla.platform-status/v1") return false;
|
|
8748
|
+
if (!record5(value2.verdict) || !Array.isArray(value2.verdict.reasons)) return false;
|
|
8749
|
+
if (!record5(value2.catalog) || !record5(value2.summary)) return false;
|
|
8750
|
+
return Array.isArray(value2.services) && Array.isArray(value2.nextActions);
|
|
8751
|
+
}
|
|
8752
|
+
function apiMessage(value2) {
|
|
8753
|
+
if (!record5(value2)) return "request failed";
|
|
8754
|
+
const error = record5(value2.error) ? value2.error : value2;
|
|
8755
|
+
return typeof error.message === "string" ? error.message : typeof error.code === "string" ? error.code : "request failed";
|
|
8756
|
+
}
|
|
8757
|
+
function record5(value2) {
|
|
8758
|
+
return !!value2 && typeof value2 === "object" && !Array.isArray(value2);
|
|
8759
|
+
}
|
|
8760
|
+
|
|
8649
8761
|
// src/o11y-verdict.ts
|
|
8650
8762
|
function statusVerdict(reads) {
|
|
8651
8763
|
const reasons = [];
|
|
@@ -8683,7 +8795,7 @@ function statusVerdict(reads) {
|
|
|
8683
8795
|
severity: "degraded"
|
|
8684
8796
|
});
|
|
8685
8797
|
}
|
|
8686
|
-
const performance =
|
|
8798
|
+
const performance = record6(reads.liveSync.body.performance) ? reads.liveSync.body.performance : null;
|
|
8687
8799
|
if (performance?.status === "unavailable") {
|
|
8688
8800
|
reasons.push({
|
|
8689
8801
|
source: "liveSync",
|
|
@@ -8764,11 +8876,11 @@ function statusVerdict(reads) {
|
|
|
8764
8876
|
reasons
|
|
8765
8877
|
};
|
|
8766
8878
|
}
|
|
8767
|
-
function
|
|
8768
|
-
return Boolean(
|
|
8879
|
+
function record6(value2) {
|
|
8880
|
+
return Boolean(value2) && typeof value2 === "object" && !Array.isArray(value2);
|
|
8769
8881
|
}
|
|
8770
|
-
function numeric2(
|
|
8771
|
-
return typeof
|
|
8882
|
+
function numeric2(value2) {
|
|
8883
|
+
return typeof value2 === "number" && Number.isFinite(value2) ? value2 : 0;
|
|
8772
8884
|
}
|
|
8773
8885
|
function collectorReason(read3, fallback) {
|
|
8774
8886
|
const reasons = read3.body.reasons;
|
|
@@ -8792,7 +8904,7 @@ function printO11yStatus(status, out) {
|
|
|
8792
8904
|
out.log(
|
|
8793
8905
|
`o11y status ${status.scope.appId}/${status.scope.env} (${status.scope.minutes}m)`
|
|
8794
8906
|
);
|
|
8795
|
-
const routes = Array.isArray(status.application.body.routes) ? status.application.body.routes.filter(
|
|
8907
|
+
const routes = Array.isArray(status.application.body.routes) ? status.application.body.routes.filter(record7) : [];
|
|
8796
8908
|
const requests = routes.reduce(
|
|
8797
8909
|
(total, row) => total + numeric3(row.requests),
|
|
8798
8910
|
0
|
|
@@ -8804,39 +8916,39 @@ function printO11yStatus(status, out) {
|
|
|
8804
8916
|
out.log(
|
|
8805
8917
|
`application ${status.application.httpStatus} ${requests} requests ${errors} errors`
|
|
8806
8918
|
);
|
|
8807
|
-
const versions = Array.isArray(status.applicationVersions.body.rows) ? status.applicationVersions.body.rows.filter(
|
|
8919
|
+
const versions = Array.isArray(status.applicationVersions.body.rows) ? status.applicationVersions.body.rows.filter(record7) : [];
|
|
8808
8920
|
out.log(
|
|
8809
8921
|
`application-versions ${status.applicationVersions.httpStatus} ${versions.length ? versions.slice(0, 5).map(
|
|
8810
8922
|
(row) => `${String(row.value || "(unattributed)")}:${numeric3(row.requests)}`
|
|
8811
8923
|
).join(", ") : "none observed"}`
|
|
8812
8924
|
);
|
|
8813
8925
|
out.log(liveSyncLine(status.liveSync));
|
|
8814
|
-
const canaryDurations =
|
|
8926
|
+
const canaryDurations = record7(status.canary.body.durationsMs) ? status.canary.body.durationsMs : {};
|
|
8815
8927
|
out.log(
|
|
8816
8928
|
`canary ${status.canary.httpStatus} ${String(status.canary.body.status ?? status.canary.body.error ?? "unavailable")} ${optionalNumeric(canaryDurations.publishToVisibleMs)} publish-to-visible`
|
|
8817
8929
|
);
|
|
8818
|
-
const collectorIngest =
|
|
8819
|
-
const collectorStorage =
|
|
8930
|
+
const collectorIngest = record7(status.collector.body.ingest) ? status.collector.body.ingest : {};
|
|
8931
|
+
const collectorStorage = record7(collectorIngest.storage) ? collectorIngest.storage : {};
|
|
8820
8932
|
out.log(
|
|
8821
8933
|
`collector ${status.collector.httpStatus} ${String(status.collector.body.status ?? status.collector.body.error ?? "unavailable")} ${numeric3(collectorStorage.affectedPoints)} affected points`
|
|
8822
8934
|
);
|
|
8823
|
-
const providerMetrics =
|
|
8824
|
-
const providerCapacity =
|
|
8825
|
-
const workerMemory =
|
|
8935
|
+
const providerMetrics = record7(status.provider.body.metrics) ? status.provider.body.metrics : {};
|
|
8936
|
+
const providerCapacity = record7(status.provider.body.capacity) ? status.provider.body.capacity : {};
|
|
8937
|
+
const workerMemory = record7(providerCapacity.memory) ? providerCapacity.memory : {};
|
|
8826
8938
|
out.log(
|
|
8827
8939
|
`cloudflare ${status.provider.httpStatus} ${String(status.provider.body.status ?? status.provider.body.error ?? "unavailable")} ${numeric3(providerMetrics.requests)} invocations ${numeric3(providerMetrics.errors)} runtime errors ${optionalBytes(workerMemory.headroomBytes)} isolate memory headroom`
|
|
8828
8940
|
);
|
|
8829
8941
|
for (const line of providerCapacityLines(status.providerCapacity)) {
|
|
8830
8942
|
out.log(line);
|
|
8831
8943
|
}
|
|
8832
|
-
const coverage =
|
|
8833
|
-
const coverageCounts =
|
|
8834
|
-
const coverageBudget =
|
|
8944
|
+
const coverage = record7(status.providerReconciliation.body.comparison) ? status.providerReconciliation.body.comparison : {};
|
|
8945
|
+
const coverageCounts = record7(status.providerReconciliation.body.counts) ? status.providerReconciliation.body.counts : {};
|
|
8946
|
+
const coverageBudget = record7(status.providerReconciliation.body.budget) ? status.providerReconciliation.body.budget : {};
|
|
8835
8947
|
out.log(
|
|
8836
8948
|
`request-coverage ${status.providerReconciliation.httpStatus} ${String(status.providerReconciliation.body.status ?? status.providerReconciliation.body.error ?? "unavailable")} ${optionalPercent(coverage.applicationCoverage)} application/provider ${numeric3(coverageCounts.applicationRequests)}/${numeric3(coverageCounts.providerRequests)} requests \xB1${optionalPercent(coverageBudget.maxRelativeError)} budget`
|
|
8837
8949
|
);
|
|
8838
8950
|
const providerPoints = Array.isArray(status.providerHistory.body.points) ? status.providerHistory.body.points.length : 0;
|
|
8839
|
-
const providerFreshness =
|
|
8951
|
+
const providerFreshness = record7(status.providerHistory.body.freshness) ? status.providerHistory.body.freshness : {};
|
|
8840
8952
|
out.log(
|
|
8841
8953
|
`cloudflare-history ${status.providerHistory.httpStatus} ${String(status.providerHistory.body.status ?? status.providerHistory.body.error ?? "unavailable")} ${providerPoints} snapshots ${optionalAge(providerFreshness.ageMs)} old`
|
|
8842
8954
|
);
|
|
@@ -8845,17 +8957,17 @@ function printO11yStatus(status, out) {
|
|
|
8845
8957
|
);
|
|
8846
8958
|
}
|
|
8847
8959
|
function providerCapacityLines(read3) {
|
|
8848
|
-
const resources =
|
|
8849
|
-
const durableObjects =
|
|
8850
|
-
const periodic =
|
|
8851
|
-
const storage =
|
|
8852
|
-
const d1 =
|
|
8853
|
-
const d1Activity =
|
|
8854
|
-
const d1Storage =
|
|
8855
|
-
const d1Latency =
|
|
8856
|
-
const r2 =
|
|
8857
|
-
const r2Operations =
|
|
8858
|
-
const r2Storage =
|
|
8960
|
+
const resources = record7(read3.body.resources) ? read3.body.resources : {};
|
|
8961
|
+
const durableObjects = record7(resources.durableObjects) ? resources.durableObjects : {};
|
|
8962
|
+
const periodic = record7(durableObjects.periodic) ? durableObjects.periodic : {};
|
|
8963
|
+
const storage = record7(durableObjects.sqliteStorage) ? durableObjects.sqliteStorage : {};
|
|
8964
|
+
const d1 = record7(resources.d1) ? resources.d1 : {};
|
|
8965
|
+
const d1Activity = record7(d1.activity) ? d1.activity : {};
|
|
8966
|
+
const d1Storage = record7(d1.storage) ? d1.storage : {};
|
|
8967
|
+
const d1Latency = record7(d1Activity.latency) ? d1Activity.latency : {};
|
|
8968
|
+
const r2 = record7(resources.r2) ? resources.r2 : {};
|
|
8969
|
+
const r2Operations = record7(r2.operations) ? r2.operations : {};
|
|
8970
|
+
const r2Storage = record7(r2.storage) ? r2.storage : {};
|
|
8859
8971
|
const status = String(
|
|
8860
8972
|
read3.body.status ?? read3.body.error ?? "unavailable"
|
|
8861
8973
|
);
|
|
@@ -8866,42 +8978,42 @@ function providerCapacityLines(read3) {
|
|
|
8866
8978
|
];
|
|
8867
8979
|
}
|
|
8868
8980
|
function liveSyncLine(read3) {
|
|
8869
|
-
const performance =
|
|
8870
|
-
const commitToSend =
|
|
8981
|
+
const performance = record7(read3.body.performance) ? read3.body.performance : {};
|
|
8982
|
+
const commitToSend = record7(performance.commitToSend) ? performance.commitToSend : {};
|
|
8871
8983
|
return `live-sync ${read3.httpStatus} ${String(read3.body.status ?? read3.body.error ?? "unavailable")} ${numeric3(read3.body.activeConnections)} active ${optionalNumeric(commitToSend.p95)} commit-to-send p95 ${numeric3(performance.sendFailures)} send failures`;
|
|
8872
8984
|
}
|
|
8873
|
-
function
|
|
8874
|
-
return Boolean(
|
|
8985
|
+
function record7(value2) {
|
|
8986
|
+
return Boolean(value2) && typeof value2 === "object" && !Array.isArray(value2);
|
|
8875
8987
|
}
|
|
8876
|
-
function numeric3(
|
|
8877
|
-
return typeof
|
|
8988
|
+
function numeric3(value2) {
|
|
8989
|
+
return typeof value2 === "number" && Number.isFinite(value2) ? value2 : 0;
|
|
8878
8990
|
}
|
|
8879
|
-
function optionalNumeric(
|
|
8880
|
-
return typeof
|
|
8991
|
+
function optionalNumeric(value2) {
|
|
8992
|
+
return typeof value2 === "number" && Number.isFinite(value2) ? `${value2} ms` : "\u2014";
|
|
8881
8993
|
}
|
|
8882
|
-
function optionalAge(
|
|
8883
|
-
if (typeof
|
|
8884
|
-
return `${Math.max(0, Math.round(
|
|
8994
|
+
function optionalAge(value2) {
|
|
8995
|
+
if (typeof value2 !== "number" || !Number.isFinite(value2)) return "unknown";
|
|
8996
|
+
return `${Math.max(0, Math.round(value2 / 1e3))}s`;
|
|
8885
8997
|
}
|
|
8886
|
-
function optionalPercent(
|
|
8887
|
-
return typeof
|
|
8998
|
+
function optionalPercent(value2) {
|
|
8999
|
+
return typeof value2 === "number" && Number.isFinite(value2) ? `${Math.round(value2 * 100)}%` : "\u2014";
|
|
8888
9000
|
}
|
|
8889
|
-
function optionalBytes(
|
|
8890
|
-
if (typeof
|
|
8891
|
-
if (
|
|
8892
|
-
return `${(
|
|
9001
|
+
function optionalBytes(value2) {
|
|
9002
|
+
if (typeof value2 !== "number" || !Number.isFinite(value2)) return "\u2014";
|
|
9003
|
+
if (value2 >= 1024 * 1024 * 1024) {
|
|
9004
|
+
return `${(value2 / (1024 * 1024 * 1024)).toFixed(2)} GiB`;
|
|
8893
9005
|
}
|
|
8894
|
-
if (
|
|
8895
|
-
return `${(
|
|
9006
|
+
if (value2 >= 1024 * 1024) {
|
|
9007
|
+
return `${(value2 / (1024 * 1024)).toFixed(1)} MiB`;
|
|
8896
9008
|
}
|
|
8897
|
-
if (
|
|
8898
|
-
return `${Math.round(
|
|
9009
|
+
if (value2 >= 1024) return `${(value2 / 1024).toFixed(1)} KiB`;
|
|
9010
|
+
return `${Math.round(value2)} B`;
|
|
8899
9011
|
}
|
|
8900
|
-
function optionalCount(
|
|
8901
|
-
return typeof
|
|
9012
|
+
function optionalCount(value2, unit) {
|
|
9013
|
+
return typeof value2 === "number" && Number.isFinite(value2) ? `${value2} ${unit}` : `\u2014 ${unit}`;
|
|
8902
9014
|
}
|
|
8903
|
-
function optionalAgeSeconds(
|
|
8904
|
-
return typeof
|
|
9015
|
+
function optionalAgeSeconds(value2) {
|
|
9016
|
+
return typeof value2 === "number" && Number.isFinite(value2) ? `${Math.max(0, Math.round(value2))}s` : "unknown";
|
|
8905
9017
|
}
|
|
8906
9018
|
|
|
8907
9019
|
// src/o11y-command.ts
|
|
@@ -9031,11 +9143,11 @@ async function o11yCommand(parsed, deps = {}) {
|
|
|
9031
9143
|
}
|
|
9032
9144
|
printO11yStatus(status, out);
|
|
9033
9145
|
}
|
|
9034
|
-
function statusMinutes(
|
|
9035
|
-
if (!Number.isSafeInteger(
|
|
9146
|
+
function statusMinutes(value2) {
|
|
9147
|
+
if (!Number.isSafeInteger(value2) || value2 < 1 || value2 > 7 * 24 * 60) {
|
|
9036
9148
|
throw new Error("--minutes must be an integer from 1 to 10080");
|
|
9037
9149
|
}
|
|
9038
|
-
return
|
|
9150
|
+
return value2;
|
|
9039
9151
|
}
|
|
9040
9152
|
async function read2(url, headers, doFetch) {
|
|
9041
9153
|
const response2 = await doFetch(url, { headers });
|
|
@@ -9043,8 +9155,8 @@ async function read2(url, headers, doFetch) {
|
|
|
9043
9155
|
let body = {};
|
|
9044
9156
|
if (text) {
|
|
9045
9157
|
try {
|
|
9046
|
-
const
|
|
9047
|
-
body =
|
|
9158
|
+
const value2 = JSON.parse(text);
|
|
9159
|
+
body = value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : { value: value2 };
|
|
9048
9160
|
} catch {
|
|
9049
9161
|
body = { message: text.slice(0, 300) };
|
|
9050
9162
|
}
|
|
@@ -9098,8 +9210,8 @@ async function postJson2(doFetch, url, bearer, body) {
|
|
|
9098
9210
|
if (!res.ok) throw new Error(`${new URL(url).pathname} failed: ${res.status} ${await responseText(res)}`);
|
|
9099
9211
|
return res.json().catch(() => ({}));
|
|
9100
9212
|
}
|
|
9101
|
-
function isRecord7(
|
|
9102
|
-
return
|
|
9213
|
+
function isRecord7(value2) {
|
|
9214
|
+
return value2 !== null && typeof value2 === "object" && !Array.isArray(value2);
|
|
9103
9215
|
}
|
|
9104
9216
|
async function responseText(res) {
|
|
9105
9217
|
try {
|
|
@@ -9232,14 +9344,14 @@ async function postJson3(doFetch, url, bearer, body) {
|
|
|
9232
9344
|
});
|
|
9233
9345
|
if (!res.ok) throw new Error(`${new URL(url).pathname} failed: ${res.status} ${await safeText5(res)}`);
|
|
9234
9346
|
}
|
|
9235
|
-
function normalizeClerkConfig(
|
|
9236
|
-
if (!
|
|
9237
|
-
if (typeof
|
|
9238
|
-
const publishableKey2 = envValue(
|
|
9347
|
+
function normalizeClerkConfig(value2) {
|
|
9348
|
+
if (!value2) return null;
|
|
9349
|
+
if (typeof value2 === "string") {
|
|
9350
|
+
const publishableKey2 = envValue(value2);
|
|
9239
9351
|
return publishableKey2 ? { publishableKey: publishableKey2 } : null;
|
|
9240
9352
|
}
|
|
9241
|
-
if (typeof
|
|
9242
|
-
const cfg =
|
|
9353
|
+
if (typeof value2 !== "object") return null;
|
|
9354
|
+
const cfg = value2;
|
|
9243
9355
|
const publishableKey = envValue(cfg.publishableKey);
|
|
9244
9356
|
return publishableKey ? { publishableKey, ...cfg.audience ? { audience: cfg.audience } : {}, ...cfg.mode ? { mode: cfg.mode } : {} } : null;
|
|
9245
9357
|
}
|
|
@@ -9516,6 +9628,7 @@ var COMMAND_SURFACE = {
|
|
|
9516
9628
|
help: {},
|
|
9517
9629
|
init: {},
|
|
9518
9630
|
o11y: { status: {} },
|
|
9631
|
+
platform: { status: {} },
|
|
9519
9632
|
pm: {
|
|
9520
9633
|
...PM_ENTITIES,
|
|
9521
9634
|
handoff: {}
|
|
@@ -9608,7 +9721,7 @@ function recordInvocation(parsed) {
|
|
|
9608
9721
|
try {
|
|
9609
9722
|
const entry = {
|
|
9610
9723
|
path: invocationPath(parsed.positionals),
|
|
9611
|
-
options: Object.entries(parsed.options).map(([name,
|
|
9724
|
+
options: Object.entries(parsed.options).map(([name, value2]) => value2 === false ? `no-${name}` : name).sort()
|
|
9612
9725
|
};
|
|
9613
9726
|
if (!entry.path.length) return;
|
|
9614
9727
|
(0, import_node_fs15.appendFileSync)(file, `${JSON.stringify(entry)}
|
|
@@ -9622,10 +9735,10 @@ var import_node_fs16 = require("fs");
|
|
|
9622
9735
|
|
|
9623
9736
|
// src/runbook-requires.ts
|
|
9624
9737
|
var SPEC = /^(@?[\w./-]+?)@(\d+\.\d+\.\d+(?:[\w.-]*)?)$/;
|
|
9625
|
-
function parseRequires(
|
|
9626
|
-
if (!
|
|
9738
|
+
function parseRequires(value2) {
|
|
9739
|
+
if (!value2) return [];
|
|
9627
9740
|
const out = [];
|
|
9628
|
-
for (const token of
|
|
9741
|
+
for (const token of value2.split(/[\s,]+/).filter(Boolean)) {
|
|
9629
9742
|
const match = SPEC.exec(token);
|
|
9630
9743
|
if (match?.[1] && match[2]) out.push({ name: match[1], min: match[2] });
|
|
9631
9744
|
}
|
|
@@ -9801,9 +9914,9 @@ function parseRunbook(text, slug) {
|
|
|
9801
9914
|
for (const line of fm[1].split(/\r?\n/)) {
|
|
9802
9915
|
const pair = /^(\w+)\s*:\s*(.+)$/.exec(line.trim());
|
|
9803
9916
|
if (!pair) continue;
|
|
9804
|
-
const
|
|
9805
|
-
if (pair[1] === "summary") meta.summary =
|
|
9806
|
-
if (pair[1] === "tags") meta.tags =
|
|
9917
|
+
const value2 = pair[2].trim().replace(/^["']|["']$/g, "");
|
|
9918
|
+
if (pair[1] === "summary") meta.summary = value2;
|
|
9919
|
+
if (pair[1] === "tags") meta.tags = value2.replace(/^\[|\]$/g, "").trim();
|
|
9807
9920
|
}
|
|
9808
9921
|
}
|
|
9809
9922
|
const lines = rest.split("\n");
|
|
@@ -9920,7 +10033,7 @@ var NOISE = /* @__PURE__ */ new Set([
|
|
|
9920
10033
|
"and",
|
|
9921
10034
|
"for"
|
|
9922
10035
|
]);
|
|
9923
|
-
var words = (
|
|
10036
|
+
var words = (value2) => value2.replace(/^@[\w-]+\//, "").split(/[^A-Za-z0-9]+/).filter((w) => w.length > 1 && !NOISE.has(w.toLowerCase()));
|
|
9924
10037
|
function namedExports(clause) {
|
|
9925
10038
|
return clause.split(",").map((part) => part.trim().split(/\s+as\s+/)[0]?.trim() ?? "").filter((name) => /^[A-Za-z_$][\w$]*$/.test(name) && name !== "type");
|
|
9926
10039
|
}
|
|
@@ -10273,8 +10386,8 @@ var import_node_process12 = __toESM(require("process"), 1);
|
|
|
10273
10386
|
var EDITOR_ENV = ["ODLA_EDITOR", "VISUAL", "EDITOR"];
|
|
10274
10387
|
function resolveEditor(env = import_node_process12.default.env) {
|
|
10275
10388
|
for (const name of EDITOR_ENV) {
|
|
10276
|
-
const
|
|
10277
|
-
if (
|
|
10389
|
+
const value2 = env[name];
|
|
10390
|
+
if (value2 && value2.trim()) return value2.trim();
|
|
10278
10391
|
}
|
|
10279
10392
|
return null;
|
|
10280
10393
|
}
|
|
@@ -10539,9 +10652,9 @@ async function runbookCommand(parsed, deps = {}) {
|
|
|
10539
10652
|
});
|
|
10540
10653
|
}
|
|
10541
10654
|
case "visibility": {
|
|
10542
|
-
const
|
|
10543
|
-
if (!
|
|
10544
|
-
return runbookVisibility(ctx, requireSlug(slug, "visibility"),
|
|
10655
|
+
const value2 = parsed.positionals[3] ?? stringOpt(parsed.options.visibility);
|
|
10656
|
+
if (!value2) throw new Error('"runbook visibility" needs operator|admin, e.g. "runbook visibility release operator"');
|
|
10657
|
+
return runbookVisibility(ctx, requireSlug(slug, "visibility"), value2);
|
|
10545
10658
|
}
|
|
10546
10659
|
case "publish":
|
|
10547
10660
|
return runbookStatus(ctx, requireSlug(slug, "publish"), "published");
|
|
@@ -10597,13 +10710,13 @@ async function interactiveConfirmation(message2, dependencies) {
|
|
|
10597
10710
|
}
|
|
10598
10711
|
}
|
|
10599
10712
|
function requiredSecurityPositional(parsed, index, label) {
|
|
10600
|
-
const
|
|
10601
|
-
if (!
|
|
10602
|
-
return
|
|
10713
|
+
const value2 = parsed.positionals[index];
|
|
10714
|
+
if (!value2) throw new Error(`${label} is required`);
|
|
10715
|
+
return value2;
|
|
10603
10716
|
}
|
|
10604
|
-
function securityProfile(
|
|
10605
|
-
if (
|
|
10606
|
-
if (
|
|
10717
|
+
function securityProfile(value2) {
|
|
10718
|
+
if (value2 === void 0) return void 0;
|
|
10719
|
+
if (value2 === "odla" || value2 === "cloudflare-app" || value2 === "generic") return value2;
|
|
10607
10720
|
throw new Error("--profile must be odla, cloudflare-app, or generic");
|
|
10608
10721
|
}
|
|
10609
10722
|
|
|
@@ -10704,9 +10817,9 @@ function routeLabel(route2) {
|
|
|
10704
10817
|
return `${route2.provider}/${route2.model}${route2.policyVersion ? ` policy v${route2.policyVersion}` : ""}`;
|
|
10705
10818
|
}
|
|
10706
10819
|
var HOSTED_SEVERITIES = ["informational", "low", "medium", "high", "critical"];
|
|
10707
|
-
function hostedSeverity(
|
|
10708
|
-
if (HOSTED_SEVERITIES.includes(
|
|
10709
|
-
return
|
|
10820
|
+
function hostedSeverity(value2, flag) {
|
|
10821
|
+
if (HOSTED_SEVERITIES.includes(value2)) {
|
|
10822
|
+
return value2;
|
|
10710
10823
|
}
|
|
10711
10824
|
throw new Error(`${flag} must be informational, low, medium, high, or critical`);
|
|
10712
10825
|
}
|
|
@@ -10789,13 +10902,13 @@ function selectEnv(requested, declared, configPath, rootDir) {
|
|
|
10789
10902
|
return env;
|
|
10790
10903
|
}
|
|
10791
10904
|
async function injectedToken(options, request2) {
|
|
10792
|
-
const
|
|
10793
|
-
if (typeof
|
|
10905
|
+
const value2 = options.token ?? await options.getToken?.(Object.freeze({ ...request2 }));
|
|
10906
|
+
if (typeof value2 !== "string" || value2.length < 8 || value2.length > 8192 || /\s|[\u0000-\u001f\u007f]/.test(value2)) {
|
|
10794
10907
|
throw new Error(
|
|
10795
10908
|
request2.selfAudit ? "Self-audit requires an injected, scoped platform security token" : "Hosted security requires an injected app developer token or getToken callback"
|
|
10796
10909
|
);
|
|
10797
10910
|
}
|
|
10798
|
-
return
|
|
10911
|
+
return value2;
|
|
10799
10912
|
}
|
|
10800
10913
|
function profileFor(name, maxHuntTasks) {
|
|
10801
10914
|
const profile = name === "odla" ? (0, import_security.odlaProfile)() : name === "cloudflare-app" ? (0, import_security.cloudflareAppProfile)() : name === "generic" ? (0, import_security.genericProfile)() : void 0;
|
|
@@ -10841,8 +10954,8 @@ async function getHostedSecurityIntent(options) {
|
|
|
10841
10954
|
}
|
|
10842
10955
|
return response2;
|
|
10843
10956
|
}
|
|
10844
|
-
function isValidIntent(
|
|
10845
|
-
return !!
|
|
10957
|
+
function isValidIntent(value2, expected) {
|
|
10958
|
+
return !!value2 && value2.executionContract === "odla.hosted-security-execution-consent.v1" && /^sha256:[a-f0-9]{64}$/.test(value2.executionDigest) && /^sha256:[a-f0-9]{64}$/.test(value2.planDigest) && value2.appId === expected.appId && value2.env === expected.env && value2.sourceId === expected.sourceId && typeof value2.repository === "string" && value2.repository.length > 2 && value2.repository.length <= 201 && typeof value2.defaultBranch === "string" && value2.defaultBranch.length > 0 && value2.defaultBranch.length <= 255 && typeof value2.requestedRef === "string" && value2.requestedRef.length > 0 && value2.requestedRef.length <= 255 && !/[\u0000-\u001f\u007f]/.test(value2.requestedRef) && ["odla", "cloudflare-app", "generic"].includes(value2.profile) && value2.sourceDisclosure === "redacted";
|
|
10846
10959
|
}
|
|
10847
10960
|
|
|
10848
10961
|
// src/security-hosted-jobs.ts
|
|
@@ -10968,17 +11081,17 @@ function hostedJobPath(appIdInput, jobIdInput) {
|
|
|
10968
11081
|
const jobId = hostedIdentifier(jobIdInput, "jobId");
|
|
10969
11082
|
return `/registry/apps/${encodeURIComponent(appId)}/security/jobs/${encodeURIComponent(jobId)}`;
|
|
10970
11083
|
}
|
|
10971
|
-
function securityPlanDigest(
|
|
10972
|
-
if (!/^sha256:[a-f0-9]{64}$/.test(
|
|
11084
|
+
function securityPlanDigest(value2) {
|
|
11085
|
+
if (!/^sha256:[a-f0-9]{64}$/.test(value2)) {
|
|
10973
11086
|
throw new Error("expected plan digest must be a sha256 digest from security plan");
|
|
10974
11087
|
}
|
|
10975
|
-
return
|
|
11088
|
+
return value2;
|
|
10976
11089
|
}
|
|
10977
|
-
function securityExecutionDigest(
|
|
10978
|
-
if (!/^sha256:[a-f0-9]{64}$/.test(
|
|
11090
|
+
function securityExecutionDigest(value2) {
|
|
11091
|
+
if (!/^sha256:[a-f0-9]{64}$/.test(value2)) {
|
|
10979
11092
|
throw new Error("expected execution digest must be a sha256 digest from security intent");
|
|
10980
11093
|
}
|
|
10981
|
-
return
|
|
11094
|
+
return value2;
|
|
10982
11095
|
}
|
|
10983
11096
|
|
|
10984
11097
|
// src/security-run-command.ts
|
|
@@ -11042,7 +11155,7 @@ async function runSourceSecurityCommand(parsed, dependencies, sourceId) {
|
|
|
11042
11155
|
...context,
|
|
11043
11156
|
jobId: job.jobId,
|
|
11044
11157
|
wait: dependencies.pollWait,
|
|
11045
|
-
onUpdate: parsed.options.json === true ? void 0 : (
|
|
11158
|
+
onUpdate: parsed.options.json === true ? void 0 : (value2) => printHostedJob(context.stdout, value2, context.platform, context.appId)
|
|
11046
11159
|
}) : job;
|
|
11047
11160
|
if (!follow) {
|
|
11048
11161
|
if (parsed.options.json === true) {
|
|
@@ -11142,9 +11255,9 @@ function enforceLocalGate(report4, parsed) {
|
|
|
11142
11255
|
throw new Error(`hosted security gate failed: ${confirmed.length} confirmed >= ${failOn}; ${leads.length} leads >= ${failOnCandidates ?? "disabled"}${incomplete ? "; coverage incomplete" : ""}`);
|
|
11143
11256
|
}
|
|
11144
11257
|
}
|
|
11145
|
-
function severityOpt(
|
|
11146
|
-
if (["informational", "low", "medium", "high", "critical"].includes(
|
|
11147
|
-
return
|
|
11258
|
+
function severityOpt(value2, flag) {
|
|
11259
|
+
if (["informational", "low", "medium", "high", "critical"].includes(value2)) {
|
|
11260
|
+
return value2;
|
|
11148
11261
|
}
|
|
11149
11262
|
throw new Error(`${flag} must be informational, low, medium, high, or critical`);
|
|
11150
11263
|
}
|
|
@@ -11252,7 +11365,7 @@ async function securityStatus(parsed, dependencies) {
|
|
|
11252
11365
|
...context,
|
|
11253
11366
|
jobId,
|
|
11254
11367
|
wait: dependencies.pollWait,
|
|
11255
|
-
onUpdate: parsed.options.json === true ? void 0 : (
|
|
11368
|
+
onUpdate: parsed.options.json === true ? void 0 : (value2) => printHostedJob(context.stdout, value2, context.platform, context.appId)
|
|
11256
11369
|
}) : await getHostedSecurityJob({ ...context, jobId });
|
|
11257
11370
|
if (parsed.options.json === true) context.stdout.log(JSON.stringify(job, null, 2));
|
|
11258
11371
|
else if (parsed.options.follow !== true) {
|
|
@@ -11336,6 +11449,10 @@ async function runCli(argv = process.argv.slice(2), dependencies = {}) {
|
|
|
11336
11449
|
await o11yCommand(parsed, runtime);
|
|
11337
11450
|
return;
|
|
11338
11451
|
}
|
|
11452
|
+
if (command === "platform") {
|
|
11453
|
+
await platformCommand(parsed, runtime);
|
|
11454
|
+
return;
|
|
11455
|
+
}
|
|
11339
11456
|
if (command === "provision") {
|
|
11340
11457
|
await provisionCommand(parsed, runtime);
|
|
11341
11458
|
return;
|