@odla-ai/cli 0.46.12 → 0.48.1
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 +33 -0
- package/dist/bin.cjs +556 -344
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-Q4BGAUEH.js → chunk-BD5KIG63.js} +519 -324
- package/dist/chunk-BD5KIG63.js.map +1 -0
- package/dist/{cli-5CDFI4AY.js → cli-MXYYOFBR.js} +2 -2
- package/dist/index.cjs +521 -326
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -2
- package/dist/index.d.ts +10 -2
- package/dist/index.js +1 -1
- package/package.json +4 -4
- package/skills/odla/references/sdks.md +5 -0
- package/dist/chunk-Q4BGAUEH.js.map +0 -1
- /package/dist/{cli-5CDFI4AY.js.map → cli-MXYYOFBR.js.map} +0 -0
|
@@ -1252,6 +1252,7 @@ var COMMAND_SURFACE = {
|
|
|
1252
1252
|
watch: {}
|
|
1253
1253
|
},
|
|
1254
1254
|
provision: {},
|
|
1255
|
+
promotion: { plan: {}, inspect: {}, status: {}, apply: {}, rollback: {}, next: {}, record: {}, cancel: {} },
|
|
1255
1256
|
runbook: {
|
|
1256
1257
|
ask: {},
|
|
1257
1258
|
search: {},
|
|
@@ -3557,9 +3558,9 @@ function canonicalValue(value2) {
|
|
|
3557
3558
|
}
|
|
3558
3559
|
if (Array.isArray(value2)) return value2.map(canonicalValue);
|
|
3559
3560
|
if (value2 && typeof value2 === "object") {
|
|
3560
|
-
const
|
|
3561
|
+
const record12 = value2;
|
|
3561
3562
|
return Object.fromEntries(
|
|
3562
|
-
Object.keys(
|
|
3563
|
+
Object.keys(record12).filter((key) => record12[key] !== void 0).sort().map((key) => [key, canonicalValue(record12[key])])
|
|
3563
3564
|
);
|
|
3564
3565
|
}
|
|
3565
3566
|
throw new TypeError("canonical JSON rejects unsupported values");
|
|
@@ -5943,10 +5944,10 @@ import { existsSync as existsSync10 } from "fs";
|
|
|
5943
5944
|
import { cpus, hostname, totalmem } from "os";
|
|
5944
5945
|
import { resolve as resolve11 } from "path";
|
|
5945
5946
|
|
|
5946
|
-
// ../harness/dist/chunk-
|
|
5947
|
+
// ../harness/dist/chunk-U324RQ4N.js
|
|
5947
5948
|
var HARNESS_PROTOCOL_VERSION = 1;
|
|
5948
5949
|
|
|
5949
|
-
// ../harness/dist/chunk-
|
|
5950
|
+
// ../harness/dist/chunk-5LRYJKUI.js
|
|
5950
5951
|
import { execFile, spawn as spawn3 } from "child_process";
|
|
5951
5952
|
import { constants } from "fs";
|
|
5952
5953
|
import { access } from "fs/promises";
|
|
@@ -6114,8 +6115,8 @@ async function materializeGitTree(source, commitSha, options = {}) {
|
|
|
6114
6115
|
const maxFiles = options.maxFiles ?? 2e4;
|
|
6115
6116
|
const maxBytes = options.maxBytes ?? 512 * 1024 * 1024;
|
|
6116
6117
|
const inventory = (await gitOutput(sourceDir, ["ls-tree", "-rz", commitSha], 16 * 1024 * 1024)).toString("utf8").split("\0").filter(Boolean);
|
|
6117
|
-
const entries = inventory.flatMap((
|
|
6118
|
-
const match = /^(100644|100755) blob ([0-9a-f]{40,64})\t([\s\S]+)$/.exec(
|
|
6118
|
+
const entries = inventory.flatMap((record12) => {
|
|
6119
|
+
const match = /^(100644|100755) blob ([0-9a-f]{40,64})\t([\s\S]+)$/.exec(record12);
|
|
6119
6120
|
return match && allowedWorkspacePath(match[3]) ? [{ mode: match[1], hash: match[2], path: match[3] }] : [];
|
|
6120
6121
|
});
|
|
6121
6122
|
if (entries.length > maxFiles) throw new Error(`workspace exceeds ${maxFiles} files`);
|
|
@@ -6319,7 +6320,165 @@ async function stageWorkspacePair(baselineSource, workspaceSource, options = {})
|
|
|
6319
6320
|
}
|
|
6320
6321
|
}
|
|
6321
6322
|
|
|
6322
|
-
// ../harness/dist/chunk-
|
|
6323
|
+
// ../harness/dist/chunk-FAN2R3GW.js
|
|
6324
|
+
var text3 = (value2, maximum) => {
|
|
6325
|
+
if (typeof value2 !== "string") return void 0;
|
|
6326
|
+
const bounded = value2.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g, " ").trim();
|
|
6327
|
+
return bounded ? bounded.slice(0, maximum) : void 0;
|
|
6328
|
+
};
|
|
6329
|
+
var integer = (value2) => Number.isSafeInteger(value2) && Number(value2) >= 0 ? Number(value2) : void 0;
|
|
6330
|
+
var record5 = (value2) => value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : void 0;
|
|
6331
|
+
var excerpt = (value2, tail = false) => {
|
|
6332
|
+
if (typeof value2 !== "string") return void 0;
|
|
6333
|
+
const safe = value2.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g, " ");
|
|
6334
|
+
const source = (tail ? safe.slice(-1e4) : safe.slice(0, 1e4)).trim();
|
|
6335
|
+
if (!source) return void 0;
|
|
6336
|
+
const lines = source.split("\n").filter((line2) => line2.trim()).map((line2) => line2.slice(0, 240));
|
|
6337
|
+
const selected = tail ? lines.slice(-10) : lines.slice(0, 10);
|
|
6338
|
+
return text3(selected.join("\n"), 2400);
|
|
6339
|
+
};
|
|
6340
|
+
var paths = (value2) => {
|
|
6341
|
+
if (!Array.isArray(value2)) return void 0;
|
|
6342
|
+
const items = value2.flatMap((item) => {
|
|
6343
|
+
const path = text3(item, 1024);
|
|
6344
|
+
return path ? [path] : [];
|
|
6345
|
+
}).slice(0, 12);
|
|
6346
|
+
return items.length ? items : void 0;
|
|
6347
|
+
};
|
|
6348
|
+
function patchStats(value2) {
|
|
6349
|
+
if (typeof value2 !== "string") return {};
|
|
6350
|
+
let additions = 0;
|
|
6351
|
+
let deletions = 0;
|
|
6352
|
+
for (const line2 of value2.slice(0, 262144).split("\n")) {
|
|
6353
|
+
if (line2.startsWith("+++") || line2.startsWith("---")) continue;
|
|
6354
|
+
if (line2.startsWith("+")) additions += 1;
|
|
6355
|
+
else if (line2.startsWith("-")) deletions += 1;
|
|
6356
|
+
}
|
|
6357
|
+
return { ...additions ? { additions } : {}, ...deletions ? { deletions } : {} };
|
|
6358
|
+
}
|
|
6359
|
+
function searchResults(value2) {
|
|
6360
|
+
if (typeof value2 !== "string") return void 0;
|
|
6361
|
+
const results = value2.split("\n").flatMap((line2) => {
|
|
6362
|
+
const match = /^([^:\n]{1,1024}):(\d+):\s?(.*)$/.exec(line2);
|
|
6363
|
+
if (!match) return [];
|
|
6364
|
+
const lineNumber = Number(match[2]);
|
|
6365
|
+
const itemText = text3(match[3], 240);
|
|
6366
|
+
if (!Number.isSafeInteger(lineNumber) || lineNumber < 1) return [];
|
|
6367
|
+
return [{ path: match[1], line: lineNumber, ...itemText ? { text: itemText } : {} }];
|
|
6368
|
+
}).slice(0, 5);
|
|
6369
|
+
return results.length ? results : void 0;
|
|
6370
|
+
}
|
|
6371
|
+
function codeToolRequestPresentation(request3) {
|
|
6372
|
+
const input = request3.input;
|
|
6373
|
+
if (request3.tool === "sandbox.read") {
|
|
6374
|
+
const path = text3(input.path, 1024);
|
|
6375
|
+
if (!path) return void 0;
|
|
6376
|
+
const startLine = integer(input.startLine);
|
|
6377
|
+
const endLine = integer(input.endLine);
|
|
6378
|
+
return { kind: "read", path, ...startLine ? { startLine } : {}, ...endLine ? { endLine } : {} };
|
|
6379
|
+
}
|
|
6380
|
+
if (request3.tool === "sandbox.list") {
|
|
6381
|
+
const scope = text3(input.prefix, 1024);
|
|
6382
|
+
return { kind: "list", ...scope ? { scope } : {} };
|
|
6383
|
+
}
|
|
6384
|
+
if (request3.tool === "sandbox.search" || request3.tool === "sandbox.overview" || request3.tool === "sandbox.where_is" || request3.tool === "sandbox.who_imports" || request3.tool === "sandbox.who_touches") {
|
|
6385
|
+
const query = text3(input.query, 512);
|
|
6386
|
+
const scope = request3.tool === "sandbox.search" ? text3(input.prefix, 1024) : void 0;
|
|
6387
|
+
if (request3.tool === "sandbox.search" && !query) return void 0;
|
|
6388
|
+
return { kind: "query", ...query ? { query } : {}, ...scope ? { scope } : {} };
|
|
6389
|
+
}
|
|
6390
|
+
if (request3.tool === "sandbox.apply_patch") {
|
|
6391
|
+
return { kind: "patch", ...patchStats(input.patch) };
|
|
6392
|
+
}
|
|
6393
|
+
const recipeId = text3(input.recipeId, 120);
|
|
6394
|
+
return recipeId ? { kind: "recipe", recipeId } : void 0;
|
|
6395
|
+
}
|
|
6396
|
+
function codeToolResultPresentation(request3, response2) {
|
|
6397
|
+
const started = codeToolRequestPresentation(request3);
|
|
6398
|
+
if (!started || !response2.ok) return started;
|
|
6399
|
+
const details = record5(response2.details);
|
|
6400
|
+
if (started.kind === "read") {
|
|
6401
|
+
return {
|
|
6402
|
+
...started,
|
|
6403
|
+
...integer(details?.startLine) ? { startLine: integer(details?.startLine) } : {},
|
|
6404
|
+
...integer(details?.endLine) ? { endLine: integer(details?.endLine) } : {},
|
|
6405
|
+
...excerpt(response2.content) ? { excerpt: excerpt(response2.content) } : {}
|
|
6406
|
+
};
|
|
6407
|
+
}
|
|
6408
|
+
if (started.kind === "list") {
|
|
6409
|
+
const listed = response2.content.split("\n").filter((line2) => line2 && !line2.startsWith("\u2026") && !line2.startsWith("Workspace ")).map((line2) => text3(line2, 1024)).filter((line2) => Boolean(line2)).slice(0, 8);
|
|
6410
|
+
return {
|
|
6411
|
+
...started,
|
|
6412
|
+
...integer(details?.count) !== void 0 ? { count: integer(details?.count) } : {},
|
|
6413
|
+
...listed.length ? { paths: listed } : {}
|
|
6414
|
+
};
|
|
6415
|
+
}
|
|
6416
|
+
if (started.kind === "query") {
|
|
6417
|
+
const results = request3.tool === "sandbox.search" ? searchResults(response2.content) : void 0;
|
|
6418
|
+
const resultExcerpt = request3.tool === "sandbox.search" ? void 0 : excerpt(response2.content);
|
|
6419
|
+
return {
|
|
6420
|
+
...started,
|
|
6421
|
+
...integer(details?.count) !== void 0 ? { count: integer(details?.count) } : {},
|
|
6422
|
+
...results ? { results } : {},
|
|
6423
|
+
...resultExcerpt ? { excerpt: resultExcerpt } : {}
|
|
6424
|
+
};
|
|
6425
|
+
}
|
|
6426
|
+
if (started.kind === "patch") {
|
|
6427
|
+
return { ...started, ...paths(details?.paths) ? { paths: paths(details?.paths) } : {} };
|
|
6428
|
+
}
|
|
6429
|
+
const output = response2.content.replace(/^Recipe [^\n]*\.?\s*/u, "");
|
|
6430
|
+
return {
|
|
6431
|
+
...started,
|
|
6432
|
+
...integer(details?.exitCode) !== void 0 ? { exitCode: integer(details?.exitCode) } : {},
|
|
6433
|
+
...typeof details?.timedOut === "boolean" ? { timedOut: details.timedOut } : {},
|
|
6434
|
+
...typeof details?.outputLimitExceeded === "boolean" ? { outputLimitExceeded: details.outputLimitExceeded } : {},
|
|
6435
|
+
...excerpt(output, true) ? { excerpt: excerpt(output, true) } : {}
|
|
6436
|
+
};
|
|
6437
|
+
}
|
|
6438
|
+
var MAX_FAILURE_REASON = 240;
|
|
6439
|
+
function toolFailureReason(response2) {
|
|
6440
|
+
if (response2.ok) return void 0;
|
|
6441
|
+
const supplied = response2.details?.failureReason;
|
|
6442
|
+
const reason = typeof supplied === "string" && supplied || DEFAULT_FAILURE_REASON[response2.content] || response2.content || "tool request failed; inspect the tool input and workspace state";
|
|
6443
|
+
return reason.slice(0, MAX_FAILURE_REASON);
|
|
6444
|
+
}
|
|
6445
|
+
var DEFAULT_FAILURE_REASON = {
|
|
6446
|
+
"tool denied by CaMeL policy": "tool denied by CaMeL policy",
|
|
6447
|
+
"review sessions are read-only": "review session is read-only; workspace changes are not permitted"
|
|
6448
|
+
};
|
|
6449
|
+
function observedBroker(input) {
|
|
6450
|
+
const now = input.now ?? Date.now;
|
|
6451
|
+
return {
|
|
6452
|
+
execute: async (context, request3) => {
|
|
6453
|
+
const startedAt = now();
|
|
6454
|
+
const operationId = input.operationIdFor(request3.requestId);
|
|
6455
|
+
const startedPresentation = codeToolRequestPresentation(request3);
|
|
6456
|
+
await input.emit({
|
|
6457
|
+
type: "tool",
|
|
6458
|
+
phase: "started",
|
|
6459
|
+
tool: request3.tool,
|
|
6460
|
+
operationId,
|
|
6461
|
+
...startedPresentation ? { presentation: startedPresentation } : {}
|
|
6462
|
+
});
|
|
6463
|
+
const response2 = await input.broker.execute(context, request3);
|
|
6464
|
+
const completedPresentation = codeToolResultPresentation(request3, response2);
|
|
6465
|
+
const failureReason = toolFailureReason(response2);
|
|
6466
|
+
await input.emit({
|
|
6467
|
+
type: "tool",
|
|
6468
|
+
phase: "completed",
|
|
6469
|
+
tool: request3.tool,
|
|
6470
|
+
ok: response2.ok,
|
|
6471
|
+
durationMs: now() - startedAt,
|
|
6472
|
+
operationId,
|
|
6473
|
+
...failureReason ? { failureReason } : {},
|
|
6474
|
+
...completedPresentation ? { presentation: completedPresentation } : {}
|
|
6475
|
+
});
|
|
6476
|
+
return response2;
|
|
6477
|
+
}
|
|
6478
|
+
};
|
|
6479
|
+
}
|
|
6480
|
+
|
|
6481
|
+
// ../harness/dist/chunk-Q4NL5XO3.js
|
|
6323
6482
|
import { createHash as createHash3 } from "crypto";
|
|
6324
6483
|
import { readFile as readFile2, readdir as readdir2 } from "fs/promises";
|
|
6325
6484
|
import { relative as relative4, resolve as resolve10 } from "path";
|
|
@@ -6363,8 +6522,8 @@ function normalize(value2) {
|
|
|
6363
6522
|
if (Array.isArray(value2)) return value2.map(normalize);
|
|
6364
6523
|
if (value2 instanceof Uint8Array) return { $bytes: [...value2] };
|
|
6365
6524
|
if (typeof value2 === "object") {
|
|
6366
|
-
const
|
|
6367
|
-
return Object.fromEntries(Object.keys(
|
|
6525
|
+
const record12 = value2;
|
|
6526
|
+
return Object.fromEntries(Object.keys(record12).filter((key) => record12[key] !== void 0).sort().map((key) => [key, normalize(record12[key])]));
|
|
6368
6527
|
}
|
|
6369
6528
|
throw new CamelError("state_conflict", "Canonical JSON rejects unsupported values.");
|
|
6370
6529
|
}
|
|
@@ -6656,7 +6815,7 @@ function validateSnapshot(snapshot, limits) {
|
|
|
6656
6815
|
}
|
|
6657
6816
|
}
|
|
6658
6817
|
|
|
6659
|
-
// ../harness/dist/chunk-
|
|
6818
|
+
// ../harness/dist/chunk-Q4NL5XO3.js
|
|
6660
6819
|
import { spawn as spawn4 } from "child_process";
|
|
6661
6820
|
import { lstat as lstat2 } from "fs/promises";
|
|
6662
6821
|
import { resolve as resolve23, sep as sep3 } from "path";
|
|
@@ -6963,7 +7122,7 @@ function looksLikeDestination(value2) {
|
|
|
6963
7122
|
return /^(?:[a-z][a-z0-9+.-]*:\/\/|\/|\\\\)/i.test(text4) || /^[\w.-]+\.[a-z]{2,}(?:[/:]|$)/i.test(text4);
|
|
6964
7123
|
}
|
|
6965
7124
|
|
|
6966
|
-
// ../harness/dist/chunk-
|
|
7125
|
+
// ../harness/dist/chunk-Q4NL5XO3.js
|
|
6967
7126
|
import { readFile as readFile4, stat as stat2 } from "fs/promises";
|
|
6968
7127
|
import { readFile as readFile3 } from "fs/promises";
|
|
6969
7128
|
import { join as join33 } from "path";
|
|
@@ -7231,7 +7390,7 @@ async function buildCodeGraph(input) {
|
|
|
7231
7390
|
return builder.build();
|
|
7232
7391
|
}
|
|
7233
7392
|
|
|
7234
|
-
// ../harness/dist/chunk-
|
|
7393
|
+
// ../harness/dist/chunk-Q4NL5XO3.js
|
|
7235
7394
|
import { createHash as createHash32 } from "crypto";
|
|
7236
7395
|
async function digestStagedWorkspace(root, limits) {
|
|
7237
7396
|
const files = [];
|
|
@@ -7290,7 +7449,7 @@ function createCodeRuntimeControlClient(options) {
|
|
|
7290
7449
|
}
|
|
7291
7450
|
const value2 = await response2.json().catch(() => null);
|
|
7292
7451
|
if (!response2.ok) {
|
|
7293
|
-
const problem =
|
|
7452
|
+
const problem = record6(record6(value2)?.error);
|
|
7294
7453
|
throw new CodeRuntimeControlError(
|
|
7295
7454
|
typeof problem?.message === "string" ? problem.message : `Code runtime request failed (${response2.status})`,
|
|
7296
7455
|
response2.status,
|
|
@@ -7311,12 +7470,12 @@ function createCodeRuntimeControlClient(options) {
|
|
|
7311
7470
|
await call4(`/registry/code/runtime/sessions/${validSessionId(sessionId)}/source`, {})
|
|
7312
7471
|
),
|
|
7313
7472
|
infer: async (sessionId, inference) => {
|
|
7314
|
-
const value2 =
|
|
7473
|
+
const value2 = record6(await call4(
|
|
7315
7474
|
`/registry/code/runtime/sessions/${validSessionId(sessionId)}/inference`,
|
|
7316
7475
|
inference,
|
|
7317
7476
|
modelRequestTimeoutMs
|
|
7318
7477
|
));
|
|
7319
|
-
if (!value2 || value2.requestId !== inference.requestId || !
|
|
7478
|
+
if (!value2 || value2.requestId !== inference.requestId || !record6(value2.response) || !record6(value2.receipt)) {
|
|
7320
7479
|
throw new CodeRuntimeControlError("invalid Code inference response", 502, "invalid_response");
|
|
7321
7480
|
}
|
|
7322
7481
|
return value2;
|
|
@@ -7496,12 +7655,12 @@ function validateHeartbeat(version, capabilities) {
|
|
|
7496
7655
|
}
|
|
7497
7656
|
}
|
|
7498
7657
|
function parseSnapshot(value2) {
|
|
7499
|
-
const root =
|
|
7500
|
-
const host =
|
|
7658
|
+
const root = record6(value2);
|
|
7659
|
+
const host = record6(root?.host);
|
|
7501
7660
|
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");
|
|
7502
7661
|
const bindingIds = /* @__PURE__ */ new Set();
|
|
7503
7662
|
const bindings = root.bindings.map((item) => {
|
|
7504
|
-
const binding =
|
|
7663
|
+
const binding = record6(item);
|
|
7505
7664
|
if (!binding || typeof binding.bindingId !== "string" || typeof binding.appId !== "string" || binding.env !== "dev" && binding.env !== "prod" || typeof binding.offerId !== "string" || binding.hostId !== host.hostId || !Number.isSafeInteger(binding.generation) || Number(binding.generation) < 1 || binding.revokedAt !== null || bindingIds.has(binding.bindingId)) {
|
|
7506
7665
|
throw invalid("binding");
|
|
7507
7666
|
}
|
|
@@ -7511,10 +7670,10 @@ function parseSnapshot(value2) {
|
|
|
7511
7670
|
const commandIds = /* @__PURE__ */ new Set();
|
|
7512
7671
|
const commandSequences = /* @__PURE__ */ new Set();
|
|
7513
7672
|
const commands = root.commands.map((item) => {
|
|
7514
|
-
const command =
|
|
7673
|
+
const command = record6(item);
|
|
7515
7674
|
const binding = bindings.find((candidate) => candidate.bindingId === command?.bindingId);
|
|
7516
7675
|
const sequenceKey = `${String(command?.instanceId)}:${String(command?.sequence)}`;
|
|
7517
|
-
if (!command || typeof command.commandId !== "string" || !/^ccmd_[0-9a-f]{32}$/.test(command.commandId) || typeof command.instanceId !== "string" || typeof command.sessionId !== "string" || !/^csess_[0-9a-f]{32}$/.test(command.sessionId) || typeof command.appId !== "string" || command.env !== "dev" && command.env !== "prod" || command.hostId !== host.hostId || !binding || binding.appId !== command.appId || binding.generation !== command.bindingGeneration || !Number.isSafeInteger(command.sequence) || Number(command.sequence) < 1 || commandIds.has(command.commandId) || commandSequences.has(sequenceKey) || !["start", "prompt", "checkpoint_stop", "resume"].includes(String(command.kind)) || !
|
|
7676
|
+
if (!command || typeof command.commandId !== "string" || !/^ccmd_[0-9a-f]{32}$/.test(command.commandId) || typeof command.instanceId !== "string" || typeof command.sessionId !== "string" || !/^csess_[0-9a-f]{32}$/.test(command.sessionId) || typeof command.appId !== "string" || command.env !== "dev" && command.env !== "prod" || command.hostId !== host.hostId || !binding || binding.appId !== command.appId || binding.generation !== command.bindingGeneration || !Number.isSafeInteger(command.sequence) || Number(command.sequence) < 1 || commandIds.has(command.commandId) || commandSequences.has(sequenceKey) || !["start", "prompt", "checkpoint_stop", "resume"].includes(String(command.kind)) || !record6(command.payload) || !Number.isSafeInteger(command.createdAt)) throw invalid("command");
|
|
7518
7677
|
commandIds.add(command.commandId);
|
|
7519
7678
|
commandSequences.add(sequenceKey);
|
|
7520
7679
|
return command;
|
|
@@ -7523,10 +7682,10 @@ function parseSnapshot(value2) {
|
|
|
7523
7682
|
}
|
|
7524
7683
|
async function parseSource(value2) {
|
|
7525
7684
|
const repositoryLimits = { maximumFiles: 1e5, maximumBytes: 80 * 1024 * 1024 };
|
|
7526
|
-
const snapshot =
|
|
7685
|
+
const snapshot = record6(record6(value2)?.snapshot);
|
|
7527
7686
|
if (!snapshot || typeof snapshot.repository !== "string" || typeof snapshot.commitSha !== "string" || typeof snapshot.treeDigest !== "string" || !Array.isArray(snapshot.files)) throw invalid("source");
|
|
7528
7687
|
const files = snapshot.files.map((value22) => {
|
|
7529
|
-
const file =
|
|
7688
|
+
const file = record6(value22);
|
|
7530
7689
|
if (!file || typeof file.path !== "string" || typeof file.content !== "string") throw invalid("source file");
|
|
7531
7690
|
return { path: file.path, content: file.content };
|
|
7532
7691
|
});
|
|
@@ -7535,11 +7694,11 @@ async function parseSource(value2) {
|
|
|
7535
7694
|
const aliases = /* @__PURE__ */ new Set();
|
|
7536
7695
|
const references = [];
|
|
7537
7696
|
for (const item of referencesValue) {
|
|
7538
|
-
const reference =
|
|
7697
|
+
const reference = record6(item);
|
|
7539
7698
|
if (!reference || typeof reference.alias !== "string" || !/^[a-z][a-z0-9-]{0,39}$/.test(reference.alias) || aliases.has(reference.alias) || reference.alias === "primary" || typeof reference.repository !== "string" || typeof reference.commitSha !== "string" || typeof reference.treeDigest !== "string" || !Array.isArray(reference.files)) throw invalid("reference source");
|
|
7540
7699
|
aliases.add(reference.alias);
|
|
7541
7700
|
const referenceFiles = reference.files.map((entry) => {
|
|
7542
|
-
const file =
|
|
7701
|
+
const file = record6(entry);
|
|
7543
7702
|
if (!file || typeof file.path !== "string" || typeof file.content !== "string") throw invalid("reference source file");
|
|
7544
7703
|
return { path: file.path, content: file.content };
|
|
7545
7704
|
});
|
|
@@ -7554,31 +7713,31 @@ async function parseSource(value2) {
|
|
|
7554
7713
|
return { ...source, treeDigest: digest, ...references.length ? { references } : {} };
|
|
7555
7714
|
}
|
|
7556
7715
|
function parseReview(value2) {
|
|
7557
|
-
const review =
|
|
7558
|
-
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");
|
|
7716
|
+
const review = record6(record6(value2)?.review);
|
|
7717
|
+
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 || !Number.isSafeInteger(review.score) || Number(review.score) < 0 || Number(review.score) > 100 || typeof review.summary !== "string" || !Array.isArray(review.findings) || review.findings.length > 12) throw invalid("review");
|
|
7559
7718
|
return review;
|
|
7560
7719
|
}
|
|
7561
7720
|
function parseCandidate(value2) {
|
|
7562
|
-
const candidate =
|
|
7721
|
+
const candidate = record6(record6(value2)?.candidate);
|
|
7563
7722
|
if (!candidate || typeof candidate.candidateId !== "string" || !/^ccand_[0-9a-f]{32}$/.test(candidate.candidateId) || !["submitted", "approved", "published", "failed"].includes(String(candidate.status))) {
|
|
7564
7723
|
throw invalid("candidate");
|
|
7565
7724
|
}
|
|
7566
7725
|
return { candidateId: candidate.candidateId, status: candidate.status };
|
|
7567
7726
|
}
|
|
7568
7727
|
function parseCollaborationSkills(value2) {
|
|
7569
|
-
const items =
|
|
7728
|
+
const items = record6(value2)?.skills;
|
|
7570
7729
|
if (!Array.isArray(items) || items.length > 16) throw invalid("collaboration skills");
|
|
7571
7730
|
const skillNames2 = /* @__PURE__ */ new Set();
|
|
7572
7731
|
const toolNames = /* @__PURE__ */ new Set();
|
|
7573
7732
|
return items.map((item) => {
|
|
7574
|
-
const skill =
|
|
7733
|
+
const skill = record6(item);
|
|
7575
7734
|
if (!skill || !validManifestName(skill.name) || skillNames2.has(skill.name) || skill.instructions !== void 0 && (typeof skill.instructions !== "string" || utf8Bytes(skill.instructions) > 32e3) || !Array.isArray(skill.tools) || !skill.tools.length || skill.tools.length > 128) {
|
|
7576
7735
|
throw invalid("collaboration skill");
|
|
7577
7736
|
}
|
|
7578
7737
|
skillNames2.add(skill.name);
|
|
7579
7738
|
const tools = skill.tools.map((candidate) => {
|
|
7580
|
-
const tool =
|
|
7581
|
-
const inputSchema =
|
|
7739
|
+
const tool = record6(candidate);
|
|
7740
|
+
const inputSchema = record6(tool?.inputSchema);
|
|
7582
7741
|
if (!tool || !validManifestName(tool.name) || toolNames.has(tool.name) || typeof tool.description !== "string" || utf8Bytes(tool.description) > 8e3 || !inputSchema || jsonBytes(inputSchema) > 64e3 || tool.concurrency !== void 0 && tool.concurrency !== "parallel") {
|
|
7583
7742
|
throw invalid("collaboration tool");
|
|
7584
7743
|
}
|
|
@@ -7603,12 +7762,12 @@ function parseCollaborationSkills(value2) {
|
|
|
7603
7762
|
}
|
|
7604
7763
|
function validateCollaborationToolRequest(value2) {
|
|
7605
7764
|
validCommandId(value2.commandId);
|
|
7606
|
-
if (typeof value2.toolCallId !== "string" || value2.toolCallId.length > 256 || !/^[^\s\u0000-\u001f\u007f]+$/.test(value2.toolCallId) || !validManifestName(value2.skill) || !validManifestName(value2.tool) || !
|
|
7765
|
+
if (typeof value2.toolCallId !== "string" || value2.toolCallId.length > 256 || !/^[^\s\u0000-\u001f\u007f]+$/.test(value2.toolCallId) || !validManifestName(value2.skill) || !validManifestName(value2.tool) || !record6(value2.input) || jsonBytes(value2.input) > 128e3) {
|
|
7607
7766
|
throw new TypeError("invalid Code collaboration tool request");
|
|
7608
7767
|
}
|
|
7609
7768
|
}
|
|
7610
7769
|
function parseCollaborationToolOutput(value2) {
|
|
7611
|
-
const output =
|
|
7770
|
+
const output = record6(record6(value2)?.output);
|
|
7612
7771
|
if (!output || output.isError !== void 0 && typeof output.isError !== "boolean") {
|
|
7613
7772
|
throw invalid("collaboration tool");
|
|
7614
7773
|
}
|
|
@@ -7617,7 +7776,7 @@ function parseCollaborationToolOutput(value2) {
|
|
|
7617
7776
|
return { content: output.content, ...output.isError === true ? { isError: true } : {} };
|
|
7618
7777
|
}
|
|
7619
7778
|
if (!Array.isArray(output.content) || output.content.length > 64 || jsonBytes(output.content) > 1e6 || !output.content.every((block2) => {
|
|
7620
|
-
const item =
|
|
7779
|
+
const item = record6(block2);
|
|
7621
7780
|
return item && ["text", "image", "audio", "document", "tool_use", "tool_result", "thinking"].includes(String(item.type));
|
|
7622
7781
|
})) throw invalid("collaboration tool");
|
|
7623
7782
|
return {
|
|
@@ -7650,17 +7809,48 @@ function jsonBytes(value2) {
|
|
|
7650
7809
|
return Number.POSITIVE_INFINITY;
|
|
7651
7810
|
}
|
|
7652
7811
|
}
|
|
7653
|
-
var
|
|
7812
|
+
var record6 = (value2) => value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
|
|
7654
7813
|
var invalid = (part) => new CodeRuntimeControlError(`invalid Code runtime ${part} response`, 502, "invalid_response");
|
|
7655
7814
|
var RESERVED = /* @__PURE__ */ new Set([".git", ".odla", ".wrangler", "node_modules", "dist", "coverage"]);
|
|
7656
7815
|
var SECRET = /^(?:\.env(?:\..+)?|\.dev\.vars|credentials(?:\..+)?\.json|dev-token(?:\..+)?\.json)$/i;
|
|
7657
7816
|
var PATH = /^[A-Za-z0-9_@+.,-]+(?:\/[A-Za-z0-9_@+.,-]+)*$/;
|
|
7658
7817
|
var FORBIDDEN = /^(?:GIT binary patch|Binary files |rename (?:from|to) |copy (?:from|to) |similarity index |old mode |new mode |deleted file mode 160000|new file mode 160000)/m;
|
|
7659
7818
|
function stripPatchEnvelope(patch2) {
|
|
7660
|
-
if (!/^\*\*\* (?:Begin|End) Patch\s*$/m.test(patch2)) return patch2;
|
|
7819
|
+
if (!/^\*\*\* (?:Begin|End) Patch\s*$/m.test(patch2)) return applyPatchDialectToDiff(patch2);
|
|
7661
7820
|
const kept = patch2.split("\n").filter((line2) => !/^\*\*\* (?:Begin|End) Patch\s*$/.test(line2));
|
|
7662
7821
|
const stripped = kept.join("\n");
|
|
7663
|
-
|
|
7822
|
+
if (/^diff --git /m.test(stripped)) return stripped;
|
|
7823
|
+
const translated = applyPatchDialectToDiff(stripped);
|
|
7824
|
+
return translated === stripped ? patch2 : translated;
|
|
7825
|
+
}
|
|
7826
|
+
function applyPatchDialectToDiff(patch2) {
|
|
7827
|
+
if (!/^\*\*\* (?:Update|Add|Delete) File: /m.test(patch2)) return patch2;
|
|
7828
|
+
const out = [];
|
|
7829
|
+
let open = false;
|
|
7830
|
+
for (const line2 of patch2.split("\n")) {
|
|
7831
|
+
const file = /^\*\*\* (Update|Add|Delete) File: (.+?)\s*$/.exec(line2);
|
|
7832
|
+
if (file) {
|
|
7833
|
+
const [, verb, raw] = file;
|
|
7834
|
+
const path = raw.trim();
|
|
7835
|
+
if (!PATH.test(path)) return patch2;
|
|
7836
|
+
out.push(`diff --git a/${path} b/${path}`);
|
|
7837
|
+
if (verb === "Add") out.push("new file mode 100644", "--- /dev/null", `+++ b/${path}`);
|
|
7838
|
+
else if (verb === "Delete") out.push(`--- a/${path}`, "+++ /dev/null");
|
|
7839
|
+
else out.push(`--- a/${path}`, `+++ b/${path}`);
|
|
7840
|
+
open = true;
|
|
7841
|
+
continue;
|
|
7842
|
+
}
|
|
7843
|
+
if (/^\*\*\* /.test(line2)) continue;
|
|
7844
|
+
if (!open) continue;
|
|
7845
|
+
if (/^@@/.test(line2)) {
|
|
7846
|
+
out.push("@@ -1 +1 @@");
|
|
7847
|
+
continue;
|
|
7848
|
+
}
|
|
7849
|
+
out.push(line2);
|
|
7850
|
+
}
|
|
7851
|
+
if (!open) return patch2;
|
|
7852
|
+
return `${out.join("\n").replace(/\n+$/, "")}
|
|
7853
|
+
`;
|
|
7664
7854
|
}
|
|
7665
7855
|
function validateCodePatch(rawPatch, maxBytes) {
|
|
7666
7856
|
const patch2 = stripPatchEnvelope(rawPatch);
|
|
@@ -7713,17 +7903,20 @@ function resolveCodePath(workspaceDir, path) {
|
|
|
7713
7903
|
if (target !== root && !target.startsWith(`${root}${sep3}`)) throw new TypeError("path escapes the staged workspace");
|
|
7714
7904
|
return target;
|
|
7715
7905
|
}
|
|
7906
|
+
function hasContextFreeHunk(patch2) {
|
|
7907
|
+
const bodies = patch2.split(/^@@.*$/m).slice(1);
|
|
7908
|
+
return bodies.some((body) => !body.split("\n").some((line2) => line2.startsWith(" ") && line2.trim().length > 0));
|
|
7909
|
+
}
|
|
7716
7910
|
function describePatchFailure(patch2, detail) {
|
|
7717
7911
|
const hunks = patch2.split("\n").filter((line2) => line2.startsWith("@@"));
|
|
7718
|
-
const
|
|
7719
|
-
const contextless = bodies.some((body) => !body.split("\n").some((line2) => line2.startsWith(" ") && line2.trim().length > 0));
|
|
7720
|
-
const hint = hunks.length > 0 && contextless ? " A hunk has no context lines; include at least one unchanged line above or below each change." : "";
|
|
7912
|
+
const hint = hunks.length > 0 && hasContextFreeHunk(patch2) ? " A hunk has no context lines; include at least one unchanged line above or below each change." : "";
|
|
7721
7913
|
return `patch did not apply: ${detail}${hint}`;
|
|
7722
7914
|
}
|
|
7723
7915
|
async function applyCodePatch(workspaceDir, rawPatch, paths2) {
|
|
7724
7916
|
const patch2 = stripPatchEnvelope(rawPatch);
|
|
7725
|
-
|
|
7726
|
-
await gitApply(workspaceDir, patch2,
|
|
7917
|
+
const zero = hasContextFreeHunk(patch2);
|
|
7918
|
+
await gitApply(workspaceDir, patch2, true, zero);
|
|
7919
|
+
await gitApply(workspaceDir, patch2, false, zero);
|
|
7727
7920
|
for (const path of paths2) {
|
|
7728
7921
|
try {
|
|
7729
7922
|
const info = await lstat2(resolveCodePath(workspaceDir, path));
|
|
@@ -7735,9 +7928,16 @@ async function applyCodePatch(workspaceDir, rawPatch, paths2) {
|
|
|
7735
7928
|
}
|
|
7736
7929
|
}
|
|
7737
7930
|
}
|
|
7738
|
-
function gitApply(cwd, patch2, check) {
|
|
7931
|
+
function gitApply(cwd, patch2, check, unidiffZero = false) {
|
|
7739
7932
|
return new Promise((accept, reject) => {
|
|
7740
|
-
const args = [
|
|
7933
|
+
const args = [
|
|
7934
|
+
"apply",
|
|
7935
|
+
"--recount",
|
|
7936
|
+
...unidiffZero ? ["--unidiff-zero"] : [],
|
|
7937
|
+
"--whitespace=nowarn",
|
|
7938
|
+
...check ? ["--check"] : [],
|
|
7939
|
+
"-"
|
|
7940
|
+
];
|
|
7741
7941
|
const child = spawn4("git", args, {
|
|
7742
7942
|
cwd,
|
|
7743
7943
|
shell: false,
|
|
@@ -7746,8 +7946,8 @@ function gitApply(cwd, patch2, check) {
|
|
|
7746
7946
|
});
|
|
7747
7947
|
let stderr2 = "";
|
|
7748
7948
|
child.stderr.setEncoding("utf8");
|
|
7749
|
-
child.stderr.on("data", (
|
|
7750
|
-
if (stderr2.length < 4e3) stderr2 +=
|
|
7949
|
+
child.stderr.on("data", (text4) => {
|
|
7950
|
+
if (stderr2.length < 4e3) stderr2 += text4.slice(0, 4e3);
|
|
7751
7951
|
});
|
|
7752
7952
|
child.once("error", reject);
|
|
7753
7953
|
child.once("exit", (code) => code === 0 ? accept() : reject(new TypeError(describePatchFailure(patch2, stderr2.trim().slice(0, 500)))));
|
|
@@ -7993,7 +8193,7 @@ function validate2(input) {
|
|
|
7993
8193
|
maximumFiles: policy.maximumFiles ?? 2e4,
|
|
7994
8194
|
maximumBytes: policy.maximumBytes ?? 512 * 1024 * 1024
|
|
7995
8195
|
};
|
|
7996
|
-
if ([...result.testPathPrefixes, ...result.testPathSuffixes].some((rule) => !RULE.test(rule)) || !
|
|
8196
|
+
if ([...result.testPathPrefixes, ...result.testPathSuffixes].some((rule) => !RULE.test(rule)) || !integer2(result.maximumChangedTests, 0, 1e4) || !integer2(result.maximumPatchBytes, 1, 4 * 1024 * 1024) || !integer2(result.maximumFiles, 1, 1e5) || !integer2(result.maximumBytes, 1, 2 * 1024 * 1024 * 1024)) {
|
|
7997
8197
|
throw new TypeError("clean verification policy exceeds its bounds");
|
|
7998
8198
|
}
|
|
7999
8199
|
return result;
|
|
@@ -8044,7 +8244,7 @@ function hashFile(path) {
|
|
|
8044
8244
|
});
|
|
8045
8245
|
}
|
|
8046
8246
|
function checkedResult(result, maximumOutputBytes) {
|
|
8047
|
-
if (!
|
|
8247
|
+
if (!integer2(result.exitCode, 0, 255) || !integer2(result.durationMs, 0, 30 * 6e4) || typeof result.stdout !== "string" || typeof result.stderr !== "string" || typeof result.outputLimitExceeded !== "boolean" || typeof result.timedOut !== "boolean") {
|
|
8048
8248
|
throw new TypeError("recipe executor returned an invalid result");
|
|
8049
8249
|
}
|
|
8050
8250
|
const bytes = Buffer.byteLength(result.stdout) + Buffer.byteLength(result.stderr);
|
|
@@ -8094,7 +8294,7 @@ function digestJson(value2) {
|
|
|
8094
8294
|
function digestBytes(value2) {
|
|
8095
8295
|
return `sha256:${createHash22("sha256").update(value2).digest("hex")}`;
|
|
8096
8296
|
}
|
|
8097
|
-
function
|
|
8297
|
+
function integer2(value2, minimum, maximum) {
|
|
8098
8298
|
return Number.isSafeInteger(value2) && value2 >= minimum && value2 <= maximum;
|
|
8099
8299
|
}
|
|
8100
8300
|
async function prepareRuntimeCheckpoint(input) {
|
|
@@ -8121,9 +8321,9 @@ async function prepareRuntimeCheckpoint(input) {
|
|
|
8121
8321
|
if (evidence.receipt.outcome === "passed") {
|
|
8122
8322
|
verification = evidence.receipt;
|
|
8123
8323
|
review = await input.review(patch2, verification);
|
|
8124
|
-
note = review
|
|
8324
|
+
note = describeReview(review);
|
|
8125
8325
|
} else {
|
|
8126
|
-
note =
|
|
8326
|
+
note = describeGateFailure(evidence);
|
|
8127
8327
|
}
|
|
8128
8328
|
} catch (cause) {
|
|
8129
8329
|
note = `Candidate verification or review failed closed: ${message(cause)}`;
|
|
@@ -8148,6 +8348,23 @@ async function prepareRuntimeCheckpoint(input) {
|
|
|
8148
8348
|
});
|
|
8149
8349
|
return { checkpoint, verification, review, note };
|
|
8150
8350
|
}
|
|
8351
|
+
function describeReview(review) {
|
|
8352
|
+
const findings = review.findings.map((finding) => ` - [${finding.severity}] ${finding.detail}`).join("\n");
|
|
8353
|
+
const head = review.verdict === "approved" ? `Clean verification and independent review passed (score ${review.score}/100).` : `Clean verification passed; independent review REJECTED this candidate (score ${review.score}/100). Address the findings and checkpoint again.`;
|
|
8354
|
+
return [head, review.summary, findings].filter(Boolean).join("\n").slice(0, 4e3);
|
|
8355
|
+
}
|
|
8356
|
+
function describeGateFailure(evidence) {
|
|
8357
|
+
const failed = evidence.receipt.recipes.filter((recipe2) => recipe2.status !== "passed");
|
|
8358
|
+
const detail = failed.map((recipe2) => {
|
|
8359
|
+
const log = evidence.logs.find((entry) => entry.recipeId === recipe2.recipeId);
|
|
8360
|
+
const output = `${log?.stdout ?? ""}
|
|
8361
|
+
${log?.stderr ?? ""}`.trim();
|
|
8362
|
+
return `${recipe2.recipeId}=${recipe2.status}${output ? `
|
|
8363
|
+
${output.slice(0, 1500)}` : ""}`;
|
|
8364
|
+
}).join("\n\n");
|
|
8365
|
+
return `Clean verification failed. Fix this and checkpoint again:
|
|
8366
|
+
${detail}`.slice(0, 4e3);
|
|
8367
|
+
}
|
|
8151
8368
|
var message = (value2) => (value2 instanceof Error ? value2.message : String(value2)).slice(0, 500);
|
|
8152
8369
|
var CodeRuntimeCheckpointManager = class {
|
|
8153
8370
|
constructor(options) {
|
|
@@ -9166,8 +9383,14 @@ function optionalInteger(value2) {
|
|
|
9166
9383
|
if (!Number.isSafeInteger(value2) || value2 < 1) throw new TypeError("line bounds must be positive integers");
|
|
9167
9384
|
return value2;
|
|
9168
9385
|
}
|
|
9386
|
+
var DEFAULT_FAILURE_REASON2 = {
|
|
9387
|
+
"tool denied by CaMeL policy": "tool denied by CaMeL policy",
|
|
9388
|
+
"review sessions are read-only": "review session is read-only; workspace changes are not permitted"
|
|
9389
|
+
};
|
|
9169
9390
|
function response(request3, ok, content2, details) {
|
|
9170
|
-
return { requestId: request3.requestId, ok, content: content2, ...details ? { details } : {} };
|
|
9391
|
+
if (ok) return { requestId: request3.requestId, ok, content: content2, ...details ? { details } : {} };
|
|
9392
|
+
const failureReason = typeof details?.failureReason === "string" && details.failureReason || DEFAULT_FAILURE_REASON2[content2] || content2 || "tool request failed; inspect the tool input and workspace state";
|
|
9393
|
+
return { requestId: request3.requestId, ok, content: content2, details: { ...details, failureReason } };
|
|
9171
9394
|
}
|
|
9172
9395
|
var cache = /* @__PURE__ */ new Map();
|
|
9173
9396
|
function workspaceGraphs(workspaceDir, paths2) {
|
|
@@ -9743,120 +9966,6 @@ async function appendCodeRuntimeEvent(control, command, event, refs) {
|
|
|
9743
9966
|
}
|
|
9744
9967
|
var digestRuntimeValue = (value2) => `sha256:${createHash32("sha256").update(value2).digest("hex")}`;
|
|
9745
9968
|
var runtimeErrorMessage = (value2) => value2 instanceof Error ? value2.message : String(value2);
|
|
9746
|
-
var text3 = (value2, maximum) => {
|
|
9747
|
-
if (typeof value2 !== "string") return void 0;
|
|
9748
|
-
const bounded = value2.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g, " ").trim();
|
|
9749
|
-
return bounded ? bounded.slice(0, maximum) : void 0;
|
|
9750
|
-
};
|
|
9751
|
-
var integer2 = (value2) => Number.isSafeInteger(value2) && Number(value2) >= 0 ? Number(value2) : void 0;
|
|
9752
|
-
var record32 = (value2) => value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : void 0;
|
|
9753
|
-
var excerpt = (value2, tail = false) => {
|
|
9754
|
-
if (typeof value2 !== "string") return void 0;
|
|
9755
|
-
const safe = value2.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g, " ");
|
|
9756
|
-
const source = (tail ? safe.slice(-1e4) : safe.slice(0, 1e4)).trim();
|
|
9757
|
-
if (!source) return void 0;
|
|
9758
|
-
const lines = source.split("\n").filter((line2) => line2.trim()).map((line2) => line2.slice(0, 240));
|
|
9759
|
-
const selected = tail ? lines.slice(-10) : lines.slice(0, 10);
|
|
9760
|
-
return text3(selected.join("\n"), 2400);
|
|
9761
|
-
};
|
|
9762
|
-
var paths = (value2) => {
|
|
9763
|
-
if (!Array.isArray(value2)) return void 0;
|
|
9764
|
-
const items = value2.flatMap((item) => {
|
|
9765
|
-
const path = text3(item, 1024);
|
|
9766
|
-
return path ? [path] : [];
|
|
9767
|
-
}).slice(0, 12);
|
|
9768
|
-
return items.length ? items : void 0;
|
|
9769
|
-
};
|
|
9770
|
-
function patchStats(value2) {
|
|
9771
|
-
if (typeof value2 !== "string") return {};
|
|
9772
|
-
let additions = 0;
|
|
9773
|
-
let deletions = 0;
|
|
9774
|
-
for (const line2 of value2.slice(0, 262144).split("\n")) {
|
|
9775
|
-
if (line2.startsWith("+++") || line2.startsWith("---")) continue;
|
|
9776
|
-
if (line2.startsWith("+")) additions += 1;
|
|
9777
|
-
else if (line2.startsWith("-")) deletions += 1;
|
|
9778
|
-
}
|
|
9779
|
-
return { ...additions ? { additions } : {}, ...deletions ? { deletions } : {} };
|
|
9780
|
-
}
|
|
9781
|
-
function searchResults(value2) {
|
|
9782
|
-
if (typeof value2 !== "string") return void 0;
|
|
9783
|
-
const results = value2.split("\n").flatMap((line2) => {
|
|
9784
|
-
const match = /^([^:\n]{1,1024}):(\d+):\s?(.*)$/.exec(line2);
|
|
9785
|
-
if (!match) return [];
|
|
9786
|
-
const lineNumber = Number(match[2]);
|
|
9787
|
-
const itemText = text3(match[3], 240);
|
|
9788
|
-
if (!Number.isSafeInteger(lineNumber) || lineNumber < 1) return [];
|
|
9789
|
-
return [{ path: match[1], line: lineNumber, ...itemText ? { text: itemText } : {} }];
|
|
9790
|
-
}).slice(0, 5);
|
|
9791
|
-
return results.length ? results : void 0;
|
|
9792
|
-
}
|
|
9793
|
-
function codeToolRequestPresentation(request3) {
|
|
9794
|
-
const input = request3.input;
|
|
9795
|
-
if (request3.tool === "sandbox.read") {
|
|
9796
|
-
const path = text3(input.path, 1024);
|
|
9797
|
-
if (!path) return void 0;
|
|
9798
|
-
const startLine = integer2(input.startLine);
|
|
9799
|
-
const endLine = integer2(input.endLine);
|
|
9800
|
-
return { kind: "read", path, ...startLine ? { startLine } : {}, ...endLine ? { endLine } : {} };
|
|
9801
|
-
}
|
|
9802
|
-
if (request3.tool === "sandbox.list") {
|
|
9803
|
-
const scope = text3(input.prefix, 1024);
|
|
9804
|
-
return { kind: "list", ...scope ? { scope } : {} };
|
|
9805
|
-
}
|
|
9806
|
-
if (request3.tool === "sandbox.search" || request3.tool === "sandbox.overview" || request3.tool === "sandbox.where_is" || request3.tool === "sandbox.who_imports" || request3.tool === "sandbox.who_touches") {
|
|
9807
|
-
const query = text3(input.query, 512);
|
|
9808
|
-
const scope = request3.tool === "sandbox.search" ? text3(input.prefix, 1024) : void 0;
|
|
9809
|
-
if (request3.tool === "sandbox.search" && !query) return void 0;
|
|
9810
|
-
return { kind: "query", ...query ? { query } : {}, ...scope ? { scope } : {} };
|
|
9811
|
-
}
|
|
9812
|
-
if (request3.tool === "sandbox.apply_patch") {
|
|
9813
|
-
return { kind: "patch", ...patchStats(input.patch) };
|
|
9814
|
-
}
|
|
9815
|
-
const recipeId = text3(input.recipeId, 120);
|
|
9816
|
-
return recipeId ? { kind: "recipe", recipeId } : void 0;
|
|
9817
|
-
}
|
|
9818
|
-
function codeToolResultPresentation(request3, response2) {
|
|
9819
|
-
const started = codeToolRequestPresentation(request3);
|
|
9820
|
-
if (!started || !response2.ok) return started;
|
|
9821
|
-
const details = record32(response2.details);
|
|
9822
|
-
if (started.kind === "read") {
|
|
9823
|
-
return {
|
|
9824
|
-
...started,
|
|
9825
|
-
...integer2(details?.startLine) ? { startLine: integer2(details?.startLine) } : {},
|
|
9826
|
-
...integer2(details?.endLine) ? { endLine: integer2(details?.endLine) } : {},
|
|
9827
|
-
...excerpt(response2.content) ? { excerpt: excerpt(response2.content) } : {}
|
|
9828
|
-
};
|
|
9829
|
-
}
|
|
9830
|
-
if (started.kind === "list") {
|
|
9831
|
-
const listed = response2.content.split("\n").filter((line2) => line2 && !line2.startsWith("\u2026") && !line2.startsWith("Workspace ")).map((line2) => text3(line2, 1024)).filter((line2) => Boolean(line2)).slice(0, 8);
|
|
9832
|
-
return {
|
|
9833
|
-
...started,
|
|
9834
|
-
...integer2(details?.count) !== void 0 ? { count: integer2(details?.count) } : {},
|
|
9835
|
-
...listed.length ? { paths: listed } : {}
|
|
9836
|
-
};
|
|
9837
|
-
}
|
|
9838
|
-
if (started.kind === "query") {
|
|
9839
|
-
const results = request3.tool === "sandbox.search" ? searchResults(response2.content) : void 0;
|
|
9840
|
-
const resultExcerpt = request3.tool === "sandbox.search" ? void 0 : excerpt(response2.content);
|
|
9841
|
-
return {
|
|
9842
|
-
...started,
|
|
9843
|
-
...integer2(details?.count) !== void 0 ? { count: integer2(details?.count) } : {},
|
|
9844
|
-
...results ? { results } : {},
|
|
9845
|
-
...resultExcerpt ? { excerpt: resultExcerpt } : {}
|
|
9846
|
-
};
|
|
9847
|
-
}
|
|
9848
|
-
if (started.kind === "patch") {
|
|
9849
|
-
return { ...started, ...paths(details?.paths) ? { paths: paths(details?.paths) } : {} };
|
|
9850
|
-
}
|
|
9851
|
-
const output = response2.content.replace(/^Recipe [^\n]*\.?\s*/u, "");
|
|
9852
|
-
return {
|
|
9853
|
-
...started,
|
|
9854
|
-
...integer2(details?.exitCode) !== void 0 ? { exitCode: integer2(details?.exitCode) } : {},
|
|
9855
|
-
...typeof details?.timedOut === "boolean" ? { timedOut: details.timedOut } : {},
|
|
9856
|
-
...typeof details?.outputLimitExceeded === "boolean" ? { outputLimitExceeded: details.outputLimitExceeded } : {},
|
|
9857
|
-
...excerpt(output, true) ? { excerpt: excerpt(output, true) } : {}
|
|
9858
|
-
};
|
|
9859
|
-
}
|
|
9860
9969
|
function codeRuntimeAcknowledgementGate(signal) {
|
|
9861
9970
|
let settle;
|
|
9862
9971
|
let settled = false;
|
|
@@ -10158,36 +10267,11 @@ var TheseusRuntimeEngine = class {
|
|
|
10158
10267
|
}
|
|
10159
10268
|
/** Report every brokered effect as it starts and finishes. */
|
|
10160
10269
|
#observed(command, active, broker) {
|
|
10161
|
-
return {
|
|
10162
|
-
|
|
10163
|
-
|
|
10164
|
-
|
|
10165
|
-
|
|
10166
|
-
await this.#event(
|
|
10167
|
-
command,
|
|
10168
|
-
{
|
|
10169
|
-
type: "tool",
|
|
10170
|
-
phase: "started",
|
|
10171
|
-
tool: request3.tool,
|
|
10172
|
-
operationId,
|
|
10173
|
-
...startedPresentation ? { presentation: startedPresentation } : {}
|
|
10174
|
-
},
|
|
10175
|
-
active.conversationRefs
|
|
10176
|
-
).catch(() => void 0);
|
|
10177
|
-
const response2 = await broker.execute(context, request3);
|
|
10178
|
-
const completedPresentation = codeToolResultPresentation(request3, response2);
|
|
10179
|
-
await this.#event(command, {
|
|
10180
|
-
type: "tool",
|
|
10181
|
-
phase: "completed",
|
|
10182
|
-
tool: request3.tool,
|
|
10183
|
-
ok: response2.ok,
|
|
10184
|
-
durationMs: Date.now() - startedAt,
|
|
10185
|
-
operationId,
|
|
10186
|
-
...completedPresentation ? { presentation: completedPresentation } : {}
|
|
10187
|
-
}, active.conversationRefs).catch(() => void 0);
|
|
10188
|
-
return response2;
|
|
10189
|
-
}
|
|
10190
|
-
};
|
|
10270
|
+
return observedBroker({
|
|
10271
|
+
broker,
|
|
10272
|
+
operationIdFor: (requestId) => digestRuntimeValue(`${command.commandId}:${requestId}`),
|
|
10273
|
+
emit: (event) => this.#event(command, event, active.conversationRefs).catch(() => void 0)
|
|
10274
|
+
});
|
|
10191
10275
|
}
|
|
10192
10276
|
async #checkpoint(command) {
|
|
10193
10277
|
const active = this.#active.get(command.sessionId);
|
|
@@ -10497,6 +10581,19 @@ function digestText(value2) {
|
|
|
10497
10581
|
// src/code-runtime-config.ts
|
|
10498
10582
|
var CODE_NODE_IMAGE = "node:24-alpine@sha256:a0b9bf06e4e6193cf7a0f58816cc935ff8c2a908f81e6f1a95432d679c54fbfd";
|
|
10499
10583
|
var CODE_BUILD_RECIPES = Object.freeze([{
|
|
10584
|
+
id: "odla-code-gates",
|
|
10585
|
+
image: CODE_NODE_IMAGE,
|
|
10586
|
+
// Selects the repository's fast, no-capability gates from the same manifest
|
|
10587
|
+
// CI and `npm run preflight` read, so a new gate is picked up without a
|
|
10588
|
+
// second list to keep in sync. The container has no shell: this is argv.
|
|
10589
|
+
command: ["node", "scripts/recipe-gates.mjs"],
|
|
10590
|
+
timeoutMs: 18e4,
|
|
10591
|
+
maxOutputBytes: 1024 * 1024,
|
|
10592
|
+
cpus: 1,
|
|
10593
|
+
// check:secrets holds ~2,500 source files in memory at once.
|
|
10594
|
+
memory: "1g",
|
|
10595
|
+
pids: 128
|
|
10596
|
+
}, {
|
|
10500
10597
|
id: "odla-code-contracts",
|
|
10501
10598
|
image: CODE_NODE_IMAGE,
|
|
10502
10599
|
command: [
|
|
@@ -10676,20 +10773,20 @@ async function runCodeRuntime(input) {
|
|
|
10676
10773
|
}
|
|
10677
10774
|
}
|
|
10678
10775
|
function parseConnection(value2, appId, appEnv) {
|
|
10679
|
-
const root =
|
|
10680
|
-
const host =
|
|
10681
|
-
const offer =
|
|
10682
|
-
const binding =
|
|
10776
|
+
const root = record7(value2);
|
|
10777
|
+
const host = record7(root?.host);
|
|
10778
|
+
const offer = record7(root?.offer);
|
|
10779
|
+
const binding = record7(root?.binding);
|
|
10683
10780
|
if (!root || typeof root.token !== "string" || !/^odla_code_host_[0-9a-f]{64}$/.test(root.token) || typeof root.resumed !== "boolean" || !host || !/^chost_[0-9a-f]{32}$/.test(String(host.hostId)) || typeof host.name !== "string" || !offer || !Number.isSafeInteger(offer.slots) || !binding || typeof binding.appId !== "string" || !binding.appId || appId && binding.appId !== appId || binding.env !== appEnv || !Number.isSafeInteger(binding.generation)) {
|
|
10684
10781
|
throw new Error("connect Code host returned an invalid response");
|
|
10685
10782
|
}
|
|
10686
10783
|
return root;
|
|
10687
10784
|
}
|
|
10688
10785
|
function apiFailure(action2, status, value2) {
|
|
10689
|
-
const message2 =
|
|
10786
|
+
const message2 = record7(record7(value2)?.error)?.message;
|
|
10690
10787
|
return `${action2} failed (${status})${typeof message2 === "string" ? `: ${message2}` : ""}`;
|
|
10691
10788
|
}
|
|
10692
|
-
function
|
|
10789
|
+
function record7(value2) {
|
|
10693
10790
|
return value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
|
|
10694
10791
|
}
|
|
10695
10792
|
|
|
@@ -11195,6 +11292,14 @@ Usage:
|
|
|
11195
11292
|
odla-ai ai models [--config odla.config.mjs] [--env dev] [--provider <id>] [--json]
|
|
11196
11293
|
odla-ai config <diff|plan> [--config odla.config.mjs] [--email <odla-account>] [--json]
|
|
11197
11294
|
odla-ai config apply --plan <plan.json> [--idempotency-key <key>] [--email <odla-account>] [--json]
|
|
11295
|
+
odla-ai promotion plan --file <promotion-plan.json> [--env dev] [--json]
|
|
11296
|
+
odla-ai promotion inspect <plan-id> [--env dev] [--json]
|
|
11297
|
+
odla-ai promotion status <plan-id> [--env dev] [--json]
|
|
11298
|
+
odla-ai promotion apply <plan-id> --approval <approval-id> [--idempotency-key <key>] [--env dev] [--json]
|
|
11299
|
+
odla-ai promotion rollback <plan-id> --approval <approval-id> [--idempotency-key <key>] [--env dev] [--json]
|
|
11300
|
+
odla-ai promotion next <plan-id> <operation-id> [--env dev] [--json]
|
|
11301
|
+
odla-ai promotion record <plan-id> <operation-id> <step-id> --file <step-receipt.json> [--env dev] [--json]
|
|
11302
|
+
odla-ai promotion cancel <plan-id> <operation-id> [--env dev] [--json]
|
|
11198
11303
|
odla-ai operations get <operation-id> [--json]
|
|
11199
11304
|
odla-ai operations wait <operation-id> [--interval <seconds>] [--timeout <seconds>] [--json]
|
|
11200
11305
|
odla-ai calendar status [--env dev] [--email <odla-account>] [--json]
|
|
@@ -11361,6 +11466,11 @@ Commands:
|
|
|
11361
11466
|
init Create a generic odla.config.mjs plus starter schema/rules files.
|
|
11362
11467
|
doctor Validate and summarize the project config without network calls.
|
|
11363
11468
|
config Diff Registry intent, freeze a CAS-bound plan, and conditionally apply its safe actions.
|
|
11469
|
+
promotion Plan and inspect exact selective-release bundles without target
|
|
11470
|
+
mutation, then queue and resume a human-approved apply or rollback
|
|
11471
|
+
from an enrolled device. Each target step is leased and receipt-
|
|
11472
|
+
journaled; approval remains bound to the immutable plan digest,
|
|
11473
|
+
target set, action, and expiry, so every mismatch fails closed.
|
|
11364
11474
|
operations Inspect or wait on one exact, durable config-operation receipt.
|
|
11365
11475
|
calendar Inspect, connect, or disconnect the live Google booking connection.
|
|
11366
11476
|
app Archive (suspend, data retained), restore, export, import, or
|
|
@@ -12236,17 +12346,17 @@ function collectEntityFields(entity, parsed, allowClear) {
|
|
|
12236
12346
|
if (entity === "task" && fields.column === "ready") fields.column = "todo";
|
|
12237
12347
|
return fields;
|
|
12238
12348
|
}
|
|
12239
|
-
function statusCol(entity,
|
|
12240
|
-
if (entity === "bug") return `${
|
|
12349
|
+
function statusCol(entity, record12) {
|
|
12350
|
+
if (entity === "bug") return `${record12.status ?? ""}/${record12.severity ?? ""}`;
|
|
12241
12351
|
if (entity === "task") {
|
|
12242
|
-
const state2 =
|
|
12243
|
-
return
|
|
12352
|
+
const state2 = record12.column === "todo" ? "ready" : String(record12.column ?? "");
|
|
12353
|
+
return record12.revision ? `${state2}; r${record12.revision}` : state2;
|
|
12244
12354
|
}
|
|
12245
|
-
return String(
|
|
12355
|
+
return String(record12.status ?? "");
|
|
12246
12356
|
}
|
|
12247
|
-
function referenceMarkup(entity,
|
|
12248
|
-
const label = (
|
|
12249
|
-
return `@[${label}](pm:${entity}/${
|
|
12357
|
+
function referenceMarkup(entity, record12) {
|
|
12358
|
+
const label = (record12.title?.trim() || `${entity} ${record12.id}`).replaceAll("]", ")");
|
|
12359
|
+
return `@[${label}](pm:${entity}/${record12.id})`;
|
|
12250
12360
|
}
|
|
12251
12361
|
var STUDIO_SECTION = {
|
|
12252
12362
|
goal: "goals",
|
|
@@ -12260,13 +12370,13 @@ function studioRecordUrl(ctx, entity, id2) {
|
|
|
12260
12370
|
ctx.platformUrl
|
|
12261
12371
|
).href;
|
|
12262
12372
|
}
|
|
12263
|
-
function studioRecordLink(ctx, entity,
|
|
12264
|
-
const label = (
|
|
12265
|
-
return `[${label}](${studioRecordUrl(ctx, entity,
|
|
12373
|
+
function studioRecordLink(ctx, entity, record12) {
|
|
12374
|
+
const label = (record12.title?.trim() || `${entity} ${record12.id}`).replaceAll("]", ")");
|
|
12375
|
+
return `[${label}](${studioRecordUrl(ctx, entity, record12.id)})`;
|
|
12266
12376
|
}
|
|
12267
|
-
function printRecord(ctx, entity,
|
|
12377
|
+
function printRecord(ctx, entity, record12) {
|
|
12268
12378
|
ctx.out.log(
|
|
12269
|
-
`${
|
|
12379
|
+
`${record12.id} [${statusCol(entity, record12)}] ${record12.appId} ${studioRecordLink(ctx, entity, record12)}`
|
|
12270
12380
|
);
|
|
12271
12381
|
}
|
|
12272
12382
|
function emit2(ctx, value2, human) {
|
|
@@ -12320,8 +12430,8 @@ async function pmAdd(ctx, entity, parsed) {
|
|
|
12320
12430
|
input,
|
|
12321
12431
|
mutationId: writeMutationId2(parsed)
|
|
12322
12432
|
});
|
|
12323
|
-
const
|
|
12324
|
-
emit2(ctx, res, () => ctx.out.log(`created ${entity}: ${studioRecordLink(ctx, entity,
|
|
12433
|
+
const record12 = { id: res.id, appId, title: String(input.title) };
|
|
12434
|
+
emit2(ctx, res, () => ctx.out.log(`created ${entity}: ${studioRecordLink(ctx, entity, record12)}`));
|
|
12325
12435
|
}
|
|
12326
12436
|
var UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
12327
12437
|
var UUID_PREFIX = /^[0-9a-f-]{8,35}$/i;
|
|
@@ -12341,7 +12451,7 @@ async function resolvePmId(ctx, entity, supplied) {
|
|
|
12341
12451
|
"GET",
|
|
12342
12452
|
`/${entity}?limit=${limit}&offset=${offset}`
|
|
12343
12453
|
);
|
|
12344
|
-
matches.push(...page2.records.map((
|
|
12454
|
+
matches.push(...page2.records.map((record12) => record12.id).filter((id2) => id2.toLowerCase().startsWith(prefix)));
|
|
12345
12455
|
offset += page2.records.length;
|
|
12346
12456
|
if (matches.length > 1 || page2.records.length === 0 || offset >= page2.total) break;
|
|
12347
12457
|
}
|
|
@@ -12355,17 +12465,17 @@ async function resolvePmId(ctx, entity, supplied) {
|
|
|
12355
12465
|
}
|
|
12356
12466
|
async function pmGet(ctx, entity, id2) {
|
|
12357
12467
|
const resolved = await resolvePmId(ctx, entity, id2);
|
|
12358
|
-
const { record:
|
|
12359
|
-
emit2(ctx,
|
|
12468
|
+
const { record: record12 } = await pmRequest(ctx, "GET", `/${entity}/${encodeURIComponent(resolved)}`);
|
|
12469
|
+
emit2(ctx, record12, () => printRecord(ctx, entity, record12));
|
|
12360
12470
|
}
|
|
12361
12471
|
async function pmReference(ctx, entity, id2) {
|
|
12362
|
-
const { record:
|
|
12472
|
+
const { record: record12 } = await pmRequest(
|
|
12363
12473
|
ctx,
|
|
12364
12474
|
"GET",
|
|
12365
12475
|
`/${entity}/${encodeURIComponent(id2)}`
|
|
12366
12476
|
);
|
|
12367
|
-
const markup = referenceMarkup(entity,
|
|
12368
|
-
emit2(ctx, { kind: `pm:${entity}`, id:
|
|
12477
|
+
const markup = referenceMarkup(entity, record12);
|
|
12478
|
+
emit2(ctx, { kind: `pm:${entity}`, id: record12.id, label: record12.title ?? "", markup }, () => {
|
|
12369
12479
|
ctx.out.log(markup);
|
|
12370
12480
|
});
|
|
12371
12481
|
}
|
|
@@ -12450,16 +12560,16 @@ var PER_ENTITY = {
|
|
|
12450
12560
|
decision: ["status", "body", "supersedesId"],
|
|
12451
12561
|
bug: ["status", "severity", "description", "goalId", "assigneeId", "decisionId"]
|
|
12452
12562
|
};
|
|
12453
|
-
function leanRecord(entity,
|
|
12563
|
+
function leanRecord(entity, record12) {
|
|
12454
12564
|
const out = {};
|
|
12455
12565
|
for (const key of [...COMMON, ...PER_ENTITY[entity]]) {
|
|
12456
|
-
const value2 =
|
|
12566
|
+
const value2 = record12[key];
|
|
12457
12567
|
if (value2 !== void 0 && value2 !== null) out[key] = value2;
|
|
12458
12568
|
}
|
|
12459
12569
|
return out;
|
|
12460
12570
|
}
|
|
12461
12571
|
function leanRecords(entity, records, verbose) {
|
|
12462
|
-
return verbose ? records : records.map((
|
|
12572
|
+
return verbose ? records : records.map((record12) => leanRecord(entity, record12));
|
|
12463
12573
|
}
|
|
12464
12574
|
|
|
12465
12575
|
// src/pm-intake.ts
|
|
@@ -12492,8 +12602,8 @@ async function pmNext(ctx, parsed) {
|
|
|
12492
12602
|
// One request for both live columns; the split below is over open work only.
|
|
12493
12603
|
listFiltered(ctx, "task", appId, projectId, { column: `${READY_COLUMN},doing` })
|
|
12494
12604
|
]);
|
|
12495
|
-
const ready = tasks.filter((
|
|
12496
|
-
const doing = tasks.filter((
|
|
12605
|
+
const ready = tasks.filter((record12) => record12.column === READY_COLUMN);
|
|
12606
|
+
const doing = tasks.filter((record12) => record12.column === "doing");
|
|
12497
12607
|
const guidance = !goals.length ? "discuss alignment with the user before creating or claiming project work" : !ready.length ? 'refine a linked Backlog task and mark it Ready with "pm task ready <id>"' : `claim the top Ready task in one call: odla-ai pm start --app ${appId}`;
|
|
12498
12608
|
const monitor = `odla-ai pm watch --app ${appId} --jsonl`;
|
|
12499
12609
|
const result = {
|
|
@@ -12514,7 +12624,7 @@ async function pmNext(ctx, parsed) {
|
|
|
12514
12624
|
]) {
|
|
12515
12625
|
ctx.out.log(`${label}:`);
|
|
12516
12626
|
if (!records.length) ctx.out.log("- (none)");
|
|
12517
|
-
else for (const
|
|
12627
|
+
else for (const record12 of records) printRecord(ctx, entity, record12);
|
|
12518
12628
|
}
|
|
12519
12629
|
ctx.out.log(`next: ${guidance}`);
|
|
12520
12630
|
ctx.out.log(`monitor: ${monitor}`);
|
|
@@ -12553,7 +12663,7 @@ async function pmHandoff(ctx, parsed) {
|
|
|
12553
12663
|
]) {
|
|
12554
12664
|
ctx.out.log(`${label}:`);
|
|
12555
12665
|
if (!records.length) ctx.out.log("- (none)");
|
|
12556
|
-
else for (const
|
|
12666
|
+
else for (const record12 of records) printRecord(ctx, entity, record12);
|
|
12557
12667
|
}
|
|
12558
12668
|
ctx.out.log(`monitor: ${monitor}`);
|
|
12559
12669
|
});
|
|
@@ -12628,14 +12738,14 @@ async function pmStart(ctx, parsed) {
|
|
|
12628
12738
|
|
|
12629
12739
|
// src/pm-links.ts
|
|
12630
12740
|
async function pmLink(ctx, entity, id2) {
|
|
12631
|
-
const { record:
|
|
12741
|
+
const { record: record12 } = await pmRequest(
|
|
12632
12742
|
ctx,
|
|
12633
12743
|
"GET",
|
|
12634
12744
|
`/${entity}/${encodeURIComponent(id2)}`
|
|
12635
12745
|
);
|
|
12636
|
-
const url = studioRecordUrl(ctx, entity,
|
|
12637
|
-
const markdown = studioRecordLink(ctx, entity,
|
|
12638
|
-
emit2(ctx, { kind: entity, id:
|
|
12746
|
+
const url = studioRecordUrl(ctx, entity, record12.id);
|
|
12747
|
+
const markdown = studioRecordLink(ctx, entity, record12);
|
|
12748
|
+
emit2(ctx, { kind: entity, id: record12.id, label: record12.title ?? "", url, markdown }, () => {
|
|
12639
12749
|
ctx.out.log(markdown);
|
|
12640
12750
|
});
|
|
12641
12751
|
}
|
|
@@ -12762,16 +12872,16 @@ async function page(ctx, appId, cursor) {
|
|
|
12762
12872
|
}
|
|
12763
12873
|
return data;
|
|
12764
12874
|
}
|
|
12765
|
-
function recordState(
|
|
12766
|
-
if (
|
|
12767
|
-
return String(
|
|
12875
|
+
function recordState(record12) {
|
|
12876
|
+
if (record12.column) return record12.column === "todo" ? "ready" : record12.column;
|
|
12877
|
+
return String(record12.status ?? "");
|
|
12768
12878
|
}
|
|
12769
12879
|
function eventRecord(event) {
|
|
12770
12880
|
return event.payload.payload;
|
|
12771
12881
|
}
|
|
12772
12882
|
function eventLabel(event) {
|
|
12773
|
-
const
|
|
12774
|
-
if (
|
|
12883
|
+
const record12 = eventRecord(event);
|
|
12884
|
+
if (record12) return String(record12.title ?? event.payload.entityId);
|
|
12775
12885
|
const body = event.payload.message?.body?.replace(/\s+/g, " ").trim();
|
|
12776
12886
|
return body || event.payload.entityId;
|
|
12777
12887
|
}
|
|
@@ -12779,10 +12889,10 @@ function report3(ctx, parsed, result) {
|
|
|
12779
12889
|
if (ctx.json) ctx.out.log(JSON.stringify(result, null, 2));
|
|
12780
12890
|
else if (parsed.options.jsonl !== true && result.found) {
|
|
12781
12891
|
for (const event of result.events ?? []) {
|
|
12782
|
-
const
|
|
12783
|
-
const state2 =
|
|
12892
|
+
const record12 = eventRecord(event);
|
|
12893
|
+
const state2 = record12 ? recordState(record12) : "comment";
|
|
12784
12894
|
ctx.out.log(
|
|
12785
|
-
`${event.id} ${event.type} ${state2}${
|
|
12895
|
+
`${event.id} ${event.type} ${state2}${record12?.revision ? `; r${record12.revision}` : ""} ${eventLabel(event)}`
|
|
12786
12896
|
);
|
|
12787
12897
|
}
|
|
12788
12898
|
}
|
|
@@ -12856,8 +12966,8 @@ async function pmWatch(ctx, parsed) {
|
|
|
12856
12966
|
}
|
|
12857
12967
|
firstSuccess = false;
|
|
12858
12968
|
const matching = current.events.filter((event) => {
|
|
12859
|
-
const
|
|
12860
|
-
const state2 =
|
|
12969
|
+
const record12 = eventRecord(event);
|
|
12970
|
+
const state2 = record12 ? recordState(record12).toLowerCase() : "";
|
|
12861
12971
|
return (!entity || event.payload.entityKind === entity) && (!action2 || event.payload.action === action2) && (!wantedState || state2 === wantedState || wantedState === "todo" && state2 === "ready") && (!by || event.actor.id === by) && (!self || event.actor.id !== self);
|
|
12862
12972
|
});
|
|
12863
12973
|
for (const event of matching) {
|
|
@@ -13288,17 +13398,17 @@ async function platformStatus(parsed, deps) {
|
|
|
13288
13398
|
}
|
|
13289
13399
|
}
|
|
13290
13400
|
function isPlatformStatus(value2) {
|
|
13291
|
-
if (!
|
|
13292
|
-
if (!
|
|
13293
|
-
if (!
|
|
13401
|
+
if (!record8(value2) || value2.schemaVersion !== "odla.platform-status/v1") return false;
|
|
13402
|
+
if (!record8(value2.verdict) || !Array.isArray(value2.verdict.reasons)) return false;
|
|
13403
|
+
if (!record8(value2.catalog) || !record8(value2.summary)) return false;
|
|
13294
13404
|
return Array.isArray(value2.services) && Array.isArray(value2.nextActions);
|
|
13295
13405
|
}
|
|
13296
13406
|
function apiMessage(value2) {
|
|
13297
|
-
if (!
|
|
13298
|
-
const error =
|
|
13407
|
+
if (!record8(value2)) return "request failed";
|
|
13408
|
+
const error = record8(value2.error) ? value2.error : value2;
|
|
13299
13409
|
return typeof error.message === "string" ? error.message : typeof error.code === "string" ? error.code : "request failed";
|
|
13300
13410
|
}
|
|
13301
|
-
function
|
|
13411
|
+
function record8(value2) {
|
|
13302
13412
|
return !!value2 && typeof value2 === "object" && !Array.isArray(value2);
|
|
13303
13413
|
}
|
|
13304
13414
|
|
|
@@ -13339,7 +13449,7 @@ function statusVerdict(reads) {
|
|
|
13339
13449
|
severity: "degraded"
|
|
13340
13450
|
});
|
|
13341
13451
|
}
|
|
13342
|
-
const performance =
|
|
13452
|
+
const performance = record9(reads.liveSync.body.performance) ? reads.liveSync.body.performance : null;
|
|
13343
13453
|
if (performance?.status === "unavailable") {
|
|
13344
13454
|
reasons.push({
|
|
13345
13455
|
source: "liveSync",
|
|
@@ -13420,7 +13530,7 @@ function statusVerdict(reads) {
|
|
|
13420
13530
|
reasons
|
|
13421
13531
|
};
|
|
13422
13532
|
}
|
|
13423
|
-
function
|
|
13533
|
+
function record9(value2) {
|
|
13424
13534
|
return Boolean(value2) && typeof value2 === "object" && !Array.isArray(value2);
|
|
13425
13535
|
}
|
|
13426
13536
|
function numeric2(value2) {
|
|
@@ -13448,7 +13558,7 @@ function printO11yStatus(status, out) {
|
|
|
13448
13558
|
out.log(
|
|
13449
13559
|
`o11y status ${status.scope.appId}/${status.scope.env} (${status.scope.minutes}m)`
|
|
13450
13560
|
);
|
|
13451
|
-
const routes = Array.isArray(status.application.body.routes) ? status.application.body.routes.filter(
|
|
13561
|
+
const routes = Array.isArray(status.application.body.routes) ? status.application.body.routes.filter(record10) : [];
|
|
13452
13562
|
const requests = routes.reduce(
|
|
13453
13563
|
(total, row) => total + numeric3(row.requests),
|
|
13454
13564
|
0
|
|
@@ -13460,39 +13570,39 @@ function printO11yStatus(status, out) {
|
|
|
13460
13570
|
out.log(
|
|
13461
13571
|
`application ${status.application.httpStatus} ${requests} requests ${errors} errors`
|
|
13462
13572
|
);
|
|
13463
|
-
const versions = Array.isArray(status.applicationVersions.body.rows) ? status.applicationVersions.body.rows.filter(
|
|
13573
|
+
const versions = Array.isArray(status.applicationVersions.body.rows) ? status.applicationVersions.body.rows.filter(record10) : [];
|
|
13464
13574
|
out.log(
|
|
13465
13575
|
`application-versions ${status.applicationVersions.httpStatus} ${versions.length ? versions.slice(0, 5).map(
|
|
13466
13576
|
(row) => `${String(row.value || "(unattributed)")}:${numeric3(row.requests)}`
|
|
13467
13577
|
).join(", ") : "none observed"}`
|
|
13468
13578
|
);
|
|
13469
13579
|
out.log(liveSyncLine(status.liveSync));
|
|
13470
|
-
const canaryDurations =
|
|
13580
|
+
const canaryDurations = record10(status.canary.body.durationsMs) ? status.canary.body.durationsMs : {};
|
|
13471
13581
|
out.log(
|
|
13472
13582
|
`canary ${status.canary.httpStatus} ${String(status.canary.body.status ?? status.canary.body.error ?? "unavailable")} ${optionalNumeric(canaryDurations.publishToVisibleMs)} publish-to-visible`
|
|
13473
13583
|
);
|
|
13474
|
-
const collectorIngest =
|
|
13475
|
-
const collectorStorage =
|
|
13584
|
+
const collectorIngest = record10(status.collector.body.ingest) ? status.collector.body.ingest : {};
|
|
13585
|
+
const collectorStorage = record10(collectorIngest.storage) ? collectorIngest.storage : {};
|
|
13476
13586
|
out.log(
|
|
13477
13587
|
`collector ${status.collector.httpStatus} ${String(status.collector.body.status ?? status.collector.body.error ?? "unavailable")} ${numeric3(collectorStorage.affectedPoints)} affected points`
|
|
13478
13588
|
);
|
|
13479
|
-
const providerMetrics =
|
|
13480
|
-
const providerCapacity =
|
|
13481
|
-
const workerMemory =
|
|
13589
|
+
const providerMetrics = record10(status.provider.body.metrics) ? status.provider.body.metrics : {};
|
|
13590
|
+
const providerCapacity = record10(status.provider.body.capacity) ? status.provider.body.capacity : {};
|
|
13591
|
+
const workerMemory = record10(providerCapacity.memory) ? providerCapacity.memory : {};
|
|
13482
13592
|
out.log(
|
|
13483
13593
|
`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`
|
|
13484
13594
|
);
|
|
13485
13595
|
for (const line2 of providerCapacityLines(status.providerCapacity)) {
|
|
13486
13596
|
out.log(line2);
|
|
13487
13597
|
}
|
|
13488
|
-
const coverage =
|
|
13489
|
-
const coverageCounts =
|
|
13490
|
-
const coverageBudget =
|
|
13598
|
+
const coverage = record10(status.providerReconciliation.body.comparison) ? status.providerReconciliation.body.comparison : {};
|
|
13599
|
+
const coverageCounts = record10(status.providerReconciliation.body.counts) ? status.providerReconciliation.body.counts : {};
|
|
13600
|
+
const coverageBudget = record10(status.providerReconciliation.body.budget) ? status.providerReconciliation.body.budget : {};
|
|
13491
13601
|
out.log(
|
|
13492
13602
|
`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`
|
|
13493
13603
|
);
|
|
13494
13604
|
const providerPoints = Array.isArray(status.providerHistory.body.points) ? status.providerHistory.body.points.length : 0;
|
|
13495
|
-
const providerFreshness =
|
|
13605
|
+
const providerFreshness = record10(status.providerHistory.body.freshness) ? status.providerHistory.body.freshness : {};
|
|
13496
13606
|
out.log(
|
|
13497
13607
|
`cloudflare-history ${status.providerHistory.httpStatus} ${String(status.providerHistory.body.status ?? status.providerHistory.body.error ?? "unavailable")} ${providerPoints} snapshots ${optionalAge(providerFreshness.ageMs)} old`
|
|
13498
13608
|
);
|
|
@@ -13501,17 +13611,17 @@ function printO11yStatus(status, out) {
|
|
|
13501
13611
|
);
|
|
13502
13612
|
}
|
|
13503
13613
|
function providerCapacityLines(read3) {
|
|
13504
|
-
const resources =
|
|
13505
|
-
const durableObjects =
|
|
13506
|
-
const periodic =
|
|
13507
|
-
const storage =
|
|
13508
|
-
const d1 =
|
|
13509
|
-
const d1Activity =
|
|
13510
|
-
const d1Storage =
|
|
13511
|
-
const d1Latency =
|
|
13512
|
-
const r2 =
|
|
13513
|
-
const r2Operations =
|
|
13514
|
-
const r2Storage =
|
|
13614
|
+
const resources = record10(read3.body.resources) ? read3.body.resources : {};
|
|
13615
|
+
const durableObjects = record10(resources.durableObjects) ? resources.durableObjects : {};
|
|
13616
|
+
const periodic = record10(durableObjects.periodic) ? durableObjects.periodic : {};
|
|
13617
|
+
const storage = record10(durableObjects.sqliteStorage) ? durableObjects.sqliteStorage : {};
|
|
13618
|
+
const d1 = record10(resources.d1) ? resources.d1 : {};
|
|
13619
|
+
const d1Activity = record10(d1.activity) ? d1.activity : {};
|
|
13620
|
+
const d1Storage = record10(d1.storage) ? d1.storage : {};
|
|
13621
|
+
const d1Latency = record10(d1Activity.latency) ? d1Activity.latency : {};
|
|
13622
|
+
const r2 = record10(resources.r2) ? resources.r2 : {};
|
|
13623
|
+
const r2Operations = record10(r2.operations) ? r2.operations : {};
|
|
13624
|
+
const r2Storage = record10(r2.storage) ? r2.storage : {};
|
|
13515
13625
|
const status = String(
|
|
13516
13626
|
read3.body.status ?? read3.body.error ?? "unavailable"
|
|
13517
13627
|
);
|
|
@@ -13522,11 +13632,11 @@ function providerCapacityLines(read3) {
|
|
|
13522
13632
|
];
|
|
13523
13633
|
}
|
|
13524
13634
|
function liveSyncLine(read3) {
|
|
13525
|
-
const performance =
|
|
13526
|
-
const commitToSend =
|
|
13635
|
+
const performance = record10(read3.body.performance) ? read3.body.performance : {};
|
|
13636
|
+
const commitToSend = record10(performance.commitToSend) ? performance.commitToSend : {};
|
|
13527
13637
|
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`;
|
|
13528
13638
|
}
|
|
13529
|
-
function
|
|
13639
|
+
function record10(value2) {
|
|
13530
13640
|
return Boolean(value2) && typeof value2 === "object" && !Array.isArray(value2);
|
|
13531
13641
|
}
|
|
13532
13642
|
function numeric3(value2) {
|
|
@@ -13864,7 +13974,7 @@ async function monitorCommand(parsed, deps = {}) {
|
|
|
13864
13974
|
if (action2 === "plan" || action2 === "apply") {
|
|
13865
13975
|
const desired = monitoringWireConfig(context.cfg, env);
|
|
13866
13976
|
const live = await request2(`${base}?env=${encodeURIComponent(env)}`, { headers }, doFetch);
|
|
13867
|
-
const currentRevision =
|
|
13977
|
+
const currentRevision = record11(live.config) ? string(live.config.revision) : null;
|
|
13868
13978
|
const changed = currentRevision !== desired.revision;
|
|
13869
13979
|
const plan = {
|
|
13870
13980
|
schemaVersion: 1,
|
|
@@ -13909,7 +14019,7 @@ async function monitorCommand(parsed, deps = {}) {
|
|
|
13909
14019
|
headers
|
|
13910
14020
|
}, doFetch);
|
|
13911
14021
|
emit3(result2, jsonOutput, out, () => {
|
|
13912
|
-
const run =
|
|
14022
|
+
const run = record11(result2.run) ? result2.run : {};
|
|
13913
14023
|
out.log(`monitor run ${appId}/${env}/${probeId}: ${string(run.outcome) ?? "unknown"}${run.failure_code ? ` (${String(run.failure_code)})` : ""}`);
|
|
13914
14024
|
});
|
|
13915
14025
|
return;
|
|
@@ -13934,12 +14044,12 @@ async function request2(url, init, doFetch) {
|
|
|
13934
14044
|
let body = {};
|
|
13935
14045
|
try {
|
|
13936
14046
|
const parsed = text4 ? JSON.parse(text4) : {};
|
|
13937
|
-
body =
|
|
14047
|
+
body = record11(parsed) ? parsed : { value: parsed };
|
|
13938
14048
|
} catch {
|
|
13939
14049
|
body = { message: text4.slice(0, 500) };
|
|
13940
14050
|
}
|
|
13941
14051
|
if (!response2.ok) {
|
|
13942
|
-
const error =
|
|
14052
|
+
const error = record11(body.error) ? body.error : body;
|
|
13943
14053
|
throw new Error(string(error.message) ?? string(error.code) ?? `monitor request failed (${response2.status})`);
|
|
13944
14054
|
}
|
|
13945
14055
|
return body;
|
|
@@ -13947,7 +14057,7 @@ async function request2(url, init, doFetch) {
|
|
|
13947
14057
|
function printRead(action2, appId, env, result, out) {
|
|
13948
14058
|
if (action2 === "status") {
|
|
13949
14059
|
out.log(`monitor status ${appId}/${env}: ${String(result.overall ?? (result.configured === false ? "not configured" : "unknown"))}`);
|
|
13950
|
-
const slos = Array.isArray(result.slos) ? result.slos.filter(
|
|
14060
|
+
const slos = Array.isArray(result.slos) ? result.slos.filter(record11) : [];
|
|
13951
14061
|
for (const slo of slos) out.log(`slo ${String(slo.id)} ${String(slo.state)} ${percent(slo.observed)} observed ${percent(slo.budgetRemaining)} budget remaining`);
|
|
13952
14062
|
const incidents = Array.isArray(result.openIncidents) ? result.openIncidents.length : 0;
|
|
13953
14063
|
const gaps = Array.isArray(result.monitoringGaps) ? result.monitoringGaps.length : 0;
|
|
@@ -13956,20 +14066,20 @@ function printRead(action2, appId, env, result, out) {
|
|
|
13956
14066
|
return;
|
|
13957
14067
|
}
|
|
13958
14068
|
if (action2 === "incidents") {
|
|
13959
|
-
const incidents = Array.isArray(result.incidents) ? result.incidents.filter(
|
|
14069
|
+
const incidents = Array.isArray(result.incidents) ? result.incidents.filter(record11) : [];
|
|
13960
14070
|
out.log(`monitor incidents ${appId}/${env}: ${incidents.length}`);
|
|
13961
14071
|
for (const incident2 of incidents) out.log(`${String(incident2.state)} ${String(incident2.kind)} ${String(incident2.slo_id)} ${new Date(Number(incident2.opened_at)).toISOString()}`);
|
|
13962
14072
|
return;
|
|
13963
14073
|
}
|
|
13964
14074
|
out.log(`monitor report ${appId}/${env}: ${String(result.period)} ${String(result.overall)}`);
|
|
13965
|
-
const probes = Array.isArray(result.probes) ? result.probes.filter(
|
|
14075
|
+
const probes = Array.isArray(result.probes) ? result.probes.filter(record11) : [];
|
|
13966
14076
|
for (const probe of probes) out.log(`probe ${String(probe.id)} ${Number(probe.good)} good ${Number(probe.bad)} bad ${Number(probe.unknown)} unknown`);
|
|
13967
14077
|
}
|
|
13968
14078
|
function emit3(value2, json, out, human) {
|
|
13969
14079
|
if (json) out.log(JSON.stringify(value2, null, 2));
|
|
13970
14080
|
else human();
|
|
13971
14081
|
}
|
|
13972
|
-
function
|
|
14082
|
+
function record11(value2) {
|
|
13973
14083
|
return value2 !== null && typeof value2 === "object" && !Array.isArray(value2);
|
|
13974
14084
|
}
|
|
13975
14085
|
function string(value2) {
|
|
@@ -14460,6 +14570,122 @@ async function provision(options) {
|
|
|
14460
14570
|
}
|
|
14461
14571
|
}
|
|
14462
14572
|
|
|
14573
|
+
// src/promotion-command.ts
|
|
14574
|
+
import { readFile as readFile5 } from "fs/promises";
|
|
14575
|
+
import { createAppsClient as createAppsClient4 } from "@odla-ai/apps";
|
|
14576
|
+
|
|
14577
|
+
// src/security-command-context.ts
|
|
14578
|
+
async function hostedSecurityContext(parsed, dependencies) {
|
|
14579
|
+
const configPath = stringOpt(parsed.options.config) ?? "odla.config.mjs";
|
|
14580
|
+
const cfg = await loadProjectConfig(configPath);
|
|
14581
|
+
const env = stringOpt(parsed.options.env) ?? (cfg.envs.includes("dev") ? "dev" : cfg.envs[0]);
|
|
14582
|
+
if (!env || !cfg.envs.includes(env)) {
|
|
14583
|
+
throw new Error(`env "${env ?? ""}" is not declared in ${configPath}`);
|
|
14584
|
+
}
|
|
14585
|
+
const platform = platformAudience(stringOpt(parsed.options.platform) ?? cfg.platformUrl);
|
|
14586
|
+
if (platformAudience(cfg.platformUrl) !== platform) {
|
|
14587
|
+
throw new Error("--platform cannot reuse a project developer token from another platform; update odla.config.mjs and authenticate there");
|
|
14588
|
+
}
|
|
14589
|
+
const doFetch = dependencies.fetch ?? fetch;
|
|
14590
|
+
const stdout = dependencies.stdout ?? console;
|
|
14591
|
+
const open = parsed.options.open === false ? false : parsed.options.open === true ? true : void 0;
|
|
14592
|
+
const token = await getDeveloperToken(
|
|
14593
|
+
cfg,
|
|
14594
|
+
{ configPath, email: stringOpt(parsed.options.email), open, openApprovalUrl: dependencies.openUrl },
|
|
14595
|
+
doFetch,
|
|
14596
|
+
stdout,
|
|
14597
|
+
{ optionalProjectCapabilities: ["app.manage"] }
|
|
14598
|
+
);
|
|
14599
|
+
return { platform, token, appId: cfg.app.id, env, fetch: doFetch, stdout };
|
|
14600
|
+
}
|
|
14601
|
+
function requiredSecurityPositional(parsed, index, label) {
|
|
14602
|
+
const value2 = parsed.positionals[index];
|
|
14603
|
+
if (!value2) throw new Error(`${label} is required`);
|
|
14604
|
+
return value2;
|
|
14605
|
+
}
|
|
14606
|
+
function securityProfile(value2) {
|
|
14607
|
+
if (value2 === void 0) return void 0;
|
|
14608
|
+
if (value2 === "odla" || value2 === "cloudflare-app" || value2 === "generic") return value2;
|
|
14609
|
+
throw new Error("--profile must be odla, cloudflare-app, or generic");
|
|
14610
|
+
}
|
|
14611
|
+
|
|
14612
|
+
// src/promotion-command.ts
|
|
14613
|
+
var render = (value2, json, out) => {
|
|
14614
|
+
if (json) out.log(JSON.stringify(value2));
|
|
14615
|
+
else out.log(JSON.stringify(value2, null, 2));
|
|
14616
|
+
};
|
|
14617
|
+
async function promotionCommand(parsed, dependencies) {
|
|
14618
|
+
const action2 = parsed.positionals[1];
|
|
14619
|
+
if (!action2 || !["plan", "inspect", "status", "apply", "rollback", "next", "record", "cancel"].includes(action2)) rejectWord(["promotion"], action2);
|
|
14620
|
+
assertArgs(parsed, ["config", "env", "platform", "email", "open", "json", "file", "approval", "idempotency-key"], 5);
|
|
14621
|
+
const context = await hostedSecurityContext(parsed, dependencies);
|
|
14622
|
+
const client = createAppsClient4({
|
|
14623
|
+
token: context.token,
|
|
14624
|
+
fetcher: { fetch: (request3, init) => {
|
|
14625
|
+
const internal = new URL(typeof request3 === "string" ? request3 : request3.url);
|
|
14626
|
+
return context.fetch(`${context.platform}${internal.pathname}${internal.search}`, init);
|
|
14627
|
+
} }
|
|
14628
|
+
});
|
|
14629
|
+
const json = parsed.options.json === true;
|
|
14630
|
+
if (action2 === "plan") {
|
|
14631
|
+
if (parsed.positionals[2]) throw new Error("promotion plan takes --file, not a positional plan id");
|
|
14632
|
+
const file = stringOpt(parsed.options.file);
|
|
14633
|
+
if (!file) throw new Error("--file <promotion-plan.json> is required");
|
|
14634
|
+
const source = JSON.parse(await readFile5(file, "utf8"));
|
|
14635
|
+
const plan2 = await client.createPromotionReleasePlan(context.appId, source);
|
|
14636
|
+
render(plan2, json, context.stdout);
|
|
14637
|
+
return;
|
|
14638
|
+
}
|
|
14639
|
+
const planId = requiredSecurityPositional(parsed, 2, "plan id");
|
|
14640
|
+
if (action2 === "inspect") {
|
|
14641
|
+
if (parsed.positionals[3]) throw new Error("promotion inspect takes only a plan id");
|
|
14642
|
+
const plan2 = await client.getPromotionReleasePlan(context.appId, planId);
|
|
14643
|
+
if (!plan2) throw new Error(`promotion release ${planId} was not found`);
|
|
14644
|
+
render(plan2, json, context.stdout);
|
|
14645
|
+
return;
|
|
14646
|
+
}
|
|
14647
|
+
if (action2 === "status") {
|
|
14648
|
+
if (parsed.positionals[3]) throw new Error("promotion status takes only a plan id");
|
|
14649
|
+
const status = await client.getPromotionReleaseStatus(context.appId, planId);
|
|
14650
|
+
if (!status) throw new Error(`promotion release ${planId} was not found`);
|
|
14651
|
+
render(status, json, context.stdout);
|
|
14652
|
+
return;
|
|
14653
|
+
}
|
|
14654
|
+
if (action2 === "next" || action2 === "cancel" || action2 === "record") {
|
|
14655
|
+
const operationId = requiredSecurityPositional(parsed, 3, "operation id");
|
|
14656
|
+
if (action2 === "next") {
|
|
14657
|
+
if (parsed.positionals[4]) throw new Error("promotion next takes only plan and operation ids");
|
|
14658
|
+
render(await client.claimPromotionReleaseWork(context.appId, planId, operationId), json, context.stdout);
|
|
14659
|
+
return;
|
|
14660
|
+
}
|
|
14661
|
+
if (action2 === "cancel") {
|
|
14662
|
+
if (parsed.positionals[4]) throw new Error("promotion cancel takes only plan and operation ids");
|
|
14663
|
+
render(await client.cancelPromotionReleaseOperation(context.appId, planId, operationId), json, context.stdout);
|
|
14664
|
+
return;
|
|
14665
|
+
}
|
|
14666
|
+
const stepId = requiredSecurityPositional(parsed, 4, "step id");
|
|
14667
|
+
const file = stringOpt(parsed.options.file);
|
|
14668
|
+
if (!file) throw new Error("--file <step-receipt.json> is required");
|
|
14669
|
+
const receipt = JSON.parse(await readFile5(file, "utf8"));
|
|
14670
|
+
render(await client.recordPromotionReleaseWork(context.appId, planId, operationId, stepId, receipt), json, context.stdout);
|
|
14671
|
+
return;
|
|
14672
|
+
}
|
|
14673
|
+
const approvalId = stringOpt(parsed.options.approval);
|
|
14674
|
+
if (parsed.positionals[3]) throw new Error(`promotion ${action2} takes only a plan id`);
|
|
14675
|
+
if (!approvalId) throw new Error(`--approval <approval-id> is required for promotion ${action2}`);
|
|
14676
|
+
const plan = await client.getPromotionReleasePlan(context.appId, planId);
|
|
14677
|
+
if (!plan) throw new Error(`promotion release ${planId} was not found`);
|
|
14678
|
+
if (plan.state !== "reviewable") throw new Error(`promotion release is ${plan.state}: ${plan.blockers.join("; ")}`);
|
|
14679
|
+
const operationAction = action2;
|
|
14680
|
+
const operation = await client.requestPromotionReleaseOperation(context.appId, planId, operationAction, {
|
|
14681
|
+
approvalId,
|
|
14682
|
+
planDigest: plan.planDigest,
|
|
14683
|
+
targetSetDigest: plan.targetSetDigest,
|
|
14684
|
+
idempotencyKey: stringOpt(parsed.options["idempotency-key"]) ?? `${operationAction}:${planId}`
|
|
14685
|
+
});
|
|
14686
|
+
render(operation, json, context.stdout);
|
|
14687
|
+
}
|
|
14688
|
+
|
|
14463
14689
|
// src/record.ts
|
|
14464
14690
|
import { appendFileSync } from "fs";
|
|
14465
14691
|
import process18 from "process";
|
|
@@ -14747,7 +14973,7 @@ async function bySlug(ctx, slug) {
|
|
|
14747
14973
|
"GET",
|
|
14748
14974
|
`/runbook?app=${encodeURIComponent(ctx.appId)}&slug=${encodeURIComponent(slug)}&limit=1`
|
|
14749
14975
|
);
|
|
14750
|
-
const filtered = page2.records.find((
|
|
14976
|
+
const filtered = page2.records.find((record12) => record12.slug === slug);
|
|
14751
14977
|
if (filtered) return filtered;
|
|
14752
14978
|
const limit = 100;
|
|
14753
14979
|
for (let offset = 0; ; offset += limit) {
|
|
@@ -14756,7 +14982,7 @@ async function bySlug(ctx, slug) {
|
|
|
14756
14982
|
"GET",
|
|
14757
14983
|
`/runbook?app=${encodeURIComponent(ctx.appId)}&limit=${limit}&offset=${offset}`
|
|
14758
14984
|
);
|
|
14759
|
-
const found = fallback.records.find((
|
|
14985
|
+
const found = fallback.records.find((record12) => record12.slug === slug);
|
|
14760
14986
|
if (found) return found;
|
|
14761
14987
|
if (!fallback.records.length || offset + fallback.records.length >= fallback.total) break;
|
|
14762
14988
|
}
|
|
@@ -15556,41 +15782,6 @@ async function runbookCommand(parsed, deps = {}) {
|
|
|
15556
15782
|
}
|
|
15557
15783
|
}
|
|
15558
15784
|
|
|
15559
|
-
// src/security-command-context.ts
|
|
15560
|
-
async function hostedSecurityContext(parsed, dependencies) {
|
|
15561
|
-
const configPath = stringOpt(parsed.options.config) ?? "odla.config.mjs";
|
|
15562
|
-
const cfg = await loadProjectConfig(configPath);
|
|
15563
|
-
const env = stringOpt(parsed.options.env) ?? (cfg.envs.includes("dev") ? "dev" : cfg.envs[0]);
|
|
15564
|
-
if (!env || !cfg.envs.includes(env)) {
|
|
15565
|
-
throw new Error(`env "${env ?? ""}" is not declared in ${configPath}`);
|
|
15566
|
-
}
|
|
15567
|
-
const platform = platformAudience(stringOpt(parsed.options.platform) ?? cfg.platformUrl);
|
|
15568
|
-
if (platformAudience(cfg.platformUrl) !== platform) {
|
|
15569
|
-
throw new Error("--platform cannot reuse a project developer token from another platform; update odla.config.mjs and authenticate there");
|
|
15570
|
-
}
|
|
15571
|
-
const doFetch = dependencies.fetch ?? fetch;
|
|
15572
|
-
const stdout = dependencies.stdout ?? console;
|
|
15573
|
-
const open = parsed.options.open === false ? false : parsed.options.open === true ? true : void 0;
|
|
15574
|
-
const token = await getDeveloperToken(
|
|
15575
|
-
cfg,
|
|
15576
|
-
{ configPath, email: stringOpt(parsed.options.email), open, openApprovalUrl: dependencies.openUrl },
|
|
15577
|
-
doFetch,
|
|
15578
|
-
stdout,
|
|
15579
|
-
{ optionalProjectCapabilities: ["app.manage"] }
|
|
15580
|
-
);
|
|
15581
|
-
return { platform, token, appId: cfg.app.id, env, fetch: doFetch, stdout };
|
|
15582
|
-
}
|
|
15583
|
-
function requiredSecurityPositional(parsed, index, label) {
|
|
15584
|
-
const value2 = parsed.positionals[index];
|
|
15585
|
-
if (!value2) throw new Error(`${label} is required`);
|
|
15586
|
-
return value2;
|
|
15587
|
-
}
|
|
15588
|
-
function securityProfile(value2) {
|
|
15589
|
-
if (value2 === void 0) return void 0;
|
|
15590
|
-
if (value2 === "odla" || value2 === "cloudflare-app" || value2 === "generic") return value2;
|
|
15591
|
-
throw new Error("--profile must be odla, cloudflare-app, or generic");
|
|
15592
|
-
}
|
|
15593
|
-
|
|
15594
15785
|
// src/security-command-output.ts
|
|
15595
15786
|
function printHostedSecurityPlan(out, plan, appId) {
|
|
15596
15787
|
out.log(`Hosted security plan for ${appId}/${plan.env}: ${plan.ready ? "ready" : "not ready"}`);
|
|
@@ -16328,6 +16519,10 @@ async function dispatchCli(argv, dependencies) {
|
|
|
16328
16519
|
await securityCommand(parsed, runtime);
|
|
16329
16520
|
return;
|
|
16330
16521
|
}
|
|
16522
|
+
if (command === "promotion") {
|
|
16523
|
+
await promotionCommand(parsed, runtime);
|
|
16524
|
+
return;
|
|
16525
|
+
}
|
|
16331
16526
|
if (command === "brand") {
|
|
16332
16527
|
await brandCommand(parsed, runtime);
|
|
16333
16528
|
return;
|
|
@@ -16492,4 +16687,4 @@ export {
|
|
|
16492
16687
|
isTerminalHostedSecurityStatus,
|
|
16493
16688
|
runCli
|
|
16494
16689
|
};
|
|
16495
|
-
//# sourceMappingURL=chunk-
|
|
16690
|
+
//# sourceMappingURL=chunk-BD5KIG63.js.map
|