@odla-ai/cli 0.25.19 → 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 +18 -0
- package/dist/bin.cjs +768 -635
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-S3EJ66VG.js → chunk-L2NG4UR4.js} +759 -626
- package/dist/chunk-L2NG4UR4.js.map +1 -0
- package/dist/index.cjs +768 -635
- 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 +2 -2
- package/dist/chunk-S3EJ66VG.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
|
|
@@ -968,6 +969,7 @@ var import_node_process8 = __toESM(require("process"), 1);
|
|
|
968
969
|
var import_node_fs4 = require("fs");
|
|
969
970
|
var import_node_path4 = require("path");
|
|
970
971
|
var import_node_url = require("url");
|
|
972
|
+
var import_apps = require("@odla-ai/apps");
|
|
971
973
|
|
|
972
974
|
// src/integration-validation.ts
|
|
973
975
|
function validateIntegrations(cfg, path, defaultServices) {
|
|
@@ -1022,17 +1024,17 @@ function validateProbes(integration, at) {
|
|
|
1022
1024
|
}
|
|
1023
1025
|
}
|
|
1024
1026
|
}
|
|
1025
|
-
function isRecord4(
|
|
1026
|
-
return
|
|
1027
|
+
function isRecord4(value2) {
|
|
1028
|
+
return value2 !== null && typeof value2 === "object" && !Array.isArray(value2);
|
|
1027
1029
|
}
|
|
1028
|
-
function safeText(
|
|
1029
|
-
return typeof
|
|
1030
|
+
function safeText(value2, max) {
|
|
1031
|
+
return typeof value2 === "string" && value2.trim().length > 0 && value2.length <= max && !/[\u0000-\u001f\u007f]/.test(value2);
|
|
1030
1032
|
}
|
|
1031
|
-
function safeProbePath(
|
|
1032
|
-
return typeof
|
|
1033
|
+
function safeProbePath(value2) {
|
|
1034
|
+
return typeof value2 === "string" && /^\/[A-Za-z0-9._~!$&'()*+,;=:@%/-]*$/.test(value2);
|
|
1033
1035
|
}
|
|
1034
|
-
function validId(
|
|
1035
|
-
return typeof
|
|
1036
|
+
function validId(value2) {
|
|
1037
|
+
return typeof value2 === "string" && /^[a-z0-9][a-z0-9-]*$/.test(value2);
|
|
1036
1038
|
}
|
|
1037
1039
|
function unique(values) {
|
|
1038
1040
|
return [...new Set(values.filter(Boolean))];
|
|
@@ -1055,6 +1057,7 @@ async function loadProjectConfig(configPath = "odla.config.mjs") {
|
|
|
1055
1057
|
const dbEndpoint = trimSlash(process.env.ODLA_DB_ENDPOINT || raw.dbEndpoint || platformUrl);
|
|
1056
1058
|
const envs = unique2(raw.envs?.length ? raw.envs : DEFAULT_ENVS);
|
|
1057
1059
|
const services = unique2(raw.services?.length ? raw.services : DEFAULT_SERVICES);
|
|
1060
|
+
validateServices(services, resolved);
|
|
1058
1061
|
validateCalendarConfig(raw, envs, services, resolved);
|
|
1059
1062
|
const local = {
|
|
1060
1063
|
tokenFile: (0, import_node_path4.resolve)(rootDir, raw.local?.tokenFile ?? ".odla/dev-token.json"),
|
|
@@ -1073,10 +1076,10 @@ async function loadProjectConfig(configPath = "odla.config.mjs") {
|
|
|
1073
1076
|
local
|
|
1074
1077
|
};
|
|
1075
1078
|
}
|
|
1076
|
-
async function resolveDataExport(cfg,
|
|
1077
|
-
if (
|
|
1078
|
-
if (typeof
|
|
1079
|
-
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);
|
|
1080
1083
|
if (target.endsWith(".json")) {
|
|
1081
1084
|
return JSON.parse((0, import_node_fs4.readFileSync)(target, "utf8"));
|
|
1082
1085
|
}
|
|
@@ -1085,7 +1088,7 @@ async function resolveDataExport(cfg, value, names) {
|
|
|
1085
1088
|
if (mod[name] !== void 0) return mod[name];
|
|
1086
1089
|
}
|
|
1087
1090
|
if (mod.default !== void 0) return mod.default;
|
|
1088
|
-
throw new Error(`${
|
|
1091
|
+
throw new Error(`${value2} did not export ${names.join(", ")} or default`);
|
|
1089
1092
|
}
|
|
1090
1093
|
function buildPlan(cfg) {
|
|
1091
1094
|
const integrationSchema = cfg.integrations?.some((integration) => integration.schema) ?? false;
|
|
@@ -1119,9 +1122,9 @@ function calendarServiceConfig(cfg, env) {
|
|
|
1119
1122
|
};
|
|
1120
1123
|
}
|
|
1121
1124
|
function calendarBookingPageUrl(cfg, env) {
|
|
1122
|
-
const
|
|
1123
|
-
if (
|
|
1124
|
-
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();
|
|
1125
1128
|
}
|
|
1126
1129
|
function rulesFromSchema(schema) {
|
|
1127
1130
|
const entities = serializedEntities(schema);
|
|
@@ -1135,10 +1138,10 @@ function serializedEntities(schema) {
|
|
|
1135
1138
|
if (!entities || typeof entities !== "object" || Array.isArray(entities)) return [];
|
|
1136
1139
|
return Object.keys(entities);
|
|
1137
1140
|
}
|
|
1138
|
-
function envValue(
|
|
1139
|
-
if (!
|
|
1140
|
-
if (
|
|
1141
|
-
return
|
|
1141
|
+
function envValue(value2) {
|
|
1142
|
+
if (!value2) return void 0;
|
|
1143
|
+
if (value2.startsWith("$")) return process.env[value2.slice(1)];
|
|
1144
|
+
return value2;
|
|
1142
1145
|
}
|
|
1143
1146
|
function validateRawConfig(raw, path) {
|
|
1144
1147
|
if (!raw || typeof raw !== "object") throw new Error(`${path} must export an object`);
|
|
@@ -1194,8 +1197,8 @@ function validateCalendarConfig(cfg, envs, services, path) {
|
|
|
1194
1197
|
if (!isRecord5(google.bookingCalendar)) throw new Error(`${path}: calendar.google.bookingCalendar must map env names to one calendar id`);
|
|
1195
1198
|
const unknownBookingEnv = Object.keys(google.bookingCalendar).find((env) => !envs.includes(env));
|
|
1196
1199
|
if (unknownBookingEnv) throw new Error(`${path}: calendar.google.bookingCalendar.${unknownBookingEnv} is not in config envs`);
|
|
1197
|
-
for (const [env,
|
|
1198
|
-
if (!safeText2(
|
|
1200
|
+
for (const [env, value2] of Object.entries(google.bookingCalendar)) {
|
|
1201
|
+
if (!safeText2(value2, 1024)) {
|
|
1199
1202
|
throw new Error(`${path}: calendar.google.bookingCalendar.${env} must be a calendar id`);
|
|
1200
1203
|
}
|
|
1201
1204
|
}
|
|
@@ -1204,45 +1207,57 @@ function validateCalendarConfig(cfg, envs, services, path) {
|
|
|
1204
1207
|
if (!isRecord5(google.bookingPageUrl)) throw new Error(`${path}: calendar.google.bookingPageUrl must map env names to HTTPS URLs or null`);
|
|
1205
1208
|
const unknownBookingEnv = Object.keys(google.bookingPageUrl).find((env) => !envs.includes(env));
|
|
1206
1209
|
if (unknownBookingEnv) throw new Error(`${path}: calendar.google.bookingPageUrl.${unknownBookingEnv} is not in config envs`);
|
|
1207
|
-
for (const [env,
|
|
1208
|
-
if (
|
|
1210
|
+
for (const [env, value2] of Object.entries(google.bookingPageUrl)) {
|
|
1211
|
+
if (value2 !== null && !safeHttpsUrl(value2)) {
|
|
1209
1212
|
throw new Error(`${path}: calendar.google.bookingPageUrl.${env} must be an HTTPS URL without credentials or fragment`);
|
|
1210
1213
|
}
|
|
1211
1214
|
}
|
|
1212
1215
|
}
|
|
1213
|
-
if (enabled && !services.includes("db")) throw new Error(`${path}: calendar service requires the db service`);
|
|
1214
1216
|
}
|
|
1215
|
-
function
|
|
1216
|
-
const
|
|
1217
|
+
function validateServices(services, path) {
|
|
1218
|
+
for (const service of services) {
|
|
1219
|
+
const definition = (0, import_apps.appServiceDefinition)(service);
|
|
1220
|
+
if (!definition) {
|
|
1221
|
+
throw new Error(`${path}: unknown service "${service}" (known: ${(0, import_apps.appServiceIds)().join(", ")})`);
|
|
1222
|
+
}
|
|
1223
|
+
for (const dependency of definition.requires) {
|
|
1224
|
+
if (!services.includes(dependency)) {
|
|
1225
|
+
throw new Error(`${path}: ${service} service requires the ${dependency} service`);
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
function assertOnly(value2, allowed, label) {
|
|
1231
|
+
const extra = Object.keys(value2).find((key) => !allowed.includes(key));
|
|
1217
1232
|
if (extra) throw new Error(`${label}.${extra} is not supported`);
|
|
1218
1233
|
}
|
|
1219
|
-
function isRecord5(
|
|
1220
|
-
return
|
|
1234
|
+
function isRecord5(value2) {
|
|
1235
|
+
return value2 !== null && typeof value2 === "object" && !Array.isArray(value2);
|
|
1221
1236
|
}
|
|
1222
|
-
function safeText2(
|
|
1223
|
-
return typeof
|
|
1237
|
+
function safeText2(value2, max) {
|
|
1238
|
+
return typeof value2 === "string" && value2.trim().length > 0 && value2.length <= max && !/[\u0000-\u001f\u007f]/.test(value2);
|
|
1224
1239
|
}
|
|
1225
|
-
function safeHttpsUrl(
|
|
1226
|
-
if (typeof
|
|
1240
|
+
function safeHttpsUrl(value2) {
|
|
1241
|
+
if (typeof value2 !== "string" || value2.length > 2048) return false;
|
|
1227
1242
|
try {
|
|
1228
|
-
const url = new URL(
|
|
1243
|
+
const url = new URL(value2);
|
|
1229
1244
|
return url.protocol === "https:" && !url.username && !url.password && !url.hash;
|
|
1230
1245
|
} catch {
|
|
1231
1246
|
return false;
|
|
1232
1247
|
}
|
|
1233
1248
|
}
|
|
1234
|
-
function validId2(
|
|
1235
|
-
return typeof
|
|
1249
|
+
function validId2(value2) {
|
|
1250
|
+
return typeof value2 === "string" && /^[a-z0-9][a-z0-9-]*$/.test(value2);
|
|
1236
1251
|
}
|
|
1237
1252
|
async function loadConfigModule(path) {
|
|
1238
1253
|
if (path.endsWith(".json")) return JSON.parse((0, import_node_fs4.readFileSync)(path, "utf8"));
|
|
1239
1254
|
const mod = await import(`${(0, import_node_url.pathToFileURL)(path).href}?t=${Date.now()}`);
|
|
1240
|
-
const
|
|
1241
|
-
if (typeof
|
|
1242
|
-
return
|
|
1255
|
+
const value2 = mod.default ?? mod.config;
|
|
1256
|
+
if (typeof value2 === "function") return await value2();
|
|
1257
|
+
return value2;
|
|
1243
1258
|
}
|
|
1244
|
-
function trimSlash(
|
|
1245
|
-
return
|
|
1259
|
+
function trimSlash(value2) {
|
|
1260
|
+
return value2.replace(/\/+$/, "");
|
|
1246
1261
|
}
|
|
1247
1262
|
function unique2(values) {
|
|
1248
1263
|
return [...new Set(values.filter(Boolean))];
|
|
@@ -1268,8 +1283,8 @@ function resolveOperatorProfile(parsed) {
|
|
|
1268
1283
|
}
|
|
1269
1284
|
assertOperatorName(name, "context");
|
|
1270
1285
|
const profiles = readOperatorProfiles(file);
|
|
1271
|
-
const
|
|
1272
|
-
if (!
|
|
1286
|
+
const value2 = Object.hasOwn(profiles, name) ? profiles[name] : void 0;
|
|
1287
|
+
if (!value2) {
|
|
1273
1288
|
throw new Error(
|
|
1274
1289
|
`operator context "${name}" not found in ${file}; run "odla-ai context list" or save it first`
|
|
1275
1290
|
);
|
|
@@ -1278,7 +1293,7 @@ function resolveOperatorProfile(parsed) {
|
|
|
1278
1293
|
name,
|
|
1279
1294
|
source: fromFlag ? "flag" : "environment",
|
|
1280
1295
|
file,
|
|
1281
|
-
value
|
|
1296
|
+
value: value2
|
|
1282
1297
|
};
|
|
1283
1298
|
}
|
|
1284
1299
|
function listOperatorProfiles(file = operatorProfileFile()) {
|
|
@@ -1306,8 +1321,8 @@ function operatorCredentialFiles(selection) {
|
|
|
1306
1321
|
scoped: (0, import_node_path5.join)(base, "admin-token.local.json")
|
|
1307
1322
|
};
|
|
1308
1323
|
}
|
|
1309
|
-
function assertOperatorName(
|
|
1310
|
-
if (!/^[a-z0-9][a-z0-9-]*$/.test(
|
|
1324
|
+
function assertOperatorName(value2, label) {
|
|
1325
|
+
if (!/^[a-z0-9][a-z0-9-]*$/.test(value2)) {
|
|
1311
1326
|
throw new Error(
|
|
1312
1327
|
`${label} must contain lowercase letters, numbers, and hyphens`
|
|
1313
1328
|
);
|
|
@@ -1333,22 +1348,22 @@ function readOperatorProfiles(file) {
|
|
|
1333
1348
|
);
|
|
1334
1349
|
}
|
|
1335
1350
|
const profiles = emptyProfiles();
|
|
1336
|
-
for (const [name,
|
|
1351
|
+
for (const [name, value2] of Object.entries(
|
|
1337
1352
|
raw.profiles
|
|
1338
1353
|
)) {
|
|
1339
1354
|
assertOperatorName(name, "context");
|
|
1340
|
-
profiles[name] = validateProfile(
|
|
1355
|
+
profiles[name] = validateProfile(value2, `operator context "${name}"`);
|
|
1341
1356
|
}
|
|
1342
1357
|
return profiles;
|
|
1343
1358
|
}
|
|
1344
1359
|
function emptyProfiles() {
|
|
1345
1360
|
return /* @__PURE__ */ Object.create(null);
|
|
1346
1361
|
}
|
|
1347
|
-
function validateProfile(
|
|
1348
|
-
if (!
|
|
1362
|
+
function validateProfile(value2, label) {
|
|
1363
|
+
if (!value2 || typeof value2 !== "object" || Array.isArray(value2)) {
|
|
1349
1364
|
throw new Error(`${label} has an invalid shape`);
|
|
1350
1365
|
}
|
|
1351
|
-
const unknown = Object.keys(
|
|
1366
|
+
const unknown = Object.keys(value2).filter(
|
|
1352
1367
|
(key) => !["platform", "app", "environment"].includes(key)
|
|
1353
1368
|
);
|
|
1354
1369
|
if (unknown.length > 0) {
|
|
@@ -1356,7 +1371,7 @@ function validateProfile(value, label) {
|
|
|
1356
1371
|
`${label} contains unsupported field(s): ${unknown.sort().join(", ")}; contexts store scope metadata only, never credentials`
|
|
1357
1372
|
);
|
|
1358
1373
|
}
|
|
1359
|
-
const candidate =
|
|
1374
|
+
const candidate = value2;
|
|
1360
1375
|
if (typeof candidate.platform !== "string") {
|
|
1361
1376
|
throw new Error(`${label} needs an absolute platform URL`);
|
|
1362
1377
|
}
|
|
@@ -1371,8 +1386,8 @@ function validateProfile(value, label) {
|
|
|
1371
1386
|
...environment2 ? { environment: environment2 } : {}
|
|
1372
1387
|
};
|
|
1373
1388
|
}
|
|
1374
|
-
function clean(
|
|
1375
|
-
const normalized =
|
|
1389
|
+
function clean(value2) {
|
|
1390
|
+
const normalized = value2?.trim();
|
|
1376
1391
|
return normalized || void 0;
|
|
1377
1392
|
}
|
|
1378
1393
|
|
|
@@ -1465,8 +1480,8 @@ async function resolveOperatorContext(parsed, options = {}) {
|
|
|
1465
1480
|
}
|
|
1466
1481
|
};
|
|
1467
1482
|
}
|
|
1468
|
-
function clean2(
|
|
1469
|
-
const normalized =
|
|
1483
|
+
function clean2(value2) {
|
|
1484
|
+
const normalized = value2?.trim();
|
|
1470
1485
|
return normalized || void 0;
|
|
1471
1486
|
}
|
|
1472
1487
|
|
|
@@ -1534,7 +1549,7 @@ async function adminCommand(parsed, deps = {}) {
|
|
|
1534
1549
|
}
|
|
1535
1550
|
|
|
1536
1551
|
// src/tenant.ts
|
|
1537
|
-
var
|
|
1552
|
+
var import_apps2 = require("@odla-ai/apps");
|
|
1538
1553
|
function resolveEnv(cfg, requested) {
|
|
1539
1554
|
const env = requested ?? (cfg.envs.includes("dev") ? "dev" : cfg.envs[0]);
|
|
1540
1555
|
if (!env || !cfg.envs.includes(env)) {
|
|
@@ -1544,7 +1559,7 @@ function resolveEnv(cfg, requested) {
|
|
|
1544
1559
|
}
|
|
1545
1560
|
function resolveTenant(cfg, requested) {
|
|
1546
1561
|
const env = resolveEnv(cfg, requested);
|
|
1547
|
-
return { env, tenant: (0,
|
|
1562
|
+
return { env, tenant: (0, import_apps2.tenantIdFor)(cfg.app.id, env) };
|
|
1548
1563
|
}
|
|
1549
1564
|
function bothTenants(cfg) {
|
|
1550
1565
|
for (const env of ["dev", "prod"]) {
|
|
@@ -1554,7 +1569,7 @@ function bothTenants(cfg) {
|
|
|
1554
1569
|
);
|
|
1555
1570
|
}
|
|
1556
1571
|
}
|
|
1557
|
-
return { sandbox: (0,
|
|
1572
|
+
return { sandbox: (0, import_apps2.tenantIdFor)(cfg.app.id, "dev"), live: (0, import_apps2.tenantIdFor)(cfg.app.id, "prod") };
|
|
1558
1573
|
}
|
|
1559
1574
|
|
|
1560
1575
|
// src/agent-command.ts
|
|
@@ -2177,44 +2192,44 @@ var REPLACEMENTS = [
|
|
|
2177
2192
|
[/\b(ghp|gho|github_pat)_[A-Za-z0-9_]+/g, "$1_[redacted]"],
|
|
2178
2193
|
[/\bAKIA[A-Z0-9]{12,}/g, "AKIA[redacted]"]
|
|
2179
2194
|
];
|
|
2180
|
-
function redactSecrets(
|
|
2181
|
-
let result =
|
|
2195
|
+
function redactSecrets(value2) {
|
|
2196
|
+
let result = value2;
|
|
2182
2197
|
for (const [pattern, replacement] of REPLACEMENTS) result = result.replace(pattern, replacement);
|
|
2183
2198
|
return result;
|
|
2184
2199
|
}
|
|
2185
2200
|
function redactingOutput(output) {
|
|
2186
|
-
const redactArgs = (args) => args.map((
|
|
2201
|
+
const redactArgs = (args) => args.map((value2) => redactOutputValue(value2, /* @__PURE__ */ new WeakMap()));
|
|
2187
2202
|
return {
|
|
2188
2203
|
log: (...args) => output.log(...redactArgs(args)),
|
|
2189
2204
|
error: (...args) => output.error(...redactArgs(args))
|
|
2190
2205
|
};
|
|
2191
2206
|
}
|
|
2192
|
-
function redactOutputValue(
|
|
2193
|
-
if (typeof
|
|
2194
|
-
if (
|
|
2195
|
-
const redacted = new Error(redactSecrets(
|
|
2196
|
-
redacted.name =
|
|
2197
|
-
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);
|
|
2198
2213
|
return redacted;
|
|
2199
2214
|
}
|
|
2200
|
-
if (!
|
|
2201
|
-
const prior = seen.get(
|
|
2215
|
+
if (!value2 || typeof value2 !== "object") return value2;
|
|
2216
|
+
const prior = seen.get(value2);
|
|
2202
2217
|
if (prior) return prior;
|
|
2203
|
-
if (Array.isArray(
|
|
2218
|
+
if (Array.isArray(value2)) {
|
|
2204
2219
|
const next2 = [];
|
|
2205
|
-
seen.set(
|
|
2206
|
-
for (const item of
|
|
2220
|
+
seen.set(value2, next2);
|
|
2221
|
+
for (const item of value2) next2.push(redactOutputValue(item, seen));
|
|
2207
2222
|
return next2;
|
|
2208
2223
|
}
|
|
2209
|
-
const prototype = Object.getPrototypeOf(
|
|
2210
|
-
if (prototype !== Object.prototype && prototype !== null) return
|
|
2224
|
+
const prototype = Object.getPrototypeOf(value2);
|
|
2225
|
+
if (prototype !== Object.prototype && prototype !== null) return value2;
|
|
2211
2226
|
const next = {};
|
|
2212
|
-
seen.set(
|
|
2213
|
-
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);
|
|
2214
2229
|
return next;
|
|
2215
2230
|
}
|
|
2216
|
-
function looksSecret(
|
|
2217
|
-
return redactSecrets(
|
|
2231
|
+
function looksSecret(value2) {
|
|
2232
|
+
return redactSecrets(value2) !== value2 || value2.includes("-----BEGIN");
|
|
2218
2233
|
}
|
|
2219
2234
|
|
|
2220
2235
|
// src/calendar-http.ts
|
|
@@ -2231,9 +2246,9 @@ async function readCalendarStatus(ctx) {
|
|
|
2231
2246
|
}
|
|
2232
2247
|
async function discoverGoogleCalendars(ctx) {
|
|
2233
2248
|
const raw = await calendarJson(ctx, "/calendars", {});
|
|
2234
|
-
const
|
|
2235
|
-
if (!
|
|
2236
|
-
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) => {
|
|
2237
2252
|
const calendar = record(item);
|
|
2238
2253
|
const id = textField(calendar?.id, 1024);
|
|
2239
2254
|
if (!calendar || !id) throw new Error(`calendar discovery returned an invalid calendar at index ${index}`);
|
|
@@ -2255,10 +2270,10 @@ async function applyCalendarSettings(ctx, bookingPageUrl) {
|
|
|
2255
2270
|
}
|
|
2256
2271
|
async function startCalendarConnection(ctx) {
|
|
2257
2272
|
const raw = await calendarJson(ctx, "/google/connect", { method: "POST", body: "{}" });
|
|
2258
|
-
const
|
|
2259
|
-
const attemptId = textField(
|
|
2260
|
-
const consentUrl = textField(
|
|
2261
|
-
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);
|
|
2262
2277
|
if (!attemptId || !consentUrl || expiresAt === void 0) throw new Error("calendar connect returned an invalid attempt");
|
|
2263
2278
|
return { attemptId, consentUrl, expiresAt };
|
|
2264
2279
|
}
|
|
@@ -2276,42 +2291,42 @@ async function requestCalendarDisconnect(ctx) {
|
|
|
2276
2291
|
}
|
|
2277
2292
|
function parseCalendarStatus(raw, env) {
|
|
2278
2293
|
const outer = wrapped(raw, "calendar");
|
|
2279
|
-
const
|
|
2280
|
-
const connection = record(
|
|
2281
|
-
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) ?? {};
|
|
2282
2297
|
const googleConfig = record(config.google) ?? config;
|
|
2283
|
-
const stateValue = calendarState(
|
|
2298
|
+
const stateValue = calendarState(value2.status ?? value2.state ?? connection.status ?? connection.state);
|
|
2284
2299
|
if (!stateValue) {
|
|
2285
2300
|
throw new Error("calendar status returned an invalid connection state");
|
|
2286
2301
|
}
|
|
2287
|
-
const providerValue =
|
|
2302
|
+
const providerValue = value2.provider ?? connection.provider ?? config.provider ?? (config.google ? "google" : void 0);
|
|
2288
2303
|
if (providerValue !== void 0 && providerValue !== null && providerValue !== "google") {
|
|
2289
2304
|
throw new Error("calendar status returned an unsupported provider");
|
|
2290
2305
|
}
|
|
2291
|
-
const accessValue =
|
|
2306
|
+
const accessValue = value2.access ?? connection.access ?? config.access ?? googleConfig.access;
|
|
2292
2307
|
if (accessValue !== void 0 && accessValue !== "book" && accessValue !== "read") {
|
|
2293
2308
|
throw new Error("calendar status returned unsupported access");
|
|
2294
2309
|
}
|
|
2295
|
-
const errorValue = record(
|
|
2296
|
-
const errorCode = textField(
|
|
2297
|
-
const bookingPageValue = Object.hasOwn(
|
|
2298
|
-
const connected = typeof (
|
|
2299
|
-
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);
|
|
2300
2315
|
return {
|
|
2301
2316
|
env,
|
|
2302
|
-
enabled: typeof
|
|
2317
|
+
enabled: typeof value2.enabled === "boolean" ? value2.enabled : true,
|
|
2303
2318
|
connected,
|
|
2304
|
-
writable: typeof
|
|
2319
|
+
writable: typeof value2.writable === "boolean" ? value2.writable : stateValue === "healthy",
|
|
2305
2320
|
provider: providerValue === "google" ? "google" : null,
|
|
2306
2321
|
status: stateValue,
|
|
2307
2322
|
...accessValue !== void 0 ? { access: "book" } : {},
|
|
2308
2323
|
...bookingCalendarId ? { bookingCalendarId } : {},
|
|
2309
2324
|
calendars: calendarIds(
|
|
2310
|
-
|
|
2325
|
+
value2.availabilityCalendars ?? config.availabilityCalendars ?? value2.configuredCalendars ?? value2.calendars ?? config.calendars ?? googleConfig.calendars
|
|
2311
2326
|
),
|
|
2312
2327
|
...optionalNullableUrl("bookingPageUrl", bookingPageValue),
|
|
2313
|
-
grantedScopes: stringList(
|
|
2314
|
-
...optionalText("attemptId",
|
|
2328
|
+
grantedScopes: stringList(value2.grantedScopes ?? connection.grantedScopes ?? connection.scopes),
|
|
2329
|
+
...optionalText("attemptId", value2.attemptId ?? connection.attemptId, 180),
|
|
2315
2330
|
...errorValue || errorCode ? { error: {
|
|
2316
2331
|
...textField(errorValue?.code, 128) ? { code: textField(errorValue?.code, 128) } : {},
|
|
2317
2332
|
...textField(errorValue?.message, 500) ? { message: textField(errorValue?.message, 500) } : {},
|
|
@@ -2319,9 +2334,9 @@ function parseCalendarStatus(raw, env) {
|
|
|
2319
2334
|
} } : {}
|
|
2320
2335
|
};
|
|
2321
2336
|
}
|
|
2322
|
-
function calendarState(
|
|
2323
|
-
if (typeof
|
|
2324
|
-
if (CALENDAR_STATES.includes(
|
|
2337
|
+
function calendarState(value2) {
|
|
2338
|
+
if (typeof value2 !== "string") return null;
|
|
2339
|
+
if (CALENDAR_STATES.includes(value2)) return value2;
|
|
2325
2340
|
const legacy = {
|
|
2326
2341
|
disabled: "not_connected",
|
|
2327
2342
|
disconnected: "disconnected",
|
|
@@ -2332,7 +2347,7 @@ function calendarState(value) {
|
|
|
2332
2347
|
ready: "healthy",
|
|
2333
2348
|
error: "failed"
|
|
2334
2349
|
};
|
|
2335
|
-
return legacy[
|
|
2350
|
+
return legacy[value2] ?? null;
|
|
2336
2351
|
}
|
|
2337
2352
|
async function calendarJson(ctx, suffix, init) {
|
|
2338
2353
|
const platform = platformAudience(ctx.platform);
|
|
@@ -2366,50 +2381,50 @@ function wrapped(raw, key) {
|
|
|
2366
2381
|
if (!outer) throw new Error("calendar returned an invalid response");
|
|
2367
2382
|
return record(outer[key]) ?? outer;
|
|
2368
2383
|
}
|
|
2369
|
-
function record(
|
|
2370
|
-
return
|
|
2384
|
+
function record(value2) {
|
|
2385
|
+
return value2 !== null && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
|
|
2371
2386
|
}
|
|
2372
|
-
function textField(
|
|
2373
|
-
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;
|
|
2374
2389
|
}
|
|
2375
|
-
function stringList(
|
|
2376
|
-
return Array.isArray(
|
|
2390
|
+
function stringList(value2) {
|
|
2391
|
+
return Array.isArray(value2) ? [...new Set(value2.filter((item) => !!textField(item, 4096)))] : [];
|
|
2377
2392
|
}
|
|
2378
|
-
function calendarIds(
|
|
2379
|
-
if (!Array.isArray(
|
|
2380
|
-
return [...new Set(
|
|
2393
|
+
function calendarIds(value2) {
|
|
2394
|
+
if (!Array.isArray(value2)) return [];
|
|
2395
|
+
return [...new Set(value2.flatMap((item) => {
|
|
2381
2396
|
if (typeof item === "string") return textField(item, 4096) ? [item] : [];
|
|
2382
2397
|
const calendar = record(item);
|
|
2383
2398
|
const id = textField(calendar?.id, 4096);
|
|
2384
2399
|
return id && calendar?.selected !== false ? [id] : [];
|
|
2385
2400
|
}))];
|
|
2386
2401
|
}
|
|
2387
|
-
function timestamp3(
|
|
2388
|
-
if (typeof
|
|
2389
|
-
if (typeof
|
|
2390
|
-
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);
|
|
2391
2406
|
if (Number.isFinite(parsed)) return parsed;
|
|
2392
2407
|
}
|
|
2393
2408
|
return void 0;
|
|
2394
2409
|
}
|
|
2395
|
-
function optionalText(key,
|
|
2396
|
-
const parsed = textField(
|
|
2410
|
+
function optionalText(key, value2, max) {
|
|
2411
|
+
const parsed = textField(value2, max);
|
|
2397
2412
|
return parsed ? { [key]: parsed } : {};
|
|
2398
2413
|
}
|
|
2399
|
-
function optionalNullableUrl(key,
|
|
2400
|
-
if (
|
|
2401
|
-
const parsed = textField(
|
|
2414
|
+
function optionalNullableUrl(key, value2) {
|
|
2415
|
+
if (value2 === null) return { [key]: null };
|
|
2416
|
+
const parsed = textField(value2, 4096);
|
|
2402
2417
|
return parsed ? { [key]: parsed } : {};
|
|
2403
2418
|
}
|
|
2404
|
-
function identifier(
|
|
2405
|
-
if (typeof
|
|
2406
|
-
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;
|
|
2407
2422
|
}
|
|
2408
|
-
function credential(
|
|
2409
|
-
if (typeof
|
|
2423
|
+
function credential(value2) {
|
|
2424
|
+
if (typeof value2 !== "string" || value2.length < 8 || value2.length > 8192 || /\s|[\u0000-\u001f\u007f]/.test(value2)) {
|
|
2410
2425
|
throw new Error("calendar requires an odla developer token");
|
|
2411
2426
|
}
|
|
2412
|
-
return
|
|
2427
|
+
return value2;
|
|
2413
2428
|
}
|
|
2414
2429
|
|
|
2415
2430
|
// src/calendar-poll.ts
|
|
@@ -2570,11 +2585,11 @@ async function connectWithContext(ctx, options) {
|
|
|
2570
2585
|
}
|
|
2571
2586
|
throw new Error('Google Calendar consent timed out; run "odla-ai calendar status" and retry connect');
|
|
2572
2587
|
}
|
|
2573
|
-
function trustedCalendarConsentUrl(platform,
|
|
2588
|
+
function trustedCalendarConsentUrl(platform, value2) {
|
|
2574
2589
|
const origin = platformAudience(platform);
|
|
2575
2590
|
let url;
|
|
2576
2591
|
try {
|
|
2577
|
-
url =
|
|
2592
|
+
url = value2.startsWith("/") ? new URL(value2, origin) : new URL(value2);
|
|
2578
2593
|
} catch {
|
|
2579
2594
|
throw new Error("odla.ai returned an invalid calendar consent URL");
|
|
2580
2595
|
}
|
|
@@ -2585,9 +2600,9 @@ function trustedCalendarConsentUrl(platform, value) {
|
|
|
2585
2600
|
}
|
|
2586
2601
|
return url.toString();
|
|
2587
2602
|
}
|
|
2588
|
-
function pollTimeout(
|
|
2589
|
-
if (!Number.isSafeInteger(
|
|
2590
|
-
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;
|
|
2591
2606
|
}
|
|
2592
2607
|
function productionConsent(env, yes, action) {
|
|
2593
2608
|
if ((env === "prod" || env === "production") && !yes) throw new Error(`refusing to ${action} for "${env}" without --yes`);
|
|
@@ -2619,6 +2634,7 @@ var CAPABILITIES = {
|
|
|
2619
2634
|
"validate integration contracts offline and smoke-test a provisioned db environment plus anonymous capability routes",
|
|
2620
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",
|
|
2621
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",
|
|
2622
2638
|
"inspect durable agent wakeups as a versioned JSON envelope and explicitly requeue one dead-lettered job with a scoped environment credential",
|
|
2623
2639
|
"run app-attributed hosted security discovery and independent validation without provider keys",
|
|
2624
2640
|
"connect/revoke source-read-only GitHub sources and drive commit-pinned hosted security jobs without PATs or provider keys",
|
|
@@ -2802,8 +2818,8 @@ function wranglerWarnings(rootDir) {
|
|
|
2802
2818
|
}
|
|
2803
2819
|
const vars = block.vars;
|
|
2804
2820
|
if (vars && typeof vars === "object") {
|
|
2805
|
-
for (const [name,
|
|
2806
|
-
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)) {
|
|
2807
2823
|
warnings.push(`wrangler ${label}vars.${name} looks like a secret \u2014 use "odla-ai secrets push" / wrangler secret put, never vars`);
|
|
2808
2824
|
}
|
|
2809
2825
|
}
|
|
@@ -2971,27 +2987,27 @@ function isUniqueAttr(schema, ns, attr) {
|
|
|
2971
2987
|
const definition = entity.attrs[attr];
|
|
2972
2988
|
return isRecord6(definition) && definition.unique === true;
|
|
2973
2989
|
}
|
|
2974
|
-
function normalizeSchema(
|
|
2975
|
-
if (
|
|
2976
|
-
if (!isRecord6(
|
|
2990
|
+
function normalizeSchema(value2) {
|
|
2991
|
+
if (value2 === void 0 || value2 === null) return { entities: {}, links: {} };
|
|
2992
|
+
if (!isRecord6(value2) || !isRecord6(value2.entities)) {
|
|
2977
2993
|
throw new Error("db schema must be a serialized schema object with an entities map");
|
|
2978
2994
|
}
|
|
2979
|
-
if (
|
|
2995
|
+
if (value2.links !== void 0 && !isRecord6(value2.links)) throw new Error("db schema links must be an object");
|
|
2980
2996
|
return {
|
|
2981
|
-
entities: { ...
|
|
2982
|
-
links: { ...
|
|
2997
|
+
entities: { ...value2.entities },
|
|
2998
|
+
links: { ...value2.links ?? {} }
|
|
2983
2999
|
};
|
|
2984
3000
|
}
|
|
2985
3001
|
function mergeMap(target, fragment, label) {
|
|
2986
|
-
for (const [name,
|
|
2987
|
-
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)) {
|
|
2988
3004
|
throw new Error(`${label} "${name}" conflicts with an existing definition`);
|
|
2989
3005
|
}
|
|
2990
|
-
target[name] =
|
|
3006
|
+
target[name] = value2;
|
|
2991
3007
|
}
|
|
2992
3008
|
}
|
|
2993
|
-
function isRecord6(
|
|
2994
|
-
return
|
|
3009
|
+
function isRecord6(value2) {
|
|
3010
|
+
return value2 !== null && typeof value2 === "object" && !Array.isArray(value2);
|
|
2995
3011
|
}
|
|
2996
3012
|
|
|
2997
3013
|
// src/doctor.ts
|
|
@@ -3032,9 +3048,9 @@ async function doctor(options) {
|
|
|
3032
3048
|
warnings.push(...integrationWarnings(database.integrations, schema, rules));
|
|
3033
3049
|
if (cfg.services.includes("ai") && !cfg.ai?.provider) warnings.push("ai service is enabled but ai.provider is not set");
|
|
3034
3050
|
if (cfg.auth?.clerk) {
|
|
3035
|
-
for (const [env,
|
|
3036
|
-
if (typeof
|
|
3037
|
-
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}`);
|
|
3038
3054
|
}
|
|
3039
3055
|
}
|
|
3040
3056
|
}
|
|
@@ -3076,10 +3092,10 @@ function harnessList(parsed) {
|
|
|
3076
3092
|
];
|
|
3077
3093
|
return selected.length ? selected : ["all"];
|
|
3078
3094
|
}
|
|
3079
|
-
function harnessOption(
|
|
3080
|
-
if (
|
|
3081
|
-
if (typeof
|
|
3082
|
-
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];
|
|
3083
3099
|
const parts = raw.flatMap((item) => item.split(","));
|
|
3084
3100
|
if (parts.some((item) => !item.trim())) {
|
|
3085
3101
|
throw new Error(`${flag} requires a harness name`);
|
|
@@ -3090,6 +3106,7 @@ function harnessOption(value, flag) {
|
|
|
3090
3106
|
// src/init.ts
|
|
3091
3107
|
var import_node_fs11 = require("fs");
|
|
3092
3108
|
var import_node_path9 = require("path");
|
|
3109
|
+
var import_apps3 = require("@odla-ai/apps");
|
|
3093
3110
|
function initProject(options) {
|
|
3094
3111
|
const out = options.stdout ?? console;
|
|
3095
3112
|
const rootDir = (0, import_node_path9.resolve)(options.rootDir ?? process.cwd());
|
|
@@ -3102,7 +3119,13 @@ function initProject(options) {
|
|
|
3102
3119
|
}
|
|
3103
3120
|
const envs = options.envs?.length ? options.envs : ["dev"];
|
|
3104
3121
|
const services = options.services?.length ? options.services : ["db", "ai"];
|
|
3105
|
-
|
|
3122
|
+
for (const service of services) {
|
|
3123
|
+
const definition = (0, import_apps3.appServiceDefinition)(service);
|
|
3124
|
+
if (!definition) throw new Error(`--services contains unknown service "${service}" (known: ${(0, import_apps3.appServiceIds)().join(", ")})`);
|
|
3125
|
+
for (const dependency of definition.requires) {
|
|
3126
|
+
if (!services.includes(dependency)) throw new Error(`--services ${service} requires ${dependency}`);
|
|
3127
|
+
}
|
|
3128
|
+
}
|
|
3106
3129
|
const aiProvider = options.aiProvider ?? "anthropic";
|
|
3107
3130
|
(0, import_node_fs11.mkdirSync)((0, import_node_path9.dirname)(configPath), { recursive: true });
|
|
3108
3131
|
(0, import_node_fs11.mkdirSync)((0, import_node_path9.resolve)(rootDir, "src/odla"), { recursive: true });
|
|
@@ -3292,7 +3315,7 @@ function assertWranglerConfig(cfg) {
|
|
|
3292
3315
|
|
|
3293
3316
|
// src/secrets-set.ts
|
|
3294
3317
|
var import_ai = require("@odla-ai/ai");
|
|
3295
|
-
var
|
|
3318
|
+
var import_apps4 = require("@odla-ai/apps");
|
|
3296
3319
|
var PROD_ENV_NAMES2 = /* @__PURE__ */ new Set(["prod", "production"]);
|
|
3297
3320
|
async function secretsSet(options) {
|
|
3298
3321
|
const name = (options.name ?? "").trim();
|
|
@@ -3300,38 +3323,38 @@ async function secretsSet(options) {
|
|
|
3300
3323
|
if (name.startsWith("$")) {
|
|
3301
3324
|
throw new Error('"$"-prefixed vault names are platform-reserved; for the Clerk secret key use "odla-ai secrets set-clerk-key"');
|
|
3302
3325
|
}
|
|
3303
|
-
const { cfg, tenantId, value, doFetch, out } = await resolveVaultWrite(options);
|
|
3326
|
+
const { cfg, tenantId, value: value2, doFetch, out } = await resolveVaultWrite(options);
|
|
3304
3327
|
const token = await getDeveloperToken(cfg, options, doFetch, out);
|
|
3305
3328
|
try {
|
|
3306
|
-
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);
|
|
3307
3330
|
} catch (err) {
|
|
3308
|
-
throw new Error(scrubValue(err instanceof Error ? err.message : String(err),
|
|
3331
|
+
throw new Error(scrubValue(err instanceof Error ? err.message : String(err), value2));
|
|
3309
3332
|
}
|
|
3310
3333
|
out.log(`${name} stored in the ${tenantId} vault (write-only; the value was never echoed and cannot be read back here)`);
|
|
3311
3334
|
}
|
|
3312
3335
|
async function secretsSetClerkKey(options) {
|
|
3313
|
-
const { cfg, tenantId, value, doFetch, out } = await resolveVaultWrite(options);
|
|
3314
|
-
if (!
|
|
3315
|
-
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)) {
|
|
3316
3339
|
throw new Error(`refusing to store an sk_test_ Clerk key for "${options.env}" \u2014 use the production instance's sk_live_ key`);
|
|
3317
3340
|
}
|
|
3318
|
-
if (
|
|
3341
|
+
if (value2.startsWith("sk_live_") && !PROD_ENV_NAMES2.has(options.env) && !options.yes) {
|
|
3319
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)`);
|
|
3320
3343
|
}
|
|
3321
3344
|
const token = await getDeveloperToken(cfg, options, doFetch, out);
|
|
3322
3345
|
const res = await doFetch(`${cfg.dbEndpoint}/admin/apps/${encodeURIComponent(tenantId)}/clerk-secret`, {
|
|
3323
3346
|
method: "POST",
|
|
3324
3347
|
headers: { authorization: `Bearer ${token}`, "content-type": "application/json" },
|
|
3325
|
-
body: JSON.stringify({ value })
|
|
3348
|
+
body: JSON.stringify({ value: value2 })
|
|
3326
3349
|
});
|
|
3327
3350
|
if (!res.ok) {
|
|
3328
|
-
const text = scrubValue((await res.text().catch(() => "")).slice(0, 300),
|
|
3351
|
+
const text = scrubValue((await res.text().catch(() => "")).slice(0, 300), value2);
|
|
3329
3352
|
throw new Error(`store Clerk secret key failed (${res.status}): ${text || "request failed"}`);
|
|
3330
3353
|
}
|
|
3331
3354
|
out.log(`Clerk secret key stored for ${tenantId} ($clerk_secret, reserved + write-only; the value was never echoed)`);
|
|
3332
3355
|
}
|
|
3333
|
-
function scrubValue(text,
|
|
3334
|
-
return redactSecrets(text).split(
|
|
3356
|
+
function scrubValue(text, value2) {
|
|
3357
|
+
return redactSecrets(text).split(value2).join("[value redacted]");
|
|
3335
3358
|
}
|
|
3336
3359
|
async function resolveVaultWrite(options) {
|
|
3337
3360
|
const out = options.stdout ?? console;
|
|
@@ -3343,8 +3366,8 @@ async function resolveVaultWrite(options) {
|
|
|
3343
3366
|
if (PROD_ENV_NAMES2.has(options.env) && !options.yes) {
|
|
3344
3367
|
throw new Error(`refusing to store a secret for "${options.env}" without --yes`);
|
|
3345
3368
|
}
|
|
3346
|
-
const
|
|
3347
|
-
return { cfg, tenantId: (0,
|
|
3369
|
+
const value2 = await secretInputValue(options, "secret");
|
|
3370
|
+
return { cfg, tenantId: (0, import_apps4.tenantIdFor)(cfg.app.id, options.env), value: value2, doFetch, out };
|
|
3348
3371
|
}
|
|
3349
3372
|
|
|
3350
3373
|
// src/skill.ts
|
|
@@ -3874,24 +3897,24 @@ var CONTROL = /[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/;
|
|
|
3874
3897
|
var HarnessProtocolError = class extends Error {
|
|
3875
3898
|
name = "HarnessProtocolError";
|
|
3876
3899
|
};
|
|
3877
|
-
function record2(
|
|
3878
|
-
return
|
|
3900
|
+
function record2(value2) {
|
|
3901
|
+
return value2 !== null && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
|
|
3879
3902
|
}
|
|
3880
|
-
function boundedText(
|
|
3881
|
-
if (typeof
|
|
3903
|
+
function boundedText(value2, label, max) {
|
|
3904
|
+
if (typeof value2 !== "string" || !value2 || value2.length > max || CONTROL.test(value2)) {
|
|
3882
3905
|
throw new HarnessProtocolError(`${label} must be a non-empty string of at most ${max} characters`);
|
|
3883
3906
|
}
|
|
3884
|
-
return
|
|
3907
|
+
return value2;
|
|
3885
3908
|
}
|
|
3886
3909
|
function parseAgentOutput(line) {
|
|
3887
3910
|
if (Buffer.byteLength(line, "utf8") > 1e6) throw new HarnessProtocolError("agent message exceeds 1 MB");
|
|
3888
|
-
let
|
|
3911
|
+
let value2;
|
|
3889
3912
|
try {
|
|
3890
|
-
|
|
3913
|
+
value2 = JSON.parse(line);
|
|
3891
3914
|
} catch {
|
|
3892
3915
|
throw new HarnessProtocolError("agent emitted invalid JSON");
|
|
3893
3916
|
}
|
|
3894
|
-
const message2 = record2(
|
|
3917
|
+
const message2 = record2(value2);
|
|
3895
3918
|
if (!message2 || message2.protocolVersion !== HARNESS_PROTOCOL_VERSION) {
|
|
3896
3919
|
throw new HarnessProtocolError(`agent protocolVersion must be ${HARNESS_PROTOCOL_VERSION}`);
|
|
3897
3920
|
}
|
|
@@ -4200,7 +4223,7 @@ async function gitOutput(cwd, args, maxBytes) {
|
|
|
4200
4223
|
else stdout.push(chunk);
|
|
4201
4224
|
});
|
|
4202
4225
|
child.stderr.on("data", (chunk) => {
|
|
4203
|
-
if (stderr.reduce((sum,
|
|
4226
|
+
if (stderr.reduce((sum, value2) => sum + value2.byteLength, 0) < 16384) stderr.push(chunk);
|
|
4204
4227
|
});
|
|
4205
4228
|
const code = await new Promise((accept, reject) => {
|
|
4206
4229
|
child.once("error", reject);
|
|
@@ -4221,7 +4244,7 @@ async function gitBlobs(cwd, entries, maxBytes) {
|
|
|
4221
4244
|
else stdout.push(chunk);
|
|
4222
4245
|
});
|
|
4223
4246
|
child.stderr.on("data", (chunk) => {
|
|
4224
|
-
if (stderr.reduce((sum,
|
|
4247
|
+
if (stderr.reduce((sum, value2) => sum + value2.byteLength, 0) < 16384) stderr.push(chunk);
|
|
4225
4248
|
});
|
|
4226
4249
|
child.stdin.end(`${entries.map((entry) => entry.hash).join("\n")}
|
|
4227
4250
|
`);
|
|
@@ -4259,8 +4282,8 @@ async function materializeGitTree(source, commitSha, options = {}) {
|
|
|
4259
4282
|
const maxFiles = options.maxFiles ?? 2e4;
|
|
4260
4283
|
const maxBytes = options.maxBytes ?? 512 * 1024 * 1024;
|
|
4261
4284
|
const inventory = (await gitOutput(sourceDir, ["ls-tree", "-rz", commitSha], 16 * 1024 * 1024)).toString("utf8").split("\0").filter(Boolean);
|
|
4262
|
-
const entries = inventory.flatMap((
|
|
4263
|
-
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);
|
|
4264
4287
|
return match && allowedWorkspacePath(match[3]) ? [{ mode: match[1], hash: match[2], path: match[3] }] : [];
|
|
4265
4288
|
});
|
|
4266
4289
|
if (entries.length > maxFiles) throw new Error(`workspace exceeds ${maxFiles} files`);
|
|
@@ -4335,7 +4358,7 @@ async function gitSourceFiles(sourceDir, maxFiles, maxBytes) {
|
|
|
4335
4358
|
else stdout.push(chunk);
|
|
4336
4359
|
});
|
|
4337
4360
|
child.stderr.on("data", (chunk) => {
|
|
4338
|
-
if (stderr.reduce((sum,
|
|
4361
|
+
if (stderr.reduce((sum, value2) => sum + value2.byteLength, 0) < 16384) stderr.push(chunk);
|
|
4339
4362
|
});
|
|
4340
4363
|
const code = await new Promise((accept, reject) => {
|
|
4341
4364
|
child.once("error", reject);
|
|
@@ -4395,7 +4418,7 @@ async function captureGitDiff(root, maxBytes) {
|
|
|
4395
4418
|
else stdout.push(chunk);
|
|
4396
4419
|
});
|
|
4397
4420
|
child.stderr.on("data", (chunk) => {
|
|
4398
|
-
if (stderr.reduce((sum,
|
|
4421
|
+
if (stderr.reduce((sum, value2) => sum + value2.byteLength, 0) < 16384) stderr.push(chunk);
|
|
4399
4422
|
});
|
|
4400
4423
|
const code = await new Promise((accept, reject) => {
|
|
4401
4424
|
child.once("error", reject);
|
|
@@ -4482,34 +4505,34 @@ var CamelError = class extends Error {
|
|
|
4482
4505
|
};
|
|
4483
4506
|
|
|
4484
4507
|
// ../camel/dist/chunk-L5DYU2E2.js
|
|
4485
|
-
function canonicalJson(
|
|
4486
|
-
return JSON.stringify(normalize(
|
|
4508
|
+
function canonicalJson(value2) {
|
|
4509
|
+
return JSON.stringify(normalize(value2));
|
|
4487
4510
|
}
|
|
4488
|
-
async function sha256Hex(
|
|
4489
|
-
const bytes = typeof
|
|
4511
|
+
async function sha256Hex(value2) {
|
|
4512
|
+
const bytes = typeof value2 === "string" ? new TextEncoder().encode(value2) : value2;
|
|
4490
4513
|
const digest = await crypto.subtle.digest("SHA-256", Uint8Array.from(bytes).buffer);
|
|
4491
4514
|
return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
4492
4515
|
}
|
|
4493
|
-
function utf8Length(
|
|
4494
|
-
if (typeof
|
|
4495
|
-
if (
|
|
4516
|
+
function utf8Length(value2) {
|
|
4517
|
+
if (typeof value2 === "string") return new TextEncoder().encode(value2).byteLength;
|
|
4518
|
+
if (value2 instanceof Uint8Array) return value2.byteLength;
|
|
4496
4519
|
try {
|
|
4497
|
-
return new TextEncoder().encode(canonicalJson(
|
|
4520
|
+
return new TextEncoder().encode(canonicalJson(value2)).byteLength;
|
|
4498
4521
|
} catch {
|
|
4499
4522
|
throw new CamelError("conversion_rejected", "Unsafe input could not be canonically measured.");
|
|
4500
4523
|
}
|
|
4501
4524
|
}
|
|
4502
|
-
function normalize(
|
|
4503
|
-
if (
|
|
4504
|
-
if (typeof
|
|
4505
|
-
if (!Number.isFinite(
|
|
4506
|
-
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;
|
|
4507
4530
|
}
|
|
4508
|
-
if (Array.isArray(
|
|
4509
|
-
if (
|
|
4510
|
-
if (typeof
|
|
4511
|
-
const
|
|
4512
|
-
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])]));
|
|
4513
4536
|
}
|
|
4514
4537
|
throw new CamelError("state_conflict", "Canonical JSON rejects unsupported values.");
|
|
4515
4538
|
}
|
|
@@ -4518,10 +4541,10 @@ function canRead(readers, readerId) {
|
|
|
4518
4541
|
}
|
|
4519
4542
|
function dependenciesOf(values, influence = "data") {
|
|
4520
4543
|
const result = [];
|
|
4521
|
-
for (const
|
|
4522
|
-
result.push(...
|
|
4523
|
-
for (const ref of
|
|
4524
|
-
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 });
|
|
4525
4548
|
}
|
|
4526
4549
|
}
|
|
4527
4550
|
const unique3 = /* @__PURE__ */ new Map();
|
|
@@ -4532,32 +4555,32 @@ function dependenciesOf(values, influence = "data") {
|
|
|
4532
4555
|
// ../camel/dist/chunk-S7EVNA2U.js
|
|
4533
4556
|
var camelValueBrand = /* @__PURE__ */ Symbol("@odla-ai/camel/value");
|
|
4534
4557
|
var authenticCamelValues = /* @__PURE__ */ new WeakSet();
|
|
4535
|
-
function isCamelValue(
|
|
4536
|
-
return typeof
|
|
4558
|
+
function isCamelValue(value2) {
|
|
4559
|
+
return typeof value2 === "object" && value2 !== null && authenticCamelValues.has(value2);
|
|
4537
4560
|
}
|
|
4538
|
-
function isSafe(
|
|
4539
|
-
return isCamelValue(
|
|
4561
|
+
function isSafe(value2) {
|
|
4562
|
+
return isCamelValue(value2) && value2.label.promptSafety === "safe";
|
|
4540
4563
|
}
|
|
4541
|
-
function isUnsafe(
|
|
4542
|
-
return isCamelValue(
|
|
4564
|
+
function isUnsafe(value2) {
|
|
4565
|
+
return isCamelValue(value2) && value2.label.promptSafety === "unsafe";
|
|
4543
4566
|
}
|
|
4544
|
-
function createSafeInternal(
|
|
4545
|
-
return createValue(
|
|
4567
|
+
function createSafeInternal(value2, safeBasis, metadata2) {
|
|
4568
|
+
return createValue(value2, {
|
|
4546
4569
|
schemaVersion: 1,
|
|
4547
4570
|
promptSafety: "safe",
|
|
4548
4571
|
safeBasis,
|
|
4549
4572
|
...copyMetadata(metadata2)
|
|
4550
4573
|
});
|
|
4551
4574
|
}
|
|
4552
|
-
function createUnsafeInternal(
|
|
4553
|
-
return createValue(
|
|
4575
|
+
function createUnsafeInternal(value2, metadata2) {
|
|
4576
|
+
return createValue(value2, {
|
|
4554
4577
|
schemaVersion: 1,
|
|
4555
4578
|
promptSafety: "unsafe",
|
|
4556
4579
|
...copyMetadata(metadata2)
|
|
4557
4580
|
});
|
|
4558
4581
|
}
|
|
4559
|
-
function createValue(
|
|
4560
|
-
const result = { value, label: Object.freeze(label) };
|
|
4582
|
+
function createValue(value2, label) {
|
|
4583
|
+
const result = { value: value2, label: Object.freeze(label) };
|
|
4561
4584
|
Object.defineProperty(result, camelValueBrand, { value: label.promptSafety, enumerable: false });
|
|
4562
4585
|
authenticCamelValues.add(result);
|
|
4563
4586
|
return Object.freeze(result);
|
|
@@ -4663,8 +4686,8 @@ async function createCodePortableCheckpoint(input) {
|
|
|
4663
4686
|
const checkpointDigest = `sha256:${await sha256Hex(canonicalJson(fields))}`;
|
|
4664
4687
|
return freeze({ ...fields, patch: input.patch, checkpointDigest });
|
|
4665
4688
|
}
|
|
4666
|
-
async function verifyCodePortableCheckpoint(
|
|
4667
|
-
const input = object(
|
|
4689
|
+
async function verifyCodePortableCheckpoint(value2) {
|
|
4690
|
+
const input = object(value2, "checkpoint");
|
|
4668
4691
|
exact2(input, ["schemaVersion", "baseCommitSha", "patch", "patchDigest", "state", "stateDigest", "checkpointDigest"]);
|
|
4669
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") {
|
|
4670
4693
|
throw invalid2("Portable checkpoint fields are malformed.");
|
|
@@ -4679,8 +4702,8 @@ async function verifyCodePortableCheckpoint(value) {
|
|
|
4679
4702
|
}
|
|
4680
4703
|
return created;
|
|
4681
4704
|
}
|
|
4682
|
-
function normalizeState(
|
|
4683
|
-
const state2 = object(
|
|
4705
|
+
function normalizeState(value2) {
|
|
4706
|
+
const state2 = object(value2, "state");
|
|
4684
4707
|
exact2(state2, [
|
|
4685
4708
|
"planCursor",
|
|
4686
4709
|
"conversationRefs",
|
|
@@ -4738,30 +4761,30 @@ function validateBaseAndPatch(baseCommitSha, patch2) {
|
|
|
4738
4761
|
throw invalid2("Portable checkpoint base or patch is malformed or outside its bounds.");
|
|
4739
4762
|
}
|
|
4740
4763
|
}
|
|
4741
|
-
function strings(
|
|
4742
|
-
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) {
|
|
4743
4766
|
throw invalid2(`Portable checkpoint ${name} is malformed or outside its bounds.`);
|
|
4744
4767
|
}
|
|
4745
|
-
const result = [...
|
|
4768
|
+
const result = [...value2];
|
|
4746
4769
|
return sort ? result.sort() : result;
|
|
4747
4770
|
}
|
|
4748
|
-
function object(
|
|
4749
|
-
if (!
|
|
4750
|
-
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;
|
|
4751
4774
|
}
|
|
4752
|
-
function exact2(
|
|
4753
|
-
if (Object.keys(
|
|
4775
|
+
function exact2(value2, keys) {
|
|
4776
|
+
if (Object.keys(value2).some((key) => !keys.includes(key)) || keys.some((key) => !(key in value2))) {
|
|
4754
4777
|
throw invalid2("Portable checkpoint contains missing or unsupported fields.");
|
|
4755
4778
|
}
|
|
4756
4779
|
}
|
|
4757
|
-
function freeze(
|
|
4780
|
+
function freeze(value2) {
|
|
4758
4781
|
return Object.freeze({
|
|
4759
|
-
...
|
|
4782
|
+
...value2,
|
|
4760
4783
|
state: Object.freeze({
|
|
4761
|
-
...
|
|
4762
|
-
conversationRefs: Object.freeze([...
|
|
4763
|
-
completedEffects: Object.freeze(
|
|
4764
|
-
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])
|
|
4765
4788
|
})
|
|
4766
4789
|
});
|
|
4767
4790
|
}
|
|
@@ -4852,61 +4875,61 @@ async function createConversionRegistry(config) {
|
|
|
4852
4875
|
if (utf8Length(source.value) > policy.maximumSourceBytes) throw new CamelError("limit_exceeded", "Unsafe conversion input exceeds its byte bound.");
|
|
4853
4876
|
return policy;
|
|
4854
4877
|
};
|
|
4855
|
-
const emit3 = (source, policy,
|
|
4878
|
+
const emit3 = (source, policy, value2) => convert(source, policy, value2, outputCounts);
|
|
4856
4879
|
const operations = Object.freeze({
|
|
4857
|
-
boolean: async (
|
|
4858
|
-
const policy = checked(
|
|
4859
|
-
return emit3(
|
|
4880
|
+
boolean: async (value2, id) => {
|
|
4881
|
+
const policy = checked(value2, id, "boolean");
|
|
4882
|
+
return emit3(value2, policy, requireBoolean(value2.value));
|
|
4860
4883
|
},
|
|
4861
|
-
integer: async (
|
|
4862
|
-
const policy = checked(
|
|
4863
|
-
return emit3(
|
|
4884
|
+
integer: async (value2, id) => {
|
|
4885
|
+
const policy = checked(value2, id, "integer");
|
|
4886
|
+
return emit3(value2, policy, boundedInteger(value2.value, policy.output));
|
|
4864
4887
|
},
|
|
4865
|
-
finiteNumber: async (
|
|
4866
|
-
const policy = checked(
|
|
4867
|
-
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));
|
|
4868
4891
|
},
|
|
4869
|
-
enum: async (
|
|
4870
|
-
const policy = checked(
|
|
4871
|
-
return emit3(
|
|
4892
|
+
enum: async (value2, id) => {
|
|
4893
|
+
const policy = checked(value2, id, "enum");
|
|
4894
|
+
return emit3(value2, policy, enumMember(value2.value, policy.output));
|
|
4872
4895
|
},
|
|
4873
|
-
date: async (
|
|
4874
|
-
const policy = checked(
|
|
4875
|
-
return emit3(
|
|
4896
|
+
date: async (value2, id) => {
|
|
4897
|
+
const policy = checked(value2, id, "date");
|
|
4898
|
+
return emit3(value2, policy, canonicalDate(value2.value, policy.output));
|
|
4876
4899
|
},
|
|
4877
|
-
registeredId: async (
|
|
4878
|
-
const policy = checked(
|
|
4900
|
+
registeredId: async (value2, id) => {
|
|
4901
|
+
const policy = checked(value2, id, "registered_id");
|
|
4879
4902
|
const registry = config.registeredIds?.[policy.output.registryId];
|
|
4880
|
-
const output = typeof
|
|
4903
|
+
const output = typeof value2.value === "string" ? registry?.values[value2.value] : void 0;
|
|
4881
4904
|
if (!output) throw new CamelError("conversion_rejected", "Registered-ID conversion rejected the candidate.");
|
|
4882
|
-
return emit3(
|
|
4905
|
+
return emit3(value2, policy, output);
|
|
4883
4906
|
},
|
|
4884
|
-
digest: async (
|
|
4885
|
-
const policy = checked(
|
|
4886
|
-
if (!(
|
|
4887
|
-
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));
|
|
4888
4911
|
},
|
|
4889
|
-
measure: async (
|
|
4890
|
-
const policy = checked(
|
|
4891
|
-
const measured = measure(
|
|
4892
|
-
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));
|
|
4893
4916
|
},
|
|
4894
|
-
test: async (
|
|
4895
|
-
const policy = checked(
|
|
4917
|
+
test: async (value2, predicateId, id) => {
|
|
4918
|
+
const policy = checked(value2, id, "boolean");
|
|
4896
4919
|
const predicate = config.predicates?.[predicateId];
|
|
4897
4920
|
if (!predicate) throw new CamelError("conversion_rejected", "Predicate is not registered.");
|
|
4898
|
-
return emit3(
|
|
4921
|
+
return emit3(value2, policy, evaluatePredicate(value2.value, predicate, config.registeredIds));
|
|
4899
4922
|
}
|
|
4900
4923
|
});
|
|
4901
4924
|
return Object.freeze({ operations, policy: (id) => policies.get(id) ?? missingPolicy() });
|
|
4902
4925
|
}
|
|
4903
|
-
async function convert(source, policy,
|
|
4926
|
+
async function convert(source, policy, value2, counts) {
|
|
4904
4927
|
const sourceKey = sourceIdentity(source);
|
|
4905
4928
|
const countKey = `${policy.conversionId}\0${sourceKey}`;
|
|
4906
4929
|
const count = counts.get(countKey) ?? 0;
|
|
4907
4930
|
if (count >= policy.maximumOutputsPerArtifact) throw new CamelError("limit_exceeded", "Conversion output count exceeds its per-source bound.");
|
|
4908
4931
|
counts.set(countKey, count + 1);
|
|
4909
|
-
return createSafeInternal(
|
|
4932
|
+
return createSafeInternal(value2, "atomic_conversion", {
|
|
4910
4933
|
readers: source.label.readers,
|
|
4911
4934
|
provenance: [...source.label.provenance, { kind: "converter", id: policy.conversionId, digest: policy.digest }],
|
|
4912
4935
|
dependencies: dependenciesOf([source])
|
|
@@ -4918,49 +4941,49 @@ function validatePolicyShape(policy) {
|
|
|
4918
4941
|
const output = policy.output;
|
|
4919
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.");
|
|
4920
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.");
|
|
4921
|
-
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.");
|
|
4922
4945
|
if (output.kind === "registered_id" && (!output.registryId || !output.registryDigest)) throw new CamelError("state_conflict", "Registered-ID conversion identity is invalid.");
|
|
4923
4946
|
if (output.kind === "date" && output.format !== "date" && output.format !== "rfc3339") throw new CamelError("state_conflict", "Date conversion format is invalid.");
|
|
4924
4947
|
if (output.kind === "digest" && output.algorithm !== "sha256") throw new CamelError("state_conflict", "Digest conversion algorithm is invalid.");
|
|
4925
4948
|
}
|
|
4926
|
-
function requireBoolean(
|
|
4927
|
-
if (typeof
|
|
4928
|
-
return
|
|
4949
|
+
function requireBoolean(value2) {
|
|
4950
|
+
if (typeof value2 !== "boolean") throw new CamelError("conversion_rejected", "Boolean conversion requires a structured boolean.");
|
|
4951
|
+
return value2;
|
|
4929
4952
|
}
|
|
4930
|
-
function boundedInteger(
|
|
4931
|
-
if (spec.kind !== "integer" || typeof
|
|
4932
|
-
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;
|
|
4933
4956
|
}
|
|
4934
|
-
function boundedNumber(
|
|
4935
|
-
if (spec.kind !== "finite_number" || typeof
|
|
4936
|
-
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);
|
|
4937
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.");
|
|
4938
|
-
return
|
|
4961
|
+
return value2;
|
|
4939
4962
|
}
|
|
4940
|
-
function enumMember(
|
|
4941
|
-
if (spec.kind !== "enum" || typeof
|
|
4942
|
-
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"));
|
|
4943
4966
|
if (member === void 0) throw new CamelError("conversion_rejected", "Enum conversion rejected a non-member.");
|
|
4944
4967
|
return member;
|
|
4945
4968
|
}
|
|
4946
|
-
function canonicalDate(
|
|
4947
|
-
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.");
|
|
4948
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})$/;
|
|
4949
|
-
const instant = Date.parse(spec.format === "date" ? `${
|
|
4950
|
-
if (!pattern.test(
|
|
4951
|
-
if (spec.earliest &&
|
|
4952
|
-
return
|
|
4953
|
-
}
|
|
4954
|
-
function measure(
|
|
4955
|
-
if (metric === "byte_length" && (typeof
|
|
4956
|
-
if (metric === "codepoint_length" && typeof
|
|
4957
|
-
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;
|
|
4958
4981
|
throw new CamelError("conversion_rejected", "Measurement input does not match the registered metric.");
|
|
4959
4982
|
}
|
|
4960
|
-
function evaluatePredicate(
|
|
4961
|
-
if (predicate.kind === "has_fields") return typeof
|
|
4962
|
-
if (predicate.kind === "registered_id") return typeof
|
|
4963
|
-
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;
|
|
4964
4987
|
return actual === predicate.valueType;
|
|
4965
4988
|
}
|
|
4966
4989
|
function sourceIdentity(source) {
|
|
@@ -4983,17 +5006,17 @@ function createCamelIngress(constants2 = []) {
|
|
|
4983
5006
|
byId.set(item.id, item);
|
|
4984
5007
|
}
|
|
4985
5008
|
const ingress = {
|
|
4986
|
-
userInstruction: (
|
|
4987
|
-
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)),
|
|
4988
5011
|
control: (id) => {
|
|
4989
5012
|
const item = byId.get(id);
|
|
4990
5013
|
if (!item) throw new CamelError("permission_denied", "Unknown control constant.");
|
|
4991
5014
|
return createSafeInternal(item.value, "harness_constant", metadata("harness", id, item.readers));
|
|
4992
5015
|
},
|
|
4993
|
-
external: (
|
|
4994
|
-
quarantinedOutput: (
|
|
5016
|
+
external: (value2, label) => createUnsafeInternal(value2, label),
|
|
5017
|
+
quarantinedOutput: (value2, input) => {
|
|
4995
5018
|
if (!input.runId) throw new CamelError("state_conflict", "Quarantined run IDs must be non-empty.");
|
|
4996
|
-
return createUnsafeInternal(
|
|
5019
|
+
return createUnsafeInternal(value2, {
|
|
4997
5020
|
readers: input.readers,
|
|
4998
5021
|
dependencies: input.dependencies,
|
|
4999
5022
|
provenance: [{ kind: "quarantined_llm", id: input.runId, digest: input.digest }]
|
|
@@ -5002,15 +5025,15 @@ function createCamelIngress(constants2 = []) {
|
|
|
5002
5025
|
};
|
|
5003
5026
|
return Object.freeze(ingress);
|
|
5004
5027
|
}
|
|
5005
|
-
function assertNoUnsafeConstant(
|
|
5006
|
-
if (typeof
|
|
5007
|
-
seen.add(
|
|
5008
|
-
if (isCamelValue(
|
|
5009
|
-
if (isUnsafe(
|
|
5010
|
-
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);
|
|
5011
5034
|
return;
|
|
5012
5035
|
}
|
|
5013
|
-
for (const child of Object.values(
|
|
5036
|
+
for (const child of Object.values(value2)) assertNoUnsafeConstant(child, seen);
|
|
5014
5037
|
}
|
|
5015
5038
|
function metadata(kind, id, readers) {
|
|
5016
5039
|
if (!id) throw new CamelError("state_conflict", "Provenance IDs must be non-empty.");
|
|
@@ -5041,7 +5064,7 @@ async function evaluate(input, registries, approvals) {
|
|
|
5041
5064
|
if (invalid3) return deny(invalid3);
|
|
5042
5065
|
if (arg.role === "selector" && !isSafe(arg.value)) confined.add(arg.value);
|
|
5043
5066
|
}
|
|
5044
|
-
if (input.controlDependencies.some((
|
|
5067
|
+
if (input.controlDependencies.some((value2) => !isSafe(value2) && !confined.has(value2))) return deny("unsafe_control_dependency");
|
|
5045
5068
|
if (confined.size > 0) {
|
|
5046
5069
|
const fixed = input.tool.unsafeSelectorPolicy?.fixedProviderIds ?? [];
|
|
5047
5070
|
const destinations = Object.values(input.args).filter((arg) => arg.role === "destination");
|
|
@@ -5068,29 +5091,29 @@ async function validateArgument(path, arg, tool, registries) {
|
|
|
5068
5091
|
if (!isSafe(arg.value)) return "unsafe_destination_argument";
|
|
5069
5092
|
if (!isControlOwned(arg.value)) return "destination_not_control_owned";
|
|
5070
5093
|
const registry = registries[arg.registryId];
|
|
5071
|
-
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;
|
|
5072
5095
|
if (!registry || !validValues || registry.digest !== arg.registryDigest || await destinationRegistryDigest(registry.values) !== registry.digest || !registry.values.includes(arg.value.value)) return "destination_not_registered";
|
|
5073
5096
|
}
|
|
5074
5097
|
if (arg.role === "selector" && !isSafe(arg.value)) return validateUnsafeSelector(path, arg.value, tool);
|
|
5075
5098
|
return void 0;
|
|
5076
5099
|
}
|
|
5077
|
-
function isControlOwned(
|
|
5078
|
-
return
|
|
5100
|
+
function isControlOwned(value2) {
|
|
5101
|
+
return value2.label.safeBasis === "system_policy" || value2.label.safeBasis === "harness_constant";
|
|
5079
5102
|
}
|
|
5080
5103
|
function copyRegistries(registries) {
|
|
5081
5104
|
return Object.freeze(Object.fromEntries(Object.entries(registries).map(([id, registry]) => [id, Object.freeze({ digest: registry.digest, values: Object.freeze([...registry.values]) })])));
|
|
5082
5105
|
}
|
|
5083
|
-
function validateUnsafeSelector(path,
|
|
5106
|
+
function validateUnsafeSelector(path, value2, tool) {
|
|
5084
5107
|
const policy = tool.unsafeSelectorPolicy;
|
|
5085
5108
|
if (!policy || policy.effect !== tool.effect || !policy.selectorPaths.includes(path)) return "unsafe_selector_not_confined";
|
|
5086
5109
|
if (!policy.fixedDestination || !policy.unsafeOutput || policy.fixedProviderIds.length === 0) return "unsafe_selector_not_confined";
|
|
5087
5110
|
if (![policy.maximumCalls, policy.maximumResultsPerCall, policy.maximumOutputBytes, policy.maximumSelectorBytes].every((bound) => Number.isSafeInteger(bound) && bound > 0)) return "unsafe_selector_not_confined";
|
|
5088
|
-
if (utf8Length(
|
|
5089
|
-
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";
|
|
5090
5113
|
return void 0;
|
|
5091
5114
|
}
|
|
5092
|
-
function looksLikeDestination(
|
|
5093
|
-
const text =
|
|
5115
|
+
function looksLikeDestination(value2) {
|
|
5116
|
+
const text = value2.trim();
|
|
5094
5117
|
return /^(?:[a-z][a-z0-9+.-]*:\/\/|\/|\\\\)/i.test(text) || /^[\w.-]+\.[a-z]{2,}(?:[/:]|$)/i.test(text);
|
|
5095
5118
|
}
|
|
5096
5119
|
|
|
@@ -5176,9 +5199,9 @@ var CodeRuntimeReconciler = class {
|
|
|
5176
5199
|
}
|
|
5177
5200
|
}
|
|
5178
5201
|
};
|
|
5179
|
-
function retryableControlFailure(
|
|
5180
|
-
if (!
|
|
5181
|
-
const failure =
|
|
5202
|
+
function retryableControlFailure(value2) {
|
|
5203
|
+
if (!value2 || typeof value2 !== "object") return false;
|
|
5204
|
+
const failure = value2;
|
|
5182
5205
|
if (failure.code === "invalid_response" || typeof failure.status !== "number") return false;
|
|
5183
5206
|
return failure.status === 408 || failure.status === 425 || failure.status === 429 || failure.status >= 500;
|
|
5184
5207
|
}
|
|
@@ -5230,16 +5253,16 @@ function createCodeRuntimeControlClient(options) {
|
|
|
5230
5253
|
if (options.signal?.aborted) throw cause;
|
|
5231
5254
|
throw new CodeRuntimeControlError("Code runtime control plane is unavailable", 503, "transport_unavailable");
|
|
5232
5255
|
}
|
|
5233
|
-
const
|
|
5256
|
+
const value2 = await response2.json().catch(() => null);
|
|
5234
5257
|
if (!response2.ok) {
|
|
5235
|
-
const problem = record3(record3(
|
|
5258
|
+
const problem = record3(record3(value2)?.error);
|
|
5236
5259
|
throw new CodeRuntimeControlError(
|
|
5237
5260
|
typeof problem?.message === "string" ? problem.message : `Code runtime request failed (${response2.status})`,
|
|
5238
5261
|
response2.status,
|
|
5239
5262
|
typeof problem?.code === "string" ? problem.code : void 0
|
|
5240
5263
|
);
|
|
5241
5264
|
}
|
|
5242
|
-
return
|
|
5265
|
+
return value2;
|
|
5243
5266
|
};
|
|
5244
5267
|
return {
|
|
5245
5268
|
heartbeat: async (version, capabilities) => {
|
|
@@ -5254,15 +5277,15 @@ function createCodeRuntimeControlClient(options) {
|
|
|
5254
5277
|
await call2(`/registry/code/runtime/sessions/${validSessionId(sessionId)}/source`, {})
|
|
5255
5278
|
),
|
|
5256
5279
|
infer: async (sessionId, inference) => {
|
|
5257
|
-
const
|
|
5280
|
+
const value2 = record3(await call2(
|
|
5258
5281
|
`/registry/code/runtime/sessions/${validSessionId(sessionId)}/inference`,
|
|
5259
5282
|
inference,
|
|
5260
5283
|
modelRequestTimeoutMs
|
|
5261
5284
|
));
|
|
5262
|
-
if (!
|
|
5285
|
+
if (!value2 || value2.requestId !== inference.requestId || !record3(value2.response) || !record3(value2.receipt)) {
|
|
5263
5286
|
throw new CodeRuntimeControlError("invalid Code inference response", 502, "invalid_response");
|
|
5264
5287
|
}
|
|
5265
|
-
return
|
|
5288
|
+
return value2;
|
|
5266
5289
|
},
|
|
5267
5290
|
review: async (sessionId, review) => parseReview(
|
|
5268
5291
|
await call2(`/registry/code/runtime/sessions/${validSessionId(sessionId)}/review`, review, modelRequestTimeoutMs)
|
|
@@ -5287,8 +5310,8 @@ function createCodeRuntimeControlClient(options) {
|
|
|
5287
5310
|
}
|
|
5288
5311
|
};
|
|
5289
5312
|
}
|
|
5290
|
-
function validatedEndpoint(
|
|
5291
|
-
const endpoint =
|
|
5313
|
+
function validatedEndpoint(value2) {
|
|
5314
|
+
const endpoint = value2.replace(/\/+$/, "");
|
|
5292
5315
|
let url;
|
|
5293
5316
|
try {
|
|
5294
5317
|
url = new URL(endpoint);
|
|
@@ -5301,9 +5324,9 @@ function validatedEndpoint(value) {
|
|
|
5301
5324
|
}
|
|
5302
5325
|
return endpoint;
|
|
5303
5326
|
}
|
|
5304
|
-
function validSessionId(
|
|
5305
|
-
if (!/^csess_[0-9a-f]{32}$/.test(
|
|
5306
|
-
return
|
|
5327
|
+
function validSessionId(value2) {
|
|
5328
|
+
if (!/^csess_[0-9a-f]{32}$/.test(value2)) throw new TypeError("invalid Code session id");
|
|
5329
|
+
return value2;
|
|
5307
5330
|
}
|
|
5308
5331
|
function validateHeartbeat(version, capabilities) {
|
|
5309
5332
|
if (!version.trim() || version.length > 80) throw new TypeError("runtimeVersion is required and at most 80 characters");
|
|
@@ -5316,8 +5339,8 @@ function validateHeartbeat(version, capabilities) {
|
|
|
5316
5339
|
throw new TypeError("runtime resources must be positive integers");
|
|
5317
5340
|
}
|
|
5318
5341
|
}
|
|
5319
|
-
function parseSnapshot(
|
|
5320
|
-
const root = record3(
|
|
5342
|
+
function parseSnapshot(value2) {
|
|
5343
|
+
const root = record3(value2);
|
|
5321
5344
|
const host = record3(root?.host);
|
|
5322
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");
|
|
5323
5346
|
const bindingIds = /* @__PURE__ */ new Set();
|
|
@@ -5342,11 +5365,11 @@ function parseSnapshot(value) {
|
|
|
5342
5365
|
});
|
|
5343
5366
|
return { host, bindings, commands };
|
|
5344
5367
|
}
|
|
5345
|
-
async function parseSource(
|
|
5346
|
-
const snapshot = record3(record3(
|
|
5368
|
+
async function parseSource(value2) {
|
|
5369
|
+
const snapshot = record3(record3(value2)?.snapshot);
|
|
5347
5370
|
if (!snapshot || typeof snapshot.repository !== "string" || typeof snapshot.commitSha !== "string" || typeof snapshot.treeDigest !== "string" || !Array.isArray(snapshot.files)) throw invalid("source");
|
|
5348
|
-
const files = snapshot.files.map((
|
|
5349
|
-
const file = record3(
|
|
5371
|
+
const files = snapshot.files.map((value22) => {
|
|
5372
|
+
const file = record3(value22);
|
|
5350
5373
|
if (!file || typeof file.path !== "string" || typeof file.content !== "string") throw invalid("source file");
|
|
5351
5374
|
return { path: file.path, content: file.content };
|
|
5352
5375
|
});
|
|
@@ -5373,19 +5396,19 @@ async function parseSource(value) {
|
|
|
5373
5396
|
if (digest !== snapshot.treeDigest) throw invalid("source digest");
|
|
5374
5397
|
return { ...source, treeDigest: digest, ...references.length ? { references } : {} };
|
|
5375
5398
|
}
|
|
5376
|
-
function parseReview(
|
|
5377
|
-
const review = record3(record3(
|
|
5399
|
+
function parseReview(value2) {
|
|
5400
|
+
const review = record3(record3(value2)?.review);
|
|
5378
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");
|
|
5379
5402
|
return review;
|
|
5380
5403
|
}
|
|
5381
|
-
function parseCandidate(
|
|
5382
|
-
const candidate = record3(record3(
|
|
5404
|
+
function parseCandidate(value2) {
|
|
5405
|
+
const candidate = record3(record3(value2)?.candidate);
|
|
5383
5406
|
if (!candidate || typeof candidate.candidateId !== "string" || !/^ccand_[0-9a-f]{32}$/.test(candidate.candidateId) || !["submitted", "approved", "published", "failed"].includes(String(candidate.status))) {
|
|
5384
5407
|
throw invalid("candidate");
|
|
5385
5408
|
}
|
|
5386
5409
|
return { candidateId: candidate.candidateId, status: candidate.status };
|
|
5387
5410
|
}
|
|
5388
|
-
var record3 = (
|
|
5411
|
+
var record3 = (value2) => value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
|
|
5389
5412
|
var invalid = (part) => new CodeRuntimeControlError(`invalid Code runtime ${part} response`, 502, "invalid_response");
|
|
5390
5413
|
var RESERVED = /* @__PURE__ */ new Set([".git", ".odla", ".wrangler", "node_modules", "dist", "coverage"]);
|
|
5391
5414
|
var SECRET = /^(?:\.env(?:\..+)?|\.dev\.vars|credentials(?:\..+)?\.json|dev-token(?:\..+)?\.json)$/i;
|
|
@@ -5419,8 +5442,8 @@ function validateCodePatch(patch2, maxBytes) {
|
|
|
5419
5442
|
if (!paths.length || new Set(paths).size !== paths.length) throw new TypeError("patch has no diffs or repeats a path");
|
|
5420
5443
|
return paths;
|
|
5421
5444
|
}
|
|
5422
|
-
function validHeaderPath(
|
|
5423
|
-
return
|
|
5445
|
+
function validHeaderPath(value2, path, prefix) {
|
|
5446
|
+
return value2 === "/dev/null" || value2 === `${prefix}/${path}`;
|
|
5424
5447
|
}
|
|
5425
5448
|
function validateRelativePath(path) {
|
|
5426
5449
|
const parts = path.split("/");
|
|
@@ -5566,8 +5589,8 @@ function assertCodeBuildRecipe(recipe2) {
|
|
|
5566
5589
|
throw new TypeError("build recipe is malformed or exceeds its control bounds");
|
|
5567
5590
|
}
|
|
5568
5591
|
}
|
|
5569
|
-
function parseMemory(
|
|
5570
|
-
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());
|
|
5571
5594
|
if (!match?.[1] || !match[2]) return 0;
|
|
5572
5595
|
const scale = match[2] === "k" ? 1024 : match[2] === "m" ? 1024 ** 2 : 1024 ** 3;
|
|
5573
5596
|
return Number(match[1]) * scale;
|
|
@@ -5802,14 +5825,14 @@ function normalizedRecipe(recipe2) {
|
|
|
5802
5825
|
expectedArtifacts: [...recipe2.expectedArtifacts ?? []].sort((left, right) => left.id.localeCompare(right.id)).map((artifact) => ({ id: artifact.id, path: artifact.path, maximumBytes: artifact.maximumBytes }))
|
|
5803
5826
|
};
|
|
5804
5827
|
}
|
|
5805
|
-
function digestJson(
|
|
5806
|
-
return digestBytes(JSON.stringify(
|
|
5828
|
+
function digestJson(value2) {
|
|
5829
|
+
return digestBytes(JSON.stringify(value2));
|
|
5807
5830
|
}
|
|
5808
|
-
function digestBytes(
|
|
5809
|
-
return `sha256:${(0, import_crypto3.createHash)("sha256").update(
|
|
5831
|
+
function digestBytes(value2) {
|
|
5832
|
+
return `sha256:${(0, import_crypto3.createHash)("sha256").update(value2).digest("hex")}`;
|
|
5810
5833
|
}
|
|
5811
|
-
function integer(
|
|
5812
|
-
return Number.isSafeInteger(
|
|
5834
|
+
function integer(value2, minimum, maximum) {
|
|
5835
|
+
return Number.isSafeInteger(value2) && value2 >= minimum && value2 <= maximum;
|
|
5813
5836
|
}
|
|
5814
5837
|
async function prepareRuntimeCheckpoint(input) {
|
|
5815
5838
|
const patch2 = await input.workspace.patch(256 * 1024);
|
|
@@ -5862,7 +5885,7 @@ async function prepareRuntimeCheckpoint(input) {
|
|
|
5862
5885
|
});
|
|
5863
5886
|
return { checkpoint, verification, review, note };
|
|
5864
5887
|
}
|
|
5865
|
-
var message = (
|
|
5888
|
+
var message = (value2) => (value2 instanceof Error ? value2.message : String(value2)).slice(0, 500);
|
|
5866
5889
|
var CodeRuntimeCheckpointManager = class {
|
|
5867
5890
|
constructor(options) {
|
|
5868
5891
|
this.options = options;
|
|
@@ -6056,7 +6079,7 @@ async function conversionPolicy(id, output) {
|
|
|
6056
6079
|
return { ...definition, digest: await conversionPolicyDigest(definition) };
|
|
6057
6080
|
}
|
|
6058
6081
|
async function registeredPolicy(id, registryId, values) {
|
|
6059
|
-
const mapping = Object.fromEntries(values.map((
|
|
6082
|
+
const mapping = Object.fromEntries(values.map((value2) => [value2, value2]));
|
|
6060
6083
|
return conversionPolicy(id, {
|
|
6061
6084
|
kind: "registered_id",
|
|
6062
6085
|
registryId,
|
|
@@ -6065,7 +6088,7 @@ async function registeredPolicy(id, registryId, values) {
|
|
|
6065
6088
|
}
|
|
6066
6089
|
async function conversionRegistry(policies, values) {
|
|
6067
6090
|
const registeredIds = Object.fromEntries(await Promise.all(Object.entries(values).map(async ([id, entries]) => {
|
|
6068
|
-
const mapping = Object.fromEntries(entries.map((
|
|
6091
|
+
const mapping = Object.fromEntries(entries.map((value2) => [value2, value2]));
|
|
6069
6092
|
return [id, { values: mapping, digest: await registeredIdRegistryDigest(mapping) }];
|
|
6070
6093
|
})));
|
|
6071
6094
|
return createConversionRegistry({ policies, registeredIds });
|
|
@@ -6089,8 +6112,8 @@ async function environment(input, options, tool) {
|
|
|
6089
6112
|
};
|
|
6090
6113
|
return { ingress, policy, fixedArgs, reader: ingress.control("reader"), runId: `${input.request.requestId}:${tool}` };
|
|
6091
6114
|
}
|
|
6092
|
-
function unsafe(base,
|
|
6093
|
-
return base.ingress.quarantinedOutput(
|
|
6115
|
+
function unsafe(base, value2, field) {
|
|
6116
|
+
return base.ingress.quarantinedOutput(value2, {
|
|
6094
6117
|
readers: base.reader.label.readers,
|
|
6095
6118
|
runId: `${base.runId}:${field}`
|
|
6096
6119
|
});
|
|
@@ -6170,14 +6193,14 @@ async function read(context, request2, options, policy) {
|
|
|
6170
6193
|
}
|
|
6171
6194
|
async function patch(context, request2, options, policy) {
|
|
6172
6195
|
exactKeys(request2.input, ["patch"]);
|
|
6173
|
-
const
|
|
6174
|
-
const paths = validateCodePatch(
|
|
6196
|
+
const value2 = stringField(request2.input, "patch");
|
|
6197
|
+
const paths = validateCodePatch(value2, options.maxPatchBytes ?? 256 * 1024);
|
|
6175
6198
|
if (paths.some((path) => options.readOnlyPrefixes?.some((prefix) => path === prefix || path.startsWith(`${prefix}/`)))) {
|
|
6176
6199
|
throw new TypeError("patch targets a read-only reference source");
|
|
6177
6200
|
}
|
|
6178
|
-
const allowed = await policy.patch(policyContext(context, request2, options, { patch:
|
|
6201
|
+
const allowed = await policy.patch(policyContext(context, request2, options, { patch: value2 }));
|
|
6179
6202
|
if (!allowed) return response(request2, false, "tool denied by CaMeL policy");
|
|
6180
|
-
await applyCodePatch(context.workspaceDir,
|
|
6203
|
+
await applyCodePatch(context.workspaceDir, value2, paths);
|
|
6181
6204
|
return response(request2, true, `Applied patch to ${paths.length} file(s).`, { paths });
|
|
6182
6205
|
}
|
|
6183
6206
|
async function recipe(context, request2, options, recipes, policy) {
|
|
@@ -6268,14 +6291,14 @@ function exactKeys(input, allowed) {
|
|
|
6268
6291
|
if (Object.keys(input).some((key) => !allowed.includes(key))) throw new TypeError("tool input contains an unsupported field");
|
|
6269
6292
|
}
|
|
6270
6293
|
function stringField(input, name) {
|
|
6271
|
-
const
|
|
6272
|
-
if (typeof
|
|
6273
|
-
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;
|
|
6274
6297
|
}
|
|
6275
|
-
function optionalInteger(
|
|
6276
|
-
if (
|
|
6277
|
-
if (!Number.isSafeInteger(
|
|
6278
|
-
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;
|
|
6279
6302
|
}
|
|
6280
6303
|
function response(request2, ok, content2, details) {
|
|
6281
6304
|
return { requestId: request2.requestId, ok, content: content2, ...details ? { details } : {} };
|
|
@@ -6321,9 +6344,9 @@ function codeLocalSource(payload) {
|
|
|
6321
6344
|
return source;
|
|
6322
6345
|
}
|
|
6323
6346
|
function codeCheckpointPayload(payload) {
|
|
6324
|
-
const
|
|
6325
|
-
if (!
|
|
6326
|
-
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;
|
|
6327
6350
|
}
|
|
6328
6351
|
function fakeCodeLease(command, metadata2) {
|
|
6329
6352
|
return {
|
|
@@ -6347,7 +6370,7 @@ function fakeCodeLease(command, metadata2) {
|
|
|
6347
6370
|
}
|
|
6348
6371
|
};
|
|
6349
6372
|
}
|
|
6350
|
-
var record22 = (
|
|
6373
|
+
var record22 = (value2) => value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
|
|
6351
6374
|
var SOURCE_LIMITS = { maxFiles: 2e4, maxBytes: 512 * 1024 * 1024 };
|
|
6352
6375
|
async function prepareRuntimeLocalSource(input) {
|
|
6353
6376
|
const { command, descriptor: descriptor2, available, repository, baseCommitSha, resume } = input;
|
|
@@ -6437,24 +6460,24 @@ async function appendCodeRuntimeEvent(control, command, event, refs) {
|
|
|
6437
6460
|
const bounded = event.type === "message" ? { ...event, body: event.body.trim().slice(0, 2e4) || `${event.actor} event` } : event;
|
|
6438
6461
|
await control.appendSessionEvent(command.sessionId, eventId, bounded);
|
|
6439
6462
|
}
|
|
6440
|
-
var digestRuntimeValue = (
|
|
6441
|
-
var runtimeErrorMessage = (
|
|
6442
|
-
var runtimeRecord = (
|
|
6443
|
-
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) => {
|
|
6444
6467
|
try {
|
|
6445
|
-
return JSON.stringify(
|
|
6468
|
+
return JSON.stringify(value2).slice(0, 1e4);
|
|
6446
6469
|
} catch {
|
|
6447
6470
|
return "[event]";
|
|
6448
6471
|
}
|
|
6449
6472
|
};
|
|
6450
|
-
function runtimeResultText(
|
|
6451
|
-
const record32 = runtimeRecord(
|
|
6473
|
+
function runtimeResultText(value2) {
|
|
6474
|
+
const record32 = runtimeRecord(value2);
|
|
6452
6475
|
if (record32 && typeof record32.text === "string") return record32.text.slice(0, 2e4);
|
|
6453
6476
|
if (record32 && typeof record32.error === "string") return `Pi failed: ${record32.error.slice(0, 19989)}`;
|
|
6454
6477
|
return null;
|
|
6455
6478
|
}
|
|
6456
|
-
function runtimeResultError(
|
|
6457
|
-
const record32 = runtimeRecord(
|
|
6479
|
+
function runtimeResultError(value2) {
|
|
6480
|
+
const record32 = runtimeRecord(value2);
|
|
6458
6481
|
return record32 && typeof record32.error === "string" && record32.error.trim() ? record32.error.trim().slice(0, 2e3) : null;
|
|
6459
6482
|
}
|
|
6460
6483
|
var CodePiRuntimeEngine = class {
|
|
@@ -6728,14 +6751,14 @@ var CodePiRuntimeEngine = class {
|
|
|
6728
6751
|
this.#active.delete(command.sessionId);
|
|
6729
6752
|
return result;
|
|
6730
6753
|
}
|
|
6731
|
-
async #failure(command, active,
|
|
6732
|
-
active.failure =
|
|
6754
|
+
async #failure(command, active, value2) {
|
|
6755
|
+
active.failure = value2.slice(0, 2e3);
|
|
6733
6756
|
if (active.acknowledged) {
|
|
6734
6757
|
await this.options.control.reportSessionFailure(command.sessionId, active.failure).catch(() => void 0);
|
|
6735
6758
|
}
|
|
6736
6759
|
}
|
|
6737
|
-
async #diagnostic(command, active,
|
|
6738
|
-
const detail =
|
|
6760
|
+
async #diagnostic(command, active, value2) {
|
|
6761
|
+
const detail = value2.trim().slice(0, 2e3) || "Pi runtime failed";
|
|
6739
6762
|
this.options.onDiagnostic?.(detail);
|
|
6740
6763
|
await this.#event(
|
|
6741
6764
|
command,
|
|
@@ -6820,6 +6843,7 @@ Usage:
|
|
|
6820
6843
|
odla-ai context save <name> [--platform <url>] [--app <id>] [--env <name>] [--json]
|
|
6821
6844
|
odla-ai context remove <name> --yes [--json]
|
|
6822
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]
|
|
6823
6847
|
odla-ai whoami [--context <name>] [--platform https://odla.ai] [--json]
|
|
6824
6848
|
odla-ai runbook ask "<question>" [--app <id>] [--all] [--json]
|
|
6825
6849
|
odla-ai runbook search "<question>" [--app <id>] [--all] [--limit <n>] [--json]
|
|
@@ -6944,6 +6968,8 @@ Commands:
|
|
|
6944
6968
|
canary, collector ingest/scheduler trust, Cloudflare-owned
|
|
6945
6969
|
runtime metrics, and a machine verdict.
|
|
6946
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.
|
|
6947
6973
|
provision Register services, compose integrations, persist credentials, optionally push secrets.
|
|
6948
6974
|
smoke Verify credentials, public-config, composed schema, db aggregate, and integration probes.
|
|
6949
6975
|
skill Same installer; --agent accepts all, claude, codex, cursor,
|
|
@@ -7030,31 +7056,31 @@ async function requestHostedSecurityJson(options, path, init, action) {
|
|
|
7030
7056
|
}
|
|
7031
7057
|
return body;
|
|
7032
7058
|
}
|
|
7033
|
-
function hostedIdentifier(
|
|
7034
|
-
const result = optionalHostedText(
|
|
7059
|
+
function hostedIdentifier(value2, name) {
|
|
7060
|
+
const result = optionalHostedText(value2, name, 180);
|
|
7035
7061
|
if (!result || !/^[A-Za-z0-9][A-Za-z0-9._:-]*$/.test(result)) {
|
|
7036
7062
|
throw new Error(`${name} is invalid`);
|
|
7037
7063
|
}
|
|
7038
7064
|
return result;
|
|
7039
7065
|
}
|
|
7040
|
-
function positivePolicyVersion(
|
|
7041
|
-
if (!Number.isSafeInteger(
|
|
7066
|
+
function positivePolicyVersion(value2, name) {
|
|
7067
|
+
if (!Number.isSafeInteger(value2) || value2 < 1) {
|
|
7042
7068
|
throw new Error(`${name} is invalid`);
|
|
7043
7069
|
}
|
|
7044
|
-
return
|
|
7070
|
+
return value2;
|
|
7045
7071
|
}
|
|
7046
|
-
function optionalHostedText(
|
|
7047
|
-
if (
|
|
7048
|
-
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)) {
|
|
7049
7075
|
throw new Error(`${name} is invalid`);
|
|
7050
7076
|
}
|
|
7051
|
-
return
|
|
7077
|
+
return value2;
|
|
7052
7078
|
}
|
|
7053
|
-
function githubRepositoryName(
|
|
7054
|
-
if (typeof
|
|
7079
|
+
function githubRepositoryName(value2) {
|
|
7080
|
+
if (typeof value2 !== "string" || value2.length > 201) {
|
|
7055
7081
|
throw new Error("repository must be owner/name");
|
|
7056
7082
|
}
|
|
7057
|
-
const parts =
|
|
7083
|
+
const parts = value2.split("/");
|
|
7058
7084
|
const owner = parts[0] ?? "";
|
|
7059
7085
|
const name = (parts[1] ?? "").replace(/\.git$/i, "");
|
|
7060
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 === "..") {
|
|
@@ -7062,10 +7088,10 @@ function githubRepositoryName(value) {
|
|
|
7062
7088
|
}
|
|
7063
7089
|
return `${owner}/${name}`;
|
|
7064
7090
|
}
|
|
7065
|
-
function trustedGitHubInstallUrl(
|
|
7091
|
+
function trustedGitHubInstallUrl(value2) {
|
|
7066
7092
|
let url;
|
|
7067
7093
|
try {
|
|
7068
|
-
url = new URL(
|
|
7094
|
+
url = new URL(value2);
|
|
7069
7095
|
} catch {
|
|
7070
7096
|
throw new Error("odla.ai returned an invalid GitHub installation URL");
|
|
7071
7097
|
}
|
|
@@ -7074,17 +7100,17 @@ function trustedGitHubInstallUrl(value) {
|
|
|
7074
7100
|
}
|
|
7075
7101
|
return url.toString();
|
|
7076
7102
|
}
|
|
7077
|
-
function hostedPollInterval(
|
|
7078
|
-
if (!Number.isSafeInteger(
|
|
7103
|
+
function hostedPollInterval(value2 = 2e3) {
|
|
7104
|
+
if (!Number.isSafeInteger(value2) || value2 < 100 || value2 > 3e4) {
|
|
7079
7105
|
throw new Error("poll interval must be 100-30000ms");
|
|
7080
7106
|
}
|
|
7081
|
-
return
|
|
7107
|
+
return value2;
|
|
7082
7108
|
}
|
|
7083
|
-
function hostedPollTimeout(
|
|
7084
|
-
if (!Number.isSafeInteger(
|
|
7109
|
+
function hostedPollTimeout(value2 = 10 * 6e4) {
|
|
7110
|
+
if (!Number.isSafeInteger(value2) || value2 < 1e3 || value2 > 60 * 6e4) {
|
|
7085
7111
|
throw new Error("poll timeout must be 1000-3600000ms");
|
|
7086
7112
|
}
|
|
7087
|
-
return
|
|
7113
|
+
return value2;
|
|
7088
7114
|
}
|
|
7089
7115
|
async function waitForHostedPoll(milliseconds, signal) {
|
|
7090
7116
|
if (signal?.aborted) throw signal.reason ?? new DOMException("aborted", "AbortError");
|
|
@@ -7096,16 +7122,16 @@ async function waitForHostedPoll(milliseconds, signal) {
|
|
|
7096
7122
|
}, { once: true });
|
|
7097
7123
|
});
|
|
7098
7124
|
}
|
|
7099
|
-
function isValidHostedSecurityPlan(
|
|
7100
|
-
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;
|
|
7101
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;
|
|
7102
|
-
return validRoute(
|
|
7128
|
+
return validRoute(value2.routes?.discovery, "security.discovery") && validRoute(value2.routes?.validation, "security.validation");
|
|
7103
7129
|
}
|
|
7104
|
-
function hostedSecurityCredential(
|
|
7105
|
-
if (typeof
|
|
7130
|
+
function hostedSecurityCredential(value2) {
|
|
7131
|
+
if (typeof value2 !== "string" || value2.length < 8 || value2.length > 8192 || /\s|[\u0000-\u001f\u007f]/.test(value2)) {
|
|
7106
7132
|
throw new Error("Hosted security requires an injected odla developer token");
|
|
7107
7133
|
}
|
|
7108
|
-
return
|
|
7134
|
+
return value2;
|
|
7109
7135
|
}
|
|
7110
7136
|
|
|
7111
7137
|
// src/security-hosted-github.ts
|
|
@@ -7258,17 +7284,17 @@ async function prepareCodeLocalSource(cwd, repository, readHead = readGitHead) {
|
|
|
7258
7284
|
}
|
|
7259
7285
|
}
|
|
7260
7286
|
async function readGitHead(cwd) {
|
|
7261
|
-
const
|
|
7287
|
+
const value2 = await new Promise((accept, reject) => {
|
|
7262
7288
|
(0, import_node_child_process5.execFile)("git", ["rev-parse", "HEAD"], { cwd, encoding: "utf8", maxBuffer: 16384 }, (error, stdout) => {
|
|
7263
7289
|
if (error) reject(new Error("code connect requires a Git checkout with an initial commit"));
|
|
7264
7290
|
else accept(stdout.trim());
|
|
7265
7291
|
});
|
|
7266
7292
|
});
|
|
7267
|
-
if (!/^[0-9a-f]{40}$/.test(
|
|
7268
|
-
return
|
|
7293
|
+
if (!/^[0-9a-f]{40}$/.test(value2)) throw new Error("code connect could not resolve the checkout HEAD commit");
|
|
7294
|
+
return value2;
|
|
7269
7295
|
}
|
|
7270
|
-
function digestText(
|
|
7271
|
-
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")}`;
|
|
7272
7298
|
}
|
|
7273
7299
|
|
|
7274
7300
|
// src/code-images.ts
|
|
@@ -7539,8 +7565,8 @@ async function runCodeRuntime(input) {
|
|
|
7539
7565
|
for (const [name, handler] of handlers) process.removeListener(name, handler);
|
|
7540
7566
|
}
|
|
7541
7567
|
}
|
|
7542
|
-
function parseConnection(
|
|
7543
|
-
const root = record4(
|
|
7568
|
+
function parseConnection(value2, appId, appEnv) {
|
|
7569
|
+
const root = record4(value2);
|
|
7544
7570
|
const host = record4(root?.host);
|
|
7545
7571
|
const offer = record4(root?.offer);
|
|
7546
7572
|
const binding = record4(root?.binding);
|
|
@@ -7549,12 +7575,12 @@ function parseConnection(value, appId, appEnv) {
|
|
|
7549
7575
|
}
|
|
7550
7576
|
return root;
|
|
7551
7577
|
}
|
|
7552
|
-
function apiFailure(action, status,
|
|
7553
|
-
const message2 = record4(record4(
|
|
7578
|
+
function apiFailure(action, status, value2) {
|
|
7579
|
+
const message2 = record4(record4(value2)?.error)?.message;
|
|
7554
7580
|
return `${action} failed (${status})${typeof message2 === "string" ? `: ${message2}` : ""}`;
|
|
7555
7581
|
}
|
|
7556
|
-
function record4(
|
|
7557
|
-
return
|
|
7582
|
+
function record4(value2) {
|
|
7583
|
+
return value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
|
|
7558
7584
|
}
|
|
7559
7585
|
|
|
7560
7586
|
// src/code-command.ts
|
|
@@ -7613,8 +7639,8 @@ function developerTokenStatus(context, parsed, now = Date.now()) {
|
|
|
7613
7639
|
cacheStatus
|
|
7614
7640
|
};
|
|
7615
7641
|
}
|
|
7616
|
-
function clean3(
|
|
7617
|
-
const normalized =
|
|
7642
|
+
function clean3(value2) {
|
|
7643
|
+
const normalized = value2?.trim();
|
|
7618
7644
|
return normalized || void 0;
|
|
7619
7645
|
}
|
|
7620
7646
|
|
|
@@ -7763,8 +7789,8 @@ async function request(ctx, method, path, body) {
|
|
|
7763
7789
|
throw new Error(`discuss ${method} ${path} failed: ${data.error ?? `registry returned ${res.status}`}`);
|
|
7764
7790
|
return data;
|
|
7765
7791
|
}
|
|
7766
|
-
function emit(ctx,
|
|
7767
|
-
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));
|
|
7768
7794
|
else human();
|
|
7769
7795
|
}
|
|
7770
7796
|
var state = (topic) => topic.resolved ? "resolved" : "open";
|
|
@@ -7809,8 +7835,8 @@ async function discussList(ctx, parsed) {
|
|
|
7809
7835
|
["limit", "limit"],
|
|
7810
7836
|
["offset", "offset"]
|
|
7811
7837
|
]) {
|
|
7812
|
-
const
|
|
7813
|
-
if (
|
|
7838
|
+
const value2 = stringOpt(parsed.options[flag]);
|
|
7839
|
+
if (value2) query.set(param, value2);
|
|
7814
7840
|
}
|
|
7815
7841
|
const qs = query.toString();
|
|
7816
7842
|
const page = await request(ctx, "GET", `/topics${qs ? `?${qs}` : ""}`);
|
|
@@ -8007,11 +8033,11 @@ var MAX_CONSECUTIVE_FAILURES = 5;
|
|
|
8007
8033
|
var MAX_BACKOFF_MS = 3e4;
|
|
8008
8034
|
function numberOpt2(parsed, flag, fallback) {
|
|
8009
8035
|
const raw = stringOpt(parsed.options[flag]);
|
|
8010
|
-
const
|
|
8011
|
-
return Number.isFinite(
|
|
8036
|
+
const value2 = raw == null ? NaN : Number(raw);
|
|
8037
|
+
return Number.isFinite(value2) && value2 > 0 ? value2 : fallback;
|
|
8012
8038
|
}
|
|
8013
|
-
function jsonl(ctx, parsed,
|
|
8014
|
-
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 }));
|
|
8015
8041
|
}
|
|
8016
8042
|
async function discussWatch(ctx, topicId, parsed) {
|
|
8017
8043
|
if (ctx.json && parsed.options.jsonl === true) throw new Error("--json and --jsonl cannot be combined");
|
|
@@ -8273,13 +8299,13 @@ async function pmRequest(ctx, method, path, body) {
|
|
|
8273
8299
|
function collectFields(parsed, allowClear) {
|
|
8274
8300
|
const out = {};
|
|
8275
8301
|
for (const [flag, spec] of Object.entries(FIELD_MAP)) {
|
|
8276
|
-
const
|
|
8277
|
-
if (
|
|
8278
|
-
if (
|
|
8302
|
+
const value2 = parsed.options[flag];
|
|
8303
|
+
if (value2 === void 0 || value2 === true) continue;
|
|
8304
|
+
if (value2 === false) {
|
|
8279
8305
|
if (allowClear) out[spec.key] = null;
|
|
8280
8306
|
continue;
|
|
8281
8307
|
}
|
|
8282
|
-
const text = stringOpt(
|
|
8308
|
+
const text = stringOpt(value2);
|
|
8283
8309
|
out[spec.key] = spec.num ? Number(text) : text;
|
|
8284
8310
|
}
|
|
8285
8311
|
return out;
|
|
@@ -8300,8 +8326,8 @@ function statusCol(entity, r) {
|
|
|
8300
8326
|
function printRecord(ctx, entity, r) {
|
|
8301
8327
|
ctx.out.log(`${r.id} [${statusCol(entity, r)}] ${r.appId} ${r.title ?? ""}`);
|
|
8302
8328
|
}
|
|
8303
|
-
function emit2(ctx,
|
|
8304
|
-
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));
|
|
8305
8331
|
else human();
|
|
8306
8332
|
}
|
|
8307
8333
|
async function pmList(ctx, entity, parsed) {
|
|
@@ -8347,8 +8373,8 @@ async function pmAdd(ctx, entity, parsed) {
|
|
|
8347
8373
|
emit2(ctx, res, () => ctx.out.log(`created ${entity} ${res.id}`));
|
|
8348
8374
|
}
|
|
8349
8375
|
async function pmGet(ctx, entity, id) {
|
|
8350
|
-
const { record:
|
|
8351
|
-
emit2(ctx,
|
|
8376
|
+
const { record: record8 } = await pmRequest(ctx, "GET", `/${entity}/${encodeURIComponent(id)}`);
|
|
8377
|
+
emit2(ctx, record8, () => printRecord(ctx, entity, record8));
|
|
8352
8378
|
}
|
|
8353
8379
|
async function pmSet(ctx, entity, id, parsed) {
|
|
8354
8380
|
const patch2 = collectEntityFields(entity, parsed, true);
|
|
@@ -8393,9 +8419,9 @@ async function pmHandoff(ctx, parsed) {
|
|
|
8393
8419
|
]);
|
|
8394
8420
|
const handoff = {
|
|
8395
8421
|
appId,
|
|
8396
|
-
unmetGoals: goals.filter((
|
|
8397
|
-
activeTasks: tasks.filter((
|
|
8398
|
-
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")
|
|
8399
8425
|
};
|
|
8400
8426
|
const result = {
|
|
8401
8427
|
...handoff,
|
|
@@ -8414,10 +8440,10 @@ async function pmHandoff(ctx, parsed) {
|
|
|
8414
8440
|
]) {
|
|
8415
8441
|
ctx.out.log(`${label}:`);
|
|
8416
8442
|
if (!records.length) ctx.out.log("- (none)");
|
|
8417
|
-
else for (const
|
|
8443
|
+
else for (const record8 of records) printRecord(
|
|
8418
8444
|
ctx,
|
|
8419
8445
|
label === "unmet goals" ? "goal" : label === "active tasks" ? "task" : "bug",
|
|
8420
|
-
|
|
8446
|
+
record8
|
|
8421
8447
|
);
|
|
8422
8448
|
}
|
|
8423
8449
|
});
|
|
@@ -8565,6 +8591,113 @@ async function pmCommand(parsed, deps = {}) {
|
|
|
8565
8591
|
}
|
|
8566
8592
|
}
|
|
8567
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
|
+
|
|
8568
8701
|
// src/o11y-verdict.ts
|
|
8569
8702
|
function statusVerdict(reads) {
|
|
8570
8703
|
const reasons = [];
|
|
@@ -8602,7 +8735,7 @@ function statusVerdict(reads) {
|
|
|
8602
8735
|
severity: "degraded"
|
|
8603
8736
|
});
|
|
8604
8737
|
}
|
|
8605
|
-
const performance =
|
|
8738
|
+
const performance = record6(reads.liveSync.body.performance) ? reads.liveSync.body.performance : null;
|
|
8606
8739
|
if (performance?.status === "unavailable") {
|
|
8607
8740
|
reasons.push({
|
|
8608
8741
|
source: "liveSync",
|
|
@@ -8683,11 +8816,11 @@ function statusVerdict(reads) {
|
|
|
8683
8816
|
reasons
|
|
8684
8817
|
};
|
|
8685
8818
|
}
|
|
8686
|
-
function
|
|
8687
|
-
return Boolean(
|
|
8819
|
+
function record6(value2) {
|
|
8820
|
+
return Boolean(value2) && typeof value2 === "object" && !Array.isArray(value2);
|
|
8688
8821
|
}
|
|
8689
|
-
function numeric2(
|
|
8690
|
-
return typeof
|
|
8822
|
+
function numeric2(value2) {
|
|
8823
|
+
return typeof value2 === "number" && Number.isFinite(value2) ? value2 : 0;
|
|
8691
8824
|
}
|
|
8692
8825
|
function collectorReason(read3, fallback) {
|
|
8693
8826
|
const reasons = read3.body.reasons;
|
|
@@ -8711,7 +8844,7 @@ function printO11yStatus(status, out) {
|
|
|
8711
8844
|
out.log(
|
|
8712
8845
|
`o11y status ${status.scope.appId}/${status.scope.env} (${status.scope.minutes}m)`
|
|
8713
8846
|
);
|
|
8714
|
-
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) : [];
|
|
8715
8848
|
const requests = routes.reduce(
|
|
8716
8849
|
(total, row) => total + numeric3(row.requests),
|
|
8717
8850
|
0
|
|
@@ -8723,39 +8856,39 @@ function printO11yStatus(status, out) {
|
|
|
8723
8856
|
out.log(
|
|
8724
8857
|
`application ${status.application.httpStatus} ${requests} requests ${errors} errors`
|
|
8725
8858
|
);
|
|
8726
|
-
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) : [];
|
|
8727
8860
|
out.log(
|
|
8728
8861
|
`application-versions ${status.applicationVersions.httpStatus} ${versions.length ? versions.slice(0, 5).map(
|
|
8729
8862
|
(row) => `${String(row.value || "(unattributed)")}:${numeric3(row.requests)}`
|
|
8730
8863
|
).join(", ") : "none observed"}`
|
|
8731
8864
|
);
|
|
8732
8865
|
out.log(liveSyncLine(status.liveSync));
|
|
8733
|
-
const canaryDurations =
|
|
8866
|
+
const canaryDurations = record7(status.canary.body.durationsMs) ? status.canary.body.durationsMs : {};
|
|
8734
8867
|
out.log(
|
|
8735
8868
|
`canary ${status.canary.httpStatus} ${String(status.canary.body.status ?? status.canary.body.error ?? "unavailable")} ${optionalNumeric(canaryDurations.publishToVisibleMs)} publish-to-visible`
|
|
8736
8869
|
);
|
|
8737
|
-
const collectorIngest =
|
|
8738
|
-
const collectorStorage =
|
|
8870
|
+
const collectorIngest = record7(status.collector.body.ingest) ? status.collector.body.ingest : {};
|
|
8871
|
+
const collectorStorage = record7(collectorIngest.storage) ? collectorIngest.storage : {};
|
|
8739
8872
|
out.log(
|
|
8740
8873
|
`collector ${status.collector.httpStatus} ${String(status.collector.body.status ?? status.collector.body.error ?? "unavailable")} ${numeric3(collectorStorage.affectedPoints)} affected points`
|
|
8741
8874
|
);
|
|
8742
|
-
const providerMetrics =
|
|
8743
|
-
const providerCapacity =
|
|
8744
|
-
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 : {};
|
|
8745
8878
|
out.log(
|
|
8746
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`
|
|
8747
8880
|
);
|
|
8748
8881
|
for (const line of providerCapacityLines(status.providerCapacity)) {
|
|
8749
8882
|
out.log(line);
|
|
8750
8883
|
}
|
|
8751
|
-
const coverage =
|
|
8752
|
-
const coverageCounts =
|
|
8753
|
-
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 : {};
|
|
8754
8887
|
out.log(
|
|
8755
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`
|
|
8756
8889
|
);
|
|
8757
8890
|
const providerPoints = Array.isArray(status.providerHistory.body.points) ? status.providerHistory.body.points.length : 0;
|
|
8758
|
-
const providerFreshness =
|
|
8891
|
+
const providerFreshness = record7(status.providerHistory.body.freshness) ? status.providerHistory.body.freshness : {};
|
|
8759
8892
|
out.log(
|
|
8760
8893
|
`cloudflare-history ${status.providerHistory.httpStatus} ${String(status.providerHistory.body.status ?? status.providerHistory.body.error ?? "unavailable")} ${providerPoints} snapshots ${optionalAge(providerFreshness.ageMs)} old`
|
|
8761
8894
|
);
|
|
@@ -8764,17 +8897,17 @@ function printO11yStatus(status, out) {
|
|
|
8764
8897
|
);
|
|
8765
8898
|
}
|
|
8766
8899
|
function providerCapacityLines(read3) {
|
|
8767
|
-
const resources =
|
|
8768
|
-
const durableObjects =
|
|
8769
|
-
const periodic =
|
|
8770
|
-
const storage =
|
|
8771
|
-
const d1 =
|
|
8772
|
-
const d1Activity =
|
|
8773
|
-
const d1Storage =
|
|
8774
|
-
const d1Latency =
|
|
8775
|
-
const r2 =
|
|
8776
|
-
const r2Operations =
|
|
8777
|
-
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 : {};
|
|
8778
8911
|
const status = String(
|
|
8779
8912
|
read3.body.status ?? read3.body.error ?? "unavailable"
|
|
8780
8913
|
);
|
|
@@ -8785,42 +8918,42 @@ function providerCapacityLines(read3) {
|
|
|
8785
8918
|
];
|
|
8786
8919
|
}
|
|
8787
8920
|
function liveSyncLine(read3) {
|
|
8788
|
-
const performance =
|
|
8789
|
-
const commitToSend =
|
|
8921
|
+
const performance = record7(read3.body.performance) ? read3.body.performance : {};
|
|
8922
|
+
const commitToSend = record7(performance.commitToSend) ? performance.commitToSend : {};
|
|
8790
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`;
|
|
8791
8924
|
}
|
|
8792
|
-
function
|
|
8793
|
-
return Boolean(
|
|
8925
|
+
function record7(value2) {
|
|
8926
|
+
return Boolean(value2) && typeof value2 === "object" && !Array.isArray(value2);
|
|
8794
8927
|
}
|
|
8795
|
-
function numeric3(
|
|
8796
|
-
return typeof
|
|
8928
|
+
function numeric3(value2) {
|
|
8929
|
+
return typeof value2 === "number" && Number.isFinite(value2) ? value2 : 0;
|
|
8797
8930
|
}
|
|
8798
|
-
function optionalNumeric(
|
|
8799
|
-
return typeof
|
|
8931
|
+
function optionalNumeric(value2) {
|
|
8932
|
+
return typeof value2 === "number" && Number.isFinite(value2) ? `${value2} ms` : "\u2014";
|
|
8800
8933
|
}
|
|
8801
|
-
function optionalAge(
|
|
8802
|
-
if (typeof
|
|
8803
|
-
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`;
|
|
8804
8937
|
}
|
|
8805
|
-
function optionalPercent(
|
|
8806
|
-
return typeof
|
|
8938
|
+
function optionalPercent(value2) {
|
|
8939
|
+
return typeof value2 === "number" && Number.isFinite(value2) ? `${Math.round(value2 * 100)}%` : "\u2014";
|
|
8807
8940
|
}
|
|
8808
|
-
function optionalBytes(
|
|
8809
|
-
if (typeof
|
|
8810
|
-
if (
|
|
8811
|
-
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`;
|
|
8812
8945
|
}
|
|
8813
|
-
if (
|
|
8814
|
-
return `${(
|
|
8946
|
+
if (value2 >= 1024 * 1024) {
|
|
8947
|
+
return `${(value2 / (1024 * 1024)).toFixed(1)} MiB`;
|
|
8815
8948
|
}
|
|
8816
|
-
if (
|
|
8817
|
-
return `${Math.round(
|
|
8949
|
+
if (value2 >= 1024) return `${(value2 / 1024).toFixed(1)} KiB`;
|
|
8950
|
+
return `${Math.round(value2)} B`;
|
|
8818
8951
|
}
|
|
8819
|
-
function optionalCount(
|
|
8820
|
-
return typeof
|
|
8952
|
+
function optionalCount(value2, unit) {
|
|
8953
|
+
return typeof value2 === "number" && Number.isFinite(value2) ? `${value2} ${unit}` : `\u2014 ${unit}`;
|
|
8821
8954
|
}
|
|
8822
|
-
function optionalAgeSeconds(
|
|
8823
|
-
return typeof
|
|
8955
|
+
function optionalAgeSeconds(value2) {
|
|
8956
|
+
return typeof value2 === "number" && Number.isFinite(value2) ? `${Math.max(0, Math.round(value2))}s` : "unknown";
|
|
8824
8957
|
}
|
|
8825
8958
|
|
|
8826
8959
|
// src/o11y-command.ts
|
|
@@ -8950,11 +9083,11 @@ async function o11yCommand(parsed, deps = {}) {
|
|
|
8950
9083
|
}
|
|
8951
9084
|
printO11yStatus(status, out);
|
|
8952
9085
|
}
|
|
8953
|
-
function statusMinutes(
|
|
8954
|
-
if (!Number.isSafeInteger(
|
|
9086
|
+
function statusMinutes(value2) {
|
|
9087
|
+
if (!Number.isSafeInteger(value2) || value2 < 1 || value2 > 7 * 24 * 60) {
|
|
8955
9088
|
throw new Error("--minutes must be an integer from 1 to 10080");
|
|
8956
9089
|
}
|
|
8957
|
-
return
|
|
9090
|
+
return value2;
|
|
8958
9091
|
}
|
|
8959
9092
|
async function read2(url, headers, doFetch) {
|
|
8960
9093
|
const response2 = await doFetch(url, { headers });
|
|
@@ -8962,8 +9095,8 @@ async function read2(url, headers, doFetch) {
|
|
|
8962
9095
|
let body = {};
|
|
8963
9096
|
if (text) {
|
|
8964
9097
|
try {
|
|
8965
|
-
const
|
|
8966
|
-
body =
|
|
9098
|
+
const value2 = JSON.parse(text);
|
|
9099
|
+
body = value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : { value: value2 };
|
|
8967
9100
|
} catch {
|
|
8968
9101
|
body = { message: text.slice(0, 300) };
|
|
8969
9102
|
}
|
|
@@ -8972,7 +9105,7 @@ async function read2(url, headers, doFetch) {
|
|
|
8972
9105
|
}
|
|
8973
9106
|
|
|
8974
9107
|
// src/provision.ts
|
|
8975
|
-
var
|
|
9108
|
+
var import_apps7 = require("@odla-ai/apps");
|
|
8976
9109
|
var import_ai3 = require("@odla-ai/ai");
|
|
8977
9110
|
var import_node_process10 = __toESM(require("process"), 1);
|
|
8978
9111
|
|
|
@@ -9017,8 +9150,8 @@ async function postJson2(doFetch, url, bearer, body) {
|
|
|
9017
9150
|
if (!res.ok) throw new Error(`${new URL(url).pathname} failed: ${res.status} ${await responseText(res)}`);
|
|
9018
9151
|
return res.json().catch(() => ({}));
|
|
9019
9152
|
}
|
|
9020
|
-
function isRecord7(
|
|
9021
|
-
return
|
|
9153
|
+
function isRecord7(value2) {
|
|
9154
|
+
return value2 !== null && typeof value2 === "object" && !Array.isArray(value2);
|
|
9022
9155
|
}
|
|
9023
9156
|
async function responseText(res) {
|
|
9024
9157
|
try {
|
|
@@ -9029,9 +9162,9 @@ async function responseText(res) {
|
|
|
9029
9162
|
}
|
|
9030
9163
|
|
|
9031
9164
|
// src/provision-credentials.ts
|
|
9032
|
-
var
|
|
9165
|
+
var import_apps5 = require("@odla-ai/apps");
|
|
9033
9166
|
async function provisionEnvCredentials(opts) {
|
|
9034
|
-
const tenantId = (0,
|
|
9167
|
+
const tenantId = (0, import_apps5.tenantIdFor)(opts.cfg.app.id, opts.env);
|
|
9035
9168
|
const prior = opts.credentials?.envs[opts.env];
|
|
9036
9169
|
let credentials = opts.credentials;
|
|
9037
9170
|
let dbKey = opts.cfg.services.includes("db") && !opts.rotateDb ? prior?.dbKey : void 0;
|
|
@@ -9125,18 +9258,13 @@ async function safeText4(res) {
|
|
|
9125
9258
|
|
|
9126
9259
|
// src/provision-helpers.ts
|
|
9127
9260
|
var import_ai2 = require("@odla-ai/ai");
|
|
9128
|
-
var
|
|
9129
|
-
function serviceRank(service) {
|
|
9130
|
-
if (service === "db") return 0;
|
|
9131
|
-
if (service === "calendar") return 2;
|
|
9132
|
-
return 1;
|
|
9133
|
-
}
|
|
9261
|
+
var import_apps6 = require("@odla-ai/apps");
|
|
9134
9262
|
function defaultSecretName(provider) {
|
|
9135
9263
|
const names = import_ai2.DEFAULT_SECRET_NAMES;
|
|
9136
9264
|
return names[provider] ?? `${provider}_api_key`;
|
|
9137
9265
|
}
|
|
9138
9266
|
async function assertTenantAdminAccess(doFetch, cfg, env, token) {
|
|
9139
|
-
const tenantId = (0,
|
|
9267
|
+
const tenantId = (0, import_apps6.tenantIdFor)(cfg.app.id, env);
|
|
9140
9268
|
const res = await doFetch(`${cfg.dbEndpoint}/admin/apps/${encodeURIComponent(tenantId)}/entitlements`, {
|
|
9141
9269
|
headers: { authorization: `Bearer ${token}` }
|
|
9142
9270
|
});
|
|
@@ -9156,14 +9284,14 @@ async function postJson3(doFetch, url, bearer, body) {
|
|
|
9156
9284
|
});
|
|
9157
9285
|
if (!res.ok) throw new Error(`${new URL(url).pathname} failed: ${res.status} ${await safeText5(res)}`);
|
|
9158
9286
|
}
|
|
9159
|
-
function normalizeClerkConfig(
|
|
9160
|
-
if (!
|
|
9161
|
-
if (typeof
|
|
9162
|
-
const publishableKey2 = envValue(
|
|
9287
|
+
function normalizeClerkConfig(value2) {
|
|
9288
|
+
if (!value2) return null;
|
|
9289
|
+
if (typeof value2 === "string") {
|
|
9290
|
+
const publishableKey2 = envValue(value2);
|
|
9163
9291
|
return publishableKey2 ? { publishableKey: publishableKey2 } : null;
|
|
9164
9292
|
}
|
|
9165
|
-
if (typeof
|
|
9166
|
-
const cfg =
|
|
9293
|
+
if (typeof value2 !== "object") return null;
|
|
9294
|
+
const cfg = value2;
|
|
9167
9295
|
const publishableKey = envValue(cfg.publishableKey);
|
|
9168
9296
|
return publishableKey ? { publishableKey, ...cfg.audience ? { audience: cfg.audience } : {}, ...cfg.mode ? { mode: cfg.mode } : {} } : null;
|
|
9169
9297
|
}
|
|
@@ -9245,7 +9373,7 @@ async function provision(options) {
|
|
|
9245
9373
|
}
|
|
9246
9374
|
const doFetch = options.fetch ?? fetch;
|
|
9247
9375
|
const token = await getDeveloperToken(cfg, options, doFetch, out);
|
|
9248
|
-
const apps = (0,
|
|
9376
|
+
const apps = (0, import_apps7.createAppsClient)({ endpoint: cfg.platformUrl, token, fetcher: { fetch: doFetch } });
|
|
9249
9377
|
const existing = await apps.resolveApp(cfg.app.id);
|
|
9250
9378
|
if (existing) {
|
|
9251
9379
|
out.log(`app: ${cfg.app.id} already exists`);
|
|
@@ -9256,7 +9384,7 @@ async function provision(options) {
|
|
|
9256
9384
|
for (const env of cfg.envs) {
|
|
9257
9385
|
await assertTenantAdminAccess(doFetch, cfg, env, token);
|
|
9258
9386
|
}
|
|
9259
|
-
const serviceOrder =
|
|
9387
|
+
const serviceOrder = (0, import_apps7.orderAppServices)(cfg.services);
|
|
9260
9388
|
for (const env of cfg.envs) {
|
|
9261
9389
|
for (const service of serviceOrder) {
|
|
9262
9390
|
if (service === "ai") {
|
|
@@ -9289,7 +9417,7 @@ async function provision(options) {
|
|
|
9289
9417
|
}
|
|
9290
9418
|
}
|
|
9291
9419
|
for (const env of cfg.envs) {
|
|
9292
|
-
const tenantId = (0,
|
|
9420
|
+
const tenantId = (0, import_apps7.tenantIdFor)(cfg.app.id, env);
|
|
9293
9421
|
credentials = await provisionEnvCredentials({
|
|
9294
9422
|
cfg,
|
|
9295
9423
|
env,
|
|
@@ -9440,6 +9568,7 @@ var COMMAND_SURFACE = {
|
|
|
9440
9568
|
help: {},
|
|
9441
9569
|
init: {},
|
|
9442
9570
|
o11y: { status: {} },
|
|
9571
|
+
platform: { status: {} },
|
|
9443
9572
|
pm: {
|
|
9444
9573
|
...PM_ENTITIES,
|
|
9445
9574
|
handoff: {}
|
|
@@ -9523,7 +9652,7 @@ function recordInvocation(parsed) {
|
|
|
9523
9652
|
try {
|
|
9524
9653
|
const entry = {
|
|
9525
9654
|
path: invocationPath(parsed.positionals),
|
|
9526
|
-
options: Object.entries(parsed.options).map(([name,
|
|
9655
|
+
options: Object.entries(parsed.options).map(([name, value2]) => value2 === false ? `no-${name}` : name).sort()
|
|
9527
9656
|
};
|
|
9528
9657
|
if (!entry.path.length) return;
|
|
9529
9658
|
(0, import_node_fs15.appendFileSync)(file, `${JSON.stringify(entry)}
|
|
@@ -9537,10 +9666,10 @@ var import_node_fs16 = require("fs");
|
|
|
9537
9666
|
|
|
9538
9667
|
// src/runbook-requires.ts
|
|
9539
9668
|
var SPEC = /^(@?[\w./-]+?)@(\d+\.\d+\.\d+(?:[\w.-]*)?)$/;
|
|
9540
|
-
function parseRequires(
|
|
9541
|
-
if (!
|
|
9669
|
+
function parseRequires(value2) {
|
|
9670
|
+
if (!value2) return [];
|
|
9542
9671
|
const out = [];
|
|
9543
|
-
for (const token of
|
|
9672
|
+
for (const token of value2.split(/[\s,]+/).filter(Boolean)) {
|
|
9544
9673
|
const match = SPEC.exec(token);
|
|
9545
9674
|
if (match?.[1] && match[2]) out.push({ name: match[1], min: match[2] });
|
|
9546
9675
|
}
|
|
@@ -9716,9 +9845,9 @@ function parseRunbook(text, slug) {
|
|
|
9716
9845
|
for (const line of fm[1].split(/\r?\n/)) {
|
|
9717
9846
|
const pair = /^(\w+)\s*:\s*(.+)$/.exec(line.trim());
|
|
9718
9847
|
if (!pair) continue;
|
|
9719
|
-
const
|
|
9720
|
-
if (pair[1] === "summary") meta.summary =
|
|
9721
|
-
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();
|
|
9722
9851
|
}
|
|
9723
9852
|
}
|
|
9724
9853
|
const lines = rest.split("\n");
|
|
@@ -9835,7 +9964,7 @@ var NOISE = /* @__PURE__ */ new Set([
|
|
|
9835
9964
|
"and",
|
|
9836
9965
|
"for"
|
|
9837
9966
|
]);
|
|
9838
|
-
var words = (
|
|
9967
|
+
var words = (value2) => value2.replace(/^@[\w-]+\//, "").split(/[^A-Za-z0-9]+/).filter((w) => w.length > 1 && !NOISE.has(w.toLowerCase()));
|
|
9839
9968
|
function namedExports(clause) {
|
|
9840
9969
|
return clause.split(",").map((part) => part.trim().split(/\s+as\s+/)[0]?.trim() ?? "").filter((name) => /^[A-Za-z_$][\w$]*$/.test(name) && name !== "type");
|
|
9841
9970
|
}
|
|
@@ -10188,8 +10317,8 @@ var import_node_process12 = __toESM(require("process"), 1);
|
|
|
10188
10317
|
var EDITOR_ENV = ["ODLA_EDITOR", "VISUAL", "EDITOR"];
|
|
10189
10318
|
function resolveEditor(env = import_node_process12.default.env) {
|
|
10190
10319
|
for (const name of EDITOR_ENV) {
|
|
10191
|
-
const
|
|
10192
|
-
if (
|
|
10320
|
+
const value2 = env[name];
|
|
10321
|
+
if (value2 && value2.trim()) return value2.trim();
|
|
10193
10322
|
}
|
|
10194
10323
|
return null;
|
|
10195
10324
|
}
|
|
@@ -10454,9 +10583,9 @@ async function runbookCommand(parsed, deps = {}) {
|
|
|
10454
10583
|
});
|
|
10455
10584
|
}
|
|
10456
10585
|
case "visibility": {
|
|
10457
|
-
const
|
|
10458
|
-
if (!
|
|
10459
|
-
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);
|
|
10460
10589
|
}
|
|
10461
10590
|
case "publish":
|
|
10462
10591
|
return runbookStatus(ctx, requireSlug(slug, "publish"), "published");
|
|
@@ -10512,13 +10641,13 @@ async function interactiveConfirmation(message2, dependencies) {
|
|
|
10512
10641
|
}
|
|
10513
10642
|
}
|
|
10514
10643
|
function requiredSecurityPositional(parsed, index, label) {
|
|
10515
|
-
const
|
|
10516
|
-
if (!
|
|
10517
|
-
return
|
|
10644
|
+
const value2 = parsed.positionals[index];
|
|
10645
|
+
if (!value2) throw new Error(`${label} is required`);
|
|
10646
|
+
return value2;
|
|
10518
10647
|
}
|
|
10519
|
-
function securityProfile(
|
|
10520
|
-
if (
|
|
10521
|
-
if (
|
|
10648
|
+
function securityProfile(value2) {
|
|
10649
|
+
if (value2 === void 0) return void 0;
|
|
10650
|
+
if (value2 === "odla" || value2 === "cloudflare-app" || value2 === "generic") return value2;
|
|
10522
10651
|
throw new Error("--profile must be odla, cloudflare-app, or generic");
|
|
10523
10652
|
}
|
|
10524
10653
|
|
|
@@ -10619,9 +10748,9 @@ function routeLabel(route2) {
|
|
|
10619
10748
|
return `${route2.provider}/${route2.model}${route2.policyVersion ? ` policy v${route2.policyVersion}` : ""}`;
|
|
10620
10749
|
}
|
|
10621
10750
|
var HOSTED_SEVERITIES = ["informational", "low", "medium", "high", "critical"];
|
|
10622
|
-
function hostedSeverity(
|
|
10623
|
-
if (HOSTED_SEVERITIES.includes(
|
|
10624
|
-
return
|
|
10751
|
+
function hostedSeverity(value2, flag) {
|
|
10752
|
+
if (HOSTED_SEVERITIES.includes(value2)) {
|
|
10753
|
+
return value2;
|
|
10625
10754
|
}
|
|
10626
10755
|
throw new Error(`${flag} must be informational, low, medium, high, or critical`);
|
|
10627
10756
|
}
|
|
@@ -10704,13 +10833,13 @@ function selectEnv(requested, declared, configPath, rootDir) {
|
|
|
10704
10833
|
return env;
|
|
10705
10834
|
}
|
|
10706
10835
|
async function injectedToken(options, request2) {
|
|
10707
|
-
const
|
|
10708
|
-
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)) {
|
|
10709
10838
|
throw new Error(
|
|
10710
10839
|
request2.selfAudit ? "Self-audit requires an injected, scoped platform security token" : "Hosted security requires an injected app developer token or getToken callback"
|
|
10711
10840
|
);
|
|
10712
10841
|
}
|
|
10713
|
-
return
|
|
10842
|
+
return value2;
|
|
10714
10843
|
}
|
|
10715
10844
|
function profileFor(name, maxHuntTasks) {
|
|
10716
10845
|
const profile = name === "odla" ? (0, import_security.odlaProfile)() : name === "cloudflare-app" ? (0, import_security.cloudflareAppProfile)() : name === "generic" ? (0, import_security.genericProfile)() : void 0;
|
|
@@ -10756,8 +10885,8 @@ async function getHostedSecurityIntent(options) {
|
|
|
10756
10885
|
}
|
|
10757
10886
|
return response2;
|
|
10758
10887
|
}
|
|
10759
|
-
function isValidIntent(
|
|
10760
|
-
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";
|
|
10761
10890
|
}
|
|
10762
10891
|
|
|
10763
10892
|
// src/security-hosted-jobs.ts
|
|
@@ -10872,17 +11001,17 @@ function hostedJobPath(appIdInput, jobIdInput) {
|
|
|
10872
11001
|
const jobId = hostedIdentifier(jobIdInput, "jobId");
|
|
10873
11002
|
return `/registry/apps/${encodeURIComponent(appId)}/security/jobs/${encodeURIComponent(jobId)}`;
|
|
10874
11003
|
}
|
|
10875
|
-
function securityPlanDigest(
|
|
10876
|
-
if (!/^sha256:[a-f0-9]{64}$/.test(
|
|
11004
|
+
function securityPlanDigest(value2) {
|
|
11005
|
+
if (!/^sha256:[a-f0-9]{64}$/.test(value2)) {
|
|
10877
11006
|
throw new Error("expected plan digest must be a sha256 digest from security plan");
|
|
10878
11007
|
}
|
|
10879
|
-
return
|
|
11008
|
+
return value2;
|
|
10880
11009
|
}
|
|
10881
|
-
function securityExecutionDigest(
|
|
10882
|
-
if (!/^sha256:[a-f0-9]{64}$/.test(
|
|
11010
|
+
function securityExecutionDigest(value2) {
|
|
11011
|
+
if (!/^sha256:[a-f0-9]{64}$/.test(value2)) {
|
|
10883
11012
|
throw new Error("expected execution digest must be a sha256 digest from security intent");
|
|
10884
11013
|
}
|
|
10885
|
-
return
|
|
11014
|
+
return value2;
|
|
10886
11015
|
}
|
|
10887
11016
|
|
|
10888
11017
|
// src/security-run-command.ts
|
|
@@ -10946,7 +11075,7 @@ async function runSourceSecurityCommand(parsed, dependencies, sourceId) {
|
|
|
10946
11075
|
...context,
|
|
10947
11076
|
jobId: job.jobId,
|
|
10948
11077
|
wait: dependencies.pollWait,
|
|
10949
|
-
onUpdate: parsed.options.json === true ? void 0 : (
|
|
11078
|
+
onUpdate: parsed.options.json === true ? void 0 : (value2) => printHostedJob(context.stdout, value2, context.platform, context.appId)
|
|
10950
11079
|
}) : job;
|
|
10951
11080
|
if (!follow) {
|
|
10952
11081
|
if (parsed.options.json === true) {
|
|
@@ -11046,9 +11175,9 @@ function enforceLocalGate(report4, parsed) {
|
|
|
11046
11175
|
throw new Error(`hosted security gate failed: ${confirmed.length} confirmed >= ${failOn}; ${leads.length} leads >= ${failOnCandidates ?? "disabled"}${incomplete ? "; coverage incomplete" : ""}`);
|
|
11047
11176
|
}
|
|
11048
11177
|
}
|
|
11049
|
-
function severityOpt(
|
|
11050
|
-
if (["informational", "low", "medium", "high", "critical"].includes(
|
|
11051
|
-
return
|
|
11178
|
+
function severityOpt(value2, flag) {
|
|
11179
|
+
if (["informational", "low", "medium", "high", "critical"].includes(value2)) {
|
|
11180
|
+
return value2;
|
|
11052
11181
|
}
|
|
11053
11182
|
throw new Error(`${flag} must be informational, low, medium, high, or critical`);
|
|
11054
11183
|
}
|
|
@@ -11156,7 +11285,7 @@ async function securityStatus(parsed, dependencies) {
|
|
|
11156
11285
|
...context,
|
|
11157
11286
|
jobId,
|
|
11158
11287
|
wait: dependencies.pollWait,
|
|
11159
|
-
onUpdate: parsed.options.json === true ? void 0 : (
|
|
11288
|
+
onUpdate: parsed.options.json === true ? void 0 : (value2) => printHostedJob(context.stdout, value2, context.platform, context.appId)
|
|
11160
11289
|
}) : await getHostedSecurityJob({ ...context, jobId });
|
|
11161
11290
|
if (parsed.options.json === true) context.stdout.log(JSON.stringify(job, null, 2));
|
|
11162
11291
|
else if (parsed.options.follow !== true) {
|
|
@@ -11240,6 +11369,10 @@ async function runCli(argv = process.argv.slice(2), dependencies = {}) {
|
|
|
11240
11369
|
await o11yCommand(parsed, runtime);
|
|
11241
11370
|
return;
|
|
11242
11371
|
}
|
|
11372
|
+
if (command === "platform") {
|
|
11373
|
+
await platformCommand(parsed, runtime);
|
|
11374
|
+
return;
|
|
11375
|
+
}
|
|
11243
11376
|
if (command === "provision") {
|
|
11244
11377
|
await provisionCommand(parsed, runtime);
|
|
11245
11378
|
return;
|