@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
|
@@ -17,22 +17,22 @@ function readJsonFile(path) {
|
|
|
17
17
|
return null;
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
|
-
function writePrivateJson(path,
|
|
21
|
-
writePrivateText(path, `${JSON.stringify(
|
|
20
|
+
function writePrivateJson(path, value2) {
|
|
21
|
+
writePrivateText(path, `${JSON.stringify(value2, null, 2)}
|
|
22
22
|
`);
|
|
23
23
|
}
|
|
24
24
|
function readCredentials(path) {
|
|
25
25
|
if (!existsSync(path)) return null;
|
|
26
|
-
let
|
|
26
|
+
let value2;
|
|
27
27
|
try {
|
|
28
|
-
|
|
28
|
+
value2 = JSON.parse(readFileSync(path, "utf8"));
|
|
29
29
|
} catch {
|
|
30
30
|
throw new Error(`credentials file ${path} is not valid JSON; fix or remove it before provisioning`);
|
|
31
31
|
}
|
|
32
|
-
if (!
|
|
32
|
+
if (!value2 || typeof value2 !== "object" || typeof value2.appId !== "string" || !value2.envs || typeof value2.envs !== "object") {
|
|
33
33
|
throw new Error(`credentials file ${path} has an invalid shape; fix or remove it before provisioning`);
|
|
34
34
|
}
|
|
35
|
-
return
|
|
35
|
+
return value2;
|
|
36
36
|
}
|
|
37
37
|
function mergeCredential(current, update) {
|
|
38
38
|
const next = current ?? {
|
|
@@ -366,8 +366,8 @@ function stillPending(pending, email) {
|
|
|
366
366
|
{ retryable: true }
|
|
367
367
|
);
|
|
368
368
|
}
|
|
369
|
-
function handshakeEmail(
|
|
370
|
-
const email = (
|
|
369
|
+
function handshakeEmail(value2, cached) {
|
|
370
|
+
const email = (value2 ?? process4.env.ODLA_USER_EMAIL ?? cached ?? "").trim().toLowerCase();
|
|
371
371
|
if (email.length > 254 || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
|
|
372
372
|
throw new Error("a fresh odla handshake requires --email <account> or ODLA_USER_EMAIL");
|
|
373
373
|
}
|
|
@@ -391,10 +391,10 @@ function handshakeUrl(platformUrl, userCode) {
|
|
|
391
391
|
url.searchParams.set("code", userCode);
|
|
392
392
|
return url.toString();
|
|
393
393
|
}
|
|
394
|
-
function platformAudience(
|
|
394
|
+
function platformAudience(value2) {
|
|
395
395
|
let url;
|
|
396
396
|
try {
|
|
397
|
-
url = new URL(
|
|
397
|
+
url = new URL(value2);
|
|
398
398
|
} catch {
|
|
399
399
|
throw new Error("platform must be an absolute URL");
|
|
400
400
|
}
|
|
@@ -436,6 +436,7 @@ function audienceBoundEnvToken(token, platform) {
|
|
|
436
436
|
return token;
|
|
437
437
|
}
|
|
438
438
|
var SCOPE_PURPOSE = {
|
|
439
|
+
"platform:status:read": "read the platform fleet health and deployment snapshot",
|
|
439
440
|
"platform:runbook:write": "add or edit odla's operational runbooks",
|
|
440
441
|
"platform:ai:policy:write": "change System AI model routing",
|
|
441
442
|
"platform:ai:policy:read": "read System AI model routing",
|
|
@@ -499,11 +500,11 @@ var SYSTEM_AI_PURPOSES = [
|
|
|
499
500
|
"security.validation",
|
|
500
501
|
"runbook.answer"
|
|
501
502
|
];
|
|
502
|
-
function requireSystemAiPurpose(
|
|
503
|
-
if (!SYSTEM_AI_PURPOSES.includes(
|
|
503
|
+
function requireSystemAiPurpose(value2) {
|
|
504
|
+
if (!SYSTEM_AI_PURPOSES.includes(value2)) {
|
|
504
505
|
throw new Error(`purpose must be one of: ${SYSTEM_AI_PURPOSES.join(", ")}`);
|
|
505
506
|
}
|
|
506
|
-
return
|
|
507
|
+
return value2;
|
|
507
508
|
}
|
|
508
509
|
|
|
509
510
|
// src/admin-ai.ts
|
|
@@ -514,22 +515,22 @@ import process6 from "process";
|
|
|
514
515
|
var MAX_BYTES = 64 * 1024;
|
|
515
516
|
async function secretInputValue(options, kind = "credential") {
|
|
516
517
|
if (options.fromEnv && options.stdin) throw new Error("choose exactly one of --from-env or --stdin");
|
|
517
|
-
let
|
|
518
|
-
if (options.fromEnv)
|
|
519
|
-
else if (options.stdin)
|
|
518
|
+
let value2;
|
|
519
|
+
if (options.fromEnv) value2 = process6.env[options.fromEnv];
|
|
520
|
+
else if (options.stdin) value2 = await (options.readStdin ?? (() => readSecretStream(kind)))();
|
|
520
521
|
else throw new Error(`${kind} input required: use --from-env <NAME> or --stdin; values are never accepted as arguments`);
|
|
521
|
-
|
|
522
|
-
if (!
|
|
523
|
-
if (new TextEncoder().encode(
|
|
524
|
-
return
|
|
522
|
+
value2 = value2?.replace(/[\r\n]+$/, "");
|
|
523
|
+
if (!value2) throw new Error(options.fromEnv ? `environment variable ${options.fromEnv} is empty or unset` : `stdin ${kind} is empty`);
|
|
524
|
+
if (new TextEncoder().encode(value2).byteLength > MAX_BYTES) throw new Error(`${kind} exceeds 64 KiB`);
|
|
525
|
+
return value2;
|
|
525
526
|
}
|
|
526
527
|
async function readSecretStream(kind, stream = process6.stdin) {
|
|
527
|
-
let
|
|
528
|
+
let value2 = "";
|
|
528
529
|
for await (const chunk of stream) {
|
|
529
|
-
|
|
530
|
-
if (
|
|
530
|
+
value2 += String(chunk);
|
|
531
|
+
if (value2.length > MAX_BYTES) throw new Error(`${kind} exceeds 64 KiB`);
|
|
531
532
|
}
|
|
532
|
-
return
|
|
533
|
+
return value2;
|
|
533
534
|
}
|
|
534
535
|
|
|
535
536
|
// src/admin-ai-audit.ts
|
|
@@ -579,13 +580,13 @@ function apiError(status, body) {
|
|
|
579
580
|
const message2 = error && typeof error.message === "string" ? error.message : isRecord(body) && typeof body.message === "string" ? body.message : "request failed";
|
|
580
581
|
return `read System AI admin changes failed (${status}): ${message2}`;
|
|
581
582
|
}
|
|
582
|
-
function timestamp(
|
|
583
|
-
if (typeof
|
|
584
|
-
const date = new Date(
|
|
583
|
+
function timestamp(value2) {
|
|
584
|
+
if (typeof value2 !== "number" || !Number.isFinite(value2)) return String(value2 ?? "");
|
|
585
|
+
const date = new Date(value2);
|
|
585
586
|
return Number.isFinite(date.valueOf()) ? date.toISOString() : "";
|
|
586
587
|
}
|
|
587
|
-
function isRecord(
|
|
588
|
-
return Boolean(
|
|
588
|
+
function isRecord(value2) {
|
|
589
|
+
return Boolean(value2) && typeof value2 === "object" && !Array.isArray(value2);
|
|
589
590
|
}
|
|
590
591
|
|
|
591
592
|
// src/admin-ai-usage.ts
|
|
@@ -607,11 +608,11 @@ async function readAdminAiUsage(request2) {
|
|
|
607
608
|
if (request2.json) request2.stdout.log(JSON.stringify(body, null, 2));
|
|
608
609
|
else printUsage(body, request2.stdout);
|
|
609
610
|
}
|
|
610
|
-
function usageLimit(
|
|
611
|
-
if (!Number.isSafeInteger(
|
|
611
|
+
function usageLimit(value2) {
|
|
612
|
+
if (!Number.isSafeInteger(value2) || value2 < 1 || value2 > 500) {
|
|
612
613
|
throw new Error("usage limit must be an integer from 1 to 500");
|
|
613
614
|
}
|
|
614
|
-
return
|
|
615
|
+
return value2;
|
|
615
616
|
}
|
|
616
617
|
function printUsage(body, out) {
|
|
617
618
|
const aggregates = isRecord2(body) && isRecord2(body.aggregates) && Array.isArray(body.aggregates.byStatus) ? body.aggregates.byStatus.filter(isRecord2) : [];
|
|
@@ -647,15 +648,15 @@ when app/env run actor purpose/role route / policy tokens cost status`);
|
|
|
647
648
|
].join(" "));
|
|
648
649
|
}
|
|
649
650
|
}
|
|
650
|
-
function numeric(
|
|
651
|
-
return typeof
|
|
651
|
+
function numeric(value2) {
|
|
652
|
+
return typeof value2 === "number" && Number.isFinite(value2) ? value2 : 0;
|
|
652
653
|
}
|
|
653
|
-
function formatMicrousd(
|
|
654
|
-
return typeof
|
|
654
|
+
function formatMicrousd(value2) {
|
|
655
|
+
return typeof value2 === "number" && Number.isFinite(value2) ? `$${(value2 / 1e6).toFixed(6)}` : "unpriced";
|
|
655
656
|
}
|
|
656
|
-
function timestamp2(
|
|
657
|
-
if (typeof
|
|
658
|
-
const date = new Date(
|
|
657
|
+
function timestamp2(value2) {
|
|
658
|
+
if (typeof value2 !== "number" || !Number.isFinite(value2)) return String(value2 ?? "");
|
|
659
|
+
const date = new Date(value2);
|
|
659
660
|
return Number.isFinite(date.valueOf()) ? date.toISOString() : "";
|
|
660
661
|
}
|
|
661
662
|
async function responseBody2(res) {
|
|
@@ -672,8 +673,8 @@ function apiError2(action, status, body) {
|
|
|
672
673
|
const message2 = error && typeof error.message === "string" ? error.message : isRecord2(body) && typeof body.message === "string" ? body.message : "request failed";
|
|
673
674
|
return `${action} failed (${status}): ${message2}`;
|
|
674
675
|
}
|
|
675
|
-
function isRecord2(
|
|
676
|
-
return Boolean(
|
|
676
|
+
function isRecord2(value2) {
|
|
677
|
+
return Boolean(value2) && typeof value2 === "object" && !Array.isArray(value2);
|
|
677
678
|
}
|
|
678
679
|
|
|
679
680
|
// src/admin-ai.ts
|
|
@@ -718,11 +719,11 @@ async function adminAi(options) {
|
|
|
718
719
|
}
|
|
719
720
|
if (options.action === "credential-set") {
|
|
720
721
|
const provider = requireProvider(options.credentialProvider);
|
|
721
|
-
const
|
|
722
|
+
const value2 = await secretInputValue(options);
|
|
722
723
|
const res2 = await doFetch(`${platform}/registry/platform/ai-credentials/${encodeURIComponent(provider)}`, {
|
|
723
724
|
method: "PUT",
|
|
724
725
|
headers,
|
|
725
|
-
body: JSON.stringify({ value })
|
|
726
|
+
body: JSON.stringify({ value: value2 })
|
|
726
727
|
});
|
|
727
728
|
const body2 = await responseBody3(res2);
|
|
728
729
|
if (!res2.ok) throw new Error(apiError3(`store ${provider} platform credential`, res2.status, body2));
|
|
@@ -822,11 +823,11 @@ async function adminAi(options) {
|
|
|
822
823
|
const policy = isRecord3(response2) && isRecord3(response2.policy) ? response2.policy : isRecord3(response2) ? response2 : {};
|
|
823
824
|
out.log(options.json ? JSON.stringify({ policy }, null, 2) : `updated ${purpose}: ${String(policy.provider ?? "unchanged")}/${String(policy.model ?? "unchanged")}`);
|
|
824
825
|
}
|
|
825
|
-
function requireProvider(
|
|
826
|
-
if (
|
|
826
|
+
function requireProvider(value2) {
|
|
827
|
+
if (value2 !== "anthropic" && value2 !== "openai" && value2 !== "google") {
|
|
827
828
|
throw new Error("provider must be one of: anthropic, openai, google");
|
|
828
829
|
}
|
|
829
|
-
return
|
|
830
|
+
return value2;
|
|
830
831
|
}
|
|
831
832
|
function policyArray(body) {
|
|
832
833
|
if (isRecord3(body) && Array.isArray(body.policies)) return body.policies.filter(isRecord3);
|
|
@@ -837,7 +838,7 @@ function catalogModels(body) {
|
|
|
837
838
|
if (!isRecord3(body) || !isRecord3(body.catalog) || !Array.isArray(body.catalog.models)) {
|
|
838
839
|
throw new Error("platform returned an invalid System AI model catalog");
|
|
839
840
|
}
|
|
840
|
-
return body.catalog.models.filter((
|
|
841
|
+
return body.catalog.models.filter((value2) => isRecord3(value2) && typeof value2.id === "string" && typeof value2.provider === "string");
|
|
841
842
|
}
|
|
842
843
|
async function responseBody3(res) {
|
|
843
844
|
const text = await res.text();
|
|
@@ -853,14 +854,15 @@ function apiError3(action, status, body) {
|
|
|
853
854
|
const message2 = error && typeof error.message === "string" ? error.message : isRecord3(body) && typeof body.message === "string" ? body.message : "request failed";
|
|
854
855
|
return `${action} failed (${status}): ${message2}`;
|
|
855
856
|
}
|
|
856
|
-
function isRecord3(
|
|
857
|
-
return Boolean(
|
|
857
|
+
function isRecord3(value2) {
|
|
858
|
+
return Boolean(value2) && typeof value2 === "object" && !Array.isArray(value2);
|
|
858
859
|
}
|
|
859
860
|
|
|
860
861
|
// src/config.ts
|
|
861
862
|
import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
|
|
862
863
|
import { dirname as dirname3, isAbsolute as isAbsolute2, resolve as resolve2 } from "path";
|
|
863
864
|
import { pathToFileURL } from "url";
|
|
865
|
+
import { appServiceDefinition, appServiceIds } from "@odla-ai/apps";
|
|
864
866
|
|
|
865
867
|
// src/integration-validation.ts
|
|
866
868
|
function validateIntegrations(cfg, path, defaultServices) {
|
|
@@ -915,17 +917,17 @@ function validateProbes(integration, at) {
|
|
|
915
917
|
}
|
|
916
918
|
}
|
|
917
919
|
}
|
|
918
|
-
function isRecord4(
|
|
919
|
-
return
|
|
920
|
+
function isRecord4(value2) {
|
|
921
|
+
return value2 !== null && typeof value2 === "object" && !Array.isArray(value2);
|
|
920
922
|
}
|
|
921
|
-
function safeText(
|
|
922
|
-
return typeof
|
|
923
|
+
function safeText(value2, max) {
|
|
924
|
+
return typeof value2 === "string" && value2.trim().length > 0 && value2.length <= max && !/[\u0000-\u001f\u007f]/.test(value2);
|
|
923
925
|
}
|
|
924
|
-
function safeProbePath(
|
|
925
|
-
return typeof
|
|
926
|
+
function safeProbePath(value2) {
|
|
927
|
+
return typeof value2 === "string" && /^\/[A-Za-z0-9._~!$&'()*+,;=:@%/-]*$/.test(value2);
|
|
926
928
|
}
|
|
927
|
-
function validId(
|
|
928
|
-
return typeof
|
|
929
|
+
function validId(value2) {
|
|
930
|
+
return typeof value2 === "string" && /^[a-z0-9][a-z0-9-]*$/.test(value2);
|
|
929
931
|
}
|
|
930
932
|
function unique(values) {
|
|
931
933
|
return [...new Set(values.filter(Boolean))];
|
|
@@ -948,6 +950,7 @@ async function loadProjectConfig(configPath = "odla.config.mjs") {
|
|
|
948
950
|
const dbEndpoint = trimSlash(process.env.ODLA_DB_ENDPOINT || raw.dbEndpoint || platformUrl);
|
|
949
951
|
const envs = unique2(raw.envs?.length ? raw.envs : DEFAULT_ENVS);
|
|
950
952
|
const services = unique2(raw.services?.length ? raw.services : DEFAULT_SERVICES);
|
|
953
|
+
validateServices(services, resolved);
|
|
951
954
|
validateCalendarConfig(raw, envs, services, resolved);
|
|
952
955
|
const local = {
|
|
953
956
|
tokenFile: resolve2(rootDir, raw.local?.tokenFile ?? ".odla/dev-token.json"),
|
|
@@ -966,10 +969,10 @@ async function loadProjectConfig(configPath = "odla.config.mjs") {
|
|
|
966
969
|
local
|
|
967
970
|
};
|
|
968
971
|
}
|
|
969
|
-
async function resolveDataExport(cfg,
|
|
970
|
-
if (
|
|
971
|
-
if (typeof
|
|
972
|
-
const target = isAbsolute2(
|
|
972
|
+
async function resolveDataExport(cfg, value2, names) {
|
|
973
|
+
if (value2 === void 0 || value2 === null || value2 === false) return void 0;
|
|
974
|
+
if (typeof value2 !== "string") return value2;
|
|
975
|
+
const target = isAbsolute2(value2) ? value2 : resolve2(cfg.rootDir, value2);
|
|
973
976
|
if (target.endsWith(".json")) {
|
|
974
977
|
return JSON.parse(readFileSync2(target, "utf8"));
|
|
975
978
|
}
|
|
@@ -978,7 +981,7 @@ async function resolveDataExport(cfg, value, names) {
|
|
|
978
981
|
if (mod[name] !== void 0) return mod[name];
|
|
979
982
|
}
|
|
980
983
|
if (mod.default !== void 0) return mod.default;
|
|
981
|
-
throw new Error(`${
|
|
984
|
+
throw new Error(`${value2} did not export ${names.join(", ")} or default`);
|
|
982
985
|
}
|
|
983
986
|
function buildPlan(cfg) {
|
|
984
987
|
const integrationSchema = cfg.integrations?.some((integration) => integration.schema) ?? false;
|
|
@@ -1012,9 +1015,9 @@ function calendarServiceConfig(cfg, env) {
|
|
|
1012
1015
|
};
|
|
1013
1016
|
}
|
|
1014
1017
|
function calendarBookingPageUrl(cfg, env) {
|
|
1015
|
-
const
|
|
1016
|
-
if (
|
|
1017
|
-
return new URL(
|
|
1018
|
+
const value2 = cfg.calendar?.google.bookingPageUrl?.[env];
|
|
1019
|
+
if (value2 === void 0 || value2 === null) return value2;
|
|
1020
|
+
return new URL(value2).toString();
|
|
1018
1021
|
}
|
|
1019
1022
|
function rulesFromSchema(schema) {
|
|
1020
1023
|
const entities = serializedEntities(schema);
|
|
@@ -1028,10 +1031,10 @@ function serializedEntities(schema) {
|
|
|
1028
1031
|
if (!entities || typeof entities !== "object" || Array.isArray(entities)) return [];
|
|
1029
1032
|
return Object.keys(entities);
|
|
1030
1033
|
}
|
|
1031
|
-
function envValue(
|
|
1032
|
-
if (!
|
|
1033
|
-
if (
|
|
1034
|
-
return
|
|
1034
|
+
function envValue(value2) {
|
|
1035
|
+
if (!value2) return void 0;
|
|
1036
|
+
if (value2.startsWith("$")) return process.env[value2.slice(1)];
|
|
1037
|
+
return value2;
|
|
1035
1038
|
}
|
|
1036
1039
|
function validateRawConfig(raw, path) {
|
|
1037
1040
|
if (!raw || typeof raw !== "object") throw new Error(`${path} must export an object`);
|
|
@@ -1087,8 +1090,8 @@ function validateCalendarConfig(cfg, envs, services, path) {
|
|
|
1087
1090
|
if (!isRecord5(google.bookingCalendar)) throw new Error(`${path}: calendar.google.bookingCalendar must map env names to one calendar id`);
|
|
1088
1091
|
const unknownBookingEnv = Object.keys(google.bookingCalendar).find((env) => !envs.includes(env));
|
|
1089
1092
|
if (unknownBookingEnv) throw new Error(`${path}: calendar.google.bookingCalendar.${unknownBookingEnv} is not in config envs`);
|
|
1090
|
-
for (const [env,
|
|
1091
|
-
if (!safeText2(
|
|
1093
|
+
for (const [env, value2] of Object.entries(google.bookingCalendar)) {
|
|
1094
|
+
if (!safeText2(value2, 1024)) {
|
|
1092
1095
|
throw new Error(`${path}: calendar.google.bookingCalendar.${env} must be a calendar id`);
|
|
1093
1096
|
}
|
|
1094
1097
|
}
|
|
@@ -1097,45 +1100,57 @@ function validateCalendarConfig(cfg, envs, services, path) {
|
|
|
1097
1100
|
if (!isRecord5(google.bookingPageUrl)) throw new Error(`${path}: calendar.google.bookingPageUrl must map env names to HTTPS URLs or null`);
|
|
1098
1101
|
const unknownBookingEnv = Object.keys(google.bookingPageUrl).find((env) => !envs.includes(env));
|
|
1099
1102
|
if (unknownBookingEnv) throw new Error(`${path}: calendar.google.bookingPageUrl.${unknownBookingEnv} is not in config envs`);
|
|
1100
|
-
for (const [env,
|
|
1101
|
-
if (
|
|
1103
|
+
for (const [env, value2] of Object.entries(google.bookingPageUrl)) {
|
|
1104
|
+
if (value2 !== null && !safeHttpsUrl(value2)) {
|
|
1102
1105
|
throw new Error(`${path}: calendar.google.bookingPageUrl.${env} must be an HTTPS URL without credentials or fragment`);
|
|
1103
1106
|
}
|
|
1104
1107
|
}
|
|
1105
1108
|
}
|
|
1106
|
-
if (enabled && !services.includes("db")) throw new Error(`${path}: calendar service requires the db service`);
|
|
1107
1109
|
}
|
|
1108
|
-
function
|
|
1109
|
-
const
|
|
1110
|
+
function validateServices(services, path) {
|
|
1111
|
+
for (const service of services) {
|
|
1112
|
+
const definition = appServiceDefinition(service);
|
|
1113
|
+
if (!definition) {
|
|
1114
|
+
throw new Error(`${path}: unknown service "${service}" (known: ${appServiceIds().join(", ")})`);
|
|
1115
|
+
}
|
|
1116
|
+
for (const dependency of definition.requires) {
|
|
1117
|
+
if (!services.includes(dependency)) {
|
|
1118
|
+
throw new Error(`${path}: ${service} service requires the ${dependency} service`);
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
function assertOnly(value2, allowed, label) {
|
|
1124
|
+
const extra = Object.keys(value2).find((key) => !allowed.includes(key));
|
|
1110
1125
|
if (extra) throw new Error(`${label}.${extra} is not supported`);
|
|
1111
1126
|
}
|
|
1112
|
-
function isRecord5(
|
|
1113
|
-
return
|
|
1127
|
+
function isRecord5(value2) {
|
|
1128
|
+
return value2 !== null && typeof value2 === "object" && !Array.isArray(value2);
|
|
1114
1129
|
}
|
|
1115
|
-
function safeText2(
|
|
1116
|
-
return typeof
|
|
1130
|
+
function safeText2(value2, max) {
|
|
1131
|
+
return typeof value2 === "string" && value2.trim().length > 0 && value2.length <= max && !/[\u0000-\u001f\u007f]/.test(value2);
|
|
1117
1132
|
}
|
|
1118
|
-
function safeHttpsUrl(
|
|
1119
|
-
if (typeof
|
|
1133
|
+
function safeHttpsUrl(value2) {
|
|
1134
|
+
if (typeof value2 !== "string" || value2.length > 2048) return false;
|
|
1120
1135
|
try {
|
|
1121
|
-
const url = new URL(
|
|
1136
|
+
const url = new URL(value2);
|
|
1122
1137
|
return url.protocol === "https:" && !url.username && !url.password && !url.hash;
|
|
1123
1138
|
} catch {
|
|
1124
1139
|
return false;
|
|
1125
1140
|
}
|
|
1126
1141
|
}
|
|
1127
|
-
function validId2(
|
|
1128
|
-
return typeof
|
|
1142
|
+
function validId2(value2) {
|
|
1143
|
+
return typeof value2 === "string" && /^[a-z0-9][a-z0-9-]*$/.test(value2);
|
|
1129
1144
|
}
|
|
1130
1145
|
async function loadConfigModule(path) {
|
|
1131
1146
|
if (path.endsWith(".json")) return JSON.parse(readFileSync2(path, "utf8"));
|
|
1132
1147
|
const mod = await import(`${pathToFileURL(path).href}?t=${Date.now()}`);
|
|
1133
|
-
const
|
|
1134
|
-
if (typeof
|
|
1135
|
-
return
|
|
1148
|
+
const value2 = mod.default ?? mod.config;
|
|
1149
|
+
if (typeof value2 === "function") return await value2();
|
|
1150
|
+
return value2;
|
|
1136
1151
|
}
|
|
1137
|
-
function trimSlash(
|
|
1138
|
-
return
|
|
1152
|
+
function trimSlash(value2) {
|
|
1153
|
+
return value2.replace(/\/+$/, "");
|
|
1139
1154
|
}
|
|
1140
1155
|
function unique2(values) {
|
|
1141
1156
|
return [...new Set(values.filter(Boolean))];
|
|
@@ -1151,44 +1166,44 @@ var REPLACEMENTS = [
|
|
|
1151
1166
|
[/\b(ghp|gho|github_pat)_[A-Za-z0-9_]+/g, "$1_[redacted]"],
|
|
1152
1167
|
[/\bAKIA[A-Z0-9]{12,}/g, "AKIA[redacted]"]
|
|
1153
1168
|
];
|
|
1154
|
-
function redactSecrets(
|
|
1155
|
-
let result =
|
|
1169
|
+
function redactSecrets(value2) {
|
|
1170
|
+
let result = value2;
|
|
1156
1171
|
for (const [pattern, replacement] of REPLACEMENTS) result = result.replace(pattern, replacement);
|
|
1157
1172
|
return result;
|
|
1158
1173
|
}
|
|
1159
1174
|
function redactingOutput(output) {
|
|
1160
|
-
const redactArgs = (args) => args.map((
|
|
1175
|
+
const redactArgs = (args) => args.map((value2) => redactOutputValue(value2, /* @__PURE__ */ new WeakMap()));
|
|
1161
1176
|
return {
|
|
1162
1177
|
log: (...args) => output.log(...redactArgs(args)),
|
|
1163
1178
|
error: (...args) => output.error(...redactArgs(args))
|
|
1164
1179
|
};
|
|
1165
1180
|
}
|
|
1166
|
-
function redactOutputValue(
|
|
1167
|
-
if (typeof
|
|
1168
|
-
if (
|
|
1169
|
-
const redacted = new Error(redactSecrets(
|
|
1170
|
-
redacted.name =
|
|
1171
|
-
if (
|
|
1181
|
+
function redactOutputValue(value2, seen) {
|
|
1182
|
+
if (typeof value2 === "string") return redactSecrets(value2);
|
|
1183
|
+
if (value2 instanceof Error) {
|
|
1184
|
+
const redacted = new Error(redactSecrets(value2.message));
|
|
1185
|
+
redacted.name = value2.name;
|
|
1186
|
+
if (value2.stack) redacted.stack = redactSecrets(value2.stack);
|
|
1172
1187
|
return redacted;
|
|
1173
1188
|
}
|
|
1174
|
-
if (!
|
|
1175
|
-
const prior = seen.get(
|
|
1189
|
+
if (!value2 || typeof value2 !== "object") return value2;
|
|
1190
|
+
const prior = seen.get(value2);
|
|
1176
1191
|
if (prior) return prior;
|
|
1177
|
-
if (Array.isArray(
|
|
1192
|
+
if (Array.isArray(value2)) {
|
|
1178
1193
|
const next2 = [];
|
|
1179
|
-
seen.set(
|
|
1180
|
-
for (const item of
|
|
1194
|
+
seen.set(value2, next2);
|
|
1195
|
+
for (const item of value2) next2.push(redactOutputValue(item, seen));
|
|
1181
1196
|
return next2;
|
|
1182
1197
|
}
|
|
1183
|
-
const prototype = Object.getPrototypeOf(
|
|
1184
|
-
if (prototype !== Object.prototype && prototype !== null) return
|
|
1198
|
+
const prototype = Object.getPrototypeOf(value2);
|
|
1199
|
+
if (prototype !== Object.prototype && prototype !== null) return value2;
|
|
1185
1200
|
const next = {};
|
|
1186
|
-
seen.set(
|
|
1187
|
-
for (const [key, item] of Object.entries(
|
|
1201
|
+
seen.set(value2, next);
|
|
1202
|
+
for (const [key, item] of Object.entries(value2)) next[key] = redactOutputValue(item, seen);
|
|
1188
1203
|
return next;
|
|
1189
1204
|
}
|
|
1190
|
-
function looksSecret(
|
|
1191
|
-
return redactSecrets(
|
|
1205
|
+
function looksSecret(value2) {
|
|
1206
|
+
return redactSecrets(value2) !== value2 || value2.includes("-----BEGIN");
|
|
1192
1207
|
}
|
|
1193
1208
|
|
|
1194
1209
|
// src/calendar-errors.ts
|
|
@@ -1230,9 +1245,9 @@ async function readCalendarStatus(ctx) {
|
|
|
1230
1245
|
}
|
|
1231
1246
|
async function discoverGoogleCalendars(ctx) {
|
|
1232
1247
|
const raw = await calendarJson(ctx, "/calendars", {});
|
|
1233
|
-
const
|
|
1234
|
-
if (!
|
|
1235
|
-
return
|
|
1248
|
+
const value2 = record(raw);
|
|
1249
|
+
if (!value2 || !Array.isArray(value2.calendars)) throw new Error("calendar discovery returned an invalid response");
|
|
1250
|
+
return value2.calendars.map((item, index) => {
|
|
1236
1251
|
const calendar = record(item);
|
|
1237
1252
|
const id = textField(calendar?.id, 1024);
|
|
1238
1253
|
if (!calendar || !id) throw new Error(`calendar discovery returned an invalid calendar at index ${index}`);
|
|
@@ -1254,10 +1269,10 @@ async function applyCalendarSettings(ctx, bookingPageUrl) {
|
|
|
1254
1269
|
}
|
|
1255
1270
|
async function startCalendarConnection(ctx) {
|
|
1256
1271
|
const raw = await calendarJson(ctx, "/google/connect", { method: "POST", body: "{}" });
|
|
1257
|
-
const
|
|
1258
|
-
const attemptId = textField(
|
|
1259
|
-
const consentUrl = textField(
|
|
1260
|
-
const expiresAt = timestamp3(
|
|
1272
|
+
const value2 = wrapped(raw, "attempt");
|
|
1273
|
+
const attemptId = textField(value2.attemptId, 180);
|
|
1274
|
+
const consentUrl = textField(value2.consentUrl, 4096);
|
|
1275
|
+
const expiresAt = timestamp3(value2.expiresAt);
|
|
1261
1276
|
if (!attemptId || !consentUrl || expiresAt === void 0) throw new Error("calendar connect returned an invalid attempt");
|
|
1262
1277
|
return { attemptId, consentUrl, expiresAt };
|
|
1263
1278
|
}
|
|
@@ -1275,42 +1290,42 @@ async function requestCalendarDisconnect(ctx) {
|
|
|
1275
1290
|
}
|
|
1276
1291
|
function parseCalendarStatus(raw, env) {
|
|
1277
1292
|
const outer = wrapped(raw, "calendar");
|
|
1278
|
-
const
|
|
1279
|
-
const connection = record(
|
|
1280
|
-
const config = record(
|
|
1293
|
+
const value2 = record(outer.attempt) ?? record(outer.status) ?? outer;
|
|
1294
|
+
const connection = record(value2.connection) ?? {};
|
|
1295
|
+
const config = record(value2.config) ?? record(outer.config) ?? {};
|
|
1281
1296
|
const googleConfig = record(config.google) ?? config;
|
|
1282
|
-
const stateValue = calendarState(
|
|
1297
|
+
const stateValue = calendarState(value2.status ?? value2.state ?? connection.status ?? connection.state);
|
|
1283
1298
|
if (!stateValue) {
|
|
1284
1299
|
throw new Error("calendar status returned an invalid connection state");
|
|
1285
1300
|
}
|
|
1286
|
-
const providerValue =
|
|
1301
|
+
const providerValue = value2.provider ?? connection.provider ?? config.provider ?? (config.google ? "google" : void 0);
|
|
1287
1302
|
if (providerValue !== void 0 && providerValue !== null && providerValue !== "google") {
|
|
1288
1303
|
throw new Error("calendar status returned an unsupported provider");
|
|
1289
1304
|
}
|
|
1290
|
-
const accessValue =
|
|
1305
|
+
const accessValue = value2.access ?? connection.access ?? config.access ?? googleConfig.access;
|
|
1291
1306
|
if (accessValue !== void 0 && accessValue !== "book" && accessValue !== "read") {
|
|
1292
1307
|
throw new Error("calendar status returned unsupported access");
|
|
1293
1308
|
}
|
|
1294
|
-
const errorValue = record(
|
|
1295
|
-
const errorCode = textField(
|
|
1296
|
-
const bookingPageValue = Object.hasOwn(
|
|
1297
|
-
const connected = typeof (
|
|
1298
|
-
const bookingCalendarId = textField(
|
|
1309
|
+
const errorValue = record(value2.error) ?? record(connection.error);
|
|
1310
|
+
const errorCode = textField(value2.lastErrorCode, 128);
|
|
1311
|
+
const bookingPageValue = Object.hasOwn(value2, "bookingPageUrl") ? value2.bookingPageUrl : Object.hasOwn(config, "bookingPageUrl") ? config.bookingPageUrl : googleConfig.bookingPageUrl;
|
|
1312
|
+
const connected = typeof (value2.connected ?? connection.connected) === "boolean" ? Boolean(value2.connected ?? connection.connected) : ["healthy", "degraded"].includes(stateValue);
|
|
1313
|
+
const bookingCalendarId = textField(value2.bookingCalendarId ?? config.bookingCalendarId, 1024);
|
|
1299
1314
|
return {
|
|
1300
1315
|
env,
|
|
1301
|
-
enabled: typeof
|
|
1316
|
+
enabled: typeof value2.enabled === "boolean" ? value2.enabled : true,
|
|
1302
1317
|
connected,
|
|
1303
|
-
writable: typeof
|
|
1318
|
+
writable: typeof value2.writable === "boolean" ? value2.writable : stateValue === "healthy",
|
|
1304
1319
|
provider: providerValue === "google" ? "google" : null,
|
|
1305
1320
|
status: stateValue,
|
|
1306
1321
|
...accessValue !== void 0 ? { access: "book" } : {},
|
|
1307
1322
|
...bookingCalendarId ? { bookingCalendarId } : {},
|
|
1308
1323
|
calendars: calendarIds(
|
|
1309
|
-
|
|
1324
|
+
value2.availabilityCalendars ?? config.availabilityCalendars ?? value2.configuredCalendars ?? value2.calendars ?? config.calendars ?? googleConfig.calendars
|
|
1310
1325
|
),
|
|
1311
1326
|
...optionalNullableUrl("bookingPageUrl", bookingPageValue),
|
|
1312
|
-
grantedScopes: stringList(
|
|
1313
|
-
...optionalText("attemptId",
|
|
1327
|
+
grantedScopes: stringList(value2.grantedScopes ?? connection.grantedScopes ?? connection.scopes),
|
|
1328
|
+
...optionalText("attemptId", value2.attemptId ?? connection.attemptId, 180),
|
|
1314
1329
|
...errorValue || errorCode ? { error: {
|
|
1315
1330
|
...textField(errorValue?.code, 128) ? { code: textField(errorValue?.code, 128) } : {},
|
|
1316
1331
|
...textField(errorValue?.message, 500) ? { message: textField(errorValue?.message, 500) } : {},
|
|
@@ -1318,9 +1333,9 @@ function parseCalendarStatus(raw, env) {
|
|
|
1318
1333
|
} } : {}
|
|
1319
1334
|
};
|
|
1320
1335
|
}
|
|
1321
|
-
function calendarState(
|
|
1322
|
-
if (typeof
|
|
1323
|
-
if (CALENDAR_STATES.includes(
|
|
1336
|
+
function calendarState(value2) {
|
|
1337
|
+
if (typeof value2 !== "string") return null;
|
|
1338
|
+
if (CALENDAR_STATES.includes(value2)) return value2;
|
|
1324
1339
|
const legacy = {
|
|
1325
1340
|
disabled: "not_connected",
|
|
1326
1341
|
disconnected: "disconnected",
|
|
@@ -1331,7 +1346,7 @@ function calendarState(value) {
|
|
|
1331
1346
|
ready: "healthy",
|
|
1332
1347
|
error: "failed"
|
|
1333
1348
|
};
|
|
1334
|
-
return legacy[
|
|
1349
|
+
return legacy[value2] ?? null;
|
|
1335
1350
|
}
|
|
1336
1351
|
async function calendarJson(ctx, suffix, init) {
|
|
1337
1352
|
const platform = platformAudience(ctx.platform);
|
|
@@ -1365,50 +1380,50 @@ function wrapped(raw, key) {
|
|
|
1365
1380
|
if (!outer) throw new Error("calendar returned an invalid response");
|
|
1366
1381
|
return record(outer[key]) ?? outer;
|
|
1367
1382
|
}
|
|
1368
|
-
function record(
|
|
1369
|
-
return
|
|
1383
|
+
function record(value2) {
|
|
1384
|
+
return value2 !== null && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
|
|
1370
1385
|
}
|
|
1371
|
-
function textField(
|
|
1372
|
-
return typeof
|
|
1386
|
+
function textField(value2, max) {
|
|
1387
|
+
return typeof value2 === "string" && value2.length > 0 && value2.length <= max && !/[\u0000-\u001f\u007f]/.test(value2) ? value2 : void 0;
|
|
1373
1388
|
}
|
|
1374
|
-
function stringList(
|
|
1375
|
-
return Array.isArray(
|
|
1389
|
+
function stringList(value2) {
|
|
1390
|
+
return Array.isArray(value2) ? [...new Set(value2.filter((item) => !!textField(item, 4096)))] : [];
|
|
1376
1391
|
}
|
|
1377
|
-
function calendarIds(
|
|
1378
|
-
if (!Array.isArray(
|
|
1379
|
-
return [...new Set(
|
|
1392
|
+
function calendarIds(value2) {
|
|
1393
|
+
if (!Array.isArray(value2)) return [];
|
|
1394
|
+
return [...new Set(value2.flatMap((item) => {
|
|
1380
1395
|
if (typeof item === "string") return textField(item, 4096) ? [item] : [];
|
|
1381
1396
|
const calendar = record(item);
|
|
1382
1397
|
const id = textField(calendar?.id, 4096);
|
|
1383
1398
|
return id && calendar?.selected !== false ? [id] : [];
|
|
1384
1399
|
}))];
|
|
1385
1400
|
}
|
|
1386
|
-
function timestamp3(
|
|
1387
|
-
if (typeof
|
|
1388
|
-
if (typeof
|
|
1389
|
-
const parsed = Date.parse(
|
|
1401
|
+
function timestamp3(value2) {
|
|
1402
|
+
if (typeof value2 === "number" && Number.isFinite(value2) && value2 >= 0) return value2;
|
|
1403
|
+
if (typeof value2 === "string") {
|
|
1404
|
+
const parsed = Date.parse(value2);
|
|
1390
1405
|
if (Number.isFinite(parsed)) return parsed;
|
|
1391
1406
|
}
|
|
1392
1407
|
return void 0;
|
|
1393
1408
|
}
|
|
1394
|
-
function optionalText(key,
|
|
1395
|
-
const parsed = textField(
|
|
1409
|
+
function optionalText(key, value2, max) {
|
|
1410
|
+
const parsed = textField(value2, max);
|
|
1396
1411
|
return parsed ? { [key]: parsed } : {};
|
|
1397
1412
|
}
|
|
1398
|
-
function optionalNullableUrl(key,
|
|
1399
|
-
if (
|
|
1400
|
-
const parsed = textField(
|
|
1413
|
+
function optionalNullableUrl(key, value2) {
|
|
1414
|
+
if (value2 === null) return { [key]: null };
|
|
1415
|
+
const parsed = textField(value2, 4096);
|
|
1401
1416
|
return parsed ? { [key]: parsed } : {};
|
|
1402
1417
|
}
|
|
1403
|
-
function identifier(
|
|
1404
|
-
if (typeof
|
|
1405
|
-
return
|
|
1418
|
+
function identifier(value2, name) {
|
|
1419
|
+
if (typeof value2 !== "string" || !/^[A-Za-z0-9][A-Za-z0-9._:-]{0,179}$/.test(value2)) throw new Error(`${name} is invalid`);
|
|
1420
|
+
return value2;
|
|
1406
1421
|
}
|
|
1407
|
-
function credential(
|
|
1408
|
-
if (typeof
|
|
1422
|
+
function credential(value2) {
|
|
1423
|
+
if (typeof value2 !== "string" || value2.length < 8 || value2.length > 8192 || /\s|[\u0000-\u001f\u007f]/.test(value2)) {
|
|
1409
1424
|
throw new Error("calendar requires an odla developer token");
|
|
1410
1425
|
}
|
|
1411
|
-
return
|
|
1426
|
+
return value2;
|
|
1412
1427
|
}
|
|
1413
1428
|
|
|
1414
1429
|
// src/calendar-poll.ts
|
|
@@ -1569,11 +1584,11 @@ async function connectWithContext(ctx, options) {
|
|
|
1569
1584
|
}
|
|
1570
1585
|
throw new Error('Google Calendar consent timed out; run "odla-ai calendar status" and retry connect');
|
|
1571
1586
|
}
|
|
1572
|
-
function trustedCalendarConsentUrl(platform,
|
|
1587
|
+
function trustedCalendarConsentUrl(platform, value2) {
|
|
1573
1588
|
const origin = platformAudience(platform);
|
|
1574
1589
|
let url;
|
|
1575
1590
|
try {
|
|
1576
|
-
url =
|
|
1591
|
+
url = value2.startsWith("/") ? new URL(value2, origin) : new URL(value2);
|
|
1577
1592
|
} catch {
|
|
1578
1593
|
throw new Error("odla.ai returned an invalid calendar consent URL");
|
|
1579
1594
|
}
|
|
@@ -1584,9 +1599,9 @@ function trustedCalendarConsentUrl(platform, value) {
|
|
|
1584
1599
|
}
|
|
1585
1600
|
return url.toString();
|
|
1586
1601
|
}
|
|
1587
|
-
function pollTimeout(
|
|
1588
|
-
if (!Number.isSafeInteger(
|
|
1589
|
-
return
|
|
1602
|
+
function pollTimeout(value2 = 10 * 6e4) {
|
|
1603
|
+
if (!Number.isSafeInteger(value2) || value2 < 1e3 || value2 > 60 * 6e4) throw new Error("calendar poll timeout must be 1000-3600000ms");
|
|
1604
|
+
return value2;
|
|
1590
1605
|
}
|
|
1591
1606
|
function productionConsent(env, yes, action) {
|
|
1592
1607
|
if ((env === "prod" || env === "production") && !yes) throw new Error(`refusing to ${action} for "${env}" without --yes`);
|
|
@@ -1618,6 +1633,7 @@ var CAPABILITIES = {
|
|
|
1618
1633
|
"validate integration contracts offline and smoke-test a provisioned db environment plus anonymous capability routes",
|
|
1619
1634
|
"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",
|
|
1620
1635
|
"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",
|
|
1636
|
+
"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",
|
|
1621
1637
|
"inspect durable agent wakeups as a versioned JSON envelope and explicitly requeue one dead-lettered job with a scoped environment credential",
|
|
1622
1638
|
"run app-attributed hosted security discovery and independent validation without provider keys",
|
|
1623
1639
|
"connect/revoke source-read-only GitHub sources and drive commit-pinned hosted security jobs without PATs or provider keys",
|
|
@@ -1801,8 +1817,8 @@ function wranglerWarnings(rootDir) {
|
|
|
1801
1817
|
}
|
|
1802
1818
|
const vars = block.vars;
|
|
1803
1819
|
if (vars && typeof vars === "object") {
|
|
1804
|
-
for (const [name,
|
|
1805
|
-
if (name === "ODLA_API_KEY" || name === "ODLA_O11Y_TOKEN" || typeof
|
|
1820
|
+
for (const [name, value2] of Object.entries(vars)) {
|
|
1821
|
+
if (name === "ODLA_API_KEY" || name === "ODLA_O11Y_TOKEN" || typeof value2 === "string" && looksSecret(value2)) {
|
|
1806
1822
|
warnings.push(`wrangler ${label}vars.${name} looks like a secret \u2014 use "odla-ai secrets push" / wrangler secret put, never vars`);
|
|
1807
1823
|
}
|
|
1808
1824
|
}
|
|
@@ -1970,27 +1986,27 @@ function isUniqueAttr(schema, ns, attr) {
|
|
|
1970
1986
|
const definition = entity.attrs[attr];
|
|
1971
1987
|
return isRecord6(definition) && definition.unique === true;
|
|
1972
1988
|
}
|
|
1973
|
-
function normalizeSchema(
|
|
1974
|
-
if (
|
|
1975
|
-
if (!isRecord6(
|
|
1989
|
+
function normalizeSchema(value2) {
|
|
1990
|
+
if (value2 === void 0 || value2 === null) return { entities: {}, links: {} };
|
|
1991
|
+
if (!isRecord6(value2) || !isRecord6(value2.entities)) {
|
|
1976
1992
|
throw new Error("db schema must be a serialized schema object with an entities map");
|
|
1977
1993
|
}
|
|
1978
|
-
if (
|
|
1994
|
+
if (value2.links !== void 0 && !isRecord6(value2.links)) throw new Error("db schema links must be an object");
|
|
1979
1995
|
return {
|
|
1980
|
-
entities: { ...
|
|
1981
|
-
links: { ...
|
|
1996
|
+
entities: { ...value2.entities },
|
|
1997
|
+
links: { ...value2.links ?? {} }
|
|
1982
1998
|
};
|
|
1983
1999
|
}
|
|
1984
2000
|
function mergeMap(target, fragment, label) {
|
|
1985
|
-
for (const [name,
|
|
1986
|
-
if (Object.hasOwn(target, name) && !isDeepStrictEqual(target[name],
|
|
2001
|
+
for (const [name, value2] of Object.entries(fragment)) {
|
|
2002
|
+
if (Object.hasOwn(target, name) && !isDeepStrictEqual(target[name], value2)) {
|
|
1987
2003
|
throw new Error(`${label} "${name}" conflicts with an existing definition`);
|
|
1988
2004
|
}
|
|
1989
|
-
target[name] =
|
|
2005
|
+
target[name] = value2;
|
|
1990
2006
|
}
|
|
1991
2007
|
}
|
|
1992
|
-
function isRecord6(
|
|
1993
|
-
return
|
|
2008
|
+
function isRecord6(value2) {
|
|
2009
|
+
return value2 !== null && typeof value2 === "object" && !Array.isArray(value2);
|
|
1994
2010
|
}
|
|
1995
2011
|
|
|
1996
2012
|
// src/doctor.ts
|
|
@@ -2031,9 +2047,9 @@ async function doctor(options) {
|
|
|
2031
2047
|
warnings.push(...integrationWarnings(database.integrations, schema, rules));
|
|
2032
2048
|
if (cfg.services.includes("ai") && !cfg.ai?.provider) warnings.push("ai service is enabled but ai.provider is not set");
|
|
2033
2049
|
if (cfg.auth?.clerk) {
|
|
2034
|
-
for (const [env,
|
|
2035
|
-
if (typeof
|
|
2036
|
-
warnings.push(`auth.clerk.${env} references unset env var ${
|
|
2050
|
+
for (const [env, value2] of Object.entries(cfg.auth.clerk)) {
|
|
2051
|
+
if (typeof value2 === "string" && value2.startsWith("$") && !process.env[value2.slice(1)]) {
|
|
2052
|
+
warnings.push(`auth.clerk.${env} references unset env var ${value2}`);
|
|
2037
2053
|
}
|
|
2038
2054
|
}
|
|
2039
2055
|
}
|
|
@@ -2070,6 +2086,7 @@ async function doctor(options) {
|
|
|
2070
2086
|
// src/init.ts
|
|
2071
2087
|
import { existsSync as existsSync6, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
2072
2088
|
import { dirname as dirname4, resolve as resolve4 } from "path";
|
|
2089
|
+
import { appServiceDefinition as appServiceDefinition2, appServiceIds as appServiceIds2 } from "@odla-ai/apps";
|
|
2073
2090
|
function initProject(options) {
|
|
2074
2091
|
const out = options.stdout ?? console;
|
|
2075
2092
|
const rootDir = resolve4(options.rootDir ?? process.cwd());
|
|
@@ -2082,7 +2099,13 @@ function initProject(options) {
|
|
|
2082
2099
|
}
|
|
2083
2100
|
const envs = options.envs?.length ? options.envs : ["dev"];
|
|
2084
2101
|
const services = options.services?.length ? options.services : ["db", "ai"];
|
|
2085
|
-
|
|
2102
|
+
for (const service of services) {
|
|
2103
|
+
const definition = appServiceDefinition2(service);
|
|
2104
|
+
if (!definition) throw new Error(`--services contains unknown service "${service}" (known: ${appServiceIds2().join(", ")})`);
|
|
2105
|
+
for (const dependency of definition.requires) {
|
|
2106
|
+
if (!services.includes(dependency)) throw new Error(`--services ${service} requires ${dependency}`);
|
|
2107
|
+
}
|
|
2108
|
+
}
|
|
2086
2109
|
const aiProvider = options.aiProvider ?? "anthropic";
|
|
2087
2110
|
mkdirSync2(dirname4(configPath), { recursive: true });
|
|
2088
2111
|
mkdirSync2(resolve4(rootDir, "src/odla"), { recursive: true });
|
|
@@ -2280,38 +2303,38 @@ async function secretsSet(options) {
|
|
|
2280
2303
|
if (name.startsWith("$")) {
|
|
2281
2304
|
throw new Error('"$"-prefixed vault names are platform-reserved; for the Clerk secret key use "odla-ai secrets set-clerk-key"');
|
|
2282
2305
|
}
|
|
2283
|
-
const { cfg, tenantId, value, doFetch, out } = await resolveVaultWrite(options);
|
|
2306
|
+
const { cfg, tenantId, value: value2, doFetch, out } = await resolveVaultWrite(options);
|
|
2284
2307
|
const token = await getDeveloperToken(cfg, options, doFetch, out);
|
|
2285
2308
|
try {
|
|
2286
|
-
await putSecret({ endpoint: cfg.dbEndpoint, token, fetch: doFetch }, tenantId, name,
|
|
2309
|
+
await putSecret({ endpoint: cfg.dbEndpoint, token, fetch: doFetch }, tenantId, name, value2);
|
|
2287
2310
|
} catch (err) {
|
|
2288
|
-
throw new Error(scrubValue(err instanceof Error ? err.message : String(err),
|
|
2311
|
+
throw new Error(scrubValue(err instanceof Error ? err.message : String(err), value2));
|
|
2289
2312
|
}
|
|
2290
2313
|
out.log(`${name} stored in the ${tenantId} vault (write-only; the value was never echoed and cannot be read back here)`);
|
|
2291
2314
|
}
|
|
2292
2315
|
async function secretsSetClerkKey(options) {
|
|
2293
|
-
const { cfg, tenantId, value, doFetch, out } = await resolveVaultWrite(options);
|
|
2294
|
-
if (!
|
|
2295
|
-
if (
|
|
2316
|
+
const { cfg, tenantId, value: value2, doFetch, out } = await resolveVaultWrite(options);
|
|
2317
|
+
if (!value2.startsWith("sk_")) throw new Error("the Clerk secret key must start with sk_ (sk_test_\u2026 or sk_live_\u2026)");
|
|
2318
|
+
if (value2.startsWith("sk_test_") && PROD_ENV_NAMES2.has(options.env)) {
|
|
2296
2319
|
throw new Error(`refusing to store an sk_test_ Clerk key for "${options.env}" \u2014 use the production instance's sk_live_ key`);
|
|
2297
2320
|
}
|
|
2298
|
-
if (
|
|
2321
|
+
if (value2.startsWith("sk_live_") && !PROD_ENV_NAMES2.has(options.env) && !options.yes) {
|
|
2299
2322
|
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)`);
|
|
2300
2323
|
}
|
|
2301
2324
|
const token = await getDeveloperToken(cfg, options, doFetch, out);
|
|
2302
2325
|
const res = await doFetch(`${cfg.dbEndpoint}/admin/apps/${encodeURIComponent(tenantId)}/clerk-secret`, {
|
|
2303
2326
|
method: "POST",
|
|
2304
2327
|
headers: { authorization: `Bearer ${token}`, "content-type": "application/json" },
|
|
2305
|
-
body: JSON.stringify({ value })
|
|
2328
|
+
body: JSON.stringify({ value: value2 })
|
|
2306
2329
|
});
|
|
2307
2330
|
if (!res.ok) {
|
|
2308
|
-
const text = scrubValue((await res.text().catch(() => "")).slice(0, 300),
|
|
2331
|
+
const text = scrubValue((await res.text().catch(() => "")).slice(0, 300), value2);
|
|
2309
2332
|
throw new Error(`store Clerk secret key failed (${res.status}): ${text || "request failed"}`);
|
|
2310
2333
|
}
|
|
2311
2334
|
out.log(`Clerk secret key stored for ${tenantId} ($clerk_secret, reserved + write-only; the value was never echoed)`);
|
|
2312
2335
|
}
|
|
2313
|
-
function scrubValue(text,
|
|
2314
|
-
return redactSecrets(text).split(
|
|
2336
|
+
function scrubValue(text, value2) {
|
|
2337
|
+
return redactSecrets(text).split(value2).join("[value redacted]");
|
|
2315
2338
|
}
|
|
2316
2339
|
async function resolveVaultWrite(options) {
|
|
2317
2340
|
const out = options.stdout ?? console;
|
|
@@ -2323,8 +2346,8 @@ async function resolveVaultWrite(options) {
|
|
|
2323
2346
|
if (PROD_ENV_NAMES2.has(options.env) && !options.yes) {
|
|
2324
2347
|
throw new Error(`refusing to store a secret for "${options.env}" without --yes`);
|
|
2325
2348
|
}
|
|
2326
|
-
const
|
|
2327
|
-
return { cfg, tenantId: tenantIdFor(cfg.app.id, options.env), value, doFetch, out };
|
|
2349
|
+
const value2 = await secretInputValue(options, "secret");
|
|
2350
|
+
return { cfg, tenantId: tenantIdFor(cfg.app.id, options.env), value: value2, doFetch, out };
|
|
2328
2351
|
}
|
|
2329
2352
|
|
|
2330
2353
|
// src/skill.ts
|
|
@@ -2765,31 +2788,31 @@ async function requestHostedSecurityJson(options, path, init, action) {
|
|
|
2765
2788
|
}
|
|
2766
2789
|
return body;
|
|
2767
2790
|
}
|
|
2768
|
-
function hostedIdentifier(
|
|
2769
|
-
const result = optionalHostedText(
|
|
2791
|
+
function hostedIdentifier(value2, name) {
|
|
2792
|
+
const result = optionalHostedText(value2, name, 180);
|
|
2770
2793
|
if (!result || !/^[A-Za-z0-9][A-Za-z0-9._:-]*$/.test(result)) {
|
|
2771
2794
|
throw new Error(`${name} is invalid`);
|
|
2772
2795
|
}
|
|
2773
2796
|
return result;
|
|
2774
2797
|
}
|
|
2775
|
-
function positivePolicyVersion(
|
|
2776
|
-
if (!Number.isSafeInteger(
|
|
2798
|
+
function positivePolicyVersion(value2, name) {
|
|
2799
|
+
if (!Number.isSafeInteger(value2) || value2 < 1) {
|
|
2777
2800
|
throw new Error(`${name} is invalid`);
|
|
2778
2801
|
}
|
|
2779
|
-
return
|
|
2802
|
+
return value2;
|
|
2780
2803
|
}
|
|
2781
|
-
function optionalHostedText(
|
|
2782
|
-
if (
|
|
2783
|
-
if (typeof
|
|
2804
|
+
function optionalHostedText(value2, name, maxLength) {
|
|
2805
|
+
if (value2 === void 0 || value2 === null || value2 === "") return void 0;
|
|
2806
|
+
if (typeof value2 !== "string" || value2.length > maxLength || /[\u0000-\u001f\u007f]/.test(value2)) {
|
|
2784
2807
|
throw new Error(`${name} is invalid`);
|
|
2785
2808
|
}
|
|
2786
|
-
return
|
|
2809
|
+
return value2;
|
|
2787
2810
|
}
|
|
2788
|
-
function githubRepositoryName(
|
|
2789
|
-
if (typeof
|
|
2811
|
+
function githubRepositoryName(value2) {
|
|
2812
|
+
if (typeof value2 !== "string" || value2.length > 201) {
|
|
2790
2813
|
throw new Error("repository must be owner/name");
|
|
2791
2814
|
}
|
|
2792
|
-
const parts =
|
|
2815
|
+
const parts = value2.split("/");
|
|
2793
2816
|
const owner = parts[0] ?? "";
|
|
2794
2817
|
const name = (parts[1] ?? "").replace(/\.git$/i, "");
|
|
2795
2818
|
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 === "..") {
|
|
@@ -2797,10 +2820,10 @@ function githubRepositoryName(value) {
|
|
|
2797
2820
|
}
|
|
2798
2821
|
return `${owner}/${name}`;
|
|
2799
2822
|
}
|
|
2800
|
-
function trustedGitHubInstallUrl(
|
|
2823
|
+
function trustedGitHubInstallUrl(value2) {
|
|
2801
2824
|
let url;
|
|
2802
2825
|
try {
|
|
2803
|
-
url = new URL(
|
|
2826
|
+
url = new URL(value2);
|
|
2804
2827
|
} catch {
|
|
2805
2828
|
throw new Error("odla.ai returned an invalid GitHub installation URL");
|
|
2806
2829
|
}
|
|
@@ -2809,17 +2832,17 @@ function trustedGitHubInstallUrl(value) {
|
|
|
2809
2832
|
}
|
|
2810
2833
|
return url.toString();
|
|
2811
2834
|
}
|
|
2812
|
-
function hostedPollInterval(
|
|
2813
|
-
if (!Number.isSafeInteger(
|
|
2835
|
+
function hostedPollInterval(value2 = 2e3) {
|
|
2836
|
+
if (!Number.isSafeInteger(value2) || value2 < 100 || value2 > 3e4) {
|
|
2814
2837
|
throw new Error("poll interval must be 100-30000ms");
|
|
2815
2838
|
}
|
|
2816
|
-
return
|
|
2839
|
+
return value2;
|
|
2817
2840
|
}
|
|
2818
|
-
function hostedPollTimeout(
|
|
2819
|
-
if (!Number.isSafeInteger(
|
|
2841
|
+
function hostedPollTimeout(value2 = 10 * 6e4) {
|
|
2842
|
+
if (!Number.isSafeInteger(value2) || value2 < 1e3 || value2 > 60 * 6e4) {
|
|
2820
2843
|
throw new Error("poll timeout must be 1000-3600000ms");
|
|
2821
2844
|
}
|
|
2822
|
-
return
|
|
2845
|
+
return value2;
|
|
2823
2846
|
}
|
|
2824
2847
|
async function waitForHostedPoll(milliseconds, signal) {
|
|
2825
2848
|
if (signal?.aborted) throw signal.reason ?? new DOMException("aborted", "AbortError");
|
|
@@ -2831,16 +2854,16 @@ async function waitForHostedPoll(milliseconds, signal) {
|
|
|
2831
2854
|
}, { once: true });
|
|
2832
2855
|
});
|
|
2833
2856
|
}
|
|
2834
|
-
function isValidHostedSecurityPlan(
|
|
2835
|
-
if (!
|
|
2857
|
+
function isValidHostedSecurityPlan(value2, env) {
|
|
2858
|
+
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;
|
|
2836
2859
|
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;
|
|
2837
|
-
return validRoute(
|
|
2860
|
+
return validRoute(value2.routes?.discovery, "security.discovery") && validRoute(value2.routes?.validation, "security.validation");
|
|
2838
2861
|
}
|
|
2839
|
-
function hostedSecurityCredential(
|
|
2840
|
-
if (typeof
|
|
2862
|
+
function hostedSecurityCredential(value2) {
|
|
2863
|
+
if (typeof value2 !== "string" || value2.length < 8 || value2.length > 8192 || /\s|[\u0000-\u001f\u007f]/.test(value2)) {
|
|
2841
2864
|
throw new Error("Hosted security requires an injected odla developer token");
|
|
2842
2865
|
}
|
|
2843
|
-
return
|
|
2866
|
+
return value2;
|
|
2844
2867
|
}
|
|
2845
2868
|
|
|
2846
2869
|
// src/security-hosted-github.ts
|
|
@@ -3068,24 +3091,24 @@ var CONTROL = /[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/;
|
|
|
3068
3091
|
var HarnessProtocolError = class extends Error {
|
|
3069
3092
|
name = "HarnessProtocolError";
|
|
3070
3093
|
};
|
|
3071
|
-
function record2(
|
|
3072
|
-
return
|
|
3094
|
+
function record2(value2) {
|
|
3095
|
+
return value2 !== null && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
|
|
3073
3096
|
}
|
|
3074
|
-
function boundedText(
|
|
3075
|
-
if (typeof
|
|
3097
|
+
function boundedText(value2, label, max) {
|
|
3098
|
+
if (typeof value2 !== "string" || !value2 || value2.length > max || CONTROL.test(value2)) {
|
|
3076
3099
|
throw new HarnessProtocolError(`${label} must be a non-empty string of at most ${max} characters`);
|
|
3077
3100
|
}
|
|
3078
|
-
return
|
|
3101
|
+
return value2;
|
|
3079
3102
|
}
|
|
3080
3103
|
function parseAgentOutput(line) {
|
|
3081
3104
|
if (Buffer.byteLength(line, "utf8") > 1e6) throw new HarnessProtocolError("agent message exceeds 1 MB");
|
|
3082
|
-
let
|
|
3105
|
+
let value2;
|
|
3083
3106
|
try {
|
|
3084
|
-
|
|
3107
|
+
value2 = JSON.parse(line);
|
|
3085
3108
|
} catch {
|
|
3086
3109
|
throw new HarnessProtocolError("agent emitted invalid JSON");
|
|
3087
3110
|
}
|
|
3088
|
-
const message2 = record2(
|
|
3111
|
+
const message2 = record2(value2);
|
|
3089
3112
|
if (!message2 || message2.protocolVersion !== HARNESS_PROTOCOL_VERSION) {
|
|
3090
3113
|
throw new HarnessProtocolError(`agent protocolVersion must be ${HARNESS_PROTOCOL_VERSION}`);
|
|
3091
3114
|
}
|
|
@@ -3394,7 +3417,7 @@ async function gitOutput(cwd, args, maxBytes) {
|
|
|
3394
3417
|
else stdout.push(chunk);
|
|
3395
3418
|
});
|
|
3396
3419
|
child.stderr.on("data", (chunk) => {
|
|
3397
|
-
if (stderr.reduce((sum,
|
|
3420
|
+
if (stderr.reduce((sum, value2) => sum + value2.byteLength, 0) < 16384) stderr.push(chunk);
|
|
3398
3421
|
});
|
|
3399
3422
|
const code = await new Promise((accept, reject) => {
|
|
3400
3423
|
child.once("error", reject);
|
|
@@ -3415,7 +3438,7 @@ async function gitBlobs(cwd, entries, maxBytes) {
|
|
|
3415
3438
|
else stdout.push(chunk);
|
|
3416
3439
|
});
|
|
3417
3440
|
child.stderr.on("data", (chunk) => {
|
|
3418
|
-
if (stderr.reduce((sum,
|
|
3441
|
+
if (stderr.reduce((sum, value2) => sum + value2.byteLength, 0) < 16384) stderr.push(chunk);
|
|
3419
3442
|
});
|
|
3420
3443
|
child.stdin.end(`${entries.map((entry) => entry.hash).join("\n")}
|
|
3421
3444
|
`);
|
|
@@ -3453,8 +3476,8 @@ async function materializeGitTree(source, commitSha, options = {}) {
|
|
|
3453
3476
|
const maxFiles = options.maxFiles ?? 2e4;
|
|
3454
3477
|
const maxBytes = options.maxBytes ?? 512 * 1024 * 1024;
|
|
3455
3478
|
const inventory = (await gitOutput(sourceDir, ["ls-tree", "-rz", commitSha], 16 * 1024 * 1024)).toString("utf8").split("\0").filter(Boolean);
|
|
3456
|
-
const entries = inventory.flatMap((
|
|
3457
|
-
const match = /^(100644|100755) blob ([0-9a-f]{40,64})\t([\s\S]+)$/.exec(
|
|
3479
|
+
const entries = inventory.flatMap((record8) => {
|
|
3480
|
+
const match = /^(100644|100755) blob ([0-9a-f]{40,64})\t([\s\S]+)$/.exec(record8);
|
|
3458
3481
|
return match && allowedWorkspacePath(match[3]) ? [{ mode: match[1], hash: match[2], path: match[3] }] : [];
|
|
3459
3482
|
});
|
|
3460
3483
|
if (entries.length > maxFiles) throw new Error(`workspace exceeds ${maxFiles} files`);
|
|
@@ -3529,7 +3552,7 @@ async function gitSourceFiles(sourceDir, maxFiles, maxBytes) {
|
|
|
3529
3552
|
else stdout.push(chunk);
|
|
3530
3553
|
});
|
|
3531
3554
|
child.stderr.on("data", (chunk) => {
|
|
3532
|
-
if (stderr.reduce((sum,
|
|
3555
|
+
if (stderr.reduce((sum, value2) => sum + value2.byteLength, 0) < 16384) stderr.push(chunk);
|
|
3533
3556
|
});
|
|
3534
3557
|
const code = await new Promise((accept, reject) => {
|
|
3535
3558
|
child.once("error", reject);
|
|
@@ -3589,7 +3612,7 @@ async function captureGitDiff(root, maxBytes) {
|
|
|
3589
3612
|
else stdout.push(chunk);
|
|
3590
3613
|
});
|
|
3591
3614
|
child.stderr.on("data", (chunk) => {
|
|
3592
|
-
if (stderr.reduce((sum,
|
|
3615
|
+
if (stderr.reduce((sum, value2) => sum + value2.byteLength, 0) < 16384) stderr.push(chunk);
|
|
3593
3616
|
});
|
|
3594
3617
|
const code = await new Promise((accept, reject) => {
|
|
3595
3618
|
child.once("error", reject);
|
|
@@ -3676,34 +3699,34 @@ var CamelError = class extends Error {
|
|
|
3676
3699
|
};
|
|
3677
3700
|
|
|
3678
3701
|
// ../camel/dist/chunk-L5DYU2E2.js
|
|
3679
|
-
function canonicalJson(
|
|
3680
|
-
return JSON.stringify(normalize(
|
|
3702
|
+
function canonicalJson(value2) {
|
|
3703
|
+
return JSON.stringify(normalize(value2));
|
|
3681
3704
|
}
|
|
3682
|
-
async function sha256Hex(
|
|
3683
|
-
const bytes = typeof
|
|
3705
|
+
async function sha256Hex(value2) {
|
|
3706
|
+
const bytes = typeof value2 === "string" ? new TextEncoder().encode(value2) : value2;
|
|
3684
3707
|
const digest = await crypto.subtle.digest("SHA-256", Uint8Array.from(bytes).buffer);
|
|
3685
3708
|
return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
3686
3709
|
}
|
|
3687
|
-
function utf8Length(
|
|
3688
|
-
if (typeof
|
|
3689
|
-
if (
|
|
3710
|
+
function utf8Length(value2) {
|
|
3711
|
+
if (typeof value2 === "string") return new TextEncoder().encode(value2).byteLength;
|
|
3712
|
+
if (value2 instanceof Uint8Array) return value2.byteLength;
|
|
3690
3713
|
try {
|
|
3691
|
-
return new TextEncoder().encode(canonicalJson(
|
|
3714
|
+
return new TextEncoder().encode(canonicalJson(value2)).byteLength;
|
|
3692
3715
|
} catch {
|
|
3693
3716
|
throw new CamelError("conversion_rejected", "Unsafe input could not be canonically measured.");
|
|
3694
3717
|
}
|
|
3695
3718
|
}
|
|
3696
|
-
function normalize(
|
|
3697
|
-
if (
|
|
3698
|
-
if (typeof
|
|
3699
|
-
if (!Number.isFinite(
|
|
3700
|
-
return
|
|
3719
|
+
function normalize(value2) {
|
|
3720
|
+
if (value2 === null || typeof value2 === "string" || typeof value2 === "boolean") return value2;
|
|
3721
|
+
if (typeof value2 === "number") {
|
|
3722
|
+
if (!Number.isFinite(value2)) throw new CamelError("state_conflict", "Canonical JSON rejects non-finite numbers.");
|
|
3723
|
+
return value2;
|
|
3701
3724
|
}
|
|
3702
|
-
if (Array.isArray(
|
|
3703
|
-
if (
|
|
3704
|
-
if (typeof
|
|
3705
|
-
const
|
|
3706
|
-
return Object.fromEntries(Object.keys(
|
|
3725
|
+
if (Array.isArray(value2)) return value2.map(normalize);
|
|
3726
|
+
if (value2 instanceof Uint8Array) return { $bytes: [...value2] };
|
|
3727
|
+
if (typeof value2 === "object") {
|
|
3728
|
+
const record8 = value2;
|
|
3729
|
+
return Object.fromEntries(Object.keys(record8).filter((key) => record8[key] !== void 0).sort().map((key) => [key, normalize(record8[key])]));
|
|
3707
3730
|
}
|
|
3708
3731
|
throw new CamelError("state_conflict", "Canonical JSON rejects unsupported values.");
|
|
3709
3732
|
}
|
|
@@ -3712,10 +3735,10 @@ function canRead(readers, readerId) {
|
|
|
3712
3735
|
}
|
|
3713
3736
|
function dependenciesOf(values, influence = "data") {
|
|
3714
3737
|
const result = [];
|
|
3715
|
-
for (const
|
|
3716
|
-
result.push(...
|
|
3717
|
-
for (const ref of
|
|
3718
|
-
result.push({ ref, influence, promptSafetyAtUse:
|
|
3738
|
+
for (const value2 of values) {
|
|
3739
|
+
result.push(...value2.label.dependencies);
|
|
3740
|
+
for (const ref of value2.label.provenance) {
|
|
3741
|
+
result.push({ ref, influence, promptSafetyAtUse: value2.label.promptSafety });
|
|
3719
3742
|
}
|
|
3720
3743
|
}
|
|
3721
3744
|
const unique3 = /* @__PURE__ */ new Map();
|
|
@@ -3726,32 +3749,32 @@ function dependenciesOf(values, influence = "data") {
|
|
|
3726
3749
|
// ../camel/dist/chunk-S7EVNA2U.js
|
|
3727
3750
|
var camelValueBrand = /* @__PURE__ */ Symbol("@odla-ai/camel/value");
|
|
3728
3751
|
var authenticCamelValues = /* @__PURE__ */ new WeakSet();
|
|
3729
|
-
function isCamelValue(
|
|
3730
|
-
return typeof
|
|
3752
|
+
function isCamelValue(value2) {
|
|
3753
|
+
return typeof value2 === "object" && value2 !== null && authenticCamelValues.has(value2);
|
|
3731
3754
|
}
|
|
3732
|
-
function isSafe(
|
|
3733
|
-
return isCamelValue(
|
|
3755
|
+
function isSafe(value2) {
|
|
3756
|
+
return isCamelValue(value2) && value2.label.promptSafety === "safe";
|
|
3734
3757
|
}
|
|
3735
|
-
function isUnsafe(
|
|
3736
|
-
return isCamelValue(
|
|
3758
|
+
function isUnsafe(value2) {
|
|
3759
|
+
return isCamelValue(value2) && value2.label.promptSafety === "unsafe";
|
|
3737
3760
|
}
|
|
3738
|
-
function createSafeInternal(
|
|
3739
|
-
return createValue(
|
|
3761
|
+
function createSafeInternal(value2, safeBasis, metadata2) {
|
|
3762
|
+
return createValue(value2, {
|
|
3740
3763
|
schemaVersion: 1,
|
|
3741
3764
|
promptSafety: "safe",
|
|
3742
3765
|
safeBasis,
|
|
3743
3766
|
...copyMetadata(metadata2)
|
|
3744
3767
|
});
|
|
3745
3768
|
}
|
|
3746
|
-
function createUnsafeInternal(
|
|
3747
|
-
return createValue(
|
|
3769
|
+
function createUnsafeInternal(value2, metadata2) {
|
|
3770
|
+
return createValue(value2, {
|
|
3748
3771
|
schemaVersion: 1,
|
|
3749
3772
|
promptSafety: "unsafe",
|
|
3750
3773
|
...copyMetadata(metadata2)
|
|
3751
3774
|
});
|
|
3752
3775
|
}
|
|
3753
|
-
function createValue(
|
|
3754
|
-
const result = { value, label: Object.freeze(label) };
|
|
3776
|
+
function createValue(value2, label) {
|
|
3777
|
+
const result = { value: value2, label: Object.freeze(label) };
|
|
3755
3778
|
Object.defineProperty(result, camelValueBrand, { value: label.promptSafety, enumerable: false });
|
|
3756
3779
|
authenticCamelValues.add(result);
|
|
3757
3780
|
return Object.freeze(result);
|
|
@@ -3857,8 +3880,8 @@ async function createCodePortableCheckpoint(input) {
|
|
|
3857
3880
|
const checkpointDigest = `sha256:${await sha256Hex(canonicalJson(fields))}`;
|
|
3858
3881
|
return freeze({ ...fields, patch: input.patch, checkpointDigest });
|
|
3859
3882
|
}
|
|
3860
|
-
async function verifyCodePortableCheckpoint(
|
|
3861
|
-
const input = object(
|
|
3883
|
+
async function verifyCodePortableCheckpoint(value2) {
|
|
3884
|
+
const input = object(value2, "checkpoint");
|
|
3862
3885
|
exact2(input, ["schemaVersion", "baseCommitSha", "patch", "patchDigest", "state", "stateDigest", "checkpointDigest"]);
|
|
3863
3886
|
if (input.schemaVersion !== 1 || typeof input.baseCommitSha !== "string" || typeof input.patch !== "string" || typeof input.patchDigest !== "string" || typeof input.stateDigest !== "string" || typeof input.checkpointDigest !== "string") {
|
|
3864
3887
|
throw invalid2("Portable checkpoint fields are malformed.");
|
|
@@ -3873,8 +3896,8 @@ async function verifyCodePortableCheckpoint(value) {
|
|
|
3873
3896
|
}
|
|
3874
3897
|
return created;
|
|
3875
3898
|
}
|
|
3876
|
-
function normalizeState(
|
|
3877
|
-
const state2 = object(
|
|
3899
|
+
function normalizeState(value2) {
|
|
3900
|
+
const state2 = object(value2, "state");
|
|
3878
3901
|
exact2(state2, [
|
|
3879
3902
|
"planCursor",
|
|
3880
3903
|
"conversationRefs",
|
|
@@ -3932,30 +3955,30 @@ function validateBaseAndPatch(baseCommitSha, patch2) {
|
|
|
3932
3955
|
throw invalid2("Portable checkpoint base or patch is malformed or outside its bounds.");
|
|
3933
3956
|
}
|
|
3934
3957
|
}
|
|
3935
|
-
function strings(
|
|
3936
|
-
if (!Array.isArray(
|
|
3958
|
+
function strings(value2, name, pattern, maximum, sort) {
|
|
3959
|
+
if (!Array.isArray(value2) || value2.length > maximum || value2.some((item) => typeof item !== "string" || !pattern.test(item)) || new Set(value2).size !== value2.length) {
|
|
3937
3960
|
throw invalid2(`Portable checkpoint ${name} is malformed or outside its bounds.`);
|
|
3938
3961
|
}
|
|
3939
|
-
const result = [...
|
|
3962
|
+
const result = [...value2];
|
|
3940
3963
|
return sort ? result.sort() : result;
|
|
3941
3964
|
}
|
|
3942
|
-
function object(
|
|
3943
|
-
if (!
|
|
3944
|
-
return
|
|
3965
|
+
function object(value2, name) {
|
|
3966
|
+
if (!value2 || typeof value2 !== "object" || Array.isArray(value2)) throw invalid2(`Portable ${name} must be an object.`);
|
|
3967
|
+
return value2;
|
|
3945
3968
|
}
|
|
3946
|
-
function exact2(
|
|
3947
|
-
if (Object.keys(
|
|
3969
|
+
function exact2(value2, keys) {
|
|
3970
|
+
if (Object.keys(value2).some((key) => !keys.includes(key)) || keys.some((key) => !(key in value2))) {
|
|
3948
3971
|
throw invalid2("Portable checkpoint contains missing or unsupported fields.");
|
|
3949
3972
|
}
|
|
3950
3973
|
}
|
|
3951
|
-
function freeze(
|
|
3974
|
+
function freeze(value2) {
|
|
3952
3975
|
return Object.freeze({
|
|
3953
|
-
...
|
|
3976
|
+
...value2,
|
|
3954
3977
|
state: Object.freeze({
|
|
3955
|
-
...
|
|
3956
|
-
conversationRefs: Object.freeze([...
|
|
3957
|
-
completedEffects: Object.freeze(
|
|
3958
|
-
unresolvedApprovals: Object.freeze([...
|
|
3978
|
+
...value2.state,
|
|
3979
|
+
conversationRefs: Object.freeze([...value2.state.conversationRefs]),
|
|
3980
|
+
completedEffects: Object.freeze(value2.state.completedEffects.map((item) => Object.freeze({ ...item }))),
|
|
3981
|
+
unresolvedApprovals: Object.freeze([...value2.state.unresolvedApprovals])
|
|
3959
3982
|
})
|
|
3960
3983
|
});
|
|
3961
3984
|
}
|
|
@@ -4046,61 +4069,61 @@ async function createConversionRegistry(config) {
|
|
|
4046
4069
|
if (utf8Length(source.value) > policy.maximumSourceBytes) throw new CamelError("limit_exceeded", "Unsafe conversion input exceeds its byte bound.");
|
|
4047
4070
|
return policy;
|
|
4048
4071
|
};
|
|
4049
|
-
const emit3 = (source, policy,
|
|
4072
|
+
const emit3 = (source, policy, value2) => convert(source, policy, value2, outputCounts);
|
|
4050
4073
|
const operations = Object.freeze({
|
|
4051
|
-
boolean: async (
|
|
4052
|
-
const policy = checked(
|
|
4053
|
-
return emit3(
|
|
4074
|
+
boolean: async (value2, id) => {
|
|
4075
|
+
const policy = checked(value2, id, "boolean");
|
|
4076
|
+
return emit3(value2, policy, requireBoolean(value2.value));
|
|
4054
4077
|
},
|
|
4055
|
-
integer: async (
|
|
4056
|
-
const policy = checked(
|
|
4057
|
-
return emit3(
|
|
4078
|
+
integer: async (value2, id) => {
|
|
4079
|
+
const policy = checked(value2, id, "integer");
|
|
4080
|
+
return emit3(value2, policy, boundedInteger(value2.value, policy.output));
|
|
4058
4081
|
},
|
|
4059
|
-
finiteNumber: async (
|
|
4060
|
-
const policy = checked(
|
|
4061
|
-
return emit3(
|
|
4082
|
+
finiteNumber: async (value2, id) => {
|
|
4083
|
+
const policy = checked(value2, id, "finite_number");
|
|
4084
|
+
return emit3(value2, policy, boundedNumber(value2.value, policy.output));
|
|
4062
4085
|
},
|
|
4063
|
-
enum: async (
|
|
4064
|
-
const policy = checked(
|
|
4065
|
-
return emit3(
|
|
4086
|
+
enum: async (value2, id) => {
|
|
4087
|
+
const policy = checked(value2, id, "enum");
|
|
4088
|
+
return emit3(value2, policy, enumMember(value2.value, policy.output));
|
|
4066
4089
|
},
|
|
4067
|
-
date: async (
|
|
4068
|
-
const policy = checked(
|
|
4069
|
-
return emit3(
|
|
4090
|
+
date: async (value2, id) => {
|
|
4091
|
+
const policy = checked(value2, id, "date");
|
|
4092
|
+
return emit3(value2, policy, canonicalDate(value2.value, policy.output));
|
|
4070
4093
|
},
|
|
4071
|
-
registeredId: async (
|
|
4072
|
-
const policy = checked(
|
|
4094
|
+
registeredId: async (value2, id) => {
|
|
4095
|
+
const policy = checked(value2, id, "registered_id");
|
|
4073
4096
|
const registry = config.registeredIds?.[policy.output.registryId];
|
|
4074
|
-
const output = typeof
|
|
4097
|
+
const output = typeof value2.value === "string" ? registry?.values[value2.value] : void 0;
|
|
4075
4098
|
if (!output) throw new CamelError("conversion_rejected", "Registered-ID conversion rejected the candidate.");
|
|
4076
|
-
return emit3(
|
|
4099
|
+
return emit3(value2, policy, output);
|
|
4077
4100
|
},
|
|
4078
|
-
digest: async (
|
|
4079
|
-
const policy = checked(
|
|
4080
|
-
if (!(
|
|
4081
|
-
return emit3(
|
|
4101
|
+
digest: async (value2, id) => {
|
|
4102
|
+
const policy = checked(value2, id, "digest");
|
|
4103
|
+
if (!(value2.value instanceof Uint8Array)) throw new CamelError("conversion_rejected", "Digest conversion requires bytes.");
|
|
4104
|
+
return emit3(value2, policy, await sha256Hex(value2.value));
|
|
4082
4105
|
},
|
|
4083
|
-
measure: async (
|
|
4084
|
-
const policy = checked(
|
|
4085
|
-
const measured = measure(
|
|
4086
|
-
return emit3(
|
|
4106
|
+
measure: async (value2, metric, id) => {
|
|
4107
|
+
const policy = checked(value2, id, "integer");
|
|
4108
|
+
const measured = measure(value2.value, metric);
|
|
4109
|
+
return emit3(value2, policy, boundedInteger(measured, policy.output));
|
|
4087
4110
|
},
|
|
4088
|
-
test: async (
|
|
4089
|
-
const policy = checked(
|
|
4111
|
+
test: async (value2, predicateId, id) => {
|
|
4112
|
+
const policy = checked(value2, id, "boolean");
|
|
4090
4113
|
const predicate = config.predicates?.[predicateId];
|
|
4091
4114
|
if (!predicate) throw new CamelError("conversion_rejected", "Predicate is not registered.");
|
|
4092
|
-
return emit3(
|
|
4115
|
+
return emit3(value2, policy, evaluatePredicate(value2.value, predicate, config.registeredIds));
|
|
4093
4116
|
}
|
|
4094
4117
|
});
|
|
4095
4118
|
return Object.freeze({ operations, policy: (id) => policies.get(id) ?? missingPolicy() });
|
|
4096
4119
|
}
|
|
4097
|
-
async function convert(source, policy,
|
|
4120
|
+
async function convert(source, policy, value2, counts) {
|
|
4098
4121
|
const sourceKey = sourceIdentity(source);
|
|
4099
4122
|
const countKey = `${policy.conversionId}\0${sourceKey}`;
|
|
4100
4123
|
const count = counts.get(countKey) ?? 0;
|
|
4101
4124
|
if (count >= policy.maximumOutputsPerArtifact) throw new CamelError("limit_exceeded", "Conversion output count exceeds its per-source bound.");
|
|
4102
4125
|
counts.set(countKey, count + 1);
|
|
4103
|
-
return createSafeInternal(
|
|
4126
|
+
return createSafeInternal(value2, "atomic_conversion", {
|
|
4104
4127
|
readers: source.label.readers,
|
|
4105
4128
|
provenance: [...source.label.provenance, { kind: "converter", id: policy.conversionId, digest: policy.digest }],
|
|
4106
4129
|
dependencies: dependenciesOf([source])
|
|
@@ -4112,49 +4135,49 @@ function validatePolicyShape(policy) {
|
|
|
4112
4135
|
const output = policy.output;
|
|
4113
4136
|
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.");
|
|
4114
4137
|
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.");
|
|
4115
|
-
if (output.kind === "enum" && (output.values.length === 0 || output.values.some((
|
|
4138
|
+
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.");
|
|
4116
4139
|
if (output.kind === "registered_id" && (!output.registryId || !output.registryDigest)) throw new CamelError("state_conflict", "Registered-ID conversion identity is invalid.");
|
|
4117
4140
|
if (output.kind === "date" && output.format !== "date" && output.format !== "rfc3339") throw new CamelError("state_conflict", "Date conversion format is invalid.");
|
|
4118
4141
|
if (output.kind === "digest" && output.algorithm !== "sha256") throw new CamelError("state_conflict", "Digest conversion algorithm is invalid.");
|
|
4119
4142
|
}
|
|
4120
|
-
function requireBoolean(
|
|
4121
|
-
if (typeof
|
|
4122
|
-
return
|
|
4143
|
+
function requireBoolean(value2) {
|
|
4144
|
+
if (typeof value2 !== "boolean") throw new CamelError("conversion_rejected", "Boolean conversion requires a structured boolean.");
|
|
4145
|
+
return value2;
|
|
4123
4146
|
}
|
|
4124
|
-
function boundedInteger(
|
|
4125
|
-
if (spec.kind !== "integer" || typeof
|
|
4126
|
-
return
|
|
4147
|
+
function boundedInteger(value2, spec) {
|
|
4148
|
+
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.");
|
|
4149
|
+
return value2;
|
|
4127
4150
|
}
|
|
4128
|
-
function boundedNumber(
|
|
4129
|
-
if (spec.kind !== "finite_number" || typeof
|
|
4130
|
-
const text = String(
|
|
4151
|
+
function boundedNumber(value2, spec) {
|
|
4152
|
+
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.");
|
|
4153
|
+
const text = String(value2);
|
|
4131
4154
|
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.");
|
|
4132
|
-
return
|
|
4155
|
+
return value2;
|
|
4133
4156
|
}
|
|
4134
|
-
function enumMember(
|
|
4135
|
-
if (spec.kind !== "enum" || typeof
|
|
4136
|
-
const member = spec.caseSensitive ? spec.values.find((item) => item ===
|
|
4157
|
+
function enumMember(value2, spec) {
|
|
4158
|
+
if (spec.kind !== "enum" || typeof value2 !== "string") throw new CamelError("conversion_rejected", "Enum conversion requires a structured string member.");
|
|
4159
|
+
const member = spec.caseSensitive ? spec.values.find((item) => item === value2) : spec.values.find((item) => item.toLocaleLowerCase("en-US") === value2.toLocaleLowerCase("en-US"));
|
|
4137
4160
|
if (member === void 0) throw new CamelError("conversion_rejected", "Enum conversion rejected a non-member.");
|
|
4138
4161
|
return member;
|
|
4139
4162
|
}
|
|
4140
|
-
function canonicalDate(
|
|
4141
|
-
if (spec.kind !== "date" || typeof
|
|
4163
|
+
function canonicalDate(value2, spec) {
|
|
4164
|
+
if (spec.kind !== "date" || typeof value2 !== "string") throw new CamelError("conversion_rejected", "Date conversion requires a canonical structured string.");
|
|
4142
4165
|
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})$/;
|
|
4143
|
-
const instant = Date.parse(spec.format === "date" ? `${
|
|
4144
|
-
if (!pattern.test(
|
|
4145
|
-
if (spec.earliest &&
|
|
4146
|
-
return
|
|
4147
|
-
}
|
|
4148
|
-
function measure(
|
|
4149
|
-
if (metric === "byte_length" && (typeof
|
|
4150
|
-
if (metric === "codepoint_length" && typeof
|
|
4151
|
-
if (metric === "item_count" && Array.isArray(
|
|
4166
|
+
const instant = Date.parse(spec.format === "date" ? `${value2}T00:00:00Z` : value2);
|
|
4167
|
+
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.");
|
|
4168
|
+
if (spec.earliest && value2 < spec.earliest || spec.latest && value2 > spec.latest) throw new CamelError("conversion_rejected", "Date conversion rejected an out-of-range value.");
|
|
4169
|
+
return value2;
|
|
4170
|
+
}
|
|
4171
|
+
function measure(value2, metric) {
|
|
4172
|
+
if (metric === "byte_length" && (typeof value2 === "string" || value2 instanceof Uint8Array)) return utf8Length(value2);
|
|
4173
|
+
if (metric === "codepoint_length" && typeof value2 === "string") return [...value2].length;
|
|
4174
|
+
if (metric === "item_count" && Array.isArray(value2)) return value2.length;
|
|
4152
4175
|
throw new CamelError("conversion_rejected", "Measurement input does not match the registered metric.");
|
|
4153
4176
|
}
|
|
4154
|
-
function evaluatePredicate(
|
|
4155
|
-
if (predicate.kind === "has_fields") return typeof
|
|
4156
|
-
if (predicate.kind === "registered_id") return typeof
|
|
4157
|
-
const actual =
|
|
4177
|
+
function evaluatePredicate(value2, predicate, registries) {
|
|
4178
|
+
if (predicate.kind === "has_fields") return typeof value2 === "object" && value2 !== null && !Array.isArray(value2) && predicate.fields.every((field) => Object.hasOwn(value2, field));
|
|
4179
|
+
if (predicate.kind === "registered_id") return typeof value2 === "string" && registries?.[predicate.registryId]?.values[value2] !== void 0;
|
|
4180
|
+
const actual = value2 === null ? "null" : Array.isArray(value2) ? "array" : typeof value2;
|
|
4158
4181
|
return actual === predicate.valueType;
|
|
4159
4182
|
}
|
|
4160
4183
|
function sourceIdentity(source) {
|
|
@@ -4177,17 +4200,17 @@ function createCamelIngress(constants2 = []) {
|
|
|
4177
4200
|
byId.set(item.id, item);
|
|
4178
4201
|
}
|
|
4179
4202
|
const ingress = {
|
|
4180
|
-
userInstruction: (
|
|
4181
|
-
systemPolicy: (
|
|
4203
|
+
userInstruction: (value2, input) => createSafeInternal(value2, "user_instruction", metadata("user_instruction", input.id, input.readers)),
|
|
4204
|
+
systemPolicy: (value2, input) => createSafeInternal(value2, "system_policy", metadata("system_policy", input.id, input.readers)),
|
|
4182
4205
|
control: (id) => {
|
|
4183
4206
|
const item = byId.get(id);
|
|
4184
4207
|
if (!item) throw new CamelError("permission_denied", "Unknown control constant.");
|
|
4185
4208
|
return createSafeInternal(item.value, "harness_constant", metadata("harness", id, item.readers));
|
|
4186
4209
|
},
|
|
4187
|
-
external: (
|
|
4188
|
-
quarantinedOutput: (
|
|
4210
|
+
external: (value2, label) => createUnsafeInternal(value2, label),
|
|
4211
|
+
quarantinedOutput: (value2, input) => {
|
|
4189
4212
|
if (!input.runId) throw new CamelError("state_conflict", "Quarantined run IDs must be non-empty.");
|
|
4190
|
-
return createUnsafeInternal(
|
|
4213
|
+
return createUnsafeInternal(value2, {
|
|
4191
4214
|
readers: input.readers,
|
|
4192
4215
|
dependencies: input.dependencies,
|
|
4193
4216
|
provenance: [{ kind: "quarantined_llm", id: input.runId, digest: input.digest }]
|
|
@@ -4196,15 +4219,15 @@ function createCamelIngress(constants2 = []) {
|
|
|
4196
4219
|
};
|
|
4197
4220
|
return Object.freeze(ingress);
|
|
4198
4221
|
}
|
|
4199
|
-
function assertNoUnsafeConstant(
|
|
4200
|
-
if (typeof
|
|
4201
|
-
seen.add(
|
|
4202
|
-
if (isCamelValue(
|
|
4203
|
-
if (isUnsafe(
|
|
4204
|
-
assertNoUnsafeConstant(
|
|
4222
|
+
function assertNoUnsafeConstant(value2, seen = /* @__PURE__ */ new WeakSet()) {
|
|
4223
|
+
if (typeof value2 !== "object" || value2 === null || seen.has(value2)) return;
|
|
4224
|
+
seen.add(value2);
|
|
4225
|
+
if (isCamelValue(value2)) {
|
|
4226
|
+
if (isUnsafe(value2)) throw new CamelError("unsafe_privileged_flow", "Control constants cannot contain Prompt-Unsafe values.");
|
|
4227
|
+
assertNoUnsafeConstant(value2.value, seen);
|
|
4205
4228
|
return;
|
|
4206
4229
|
}
|
|
4207
|
-
for (const child of Object.values(
|
|
4230
|
+
for (const child of Object.values(value2)) assertNoUnsafeConstant(child, seen);
|
|
4208
4231
|
}
|
|
4209
4232
|
function metadata(kind, id, readers) {
|
|
4210
4233
|
if (!id) throw new CamelError("state_conflict", "Provenance IDs must be non-empty.");
|
|
@@ -4235,7 +4258,7 @@ async function evaluate(input, registries, approvals) {
|
|
|
4235
4258
|
if (invalid3) return deny(invalid3);
|
|
4236
4259
|
if (arg.role === "selector" && !isSafe(arg.value)) confined.add(arg.value);
|
|
4237
4260
|
}
|
|
4238
|
-
if (input.controlDependencies.some((
|
|
4261
|
+
if (input.controlDependencies.some((value2) => !isSafe(value2) && !confined.has(value2))) return deny("unsafe_control_dependency");
|
|
4239
4262
|
if (confined.size > 0) {
|
|
4240
4263
|
const fixed = input.tool.unsafeSelectorPolicy?.fixedProviderIds ?? [];
|
|
4241
4264
|
const destinations = Object.values(input.args).filter((arg) => arg.role === "destination");
|
|
@@ -4262,29 +4285,29 @@ async function validateArgument(path, arg, tool, registries) {
|
|
|
4262
4285
|
if (!isSafe(arg.value)) return "unsafe_destination_argument";
|
|
4263
4286
|
if (!isControlOwned(arg.value)) return "destination_not_control_owned";
|
|
4264
4287
|
const registry = registries[arg.registryId];
|
|
4265
|
-
const validValues = registry && registry.values.length > 0 && registry.values.every((
|
|
4288
|
+
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;
|
|
4266
4289
|
if (!registry || !validValues || registry.digest !== arg.registryDigest || await destinationRegistryDigest(registry.values) !== registry.digest || !registry.values.includes(arg.value.value)) return "destination_not_registered";
|
|
4267
4290
|
}
|
|
4268
4291
|
if (arg.role === "selector" && !isSafe(arg.value)) return validateUnsafeSelector(path, arg.value, tool);
|
|
4269
4292
|
return void 0;
|
|
4270
4293
|
}
|
|
4271
|
-
function isControlOwned(
|
|
4272
|
-
return
|
|
4294
|
+
function isControlOwned(value2) {
|
|
4295
|
+
return value2.label.safeBasis === "system_policy" || value2.label.safeBasis === "harness_constant";
|
|
4273
4296
|
}
|
|
4274
4297
|
function copyRegistries(registries) {
|
|
4275
4298
|
return Object.freeze(Object.fromEntries(Object.entries(registries).map(([id, registry]) => [id, Object.freeze({ digest: registry.digest, values: Object.freeze([...registry.values]) })])));
|
|
4276
4299
|
}
|
|
4277
|
-
function validateUnsafeSelector(path,
|
|
4300
|
+
function validateUnsafeSelector(path, value2, tool) {
|
|
4278
4301
|
const policy = tool.unsafeSelectorPolicy;
|
|
4279
4302
|
if (!policy || policy.effect !== tool.effect || !policy.selectorPaths.includes(path)) return "unsafe_selector_not_confined";
|
|
4280
4303
|
if (!policy.fixedDestination || !policy.unsafeOutput || policy.fixedProviderIds.length === 0) return "unsafe_selector_not_confined";
|
|
4281
4304
|
if (![policy.maximumCalls, policy.maximumResultsPerCall, policy.maximumOutputBytes, policy.maximumSelectorBytes].every((bound) => Number.isSafeInteger(bound) && bound > 0)) return "unsafe_selector_not_confined";
|
|
4282
|
-
if (utf8Length(
|
|
4283
|
-
if (typeof
|
|
4305
|
+
if (utf8Length(value2.value) > policy.maximumSelectorBytes) return "unsafe_selector_too_large";
|
|
4306
|
+
if (typeof value2.value === "string" && looksLikeDestination(value2.value)) return "unsafe_selector_is_destination";
|
|
4284
4307
|
return void 0;
|
|
4285
4308
|
}
|
|
4286
|
-
function looksLikeDestination(
|
|
4287
|
-
const text =
|
|
4309
|
+
function looksLikeDestination(value2) {
|
|
4310
|
+
const text = value2.trim();
|
|
4288
4311
|
return /^(?:[a-z][a-z0-9+.-]*:\/\/|\/|\\\\)/i.test(text) || /^[\w.-]+\.[a-z]{2,}(?:[/:]|$)/i.test(text);
|
|
4289
4312
|
}
|
|
4290
4313
|
|
|
@@ -4370,9 +4393,9 @@ var CodeRuntimeReconciler = class {
|
|
|
4370
4393
|
}
|
|
4371
4394
|
}
|
|
4372
4395
|
};
|
|
4373
|
-
function retryableControlFailure(
|
|
4374
|
-
if (!
|
|
4375
|
-
const failure =
|
|
4396
|
+
function retryableControlFailure(value2) {
|
|
4397
|
+
if (!value2 || typeof value2 !== "object") return false;
|
|
4398
|
+
const failure = value2;
|
|
4376
4399
|
if (failure.code === "invalid_response" || typeof failure.status !== "number") return false;
|
|
4377
4400
|
return failure.status === 408 || failure.status === 425 || failure.status === 429 || failure.status >= 500;
|
|
4378
4401
|
}
|
|
@@ -4424,16 +4447,16 @@ function createCodeRuntimeControlClient(options) {
|
|
|
4424
4447
|
if (options.signal?.aborted) throw cause;
|
|
4425
4448
|
throw new CodeRuntimeControlError("Code runtime control plane is unavailable", 503, "transport_unavailable");
|
|
4426
4449
|
}
|
|
4427
|
-
const
|
|
4450
|
+
const value2 = await response2.json().catch(() => null);
|
|
4428
4451
|
if (!response2.ok) {
|
|
4429
|
-
const problem = record3(record3(
|
|
4452
|
+
const problem = record3(record3(value2)?.error);
|
|
4430
4453
|
throw new CodeRuntimeControlError(
|
|
4431
4454
|
typeof problem?.message === "string" ? problem.message : `Code runtime request failed (${response2.status})`,
|
|
4432
4455
|
response2.status,
|
|
4433
4456
|
typeof problem?.code === "string" ? problem.code : void 0
|
|
4434
4457
|
);
|
|
4435
4458
|
}
|
|
4436
|
-
return
|
|
4459
|
+
return value2;
|
|
4437
4460
|
};
|
|
4438
4461
|
return {
|
|
4439
4462
|
heartbeat: async (version, capabilities) => {
|
|
@@ -4448,15 +4471,15 @@ function createCodeRuntimeControlClient(options) {
|
|
|
4448
4471
|
await call2(`/registry/code/runtime/sessions/${validSessionId(sessionId)}/source`, {})
|
|
4449
4472
|
),
|
|
4450
4473
|
infer: async (sessionId, inference) => {
|
|
4451
|
-
const
|
|
4474
|
+
const value2 = record3(await call2(
|
|
4452
4475
|
`/registry/code/runtime/sessions/${validSessionId(sessionId)}/inference`,
|
|
4453
4476
|
inference,
|
|
4454
4477
|
modelRequestTimeoutMs
|
|
4455
4478
|
));
|
|
4456
|
-
if (!
|
|
4479
|
+
if (!value2 || value2.requestId !== inference.requestId || !record3(value2.response) || !record3(value2.receipt)) {
|
|
4457
4480
|
throw new CodeRuntimeControlError("invalid Code inference response", 502, "invalid_response");
|
|
4458
4481
|
}
|
|
4459
|
-
return
|
|
4482
|
+
return value2;
|
|
4460
4483
|
},
|
|
4461
4484
|
review: async (sessionId, review) => parseReview(
|
|
4462
4485
|
await call2(`/registry/code/runtime/sessions/${validSessionId(sessionId)}/review`, review, modelRequestTimeoutMs)
|
|
@@ -4481,8 +4504,8 @@ function createCodeRuntimeControlClient(options) {
|
|
|
4481
4504
|
}
|
|
4482
4505
|
};
|
|
4483
4506
|
}
|
|
4484
|
-
function validatedEndpoint(
|
|
4485
|
-
const endpoint =
|
|
4507
|
+
function validatedEndpoint(value2) {
|
|
4508
|
+
const endpoint = value2.replace(/\/+$/, "");
|
|
4486
4509
|
let url;
|
|
4487
4510
|
try {
|
|
4488
4511
|
url = new URL(endpoint);
|
|
@@ -4495,9 +4518,9 @@ function validatedEndpoint(value) {
|
|
|
4495
4518
|
}
|
|
4496
4519
|
return endpoint;
|
|
4497
4520
|
}
|
|
4498
|
-
function validSessionId(
|
|
4499
|
-
if (!/^csess_[0-9a-f]{32}$/.test(
|
|
4500
|
-
return
|
|
4521
|
+
function validSessionId(value2) {
|
|
4522
|
+
if (!/^csess_[0-9a-f]{32}$/.test(value2)) throw new TypeError("invalid Code session id");
|
|
4523
|
+
return value2;
|
|
4501
4524
|
}
|
|
4502
4525
|
function validateHeartbeat(version, capabilities) {
|
|
4503
4526
|
if (!version.trim() || version.length > 80) throw new TypeError("runtimeVersion is required and at most 80 characters");
|
|
@@ -4510,8 +4533,8 @@ function validateHeartbeat(version, capabilities) {
|
|
|
4510
4533
|
throw new TypeError("runtime resources must be positive integers");
|
|
4511
4534
|
}
|
|
4512
4535
|
}
|
|
4513
|
-
function parseSnapshot(
|
|
4514
|
-
const root = record3(
|
|
4536
|
+
function parseSnapshot(value2) {
|
|
4537
|
+
const root = record3(value2);
|
|
4515
4538
|
const host = record3(root?.host);
|
|
4516
4539
|
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");
|
|
4517
4540
|
const bindingIds = /* @__PURE__ */ new Set();
|
|
@@ -4536,11 +4559,11 @@ function parseSnapshot(value) {
|
|
|
4536
4559
|
});
|
|
4537
4560
|
return { host, bindings, commands };
|
|
4538
4561
|
}
|
|
4539
|
-
async function parseSource(
|
|
4540
|
-
const snapshot = record3(record3(
|
|
4562
|
+
async function parseSource(value2) {
|
|
4563
|
+
const snapshot = record3(record3(value2)?.snapshot);
|
|
4541
4564
|
if (!snapshot || typeof snapshot.repository !== "string" || typeof snapshot.commitSha !== "string" || typeof snapshot.treeDigest !== "string" || !Array.isArray(snapshot.files)) throw invalid("source");
|
|
4542
|
-
const files = snapshot.files.map((
|
|
4543
|
-
const file = record3(
|
|
4565
|
+
const files = snapshot.files.map((value22) => {
|
|
4566
|
+
const file = record3(value22);
|
|
4544
4567
|
if (!file || typeof file.path !== "string" || typeof file.content !== "string") throw invalid("source file");
|
|
4545
4568
|
return { path: file.path, content: file.content };
|
|
4546
4569
|
});
|
|
@@ -4567,19 +4590,19 @@ async function parseSource(value) {
|
|
|
4567
4590
|
if (digest !== snapshot.treeDigest) throw invalid("source digest");
|
|
4568
4591
|
return { ...source, treeDigest: digest, ...references.length ? { references } : {} };
|
|
4569
4592
|
}
|
|
4570
|
-
function parseReview(
|
|
4571
|
-
const review = record3(record3(
|
|
4593
|
+
function parseReview(value2) {
|
|
4594
|
+
const review = record3(record3(value2)?.review);
|
|
4572
4595
|
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");
|
|
4573
4596
|
return review;
|
|
4574
4597
|
}
|
|
4575
|
-
function parseCandidate(
|
|
4576
|
-
const candidate = record3(record3(
|
|
4598
|
+
function parseCandidate(value2) {
|
|
4599
|
+
const candidate = record3(record3(value2)?.candidate);
|
|
4577
4600
|
if (!candidate || typeof candidate.candidateId !== "string" || !/^ccand_[0-9a-f]{32}$/.test(candidate.candidateId) || !["submitted", "approved", "published", "failed"].includes(String(candidate.status))) {
|
|
4578
4601
|
throw invalid("candidate");
|
|
4579
4602
|
}
|
|
4580
4603
|
return { candidateId: candidate.candidateId, status: candidate.status };
|
|
4581
4604
|
}
|
|
4582
|
-
var record3 = (
|
|
4605
|
+
var record3 = (value2) => value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
|
|
4583
4606
|
var invalid = (part) => new CodeRuntimeControlError(`invalid Code runtime ${part} response`, 502, "invalid_response");
|
|
4584
4607
|
var RESERVED = /* @__PURE__ */ new Set([".git", ".odla", ".wrangler", "node_modules", "dist", "coverage"]);
|
|
4585
4608
|
var SECRET = /^(?:\.env(?:\..+)?|\.dev\.vars|credentials(?:\..+)?\.json|dev-token(?:\..+)?\.json)$/i;
|
|
@@ -4613,8 +4636,8 @@ function validateCodePatch(patch2, maxBytes) {
|
|
|
4613
4636
|
if (!paths.length || new Set(paths).size !== paths.length) throw new TypeError("patch has no diffs or repeats a path");
|
|
4614
4637
|
return paths;
|
|
4615
4638
|
}
|
|
4616
|
-
function validHeaderPath(
|
|
4617
|
-
return
|
|
4639
|
+
function validHeaderPath(value2, path, prefix) {
|
|
4640
|
+
return value2 === "/dev/null" || value2 === `${prefix}/${path}`;
|
|
4618
4641
|
}
|
|
4619
4642
|
function validateRelativePath(path) {
|
|
4620
4643
|
const parts = path.split("/");
|
|
@@ -4760,8 +4783,8 @@ function assertCodeBuildRecipe(recipe2) {
|
|
|
4760
4783
|
throw new TypeError("build recipe is malformed or exceeds its control bounds");
|
|
4761
4784
|
}
|
|
4762
4785
|
}
|
|
4763
|
-
function parseMemory(
|
|
4764
|
-
const match = /^([1-9][0-9]{0,4})([kmg])$/.exec(
|
|
4786
|
+
function parseMemory(value2) {
|
|
4787
|
+
const match = /^([1-9][0-9]{0,4})([kmg])$/.exec(value2.toLowerCase());
|
|
4765
4788
|
if (!match?.[1] || !match[2]) return 0;
|
|
4766
4789
|
const scale = match[2] === "k" ? 1024 : match[2] === "m" ? 1024 ** 2 : 1024 ** 3;
|
|
4767
4790
|
return Number(match[1]) * scale;
|
|
@@ -4996,14 +5019,14 @@ function normalizedRecipe(recipe2) {
|
|
|
4996
5019
|
expectedArtifacts: [...recipe2.expectedArtifacts ?? []].sort((left, right) => left.id.localeCompare(right.id)).map((artifact) => ({ id: artifact.id, path: artifact.path, maximumBytes: artifact.maximumBytes }))
|
|
4997
5020
|
};
|
|
4998
5021
|
}
|
|
4999
|
-
function digestJson(
|
|
5000
|
-
return digestBytes(JSON.stringify(
|
|
5022
|
+
function digestJson(value2) {
|
|
5023
|
+
return digestBytes(JSON.stringify(value2));
|
|
5001
5024
|
}
|
|
5002
|
-
function digestBytes(
|
|
5003
|
-
return `sha256:${createHash22("sha256").update(
|
|
5025
|
+
function digestBytes(value2) {
|
|
5026
|
+
return `sha256:${createHash22("sha256").update(value2).digest("hex")}`;
|
|
5004
5027
|
}
|
|
5005
|
-
function integer(
|
|
5006
|
-
return Number.isSafeInteger(
|
|
5028
|
+
function integer(value2, minimum, maximum) {
|
|
5029
|
+
return Number.isSafeInteger(value2) && value2 >= minimum && value2 <= maximum;
|
|
5007
5030
|
}
|
|
5008
5031
|
async function prepareRuntimeCheckpoint(input) {
|
|
5009
5032
|
const patch2 = await input.workspace.patch(256 * 1024);
|
|
@@ -5056,7 +5079,7 @@ async function prepareRuntimeCheckpoint(input) {
|
|
|
5056
5079
|
});
|
|
5057
5080
|
return { checkpoint, verification, review, note };
|
|
5058
5081
|
}
|
|
5059
|
-
var message = (
|
|
5082
|
+
var message = (value2) => (value2 instanceof Error ? value2.message : String(value2)).slice(0, 500);
|
|
5060
5083
|
var CodeRuntimeCheckpointManager = class {
|
|
5061
5084
|
constructor(options) {
|
|
5062
5085
|
this.options = options;
|
|
@@ -5250,7 +5273,7 @@ async function conversionPolicy(id, output) {
|
|
|
5250
5273
|
return { ...definition, digest: await conversionPolicyDigest(definition) };
|
|
5251
5274
|
}
|
|
5252
5275
|
async function registeredPolicy(id, registryId, values) {
|
|
5253
|
-
const mapping = Object.fromEntries(values.map((
|
|
5276
|
+
const mapping = Object.fromEntries(values.map((value2) => [value2, value2]));
|
|
5254
5277
|
return conversionPolicy(id, {
|
|
5255
5278
|
kind: "registered_id",
|
|
5256
5279
|
registryId,
|
|
@@ -5259,7 +5282,7 @@ async function registeredPolicy(id, registryId, values) {
|
|
|
5259
5282
|
}
|
|
5260
5283
|
async function conversionRegistry(policies, values) {
|
|
5261
5284
|
const registeredIds = Object.fromEntries(await Promise.all(Object.entries(values).map(async ([id, entries]) => {
|
|
5262
|
-
const mapping = Object.fromEntries(entries.map((
|
|
5285
|
+
const mapping = Object.fromEntries(entries.map((value2) => [value2, value2]));
|
|
5263
5286
|
return [id, { values: mapping, digest: await registeredIdRegistryDigest(mapping) }];
|
|
5264
5287
|
})));
|
|
5265
5288
|
return createConversionRegistry({ policies, registeredIds });
|
|
@@ -5283,8 +5306,8 @@ async function environment(input, options, tool) {
|
|
|
5283
5306
|
};
|
|
5284
5307
|
return { ingress, policy, fixedArgs, reader: ingress.control("reader"), runId: `${input.request.requestId}:${tool}` };
|
|
5285
5308
|
}
|
|
5286
|
-
function unsafe(base,
|
|
5287
|
-
return base.ingress.quarantinedOutput(
|
|
5309
|
+
function unsafe(base, value2, field) {
|
|
5310
|
+
return base.ingress.quarantinedOutput(value2, {
|
|
5288
5311
|
readers: base.reader.label.readers,
|
|
5289
5312
|
runId: `${base.runId}:${field}`
|
|
5290
5313
|
});
|
|
@@ -5364,14 +5387,14 @@ async function read(context, request2, options, policy) {
|
|
|
5364
5387
|
}
|
|
5365
5388
|
async function patch(context, request2, options, policy) {
|
|
5366
5389
|
exactKeys(request2.input, ["patch"]);
|
|
5367
|
-
const
|
|
5368
|
-
const paths = validateCodePatch(
|
|
5390
|
+
const value2 = stringField(request2.input, "patch");
|
|
5391
|
+
const paths = validateCodePatch(value2, options.maxPatchBytes ?? 256 * 1024);
|
|
5369
5392
|
if (paths.some((path) => options.readOnlyPrefixes?.some((prefix) => path === prefix || path.startsWith(`${prefix}/`)))) {
|
|
5370
5393
|
throw new TypeError("patch targets a read-only reference source");
|
|
5371
5394
|
}
|
|
5372
|
-
const allowed = await policy.patch(policyContext(context, request2, options, { patch:
|
|
5395
|
+
const allowed = await policy.patch(policyContext(context, request2, options, { patch: value2 }));
|
|
5373
5396
|
if (!allowed) return response(request2, false, "tool denied by CaMeL policy");
|
|
5374
|
-
await applyCodePatch(context.workspaceDir,
|
|
5397
|
+
await applyCodePatch(context.workspaceDir, value2, paths);
|
|
5375
5398
|
return response(request2, true, `Applied patch to ${paths.length} file(s).`, { paths });
|
|
5376
5399
|
}
|
|
5377
5400
|
async function recipe(context, request2, options, recipes, policy) {
|
|
@@ -5462,14 +5485,14 @@ function exactKeys(input, allowed) {
|
|
|
5462
5485
|
if (Object.keys(input).some((key) => !allowed.includes(key))) throw new TypeError("tool input contains an unsupported field");
|
|
5463
5486
|
}
|
|
5464
5487
|
function stringField(input, name) {
|
|
5465
|
-
const
|
|
5466
|
-
if (typeof
|
|
5467
|
-
return
|
|
5488
|
+
const value2 = input[name];
|
|
5489
|
+
if (typeof value2 !== "string" || !value2) throw new TypeError(`${name} must be a non-empty string`);
|
|
5490
|
+
return value2;
|
|
5468
5491
|
}
|
|
5469
|
-
function optionalInteger(
|
|
5470
|
-
if (
|
|
5471
|
-
if (!Number.isSafeInteger(
|
|
5472
|
-
return
|
|
5492
|
+
function optionalInteger(value2) {
|
|
5493
|
+
if (value2 === void 0) return void 0;
|
|
5494
|
+
if (!Number.isSafeInteger(value2) || value2 < 1) throw new TypeError("line bounds must be positive integers");
|
|
5495
|
+
return value2;
|
|
5473
5496
|
}
|
|
5474
5497
|
function response(request2, ok, content2, details) {
|
|
5475
5498
|
return { requestId: request2.requestId, ok, content: content2, ...details ? { details } : {} };
|
|
@@ -5515,9 +5538,9 @@ function codeLocalSource(payload) {
|
|
|
5515
5538
|
return source;
|
|
5516
5539
|
}
|
|
5517
5540
|
function codeCheckpointPayload(payload) {
|
|
5518
|
-
const
|
|
5519
|
-
if (!
|
|
5520
|
-
return
|
|
5541
|
+
const value2 = payload.checkpoint;
|
|
5542
|
+
if (!value2 || typeof value2 !== "object" || Array.isArray(value2)) throw new TypeError("resume checkpoint is missing");
|
|
5543
|
+
return value2;
|
|
5521
5544
|
}
|
|
5522
5545
|
function fakeCodeLease(command, metadata2) {
|
|
5523
5546
|
return {
|
|
@@ -5541,7 +5564,7 @@ function fakeCodeLease(command, metadata2) {
|
|
|
5541
5564
|
}
|
|
5542
5565
|
};
|
|
5543
5566
|
}
|
|
5544
|
-
var record22 = (
|
|
5567
|
+
var record22 = (value2) => value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
|
|
5545
5568
|
var SOURCE_LIMITS = { maxFiles: 2e4, maxBytes: 512 * 1024 * 1024 };
|
|
5546
5569
|
async function prepareRuntimeLocalSource(input) {
|
|
5547
5570
|
const { command, descriptor: descriptor2, available, repository, baseCommitSha, resume } = input;
|
|
@@ -5631,24 +5654,24 @@ async function appendCodeRuntimeEvent(control, command, event, refs) {
|
|
|
5631
5654
|
const bounded = event.type === "message" ? { ...event, body: event.body.trim().slice(0, 2e4) || `${event.actor} event` } : event;
|
|
5632
5655
|
await control.appendSessionEvent(command.sessionId, eventId, bounded);
|
|
5633
5656
|
}
|
|
5634
|
-
var digestRuntimeValue = (
|
|
5635
|
-
var runtimeErrorMessage = (
|
|
5636
|
-
var runtimeRecord = (
|
|
5637
|
-
var safeRuntimeJson = (
|
|
5657
|
+
var digestRuntimeValue = (value2) => `sha256:${createHash3("sha256").update(value2).digest("hex")}`;
|
|
5658
|
+
var runtimeErrorMessage = (value2) => value2 instanceof Error ? value2.message : String(value2);
|
|
5659
|
+
var runtimeRecord = (value2) => value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
|
|
5660
|
+
var safeRuntimeJson = (value2) => {
|
|
5638
5661
|
try {
|
|
5639
|
-
return JSON.stringify(
|
|
5662
|
+
return JSON.stringify(value2).slice(0, 1e4);
|
|
5640
5663
|
} catch {
|
|
5641
5664
|
return "[event]";
|
|
5642
5665
|
}
|
|
5643
5666
|
};
|
|
5644
|
-
function runtimeResultText(
|
|
5645
|
-
const record32 = runtimeRecord(
|
|
5667
|
+
function runtimeResultText(value2) {
|
|
5668
|
+
const record32 = runtimeRecord(value2);
|
|
5646
5669
|
if (record32 && typeof record32.text === "string") return record32.text.slice(0, 2e4);
|
|
5647
5670
|
if (record32 && typeof record32.error === "string") return `Pi failed: ${record32.error.slice(0, 19989)}`;
|
|
5648
5671
|
return null;
|
|
5649
5672
|
}
|
|
5650
|
-
function runtimeResultError(
|
|
5651
|
-
const record32 = runtimeRecord(
|
|
5673
|
+
function runtimeResultError(value2) {
|
|
5674
|
+
const record32 = runtimeRecord(value2);
|
|
5652
5675
|
return record32 && typeof record32.error === "string" && record32.error.trim() ? record32.error.trim().slice(0, 2e3) : null;
|
|
5653
5676
|
}
|
|
5654
5677
|
var CodePiRuntimeEngine = class {
|
|
@@ -5922,14 +5945,14 @@ var CodePiRuntimeEngine = class {
|
|
|
5922
5945
|
this.#active.delete(command.sessionId);
|
|
5923
5946
|
return result;
|
|
5924
5947
|
}
|
|
5925
|
-
async #failure(command, active,
|
|
5926
|
-
active.failure =
|
|
5948
|
+
async #failure(command, active, value2) {
|
|
5949
|
+
active.failure = value2.slice(0, 2e3);
|
|
5927
5950
|
if (active.acknowledged) {
|
|
5928
5951
|
await this.options.control.reportSessionFailure(command.sessionId, active.failure).catch(() => void 0);
|
|
5929
5952
|
}
|
|
5930
5953
|
}
|
|
5931
|
-
async #diagnostic(command, active,
|
|
5932
|
-
const detail =
|
|
5954
|
+
async #diagnostic(command, active, value2) {
|
|
5955
|
+
const detail = value2.trim().slice(0, 2e3) || "Pi runtime failed";
|
|
5933
5956
|
this.options.onDiagnostic?.(detail);
|
|
5934
5957
|
await this.#event(
|
|
5935
5958
|
command,
|
|
@@ -6014,6 +6037,7 @@ Usage:
|
|
|
6014
6037
|
odla-ai context save <name> [--platform <url>] [--app <id>] [--env <name>] [--json]
|
|
6015
6038
|
odla-ai context remove <name> --yes [--json]
|
|
6016
6039
|
odla-ai o11y status [--app <id>] [--context <name>] [--platform https://odla.ai] [--env prod] [--minutes 60] [--json]
|
|
6040
|
+
odla-ai platform status [--context <name>] [--platform https://odla.ai] [--email <odla-account>] [--json]
|
|
6017
6041
|
odla-ai whoami [--context <name>] [--platform https://odla.ai] [--json]
|
|
6018
6042
|
odla-ai runbook ask "<question>" [--app <id>] [--all] [--json]
|
|
6019
6043
|
odla-ai runbook search "<question>" [--app <id>] [--all] [--limit <n>] [--json]
|
|
@@ -6138,6 +6162,8 @@ Commands:
|
|
|
6138
6162
|
canary, collector ingest/scheduler trust, Cloudflare-owned
|
|
6139
6163
|
runtime metrics, and a machine verdict.
|
|
6140
6164
|
--json keeps auth progress on stderr for unattended agents.
|
|
6165
|
+
platform Read canonical fleet health, releases, provider load/freshness,
|
|
6166
|
+
explicit unknowns, and next actions through a read-only grant.
|
|
6141
6167
|
provision Register services, compose integrations, persist credentials, optionally push secrets.
|
|
6142
6168
|
smoke Verify credentials, public-config, composed schema, db aggregate, and integration probes.
|
|
6143
6169
|
skill Same installer; --agent accepts all, claude, codex, cursor,
|
|
@@ -6238,17 +6264,17 @@ async function prepareCodeLocalSource(cwd, repository, readHead = readGitHead) {
|
|
|
6238
6264
|
}
|
|
6239
6265
|
}
|
|
6240
6266
|
async function readGitHead(cwd) {
|
|
6241
|
-
const
|
|
6267
|
+
const value2 = await new Promise((accept, reject) => {
|
|
6242
6268
|
execFile3("git", ["rev-parse", "HEAD"], { cwd, encoding: "utf8", maxBuffer: 16384 }, (error, stdout) => {
|
|
6243
6269
|
if (error) reject(new Error("code connect requires a Git checkout with an initial commit"));
|
|
6244
6270
|
else accept(stdout.trim());
|
|
6245
6271
|
});
|
|
6246
6272
|
});
|
|
6247
|
-
if (!/^[0-9a-f]{40}$/.test(
|
|
6248
|
-
return
|
|
6273
|
+
if (!/^[0-9a-f]{40}$/.test(value2)) throw new Error("code connect could not resolve the checkout HEAD commit");
|
|
6274
|
+
return value2;
|
|
6249
6275
|
}
|
|
6250
|
-
function digestText(
|
|
6251
|
-
return `sha256:${createHash4("sha256").update(
|
|
6276
|
+
function digestText(value2) {
|
|
6277
|
+
return `sha256:${createHash4("sha256").update(value2).digest("hex")}`;
|
|
6252
6278
|
}
|
|
6253
6279
|
|
|
6254
6280
|
// src/code-connect.ts
|
|
@@ -6412,8 +6438,8 @@ async function runCodeRuntime(input) {
|
|
|
6412
6438
|
for (const [name, handler] of handlers) process.removeListener(name, handler);
|
|
6413
6439
|
}
|
|
6414
6440
|
}
|
|
6415
|
-
function parseConnection(
|
|
6416
|
-
const root = record4(
|
|
6441
|
+
function parseConnection(value2, appId, appEnv) {
|
|
6442
|
+
const root = record4(value2);
|
|
6417
6443
|
const host = record4(root?.host);
|
|
6418
6444
|
const offer = record4(root?.offer);
|
|
6419
6445
|
const binding = record4(root?.binding);
|
|
@@ -6422,16 +6448,16 @@ function parseConnection(value, appId, appEnv) {
|
|
|
6422
6448
|
}
|
|
6423
6449
|
return root;
|
|
6424
6450
|
}
|
|
6425
|
-
function apiFailure(action, status,
|
|
6426
|
-
const message2 = record4(record4(
|
|
6451
|
+
function apiFailure(action, status, value2) {
|
|
6452
|
+
const message2 = record4(record4(value2)?.error)?.message;
|
|
6427
6453
|
return `${action} failed (${status})${typeof message2 === "string" ? `: ${message2}` : ""}`;
|
|
6428
6454
|
}
|
|
6429
|
-
function record4(
|
|
6430
|
-
return
|
|
6455
|
+
function record4(value2) {
|
|
6456
|
+
return value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
|
|
6431
6457
|
}
|
|
6432
6458
|
|
|
6433
6459
|
// src/provision.ts
|
|
6434
|
-
import { createAppsClient, tenantIdFor as tenantIdFor4 } from "@odla-ai/apps";
|
|
6460
|
+
import { createAppsClient, orderAppServices, tenantIdFor as tenantIdFor4 } from "@odla-ai/apps";
|
|
6435
6461
|
import { putSecret as putSecret2 } from "@odla-ai/ai";
|
|
6436
6462
|
import process8 from "process";
|
|
6437
6463
|
|
|
@@ -6476,8 +6502,8 @@ async function postJson2(doFetch, url, bearer, body) {
|
|
|
6476
6502
|
if (!res.ok) throw new Error(`${new URL(url).pathname} failed: ${res.status} ${await responseText(res)}`);
|
|
6477
6503
|
return res.json().catch(() => ({}));
|
|
6478
6504
|
}
|
|
6479
|
-
function isRecord7(
|
|
6480
|
-
return
|
|
6505
|
+
function isRecord7(value2) {
|
|
6506
|
+
return value2 !== null && typeof value2 === "object" && !Array.isArray(value2);
|
|
6481
6507
|
}
|
|
6482
6508
|
async function responseText(res) {
|
|
6483
6509
|
try {
|
|
@@ -6585,11 +6611,6 @@ async function safeText4(res) {
|
|
|
6585
6611
|
// src/provision-helpers.ts
|
|
6586
6612
|
import { DEFAULT_SECRET_NAMES } from "@odla-ai/ai";
|
|
6587
6613
|
import { tenantIdFor as tenantIdFor3 } from "@odla-ai/apps";
|
|
6588
|
-
function serviceRank(service) {
|
|
6589
|
-
if (service === "db") return 0;
|
|
6590
|
-
if (service === "calendar") return 2;
|
|
6591
|
-
return 1;
|
|
6592
|
-
}
|
|
6593
6614
|
function defaultSecretName(provider) {
|
|
6594
6615
|
const names = DEFAULT_SECRET_NAMES;
|
|
6595
6616
|
return names[provider] ?? `${provider}_api_key`;
|
|
@@ -6615,14 +6636,14 @@ async function postJson3(doFetch, url, bearer, body) {
|
|
|
6615
6636
|
});
|
|
6616
6637
|
if (!res.ok) throw new Error(`${new URL(url).pathname} failed: ${res.status} ${await safeText5(res)}`);
|
|
6617
6638
|
}
|
|
6618
|
-
function normalizeClerkConfig(
|
|
6619
|
-
if (!
|
|
6620
|
-
if (typeof
|
|
6621
|
-
const publishableKey2 = envValue(
|
|
6639
|
+
function normalizeClerkConfig(value2) {
|
|
6640
|
+
if (!value2) return null;
|
|
6641
|
+
if (typeof value2 === "string") {
|
|
6642
|
+
const publishableKey2 = envValue(value2);
|
|
6622
6643
|
return publishableKey2 ? { publishableKey: publishableKey2 } : null;
|
|
6623
6644
|
}
|
|
6624
|
-
if (typeof
|
|
6625
|
-
const cfg =
|
|
6645
|
+
if (typeof value2 !== "object") return null;
|
|
6646
|
+
const cfg = value2;
|
|
6626
6647
|
const publishableKey = envValue(cfg.publishableKey);
|
|
6627
6648
|
return publishableKey ? { publishableKey, ...cfg.audience ? { audience: cfg.audience } : {}, ...cfg.mode ? { mode: cfg.mode } : {} } : null;
|
|
6628
6649
|
}
|
|
@@ -6715,7 +6736,7 @@ async function provision(options) {
|
|
|
6715
6736
|
for (const env of cfg.envs) {
|
|
6716
6737
|
await assertTenantAdminAccess(doFetch, cfg, env, token);
|
|
6717
6738
|
}
|
|
6718
|
-
const serviceOrder =
|
|
6739
|
+
const serviceOrder = orderAppServices(cfg.services);
|
|
6719
6740
|
for (const env of cfg.envs) {
|
|
6720
6741
|
for (const service of serviceOrder) {
|
|
6721
6742
|
if (service === "ai") {
|
|
@@ -6895,6 +6916,7 @@ var COMMAND_SURFACE = {
|
|
|
6895
6916
|
help: {},
|
|
6896
6917
|
init: {},
|
|
6897
6918
|
o11y: { status: {} },
|
|
6919
|
+
platform: { status: {} },
|
|
6898
6920
|
pm: {
|
|
6899
6921
|
...PM_ENTITIES,
|
|
6900
6922
|
handoff: {}
|
|
@@ -7062,13 +7084,13 @@ function selectEnv(requested, declared, configPath, rootDir) {
|
|
|
7062
7084
|
return env;
|
|
7063
7085
|
}
|
|
7064
7086
|
async function injectedToken(options, request2) {
|
|
7065
|
-
const
|
|
7066
|
-
if (typeof
|
|
7087
|
+
const value2 = options.token ?? await options.getToken?.(Object.freeze({ ...request2 }));
|
|
7088
|
+
if (typeof value2 !== "string" || value2.length < 8 || value2.length > 8192 || /\s|[\u0000-\u001f\u007f]/.test(value2)) {
|
|
7067
7089
|
throw new Error(
|
|
7068
7090
|
request2.selfAudit ? "Self-audit requires an injected, scoped platform security token" : "Hosted security requires an injected app developer token or getToken callback"
|
|
7069
7091
|
);
|
|
7070
7092
|
}
|
|
7071
|
-
return
|
|
7093
|
+
return value2;
|
|
7072
7094
|
}
|
|
7073
7095
|
function profileFor(name, maxHuntTasks) {
|
|
7074
7096
|
const profile = name === "odla" ? odlaProfile() : name === "cloudflare-app" ? cloudflareAppProfile() : name === "generic" ? genericProfile() : void 0;
|
|
@@ -7114,8 +7136,8 @@ async function getHostedSecurityIntent(options) {
|
|
|
7114
7136
|
}
|
|
7115
7137
|
return response2;
|
|
7116
7138
|
}
|
|
7117
|
-
function isValidIntent(
|
|
7118
|
-
return !!
|
|
7139
|
+
function isValidIntent(value2, expected) {
|
|
7140
|
+
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";
|
|
7119
7141
|
}
|
|
7120
7142
|
|
|
7121
7143
|
// src/security-hosted-jobs.ts
|
|
@@ -7241,17 +7263,17 @@ function hostedJobPath(appIdInput, jobIdInput) {
|
|
|
7241
7263
|
const jobId = hostedIdentifier(jobIdInput, "jobId");
|
|
7242
7264
|
return `/registry/apps/${encodeURIComponent(appId)}/security/jobs/${encodeURIComponent(jobId)}`;
|
|
7243
7265
|
}
|
|
7244
|
-
function securityPlanDigest(
|
|
7245
|
-
if (!/^sha256:[a-f0-9]{64}$/.test(
|
|
7266
|
+
function securityPlanDigest(value2) {
|
|
7267
|
+
if (!/^sha256:[a-f0-9]{64}$/.test(value2)) {
|
|
7246
7268
|
throw new Error("expected plan digest must be a sha256 digest from security plan");
|
|
7247
7269
|
}
|
|
7248
|
-
return
|
|
7270
|
+
return value2;
|
|
7249
7271
|
}
|
|
7250
|
-
function securityExecutionDigest(
|
|
7251
|
-
if (!/^sha256:[a-f0-9]{64}$/.test(
|
|
7272
|
+
function securityExecutionDigest(value2) {
|
|
7273
|
+
if (!/^sha256:[a-f0-9]{64}$/.test(value2)) {
|
|
7252
7274
|
throw new Error("expected execution digest must be a sha256 digest from security intent");
|
|
7253
7275
|
}
|
|
7254
|
-
return
|
|
7276
|
+
return value2;
|
|
7255
7277
|
}
|
|
7256
7278
|
|
|
7257
7279
|
// src/argv.ts
|
|
@@ -7275,10 +7297,10 @@ function parseArgv(argv) {
|
|
|
7275
7297
|
addOption(options, rawName, arg.slice(eq + 1));
|
|
7276
7298
|
continue;
|
|
7277
7299
|
}
|
|
7278
|
-
const
|
|
7279
|
-
if (
|
|
7300
|
+
const value2 = argv[i + 1];
|
|
7301
|
+
if (value2 !== void 0 && !value2.startsWith("--")) {
|
|
7280
7302
|
i++;
|
|
7281
|
-
addOption(options, rawName,
|
|
7303
|
+
addOption(options, rawName, value2);
|
|
7282
7304
|
} else {
|
|
7283
7305
|
addOption(options, rawName, true);
|
|
7284
7306
|
}
|
|
@@ -7294,39 +7316,39 @@ function assertArgs(parsed, allowedOptions2, maxPositionals) {
|
|
|
7294
7316
|
throw new Error(`unexpected argument "${parsed.positionals[maxPositionals]}"; run "odla-ai help"`);
|
|
7295
7317
|
}
|
|
7296
7318
|
}
|
|
7297
|
-
function requiredString(
|
|
7298
|
-
const result = stringOpt(
|
|
7319
|
+
function requiredString(value2, name) {
|
|
7320
|
+
const result = stringOpt(value2);
|
|
7299
7321
|
if (!result) throw new Error(`${name} is required`);
|
|
7300
7322
|
return result;
|
|
7301
7323
|
}
|
|
7302
|
-
function stringOpt(
|
|
7303
|
-
if (typeof
|
|
7304
|
-
if (Array.isArray(
|
|
7324
|
+
function stringOpt(value2) {
|
|
7325
|
+
if (typeof value2 === "string") return value2;
|
|
7326
|
+
if (Array.isArray(value2)) return value2[value2.length - 1];
|
|
7305
7327
|
return void 0;
|
|
7306
7328
|
}
|
|
7307
|
-
function listOpt(
|
|
7308
|
-
if (
|
|
7309
|
-
const values = Array.isArray(
|
|
7329
|
+
function listOpt(value2) {
|
|
7330
|
+
if (value2 === void 0 || typeof value2 === "boolean") return void 0;
|
|
7331
|
+
const values = Array.isArray(value2) ? value2 : [value2];
|
|
7310
7332
|
return values.flatMap((item) => item.split(",")).map((item) => item.trim()).filter(Boolean);
|
|
7311
7333
|
}
|
|
7312
|
-
function boolOpt(
|
|
7313
|
-
if (typeof
|
|
7314
|
-
if (typeof
|
|
7315
|
-
if (
|
|
7334
|
+
function boolOpt(value2) {
|
|
7335
|
+
if (typeof value2 === "boolean") return value2;
|
|
7336
|
+
if (typeof value2 === "string" && (value2 === "true" || value2 === "false")) return value2 === "true";
|
|
7337
|
+
if (value2 === void 0) return void 0;
|
|
7316
7338
|
throw new Error("boolean option must be true or false");
|
|
7317
7339
|
}
|
|
7318
|
-
function numberOpt(
|
|
7319
|
-
if (
|
|
7320
|
-
const raw = stringOpt(
|
|
7340
|
+
function numberOpt(value2, flag) {
|
|
7341
|
+
if (value2 === void 0) return void 0;
|
|
7342
|
+
const raw = stringOpt(value2);
|
|
7321
7343
|
const parsed = raw === void 0 ? Number.NaN : Number(raw);
|
|
7322
7344
|
if (!Number.isSafeInteger(parsed) || parsed < 1) throw new Error(`${flag} requires a positive integer`);
|
|
7323
7345
|
return parsed;
|
|
7324
7346
|
}
|
|
7325
|
-
function addOption(options, name,
|
|
7347
|
+
function addOption(options, name, value2) {
|
|
7326
7348
|
const current = options[name];
|
|
7327
|
-
if (current === void 0) options[name] =
|
|
7328
|
-
else if (Array.isArray(current)) current.push(String(
|
|
7329
|
-
else options[name] = [String(current), String(
|
|
7349
|
+
if (current === void 0) options[name] = value2;
|
|
7350
|
+
else if (Array.isArray(current)) current.push(String(value2));
|
|
7351
|
+
else options[name] = [String(current), String(value2)];
|
|
7330
7352
|
}
|
|
7331
7353
|
|
|
7332
7354
|
// src/operator-context.ts
|
|
@@ -7354,8 +7376,8 @@ function resolveOperatorProfile(parsed) {
|
|
|
7354
7376
|
}
|
|
7355
7377
|
assertOperatorName(name, "context");
|
|
7356
7378
|
const profiles = readOperatorProfiles(file);
|
|
7357
|
-
const
|
|
7358
|
-
if (!
|
|
7379
|
+
const value2 = Object.hasOwn(profiles, name) ? profiles[name] : void 0;
|
|
7380
|
+
if (!value2) {
|
|
7359
7381
|
throw new Error(
|
|
7360
7382
|
`operator context "${name}" not found in ${file}; run "odla-ai context list" or save it first`
|
|
7361
7383
|
);
|
|
@@ -7364,7 +7386,7 @@ function resolveOperatorProfile(parsed) {
|
|
|
7364
7386
|
name,
|
|
7365
7387
|
source: fromFlag ? "flag" : "environment",
|
|
7366
7388
|
file,
|
|
7367
|
-
value
|
|
7389
|
+
value: value2
|
|
7368
7390
|
};
|
|
7369
7391
|
}
|
|
7370
7392
|
function listOperatorProfiles(file = operatorProfileFile()) {
|
|
@@ -7392,8 +7414,8 @@ function operatorCredentialFiles(selection) {
|
|
|
7392
7414
|
scoped: join9(base, "admin-token.local.json")
|
|
7393
7415
|
};
|
|
7394
7416
|
}
|
|
7395
|
-
function assertOperatorName(
|
|
7396
|
-
if (!/^[a-z0-9][a-z0-9-]*$/.test(
|
|
7417
|
+
function assertOperatorName(value2, label) {
|
|
7418
|
+
if (!/^[a-z0-9][a-z0-9-]*$/.test(value2)) {
|
|
7397
7419
|
throw new Error(
|
|
7398
7420
|
`${label} must contain lowercase letters, numbers, and hyphens`
|
|
7399
7421
|
);
|
|
@@ -7419,22 +7441,22 @@ function readOperatorProfiles(file) {
|
|
|
7419
7441
|
);
|
|
7420
7442
|
}
|
|
7421
7443
|
const profiles = emptyProfiles();
|
|
7422
|
-
for (const [name,
|
|
7444
|
+
for (const [name, value2] of Object.entries(
|
|
7423
7445
|
raw.profiles
|
|
7424
7446
|
)) {
|
|
7425
7447
|
assertOperatorName(name, "context");
|
|
7426
|
-
profiles[name] = validateProfile(
|
|
7448
|
+
profiles[name] = validateProfile(value2, `operator context "${name}"`);
|
|
7427
7449
|
}
|
|
7428
7450
|
return profiles;
|
|
7429
7451
|
}
|
|
7430
7452
|
function emptyProfiles() {
|
|
7431
7453
|
return /* @__PURE__ */ Object.create(null);
|
|
7432
7454
|
}
|
|
7433
|
-
function validateProfile(
|
|
7434
|
-
if (!
|
|
7455
|
+
function validateProfile(value2, label) {
|
|
7456
|
+
if (!value2 || typeof value2 !== "object" || Array.isArray(value2)) {
|
|
7435
7457
|
throw new Error(`${label} has an invalid shape`);
|
|
7436
7458
|
}
|
|
7437
|
-
const unknown = Object.keys(
|
|
7459
|
+
const unknown = Object.keys(value2).filter(
|
|
7438
7460
|
(key) => !["platform", "app", "environment"].includes(key)
|
|
7439
7461
|
);
|
|
7440
7462
|
if (unknown.length > 0) {
|
|
@@ -7442,7 +7464,7 @@ function validateProfile(value, label) {
|
|
|
7442
7464
|
`${label} contains unsupported field(s): ${unknown.sort().join(", ")}; contexts store scope metadata only, never credentials`
|
|
7443
7465
|
);
|
|
7444
7466
|
}
|
|
7445
|
-
const candidate =
|
|
7467
|
+
const candidate = value2;
|
|
7446
7468
|
if (typeof candidate.platform !== "string") {
|
|
7447
7469
|
throw new Error(`${label} needs an absolute platform URL`);
|
|
7448
7470
|
}
|
|
@@ -7457,8 +7479,8 @@ function validateProfile(value, label) {
|
|
|
7457
7479
|
...environment2 ? { environment: environment2 } : {}
|
|
7458
7480
|
};
|
|
7459
7481
|
}
|
|
7460
|
-
function clean(
|
|
7461
|
-
const normalized =
|
|
7482
|
+
function clean(value2) {
|
|
7483
|
+
const normalized = value2?.trim();
|
|
7462
7484
|
return normalized || void 0;
|
|
7463
7485
|
}
|
|
7464
7486
|
|
|
@@ -7551,8 +7573,8 @@ async function resolveOperatorContext(parsed, options = {}) {
|
|
|
7551
7573
|
}
|
|
7552
7574
|
};
|
|
7553
7575
|
}
|
|
7554
|
-
function clean2(
|
|
7555
|
-
const normalized =
|
|
7576
|
+
function clean2(value2) {
|
|
7577
|
+
const normalized = value2?.trim();
|
|
7556
7578
|
return normalized || void 0;
|
|
7557
7579
|
}
|
|
7558
7580
|
|
|
@@ -8241,10 +8263,10 @@ function harnessList(parsed) {
|
|
|
8241
8263
|
];
|
|
8242
8264
|
return selected.length ? selected : ["all"];
|
|
8243
8265
|
}
|
|
8244
|
-
function harnessOption(
|
|
8245
|
-
if (
|
|
8246
|
-
if (typeof
|
|
8247
|
-
const raw = Array.isArray(
|
|
8266
|
+
function harnessOption(value2, flag) {
|
|
8267
|
+
if (value2 === void 0) return [];
|
|
8268
|
+
if (typeof value2 === "boolean") throw new Error(`${flag} requires a harness name`);
|
|
8269
|
+
const raw = Array.isArray(value2) ? value2 : [value2];
|
|
8248
8270
|
const parts = raw.flatMap((item) => item.split(","));
|
|
8249
8271
|
if (parts.some((item) => !item.trim())) {
|
|
8250
8272
|
throw new Error(`${flag} requires a harness name`);
|
|
@@ -8413,8 +8435,8 @@ function developerTokenStatus(context, parsed, now = Date.now()) {
|
|
|
8413
8435
|
cacheStatus
|
|
8414
8436
|
};
|
|
8415
8437
|
}
|
|
8416
|
-
function clean3(
|
|
8417
|
-
const normalized =
|
|
8438
|
+
function clean3(value2) {
|
|
8439
|
+
const normalized = value2?.trim();
|
|
8418
8440
|
return normalized || void 0;
|
|
8419
8441
|
}
|
|
8420
8442
|
|
|
@@ -8563,8 +8585,8 @@ async function request(ctx, method, path, body) {
|
|
|
8563
8585
|
throw new Error(`discuss ${method} ${path} failed: ${data.error ?? `registry returned ${res.status}`}`);
|
|
8564
8586
|
return data;
|
|
8565
8587
|
}
|
|
8566
|
-
function emit(ctx,
|
|
8567
|
-
if (ctx.json) ctx.out.log(JSON.stringify(
|
|
8588
|
+
function emit(ctx, value2, human) {
|
|
8589
|
+
if (ctx.json) ctx.out.log(JSON.stringify(value2, null, 2));
|
|
8568
8590
|
else human();
|
|
8569
8591
|
}
|
|
8570
8592
|
var state = (topic) => topic.resolved ? "resolved" : "open";
|
|
@@ -8609,8 +8631,8 @@ async function discussList(ctx, parsed) {
|
|
|
8609
8631
|
["limit", "limit"],
|
|
8610
8632
|
["offset", "offset"]
|
|
8611
8633
|
]) {
|
|
8612
|
-
const
|
|
8613
|
-
if (
|
|
8634
|
+
const value2 = stringOpt(parsed.options[flag]);
|
|
8635
|
+
if (value2) query.set(param, value2);
|
|
8614
8636
|
}
|
|
8615
8637
|
const qs = query.toString();
|
|
8616
8638
|
const page = await request(ctx, "GET", `/topics${qs ? `?${qs}` : ""}`);
|
|
@@ -8807,11 +8829,11 @@ var MAX_CONSECUTIVE_FAILURES = 5;
|
|
|
8807
8829
|
var MAX_BACKOFF_MS = 3e4;
|
|
8808
8830
|
function numberOpt2(parsed, flag, fallback) {
|
|
8809
8831
|
const raw = stringOpt(parsed.options[flag]);
|
|
8810
|
-
const
|
|
8811
|
-
return Number.isFinite(
|
|
8832
|
+
const value2 = raw == null ? NaN : Number(raw);
|
|
8833
|
+
return Number.isFinite(value2) && value2 > 0 ? value2 : fallback;
|
|
8812
8834
|
}
|
|
8813
|
-
function jsonl(ctx, parsed,
|
|
8814
|
-
if (parsed.options.jsonl === true) ctx.out.log(JSON.stringify({ v: 1, ...
|
|
8835
|
+
function jsonl(ctx, parsed, value2) {
|
|
8836
|
+
if (parsed.options.jsonl === true) ctx.out.log(JSON.stringify({ v: 1, ...value2 }));
|
|
8815
8837
|
}
|
|
8816
8838
|
async function discussWatch(ctx, topicId, parsed) {
|
|
8817
8839
|
if (ctx.json && parsed.options.jsonl === true) throw new Error("--json and --jsonl cannot be combined");
|
|
@@ -9073,13 +9095,13 @@ async function pmRequest(ctx, method, path, body) {
|
|
|
9073
9095
|
function collectFields(parsed, allowClear) {
|
|
9074
9096
|
const out = {};
|
|
9075
9097
|
for (const [flag, spec] of Object.entries(FIELD_MAP)) {
|
|
9076
|
-
const
|
|
9077
|
-
if (
|
|
9078
|
-
if (
|
|
9098
|
+
const value2 = parsed.options[flag];
|
|
9099
|
+
if (value2 === void 0 || value2 === true) continue;
|
|
9100
|
+
if (value2 === false) {
|
|
9079
9101
|
if (allowClear) out[spec.key] = null;
|
|
9080
9102
|
continue;
|
|
9081
9103
|
}
|
|
9082
|
-
const text = stringOpt(
|
|
9104
|
+
const text = stringOpt(value2);
|
|
9083
9105
|
out[spec.key] = spec.num ? Number(text) : text;
|
|
9084
9106
|
}
|
|
9085
9107
|
return out;
|
|
@@ -9100,8 +9122,8 @@ function statusCol(entity, r) {
|
|
|
9100
9122
|
function printRecord(ctx, entity, r) {
|
|
9101
9123
|
ctx.out.log(`${r.id} [${statusCol(entity, r)}] ${r.appId} ${r.title ?? ""}`);
|
|
9102
9124
|
}
|
|
9103
|
-
function emit2(ctx,
|
|
9104
|
-
if (ctx.json) ctx.out.log(JSON.stringify(
|
|
9125
|
+
function emit2(ctx, value2, human) {
|
|
9126
|
+
if (ctx.json) ctx.out.log(JSON.stringify(value2, null, 2));
|
|
9105
9127
|
else human();
|
|
9106
9128
|
}
|
|
9107
9129
|
async function pmList(ctx, entity, parsed) {
|
|
@@ -9147,8 +9169,8 @@ async function pmAdd(ctx, entity, parsed) {
|
|
|
9147
9169
|
emit2(ctx, res, () => ctx.out.log(`created ${entity} ${res.id}`));
|
|
9148
9170
|
}
|
|
9149
9171
|
async function pmGet(ctx, entity, id) {
|
|
9150
|
-
const { record:
|
|
9151
|
-
emit2(ctx,
|
|
9172
|
+
const { record: record8 } = await pmRequest(ctx, "GET", `/${entity}/${encodeURIComponent(id)}`);
|
|
9173
|
+
emit2(ctx, record8, () => printRecord(ctx, entity, record8));
|
|
9152
9174
|
}
|
|
9153
9175
|
async function pmSet(ctx, entity, id, parsed) {
|
|
9154
9176
|
const patch2 = collectEntityFields(entity, parsed, true);
|
|
@@ -9193,9 +9215,9 @@ async function pmHandoff(ctx, parsed) {
|
|
|
9193
9215
|
]);
|
|
9194
9216
|
const handoff = {
|
|
9195
9217
|
appId,
|
|
9196
|
-
unmetGoals: goals.filter((
|
|
9197
|
-
activeTasks: tasks.filter((
|
|
9198
|
-
openBugs: bugs.filter((
|
|
9218
|
+
unmetGoals: goals.filter((record8) => record8.status !== "met"),
|
|
9219
|
+
activeTasks: tasks.filter((record8) => record8.column !== "done"),
|
|
9220
|
+
openBugs: bugs.filter((record8) => record8.status !== "fixed" && record8.status !== "wontfix")
|
|
9199
9221
|
};
|
|
9200
9222
|
const result = {
|
|
9201
9223
|
...handoff,
|
|
@@ -9214,10 +9236,10 @@ async function pmHandoff(ctx, parsed) {
|
|
|
9214
9236
|
]) {
|
|
9215
9237
|
ctx.out.log(`${label}:`);
|
|
9216
9238
|
if (!records.length) ctx.out.log("- (none)");
|
|
9217
|
-
else for (const
|
|
9239
|
+
else for (const record8 of records) printRecord(
|
|
9218
9240
|
ctx,
|
|
9219
9241
|
label === "unmet goals" ? "goal" : label === "active tasks" ? "task" : "bug",
|
|
9220
|
-
|
|
9242
|
+
record8
|
|
9221
9243
|
);
|
|
9222
9244
|
}
|
|
9223
9245
|
});
|
|
@@ -9365,6 +9387,113 @@ async function pmCommand(parsed, deps = {}) {
|
|
|
9365
9387
|
}
|
|
9366
9388
|
}
|
|
9367
9389
|
|
|
9390
|
+
// src/platform-output.ts
|
|
9391
|
+
function printPlatformStatus(status, out) {
|
|
9392
|
+
out.log(`platform ${status.verdict.status} ${status.observedAt}`);
|
|
9393
|
+
out.log(
|
|
9394
|
+
`fleet ${status.summary.healthy}/${status.summary.services} healthy ${status.summary.required} required ${status.summary.unreachable} unreachable ${status.summary.notConfigured} not configured`
|
|
9395
|
+
);
|
|
9396
|
+
out.log(`catalog ${status.catalog.revision}`);
|
|
9397
|
+
out.log(
|
|
9398
|
+
"service required health probe ms version provider age requests errors cpu p99 us wall p99 us"
|
|
9399
|
+
);
|
|
9400
|
+
for (const service of status.services) {
|
|
9401
|
+
const metrics = service.provider.metrics;
|
|
9402
|
+
out.log([
|
|
9403
|
+
service.id,
|
|
9404
|
+
service.required ? "yes" : "no",
|
|
9405
|
+
service.health.status,
|
|
9406
|
+
value(service.health.latencyMs),
|
|
9407
|
+
service.release.observedVersionId ?? "unknown",
|
|
9408
|
+
service.provider.status,
|
|
9409
|
+
age(service.provider.ageMs),
|
|
9410
|
+
value(metrics?.requests),
|
|
9411
|
+
value(metrics?.errors),
|
|
9412
|
+
value(metrics?.cpuTimeP99),
|
|
9413
|
+
value(metrics?.wallTimeP99)
|
|
9414
|
+
].join(" "));
|
|
9415
|
+
}
|
|
9416
|
+
if (status.verdict.reasons.length) {
|
|
9417
|
+
out.log(`reasons ${status.verdict.reasons.join(", ")}`);
|
|
9418
|
+
}
|
|
9419
|
+
for (const action of status.nextActions) {
|
|
9420
|
+
out.log(`next ${action.service} ${action.code} ${action.message}`);
|
|
9421
|
+
}
|
|
9422
|
+
}
|
|
9423
|
+
function value(input) {
|
|
9424
|
+
return input === null || input === void 0 ? "unknown" : String(input);
|
|
9425
|
+
}
|
|
9426
|
+
function age(input) {
|
|
9427
|
+
if (input === null) return "unknown";
|
|
9428
|
+
if (input < 1e3) return `${input}ms`;
|
|
9429
|
+
if (input < 6e4) return `${Math.round(input / 1e3)}s`;
|
|
9430
|
+
return `${Math.round(input / 6e4)}m`;
|
|
9431
|
+
}
|
|
9432
|
+
|
|
9433
|
+
// src/platform-command.ts
|
|
9434
|
+
async function platformCommand(parsed, deps = {}) {
|
|
9435
|
+
assertArgs(
|
|
9436
|
+
parsed,
|
|
9437
|
+
["config", "context", "platform", "token", "email", "open", "json"],
|
|
9438
|
+
2
|
|
9439
|
+
);
|
|
9440
|
+
const action = parsed.positionals[1];
|
|
9441
|
+
if (action !== "status") {
|
|
9442
|
+
throw new Error(
|
|
9443
|
+
`unknown platform action "${action ?? ""}". Try "odla-ai platform status --json".`
|
|
9444
|
+
);
|
|
9445
|
+
}
|
|
9446
|
+
const context = await resolveOperatorContext(parsed, {
|
|
9447
|
+
allowMissingConfig: true
|
|
9448
|
+
});
|
|
9449
|
+
const platform = context.platform.value;
|
|
9450
|
+
const doFetch = deps.fetch ?? fetch;
|
|
9451
|
+
const out = deps.stdout ?? console;
|
|
9452
|
+
const token = await resolveAdminPlatformToken({
|
|
9453
|
+
platform,
|
|
9454
|
+
scope: "platform:status:read",
|
|
9455
|
+
token: stringOpt(parsed.options.token),
|
|
9456
|
+
tokenFile: context.credentials.scopedTokenFile,
|
|
9457
|
+
email: stringOpt(parsed.options.email),
|
|
9458
|
+
open: parsed.options.open === false ? false : parsed.options.open === true ? true : void 0,
|
|
9459
|
+
fetch: doFetch,
|
|
9460
|
+
stdout: out,
|
|
9461
|
+
openApprovalUrl: deps.openUrl,
|
|
9462
|
+
label: "odla CLI (platform fleet status)"
|
|
9463
|
+
});
|
|
9464
|
+
const response2 = await doFetch(`${platform}/registry/platform/status`, {
|
|
9465
|
+
headers: { authorization: `Bearer ${token}` }
|
|
9466
|
+
});
|
|
9467
|
+
const body = await response2.json().catch(() => null);
|
|
9468
|
+
if (!response2.ok) {
|
|
9469
|
+
throw new Error(
|
|
9470
|
+
`read platform status failed (HTTP ${response2.status}): ${apiMessage(body)}`
|
|
9471
|
+
);
|
|
9472
|
+
}
|
|
9473
|
+
if (!isPlatformStatus(body)) {
|
|
9474
|
+
throw new Error("platform returned an invalid odla.platform-status/v1 envelope");
|
|
9475
|
+
}
|
|
9476
|
+
if (parsed.options.json === true) {
|
|
9477
|
+
out.log(JSON.stringify(body, null, 2));
|
|
9478
|
+
} else {
|
|
9479
|
+
printPlatformStatus(body, out);
|
|
9480
|
+
}
|
|
9481
|
+
}
|
|
9482
|
+
function isPlatformStatus(value2) {
|
|
9483
|
+
if (!record5(value2) || value2.schemaVersion !== "odla.platform-status/v1") return false;
|
|
9484
|
+
if (!record5(value2.verdict) || !Array.isArray(value2.verdict.reasons)) return false;
|
|
9485
|
+
if (!record5(value2.catalog) || !record5(value2.summary)) return false;
|
|
9486
|
+
return Array.isArray(value2.services) && Array.isArray(value2.nextActions);
|
|
9487
|
+
}
|
|
9488
|
+
function apiMessage(value2) {
|
|
9489
|
+
if (!record5(value2)) return "request failed";
|
|
9490
|
+
const error = record5(value2.error) ? value2.error : value2;
|
|
9491
|
+
return typeof error.message === "string" ? error.message : typeof error.code === "string" ? error.code : "request failed";
|
|
9492
|
+
}
|
|
9493
|
+
function record5(value2) {
|
|
9494
|
+
return !!value2 && typeof value2 === "object" && !Array.isArray(value2);
|
|
9495
|
+
}
|
|
9496
|
+
|
|
9368
9497
|
// src/o11y-verdict.ts
|
|
9369
9498
|
function statusVerdict(reads) {
|
|
9370
9499
|
const reasons = [];
|
|
@@ -9402,7 +9531,7 @@ function statusVerdict(reads) {
|
|
|
9402
9531
|
severity: "degraded"
|
|
9403
9532
|
});
|
|
9404
9533
|
}
|
|
9405
|
-
const performance =
|
|
9534
|
+
const performance = record6(reads.liveSync.body.performance) ? reads.liveSync.body.performance : null;
|
|
9406
9535
|
if (performance?.status === "unavailable") {
|
|
9407
9536
|
reasons.push({
|
|
9408
9537
|
source: "liveSync",
|
|
@@ -9483,11 +9612,11 @@ function statusVerdict(reads) {
|
|
|
9483
9612
|
reasons
|
|
9484
9613
|
};
|
|
9485
9614
|
}
|
|
9486
|
-
function
|
|
9487
|
-
return Boolean(
|
|
9615
|
+
function record6(value2) {
|
|
9616
|
+
return Boolean(value2) && typeof value2 === "object" && !Array.isArray(value2);
|
|
9488
9617
|
}
|
|
9489
|
-
function numeric2(
|
|
9490
|
-
return typeof
|
|
9618
|
+
function numeric2(value2) {
|
|
9619
|
+
return typeof value2 === "number" && Number.isFinite(value2) ? value2 : 0;
|
|
9491
9620
|
}
|
|
9492
9621
|
function collectorReason(read3, fallback) {
|
|
9493
9622
|
const reasons = read3.body.reasons;
|
|
@@ -9511,7 +9640,7 @@ function printO11yStatus(status, out) {
|
|
|
9511
9640
|
out.log(
|
|
9512
9641
|
`o11y status ${status.scope.appId}/${status.scope.env} (${status.scope.minutes}m)`
|
|
9513
9642
|
);
|
|
9514
|
-
const routes = Array.isArray(status.application.body.routes) ? status.application.body.routes.filter(
|
|
9643
|
+
const routes = Array.isArray(status.application.body.routes) ? status.application.body.routes.filter(record7) : [];
|
|
9515
9644
|
const requests = routes.reduce(
|
|
9516
9645
|
(total, row) => total + numeric3(row.requests),
|
|
9517
9646
|
0
|
|
@@ -9523,39 +9652,39 @@ function printO11yStatus(status, out) {
|
|
|
9523
9652
|
out.log(
|
|
9524
9653
|
`application ${status.application.httpStatus} ${requests} requests ${errors} errors`
|
|
9525
9654
|
);
|
|
9526
|
-
const versions = Array.isArray(status.applicationVersions.body.rows) ? status.applicationVersions.body.rows.filter(
|
|
9655
|
+
const versions = Array.isArray(status.applicationVersions.body.rows) ? status.applicationVersions.body.rows.filter(record7) : [];
|
|
9527
9656
|
out.log(
|
|
9528
9657
|
`application-versions ${status.applicationVersions.httpStatus} ${versions.length ? versions.slice(0, 5).map(
|
|
9529
9658
|
(row) => `${String(row.value || "(unattributed)")}:${numeric3(row.requests)}`
|
|
9530
9659
|
).join(", ") : "none observed"}`
|
|
9531
9660
|
);
|
|
9532
9661
|
out.log(liveSyncLine(status.liveSync));
|
|
9533
|
-
const canaryDurations =
|
|
9662
|
+
const canaryDurations = record7(status.canary.body.durationsMs) ? status.canary.body.durationsMs : {};
|
|
9534
9663
|
out.log(
|
|
9535
9664
|
`canary ${status.canary.httpStatus} ${String(status.canary.body.status ?? status.canary.body.error ?? "unavailable")} ${optionalNumeric(canaryDurations.publishToVisibleMs)} publish-to-visible`
|
|
9536
9665
|
);
|
|
9537
|
-
const collectorIngest =
|
|
9538
|
-
const collectorStorage =
|
|
9666
|
+
const collectorIngest = record7(status.collector.body.ingest) ? status.collector.body.ingest : {};
|
|
9667
|
+
const collectorStorage = record7(collectorIngest.storage) ? collectorIngest.storage : {};
|
|
9539
9668
|
out.log(
|
|
9540
9669
|
`collector ${status.collector.httpStatus} ${String(status.collector.body.status ?? status.collector.body.error ?? "unavailable")} ${numeric3(collectorStorage.affectedPoints)} affected points`
|
|
9541
9670
|
);
|
|
9542
|
-
const providerMetrics =
|
|
9543
|
-
const providerCapacity =
|
|
9544
|
-
const workerMemory =
|
|
9671
|
+
const providerMetrics = record7(status.provider.body.metrics) ? status.provider.body.metrics : {};
|
|
9672
|
+
const providerCapacity = record7(status.provider.body.capacity) ? status.provider.body.capacity : {};
|
|
9673
|
+
const workerMemory = record7(providerCapacity.memory) ? providerCapacity.memory : {};
|
|
9545
9674
|
out.log(
|
|
9546
9675
|
`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`
|
|
9547
9676
|
);
|
|
9548
9677
|
for (const line of providerCapacityLines(status.providerCapacity)) {
|
|
9549
9678
|
out.log(line);
|
|
9550
9679
|
}
|
|
9551
|
-
const coverage =
|
|
9552
|
-
const coverageCounts =
|
|
9553
|
-
const coverageBudget =
|
|
9680
|
+
const coverage = record7(status.providerReconciliation.body.comparison) ? status.providerReconciliation.body.comparison : {};
|
|
9681
|
+
const coverageCounts = record7(status.providerReconciliation.body.counts) ? status.providerReconciliation.body.counts : {};
|
|
9682
|
+
const coverageBudget = record7(status.providerReconciliation.body.budget) ? status.providerReconciliation.body.budget : {};
|
|
9554
9683
|
out.log(
|
|
9555
9684
|
`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`
|
|
9556
9685
|
);
|
|
9557
9686
|
const providerPoints = Array.isArray(status.providerHistory.body.points) ? status.providerHistory.body.points.length : 0;
|
|
9558
|
-
const providerFreshness =
|
|
9687
|
+
const providerFreshness = record7(status.providerHistory.body.freshness) ? status.providerHistory.body.freshness : {};
|
|
9559
9688
|
out.log(
|
|
9560
9689
|
`cloudflare-history ${status.providerHistory.httpStatus} ${String(status.providerHistory.body.status ?? status.providerHistory.body.error ?? "unavailable")} ${providerPoints} snapshots ${optionalAge(providerFreshness.ageMs)} old`
|
|
9561
9690
|
);
|
|
@@ -9564,17 +9693,17 @@ function printO11yStatus(status, out) {
|
|
|
9564
9693
|
);
|
|
9565
9694
|
}
|
|
9566
9695
|
function providerCapacityLines(read3) {
|
|
9567
|
-
const resources =
|
|
9568
|
-
const durableObjects =
|
|
9569
|
-
const periodic =
|
|
9570
|
-
const storage =
|
|
9571
|
-
const d1 =
|
|
9572
|
-
const d1Activity =
|
|
9573
|
-
const d1Storage =
|
|
9574
|
-
const d1Latency =
|
|
9575
|
-
const r2 =
|
|
9576
|
-
const r2Operations =
|
|
9577
|
-
const r2Storage =
|
|
9696
|
+
const resources = record7(read3.body.resources) ? read3.body.resources : {};
|
|
9697
|
+
const durableObjects = record7(resources.durableObjects) ? resources.durableObjects : {};
|
|
9698
|
+
const periodic = record7(durableObjects.periodic) ? durableObjects.periodic : {};
|
|
9699
|
+
const storage = record7(durableObjects.sqliteStorage) ? durableObjects.sqliteStorage : {};
|
|
9700
|
+
const d1 = record7(resources.d1) ? resources.d1 : {};
|
|
9701
|
+
const d1Activity = record7(d1.activity) ? d1.activity : {};
|
|
9702
|
+
const d1Storage = record7(d1.storage) ? d1.storage : {};
|
|
9703
|
+
const d1Latency = record7(d1Activity.latency) ? d1Activity.latency : {};
|
|
9704
|
+
const r2 = record7(resources.r2) ? resources.r2 : {};
|
|
9705
|
+
const r2Operations = record7(r2.operations) ? r2.operations : {};
|
|
9706
|
+
const r2Storage = record7(r2.storage) ? r2.storage : {};
|
|
9578
9707
|
const status = String(
|
|
9579
9708
|
read3.body.status ?? read3.body.error ?? "unavailable"
|
|
9580
9709
|
);
|
|
@@ -9585,42 +9714,42 @@ function providerCapacityLines(read3) {
|
|
|
9585
9714
|
];
|
|
9586
9715
|
}
|
|
9587
9716
|
function liveSyncLine(read3) {
|
|
9588
|
-
const performance =
|
|
9589
|
-
const commitToSend =
|
|
9717
|
+
const performance = record7(read3.body.performance) ? read3.body.performance : {};
|
|
9718
|
+
const commitToSend = record7(performance.commitToSend) ? performance.commitToSend : {};
|
|
9590
9719
|
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`;
|
|
9591
9720
|
}
|
|
9592
|
-
function
|
|
9593
|
-
return Boolean(
|
|
9721
|
+
function record7(value2) {
|
|
9722
|
+
return Boolean(value2) && typeof value2 === "object" && !Array.isArray(value2);
|
|
9594
9723
|
}
|
|
9595
|
-
function numeric3(
|
|
9596
|
-
return typeof
|
|
9724
|
+
function numeric3(value2) {
|
|
9725
|
+
return typeof value2 === "number" && Number.isFinite(value2) ? value2 : 0;
|
|
9597
9726
|
}
|
|
9598
|
-
function optionalNumeric(
|
|
9599
|
-
return typeof
|
|
9727
|
+
function optionalNumeric(value2) {
|
|
9728
|
+
return typeof value2 === "number" && Number.isFinite(value2) ? `${value2} ms` : "\u2014";
|
|
9600
9729
|
}
|
|
9601
|
-
function optionalAge(
|
|
9602
|
-
if (typeof
|
|
9603
|
-
return `${Math.max(0, Math.round(
|
|
9730
|
+
function optionalAge(value2) {
|
|
9731
|
+
if (typeof value2 !== "number" || !Number.isFinite(value2)) return "unknown";
|
|
9732
|
+
return `${Math.max(0, Math.round(value2 / 1e3))}s`;
|
|
9604
9733
|
}
|
|
9605
|
-
function optionalPercent(
|
|
9606
|
-
return typeof
|
|
9734
|
+
function optionalPercent(value2) {
|
|
9735
|
+
return typeof value2 === "number" && Number.isFinite(value2) ? `${Math.round(value2 * 100)}%` : "\u2014";
|
|
9607
9736
|
}
|
|
9608
|
-
function optionalBytes(
|
|
9609
|
-
if (typeof
|
|
9610
|
-
if (
|
|
9611
|
-
return `${(
|
|
9737
|
+
function optionalBytes(value2) {
|
|
9738
|
+
if (typeof value2 !== "number" || !Number.isFinite(value2)) return "\u2014";
|
|
9739
|
+
if (value2 >= 1024 * 1024 * 1024) {
|
|
9740
|
+
return `${(value2 / (1024 * 1024 * 1024)).toFixed(2)} GiB`;
|
|
9612
9741
|
}
|
|
9613
|
-
if (
|
|
9614
|
-
return `${(
|
|
9742
|
+
if (value2 >= 1024 * 1024) {
|
|
9743
|
+
return `${(value2 / (1024 * 1024)).toFixed(1)} MiB`;
|
|
9615
9744
|
}
|
|
9616
|
-
if (
|
|
9617
|
-
return `${Math.round(
|
|
9745
|
+
if (value2 >= 1024) return `${(value2 / 1024).toFixed(1)} KiB`;
|
|
9746
|
+
return `${Math.round(value2)} B`;
|
|
9618
9747
|
}
|
|
9619
|
-
function optionalCount(
|
|
9620
|
-
return typeof
|
|
9748
|
+
function optionalCount(value2, unit) {
|
|
9749
|
+
return typeof value2 === "number" && Number.isFinite(value2) ? `${value2} ${unit}` : `\u2014 ${unit}`;
|
|
9621
9750
|
}
|
|
9622
|
-
function optionalAgeSeconds(
|
|
9623
|
-
return typeof
|
|
9751
|
+
function optionalAgeSeconds(value2) {
|
|
9752
|
+
return typeof value2 === "number" && Number.isFinite(value2) ? `${Math.max(0, Math.round(value2))}s` : "unknown";
|
|
9624
9753
|
}
|
|
9625
9754
|
|
|
9626
9755
|
// src/o11y-command.ts
|
|
@@ -9750,11 +9879,11 @@ async function o11yCommand(parsed, deps = {}) {
|
|
|
9750
9879
|
}
|
|
9751
9880
|
printO11yStatus(status, out);
|
|
9752
9881
|
}
|
|
9753
|
-
function statusMinutes(
|
|
9754
|
-
if (!Number.isSafeInteger(
|
|
9882
|
+
function statusMinutes(value2) {
|
|
9883
|
+
if (!Number.isSafeInteger(value2) || value2 < 1 || value2 > 7 * 24 * 60) {
|
|
9755
9884
|
throw new Error("--minutes must be an integer from 1 to 10080");
|
|
9756
9885
|
}
|
|
9757
|
-
return
|
|
9886
|
+
return value2;
|
|
9758
9887
|
}
|
|
9759
9888
|
async function read2(url, headers, doFetch) {
|
|
9760
9889
|
const response2 = await doFetch(url, { headers });
|
|
@@ -9762,8 +9891,8 @@ async function read2(url, headers, doFetch) {
|
|
|
9762
9891
|
let body = {};
|
|
9763
9892
|
if (text) {
|
|
9764
9893
|
try {
|
|
9765
|
-
const
|
|
9766
|
-
body =
|
|
9894
|
+
const value2 = JSON.parse(text);
|
|
9895
|
+
body = value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : { value: value2 };
|
|
9767
9896
|
} catch {
|
|
9768
9897
|
body = { message: text.slice(0, 300) };
|
|
9769
9898
|
}
|
|
@@ -9780,7 +9909,7 @@ function recordInvocation(parsed) {
|
|
|
9780
9909
|
try {
|
|
9781
9910
|
const entry = {
|
|
9782
9911
|
path: invocationPath(parsed.positionals),
|
|
9783
|
-
options: Object.entries(parsed.options).map(([name,
|
|
9912
|
+
options: Object.entries(parsed.options).map(([name, value2]) => value2 === false ? `no-${name}` : name).sort()
|
|
9784
9913
|
};
|
|
9785
9914
|
if (!entry.path.length) return;
|
|
9786
9915
|
appendFileSync(file, `${JSON.stringify(entry)}
|
|
@@ -9794,10 +9923,10 @@ import { readFileSync as readFileSync9 } from "fs";
|
|
|
9794
9923
|
|
|
9795
9924
|
// src/runbook-requires.ts
|
|
9796
9925
|
var SPEC = /^(@?[\w./-]+?)@(\d+\.\d+\.\d+(?:[\w.-]*)?)$/;
|
|
9797
|
-
function parseRequires(
|
|
9798
|
-
if (!
|
|
9926
|
+
function parseRequires(value2) {
|
|
9927
|
+
if (!value2) return [];
|
|
9799
9928
|
const out = [];
|
|
9800
|
-
for (const token of
|
|
9929
|
+
for (const token of value2.split(/[\s,]+/).filter(Boolean)) {
|
|
9801
9930
|
const match = SPEC.exec(token);
|
|
9802
9931
|
if (match?.[1] && match[2]) out.push({ name: match[1], min: match[2] });
|
|
9803
9932
|
}
|
|
@@ -9973,9 +10102,9 @@ function parseRunbook(text, slug) {
|
|
|
9973
10102
|
for (const line of fm[1].split(/\r?\n/)) {
|
|
9974
10103
|
const pair = /^(\w+)\s*:\s*(.+)$/.exec(line.trim());
|
|
9975
10104
|
if (!pair) continue;
|
|
9976
|
-
const
|
|
9977
|
-
if (pair[1] === "summary") meta.summary =
|
|
9978
|
-
if (pair[1] === "tags") meta.tags =
|
|
10105
|
+
const value2 = pair[2].trim().replace(/^["']|["']$/g, "");
|
|
10106
|
+
if (pair[1] === "summary") meta.summary = value2;
|
|
10107
|
+
if (pair[1] === "tags") meta.tags = value2.replace(/^\[|\]$/g, "").trim();
|
|
9979
10108
|
}
|
|
9980
10109
|
}
|
|
9981
10110
|
const lines = rest.split("\n");
|
|
@@ -10092,7 +10221,7 @@ var NOISE = /* @__PURE__ */ new Set([
|
|
|
10092
10221
|
"and",
|
|
10093
10222
|
"for"
|
|
10094
10223
|
]);
|
|
10095
|
-
var words = (
|
|
10224
|
+
var words = (value2) => value2.replace(/^@[\w-]+\//, "").split(/[^A-Za-z0-9]+/).filter((w) => w.length > 1 && !NOISE.has(w.toLowerCase()));
|
|
10096
10225
|
function namedExports(clause) {
|
|
10097
10226
|
return clause.split(",").map((part) => part.trim().split(/\s+as\s+/)[0]?.trim() ?? "").filter((name) => /^[A-Za-z_$][\w$]*$/.test(name) && name !== "type");
|
|
10098
10227
|
}
|
|
@@ -10445,8 +10574,8 @@ import process13 from "process";
|
|
|
10445
10574
|
var EDITOR_ENV = ["ODLA_EDITOR", "VISUAL", "EDITOR"];
|
|
10446
10575
|
function resolveEditor(env = process13.env) {
|
|
10447
10576
|
for (const name of EDITOR_ENV) {
|
|
10448
|
-
const
|
|
10449
|
-
if (
|
|
10577
|
+
const value2 = env[name];
|
|
10578
|
+
if (value2 && value2.trim()) return value2.trim();
|
|
10450
10579
|
}
|
|
10451
10580
|
return null;
|
|
10452
10581
|
}
|
|
@@ -10711,9 +10840,9 @@ async function runbookCommand(parsed, deps = {}) {
|
|
|
10711
10840
|
});
|
|
10712
10841
|
}
|
|
10713
10842
|
case "visibility": {
|
|
10714
|
-
const
|
|
10715
|
-
if (!
|
|
10716
|
-
return runbookVisibility(ctx, requireSlug(slug, "visibility"),
|
|
10843
|
+
const value2 = parsed.positionals[3] ?? stringOpt(parsed.options.visibility);
|
|
10844
|
+
if (!value2) throw new Error('"runbook visibility" needs operator|admin, e.g. "runbook visibility release operator"');
|
|
10845
|
+
return runbookVisibility(ctx, requireSlug(slug, "visibility"), value2);
|
|
10717
10846
|
}
|
|
10718
10847
|
case "publish":
|
|
10719
10848
|
return runbookStatus(ctx, requireSlug(slug, "publish"), "published");
|
|
@@ -10769,13 +10898,13 @@ async function interactiveConfirmation(message2, dependencies) {
|
|
|
10769
10898
|
}
|
|
10770
10899
|
}
|
|
10771
10900
|
function requiredSecurityPositional(parsed, index, label) {
|
|
10772
|
-
const
|
|
10773
|
-
if (!
|
|
10774
|
-
return
|
|
10901
|
+
const value2 = parsed.positionals[index];
|
|
10902
|
+
if (!value2) throw new Error(`${label} is required`);
|
|
10903
|
+
return value2;
|
|
10775
10904
|
}
|
|
10776
|
-
function securityProfile(
|
|
10777
|
-
if (
|
|
10778
|
-
if (
|
|
10905
|
+
function securityProfile(value2) {
|
|
10906
|
+
if (value2 === void 0) return void 0;
|
|
10907
|
+
if (value2 === "odla" || value2 === "cloudflare-app" || value2 === "generic") return value2;
|
|
10779
10908
|
throw new Error("--profile must be odla, cloudflare-app, or generic");
|
|
10780
10909
|
}
|
|
10781
10910
|
|
|
@@ -10876,9 +11005,9 @@ function routeLabel(route2) {
|
|
|
10876
11005
|
return `${route2.provider}/${route2.model}${route2.policyVersion ? ` policy v${route2.policyVersion}` : ""}`;
|
|
10877
11006
|
}
|
|
10878
11007
|
var HOSTED_SEVERITIES = ["informational", "low", "medium", "high", "critical"];
|
|
10879
|
-
function hostedSeverity(
|
|
10880
|
-
if (HOSTED_SEVERITIES.includes(
|
|
10881
|
-
return
|
|
11008
|
+
function hostedSeverity(value2, flag) {
|
|
11009
|
+
if (HOSTED_SEVERITIES.includes(value2)) {
|
|
11010
|
+
return value2;
|
|
10882
11011
|
}
|
|
10883
11012
|
throw new Error(`${flag} must be informational, low, medium, high, or critical`);
|
|
10884
11013
|
}
|
|
@@ -10945,7 +11074,7 @@ async function runSourceSecurityCommand(parsed, dependencies, sourceId) {
|
|
|
10945
11074
|
...context,
|
|
10946
11075
|
jobId: job.jobId,
|
|
10947
11076
|
wait: dependencies.pollWait,
|
|
10948
|
-
onUpdate: parsed.options.json === true ? void 0 : (
|
|
11077
|
+
onUpdate: parsed.options.json === true ? void 0 : (value2) => printHostedJob(context.stdout, value2, context.platform, context.appId)
|
|
10949
11078
|
}) : job;
|
|
10950
11079
|
if (!follow) {
|
|
10951
11080
|
if (parsed.options.json === true) {
|
|
@@ -11045,9 +11174,9 @@ function enforceLocalGate(report4, parsed) {
|
|
|
11045
11174
|
throw new Error(`hosted security gate failed: ${confirmed.length} confirmed >= ${failOn}; ${leads.length} leads >= ${failOnCandidates ?? "disabled"}${incomplete ? "; coverage incomplete" : ""}`);
|
|
11046
11175
|
}
|
|
11047
11176
|
}
|
|
11048
|
-
function severityOpt(
|
|
11049
|
-
if (["informational", "low", "medium", "high", "critical"].includes(
|
|
11050
|
-
return
|
|
11177
|
+
function severityOpt(value2, flag) {
|
|
11178
|
+
if (["informational", "low", "medium", "high", "critical"].includes(value2)) {
|
|
11179
|
+
return value2;
|
|
11051
11180
|
}
|
|
11052
11181
|
throw new Error(`${flag} must be informational, low, medium, high, or critical`);
|
|
11053
11182
|
}
|
|
@@ -11155,7 +11284,7 @@ async function securityStatus(parsed, dependencies) {
|
|
|
11155
11284
|
...context,
|
|
11156
11285
|
jobId,
|
|
11157
11286
|
wait: dependencies.pollWait,
|
|
11158
|
-
onUpdate: parsed.options.json === true ? void 0 : (
|
|
11287
|
+
onUpdate: parsed.options.json === true ? void 0 : (value2) => printHostedJob(context.stdout, value2, context.platform, context.appId)
|
|
11159
11288
|
}) : await getHostedSecurityJob({ ...context, jobId });
|
|
11160
11289
|
if (parsed.options.json === true) context.stdout.log(JSON.stringify(job, null, 2));
|
|
11161
11290
|
else if (parsed.options.follow !== true) {
|
|
@@ -11239,6 +11368,10 @@ async function runCli(argv = process.argv.slice(2), dependencies = {}) {
|
|
|
11239
11368
|
await o11yCommand(parsed, runtime);
|
|
11240
11369
|
return;
|
|
11241
11370
|
}
|
|
11371
|
+
if (command === "platform") {
|
|
11372
|
+
await platformCommand(parsed, runtime);
|
|
11373
|
+
return;
|
|
11374
|
+
}
|
|
11242
11375
|
if (command === "provision") {
|
|
11243
11376
|
await provisionCommand(parsed, runtime);
|
|
11244
11377
|
return;
|
|
@@ -11358,4 +11491,4 @@ export {
|
|
|
11358
11491
|
exitCodeFor,
|
|
11359
11492
|
runCli
|
|
11360
11493
|
};
|
|
11361
|
-
//# sourceMappingURL=chunk-
|
|
11494
|
+
//# sourceMappingURL=chunk-L2NG4UR4.js.map
|