@odla-ai/cli 0.25.19 → 0.25.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -0
- package/dist/bin.cjs +768 -635
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-S3EJ66VG.js → chunk-L2NG4UR4.js} +759 -626
- package/dist/chunk-L2NG4UR4.js.map +1 -0
- package/dist/index.cjs +768 -635
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-S3EJ66VG.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -142,22 +142,22 @@ function readJsonFile(path) {
|
|
|
142
142
|
return null;
|
|
143
143
|
}
|
|
144
144
|
}
|
|
145
|
-
function writePrivateJson(path,
|
|
146
|
-
writePrivateText(path, `${JSON.stringify(
|
|
145
|
+
function writePrivateJson(path, value2) {
|
|
146
|
+
writePrivateText(path, `${JSON.stringify(value2, null, 2)}
|
|
147
147
|
`);
|
|
148
148
|
}
|
|
149
149
|
function readCredentials(path) {
|
|
150
150
|
if (!(0, import_node_fs.existsSync)(path)) return null;
|
|
151
|
-
let
|
|
151
|
+
let value2;
|
|
152
152
|
try {
|
|
153
|
-
|
|
153
|
+
value2 = JSON.parse((0, import_node_fs.readFileSync)(path, "utf8"));
|
|
154
154
|
} catch {
|
|
155
155
|
throw new Error(`credentials file ${path} is not valid JSON; fix or remove it before provisioning`);
|
|
156
156
|
}
|
|
157
|
-
if (!
|
|
157
|
+
if (!value2 || typeof value2 !== "object" || typeof value2.appId !== "string" || !value2.envs || typeof value2.envs !== "object") {
|
|
158
158
|
throw new Error(`credentials file ${path} has an invalid shape; fix or remove it before provisioning`);
|
|
159
159
|
}
|
|
160
|
-
return
|
|
160
|
+
return value2;
|
|
161
161
|
}
|
|
162
162
|
function mergeCredential(current, update) {
|
|
163
163
|
const next = current ?? {
|
|
@@ -452,8 +452,8 @@ function stillPending(pending, email) {
|
|
|
452
452
|
{ retryable: true }
|
|
453
453
|
);
|
|
454
454
|
}
|
|
455
|
-
function handshakeEmail(
|
|
456
|
-
const email = (
|
|
455
|
+
function handshakeEmail(value2, cached) {
|
|
456
|
+
const email = (value2 ?? import_node_process3.default.env.ODLA_USER_EMAIL ?? cached ?? "").trim().toLowerCase();
|
|
457
457
|
if (email.length > 254 || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
|
|
458
458
|
throw new Error("a fresh odla handshake requires --email <account> or ODLA_USER_EMAIL");
|
|
459
459
|
}
|
|
@@ -477,10 +477,10 @@ function handshakeUrl(platformUrl, userCode) {
|
|
|
477
477
|
url.searchParams.set("code", userCode);
|
|
478
478
|
return url.toString();
|
|
479
479
|
}
|
|
480
|
-
function platformAudience(
|
|
480
|
+
function platformAudience(value2) {
|
|
481
481
|
let url;
|
|
482
482
|
try {
|
|
483
|
-
url = new URL(
|
|
483
|
+
url = new URL(value2);
|
|
484
484
|
} catch {
|
|
485
485
|
throw new Error("platform must be an absolute URL");
|
|
486
486
|
}
|
|
@@ -499,22 +499,22 @@ var import_node_process4 = __toESM(require("process"), 1);
|
|
|
499
499
|
var MAX_BYTES = 64 * 1024;
|
|
500
500
|
async function secretInputValue(options, kind = "credential") {
|
|
501
501
|
if (options.fromEnv && options.stdin) throw new Error("choose exactly one of --from-env or --stdin");
|
|
502
|
-
let
|
|
503
|
-
if (options.fromEnv)
|
|
504
|
-
else if (options.stdin)
|
|
502
|
+
let value2;
|
|
503
|
+
if (options.fromEnv) value2 = import_node_process4.default.env[options.fromEnv];
|
|
504
|
+
else if (options.stdin) value2 = await (options.readStdin ?? (() => readSecretStream(kind)))();
|
|
505
505
|
else throw new Error(`${kind} input required: use --from-env <NAME> or --stdin; values are never accepted as arguments`);
|
|
506
|
-
|
|
507
|
-
if (!
|
|
508
|
-
if (new TextEncoder().encode(
|
|
509
|
-
return
|
|
506
|
+
value2 = value2?.replace(/[\r\n]+$/, "");
|
|
507
|
+
if (!value2) throw new Error(options.fromEnv ? `environment variable ${options.fromEnv} is empty or unset` : `stdin ${kind} is empty`);
|
|
508
|
+
if (new TextEncoder().encode(value2).byteLength > MAX_BYTES) throw new Error(`${kind} exceeds 64 KiB`);
|
|
509
|
+
return value2;
|
|
510
510
|
}
|
|
511
511
|
async function readSecretStream(kind, stream = import_node_process4.default.stdin) {
|
|
512
|
-
let
|
|
512
|
+
let value2 = "";
|
|
513
513
|
for await (const chunk of stream) {
|
|
514
|
-
|
|
515
|
-
if (
|
|
514
|
+
value2 += String(chunk);
|
|
515
|
+
if (value2.length > MAX_BYTES) throw new Error(`${kind} exceeds 64 KiB`);
|
|
516
516
|
}
|
|
517
|
-
return
|
|
517
|
+
return value2;
|
|
518
518
|
}
|
|
519
519
|
|
|
520
520
|
// src/admin-ai-auth.ts
|
|
@@ -549,6 +549,7 @@ function audienceBoundEnvToken(token, platform) {
|
|
|
549
549
|
return token;
|
|
550
550
|
}
|
|
551
551
|
var SCOPE_PURPOSE = {
|
|
552
|
+
"platform:status:read": "read the platform fleet health and deployment snapshot",
|
|
552
553
|
"platform:runbook:write": "add or edit odla's operational runbooks",
|
|
553
554
|
"platform:ai:policy:write": "change System AI model routing",
|
|
554
555
|
"platform:ai:policy:read": "read System AI model routing",
|
|
@@ -652,13 +653,13 @@ function apiError(status, body) {
|
|
|
652
653
|
const message2 = error && typeof error.message === "string" ? error.message : isRecord(body) && typeof body.message === "string" ? body.message : "request failed";
|
|
653
654
|
return `read System AI admin changes failed (${status}): ${message2}`;
|
|
654
655
|
}
|
|
655
|
-
function timestamp(
|
|
656
|
-
if (typeof
|
|
657
|
-
const date = new Date(
|
|
656
|
+
function timestamp(value2) {
|
|
657
|
+
if (typeof value2 !== "number" || !Number.isFinite(value2)) return String(value2 ?? "");
|
|
658
|
+
const date = new Date(value2);
|
|
658
659
|
return Number.isFinite(date.valueOf()) ? date.toISOString() : "";
|
|
659
660
|
}
|
|
660
|
-
function isRecord(
|
|
661
|
-
return Boolean(
|
|
661
|
+
function isRecord(value2) {
|
|
662
|
+
return Boolean(value2) && typeof value2 === "object" && !Array.isArray(value2);
|
|
662
663
|
}
|
|
663
664
|
|
|
664
665
|
// src/admin-ai-policy.ts
|
|
@@ -668,11 +669,11 @@ var SYSTEM_AI_PURPOSES = [
|
|
|
668
669
|
"security.validation",
|
|
669
670
|
"runbook.answer"
|
|
670
671
|
];
|
|
671
|
-
function requireSystemAiPurpose(
|
|
672
|
-
if (!SYSTEM_AI_PURPOSES.includes(
|
|
672
|
+
function requireSystemAiPurpose(value2) {
|
|
673
|
+
if (!SYSTEM_AI_PURPOSES.includes(value2)) {
|
|
673
674
|
throw new Error(`purpose must be one of: ${SYSTEM_AI_PURPOSES.join(", ")}`);
|
|
674
675
|
}
|
|
675
|
-
return
|
|
676
|
+
return value2;
|
|
676
677
|
}
|
|
677
678
|
|
|
678
679
|
// src/admin-ai-usage.ts
|
|
@@ -694,11 +695,11 @@ async function readAdminAiUsage(request2) {
|
|
|
694
695
|
if (request2.json) request2.stdout.log(JSON.stringify(body, null, 2));
|
|
695
696
|
else printUsage(body, request2.stdout);
|
|
696
697
|
}
|
|
697
|
-
function usageLimit(
|
|
698
|
-
if (!Number.isSafeInteger(
|
|
698
|
+
function usageLimit(value2) {
|
|
699
|
+
if (!Number.isSafeInteger(value2) || value2 < 1 || value2 > 500) {
|
|
699
700
|
throw new Error("usage limit must be an integer from 1 to 500");
|
|
700
701
|
}
|
|
701
|
-
return
|
|
702
|
+
return value2;
|
|
702
703
|
}
|
|
703
704
|
function printUsage(body, out) {
|
|
704
705
|
const aggregates = isRecord2(body) && isRecord2(body.aggregates) && Array.isArray(body.aggregates.byStatus) ? body.aggregates.byStatus.filter(isRecord2) : [];
|
|
@@ -734,15 +735,15 @@ when app/env run actor purpose/role route / policy tokens cost status`);
|
|
|
734
735
|
].join(" "));
|
|
735
736
|
}
|
|
736
737
|
}
|
|
737
|
-
function numeric(
|
|
738
|
-
return typeof
|
|
738
|
+
function numeric(value2) {
|
|
739
|
+
return typeof value2 === "number" && Number.isFinite(value2) ? value2 : 0;
|
|
739
740
|
}
|
|
740
|
-
function formatMicrousd(
|
|
741
|
-
return typeof
|
|
741
|
+
function formatMicrousd(value2) {
|
|
742
|
+
return typeof value2 === "number" && Number.isFinite(value2) ? `$${(value2 / 1e6).toFixed(6)}` : "unpriced";
|
|
742
743
|
}
|
|
743
|
-
function timestamp2(
|
|
744
|
-
if (typeof
|
|
745
|
-
const date = new Date(
|
|
744
|
+
function timestamp2(value2) {
|
|
745
|
+
if (typeof value2 !== "number" || !Number.isFinite(value2)) return String(value2 ?? "");
|
|
746
|
+
const date = new Date(value2);
|
|
746
747
|
return Number.isFinite(date.valueOf()) ? date.toISOString() : "";
|
|
747
748
|
}
|
|
748
749
|
async function responseBody2(res) {
|
|
@@ -759,8 +760,8 @@ function apiError2(action, status, body) {
|
|
|
759
760
|
const message2 = error && typeof error.message === "string" ? error.message : isRecord2(body) && typeof body.message === "string" ? body.message : "request failed";
|
|
760
761
|
return `${action} failed (${status}): ${message2}`;
|
|
761
762
|
}
|
|
762
|
-
function isRecord2(
|
|
763
|
-
return Boolean(
|
|
763
|
+
function isRecord2(value2) {
|
|
764
|
+
return Boolean(value2) && typeof value2 === "object" && !Array.isArray(value2);
|
|
764
765
|
}
|
|
765
766
|
|
|
766
767
|
// src/admin-ai.ts
|
|
@@ -805,11 +806,11 @@ async function adminAi(options) {
|
|
|
805
806
|
}
|
|
806
807
|
if (options.action === "credential-set") {
|
|
807
808
|
const provider = requireProvider(options.credentialProvider);
|
|
808
|
-
const
|
|
809
|
+
const value2 = await secretInputValue(options);
|
|
809
810
|
const res2 = await doFetch(`${platform}/registry/platform/ai-credentials/${encodeURIComponent(provider)}`, {
|
|
810
811
|
method: "PUT",
|
|
811
812
|
headers,
|
|
812
|
-
body: JSON.stringify({ value })
|
|
813
|
+
body: JSON.stringify({ value: value2 })
|
|
813
814
|
});
|
|
814
815
|
const body2 = await responseBody3(res2);
|
|
815
816
|
if (!res2.ok) throw new Error(apiError3(`store ${provider} platform credential`, res2.status, body2));
|
|
@@ -909,11 +910,11 @@ async function adminAi(options) {
|
|
|
909
910
|
const policy = isRecord3(response2) && isRecord3(response2.policy) ? response2.policy : isRecord3(response2) ? response2 : {};
|
|
910
911
|
out.log(options.json ? JSON.stringify({ policy }, null, 2) : `updated ${purpose}: ${String(policy.provider ?? "unchanged")}/${String(policy.model ?? "unchanged")}`);
|
|
911
912
|
}
|
|
912
|
-
function requireProvider(
|
|
913
|
-
if (
|
|
913
|
+
function requireProvider(value2) {
|
|
914
|
+
if (value2 !== "anthropic" && value2 !== "openai" && value2 !== "google") {
|
|
914
915
|
throw new Error("provider must be one of: anthropic, openai, google");
|
|
915
916
|
}
|
|
916
|
-
return
|
|
917
|
+
return value2;
|
|
917
918
|
}
|
|
918
919
|
function policyArray(body) {
|
|
919
920
|
if (isRecord3(body) && Array.isArray(body.policies)) return body.policies.filter(isRecord3);
|
|
@@ -924,7 +925,7 @@ function catalogModels(body) {
|
|
|
924
925
|
if (!isRecord3(body) || !isRecord3(body.catalog) || !Array.isArray(body.catalog.models)) {
|
|
925
926
|
throw new Error("platform returned an invalid System AI model catalog");
|
|
926
927
|
}
|
|
927
|
-
return body.catalog.models.filter((
|
|
928
|
+
return body.catalog.models.filter((value2) => isRecord3(value2) && typeof value2.id === "string" && typeof value2.provider === "string");
|
|
928
929
|
}
|
|
929
930
|
async function responseBody3(res) {
|
|
930
931
|
const text = await res.text();
|
|
@@ -940,8 +941,8 @@ function apiError3(action, status, body) {
|
|
|
940
941
|
const message2 = error && typeof error.message === "string" ? error.message : isRecord3(body) && typeof body.message === "string" ? body.message : "request failed";
|
|
941
942
|
return `${action} failed (${status}): ${message2}`;
|
|
942
943
|
}
|
|
943
|
-
function isRecord3(
|
|
944
|
-
return Boolean(
|
|
944
|
+
function isRecord3(value2) {
|
|
945
|
+
return Boolean(value2) && typeof value2 === "object" && !Array.isArray(value2);
|
|
945
946
|
}
|
|
946
947
|
|
|
947
948
|
// src/argv.ts
|
|
@@ -965,10 +966,10 @@ function parseArgv(argv) {
|
|
|
965
966
|
addOption(options, rawName, arg.slice(eq + 1));
|
|
966
967
|
continue;
|
|
967
968
|
}
|
|
968
|
-
const
|
|
969
|
-
if (
|
|
969
|
+
const value2 = argv[i + 1];
|
|
970
|
+
if (value2 !== void 0 && !value2.startsWith("--")) {
|
|
970
971
|
i++;
|
|
971
|
-
addOption(options, rawName,
|
|
972
|
+
addOption(options, rawName, value2);
|
|
972
973
|
} else {
|
|
973
974
|
addOption(options, rawName, true);
|
|
974
975
|
}
|
|
@@ -984,39 +985,39 @@ function assertArgs(parsed, allowedOptions2, maxPositionals) {
|
|
|
984
985
|
throw new Error(`unexpected argument "${parsed.positionals[maxPositionals]}"; run "odla-ai help"`);
|
|
985
986
|
}
|
|
986
987
|
}
|
|
987
|
-
function requiredString(
|
|
988
|
-
const result = stringOpt(
|
|
988
|
+
function requiredString(value2, name) {
|
|
989
|
+
const result = stringOpt(value2);
|
|
989
990
|
if (!result) throw new Error(`${name} is required`);
|
|
990
991
|
return result;
|
|
991
992
|
}
|
|
992
|
-
function stringOpt(
|
|
993
|
-
if (typeof
|
|
994
|
-
if (Array.isArray(
|
|
993
|
+
function stringOpt(value2) {
|
|
994
|
+
if (typeof value2 === "string") return value2;
|
|
995
|
+
if (Array.isArray(value2)) return value2[value2.length - 1];
|
|
995
996
|
return void 0;
|
|
996
997
|
}
|
|
997
|
-
function listOpt(
|
|
998
|
-
if (
|
|
999
|
-
const values = Array.isArray(
|
|
998
|
+
function listOpt(value2) {
|
|
999
|
+
if (value2 === void 0 || typeof value2 === "boolean") return void 0;
|
|
1000
|
+
const values = Array.isArray(value2) ? value2 : [value2];
|
|
1000
1001
|
return values.flatMap((item) => item.split(",")).map((item) => item.trim()).filter(Boolean);
|
|
1001
1002
|
}
|
|
1002
|
-
function boolOpt(
|
|
1003
|
-
if (typeof
|
|
1004
|
-
if (typeof
|
|
1005
|
-
if (
|
|
1003
|
+
function boolOpt(value2) {
|
|
1004
|
+
if (typeof value2 === "boolean") return value2;
|
|
1005
|
+
if (typeof value2 === "string" && (value2 === "true" || value2 === "false")) return value2 === "true";
|
|
1006
|
+
if (value2 === void 0) return void 0;
|
|
1006
1007
|
throw new Error("boolean option must be true or false");
|
|
1007
1008
|
}
|
|
1008
|
-
function numberOpt(
|
|
1009
|
-
if (
|
|
1010
|
-
const raw = stringOpt(
|
|
1009
|
+
function numberOpt(value2, flag) {
|
|
1010
|
+
if (value2 === void 0) return void 0;
|
|
1011
|
+
const raw = stringOpt(value2);
|
|
1011
1012
|
const parsed = raw === void 0 ? Number.NaN : Number(raw);
|
|
1012
1013
|
if (!Number.isSafeInteger(parsed) || parsed < 1) throw new Error(`${flag} requires a positive integer`);
|
|
1013
1014
|
return parsed;
|
|
1014
1015
|
}
|
|
1015
|
-
function addOption(options, name,
|
|
1016
|
+
function addOption(options, name, value2) {
|
|
1016
1017
|
const current = options[name];
|
|
1017
|
-
if (current === void 0) options[name] =
|
|
1018
|
-
else if (Array.isArray(current)) current.push(String(
|
|
1019
|
-
else options[name] = [String(current), String(
|
|
1018
|
+
if (current === void 0) options[name] = value2;
|
|
1019
|
+
else if (Array.isArray(current)) current.push(String(value2));
|
|
1020
|
+
else options[name] = [String(current), String(value2)];
|
|
1020
1021
|
}
|
|
1021
1022
|
|
|
1022
1023
|
// src/operator-context.ts
|
|
@@ -1028,6 +1029,7 @@ var import_node_process8 = __toESM(require("process"), 1);
|
|
|
1028
1029
|
var import_node_fs4 = require("fs");
|
|
1029
1030
|
var import_node_path4 = require("path");
|
|
1030
1031
|
var import_node_url = require("url");
|
|
1032
|
+
var import_apps = require("@odla-ai/apps");
|
|
1031
1033
|
|
|
1032
1034
|
// src/integration-validation.ts
|
|
1033
1035
|
function validateIntegrations(cfg, path, defaultServices) {
|
|
@@ -1082,17 +1084,17 @@ function validateProbes(integration, at) {
|
|
|
1082
1084
|
}
|
|
1083
1085
|
}
|
|
1084
1086
|
}
|
|
1085
|
-
function isRecord4(
|
|
1086
|
-
return
|
|
1087
|
+
function isRecord4(value2) {
|
|
1088
|
+
return value2 !== null && typeof value2 === "object" && !Array.isArray(value2);
|
|
1087
1089
|
}
|
|
1088
|
-
function safeText(
|
|
1089
|
-
return typeof
|
|
1090
|
+
function safeText(value2, max) {
|
|
1091
|
+
return typeof value2 === "string" && value2.trim().length > 0 && value2.length <= max && !/[\u0000-\u001f\u007f]/.test(value2);
|
|
1090
1092
|
}
|
|
1091
|
-
function safeProbePath(
|
|
1092
|
-
return typeof
|
|
1093
|
+
function safeProbePath(value2) {
|
|
1094
|
+
return typeof value2 === "string" && /^\/[A-Za-z0-9._~!$&'()*+,;=:@%/-]*$/.test(value2);
|
|
1093
1095
|
}
|
|
1094
|
-
function validId(
|
|
1095
|
-
return typeof
|
|
1096
|
+
function validId(value2) {
|
|
1097
|
+
return typeof value2 === "string" && /^[a-z0-9][a-z0-9-]*$/.test(value2);
|
|
1096
1098
|
}
|
|
1097
1099
|
function unique(values) {
|
|
1098
1100
|
return [...new Set(values.filter(Boolean))];
|
|
@@ -1115,6 +1117,7 @@ async function loadProjectConfig(configPath = "odla.config.mjs") {
|
|
|
1115
1117
|
const dbEndpoint = trimSlash(process.env.ODLA_DB_ENDPOINT || raw.dbEndpoint || platformUrl);
|
|
1116
1118
|
const envs = unique2(raw.envs?.length ? raw.envs : DEFAULT_ENVS);
|
|
1117
1119
|
const services = unique2(raw.services?.length ? raw.services : DEFAULT_SERVICES);
|
|
1120
|
+
validateServices(services, resolved);
|
|
1118
1121
|
validateCalendarConfig(raw, envs, services, resolved);
|
|
1119
1122
|
const local = {
|
|
1120
1123
|
tokenFile: (0, import_node_path4.resolve)(rootDir, raw.local?.tokenFile ?? ".odla/dev-token.json"),
|
|
@@ -1133,10 +1136,10 @@ async function loadProjectConfig(configPath = "odla.config.mjs") {
|
|
|
1133
1136
|
local
|
|
1134
1137
|
};
|
|
1135
1138
|
}
|
|
1136
|
-
async function resolveDataExport(cfg,
|
|
1137
|
-
if (
|
|
1138
|
-
if (typeof
|
|
1139
|
-
const target = (0, import_node_path4.isAbsolute)(
|
|
1139
|
+
async function resolveDataExport(cfg, value2, names) {
|
|
1140
|
+
if (value2 === void 0 || value2 === null || value2 === false) return void 0;
|
|
1141
|
+
if (typeof value2 !== "string") return value2;
|
|
1142
|
+
const target = (0, import_node_path4.isAbsolute)(value2) ? value2 : (0, import_node_path4.resolve)(cfg.rootDir, value2);
|
|
1140
1143
|
if (target.endsWith(".json")) {
|
|
1141
1144
|
return JSON.parse((0, import_node_fs4.readFileSync)(target, "utf8"));
|
|
1142
1145
|
}
|
|
@@ -1145,7 +1148,7 @@ async function resolveDataExport(cfg, value, names) {
|
|
|
1145
1148
|
if (mod[name] !== void 0) return mod[name];
|
|
1146
1149
|
}
|
|
1147
1150
|
if (mod.default !== void 0) return mod.default;
|
|
1148
|
-
throw new Error(`${
|
|
1151
|
+
throw new Error(`${value2} did not export ${names.join(", ")} or default`);
|
|
1149
1152
|
}
|
|
1150
1153
|
function buildPlan(cfg) {
|
|
1151
1154
|
const integrationSchema = cfg.integrations?.some((integration) => integration.schema) ?? false;
|
|
@@ -1179,9 +1182,9 @@ function calendarServiceConfig(cfg, env) {
|
|
|
1179
1182
|
};
|
|
1180
1183
|
}
|
|
1181
1184
|
function calendarBookingPageUrl(cfg, env) {
|
|
1182
|
-
const
|
|
1183
|
-
if (
|
|
1184
|
-
return new URL(
|
|
1185
|
+
const value2 = cfg.calendar?.google.bookingPageUrl?.[env];
|
|
1186
|
+
if (value2 === void 0 || value2 === null) return value2;
|
|
1187
|
+
return new URL(value2).toString();
|
|
1185
1188
|
}
|
|
1186
1189
|
function rulesFromSchema(schema) {
|
|
1187
1190
|
const entities = serializedEntities(schema);
|
|
@@ -1195,10 +1198,10 @@ function serializedEntities(schema) {
|
|
|
1195
1198
|
if (!entities || typeof entities !== "object" || Array.isArray(entities)) return [];
|
|
1196
1199
|
return Object.keys(entities);
|
|
1197
1200
|
}
|
|
1198
|
-
function envValue(
|
|
1199
|
-
if (!
|
|
1200
|
-
if (
|
|
1201
|
-
return
|
|
1201
|
+
function envValue(value2) {
|
|
1202
|
+
if (!value2) return void 0;
|
|
1203
|
+
if (value2.startsWith("$")) return process.env[value2.slice(1)];
|
|
1204
|
+
return value2;
|
|
1202
1205
|
}
|
|
1203
1206
|
function validateRawConfig(raw, path) {
|
|
1204
1207
|
if (!raw || typeof raw !== "object") throw new Error(`${path} must export an object`);
|
|
@@ -1254,8 +1257,8 @@ function validateCalendarConfig(cfg, envs, services, path) {
|
|
|
1254
1257
|
if (!isRecord5(google.bookingCalendar)) throw new Error(`${path}: calendar.google.bookingCalendar must map env names to one calendar id`);
|
|
1255
1258
|
const unknownBookingEnv = Object.keys(google.bookingCalendar).find((env) => !envs.includes(env));
|
|
1256
1259
|
if (unknownBookingEnv) throw new Error(`${path}: calendar.google.bookingCalendar.${unknownBookingEnv} is not in config envs`);
|
|
1257
|
-
for (const [env,
|
|
1258
|
-
if (!safeText2(
|
|
1260
|
+
for (const [env, value2] of Object.entries(google.bookingCalendar)) {
|
|
1261
|
+
if (!safeText2(value2, 1024)) {
|
|
1259
1262
|
throw new Error(`${path}: calendar.google.bookingCalendar.${env} must be a calendar id`);
|
|
1260
1263
|
}
|
|
1261
1264
|
}
|
|
@@ -1264,45 +1267,57 @@ function validateCalendarConfig(cfg, envs, services, path) {
|
|
|
1264
1267
|
if (!isRecord5(google.bookingPageUrl)) throw new Error(`${path}: calendar.google.bookingPageUrl must map env names to HTTPS URLs or null`);
|
|
1265
1268
|
const unknownBookingEnv = Object.keys(google.bookingPageUrl).find((env) => !envs.includes(env));
|
|
1266
1269
|
if (unknownBookingEnv) throw new Error(`${path}: calendar.google.bookingPageUrl.${unknownBookingEnv} is not in config envs`);
|
|
1267
|
-
for (const [env,
|
|
1268
|
-
if (
|
|
1270
|
+
for (const [env, value2] of Object.entries(google.bookingPageUrl)) {
|
|
1271
|
+
if (value2 !== null && !safeHttpsUrl(value2)) {
|
|
1269
1272
|
throw new Error(`${path}: calendar.google.bookingPageUrl.${env} must be an HTTPS URL without credentials or fragment`);
|
|
1270
1273
|
}
|
|
1271
1274
|
}
|
|
1272
1275
|
}
|
|
1273
|
-
if (enabled && !services.includes("db")) throw new Error(`${path}: calendar service requires the db service`);
|
|
1274
1276
|
}
|
|
1275
|
-
function
|
|
1276
|
-
const
|
|
1277
|
+
function validateServices(services, path) {
|
|
1278
|
+
for (const service of services) {
|
|
1279
|
+
const definition = (0, import_apps.appServiceDefinition)(service);
|
|
1280
|
+
if (!definition) {
|
|
1281
|
+
throw new Error(`${path}: unknown service "${service}" (known: ${(0, import_apps.appServiceIds)().join(", ")})`);
|
|
1282
|
+
}
|
|
1283
|
+
for (const dependency of definition.requires) {
|
|
1284
|
+
if (!services.includes(dependency)) {
|
|
1285
|
+
throw new Error(`${path}: ${service} service requires the ${dependency} service`);
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
function assertOnly(value2, allowed, label) {
|
|
1291
|
+
const extra = Object.keys(value2).find((key) => !allowed.includes(key));
|
|
1277
1292
|
if (extra) throw new Error(`${label}.${extra} is not supported`);
|
|
1278
1293
|
}
|
|
1279
|
-
function isRecord5(
|
|
1280
|
-
return
|
|
1294
|
+
function isRecord5(value2) {
|
|
1295
|
+
return value2 !== null && typeof value2 === "object" && !Array.isArray(value2);
|
|
1281
1296
|
}
|
|
1282
|
-
function safeText2(
|
|
1283
|
-
return typeof
|
|
1297
|
+
function safeText2(value2, max) {
|
|
1298
|
+
return typeof value2 === "string" && value2.trim().length > 0 && value2.length <= max && !/[\u0000-\u001f\u007f]/.test(value2);
|
|
1284
1299
|
}
|
|
1285
|
-
function safeHttpsUrl(
|
|
1286
|
-
if (typeof
|
|
1300
|
+
function safeHttpsUrl(value2) {
|
|
1301
|
+
if (typeof value2 !== "string" || value2.length > 2048) return false;
|
|
1287
1302
|
try {
|
|
1288
|
-
const url = new URL(
|
|
1303
|
+
const url = new URL(value2);
|
|
1289
1304
|
return url.protocol === "https:" && !url.username && !url.password && !url.hash;
|
|
1290
1305
|
} catch {
|
|
1291
1306
|
return false;
|
|
1292
1307
|
}
|
|
1293
1308
|
}
|
|
1294
|
-
function validId2(
|
|
1295
|
-
return typeof
|
|
1309
|
+
function validId2(value2) {
|
|
1310
|
+
return typeof value2 === "string" && /^[a-z0-9][a-z0-9-]*$/.test(value2);
|
|
1296
1311
|
}
|
|
1297
1312
|
async function loadConfigModule(path) {
|
|
1298
1313
|
if (path.endsWith(".json")) return JSON.parse((0, import_node_fs4.readFileSync)(path, "utf8"));
|
|
1299
1314
|
const mod = await import(`${(0, import_node_url.pathToFileURL)(path).href}?t=${Date.now()}`);
|
|
1300
|
-
const
|
|
1301
|
-
if (typeof
|
|
1302
|
-
return
|
|
1315
|
+
const value2 = mod.default ?? mod.config;
|
|
1316
|
+
if (typeof value2 === "function") return await value2();
|
|
1317
|
+
return value2;
|
|
1303
1318
|
}
|
|
1304
|
-
function trimSlash(
|
|
1305
|
-
return
|
|
1319
|
+
function trimSlash(value2) {
|
|
1320
|
+
return value2.replace(/\/+$/, "");
|
|
1306
1321
|
}
|
|
1307
1322
|
function unique2(values) {
|
|
1308
1323
|
return [...new Set(values.filter(Boolean))];
|
|
@@ -1328,8 +1343,8 @@ function resolveOperatorProfile(parsed) {
|
|
|
1328
1343
|
}
|
|
1329
1344
|
assertOperatorName(name, "context");
|
|
1330
1345
|
const profiles = readOperatorProfiles(file);
|
|
1331
|
-
const
|
|
1332
|
-
if (!
|
|
1346
|
+
const value2 = Object.hasOwn(profiles, name) ? profiles[name] : void 0;
|
|
1347
|
+
if (!value2) {
|
|
1333
1348
|
throw new Error(
|
|
1334
1349
|
`operator context "${name}" not found in ${file}; run "odla-ai context list" or save it first`
|
|
1335
1350
|
);
|
|
@@ -1338,7 +1353,7 @@ function resolveOperatorProfile(parsed) {
|
|
|
1338
1353
|
name,
|
|
1339
1354
|
source: fromFlag ? "flag" : "environment",
|
|
1340
1355
|
file,
|
|
1341
|
-
value
|
|
1356
|
+
value: value2
|
|
1342
1357
|
};
|
|
1343
1358
|
}
|
|
1344
1359
|
function listOperatorProfiles(file = operatorProfileFile()) {
|
|
@@ -1366,8 +1381,8 @@ function operatorCredentialFiles(selection) {
|
|
|
1366
1381
|
scoped: (0, import_node_path5.join)(base, "admin-token.local.json")
|
|
1367
1382
|
};
|
|
1368
1383
|
}
|
|
1369
|
-
function assertOperatorName(
|
|
1370
|
-
if (!/^[a-z0-9][a-z0-9-]*$/.test(
|
|
1384
|
+
function assertOperatorName(value2, label) {
|
|
1385
|
+
if (!/^[a-z0-9][a-z0-9-]*$/.test(value2)) {
|
|
1371
1386
|
throw new Error(
|
|
1372
1387
|
`${label} must contain lowercase letters, numbers, and hyphens`
|
|
1373
1388
|
);
|
|
@@ -1393,22 +1408,22 @@ function readOperatorProfiles(file) {
|
|
|
1393
1408
|
);
|
|
1394
1409
|
}
|
|
1395
1410
|
const profiles = emptyProfiles();
|
|
1396
|
-
for (const [name,
|
|
1411
|
+
for (const [name, value2] of Object.entries(
|
|
1397
1412
|
raw.profiles
|
|
1398
1413
|
)) {
|
|
1399
1414
|
assertOperatorName(name, "context");
|
|
1400
|
-
profiles[name] = validateProfile(
|
|
1415
|
+
profiles[name] = validateProfile(value2, `operator context "${name}"`);
|
|
1401
1416
|
}
|
|
1402
1417
|
return profiles;
|
|
1403
1418
|
}
|
|
1404
1419
|
function emptyProfiles() {
|
|
1405
1420
|
return /* @__PURE__ */ Object.create(null);
|
|
1406
1421
|
}
|
|
1407
|
-
function validateProfile(
|
|
1408
|
-
if (!
|
|
1422
|
+
function validateProfile(value2, label) {
|
|
1423
|
+
if (!value2 || typeof value2 !== "object" || Array.isArray(value2)) {
|
|
1409
1424
|
throw new Error(`${label} has an invalid shape`);
|
|
1410
1425
|
}
|
|
1411
|
-
const unknown = Object.keys(
|
|
1426
|
+
const unknown = Object.keys(value2).filter(
|
|
1412
1427
|
(key) => !["platform", "app", "environment"].includes(key)
|
|
1413
1428
|
);
|
|
1414
1429
|
if (unknown.length > 0) {
|
|
@@ -1416,7 +1431,7 @@ function validateProfile(value, label) {
|
|
|
1416
1431
|
`${label} contains unsupported field(s): ${unknown.sort().join(", ")}; contexts store scope metadata only, never credentials`
|
|
1417
1432
|
);
|
|
1418
1433
|
}
|
|
1419
|
-
const candidate =
|
|
1434
|
+
const candidate = value2;
|
|
1420
1435
|
if (typeof candidate.platform !== "string") {
|
|
1421
1436
|
throw new Error(`${label} needs an absolute platform URL`);
|
|
1422
1437
|
}
|
|
@@ -1431,8 +1446,8 @@ function validateProfile(value, label) {
|
|
|
1431
1446
|
...environment2 ? { environment: environment2 } : {}
|
|
1432
1447
|
};
|
|
1433
1448
|
}
|
|
1434
|
-
function clean(
|
|
1435
|
-
const normalized =
|
|
1449
|
+
function clean(value2) {
|
|
1450
|
+
const normalized = value2?.trim();
|
|
1436
1451
|
return normalized || void 0;
|
|
1437
1452
|
}
|
|
1438
1453
|
|
|
@@ -1525,8 +1540,8 @@ async function resolveOperatorContext(parsed, options = {}) {
|
|
|
1525
1540
|
}
|
|
1526
1541
|
};
|
|
1527
1542
|
}
|
|
1528
|
-
function clean2(
|
|
1529
|
-
const normalized =
|
|
1543
|
+
function clean2(value2) {
|
|
1544
|
+
const normalized = value2?.trim();
|
|
1530
1545
|
return normalized || void 0;
|
|
1531
1546
|
}
|
|
1532
1547
|
|
|
@@ -1594,7 +1609,7 @@ async function adminCommand(parsed, deps = {}) {
|
|
|
1594
1609
|
}
|
|
1595
1610
|
|
|
1596
1611
|
// src/tenant.ts
|
|
1597
|
-
var
|
|
1612
|
+
var import_apps2 = require("@odla-ai/apps");
|
|
1598
1613
|
function resolveEnv(cfg, requested) {
|
|
1599
1614
|
const env = requested ?? (cfg.envs.includes("dev") ? "dev" : cfg.envs[0]);
|
|
1600
1615
|
if (!env || !cfg.envs.includes(env)) {
|
|
@@ -1604,7 +1619,7 @@ function resolveEnv(cfg, requested) {
|
|
|
1604
1619
|
}
|
|
1605
1620
|
function resolveTenant(cfg, requested) {
|
|
1606
1621
|
const env = resolveEnv(cfg, requested);
|
|
1607
|
-
return { env, tenant: (0,
|
|
1622
|
+
return { env, tenant: (0, import_apps2.tenantIdFor)(cfg.app.id, env) };
|
|
1608
1623
|
}
|
|
1609
1624
|
function bothTenants(cfg) {
|
|
1610
1625
|
for (const env of ["dev", "prod"]) {
|
|
@@ -1614,7 +1629,7 @@ function bothTenants(cfg) {
|
|
|
1614
1629
|
);
|
|
1615
1630
|
}
|
|
1616
1631
|
}
|
|
1617
|
-
return { sandbox: (0,
|
|
1632
|
+
return { sandbox: (0, import_apps2.tenantIdFor)(cfg.app.id, "dev"), live: (0, import_apps2.tenantIdFor)(cfg.app.id, "prod") };
|
|
1618
1633
|
}
|
|
1619
1634
|
|
|
1620
1635
|
// src/agent-command.ts
|
|
@@ -2237,44 +2252,44 @@ var REPLACEMENTS = [
|
|
|
2237
2252
|
[/\b(ghp|gho|github_pat)_[A-Za-z0-9_]+/g, "$1_[redacted]"],
|
|
2238
2253
|
[/\bAKIA[A-Z0-9]{12,}/g, "AKIA[redacted]"]
|
|
2239
2254
|
];
|
|
2240
|
-
function redactSecrets(
|
|
2241
|
-
let result =
|
|
2255
|
+
function redactSecrets(value2) {
|
|
2256
|
+
let result = value2;
|
|
2242
2257
|
for (const [pattern, replacement] of REPLACEMENTS) result = result.replace(pattern, replacement);
|
|
2243
2258
|
return result;
|
|
2244
2259
|
}
|
|
2245
2260
|
function redactingOutput(output) {
|
|
2246
|
-
const redactArgs = (args) => args.map((
|
|
2261
|
+
const redactArgs = (args) => args.map((value2) => redactOutputValue(value2, /* @__PURE__ */ new WeakMap()));
|
|
2247
2262
|
return {
|
|
2248
2263
|
log: (...args) => output.log(...redactArgs(args)),
|
|
2249
2264
|
error: (...args) => output.error(...redactArgs(args))
|
|
2250
2265
|
};
|
|
2251
2266
|
}
|
|
2252
|
-
function redactOutputValue(
|
|
2253
|
-
if (typeof
|
|
2254
|
-
if (
|
|
2255
|
-
const redacted = new Error(redactSecrets(
|
|
2256
|
-
redacted.name =
|
|
2257
|
-
if (
|
|
2267
|
+
function redactOutputValue(value2, seen) {
|
|
2268
|
+
if (typeof value2 === "string") return redactSecrets(value2);
|
|
2269
|
+
if (value2 instanceof Error) {
|
|
2270
|
+
const redacted = new Error(redactSecrets(value2.message));
|
|
2271
|
+
redacted.name = value2.name;
|
|
2272
|
+
if (value2.stack) redacted.stack = redactSecrets(value2.stack);
|
|
2258
2273
|
return redacted;
|
|
2259
2274
|
}
|
|
2260
|
-
if (!
|
|
2261
|
-
const prior = seen.get(
|
|
2275
|
+
if (!value2 || typeof value2 !== "object") return value2;
|
|
2276
|
+
const prior = seen.get(value2);
|
|
2262
2277
|
if (prior) return prior;
|
|
2263
|
-
if (Array.isArray(
|
|
2278
|
+
if (Array.isArray(value2)) {
|
|
2264
2279
|
const next2 = [];
|
|
2265
|
-
seen.set(
|
|
2266
|
-
for (const item of
|
|
2280
|
+
seen.set(value2, next2);
|
|
2281
|
+
for (const item of value2) next2.push(redactOutputValue(item, seen));
|
|
2267
2282
|
return next2;
|
|
2268
2283
|
}
|
|
2269
|
-
const prototype = Object.getPrototypeOf(
|
|
2270
|
-
if (prototype !== Object.prototype && prototype !== null) return
|
|
2284
|
+
const prototype = Object.getPrototypeOf(value2);
|
|
2285
|
+
if (prototype !== Object.prototype && prototype !== null) return value2;
|
|
2271
2286
|
const next = {};
|
|
2272
|
-
seen.set(
|
|
2273
|
-
for (const [key, item] of Object.entries(
|
|
2287
|
+
seen.set(value2, next);
|
|
2288
|
+
for (const [key, item] of Object.entries(value2)) next[key] = redactOutputValue(item, seen);
|
|
2274
2289
|
return next;
|
|
2275
2290
|
}
|
|
2276
|
-
function looksSecret(
|
|
2277
|
-
return redactSecrets(
|
|
2291
|
+
function looksSecret(value2) {
|
|
2292
|
+
return redactSecrets(value2) !== value2 || value2.includes("-----BEGIN");
|
|
2278
2293
|
}
|
|
2279
2294
|
|
|
2280
2295
|
// src/calendar-http.ts
|
|
@@ -2291,9 +2306,9 @@ async function readCalendarStatus(ctx) {
|
|
|
2291
2306
|
}
|
|
2292
2307
|
async function discoverGoogleCalendars(ctx) {
|
|
2293
2308
|
const raw = await calendarJson(ctx, "/calendars", {});
|
|
2294
|
-
const
|
|
2295
|
-
if (!
|
|
2296
|
-
return
|
|
2309
|
+
const value2 = record(raw);
|
|
2310
|
+
if (!value2 || !Array.isArray(value2.calendars)) throw new Error("calendar discovery returned an invalid response");
|
|
2311
|
+
return value2.calendars.map((item, index) => {
|
|
2297
2312
|
const calendar = record(item);
|
|
2298
2313
|
const id = textField(calendar?.id, 1024);
|
|
2299
2314
|
if (!calendar || !id) throw new Error(`calendar discovery returned an invalid calendar at index ${index}`);
|
|
@@ -2315,10 +2330,10 @@ async function applyCalendarSettings(ctx, bookingPageUrl) {
|
|
|
2315
2330
|
}
|
|
2316
2331
|
async function startCalendarConnection(ctx) {
|
|
2317
2332
|
const raw = await calendarJson(ctx, "/google/connect", { method: "POST", body: "{}" });
|
|
2318
|
-
const
|
|
2319
|
-
const attemptId = textField(
|
|
2320
|
-
const consentUrl = textField(
|
|
2321
|
-
const expiresAt = timestamp3(
|
|
2333
|
+
const value2 = wrapped(raw, "attempt");
|
|
2334
|
+
const attemptId = textField(value2.attemptId, 180);
|
|
2335
|
+
const consentUrl = textField(value2.consentUrl, 4096);
|
|
2336
|
+
const expiresAt = timestamp3(value2.expiresAt);
|
|
2322
2337
|
if (!attemptId || !consentUrl || expiresAt === void 0) throw new Error("calendar connect returned an invalid attempt");
|
|
2323
2338
|
return { attemptId, consentUrl, expiresAt };
|
|
2324
2339
|
}
|
|
@@ -2336,42 +2351,42 @@ async function requestCalendarDisconnect(ctx) {
|
|
|
2336
2351
|
}
|
|
2337
2352
|
function parseCalendarStatus(raw, env) {
|
|
2338
2353
|
const outer = wrapped(raw, "calendar");
|
|
2339
|
-
const
|
|
2340
|
-
const connection = record(
|
|
2341
|
-
const config = record(
|
|
2354
|
+
const value2 = record(outer.attempt) ?? record(outer.status) ?? outer;
|
|
2355
|
+
const connection = record(value2.connection) ?? {};
|
|
2356
|
+
const config = record(value2.config) ?? record(outer.config) ?? {};
|
|
2342
2357
|
const googleConfig = record(config.google) ?? config;
|
|
2343
|
-
const stateValue = calendarState(
|
|
2358
|
+
const stateValue = calendarState(value2.status ?? value2.state ?? connection.status ?? connection.state);
|
|
2344
2359
|
if (!stateValue) {
|
|
2345
2360
|
throw new Error("calendar status returned an invalid connection state");
|
|
2346
2361
|
}
|
|
2347
|
-
const providerValue =
|
|
2362
|
+
const providerValue = value2.provider ?? connection.provider ?? config.provider ?? (config.google ? "google" : void 0);
|
|
2348
2363
|
if (providerValue !== void 0 && providerValue !== null && providerValue !== "google") {
|
|
2349
2364
|
throw new Error("calendar status returned an unsupported provider");
|
|
2350
2365
|
}
|
|
2351
|
-
const accessValue =
|
|
2366
|
+
const accessValue = value2.access ?? connection.access ?? config.access ?? googleConfig.access;
|
|
2352
2367
|
if (accessValue !== void 0 && accessValue !== "book" && accessValue !== "read") {
|
|
2353
2368
|
throw new Error("calendar status returned unsupported access");
|
|
2354
2369
|
}
|
|
2355
|
-
const errorValue = record(
|
|
2356
|
-
const errorCode = textField(
|
|
2357
|
-
const bookingPageValue = Object.hasOwn(
|
|
2358
|
-
const connected = typeof (
|
|
2359
|
-
const bookingCalendarId = textField(
|
|
2370
|
+
const errorValue = record(value2.error) ?? record(connection.error);
|
|
2371
|
+
const errorCode = textField(value2.lastErrorCode, 128);
|
|
2372
|
+
const bookingPageValue = Object.hasOwn(value2, "bookingPageUrl") ? value2.bookingPageUrl : Object.hasOwn(config, "bookingPageUrl") ? config.bookingPageUrl : googleConfig.bookingPageUrl;
|
|
2373
|
+
const connected = typeof (value2.connected ?? connection.connected) === "boolean" ? Boolean(value2.connected ?? connection.connected) : ["healthy", "degraded"].includes(stateValue);
|
|
2374
|
+
const bookingCalendarId = textField(value2.bookingCalendarId ?? config.bookingCalendarId, 1024);
|
|
2360
2375
|
return {
|
|
2361
2376
|
env,
|
|
2362
|
-
enabled: typeof
|
|
2377
|
+
enabled: typeof value2.enabled === "boolean" ? value2.enabled : true,
|
|
2363
2378
|
connected,
|
|
2364
|
-
writable: typeof
|
|
2379
|
+
writable: typeof value2.writable === "boolean" ? value2.writable : stateValue === "healthy",
|
|
2365
2380
|
provider: providerValue === "google" ? "google" : null,
|
|
2366
2381
|
status: stateValue,
|
|
2367
2382
|
...accessValue !== void 0 ? { access: "book" } : {},
|
|
2368
2383
|
...bookingCalendarId ? { bookingCalendarId } : {},
|
|
2369
2384
|
calendars: calendarIds(
|
|
2370
|
-
|
|
2385
|
+
value2.availabilityCalendars ?? config.availabilityCalendars ?? value2.configuredCalendars ?? value2.calendars ?? config.calendars ?? googleConfig.calendars
|
|
2371
2386
|
),
|
|
2372
2387
|
...optionalNullableUrl("bookingPageUrl", bookingPageValue),
|
|
2373
|
-
grantedScopes: stringList(
|
|
2374
|
-
...optionalText("attemptId",
|
|
2388
|
+
grantedScopes: stringList(value2.grantedScopes ?? connection.grantedScopes ?? connection.scopes),
|
|
2389
|
+
...optionalText("attemptId", value2.attemptId ?? connection.attemptId, 180),
|
|
2375
2390
|
...errorValue || errorCode ? { error: {
|
|
2376
2391
|
...textField(errorValue?.code, 128) ? { code: textField(errorValue?.code, 128) } : {},
|
|
2377
2392
|
...textField(errorValue?.message, 500) ? { message: textField(errorValue?.message, 500) } : {},
|
|
@@ -2379,9 +2394,9 @@ function parseCalendarStatus(raw, env) {
|
|
|
2379
2394
|
} } : {}
|
|
2380
2395
|
};
|
|
2381
2396
|
}
|
|
2382
|
-
function calendarState(
|
|
2383
|
-
if (typeof
|
|
2384
|
-
if (CALENDAR_STATES.includes(
|
|
2397
|
+
function calendarState(value2) {
|
|
2398
|
+
if (typeof value2 !== "string") return null;
|
|
2399
|
+
if (CALENDAR_STATES.includes(value2)) return value2;
|
|
2385
2400
|
const legacy = {
|
|
2386
2401
|
disabled: "not_connected",
|
|
2387
2402
|
disconnected: "disconnected",
|
|
@@ -2392,7 +2407,7 @@ function calendarState(value) {
|
|
|
2392
2407
|
ready: "healthy",
|
|
2393
2408
|
error: "failed"
|
|
2394
2409
|
};
|
|
2395
|
-
return legacy[
|
|
2410
|
+
return legacy[value2] ?? null;
|
|
2396
2411
|
}
|
|
2397
2412
|
async function calendarJson(ctx, suffix, init) {
|
|
2398
2413
|
const platform = platformAudience(ctx.platform);
|
|
@@ -2426,50 +2441,50 @@ function wrapped(raw, key) {
|
|
|
2426
2441
|
if (!outer) throw new Error("calendar returned an invalid response");
|
|
2427
2442
|
return record(outer[key]) ?? outer;
|
|
2428
2443
|
}
|
|
2429
|
-
function record(
|
|
2430
|
-
return
|
|
2444
|
+
function record(value2) {
|
|
2445
|
+
return value2 !== null && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
|
|
2431
2446
|
}
|
|
2432
|
-
function textField(
|
|
2433
|
-
return typeof
|
|
2447
|
+
function textField(value2, max) {
|
|
2448
|
+
return typeof value2 === "string" && value2.length > 0 && value2.length <= max && !/[\u0000-\u001f\u007f]/.test(value2) ? value2 : void 0;
|
|
2434
2449
|
}
|
|
2435
|
-
function stringList(
|
|
2436
|
-
return Array.isArray(
|
|
2450
|
+
function stringList(value2) {
|
|
2451
|
+
return Array.isArray(value2) ? [...new Set(value2.filter((item) => !!textField(item, 4096)))] : [];
|
|
2437
2452
|
}
|
|
2438
|
-
function calendarIds(
|
|
2439
|
-
if (!Array.isArray(
|
|
2440
|
-
return [...new Set(
|
|
2453
|
+
function calendarIds(value2) {
|
|
2454
|
+
if (!Array.isArray(value2)) return [];
|
|
2455
|
+
return [...new Set(value2.flatMap((item) => {
|
|
2441
2456
|
if (typeof item === "string") return textField(item, 4096) ? [item] : [];
|
|
2442
2457
|
const calendar = record(item);
|
|
2443
2458
|
const id = textField(calendar?.id, 4096);
|
|
2444
2459
|
return id && calendar?.selected !== false ? [id] : [];
|
|
2445
2460
|
}))];
|
|
2446
2461
|
}
|
|
2447
|
-
function timestamp3(
|
|
2448
|
-
if (typeof
|
|
2449
|
-
if (typeof
|
|
2450
|
-
const parsed = Date.parse(
|
|
2462
|
+
function timestamp3(value2) {
|
|
2463
|
+
if (typeof value2 === "number" && Number.isFinite(value2) && value2 >= 0) return value2;
|
|
2464
|
+
if (typeof value2 === "string") {
|
|
2465
|
+
const parsed = Date.parse(value2);
|
|
2451
2466
|
if (Number.isFinite(parsed)) return parsed;
|
|
2452
2467
|
}
|
|
2453
2468
|
return void 0;
|
|
2454
2469
|
}
|
|
2455
|
-
function optionalText(key,
|
|
2456
|
-
const parsed = textField(
|
|
2470
|
+
function optionalText(key, value2, max) {
|
|
2471
|
+
const parsed = textField(value2, max);
|
|
2457
2472
|
return parsed ? { [key]: parsed } : {};
|
|
2458
2473
|
}
|
|
2459
|
-
function optionalNullableUrl(key,
|
|
2460
|
-
if (
|
|
2461
|
-
const parsed = textField(
|
|
2474
|
+
function optionalNullableUrl(key, value2) {
|
|
2475
|
+
if (value2 === null) return { [key]: null };
|
|
2476
|
+
const parsed = textField(value2, 4096);
|
|
2462
2477
|
return parsed ? { [key]: parsed } : {};
|
|
2463
2478
|
}
|
|
2464
|
-
function identifier(
|
|
2465
|
-
if (typeof
|
|
2466
|
-
return
|
|
2479
|
+
function identifier(value2, name) {
|
|
2480
|
+
if (typeof value2 !== "string" || !/^[A-Za-z0-9][A-Za-z0-9._:-]{0,179}$/.test(value2)) throw new Error(`${name} is invalid`);
|
|
2481
|
+
return value2;
|
|
2467
2482
|
}
|
|
2468
|
-
function credential(
|
|
2469
|
-
if (typeof
|
|
2483
|
+
function credential(value2) {
|
|
2484
|
+
if (typeof value2 !== "string" || value2.length < 8 || value2.length > 8192 || /\s|[\u0000-\u001f\u007f]/.test(value2)) {
|
|
2470
2485
|
throw new Error("calendar requires an odla developer token");
|
|
2471
2486
|
}
|
|
2472
|
-
return
|
|
2487
|
+
return value2;
|
|
2473
2488
|
}
|
|
2474
2489
|
|
|
2475
2490
|
// src/calendar-poll.ts
|
|
@@ -2630,11 +2645,11 @@ async function connectWithContext(ctx, options) {
|
|
|
2630
2645
|
}
|
|
2631
2646
|
throw new Error('Google Calendar consent timed out; run "odla-ai calendar status" and retry connect');
|
|
2632
2647
|
}
|
|
2633
|
-
function trustedCalendarConsentUrl(platform,
|
|
2648
|
+
function trustedCalendarConsentUrl(platform, value2) {
|
|
2634
2649
|
const origin = platformAudience(platform);
|
|
2635
2650
|
let url;
|
|
2636
2651
|
try {
|
|
2637
|
-
url =
|
|
2652
|
+
url = value2.startsWith("/") ? new URL(value2, origin) : new URL(value2);
|
|
2638
2653
|
} catch {
|
|
2639
2654
|
throw new Error("odla.ai returned an invalid calendar consent URL");
|
|
2640
2655
|
}
|
|
@@ -2645,9 +2660,9 @@ function trustedCalendarConsentUrl(platform, value) {
|
|
|
2645
2660
|
}
|
|
2646
2661
|
return url.toString();
|
|
2647
2662
|
}
|
|
2648
|
-
function pollTimeout(
|
|
2649
|
-
if (!Number.isSafeInteger(
|
|
2650
|
-
return
|
|
2663
|
+
function pollTimeout(value2 = 10 * 6e4) {
|
|
2664
|
+
if (!Number.isSafeInteger(value2) || value2 < 1e3 || value2 > 60 * 6e4) throw new Error("calendar poll timeout must be 1000-3600000ms");
|
|
2665
|
+
return value2;
|
|
2651
2666
|
}
|
|
2652
2667
|
function productionConsent(env, yes, action) {
|
|
2653
2668
|
if ((env === "prod" || env === "production") && !yes) throw new Error(`refusing to ${action} for "${env}" without --yes`);
|
|
@@ -2679,6 +2694,7 @@ var CAPABILITIES = {
|
|
|
2679
2694
|
"validate integration contracts offline and smoke-test a provisioned db environment plus anonymous capability routes",
|
|
2680
2695
|
"save and explicitly select non-secret named operator contexts with isolated credential caches; resolve and explain platform, app, environment, and credential provenance without authenticating; then run PM, Discussions, o11y, runbook, and identity operations outside a project checkout",
|
|
2681
2696
|
"read one versioned o11y status envelope spanning application RED, exact Worker versions and Cloudflare colos observed in traffic, current live-sync freshness/load, the protected commit-to-visible canary, collector ingest/scheduler trust, provider-owned runtime metrics, account-scoped Durable Object, D1, and R2 evidence under odla-db, and a bounded machine verdict",
|
|
2697
|
+
"read one canonical platform fleet snapshot over private service bindings, including release identities, probe latency, Cloudflare load/runtime freshness, explicit unknowns, and stable next actions through a read-only capability",
|
|
2682
2698
|
"inspect durable agent wakeups as a versioned JSON envelope and explicitly requeue one dead-lettered job with a scoped environment credential",
|
|
2683
2699
|
"run app-attributed hosted security discovery and independent validation without provider keys",
|
|
2684
2700
|
"connect/revoke source-read-only GitHub sources and drive commit-pinned hosted security jobs without PATs or provider keys",
|
|
@@ -2862,8 +2878,8 @@ function wranglerWarnings(rootDir) {
|
|
|
2862
2878
|
}
|
|
2863
2879
|
const vars = block.vars;
|
|
2864
2880
|
if (vars && typeof vars === "object") {
|
|
2865
|
-
for (const [name,
|
|
2866
|
-
if (name === "ODLA_API_KEY" || name === "ODLA_O11Y_TOKEN" || typeof
|
|
2881
|
+
for (const [name, value2] of Object.entries(vars)) {
|
|
2882
|
+
if (name === "ODLA_API_KEY" || name === "ODLA_O11Y_TOKEN" || typeof value2 === "string" && looksSecret(value2)) {
|
|
2867
2883
|
warnings.push(`wrangler ${label}vars.${name} looks like a secret \u2014 use "odla-ai secrets push" / wrangler secret put, never vars`);
|
|
2868
2884
|
}
|
|
2869
2885
|
}
|
|
@@ -3031,27 +3047,27 @@ function isUniqueAttr(schema, ns, attr) {
|
|
|
3031
3047
|
const definition = entity.attrs[attr];
|
|
3032
3048
|
return isRecord6(definition) && definition.unique === true;
|
|
3033
3049
|
}
|
|
3034
|
-
function normalizeSchema(
|
|
3035
|
-
if (
|
|
3036
|
-
if (!isRecord6(
|
|
3050
|
+
function normalizeSchema(value2) {
|
|
3051
|
+
if (value2 === void 0 || value2 === null) return { entities: {}, links: {} };
|
|
3052
|
+
if (!isRecord6(value2) || !isRecord6(value2.entities)) {
|
|
3037
3053
|
throw new Error("db schema must be a serialized schema object with an entities map");
|
|
3038
3054
|
}
|
|
3039
|
-
if (
|
|
3055
|
+
if (value2.links !== void 0 && !isRecord6(value2.links)) throw new Error("db schema links must be an object");
|
|
3040
3056
|
return {
|
|
3041
|
-
entities: { ...
|
|
3042
|
-
links: { ...
|
|
3057
|
+
entities: { ...value2.entities },
|
|
3058
|
+
links: { ...value2.links ?? {} }
|
|
3043
3059
|
};
|
|
3044
3060
|
}
|
|
3045
3061
|
function mergeMap(target, fragment, label) {
|
|
3046
|
-
for (const [name,
|
|
3047
|
-
if (Object.hasOwn(target, name) && !(0, import_node_util.isDeepStrictEqual)(target[name],
|
|
3062
|
+
for (const [name, value2] of Object.entries(fragment)) {
|
|
3063
|
+
if (Object.hasOwn(target, name) && !(0, import_node_util.isDeepStrictEqual)(target[name], value2)) {
|
|
3048
3064
|
throw new Error(`${label} "${name}" conflicts with an existing definition`);
|
|
3049
3065
|
}
|
|
3050
|
-
target[name] =
|
|
3066
|
+
target[name] = value2;
|
|
3051
3067
|
}
|
|
3052
3068
|
}
|
|
3053
|
-
function isRecord6(
|
|
3054
|
-
return
|
|
3069
|
+
function isRecord6(value2) {
|
|
3070
|
+
return value2 !== null && typeof value2 === "object" && !Array.isArray(value2);
|
|
3055
3071
|
}
|
|
3056
3072
|
|
|
3057
3073
|
// src/doctor.ts
|
|
@@ -3092,9 +3108,9 @@ async function doctor(options) {
|
|
|
3092
3108
|
warnings.push(...integrationWarnings(database.integrations, schema, rules));
|
|
3093
3109
|
if (cfg.services.includes("ai") && !cfg.ai?.provider) warnings.push("ai service is enabled but ai.provider is not set");
|
|
3094
3110
|
if (cfg.auth?.clerk) {
|
|
3095
|
-
for (const [env,
|
|
3096
|
-
if (typeof
|
|
3097
|
-
warnings.push(`auth.clerk.${env} references unset env var ${
|
|
3111
|
+
for (const [env, value2] of Object.entries(cfg.auth.clerk)) {
|
|
3112
|
+
if (typeof value2 === "string" && value2.startsWith("$") && !process.env[value2.slice(1)]) {
|
|
3113
|
+
warnings.push(`auth.clerk.${env} references unset env var ${value2}`);
|
|
3098
3114
|
}
|
|
3099
3115
|
}
|
|
3100
3116
|
}
|
|
@@ -3136,10 +3152,10 @@ function harnessList(parsed) {
|
|
|
3136
3152
|
];
|
|
3137
3153
|
return selected.length ? selected : ["all"];
|
|
3138
3154
|
}
|
|
3139
|
-
function harnessOption(
|
|
3140
|
-
if (
|
|
3141
|
-
if (typeof
|
|
3142
|
-
const raw = Array.isArray(
|
|
3155
|
+
function harnessOption(value2, flag) {
|
|
3156
|
+
if (value2 === void 0) return [];
|
|
3157
|
+
if (typeof value2 === "boolean") throw new Error(`${flag} requires a harness name`);
|
|
3158
|
+
const raw = Array.isArray(value2) ? value2 : [value2];
|
|
3143
3159
|
const parts = raw.flatMap((item) => item.split(","));
|
|
3144
3160
|
if (parts.some((item) => !item.trim())) {
|
|
3145
3161
|
throw new Error(`${flag} requires a harness name`);
|
|
@@ -3150,6 +3166,7 @@ function harnessOption(value, flag) {
|
|
|
3150
3166
|
// src/init.ts
|
|
3151
3167
|
var import_node_fs11 = require("fs");
|
|
3152
3168
|
var import_node_path9 = require("path");
|
|
3169
|
+
var import_apps3 = require("@odla-ai/apps");
|
|
3153
3170
|
function initProject(options) {
|
|
3154
3171
|
const out = options.stdout ?? console;
|
|
3155
3172
|
const rootDir = (0, import_node_path9.resolve)(options.rootDir ?? process.cwd());
|
|
@@ -3162,7 +3179,13 @@ function initProject(options) {
|
|
|
3162
3179
|
}
|
|
3163
3180
|
const envs = options.envs?.length ? options.envs : ["dev"];
|
|
3164
3181
|
const services = options.services?.length ? options.services : ["db", "ai"];
|
|
3165
|
-
|
|
3182
|
+
for (const service of services) {
|
|
3183
|
+
const definition = (0, import_apps3.appServiceDefinition)(service);
|
|
3184
|
+
if (!definition) throw new Error(`--services contains unknown service "${service}" (known: ${(0, import_apps3.appServiceIds)().join(", ")})`);
|
|
3185
|
+
for (const dependency of definition.requires) {
|
|
3186
|
+
if (!services.includes(dependency)) throw new Error(`--services ${service} requires ${dependency}`);
|
|
3187
|
+
}
|
|
3188
|
+
}
|
|
3166
3189
|
const aiProvider = options.aiProvider ?? "anthropic";
|
|
3167
3190
|
(0, import_node_fs11.mkdirSync)((0, import_node_path9.dirname)(configPath), { recursive: true });
|
|
3168
3191
|
(0, import_node_fs11.mkdirSync)((0, import_node_path9.resolve)(rootDir, "src/odla"), { recursive: true });
|
|
@@ -3352,7 +3375,7 @@ function assertWranglerConfig(cfg) {
|
|
|
3352
3375
|
|
|
3353
3376
|
// src/secrets-set.ts
|
|
3354
3377
|
var import_ai = require("@odla-ai/ai");
|
|
3355
|
-
var
|
|
3378
|
+
var import_apps4 = require("@odla-ai/apps");
|
|
3356
3379
|
var PROD_ENV_NAMES2 = /* @__PURE__ */ new Set(["prod", "production"]);
|
|
3357
3380
|
async function secretsSet(options) {
|
|
3358
3381
|
const name = (options.name ?? "").trim();
|
|
@@ -3360,38 +3383,38 @@ async function secretsSet(options) {
|
|
|
3360
3383
|
if (name.startsWith("$")) {
|
|
3361
3384
|
throw new Error('"$"-prefixed vault names are platform-reserved; for the Clerk secret key use "odla-ai secrets set-clerk-key"');
|
|
3362
3385
|
}
|
|
3363
|
-
const { cfg, tenantId, value, doFetch, out } = await resolveVaultWrite(options);
|
|
3386
|
+
const { cfg, tenantId, value: value2, doFetch, out } = await resolveVaultWrite(options);
|
|
3364
3387
|
const token = await getDeveloperToken(cfg, options, doFetch, out);
|
|
3365
3388
|
try {
|
|
3366
|
-
await (0, import_ai.putSecret)({ endpoint: cfg.dbEndpoint, token, fetch: doFetch }, tenantId, name,
|
|
3389
|
+
await (0, import_ai.putSecret)({ endpoint: cfg.dbEndpoint, token, fetch: doFetch }, tenantId, name, value2);
|
|
3367
3390
|
} catch (err) {
|
|
3368
|
-
throw new Error(scrubValue(err instanceof Error ? err.message : String(err),
|
|
3391
|
+
throw new Error(scrubValue(err instanceof Error ? err.message : String(err), value2));
|
|
3369
3392
|
}
|
|
3370
3393
|
out.log(`${name} stored in the ${tenantId} vault (write-only; the value was never echoed and cannot be read back here)`);
|
|
3371
3394
|
}
|
|
3372
3395
|
async function secretsSetClerkKey(options) {
|
|
3373
|
-
const { cfg, tenantId, value, doFetch, out } = await resolveVaultWrite(options);
|
|
3374
|
-
if (!
|
|
3375
|
-
if (
|
|
3396
|
+
const { cfg, tenantId, value: value2, doFetch, out } = await resolveVaultWrite(options);
|
|
3397
|
+
if (!value2.startsWith("sk_")) throw new Error("the Clerk secret key must start with sk_ (sk_test_\u2026 or sk_live_\u2026)");
|
|
3398
|
+
if (value2.startsWith("sk_test_") && PROD_ENV_NAMES2.has(options.env)) {
|
|
3376
3399
|
throw new Error(`refusing to store an sk_test_ Clerk key for "${options.env}" \u2014 use the production instance's sk_live_ key`);
|
|
3377
3400
|
}
|
|
3378
|
-
if (
|
|
3401
|
+
if (value2.startsWith("sk_live_") && !PROD_ENV_NAMES2.has(options.env) && !options.yes) {
|
|
3379
3402
|
throw new Error(`refusing to store an sk_live_ Clerk key for "${options.env}" without --yes (live users would sync into a non-prod tenant)`);
|
|
3380
3403
|
}
|
|
3381
3404
|
const token = await getDeveloperToken(cfg, options, doFetch, out);
|
|
3382
3405
|
const res = await doFetch(`${cfg.dbEndpoint}/admin/apps/${encodeURIComponent(tenantId)}/clerk-secret`, {
|
|
3383
3406
|
method: "POST",
|
|
3384
3407
|
headers: { authorization: `Bearer ${token}`, "content-type": "application/json" },
|
|
3385
|
-
body: JSON.stringify({ value })
|
|
3408
|
+
body: JSON.stringify({ value: value2 })
|
|
3386
3409
|
});
|
|
3387
3410
|
if (!res.ok) {
|
|
3388
|
-
const text = scrubValue((await res.text().catch(() => "")).slice(0, 300),
|
|
3411
|
+
const text = scrubValue((await res.text().catch(() => "")).slice(0, 300), value2);
|
|
3389
3412
|
throw new Error(`store Clerk secret key failed (${res.status}): ${text || "request failed"}`);
|
|
3390
3413
|
}
|
|
3391
3414
|
out.log(`Clerk secret key stored for ${tenantId} ($clerk_secret, reserved + write-only; the value was never echoed)`);
|
|
3392
3415
|
}
|
|
3393
|
-
function scrubValue(text,
|
|
3394
|
-
return redactSecrets(text).split(
|
|
3416
|
+
function scrubValue(text, value2) {
|
|
3417
|
+
return redactSecrets(text).split(value2).join("[value redacted]");
|
|
3395
3418
|
}
|
|
3396
3419
|
async function resolveVaultWrite(options) {
|
|
3397
3420
|
const out = options.stdout ?? console;
|
|
@@ -3403,8 +3426,8 @@ async function resolveVaultWrite(options) {
|
|
|
3403
3426
|
if (PROD_ENV_NAMES2.has(options.env) && !options.yes) {
|
|
3404
3427
|
throw new Error(`refusing to store a secret for "${options.env}" without --yes`);
|
|
3405
3428
|
}
|
|
3406
|
-
const
|
|
3407
|
-
return { cfg, tenantId: (0,
|
|
3429
|
+
const value2 = await secretInputValue(options, "secret");
|
|
3430
|
+
return { cfg, tenantId: (0, import_apps4.tenantIdFor)(cfg.app.id, options.env), value: value2, doFetch, out };
|
|
3408
3431
|
}
|
|
3409
3432
|
|
|
3410
3433
|
// src/skill.ts
|
|
@@ -3934,24 +3957,24 @@ var CONTROL = /[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/;
|
|
|
3934
3957
|
var HarnessProtocolError = class extends Error {
|
|
3935
3958
|
name = "HarnessProtocolError";
|
|
3936
3959
|
};
|
|
3937
|
-
function record2(
|
|
3938
|
-
return
|
|
3960
|
+
function record2(value2) {
|
|
3961
|
+
return value2 !== null && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
|
|
3939
3962
|
}
|
|
3940
|
-
function boundedText(
|
|
3941
|
-
if (typeof
|
|
3963
|
+
function boundedText(value2, label, max) {
|
|
3964
|
+
if (typeof value2 !== "string" || !value2 || value2.length > max || CONTROL.test(value2)) {
|
|
3942
3965
|
throw new HarnessProtocolError(`${label} must be a non-empty string of at most ${max} characters`);
|
|
3943
3966
|
}
|
|
3944
|
-
return
|
|
3967
|
+
return value2;
|
|
3945
3968
|
}
|
|
3946
3969
|
function parseAgentOutput(line) {
|
|
3947
3970
|
if (Buffer.byteLength(line, "utf8") > 1e6) throw new HarnessProtocolError("agent message exceeds 1 MB");
|
|
3948
|
-
let
|
|
3971
|
+
let value2;
|
|
3949
3972
|
try {
|
|
3950
|
-
|
|
3973
|
+
value2 = JSON.parse(line);
|
|
3951
3974
|
} catch {
|
|
3952
3975
|
throw new HarnessProtocolError("agent emitted invalid JSON");
|
|
3953
3976
|
}
|
|
3954
|
-
const message2 = record2(
|
|
3977
|
+
const message2 = record2(value2);
|
|
3955
3978
|
if (!message2 || message2.protocolVersion !== HARNESS_PROTOCOL_VERSION) {
|
|
3956
3979
|
throw new HarnessProtocolError(`agent protocolVersion must be ${HARNESS_PROTOCOL_VERSION}`);
|
|
3957
3980
|
}
|
|
@@ -4260,7 +4283,7 @@ async function gitOutput(cwd, args, maxBytes) {
|
|
|
4260
4283
|
else stdout.push(chunk);
|
|
4261
4284
|
});
|
|
4262
4285
|
child.stderr.on("data", (chunk) => {
|
|
4263
|
-
if (stderr.reduce((sum,
|
|
4286
|
+
if (stderr.reduce((sum, value2) => sum + value2.byteLength, 0) < 16384) stderr.push(chunk);
|
|
4264
4287
|
});
|
|
4265
4288
|
const code = await new Promise((accept, reject) => {
|
|
4266
4289
|
child.once("error", reject);
|
|
@@ -4281,7 +4304,7 @@ async function gitBlobs(cwd, entries, maxBytes) {
|
|
|
4281
4304
|
else stdout.push(chunk);
|
|
4282
4305
|
});
|
|
4283
4306
|
child.stderr.on("data", (chunk) => {
|
|
4284
|
-
if (stderr.reduce((sum,
|
|
4307
|
+
if (stderr.reduce((sum, value2) => sum + value2.byteLength, 0) < 16384) stderr.push(chunk);
|
|
4285
4308
|
});
|
|
4286
4309
|
child.stdin.end(`${entries.map((entry) => entry.hash).join("\n")}
|
|
4287
4310
|
`);
|
|
@@ -4319,8 +4342,8 @@ async function materializeGitTree(source, commitSha, options = {}) {
|
|
|
4319
4342
|
const maxFiles = options.maxFiles ?? 2e4;
|
|
4320
4343
|
const maxBytes = options.maxBytes ?? 512 * 1024 * 1024;
|
|
4321
4344
|
const inventory = (await gitOutput(sourceDir, ["ls-tree", "-rz", commitSha], 16 * 1024 * 1024)).toString("utf8").split("\0").filter(Boolean);
|
|
4322
|
-
const entries = inventory.flatMap((
|
|
4323
|
-
const match = /^(100644|100755) blob ([0-9a-f]{40,64})\t([\s\S]+)$/.exec(
|
|
4345
|
+
const entries = inventory.flatMap((record8) => {
|
|
4346
|
+
const match = /^(100644|100755) blob ([0-9a-f]{40,64})\t([\s\S]+)$/.exec(record8);
|
|
4324
4347
|
return match && allowedWorkspacePath(match[3]) ? [{ mode: match[1], hash: match[2], path: match[3] }] : [];
|
|
4325
4348
|
});
|
|
4326
4349
|
if (entries.length > maxFiles) throw new Error(`workspace exceeds ${maxFiles} files`);
|
|
@@ -4395,7 +4418,7 @@ async function gitSourceFiles(sourceDir, maxFiles, maxBytes) {
|
|
|
4395
4418
|
else stdout.push(chunk);
|
|
4396
4419
|
});
|
|
4397
4420
|
child.stderr.on("data", (chunk) => {
|
|
4398
|
-
if (stderr.reduce((sum,
|
|
4421
|
+
if (stderr.reduce((sum, value2) => sum + value2.byteLength, 0) < 16384) stderr.push(chunk);
|
|
4399
4422
|
});
|
|
4400
4423
|
const code = await new Promise((accept, reject) => {
|
|
4401
4424
|
child.once("error", reject);
|
|
@@ -4455,7 +4478,7 @@ async function captureGitDiff(root, maxBytes) {
|
|
|
4455
4478
|
else stdout.push(chunk);
|
|
4456
4479
|
});
|
|
4457
4480
|
child.stderr.on("data", (chunk) => {
|
|
4458
|
-
if (stderr.reduce((sum,
|
|
4481
|
+
if (stderr.reduce((sum, value2) => sum + value2.byteLength, 0) < 16384) stderr.push(chunk);
|
|
4459
4482
|
});
|
|
4460
4483
|
const code = await new Promise((accept, reject) => {
|
|
4461
4484
|
child.once("error", reject);
|
|
@@ -4542,34 +4565,34 @@ var CamelError = class extends Error {
|
|
|
4542
4565
|
};
|
|
4543
4566
|
|
|
4544
4567
|
// ../camel/dist/chunk-L5DYU2E2.js
|
|
4545
|
-
function canonicalJson(
|
|
4546
|
-
return JSON.stringify(normalize(
|
|
4568
|
+
function canonicalJson(value2) {
|
|
4569
|
+
return JSON.stringify(normalize(value2));
|
|
4547
4570
|
}
|
|
4548
|
-
async function sha256Hex(
|
|
4549
|
-
const bytes = typeof
|
|
4571
|
+
async function sha256Hex(value2) {
|
|
4572
|
+
const bytes = typeof value2 === "string" ? new TextEncoder().encode(value2) : value2;
|
|
4550
4573
|
const digest = await crypto.subtle.digest("SHA-256", Uint8Array.from(bytes).buffer);
|
|
4551
4574
|
return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
4552
4575
|
}
|
|
4553
|
-
function utf8Length(
|
|
4554
|
-
if (typeof
|
|
4555
|
-
if (
|
|
4576
|
+
function utf8Length(value2) {
|
|
4577
|
+
if (typeof value2 === "string") return new TextEncoder().encode(value2).byteLength;
|
|
4578
|
+
if (value2 instanceof Uint8Array) return value2.byteLength;
|
|
4556
4579
|
try {
|
|
4557
|
-
return new TextEncoder().encode(canonicalJson(
|
|
4580
|
+
return new TextEncoder().encode(canonicalJson(value2)).byteLength;
|
|
4558
4581
|
} catch {
|
|
4559
4582
|
throw new CamelError("conversion_rejected", "Unsafe input could not be canonically measured.");
|
|
4560
4583
|
}
|
|
4561
4584
|
}
|
|
4562
|
-
function normalize(
|
|
4563
|
-
if (
|
|
4564
|
-
if (typeof
|
|
4565
|
-
if (!Number.isFinite(
|
|
4566
|
-
return
|
|
4585
|
+
function normalize(value2) {
|
|
4586
|
+
if (value2 === null || typeof value2 === "string" || typeof value2 === "boolean") return value2;
|
|
4587
|
+
if (typeof value2 === "number") {
|
|
4588
|
+
if (!Number.isFinite(value2)) throw new CamelError("state_conflict", "Canonical JSON rejects non-finite numbers.");
|
|
4589
|
+
return value2;
|
|
4567
4590
|
}
|
|
4568
|
-
if (Array.isArray(
|
|
4569
|
-
if (
|
|
4570
|
-
if (typeof
|
|
4571
|
-
const
|
|
4572
|
-
return Object.fromEntries(Object.keys(
|
|
4591
|
+
if (Array.isArray(value2)) return value2.map(normalize);
|
|
4592
|
+
if (value2 instanceof Uint8Array) return { $bytes: [...value2] };
|
|
4593
|
+
if (typeof value2 === "object") {
|
|
4594
|
+
const record8 = value2;
|
|
4595
|
+
return Object.fromEntries(Object.keys(record8).filter((key) => record8[key] !== void 0).sort().map((key) => [key, normalize(record8[key])]));
|
|
4573
4596
|
}
|
|
4574
4597
|
throw new CamelError("state_conflict", "Canonical JSON rejects unsupported values.");
|
|
4575
4598
|
}
|
|
@@ -4578,10 +4601,10 @@ function canRead(readers, readerId) {
|
|
|
4578
4601
|
}
|
|
4579
4602
|
function dependenciesOf(values, influence = "data") {
|
|
4580
4603
|
const result = [];
|
|
4581
|
-
for (const
|
|
4582
|
-
result.push(...
|
|
4583
|
-
for (const ref of
|
|
4584
|
-
result.push({ ref, influence, promptSafetyAtUse:
|
|
4604
|
+
for (const value2 of values) {
|
|
4605
|
+
result.push(...value2.label.dependencies);
|
|
4606
|
+
for (const ref of value2.label.provenance) {
|
|
4607
|
+
result.push({ ref, influence, promptSafetyAtUse: value2.label.promptSafety });
|
|
4585
4608
|
}
|
|
4586
4609
|
}
|
|
4587
4610
|
const unique3 = /* @__PURE__ */ new Map();
|
|
@@ -4592,32 +4615,32 @@ function dependenciesOf(values, influence = "data") {
|
|
|
4592
4615
|
// ../camel/dist/chunk-S7EVNA2U.js
|
|
4593
4616
|
var camelValueBrand = /* @__PURE__ */ Symbol("@odla-ai/camel/value");
|
|
4594
4617
|
var authenticCamelValues = /* @__PURE__ */ new WeakSet();
|
|
4595
|
-
function isCamelValue(
|
|
4596
|
-
return typeof
|
|
4618
|
+
function isCamelValue(value2) {
|
|
4619
|
+
return typeof value2 === "object" && value2 !== null && authenticCamelValues.has(value2);
|
|
4597
4620
|
}
|
|
4598
|
-
function isSafe(
|
|
4599
|
-
return isCamelValue(
|
|
4621
|
+
function isSafe(value2) {
|
|
4622
|
+
return isCamelValue(value2) && value2.label.promptSafety === "safe";
|
|
4600
4623
|
}
|
|
4601
|
-
function isUnsafe(
|
|
4602
|
-
return isCamelValue(
|
|
4624
|
+
function isUnsafe(value2) {
|
|
4625
|
+
return isCamelValue(value2) && value2.label.promptSafety === "unsafe";
|
|
4603
4626
|
}
|
|
4604
|
-
function createSafeInternal(
|
|
4605
|
-
return createValue(
|
|
4627
|
+
function createSafeInternal(value2, safeBasis, metadata2) {
|
|
4628
|
+
return createValue(value2, {
|
|
4606
4629
|
schemaVersion: 1,
|
|
4607
4630
|
promptSafety: "safe",
|
|
4608
4631
|
safeBasis,
|
|
4609
4632
|
...copyMetadata(metadata2)
|
|
4610
4633
|
});
|
|
4611
4634
|
}
|
|
4612
|
-
function createUnsafeInternal(
|
|
4613
|
-
return createValue(
|
|
4635
|
+
function createUnsafeInternal(value2, metadata2) {
|
|
4636
|
+
return createValue(value2, {
|
|
4614
4637
|
schemaVersion: 1,
|
|
4615
4638
|
promptSafety: "unsafe",
|
|
4616
4639
|
...copyMetadata(metadata2)
|
|
4617
4640
|
});
|
|
4618
4641
|
}
|
|
4619
|
-
function createValue(
|
|
4620
|
-
const result = { value, label: Object.freeze(label) };
|
|
4642
|
+
function createValue(value2, label) {
|
|
4643
|
+
const result = { value: value2, label: Object.freeze(label) };
|
|
4621
4644
|
Object.defineProperty(result, camelValueBrand, { value: label.promptSafety, enumerable: false });
|
|
4622
4645
|
authenticCamelValues.add(result);
|
|
4623
4646
|
return Object.freeze(result);
|
|
@@ -4723,8 +4746,8 @@ async function createCodePortableCheckpoint(input) {
|
|
|
4723
4746
|
const checkpointDigest = `sha256:${await sha256Hex(canonicalJson(fields))}`;
|
|
4724
4747
|
return freeze({ ...fields, patch: input.patch, checkpointDigest });
|
|
4725
4748
|
}
|
|
4726
|
-
async function verifyCodePortableCheckpoint(
|
|
4727
|
-
const input = object(
|
|
4749
|
+
async function verifyCodePortableCheckpoint(value2) {
|
|
4750
|
+
const input = object(value2, "checkpoint");
|
|
4728
4751
|
exact2(input, ["schemaVersion", "baseCommitSha", "patch", "patchDigest", "state", "stateDigest", "checkpointDigest"]);
|
|
4729
4752
|
if (input.schemaVersion !== 1 || typeof input.baseCommitSha !== "string" || typeof input.patch !== "string" || typeof input.patchDigest !== "string" || typeof input.stateDigest !== "string" || typeof input.checkpointDigest !== "string") {
|
|
4730
4753
|
throw invalid2("Portable checkpoint fields are malformed.");
|
|
@@ -4739,8 +4762,8 @@ async function verifyCodePortableCheckpoint(value) {
|
|
|
4739
4762
|
}
|
|
4740
4763
|
return created;
|
|
4741
4764
|
}
|
|
4742
|
-
function normalizeState(
|
|
4743
|
-
const state2 = object(
|
|
4765
|
+
function normalizeState(value2) {
|
|
4766
|
+
const state2 = object(value2, "state");
|
|
4744
4767
|
exact2(state2, [
|
|
4745
4768
|
"planCursor",
|
|
4746
4769
|
"conversationRefs",
|
|
@@ -4798,30 +4821,30 @@ function validateBaseAndPatch(baseCommitSha, patch2) {
|
|
|
4798
4821
|
throw invalid2("Portable checkpoint base or patch is malformed or outside its bounds.");
|
|
4799
4822
|
}
|
|
4800
4823
|
}
|
|
4801
|
-
function strings(
|
|
4802
|
-
if (!Array.isArray(
|
|
4824
|
+
function strings(value2, name, pattern, maximum, sort) {
|
|
4825
|
+
if (!Array.isArray(value2) || value2.length > maximum || value2.some((item) => typeof item !== "string" || !pattern.test(item)) || new Set(value2).size !== value2.length) {
|
|
4803
4826
|
throw invalid2(`Portable checkpoint ${name} is malformed or outside its bounds.`);
|
|
4804
4827
|
}
|
|
4805
|
-
const result = [...
|
|
4828
|
+
const result = [...value2];
|
|
4806
4829
|
return sort ? result.sort() : result;
|
|
4807
4830
|
}
|
|
4808
|
-
function object(
|
|
4809
|
-
if (!
|
|
4810
|
-
return
|
|
4831
|
+
function object(value2, name) {
|
|
4832
|
+
if (!value2 || typeof value2 !== "object" || Array.isArray(value2)) throw invalid2(`Portable ${name} must be an object.`);
|
|
4833
|
+
return value2;
|
|
4811
4834
|
}
|
|
4812
|
-
function exact2(
|
|
4813
|
-
if (Object.keys(
|
|
4835
|
+
function exact2(value2, keys) {
|
|
4836
|
+
if (Object.keys(value2).some((key) => !keys.includes(key)) || keys.some((key) => !(key in value2))) {
|
|
4814
4837
|
throw invalid2("Portable checkpoint contains missing or unsupported fields.");
|
|
4815
4838
|
}
|
|
4816
4839
|
}
|
|
4817
|
-
function freeze(
|
|
4840
|
+
function freeze(value2) {
|
|
4818
4841
|
return Object.freeze({
|
|
4819
|
-
...
|
|
4842
|
+
...value2,
|
|
4820
4843
|
state: Object.freeze({
|
|
4821
|
-
...
|
|
4822
|
-
conversationRefs: Object.freeze([...
|
|
4823
|
-
completedEffects: Object.freeze(
|
|
4824
|
-
unresolvedApprovals: Object.freeze([...
|
|
4844
|
+
...value2.state,
|
|
4845
|
+
conversationRefs: Object.freeze([...value2.state.conversationRefs]),
|
|
4846
|
+
completedEffects: Object.freeze(value2.state.completedEffects.map((item) => Object.freeze({ ...item }))),
|
|
4847
|
+
unresolvedApprovals: Object.freeze([...value2.state.unresolvedApprovals])
|
|
4825
4848
|
})
|
|
4826
4849
|
});
|
|
4827
4850
|
}
|
|
@@ -4912,61 +4935,61 @@ async function createConversionRegistry(config) {
|
|
|
4912
4935
|
if (utf8Length(source.value) > policy.maximumSourceBytes) throw new CamelError("limit_exceeded", "Unsafe conversion input exceeds its byte bound.");
|
|
4913
4936
|
return policy;
|
|
4914
4937
|
};
|
|
4915
|
-
const emit3 = (source, policy,
|
|
4938
|
+
const emit3 = (source, policy, value2) => convert(source, policy, value2, outputCounts);
|
|
4916
4939
|
const operations = Object.freeze({
|
|
4917
|
-
boolean: async (
|
|
4918
|
-
const policy = checked(
|
|
4919
|
-
return emit3(
|
|
4940
|
+
boolean: async (value2, id) => {
|
|
4941
|
+
const policy = checked(value2, id, "boolean");
|
|
4942
|
+
return emit3(value2, policy, requireBoolean(value2.value));
|
|
4920
4943
|
},
|
|
4921
|
-
integer: async (
|
|
4922
|
-
const policy = checked(
|
|
4923
|
-
return emit3(
|
|
4944
|
+
integer: async (value2, id) => {
|
|
4945
|
+
const policy = checked(value2, id, "integer");
|
|
4946
|
+
return emit3(value2, policy, boundedInteger(value2.value, policy.output));
|
|
4924
4947
|
},
|
|
4925
|
-
finiteNumber: async (
|
|
4926
|
-
const policy = checked(
|
|
4927
|
-
return emit3(
|
|
4948
|
+
finiteNumber: async (value2, id) => {
|
|
4949
|
+
const policy = checked(value2, id, "finite_number");
|
|
4950
|
+
return emit3(value2, policy, boundedNumber(value2.value, policy.output));
|
|
4928
4951
|
},
|
|
4929
|
-
enum: async (
|
|
4930
|
-
const policy = checked(
|
|
4931
|
-
return emit3(
|
|
4952
|
+
enum: async (value2, id) => {
|
|
4953
|
+
const policy = checked(value2, id, "enum");
|
|
4954
|
+
return emit3(value2, policy, enumMember(value2.value, policy.output));
|
|
4932
4955
|
},
|
|
4933
|
-
date: async (
|
|
4934
|
-
const policy = checked(
|
|
4935
|
-
return emit3(
|
|
4956
|
+
date: async (value2, id) => {
|
|
4957
|
+
const policy = checked(value2, id, "date");
|
|
4958
|
+
return emit3(value2, policy, canonicalDate(value2.value, policy.output));
|
|
4936
4959
|
},
|
|
4937
|
-
registeredId: async (
|
|
4938
|
-
const policy = checked(
|
|
4960
|
+
registeredId: async (value2, id) => {
|
|
4961
|
+
const policy = checked(value2, id, "registered_id");
|
|
4939
4962
|
const registry = config.registeredIds?.[policy.output.registryId];
|
|
4940
|
-
const output = typeof
|
|
4963
|
+
const output = typeof value2.value === "string" ? registry?.values[value2.value] : void 0;
|
|
4941
4964
|
if (!output) throw new CamelError("conversion_rejected", "Registered-ID conversion rejected the candidate.");
|
|
4942
|
-
return emit3(
|
|
4965
|
+
return emit3(value2, policy, output);
|
|
4943
4966
|
},
|
|
4944
|
-
digest: async (
|
|
4945
|
-
const policy = checked(
|
|
4946
|
-
if (!(
|
|
4947
|
-
return emit3(
|
|
4967
|
+
digest: async (value2, id) => {
|
|
4968
|
+
const policy = checked(value2, id, "digest");
|
|
4969
|
+
if (!(value2.value instanceof Uint8Array)) throw new CamelError("conversion_rejected", "Digest conversion requires bytes.");
|
|
4970
|
+
return emit3(value2, policy, await sha256Hex(value2.value));
|
|
4948
4971
|
},
|
|
4949
|
-
measure: async (
|
|
4950
|
-
const policy = checked(
|
|
4951
|
-
const measured = measure(
|
|
4952
|
-
return emit3(
|
|
4972
|
+
measure: async (value2, metric, id) => {
|
|
4973
|
+
const policy = checked(value2, id, "integer");
|
|
4974
|
+
const measured = measure(value2.value, metric);
|
|
4975
|
+
return emit3(value2, policy, boundedInteger(measured, policy.output));
|
|
4953
4976
|
},
|
|
4954
|
-
test: async (
|
|
4955
|
-
const policy = checked(
|
|
4977
|
+
test: async (value2, predicateId, id) => {
|
|
4978
|
+
const policy = checked(value2, id, "boolean");
|
|
4956
4979
|
const predicate = config.predicates?.[predicateId];
|
|
4957
4980
|
if (!predicate) throw new CamelError("conversion_rejected", "Predicate is not registered.");
|
|
4958
|
-
return emit3(
|
|
4981
|
+
return emit3(value2, policy, evaluatePredicate(value2.value, predicate, config.registeredIds));
|
|
4959
4982
|
}
|
|
4960
4983
|
});
|
|
4961
4984
|
return Object.freeze({ operations, policy: (id) => policies.get(id) ?? missingPolicy() });
|
|
4962
4985
|
}
|
|
4963
|
-
async function convert(source, policy,
|
|
4986
|
+
async function convert(source, policy, value2, counts) {
|
|
4964
4987
|
const sourceKey = sourceIdentity(source);
|
|
4965
4988
|
const countKey = `${policy.conversionId}\0${sourceKey}`;
|
|
4966
4989
|
const count = counts.get(countKey) ?? 0;
|
|
4967
4990
|
if (count >= policy.maximumOutputsPerArtifact) throw new CamelError("limit_exceeded", "Conversion output count exceeds its per-source bound.");
|
|
4968
4991
|
counts.set(countKey, count + 1);
|
|
4969
|
-
return createSafeInternal(
|
|
4992
|
+
return createSafeInternal(value2, "atomic_conversion", {
|
|
4970
4993
|
readers: source.label.readers,
|
|
4971
4994
|
provenance: [...source.label.provenance, { kind: "converter", id: policy.conversionId, digest: policy.digest }],
|
|
4972
4995
|
dependencies: dependenciesOf([source])
|
|
@@ -4978,49 +5001,49 @@ function validatePolicyShape(policy) {
|
|
|
4978
5001
|
const output = policy.output;
|
|
4979
5002
|
if ((output.kind === "integer" || output.kind === "finite_number") && (!Number.isFinite(output.minimum) || !Number.isFinite(output.maximum) || output.minimum > output.maximum)) throw new CamelError("state_conflict", "Numeric conversion bounds are invalid.");
|
|
4980
5003
|
if (output.kind === "finite_number" && (!Number.isSafeInteger(output.maximumDecimalPlaces) || output.maximumDecimalPlaces < 0 || output.maximumDecimalPlaces > 15)) throw new CamelError("state_conflict", "Decimal-place bound is invalid.");
|
|
4981
|
-
if (output.kind === "enum" && (output.values.length === 0 || output.values.some((
|
|
5004
|
+
if (output.kind === "enum" && (output.values.length === 0 || output.values.some((value2) => typeof value2 !== "string" || !value2) || new Set(output.values).size !== output.values.length)) throw new CamelError("state_conflict", "Enum conversion members must be unique and non-empty.");
|
|
4982
5005
|
if (output.kind === "registered_id" && (!output.registryId || !output.registryDigest)) throw new CamelError("state_conflict", "Registered-ID conversion identity is invalid.");
|
|
4983
5006
|
if (output.kind === "date" && output.format !== "date" && output.format !== "rfc3339") throw new CamelError("state_conflict", "Date conversion format is invalid.");
|
|
4984
5007
|
if (output.kind === "digest" && output.algorithm !== "sha256") throw new CamelError("state_conflict", "Digest conversion algorithm is invalid.");
|
|
4985
5008
|
}
|
|
4986
|
-
function requireBoolean(
|
|
4987
|
-
if (typeof
|
|
4988
|
-
return
|
|
5009
|
+
function requireBoolean(value2) {
|
|
5010
|
+
if (typeof value2 !== "boolean") throw new CamelError("conversion_rejected", "Boolean conversion requires a structured boolean.");
|
|
5011
|
+
return value2;
|
|
4989
5012
|
}
|
|
4990
|
-
function boundedInteger(
|
|
4991
|
-
if (spec.kind !== "integer" || typeof
|
|
4992
|
-
return
|
|
5013
|
+
function boundedInteger(value2, spec) {
|
|
5014
|
+
if (spec.kind !== "integer" || typeof value2 !== "number" || !Number.isSafeInteger(value2) || value2 < spec.minimum || value2 > spec.maximum) throw new CamelError("conversion_rejected", "Integer conversion rejected the structured value.");
|
|
5015
|
+
return value2;
|
|
4993
5016
|
}
|
|
4994
|
-
function boundedNumber(
|
|
4995
|
-
if (spec.kind !== "finite_number" || typeof
|
|
4996
|
-
const text = String(
|
|
5017
|
+
function boundedNumber(value2, spec) {
|
|
5018
|
+
if (spec.kind !== "finite_number" || typeof value2 !== "number" || !Number.isFinite(value2) || value2 < spec.minimum || value2 > spec.maximum) throw new CamelError("conversion_rejected", "Finite-number conversion rejected the structured value.");
|
|
5019
|
+
const text = String(value2);
|
|
4997
5020
|
if (/e/i.test(text) || (text.split(".")[1]?.length ?? 0) > spec.maximumDecimalPlaces) throw new CamelError("conversion_rejected", "Finite-number conversion rejected a non-canonical decimal.");
|
|
4998
|
-
return
|
|
5021
|
+
return value2;
|
|
4999
5022
|
}
|
|
5000
|
-
function enumMember(
|
|
5001
|
-
if (spec.kind !== "enum" || typeof
|
|
5002
|
-
const member = spec.caseSensitive ? spec.values.find((item) => item ===
|
|
5023
|
+
function enumMember(value2, spec) {
|
|
5024
|
+
if (spec.kind !== "enum" || typeof value2 !== "string") throw new CamelError("conversion_rejected", "Enum conversion requires a structured string member.");
|
|
5025
|
+
const member = spec.caseSensitive ? spec.values.find((item) => item === value2) : spec.values.find((item) => item.toLocaleLowerCase("en-US") === value2.toLocaleLowerCase("en-US"));
|
|
5003
5026
|
if (member === void 0) throw new CamelError("conversion_rejected", "Enum conversion rejected a non-member.");
|
|
5004
5027
|
return member;
|
|
5005
5028
|
}
|
|
5006
|
-
function canonicalDate(
|
|
5007
|
-
if (spec.kind !== "date" || typeof
|
|
5029
|
+
function canonicalDate(value2, spec) {
|
|
5030
|
+
if (spec.kind !== "date" || typeof value2 !== "string") throw new CamelError("conversion_rejected", "Date conversion requires a canonical structured string.");
|
|
5008
5031
|
const pattern = spec.format === "date" ? /^\d{4}-\d{2}-\d{2}$/ : /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?(?:Z|[+-]\d{2}:\d{2})$/;
|
|
5009
|
-
const instant = Date.parse(spec.format === "date" ? `${
|
|
5010
|
-
if (!pattern.test(
|
|
5011
|
-
if (spec.earliest &&
|
|
5012
|
-
return
|
|
5013
|
-
}
|
|
5014
|
-
function measure(
|
|
5015
|
-
if (metric === "byte_length" && (typeof
|
|
5016
|
-
if (metric === "codepoint_length" && typeof
|
|
5017
|
-
if (metric === "item_count" && Array.isArray(
|
|
5032
|
+
const instant = Date.parse(spec.format === "date" ? `${value2}T00:00:00Z` : value2);
|
|
5033
|
+
if (!pattern.test(value2) || !Number.isFinite(instant) || spec.format === "date" && new Date(instant).toISOString().slice(0, 10) !== value2) throw new CamelError("conversion_rejected", "Date conversion rejected a non-canonical value.");
|
|
5034
|
+
if (spec.earliest && value2 < spec.earliest || spec.latest && value2 > spec.latest) throw new CamelError("conversion_rejected", "Date conversion rejected an out-of-range value.");
|
|
5035
|
+
return value2;
|
|
5036
|
+
}
|
|
5037
|
+
function measure(value2, metric) {
|
|
5038
|
+
if (metric === "byte_length" && (typeof value2 === "string" || value2 instanceof Uint8Array)) return utf8Length(value2);
|
|
5039
|
+
if (metric === "codepoint_length" && typeof value2 === "string") return [...value2].length;
|
|
5040
|
+
if (metric === "item_count" && Array.isArray(value2)) return value2.length;
|
|
5018
5041
|
throw new CamelError("conversion_rejected", "Measurement input does not match the registered metric.");
|
|
5019
5042
|
}
|
|
5020
|
-
function evaluatePredicate(
|
|
5021
|
-
if (predicate.kind === "has_fields") return typeof
|
|
5022
|
-
if (predicate.kind === "registered_id") return typeof
|
|
5023
|
-
const actual =
|
|
5043
|
+
function evaluatePredicate(value2, predicate, registries) {
|
|
5044
|
+
if (predicate.kind === "has_fields") return typeof value2 === "object" && value2 !== null && !Array.isArray(value2) && predicate.fields.every((field) => Object.hasOwn(value2, field));
|
|
5045
|
+
if (predicate.kind === "registered_id") return typeof value2 === "string" && registries?.[predicate.registryId]?.values[value2] !== void 0;
|
|
5046
|
+
const actual = value2 === null ? "null" : Array.isArray(value2) ? "array" : typeof value2;
|
|
5024
5047
|
return actual === predicate.valueType;
|
|
5025
5048
|
}
|
|
5026
5049
|
function sourceIdentity(source) {
|
|
@@ -5043,17 +5066,17 @@ function createCamelIngress(constants2 = []) {
|
|
|
5043
5066
|
byId.set(item.id, item);
|
|
5044
5067
|
}
|
|
5045
5068
|
const ingress = {
|
|
5046
|
-
userInstruction: (
|
|
5047
|
-
systemPolicy: (
|
|
5069
|
+
userInstruction: (value2, input) => createSafeInternal(value2, "user_instruction", metadata("user_instruction", input.id, input.readers)),
|
|
5070
|
+
systemPolicy: (value2, input) => createSafeInternal(value2, "system_policy", metadata("system_policy", input.id, input.readers)),
|
|
5048
5071
|
control: (id) => {
|
|
5049
5072
|
const item = byId.get(id);
|
|
5050
5073
|
if (!item) throw new CamelError("permission_denied", "Unknown control constant.");
|
|
5051
5074
|
return createSafeInternal(item.value, "harness_constant", metadata("harness", id, item.readers));
|
|
5052
5075
|
},
|
|
5053
|
-
external: (
|
|
5054
|
-
quarantinedOutput: (
|
|
5076
|
+
external: (value2, label) => createUnsafeInternal(value2, label),
|
|
5077
|
+
quarantinedOutput: (value2, input) => {
|
|
5055
5078
|
if (!input.runId) throw new CamelError("state_conflict", "Quarantined run IDs must be non-empty.");
|
|
5056
|
-
return createUnsafeInternal(
|
|
5079
|
+
return createUnsafeInternal(value2, {
|
|
5057
5080
|
readers: input.readers,
|
|
5058
5081
|
dependencies: input.dependencies,
|
|
5059
5082
|
provenance: [{ kind: "quarantined_llm", id: input.runId, digest: input.digest }]
|
|
@@ -5062,15 +5085,15 @@ function createCamelIngress(constants2 = []) {
|
|
|
5062
5085
|
};
|
|
5063
5086
|
return Object.freeze(ingress);
|
|
5064
5087
|
}
|
|
5065
|
-
function assertNoUnsafeConstant(
|
|
5066
|
-
if (typeof
|
|
5067
|
-
seen.add(
|
|
5068
|
-
if (isCamelValue(
|
|
5069
|
-
if (isUnsafe(
|
|
5070
|
-
assertNoUnsafeConstant(
|
|
5088
|
+
function assertNoUnsafeConstant(value2, seen = /* @__PURE__ */ new WeakSet()) {
|
|
5089
|
+
if (typeof value2 !== "object" || value2 === null || seen.has(value2)) return;
|
|
5090
|
+
seen.add(value2);
|
|
5091
|
+
if (isCamelValue(value2)) {
|
|
5092
|
+
if (isUnsafe(value2)) throw new CamelError("unsafe_privileged_flow", "Control constants cannot contain Prompt-Unsafe values.");
|
|
5093
|
+
assertNoUnsafeConstant(value2.value, seen);
|
|
5071
5094
|
return;
|
|
5072
5095
|
}
|
|
5073
|
-
for (const child of Object.values(
|
|
5096
|
+
for (const child of Object.values(value2)) assertNoUnsafeConstant(child, seen);
|
|
5074
5097
|
}
|
|
5075
5098
|
function metadata(kind, id, readers) {
|
|
5076
5099
|
if (!id) throw new CamelError("state_conflict", "Provenance IDs must be non-empty.");
|
|
@@ -5101,7 +5124,7 @@ async function evaluate(input, registries, approvals) {
|
|
|
5101
5124
|
if (invalid3) return deny(invalid3);
|
|
5102
5125
|
if (arg.role === "selector" && !isSafe(arg.value)) confined.add(arg.value);
|
|
5103
5126
|
}
|
|
5104
|
-
if (input.controlDependencies.some((
|
|
5127
|
+
if (input.controlDependencies.some((value2) => !isSafe(value2) && !confined.has(value2))) return deny("unsafe_control_dependency");
|
|
5105
5128
|
if (confined.size > 0) {
|
|
5106
5129
|
const fixed = input.tool.unsafeSelectorPolicy?.fixedProviderIds ?? [];
|
|
5107
5130
|
const destinations = Object.values(input.args).filter((arg) => arg.role === "destination");
|
|
@@ -5128,29 +5151,29 @@ async function validateArgument(path, arg, tool, registries) {
|
|
|
5128
5151
|
if (!isSafe(arg.value)) return "unsafe_destination_argument";
|
|
5129
5152
|
if (!isControlOwned(arg.value)) return "destination_not_control_owned";
|
|
5130
5153
|
const registry = registries[arg.registryId];
|
|
5131
|
-
const validValues = registry && registry.values.length > 0 && registry.values.every((
|
|
5154
|
+
const validValues = registry && registry.values.length > 0 && registry.values.every((value2) => typeof value2 === "string" && value2.length > 0) && new Set(registry.values).size === registry.values.length;
|
|
5132
5155
|
if (!registry || !validValues || registry.digest !== arg.registryDigest || await destinationRegistryDigest(registry.values) !== registry.digest || !registry.values.includes(arg.value.value)) return "destination_not_registered";
|
|
5133
5156
|
}
|
|
5134
5157
|
if (arg.role === "selector" && !isSafe(arg.value)) return validateUnsafeSelector(path, arg.value, tool);
|
|
5135
5158
|
return void 0;
|
|
5136
5159
|
}
|
|
5137
|
-
function isControlOwned(
|
|
5138
|
-
return
|
|
5160
|
+
function isControlOwned(value2) {
|
|
5161
|
+
return value2.label.safeBasis === "system_policy" || value2.label.safeBasis === "harness_constant";
|
|
5139
5162
|
}
|
|
5140
5163
|
function copyRegistries(registries) {
|
|
5141
5164
|
return Object.freeze(Object.fromEntries(Object.entries(registries).map(([id, registry]) => [id, Object.freeze({ digest: registry.digest, values: Object.freeze([...registry.values]) })])));
|
|
5142
5165
|
}
|
|
5143
|
-
function validateUnsafeSelector(path,
|
|
5166
|
+
function validateUnsafeSelector(path, value2, tool) {
|
|
5144
5167
|
const policy = tool.unsafeSelectorPolicy;
|
|
5145
5168
|
if (!policy || policy.effect !== tool.effect || !policy.selectorPaths.includes(path)) return "unsafe_selector_not_confined";
|
|
5146
5169
|
if (!policy.fixedDestination || !policy.unsafeOutput || policy.fixedProviderIds.length === 0) return "unsafe_selector_not_confined";
|
|
5147
5170
|
if (![policy.maximumCalls, policy.maximumResultsPerCall, policy.maximumOutputBytes, policy.maximumSelectorBytes].every((bound) => Number.isSafeInteger(bound) && bound > 0)) return "unsafe_selector_not_confined";
|
|
5148
|
-
if (utf8Length(
|
|
5149
|
-
if (typeof
|
|
5171
|
+
if (utf8Length(value2.value) > policy.maximumSelectorBytes) return "unsafe_selector_too_large";
|
|
5172
|
+
if (typeof value2.value === "string" && looksLikeDestination(value2.value)) return "unsafe_selector_is_destination";
|
|
5150
5173
|
return void 0;
|
|
5151
5174
|
}
|
|
5152
|
-
function looksLikeDestination(
|
|
5153
|
-
const text =
|
|
5175
|
+
function looksLikeDestination(value2) {
|
|
5176
|
+
const text = value2.trim();
|
|
5154
5177
|
return /^(?:[a-z][a-z0-9+.-]*:\/\/|\/|\\\\)/i.test(text) || /^[\w.-]+\.[a-z]{2,}(?:[/:]|$)/i.test(text);
|
|
5155
5178
|
}
|
|
5156
5179
|
|
|
@@ -5236,9 +5259,9 @@ var CodeRuntimeReconciler = class {
|
|
|
5236
5259
|
}
|
|
5237
5260
|
}
|
|
5238
5261
|
};
|
|
5239
|
-
function retryableControlFailure(
|
|
5240
|
-
if (!
|
|
5241
|
-
const failure =
|
|
5262
|
+
function retryableControlFailure(value2) {
|
|
5263
|
+
if (!value2 || typeof value2 !== "object") return false;
|
|
5264
|
+
const failure = value2;
|
|
5242
5265
|
if (failure.code === "invalid_response" || typeof failure.status !== "number") return false;
|
|
5243
5266
|
return failure.status === 408 || failure.status === 425 || failure.status === 429 || failure.status >= 500;
|
|
5244
5267
|
}
|
|
@@ -5290,16 +5313,16 @@ function createCodeRuntimeControlClient(options) {
|
|
|
5290
5313
|
if (options.signal?.aborted) throw cause;
|
|
5291
5314
|
throw new CodeRuntimeControlError("Code runtime control plane is unavailable", 503, "transport_unavailable");
|
|
5292
5315
|
}
|
|
5293
|
-
const
|
|
5316
|
+
const value2 = await response2.json().catch(() => null);
|
|
5294
5317
|
if (!response2.ok) {
|
|
5295
|
-
const problem = record3(record3(
|
|
5318
|
+
const problem = record3(record3(value2)?.error);
|
|
5296
5319
|
throw new CodeRuntimeControlError(
|
|
5297
5320
|
typeof problem?.message === "string" ? problem.message : `Code runtime request failed (${response2.status})`,
|
|
5298
5321
|
response2.status,
|
|
5299
5322
|
typeof problem?.code === "string" ? problem.code : void 0
|
|
5300
5323
|
);
|
|
5301
5324
|
}
|
|
5302
|
-
return
|
|
5325
|
+
return value2;
|
|
5303
5326
|
};
|
|
5304
5327
|
return {
|
|
5305
5328
|
heartbeat: async (version, capabilities) => {
|
|
@@ -5314,15 +5337,15 @@ function createCodeRuntimeControlClient(options) {
|
|
|
5314
5337
|
await call2(`/registry/code/runtime/sessions/${validSessionId(sessionId)}/source`, {})
|
|
5315
5338
|
),
|
|
5316
5339
|
infer: async (sessionId, inference) => {
|
|
5317
|
-
const
|
|
5340
|
+
const value2 = record3(await call2(
|
|
5318
5341
|
`/registry/code/runtime/sessions/${validSessionId(sessionId)}/inference`,
|
|
5319
5342
|
inference,
|
|
5320
5343
|
modelRequestTimeoutMs
|
|
5321
5344
|
));
|
|
5322
|
-
if (!
|
|
5345
|
+
if (!value2 || value2.requestId !== inference.requestId || !record3(value2.response) || !record3(value2.receipt)) {
|
|
5323
5346
|
throw new CodeRuntimeControlError("invalid Code inference response", 502, "invalid_response");
|
|
5324
5347
|
}
|
|
5325
|
-
return
|
|
5348
|
+
return value2;
|
|
5326
5349
|
},
|
|
5327
5350
|
review: async (sessionId, review) => parseReview(
|
|
5328
5351
|
await call2(`/registry/code/runtime/sessions/${validSessionId(sessionId)}/review`, review, modelRequestTimeoutMs)
|
|
@@ -5347,8 +5370,8 @@ function createCodeRuntimeControlClient(options) {
|
|
|
5347
5370
|
}
|
|
5348
5371
|
};
|
|
5349
5372
|
}
|
|
5350
|
-
function validatedEndpoint(
|
|
5351
|
-
const endpoint =
|
|
5373
|
+
function validatedEndpoint(value2) {
|
|
5374
|
+
const endpoint = value2.replace(/\/+$/, "");
|
|
5352
5375
|
let url;
|
|
5353
5376
|
try {
|
|
5354
5377
|
url = new URL(endpoint);
|
|
@@ -5361,9 +5384,9 @@ function validatedEndpoint(value) {
|
|
|
5361
5384
|
}
|
|
5362
5385
|
return endpoint;
|
|
5363
5386
|
}
|
|
5364
|
-
function validSessionId(
|
|
5365
|
-
if (!/^csess_[0-9a-f]{32}$/.test(
|
|
5366
|
-
return
|
|
5387
|
+
function validSessionId(value2) {
|
|
5388
|
+
if (!/^csess_[0-9a-f]{32}$/.test(value2)) throw new TypeError("invalid Code session id");
|
|
5389
|
+
return value2;
|
|
5367
5390
|
}
|
|
5368
5391
|
function validateHeartbeat(version, capabilities) {
|
|
5369
5392
|
if (!version.trim() || version.length > 80) throw new TypeError("runtimeVersion is required and at most 80 characters");
|
|
@@ -5376,8 +5399,8 @@ function validateHeartbeat(version, capabilities) {
|
|
|
5376
5399
|
throw new TypeError("runtime resources must be positive integers");
|
|
5377
5400
|
}
|
|
5378
5401
|
}
|
|
5379
|
-
function parseSnapshot(
|
|
5380
|
-
const root = record3(
|
|
5402
|
+
function parseSnapshot(value2) {
|
|
5403
|
+
const root = record3(value2);
|
|
5381
5404
|
const host = record3(root?.host);
|
|
5382
5405
|
if (!host || typeof host.hostId !== "string" || typeof host.runtimeVersion !== "string" || !Number.isSafeInteger(host.lastSeenAt) || host.revokedAt !== null || !Array.isArray(root?.bindings) || root.bindings.length > 1024 || !Array.isArray(root?.commands) || root.commands.length > 64) throw invalid("heartbeat");
|
|
5383
5406
|
const bindingIds = /* @__PURE__ */ new Set();
|
|
@@ -5402,11 +5425,11 @@ function parseSnapshot(value) {
|
|
|
5402
5425
|
});
|
|
5403
5426
|
return { host, bindings, commands };
|
|
5404
5427
|
}
|
|
5405
|
-
async function parseSource(
|
|
5406
|
-
const snapshot = record3(record3(
|
|
5428
|
+
async function parseSource(value2) {
|
|
5429
|
+
const snapshot = record3(record3(value2)?.snapshot);
|
|
5407
5430
|
if (!snapshot || typeof snapshot.repository !== "string" || typeof snapshot.commitSha !== "string" || typeof snapshot.treeDigest !== "string" || !Array.isArray(snapshot.files)) throw invalid("source");
|
|
5408
|
-
const files = snapshot.files.map((
|
|
5409
|
-
const file = record3(
|
|
5431
|
+
const files = snapshot.files.map((value22) => {
|
|
5432
|
+
const file = record3(value22);
|
|
5410
5433
|
if (!file || typeof file.path !== "string" || typeof file.content !== "string") throw invalid("source file");
|
|
5411
5434
|
return { path: file.path, content: file.content };
|
|
5412
5435
|
});
|
|
@@ -5433,19 +5456,19 @@ async function parseSource(value) {
|
|
|
5433
5456
|
if (digest !== snapshot.treeDigest) throw invalid("source digest");
|
|
5434
5457
|
return { ...source, treeDigest: digest, ...references.length ? { references } : {} };
|
|
5435
5458
|
}
|
|
5436
|
-
function parseReview(
|
|
5437
|
-
const review = record3(record3(
|
|
5459
|
+
function parseReview(value2) {
|
|
5460
|
+
const review = record3(record3(value2)?.review);
|
|
5438
5461
|
if (!review || !["approved", "rejected"].includes(String(review.verdict)) || typeof review.reviewDigest !== "string" || !/^sha256:[0-9a-f]{64}$/.test(review.reviewDigest) || typeof review.provider !== "string" || !review.provider || typeof review.model !== "string" || !review.model || !Number.isSafeInteger(review.policyVersion) || Number(review.policyVersion) < 1) throw invalid("review");
|
|
5439
5462
|
return review;
|
|
5440
5463
|
}
|
|
5441
|
-
function parseCandidate(
|
|
5442
|
-
const candidate = record3(record3(
|
|
5464
|
+
function parseCandidate(value2) {
|
|
5465
|
+
const candidate = record3(record3(value2)?.candidate);
|
|
5443
5466
|
if (!candidate || typeof candidate.candidateId !== "string" || !/^ccand_[0-9a-f]{32}$/.test(candidate.candidateId) || !["submitted", "approved", "published", "failed"].includes(String(candidate.status))) {
|
|
5444
5467
|
throw invalid("candidate");
|
|
5445
5468
|
}
|
|
5446
5469
|
return { candidateId: candidate.candidateId, status: candidate.status };
|
|
5447
5470
|
}
|
|
5448
|
-
var record3 = (
|
|
5471
|
+
var record3 = (value2) => value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
|
|
5449
5472
|
var invalid = (part) => new CodeRuntimeControlError(`invalid Code runtime ${part} response`, 502, "invalid_response");
|
|
5450
5473
|
var RESERVED = /* @__PURE__ */ new Set([".git", ".odla", ".wrangler", "node_modules", "dist", "coverage"]);
|
|
5451
5474
|
var SECRET = /^(?:\.env(?:\..+)?|\.dev\.vars|credentials(?:\..+)?\.json|dev-token(?:\..+)?\.json)$/i;
|
|
@@ -5479,8 +5502,8 @@ function validateCodePatch(patch2, maxBytes) {
|
|
|
5479
5502
|
if (!paths.length || new Set(paths).size !== paths.length) throw new TypeError("patch has no diffs or repeats a path");
|
|
5480
5503
|
return paths;
|
|
5481
5504
|
}
|
|
5482
|
-
function validHeaderPath(
|
|
5483
|
-
return
|
|
5505
|
+
function validHeaderPath(value2, path, prefix) {
|
|
5506
|
+
return value2 === "/dev/null" || value2 === `${prefix}/${path}`;
|
|
5484
5507
|
}
|
|
5485
5508
|
function validateRelativePath(path) {
|
|
5486
5509
|
const parts = path.split("/");
|
|
@@ -5626,8 +5649,8 @@ function assertCodeBuildRecipe(recipe2) {
|
|
|
5626
5649
|
throw new TypeError("build recipe is malformed or exceeds its control bounds");
|
|
5627
5650
|
}
|
|
5628
5651
|
}
|
|
5629
|
-
function parseMemory(
|
|
5630
|
-
const match = /^([1-9][0-9]{0,4})([kmg])$/.exec(
|
|
5652
|
+
function parseMemory(value2) {
|
|
5653
|
+
const match = /^([1-9][0-9]{0,4})([kmg])$/.exec(value2.toLowerCase());
|
|
5631
5654
|
if (!match?.[1] || !match[2]) return 0;
|
|
5632
5655
|
const scale = match[2] === "k" ? 1024 : match[2] === "m" ? 1024 ** 2 : 1024 ** 3;
|
|
5633
5656
|
return Number(match[1]) * scale;
|
|
@@ -5862,14 +5885,14 @@ function normalizedRecipe(recipe2) {
|
|
|
5862
5885
|
expectedArtifacts: [...recipe2.expectedArtifacts ?? []].sort((left, right) => left.id.localeCompare(right.id)).map((artifact) => ({ id: artifact.id, path: artifact.path, maximumBytes: artifact.maximumBytes }))
|
|
5863
5886
|
};
|
|
5864
5887
|
}
|
|
5865
|
-
function digestJson(
|
|
5866
|
-
return digestBytes(JSON.stringify(
|
|
5888
|
+
function digestJson(value2) {
|
|
5889
|
+
return digestBytes(JSON.stringify(value2));
|
|
5867
5890
|
}
|
|
5868
|
-
function digestBytes(
|
|
5869
|
-
return `sha256:${(0, import_crypto3.createHash)("sha256").update(
|
|
5891
|
+
function digestBytes(value2) {
|
|
5892
|
+
return `sha256:${(0, import_crypto3.createHash)("sha256").update(value2).digest("hex")}`;
|
|
5870
5893
|
}
|
|
5871
|
-
function integer(
|
|
5872
|
-
return Number.isSafeInteger(
|
|
5894
|
+
function integer(value2, minimum, maximum) {
|
|
5895
|
+
return Number.isSafeInteger(value2) && value2 >= minimum && value2 <= maximum;
|
|
5873
5896
|
}
|
|
5874
5897
|
async function prepareRuntimeCheckpoint(input) {
|
|
5875
5898
|
const patch2 = await input.workspace.patch(256 * 1024);
|
|
@@ -5922,7 +5945,7 @@ async function prepareRuntimeCheckpoint(input) {
|
|
|
5922
5945
|
});
|
|
5923
5946
|
return { checkpoint, verification, review, note };
|
|
5924
5947
|
}
|
|
5925
|
-
var message = (
|
|
5948
|
+
var message = (value2) => (value2 instanceof Error ? value2.message : String(value2)).slice(0, 500);
|
|
5926
5949
|
var CodeRuntimeCheckpointManager = class {
|
|
5927
5950
|
constructor(options) {
|
|
5928
5951
|
this.options = options;
|
|
@@ -6116,7 +6139,7 @@ async function conversionPolicy(id, output) {
|
|
|
6116
6139
|
return { ...definition, digest: await conversionPolicyDigest(definition) };
|
|
6117
6140
|
}
|
|
6118
6141
|
async function registeredPolicy(id, registryId, values) {
|
|
6119
|
-
const mapping = Object.fromEntries(values.map((
|
|
6142
|
+
const mapping = Object.fromEntries(values.map((value2) => [value2, value2]));
|
|
6120
6143
|
return conversionPolicy(id, {
|
|
6121
6144
|
kind: "registered_id",
|
|
6122
6145
|
registryId,
|
|
@@ -6125,7 +6148,7 @@ async function registeredPolicy(id, registryId, values) {
|
|
|
6125
6148
|
}
|
|
6126
6149
|
async function conversionRegistry(policies, values) {
|
|
6127
6150
|
const registeredIds = Object.fromEntries(await Promise.all(Object.entries(values).map(async ([id, entries]) => {
|
|
6128
|
-
const mapping = Object.fromEntries(entries.map((
|
|
6151
|
+
const mapping = Object.fromEntries(entries.map((value2) => [value2, value2]));
|
|
6129
6152
|
return [id, { values: mapping, digest: await registeredIdRegistryDigest(mapping) }];
|
|
6130
6153
|
})));
|
|
6131
6154
|
return createConversionRegistry({ policies, registeredIds });
|
|
@@ -6149,8 +6172,8 @@ async function environment(input, options, tool) {
|
|
|
6149
6172
|
};
|
|
6150
6173
|
return { ingress, policy, fixedArgs, reader: ingress.control("reader"), runId: `${input.request.requestId}:${tool}` };
|
|
6151
6174
|
}
|
|
6152
|
-
function unsafe(base,
|
|
6153
|
-
return base.ingress.quarantinedOutput(
|
|
6175
|
+
function unsafe(base, value2, field) {
|
|
6176
|
+
return base.ingress.quarantinedOutput(value2, {
|
|
6154
6177
|
readers: base.reader.label.readers,
|
|
6155
6178
|
runId: `${base.runId}:${field}`
|
|
6156
6179
|
});
|
|
@@ -6230,14 +6253,14 @@ async function read(context, request2, options, policy) {
|
|
|
6230
6253
|
}
|
|
6231
6254
|
async function patch(context, request2, options, policy) {
|
|
6232
6255
|
exactKeys(request2.input, ["patch"]);
|
|
6233
|
-
const
|
|
6234
|
-
const paths = validateCodePatch(
|
|
6256
|
+
const value2 = stringField(request2.input, "patch");
|
|
6257
|
+
const paths = validateCodePatch(value2, options.maxPatchBytes ?? 256 * 1024);
|
|
6235
6258
|
if (paths.some((path) => options.readOnlyPrefixes?.some((prefix) => path === prefix || path.startsWith(`${prefix}/`)))) {
|
|
6236
6259
|
throw new TypeError("patch targets a read-only reference source");
|
|
6237
6260
|
}
|
|
6238
|
-
const allowed = await policy.patch(policyContext(context, request2, options, { patch:
|
|
6261
|
+
const allowed = await policy.patch(policyContext(context, request2, options, { patch: value2 }));
|
|
6239
6262
|
if (!allowed) return response(request2, false, "tool denied by CaMeL policy");
|
|
6240
|
-
await applyCodePatch(context.workspaceDir,
|
|
6263
|
+
await applyCodePatch(context.workspaceDir, value2, paths);
|
|
6241
6264
|
return response(request2, true, `Applied patch to ${paths.length} file(s).`, { paths });
|
|
6242
6265
|
}
|
|
6243
6266
|
async function recipe(context, request2, options, recipes, policy) {
|
|
@@ -6328,14 +6351,14 @@ function exactKeys(input, allowed) {
|
|
|
6328
6351
|
if (Object.keys(input).some((key) => !allowed.includes(key))) throw new TypeError("tool input contains an unsupported field");
|
|
6329
6352
|
}
|
|
6330
6353
|
function stringField(input, name) {
|
|
6331
|
-
const
|
|
6332
|
-
if (typeof
|
|
6333
|
-
return
|
|
6354
|
+
const value2 = input[name];
|
|
6355
|
+
if (typeof value2 !== "string" || !value2) throw new TypeError(`${name} must be a non-empty string`);
|
|
6356
|
+
return value2;
|
|
6334
6357
|
}
|
|
6335
|
-
function optionalInteger(
|
|
6336
|
-
if (
|
|
6337
|
-
if (!Number.isSafeInteger(
|
|
6338
|
-
return
|
|
6358
|
+
function optionalInteger(value2) {
|
|
6359
|
+
if (value2 === void 0) return void 0;
|
|
6360
|
+
if (!Number.isSafeInteger(value2) || value2 < 1) throw new TypeError("line bounds must be positive integers");
|
|
6361
|
+
return value2;
|
|
6339
6362
|
}
|
|
6340
6363
|
function response(request2, ok, content2, details) {
|
|
6341
6364
|
return { requestId: request2.requestId, ok, content: content2, ...details ? { details } : {} };
|
|
@@ -6381,9 +6404,9 @@ function codeLocalSource(payload) {
|
|
|
6381
6404
|
return source;
|
|
6382
6405
|
}
|
|
6383
6406
|
function codeCheckpointPayload(payload) {
|
|
6384
|
-
const
|
|
6385
|
-
if (!
|
|
6386
|
-
return
|
|
6407
|
+
const value2 = payload.checkpoint;
|
|
6408
|
+
if (!value2 || typeof value2 !== "object" || Array.isArray(value2)) throw new TypeError("resume checkpoint is missing");
|
|
6409
|
+
return value2;
|
|
6387
6410
|
}
|
|
6388
6411
|
function fakeCodeLease(command, metadata2) {
|
|
6389
6412
|
return {
|
|
@@ -6407,7 +6430,7 @@ function fakeCodeLease(command, metadata2) {
|
|
|
6407
6430
|
}
|
|
6408
6431
|
};
|
|
6409
6432
|
}
|
|
6410
|
-
var record22 = (
|
|
6433
|
+
var record22 = (value2) => value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
|
|
6411
6434
|
var SOURCE_LIMITS = { maxFiles: 2e4, maxBytes: 512 * 1024 * 1024 };
|
|
6412
6435
|
async function prepareRuntimeLocalSource(input) {
|
|
6413
6436
|
const { command, descriptor: descriptor2, available, repository, baseCommitSha, resume } = input;
|
|
@@ -6497,24 +6520,24 @@ async function appendCodeRuntimeEvent(control, command, event, refs) {
|
|
|
6497
6520
|
const bounded = event.type === "message" ? { ...event, body: event.body.trim().slice(0, 2e4) || `${event.actor} event` } : event;
|
|
6498
6521
|
await control.appendSessionEvent(command.sessionId, eventId, bounded);
|
|
6499
6522
|
}
|
|
6500
|
-
var digestRuntimeValue = (
|
|
6501
|
-
var runtimeErrorMessage = (
|
|
6502
|
-
var runtimeRecord = (
|
|
6503
|
-
var safeRuntimeJson = (
|
|
6523
|
+
var digestRuntimeValue = (value2) => `sha256:${(0, import_crypto4.createHash)("sha256").update(value2).digest("hex")}`;
|
|
6524
|
+
var runtimeErrorMessage = (value2) => value2 instanceof Error ? value2.message : String(value2);
|
|
6525
|
+
var runtimeRecord = (value2) => value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
|
|
6526
|
+
var safeRuntimeJson = (value2) => {
|
|
6504
6527
|
try {
|
|
6505
|
-
return JSON.stringify(
|
|
6528
|
+
return JSON.stringify(value2).slice(0, 1e4);
|
|
6506
6529
|
} catch {
|
|
6507
6530
|
return "[event]";
|
|
6508
6531
|
}
|
|
6509
6532
|
};
|
|
6510
|
-
function runtimeResultText(
|
|
6511
|
-
const record32 = runtimeRecord(
|
|
6533
|
+
function runtimeResultText(value2) {
|
|
6534
|
+
const record32 = runtimeRecord(value2);
|
|
6512
6535
|
if (record32 && typeof record32.text === "string") return record32.text.slice(0, 2e4);
|
|
6513
6536
|
if (record32 && typeof record32.error === "string") return `Pi failed: ${record32.error.slice(0, 19989)}`;
|
|
6514
6537
|
return null;
|
|
6515
6538
|
}
|
|
6516
|
-
function runtimeResultError(
|
|
6517
|
-
const record32 = runtimeRecord(
|
|
6539
|
+
function runtimeResultError(value2) {
|
|
6540
|
+
const record32 = runtimeRecord(value2);
|
|
6518
6541
|
return record32 && typeof record32.error === "string" && record32.error.trim() ? record32.error.trim().slice(0, 2e3) : null;
|
|
6519
6542
|
}
|
|
6520
6543
|
var CodePiRuntimeEngine = class {
|
|
@@ -6788,14 +6811,14 @@ var CodePiRuntimeEngine = class {
|
|
|
6788
6811
|
this.#active.delete(command.sessionId);
|
|
6789
6812
|
return result;
|
|
6790
6813
|
}
|
|
6791
|
-
async #failure(command, active,
|
|
6792
|
-
active.failure =
|
|
6814
|
+
async #failure(command, active, value2) {
|
|
6815
|
+
active.failure = value2.slice(0, 2e3);
|
|
6793
6816
|
if (active.acknowledged) {
|
|
6794
6817
|
await this.options.control.reportSessionFailure(command.sessionId, active.failure).catch(() => void 0);
|
|
6795
6818
|
}
|
|
6796
6819
|
}
|
|
6797
|
-
async #diagnostic(command, active,
|
|
6798
|
-
const detail =
|
|
6820
|
+
async #diagnostic(command, active, value2) {
|
|
6821
|
+
const detail = value2.trim().slice(0, 2e3) || "Pi runtime failed";
|
|
6799
6822
|
this.options.onDiagnostic?.(detail);
|
|
6800
6823
|
await this.#event(
|
|
6801
6824
|
command,
|
|
@@ -6880,6 +6903,7 @@ Usage:
|
|
|
6880
6903
|
odla-ai context save <name> [--platform <url>] [--app <id>] [--env <name>] [--json]
|
|
6881
6904
|
odla-ai context remove <name> --yes [--json]
|
|
6882
6905
|
odla-ai o11y status [--app <id>] [--context <name>] [--platform https://odla.ai] [--env prod] [--minutes 60] [--json]
|
|
6906
|
+
odla-ai platform status [--context <name>] [--platform https://odla.ai] [--email <odla-account>] [--json]
|
|
6883
6907
|
odla-ai whoami [--context <name>] [--platform https://odla.ai] [--json]
|
|
6884
6908
|
odla-ai runbook ask "<question>" [--app <id>] [--all] [--json]
|
|
6885
6909
|
odla-ai runbook search "<question>" [--app <id>] [--all] [--limit <n>] [--json]
|
|
@@ -7004,6 +7028,8 @@ Commands:
|
|
|
7004
7028
|
canary, collector ingest/scheduler trust, Cloudflare-owned
|
|
7005
7029
|
runtime metrics, and a machine verdict.
|
|
7006
7030
|
--json keeps auth progress on stderr for unattended agents.
|
|
7031
|
+
platform Read canonical fleet health, releases, provider load/freshness,
|
|
7032
|
+
explicit unknowns, and next actions through a read-only grant.
|
|
7007
7033
|
provision Register services, compose integrations, persist credentials, optionally push secrets.
|
|
7008
7034
|
smoke Verify credentials, public-config, composed schema, db aggregate, and integration probes.
|
|
7009
7035
|
skill Same installer; --agent accepts all, claude, codex, cursor,
|
|
@@ -7090,31 +7116,31 @@ async function requestHostedSecurityJson(options, path, init, action) {
|
|
|
7090
7116
|
}
|
|
7091
7117
|
return body;
|
|
7092
7118
|
}
|
|
7093
|
-
function hostedIdentifier(
|
|
7094
|
-
const result = optionalHostedText(
|
|
7119
|
+
function hostedIdentifier(value2, name) {
|
|
7120
|
+
const result = optionalHostedText(value2, name, 180);
|
|
7095
7121
|
if (!result || !/^[A-Za-z0-9][A-Za-z0-9._:-]*$/.test(result)) {
|
|
7096
7122
|
throw new Error(`${name} is invalid`);
|
|
7097
7123
|
}
|
|
7098
7124
|
return result;
|
|
7099
7125
|
}
|
|
7100
|
-
function positivePolicyVersion(
|
|
7101
|
-
if (!Number.isSafeInteger(
|
|
7126
|
+
function positivePolicyVersion(value2, name) {
|
|
7127
|
+
if (!Number.isSafeInteger(value2) || value2 < 1) {
|
|
7102
7128
|
throw new Error(`${name} is invalid`);
|
|
7103
7129
|
}
|
|
7104
|
-
return
|
|
7130
|
+
return value2;
|
|
7105
7131
|
}
|
|
7106
|
-
function optionalHostedText(
|
|
7107
|
-
if (
|
|
7108
|
-
if (typeof
|
|
7132
|
+
function optionalHostedText(value2, name, maxLength) {
|
|
7133
|
+
if (value2 === void 0 || value2 === null || value2 === "") return void 0;
|
|
7134
|
+
if (typeof value2 !== "string" || value2.length > maxLength || /[\u0000-\u001f\u007f]/.test(value2)) {
|
|
7109
7135
|
throw new Error(`${name} is invalid`);
|
|
7110
7136
|
}
|
|
7111
|
-
return
|
|
7137
|
+
return value2;
|
|
7112
7138
|
}
|
|
7113
|
-
function githubRepositoryName(
|
|
7114
|
-
if (typeof
|
|
7139
|
+
function githubRepositoryName(value2) {
|
|
7140
|
+
if (typeof value2 !== "string" || value2.length > 201) {
|
|
7115
7141
|
throw new Error("repository must be owner/name");
|
|
7116
7142
|
}
|
|
7117
|
-
const parts =
|
|
7143
|
+
const parts = value2.split("/");
|
|
7118
7144
|
const owner = parts[0] ?? "";
|
|
7119
7145
|
const name = (parts[1] ?? "").replace(/\.git$/i, "");
|
|
7120
7146
|
if (parts.length !== 2 || !/^[A-Za-z0-9](?:[A-Za-z0-9-]{0,98}[A-Za-z0-9])?$/.test(owner) || !/^[A-Za-z0-9_.-]{1,100}$/.test(name) || name === "." || name === "..") {
|
|
@@ -7122,10 +7148,10 @@ function githubRepositoryName(value) {
|
|
|
7122
7148
|
}
|
|
7123
7149
|
return `${owner}/${name}`;
|
|
7124
7150
|
}
|
|
7125
|
-
function trustedGitHubInstallUrl(
|
|
7151
|
+
function trustedGitHubInstallUrl(value2) {
|
|
7126
7152
|
let url;
|
|
7127
7153
|
try {
|
|
7128
|
-
url = new URL(
|
|
7154
|
+
url = new URL(value2);
|
|
7129
7155
|
} catch {
|
|
7130
7156
|
throw new Error("odla.ai returned an invalid GitHub installation URL");
|
|
7131
7157
|
}
|
|
@@ -7134,17 +7160,17 @@ function trustedGitHubInstallUrl(value) {
|
|
|
7134
7160
|
}
|
|
7135
7161
|
return url.toString();
|
|
7136
7162
|
}
|
|
7137
|
-
function hostedPollInterval(
|
|
7138
|
-
if (!Number.isSafeInteger(
|
|
7163
|
+
function hostedPollInterval(value2 = 2e3) {
|
|
7164
|
+
if (!Number.isSafeInteger(value2) || value2 < 100 || value2 > 3e4) {
|
|
7139
7165
|
throw new Error("poll interval must be 100-30000ms");
|
|
7140
7166
|
}
|
|
7141
|
-
return
|
|
7167
|
+
return value2;
|
|
7142
7168
|
}
|
|
7143
|
-
function hostedPollTimeout(
|
|
7144
|
-
if (!Number.isSafeInteger(
|
|
7169
|
+
function hostedPollTimeout(value2 = 10 * 6e4) {
|
|
7170
|
+
if (!Number.isSafeInteger(value2) || value2 < 1e3 || value2 > 60 * 6e4) {
|
|
7145
7171
|
throw new Error("poll timeout must be 1000-3600000ms");
|
|
7146
7172
|
}
|
|
7147
|
-
return
|
|
7173
|
+
return value2;
|
|
7148
7174
|
}
|
|
7149
7175
|
async function waitForHostedPoll(milliseconds, signal) {
|
|
7150
7176
|
if (signal?.aborted) throw signal.reason ?? new DOMException("aborted", "AbortError");
|
|
@@ -7156,16 +7182,16 @@ async function waitForHostedPoll(milliseconds, signal) {
|
|
|
7156
7182
|
}, { once: true });
|
|
7157
7183
|
});
|
|
7158
7184
|
}
|
|
7159
|
-
function isValidHostedSecurityPlan(
|
|
7160
|
-
if (!
|
|
7185
|
+
function isValidHostedSecurityPlan(value2, env) {
|
|
7186
|
+
if (!value2 || value2.env !== env || !/^sha256:[a-f0-9]{64}$/.test(value2.planDigest) || value2.consentContract !== "odla.hosted-security-consent.v1" || value2.reportProjection !== "odla.hosted-security-report.v1" || value2.redactionContract !== "odla.best-effort-credential-pattern-redaction.v1" || typeof value2.promptBundle !== "string" || value2.promptBundle.length < 1 || value2.promptBundle.length > 100 || typeof value2.ready !== "boolean" || typeof value2.independent !== "boolean" || value2.sourceDisclosure !== "redacted" || value2.targetExecution !== false || !Number.isSafeInteger(value2.reportRetentionDays) || value2.reportRetentionDays < 1) return false;
|
|
7161
7187
|
const validRoute = (route2, purpose) => !!route2 && route2.purpose === purpose && typeof route2.enabled === "boolean" && typeof route2.credentialReady === "boolean" && typeof route2.provider === "string" && route2.provider.length > 0 && route2.provider.length <= 100 && typeof route2.model === "string" && route2.model.length > 0 && route2.model.length <= 200 && Number.isSafeInteger(route2.policyVersion) && route2.policyVersion >= 1 && Number.isSafeInteger(route2.maxCallsPerRun) && route2.maxCallsPerRun >= 1 && Number.isSafeInteger(route2.maxInputBytes) && route2.maxInputBytes >= 1 && Number.isSafeInteger(route2.maxOutputTokens) && route2.maxOutputTokens >= 1;
|
|
7162
|
-
return validRoute(
|
|
7188
|
+
return validRoute(value2.routes?.discovery, "security.discovery") && validRoute(value2.routes?.validation, "security.validation");
|
|
7163
7189
|
}
|
|
7164
|
-
function hostedSecurityCredential(
|
|
7165
|
-
if (typeof
|
|
7190
|
+
function hostedSecurityCredential(value2) {
|
|
7191
|
+
if (typeof value2 !== "string" || value2.length < 8 || value2.length > 8192 || /\s|[\u0000-\u001f\u007f]/.test(value2)) {
|
|
7166
7192
|
throw new Error("Hosted security requires an injected odla developer token");
|
|
7167
7193
|
}
|
|
7168
|
-
return
|
|
7194
|
+
return value2;
|
|
7169
7195
|
}
|
|
7170
7196
|
|
|
7171
7197
|
// src/security-hosted-github.ts
|
|
@@ -7318,17 +7344,17 @@ async function prepareCodeLocalSource(cwd, repository, readHead = readGitHead) {
|
|
|
7318
7344
|
}
|
|
7319
7345
|
}
|
|
7320
7346
|
async function readGitHead(cwd) {
|
|
7321
|
-
const
|
|
7347
|
+
const value2 = await new Promise((accept, reject) => {
|
|
7322
7348
|
(0, import_node_child_process5.execFile)("git", ["rev-parse", "HEAD"], { cwd, encoding: "utf8", maxBuffer: 16384 }, (error, stdout) => {
|
|
7323
7349
|
if (error) reject(new Error("code connect requires a Git checkout with an initial commit"));
|
|
7324
7350
|
else accept(stdout.trim());
|
|
7325
7351
|
});
|
|
7326
7352
|
});
|
|
7327
|
-
if (!/^[0-9a-f]{40}$/.test(
|
|
7328
|
-
return
|
|
7353
|
+
if (!/^[0-9a-f]{40}$/.test(value2)) throw new Error("code connect could not resolve the checkout HEAD commit");
|
|
7354
|
+
return value2;
|
|
7329
7355
|
}
|
|
7330
|
-
function digestText(
|
|
7331
|
-
return `sha256:${(0, import_node_crypto.createHash)("sha256").update(
|
|
7356
|
+
function digestText(value2) {
|
|
7357
|
+
return `sha256:${(0, import_node_crypto.createHash)("sha256").update(value2).digest("hex")}`;
|
|
7332
7358
|
}
|
|
7333
7359
|
|
|
7334
7360
|
// src/code-images.ts
|
|
@@ -7599,8 +7625,8 @@ async function runCodeRuntime(input) {
|
|
|
7599
7625
|
for (const [name, handler] of handlers) process.removeListener(name, handler);
|
|
7600
7626
|
}
|
|
7601
7627
|
}
|
|
7602
|
-
function parseConnection(
|
|
7603
|
-
const root = record4(
|
|
7628
|
+
function parseConnection(value2, appId, appEnv) {
|
|
7629
|
+
const root = record4(value2);
|
|
7604
7630
|
const host = record4(root?.host);
|
|
7605
7631
|
const offer = record4(root?.offer);
|
|
7606
7632
|
const binding = record4(root?.binding);
|
|
@@ -7609,12 +7635,12 @@ function parseConnection(value, appId, appEnv) {
|
|
|
7609
7635
|
}
|
|
7610
7636
|
return root;
|
|
7611
7637
|
}
|
|
7612
|
-
function apiFailure(action, status,
|
|
7613
|
-
const message2 = record4(record4(
|
|
7638
|
+
function apiFailure(action, status, value2) {
|
|
7639
|
+
const message2 = record4(record4(value2)?.error)?.message;
|
|
7614
7640
|
return `${action} failed (${status})${typeof message2 === "string" ? `: ${message2}` : ""}`;
|
|
7615
7641
|
}
|
|
7616
|
-
function record4(
|
|
7617
|
-
return
|
|
7642
|
+
function record4(value2) {
|
|
7643
|
+
return value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
|
|
7618
7644
|
}
|
|
7619
7645
|
|
|
7620
7646
|
// src/code-command.ts
|
|
@@ -7673,8 +7699,8 @@ function developerTokenStatus(context, parsed, now = Date.now()) {
|
|
|
7673
7699
|
cacheStatus
|
|
7674
7700
|
};
|
|
7675
7701
|
}
|
|
7676
|
-
function clean3(
|
|
7677
|
-
const normalized =
|
|
7702
|
+
function clean3(value2) {
|
|
7703
|
+
const normalized = value2?.trim();
|
|
7678
7704
|
return normalized || void 0;
|
|
7679
7705
|
}
|
|
7680
7706
|
|
|
@@ -7823,8 +7849,8 @@ async function request(ctx, method, path, body) {
|
|
|
7823
7849
|
throw new Error(`discuss ${method} ${path} failed: ${data.error ?? `registry returned ${res.status}`}`);
|
|
7824
7850
|
return data;
|
|
7825
7851
|
}
|
|
7826
|
-
function emit(ctx,
|
|
7827
|
-
if (ctx.json) ctx.out.log(JSON.stringify(
|
|
7852
|
+
function emit(ctx, value2, human) {
|
|
7853
|
+
if (ctx.json) ctx.out.log(JSON.stringify(value2, null, 2));
|
|
7828
7854
|
else human();
|
|
7829
7855
|
}
|
|
7830
7856
|
var state = (topic) => topic.resolved ? "resolved" : "open";
|
|
@@ -7869,8 +7895,8 @@ async function discussList(ctx, parsed) {
|
|
|
7869
7895
|
["limit", "limit"],
|
|
7870
7896
|
["offset", "offset"]
|
|
7871
7897
|
]) {
|
|
7872
|
-
const
|
|
7873
|
-
if (
|
|
7898
|
+
const value2 = stringOpt(parsed.options[flag]);
|
|
7899
|
+
if (value2) query.set(param, value2);
|
|
7874
7900
|
}
|
|
7875
7901
|
const qs = query.toString();
|
|
7876
7902
|
const page = await request(ctx, "GET", `/topics${qs ? `?${qs}` : ""}`);
|
|
@@ -8067,11 +8093,11 @@ var MAX_CONSECUTIVE_FAILURES = 5;
|
|
|
8067
8093
|
var MAX_BACKOFF_MS = 3e4;
|
|
8068
8094
|
function numberOpt2(parsed, flag, fallback) {
|
|
8069
8095
|
const raw = stringOpt(parsed.options[flag]);
|
|
8070
|
-
const
|
|
8071
|
-
return Number.isFinite(
|
|
8096
|
+
const value2 = raw == null ? NaN : Number(raw);
|
|
8097
|
+
return Number.isFinite(value2) && value2 > 0 ? value2 : fallback;
|
|
8072
8098
|
}
|
|
8073
|
-
function jsonl(ctx, parsed,
|
|
8074
|
-
if (parsed.options.jsonl === true) ctx.out.log(JSON.stringify({ v: 1, ...
|
|
8099
|
+
function jsonl(ctx, parsed, value2) {
|
|
8100
|
+
if (parsed.options.jsonl === true) ctx.out.log(JSON.stringify({ v: 1, ...value2 }));
|
|
8075
8101
|
}
|
|
8076
8102
|
async function discussWatch(ctx, topicId, parsed) {
|
|
8077
8103
|
if (ctx.json && parsed.options.jsonl === true) throw new Error("--json and --jsonl cannot be combined");
|
|
@@ -8333,13 +8359,13 @@ async function pmRequest(ctx, method, path, body) {
|
|
|
8333
8359
|
function collectFields(parsed, allowClear) {
|
|
8334
8360
|
const out = {};
|
|
8335
8361
|
for (const [flag, spec] of Object.entries(FIELD_MAP)) {
|
|
8336
|
-
const
|
|
8337
|
-
if (
|
|
8338
|
-
if (
|
|
8362
|
+
const value2 = parsed.options[flag];
|
|
8363
|
+
if (value2 === void 0 || value2 === true) continue;
|
|
8364
|
+
if (value2 === false) {
|
|
8339
8365
|
if (allowClear) out[spec.key] = null;
|
|
8340
8366
|
continue;
|
|
8341
8367
|
}
|
|
8342
|
-
const text = stringOpt(
|
|
8368
|
+
const text = stringOpt(value2);
|
|
8343
8369
|
out[spec.key] = spec.num ? Number(text) : text;
|
|
8344
8370
|
}
|
|
8345
8371
|
return out;
|
|
@@ -8360,8 +8386,8 @@ function statusCol(entity, r) {
|
|
|
8360
8386
|
function printRecord(ctx, entity, r) {
|
|
8361
8387
|
ctx.out.log(`${r.id} [${statusCol(entity, r)}] ${r.appId} ${r.title ?? ""}`);
|
|
8362
8388
|
}
|
|
8363
|
-
function emit2(ctx,
|
|
8364
|
-
if (ctx.json) ctx.out.log(JSON.stringify(
|
|
8389
|
+
function emit2(ctx, value2, human) {
|
|
8390
|
+
if (ctx.json) ctx.out.log(JSON.stringify(value2, null, 2));
|
|
8365
8391
|
else human();
|
|
8366
8392
|
}
|
|
8367
8393
|
async function pmList(ctx, entity, parsed) {
|
|
@@ -8407,8 +8433,8 @@ async function pmAdd(ctx, entity, parsed) {
|
|
|
8407
8433
|
emit2(ctx, res, () => ctx.out.log(`created ${entity} ${res.id}`));
|
|
8408
8434
|
}
|
|
8409
8435
|
async function pmGet(ctx, entity, id) {
|
|
8410
|
-
const { record:
|
|
8411
|
-
emit2(ctx,
|
|
8436
|
+
const { record: record8 } = await pmRequest(ctx, "GET", `/${entity}/${encodeURIComponent(id)}`);
|
|
8437
|
+
emit2(ctx, record8, () => printRecord(ctx, entity, record8));
|
|
8412
8438
|
}
|
|
8413
8439
|
async function pmSet(ctx, entity, id, parsed) {
|
|
8414
8440
|
const patch2 = collectEntityFields(entity, parsed, true);
|
|
@@ -8453,9 +8479,9 @@ async function pmHandoff(ctx, parsed) {
|
|
|
8453
8479
|
]);
|
|
8454
8480
|
const handoff = {
|
|
8455
8481
|
appId,
|
|
8456
|
-
unmetGoals: goals.filter((
|
|
8457
|
-
activeTasks: tasks.filter((
|
|
8458
|
-
openBugs: bugs.filter((
|
|
8482
|
+
unmetGoals: goals.filter((record8) => record8.status !== "met"),
|
|
8483
|
+
activeTasks: tasks.filter((record8) => record8.column !== "done"),
|
|
8484
|
+
openBugs: bugs.filter((record8) => record8.status !== "fixed" && record8.status !== "wontfix")
|
|
8459
8485
|
};
|
|
8460
8486
|
const result = {
|
|
8461
8487
|
...handoff,
|
|
@@ -8474,10 +8500,10 @@ async function pmHandoff(ctx, parsed) {
|
|
|
8474
8500
|
]) {
|
|
8475
8501
|
ctx.out.log(`${label}:`);
|
|
8476
8502
|
if (!records.length) ctx.out.log("- (none)");
|
|
8477
|
-
else for (const
|
|
8503
|
+
else for (const record8 of records) printRecord(
|
|
8478
8504
|
ctx,
|
|
8479
8505
|
label === "unmet goals" ? "goal" : label === "active tasks" ? "task" : "bug",
|
|
8480
|
-
|
|
8506
|
+
record8
|
|
8481
8507
|
);
|
|
8482
8508
|
}
|
|
8483
8509
|
});
|
|
@@ -8625,6 +8651,113 @@ async function pmCommand(parsed, deps = {}) {
|
|
|
8625
8651
|
}
|
|
8626
8652
|
}
|
|
8627
8653
|
|
|
8654
|
+
// src/platform-output.ts
|
|
8655
|
+
function printPlatformStatus(status, out) {
|
|
8656
|
+
out.log(`platform ${status.verdict.status} ${status.observedAt}`);
|
|
8657
|
+
out.log(
|
|
8658
|
+
`fleet ${status.summary.healthy}/${status.summary.services} healthy ${status.summary.required} required ${status.summary.unreachable} unreachable ${status.summary.notConfigured} not configured`
|
|
8659
|
+
);
|
|
8660
|
+
out.log(`catalog ${status.catalog.revision}`);
|
|
8661
|
+
out.log(
|
|
8662
|
+
"service required health probe ms version provider age requests errors cpu p99 us wall p99 us"
|
|
8663
|
+
);
|
|
8664
|
+
for (const service of status.services) {
|
|
8665
|
+
const metrics = service.provider.metrics;
|
|
8666
|
+
out.log([
|
|
8667
|
+
service.id,
|
|
8668
|
+
service.required ? "yes" : "no",
|
|
8669
|
+
service.health.status,
|
|
8670
|
+
value(service.health.latencyMs),
|
|
8671
|
+
service.release.observedVersionId ?? "unknown",
|
|
8672
|
+
service.provider.status,
|
|
8673
|
+
age(service.provider.ageMs),
|
|
8674
|
+
value(metrics?.requests),
|
|
8675
|
+
value(metrics?.errors),
|
|
8676
|
+
value(metrics?.cpuTimeP99),
|
|
8677
|
+
value(metrics?.wallTimeP99)
|
|
8678
|
+
].join(" "));
|
|
8679
|
+
}
|
|
8680
|
+
if (status.verdict.reasons.length) {
|
|
8681
|
+
out.log(`reasons ${status.verdict.reasons.join(", ")}`);
|
|
8682
|
+
}
|
|
8683
|
+
for (const action of status.nextActions) {
|
|
8684
|
+
out.log(`next ${action.service} ${action.code} ${action.message}`);
|
|
8685
|
+
}
|
|
8686
|
+
}
|
|
8687
|
+
function value(input) {
|
|
8688
|
+
return input === null || input === void 0 ? "unknown" : String(input);
|
|
8689
|
+
}
|
|
8690
|
+
function age(input) {
|
|
8691
|
+
if (input === null) return "unknown";
|
|
8692
|
+
if (input < 1e3) return `${input}ms`;
|
|
8693
|
+
if (input < 6e4) return `${Math.round(input / 1e3)}s`;
|
|
8694
|
+
return `${Math.round(input / 6e4)}m`;
|
|
8695
|
+
}
|
|
8696
|
+
|
|
8697
|
+
// src/platform-command.ts
|
|
8698
|
+
async function platformCommand(parsed, deps = {}) {
|
|
8699
|
+
assertArgs(
|
|
8700
|
+
parsed,
|
|
8701
|
+
["config", "context", "platform", "token", "email", "open", "json"],
|
|
8702
|
+
2
|
|
8703
|
+
);
|
|
8704
|
+
const action = parsed.positionals[1];
|
|
8705
|
+
if (action !== "status") {
|
|
8706
|
+
throw new Error(
|
|
8707
|
+
`unknown platform action "${action ?? ""}". Try "odla-ai platform status --json".`
|
|
8708
|
+
);
|
|
8709
|
+
}
|
|
8710
|
+
const context = await resolveOperatorContext(parsed, {
|
|
8711
|
+
allowMissingConfig: true
|
|
8712
|
+
});
|
|
8713
|
+
const platform = context.platform.value;
|
|
8714
|
+
const doFetch = deps.fetch ?? fetch;
|
|
8715
|
+
const out = deps.stdout ?? console;
|
|
8716
|
+
const token = await resolveAdminPlatformToken({
|
|
8717
|
+
platform,
|
|
8718
|
+
scope: "platform:status:read",
|
|
8719
|
+
token: stringOpt(parsed.options.token),
|
|
8720
|
+
tokenFile: context.credentials.scopedTokenFile,
|
|
8721
|
+
email: stringOpt(parsed.options.email),
|
|
8722
|
+
open: parsed.options.open === false ? false : parsed.options.open === true ? true : void 0,
|
|
8723
|
+
fetch: doFetch,
|
|
8724
|
+
stdout: out,
|
|
8725
|
+
openApprovalUrl: deps.openUrl,
|
|
8726
|
+
label: "odla CLI (platform fleet status)"
|
|
8727
|
+
});
|
|
8728
|
+
const response2 = await doFetch(`${platform}/registry/platform/status`, {
|
|
8729
|
+
headers: { authorization: `Bearer ${token}` }
|
|
8730
|
+
});
|
|
8731
|
+
const body = await response2.json().catch(() => null);
|
|
8732
|
+
if (!response2.ok) {
|
|
8733
|
+
throw new Error(
|
|
8734
|
+
`read platform status failed (HTTP ${response2.status}): ${apiMessage(body)}`
|
|
8735
|
+
);
|
|
8736
|
+
}
|
|
8737
|
+
if (!isPlatformStatus(body)) {
|
|
8738
|
+
throw new Error("platform returned an invalid odla.platform-status/v1 envelope");
|
|
8739
|
+
}
|
|
8740
|
+
if (parsed.options.json === true) {
|
|
8741
|
+
out.log(JSON.stringify(body, null, 2));
|
|
8742
|
+
} else {
|
|
8743
|
+
printPlatformStatus(body, out);
|
|
8744
|
+
}
|
|
8745
|
+
}
|
|
8746
|
+
function isPlatformStatus(value2) {
|
|
8747
|
+
if (!record5(value2) || value2.schemaVersion !== "odla.platform-status/v1") return false;
|
|
8748
|
+
if (!record5(value2.verdict) || !Array.isArray(value2.verdict.reasons)) return false;
|
|
8749
|
+
if (!record5(value2.catalog) || !record5(value2.summary)) return false;
|
|
8750
|
+
return Array.isArray(value2.services) && Array.isArray(value2.nextActions);
|
|
8751
|
+
}
|
|
8752
|
+
function apiMessage(value2) {
|
|
8753
|
+
if (!record5(value2)) return "request failed";
|
|
8754
|
+
const error = record5(value2.error) ? value2.error : value2;
|
|
8755
|
+
return typeof error.message === "string" ? error.message : typeof error.code === "string" ? error.code : "request failed";
|
|
8756
|
+
}
|
|
8757
|
+
function record5(value2) {
|
|
8758
|
+
return !!value2 && typeof value2 === "object" && !Array.isArray(value2);
|
|
8759
|
+
}
|
|
8760
|
+
|
|
8628
8761
|
// src/o11y-verdict.ts
|
|
8629
8762
|
function statusVerdict(reads) {
|
|
8630
8763
|
const reasons = [];
|
|
@@ -8662,7 +8795,7 @@ function statusVerdict(reads) {
|
|
|
8662
8795
|
severity: "degraded"
|
|
8663
8796
|
});
|
|
8664
8797
|
}
|
|
8665
|
-
const performance =
|
|
8798
|
+
const performance = record6(reads.liveSync.body.performance) ? reads.liveSync.body.performance : null;
|
|
8666
8799
|
if (performance?.status === "unavailable") {
|
|
8667
8800
|
reasons.push({
|
|
8668
8801
|
source: "liveSync",
|
|
@@ -8743,11 +8876,11 @@ function statusVerdict(reads) {
|
|
|
8743
8876
|
reasons
|
|
8744
8877
|
};
|
|
8745
8878
|
}
|
|
8746
|
-
function
|
|
8747
|
-
return Boolean(
|
|
8879
|
+
function record6(value2) {
|
|
8880
|
+
return Boolean(value2) && typeof value2 === "object" && !Array.isArray(value2);
|
|
8748
8881
|
}
|
|
8749
|
-
function numeric2(
|
|
8750
|
-
return typeof
|
|
8882
|
+
function numeric2(value2) {
|
|
8883
|
+
return typeof value2 === "number" && Number.isFinite(value2) ? value2 : 0;
|
|
8751
8884
|
}
|
|
8752
8885
|
function collectorReason(read3, fallback) {
|
|
8753
8886
|
const reasons = read3.body.reasons;
|
|
@@ -8771,7 +8904,7 @@ function printO11yStatus(status, out) {
|
|
|
8771
8904
|
out.log(
|
|
8772
8905
|
`o11y status ${status.scope.appId}/${status.scope.env} (${status.scope.minutes}m)`
|
|
8773
8906
|
);
|
|
8774
|
-
const routes = Array.isArray(status.application.body.routes) ? status.application.body.routes.filter(
|
|
8907
|
+
const routes = Array.isArray(status.application.body.routes) ? status.application.body.routes.filter(record7) : [];
|
|
8775
8908
|
const requests = routes.reduce(
|
|
8776
8909
|
(total, row) => total + numeric3(row.requests),
|
|
8777
8910
|
0
|
|
@@ -8783,39 +8916,39 @@ function printO11yStatus(status, out) {
|
|
|
8783
8916
|
out.log(
|
|
8784
8917
|
`application ${status.application.httpStatus} ${requests} requests ${errors} errors`
|
|
8785
8918
|
);
|
|
8786
|
-
const versions = Array.isArray(status.applicationVersions.body.rows) ? status.applicationVersions.body.rows.filter(
|
|
8919
|
+
const versions = Array.isArray(status.applicationVersions.body.rows) ? status.applicationVersions.body.rows.filter(record7) : [];
|
|
8787
8920
|
out.log(
|
|
8788
8921
|
`application-versions ${status.applicationVersions.httpStatus} ${versions.length ? versions.slice(0, 5).map(
|
|
8789
8922
|
(row) => `${String(row.value || "(unattributed)")}:${numeric3(row.requests)}`
|
|
8790
8923
|
).join(", ") : "none observed"}`
|
|
8791
8924
|
);
|
|
8792
8925
|
out.log(liveSyncLine(status.liveSync));
|
|
8793
|
-
const canaryDurations =
|
|
8926
|
+
const canaryDurations = record7(status.canary.body.durationsMs) ? status.canary.body.durationsMs : {};
|
|
8794
8927
|
out.log(
|
|
8795
8928
|
`canary ${status.canary.httpStatus} ${String(status.canary.body.status ?? status.canary.body.error ?? "unavailable")} ${optionalNumeric(canaryDurations.publishToVisibleMs)} publish-to-visible`
|
|
8796
8929
|
);
|
|
8797
|
-
const collectorIngest =
|
|
8798
|
-
const collectorStorage =
|
|
8930
|
+
const collectorIngest = record7(status.collector.body.ingest) ? status.collector.body.ingest : {};
|
|
8931
|
+
const collectorStorage = record7(collectorIngest.storage) ? collectorIngest.storage : {};
|
|
8799
8932
|
out.log(
|
|
8800
8933
|
`collector ${status.collector.httpStatus} ${String(status.collector.body.status ?? status.collector.body.error ?? "unavailable")} ${numeric3(collectorStorage.affectedPoints)} affected points`
|
|
8801
8934
|
);
|
|
8802
|
-
const providerMetrics =
|
|
8803
|
-
const providerCapacity =
|
|
8804
|
-
const workerMemory =
|
|
8935
|
+
const providerMetrics = record7(status.provider.body.metrics) ? status.provider.body.metrics : {};
|
|
8936
|
+
const providerCapacity = record7(status.provider.body.capacity) ? status.provider.body.capacity : {};
|
|
8937
|
+
const workerMemory = record7(providerCapacity.memory) ? providerCapacity.memory : {};
|
|
8805
8938
|
out.log(
|
|
8806
8939
|
`cloudflare ${status.provider.httpStatus} ${String(status.provider.body.status ?? status.provider.body.error ?? "unavailable")} ${numeric3(providerMetrics.requests)} invocations ${numeric3(providerMetrics.errors)} runtime errors ${optionalBytes(workerMemory.headroomBytes)} isolate memory headroom`
|
|
8807
8940
|
);
|
|
8808
8941
|
for (const line of providerCapacityLines(status.providerCapacity)) {
|
|
8809
8942
|
out.log(line);
|
|
8810
8943
|
}
|
|
8811
|
-
const coverage =
|
|
8812
|
-
const coverageCounts =
|
|
8813
|
-
const coverageBudget =
|
|
8944
|
+
const coverage = record7(status.providerReconciliation.body.comparison) ? status.providerReconciliation.body.comparison : {};
|
|
8945
|
+
const coverageCounts = record7(status.providerReconciliation.body.counts) ? status.providerReconciliation.body.counts : {};
|
|
8946
|
+
const coverageBudget = record7(status.providerReconciliation.body.budget) ? status.providerReconciliation.body.budget : {};
|
|
8814
8947
|
out.log(
|
|
8815
8948
|
`request-coverage ${status.providerReconciliation.httpStatus} ${String(status.providerReconciliation.body.status ?? status.providerReconciliation.body.error ?? "unavailable")} ${optionalPercent(coverage.applicationCoverage)} application/provider ${numeric3(coverageCounts.applicationRequests)}/${numeric3(coverageCounts.providerRequests)} requests \xB1${optionalPercent(coverageBudget.maxRelativeError)} budget`
|
|
8816
8949
|
);
|
|
8817
8950
|
const providerPoints = Array.isArray(status.providerHistory.body.points) ? status.providerHistory.body.points.length : 0;
|
|
8818
|
-
const providerFreshness =
|
|
8951
|
+
const providerFreshness = record7(status.providerHistory.body.freshness) ? status.providerHistory.body.freshness : {};
|
|
8819
8952
|
out.log(
|
|
8820
8953
|
`cloudflare-history ${status.providerHistory.httpStatus} ${String(status.providerHistory.body.status ?? status.providerHistory.body.error ?? "unavailable")} ${providerPoints} snapshots ${optionalAge(providerFreshness.ageMs)} old`
|
|
8821
8954
|
);
|
|
@@ -8824,17 +8957,17 @@ function printO11yStatus(status, out) {
|
|
|
8824
8957
|
);
|
|
8825
8958
|
}
|
|
8826
8959
|
function providerCapacityLines(read3) {
|
|
8827
|
-
const resources =
|
|
8828
|
-
const durableObjects =
|
|
8829
|
-
const periodic =
|
|
8830
|
-
const storage =
|
|
8831
|
-
const d1 =
|
|
8832
|
-
const d1Activity =
|
|
8833
|
-
const d1Storage =
|
|
8834
|
-
const d1Latency =
|
|
8835
|
-
const r2 =
|
|
8836
|
-
const r2Operations =
|
|
8837
|
-
const r2Storage =
|
|
8960
|
+
const resources = record7(read3.body.resources) ? read3.body.resources : {};
|
|
8961
|
+
const durableObjects = record7(resources.durableObjects) ? resources.durableObjects : {};
|
|
8962
|
+
const periodic = record7(durableObjects.periodic) ? durableObjects.periodic : {};
|
|
8963
|
+
const storage = record7(durableObjects.sqliteStorage) ? durableObjects.sqliteStorage : {};
|
|
8964
|
+
const d1 = record7(resources.d1) ? resources.d1 : {};
|
|
8965
|
+
const d1Activity = record7(d1.activity) ? d1.activity : {};
|
|
8966
|
+
const d1Storage = record7(d1.storage) ? d1.storage : {};
|
|
8967
|
+
const d1Latency = record7(d1Activity.latency) ? d1Activity.latency : {};
|
|
8968
|
+
const r2 = record7(resources.r2) ? resources.r2 : {};
|
|
8969
|
+
const r2Operations = record7(r2.operations) ? r2.operations : {};
|
|
8970
|
+
const r2Storage = record7(r2.storage) ? r2.storage : {};
|
|
8838
8971
|
const status = String(
|
|
8839
8972
|
read3.body.status ?? read3.body.error ?? "unavailable"
|
|
8840
8973
|
);
|
|
@@ -8845,42 +8978,42 @@ function providerCapacityLines(read3) {
|
|
|
8845
8978
|
];
|
|
8846
8979
|
}
|
|
8847
8980
|
function liveSyncLine(read3) {
|
|
8848
|
-
const performance =
|
|
8849
|
-
const commitToSend =
|
|
8981
|
+
const performance = record7(read3.body.performance) ? read3.body.performance : {};
|
|
8982
|
+
const commitToSend = record7(performance.commitToSend) ? performance.commitToSend : {};
|
|
8850
8983
|
return `live-sync ${read3.httpStatus} ${String(read3.body.status ?? read3.body.error ?? "unavailable")} ${numeric3(read3.body.activeConnections)} active ${optionalNumeric(commitToSend.p95)} commit-to-send p95 ${numeric3(performance.sendFailures)} send failures`;
|
|
8851
8984
|
}
|
|
8852
|
-
function
|
|
8853
|
-
return Boolean(
|
|
8985
|
+
function record7(value2) {
|
|
8986
|
+
return Boolean(value2) && typeof value2 === "object" && !Array.isArray(value2);
|
|
8854
8987
|
}
|
|
8855
|
-
function numeric3(
|
|
8856
|
-
return typeof
|
|
8988
|
+
function numeric3(value2) {
|
|
8989
|
+
return typeof value2 === "number" && Number.isFinite(value2) ? value2 : 0;
|
|
8857
8990
|
}
|
|
8858
|
-
function optionalNumeric(
|
|
8859
|
-
return typeof
|
|
8991
|
+
function optionalNumeric(value2) {
|
|
8992
|
+
return typeof value2 === "number" && Number.isFinite(value2) ? `${value2} ms` : "\u2014";
|
|
8860
8993
|
}
|
|
8861
|
-
function optionalAge(
|
|
8862
|
-
if (typeof
|
|
8863
|
-
return `${Math.max(0, Math.round(
|
|
8994
|
+
function optionalAge(value2) {
|
|
8995
|
+
if (typeof value2 !== "number" || !Number.isFinite(value2)) return "unknown";
|
|
8996
|
+
return `${Math.max(0, Math.round(value2 / 1e3))}s`;
|
|
8864
8997
|
}
|
|
8865
|
-
function optionalPercent(
|
|
8866
|
-
return typeof
|
|
8998
|
+
function optionalPercent(value2) {
|
|
8999
|
+
return typeof value2 === "number" && Number.isFinite(value2) ? `${Math.round(value2 * 100)}%` : "\u2014";
|
|
8867
9000
|
}
|
|
8868
|
-
function optionalBytes(
|
|
8869
|
-
if (typeof
|
|
8870
|
-
if (
|
|
8871
|
-
return `${(
|
|
9001
|
+
function optionalBytes(value2) {
|
|
9002
|
+
if (typeof value2 !== "number" || !Number.isFinite(value2)) return "\u2014";
|
|
9003
|
+
if (value2 >= 1024 * 1024 * 1024) {
|
|
9004
|
+
return `${(value2 / (1024 * 1024 * 1024)).toFixed(2)} GiB`;
|
|
8872
9005
|
}
|
|
8873
|
-
if (
|
|
8874
|
-
return `${(
|
|
9006
|
+
if (value2 >= 1024 * 1024) {
|
|
9007
|
+
return `${(value2 / (1024 * 1024)).toFixed(1)} MiB`;
|
|
8875
9008
|
}
|
|
8876
|
-
if (
|
|
8877
|
-
return `${Math.round(
|
|
9009
|
+
if (value2 >= 1024) return `${(value2 / 1024).toFixed(1)} KiB`;
|
|
9010
|
+
return `${Math.round(value2)} B`;
|
|
8878
9011
|
}
|
|
8879
|
-
function optionalCount(
|
|
8880
|
-
return typeof
|
|
9012
|
+
function optionalCount(value2, unit) {
|
|
9013
|
+
return typeof value2 === "number" && Number.isFinite(value2) ? `${value2} ${unit}` : `\u2014 ${unit}`;
|
|
8881
9014
|
}
|
|
8882
|
-
function optionalAgeSeconds(
|
|
8883
|
-
return typeof
|
|
9015
|
+
function optionalAgeSeconds(value2) {
|
|
9016
|
+
return typeof value2 === "number" && Number.isFinite(value2) ? `${Math.max(0, Math.round(value2))}s` : "unknown";
|
|
8884
9017
|
}
|
|
8885
9018
|
|
|
8886
9019
|
// src/o11y-command.ts
|
|
@@ -9010,11 +9143,11 @@ async function o11yCommand(parsed, deps = {}) {
|
|
|
9010
9143
|
}
|
|
9011
9144
|
printO11yStatus(status, out);
|
|
9012
9145
|
}
|
|
9013
|
-
function statusMinutes(
|
|
9014
|
-
if (!Number.isSafeInteger(
|
|
9146
|
+
function statusMinutes(value2) {
|
|
9147
|
+
if (!Number.isSafeInteger(value2) || value2 < 1 || value2 > 7 * 24 * 60) {
|
|
9015
9148
|
throw new Error("--minutes must be an integer from 1 to 10080");
|
|
9016
9149
|
}
|
|
9017
|
-
return
|
|
9150
|
+
return value2;
|
|
9018
9151
|
}
|
|
9019
9152
|
async function read2(url, headers, doFetch) {
|
|
9020
9153
|
const response2 = await doFetch(url, { headers });
|
|
@@ -9022,8 +9155,8 @@ async function read2(url, headers, doFetch) {
|
|
|
9022
9155
|
let body = {};
|
|
9023
9156
|
if (text) {
|
|
9024
9157
|
try {
|
|
9025
|
-
const
|
|
9026
|
-
body =
|
|
9158
|
+
const value2 = JSON.parse(text);
|
|
9159
|
+
body = value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : { value: value2 };
|
|
9027
9160
|
} catch {
|
|
9028
9161
|
body = { message: text.slice(0, 300) };
|
|
9029
9162
|
}
|
|
@@ -9032,7 +9165,7 @@ async function read2(url, headers, doFetch) {
|
|
|
9032
9165
|
}
|
|
9033
9166
|
|
|
9034
9167
|
// src/provision.ts
|
|
9035
|
-
var
|
|
9168
|
+
var import_apps7 = require("@odla-ai/apps");
|
|
9036
9169
|
var import_ai3 = require("@odla-ai/ai");
|
|
9037
9170
|
var import_node_process10 = __toESM(require("process"), 1);
|
|
9038
9171
|
|
|
@@ -9077,8 +9210,8 @@ async function postJson2(doFetch, url, bearer, body) {
|
|
|
9077
9210
|
if (!res.ok) throw new Error(`${new URL(url).pathname} failed: ${res.status} ${await responseText(res)}`);
|
|
9078
9211
|
return res.json().catch(() => ({}));
|
|
9079
9212
|
}
|
|
9080
|
-
function isRecord7(
|
|
9081
|
-
return
|
|
9213
|
+
function isRecord7(value2) {
|
|
9214
|
+
return value2 !== null && typeof value2 === "object" && !Array.isArray(value2);
|
|
9082
9215
|
}
|
|
9083
9216
|
async function responseText(res) {
|
|
9084
9217
|
try {
|
|
@@ -9089,9 +9222,9 @@ async function responseText(res) {
|
|
|
9089
9222
|
}
|
|
9090
9223
|
|
|
9091
9224
|
// src/provision-credentials.ts
|
|
9092
|
-
var
|
|
9225
|
+
var import_apps5 = require("@odla-ai/apps");
|
|
9093
9226
|
async function provisionEnvCredentials(opts) {
|
|
9094
|
-
const tenantId = (0,
|
|
9227
|
+
const tenantId = (0, import_apps5.tenantIdFor)(opts.cfg.app.id, opts.env);
|
|
9095
9228
|
const prior = opts.credentials?.envs[opts.env];
|
|
9096
9229
|
let credentials = opts.credentials;
|
|
9097
9230
|
let dbKey = opts.cfg.services.includes("db") && !opts.rotateDb ? prior?.dbKey : void 0;
|
|
@@ -9185,18 +9318,13 @@ async function safeText4(res) {
|
|
|
9185
9318
|
|
|
9186
9319
|
// src/provision-helpers.ts
|
|
9187
9320
|
var import_ai2 = require("@odla-ai/ai");
|
|
9188
|
-
var
|
|
9189
|
-
function serviceRank(service) {
|
|
9190
|
-
if (service === "db") return 0;
|
|
9191
|
-
if (service === "calendar") return 2;
|
|
9192
|
-
return 1;
|
|
9193
|
-
}
|
|
9321
|
+
var import_apps6 = require("@odla-ai/apps");
|
|
9194
9322
|
function defaultSecretName(provider) {
|
|
9195
9323
|
const names = import_ai2.DEFAULT_SECRET_NAMES;
|
|
9196
9324
|
return names[provider] ?? `${provider}_api_key`;
|
|
9197
9325
|
}
|
|
9198
9326
|
async function assertTenantAdminAccess(doFetch, cfg, env, token) {
|
|
9199
|
-
const tenantId = (0,
|
|
9327
|
+
const tenantId = (0, import_apps6.tenantIdFor)(cfg.app.id, env);
|
|
9200
9328
|
const res = await doFetch(`${cfg.dbEndpoint}/admin/apps/${encodeURIComponent(tenantId)}/entitlements`, {
|
|
9201
9329
|
headers: { authorization: `Bearer ${token}` }
|
|
9202
9330
|
});
|
|
@@ -9216,14 +9344,14 @@ async function postJson3(doFetch, url, bearer, body) {
|
|
|
9216
9344
|
});
|
|
9217
9345
|
if (!res.ok) throw new Error(`${new URL(url).pathname} failed: ${res.status} ${await safeText5(res)}`);
|
|
9218
9346
|
}
|
|
9219
|
-
function normalizeClerkConfig(
|
|
9220
|
-
if (!
|
|
9221
|
-
if (typeof
|
|
9222
|
-
const publishableKey2 = envValue(
|
|
9347
|
+
function normalizeClerkConfig(value2) {
|
|
9348
|
+
if (!value2) return null;
|
|
9349
|
+
if (typeof value2 === "string") {
|
|
9350
|
+
const publishableKey2 = envValue(value2);
|
|
9223
9351
|
return publishableKey2 ? { publishableKey: publishableKey2 } : null;
|
|
9224
9352
|
}
|
|
9225
|
-
if (typeof
|
|
9226
|
-
const cfg =
|
|
9353
|
+
if (typeof value2 !== "object") return null;
|
|
9354
|
+
const cfg = value2;
|
|
9227
9355
|
const publishableKey = envValue(cfg.publishableKey);
|
|
9228
9356
|
return publishableKey ? { publishableKey, ...cfg.audience ? { audience: cfg.audience } : {}, ...cfg.mode ? { mode: cfg.mode } : {} } : null;
|
|
9229
9357
|
}
|
|
@@ -9305,7 +9433,7 @@ async function provision(options) {
|
|
|
9305
9433
|
}
|
|
9306
9434
|
const doFetch = options.fetch ?? fetch;
|
|
9307
9435
|
const token = await getDeveloperToken(cfg, options, doFetch, out);
|
|
9308
|
-
const apps = (0,
|
|
9436
|
+
const apps = (0, import_apps7.createAppsClient)({ endpoint: cfg.platformUrl, token, fetcher: { fetch: doFetch } });
|
|
9309
9437
|
const existing = await apps.resolveApp(cfg.app.id);
|
|
9310
9438
|
if (existing) {
|
|
9311
9439
|
out.log(`app: ${cfg.app.id} already exists`);
|
|
@@ -9316,7 +9444,7 @@ async function provision(options) {
|
|
|
9316
9444
|
for (const env of cfg.envs) {
|
|
9317
9445
|
await assertTenantAdminAccess(doFetch, cfg, env, token);
|
|
9318
9446
|
}
|
|
9319
|
-
const serviceOrder =
|
|
9447
|
+
const serviceOrder = (0, import_apps7.orderAppServices)(cfg.services);
|
|
9320
9448
|
for (const env of cfg.envs) {
|
|
9321
9449
|
for (const service of serviceOrder) {
|
|
9322
9450
|
if (service === "ai") {
|
|
@@ -9349,7 +9477,7 @@ async function provision(options) {
|
|
|
9349
9477
|
}
|
|
9350
9478
|
}
|
|
9351
9479
|
for (const env of cfg.envs) {
|
|
9352
|
-
const tenantId = (0,
|
|
9480
|
+
const tenantId = (0, import_apps7.tenantIdFor)(cfg.app.id, env);
|
|
9353
9481
|
credentials = await provisionEnvCredentials({
|
|
9354
9482
|
cfg,
|
|
9355
9483
|
env,
|
|
@@ -9500,6 +9628,7 @@ var COMMAND_SURFACE = {
|
|
|
9500
9628
|
help: {},
|
|
9501
9629
|
init: {},
|
|
9502
9630
|
o11y: { status: {} },
|
|
9631
|
+
platform: { status: {} },
|
|
9503
9632
|
pm: {
|
|
9504
9633
|
...PM_ENTITIES,
|
|
9505
9634
|
handoff: {}
|
|
@@ -9592,7 +9721,7 @@ function recordInvocation(parsed) {
|
|
|
9592
9721
|
try {
|
|
9593
9722
|
const entry = {
|
|
9594
9723
|
path: invocationPath(parsed.positionals),
|
|
9595
|
-
options: Object.entries(parsed.options).map(([name,
|
|
9724
|
+
options: Object.entries(parsed.options).map(([name, value2]) => value2 === false ? `no-${name}` : name).sort()
|
|
9596
9725
|
};
|
|
9597
9726
|
if (!entry.path.length) return;
|
|
9598
9727
|
(0, import_node_fs15.appendFileSync)(file, `${JSON.stringify(entry)}
|
|
@@ -9606,10 +9735,10 @@ var import_node_fs16 = require("fs");
|
|
|
9606
9735
|
|
|
9607
9736
|
// src/runbook-requires.ts
|
|
9608
9737
|
var SPEC = /^(@?[\w./-]+?)@(\d+\.\d+\.\d+(?:[\w.-]*)?)$/;
|
|
9609
|
-
function parseRequires(
|
|
9610
|
-
if (!
|
|
9738
|
+
function parseRequires(value2) {
|
|
9739
|
+
if (!value2) return [];
|
|
9611
9740
|
const out = [];
|
|
9612
|
-
for (const token of
|
|
9741
|
+
for (const token of value2.split(/[\s,]+/).filter(Boolean)) {
|
|
9613
9742
|
const match = SPEC.exec(token);
|
|
9614
9743
|
if (match?.[1] && match[2]) out.push({ name: match[1], min: match[2] });
|
|
9615
9744
|
}
|
|
@@ -9785,9 +9914,9 @@ function parseRunbook(text, slug) {
|
|
|
9785
9914
|
for (const line of fm[1].split(/\r?\n/)) {
|
|
9786
9915
|
const pair = /^(\w+)\s*:\s*(.+)$/.exec(line.trim());
|
|
9787
9916
|
if (!pair) continue;
|
|
9788
|
-
const
|
|
9789
|
-
if (pair[1] === "summary") meta.summary =
|
|
9790
|
-
if (pair[1] === "tags") meta.tags =
|
|
9917
|
+
const value2 = pair[2].trim().replace(/^["']|["']$/g, "");
|
|
9918
|
+
if (pair[1] === "summary") meta.summary = value2;
|
|
9919
|
+
if (pair[1] === "tags") meta.tags = value2.replace(/^\[|\]$/g, "").trim();
|
|
9791
9920
|
}
|
|
9792
9921
|
}
|
|
9793
9922
|
const lines = rest.split("\n");
|
|
@@ -9904,7 +10033,7 @@ var NOISE = /* @__PURE__ */ new Set([
|
|
|
9904
10033
|
"and",
|
|
9905
10034
|
"for"
|
|
9906
10035
|
]);
|
|
9907
|
-
var words = (
|
|
10036
|
+
var words = (value2) => value2.replace(/^@[\w-]+\//, "").split(/[^A-Za-z0-9]+/).filter((w) => w.length > 1 && !NOISE.has(w.toLowerCase()));
|
|
9908
10037
|
function namedExports(clause) {
|
|
9909
10038
|
return clause.split(",").map((part) => part.trim().split(/\s+as\s+/)[0]?.trim() ?? "").filter((name) => /^[A-Za-z_$][\w$]*$/.test(name) && name !== "type");
|
|
9910
10039
|
}
|
|
@@ -10257,8 +10386,8 @@ var import_node_process12 = __toESM(require("process"), 1);
|
|
|
10257
10386
|
var EDITOR_ENV = ["ODLA_EDITOR", "VISUAL", "EDITOR"];
|
|
10258
10387
|
function resolveEditor(env = import_node_process12.default.env) {
|
|
10259
10388
|
for (const name of EDITOR_ENV) {
|
|
10260
|
-
const
|
|
10261
|
-
if (
|
|
10389
|
+
const value2 = env[name];
|
|
10390
|
+
if (value2 && value2.trim()) return value2.trim();
|
|
10262
10391
|
}
|
|
10263
10392
|
return null;
|
|
10264
10393
|
}
|
|
@@ -10523,9 +10652,9 @@ async function runbookCommand(parsed, deps = {}) {
|
|
|
10523
10652
|
});
|
|
10524
10653
|
}
|
|
10525
10654
|
case "visibility": {
|
|
10526
|
-
const
|
|
10527
|
-
if (!
|
|
10528
|
-
return runbookVisibility(ctx, requireSlug(slug, "visibility"),
|
|
10655
|
+
const value2 = parsed.positionals[3] ?? stringOpt(parsed.options.visibility);
|
|
10656
|
+
if (!value2) throw new Error('"runbook visibility" needs operator|admin, e.g. "runbook visibility release operator"');
|
|
10657
|
+
return runbookVisibility(ctx, requireSlug(slug, "visibility"), value2);
|
|
10529
10658
|
}
|
|
10530
10659
|
case "publish":
|
|
10531
10660
|
return runbookStatus(ctx, requireSlug(slug, "publish"), "published");
|
|
@@ -10581,13 +10710,13 @@ async function interactiveConfirmation(message2, dependencies) {
|
|
|
10581
10710
|
}
|
|
10582
10711
|
}
|
|
10583
10712
|
function requiredSecurityPositional(parsed, index, label) {
|
|
10584
|
-
const
|
|
10585
|
-
if (!
|
|
10586
|
-
return
|
|
10713
|
+
const value2 = parsed.positionals[index];
|
|
10714
|
+
if (!value2) throw new Error(`${label} is required`);
|
|
10715
|
+
return value2;
|
|
10587
10716
|
}
|
|
10588
|
-
function securityProfile(
|
|
10589
|
-
if (
|
|
10590
|
-
if (
|
|
10717
|
+
function securityProfile(value2) {
|
|
10718
|
+
if (value2 === void 0) return void 0;
|
|
10719
|
+
if (value2 === "odla" || value2 === "cloudflare-app" || value2 === "generic") return value2;
|
|
10591
10720
|
throw new Error("--profile must be odla, cloudflare-app, or generic");
|
|
10592
10721
|
}
|
|
10593
10722
|
|
|
@@ -10688,9 +10817,9 @@ function routeLabel(route2) {
|
|
|
10688
10817
|
return `${route2.provider}/${route2.model}${route2.policyVersion ? ` policy v${route2.policyVersion}` : ""}`;
|
|
10689
10818
|
}
|
|
10690
10819
|
var HOSTED_SEVERITIES = ["informational", "low", "medium", "high", "critical"];
|
|
10691
|
-
function hostedSeverity(
|
|
10692
|
-
if (HOSTED_SEVERITIES.includes(
|
|
10693
|
-
return
|
|
10820
|
+
function hostedSeverity(value2, flag) {
|
|
10821
|
+
if (HOSTED_SEVERITIES.includes(value2)) {
|
|
10822
|
+
return value2;
|
|
10694
10823
|
}
|
|
10695
10824
|
throw new Error(`${flag} must be informational, low, medium, high, or critical`);
|
|
10696
10825
|
}
|
|
@@ -10773,13 +10902,13 @@ function selectEnv(requested, declared, configPath, rootDir) {
|
|
|
10773
10902
|
return env;
|
|
10774
10903
|
}
|
|
10775
10904
|
async function injectedToken(options, request2) {
|
|
10776
|
-
const
|
|
10777
|
-
if (typeof
|
|
10905
|
+
const value2 = options.token ?? await options.getToken?.(Object.freeze({ ...request2 }));
|
|
10906
|
+
if (typeof value2 !== "string" || value2.length < 8 || value2.length > 8192 || /\s|[\u0000-\u001f\u007f]/.test(value2)) {
|
|
10778
10907
|
throw new Error(
|
|
10779
10908
|
request2.selfAudit ? "Self-audit requires an injected, scoped platform security token" : "Hosted security requires an injected app developer token or getToken callback"
|
|
10780
10909
|
);
|
|
10781
10910
|
}
|
|
10782
|
-
return
|
|
10911
|
+
return value2;
|
|
10783
10912
|
}
|
|
10784
10913
|
function profileFor(name, maxHuntTasks) {
|
|
10785
10914
|
const profile = name === "odla" ? (0, import_security.odlaProfile)() : name === "cloudflare-app" ? (0, import_security.cloudflareAppProfile)() : name === "generic" ? (0, import_security.genericProfile)() : void 0;
|
|
@@ -10825,8 +10954,8 @@ async function getHostedSecurityIntent(options) {
|
|
|
10825
10954
|
}
|
|
10826
10955
|
return response2;
|
|
10827
10956
|
}
|
|
10828
|
-
function isValidIntent(
|
|
10829
|
-
return !!
|
|
10957
|
+
function isValidIntent(value2, expected) {
|
|
10958
|
+
return !!value2 && value2.executionContract === "odla.hosted-security-execution-consent.v1" && /^sha256:[a-f0-9]{64}$/.test(value2.executionDigest) && /^sha256:[a-f0-9]{64}$/.test(value2.planDigest) && value2.appId === expected.appId && value2.env === expected.env && value2.sourceId === expected.sourceId && typeof value2.repository === "string" && value2.repository.length > 2 && value2.repository.length <= 201 && typeof value2.defaultBranch === "string" && value2.defaultBranch.length > 0 && value2.defaultBranch.length <= 255 && typeof value2.requestedRef === "string" && value2.requestedRef.length > 0 && value2.requestedRef.length <= 255 && !/[\u0000-\u001f\u007f]/.test(value2.requestedRef) && ["odla", "cloudflare-app", "generic"].includes(value2.profile) && value2.sourceDisclosure === "redacted";
|
|
10830
10959
|
}
|
|
10831
10960
|
|
|
10832
10961
|
// src/security-hosted-jobs.ts
|
|
@@ -10952,17 +11081,17 @@ function hostedJobPath(appIdInput, jobIdInput) {
|
|
|
10952
11081
|
const jobId = hostedIdentifier(jobIdInput, "jobId");
|
|
10953
11082
|
return `/registry/apps/${encodeURIComponent(appId)}/security/jobs/${encodeURIComponent(jobId)}`;
|
|
10954
11083
|
}
|
|
10955
|
-
function securityPlanDigest(
|
|
10956
|
-
if (!/^sha256:[a-f0-9]{64}$/.test(
|
|
11084
|
+
function securityPlanDigest(value2) {
|
|
11085
|
+
if (!/^sha256:[a-f0-9]{64}$/.test(value2)) {
|
|
10957
11086
|
throw new Error("expected plan digest must be a sha256 digest from security plan");
|
|
10958
11087
|
}
|
|
10959
|
-
return
|
|
11088
|
+
return value2;
|
|
10960
11089
|
}
|
|
10961
|
-
function securityExecutionDigest(
|
|
10962
|
-
if (!/^sha256:[a-f0-9]{64}$/.test(
|
|
11090
|
+
function securityExecutionDigest(value2) {
|
|
11091
|
+
if (!/^sha256:[a-f0-9]{64}$/.test(value2)) {
|
|
10963
11092
|
throw new Error("expected execution digest must be a sha256 digest from security intent");
|
|
10964
11093
|
}
|
|
10965
|
-
return
|
|
11094
|
+
return value2;
|
|
10966
11095
|
}
|
|
10967
11096
|
|
|
10968
11097
|
// src/security-run-command.ts
|
|
@@ -11026,7 +11155,7 @@ async function runSourceSecurityCommand(parsed, dependencies, sourceId) {
|
|
|
11026
11155
|
...context,
|
|
11027
11156
|
jobId: job.jobId,
|
|
11028
11157
|
wait: dependencies.pollWait,
|
|
11029
|
-
onUpdate: parsed.options.json === true ? void 0 : (
|
|
11158
|
+
onUpdate: parsed.options.json === true ? void 0 : (value2) => printHostedJob(context.stdout, value2, context.platform, context.appId)
|
|
11030
11159
|
}) : job;
|
|
11031
11160
|
if (!follow) {
|
|
11032
11161
|
if (parsed.options.json === true) {
|
|
@@ -11126,9 +11255,9 @@ function enforceLocalGate(report4, parsed) {
|
|
|
11126
11255
|
throw new Error(`hosted security gate failed: ${confirmed.length} confirmed >= ${failOn}; ${leads.length} leads >= ${failOnCandidates ?? "disabled"}${incomplete ? "; coverage incomplete" : ""}`);
|
|
11127
11256
|
}
|
|
11128
11257
|
}
|
|
11129
|
-
function severityOpt(
|
|
11130
|
-
if (["informational", "low", "medium", "high", "critical"].includes(
|
|
11131
|
-
return
|
|
11258
|
+
function severityOpt(value2, flag) {
|
|
11259
|
+
if (["informational", "low", "medium", "high", "critical"].includes(value2)) {
|
|
11260
|
+
return value2;
|
|
11132
11261
|
}
|
|
11133
11262
|
throw new Error(`${flag} must be informational, low, medium, high, or critical`);
|
|
11134
11263
|
}
|
|
@@ -11236,7 +11365,7 @@ async function securityStatus(parsed, dependencies) {
|
|
|
11236
11365
|
...context,
|
|
11237
11366
|
jobId,
|
|
11238
11367
|
wait: dependencies.pollWait,
|
|
11239
|
-
onUpdate: parsed.options.json === true ? void 0 : (
|
|
11368
|
+
onUpdate: parsed.options.json === true ? void 0 : (value2) => printHostedJob(context.stdout, value2, context.platform, context.appId)
|
|
11240
11369
|
}) : await getHostedSecurityJob({ ...context, jobId });
|
|
11241
11370
|
if (parsed.options.json === true) context.stdout.log(JSON.stringify(job, null, 2));
|
|
11242
11371
|
else if (parsed.options.follow !== true) {
|
|
@@ -11320,6 +11449,10 @@ async function runCli(argv = process.argv.slice(2), dependencies = {}) {
|
|
|
11320
11449
|
await o11yCommand(parsed, runtime);
|
|
11321
11450
|
return;
|
|
11322
11451
|
}
|
|
11452
|
+
if (command === "platform") {
|
|
11453
|
+
await platformCommand(parsed, runtime);
|
|
11454
|
+
return;
|
|
11455
|
+
}
|
|
11323
11456
|
if (command === "provision") {
|
|
11324
11457
|
await provisionCommand(parsed, runtime);
|
|
11325
11458
|
return;
|