@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/bin.cjs
CHANGED
|
@@ -82,22 +82,22 @@ function readJsonFile(path) {
|
|
|
82
82
|
return null;
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
|
-
function writePrivateJson(path,
|
|
86
|
-
writePrivateText(path, `${JSON.stringify(
|
|
85
|
+
function writePrivateJson(path, value2) {
|
|
86
|
+
writePrivateText(path, `${JSON.stringify(value2, null, 2)}
|
|
87
87
|
`);
|
|
88
88
|
}
|
|
89
89
|
function readCredentials(path) {
|
|
90
90
|
if (!(0, import_node_fs.existsSync)(path)) return null;
|
|
91
|
-
let
|
|
91
|
+
let value2;
|
|
92
92
|
try {
|
|
93
|
-
|
|
93
|
+
value2 = JSON.parse((0, import_node_fs.readFileSync)(path, "utf8"));
|
|
94
94
|
} catch {
|
|
95
95
|
throw new Error(`credentials file ${path} is not valid JSON; fix or remove it before provisioning`);
|
|
96
96
|
}
|
|
97
|
-
if (!
|
|
97
|
+
if (!value2 || typeof value2 !== "object" || typeof value2.appId !== "string" || !value2.envs || typeof value2.envs !== "object") {
|
|
98
98
|
throw new Error(`credentials file ${path} has an invalid shape; fix or remove it before provisioning`);
|
|
99
99
|
}
|
|
100
|
-
return
|
|
100
|
+
return value2;
|
|
101
101
|
}
|
|
102
102
|
function mergeCredential(current, update) {
|
|
103
103
|
const next = current ?? {
|
|
@@ -392,8 +392,8 @@ function stillPending(pending, email) {
|
|
|
392
392
|
{ retryable: true }
|
|
393
393
|
);
|
|
394
394
|
}
|
|
395
|
-
function handshakeEmail(
|
|
396
|
-
const email = (
|
|
395
|
+
function handshakeEmail(value2, cached) {
|
|
396
|
+
const email = (value2 ?? import_node_process3.default.env.ODLA_USER_EMAIL ?? cached ?? "").trim().toLowerCase();
|
|
397
397
|
if (email.length > 254 || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
|
|
398
398
|
throw new Error("a fresh odla handshake requires --email <account> or ODLA_USER_EMAIL");
|
|
399
399
|
}
|
|
@@ -417,10 +417,10 @@ function handshakeUrl(platformUrl, userCode) {
|
|
|
417
417
|
url.searchParams.set("code", userCode);
|
|
418
418
|
return url.toString();
|
|
419
419
|
}
|
|
420
|
-
function platformAudience(
|
|
420
|
+
function platformAudience(value2) {
|
|
421
421
|
let url;
|
|
422
422
|
try {
|
|
423
|
-
url = new URL(
|
|
423
|
+
url = new URL(value2);
|
|
424
424
|
} catch {
|
|
425
425
|
throw new Error("platform must be an absolute URL");
|
|
426
426
|
}
|
|
@@ -439,22 +439,22 @@ var import_node_process4 = __toESM(require("process"), 1);
|
|
|
439
439
|
var MAX_BYTES = 64 * 1024;
|
|
440
440
|
async function secretInputValue(options, kind = "credential") {
|
|
441
441
|
if (options.fromEnv && options.stdin) throw new Error("choose exactly one of --from-env or --stdin");
|
|
442
|
-
let
|
|
443
|
-
if (options.fromEnv)
|
|
444
|
-
else if (options.stdin)
|
|
442
|
+
let value2;
|
|
443
|
+
if (options.fromEnv) value2 = import_node_process4.default.env[options.fromEnv];
|
|
444
|
+
else if (options.stdin) value2 = await (options.readStdin ?? (() => readSecretStream(kind)))();
|
|
445
445
|
else throw new Error(`${kind} input required: use --from-env <NAME> or --stdin; values are never accepted as arguments`);
|
|
446
|
-
|
|
447
|
-
if (!
|
|
448
|
-
if (new TextEncoder().encode(
|
|
449
|
-
return
|
|
446
|
+
value2 = value2?.replace(/[\r\n]+$/, "");
|
|
447
|
+
if (!value2) throw new Error(options.fromEnv ? `environment variable ${options.fromEnv} is empty or unset` : `stdin ${kind} is empty`);
|
|
448
|
+
if (new TextEncoder().encode(value2).byteLength > MAX_BYTES) throw new Error(`${kind} exceeds 64 KiB`);
|
|
449
|
+
return value2;
|
|
450
450
|
}
|
|
451
451
|
async function readSecretStream(kind, stream = import_node_process4.default.stdin) {
|
|
452
|
-
let
|
|
452
|
+
let value2 = "";
|
|
453
453
|
for await (const chunk of stream) {
|
|
454
|
-
|
|
455
|
-
if (
|
|
454
|
+
value2 += String(chunk);
|
|
455
|
+
if (value2.length > MAX_BYTES) throw new Error(`${kind} exceeds 64 KiB`);
|
|
456
456
|
}
|
|
457
|
-
return
|
|
457
|
+
return value2;
|
|
458
458
|
}
|
|
459
459
|
|
|
460
460
|
// src/admin-ai-auth.ts
|
|
@@ -489,6 +489,7 @@ function audienceBoundEnvToken(token, platform) {
|
|
|
489
489
|
return token;
|
|
490
490
|
}
|
|
491
491
|
var SCOPE_PURPOSE = {
|
|
492
|
+
"platform:status:read": "read the platform fleet health and deployment snapshot",
|
|
492
493
|
"platform:runbook:write": "add or edit odla's operational runbooks",
|
|
493
494
|
"platform:ai:policy:write": "change System AI model routing",
|
|
494
495
|
"platform:ai:policy:read": "read System AI model routing",
|
|
@@ -592,13 +593,13 @@ function apiError(status, body) {
|
|
|
592
593
|
const message2 = error && typeof error.message === "string" ? error.message : isRecord(body) && typeof body.message === "string" ? body.message : "request failed";
|
|
593
594
|
return `read System AI admin changes failed (${status}): ${message2}`;
|
|
594
595
|
}
|
|
595
|
-
function timestamp(
|
|
596
|
-
if (typeof
|
|
597
|
-
const date = new Date(
|
|
596
|
+
function timestamp(value2) {
|
|
597
|
+
if (typeof value2 !== "number" || !Number.isFinite(value2)) return String(value2 ?? "");
|
|
598
|
+
const date = new Date(value2);
|
|
598
599
|
return Number.isFinite(date.valueOf()) ? date.toISOString() : "";
|
|
599
600
|
}
|
|
600
|
-
function isRecord(
|
|
601
|
-
return Boolean(
|
|
601
|
+
function isRecord(value2) {
|
|
602
|
+
return Boolean(value2) && typeof value2 === "object" && !Array.isArray(value2);
|
|
602
603
|
}
|
|
603
604
|
|
|
604
605
|
// src/admin-ai-policy.ts
|
|
@@ -608,11 +609,11 @@ var SYSTEM_AI_PURPOSES = [
|
|
|
608
609
|
"security.validation",
|
|
609
610
|
"runbook.answer"
|
|
610
611
|
];
|
|
611
|
-
function requireSystemAiPurpose(
|
|
612
|
-
if (!SYSTEM_AI_PURPOSES.includes(
|
|
612
|
+
function requireSystemAiPurpose(value2) {
|
|
613
|
+
if (!SYSTEM_AI_PURPOSES.includes(value2)) {
|
|
613
614
|
throw new Error(`purpose must be one of: ${SYSTEM_AI_PURPOSES.join(", ")}`);
|
|
614
615
|
}
|
|
615
|
-
return
|
|
616
|
+
return value2;
|
|
616
617
|
}
|
|
617
618
|
|
|
618
619
|
// src/admin-ai-usage.ts
|
|
@@ -634,11 +635,11 @@ async function readAdminAiUsage(request2) {
|
|
|
634
635
|
if (request2.json) request2.stdout.log(JSON.stringify(body, null, 2));
|
|
635
636
|
else printUsage(body, request2.stdout);
|
|
636
637
|
}
|
|
637
|
-
function usageLimit(
|
|
638
|
-
if (!Number.isSafeInteger(
|
|
638
|
+
function usageLimit(value2) {
|
|
639
|
+
if (!Number.isSafeInteger(value2) || value2 < 1 || value2 > 500) {
|
|
639
640
|
throw new Error("usage limit must be an integer from 1 to 500");
|
|
640
641
|
}
|
|
641
|
-
return
|
|
642
|
+
return value2;
|
|
642
643
|
}
|
|
643
644
|
function printUsage(body, out) {
|
|
644
645
|
const aggregates = isRecord2(body) && isRecord2(body.aggregates) && Array.isArray(body.aggregates.byStatus) ? body.aggregates.byStatus.filter(isRecord2) : [];
|
|
@@ -674,15 +675,15 @@ when app/env run actor purpose/role route / policy tokens cost status`);
|
|
|
674
675
|
].join(" "));
|
|
675
676
|
}
|
|
676
677
|
}
|
|
677
|
-
function numeric(
|
|
678
|
-
return typeof
|
|
678
|
+
function numeric(value2) {
|
|
679
|
+
return typeof value2 === "number" && Number.isFinite(value2) ? value2 : 0;
|
|
679
680
|
}
|
|
680
|
-
function formatMicrousd(
|
|
681
|
-
return typeof
|
|
681
|
+
function formatMicrousd(value2) {
|
|
682
|
+
return typeof value2 === "number" && Number.isFinite(value2) ? `$${(value2 / 1e6).toFixed(6)}` : "unpriced";
|
|
682
683
|
}
|
|
683
|
-
function timestamp2(
|
|
684
|
-
if (typeof
|
|
685
|
-
const date = new Date(
|
|
684
|
+
function timestamp2(value2) {
|
|
685
|
+
if (typeof value2 !== "number" || !Number.isFinite(value2)) return String(value2 ?? "");
|
|
686
|
+
const date = new Date(value2);
|
|
686
687
|
return Number.isFinite(date.valueOf()) ? date.toISOString() : "";
|
|
687
688
|
}
|
|
688
689
|
async function responseBody2(res) {
|
|
@@ -699,8 +700,8 @@ function apiError2(action, status, body) {
|
|
|
699
700
|
const message2 = error && typeof error.message === "string" ? error.message : isRecord2(body) && typeof body.message === "string" ? body.message : "request failed";
|
|
700
701
|
return `${action} failed (${status}): ${message2}`;
|
|
701
702
|
}
|
|
702
|
-
function isRecord2(
|
|
703
|
-
return Boolean(
|
|
703
|
+
function isRecord2(value2) {
|
|
704
|
+
return Boolean(value2) && typeof value2 === "object" && !Array.isArray(value2);
|
|
704
705
|
}
|
|
705
706
|
|
|
706
707
|
// src/admin-ai.ts
|
|
@@ -745,11 +746,11 @@ async function adminAi(options) {
|
|
|
745
746
|
}
|
|
746
747
|
if (options.action === "credential-set") {
|
|
747
748
|
const provider = requireProvider(options.credentialProvider);
|
|
748
|
-
const
|
|
749
|
+
const value2 = await secretInputValue(options);
|
|
749
750
|
const res2 = await doFetch(`${platform}/registry/platform/ai-credentials/${encodeURIComponent(provider)}`, {
|
|
750
751
|
method: "PUT",
|
|
751
752
|
headers,
|
|
752
|
-
body: JSON.stringify({ value })
|
|
753
|
+
body: JSON.stringify({ value: value2 })
|
|
753
754
|
});
|
|
754
755
|
const body2 = await responseBody3(res2);
|
|
755
756
|
if (!res2.ok) throw new Error(apiError3(`store ${provider} platform credential`, res2.status, body2));
|
|
@@ -849,11 +850,11 @@ async function adminAi(options) {
|
|
|
849
850
|
const policy = isRecord3(response2) && isRecord3(response2.policy) ? response2.policy : isRecord3(response2) ? response2 : {};
|
|
850
851
|
out.log(options.json ? JSON.stringify({ policy }, null, 2) : `updated ${purpose}: ${String(policy.provider ?? "unchanged")}/${String(policy.model ?? "unchanged")}`);
|
|
851
852
|
}
|
|
852
|
-
function requireProvider(
|
|
853
|
-
if (
|
|
853
|
+
function requireProvider(value2) {
|
|
854
|
+
if (value2 !== "anthropic" && value2 !== "openai" && value2 !== "google") {
|
|
854
855
|
throw new Error("provider must be one of: anthropic, openai, google");
|
|
855
856
|
}
|
|
856
|
-
return
|
|
857
|
+
return value2;
|
|
857
858
|
}
|
|
858
859
|
function policyArray(body) {
|
|
859
860
|
if (isRecord3(body) && Array.isArray(body.policies)) return body.policies.filter(isRecord3);
|
|
@@ -864,7 +865,7 @@ function catalogModels(body) {
|
|
|
864
865
|
if (!isRecord3(body) || !isRecord3(body.catalog) || !Array.isArray(body.catalog.models)) {
|
|
865
866
|
throw new Error("platform returned an invalid System AI model catalog");
|
|
866
867
|
}
|
|
867
|
-
return body.catalog.models.filter((
|
|
868
|
+
return body.catalog.models.filter((value2) => isRecord3(value2) && typeof value2.id === "string" && typeof value2.provider === "string");
|
|
868
869
|
}
|
|
869
870
|
async function responseBody3(res) {
|
|
870
871
|
const text = await res.text();
|
|
@@ -880,8 +881,8 @@ function apiError3(action, status, body) {
|
|
|
880
881
|
const message2 = error && typeof error.message === "string" ? error.message : isRecord3(body) && typeof body.message === "string" ? body.message : "request failed";
|
|
881
882
|
return `${action} failed (${status}): ${message2}`;
|
|
882
883
|
}
|
|
883
|
-
function isRecord3(
|
|
884
|
-
return Boolean(
|
|
884
|
+
function isRecord3(value2) {
|
|
885
|
+
return Boolean(value2) && typeof value2 === "object" && !Array.isArray(value2);
|
|
885
886
|
}
|
|
886
887
|
|
|
887
888
|
// src/argv.ts
|
|
@@ -905,10 +906,10 @@ function parseArgv(argv) {
|
|
|
905
906
|
addOption(options, rawName, arg.slice(eq + 1));
|
|
906
907
|
continue;
|
|
907
908
|
}
|
|
908
|
-
const
|
|
909
|
-
if (
|
|
909
|
+
const value2 = argv[i + 1];
|
|
910
|
+
if (value2 !== void 0 && !value2.startsWith("--")) {
|
|
910
911
|
i++;
|
|
911
|
-
addOption(options, rawName,
|
|
912
|
+
addOption(options, rawName, value2);
|
|
912
913
|
} else {
|
|
913
914
|
addOption(options, rawName, true);
|
|
914
915
|
}
|
|
@@ -924,39 +925,39 @@ function assertArgs(parsed, allowedOptions2, maxPositionals) {
|
|
|
924
925
|
throw new Error(`unexpected argument "${parsed.positionals[maxPositionals]}"; run "odla-ai help"`);
|
|
925
926
|
}
|
|
926
927
|
}
|
|
927
|
-
function requiredString(
|
|
928
|
-
const result = stringOpt(
|
|
928
|
+
function requiredString(value2, name) {
|
|
929
|
+
const result = stringOpt(value2);
|
|
929
930
|
if (!result) throw new Error(`${name} is required`);
|
|
930
931
|
return result;
|
|
931
932
|
}
|
|
932
|
-
function stringOpt(
|
|
933
|
-
if (typeof
|
|
934
|
-
if (Array.isArray(
|
|
933
|
+
function stringOpt(value2) {
|
|
934
|
+
if (typeof value2 === "string") return value2;
|
|
935
|
+
if (Array.isArray(value2)) return value2[value2.length - 1];
|
|
935
936
|
return void 0;
|
|
936
937
|
}
|
|
937
|
-
function listOpt(
|
|
938
|
-
if (
|
|
939
|
-
const values = Array.isArray(
|
|
938
|
+
function listOpt(value2) {
|
|
939
|
+
if (value2 === void 0 || typeof value2 === "boolean") return void 0;
|
|
940
|
+
const values = Array.isArray(value2) ? value2 : [value2];
|
|
940
941
|
return values.flatMap((item) => item.split(",")).map((item) => item.trim()).filter(Boolean);
|
|
941
942
|
}
|
|
942
|
-
function boolOpt(
|
|
943
|
-
if (typeof
|
|
944
|
-
if (typeof
|
|
945
|
-
if (
|
|
943
|
+
function boolOpt(value2) {
|
|
944
|
+
if (typeof value2 === "boolean") return value2;
|
|
945
|
+
if (typeof value2 === "string" && (value2 === "true" || value2 === "false")) return value2 === "true";
|
|
946
|
+
if (value2 === void 0) return void 0;
|
|
946
947
|
throw new Error("boolean option must be true or false");
|
|
947
948
|
}
|
|
948
|
-
function numberOpt(
|
|
949
|
-
if (
|
|
950
|
-
const raw = stringOpt(
|
|
949
|
+
function numberOpt(value2, flag) {
|
|
950
|
+
if (value2 === void 0) return void 0;
|
|
951
|
+
const raw = stringOpt(value2);
|
|
951
952
|
const parsed = raw === void 0 ? Number.NaN : Number(raw);
|
|
952
953
|
if (!Number.isSafeInteger(parsed) || parsed < 1) throw new Error(`${flag} requires a positive integer`);
|
|
953
954
|
return parsed;
|
|
954
955
|
}
|
|
955
|
-
function addOption(options, name,
|
|
956
|
+
function addOption(options, name, value2) {
|
|
956
957
|
const current = options[name];
|
|
957
|
-
if (current === void 0) options[name] =
|
|
958
|
-
else if (Array.isArray(current)) current.push(String(
|
|
959
|
-
else options[name] = [String(current), String(
|
|
958
|
+
if (current === void 0) options[name] = value2;
|
|
959
|
+
else if (Array.isArray(current)) current.push(String(value2));
|
|
960
|
+
else options[name] = [String(current), String(value2)];
|
|
960
961
|
}
|
|
961
962
|
|
|
962
963
|
// src/operator-context.ts
|
|
@@ -1023,17 +1024,17 @@ function validateProbes(integration, at) {
|
|
|
1023
1024
|
}
|
|
1024
1025
|
}
|
|
1025
1026
|
}
|
|
1026
|
-
function isRecord4(
|
|
1027
|
-
return
|
|
1027
|
+
function isRecord4(value2) {
|
|
1028
|
+
return value2 !== null && typeof value2 === "object" && !Array.isArray(value2);
|
|
1028
1029
|
}
|
|
1029
|
-
function safeText(
|
|
1030
|
-
return typeof
|
|
1030
|
+
function safeText(value2, max) {
|
|
1031
|
+
return typeof value2 === "string" && value2.trim().length > 0 && value2.length <= max && !/[\u0000-\u001f\u007f]/.test(value2);
|
|
1031
1032
|
}
|
|
1032
|
-
function safeProbePath(
|
|
1033
|
-
return typeof
|
|
1033
|
+
function safeProbePath(value2) {
|
|
1034
|
+
return typeof value2 === "string" && /^\/[A-Za-z0-9._~!$&'()*+,;=:@%/-]*$/.test(value2);
|
|
1034
1035
|
}
|
|
1035
|
-
function validId(
|
|
1036
|
-
return typeof
|
|
1036
|
+
function validId(value2) {
|
|
1037
|
+
return typeof value2 === "string" && /^[a-z0-9][a-z0-9-]*$/.test(value2);
|
|
1037
1038
|
}
|
|
1038
1039
|
function unique(values) {
|
|
1039
1040
|
return [...new Set(values.filter(Boolean))];
|
|
@@ -1075,10 +1076,10 @@ async function loadProjectConfig(configPath = "odla.config.mjs") {
|
|
|
1075
1076
|
local
|
|
1076
1077
|
};
|
|
1077
1078
|
}
|
|
1078
|
-
async function resolveDataExport(cfg,
|
|
1079
|
-
if (
|
|
1080
|
-
if (typeof
|
|
1081
|
-
const target = (0, import_node_path4.isAbsolute)(
|
|
1079
|
+
async function resolveDataExport(cfg, value2, names) {
|
|
1080
|
+
if (value2 === void 0 || value2 === null || value2 === false) return void 0;
|
|
1081
|
+
if (typeof value2 !== "string") return value2;
|
|
1082
|
+
const target = (0, import_node_path4.isAbsolute)(value2) ? value2 : (0, import_node_path4.resolve)(cfg.rootDir, value2);
|
|
1082
1083
|
if (target.endsWith(".json")) {
|
|
1083
1084
|
return JSON.parse((0, import_node_fs4.readFileSync)(target, "utf8"));
|
|
1084
1085
|
}
|
|
@@ -1087,7 +1088,7 @@ async function resolveDataExport(cfg, value, names) {
|
|
|
1087
1088
|
if (mod[name] !== void 0) return mod[name];
|
|
1088
1089
|
}
|
|
1089
1090
|
if (mod.default !== void 0) return mod.default;
|
|
1090
|
-
throw new Error(`${
|
|
1091
|
+
throw new Error(`${value2} did not export ${names.join(", ")} or default`);
|
|
1091
1092
|
}
|
|
1092
1093
|
function buildPlan(cfg) {
|
|
1093
1094
|
const integrationSchema = cfg.integrations?.some((integration) => integration.schema) ?? false;
|
|
@@ -1121,9 +1122,9 @@ function calendarServiceConfig(cfg, env) {
|
|
|
1121
1122
|
};
|
|
1122
1123
|
}
|
|
1123
1124
|
function calendarBookingPageUrl(cfg, env) {
|
|
1124
|
-
const
|
|
1125
|
-
if (
|
|
1126
|
-
return new URL(
|
|
1125
|
+
const value2 = cfg.calendar?.google.bookingPageUrl?.[env];
|
|
1126
|
+
if (value2 === void 0 || value2 === null) return value2;
|
|
1127
|
+
return new URL(value2).toString();
|
|
1127
1128
|
}
|
|
1128
1129
|
function rulesFromSchema(schema) {
|
|
1129
1130
|
const entities = serializedEntities(schema);
|
|
@@ -1137,10 +1138,10 @@ function serializedEntities(schema) {
|
|
|
1137
1138
|
if (!entities || typeof entities !== "object" || Array.isArray(entities)) return [];
|
|
1138
1139
|
return Object.keys(entities);
|
|
1139
1140
|
}
|
|
1140
|
-
function envValue(
|
|
1141
|
-
if (!
|
|
1142
|
-
if (
|
|
1143
|
-
return
|
|
1141
|
+
function envValue(value2) {
|
|
1142
|
+
if (!value2) return void 0;
|
|
1143
|
+
if (value2.startsWith("$")) return process.env[value2.slice(1)];
|
|
1144
|
+
return value2;
|
|
1144
1145
|
}
|
|
1145
1146
|
function validateRawConfig(raw, path) {
|
|
1146
1147
|
if (!raw || typeof raw !== "object") throw new Error(`${path} must export an object`);
|
|
@@ -1196,8 +1197,8 @@ function validateCalendarConfig(cfg, envs, services, path) {
|
|
|
1196
1197
|
if (!isRecord5(google.bookingCalendar)) throw new Error(`${path}: calendar.google.bookingCalendar must map env names to one calendar id`);
|
|
1197
1198
|
const unknownBookingEnv = Object.keys(google.bookingCalendar).find((env) => !envs.includes(env));
|
|
1198
1199
|
if (unknownBookingEnv) throw new Error(`${path}: calendar.google.bookingCalendar.${unknownBookingEnv} is not in config envs`);
|
|
1199
|
-
for (const [env,
|
|
1200
|
-
if (!safeText2(
|
|
1200
|
+
for (const [env, value2] of Object.entries(google.bookingCalendar)) {
|
|
1201
|
+
if (!safeText2(value2, 1024)) {
|
|
1201
1202
|
throw new Error(`${path}: calendar.google.bookingCalendar.${env} must be a calendar id`);
|
|
1202
1203
|
}
|
|
1203
1204
|
}
|
|
@@ -1206,8 +1207,8 @@ function validateCalendarConfig(cfg, envs, services, path) {
|
|
|
1206
1207
|
if (!isRecord5(google.bookingPageUrl)) throw new Error(`${path}: calendar.google.bookingPageUrl must map env names to HTTPS URLs or null`);
|
|
1207
1208
|
const unknownBookingEnv = Object.keys(google.bookingPageUrl).find((env) => !envs.includes(env));
|
|
1208
1209
|
if (unknownBookingEnv) throw new Error(`${path}: calendar.google.bookingPageUrl.${unknownBookingEnv} is not in config envs`);
|
|
1209
|
-
for (const [env,
|
|
1210
|
-
if (
|
|
1210
|
+
for (const [env, value2] of Object.entries(google.bookingPageUrl)) {
|
|
1211
|
+
if (value2 !== null && !safeHttpsUrl(value2)) {
|
|
1211
1212
|
throw new Error(`${path}: calendar.google.bookingPageUrl.${env} must be an HTTPS URL without credentials or fragment`);
|
|
1212
1213
|
}
|
|
1213
1214
|
}
|
|
@@ -1226,37 +1227,37 @@ function validateServices(services, path) {
|
|
|
1226
1227
|
}
|
|
1227
1228
|
}
|
|
1228
1229
|
}
|
|
1229
|
-
function assertOnly(
|
|
1230
|
-
const extra = Object.keys(
|
|
1230
|
+
function assertOnly(value2, allowed, label) {
|
|
1231
|
+
const extra = Object.keys(value2).find((key) => !allowed.includes(key));
|
|
1231
1232
|
if (extra) throw new Error(`${label}.${extra} is not supported`);
|
|
1232
1233
|
}
|
|
1233
|
-
function isRecord5(
|
|
1234
|
-
return
|
|
1234
|
+
function isRecord5(value2) {
|
|
1235
|
+
return value2 !== null && typeof value2 === "object" && !Array.isArray(value2);
|
|
1235
1236
|
}
|
|
1236
|
-
function safeText2(
|
|
1237
|
-
return typeof
|
|
1237
|
+
function safeText2(value2, max) {
|
|
1238
|
+
return typeof value2 === "string" && value2.trim().length > 0 && value2.length <= max && !/[\u0000-\u001f\u007f]/.test(value2);
|
|
1238
1239
|
}
|
|
1239
|
-
function safeHttpsUrl(
|
|
1240
|
-
if (typeof
|
|
1240
|
+
function safeHttpsUrl(value2) {
|
|
1241
|
+
if (typeof value2 !== "string" || value2.length > 2048) return false;
|
|
1241
1242
|
try {
|
|
1242
|
-
const url = new URL(
|
|
1243
|
+
const url = new URL(value2);
|
|
1243
1244
|
return url.protocol === "https:" && !url.username && !url.password && !url.hash;
|
|
1244
1245
|
} catch {
|
|
1245
1246
|
return false;
|
|
1246
1247
|
}
|
|
1247
1248
|
}
|
|
1248
|
-
function validId2(
|
|
1249
|
-
return typeof
|
|
1249
|
+
function validId2(value2) {
|
|
1250
|
+
return typeof value2 === "string" && /^[a-z0-9][a-z0-9-]*$/.test(value2);
|
|
1250
1251
|
}
|
|
1251
1252
|
async function loadConfigModule(path) {
|
|
1252
1253
|
if (path.endsWith(".json")) return JSON.parse((0, import_node_fs4.readFileSync)(path, "utf8"));
|
|
1253
1254
|
const mod = await import(`${(0, import_node_url.pathToFileURL)(path).href}?t=${Date.now()}`);
|
|
1254
|
-
const
|
|
1255
|
-
if (typeof
|
|
1256
|
-
return
|
|
1255
|
+
const value2 = mod.default ?? mod.config;
|
|
1256
|
+
if (typeof value2 === "function") return await value2();
|
|
1257
|
+
return value2;
|
|
1257
1258
|
}
|
|
1258
|
-
function trimSlash(
|
|
1259
|
-
return
|
|
1259
|
+
function trimSlash(value2) {
|
|
1260
|
+
return value2.replace(/\/+$/, "");
|
|
1260
1261
|
}
|
|
1261
1262
|
function unique2(values) {
|
|
1262
1263
|
return [...new Set(values.filter(Boolean))];
|
|
@@ -1282,8 +1283,8 @@ function resolveOperatorProfile(parsed) {
|
|
|
1282
1283
|
}
|
|
1283
1284
|
assertOperatorName(name, "context");
|
|
1284
1285
|
const profiles = readOperatorProfiles(file);
|
|
1285
|
-
const
|
|
1286
|
-
if (!
|
|
1286
|
+
const value2 = Object.hasOwn(profiles, name) ? profiles[name] : void 0;
|
|
1287
|
+
if (!value2) {
|
|
1287
1288
|
throw new Error(
|
|
1288
1289
|
`operator context "${name}" not found in ${file}; run "odla-ai context list" or save it first`
|
|
1289
1290
|
);
|
|
@@ -1292,7 +1293,7 @@ function resolveOperatorProfile(parsed) {
|
|
|
1292
1293
|
name,
|
|
1293
1294
|
source: fromFlag ? "flag" : "environment",
|
|
1294
1295
|
file,
|
|
1295
|
-
value
|
|
1296
|
+
value: value2
|
|
1296
1297
|
};
|
|
1297
1298
|
}
|
|
1298
1299
|
function listOperatorProfiles(file = operatorProfileFile()) {
|
|
@@ -1320,8 +1321,8 @@ function operatorCredentialFiles(selection) {
|
|
|
1320
1321
|
scoped: (0, import_node_path5.join)(base, "admin-token.local.json")
|
|
1321
1322
|
};
|
|
1322
1323
|
}
|
|
1323
|
-
function assertOperatorName(
|
|
1324
|
-
if (!/^[a-z0-9][a-z0-9-]*$/.test(
|
|
1324
|
+
function assertOperatorName(value2, label) {
|
|
1325
|
+
if (!/^[a-z0-9][a-z0-9-]*$/.test(value2)) {
|
|
1325
1326
|
throw new Error(
|
|
1326
1327
|
`${label} must contain lowercase letters, numbers, and hyphens`
|
|
1327
1328
|
);
|
|
@@ -1347,22 +1348,22 @@ function readOperatorProfiles(file) {
|
|
|
1347
1348
|
);
|
|
1348
1349
|
}
|
|
1349
1350
|
const profiles = emptyProfiles();
|
|
1350
|
-
for (const [name,
|
|
1351
|
+
for (const [name, value2] of Object.entries(
|
|
1351
1352
|
raw.profiles
|
|
1352
1353
|
)) {
|
|
1353
1354
|
assertOperatorName(name, "context");
|
|
1354
|
-
profiles[name] = validateProfile(
|
|
1355
|
+
profiles[name] = validateProfile(value2, `operator context "${name}"`);
|
|
1355
1356
|
}
|
|
1356
1357
|
return profiles;
|
|
1357
1358
|
}
|
|
1358
1359
|
function emptyProfiles() {
|
|
1359
1360
|
return /* @__PURE__ */ Object.create(null);
|
|
1360
1361
|
}
|
|
1361
|
-
function validateProfile(
|
|
1362
|
-
if (!
|
|
1362
|
+
function validateProfile(value2, label) {
|
|
1363
|
+
if (!value2 || typeof value2 !== "object" || Array.isArray(value2)) {
|
|
1363
1364
|
throw new Error(`${label} has an invalid shape`);
|
|
1364
1365
|
}
|
|
1365
|
-
const unknown = Object.keys(
|
|
1366
|
+
const unknown = Object.keys(value2).filter(
|
|
1366
1367
|
(key) => !["platform", "app", "environment"].includes(key)
|
|
1367
1368
|
);
|
|
1368
1369
|
if (unknown.length > 0) {
|
|
@@ -1370,7 +1371,7 @@ function validateProfile(value, label) {
|
|
|
1370
1371
|
`${label} contains unsupported field(s): ${unknown.sort().join(", ")}; contexts store scope metadata only, never credentials`
|
|
1371
1372
|
);
|
|
1372
1373
|
}
|
|
1373
|
-
const candidate =
|
|
1374
|
+
const candidate = value2;
|
|
1374
1375
|
if (typeof candidate.platform !== "string") {
|
|
1375
1376
|
throw new Error(`${label} needs an absolute platform URL`);
|
|
1376
1377
|
}
|
|
@@ -1385,8 +1386,8 @@ function validateProfile(value, label) {
|
|
|
1385
1386
|
...environment2 ? { environment: environment2 } : {}
|
|
1386
1387
|
};
|
|
1387
1388
|
}
|
|
1388
|
-
function clean(
|
|
1389
|
-
const normalized =
|
|
1389
|
+
function clean(value2) {
|
|
1390
|
+
const normalized = value2?.trim();
|
|
1390
1391
|
return normalized || void 0;
|
|
1391
1392
|
}
|
|
1392
1393
|
|
|
@@ -1479,8 +1480,8 @@ async function resolveOperatorContext(parsed, options = {}) {
|
|
|
1479
1480
|
}
|
|
1480
1481
|
};
|
|
1481
1482
|
}
|
|
1482
|
-
function clean2(
|
|
1483
|
-
const normalized =
|
|
1483
|
+
function clean2(value2) {
|
|
1484
|
+
const normalized = value2?.trim();
|
|
1484
1485
|
return normalized || void 0;
|
|
1485
1486
|
}
|
|
1486
1487
|
|
|
@@ -2191,44 +2192,44 @@ var REPLACEMENTS = [
|
|
|
2191
2192
|
[/\b(ghp|gho|github_pat)_[A-Za-z0-9_]+/g, "$1_[redacted]"],
|
|
2192
2193
|
[/\bAKIA[A-Z0-9]{12,}/g, "AKIA[redacted]"]
|
|
2193
2194
|
];
|
|
2194
|
-
function redactSecrets(
|
|
2195
|
-
let result =
|
|
2195
|
+
function redactSecrets(value2) {
|
|
2196
|
+
let result = value2;
|
|
2196
2197
|
for (const [pattern, replacement] of REPLACEMENTS) result = result.replace(pattern, replacement);
|
|
2197
2198
|
return result;
|
|
2198
2199
|
}
|
|
2199
2200
|
function redactingOutput(output) {
|
|
2200
|
-
const redactArgs = (args) => args.map((
|
|
2201
|
+
const redactArgs = (args) => args.map((value2) => redactOutputValue(value2, /* @__PURE__ */ new WeakMap()));
|
|
2201
2202
|
return {
|
|
2202
2203
|
log: (...args) => output.log(...redactArgs(args)),
|
|
2203
2204
|
error: (...args) => output.error(...redactArgs(args))
|
|
2204
2205
|
};
|
|
2205
2206
|
}
|
|
2206
|
-
function redactOutputValue(
|
|
2207
|
-
if (typeof
|
|
2208
|
-
if (
|
|
2209
|
-
const redacted = new Error(redactSecrets(
|
|
2210
|
-
redacted.name =
|
|
2211
|
-
if (
|
|
2207
|
+
function redactOutputValue(value2, seen) {
|
|
2208
|
+
if (typeof value2 === "string") return redactSecrets(value2);
|
|
2209
|
+
if (value2 instanceof Error) {
|
|
2210
|
+
const redacted = new Error(redactSecrets(value2.message));
|
|
2211
|
+
redacted.name = value2.name;
|
|
2212
|
+
if (value2.stack) redacted.stack = redactSecrets(value2.stack);
|
|
2212
2213
|
return redacted;
|
|
2213
2214
|
}
|
|
2214
|
-
if (!
|
|
2215
|
-
const prior = seen.get(
|
|
2215
|
+
if (!value2 || typeof value2 !== "object") return value2;
|
|
2216
|
+
const prior = seen.get(value2);
|
|
2216
2217
|
if (prior) return prior;
|
|
2217
|
-
if (Array.isArray(
|
|
2218
|
+
if (Array.isArray(value2)) {
|
|
2218
2219
|
const next2 = [];
|
|
2219
|
-
seen.set(
|
|
2220
|
-
for (const item of
|
|
2220
|
+
seen.set(value2, next2);
|
|
2221
|
+
for (const item of value2) next2.push(redactOutputValue(item, seen));
|
|
2221
2222
|
return next2;
|
|
2222
2223
|
}
|
|
2223
|
-
const prototype = Object.getPrototypeOf(
|
|
2224
|
-
if (prototype !== Object.prototype && prototype !== null) return
|
|
2224
|
+
const prototype = Object.getPrototypeOf(value2);
|
|
2225
|
+
if (prototype !== Object.prototype && prototype !== null) return value2;
|
|
2225
2226
|
const next = {};
|
|
2226
|
-
seen.set(
|
|
2227
|
-
for (const [key, item] of Object.entries(
|
|
2227
|
+
seen.set(value2, next);
|
|
2228
|
+
for (const [key, item] of Object.entries(value2)) next[key] = redactOutputValue(item, seen);
|
|
2228
2229
|
return next;
|
|
2229
2230
|
}
|
|
2230
|
-
function looksSecret(
|
|
2231
|
-
return redactSecrets(
|
|
2231
|
+
function looksSecret(value2) {
|
|
2232
|
+
return redactSecrets(value2) !== value2 || value2.includes("-----BEGIN");
|
|
2232
2233
|
}
|
|
2233
2234
|
|
|
2234
2235
|
// src/calendar-http.ts
|
|
@@ -2245,9 +2246,9 @@ async function readCalendarStatus(ctx) {
|
|
|
2245
2246
|
}
|
|
2246
2247
|
async function discoverGoogleCalendars(ctx) {
|
|
2247
2248
|
const raw = await calendarJson(ctx, "/calendars", {});
|
|
2248
|
-
const
|
|
2249
|
-
if (!
|
|
2250
|
-
return
|
|
2249
|
+
const value2 = record(raw);
|
|
2250
|
+
if (!value2 || !Array.isArray(value2.calendars)) throw new Error("calendar discovery returned an invalid response");
|
|
2251
|
+
return value2.calendars.map((item, index) => {
|
|
2251
2252
|
const calendar = record(item);
|
|
2252
2253
|
const id = textField(calendar?.id, 1024);
|
|
2253
2254
|
if (!calendar || !id) throw new Error(`calendar discovery returned an invalid calendar at index ${index}`);
|
|
@@ -2269,10 +2270,10 @@ async function applyCalendarSettings(ctx, bookingPageUrl) {
|
|
|
2269
2270
|
}
|
|
2270
2271
|
async function startCalendarConnection(ctx) {
|
|
2271
2272
|
const raw = await calendarJson(ctx, "/google/connect", { method: "POST", body: "{}" });
|
|
2272
|
-
const
|
|
2273
|
-
const attemptId = textField(
|
|
2274
|
-
const consentUrl = textField(
|
|
2275
|
-
const expiresAt = timestamp3(
|
|
2273
|
+
const value2 = wrapped(raw, "attempt");
|
|
2274
|
+
const attemptId = textField(value2.attemptId, 180);
|
|
2275
|
+
const consentUrl = textField(value2.consentUrl, 4096);
|
|
2276
|
+
const expiresAt = timestamp3(value2.expiresAt);
|
|
2276
2277
|
if (!attemptId || !consentUrl || expiresAt === void 0) throw new Error("calendar connect returned an invalid attempt");
|
|
2277
2278
|
return { attemptId, consentUrl, expiresAt };
|
|
2278
2279
|
}
|
|
@@ -2290,42 +2291,42 @@ async function requestCalendarDisconnect(ctx) {
|
|
|
2290
2291
|
}
|
|
2291
2292
|
function parseCalendarStatus(raw, env) {
|
|
2292
2293
|
const outer = wrapped(raw, "calendar");
|
|
2293
|
-
const
|
|
2294
|
-
const connection = record(
|
|
2295
|
-
const config = record(
|
|
2294
|
+
const value2 = record(outer.attempt) ?? record(outer.status) ?? outer;
|
|
2295
|
+
const connection = record(value2.connection) ?? {};
|
|
2296
|
+
const config = record(value2.config) ?? record(outer.config) ?? {};
|
|
2296
2297
|
const googleConfig = record(config.google) ?? config;
|
|
2297
|
-
const stateValue = calendarState(
|
|
2298
|
+
const stateValue = calendarState(value2.status ?? value2.state ?? connection.status ?? connection.state);
|
|
2298
2299
|
if (!stateValue) {
|
|
2299
2300
|
throw new Error("calendar status returned an invalid connection state");
|
|
2300
2301
|
}
|
|
2301
|
-
const providerValue =
|
|
2302
|
+
const providerValue = value2.provider ?? connection.provider ?? config.provider ?? (config.google ? "google" : void 0);
|
|
2302
2303
|
if (providerValue !== void 0 && providerValue !== null && providerValue !== "google") {
|
|
2303
2304
|
throw new Error("calendar status returned an unsupported provider");
|
|
2304
2305
|
}
|
|
2305
|
-
const accessValue =
|
|
2306
|
+
const accessValue = value2.access ?? connection.access ?? config.access ?? googleConfig.access;
|
|
2306
2307
|
if (accessValue !== void 0 && accessValue !== "book" && accessValue !== "read") {
|
|
2307
2308
|
throw new Error("calendar status returned unsupported access");
|
|
2308
2309
|
}
|
|
2309
|
-
const errorValue = record(
|
|
2310
|
-
const errorCode = textField(
|
|
2311
|
-
const bookingPageValue = Object.hasOwn(
|
|
2312
|
-
const connected = typeof (
|
|
2313
|
-
const bookingCalendarId = textField(
|
|
2310
|
+
const errorValue = record(value2.error) ?? record(connection.error);
|
|
2311
|
+
const errorCode = textField(value2.lastErrorCode, 128);
|
|
2312
|
+
const bookingPageValue = Object.hasOwn(value2, "bookingPageUrl") ? value2.bookingPageUrl : Object.hasOwn(config, "bookingPageUrl") ? config.bookingPageUrl : googleConfig.bookingPageUrl;
|
|
2313
|
+
const connected = typeof (value2.connected ?? connection.connected) === "boolean" ? Boolean(value2.connected ?? connection.connected) : ["healthy", "degraded"].includes(stateValue);
|
|
2314
|
+
const bookingCalendarId = textField(value2.bookingCalendarId ?? config.bookingCalendarId, 1024);
|
|
2314
2315
|
return {
|
|
2315
2316
|
env,
|
|
2316
|
-
enabled: typeof
|
|
2317
|
+
enabled: typeof value2.enabled === "boolean" ? value2.enabled : true,
|
|
2317
2318
|
connected,
|
|
2318
|
-
writable: typeof
|
|
2319
|
+
writable: typeof value2.writable === "boolean" ? value2.writable : stateValue === "healthy",
|
|
2319
2320
|
provider: providerValue === "google" ? "google" : null,
|
|
2320
2321
|
status: stateValue,
|
|
2321
2322
|
...accessValue !== void 0 ? { access: "book" } : {},
|
|
2322
2323
|
...bookingCalendarId ? { bookingCalendarId } : {},
|
|
2323
2324
|
calendars: calendarIds(
|
|
2324
|
-
|
|
2325
|
+
value2.availabilityCalendars ?? config.availabilityCalendars ?? value2.configuredCalendars ?? value2.calendars ?? config.calendars ?? googleConfig.calendars
|
|
2325
2326
|
),
|
|
2326
2327
|
...optionalNullableUrl("bookingPageUrl", bookingPageValue),
|
|
2327
|
-
grantedScopes: stringList(
|
|
2328
|
-
...optionalText("attemptId",
|
|
2328
|
+
grantedScopes: stringList(value2.grantedScopes ?? connection.grantedScopes ?? connection.scopes),
|
|
2329
|
+
...optionalText("attemptId", value2.attemptId ?? connection.attemptId, 180),
|
|
2329
2330
|
...errorValue || errorCode ? { error: {
|
|
2330
2331
|
...textField(errorValue?.code, 128) ? { code: textField(errorValue?.code, 128) } : {},
|
|
2331
2332
|
...textField(errorValue?.message, 500) ? { message: textField(errorValue?.message, 500) } : {},
|
|
@@ -2333,9 +2334,9 @@ function parseCalendarStatus(raw, env) {
|
|
|
2333
2334
|
} } : {}
|
|
2334
2335
|
};
|
|
2335
2336
|
}
|
|
2336
|
-
function calendarState(
|
|
2337
|
-
if (typeof
|
|
2338
|
-
if (CALENDAR_STATES.includes(
|
|
2337
|
+
function calendarState(value2) {
|
|
2338
|
+
if (typeof value2 !== "string") return null;
|
|
2339
|
+
if (CALENDAR_STATES.includes(value2)) return value2;
|
|
2339
2340
|
const legacy = {
|
|
2340
2341
|
disabled: "not_connected",
|
|
2341
2342
|
disconnected: "disconnected",
|
|
@@ -2346,7 +2347,7 @@ function calendarState(value) {
|
|
|
2346
2347
|
ready: "healthy",
|
|
2347
2348
|
error: "failed"
|
|
2348
2349
|
};
|
|
2349
|
-
return legacy[
|
|
2350
|
+
return legacy[value2] ?? null;
|
|
2350
2351
|
}
|
|
2351
2352
|
async function calendarJson(ctx, suffix, init) {
|
|
2352
2353
|
const platform = platformAudience(ctx.platform);
|
|
@@ -2380,50 +2381,50 @@ function wrapped(raw, key) {
|
|
|
2380
2381
|
if (!outer) throw new Error("calendar returned an invalid response");
|
|
2381
2382
|
return record(outer[key]) ?? outer;
|
|
2382
2383
|
}
|
|
2383
|
-
function record(
|
|
2384
|
-
return
|
|
2384
|
+
function record(value2) {
|
|
2385
|
+
return value2 !== null && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
|
|
2385
2386
|
}
|
|
2386
|
-
function textField(
|
|
2387
|
-
return typeof
|
|
2387
|
+
function textField(value2, max) {
|
|
2388
|
+
return typeof value2 === "string" && value2.length > 0 && value2.length <= max && !/[\u0000-\u001f\u007f]/.test(value2) ? value2 : void 0;
|
|
2388
2389
|
}
|
|
2389
|
-
function stringList(
|
|
2390
|
-
return Array.isArray(
|
|
2390
|
+
function stringList(value2) {
|
|
2391
|
+
return Array.isArray(value2) ? [...new Set(value2.filter((item) => !!textField(item, 4096)))] : [];
|
|
2391
2392
|
}
|
|
2392
|
-
function calendarIds(
|
|
2393
|
-
if (!Array.isArray(
|
|
2394
|
-
return [...new Set(
|
|
2393
|
+
function calendarIds(value2) {
|
|
2394
|
+
if (!Array.isArray(value2)) return [];
|
|
2395
|
+
return [...new Set(value2.flatMap((item) => {
|
|
2395
2396
|
if (typeof item === "string") return textField(item, 4096) ? [item] : [];
|
|
2396
2397
|
const calendar = record(item);
|
|
2397
2398
|
const id = textField(calendar?.id, 4096);
|
|
2398
2399
|
return id && calendar?.selected !== false ? [id] : [];
|
|
2399
2400
|
}))];
|
|
2400
2401
|
}
|
|
2401
|
-
function timestamp3(
|
|
2402
|
-
if (typeof
|
|
2403
|
-
if (typeof
|
|
2404
|
-
const parsed = Date.parse(
|
|
2402
|
+
function timestamp3(value2) {
|
|
2403
|
+
if (typeof value2 === "number" && Number.isFinite(value2) && value2 >= 0) return value2;
|
|
2404
|
+
if (typeof value2 === "string") {
|
|
2405
|
+
const parsed = Date.parse(value2);
|
|
2405
2406
|
if (Number.isFinite(parsed)) return parsed;
|
|
2406
2407
|
}
|
|
2407
2408
|
return void 0;
|
|
2408
2409
|
}
|
|
2409
|
-
function optionalText(key,
|
|
2410
|
-
const parsed = textField(
|
|
2410
|
+
function optionalText(key, value2, max) {
|
|
2411
|
+
const parsed = textField(value2, max);
|
|
2411
2412
|
return parsed ? { [key]: parsed } : {};
|
|
2412
2413
|
}
|
|
2413
|
-
function optionalNullableUrl(key,
|
|
2414
|
-
if (
|
|
2415
|
-
const parsed = textField(
|
|
2414
|
+
function optionalNullableUrl(key, value2) {
|
|
2415
|
+
if (value2 === null) return { [key]: null };
|
|
2416
|
+
const parsed = textField(value2, 4096);
|
|
2416
2417
|
return parsed ? { [key]: parsed } : {};
|
|
2417
2418
|
}
|
|
2418
|
-
function identifier(
|
|
2419
|
-
if (typeof
|
|
2420
|
-
return
|
|
2419
|
+
function identifier(value2, name) {
|
|
2420
|
+
if (typeof value2 !== "string" || !/^[A-Za-z0-9][A-Za-z0-9._:-]{0,179}$/.test(value2)) throw new Error(`${name} is invalid`);
|
|
2421
|
+
return value2;
|
|
2421
2422
|
}
|
|
2422
|
-
function credential(
|
|
2423
|
-
if (typeof
|
|
2423
|
+
function credential(value2) {
|
|
2424
|
+
if (typeof value2 !== "string" || value2.length < 8 || value2.length > 8192 || /\s|[\u0000-\u001f\u007f]/.test(value2)) {
|
|
2424
2425
|
throw new Error("calendar requires an odla developer token");
|
|
2425
2426
|
}
|
|
2426
|
-
return
|
|
2427
|
+
return value2;
|
|
2427
2428
|
}
|
|
2428
2429
|
|
|
2429
2430
|
// src/calendar-poll.ts
|
|
@@ -2584,11 +2585,11 @@ async function connectWithContext(ctx, options) {
|
|
|
2584
2585
|
}
|
|
2585
2586
|
throw new Error('Google Calendar consent timed out; run "odla-ai calendar status" and retry connect');
|
|
2586
2587
|
}
|
|
2587
|
-
function trustedCalendarConsentUrl(platform,
|
|
2588
|
+
function trustedCalendarConsentUrl(platform, value2) {
|
|
2588
2589
|
const origin = platformAudience(platform);
|
|
2589
2590
|
let url;
|
|
2590
2591
|
try {
|
|
2591
|
-
url =
|
|
2592
|
+
url = value2.startsWith("/") ? new URL(value2, origin) : new URL(value2);
|
|
2592
2593
|
} catch {
|
|
2593
2594
|
throw new Error("odla.ai returned an invalid calendar consent URL");
|
|
2594
2595
|
}
|
|
@@ -2599,9 +2600,9 @@ function trustedCalendarConsentUrl(platform, value) {
|
|
|
2599
2600
|
}
|
|
2600
2601
|
return url.toString();
|
|
2601
2602
|
}
|
|
2602
|
-
function pollTimeout(
|
|
2603
|
-
if (!Number.isSafeInteger(
|
|
2604
|
-
return
|
|
2603
|
+
function pollTimeout(value2 = 10 * 6e4) {
|
|
2604
|
+
if (!Number.isSafeInteger(value2) || value2 < 1e3 || value2 > 60 * 6e4) throw new Error("calendar poll timeout must be 1000-3600000ms");
|
|
2605
|
+
return value2;
|
|
2605
2606
|
}
|
|
2606
2607
|
function productionConsent(env, yes, action) {
|
|
2607
2608
|
if ((env === "prod" || env === "production") && !yes) throw new Error(`refusing to ${action} for "${env}" without --yes`);
|
|
@@ -2633,6 +2634,7 @@ var CAPABILITIES = {
|
|
|
2633
2634
|
"validate integration contracts offline and smoke-test a provisioned db environment plus anonymous capability routes",
|
|
2634
2635
|
"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",
|
|
2635
2636
|
"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",
|
|
2637
|
+
"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",
|
|
2636
2638
|
"inspect durable agent wakeups as a versioned JSON envelope and explicitly requeue one dead-lettered job with a scoped environment credential",
|
|
2637
2639
|
"run app-attributed hosted security discovery and independent validation without provider keys",
|
|
2638
2640
|
"connect/revoke source-read-only GitHub sources and drive commit-pinned hosted security jobs without PATs or provider keys",
|
|
@@ -2816,8 +2818,8 @@ function wranglerWarnings(rootDir) {
|
|
|
2816
2818
|
}
|
|
2817
2819
|
const vars = block.vars;
|
|
2818
2820
|
if (vars && typeof vars === "object") {
|
|
2819
|
-
for (const [name,
|
|
2820
|
-
if (name === "ODLA_API_KEY" || name === "ODLA_O11Y_TOKEN" || typeof
|
|
2821
|
+
for (const [name, value2] of Object.entries(vars)) {
|
|
2822
|
+
if (name === "ODLA_API_KEY" || name === "ODLA_O11Y_TOKEN" || typeof value2 === "string" && looksSecret(value2)) {
|
|
2821
2823
|
warnings.push(`wrangler ${label}vars.${name} looks like a secret \u2014 use "odla-ai secrets push" / wrangler secret put, never vars`);
|
|
2822
2824
|
}
|
|
2823
2825
|
}
|
|
@@ -2985,27 +2987,27 @@ function isUniqueAttr(schema, ns, attr) {
|
|
|
2985
2987
|
const definition = entity.attrs[attr];
|
|
2986
2988
|
return isRecord6(definition) && definition.unique === true;
|
|
2987
2989
|
}
|
|
2988
|
-
function normalizeSchema(
|
|
2989
|
-
if (
|
|
2990
|
-
if (!isRecord6(
|
|
2990
|
+
function normalizeSchema(value2) {
|
|
2991
|
+
if (value2 === void 0 || value2 === null) return { entities: {}, links: {} };
|
|
2992
|
+
if (!isRecord6(value2) || !isRecord6(value2.entities)) {
|
|
2991
2993
|
throw new Error("db schema must be a serialized schema object with an entities map");
|
|
2992
2994
|
}
|
|
2993
|
-
if (
|
|
2995
|
+
if (value2.links !== void 0 && !isRecord6(value2.links)) throw new Error("db schema links must be an object");
|
|
2994
2996
|
return {
|
|
2995
|
-
entities: { ...
|
|
2996
|
-
links: { ...
|
|
2997
|
+
entities: { ...value2.entities },
|
|
2998
|
+
links: { ...value2.links ?? {} }
|
|
2997
2999
|
};
|
|
2998
3000
|
}
|
|
2999
3001
|
function mergeMap(target, fragment, label) {
|
|
3000
|
-
for (const [name,
|
|
3001
|
-
if (Object.hasOwn(target, name) && !(0, import_node_util.isDeepStrictEqual)(target[name],
|
|
3002
|
+
for (const [name, value2] of Object.entries(fragment)) {
|
|
3003
|
+
if (Object.hasOwn(target, name) && !(0, import_node_util.isDeepStrictEqual)(target[name], value2)) {
|
|
3002
3004
|
throw new Error(`${label} "${name}" conflicts with an existing definition`);
|
|
3003
3005
|
}
|
|
3004
|
-
target[name] =
|
|
3006
|
+
target[name] = value2;
|
|
3005
3007
|
}
|
|
3006
3008
|
}
|
|
3007
|
-
function isRecord6(
|
|
3008
|
-
return
|
|
3009
|
+
function isRecord6(value2) {
|
|
3010
|
+
return value2 !== null && typeof value2 === "object" && !Array.isArray(value2);
|
|
3009
3011
|
}
|
|
3010
3012
|
|
|
3011
3013
|
// src/doctor.ts
|
|
@@ -3046,9 +3048,9 @@ async function doctor(options) {
|
|
|
3046
3048
|
warnings.push(...integrationWarnings(database.integrations, schema, rules));
|
|
3047
3049
|
if (cfg.services.includes("ai") && !cfg.ai?.provider) warnings.push("ai service is enabled but ai.provider is not set");
|
|
3048
3050
|
if (cfg.auth?.clerk) {
|
|
3049
|
-
for (const [env,
|
|
3050
|
-
if (typeof
|
|
3051
|
-
warnings.push(`auth.clerk.${env} references unset env var ${
|
|
3051
|
+
for (const [env, value2] of Object.entries(cfg.auth.clerk)) {
|
|
3052
|
+
if (typeof value2 === "string" && value2.startsWith("$") && !process.env[value2.slice(1)]) {
|
|
3053
|
+
warnings.push(`auth.clerk.${env} references unset env var ${value2}`);
|
|
3052
3054
|
}
|
|
3053
3055
|
}
|
|
3054
3056
|
}
|
|
@@ -3090,10 +3092,10 @@ function harnessList(parsed) {
|
|
|
3090
3092
|
];
|
|
3091
3093
|
return selected.length ? selected : ["all"];
|
|
3092
3094
|
}
|
|
3093
|
-
function harnessOption(
|
|
3094
|
-
if (
|
|
3095
|
-
if (typeof
|
|
3096
|
-
const raw = Array.isArray(
|
|
3095
|
+
function harnessOption(value2, flag) {
|
|
3096
|
+
if (value2 === void 0) return [];
|
|
3097
|
+
if (typeof value2 === "boolean") throw new Error(`${flag} requires a harness name`);
|
|
3098
|
+
const raw = Array.isArray(value2) ? value2 : [value2];
|
|
3097
3099
|
const parts = raw.flatMap((item) => item.split(","));
|
|
3098
3100
|
if (parts.some((item) => !item.trim())) {
|
|
3099
3101
|
throw new Error(`${flag} requires a harness name`);
|
|
@@ -3321,38 +3323,38 @@ async function secretsSet(options) {
|
|
|
3321
3323
|
if (name.startsWith("$")) {
|
|
3322
3324
|
throw new Error('"$"-prefixed vault names are platform-reserved; for the Clerk secret key use "odla-ai secrets set-clerk-key"');
|
|
3323
3325
|
}
|
|
3324
|
-
const { cfg, tenantId, value, doFetch, out } = await resolveVaultWrite(options);
|
|
3326
|
+
const { cfg, tenantId, value: value2, doFetch, out } = await resolveVaultWrite(options);
|
|
3325
3327
|
const token = await getDeveloperToken(cfg, options, doFetch, out);
|
|
3326
3328
|
try {
|
|
3327
|
-
await (0, import_ai.putSecret)({ endpoint: cfg.dbEndpoint, token, fetch: doFetch }, tenantId, name,
|
|
3329
|
+
await (0, import_ai.putSecret)({ endpoint: cfg.dbEndpoint, token, fetch: doFetch }, tenantId, name, value2);
|
|
3328
3330
|
} catch (err) {
|
|
3329
|
-
throw new Error(scrubValue(err instanceof Error ? err.message : String(err),
|
|
3331
|
+
throw new Error(scrubValue(err instanceof Error ? err.message : String(err), value2));
|
|
3330
3332
|
}
|
|
3331
3333
|
out.log(`${name} stored in the ${tenantId} vault (write-only; the value was never echoed and cannot be read back here)`);
|
|
3332
3334
|
}
|
|
3333
3335
|
async function secretsSetClerkKey(options) {
|
|
3334
|
-
const { cfg, tenantId, value, doFetch, out } = await resolveVaultWrite(options);
|
|
3335
|
-
if (!
|
|
3336
|
-
if (
|
|
3336
|
+
const { cfg, tenantId, value: value2, doFetch, out } = await resolveVaultWrite(options);
|
|
3337
|
+
if (!value2.startsWith("sk_")) throw new Error("the Clerk secret key must start with sk_ (sk_test_\u2026 or sk_live_\u2026)");
|
|
3338
|
+
if (value2.startsWith("sk_test_") && PROD_ENV_NAMES2.has(options.env)) {
|
|
3337
3339
|
throw new Error(`refusing to store an sk_test_ Clerk key for "${options.env}" \u2014 use the production instance's sk_live_ key`);
|
|
3338
3340
|
}
|
|
3339
|
-
if (
|
|
3341
|
+
if (value2.startsWith("sk_live_") && !PROD_ENV_NAMES2.has(options.env) && !options.yes) {
|
|
3340
3342
|
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)`);
|
|
3341
3343
|
}
|
|
3342
3344
|
const token = await getDeveloperToken(cfg, options, doFetch, out);
|
|
3343
3345
|
const res = await doFetch(`${cfg.dbEndpoint}/admin/apps/${encodeURIComponent(tenantId)}/clerk-secret`, {
|
|
3344
3346
|
method: "POST",
|
|
3345
3347
|
headers: { authorization: `Bearer ${token}`, "content-type": "application/json" },
|
|
3346
|
-
body: JSON.stringify({ value })
|
|
3348
|
+
body: JSON.stringify({ value: value2 })
|
|
3347
3349
|
});
|
|
3348
3350
|
if (!res.ok) {
|
|
3349
|
-
const text = scrubValue((await res.text().catch(() => "")).slice(0, 300),
|
|
3351
|
+
const text = scrubValue((await res.text().catch(() => "")).slice(0, 300), value2);
|
|
3350
3352
|
throw new Error(`store Clerk secret key failed (${res.status}): ${text || "request failed"}`);
|
|
3351
3353
|
}
|
|
3352
3354
|
out.log(`Clerk secret key stored for ${tenantId} ($clerk_secret, reserved + write-only; the value was never echoed)`);
|
|
3353
3355
|
}
|
|
3354
|
-
function scrubValue(text,
|
|
3355
|
-
return redactSecrets(text).split(
|
|
3356
|
+
function scrubValue(text, value2) {
|
|
3357
|
+
return redactSecrets(text).split(value2).join("[value redacted]");
|
|
3356
3358
|
}
|
|
3357
3359
|
async function resolveVaultWrite(options) {
|
|
3358
3360
|
const out = options.stdout ?? console;
|
|
@@ -3364,8 +3366,8 @@ async function resolveVaultWrite(options) {
|
|
|
3364
3366
|
if (PROD_ENV_NAMES2.has(options.env) && !options.yes) {
|
|
3365
3367
|
throw new Error(`refusing to store a secret for "${options.env}" without --yes`);
|
|
3366
3368
|
}
|
|
3367
|
-
const
|
|
3368
|
-
return { cfg, tenantId: (0, import_apps4.tenantIdFor)(cfg.app.id, options.env), value, doFetch, out };
|
|
3369
|
+
const value2 = await secretInputValue(options, "secret");
|
|
3370
|
+
return { cfg, tenantId: (0, import_apps4.tenantIdFor)(cfg.app.id, options.env), value: value2, doFetch, out };
|
|
3369
3371
|
}
|
|
3370
3372
|
|
|
3371
3373
|
// src/skill.ts
|
|
@@ -3895,24 +3897,24 @@ var CONTROL = /[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/;
|
|
|
3895
3897
|
var HarnessProtocolError = class extends Error {
|
|
3896
3898
|
name = "HarnessProtocolError";
|
|
3897
3899
|
};
|
|
3898
|
-
function record2(
|
|
3899
|
-
return
|
|
3900
|
+
function record2(value2) {
|
|
3901
|
+
return value2 !== null && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
|
|
3900
3902
|
}
|
|
3901
|
-
function boundedText(
|
|
3902
|
-
if (typeof
|
|
3903
|
+
function boundedText(value2, label, max) {
|
|
3904
|
+
if (typeof value2 !== "string" || !value2 || value2.length > max || CONTROL.test(value2)) {
|
|
3903
3905
|
throw new HarnessProtocolError(`${label} must be a non-empty string of at most ${max} characters`);
|
|
3904
3906
|
}
|
|
3905
|
-
return
|
|
3907
|
+
return value2;
|
|
3906
3908
|
}
|
|
3907
3909
|
function parseAgentOutput(line) {
|
|
3908
3910
|
if (Buffer.byteLength(line, "utf8") > 1e6) throw new HarnessProtocolError("agent message exceeds 1 MB");
|
|
3909
|
-
let
|
|
3911
|
+
let value2;
|
|
3910
3912
|
try {
|
|
3911
|
-
|
|
3913
|
+
value2 = JSON.parse(line);
|
|
3912
3914
|
} catch {
|
|
3913
3915
|
throw new HarnessProtocolError("agent emitted invalid JSON");
|
|
3914
3916
|
}
|
|
3915
|
-
const message2 = record2(
|
|
3917
|
+
const message2 = record2(value2);
|
|
3916
3918
|
if (!message2 || message2.protocolVersion !== HARNESS_PROTOCOL_VERSION) {
|
|
3917
3919
|
throw new HarnessProtocolError(`agent protocolVersion must be ${HARNESS_PROTOCOL_VERSION}`);
|
|
3918
3920
|
}
|
|
@@ -4221,7 +4223,7 @@ async function gitOutput(cwd, args, maxBytes) {
|
|
|
4221
4223
|
else stdout.push(chunk);
|
|
4222
4224
|
});
|
|
4223
4225
|
child.stderr.on("data", (chunk) => {
|
|
4224
|
-
if (stderr.reduce((sum,
|
|
4226
|
+
if (stderr.reduce((sum, value2) => sum + value2.byteLength, 0) < 16384) stderr.push(chunk);
|
|
4225
4227
|
});
|
|
4226
4228
|
const code = await new Promise((accept, reject) => {
|
|
4227
4229
|
child.once("error", reject);
|
|
@@ -4242,7 +4244,7 @@ async function gitBlobs(cwd, entries, maxBytes) {
|
|
|
4242
4244
|
else stdout.push(chunk);
|
|
4243
4245
|
});
|
|
4244
4246
|
child.stderr.on("data", (chunk) => {
|
|
4245
|
-
if (stderr.reduce((sum,
|
|
4247
|
+
if (stderr.reduce((sum, value2) => sum + value2.byteLength, 0) < 16384) stderr.push(chunk);
|
|
4246
4248
|
});
|
|
4247
4249
|
child.stdin.end(`${entries.map((entry) => entry.hash).join("\n")}
|
|
4248
4250
|
`);
|
|
@@ -4280,8 +4282,8 @@ async function materializeGitTree(source, commitSha, options = {}) {
|
|
|
4280
4282
|
const maxFiles = options.maxFiles ?? 2e4;
|
|
4281
4283
|
const maxBytes = options.maxBytes ?? 512 * 1024 * 1024;
|
|
4282
4284
|
const inventory = (await gitOutput(sourceDir, ["ls-tree", "-rz", commitSha], 16 * 1024 * 1024)).toString("utf8").split("\0").filter(Boolean);
|
|
4283
|
-
const entries = inventory.flatMap((
|
|
4284
|
-
const match = /^(100644|100755) blob ([0-9a-f]{40,64})\t([\s\S]+)$/.exec(
|
|
4285
|
+
const entries = inventory.flatMap((record8) => {
|
|
4286
|
+
const match = /^(100644|100755) blob ([0-9a-f]{40,64})\t([\s\S]+)$/.exec(record8);
|
|
4285
4287
|
return match && allowedWorkspacePath(match[3]) ? [{ mode: match[1], hash: match[2], path: match[3] }] : [];
|
|
4286
4288
|
});
|
|
4287
4289
|
if (entries.length > maxFiles) throw new Error(`workspace exceeds ${maxFiles} files`);
|
|
@@ -4356,7 +4358,7 @@ async function gitSourceFiles(sourceDir, maxFiles, maxBytes) {
|
|
|
4356
4358
|
else stdout.push(chunk);
|
|
4357
4359
|
});
|
|
4358
4360
|
child.stderr.on("data", (chunk) => {
|
|
4359
|
-
if (stderr.reduce((sum,
|
|
4361
|
+
if (stderr.reduce((sum, value2) => sum + value2.byteLength, 0) < 16384) stderr.push(chunk);
|
|
4360
4362
|
});
|
|
4361
4363
|
const code = await new Promise((accept, reject) => {
|
|
4362
4364
|
child.once("error", reject);
|
|
@@ -4416,7 +4418,7 @@ async function captureGitDiff(root, 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);
|
|
@@ -4503,34 +4505,34 @@ var CamelError = class extends Error {
|
|
|
4503
4505
|
};
|
|
4504
4506
|
|
|
4505
4507
|
// ../camel/dist/chunk-L5DYU2E2.js
|
|
4506
|
-
function canonicalJson(
|
|
4507
|
-
return JSON.stringify(normalize(
|
|
4508
|
+
function canonicalJson(value2) {
|
|
4509
|
+
return JSON.stringify(normalize(value2));
|
|
4508
4510
|
}
|
|
4509
|
-
async function sha256Hex(
|
|
4510
|
-
const bytes = typeof
|
|
4511
|
+
async function sha256Hex(value2) {
|
|
4512
|
+
const bytes = typeof value2 === "string" ? new TextEncoder().encode(value2) : value2;
|
|
4511
4513
|
const digest = await crypto.subtle.digest("SHA-256", Uint8Array.from(bytes).buffer);
|
|
4512
4514
|
return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
4513
4515
|
}
|
|
4514
|
-
function utf8Length(
|
|
4515
|
-
if (typeof
|
|
4516
|
-
if (
|
|
4516
|
+
function utf8Length(value2) {
|
|
4517
|
+
if (typeof value2 === "string") return new TextEncoder().encode(value2).byteLength;
|
|
4518
|
+
if (value2 instanceof Uint8Array) return value2.byteLength;
|
|
4517
4519
|
try {
|
|
4518
|
-
return new TextEncoder().encode(canonicalJson(
|
|
4520
|
+
return new TextEncoder().encode(canonicalJson(value2)).byteLength;
|
|
4519
4521
|
} catch {
|
|
4520
4522
|
throw new CamelError("conversion_rejected", "Unsafe input could not be canonically measured.");
|
|
4521
4523
|
}
|
|
4522
4524
|
}
|
|
4523
|
-
function normalize(
|
|
4524
|
-
if (
|
|
4525
|
-
if (typeof
|
|
4526
|
-
if (!Number.isFinite(
|
|
4527
|
-
return
|
|
4525
|
+
function normalize(value2) {
|
|
4526
|
+
if (value2 === null || typeof value2 === "string" || typeof value2 === "boolean") return value2;
|
|
4527
|
+
if (typeof value2 === "number") {
|
|
4528
|
+
if (!Number.isFinite(value2)) throw new CamelError("state_conflict", "Canonical JSON rejects non-finite numbers.");
|
|
4529
|
+
return value2;
|
|
4528
4530
|
}
|
|
4529
|
-
if (Array.isArray(
|
|
4530
|
-
if (
|
|
4531
|
-
if (typeof
|
|
4532
|
-
const
|
|
4533
|
-
return Object.fromEntries(Object.keys(
|
|
4531
|
+
if (Array.isArray(value2)) return value2.map(normalize);
|
|
4532
|
+
if (value2 instanceof Uint8Array) return { $bytes: [...value2] };
|
|
4533
|
+
if (typeof value2 === "object") {
|
|
4534
|
+
const record8 = value2;
|
|
4535
|
+
return Object.fromEntries(Object.keys(record8).filter((key) => record8[key] !== void 0).sort().map((key) => [key, normalize(record8[key])]));
|
|
4534
4536
|
}
|
|
4535
4537
|
throw new CamelError("state_conflict", "Canonical JSON rejects unsupported values.");
|
|
4536
4538
|
}
|
|
@@ -4539,10 +4541,10 @@ function canRead(readers, readerId) {
|
|
|
4539
4541
|
}
|
|
4540
4542
|
function dependenciesOf(values, influence = "data") {
|
|
4541
4543
|
const result = [];
|
|
4542
|
-
for (const
|
|
4543
|
-
result.push(...
|
|
4544
|
-
for (const ref of
|
|
4545
|
-
result.push({ ref, influence, promptSafetyAtUse:
|
|
4544
|
+
for (const value2 of values) {
|
|
4545
|
+
result.push(...value2.label.dependencies);
|
|
4546
|
+
for (const ref of value2.label.provenance) {
|
|
4547
|
+
result.push({ ref, influence, promptSafetyAtUse: value2.label.promptSafety });
|
|
4546
4548
|
}
|
|
4547
4549
|
}
|
|
4548
4550
|
const unique3 = /* @__PURE__ */ new Map();
|
|
@@ -4553,32 +4555,32 @@ function dependenciesOf(values, influence = "data") {
|
|
|
4553
4555
|
// ../camel/dist/chunk-S7EVNA2U.js
|
|
4554
4556
|
var camelValueBrand = /* @__PURE__ */ Symbol("@odla-ai/camel/value");
|
|
4555
4557
|
var authenticCamelValues = /* @__PURE__ */ new WeakSet();
|
|
4556
|
-
function isCamelValue(
|
|
4557
|
-
return typeof
|
|
4558
|
+
function isCamelValue(value2) {
|
|
4559
|
+
return typeof value2 === "object" && value2 !== null && authenticCamelValues.has(value2);
|
|
4558
4560
|
}
|
|
4559
|
-
function isSafe(
|
|
4560
|
-
return isCamelValue(
|
|
4561
|
+
function isSafe(value2) {
|
|
4562
|
+
return isCamelValue(value2) && value2.label.promptSafety === "safe";
|
|
4561
4563
|
}
|
|
4562
|
-
function isUnsafe(
|
|
4563
|
-
return isCamelValue(
|
|
4564
|
+
function isUnsafe(value2) {
|
|
4565
|
+
return isCamelValue(value2) && value2.label.promptSafety === "unsafe";
|
|
4564
4566
|
}
|
|
4565
|
-
function createSafeInternal(
|
|
4566
|
-
return createValue(
|
|
4567
|
+
function createSafeInternal(value2, safeBasis, metadata2) {
|
|
4568
|
+
return createValue(value2, {
|
|
4567
4569
|
schemaVersion: 1,
|
|
4568
4570
|
promptSafety: "safe",
|
|
4569
4571
|
safeBasis,
|
|
4570
4572
|
...copyMetadata(metadata2)
|
|
4571
4573
|
});
|
|
4572
4574
|
}
|
|
4573
|
-
function createUnsafeInternal(
|
|
4574
|
-
return createValue(
|
|
4575
|
+
function createUnsafeInternal(value2, metadata2) {
|
|
4576
|
+
return createValue(value2, {
|
|
4575
4577
|
schemaVersion: 1,
|
|
4576
4578
|
promptSafety: "unsafe",
|
|
4577
4579
|
...copyMetadata(metadata2)
|
|
4578
4580
|
});
|
|
4579
4581
|
}
|
|
4580
|
-
function createValue(
|
|
4581
|
-
const result = { value, label: Object.freeze(label) };
|
|
4582
|
+
function createValue(value2, label) {
|
|
4583
|
+
const result = { value: value2, label: Object.freeze(label) };
|
|
4582
4584
|
Object.defineProperty(result, camelValueBrand, { value: label.promptSafety, enumerable: false });
|
|
4583
4585
|
authenticCamelValues.add(result);
|
|
4584
4586
|
return Object.freeze(result);
|
|
@@ -4684,8 +4686,8 @@ async function createCodePortableCheckpoint(input) {
|
|
|
4684
4686
|
const checkpointDigest = `sha256:${await sha256Hex(canonicalJson(fields))}`;
|
|
4685
4687
|
return freeze({ ...fields, patch: input.patch, checkpointDigest });
|
|
4686
4688
|
}
|
|
4687
|
-
async function verifyCodePortableCheckpoint(
|
|
4688
|
-
const input = object(
|
|
4689
|
+
async function verifyCodePortableCheckpoint(value2) {
|
|
4690
|
+
const input = object(value2, "checkpoint");
|
|
4689
4691
|
exact2(input, ["schemaVersion", "baseCommitSha", "patch", "patchDigest", "state", "stateDigest", "checkpointDigest"]);
|
|
4690
4692
|
if (input.schemaVersion !== 1 || typeof input.baseCommitSha !== "string" || typeof input.patch !== "string" || typeof input.patchDigest !== "string" || typeof input.stateDigest !== "string" || typeof input.checkpointDigest !== "string") {
|
|
4691
4693
|
throw invalid2("Portable checkpoint fields are malformed.");
|
|
@@ -4700,8 +4702,8 @@ async function verifyCodePortableCheckpoint(value) {
|
|
|
4700
4702
|
}
|
|
4701
4703
|
return created;
|
|
4702
4704
|
}
|
|
4703
|
-
function normalizeState(
|
|
4704
|
-
const state2 = object(
|
|
4705
|
+
function normalizeState(value2) {
|
|
4706
|
+
const state2 = object(value2, "state");
|
|
4705
4707
|
exact2(state2, [
|
|
4706
4708
|
"planCursor",
|
|
4707
4709
|
"conversationRefs",
|
|
@@ -4759,30 +4761,30 @@ function validateBaseAndPatch(baseCommitSha, patch2) {
|
|
|
4759
4761
|
throw invalid2("Portable checkpoint base or patch is malformed or outside its bounds.");
|
|
4760
4762
|
}
|
|
4761
4763
|
}
|
|
4762
|
-
function strings(
|
|
4763
|
-
if (!Array.isArray(
|
|
4764
|
+
function strings(value2, name, pattern, maximum, sort) {
|
|
4765
|
+
if (!Array.isArray(value2) || value2.length > maximum || value2.some((item) => typeof item !== "string" || !pattern.test(item)) || new Set(value2).size !== value2.length) {
|
|
4764
4766
|
throw invalid2(`Portable checkpoint ${name} is malformed or outside its bounds.`);
|
|
4765
4767
|
}
|
|
4766
|
-
const result = [...
|
|
4768
|
+
const result = [...value2];
|
|
4767
4769
|
return sort ? result.sort() : result;
|
|
4768
4770
|
}
|
|
4769
|
-
function object(
|
|
4770
|
-
if (!
|
|
4771
|
-
return
|
|
4771
|
+
function object(value2, name) {
|
|
4772
|
+
if (!value2 || typeof value2 !== "object" || Array.isArray(value2)) throw invalid2(`Portable ${name} must be an object.`);
|
|
4773
|
+
return value2;
|
|
4772
4774
|
}
|
|
4773
|
-
function exact2(
|
|
4774
|
-
if (Object.keys(
|
|
4775
|
+
function exact2(value2, keys) {
|
|
4776
|
+
if (Object.keys(value2).some((key) => !keys.includes(key)) || keys.some((key) => !(key in value2))) {
|
|
4775
4777
|
throw invalid2("Portable checkpoint contains missing or unsupported fields.");
|
|
4776
4778
|
}
|
|
4777
4779
|
}
|
|
4778
|
-
function freeze(
|
|
4780
|
+
function freeze(value2) {
|
|
4779
4781
|
return Object.freeze({
|
|
4780
|
-
...
|
|
4782
|
+
...value2,
|
|
4781
4783
|
state: Object.freeze({
|
|
4782
|
-
...
|
|
4783
|
-
conversationRefs: Object.freeze([...
|
|
4784
|
-
completedEffects: Object.freeze(
|
|
4785
|
-
unresolvedApprovals: Object.freeze([...
|
|
4784
|
+
...value2.state,
|
|
4785
|
+
conversationRefs: Object.freeze([...value2.state.conversationRefs]),
|
|
4786
|
+
completedEffects: Object.freeze(value2.state.completedEffects.map((item) => Object.freeze({ ...item }))),
|
|
4787
|
+
unresolvedApprovals: Object.freeze([...value2.state.unresolvedApprovals])
|
|
4786
4788
|
})
|
|
4787
4789
|
});
|
|
4788
4790
|
}
|
|
@@ -4873,61 +4875,61 @@ async function createConversionRegistry(config) {
|
|
|
4873
4875
|
if (utf8Length(source.value) > policy.maximumSourceBytes) throw new CamelError("limit_exceeded", "Unsafe conversion input exceeds its byte bound.");
|
|
4874
4876
|
return policy;
|
|
4875
4877
|
};
|
|
4876
|
-
const emit3 = (source, policy,
|
|
4878
|
+
const emit3 = (source, policy, value2) => convert(source, policy, value2, outputCounts);
|
|
4877
4879
|
const operations = Object.freeze({
|
|
4878
|
-
boolean: async (
|
|
4879
|
-
const policy = checked(
|
|
4880
|
-
return emit3(
|
|
4880
|
+
boolean: async (value2, id) => {
|
|
4881
|
+
const policy = checked(value2, id, "boolean");
|
|
4882
|
+
return emit3(value2, policy, requireBoolean(value2.value));
|
|
4881
4883
|
},
|
|
4882
|
-
integer: async (
|
|
4883
|
-
const policy = checked(
|
|
4884
|
-
return emit3(
|
|
4884
|
+
integer: async (value2, id) => {
|
|
4885
|
+
const policy = checked(value2, id, "integer");
|
|
4886
|
+
return emit3(value2, policy, boundedInteger(value2.value, policy.output));
|
|
4885
4887
|
},
|
|
4886
|
-
finiteNumber: async (
|
|
4887
|
-
const policy = checked(
|
|
4888
|
-
return emit3(
|
|
4888
|
+
finiteNumber: async (value2, id) => {
|
|
4889
|
+
const policy = checked(value2, id, "finite_number");
|
|
4890
|
+
return emit3(value2, policy, boundedNumber(value2.value, policy.output));
|
|
4889
4891
|
},
|
|
4890
|
-
enum: async (
|
|
4891
|
-
const policy = checked(
|
|
4892
|
-
return emit3(
|
|
4892
|
+
enum: async (value2, id) => {
|
|
4893
|
+
const policy = checked(value2, id, "enum");
|
|
4894
|
+
return emit3(value2, policy, enumMember(value2.value, policy.output));
|
|
4893
4895
|
},
|
|
4894
|
-
date: async (
|
|
4895
|
-
const policy = checked(
|
|
4896
|
-
return emit3(
|
|
4896
|
+
date: async (value2, id) => {
|
|
4897
|
+
const policy = checked(value2, id, "date");
|
|
4898
|
+
return emit3(value2, policy, canonicalDate(value2.value, policy.output));
|
|
4897
4899
|
},
|
|
4898
|
-
registeredId: async (
|
|
4899
|
-
const policy = checked(
|
|
4900
|
+
registeredId: async (value2, id) => {
|
|
4901
|
+
const policy = checked(value2, id, "registered_id");
|
|
4900
4902
|
const registry = config.registeredIds?.[policy.output.registryId];
|
|
4901
|
-
const output = typeof
|
|
4903
|
+
const output = typeof value2.value === "string" ? registry?.values[value2.value] : void 0;
|
|
4902
4904
|
if (!output) throw new CamelError("conversion_rejected", "Registered-ID conversion rejected the candidate.");
|
|
4903
|
-
return emit3(
|
|
4905
|
+
return emit3(value2, policy, output);
|
|
4904
4906
|
},
|
|
4905
|
-
digest: async (
|
|
4906
|
-
const policy = checked(
|
|
4907
|
-
if (!(
|
|
4908
|
-
return emit3(
|
|
4907
|
+
digest: async (value2, id) => {
|
|
4908
|
+
const policy = checked(value2, id, "digest");
|
|
4909
|
+
if (!(value2.value instanceof Uint8Array)) throw new CamelError("conversion_rejected", "Digest conversion requires bytes.");
|
|
4910
|
+
return emit3(value2, policy, await sha256Hex(value2.value));
|
|
4909
4911
|
},
|
|
4910
|
-
measure: async (
|
|
4911
|
-
const policy = checked(
|
|
4912
|
-
const measured = measure(
|
|
4913
|
-
return emit3(
|
|
4912
|
+
measure: async (value2, metric, id) => {
|
|
4913
|
+
const policy = checked(value2, id, "integer");
|
|
4914
|
+
const measured = measure(value2.value, metric);
|
|
4915
|
+
return emit3(value2, policy, boundedInteger(measured, policy.output));
|
|
4914
4916
|
},
|
|
4915
|
-
test: async (
|
|
4916
|
-
const policy = checked(
|
|
4917
|
+
test: async (value2, predicateId, id) => {
|
|
4918
|
+
const policy = checked(value2, id, "boolean");
|
|
4917
4919
|
const predicate = config.predicates?.[predicateId];
|
|
4918
4920
|
if (!predicate) throw new CamelError("conversion_rejected", "Predicate is not registered.");
|
|
4919
|
-
return emit3(
|
|
4921
|
+
return emit3(value2, policy, evaluatePredicate(value2.value, predicate, config.registeredIds));
|
|
4920
4922
|
}
|
|
4921
4923
|
});
|
|
4922
4924
|
return Object.freeze({ operations, policy: (id) => policies.get(id) ?? missingPolicy() });
|
|
4923
4925
|
}
|
|
4924
|
-
async function convert(source, policy,
|
|
4926
|
+
async function convert(source, policy, value2, counts) {
|
|
4925
4927
|
const sourceKey = sourceIdentity(source);
|
|
4926
4928
|
const countKey = `${policy.conversionId}\0${sourceKey}`;
|
|
4927
4929
|
const count = counts.get(countKey) ?? 0;
|
|
4928
4930
|
if (count >= policy.maximumOutputsPerArtifact) throw new CamelError("limit_exceeded", "Conversion output count exceeds its per-source bound.");
|
|
4929
4931
|
counts.set(countKey, count + 1);
|
|
4930
|
-
return createSafeInternal(
|
|
4932
|
+
return createSafeInternal(value2, "atomic_conversion", {
|
|
4931
4933
|
readers: source.label.readers,
|
|
4932
4934
|
provenance: [...source.label.provenance, { kind: "converter", id: policy.conversionId, digest: policy.digest }],
|
|
4933
4935
|
dependencies: dependenciesOf([source])
|
|
@@ -4939,49 +4941,49 @@ function validatePolicyShape(policy) {
|
|
|
4939
4941
|
const output = policy.output;
|
|
4940
4942
|
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.");
|
|
4941
4943
|
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.");
|
|
4942
|
-
if (output.kind === "enum" && (output.values.length === 0 || output.values.some((
|
|
4944
|
+
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.");
|
|
4943
4945
|
if (output.kind === "registered_id" && (!output.registryId || !output.registryDigest)) throw new CamelError("state_conflict", "Registered-ID conversion identity is invalid.");
|
|
4944
4946
|
if (output.kind === "date" && output.format !== "date" && output.format !== "rfc3339") throw new CamelError("state_conflict", "Date conversion format is invalid.");
|
|
4945
4947
|
if (output.kind === "digest" && output.algorithm !== "sha256") throw new CamelError("state_conflict", "Digest conversion algorithm is invalid.");
|
|
4946
4948
|
}
|
|
4947
|
-
function requireBoolean(
|
|
4948
|
-
if (typeof
|
|
4949
|
-
return
|
|
4949
|
+
function requireBoolean(value2) {
|
|
4950
|
+
if (typeof value2 !== "boolean") throw new CamelError("conversion_rejected", "Boolean conversion requires a structured boolean.");
|
|
4951
|
+
return value2;
|
|
4950
4952
|
}
|
|
4951
|
-
function boundedInteger(
|
|
4952
|
-
if (spec.kind !== "integer" || typeof
|
|
4953
|
-
return
|
|
4953
|
+
function boundedInteger(value2, spec) {
|
|
4954
|
+
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.");
|
|
4955
|
+
return value2;
|
|
4954
4956
|
}
|
|
4955
|
-
function boundedNumber(
|
|
4956
|
-
if (spec.kind !== "finite_number" || typeof
|
|
4957
|
-
const text = String(
|
|
4957
|
+
function boundedNumber(value2, spec) {
|
|
4958
|
+
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.");
|
|
4959
|
+
const text = String(value2);
|
|
4958
4960
|
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.");
|
|
4959
|
-
return
|
|
4961
|
+
return value2;
|
|
4960
4962
|
}
|
|
4961
|
-
function enumMember(
|
|
4962
|
-
if (spec.kind !== "enum" || typeof
|
|
4963
|
-
const member = spec.caseSensitive ? spec.values.find((item) => item ===
|
|
4963
|
+
function enumMember(value2, spec) {
|
|
4964
|
+
if (spec.kind !== "enum" || typeof value2 !== "string") throw new CamelError("conversion_rejected", "Enum conversion requires a structured string member.");
|
|
4965
|
+
const member = spec.caseSensitive ? spec.values.find((item) => item === value2) : spec.values.find((item) => item.toLocaleLowerCase("en-US") === value2.toLocaleLowerCase("en-US"));
|
|
4964
4966
|
if (member === void 0) throw new CamelError("conversion_rejected", "Enum conversion rejected a non-member.");
|
|
4965
4967
|
return member;
|
|
4966
4968
|
}
|
|
4967
|
-
function canonicalDate(
|
|
4968
|
-
if (spec.kind !== "date" || typeof
|
|
4969
|
+
function canonicalDate(value2, spec) {
|
|
4970
|
+
if (spec.kind !== "date" || typeof value2 !== "string") throw new CamelError("conversion_rejected", "Date conversion requires a canonical structured string.");
|
|
4969
4971
|
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})$/;
|
|
4970
|
-
const instant = Date.parse(spec.format === "date" ? `${
|
|
4971
|
-
if (!pattern.test(
|
|
4972
|
-
if (spec.earliest &&
|
|
4973
|
-
return
|
|
4974
|
-
}
|
|
4975
|
-
function measure(
|
|
4976
|
-
if (metric === "byte_length" && (typeof
|
|
4977
|
-
if (metric === "codepoint_length" && typeof
|
|
4978
|
-
if (metric === "item_count" && Array.isArray(
|
|
4972
|
+
const instant = Date.parse(spec.format === "date" ? `${value2}T00:00:00Z` : value2);
|
|
4973
|
+
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.");
|
|
4974
|
+
if (spec.earliest && value2 < spec.earliest || spec.latest && value2 > spec.latest) throw new CamelError("conversion_rejected", "Date conversion rejected an out-of-range value.");
|
|
4975
|
+
return value2;
|
|
4976
|
+
}
|
|
4977
|
+
function measure(value2, metric) {
|
|
4978
|
+
if (metric === "byte_length" && (typeof value2 === "string" || value2 instanceof Uint8Array)) return utf8Length(value2);
|
|
4979
|
+
if (metric === "codepoint_length" && typeof value2 === "string") return [...value2].length;
|
|
4980
|
+
if (metric === "item_count" && Array.isArray(value2)) return value2.length;
|
|
4979
4981
|
throw new CamelError("conversion_rejected", "Measurement input does not match the registered metric.");
|
|
4980
4982
|
}
|
|
4981
|
-
function evaluatePredicate(
|
|
4982
|
-
if (predicate.kind === "has_fields") return typeof
|
|
4983
|
-
if (predicate.kind === "registered_id") return typeof
|
|
4984
|
-
const actual =
|
|
4983
|
+
function evaluatePredicate(value2, predicate, registries) {
|
|
4984
|
+
if (predicate.kind === "has_fields") return typeof value2 === "object" && value2 !== null && !Array.isArray(value2) && predicate.fields.every((field) => Object.hasOwn(value2, field));
|
|
4985
|
+
if (predicate.kind === "registered_id") return typeof value2 === "string" && registries?.[predicate.registryId]?.values[value2] !== void 0;
|
|
4986
|
+
const actual = value2 === null ? "null" : Array.isArray(value2) ? "array" : typeof value2;
|
|
4985
4987
|
return actual === predicate.valueType;
|
|
4986
4988
|
}
|
|
4987
4989
|
function sourceIdentity(source) {
|
|
@@ -5004,17 +5006,17 @@ function createCamelIngress(constants2 = []) {
|
|
|
5004
5006
|
byId.set(item.id, item);
|
|
5005
5007
|
}
|
|
5006
5008
|
const ingress = {
|
|
5007
|
-
userInstruction: (
|
|
5008
|
-
systemPolicy: (
|
|
5009
|
+
userInstruction: (value2, input) => createSafeInternal(value2, "user_instruction", metadata("user_instruction", input.id, input.readers)),
|
|
5010
|
+
systemPolicy: (value2, input) => createSafeInternal(value2, "system_policy", metadata("system_policy", input.id, input.readers)),
|
|
5009
5011
|
control: (id) => {
|
|
5010
5012
|
const item = byId.get(id);
|
|
5011
5013
|
if (!item) throw new CamelError("permission_denied", "Unknown control constant.");
|
|
5012
5014
|
return createSafeInternal(item.value, "harness_constant", metadata("harness", id, item.readers));
|
|
5013
5015
|
},
|
|
5014
|
-
external: (
|
|
5015
|
-
quarantinedOutput: (
|
|
5016
|
+
external: (value2, label) => createUnsafeInternal(value2, label),
|
|
5017
|
+
quarantinedOutput: (value2, input) => {
|
|
5016
5018
|
if (!input.runId) throw new CamelError("state_conflict", "Quarantined run IDs must be non-empty.");
|
|
5017
|
-
return createUnsafeInternal(
|
|
5019
|
+
return createUnsafeInternal(value2, {
|
|
5018
5020
|
readers: input.readers,
|
|
5019
5021
|
dependencies: input.dependencies,
|
|
5020
5022
|
provenance: [{ kind: "quarantined_llm", id: input.runId, digest: input.digest }]
|
|
@@ -5023,15 +5025,15 @@ function createCamelIngress(constants2 = []) {
|
|
|
5023
5025
|
};
|
|
5024
5026
|
return Object.freeze(ingress);
|
|
5025
5027
|
}
|
|
5026
|
-
function assertNoUnsafeConstant(
|
|
5027
|
-
if (typeof
|
|
5028
|
-
seen.add(
|
|
5029
|
-
if (isCamelValue(
|
|
5030
|
-
if (isUnsafe(
|
|
5031
|
-
assertNoUnsafeConstant(
|
|
5028
|
+
function assertNoUnsafeConstant(value2, seen = /* @__PURE__ */ new WeakSet()) {
|
|
5029
|
+
if (typeof value2 !== "object" || value2 === null || seen.has(value2)) return;
|
|
5030
|
+
seen.add(value2);
|
|
5031
|
+
if (isCamelValue(value2)) {
|
|
5032
|
+
if (isUnsafe(value2)) throw new CamelError("unsafe_privileged_flow", "Control constants cannot contain Prompt-Unsafe values.");
|
|
5033
|
+
assertNoUnsafeConstant(value2.value, seen);
|
|
5032
5034
|
return;
|
|
5033
5035
|
}
|
|
5034
|
-
for (const child of Object.values(
|
|
5036
|
+
for (const child of Object.values(value2)) assertNoUnsafeConstant(child, seen);
|
|
5035
5037
|
}
|
|
5036
5038
|
function metadata(kind, id, readers) {
|
|
5037
5039
|
if (!id) throw new CamelError("state_conflict", "Provenance IDs must be non-empty.");
|
|
@@ -5062,7 +5064,7 @@ async function evaluate(input, registries, approvals) {
|
|
|
5062
5064
|
if (invalid3) return deny(invalid3);
|
|
5063
5065
|
if (arg.role === "selector" && !isSafe(arg.value)) confined.add(arg.value);
|
|
5064
5066
|
}
|
|
5065
|
-
if (input.controlDependencies.some((
|
|
5067
|
+
if (input.controlDependencies.some((value2) => !isSafe(value2) && !confined.has(value2))) return deny("unsafe_control_dependency");
|
|
5066
5068
|
if (confined.size > 0) {
|
|
5067
5069
|
const fixed = input.tool.unsafeSelectorPolicy?.fixedProviderIds ?? [];
|
|
5068
5070
|
const destinations = Object.values(input.args).filter((arg) => arg.role === "destination");
|
|
@@ -5089,29 +5091,29 @@ async function validateArgument(path, arg, tool, registries) {
|
|
|
5089
5091
|
if (!isSafe(arg.value)) return "unsafe_destination_argument";
|
|
5090
5092
|
if (!isControlOwned(arg.value)) return "destination_not_control_owned";
|
|
5091
5093
|
const registry = registries[arg.registryId];
|
|
5092
|
-
const validValues = registry && registry.values.length > 0 && registry.values.every((
|
|
5094
|
+
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;
|
|
5093
5095
|
if (!registry || !validValues || registry.digest !== arg.registryDigest || await destinationRegistryDigest(registry.values) !== registry.digest || !registry.values.includes(arg.value.value)) return "destination_not_registered";
|
|
5094
5096
|
}
|
|
5095
5097
|
if (arg.role === "selector" && !isSafe(arg.value)) return validateUnsafeSelector(path, arg.value, tool);
|
|
5096
5098
|
return void 0;
|
|
5097
5099
|
}
|
|
5098
|
-
function isControlOwned(
|
|
5099
|
-
return
|
|
5100
|
+
function isControlOwned(value2) {
|
|
5101
|
+
return value2.label.safeBasis === "system_policy" || value2.label.safeBasis === "harness_constant";
|
|
5100
5102
|
}
|
|
5101
5103
|
function copyRegistries(registries) {
|
|
5102
5104
|
return Object.freeze(Object.fromEntries(Object.entries(registries).map(([id, registry]) => [id, Object.freeze({ digest: registry.digest, values: Object.freeze([...registry.values]) })])));
|
|
5103
5105
|
}
|
|
5104
|
-
function validateUnsafeSelector(path,
|
|
5106
|
+
function validateUnsafeSelector(path, value2, tool) {
|
|
5105
5107
|
const policy = tool.unsafeSelectorPolicy;
|
|
5106
5108
|
if (!policy || policy.effect !== tool.effect || !policy.selectorPaths.includes(path)) return "unsafe_selector_not_confined";
|
|
5107
5109
|
if (!policy.fixedDestination || !policy.unsafeOutput || policy.fixedProviderIds.length === 0) return "unsafe_selector_not_confined";
|
|
5108
5110
|
if (![policy.maximumCalls, policy.maximumResultsPerCall, policy.maximumOutputBytes, policy.maximumSelectorBytes].every((bound) => Number.isSafeInteger(bound) && bound > 0)) return "unsafe_selector_not_confined";
|
|
5109
|
-
if (utf8Length(
|
|
5110
|
-
if (typeof
|
|
5111
|
+
if (utf8Length(value2.value) > policy.maximumSelectorBytes) return "unsafe_selector_too_large";
|
|
5112
|
+
if (typeof value2.value === "string" && looksLikeDestination(value2.value)) return "unsafe_selector_is_destination";
|
|
5111
5113
|
return void 0;
|
|
5112
5114
|
}
|
|
5113
|
-
function looksLikeDestination(
|
|
5114
|
-
const text =
|
|
5115
|
+
function looksLikeDestination(value2) {
|
|
5116
|
+
const text = value2.trim();
|
|
5115
5117
|
return /^(?:[a-z][a-z0-9+.-]*:\/\/|\/|\\\\)/i.test(text) || /^[\w.-]+\.[a-z]{2,}(?:[/:]|$)/i.test(text);
|
|
5116
5118
|
}
|
|
5117
5119
|
|
|
@@ -5197,9 +5199,9 @@ var CodeRuntimeReconciler = class {
|
|
|
5197
5199
|
}
|
|
5198
5200
|
}
|
|
5199
5201
|
};
|
|
5200
|
-
function retryableControlFailure(
|
|
5201
|
-
if (!
|
|
5202
|
-
const failure =
|
|
5202
|
+
function retryableControlFailure(value2) {
|
|
5203
|
+
if (!value2 || typeof value2 !== "object") return false;
|
|
5204
|
+
const failure = value2;
|
|
5203
5205
|
if (failure.code === "invalid_response" || typeof failure.status !== "number") return false;
|
|
5204
5206
|
return failure.status === 408 || failure.status === 425 || failure.status === 429 || failure.status >= 500;
|
|
5205
5207
|
}
|
|
@@ -5251,16 +5253,16 @@ function createCodeRuntimeControlClient(options) {
|
|
|
5251
5253
|
if (options.signal?.aborted) throw cause;
|
|
5252
5254
|
throw new CodeRuntimeControlError("Code runtime control plane is unavailable", 503, "transport_unavailable");
|
|
5253
5255
|
}
|
|
5254
|
-
const
|
|
5256
|
+
const value2 = await response2.json().catch(() => null);
|
|
5255
5257
|
if (!response2.ok) {
|
|
5256
|
-
const problem = record3(record3(
|
|
5258
|
+
const problem = record3(record3(value2)?.error);
|
|
5257
5259
|
throw new CodeRuntimeControlError(
|
|
5258
5260
|
typeof problem?.message === "string" ? problem.message : `Code runtime request failed (${response2.status})`,
|
|
5259
5261
|
response2.status,
|
|
5260
5262
|
typeof problem?.code === "string" ? problem.code : void 0
|
|
5261
5263
|
);
|
|
5262
5264
|
}
|
|
5263
|
-
return
|
|
5265
|
+
return value2;
|
|
5264
5266
|
};
|
|
5265
5267
|
return {
|
|
5266
5268
|
heartbeat: async (version, capabilities) => {
|
|
@@ -5275,15 +5277,15 @@ function createCodeRuntimeControlClient(options) {
|
|
|
5275
5277
|
await call2(`/registry/code/runtime/sessions/${validSessionId(sessionId)}/source`, {})
|
|
5276
5278
|
),
|
|
5277
5279
|
infer: async (sessionId, inference) => {
|
|
5278
|
-
const
|
|
5280
|
+
const value2 = record3(await call2(
|
|
5279
5281
|
`/registry/code/runtime/sessions/${validSessionId(sessionId)}/inference`,
|
|
5280
5282
|
inference,
|
|
5281
5283
|
modelRequestTimeoutMs
|
|
5282
5284
|
));
|
|
5283
|
-
if (!
|
|
5285
|
+
if (!value2 || value2.requestId !== inference.requestId || !record3(value2.response) || !record3(value2.receipt)) {
|
|
5284
5286
|
throw new CodeRuntimeControlError("invalid Code inference response", 502, "invalid_response");
|
|
5285
5287
|
}
|
|
5286
|
-
return
|
|
5288
|
+
return value2;
|
|
5287
5289
|
},
|
|
5288
5290
|
review: async (sessionId, review) => parseReview(
|
|
5289
5291
|
await call2(`/registry/code/runtime/sessions/${validSessionId(sessionId)}/review`, review, modelRequestTimeoutMs)
|
|
@@ -5308,8 +5310,8 @@ function createCodeRuntimeControlClient(options) {
|
|
|
5308
5310
|
}
|
|
5309
5311
|
};
|
|
5310
5312
|
}
|
|
5311
|
-
function validatedEndpoint(
|
|
5312
|
-
const endpoint =
|
|
5313
|
+
function validatedEndpoint(value2) {
|
|
5314
|
+
const endpoint = value2.replace(/\/+$/, "");
|
|
5313
5315
|
let url;
|
|
5314
5316
|
try {
|
|
5315
5317
|
url = new URL(endpoint);
|
|
@@ -5322,9 +5324,9 @@ function validatedEndpoint(value) {
|
|
|
5322
5324
|
}
|
|
5323
5325
|
return endpoint;
|
|
5324
5326
|
}
|
|
5325
|
-
function validSessionId(
|
|
5326
|
-
if (!/^csess_[0-9a-f]{32}$/.test(
|
|
5327
|
-
return
|
|
5327
|
+
function validSessionId(value2) {
|
|
5328
|
+
if (!/^csess_[0-9a-f]{32}$/.test(value2)) throw new TypeError("invalid Code session id");
|
|
5329
|
+
return value2;
|
|
5328
5330
|
}
|
|
5329
5331
|
function validateHeartbeat(version, capabilities) {
|
|
5330
5332
|
if (!version.trim() || version.length > 80) throw new TypeError("runtimeVersion is required and at most 80 characters");
|
|
@@ -5337,8 +5339,8 @@ function validateHeartbeat(version, capabilities) {
|
|
|
5337
5339
|
throw new TypeError("runtime resources must be positive integers");
|
|
5338
5340
|
}
|
|
5339
5341
|
}
|
|
5340
|
-
function parseSnapshot(
|
|
5341
|
-
const root = record3(
|
|
5342
|
+
function parseSnapshot(value2) {
|
|
5343
|
+
const root = record3(value2);
|
|
5342
5344
|
const host = record3(root?.host);
|
|
5343
5345
|
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");
|
|
5344
5346
|
const bindingIds = /* @__PURE__ */ new Set();
|
|
@@ -5363,11 +5365,11 @@ function parseSnapshot(value) {
|
|
|
5363
5365
|
});
|
|
5364
5366
|
return { host, bindings, commands };
|
|
5365
5367
|
}
|
|
5366
|
-
async function parseSource(
|
|
5367
|
-
const snapshot = record3(record3(
|
|
5368
|
+
async function parseSource(value2) {
|
|
5369
|
+
const snapshot = record3(record3(value2)?.snapshot);
|
|
5368
5370
|
if (!snapshot || typeof snapshot.repository !== "string" || typeof snapshot.commitSha !== "string" || typeof snapshot.treeDigest !== "string" || !Array.isArray(snapshot.files)) throw invalid("source");
|
|
5369
|
-
const files = snapshot.files.map((
|
|
5370
|
-
const file = record3(
|
|
5371
|
+
const files = snapshot.files.map((value22) => {
|
|
5372
|
+
const file = record3(value22);
|
|
5371
5373
|
if (!file || typeof file.path !== "string" || typeof file.content !== "string") throw invalid("source file");
|
|
5372
5374
|
return { path: file.path, content: file.content };
|
|
5373
5375
|
});
|
|
@@ -5394,19 +5396,19 @@ async function parseSource(value) {
|
|
|
5394
5396
|
if (digest !== snapshot.treeDigest) throw invalid("source digest");
|
|
5395
5397
|
return { ...source, treeDigest: digest, ...references.length ? { references } : {} };
|
|
5396
5398
|
}
|
|
5397
|
-
function parseReview(
|
|
5398
|
-
const review = record3(record3(
|
|
5399
|
+
function parseReview(value2) {
|
|
5400
|
+
const review = record3(record3(value2)?.review);
|
|
5399
5401
|
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");
|
|
5400
5402
|
return review;
|
|
5401
5403
|
}
|
|
5402
|
-
function parseCandidate(
|
|
5403
|
-
const candidate = record3(record3(
|
|
5404
|
+
function parseCandidate(value2) {
|
|
5405
|
+
const candidate = record3(record3(value2)?.candidate);
|
|
5404
5406
|
if (!candidate || typeof candidate.candidateId !== "string" || !/^ccand_[0-9a-f]{32}$/.test(candidate.candidateId) || !["submitted", "approved", "published", "failed"].includes(String(candidate.status))) {
|
|
5405
5407
|
throw invalid("candidate");
|
|
5406
5408
|
}
|
|
5407
5409
|
return { candidateId: candidate.candidateId, status: candidate.status };
|
|
5408
5410
|
}
|
|
5409
|
-
var record3 = (
|
|
5411
|
+
var record3 = (value2) => value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
|
|
5410
5412
|
var invalid = (part) => new CodeRuntimeControlError(`invalid Code runtime ${part} response`, 502, "invalid_response");
|
|
5411
5413
|
var RESERVED = /* @__PURE__ */ new Set([".git", ".odla", ".wrangler", "node_modules", "dist", "coverage"]);
|
|
5412
5414
|
var SECRET = /^(?:\.env(?:\..+)?|\.dev\.vars|credentials(?:\..+)?\.json|dev-token(?:\..+)?\.json)$/i;
|
|
@@ -5440,8 +5442,8 @@ function validateCodePatch(patch2, maxBytes) {
|
|
|
5440
5442
|
if (!paths.length || new Set(paths).size !== paths.length) throw new TypeError("patch has no diffs or repeats a path");
|
|
5441
5443
|
return paths;
|
|
5442
5444
|
}
|
|
5443
|
-
function validHeaderPath(
|
|
5444
|
-
return
|
|
5445
|
+
function validHeaderPath(value2, path, prefix) {
|
|
5446
|
+
return value2 === "/dev/null" || value2 === `${prefix}/${path}`;
|
|
5445
5447
|
}
|
|
5446
5448
|
function validateRelativePath(path) {
|
|
5447
5449
|
const parts = path.split("/");
|
|
@@ -5587,8 +5589,8 @@ function assertCodeBuildRecipe(recipe2) {
|
|
|
5587
5589
|
throw new TypeError("build recipe is malformed or exceeds its control bounds");
|
|
5588
5590
|
}
|
|
5589
5591
|
}
|
|
5590
|
-
function parseMemory(
|
|
5591
|
-
const match = /^([1-9][0-9]{0,4})([kmg])$/.exec(
|
|
5592
|
+
function parseMemory(value2) {
|
|
5593
|
+
const match = /^([1-9][0-9]{0,4})([kmg])$/.exec(value2.toLowerCase());
|
|
5592
5594
|
if (!match?.[1] || !match[2]) return 0;
|
|
5593
5595
|
const scale = match[2] === "k" ? 1024 : match[2] === "m" ? 1024 ** 2 : 1024 ** 3;
|
|
5594
5596
|
return Number(match[1]) * scale;
|
|
@@ -5823,14 +5825,14 @@ function normalizedRecipe(recipe2) {
|
|
|
5823
5825
|
expectedArtifacts: [...recipe2.expectedArtifacts ?? []].sort((left, right) => left.id.localeCompare(right.id)).map((artifact) => ({ id: artifact.id, path: artifact.path, maximumBytes: artifact.maximumBytes }))
|
|
5824
5826
|
};
|
|
5825
5827
|
}
|
|
5826
|
-
function digestJson(
|
|
5827
|
-
return digestBytes(JSON.stringify(
|
|
5828
|
+
function digestJson(value2) {
|
|
5829
|
+
return digestBytes(JSON.stringify(value2));
|
|
5828
5830
|
}
|
|
5829
|
-
function digestBytes(
|
|
5830
|
-
return `sha256:${(0, import_crypto3.createHash)("sha256").update(
|
|
5831
|
+
function digestBytes(value2) {
|
|
5832
|
+
return `sha256:${(0, import_crypto3.createHash)("sha256").update(value2).digest("hex")}`;
|
|
5831
5833
|
}
|
|
5832
|
-
function integer(
|
|
5833
|
-
return Number.isSafeInteger(
|
|
5834
|
+
function integer(value2, minimum, maximum) {
|
|
5835
|
+
return Number.isSafeInteger(value2) && value2 >= minimum && value2 <= maximum;
|
|
5834
5836
|
}
|
|
5835
5837
|
async function prepareRuntimeCheckpoint(input) {
|
|
5836
5838
|
const patch2 = await input.workspace.patch(256 * 1024);
|
|
@@ -5883,7 +5885,7 @@ async function prepareRuntimeCheckpoint(input) {
|
|
|
5883
5885
|
});
|
|
5884
5886
|
return { checkpoint, verification, review, note };
|
|
5885
5887
|
}
|
|
5886
|
-
var message = (
|
|
5888
|
+
var message = (value2) => (value2 instanceof Error ? value2.message : String(value2)).slice(0, 500);
|
|
5887
5889
|
var CodeRuntimeCheckpointManager = class {
|
|
5888
5890
|
constructor(options) {
|
|
5889
5891
|
this.options = options;
|
|
@@ -6077,7 +6079,7 @@ async function conversionPolicy(id, output) {
|
|
|
6077
6079
|
return { ...definition, digest: await conversionPolicyDigest(definition) };
|
|
6078
6080
|
}
|
|
6079
6081
|
async function registeredPolicy(id, registryId, values) {
|
|
6080
|
-
const mapping = Object.fromEntries(values.map((
|
|
6082
|
+
const mapping = Object.fromEntries(values.map((value2) => [value2, value2]));
|
|
6081
6083
|
return conversionPolicy(id, {
|
|
6082
6084
|
kind: "registered_id",
|
|
6083
6085
|
registryId,
|
|
@@ -6086,7 +6088,7 @@ async function registeredPolicy(id, registryId, values) {
|
|
|
6086
6088
|
}
|
|
6087
6089
|
async function conversionRegistry(policies, values) {
|
|
6088
6090
|
const registeredIds = Object.fromEntries(await Promise.all(Object.entries(values).map(async ([id, entries]) => {
|
|
6089
|
-
const mapping = Object.fromEntries(entries.map((
|
|
6091
|
+
const mapping = Object.fromEntries(entries.map((value2) => [value2, value2]));
|
|
6090
6092
|
return [id, { values: mapping, digest: await registeredIdRegistryDigest(mapping) }];
|
|
6091
6093
|
})));
|
|
6092
6094
|
return createConversionRegistry({ policies, registeredIds });
|
|
@@ -6110,8 +6112,8 @@ async function environment(input, options, tool) {
|
|
|
6110
6112
|
};
|
|
6111
6113
|
return { ingress, policy, fixedArgs, reader: ingress.control("reader"), runId: `${input.request.requestId}:${tool}` };
|
|
6112
6114
|
}
|
|
6113
|
-
function unsafe(base,
|
|
6114
|
-
return base.ingress.quarantinedOutput(
|
|
6115
|
+
function unsafe(base, value2, field) {
|
|
6116
|
+
return base.ingress.quarantinedOutput(value2, {
|
|
6115
6117
|
readers: base.reader.label.readers,
|
|
6116
6118
|
runId: `${base.runId}:${field}`
|
|
6117
6119
|
});
|
|
@@ -6191,14 +6193,14 @@ async function read(context, request2, options, policy) {
|
|
|
6191
6193
|
}
|
|
6192
6194
|
async function patch(context, request2, options, policy) {
|
|
6193
6195
|
exactKeys(request2.input, ["patch"]);
|
|
6194
|
-
const
|
|
6195
|
-
const paths = validateCodePatch(
|
|
6196
|
+
const value2 = stringField(request2.input, "patch");
|
|
6197
|
+
const paths = validateCodePatch(value2, options.maxPatchBytes ?? 256 * 1024);
|
|
6196
6198
|
if (paths.some((path) => options.readOnlyPrefixes?.some((prefix) => path === prefix || path.startsWith(`${prefix}/`)))) {
|
|
6197
6199
|
throw new TypeError("patch targets a read-only reference source");
|
|
6198
6200
|
}
|
|
6199
|
-
const allowed = await policy.patch(policyContext(context, request2, options, { patch:
|
|
6201
|
+
const allowed = await policy.patch(policyContext(context, request2, options, { patch: value2 }));
|
|
6200
6202
|
if (!allowed) return response(request2, false, "tool denied by CaMeL policy");
|
|
6201
|
-
await applyCodePatch(context.workspaceDir,
|
|
6203
|
+
await applyCodePatch(context.workspaceDir, value2, paths);
|
|
6202
6204
|
return response(request2, true, `Applied patch to ${paths.length} file(s).`, { paths });
|
|
6203
6205
|
}
|
|
6204
6206
|
async function recipe(context, request2, options, recipes, policy) {
|
|
@@ -6289,14 +6291,14 @@ function exactKeys(input, allowed) {
|
|
|
6289
6291
|
if (Object.keys(input).some((key) => !allowed.includes(key))) throw new TypeError("tool input contains an unsupported field");
|
|
6290
6292
|
}
|
|
6291
6293
|
function stringField(input, name) {
|
|
6292
|
-
const
|
|
6293
|
-
if (typeof
|
|
6294
|
-
return
|
|
6294
|
+
const value2 = input[name];
|
|
6295
|
+
if (typeof value2 !== "string" || !value2) throw new TypeError(`${name} must be a non-empty string`);
|
|
6296
|
+
return value2;
|
|
6295
6297
|
}
|
|
6296
|
-
function optionalInteger(
|
|
6297
|
-
if (
|
|
6298
|
-
if (!Number.isSafeInteger(
|
|
6299
|
-
return
|
|
6298
|
+
function optionalInteger(value2) {
|
|
6299
|
+
if (value2 === void 0) return void 0;
|
|
6300
|
+
if (!Number.isSafeInteger(value2) || value2 < 1) throw new TypeError("line bounds must be positive integers");
|
|
6301
|
+
return value2;
|
|
6300
6302
|
}
|
|
6301
6303
|
function response(request2, ok, content2, details) {
|
|
6302
6304
|
return { requestId: request2.requestId, ok, content: content2, ...details ? { details } : {} };
|
|
@@ -6342,9 +6344,9 @@ function codeLocalSource(payload) {
|
|
|
6342
6344
|
return source;
|
|
6343
6345
|
}
|
|
6344
6346
|
function codeCheckpointPayload(payload) {
|
|
6345
|
-
const
|
|
6346
|
-
if (!
|
|
6347
|
-
return
|
|
6347
|
+
const value2 = payload.checkpoint;
|
|
6348
|
+
if (!value2 || typeof value2 !== "object" || Array.isArray(value2)) throw new TypeError("resume checkpoint is missing");
|
|
6349
|
+
return value2;
|
|
6348
6350
|
}
|
|
6349
6351
|
function fakeCodeLease(command, metadata2) {
|
|
6350
6352
|
return {
|
|
@@ -6368,7 +6370,7 @@ function fakeCodeLease(command, metadata2) {
|
|
|
6368
6370
|
}
|
|
6369
6371
|
};
|
|
6370
6372
|
}
|
|
6371
|
-
var record22 = (
|
|
6373
|
+
var record22 = (value2) => value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
|
|
6372
6374
|
var SOURCE_LIMITS = { maxFiles: 2e4, maxBytes: 512 * 1024 * 1024 };
|
|
6373
6375
|
async function prepareRuntimeLocalSource(input) {
|
|
6374
6376
|
const { command, descriptor: descriptor2, available, repository, baseCommitSha, resume } = input;
|
|
@@ -6458,24 +6460,24 @@ async function appendCodeRuntimeEvent(control, command, event, refs) {
|
|
|
6458
6460
|
const bounded = event.type === "message" ? { ...event, body: event.body.trim().slice(0, 2e4) || `${event.actor} event` } : event;
|
|
6459
6461
|
await control.appendSessionEvent(command.sessionId, eventId, bounded);
|
|
6460
6462
|
}
|
|
6461
|
-
var digestRuntimeValue = (
|
|
6462
|
-
var runtimeErrorMessage = (
|
|
6463
|
-
var runtimeRecord = (
|
|
6464
|
-
var safeRuntimeJson = (
|
|
6463
|
+
var digestRuntimeValue = (value2) => `sha256:${(0, import_crypto4.createHash)("sha256").update(value2).digest("hex")}`;
|
|
6464
|
+
var runtimeErrorMessage = (value2) => value2 instanceof Error ? value2.message : String(value2);
|
|
6465
|
+
var runtimeRecord = (value2) => value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
|
|
6466
|
+
var safeRuntimeJson = (value2) => {
|
|
6465
6467
|
try {
|
|
6466
|
-
return JSON.stringify(
|
|
6468
|
+
return JSON.stringify(value2).slice(0, 1e4);
|
|
6467
6469
|
} catch {
|
|
6468
6470
|
return "[event]";
|
|
6469
6471
|
}
|
|
6470
6472
|
};
|
|
6471
|
-
function runtimeResultText(
|
|
6472
|
-
const record32 = runtimeRecord(
|
|
6473
|
+
function runtimeResultText(value2) {
|
|
6474
|
+
const record32 = runtimeRecord(value2);
|
|
6473
6475
|
if (record32 && typeof record32.text === "string") return record32.text.slice(0, 2e4);
|
|
6474
6476
|
if (record32 && typeof record32.error === "string") return `Pi failed: ${record32.error.slice(0, 19989)}`;
|
|
6475
6477
|
return null;
|
|
6476
6478
|
}
|
|
6477
|
-
function runtimeResultError(
|
|
6478
|
-
const record32 = runtimeRecord(
|
|
6479
|
+
function runtimeResultError(value2) {
|
|
6480
|
+
const record32 = runtimeRecord(value2);
|
|
6479
6481
|
return record32 && typeof record32.error === "string" && record32.error.trim() ? record32.error.trim().slice(0, 2e3) : null;
|
|
6480
6482
|
}
|
|
6481
6483
|
var CodePiRuntimeEngine = class {
|
|
@@ -6749,14 +6751,14 @@ var CodePiRuntimeEngine = class {
|
|
|
6749
6751
|
this.#active.delete(command.sessionId);
|
|
6750
6752
|
return result;
|
|
6751
6753
|
}
|
|
6752
|
-
async #failure(command, active,
|
|
6753
|
-
active.failure =
|
|
6754
|
+
async #failure(command, active, value2) {
|
|
6755
|
+
active.failure = value2.slice(0, 2e3);
|
|
6754
6756
|
if (active.acknowledged) {
|
|
6755
6757
|
await this.options.control.reportSessionFailure(command.sessionId, active.failure).catch(() => void 0);
|
|
6756
6758
|
}
|
|
6757
6759
|
}
|
|
6758
|
-
async #diagnostic(command, active,
|
|
6759
|
-
const detail =
|
|
6760
|
+
async #diagnostic(command, active, value2) {
|
|
6761
|
+
const detail = value2.trim().slice(0, 2e3) || "Pi runtime failed";
|
|
6760
6762
|
this.options.onDiagnostic?.(detail);
|
|
6761
6763
|
await this.#event(
|
|
6762
6764
|
command,
|
|
@@ -6841,6 +6843,7 @@ Usage:
|
|
|
6841
6843
|
odla-ai context save <name> [--platform <url>] [--app <id>] [--env <name>] [--json]
|
|
6842
6844
|
odla-ai context remove <name> --yes [--json]
|
|
6843
6845
|
odla-ai o11y status [--app <id>] [--context <name>] [--platform https://odla.ai] [--env prod] [--minutes 60] [--json]
|
|
6846
|
+
odla-ai platform status [--context <name>] [--platform https://odla.ai] [--email <odla-account>] [--json]
|
|
6844
6847
|
odla-ai whoami [--context <name>] [--platform https://odla.ai] [--json]
|
|
6845
6848
|
odla-ai runbook ask "<question>" [--app <id>] [--all] [--json]
|
|
6846
6849
|
odla-ai runbook search "<question>" [--app <id>] [--all] [--limit <n>] [--json]
|
|
@@ -6965,6 +6968,8 @@ Commands:
|
|
|
6965
6968
|
canary, collector ingest/scheduler trust, Cloudflare-owned
|
|
6966
6969
|
runtime metrics, and a machine verdict.
|
|
6967
6970
|
--json keeps auth progress on stderr for unattended agents.
|
|
6971
|
+
platform Read canonical fleet health, releases, provider load/freshness,
|
|
6972
|
+
explicit unknowns, and next actions through a read-only grant.
|
|
6968
6973
|
provision Register services, compose integrations, persist credentials, optionally push secrets.
|
|
6969
6974
|
smoke Verify credentials, public-config, composed schema, db aggregate, and integration probes.
|
|
6970
6975
|
skill Same installer; --agent accepts all, claude, codex, cursor,
|
|
@@ -7051,31 +7056,31 @@ async function requestHostedSecurityJson(options, path, init, action) {
|
|
|
7051
7056
|
}
|
|
7052
7057
|
return body;
|
|
7053
7058
|
}
|
|
7054
|
-
function hostedIdentifier(
|
|
7055
|
-
const result = optionalHostedText(
|
|
7059
|
+
function hostedIdentifier(value2, name) {
|
|
7060
|
+
const result = optionalHostedText(value2, name, 180);
|
|
7056
7061
|
if (!result || !/^[A-Za-z0-9][A-Za-z0-9._:-]*$/.test(result)) {
|
|
7057
7062
|
throw new Error(`${name} is invalid`);
|
|
7058
7063
|
}
|
|
7059
7064
|
return result;
|
|
7060
7065
|
}
|
|
7061
|
-
function positivePolicyVersion(
|
|
7062
|
-
if (!Number.isSafeInteger(
|
|
7066
|
+
function positivePolicyVersion(value2, name) {
|
|
7067
|
+
if (!Number.isSafeInteger(value2) || value2 < 1) {
|
|
7063
7068
|
throw new Error(`${name} is invalid`);
|
|
7064
7069
|
}
|
|
7065
|
-
return
|
|
7070
|
+
return value2;
|
|
7066
7071
|
}
|
|
7067
|
-
function optionalHostedText(
|
|
7068
|
-
if (
|
|
7069
|
-
if (typeof
|
|
7072
|
+
function optionalHostedText(value2, name, maxLength) {
|
|
7073
|
+
if (value2 === void 0 || value2 === null || value2 === "") return void 0;
|
|
7074
|
+
if (typeof value2 !== "string" || value2.length > maxLength || /[\u0000-\u001f\u007f]/.test(value2)) {
|
|
7070
7075
|
throw new Error(`${name} is invalid`);
|
|
7071
7076
|
}
|
|
7072
|
-
return
|
|
7077
|
+
return value2;
|
|
7073
7078
|
}
|
|
7074
|
-
function githubRepositoryName(
|
|
7075
|
-
if (typeof
|
|
7079
|
+
function githubRepositoryName(value2) {
|
|
7080
|
+
if (typeof value2 !== "string" || value2.length > 201) {
|
|
7076
7081
|
throw new Error("repository must be owner/name");
|
|
7077
7082
|
}
|
|
7078
|
-
const parts =
|
|
7083
|
+
const parts = value2.split("/");
|
|
7079
7084
|
const owner = parts[0] ?? "";
|
|
7080
7085
|
const name = (parts[1] ?? "").replace(/\.git$/i, "");
|
|
7081
7086
|
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 === "..") {
|
|
@@ -7083,10 +7088,10 @@ function githubRepositoryName(value) {
|
|
|
7083
7088
|
}
|
|
7084
7089
|
return `${owner}/${name}`;
|
|
7085
7090
|
}
|
|
7086
|
-
function trustedGitHubInstallUrl(
|
|
7091
|
+
function trustedGitHubInstallUrl(value2) {
|
|
7087
7092
|
let url;
|
|
7088
7093
|
try {
|
|
7089
|
-
url = new URL(
|
|
7094
|
+
url = new URL(value2);
|
|
7090
7095
|
} catch {
|
|
7091
7096
|
throw new Error("odla.ai returned an invalid GitHub installation URL");
|
|
7092
7097
|
}
|
|
@@ -7095,17 +7100,17 @@ function trustedGitHubInstallUrl(value) {
|
|
|
7095
7100
|
}
|
|
7096
7101
|
return url.toString();
|
|
7097
7102
|
}
|
|
7098
|
-
function hostedPollInterval(
|
|
7099
|
-
if (!Number.isSafeInteger(
|
|
7103
|
+
function hostedPollInterval(value2 = 2e3) {
|
|
7104
|
+
if (!Number.isSafeInteger(value2) || value2 < 100 || value2 > 3e4) {
|
|
7100
7105
|
throw new Error("poll interval must be 100-30000ms");
|
|
7101
7106
|
}
|
|
7102
|
-
return
|
|
7107
|
+
return value2;
|
|
7103
7108
|
}
|
|
7104
|
-
function hostedPollTimeout(
|
|
7105
|
-
if (!Number.isSafeInteger(
|
|
7109
|
+
function hostedPollTimeout(value2 = 10 * 6e4) {
|
|
7110
|
+
if (!Number.isSafeInteger(value2) || value2 < 1e3 || value2 > 60 * 6e4) {
|
|
7106
7111
|
throw new Error("poll timeout must be 1000-3600000ms");
|
|
7107
7112
|
}
|
|
7108
|
-
return
|
|
7113
|
+
return value2;
|
|
7109
7114
|
}
|
|
7110
7115
|
async function waitForHostedPoll(milliseconds, signal) {
|
|
7111
7116
|
if (signal?.aborted) throw signal.reason ?? new DOMException("aborted", "AbortError");
|
|
@@ -7117,16 +7122,16 @@ async function waitForHostedPoll(milliseconds, signal) {
|
|
|
7117
7122
|
}, { once: true });
|
|
7118
7123
|
});
|
|
7119
7124
|
}
|
|
7120
|
-
function isValidHostedSecurityPlan(
|
|
7121
|
-
if (!
|
|
7125
|
+
function isValidHostedSecurityPlan(value2, env) {
|
|
7126
|
+
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;
|
|
7122
7127
|
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;
|
|
7123
|
-
return validRoute(
|
|
7128
|
+
return validRoute(value2.routes?.discovery, "security.discovery") && validRoute(value2.routes?.validation, "security.validation");
|
|
7124
7129
|
}
|
|
7125
|
-
function hostedSecurityCredential(
|
|
7126
|
-
if (typeof
|
|
7130
|
+
function hostedSecurityCredential(value2) {
|
|
7131
|
+
if (typeof value2 !== "string" || value2.length < 8 || value2.length > 8192 || /\s|[\u0000-\u001f\u007f]/.test(value2)) {
|
|
7127
7132
|
throw new Error("Hosted security requires an injected odla developer token");
|
|
7128
7133
|
}
|
|
7129
|
-
return
|
|
7134
|
+
return value2;
|
|
7130
7135
|
}
|
|
7131
7136
|
|
|
7132
7137
|
// src/security-hosted-github.ts
|
|
@@ -7279,17 +7284,17 @@ async function prepareCodeLocalSource(cwd, repository, readHead = readGitHead) {
|
|
|
7279
7284
|
}
|
|
7280
7285
|
}
|
|
7281
7286
|
async function readGitHead(cwd) {
|
|
7282
|
-
const
|
|
7287
|
+
const value2 = await new Promise((accept, reject) => {
|
|
7283
7288
|
(0, import_node_child_process5.execFile)("git", ["rev-parse", "HEAD"], { cwd, encoding: "utf8", maxBuffer: 16384 }, (error, stdout) => {
|
|
7284
7289
|
if (error) reject(new Error("code connect requires a Git checkout with an initial commit"));
|
|
7285
7290
|
else accept(stdout.trim());
|
|
7286
7291
|
});
|
|
7287
7292
|
});
|
|
7288
|
-
if (!/^[0-9a-f]{40}$/.test(
|
|
7289
|
-
return
|
|
7293
|
+
if (!/^[0-9a-f]{40}$/.test(value2)) throw new Error("code connect could not resolve the checkout HEAD commit");
|
|
7294
|
+
return value2;
|
|
7290
7295
|
}
|
|
7291
|
-
function digestText(
|
|
7292
|
-
return `sha256:${(0, import_node_crypto.createHash)("sha256").update(
|
|
7296
|
+
function digestText(value2) {
|
|
7297
|
+
return `sha256:${(0, import_node_crypto.createHash)("sha256").update(value2).digest("hex")}`;
|
|
7293
7298
|
}
|
|
7294
7299
|
|
|
7295
7300
|
// src/code-images.ts
|
|
@@ -7560,8 +7565,8 @@ async function runCodeRuntime(input) {
|
|
|
7560
7565
|
for (const [name, handler] of handlers) process.removeListener(name, handler);
|
|
7561
7566
|
}
|
|
7562
7567
|
}
|
|
7563
|
-
function parseConnection(
|
|
7564
|
-
const root = record4(
|
|
7568
|
+
function parseConnection(value2, appId, appEnv) {
|
|
7569
|
+
const root = record4(value2);
|
|
7565
7570
|
const host = record4(root?.host);
|
|
7566
7571
|
const offer = record4(root?.offer);
|
|
7567
7572
|
const binding = record4(root?.binding);
|
|
@@ -7570,12 +7575,12 @@ function parseConnection(value, appId, appEnv) {
|
|
|
7570
7575
|
}
|
|
7571
7576
|
return root;
|
|
7572
7577
|
}
|
|
7573
|
-
function apiFailure(action, status,
|
|
7574
|
-
const message2 = record4(record4(
|
|
7578
|
+
function apiFailure(action, status, value2) {
|
|
7579
|
+
const message2 = record4(record4(value2)?.error)?.message;
|
|
7575
7580
|
return `${action} failed (${status})${typeof message2 === "string" ? `: ${message2}` : ""}`;
|
|
7576
7581
|
}
|
|
7577
|
-
function record4(
|
|
7578
|
-
return
|
|
7582
|
+
function record4(value2) {
|
|
7583
|
+
return value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
|
|
7579
7584
|
}
|
|
7580
7585
|
|
|
7581
7586
|
// src/code-command.ts
|
|
@@ -7634,8 +7639,8 @@ function developerTokenStatus(context, parsed, now = Date.now()) {
|
|
|
7634
7639
|
cacheStatus
|
|
7635
7640
|
};
|
|
7636
7641
|
}
|
|
7637
|
-
function clean3(
|
|
7638
|
-
const normalized =
|
|
7642
|
+
function clean3(value2) {
|
|
7643
|
+
const normalized = value2?.trim();
|
|
7639
7644
|
return normalized || void 0;
|
|
7640
7645
|
}
|
|
7641
7646
|
|
|
@@ -7784,8 +7789,8 @@ async function request(ctx, method, path, body) {
|
|
|
7784
7789
|
throw new Error(`discuss ${method} ${path} failed: ${data.error ?? `registry returned ${res.status}`}`);
|
|
7785
7790
|
return data;
|
|
7786
7791
|
}
|
|
7787
|
-
function emit(ctx,
|
|
7788
|
-
if (ctx.json) ctx.out.log(JSON.stringify(
|
|
7792
|
+
function emit(ctx, value2, human) {
|
|
7793
|
+
if (ctx.json) ctx.out.log(JSON.stringify(value2, null, 2));
|
|
7789
7794
|
else human();
|
|
7790
7795
|
}
|
|
7791
7796
|
var state = (topic) => topic.resolved ? "resolved" : "open";
|
|
@@ -7830,8 +7835,8 @@ async function discussList(ctx, parsed) {
|
|
|
7830
7835
|
["limit", "limit"],
|
|
7831
7836
|
["offset", "offset"]
|
|
7832
7837
|
]) {
|
|
7833
|
-
const
|
|
7834
|
-
if (
|
|
7838
|
+
const value2 = stringOpt(parsed.options[flag]);
|
|
7839
|
+
if (value2) query.set(param, value2);
|
|
7835
7840
|
}
|
|
7836
7841
|
const qs = query.toString();
|
|
7837
7842
|
const page = await request(ctx, "GET", `/topics${qs ? `?${qs}` : ""}`);
|
|
@@ -8028,11 +8033,11 @@ var MAX_CONSECUTIVE_FAILURES = 5;
|
|
|
8028
8033
|
var MAX_BACKOFF_MS = 3e4;
|
|
8029
8034
|
function numberOpt2(parsed, flag, fallback) {
|
|
8030
8035
|
const raw = stringOpt(parsed.options[flag]);
|
|
8031
|
-
const
|
|
8032
|
-
return Number.isFinite(
|
|
8036
|
+
const value2 = raw == null ? NaN : Number(raw);
|
|
8037
|
+
return Number.isFinite(value2) && value2 > 0 ? value2 : fallback;
|
|
8033
8038
|
}
|
|
8034
|
-
function jsonl(ctx, parsed,
|
|
8035
|
-
if (parsed.options.jsonl === true) ctx.out.log(JSON.stringify({ v: 1, ...
|
|
8039
|
+
function jsonl(ctx, parsed, value2) {
|
|
8040
|
+
if (parsed.options.jsonl === true) ctx.out.log(JSON.stringify({ v: 1, ...value2 }));
|
|
8036
8041
|
}
|
|
8037
8042
|
async function discussWatch(ctx, topicId, parsed) {
|
|
8038
8043
|
if (ctx.json && parsed.options.jsonl === true) throw new Error("--json and --jsonl cannot be combined");
|
|
@@ -8294,13 +8299,13 @@ async function pmRequest(ctx, method, path, body) {
|
|
|
8294
8299
|
function collectFields(parsed, allowClear) {
|
|
8295
8300
|
const out = {};
|
|
8296
8301
|
for (const [flag, spec] of Object.entries(FIELD_MAP)) {
|
|
8297
|
-
const
|
|
8298
|
-
if (
|
|
8299
|
-
if (
|
|
8302
|
+
const value2 = parsed.options[flag];
|
|
8303
|
+
if (value2 === void 0 || value2 === true) continue;
|
|
8304
|
+
if (value2 === false) {
|
|
8300
8305
|
if (allowClear) out[spec.key] = null;
|
|
8301
8306
|
continue;
|
|
8302
8307
|
}
|
|
8303
|
-
const text = stringOpt(
|
|
8308
|
+
const text = stringOpt(value2);
|
|
8304
8309
|
out[spec.key] = spec.num ? Number(text) : text;
|
|
8305
8310
|
}
|
|
8306
8311
|
return out;
|
|
@@ -8321,8 +8326,8 @@ function statusCol(entity, r) {
|
|
|
8321
8326
|
function printRecord(ctx, entity, r) {
|
|
8322
8327
|
ctx.out.log(`${r.id} [${statusCol(entity, r)}] ${r.appId} ${r.title ?? ""}`);
|
|
8323
8328
|
}
|
|
8324
|
-
function emit2(ctx,
|
|
8325
|
-
if (ctx.json) ctx.out.log(JSON.stringify(
|
|
8329
|
+
function emit2(ctx, value2, human) {
|
|
8330
|
+
if (ctx.json) ctx.out.log(JSON.stringify(value2, null, 2));
|
|
8326
8331
|
else human();
|
|
8327
8332
|
}
|
|
8328
8333
|
async function pmList(ctx, entity, parsed) {
|
|
@@ -8368,8 +8373,8 @@ async function pmAdd(ctx, entity, parsed) {
|
|
|
8368
8373
|
emit2(ctx, res, () => ctx.out.log(`created ${entity} ${res.id}`));
|
|
8369
8374
|
}
|
|
8370
8375
|
async function pmGet(ctx, entity, id) {
|
|
8371
|
-
const { record:
|
|
8372
|
-
emit2(ctx,
|
|
8376
|
+
const { record: record8 } = await pmRequest(ctx, "GET", `/${entity}/${encodeURIComponent(id)}`);
|
|
8377
|
+
emit2(ctx, record8, () => printRecord(ctx, entity, record8));
|
|
8373
8378
|
}
|
|
8374
8379
|
async function pmSet(ctx, entity, id, parsed) {
|
|
8375
8380
|
const patch2 = collectEntityFields(entity, parsed, true);
|
|
@@ -8414,9 +8419,9 @@ async function pmHandoff(ctx, parsed) {
|
|
|
8414
8419
|
]);
|
|
8415
8420
|
const handoff = {
|
|
8416
8421
|
appId,
|
|
8417
|
-
unmetGoals: goals.filter((
|
|
8418
|
-
activeTasks: tasks.filter((
|
|
8419
|
-
openBugs: bugs.filter((
|
|
8422
|
+
unmetGoals: goals.filter((record8) => record8.status !== "met"),
|
|
8423
|
+
activeTasks: tasks.filter((record8) => record8.column !== "done"),
|
|
8424
|
+
openBugs: bugs.filter((record8) => record8.status !== "fixed" && record8.status !== "wontfix")
|
|
8420
8425
|
};
|
|
8421
8426
|
const result = {
|
|
8422
8427
|
...handoff,
|
|
@@ -8435,10 +8440,10 @@ async function pmHandoff(ctx, parsed) {
|
|
|
8435
8440
|
]) {
|
|
8436
8441
|
ctx.out.log(`${label}:`);
|
|
8437
8442
|
if (!records.length) ctx.out.log("- (none)");
|
|
8438
|
-
else for (const
|
|
8443
|
+
else for (const record8 of records) printRecord(
|
|
8439
8444
|
ctx,
|
|
8440
8445
|
label === "unmet goals" ? "goal" : label === "active tasks" ? "task" : "bug",
|
|
8441
|
-
|
|
8446
|
+
record8
|
|
8442
8447
|
);
|
|
8443
8448
|
}
|
|
8444
8449
|
});
|
|
@@ -8586,6 +8591,113 @@ async function pmCommand(parsed, deps = {}) {
|
|
|
8586
8591
|
}
|
|
8587
8592
|
}
|
|
8588
8593
|
|
|
8594
|
+
// src/platform-output.ts
|
|
8595
|
+
function printPlatformStatus(status, out) {
|
|
8596
|
+
out.log(`platform ${status.verdict.status} ${status.observedAt}`);
|
|
8597
|
+
out.log(
|
|
8598
|
+
`fleet ${status.summary.healthy}/${status.summary.services} healthy ${status.summary.required} required ${status.summary.unreachable} unreachable ${status.summary.notConfigured} not configured`
|
|
8599
|
+
);
|
|
8600
|
+
out.log(`catalog ${status.catalog.revision}`);
|
|
8601
|
+
out.log(
|
|
8602
|
+
"service required health probe ms version provider age requests errors cpu p99 us wall p99 us"
|
|
8603
|
+
);
|
|
8604
|
+
for (const service of status.services) {
|
|
8605
|
+
const metrics = service.provider.metrics;
|
|
8606
|
+
out.log([
|
|
8607
|
+
service.id,
|
|
8608
|
+
service.required ? "yes" : "no",
|
|
8609
|
+
service.health.status,
|
|
8610
|
+
value(service.health.latencyMs),
|
|
8611
|
+
service.release.observedVersionId ?? "unknown",
|
|
8612
|
+
service.provider.status,
|
|
8613
|
+
age(service.provider.ageMs),
|
|
8614
|
+
value(metrics?.requests),
|
|
8615
|
+
value(metrics?.errors),
|
|
8616
|
+
value(metrics?.cpuTimeP99),
|
|
8617
|
+
value(metrics?.wallTimeP99)
|
|
8618
|
+
].join(" "));
|
|
8619
|
+
}
|
|
8620
|
+
if (status.verdict.reasons.length) {
|
|
8621
|
+
out.log(`reasons ${status.verdict.reasons.join(", ")}`);
|
|
8622
|
+
}
|
|
8623
|
+
for (const action of status.nextActions) {
|
|
8624
|
+
out.log(`next ${action.service} ${action.code} ${action.message}`);
|
|
8625
|
+
}
|
|
8626
|
+
}
|
|
8627
|
+
function value(input) {
|
|
8628
|
+
return input === null || input === void 0 ? "unknown" : String(input);
|
|
8629
|
+
}
|
|
8630
|
+
function age(input) {
|
|
8631
|
+
if (input === null) return "unknown";
|
|
8632
|
+
if (input < 1e3) return `${input}ms`;
|
|
8633
|
+
if (input < 6e4) return `${Math.round(input / 1e3)}s`;
|
|
8634
|
+
return `${Math.round(input / 6e4)}m`;
|
|
8635
|
+
}
|
|
8636
|
+
|
|
8637
|
+
// src/platform-command.ts
|
|
8638
|
+
async function platformCommand(parsed, deps = {}) {
|
|
8639
|
+
assertArgs(
|
|
8640
|
+
parsed,
|
|
8641
|
+
["config", "context", "platform", "token", "email", "open", "json"],
|
|
8642
|
+
2
|
|
8643
|
+
);
|
|
8644
|
+
const action = parsed.positionals[1];
|
|
8645
|
+
if (action !== "status") {
|
|
8646
|
+
throw new Error(
|
|
8647
|
+
`unknown platform action "${action ?? ""}". Try "odla-ai platform status --json".`
|
|
8648
|
+
);
|
|
8649
|
+
}
|
|
8650
|
+
const context = await resolveOperatorContext(parsed, {
|
|
8651
|
+
allowMissingConfig: true
|
|
8652
|
+
});
|
|
8653
|
+
const platform = context.platform.value;
|
|
8654
|
+
const doFetch = deps.fetch ?? fetch;
|
|
8655
|
+
const out = deps.stdout ?? console;
|
|
8656
|
+
const token = await resolveAdminPlatformToken({
|
|
8657
|
+
platform,
|
|
8658
|
+
scope: "platform:status:read",
|
|
8659
|
+
token: stringOpt(parsed.options.token),
|
|
8660
|
+
tokenFile: context.credentials.scopedTokenFile,
|
|
8661
|
+
email: stringOpt(parsed.options.email),
|
|
8662
|
+
open: parsed.options.open === false ? false : parsed.options.open === true ? true : void 0,
|
|
8663
|
+
fetch: doFetch,
|
|
8664
|
+
stdout: out,
|
|
8665
|
+
openApprovalUrl: deps.openUrl,
|
|
8666
|
+
label: "odla CLI (platform fleet status)"
|
|
8667
|
+
});
|
|
8668
|
+
const response2 = await doFetch(`${platform}/registry/platform/status`, {
|
|
8669
|
+
headers: { authorization: `Bearer ${token}` }
|
|
8670
|
+
});
|
|
8671
|
+
const body = await response2.json().catch(() => null);
|
|
8672
|
+
if (!response2.ok) {
|
|
8673
|
+
throw new Error(
|
|
8674
|
+
`read platform status failed (HTTP ${response2.status}): ${apiMessage(body)}`
|
|
8675
|
+
);
|
|
8676
|
+
}
|
|
8677
|
+
if (!isPlatformStatus(body)) {
|
|
8678
|
+
throw new Error("platform returned an invalid odla.platform-status/v1 envelope");
|
|
8679
|
+
}
|
|
8680
|
+
if (parsed.options.json === true) {
|
|
8681
|
+
out.log(JSON.stringify(body, null, 2));
|
|
8682
|
+
} else {
|
|
8683
|
+
printPlatformStatus(body, out);
|
|
8684
|
+
}
|
|
8685
|
+
}
|
|
8686
|
+
function isPlatformStatus(value2) {
|
|
8687
|
+
if (!record5(value2) || value2.schemaVersion !== "odla.platform-status/v1") return false;
|
|
8688
|
+
if (!record5(value2.verdict) || !Array.isArray(value2.verdict.reasons)) return false;
|
|
8689
|
+
if (!record5(value2.catalog) || !record5(value2.summary)) return false;
|
|
8690
|
+
return Array.isArray(value2.services) && Array.isArray(value2.nextActions);
|
|
8691
|
+
}
|
|
8692
|
+
function apiMessage(value2) {
|
|
8693
|
+
if (!record5(value2)) return "request failed";
|
|
8694
|
+
const error = record5(value2.error) ? value2.error : value2;
|
|
8695
|
+
return typeof error.message === "string" ? error.message : typeof error.code === "string" ? error.code : "request failed";
|
|
8696
|
+
}
|
|
8697
|
+
function record5(value2) {
|
|
8698
|
+
return !!value2 && typeof value2 === "object" && !Array.isArray(value2);
|
|
8699
|
+
}
|
|
8700
|
+
|
|
8589
8701
|
// src/o11y-verdict.ts
|
|
8590
8702
|
function statusVerdict(reads) {
|
|
8591
8703
|
const reasons = [];
|
|
@@ -8623,7 +8735,7 @@ function statusVerdict(reads) {
|
|
|
8623
8735
|
severity: "degraded"
|
|
8624
8736
|
});
|
|
8625
8737
|
}
|
|
8626
|
-
const performance =
|
|
8738
|
+
const performance = record6(reads.liveSync.body.performance) ? reads.liveSync.body.performance : null;
|
|
8627
8739
|
if (performance?.status === "unavailable") {
|
|
8628
8740
|
reasons.push({
|
|
8629
8741
|
source: "liveSync",
|
|
@@ -8704,11 +8816,11 @@ function statusVerdict(reads) {
|
|
|
8704
8816
|
reasons
|
|
8705
8817
|
};
|
|
8706
8818
|
}
|
|
8707
|
-
function
|
|
8708
|
-
return Boolean(
|
|
8819
|
+
function record6(value2) {
|
|
8820
|
+
return Boolean(value2) && typeof value2 === "object" && !Array.isArray(value2);
|
|
8709
8821
|
}
|
|
8710
|
-
function numeric2(
|
|
8711
|
-
return typeof
|
|
8822
|
+
function numeric2(value2) {
|
|
8823
|
+
return typeof value2 === "number" && Number.isFinite(value2) ? value2 : 0;
|
|
8712
8824
|
}
|
|
8713
8825
|
function collectorReason(read3, fallback) {
|
|
8714
8826
|
const reasons = read3.body.reasons;
|
|
@@ -8732,7 +8844,7 @@ function printO11yStatus(status, out) {
|
|
|
8732
8844
|
out.log(
|
|
8733
8845
|
`o11y status ${status.scope.appId}/${status.scope.env} (${status.scope.minutes}m)`
|
|
8734
8846
|
);
|
|
8735
|
-
const routes = Array.isArray(status.application.body.routes) ? status.application.body.routes.filter(
|
|
8847
|
+
const routes = Array.isArray(status.application.body.routes) ? status.application.body.routes.filter(record7) : [];
|
|
8736
8848
|
const requests = routes.reduce(
|
|
8737
8849
|
(total, row) => total + numeric3(row.requests),
|
|
8738
8850
|
0
|
|
@@ -8744,39 +8856,39 @@ function printO11yStatus(status, out) {
|
|
|
8744
8856
|
out.log(
|
|
8745
8857
|
`application ${status.application.httpStatus} ${requests} requests ${errors} errors`
|
|
8746
8858
|
);
|
|
8747
|
-
const versions = Array.isArray(status.applicationVersions.body.rows) ? status.applicationVersions.body.rows.filter(
|
|
8859
|
+
const versions = Array.isArray(status.applicationVersions.body.rows) ? status.applicationVersions.body.rows.filter(record7) : [];
|
|
8748
8860
|
out.log(
|
|
8749
8861
|
`application-versions ${status.applicationVersions.httpStatus} ${versions.length ? versions.slice(0, 5).map(
|
|
8750
8862
|
(row) => `${String(row.value || "(unattributed)")}:${numeric3(row.requests)}`
|
|
8751
8863
|
).join(", ") : "none observed"}`
|
|
8752
8864
|
);
|
|
8753
8865
|
out.log(liveSyncLine(status.liveSync));
|
|
8754
|
-
const canaryDurations =
|
|
8866
|
+
const canaryDurations = record7(status.canary.body.durationsMs) ? status.canary.body.durationsMs : {};
|
|
8755
8867
|
out.log(
|
|
8756
8868
|
`canary ${status.canary.httpStatus} ${String(status.canary.body.status ?? status.canary.body.error ?? "unavailable")} ${optionalNumeric(canaryDurations.publishToVisibleMs)} publish-to-visible`
|
|
8757
8869
|
);
|
|
8758
|
-
const collectorIngest =
|
|
8759
|
-
const collectorStorage =
|
|
8870
|
+
const collectorIngest = record7(status.collector.body.ingest) ? status.collector.body.ingest : {};
|
|
8871
|
+
const collectorStorage = record7(collectorIngest.storage) ? collectorIngest.storage : {};
|
|
8760
8872
|
out.log(
|
|
8761
8873
|
`collector ${status.collector.httpStatus} ${String(status.collector.body.status ?? status.collector.body.error ?? "unavailable")} ${numeric3(collectorStorage.affectedPoints)} affected points`
|
|
8762
8874
|
);
|
|
8763
|
-
const providerMetrics =
|
|
8764
|
-
const providerCapacity =
|
|
8765
|
-
const workerMemory =
|
|
8875
|
+
const providerMetrics = record7(status.provider.body.metrics) ? status.provider.body.metrics : {};
|
|
8876
|
+
const providerCapacity = record7(status.provider.body.capacity) ? status.provider.body.capacity : {};
|
|
8877
|
+
const workerMemory = record7(providerCapacity.memory) ? providerCapacity.memory : {};
|
|
8766
8878
|
out.log(
|
|
8767
8879
|
`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`
|
|
8768
8880
|
);
|
|
8769
8881
|
for (const line of providerCapacityLines(status.providerCapacity)) {
|
|
8770
8882
|
out.log(line);
|
|
8771
8883
|
}
|
|
8772
|
-
const coverage =
|
|
8773
|
-
const coverageCounts =
|
|
8774
|
-
const coverageBudget =
|
|
8884
|
+
const coverage = record7(status.providerReconciliation.body.comparison) ? status.providerReconciliation.body.comparison : {};
|
|
8885
|
+
const coverageCounts = record7(status.providerReconciliation.body.counts) ? status.providerReconciliation.body.counts : {};
|
|
8886
|
+
const coverageBudget = record7(status.providerReconciliation.body.budget) ? status.providerReconciliation.body.budget : {};
|
|
8775
8887
|
out.log(
|
|
8776
8888
|
`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`
|
|
8777
8889
|
);
|
|
8778
8890
|
const providerPoints = Array.isArray(status.providerHistory.body.points) ? status.providerHistory.body.points.length : 0;
|
|
8779
|
-
const providerFreshness =
|
|
8891
|
+
const providerFreshness = record7(status.providerHistory.body.freshness) ? status.providerHistory.body.freshness : {};
|
|
8780
8892
|
out.log(
|
|
8781
8893
|
`cloudflare-history ${status.providerHistory.httpStatus} ${String(status.providerHistory.body.status ?? status.providerHistory.body.error ?? "unavailable")} ${providerPoints} snapshots ${optionalAge(providerFreshness.ageMs)} old`
|
|
8782
8894
|
);
|
|
@@ -8785,17 +8897,17 @@ function printO11yStatus(status, out) {
|
|
|
8785
8897
|
);
|
|
8786
8898
|
}
|
|
8787
8899
|
function providerCapacityLines(read3) {
|
|
8788
|
-
const resources =
|
|
8789
|
-
const durableObjects =
|
|
8790
|
-
const periodic =
|
|
8791
|
-
const storage =
|
|
8792
|
-
const d1 =
|
|
8793
|
-
const d1Activity =
|
|
8794
|
-
const d1Storage =
|
|
8795
|
-
const d1Latency =
|
|
8796
|
-
const r2 =
|
|
8797
|
-
const r2Operations =
|
|
8798
|
-
const r2Storage =
|
|
8900
|
+
const resources = record7(read3.body.resources) ? read3.body.resources : {};
|
|
8901
|
+
const durableObjects = record7(resources.durableObjects) ? resources.durableObjects : {};
|
|
8902
|
+
const periodic = record7(durableObjects.periodic) ? durableObjects.periodic : {};
|
|
8903
|
+
const storage = record7(durableObjects.sqliteStorage) ? durableObjects.sqliteStorage : {};
|
|
8904
|
+
const d1 = record7(resources.d1) ? resources.d1 : {};
|
|
8905
|
+
const d1Activity = record7(d1.activity) ? d1.activity : {};
|
|
8906
|
+
const d1Storage = record7(d1.storage) ? d1.storage : {};
|
|
8907
|
+
const d1Latency = record7(d1Activity.latency) ? d1Activity.latency : {};
|
|
8908
|
+
const r2 = record7(resources.r2) ? resources.r2 : {};
|
|
8909
|
+
const r2Operations = record7(r2.operations) ? r2.operations : {};
|
|
8910
|
+
const r2Storage = record7(r2.storage) ? r2.storage : {};
|
|
8799
8911
|
const status = String(
|
|
8800
8912
|
read3.body.status ?? read3.body.error ?? "unavailable"
|
|
8801
8913
|
);
|
|
@@ -8806,42 +8918,42 @@ function providerCapacityLines(read3) {
|
|
|
8806
8918
|
];
|
|
8807
8919
|
}
|
|
8808
8920
|
function liveSyncLine(read3) {
|
|
8809
|
-
const performance =
|
|
8810
|
-
const commitToSend =
|
|
8921
|
+
const performance = record7(read3.body.performance) ? read3.body.performance : {};
|
|
8922
|
+
const commitToSend = record7(performance.commitToSend) ? performance.commitToSend : {};
|
|
8811
8923
|
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`;
|
|
8812
8924
|
}
|
|
8813
|
-
function
|
|
8814
|
-
return Boolean(
|
|
8925
|
+
function record7(value2) {
|
|
8926
|
+
return Boolean(value2) && typeof value2 === "object" && !Array.isArray(value2);
|
|
8815
8927
|
}
|
|
8816
|
-
function numeric3(
|
|
8817
|
-
return typeof
|
|
8928
|
+
function numeric3(value2) {
|
|
8929
|
+
return typeof value2 === "number" && Number.isFinite(value2) ? value2 : 0;
|
|
8818
8930
|
}
|
|
8819
|
-
function optionalNumeric(
|
|
8820
|
-
return typeof
|
|
8931
|
+
function optionalNumeric(value2) {
|
|
8932
|
+
return typeof value2 === "number" && Number.isFinite(value2) ? `${value2} ms` : "\u2014";
|
|
8821
8933
|
}
|
|
8822
|
-
function optionalAge(
|
|
8823
|
-
if (typeof
|
|
8824
|
-
return `${Math.max(0, Math.round(
|
|
8934
|
+
function optionalAge(value2) {
|
|
8935
|
+
if (typeof value2 !== "number" || !Number.isFinite(value2)) return "unknown";
|
|
8936
|
+
return `${Math.max(0, Math.round(value2 / 1e3))}s`;
|
|
8825
8937
|
}
|
|
8826
|
-
function optionalPercent(
|
|
8827
|
-
return typeof
|
|
8938
|
+
function optionalPercent(value2) {
|
|
8939
|
+
return typeof value2 === "number" && Number.isFinite(value2) ? `${Math.round(value2 * 100)}%` : "\u2014";
|
|
8828
8940
|
}
|
|
8829
|
-
function optionalBytes(
|
|
8830
|
-
if (typeof
|
|
8831
|
-
if (
|
|
8832
|
-
return `${(
|
|
8941
|
+
function optionalBytes(value2) {
|
|
8942
|
+
if (typeof value2 !== "number" || !Number.isFinite(value2)) return "\u2014";
|
|
8943
|
+
if (value2 >= 1024 * 1024 * 1024) {
|
|
8944
|
+
return `${(value2 / (1024 * 1024 * 1024)).toFixed(2)} GiB`;
|
|
8833
8945
|
}
|
|
8834
|
-
if (
|
|
8835
|
-
return `${(
|
|
8946
|
+
if (value2 >= 1024 * 1024) {
|
|
8947
|
+
return `${(value2 / (1024 * 1024)).toFixed(1)} MiB`;
|
|
8836
8948
|
}
|
|
8837
|
-
if (
|
|
8838
|
-
return `${Math.round(
|
|
8949
|
+
if (value2 >= 1024) return `${(value2 / 1024).toFixed(1)} KiB`;
|
|
8950
|
+
return `${Math.round(value2)} B`;
|
|
8839
8951
|
}
|
|
8840
|
-
function optionalCount(
|
|
8841
|
-
return typeof
|
|
8952
|
+
function optionalCount(value2, unit) {
|
|
8953
|
+
return typeof value2 === "number" && Number.isFinite(value2) ? `${value2} ${unit}` : `\u2014 ${unit}`;
|
|
8842
8954
|
}
|
|
8843
|
-
function optionalAgeSeconds(
|
|
8844
|
-
return typeof
|
|
8955
|
+
function optionalAgeSeconds(value2) {
|
|
8956
|
+
return typeof value2 === "number" && Number.isFinite(value2) ? `${Math.max(0, Math.round(value2))}s` : "unknown";
|
|
8845
8957
|
}
|
|
8846
8958
|
|
|
8847
8959
|
// src/o11y-command.ts
|
|
@@ -8971,11 +9083,11 @@ async function o11yCommand(parsed, deps = {}) {
|
|
|
8971
9083
|
}
|
|
8972
9084
|
printO11yStatus(status, out);
|
|
8973
9085
|
}
|
|
8974
|
-
function statusMinutes(
|
|
8975
|
-
if (!Number.isSafeInteger(
|
|
9086
|
+
function statusMinutes(value2) {
|
|
9087
|
+
if (!Number.isSafeInteger(value2) || value2 < 1 || value2 > 7 * 24 * 60) {
|
|
8976
9088
|
throw new Error("--minutes must be an integer from 1 to 10080");
|
|
8977
9089
|
}
|
|
8978
|
-
return
|
|
9090
|
+
return value2;
|
|
8979
9091
|
}
|
|
8980
9092
|
async function read2(url, headers, doFetch) {
|
|
8981
9093
|
const response2 = await doFetch(url, { headers });
|
|
@@ -8983,8 +9095,8 @@ async function read2(url, headers, doFetch) {
|
|
|
8983
9095
|
let body = {};
|
|
8984
9096
|
if (text) {
|
|
8985
9097
|
try {
|
|
8986
|
-
const
|
|
8987
|
-
body =
|
|
9098
|
+
const value2 = JSON.parse(text);
|
|
9099
|
+
body = value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : { value: value2 };
|
|
8988
9100
|
} catch {
|
|
8989
9101
|
body = { message: text.slice(0, 300) };
|
|
8990
9102
|
}
|
|
@@ -9038,8 +9150,8 @@ async function postJson2(doFetch, url, bearer, body) {
|
|
|
9038
9150
|
if (!res.ok) throw new Error(`${new URL(url).pathname} failed: ${res.status} ${await responseText(res)}`);
|
|
9039
9151
|
return res.json().catch(() => ({}));
|
|
9040
9152
|
}
|
|
9041
|
-
function isRecord7(
|
|
9042
|
-
return
|
|
9153
|
+
function isRecord7(value2) {
|
|
9154
|
+
return value2 !== null && typeof value2 === "object" && !Array.isArray(value2);
|
|
9043
9155
|
}
|
|
9044
9156
|
async function responseText(res) {
|
|
9045
9157
|
try {
|
|
@@ -9172,14 +9284,14 @@ async function postJson3(doFetch, url, bearer, body) {
|
|
|
9172
9284
|
});
|
|
9173
9285
|
if (!res.ok) throw new Error(`${new URL(url).pathname} failed: ${res.status} ${await safeText5(res)}`);
|
|
9174
9286
|
}
|
|
9175
|
-
function normalizeClerkConfig(
|
|
9176
|
-
if (!
|
|
9177
|
-
if (typeof
|
|
9178
|
-
const publishableKey2 = envValue(
|
|
9287
|
+
function normalizeClerkConfig(value2) {
|
|
9288
|
+
if (!value2) return null;
|
|
9289
|
+
if (typeof value2 === "string") {
|
|
9290
|
+
const publishableKey2 = envValue(value2);
|
|
9179
9291
|
return publishableKey2 ? { publishableKey: publishableKey2 } : null;
|
|
9180
9292
|
}
|
|
9181
|
-
if (typeof
|
|
9182
|
-
const cfg =
|
|
9293
|
+
if (typeof value2 !== "object") return null;
|
|
9294
|
+
const cfg = value2;
|
|
9183
9295
|
const publishableKey = envValue(cfg.publishableKey);
|
|
9184
9296
|
return publishableKey ? { publishableKey, ...cfg.audience ? { audience: cfg.audience } : {}, ...cfg.mode ? { mode: cfg.mode } : {} } : null;
|
|
9185
9297
|
}
|
|
@@ -9456,6 +9568,7 @@ var COMMAND_SURFACE = {
|
|
|
9456
9568
|
help: {},
|
|
9457
9569
|
init: {},
|
|
9458
9570
|
o11y: { status: {} },
|
|
9571
|
+
platform: { status: {} },
|
|
9459
9572
|
pm: {
|
|
9460
9573
|
...PM_ENTITIES,
|
|
9461
9574
|
handoff: {}
|
|
@@ -9539,7 +9652,7 @@ function recordInvocation(parsed) {
|
|
|
9539
9652
|
try {
|
|
9540
9653
|
const entry = {
|
|
9541
9654
|
path: invocationPath(parsed.positionals),
|
|
9542
|
-
options: Object.entries(parsed.options).map(([name,
|
|
9655
|
+
options: Object.entries(parsed.options).map(([name, value2]) => value2 === false ? `no-${name}` : name).sort()
|
|
9543
9656
|
};
|
|
9544
9657
|
if (!entry.path.length) return;
|
|
9545
9658
|
(0, import_node_fs15.appendFileSync)(file, `${JSON.stringify(entry)}
|
|
@@ -9553,10 +9666,10 @@ var import_node_fs16 = require("fs");
|
|
|
9553
9666
|
|
|
9554
9667
|
// src/runbook-requires.ts
|
|
9555
9668
|
var SPEC = /^(@?[\w./-]+?)@(\d+\.\d+\.\d+(?:[\w.-]*)?)$/;
|
|
9556
|
-
function parseRequires(
|
|
9557
|
-
if (!
|
|
9669
|
+
function parseRequires(value2) {
|
|
9670
|
+
if (!value2) return [];
|
|
9558
9671
|
const out = [];
|
|
9559
|
-
for (const token of
|
|
9672
|
+
for (const token of value2.split(/[\s,]+/).filter(Boolean)) {
|
|
9560
9673
|
const match = SPEC.exec(token);
|
|
9561
9674
|
if (match?.[1] && match[2]) out.push({ name: match[1], min: match[2] });
|
|
9562
9675
|
}
|
|
@@ -9732,9 +9845,9 @@ function parseRunbook(text, slug) {
|
|
|
9732
9845
|
for (const line of fm[1].split(/\r?\n/)) {
|
|
9733
9846
|
const pair = /^(\w+)\s*:\s*(.+)$/.exec(line.trim());
|
|
9734
9847
|
if (!pair) continue;
|
|
9735
|
-
const
|
|
9736
|
-
if (pair[1] === "summary") meta.summary =
|
|
9737
|
-
if (pair[1] === "tags") meta.tags =
|
|
9848
|
+
const value2 = pair[2].trim().replace(/^["']|["']$/g, "");
|
|
9849
|
+
if (pair[1] === "summary") meta.summary = value2;
|
|
9850
|
+
if (pair[1] === "tags") meta.tags = value2.replace(/^\[|\]$/g, "").trim();
|
|
9738
9851
|
}
|
|
9739
9852
|
}
|
|
9740
9853
|
const lines = rest.split("\n");
|
|
@@ -9851,7 +9964,7 @@ var NOISE = /* @__PURE__ */ new Set([
|
|
|
9851
9964
|
"and",
|
|
9852
9965
|
"for"
|
|
9853
9966
|
]);
|
|
9854
|
-
var words = (
|
|
9967
|
+
var words = (value2) => value2.replace(/^@[\w-]+\//, "").split(/[^A-Za-z0-9]+/).filter((w) => w.length > 1 && !NOISE.has(w.toLowerCase()));
|
|
9855
9968
|
function namedExports(clause) {
|
|
9856
9969
|
return clause.split(",").map((part) => part.trim().split(/\s+as\s+/)[0]?.trim() ?? "").filter((name) => /^[A-Za-z_$][\w$]*$/.test(name) && name !== "type");
|
|
9857
9970
|
}
|
|
@@ -10204,8 +10317,8 @@ var import_node_process12 = __toESM(require("process"), 1);
|
|
|
10204
10317
|
var EDITOR_ENV = ["ODLA_EDITOR", "VISUAL", "EDITOR"];
|
|
10205
10318
|
function resolveEditor(env = import_node_process12.default.env) {
|
|
10206
10319
|
for (const name of EDITOR_ENV) {
|
|
10207
|
-
const
|
|
10208
|
-
if (
|
|
10320
|
+
const value2 = env[name];
|
|
10321
|
+
if (value2 && value2.trim()) return value2.trim();
|
|
10209
10322
|
}
|
|
10210
10323
|
return null;
|
|
10211
10324
|
}
|
|
@@ -10470,9 +10583,9 @@ async function runbookCommand(parsed, deps = {}) {
|
|
|
10470
10583
|
});
|
|
10471
10584
|
}
|
|
10472
10585
|
case "visibility": {
|
|
10473
|
-
const
|
|
10474
|
-
if (!
|
|
10475
|
-
return runbookVisibility(ctx, requireSlug(slug, "visibility"),
|
|
10586
|
+
const value2 = parsed.positionals[3] ?? stringOpt(parsed.options.visibility);
|
|
10587
|
+
if (!value2) throw new Error('"runbook visibility" needs operator|admin, e.g. "runbook visibility release operator"');
|
|
10588
|
+
return runbookVisibility(ctx, requireSlug(slug, "visibility"), value2);
|
|
10476
10589
|
}
|
|
10477
10590
|
case "publish":
|
|
10478
10591
|
return runbookStatus(ctx, requireSlug(slug, "publish"), "published");
|
|
@@ -10528,13 +10641,13 @@ async function interactiveConfirmation(message2, dependencies) {
|
|
|
10528
10641
|
}
|
|
10529
10642
|
}
|
|
10530
10643
|
function requiredSecurityPositional(parsed, index, label) {
|
|
10531
|
-
const
|
|
10532
|
-
if (!
|
|
10533
|
-
return
|
|
10644
|
+
const value2 = parsed.positionals[index];
|
|
10645
|
+
if (!value2) throw new Error(`${label} is required`);
|
|
10646
|
+
return value2;
|
|
10534
10647
|
}
|
|
10535
|
-
function securityProfile(
|
|
10536
|
-
if (
|
|
10537
|
-
if (
|
|
10648
|
+
function securityProfile(value2) {
|
|
10649
|
+
if (value2 === void 0) return void 0;
|
|
10650
|
+
if (value2 === "odla" || value2 === "cloudflare-app" || value2 === "generic") return value2;
|
|
10538
10651
|
throw new Error("--profile must be odla, cloudflare-app, or generic");
|
|
10539
10652
|
}
|
|
10540
10653
|
|
|
@@ -10635,9 +10748,9 @@ function routeLabel(route2) {
|
|
|
10635
10748
|
return `${route2.provider}/${route2.model}${route2.policyVersion ? ` policy v${route2.policyVersion}` : ""}`;
|
|
10636
10749
|
}
|
|
10637
10750
|
var HOSTED_SEVERITIES = ["informational", "low", "medium", "high", "critical"];
|
|
10638
|
-
function hostedSeverity(
|
|
10639
|
-
if (HOSTED_SEVERITIES.includes(
|
|
10640
|
-
return
|
|
10751
|
+
function hostedSeverity(value2, flag) {
|
|
10752
|
+
if (HOSTED_SEVERITIES.includes(value2)) {
|
|
10753
|
+
return value2;
|
|
10641
10754
|
}
|
|
10642
10755
|
throw new Error(`${flag} must be informational, low, medium, high, or critical`);
|
|
10643
10756
|
}
|
|
@@ -10720,13 +10833,13 @@ function selectEnv(requested, declared, configPath, rootDir) {
|
|
|
10720
10833
|
return env;
|
|
10721
10834
|
}
|
|
10722
10835
|
async function injectedToken(options, request2) {
|
|
10723
|
-
const
|
|
10724
|
-
if (typeof
|
|
10836
|
+
const value2 = options.token ?? await options.getToken?.(Object.freeze({ ...request2 }));
|
|
10837
|
+
if (typeof value2 !== "string" || value2.length < 8 || value2.length > 8192 || /\s|[\u0000-\u001f\u007f]/.test(value2)) {
|
|
10725
10838
|
throw new Error(
|
|
10726
10839
|
request2.selfAudit ? "Self-audit requires an injected, scoped platform security token" : "Hosted security requires an injected app developer token or getToken callback"
|
|
10727
10840
|
);
|
|
10728
10841
|
}
|
|
10729
|
-
return
|
|
10842
|
+
return value2;
|
|
10730
10843
|
}
|
|
10731
10844
|
function profileFor(name, maxHuntTasks) {
|
|
10732
10845
|
const profile = name === "odla" ? (0, import_security.odlaProfile)() : name === "cloudflare-app" ? (0, import_security.cloudflareAppProfile)() : name === "generic" ? (0, import_security.genericProfile)() : void 0;
|
|
@@ -10772,8 +10885,8 @@ async function getHostedSecurityIntent(options) {
|
|
|
10772
10885
|
}
|
|
10773
10886
|
return response2;
|
|
10774
10887
|
}
|
|
10775
|
-
function isValidIntent(
|
|
10776
|
-
return !!
|
|
10888
|
+
function isValidIntent(value2, expected) {
|
|
10889
|
+
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";
|
|
10777
10890
|
}
|
|
10778
10891
|
|
|
10779
10892
|
// src/security-hosted-jobs.ts
|
|
@@ -10888,17 +11001,17 @@ function hostedJobPath(appIdInput, jobIdInput) {
|
|
|
10888
11001
|
const jobId = hostedIdentifier(jobIdInput, "jobId");
|
|
10889
11002
|
return `/registry/apps/${encodeURIComponent(appId)}/security/jobs/${encodeURIComponent(jobId)}`;
|
|
10890
11003
|
}
|
|
10891
|
-
function securityPlanDigest(
|
|
10892
|
-
if (!/^sha256:[a-f0-9]{64}$/.test(
|
|
11004
|
+
function securityPlanDigest(value2) {
|
|
11005
|
+
if (!/^sha256:[a-f0-9]{64}$/.test(value2)) {
|
|
10893
11006
|
throw new Error("expected plan digest must be a sha256 digest from security plan");
|
|
10894
11007
|
}
|
|
10895
|
-
return
|
|
11008
|
+
return value2;
|
|
10896
11009
|
}
|
|
10897
|
-
function securityExecutionDigest(
|
|
10898
|
-
if (!/^sha256:[a-f0-9]{64}$/.test(
|
|
11010
|
+
function securityExecutionDigest(value2) {
|
|
11011
|
+
if (!/^sha256:[a-f0-9]{64}$/.test(value2)) {
|
|
10899
11012
|
throw new Error("expected execution digest must be a sha256 digest from security intent");
|
|
10900
11013
|
}
|
|
10901
|
-
return
|
|
11014
|
+
return value2;
|
|
10902
11015
|
}
|
|
10903
11016
|
|
|
10904
11017
|
// src/security-run-command.ts
|
|
@@ -10962,7 +11075,7 @@ async function runSourceSecurityCommand(parsed, dependencies, sourceId) {
|
|
|
10962
11075
|
...context,
|
|
10963
11076
|
jobId: job.jobId,
|
|
10964
11077
|
wait: dependencies.pollWait,
|
|
10965
|
-
onUpdate: parsed.options.json === true ? void 0 : (
|
|
11078
|
+
onUpdate: parsed.options.json === true ? void 0 : (value2) => printHostedJob(context.stdout, value2, context.platform, context.appId)
|
|
10966
11079
|
}) : job;
|
|
10967
11080
|
if (!follow) {
|
|
10968
11081
|
if (parsed.options.json === true) {
|
|
@@ -11062,9 +11175,9 @@ function enforceLocalGate(report4, parsed) {
|
|
|
11062
11175
|
throw new Error(`hosted security gate failed: ${confirmed.length} confirmed >= ${failOn}; ${leads.length} leads >= ${failOnCandidates ?? "disabled"}${incomplete ? "; coverage incomplete" : ""}`);
|
|
11063
11176
|
}
|
|
11064
11177
|
}
|
|
11065
|
-
function severityOpt(
|
|
11066
|
-
if (["informational", "low", "medium", "high", "critical"].includes(
|
|
11067
|
-
return
|
|
11178
|
+
function severityOpt(value2, flag) {
|
|
11179
|
+
if (["informational", "low", "medium", "high", "critical"].includes(value2)) {
|
|
11180
|
+
return value2;
|
|
11068
11181
|
}
|
|
11069
11182
|
throw new Error(`${flag} must be informational, low, medium, high, or critical`);
|
|
11070
11183
|
}
|
|
@@ -11172,7 +11285,7 @@ async function securityStatus(parsed, dependencies) {
|
|
|
11172
11285
|
...context,
|
|
11173
11286
|
jobId,
|
|
11174
11287
|
wait: dependencies.pollWait,
|
|
11175
|
-
onUpdate: parsed.options.json === true ? void 0 : (
|
|
11288
|
+
onUpdate: parsed.options.json === true ? void 0 : (value2) => printHostedJob(context.stdout, value2, context.platform, context.appId)
|
|
11176
11289
|
}) : await getHostedSecurityJob({ ...context, jobId });
|
|
11177
11290
|
if (parsed.options.json === true) context.stdout.log(JSON.stringify(job, null, 2));
|
|
11178
11291
|
else if (parsed.options.follow !== true) {
|
|
@@ -11256,6 +11369,10 @@ async function runCli(argv = process.argv.slice(2), dependencies = {}) {
|
|
|
11256
11369
|
await o11yCommand(parsed, runtime);
|
|
11257
11370
|
return;
|
|
11258
11371
|
}
|
|
11372
|
+
if (command === "platform") {
|
|
11373
|
+
await platformCommand(parsed, runtime);
|
|
11374
|
+
return;
|
|
11375
|
+
}
|
|
11259
11376
|
if (command === "provision") {
|
|
11260
11377
|
await provisionCommand(parsed, runtime);
|
|
11261
11378
|
return;
|