@odla-ai/cli 0.46.11 → 0.48.0
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 +615 -347
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-J6GIGX6T.js → chunk-BD5KIG63.js} +578 -327
- package/dist/chunk-BD5KIG63.js.map +1 -0
- package/dist/{cli-BI26ENP4.js → cli-MXYYOFBR.js} +2 -2
- package/dist/index.cjs +580 -329
- 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 +3 -3
- package/skills/odla/references/sdks.md +5 -0
- package/dist/chunk-J6GIGX6T.js.map +0 -1
- /package/dist/{cli-BI26ENP4.js.map → cli-MXYYOFBR.js.map} +0 -0
package/dist/bin.cjs
CHANGED
|
@@ -1783,6 +1783,7 @@ var init_surface = __esm({
|
|
|
1783
1783
|
watch: {}
|
|
1784
1784
|
},
|
|
1785
1785
|
provision: {},
|
|
1786
|
+
promotion: { plan: {}, inspect: {}, status: {}, apply: {}, rollback: {}, next: {}, record: {}, cancel: {} },
|
|
1786
1787
|
runbook: {
|
|
1787
1788
|
ask: {},
|
|
1788
1789
|
search: {},
|
|
@@ -4270,9 +4271,9 @@ function canonicalValue(value2) {
|
|
|
4270
4271
|
}
|
|
4271
4272
|
if (Array.isArray(value2)) return value2.map(canonicalValue);
|
|
4272
4273
|
if (value2 && typeof value2 === "object") {
|
|
4273
|
-
const
|
|
4274
|
+
const record12 = value2;
|
|
4274
4275
|
return Object.fromEntries(
|
|
4275
|
-
Object.keys(
|
|
4276
|
+
Object.keys(record12).filter((key) => record12[key] !== void 0).sort().map((key) => [key, canonicalValue(record12[key])])
|
|
4276
4277
|
);
|
|
4277
4278
|
}
|
|
4278
4279
|
throw new TypeError("canonical JSON rejects unsupported values");
|
|
@@ -6878,17 +6879,17 @@ var init_cli_project = __esm({
|
|
|
6878
6879
|
}
|
|
6879
6880
|
});
|
|
6880
6881
|
|
|
6881
|
-
// ../harness/dist/chunk-
|
|
6882
|
+
// ../harness/dist/chunk-U324RQ4N.js
|
|
6882
6883
|
var HARNESS_PROTOCOL_VERSION;
|
|
6883
|
-
var
|
|
6884
|
-
"../harness/dist/chunk-
|
|
6884
|
+
var init_chunk_U324RQ4N = __esm({
|
|
6885
|
+
"../harness/dist/chunk-U324RQ4N.js"() {
|
|
6885
6886
|
"use strict";
|
|
6886
6887
|
init_cjs_shims();
|
|
6887
6888
|
HARNESS_PROTOCOL_VERSION = 1;
|
|
6888
6889
|
}
|
|
6889
6890
|
});
|
|
6890
6891
|
|
|
6891
|
-
// ../harness/dist/chunk-
|
|
6892
|
+
// ../harness/dist/chunk-5LRYJKUI.js
|
|
6892
6893
|
function assertPinnedImage(image) {
|
|
6893
6894
|
if (!DIGEST_IMAGE.test(image)) throw new TypeError("container image must be pinned by sha256 digest");
|
|
6894
6895
|
}
|
|
@@ -7032,8 +7033,8 @@ async function materializeGitTree(source, commitSha, options = {}) {
|
|
|
7032
7033
|
const maxFiles = options.maxFiles ?? 2e4;
|
|
7033
7034
|
const maxBytes = options.maxBytes ?? 512 * 1024 * 1024;
|
|
7034
7035
|
const inventory = (await gitOutput(sourceDir, ["ls-tree", "-rz", commitSha], 16 * 1024 * 1024)).toString("utf8").split("\0").filter(Boolean);
|
|
7035
|
-
const entries = inventory.flatMap((
|
|
7036
|
-
const match = /^(100644|100755) blob ([0-9a-f]{40,64})\t([\s\S]+)$/.exec(
|
|
7036
|
+
const entries = inventory.flatMap((record12) => {
|
|
7037
|
+
const match = /^(100644|100755) blob ([0-9a-f]{40,64})\t([\s\S]+)$/.exec(record12);
|
|
7037
7038
|
return match && allowedWorkspacePath(match[3]) ? [{ mode: match[1], hash: match[2], path: match[3] }] : [];
|
|
7038
7039
|
});
|
|
7039
7040
|
if (entries.length > maxFiles) throw new Error(`workspace exceeds ${maxFiles} files`);
|
|
@@ -7237,8 +7238,8 @@ async function stageWorkspacePair(baselineSource, workspaceSource, options = {})
|
|
|
7237
7238
|
}
|
|
7238
7239
|
}
|
|
7239
7240
|
var import_child_process, import_fs, import_promises2, import_path, import_process, import_promises3, import_os, import_path2, import_child_process2, import_path3, import_promises4, import_os2, import_path4, import_child_process3, DIGEST_IMAGE, SKIP_WORKSPACE_DIRS, SECRET_WORKSPACE_FILE;
|
|
7240
|
-
var
|
|
7241
|
-
"../harness/dist/chunk-
|
|
7241
|
+
var init_chunk_5LRYJKUI = __esm({
|
|
7242
|
+
"../harness/dist/chunk-5LRYJKUI.js"() {
|
|
7242
7243
|
"use strict";
|
|
7243
7244
|
init_cjs_shims();
|
|
7244
7245
|
import_child_process = require("child_process");
|
|
@@ -7268,6 +7269,171 @@ var init_chunk_CR6RE3A2 = __esm({
|
|
|
7268
7269
|
}
|
|
7269
7270
|
});
|
|
7270
7271
|
|
|
7272
|
+
// ../harness/dist/chunk-FAN2R3GW.js
|
|
7273
|
+
function patchStats(value2) {
|
|
7274
|
+
if (typeof value2 !== "string") return {};
|
|
7275
|
+
let additions = 0;
|
|
7276
|
+
let deletions = 0;
|
|
7277
|
+
for (const line2 of value2.slice(0, 262144).split("\n")) {
|
|
7278
|
+
if (line2.startsWith("+++") || line2.startsWith("---")) continue;
|
|
7279
|
+
if (line2.startsWith("+")) additions += 1;
|
|
7280
|
+
else if (line2.startsWith("-")) deletions += 1;
|
|
7281
|
+
}
|
|
7282
|
+
return { ...additions ? { additions } : {}, ...deletions ? { deletions } : {} };
|
|
7283
|
+
}
|
|
7284
|
+
function searchResults(value2) {
|
|
7285
|
+
if (typeof value2 !== "string") return void 0;
|
|
7286
|
+
const results = value2.split("\n").flatMap((line2) => {
|
|
7287
|
+
const match = /^([^:\n]{1,1024}):(\d+):\s?(.*)$/.exec(line2);
|
|
7288
|
+
if (!match) return [];
|
|
7289
|
+
const lineNumber = Number(match[2]);
|
|
7290
|
+
const itemText = text3(match[3], 240);
|
|
7291
|
+
if (!Number.isSafeInteger(lineNumber) || lineNumber < 1) return [];
|
|
7292
|
+
return [{ path: match[1], line: lineNumber, ...itemText ? { text: itemText } : {} }];
|
|
7293
|
+
}).slice(0, 5);
|
|
7294
|
+
return results.length ? results : void 0;
|
|
7295
|
+
}
|
|
7296
|
+
function codeToolRequestPresentation(request3) {
|
|
7297
|
+
const input = request3.input;
|
|
7298
|
+
if (request3.tool === "sandbox.read") {
|
|
7299
|
+
const path = text3(input.path, 1024);
|
|
7300
|
+
if (!path) return void 0;
|
|
7301
|
+
const startLine = integer(input.startLine);
|
|
7302
|
+
const endLine = integer(input.endLine);
|
|
7303
|
+
return { kind: "read", path, ...startLine ? { startLine } : {}, ...endLine ? { endLine } : {} };
|
|
7304
|
+
}
|
|
7305
|
+
if (request3.tool === "sandbox.list") {
|
|
7306
|
+
const scope = text3(input.prefix, 1024);
|
|
7307
|
+
return { kind: "list", ...scope ? { scope } : {} };
|
|
7308
|
+
}
|
|
7309
|
+
if (request3.tool === "sandbox.search" || request3.tool === "sandbox.overview" || request3.tool === "sandbox.where_is" || request3.tool === "sandbox.who_imports" || request3.tool === "sandbox.who_touches") {
|
|
7310
|
+
const query = text3(input.query, 512);
|
|
7311
|
+
const scope = request3.tool === "sandbox.search" ? text3(input.prefix, 1024) : void 0;
|
|
7312
|
+
if (request3.tool === "sandbox.search" && !query) return void 0;
|
|
7313
|
+
return { kind: "query", ...query ? { query } : {}, ...scope ? { scope } : {} };
|
|
7314
|
+
}
|
|
7315
|
+
if (request3.tool === "sandbox.apply_patch") {
|
|
7316
|
+
return { kind: "patch", ...patchStats(input.patch) };
|
|
7317
|
+
}
|
|
7318
|
+
const recipeId = text3(input.recipeId, 120);
|
|
7319
|
+
return recipeId ? { kind: "recipe", recipeId } : void 0;
|
|
7320
|
+
}
|
|
7321
|
+
function codeToolResultPresentation(request3, response2) {
|
|
7322
|
+
const started = codeToolRequestPresentation(request3);
|
|
7323
|
+
if (!started || !response2.ok) return started;
|
|
7324
|
+
const details = record5(response2.details);
|
|
7325
|
+
if (started.kind === "read") {
|
|
7326
|
+
return {
|
|
7327
|
+
...started,
|
|
7328
|
+
...integer(details?.startLine) ? { startLine: integer(details?.startLine) } : {},
|
|
7329
|
+
...integer(details?.endLine) ? { endLine: integer(details?.endLine) } : {},
|
|
7330
|
+
...excerpt(response2.content) ? { excerpt: excerpt(response2.content) } : {}
|
|
7331
|
+
};
|
|
7332
|
+
}
|
|
7333
|
+
if (started.kind === "list") {
|
|
7334
|
+
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);
|
|
7335
|
+
return {
|
|
7336
|
+
...started,
|
|
7337
|
+
...integer(details?.count) !== void 0 ? { count: integer(details?.count) } : {},
|
|
7338
|
+
...listed.length ? { paths: listed } : {}
|
|
7339
|
+
};
|
|
7340
|
+
}
|
|
7341
|
+
if (started.kind === "query") {
|
|
7342
|
+
const results = request3.tool === "sandbox.search" ? searchResults(response2.content) : void 0;
|
|
7343
|
+
const resultExcerpt = request3.tool === "sandbox.search" ? void 0 : excerpt(response2.content);
|
|
7344
|
+
return {
|
|
7345
|
+
...started,
|
|
7346
|
+
...integer(details?.count) !== void 0 ? { count: integer(details?.count) } : {},
|
|
7347
|
+
...results ? { results } : {},
|
|
7348
|
+
...resultExcerpt ? { excerpt: resultExcerpt } : {}
|
|
7349
|
+
};
|
|
7350
|
+
}
|
|
7351
|
+
if (started.kind === "patch") {
|
|
7352
|
+
return { ...started, ...paths(details?.paths) ? { paths: paths(details?.paths) } : {} };
|
|
7353
|
+
}
|
|
7354
|
+
const output = response2.content.replace(/^Recipe [^\n]*\.?\s*/u, "");
|
|
7355
|
+
return {
|
|
7356
|
+
...started,
|
|
7357
|
+
...integer(details?.exitCode) !== void 0 ? { exitCode: integer(details?.exitCode) } : {},
|
|
7358
|
+
...typeof details?.timedOut === "boolean" ? { timedOut: details.timedOut } : {},
|
|
7359
|
+
...typeof details?.outputLimitExceeded === "boolean" ? { outputLimitExceeded: details.outputLimitExceeded } : {},
|
|
7360
|
+
...excerpt(output, true) ? { excerpt: excerpt(output, true) } : {}
|
|
7361
|
+
};
|
|
7362
|
+
}
|
|
7363
|
+
function toolFailureReason(response2) {
|
|
7364
|
+
if (response2.ok) return void 0;
|
|
7365
|
+
const supplied = response2.details?.failureReason;
|
|
7366
|
+
const reason = typeof supplied === "string" && supplied || DEFAULT_FAILURE_REASON[response2.content] || response2.content || "tool request failed; inspect the tool input and workspace state";
|
|
7367
|
+
return reason.slice(0, MAX_FAILURE_REASON);
|
|
7368
|
+
}
|
|
7369
|
+
function observedBroker(input) {
|
|
7370
|
+
const now = input.now ?? Date.now;
|
|
7371
|
+
return {
|
|
7372
|
+
execute: async (context, request3) => {
|
|
7373
|
+
const startedAt = now();
|
|
7374
|
+
const operationId = input.operationIdFor(request3.requestId);
|
|
7375
|
+
const startedPresentation = codeToolRequestPresentation(request3);
|
|
7376
|
+
await input.emit({
|
|
7377
|
+
type: "tool",
|
|
7378
|
+
phase: "started",
|
|
7379
|
+
tool: request3.tool,
|
|
7380
|
+
operationId,
|
|
7381
|
+
...startedPresentation ? { presentation: startedPresentation } : {}
|
|
7382
|
+
});
|
|
7383
|
+
const response2 = await input.broker.execute(context, request3);
|
|
7384
|
+
const completedPresentation = codeToolResultPresentation(request3, response2);
|
|
7385
|
+
const failureReason = toolFailureReason(response2);
|
|
7386
|
+
await input.emit({
|
|
7387
|
+
type: "tool",
|
|
7388
|
+
phase: "completed",
|
|
7389
|
+
tool: request3.tool,
|
|
7390
|
+
ok: response2.ok,
|
|
7391
|
+
durationMs: now() - startedAt,
|
|
7392
|
+
operationId,
|
|
7393
|
+
...failureReason ? { failureReason } : {},
|
|
7394
|
+
...completedPresentation ? { presentation: completedPresentation } : {}
|
|
7395
|
+
});
|
|
7396
|
+
return response2;
|
|
7397
|
+
}
|
|
7398
|
+
};
|
|
7399
|
+
}
|
|
7400
|
+
var text3, integer, record5, excerpt, paths, MAX_FAILURE_REASON, DEFAULT_FAILURE_REASON;
|
|
7401
|
+
var init_chunk_FAN2R3GW = __esm({
|
|
7402
|
+
"../harness/dist/chunk-FAN2R3GW.js"() {
|
|
7403
|
+
"use strict";
|
|
7404
|
+
init_cjs_shims();
|
|
7405
|
+
text3 = (value2, maximum) => {
|
|
7406
|
+
if (typeof value2 !== "string") return void 0;
|
|
7407
|
+
const bounded = value2.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g, " ").trim();
|
|
7408
|
+
return bounded ? bounded.slice(0, maximum) : void 0;
|
|
7409
|
+
};
|
|
7410
|
+
integer = (value2) => Number.isSafeInteger(value2) && Number(value2) >= 0 ? Number(value2) : void 0;
|
|
7411
|
+
record5 = (value2) => value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : void 0;
|
|
7412
|
+
excerpt = (value2, tail = false) => {
|
|
7413
|
+
if (typeof value2 !== "string") return void 0;
|
|
7414
|
+
const safe = value2.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g, " ");
|
|
7415
|
+
const source = (tail ? safe.slice(-1e4) : safe.slice(0, 1e4)).trim();
|
|
7416
|
+
if (!source) return void 0;
|
|
7417
|
+
const lines = source.split("\n").filter((line2) => line2.trim()).map((line2) => line2.slice(0, 240));
|
|
7418
|
+
const selected = tail ? lines.slice(-10) : lines.slice(0, 10);
|
|
7419
|
+
return text3(selected.join("\n"), 2400);
|
|
7420
|
+
};
|
|
7421
|
+
paths = (value2) => {
|
|
7422
|
+
if (!Array.isArray(value2)) return void 0;
|
|
7423
|
+
const items = value2.flatMap((item) => {
|
|
7424
|
+
const path = text3(item, 1024);
|
|
7425
|
+
return path ? [path] : [];
|
|
7426
|
+
}).slice(0, 12);
|
|
7427
|
+
return items.length ? items : void 0;
|
|
7428
|
+
};
|
|
7429
|
+
MAX_FAILURE_REASON = 240;
|
|
7430
|
+
DEFAULT_FAILURE_REASON = {
|
|
7431
|
+
"tool denied by CaMeL policy": "tool denied by CaMeL policy",
|
|
7432
|
+
"review sessions are read-only": "review session is read-only; workspace changes are not permitted"
|
|
7433
|
+
};
|
|
7434
|
+
}
|
|
7435
|
+
});
|
|
7436
|
+
|
|
7271
7437
|
// ../camel/dist/chunk-7FHPOQVP.js
|
|
7272
7438
|
var CamelError;
|
|
7273
7439
|
var init_chunk_7FHPOQVP = __esm({
|
|
@@ -7314,8 +7480,8 @@ function normalize(value2) {
|
|
|
7314
7480
|
if (Array.isArray(value2)) return value2.map(normalize);
|
|
7315
7481
|
if (value2 instanceof Uint8Array) return { $bytes: [...value2] };
|
|
7316
7482
|
if (typeof value2 === "object") {
|
|
7317
|
-
const
|
|
7318
|
-
return Object.fromEntries(Object.keys(
|
|
7483
|
+
const record12 = value2;
|
|
7484
|
+
return Object.fromEntries(Object.keys(record12).filter((key) => record12[key] !== void 0).sort().map((key) => [key, normalize(record12[key])]));
|
|
7319
7485
|
}
|
|
7320
7486
|
throw new CamelError("state_conflict", "Canonical JSON rejects unsupported values.");
|
|
7321
7487
|
}
|
|
@@ -8236,7 +8402,7 @@ var init_code2 = __esm({
|
|
|
8236
8402
|
}
|
|
8237
8403
|
});
|
|
8238
8404
|
|
|
8239
|
-
// ../harness/dist/chunk-
|
|
8405
|
+
// ../harness/dist/chunk-Q4NL5XO3.js
|
|
8240
8406
|
async function digestStagedWorkspace(root, limits) {
|
|
8241
8407
|
const files = [];
|
|
8242
8408
|
const walk = async (directory) => {
|
|
@@ -8294,7 +8460,7 @@ function createCodeRuntimeControlClient(options) {
|
|
|
8294
8460
|
}
|
|
8295
8461
|
const value2 = await response2.json().catch(() => null);
|
|
8296
8462
|
if (!response2.ok) {
|
|
8297
|
-
const problem =
|
|
8463
|
+
const problem = record6(record6(value2)?.error);
|
|
8298
8464
|
throw new CodeRuntimeControlError(
|
|
8299
8465
|
typeof problem?.message === "string" ? problem.message : `Code runtime request failed (${response2.status})`,
|
|
8300
8466
|
response2.status,
|
|
@@ -8315,12 +8481,12 @@ function createCodeRuntimeControlClient(options) {
|
|
|
8315
8481
|
await call4(`/registry/code/runtime/sessions/${validSessionId(sessionId)}/source`, {})
|
|
8316
8482
|
),
|
|
8317
8483
|
infer: async (sessionId, inference) => {
|
|
8318
|
-
const value2 =
|
|
8484
|
+
const value2 = record6(await call4(
|
|
8319
8485
|
`/registry/code/runtime/sessions/${validSessionId(sessionId)}/inference`,
|
|
8320
8486
|
inference,
|
|
8321
8487
|
modelRequestTimeoutMs
|
|
8322
8488
|
));
|
|
8323
|
-
if (!value2 || value2.requestId !== inference.requestId || !
|
|
8489
|
+
if (!value2 || value2.requestId !== inference.requestId || !record6(value2.response) || !record6(value2.receipt)) {
|
|
8324
8490
|
throw new CodeRuntimeControlError("invalid Code inference response", 502, "invalid_response");
|
|
8325
8491
|
}
|
|
8326
8492
|
return value2;
|
|
@@ -8451,12 +8617,12 @@ function validateHeartbeat(version, capabilities) {
|
|
|
8451
8617
|
}
|
|
8452
8618
|
}
|
|
8453
8619
|
function parseSnapshot(value2) {
|
|
8454
|
-
const root =
|
|
8455
|
-
const host =
|
|
8620
|
+
const root = record6(value2);
|
|
8621
|
+
const host = record6(root?.host);
|
|
8456
8622
|
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");
|
|
8457
8623
|
const bindingIds = /* @__PURE__ */ new Set();
|
|
8458
8624
|
const bindings = root.bindings.map((item) => {
|
|
8459
|
-
const binding =
|
|
8625
|
+
const binding = record6(item);
|
|
8460
8626
|
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)) {
|
|
8461
8627
|
throw invalid("binding");
|
|
8462
8628
|
}
|
|
@@ -8466,10 +8632,10 @@ function parseSnapshot(value2) {
|
|
|
8466
8632
|
const commandIds = /* @__PURE__ */ new Set();
|
|
8467
8633
|
const commandSequences = /* @__PURE__ */ new Set();
|
|
8468
8634
|
const commands = root.commands.map((item) => {
|
|
8469
|
-
const command =
|
|
8635
|
+
const command = record6(item);
|
|
8470
8636
|
const binding = bindings.find((candidate) => candidate.bindingId === command?.bindingId);
|
|
8471
8637
|
const sequenceKey = `${String(command?.instanceId)}:${String(command?.sequence)}`;
|
|
8472
|
-
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)) || !
|
|
8638
|
+
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");
|
|
8473
8639
|
commandIds.add(command.commandId);
|
|
8474
8640
|
commandSequences.add(sequenceKey);
|
|
8475
8641
|
return command;
|
|
@@ -8478,10 +8644,10 @@ function parseSnapshot(value2) {
|
|
|
8478
8644
|
}
|
|
8479
8645
|
async function parseSource(value2) {
|
|
8480
8646
|
const repositoryLimits = { maximumFiles: 1e5, maximumBytes: 80 * 1024 * 1024 };
|
|
8481
|
-
const snapshot =
|
|
8647
|
+
const snapshot = record6(record6(value2)?.snapshot);
|
|
8482
8648
|
if (!snapshot || typeof snapshot.repository !== "string" || typeof snapshot.commitSha !== "string" || typeof snapshot.treeDigest !== "string" || !Array.isArray(snapshot.files)) throw invalid("source");
|
|
8483
8649
|
const files = snapshot.files.map((value22) => {
|
|
8484
|
-
const file =
|
|
8650
|
+
const file = record6(value22);
|
|
8485
8651
|
if (!file || typeof file.path !== "string" || typeof file.content !== "string") throw invalid("source file");
|
|
8486
8652
|
return { path: file.path, content: file.content };
|
|
8487
8653
|
});
|
|
@@ -8490,11 +8656,11 @@ async function parseSource(value2) {
|
|
|
8490
8656
|
const aliases = /* @__PURE__ */ new Set();
|
|
8491
8657
|
const references = [];
|
|
8492
8658
|
for (const item of referencesValue) {
|
|
8493
|
-
const reference =
|
|
8659
|
+
const reference = record6(item);
|
|
8494
8660
|
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");
|
|
8495
8661
|
aliases.add(reference.alias);
|
|
8496
8662
|
const referenceFiles = reference.files.map((entry) => {
|
|
8497
|
-
const file =
|
|
8663
|
+
const file = record6(entry);
|
|
8498
8664
|
if (!file || typeof file.path !== "string" || typeof file.content !== "string") throw invalid("reference source file");
|
|
8499
8665
|
return { path: file.path, content: file.content };
|
|
8500
8666
|
});
|
|
@@ -8509,31 +8675,31 @@ async function parseSource(value2) {
|
|
|
8509
8675
|
return { ...source, treeDigest: digest, ...references.length ? { references } : {} };
|
|
8510
8676
|
}
|
|
8511
8677
|
function parseReview(value2) {
|
|
8512
|
-
const review =
|
|
8513
|
-
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");
|
|
8678
|
+
const review = record6(record6(value2)?.review);
|
|
8679
|
+
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");
|
|
8514
8680
|
return review;
|
|
8515
8681
|
}
|
|
8516
8682
|
function parseCandidate(value2) {
|
|
8517
|
-
const candidate =
|
|
8683
|
+
const candidate = record6(record6(value2)?.candidate);
|
|
8518
8684
|
if (!candidate || typeof candidate.candidateId !== "string" || !/^ccand_[0-9a-f]{32}$/.test(candidate.candidateId) || !["submitted", "approved", "published", "failed"].includes(String(candidate.status))) {
|
|
8519
8685
|
throw invalid("candidate");
|
|
8520
8686
|
}
|
|
8521
8687
|
return { candidateId: candidate.candidateId, status: candidate.status };
|
|
8522
8688
|
}
|
|
8523
8689
|
function parseCollaborationSkills(value2) {
|
|
8524
|
-
const items =
|
|
8690
|
+
const items = record6(value2)?.skills;
|
|
8525
8691
|
if (!Array.isArray(items) || items.length > 16) throw invalid("collaboration skills");
|
|
8526
8692
|
const skillNames2 = /* @__PURE__ */ new Set();
|
|
8527
8693
|
const toolNames = /* @__PURE__ */ new Set();
|
|
8528
8694
|
return items.map((item) => {
|
|
8529
|
-
const skill =
|
|
8695
|
+
const skill = record6(item);
|
|
8530
8696
|
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) {
|
|
8531
8697
|
throw invalid("collaboration skill");
|
|
8532
8698
|
}
|
|
8533
8699
|
skillNames2.add(skill.name);
|
|
8534
8700
|
const tools = skill.tools.map((candidate) => {
|
|
8535
|
-
const tool =
|
|
8536
|
-
const inputSchema =
|
|
8701
|
+
const tool = record6(candidate);
|
|
8702
|
+
const inputSchema = record6(tool?.inputSchema);
|
|
8537
8703
|
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") {
|
|
8538
8704
|
throw invalid("collaboration tool");
|
|
8539
8705
|
}
|
|
@@ -8558,12 +8724,12 @@ function parseCollaborationSkills(value2) {
|
|
|
8558
8724
|
}
|
|
8559
8725
|
function validateCollaborationToolRequest(value2) {
|
|
8560
8726
|
validCommandId(value2.commandId);
|
|
8561
|
-
if (typeof value2.toolCallId !== "string" || value2.toolCallId.length > 256 || !/^[^\s\u0000-\u001f\u007f]+$/.test(value2.toolCallId) || !validManifestName(value2.skill) || !validManifestName(value2.tool) || !
|
|
8727
|
+
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) {
|
|
8562
8728
|
throw new TypeError("invalid Code collaboration tool request");
|
|
8563
8729
|
}
|
|
8564
8730
|
}
|
|
8565
8731
|
function parseCollaborationToolOutput(value2) {
|
|
8566
|
-
const output =
|
|
8732
|
+
const output = record6(record6(value2)?.output);
|
|
8567
8733
|
if (!output || output.isError !== void 0 && typeof output.isError !== "boolean") {
|
|
8568
8734
|
throw invalid("collaboration tool");
|
|
8569
8735
|
}
|
|
@@ -8572,7 +8738,7 @@ function parseCollaborationToolOutput(value2) {
|
|
|
8572
8738
|
return { content: output.content, ...output.isError === true ? { isError: true } : {} };
|
|
8573
8739
|
}
|
|
8574
8740
|
if (!Array.isArray(output.content) || output.content.length > 64 || jsonBytes(output.content) > 1e6 || !output.content.every((block2) => {
|
|
8575
|
-
const item =
|
|
8741
|
+
const item = record6(block2);
|
|
8576
8742
|
return item && ["text", "image", "audio", "document", "tool_use", "tool_result", "thinking"].includes(String(item.type));
|
|
8577
8743
|
})) throw invalid("collaboration tool");
|
|
8578
8744
|
return {
|
|
@@ -8606,10 +8772,41 @@ function jsonBytes(value2) {
|
|
|
8606
8772
|
}
|
|
8607
8773
|
}
|
|
8608
8774
|
function stripPatchEnvelope(patch2) {
|
|
8609
|
-
if (!/^\*\*\* (?:Begin|End) Patch\s*$/m.test(patch2)) return patch2;
|
|
8775
|
+
if (!/^\*\*\* (?:Begin|End) Patch\s*$/m.test(patch2)) return applyPatchDialectToDiff(patch2);
|
|
8610
8776
|
const kept = patch2.split("\n").filter((line2) => !/^\*\*\* (?:Begin|End) Patch\s*$/.test(line2));
|
|
8611
8777
|
const stripped = kept.join("\n");
|
|
8612
|
-
|
|
8778
|
+
if (/^diff --git /m.test(stripped)) return stripped;
|
|
8779
|
+
const translated = applyPatchDialectToDiff(stripped);
|
|
8780
|
+
return translated === stripped ? patch2 : translated;
|
|
8781
|
+
}
|
|
8782
|
+
function applyPatchDialectToDiff(patch2) {
|
|
8783
|
+
if (!/^\*\*\* (?:Update|Add|Delete) File: /m.test(patch2)) return patch2;
|
|
8784
|
+
const out = [];
|
|
8785
|
+
let open = false;
|
|
8786
|
+
for (const line2 of patch2.split("\n")) {
|
|
8787
|
+
const file = /^\*\*\* (Update|Add|Delete) File: (.+?)\s*$/.exec(line2);
|
|
8788
|
+
if (file) {
|
|
8789
|
+
const [, verb, raw] = file;
|
|
8790
|
+
const path = raw.trim();
|
|
8791
|
+
if (!PATH.test(path)) return patch2;
|
|
8792
|
+
out.push(`diff --git a/${path} b/${path}`);
|
|
8793
|
+
if (verb === "Add") out.push("new file mode 100644", "--- /dev/null", `+++ b/${path}`);
|
|
8794
|
+
else if (verb === "Delete") out.push(`--- a/${path}`, "+++ /dev/null");
|
|
8795
|
+
else out.push(`--- a/${path}`, `+++ b/${path}`);
|
|
8796
|
+
open = true;
|
|
8797
|
+
continue;
|
|
8798
|
+
}
|
|
8799
|
+
if (/^\*\*\* /.test(line2)) continue;
|
|
8800
|
+
if (!open) continue;
|
|
8801
|
+
if (/^@@/.test(line2)) {
|
|
8802
|
+
out.push("@@ -1 +1 @@");
|
|
8803
|
+
continue;
|
|
8804
|
+
}
|
|
8805
|
+
out.push(line2);
|
|
8806
|
+
}
|
|
8807
|
+
if (!open) return patch2;
|
|
8808
|
+
return `${out.join("\n").replace(/\n+$/, "")}
|
|
8809
|
+
`;
|
|
8613
8810
|
}
|
|
8614
8811
|
function validateCodePatch(rawPatch, maxBytes) {
|
|
8615
8812
|
const patch2 = stripPatchEnvelope(rawPatch);
|
|
@@ -8662,17 +8859,20 @@ function resolveCodePath(workspaceDir, path) {
|
|
|
8662
8859
|
if (target !== root && !target.startsWith(`${root}${import_path6.sep}`)) throw new TypeError("path escapes the staged workspace");
|
|
8663
8860
|
return target;
|
|
8664
8861
|
}
|
|
8862
|
+
function hasContextFreeHunk(patch2) {
|
|
8863
|
+
const bodies = patch2.split(/^@@.*$/m).slice(1);
|
|
8864
|
+
return bodies.some((body) => !body.split("\n").some((line2) => line2.startsWith(" ") && line2.trim().length > 0));
|
|
8865
|
+
}
|
|
8665
8866
|
function describePatchFailure(patch2, detail) {
|
|
8666
8867
|
const hunks = patch2.split("\n").filter((line2) => line2.startsWith("@@"));
|
|
8667
|
-
const
|
|
8668
|
-
const contextless = bodies.some((body) => !body.split("\n").some((line2) => line2.startsWith(" ") && line2.trim().length > 0));
|
|
8669
|
-
const hint = hunks.length > 0 && contextless ? " A hunk has no context lines; include at least one unchanged line above or below each change." : "";
|
|
8868
|
+
const hint = hunks.length > 0 && hasContextFreeHunk(patch2) ? " A hunk has no context lines; include at least one unchanged line above or below each change." : "";
|
|
8670
8869
|
return `patch did not apply: ${detail}${hint}`;
|
|
8671
8870
|
}
|
|
8672
8871
|
async function applyCodePatch(workspaceDir, rawPatch, paths2) {
|
|
8673
8872
|
const patch2 = stripPatchEnvelope(rawPatch);
|
|
8674
|
-
|
|
8675
|
-
await gitApply(workspaceDir, patch2,
|
|
8873
|
+
const zero = hasContextFreeHunk(patch2);
|
|
8874
|
+
await gitApply(workspaceDir, patch2, true, zero);
|
|
8875
|
+
await gitApply(workspaceDir, patch2, false, zero);
|
|
8676
8876
|
for (const path of paths2) {
|
|
8677
8877
|
try {
|
|
8678
8878
|
const info = await (0, import_promises6.lstat)(resolveCodePath(workspaceDir, path));
|
|
@@ -8684,9 +8884,16 @@ async function applyCodePatch(workspaceDir, rawPatch, paths2) {
|
|
|
8684
8884
|
}
|
|
8685
8885
|
}
|
|
8686
8886
|
}
|
|
8687
|
-
function gitApply(cwd, patch2, check) {
|
|
8887
|
+
function gitApply(cwd, patch2, check, unidiffZero = false) {
|
|
8688
8888
|
return new Promise((accept, reject) => {
|
|
8689
|
-
const args = [
|
|
8889
|
+
const args = [
|
|
8890
|
+
"apply",
|
|
8891
|
+
"--recount",
|
|
8892
|
+
...unidiffZero ? ["--unidiff-zero"] : [],
|
|
8893
|
+
"--whitespace=nowarn",
|
|
8894
|
+
...check ? ["--check"] : [],
|
|
8895
|
+
"-"
|
|
8896
|
+
];
|
|
8690
8897
|
const child = (0, import_child_process4.spawn)("git", args, {
|
|
8691
8898
|
cwd,
|
|
8692
8899
|
shell: false,
|
|
@@ -8695,8 +8902,8 @@ function gitApply(cwd, patch2, check) {
|
|
|
8695
8902
|
});
|
|
8696
8903
|
let stderr2 = "";
|
|
8697
8904
|
child.stderr.setEncoding("utf8");
|
|
8698
|
-
child.stderr.on("data", (
|
|
8699
|
-
if (stderr2.length < 4e3) stderr2 +=
|
|
8905
|
+
child.stderr.on("data", (text4) => {
|
|
8906
|
+
if (stderr2.length < 4e3) stderr2 += text4.slice(0, 4e3);
|
|
8700
8907
|
});
|
|
8701
8908
|
child.once("error", reject);
|
|
8702
8909
|
child.once("exit", (code) => code === 0 ? accept() : reject(new TypeError(describePatchFailure(patch2, stderr2.trim().slice(0, 500)))));
|
|
@@ -8934,7 +9141,7 @@ function validate2(input) {
|
|
|
8934
9141
|
maximumFiles: policy.maximumFiles ?? 2e4,
|
|
8935
9142
|
maximumBytes: policy.maximumBytes ?? 512 * 1024 * 1024
|
|
8936
9143
|
};
|
|
8937
|
-
if ([...result.testPathPrefixes, ...result.testPathSuffixes].some((rule) => !RULE.test(rule)) || !
|
|
9144
|
+
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)) {
|
|
8938
9145
|
throw new TypeError("clean verification policy exceeds its bounds");
|
|
8939
9146
|
}
|
|
8940
9147
|
return result;
|
|
@@ -8985,7 +9192,7 @@ function hashFile(path) {
|
|
|
8985
9192
|
});
|
|
8986
9193
|
}
|
|
8987
9194
|
function checkedResult(result, maximumOutputBytes) {
|
|
8988
|
-
if (!
|
|
9195
|
+
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") {
|
|
8989
9196
|
throw new TypeError("recipe executor returned an invalid result");
|
|
8990
9197
|
}
|
|
8991
9198
|
const bytes = Buffer.byteLength(result.stdout) + Buffer.byteLength(result.stderr);
|
|
@@ -9035,7 +9242,7 @@ function digestJson(value2) {
|
|
|
9035
9242
|
function digestBytes(value2) {
|
|
9036
9243
|
return `sha256:${(0, import_crypto3.createHash)("sha256").update(value2).digest("hex")}`;
|
|
9037
9244
|
}
|
|
9038
|
-
function
|
|
9245
|
+
function integer2(value2, minimum, maximum) {
|
|
9039
9246
|
return Number.isSafeInteger(value2) && value2 >= minimum && value2 <= maximum;
|
|
9040
9247
|
}
|
|
9041
9248
|
async function prepareRuntimeCheckpoint(input) {
|
|
@@ -9062,9 +9269,9 @@ async function prepareRuntimeCheckpoint(input) {
|
|
|
9062
9269
|
if (evidence.receipt.outcome === "passed") {
|
|
9063
9270
|
verification = evidence.receipt;
|
|
9064
9271
|
review = await input.review(patch2, verification);
|
|
9065
|
-
note = review
|
|
9272
|
+
note = describeReview(review);
|
|
9066
9273
|
} else {
|
|
9067
|
-
note =
|
|
9274
|
+
note = describeGateFailure(evidence);
|
|
9068
9275
|
}
|
|
9069
9276
|
} catch (cause) {
|
|
9070
9277
|
note = `Candidate verification or review failed closed: ${message(cause)}`;
|
|
@@ -9089,6 +9296,23 @@ async function prepareRuntimeCheckpoint(input) {
|
|
|
9089
9296
|
});
|
|
9090
9297
|
return { checkpoint, verification, review, note };
|
|
9091
9298
|
}
|
|
9299
|
+
function describeReview(review) {
|
|
9300
|
+
const findings = review.findings.map((finding) => ` - [${finding.severity}] ${finding.detail}`).join("\n");
|
|
9301
|
+
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.`;
|
|
9302
|
+
return [head, review.summary, findings].filter(Boolean).join("\n").slice(0, 4e3);
|
|
9303
|
+
}
|
|
9304
|
+
function describeGateFailure(evidence) {
|
|
9305
|
+
const failed = evidence.receipt.recipes.filter((recipe2) => recipe2.status !== "passed");
|
|
9306
|
+
const detail = failed.map((recipe2) => {
|
|
9307
|
+
const log = evidence.logs.find((entry) => entry.recipeId === recipe2.recipeId);
|
|
9308
|
+
const output = `${log?.stdout ?? ""}
|
|
9309
|
+
${log?.stderr ?? ""}`.trim();
|
|
9310
|
+
return `${recipe2.recipeId}=${recipe2.status}${output ? `
|
|
9311
|
+
${output.slice(0, 1500)}` : ""}`;
|
|
9312
|
+
}).join("\n\n");
|
|
9313
|
+
return `Clean verification failed. Fix this and checkpoint again:
|
|
9314
|
+
${detail}`.slice(0, 4e3);
|
|
9315
|
+
}
|
|
9092
9316
|
function codeCommandMetadata(payload, resume) {
|
|
9093
9317
|
const trusted = record22(payload.trustedBase);
|
|
9094
9318
|
const role = payload.role;
|
|
@@ -9969,7 +10193,9 @@ function optionalInteger(value2) {
|
|
|
9969
10193
|
return value2;
|
|
9970
10194
|
}
|
|
9971
10195
|
function response(request3, ok, content2, details) {
|
|
9972
|
-
return { requestId: request3.requestId, ok, content: content2, ...details ? { details } : {} };
|
|
10196
|
+
if (ok) return { requestId: request3.requestId, ok, content: content2, ...details ? { details } : {} };
|
|
10197
|
+
const failureReason = typeof details?.failureReason === "string" && details.failureReason || DEFAULT_FAILURE_REASON2[content2] || content2 || "tool request failed; inspect the tool input and workspace state";
|
|
10198
|
+
return { requestId: request3.requestId, ok, content: content2, details: { ...details, failureReason } };
|
|
9973
10199
|
}
|
|
9974
10200
|
function workspaceGraphs(workspaceDir, paths2) {
|
|
9975
10201
|
const existing = cache.get(workspaceDir);
|
|
@@ -10533,96 +10759,6 @@ async function appendCodeRuntimeEvent(control, command, event, refs) {
|
|
|
10533
10759
|
const bounded = attributed.type === "message" ? { ...attributed, body: attributed.body.trim().slice(0, 2e4) || `${attributed.actor} event` } : attributed;
|
|
10534
10760
|
await control.appendSessionEvent(command.sessionId, eventId, bounded);
|
|
10535
10761
|
}
|
|
10536
|
-
function patchStats(value2) {
|
|
10537
|
-
if (typeof value2 !== "string") return {};
|
|
10538
|
-
let additions = 0;
|
|
10539
|
-
let deletions = 0;
|
|
10540
|
-
for (const line2 of value2.slice(0, 262144).split("\n")) {
|
|
10541
|
-
if (line2.startsWith("+++") || line2.startsWith("---")) continue;
|
|
10542
|
-
if (line2.startsWith("+")) additions += 1;
|
|
10543
|
-
else if (line2.startsWith("-")) deletions += 1;
|
|
10544
|
-
}
|
|
10545
|
-
return { ...additions ? { additions } : {}, ...deletions ? { deletions } : {} };
|
|
10546
|
-
}
|
|
10547
|
-
function searchResults(value2) {
|
|
10548
|
-
if (typeof value2 !== "string") return void 0;
|
|
10549
|
-
const results = value2.split("\n").flatMap((line2) => {
|
|
10550
|
-
const match = /^([^:\n]{1,1024}):(\d+):\s?(.*)$/.exec(line2);
|
|
10551
|
-
if (!match) return [];
|
|
10552
|
-
const lineNumber = Number(match[2]);
|
|
10553
|
-
const itemText = text3(match[3], 240);
|
|
10554
|
-
if (!Number.isSafeInteger(lineNumber) || lineNumber < 1) return [];
|
|
10555
|
-
return [{ path: match[1], line: lineNumber, ...itemText ? { text: itemText } : {} }];
|
|
10556
|
-
}).slice(0, 5);
|
|
10557
|
-
return results.length ? results : void 0;
|
|
10558
|
-
}
|
|
10559
|
-
function codeToolRequestPresentation(request3) {
|
|
10560
|
-
const input = request3.input;
|
|
10561
|
-
if (request3.tool === "sandbox.read") {
|
|
10562
|
-
const path = text3(input.path, 1024);
|
|
10563
|
-
if (!path) return void 0;
|
|
10564
|
-
const startLine = integer2(input.startLine);
|
|
10565
|
-
const endLine = integer2(input.endLine);
|
|
10566
|
-
return { kind: "read", path, ...startLine ? { startLine } : {}, ...endLine ? { endLine } : {} };
|
|
10567
|
-
}
|
|
10568
|
-
if (request3.tool === "sandbox.list") {
|
|
10569
|
-
const scope = text3(input.prefix, 1024);
|
|
10570
|
-
return { kind: "list", ...scope ? { scope } : {} };
|
|
10571
|
-
}
|
|
10572
|
-
if (request3.tool === "sandbox.search" || request3.tool === "sandbox.overview" || request3.tool === "sandbox.where_is" || request3.tool === "sandbox.who_imports" || request3.tool === "sandbox.who_touches") {
|
|
10573
|
-
const query = text3(input.query, 512);
|
|
10574
|
-
const scope = request3.tool === "sandbox.search" ? text3(input.prefix, 1024) : void 0;
|
|
10575
|
-
if (request3.tool === "sandbox.search" && !query) return void 0;
|
|
10576
|
-
return { kind: "query", ...query ? { query } : {}, ...scope ? { scope } : {} };
|
|
10577
|
-
}
|
|
10578
|
-
if (request3.tool === "sandbox.apply_patch") {
|
|
10579
|
-
return { kind: "patch", ...patchStats(input.patch) };
|
|
10580
|
-
}
|
|
10581
|
-
const recipeId = text3(input.recipeId, 120);
|
|
10582
|
-
return recipeId ? { kind: "recipe", recipeId } : void 0;
|
|
10583
|
-
}
|
|
10584
|
-
function codeToolResultPresentation(request3, response2) {
|
|
10585
|
-
const started = codeToolRequestPresentation(request3);
|
|
10586
|
-
if (!started || !response2.ok) return started;
|
|
10587
|
-
const details = record32(response2.details);
|
|
10588
|
-
if (started.kind === "read") {
|
|
10589
|
-
return {
|
|
10590
|
-
...started,
|
|
10591
|
-
...integer2(details?.startLine) ? { startLine: integer2(details?.startLine) } : {},
|
|
10592
|
-
...integer2(details?.endLine) ? { endLine: integer2(details?.endLine) } : {},
|
|
10593
|
-
...excerpt(response2.content) ? { excerpt: excerpt(response2.content) } : {}
|
|
10594
|
-
};
|
|
10595
|
-
}
|
|
10596
|
-
if (started.kind === "list") {
|
|
10597
|
-
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);
|
|
10598
|
-
return {
|
|
10599
|
-
...started,
|
|
10600
|
-
...integer2(details?.count) !== void 0 ? { count: integer2(details?.count) } : {},
|
|
10601
|
-
...listed.length ? { paths: listed } : {}
|
|
10602
|
-
};
|
|
10603
|
-
}
|
|
10604
|
-
if (started.kind === "query") {
|
|
10605
|
-
const results = request3.tool === "sandbox.search" ? searchResults(response2.content) : void 0;
|
|
10606
|
-
const resultExcerpt = request3.tool === "sandbox.search" ? void 0 : excerpt(response2.content);
|
|
10607
|
-
return {
|
|
10608
|
-
...started,
|
|
10609
|
-
...integer2(details?.count) !== void 0 ? { count: integer2(details?.count) } : {},
|
|
10610
|
-
...results ? { results } : {},
|
|
10611
|
-
...resultExcerpt ? { excerpt: resultExcerpt } : {}
|
|
10612
|
-
};
|
|
10613
|
-
}
|
|
10614
|
-
if (started.kind === "patch") {
|
|
10615
|
-
return { ...started, ...paths(details?.paths) ? { paths: paths(details?.paths) } : {} };
|
|
10616
|
-
}
|
|
10617
|
-
const output = response2.content.replace(/^Recipe [^\n]*\.?\s*/u, "");
|
|
10618
|
-
return {
|
|
10619
|
-
...started,
|
|
10620
|
-
...integer2(details?.exitCode) !== void 0 ? { exitCode: integer2(details?.exitCode) } : {},
|
|
10621
|
-
...typeof details?.timedOut === "boolean" ? { timedOut: details.timedOut } : {},
|
|
10622
|
-
...typeof details?.outputLimitExceeded === "boolean" ? { outputLimitExceeded: details.outputLimitExceeded } : {},
|
|
10623
|
-
...excerpt(output, true) ? { excerpt: excerpt(output, true) } : {}
|
|
10624
|
-
};
|
|
10625
|
-
}
|
|
10626
10762
|
function codeRuntimeAcknowledgementGate(signal) {
|
|
10627
10763
|
let settle;
|
|
10628
10764
|
let settled = false;
|
|
@@ -10640,13 +10776,63 @@ function codeRuntimeAcknowledgementGate(signal) {
|
|
|
10640
10776
|
else signal.addEventListener("abort", onAbort, { once: true });
|
|
10641
10777
|
return { ready, release };
|
|
10642
10778
|
}
|
|
10643
|
-
|
|
10644
|
-
|
|
10645
|
-
|
|
10779
|
+
function observeCodeRuntimeSessionSkills(command, skills, emit4) {
|
|
10780
|
+
return skills.map((skill) => ({
|
|
10781
|
+
...skill,
|
|
10782
|
+
tools: skill.tools.map((tool) => {
|
|
10783
|
+
if (!tool.handler) return tool;
|
|
10784
|
+
const handler = tool.handler;
|
|
10785
|
+
return {
|
|
10786
|
+
...tool,
|
|
10787
|
+
handler: async (input, context) => {
|
|
10788
|
+
const startedAt = Date.now();
|
|
10789
|
+
const operationId = digestRuntimeValue(
|
|
10790
|
+
`${command.commandId}:${skill.name}:${tool.name}:${context.toolCallId ?? "missing"}`
|
|
10791
|
+
);
|
|
10792
|
+
await emit4({
|
|
10793
|
+
type: "collaboration",
|
|
10794
|
+
phase: "started",
|
|
10795
|
+
skill: skill.name,
|
|
10796
|
+
tool: tool.name,
|
|
10797
|
+
operationId
|
|
10798
|
+
}).catch(() => void 0);
|
|
10799
|
+
try {
|
|
10800
|
+
const output = await handler(input, context);
|
|
10801
|
+
await emit4({
|
|
10802
|
+
type: "collaboration",
|
|
10803
|
+
phase: "completed",
|
|
10804
|
+
skill: skill.name,
|
|
10805
|
+
tool: tool.name,
|
|
10806
|
+
operationId,
|
|
10807
|
+
ok: output.isError !== true,
|
|
10808
|
+
durationMs: Date.now() - startedAt
|
|
10809
|
+
}).catch(() => void 0);
|
|
10810
|
+
return output;
|
|
10811
|
+
} catch (cause) {
|
|
10812
|
+
await emit4({
|
|
10813
|
+
type: "collaboration",
|
|
10814
|
+
phase: "completed",
|
|
10815
|
+
skill: skill.name,
|
|
10816
|
+
tool: tool.name,
|
|
10817
|
+
operationId,
|
|
10818
|
+
ok: false,
|
|
10819
|
+
durationMs: Date.now() - startedAt
|
|
10820
|
+
}).catch(() => void 0);
|
|
10821
|
+
throw cause;
|
|
10822
|
+
}
|
|
10823
|
+
}
|
|
10824
|
+
};
|
|
10825
|
+
})
|
|
10826
|
+
}));
|
|
10827
|
+
}
|
|
10828
|
+
var import_crypto, import_promises5, import_path5, import_child_process4, import_promises6, import_path6, import_child_process5, import_process2, import_crypto2, import_crypto3, import_fs2, import_promises7, import_path7, import_promises8, import_os3, import_path8, import_ai4, import_ai5, import_child_process6, import_promises9, import_path9, import_promises10, import_promises11, import_path10, import_crypto4, CODE_RUNTIME_PROTOCOL_VERSION, CodeRuntimeReconciler, CodeRuntimeControlError, record6, invalid, RESERVED, SECRET, PATH, FORBIDDEN, ARTIFACT_PATH, PRIVATE_ARTIFACT_PART, SHA3, DIGEST3, ID3, RULE, DEFAULT_PREFIXES, DEFAULT_SUFFIXES, message, CodeRuntimeCheckpointManager, record22, SOURCE_LIMITS, RESERVED2, SECRET2, SOURCE_MAX_FILES, SOURCE_MAX_BYTES, SOURCE_SET_MAX_BYTES, V1_SYSTEM_PROMPT, V2_SYSTEM_PROMPT, V3_SYSTEM_PROMPT, SYSTEM_PROMPT_FOR, DEFAULT_MAX_FILES, DEFAULT_MAX_RESULTS, DEFAULT_MAX_FILE_BYTES, MAX_NATIVE_ARG_BYTES, DESTINATIONS, READ, LIST, SEARCH, GRAPH, PATCH, RECIPE, DEFAULT_FAILURE_REASON2, cache, shortId, GRAPH_TOOLS, MAX_MEMORY_BODY, POSITIVE, digestRuntimeValue, runtimeErrorMessage, TheseusRuntimeEngine;
|
|
10829
|
+
var init_chunk_Q4NL5XO3 = __esm({
|
|
10830
|
+
"../harness/dist/chunk-Q4NL5XO3.js"() {
|
|
10646
10831
|
"use strict";
|
|
10647
10832
|
init_cjs_shims();
|
|
10648
|
-
|
|
10649
|
-
|
|
10833
|
+
init_chunk_FAN2R3GW();
|
|
10834
|
+
init_chunk_5LRYJKUI();
|
|
10835
|
+
init_chunk_U324RQ4N();
|
|
10650
10836
|
import_crypto = require("crypto");
|
|
10651
10837
|
import_promises5 = require("fs/promises");
|
|
10652
10838
|
import_path5 = require("path");
|
|
@@ -10728,7 +10914,7 @@ var init_chunk_J7XU5QB7 = __esm({
|
|
|
10728
10914
|
code;
|
|
10729
10915
|
name = "CodeRuntimeControlError";
|
|
10730
10916
|
};
|
|
10731
|
-
|
|
10917
|
+
record6 = (value2) => value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
|
|
10732
10918
|
invalid = (part) => new CodeRuntimeControlError(`invalid Code runtime ${part} response`, 502, "invalid_response");
|
|
10733
10919
|
RESERVED = /* @__PURE__ */ new Set([".git", ".odla", ".wrangler", "node_modules", "dist", "coverage"]);
|
|
10734
10920
|
SECRET = /^(?:\.env(?:\..+)?|\.dev\.vars|credentials(?:\..+)?\.json|dev-token(?:\..+)?\.json)$/i;
|
|
@@ -10881,6 +11067,10 @@ Never claim a build or test passed unless odla_run_recipe returned that result.`
|
|
|
10881
11067
|
recipeId: "selector",
|
|
10882
11068
|
sourceDigest: "payload"
|
|
10883
11069
|
});
|
|
11070
|
+
DEFAULT_FAILURE_REASON2 = {
|
|
11071
|
+
"tool denied by CaMeL policy": "tool denied by CaMeL policy",
|
|
11072
|
+
"review sessions are read-only": "review session is read-only; workspace changes are not permitted"
|
|
11073
|
+
};
|
|
10884
11074
|
cache = /* @__PURE__ */ new Map();
|
|
10885
11075
|
shortId = (id2) => id2.slice(id2.indexOf(":") + 1);
|
|
10886
11076
|
GRAPH_TOOLS = /* @__PURE__ */ new Set([
|
|
@@ -10893,30 +11083,6 @@ Never claim a build or test passed unless odla_run_recipe returned that result.`
|
|
|
10893
11083
|
POSITIVE = (value2) => Number.isFinite(value2) && Number(value2) > 0 ? Number(value2) : void 0;
|
|
10894
11084
|
digestRuntimeValue = (value2) => `sha256:${(0, import_crypto4.createHash)("sha256").update(value2).digest("hex")}`;
|
|
10895
11085
|
runtimeErrorMessage = (value2) => value2 instanceof Error ? value2.message : String(value2);
|
|
10896
|
-
text3 = (value2, maximum) => {
|
|
10897
|
-
if (typeof value2 !== "string") return void 0;
|
|
10898
|
-
const bounded = value2.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g, " ").trim();
|
|
10899
|
-
return bounded ? bounded.slice(0, maximum) : void 0;
|
|
10900
|
-
};
|
|
10901
|
-
integer2 = (value2) => Number.isSafeInteger(value2) && Number(value2) >= 0 ? Number(value2) : void 0;
|
|
10902
|
-
record32 = (value2) => value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : void 0;
|
|
10903
|
-
excerpt = (value2, tail = false) => {
|
|
10904
|
-
if (typeof value2 !== "string") return void 0;
|
|
10905
|
-
const safe = value2.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g, " ");
|
|
10906
|
-
const source = (tail ? safe.slice(-1e4) : safe.slice(0, 1e4)).trim();
|
|
10907
|
-
if (!source) return void 0;
|
|
10908
|
-
const lines = source.split("\n").filter((line2) => line2.trim()).map((line2) => line2.slice(0, 240));
|
|
10909
|
-
const selected = tail ? lines.slice(-10) : lines.slice(0, 10);
|
|
10910
|
-
return text3(selected.join("\n"), 2400);
|
|
10911
|
-
};
|
|
10912
|
-
paths = (value2) => {
|
|
10913
|
-
if (!Array.isArray(value2)) return void 0;
|
|
10914
|
-
const items = value2.flatMap((item) => {
|
|
10915
|
-
const path = text3(item, 1024);
|
|
10916
|
-
return path ? [path] : [];
|
|
10917
|
-
}).slice(0, 12);
|
|
10918
|
-
return items.length ? items : void 0;
|
|
10919
|
-
};
|
|
10920
11086
|
TheseusRuntimeEngine = class {
|
|
10921
11087
|
constructor(options) {
|
|
10922
11088
|
this.options = options;
|
|
@@ -11113,7 +11279,7 @@ Never claim a build or test passed unless odla_run_recipe returned that result.`
|
|
|
11113
11279
|
event: (event) => this.#event(command, event, active.conversationRefs)
|
|
11114
11280
|
});
|
|
11115
11281
|
await this.#event(command, { type: "status", status: "running" }, active.conversationRefs);
|
|
11116
|
-
const extraSkills = await sessionSkillsFor(this.options, command);
|
|
11282
|
+
const extraSkills = observeCodeRuntimeSessionSkills(command, await sessionSkillsFor(this.options, command), (event) => this.#event(command, event, active.conversationRefs));
|
|
11117
11283
|
const result = await this.#attempt({
|
|
11118
11284
|
inference,
|
|
11119
11285
|
broker,
|
|
@@ -11152,36 +11318,11 @@ Never claim a build or test passed unless odla_run_recipe returned that result.`
|
|
|
11152
11318
|
}
|
|
11153
11319
|
/** Report every brokered effect as it starts and finishes. */
|
|
11154
11320
|
#observed(command, active, broker) {
|
|
11155
|
-
return {
|
|
11156
|
-
|
|
11157
|
-
|
|
11158
|
-
|
|
11159
|
-
|
|
11160
|
-
await this.#event(
|
|
11161
|
-
command,
|
|
11162
|
-
{
|
|
11163
|
-
type: "tool",
|
|
11164
|
-
phase: "started",
|
|
11165
|
-
tool: request3.tool,
|
|
11166
|
-
operationId,
|
|
11167
|
-
...startedPresentation ? { presentation: startedPresentation } : {}
|
|
11168
|
-
},
|
|
11169
|
-
active.conversationRefs
|
|
11170
|
-
).catch(() => void 0);
|
|
11171
|
-
const response2 = await broker.execute(context, request3);
|
|
11172
|
-
const completedPresentation = codeToolResultPresentation(request3, response2);
|
|
11173
|
-
await this.#event(command, {
|
|
11174
|
-
type: "tool",
|
|
11175
|
-
phase: "completed",
|
|
11176
|
-
tool: request3.tool,
|
|
11177
|
-
ok: response2.ok,
|
|
11178
|
-
durationMs: Date.now() - startedAt,
|
|
11179
|
-
operationId,
|
|
11180
|
-
...completedPresentation ? { presentation: completedPresentation } : {}
|
|
11181
|
-
}, active.conversationRefs).catch(() => void 0);
|
|
11182
|
-
return response2;
|
|
11183
|
-
}
|
|
11184
|
-
};
|
|
11321
|
+
return observedBroker({
|
|
11322
|
+
broker,
|
|
11323
|
+
operationIdFor: (requestId) => digestRuntimeValue(`${command.commandId}:${requestId}`),
|
|
11324
|
+
emit: (event) => this.#event(command, event, active.conversationRefs).catch(() => void 0)
|
|
11325
|
+
});
|
|
11185
11326
|
}
|
|
11186
11327
|
async #checkpoint(command) {
|
|
11187
11328
|
const active = this.#active.get(command.sessionId);
|
|
@@ -11218,8 +11359,8 @@ var init_node = __esm({
|
|
|
11218
11359
|
"../harness/dist/node.js"() {
|
|
11219
11360
|
"use strict";
|
|
11220
11361
|
init_cjs_shims();
|
|
11221
|
-
|
|
11222
|
-
|
|
11362
|
+
init_chunk_Q4NL5XO3();
|
|
11363
|
+
init_chunk_5LRYJKUI();
|
|
11223
11364
|
MEASURED_PREMIUM = Object.freeze({
|
|
11224
11365
|
/** 3 racers vs pure depth at equal budget: 21,044 / 7,936. */
|
|
11225
11366
|
racePerRacer: 0.55,
|
|
@@ -11461,6 +11602,19 @@ var init_code_runtime_config = __esm({
|
|
|
11461
11602
|
init_cjs_shims();
|
|
11462
11603
|
CODE_NODE_IMAGE = "node:24-alpine@sha256:a0b9bf06e4e6193cf7a0f58816cc935ff8c2a908f81e6f1a95432d679c54fbfd";
|
|
11463
11604
|
CODE_BUILD_RECIPES = Object.freeze([{
|
|
11605
|
+
id: "odla-code-gates",
|
|
11606
|
+
image: CODE_NODE_IMAGE,
|
|
11607
|
+
// Selects the repository's fast, no-capability gates from the same manifest
|
|
11608
|
+
// CI and `npm run preflight` read, so a new gate is picked up without a
|
|
11609
|
+
// second list to keep in sync. The container has no shell: this is argv.
|
|
11610
|
+
command: ["node", "scripts/recipe-gates.mjs"],
|
|
11611
|
+
timeoutMs: 18e4,
|
|
11612
|
+
maxOutputBytes: 1024 * 1024,
|
|
11613
|
+
cpus: 1,
|
|
11614
|
+
// check:secrets holds ~2,500 source files in memory at once.
|
|
11615
|
+
memory: "1g",
|
|
11616
|
+
pids: 128
|
|
11617
|
+
}, {
|
|
11464
11618
|
id: "odla-code-contracts",
|
|
11465
11619
|
image: CODE_NODE_IMAGE,
|
|
11466
11620
|
command: [
|
|
@@ -11642,20 +11796,20 @@ async function runCodeRuntime(input) {
|
|
|
11642
11796
|
}
|
|
11643
11797
|
}
|
|
11644
11798
|
function parseConnection(value2, appId, appEnv) {
|
|
11645
|
-
const root =
|
|
11646
|
-
const host =
|
|
11647
|
-
const offer =
|
|
11648
|
-
const binding =
|
|
11799
|
+
const root = record7(value2);
|
|
11800
|
+
const host = record7(root?.host);
|
|
11801
|
+
const offer = record7(root?.offer);
|
|
11802
|
+
const binding = record7(root?.binding);
|
|
11649
11803
|
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)) {
|
|
11650
11804
|
throw new Error("connect Code host returned an invalid response");
|
|
11651
11805
|
}
|
|
11652
11806
|
return root;
|
|
11653
11807
|
}
|
|
11654
11808
|
function apiFailure(action2, status, value2) {
|
|
11655
|
-
const message2 =
|
|
11809
|
+
const message2 = record7(record7(value2)?.error)?.message;
|
|
11656
11810
|
return `${action2} failed (${status})${typeof message2 === "string" ? `: ${message2}` : ""}`;
|
|
11657
11811
|
}
|
|
11658
|
-
function
|
|
11812
|
+
function record7(value2) {
|
|
11659
11813
|
return value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
|
|
11660
11814
|
}
|
|
11661
11815
|
var import_node_fs18, import_node_os5, import_node_path18;
|
|
@@ -12250,6 +12404,14 @@ Usage:
|
|
|
12250
12404
|
odla-ai ai models [--config odla.config.mjs] [--env dev] [--provider <id>] [--json]
|
|
12251
12405
|
odla-ai config <diff|plan> [--config odla.config.mjs] [--email <odla-account>] [--json]
|
|
12252
12406
|
odla-ai config apply --plan <plan.json> [--idempotency-key <key>] [--email <odla-account>] [--json]
|
|
12407
|
+
odla-ai promotion plan --file <promotion-plan.json> [--env dev] [--json]
|
|
12408
|
+
odla-ai promotion inspect <plan-id> [--env dev] [--json]
|
|
12409
|
+
odla-ai promotion status <plan-id> [--env dev] [--json]
|
|
12410
|
+
odla-ai promotion apply <plan-id> --approval <approval-id> [--idempotency-key <key>] [--env dev] [--json]
|
|
12411
|
+
odla-ai promotion rollback <plan-id> --approval <approval-id> [--idempotency-key <key>] [--env dev] [--json]
|
|
12412
|
+
odla-ai promotion next <plan-id> <operation-id> [--env dev] [--json]
|
|
12413
|
+
odla-ai promotion record <plan-id> <operation-id> <step-id> --file <step-receipt.json> [--env dev] [--json]
|
|
12414
|
+
odla-ai promotion cancel <plan-id> <operation-id> [--env dev] [--json]
|
|
12253
12415
|
odla-ai operations get <operation-id> [--json]
|
|
12254
12416
|
odla-ai operations wait <operation-id> [--interval <seconds>] [--timeout <seconds>] [--json]
|
|
12255
12417
|
odla-ai calendar status [--env dev] [--email <odla-account>] [--json]
|
|
@@ -12418,6 +12580,11 @@ Commands:
|
|
|
12418
12580
|
init Create a generic odla.config.mjs plus starter schema/rules files.
|
|
12419
12581
|
doctor Validate and summarize the project config without network calls.
|
|
12420
12582
|
config Diff Registry intent, freeze a CAS-bound plan, and conditionally apply its safe actions.
|
|
12583
|
+
promotion Plan and inspect exact selective-release bundles without target
|
|
12584
|
+
mutation, then queue and resume a human-approved apply or rollback
|
|
12585
|
+
from an enrolled device. Each target step is leased and receipt-
|
|
12586
|
+
journaled; approval remains bound to the immutable plan digest,
|
|
12587
|
+
target set, action, and expiry, so every mismatch fails closed.
|
|
12421
12588
|
operations Inspect or wait on one exact, durable config-operation receipt.
|
|
12422
12589
|
calendar Inspect, connect, or disconnect the live Google booking connection.
|
|
12423
12590
|
app Archive (suspend, data retained), restore, export, import, or
|
|
@@ -13327,17 +13494,17 @@ function collectEntityFields(entity, parsed, allowClear) {
|
|
|
13327
13494
|
if (entity === "task" && fields.column === "ready") fields.column = "todo";
|
|
13328
13495
|
return fields;
|
|
13329
13496
|
}
|
|
13330
|
-
function statusCol(entity,
|
|
13331
|
-
if (entity === "bug") return `${
|
|
13497
|
+
function statusCol(entity, record12) {
|
|
13498
|
+
if (entity === "bug") return `${record12.status ?? ""}/${record12.severity ?? ""}`;
|
|
13332
13499
|
if (entity === "task") {
|
|
13333
|
-
const state2 =
|
|
13334
|
-
return
|
|
13500
|
+
const state2 = record12.column === "todo" ? "ready" : String(record12.column ?? "");
|
|
13501
|
+
return record12.revision ? `${state2}; r${record12.revision}` : state2;
|
|
13335
13502
|
}
|
|
13336
|
-
return String(
|
|
13503
|
+
return String(record12.status ?? "");
|
|
13337
13504
|
}
|
|
13338
|
-
function referenceMarkup(entity,
|
|
13339
|
-
const label = (
|
|
13340
|
-
return `@[${label}](pm:${entity}/${
|
|
13505
|
+
function referenceMarkup(entity, record12) {
|
|
13506
|
+
const label = (record12.title?.trim() || `${entity} ${record12.id}`).replaceAll("]", ")");
|
|
13507
|
+
return `@[${label}](pm:${entity}/${record12.id})`;
|
|
13341
13508
|
}
|
|
13342
13509
|
function studioRecordUrl(ctx, entity, id2) {
|
|
13343
13510
|
return new URL(
|
|
@@ -13345,13 +13512,13 @@ function studioRecordUrl(ctx, entity, id2) {
|
|
|
13345
13512
|
ctx.platformUrl
|
|
13346
13513
|
).href;
|
|
13347
13514
|
}
|
|
13348
|
-
function studioRecordLink(ctx, entity,
|
|
13349
|
-
const label = (
|
|
13350
|
-
return `[${label}](${studioRecordUrl(ctx, entity,
|
|
13515
|
+
function studioRecordLink(ctx, entity, record12) {
|
|
13516
|
+
const label = (record12.title?.trim() || `${entity} ${record12.id}`).replaceAll("]", ")");
|
|
13517
|
+
return `[${label}](${studioRecordUrl(ctx, entity, record12.id)})`;
|
|
13351
13518
|
}
|
|
13352
|
-
function printRecord(ctx, entity,
|
|
13519
|
+
function printRecord(ctx, entity, record12) {
|
|
13353
13520
|
ctx.out.log(
|
|
13354
|
-
`${
|
|
13521
|
+
`${record12.id} [${statusCol(entity, record12)}] ${record12.appId} ${studioRecordLink(ctx, entity, record12)}`
|
|
13355
13522
|
);
|
|
13356
13523
|
}
|
|
13357
13524
|
function emit2(ctx, value2, human) {
|
|
@@ -13455,8 +13622,8 @@ async function pmAdd(ctx, entity, parsed) {
|
|
|
13455
13622
|
input,
|
|
13456
13623
|
mutationId: writeMutationId2(parsed)
|
|
13457
13624
|
});
|
|
13458
|
-
const
|
|
13459
|
-
emit2(ctx, res, () => ctx.out.log(`created ${entity}: ${studioRecordLink(ctx, entity,
|
|
13625
|
+
const record12 = { id: res.id, appId, title: String(input.title) };
|
|
13626
|
+
emit2(ctx, res, () => ctx.out.log(`created ${entity}: ${studioRecordLink(ctx, entity, record12)}`));
|
|
13460
13627
|
}
|
|
13461
13628
|
function looksLikeUuidPrefix(value2) {
|
|
13462
13629
|
if (!UUID_PREFIX.test(value2) || !/[0-9a-f]/i.test(value2)) return false;
|
|
@@ -13474,7 +13641,7 @@ async function resolvePmId(ctx, entity, supplied) {
|
|
|
13474
13641
|
"GET",
|
|
13475
13642
|
`/${entity}?limit=${limit}&offset=${offset}`
|
|
13476
13643
|
);
|
|
13477
|
-
matches.push(...page2.records.map((
|
|
13644
|
+
matches.push(...page2.records.map((record12) => record12.id).filter((id2) => id2.toLowerCase().startsWith(prefix)));
|
|
13478
13645
|
offset += page2.records.length;
|
|
13479
13646
|
if (matches.length > 1 || page2.records.length === 0 || offset >= page2.total) break;
|
|
13480
13647
|
}
|
|
@@ -13488,17 +13655,17 @@ async function resolvePmId(ctx, entity, supplied) {
|
|
|
13488
13655
|
}
|
|
13489
13656
|
async function pmGet(ctx, entity, id2) {
|
|
13490
13657
|
const resolved = await resolvePmId(ctx, entity, id2);
|
|
13491
|
-
const { record:
|
|
13492
|
-
emit2(ctx,
|
|
13658
|
+
const { record: record12 } = await pmRequest(ctx, "GET", `/${entity}/${encodeURIComponent(resolved)}`);
|
|
13659
|
+
emit2(ctx, record12, () => printRecord(ctx, entity, record12));
|
|
13493
13660
|
}
|
|
13494
13661
|
async function pmReference(ctx, entity, id2) {
|
|
13495
|
-
const { record:
|
|
13662
|
+
const { record: record12 } = await pmRequest(
|
|
13496
13663
|
ctx,
|
|
13497
13664
|
"GET",
|
|
13498
13665
|
`/${entity}/${encodeURIComponent(id2)}`
|
|
13499
13666
|
);
|
|
13500
|
-
const markup = referenceMarkup(entity,
|
|
13501
|
-
emit2(ctx, { kind: `pm:${entity}`, id:
|
|
13667
|
+
const markup = referenceMarkup(entity, record12);
|
|
13668
|
+
emit2(ctx, { kind: `pm:${entity}`, id: record12.id, label: record12.title ?? "", markup }, () => {
|
|
13502
13669
|
ctx.out.log(markup);
|
|
13503
13670
|
});
|
|
13504
13671
|
}
|
|
@@ -13577,16 +13744,16 @@ var init_pm_actions = __esm({
|
|
|
13577
13744
|
});
|
|
13578
13745
|
|
|
13579
13746
|
// src/pm-lean.ts
|
|
13580
|
-
function leanRecord(entity,
|
|
13747
|
+
function leanRecord(entity, record12) {
|
|
13581
13748
|
const out = {};
|
|
13582
13749
|
for (const key of [...COMMON, ...PER_ENTITY[entity]]) {
|
|
13583
|
-
const value2 =
|
|
13750
|
+
const value2 = record12[key];
|
|
13584
13751
|
if (value2 !== void 0 && value2 !== null) out[key] = value2;
|
|
13585
13752
|
}
|
|
13586
13753
|
return out;
|
|
13587
13754
|
}
|
|
13588
13755
|
function leanRecords(entity, records, verbose) {
|
|
13589
|
-
return verbose ? records : records.map((
|
|
13756
|
+
return verbose ? records : records.map((record12) => leanRecord(entity, record12));
|
|
13590
13757
|
}
|
|
13591
13758
|
var COMMON, PER_ENTITY;
|
|
13592
13759
|
var init_pm_lean = __esm({
|
|
@@ -13638,16 +13805,18 @@ async function pmNext(ctx, parsed) {
|
|
|
13638
13805
|
// One request for both live columns; the split below is over open work only.
|
|
13639
13806
|
listFiltered(ctx, "task", appId, projectId, { column: `${READY_COLUMN},doing` })
|
|
13640
13807
|
]);
|
|
13641
|
-
const ready = tasks.filter((
|
|
13642
|
-
const doing = tasks.filter((
|
|
13808
|
+
const ready = tasks.filter((record12) => record12.column === READY_COLUMN);
|
|
13809
|
+
const doing = tasks.filter((record12) => record12.column === "doing");
|
|
13643
13810
|
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}`;
|
|
13811
|
+
const monitor = `odla-ai pm watch --app ${appId} --jsonl`;
|
|
13644
13812
|
const result = {
|
|
13645
13813
|
appId,
|
|
13646
13814
|
projectId,
|
|
13647
13815
|
openGoals: leanRecords("goal", goals, verbose),
|
|
13648
13816
|
doing: leanRecords("task", doing, verbose),
|
|
13649
13817
|
ready: leanRecords("task", ready, verbose),
|
|
13650
|
-
next: guidance
|
|
13818
|
+
next: guidance,
|
|
13819
|
+
monitor
|
|
13651
13820
|
};
|
|
13652
13821
|
emit2(ctx, result, () => {
|
|
13653
13822
|
ctx.out.log(`${appId}: goal-aligned work intake (read only)`);
|
|
@@ -13658,9 +13827,10 @@ async function pmNext(ctx, parsed) {
|
|
|
13658
13827
|
]) {
|
|
13659
13828
|
ctx.out.log(`${label}:`);
|
|
13660
13829
|
if (!records.length) ctx.out.log("- (none)");
|
|
13661
|
-
else for (const
|
|
13830
|
+
else for (const record12 of records) printRecord(ctx, entity, record12);
|
|
13662
13831
|
}
|
|
13663
13832
|
ctx.out.log(`next: ${guidance}`);
|
|
13833
|
+
ctx.out.log(`monitor: ${monitor}`);
|
|
13664
13834
|
});
|
|
13665
13835
|
}
|
|
13666
13836
|
async function pmHandoff(ctx, parsed) {
|
|
@@ -13672,17 +13842,20 @@ async function pmHandoff(ctx, parsed) {
|
|
|
13672
13842
|
listFiltered(ctx, "bug", appId, projectId, { status: OPEN_BUG_STATUSES })
|
|
13673
13843
|
]);
|
|
13674
13844
|
const clean4 = !goals.length && !tasks.length && !bugs.length;
|
|
13845
|
+
const monitor = `odla-ai pm watch --app ${appId} --jsonl`;
|
|
13675
13846
|
const result = {
|
|
13676
13847
|
appId,
|
|
13677
13848
|
projectId,
|
|
13678
13849
|
unmetGoals: leanRecords("goal", goals, verbose),
|
|
13679
13850
|
activeTasks: leanRecords("task", tasks, verbose),
|
|
13680
13851
|
openBugs: leanRecords("bug", bugs, verbose),
|
|
13681
|
-
clean: clean4
|
|
13852
|
+
clean: clean4,
|
|
13853
|
+
monitor
|
|
13682
13854
|
};
|
|
13683
13855
|
emit2(ctx, result, () => {
|
|
13684
13856
|
if (clean4) {
|
|
13685
13857
|
ctx.out.log(`${appId}: no unresolved PM work`);
|
|
13858
|
+
ctx.out.log(`monitor: ${monitor}`);
|
|
13686
13859
|
return;
|
|
13687
13860
|
}
|
|
13688
13861
|
ctx.out.log(`${appId}: authoritative PM handoff`);
|
|
@@ -13693,8 +13866,9 @@ async function pmHandoff(ctx, parsed) {
|
|
|
13693
13866
|
]) {
|
|
13694
13867
|
ctx.out.log(`${label}:`);
|
|
13695
13868
|
if (!records.length) ctx.out.log("- (none)");
|
|
13696
|
-
else for (const
|
|
13869
|
+
else for (const record12 of records) printRecord(ctx, entity, record12);
|
|
13697
13870
|
}
|
|
13871
|
+
ctx.out.log(`monitor: ${monitor}`);
|
|
13698
13872
|
});
|
|
13699
13873
|
}
|
|
13700
13874
|
var READY_COLUMN, UNMET_GOAL_STATUS, ACTIVE_TASK_COLUMNS, OPEN_BUG_STATUSES, wantsVerbose;
|
|
@@ -13793,14 +13967,14 @@ var init_pm_start = __esm({
|
|
|
13793
13967
|
|
|
13794
13968
|
// src/pm-links.ts
|
|
13795
13969
|
async function pmLink(ctx, entity, id2) {
|
|
13796
|
-
const { record:
|
|
13970
|
+
const { record: record12 } = await pmRequest(
|
|
13797
13971
|
ctx,
|
|
13798
13972
|
"GET",
|
|
13799
13973
|
`/${entity}/${encodeURIComponent(id2)}`
|
|
13800
13974
|
);
|
|
13801
|
-
const url = studioRecordUrl(ctx, entity,
|
|
13802
|
-
const markdown = studioRecordLink(ctx, entity,
|
|
13803
|
-
emit2(ctx, { kind: entity, id:
|
|
13975
|
+
const url = studioRecordUrl(ctx, entity, record12.id);
|
|
13976
|
+
const markdown = studioRecordLink(ctx, entity, record12);
|
|
13977
|
+
emit2(ctx, { kind: entity, id: record12.id, label: record12.title ?? "", url, markdown }, () => {
|
|
13804
13978
|
ctx.out.log(markdown);
|
|
13805
13979
|
});
|
|
13806
13980
|
}
|
|
@@ -13955,16 +14129,16 @@ async function page(ctx, appId, cursor) {
|
|
|
13955
14129
|
}
|
|
13956
14130
|
return data;
|
|
13957
14131
|
}
|
|
13958
|
-
function recordState(
|
|
13959
|
-
if (
|
|
13960
|
-
return String(
|
|
14132
|
+
function recordState(record12) {
|
|
14133
|
+
if (record12.column) return record12.column === "todo" ? "ready" : record12.column;
|
|
14134
|
+
return String(record12.status ?? "");
|
|
13961
14135
|
}
|
|
13962
14136
|
function eventRecord(event) {
|
|
13963
14137
|
return event.payload.payload;
|
|
13964
14138
|
}
|
|
13965
14139
|
function eventLabel(event) {
|
|
13966
|
-
const
|
|
13967
|
-
if (
|
|
14140
|
+
const record12 = eventRecord(event);
|
|
14141
|
+
if (record12) return String(record12.title ?? event.payload.entityId);
|
|
13968
14142
|
const body = event.payload.message?.body?.replace(/\s+/g, " ").trim();
|
|
13969
14143
|
return body || event.payload.entityId;
|
|
13970
14144
|
}
|
|
@@ -13972,10 +14146,10 @@ function report3(ctx, parsed, result) {
|
|
|
13972
14146
|
if (ctx.json) ctx.out.log(JSON.stringify(result, null, 2));
|
|
13973
14147
|
else if (parsed.options.jsonl !== true && result.found) {
|
|
13974
14148
|
for (const event of result.events ?? []) {
|
|
13975
|
-
const
|
|
13976
|
-
const state2 =
|
|
14149
|
+
const record12 = eventRecord(event);
|
|
14150
|
+
const state2 = record12 ? recordState(record12) : "comment";
|
|
13977
14151
|
ctx.out.log(
|
|
13978
|
-
`${event.id} ${event.type} ${state2}${
|
|
14152
|
+
`${event.id} ${event.type} ${state2}${record12?.revision ? `; r${record12.revision}` : ""} ${eventLabel(event)}`
|
|
13979
14153
|
);
|
|
13980
14154
|
}
|
|
13981
14155
|
}
|
|
@@ -14049,8 +14223,8 @@ async function pmWatch(ctx, parsed) {
|
|
|
14049
14223
|
}
|
|
14050
14224
|
firstSuccess = false;
|
|
14051
14225
|
const matching = current.events.filter((event) => {
|
|
14052
|
-
const
|
|
14053
|
-
const state2 =
|
|
14226
|
+
const record12 = eventRecord(event);
|
|
14227
|
+
const state2 = record12 ? recordState(record12).toLowerCase() : "";
|
|
14054
14228
|
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);
|
|
14055
14229
|
});
|
|
14056
14230
|
for (const event of matching) {
|
|
@@ -14538,17 +14712,17 @@ async function platformStatus(parsed, deps) {
|
|
|
14538
14712
|
}
|
|
14539
14713
|
}
|
|
14540
14714
|
function isPlatformStatus(value2) {
|
|
14541
|
-
if (!
|
|
14542
|
-
if (!
|
|
14543
|
-
if (!
|
|
14715
|
+
if (!record8(value2) || value2.schemaVersion !== "odla.platform-status/v1") return false;
|
|
14716
|
+
if (!record8(value2.verdict) || !Array.isArray(value2.verdict.reasons)) return false;
|
|
14717
|
+
if (!record8(value2.catalog) || !record8(value2.summary)) return false;
|
|
14544
14718
|
return Array.isArray(value2.services) && Array.isArray(value2.nextActions);
|
|
14545
14719
|
}
|
|
14546
14720
|
function apiMessage(value2) {
|
|
14547
|
-
if (!
|
|
14548
|
-
const error =
|
|
14721
|
+
if (!record8(value2)) return "request failed";
|
|
14722
|
+
const error = record8(value2.error) ? value2.error : value2;
|
|
14549
14723
|
return typeof error.message === "string" ? error.message : typeof error.code === "string" ? error.code : "request failed";
|
|
14550
14724
|
}
|
|
14551
|
-
function
|
|
14725
|
+
function record8(value2) {
|
|
14552
14726
|
return !!value2 && typeof value2 === "object" && !Array.isArray(value2);
|
|
14553
14727
|
}
|
|
14554
14728
|
var init_platform_command = __esm({
|
|
@@ -14600,7 +14774,7 @@ function statusVerdict(reads) {
|
|
|
14600
14774
|
severity: "degraded"
|
|
14601
14775
|
});
|
|
14602
14776
|
}
|
|
14603
|
-
const performance =
|
|
14777
|
+
const performance = record9(reads.liveSync.body.performance) ? reads.liveSync.body.performance : null;
|
|
14604
14778
|
if (performance?.status === "unavailable") {
|
|
14605
14779
|
reasons.push({
|
|
14606
14780
|
source: "liveSync",
|
|
@@ -14681,7 +14855,7 @@ function statusVerdict(reads) {
|
|
|
14681
14855
|
reasons
|
|
14682
14856
|
};
|
|
14683
14857
|
}
|
|
14684
|
-
function
|
|
14858
|
+
function record9(value2) {
|
|
14685
14859
|
return Boolean(value2) && typeof value2 === "object" && !Array.isArray(value2);
|
|
14686
14860
|
}
|
|
14687
14861
|
function numeric2(value2) {
|
|
@@ -14715,7 +14889,7 @@ function printO11yStatus(status, out) {
|
|
|
14715
14889
|
out.log(
|
|
14716
14890
|
`o11y status ${status.scope.appId}/${status.scope.env} (${status.scope.minutes}m)`
|
|
14717
14891
|
);
|
|
14718
|
-
const routes = Array.isArray(status.application.body.routes) ? status.application.body.routes.filter(
|
|
14892
|
+
const routes = Array.isArray(status.application.body.routes) ? status.application.body.routes.filter(record10) : [];
|
|
14719
14893
|
const requests = routes.reduce(
|
|
14720
14894
|
(total, row) => total + numeric3(row.requests),
|
|
14721
14895
|
0
|
|
@@ -14727,39 +14901,39 @@ function printO11yStatus(status, out) {
|
|
|
14727
14901
|
out.log(
|
|
14728
14902
|
`application ${status.application.httpStatus} ${requests} requests ${errors} errors`
|
|
14729
14903
|
);
|
|
14730
|
-
const versions = Array.isArray(status.applicationVersions.body.rows) ? status.applicationVersions.body.rows.filter(
|
|
14904
|
+
const versions = Array.isArray(status.applicationVersions.body.rows) ? status.applicationVersions.body.rows.filter(record10) : [];
|
|
14731
14905
|
out.log(
|
|
14732
14906
|
`application-versions ${status.applicationVersions.httpStatus} ${versions.length ? versions.slice(0, 5).map(
|
|
14733
14907
|
(row) => `${String(row.value || "(unattributed)")}:${numeric3(row.requests)}`
|
|
14734
14908
|
).join(", ") : "none observed"}`
|
|
14735
14909
|
);
|
|
14736
14910
|
out.log(liveSyncLine(status.liveSync));
|
|
14737
|
-
const canaryDurations =
|
|
14911
|
+
const canaryDurations = record10(status.canary.body.durationsMs) ? status.canary.body.durationsMs : {};
|
|
14738
14912
|
out.log(
|
|
14739
14913
|
`canary ${status.canary.httpStatus} ${String(status.canary.body.status ?? status.canary.body.error ?? "unavailable")} ${optionalNumeric(canaryDurations.publishToVisibleMs)} publish-to-visible`
|
|
14740
14914
|
);
|
|
14741
|
-
const collectorIngest =
|
|
14742
|
-
const collectorStorage =
|
|
14915
|
+
const collectorIngest = record10(status.collector.body.ingest) ? status.collector.body.ingest : {};
|
|
14916
|
+
const collectorStorage = record10(collectorIngest.storage) ? collectorIngest.storage : {};
|
|
14743
14917
|
out.log(
|
|
14744
14918
|
`collector ${status.collector.httpStatus} ${String(status.collector.body.status ?? status.collector.body.error ?? "unavailable")} ${numeric3(collectorStorage.affectedPoints)} affected points`
|
|
14745
14919
|
);
|
|
14746
|
-
const providerMetrics =
|
|
14747
|
-
const providerCapacity =
|
|
14748
|
-
const workerMemory =
|
|
14920
|
+
const providerMetrics = record10(status.provider.body.metrics) ? status.provider.body.metrics : {};
|
|
14921
|
+
const providerCapacity = record10(status.provider.body.capacity) ? status.provider.body.capacity : {};
|
|
14922
|
+
const workerMemory = record10(providerCapacity.memory) ? providerCapacity.memory : {};
|
|
14749
14923
|
out.log(
|
|
14750
14924
|
`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`
|
|
14751
14925
|
);
|
|
14752
14926
|
for (const line2 of providerCapacityLines(status.providerCapacity)) {
|
|
14753
14927
|
out.log(line2);
|
|
14754
14928
|
}
|
|
14755
|
-
const coverage =
|
|
14756
|
-
const coverageCounts =
|
|
14757
|
-
const coverageBudget =
|
|
14929
|
+
const coverage = record10(status.providerReconciliation.body.comparison) ? status.providerReconciliation.body.comparison : {};
|
|
14930
|
+
const coverageCounts = record10(status.providerReconciliation.body.counts) ? status.providerReconciliation.body.counts : {};
|
|
14931
|
+
const coverageBudget = record10(status.providerReconciliation.body.budget) ? status.providerReconciliation.body.budget : {};
|
|
14758
14932
|
out.log(
|
|
14759
14933
|
`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`
|
|
14760
14934
|
);
|
|
14761
14935
|
const providerPoints = Array.isArray(status.providerHistory.body.points) ? status.providerHistory.body.points.length : 0;
|
|
14762
|
-
const providerFreshness =
|
|
14936
|
+
const providerFreshness = record10(status.providerHistory.body.freshness) ? status.providerHistory.body.freshness : {};
|
|
14763
14937
|
out.log(
|
|
14764
14938
|
`cloudflare-history ${status.providerHistory.httpStatus} ${String(status.providerHistory.body.status ?? status.providerHistory.body.error ?? "unavailable")} ${providerPoints} snapshots ${optionalAge(providerFreshness.ageMs)} old`
|
|
14765
14939
|
);
|
|
@@ -14768,17 +14942,17 @@ function printO11yStatus(status, out) {
|
|
|
14768
14942
|
);
|
|
14769
14943
|
}
|
|
14770
14944
|
function providerCapacityLines(read3) {
|
|
14771
|
-
const resources =
|
|
14772
|
-
const durableObjects =
|
|
14773
|
-
const periodic =
|
|
14774
|
-
const storage =
|
|
14775
|
-
const d1 =
|
|
14776
|
-
const d1Activity =
|
|
14777
|
-
const d1Storage =
|
|
14778
|
-
const d1Latency =
|
|
14779
|
-
const r2 =
|
|
14780
|
-
const r2Operations =
|
|
14781
|
-
const r2Storage =
|
|
14945
|
+
const resources = record10(read3.body.resources) ? read3.body.resources : {};
|
|
14946
|
+
const durableObjects = record10(resources.durableObjects) ? resources.durableObjects : {};
|
|
14947
|
+
const periodic = record10(durableObjects.periodic) ? durableObjects.periodic : {};
|
|
14948
|
+
const storage = record10(durableObjects.sqliteStorage) ? durableObjects.sqliteStorage : {};
|
|
14949
|
+
const d1 = record10(resources.d1) ? resources.d1 : {};
|
|
14950
|
+
const d1Activity = record10(d1.activity) ? d1.activity : {};
|
|
14951
|
+
const d1Storage = record10(d1.storage) ? d1.storage : {};
|
|
14952
|
+
const d1Latency = record10(d1Activity.latency) ? d1Activity.latency : {};
|
|
14953
|
+
const r2 = record10(resources.r2) ? resources.r2 : {};
|
|
14954
|
+
const r2Operations = record10(r2.operations) ? r2.operations : {};
|
|
14955
|
+
const r2Storage = record10(r2.storage) ? r2.storage : {};
|
|
14782
14956
|
const status = String(
|
|
14783
14957
|
read3.body.status ?? read3.body.error ?? "unavailable"
|
|
14784
14958
|
);
|
|
@@ -14789,11 +14963,11 @@ function providerCapacityLines(read3) {
|
|
|
14789
14963
|
];
|
|
14790
14964
|
}
|
|
14791
14965
|
function liveSyncLine(read3) {
|
|
14792
|
-
const performance =
|
|
14793
|
-
const commitToSend =
|
|
14966
|
+
const performance = record10(read3.body.performance) ? read3.body.performance : {};
|
|
14967
|
+
const commitToSend = record10(performance.commitToSend) ? performance.commitToSend : {};
|
|
14794
14968
|
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`;
|
|
14795
14969
|
}
|
|
14796
|
-
function
|
|
14970
|
+
function record10(value2) {
|
|
14797
14971
|
return Boolean(value2) && typeof value2 === "object" && !Array.isArray(value2);
|
|
14798
14972
|
}
|
|
14799
14973
|
function numeric3(value2) {
|
|
@@ -15141,7 +15315,7 @@ async function monitorCommand(parsed, deps = {}) {
|
|
|
15141
15315
|
if (action2 === "plan" || action2 === "apply") {
|
|
15142
15316
|
const desired = monitoringWireConfig(context.cfg, env);
|
|
15143
15317
|
const live = await request2(`${base}?env=${encodeURIComponent(env)}`, { headers }, doFetch);
|
|
15144
|
-
const currentRevision =
|
|
15318
|
+
const currentRevision = record11(live.config) ? string(live.config.revision) : null;
|
|
15145
15319
|
const changed = currentRevision !== desired.revision;
|
|
15146
15320
|
const plan = {
|
|
15147
15321
|
schemaVersion: 1,
|
|
@@ -15186,7 +15360,7 @@ async function monitorCommand(parsed, deps = {}) {
|
|
|
15186
15360
|
headers
|
|
15187
15361
|
}, doFetch);
|
|
15188
15362
|
emit3(result2, jsonOutput, out, () => {
|
|
15189
|
-
const run =
|
|
15363
|
+
const run = record11(result2.run) ? result2.run : {};
|
|
15190
15364
|
out.log(`monitor run ${appId}/${env}/${probeId}: ${string(run.outcome) ?? "unknown"}${run.failure_code ? ` (${String(run.failure_code)})` : ""}`);
|
|
15191
15365
|
});
|
|
15192
15366
|
return;
|
|
@@ -15211,12 +15385,12 @@ async function request2(url, init, doFetch) {
|
|
|
15211
15385
|
let body = {};
|
|
15212
15386
|
try {
|
|
15213
15387
|
const parsed = text4 ? JSON.parse(text4) : {};
|
|
15214
|
-
body =
|
|
15388
|
+
body = record11(parsed) ? parsed : { value: parsed };
|
|
15215
15389
|
} catch {
|
|
15216
15390
|
body = { message: text4.slice(0, 500) };
|
|
15217
15391
|
}
|
|
15218
15392
|
if (!response2.ok) {
|
|
15219
|
-
const error =
|
|
15393
|
+
const error = record11(body.error) ? body.error : body;
|
|
15220
15394
|
throw new Error(string(error.message) ?? string(error.code) ?? `monitor request failed (${response2.status})`);
|
|
15221
15395
|
}
|
|
15222
15396
|
return body;
|
|
@@ -15224,7 +15398,7 @@ async function request2(url, init, doFetch) {
|
|
|
15224
15398
|
function printRead(action2, appId, env, result, out) {
|
|
15225
15399
|
if (action2 === "status") {
|
|
15226
15400
|
out.log(`monitor status ${appId}/${env}: ${String(result.overall ?? (result.configured === false ? "not configured" : "unknown"))}`);
|
|
15227
|
-
const slos = Array.isArray(result.slos) ? result.slos.filter(
|
|
15401
|
+
const slos = Array.isArray(result.slos) ? result.slos.filter(record11) : [];
|
|
15228
15402
|
for (const slo of slos) out.log(`slo ${String(slo.id)} ${String(slo.state)} ${percent(slo.observed)} observed ${percent(slo.budgetRemaining)} budget remaining`);
|
|
15229
15403
|
const incidents = Array.isArray(result.openIncidents) ? result.openIncidents.length : 0;
|
|
15230
15404
|
const gaps = Array.isArray(result.monitoringGaps) ? result.monitoringGaps.length : 0;
|
|
@@ -15233,20 +15407,20 @@ function printRead(action2, appId, env, result, out) {
|
|
|
15233
15407
|
return;
|
|
15234
15408
|
}
|
|
15235
15409
|
if (action2 === "incidents") {
|
|
15236
|
-
const incidents = Array.isArray(result.incidents) ? result.incidents.filter(
|
|
15410
|
+
const incidents = Array.isArray(result.incidents) ? result.incidents.filter(record11) : [];
|
|
15237
15411
|
out.log(`monitor incidents ${appId}/${env}: ${incidents.length}`);
|
|
15238
15412
|
for (const incident2 of incidents) out.log(`${String(incident2.state)} ${String(incident2.kind)} ${String(incident2.slo_id)} ${new Date(Number(incident2.opened_at)).toISOString()}`);
|
|
15239
15413
|
return;
|
|
15240
15414
|
}
|
|
15241
15415
|
out.log(`monitor report ${appId}/${env}: ${String(result.period)} ${String(result.overall)}`);
|
|
15242
|
-
const probes = Array.isArray(result.probes) ? result.probes.filter(
|
|
15416
|
+
const probes = Array.isArray(result.probes) ? result.probes.filter(record11) : [];
|
|
15243
15417
|
for (const probe of probes) out.log(`probe ${String(probe.id)} ${Number(probe.good)} good ${Number(probe.bad)} bad ${Number(probe.unknown)} unknown`);
|
|
15244
15418
|
}
|
|
15245
15419
|
function emit3(value2, json, out, human) {
|
|
15246
15420
|
if (json) out.log(JSON.stringify(value2, null, 2));
|
|
15247
15421
|
else human();
|
|
15248
15422
|
}
|
|
15249
|
-
function
|
|
15423
|
+
function record11(value2) {
|
|
15250
15424
|
return value2 !== null && typeof value2 === "object" && !Array.isArray(value2);
|
|
15251
15425
|
}
|
|
15252
15426
|
function string(value2) {
|
|
@@ -15814,6 +15988,139 @@ var init_provision = __esm({
|
|
|
15814
15988
|
}
|
|
15815
15989
|
});
|
|
15816
15990
|
|
|
15991
|
+
// src/security-command-context.ts
|
|
15992
|
+
async function hostedSecurityContext(parsed, dependencies) {
|
|
15993
|
+
const configPath = stringOpt(parsed.options.config) ?? "odla.config.mjs";
|
|
15994
|
+
const cfg = await loadProjectConfig(configPath);
|
|
15995
|
+
const env = stringOpt(parsed.options.env) ?? (cfg.envs.includes("dev") ? "dev" : cfg.envs[0]);
|
|
15996
|
+
if (!env || !cfg.envs.includes(env)) {
|
|
15997
|
+
throw new Error(`env "${env ?? ""}" is not declared in ${configPath}`);
|
|
15998
|
+
}
|
|
15999
|
+
const platform = platformAudience(stringOpt(parsed.options.platform) ?? cfg.platformUrl);
|
|
16000
|
+
if (platformAudience(cfg.platformUrl) !== platform) {
|
|
16001
|
+
throw new Error("--platform cannot reuse a project developer token from another platform; update odla.config.mjs and authenticate there");
|
|
16002
|
+
}
|
|
16003
|
+
const doFetch = dependencies.fetch ?? fetch;
|
|
16004
|
+
const stdout = dependencies.stdout ?? console;
|
|
16005
|
+
const open = parsed.options.open === false ? false : parsed.options.open === true ? true : void 0;
|
|
16006
|
+
const token = await getDeveloperToken(
|
|
16007
|
+
cfg,
|
|
16008
|
+
{ configPath, email: stringOpt(parsed.options.email), open, openApprovalUrl: dependencies.openUrl },
|
|
16009
|
+
doFetch,
|
|
16010
|
+
stdout,
|
|
16011
|
+
{ optionalProjectCapabilities: ["app.manage"] }
|
|
16012
|
+
);
|
|
16013
|
+
return { platform, token, appId: cfg.app.id, env, fetch: doFetch, stdout };
|
|
16014
|
+
}
|
|
16015
|
+
function requiredSecurityPositional(parsed, index, label) {
|
|
16016
|
+
const value2 = parsed.positionals[index];
|
|
16017
|
+
if (!value2) throw new Error(`${label} is required`);
|
|
16018
|
+
return value2;
|
|
16019
|
+
}
|
|
16020
|
+
function securityProfile(value2) {
|
|
16021
|
+
if (value2 === void 0) return void 0;
|
|
16022
|
+
if (value2 === "odla" || value2 === "cloudflare-app" || value2 === "generic") return value2;
|
|
16023
|
+
throw new Error("--profile must be odla, cloudflare-app, or generic");
|
|
16024
|
+
}
|
|
16025
|
+
var init_security_command_context = __esm({
|
|
16026
|
+
"src/security-command-context.ts"() {
|
|
16027
|
+
"use strict";
|
|
16028
|
+
init_cjs_shims();
|
|
16029
|
+
init_argv();
|
|
16030
|
+
init_config();
|
|
16031
|
+
init_token();
|
|
16032
|
+
}
|
|
16033
|
+
});
|
|
16034
|
+
|
|
16035
|
+
// src/promotion-command.ts
|
|
16036
|
+
async function promotionCommand(parsed, dependencies) {
|
|
16037
|
+
const action2 = parsed.positionals[1];
|
|
16038
|
+
if (!action2 || !["plan", "inspect", "status", "apply", "rollback", "next", "record", "cancel"].includes(action2)) rejectWord(["promotion"], action2);
|
|
16039
|
+
assertArgs(parsed, ["config", "env", "platform", "email", "open", "json", "file", "approval", "idempotency-key"], 5);
|
|
16040
|
+
const context = await hostedSecurityContext(parsed, dependencies);
|
|
16041
|
+
const client = (0, import_apps14.createAppsClient)({
|
|
16042
|
+
token: context.token,
|
|
16043
|
+
fetcher: { fetch: (request3, init) => {
|
|
16044
|
+
const internal = new URL(typeof request3 === "string" ? request3 : request3.url);
|
|
16045
|
+
return context.fetch(`${context.platform}${internal.pathname}${internal.search}`, init);
|
|
16046
|
+
} }
|
|
16047
|
+
});
|
|
16048
|
+
const json = parsed.options.json === true;
|
|
16049
|
+
if (action2 === "plan") {
|
|
16050
|
+
if (parsed.positionals[2]) throw new Error("promotion plan takes --file, not a positional plan id");
|
|
16051
|
+
const file = stringOpt(parsed.options.file);
|
|
16052
|
+
if (!file) throw new Error("--file <promotion-plan.json> is required");
|
|
16053
|
+
const source = JSON.parse(await (0, import_promises12.readFile)(file, "utf8"));
|
|
16054
|
+
const plan2 = await client.createPromotionReleasePlan(context.appId, source);
|
|
16055
|
+
render(plan2, json, context.stdout);
|
|
16056
|
+
return;
|
|
16057
|
+
}
|
|
16058
|
+
const planId = requiredSecurityPositional(parsed, 2, "plan id");
|
|
16059
|
+
if (action2 === "inspect") {
|
|
16060
|
+
if (parsed.positionals[3]) throw new Error("promotion inspect takes only a plan id");
|
|
16061
|
+
const plan2 = await client.getPromotionReleasePlan(context.appId, planId);
|
|
16062
|
+
if (!plan2) throw new Error(`promotion release ${planId} was not found`);
|
|
16063
|
+
render(plan2, json, context.stdout);
|
|
16064
|
+
return;
|
|
16065
|
+
}
|
|
16066
|
+
if (action2 === "status") {
|
|
16067
|
+
if (parsed.positionals[3]) throw new Error("promotion status takes only a plan id");
|
|
16068
|
+
const status = await client.getPromotionReleaseStatus(context.appId, planId);
|
|
16069
|
+
if (!status) throw new Error(`promotion release ${planId} was not found`);
|
|
16070
|
+
render(status, json, context.stdout);
|
|
16071
|
+
return;
|
|
16072
|
+
}
|
|
16073
|
+
if (action2 === "next" || action2 === "cancel" || action2 === "record") {
|
|
16074
|
+
const operationId = requiredSecurityPositional(parsed, 3, "operation id");
|
|
16075
|
+
if (action2 === "next") {
|
|
16076
|
+
if (parsed.positionals[4]) throw new Error("promotion next takes only plan and operation ids");
|
|
16077
|
+
render(await client.claimPromotionReleaseWork(context.appId, planId, operationId), json, context.stdout);
|
|
16078
|
+
return;
|
|
16079
|
+
}
|
|
16080
|
+
if (action2 === "cancel") {
|
|
16081
|
+
if (parsed.positionals[4]) throw new Error("promotion cancel takes only plan and operation ids");
|
|
16082
|
+
render(await client.cancelPromotionReleaseOperation(context.appId, planId, operationId), json, context.stdout);
|
|
16083
|
+
return;
|
|
16084
|
+
}
|
|
16085
|
+
const stepId = requiredSecurityPositional(parsed, 4, "step id");
|
|
16086
|
+
const file = stringOpt(parsed.options.file);
|
|
16087
|
+
if (!file) throw new Error("--file <step-receipt.json> is required");
|
|
16088
|
+
const receipt = JSON.parse(await (0, import_promises12.readFile)(file, "utf8"));
|
|
16089
|
+
render(await client.recordPromotionReleaseWork(context.appId, planId, operationId, stepId, receipt), json, context.stdout);
|
|
16090
|
+
return;
|
|
16091
|
+
}
|
|
16092
|
+
const approvalId = stringOpt(parsed.options.approval);
|
|
16093
|
+
if (parsed.positionals[3]) throw new Error(`promotion ${action2} takes only a plan id`);
|
|
16094
|
+
if (!approvalId) throw new Error(`--approval <approval-id> is required for promotion ${action2}`);
|
|
16095
|
+
const plan = await client.getPromotionReleasePlan(context.appId, planId);
|
|
16096
|
+
if (!plan) throw new Error(`promotion release ${planId} was not found`);
|
|
16097
|
+
if (plan.state !== "reviewable") throw new Error(`promotion release is ${plan.state}: ${plan.blockers.join("; ")}`);
|
|
16098
|
+
const operationAction = action2;
|
|
16099
|
+
const operation = await client.requestPromotionReleaseOperation(context.appId, planId, operationAction, {
|
|
16100
|
+
approvalId,
|
|
16101
|
+
planDigest: plan.planDigest,
|
|
16102
|
+
targetSetDigest: plan.targetSetDigest,
|
|
16103
|
+
idempotencyKey: stringOpt(parsed.options["idempotency-key"]) ?? `${operationAction}:${planId}`
|
|
16104
|
+
});
|
|
16105
|
+
render(operation, json, context.stdout);
|
|
16106
|
+
}
|
|
16107
|
+
var import_promises12, import_apps14, render;
|
|
16108
|
+
var init_promotion_command = __esm({
|
|
16109
|
+
"src/promotion-command.ts"() {
|
|
16110
|
+
"use strict";
|
|
16111
|
+
init_cjs_shims();
|
|
16112
|
+
import_promises12 = require("fs/promises");
|
|
16113
|
+
import_apps14 = require("@odla-ai/apps");
|
|
16114
|
+
init_argv();
|
|
16115
|
+
init_security_command_context();
|
|
16116
|
+
init_surface();
|
|
16117
|
+
render = (value2, json, out) => {
|
|
16118
|
+
if (json) out.log(JSON.stringify(value2));
|
|
16119
|
+
else out.log(JSON.stringify(value2, null, 2));
|
|
16120
|
+
};
|
|
16121
|
+
}
|
|
16122
|
+
});
|
|
16123
|
+
|
|
15817
16124
|
// src/record.ts
|
|
15818
16125
|
function recordInvocation(parsed) {
|
|
15819
16126
|
const file = import_node_process19.default.env.ODLA_CLI_RECORD;
|
|
@@ -15845,7 +16152,7 @@ function advisoryCollectingFetch(inner, sink) {
|
|
|
15845
16152
|
return (async (input, init) => {
|
|
15846
16153
|
const response2 = await inner(input, init);
|
|
15847
16154
|
try {
|
|
15848
|
-
sink.push(...(0,
|
|
16155
|
+
sink.push(...(0, import_apps15.parseAdvisories)(response2));
|
|
15849
16156
|
} catch {
|
|
15850
16157
|
}
|
|
15851
16158
|
return response2;
|
|
@@ -15864,15 +16171,15 @@ function renderAdvisories(out, advisories, env = process.env) {
|
|
|
15864
16171
|
const key = `${advisory.code}:${advisory.message}`;
|
|
15865
16172
|
if (seen.has(key)) continue;
|
|
15866
16173
|
seen.add(key);
|
|
15867
|
-
out.error((0,
|
|
16174
|
+
out.error((0, import_apps15.formatAdvisory)(advisory));
|
|
15868
16175
|
}
|
|
15869
16176
|
}
|
|
15870
|
-
var
|
|
16177
|
+
var import_apps15, superseded;
|
|
15871
16178
|
var init_advisory_output = __esm({
|
|
15872
16179
|
"src/advisory-output.ts"() {
|
|
15873
16180
|
"use strict";
|
|
15874
16181
|
init_cjs_shims();
|
|
15875
|
-
|
|
16182
|
+
import_apps15 = require("@odla-ai/apps");
|
|
15876
16183
|
superseded = /* @__PURE__ */ new Set();
|
|
15877
16184
|
}
|
|
15878
16185
|
});
|
|
@@ -16131,7 +16438,7 @@ async function bySlug(ctx, slug) {
|
|
|
16131
16438
|
"GET",
|
|
16132
16439
|
`/runbook?app=${encodeURIComponent(ctx.appId)}&slug=${encodeURIComponent(slug)}&limit=1`
|
|
16133
16440
|
);
|
|
16134
|
-
const filtered = page2.records.find((
|
|
16441
|
+
const filtered = page2.records.find((record12) => record12.slug === slug);
|
|
16135
16442
|
if (filtered) return filtered;
|
|
16136
16443
|
const limit = 100;
|
|
16137
16444
|
for (let offset = 0; ; offset += limit) {
|
|
@@ -16140,7 +16447,7 @@ async function bySlug(ctx, slug) {
|
|
|
16140
16447
|
"GET",
|
|
16141
16448
|
`/runbook?app=${encodeURIComponent(ctx.appId)}&limit=${limit}&offset=${offset}`
|
|
16142
16449
|
);
|
|
16143
|
-
const found = fallback.records.find((
|
|
16450
|
+
const found = fallback.records.find((record12) => record12.slug === slug);
|
|
16144
16451
|
if (found) return found;
|
|
16145
16452
|
if (!fallback.records.length || offset + fallback.records.length >= fallback.total) break;
|
|
16146
16453
|
}
|
|
@@ -17025,50 +17332,6 @@ var init_runbook_command = __esm({
|
|
|
17025
17332
|
}
|
|
17026
17333
|
});
|
|
17027
17334
|
|
|
17028
|
-
// src/security-command-context.ts
|
|
17029
|
-
async function hostedSecurityContext(parsed, dependencies) {
|
|
17030
|
-
const configPath = stringOpt(parsed.options.config) ?? "odla.config.mjs";
|
|
17031
|
-
const cfg = await loadProjectConfig(configPath);
|
|
17032
|
-
const env = stringOpt(parsed.options.env) ?? (cfg.envs.includes("dev") ? "dev" : cfg.envs[0]);
|
|
17033
|
-
if (!env || !cfg.envs.includes(env)) {
|
|
17034
|
-
throw new Error(`env "${env ?? ""}" is not declared in ${configPath}`);
|
|
17035
|
-
}
|
|
17036
|
-
const platform = platformAudience(stringOpt(parsed.options.platform) ?? cfg.platformUrl);
|
|
17037
|
-
if (platformAudience(cfg.platformUrl) !== platform) {
|
|
17038
|
-
throw new Error("--platform cannot reuse a project developer token from another platform; update odla.config.mjs and authenticate there");
|
|
17039
|
-
}
|
|
17040
|
-
const doFetch = dependencies.fetch ?? fetch;
|
|
17041
|
-
const stdout = dependencies.stdout ?? console;
|
|
17042
|
-
const open = parsed.options.open === false ? false : parsed.options.open === true ? true : void 0;
|
|
17043
|
-
const token = await getDeveloperToken(
|
|
17044
|
-
cfg,
|
|
17045
|
-
{ configPath, email: stringOpt(parsed.options.email), open, openApprovalUrl: dependencies.openUrl },
|
|
17046
|
-
doFetch,
|
|
17047
|
-
stdout,
|
|
17048
|
-
{ optionalProjectCapabilities: ["app.manage"] }
|
|
17049
|
-
);
|
|
17050
|
-
return { platform, token, appId: cfg.app.id, env, fetch: doFetch, stdout };
|
|
17051
|
-
}
|
|
17052
|
-
function requiredSecurityPositional(parsed, index, label) {
|
|
17053
|
-
const value2 = parsed.positionals[index];
|
|
17054
|
-
if (!value2) throw new Error(`${label} is required`);
|
|
17055
|
-
return value2;
|
|
17056
|
-
}
|
|
17057
|
-
function securityProfile(value2) {
|
|
17058
|
-
if (value2 === void 0) return void 0;
|
|
17059
|
-
if (value2 === "odla" || value2 === "cloudflare-app" || value2 === "generic") return value2;
|
|
17060
|
-
throw new Error("--profile must be odla, cloudflare-app, or generic");
|
|
17061
|
-
}
|
|
17062
|
-
var init_security_command_context = __esm({
|
|
17063
|
-
"src/security-command-context.ts"() {
|
|
17064
|
-
"use strict";
|
|
17065
|
-
init_cjs_shims();
|
|
17066
|
-
init_argv();
|
|
17067
|
-
init_config();
|
|
17068
|
-
init_token();
|
|
17069
|
-
}
|
|
17070
|
-
});
|
|
17071
|
-
|
|
17072
17335
|
// src/security-command-output.ts
|
|
17073
17336
|
function printHostedSecurityPlan(out, plan, appId) {
|
|
17074
17337
|
out.log(`Hosted security plan for ${appId}/${plan.env}: ${plan.ready ? "ready" : "not ready"}`);
|
|
@@ -17860,6 +18123,10 @@ async function dispatchCli(argv2, dependencies) {
|
|
|
17860
18123
|
await securityCommand(parsed, runtime);
|
|
17861
18124
|
return;
|
|
17862
18125
|
}
|
|
18126
|
+
if (command === "promotion") {
|
|
18127
|
+
await promotionCommand(parsed, runtime);
|
|
18128
|
+
return;
|
|
18129
|
+
}
|
|
17863
18130
|
if (command === "brand") {
|
|
17864
18131
|
await brandCommand(parsed, runtime);
|
|
17865
18132
|
return;
|
|
@@ -17989,6 +18256,7 @@ var init_cli = __esm({
|
|
|
17989
18256
|
init_o11y_command();
|
|
17990
18257
|
init_monitor_command();
|
|
17991
18258
|
init_provision();
|
|
18259
|
+
init_promotion_command();
|
|
17992
18260
|
init_record();
|
|
17993
18261
|
init_advisory_output();
|
|
17994
18262
|
init_cached_credential();
|