@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.
@@ -1252,6 +1252,7 @@ var COMMAND_SURFACE = {
1252
1252
  watch: {}
1253
1253
  },
1254
1254
  provision: {},
1255
+ promotion: { plan: {}, inspect: {}, status: {}, apply: {}, rollback: {}, next: {}, record: {}, cancel: {} },
1255
1256
  runbook: {
1256
1257
  ask: {},
1257
1258
  search: {},
@@ -3557,9 +3558,9 @@ function canonicalValue(value2) {
3557
3558
  }
3558
3559
  if (Array.isArray(value2)) return value2.map(canonicalValue);
3559
3560
  if (value2 && typeof value2 === "object") {
3560
- const record11 = value2;
3561
+ const record12 = value2;
3561
3562
  return Object.fromEntries(
3562
- Object.keys(record11).filter((key) => record11[key] !== void 0).sort().map((key) => [key, canonicalValue(record11[key])])
3563
+ Object.keys(record12).filter((key) => record12[key] !== void 0).sort().map((key) => [key, canonicalValue(record12[key])])
3563
3564
  );
3564
3565
  }
3565
3566
  throw new TypeError("canonical JSON rejects unsupported values");
@@ -5943,10 +5944,10 @@ import { existsSync as existsSync10 } from "fs";
5943
5944
  import { cpus, hostname, totalmem } from "os";
5944
5945
  import { resolve as resolve11 } from "path";
5945
5946
 
5946
- // ../harness/dist/chunk-RXNHCGWE.js
5947
+ // ../harness/dist/chunk-U324RQ4N.js
5947
5948
  var HARNESS_PROTOCOL_VERSION = 1;
5948
5949
 
5949
- // ../harness/dist/chunk-CR6RE3A2.js
5950
+ // ../harness/dist/chunk-5LRYJKUI.js
5950
5951
  import { execFile, spawn as spawn3 } from "child_process";
5951
5952
  import { constants } from "fs";
5952
5953
  import { access } from "fs/promises";
@@ -6114,8 +6115,8 @@ async function materializeGitTree(source, commitSha, options = {}) {
6114
6115
  const maxFiles = options.maxFiles ?? 2e4;
6115
6116
  const maxBytes = options.maxBytes ?? 512 * 1024 * 1024;
6116
6117
  const inventory = (await gitOutput(sourceDir, ["ls-tree", "-rz", commitSha], 16 * 1024 * 1024)).toString("utf8").split("\0").filter(Boolean);
6117
- const entries = inventory.flatMap((record11) => {
6118
- const match = /^(100644|100755) blob ([0-9a-f]{40,64})\t([\s\S]+)$/.exec(record11);
6118
+ const entries = inventory.flatMap((record12) => {
6119
+ const match = /^(100644|100755) blob ([0-9a-f]{40,64})\t([\s\S]+)$/.exec(record12);
6119
6120
  return match && allowedWorkspacePath(match[3]) ? [{ mode: match[1], hash: match[2], path: match[3] }] : [];
6120
6121
  });
6121
6122
  if (entries.length > maxFiles) throw new Error(`workspace exceeds ${maxFiles} files`);
@@ -6319,7 +6320,165 @@ async function stageWorkspacePair(baselineSource, workspaceSource, options = {})
6319
6320
  }
6320
6321
  }
6321
6322
 
6322
- // ../harness/dist/chunk-J7XU5QB7.js
6323
+ // ../harness/dist/chunk-FAN2R3GW.js
6324
+ var text3 = (value2, maximum) => {
6325
+ if (typeof value2 !== "string") return void 0;
6326
+ const bounded = value2.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g, " ").trim();
6327
+ return bounded ? bounded.slice(0, maximum) : void 0;
6328
+ };
6329
+ var integer = (value2) => Number.isSafeInteger(value2) && Number(value2) >= 0 ? Number(value2) : void 0;
6330
+ var record5 = (value2) => value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : void 0;
6331
+ var excerpt = (value2, tail = false) => {
6332
+ if (typeof value2 !== "string") return void 0;
6333
+ const safe = value2.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g, " ");
6334
+ const source = (tail ? safe.slice(-1e4) : safe.slice(0, 1e4)).trim();
6335
+ if (!source) return void 0;
6336
+ const lines = source.split("\n").filter((line2) => line2.trim()).map((line2) => line2.slice(0, 240));
6337
+ const selected = tail ? lines.slice(-10) : lines.slice(0, 10);
6338
+ return text3(selected.join("\n"), 2400);
6339
+ };
6340
+ var paths = (value2) => {
6341
+ if (!Array.isArray(value2)) return void 0;
6342
+ const items = value2.flatMap((item) => {
6343
+ const path = text3(item, 1024);
6344
+ return path ? [path] : [];
6345
+ }).slice(0, 12);
6346
+ return items.length ? items : void 0;
6347
+ };
6348
+ function patchStats(value2) {
6349
+ if (typeof value2 !== "string") return {};
6350
+ let additions = 0;
6351
+ let deletions = 0;
6352
+ for (const line2 of value2.slice(0, 262144).split("\n")) {
6353
+ if (line2.startsWith("+++") || line2.startsWith("---")) continue;
6354
+ if (line2.startsWith("+")) additions += 1;
6355
+ else if (line2.startsWith("-")) deletions += 1;
6356
+ }
6357
+ return { ...additions ? { additions } : {}, ...deletions ? { deletions } : {} };
6358
+ }
6359
+ function searchResults(value2) {
6360
+ if (typeof value2 !== "string") return void 0;
6361
+ const results = value2.split("\n").flatMap((line2) => {
6362
+ const match = /^([^:\n]{1,1024}):(\d+):\s?(.*)$/.exec(line2);
6363
+ if (!match) return [];
6364
+ const lineNumber = Number(match[2]);
6365
+ const itemText = text3(match[3], 240);
6366
+ if (!Number.isSafeInteger(lineNumber) || lineNumber < 1) return [];
6367
+ return [{ path: match[1], line: lineNumber, ...itemText ? { text: itemText } : {} }];
6368
+ }).slice(0, 5);
6369
+ return results.length ? results : void 0;
6370
+ }
6371
+ function codeToolRequestPresentation(request3) {
6372
+ const input = request3.input;
6373
+ if (request3.tool === "sandbox.read") {
6374
+ const path = text3(input.path, 1024);
6375
+ if (!path) return void 0;
6376
+ const startLine = integer(input.startLine);
6377
+ const endLine = integer(input.endLine);
6378
+ return { kind: "read", path, ...startLine ? { startLine } : {}, ...endLine ? { endLine } : {} };
6379
+ }
6380
+ if (request3.tool === "sandbox.list") {
6381
+ const scope = text3(input.prefix, 1024);
6382
+ return { kind: "list", ...scope ? { scope } : {} };
6383
+ }
6384
+ if (request3.tool === "sandbox.search" || request3.tool === "sandbox.overview" || request3.tool === "sandbox.where_is" || request3.tool === "sandbox.who_imports" || request3.tool === "sandbox.who_touches") {
6385
+ const query = text3(input.query, 512);
6386
+ const scope = request3.tool === "sandbox.search" ? text3(input.prefix, 1024) : void 0;
6387
+ if (request3.tool === "sandbox.search" && !query) return void 0;
6388
+ return { kind: "query", ...query ? { query } : {}, ...scope ? { scope } : {} };
6389
+ }
6390
+ if (request3.tool === "sandbox.apply_patch") {
6391
+ return { kind: "patch", ...patchStats(input.patch) };
6392
+ }
6393
+ const recipeId = text3(input.recipeId, 120);
6394
+ return recipeId ? { kind: "recipe", recipeId } : void 0;
6395
+ }
6396
+ function codeToolResultPresentation(request3, response2) {
6397
+ const started = codeToolRequestPresentation(request3);
6398
+ if (!started || !response2.ok) return started;
6399
+ const details = record5(response2.details);
6400
+ if (started.kind === "read") {
6401
+ return {
6402
+ ...started,
6403
+ ...integer(details?.startLine) ? { startLine: integer(details?.startLine) } : {},
6404
+ ...integer(details?.endLine) ? { endLine: integer(details?.endLine) } : {},
6405
+ ...excerpt(response2.content) ? { excerpt: excerpt(response2.content) } : {}
6406
+ };
6407
+ }
6408
+ if (started.kind === "list") {
6409
+ const listed = response2.content.split("\n").filter((line2) => line2 && !line2.startsWith("\u2026") && !line2.startsWith("Workspace ")).map((line2) => text3(line2, 1024)).filter((line2) => Boolean(line2)).slice(0, 8);
6410
+ return {
6411
+ ...started,
6412
+ ...integer(details?.count) !== void 0 ? { count: integer(details?.count) } : {},
6413
+ ...listed.length ? { paths: listed } : {}
6414
+ };
6415
+ }
6416
+ if (started.kind === "query") {
6417
+ const results = request3.tool === "sandbox.search" ? searchResults(response2.content) : void 0;
6418
+ const resultExcerpt = request3.tool === "sandbox.search" ? void 0 : excerpt(response2.content);
6419
+ return {
6420
+ ...started,
6421
+ ...integer(details?.count) !== void 0 ? { count: integer(details?.count) } : {},
6422
+ ...results ? { results } : {},
6423
+ ...resultExcerpt ? { excerpt: resultExcerpt } : {}
6424
+ };
6425
+ }
6426
+ if (started.kind === "patch") {
6427
+ return { ...started, ...paths(details?.paths) ? { paths: paths(details?.paths) } : {} };
6428
+ }
6429
+ const output = response2.content.replace(/^Recipe [^\n]*\.?\s*/u, "");
6430
+ return {
6431
+ ...started,
6432
+ ...integer(details?.exitCode) !== void 0 ? { exitCode: integer(details?.exitCode) } : {},
6433
+ ...typeof details?.timedOut === "boolean" ? { timedOut: details.timedOut } : {},
6434
+ ...typeof details?.outputLimitExceeded === "boolean" ? { outputLimitExceeded: details.outputLimitExceeded } : {},
6435
+ ...excerpt(output, true) ? { excerpt: excerpt(output, true) } : {}
6436
+ };
6437
+ }
6438
+ var MAX_FAILURE_REASON = 240;
6439
+ function toolFailureReason(response2) {
6440
+ if (response2.ok) return void 0;
6441
+ const supplied = response2.details?.failureReason;
6442
+ const reason = typeof supplied === "string" && supplied || DEFAULT_FAILURE_REASON[response2.content] || response2.content || "tool request failed; inspect the tool input and workspace state";
6443
+ return reason.slice(0, MAX_FAILURE_REASON);
6444
+ }
6445
+ var DEFAULT_FAILURE_REASON = {
6446
+ "tool denied by CaMeL policy": "tool denied by CaMeL policy",
6447
+ "review sessions are read-only": "review session is read-only; workspace changes are not permitted"
6448
+ };
6449
+ function observedBroker(input) {
6450
+ const now = input.now ?? Date.now;
6451
+ return {
6452
+ execute: async (context, request3) => {
6453
+ const startedAt = now();
6454
+ const operationId = input.operationIdFor(request3.requestId);
6455
+ const startedPresentation = codeToolRequestPresentation(request3);
6456
+ await input.emit({
6457
+ type: "tool",
6458
+ phase: "started",
6459
+ tool: request3.tool,
6460
+ operationId,
6461
+ ...startedPresentation ? { presentation: startedPresentation } : {}
6462
+ });
6463
+ const response2 = await input.broker.execute(context, request3);
6464
+ const completedPresentation = codeToolResultPresentation(request3, response2);
6465
+ const failureReason = toolFailureReason(response2);
6466
+ await input.emit({
6467
+ type: "tool",
6468
+ phase: "completed",
6469
+ tool: request3.tool,
6470
+ ok: response2.ok,
6471
+ durationMs: now() - startedAt,
6472
+ operationId,
6473
+ ...failureReason ? { failureReason } : {},
6474
+ ...completedPresentation ? { presentation: completedPresentation } : {}
6475
+ });
6476
+ return response2;
6477
+ }
6478
+ };
6479
+ }
6480
+
6481
+ // ../harness/dist/chunk-Q4NL5XO3.js
6323
6482
  import { createHash as createHash3 } from "crypto";
6324
6483
  import { readFile as readFile2, readdir as readdir2 } from "fs/promises";
6325
6484
  import { relative as relative4, resolve as resolve10 } from "path";
@@ -6363,8 +6522,8 @@ function normalize(value2) {
6363
6522
  if (Array.isArray(value2)) return value2.map(normalize);
6364
6523
  if (value2 instanceof Uint8Array) return { $bytes: [...value2] };
6365
6524
  if (typeof value2 === "object") {
6366
- const record11 = value2;
6367
- return Object.fromEntries(Object.keys(record11).filter((key) => record11[key] !== void 0).sort().map((key) => [key, normalize(record11[key])]));
6525
+ const record12 = value2;
6526
+ return Object.fromEntries(Object.keys(record12).filter((key) => record12[key] !== void 0).sort().map((key) => [key, normalize(record12[key])]));
6368
6527
  }
6369
6528
  throw new CamelError("state_conflict", "Canonical JSON rejects unsupported values.");
6370
6529
  }
@@ -6656,7 +6815,7 @@ function validateSnapshot(snapshot, limits) {
6656
6815
  }
6657
6816
  }
6658
6817
 
6659
- // ../harness/dist/chunk-J7XU5QB7.js
6818
+ // ../harness/dist/chunk-Q4NL5XO3.js
6660
6819
  import { spawn as spawn4 } from "child_process";
6661
6820
  import { lstat as lstat2 } from "fs/promises";
6662
6821
  import { resolve as resolve23, sep as sep3 } from "path";
@@ -6963,7 +7122,7 @@ function looksLikeDestination(value2) {
6963
7122
  return /^(?:[a-z][a-z0-9+.-]*:\/\/|\/|\\\\)/i.test(text4) || /^[\w.-]+\.[a-z]{2,}(?:[/:]|$)/i.test(text4);
6964
7123
  }
6965
7124
 
6966
- // ../harness/dist/chunk-J7XU5QB7.js
7125
+ // ../harness/dist/chunk-Q4NL5XO3.js
6967
7126
  import { readFile as readFile4, stat as stat2 } from "fs/promises";
6968
7127
  import { readFile as readFile3 } from "fs/promises";
6969
7128
  import { join as join33 } from "path";
@@ -7231,7 +7390,7 @@ async function buildCodeGraph(input) {
7231
7390
  return builder.build();
7232
7391
  }
7233
7392
 
7234
- // ../harness/dist/chunk-J7XU5QB7.js
7393
+ // ../harness/dist/chunk-Q4NL5XO3.js
7235
7394
  import { createHash as createHash32 } from "crypto";
7236
7395
  async function digestStagedWorkspace(root, limits) {
7237
7396
  const files = [];
@@ -7290,7 +7449,7 @@ function createCodeRuntimeControlClient(options) {
7290
7449
  }
7291
7450
  const value2 = await response2.json().catch(() => null);
7292
7451
  if (!response2.ok) {
7293
- const problem = record5(record5(value2)?.error);
7452
+ const problem = record6(record6(value2)?.error);
7294
7453
  throw new CodeRuntimeControlError(
7295
7454
  typeof problem?.message === "string" ? problem.message : `Code runtime request failed (${response2.status})`,
7296
7455
  response2.status,
@@ -7311,12 +7470,12 @@ function createCodeRuntimeControlClient(options) {
7311
7470
  await call4(`/registry/code/runtime/sessions/${validSessionId(sessionId)}/source`, {})
7312
7471
  ),
7313
7472
  infer: async (sessionId, inference) => {
7314
- const value2 = record5(await call4(
7473
+ const value2 = record6(await call4(
7315
7474
  `/registry/code/runtime/sessions/${validSessionId(sessionId)}/inference`,
7316
7475
  inference,
7317
7476
  modelRequestTimeoutMs
7318
7477
  ));
7319
- if (!value2 || value2.requestId !== inference.requestId || !record5(value2.response) || !record5(value2.receipt)) {
7478
+ if (!value2 || value2.requestId !== inference.requestId || !record6(value2.response) || !record6(value2.receipt)) {
7320
7479
  throw new CodeRuntimeControlError("invalid Code inference response", 502, "invalid_response");
7321
7480
  }
7322
7481
  return value2;
@@ -7496,12 +7655,12 @@ function validateHeartbeat(version, capabilities) {
7496
7655
  }
7497
7656
  }
7498
7657
  function parseSnapshot(value2) {
7499
- const root = record5(value2);
7500
- const host = record5(root?.host);
7658
+ const root = record6(value2);
7659
+ const host = record6(root?.host);
7501
7660
  if (!host || typeof host.hostId !== "string" || typeof host.runtimeVersion !== "string" || !Number.isSafeInteger(host.lastSeenAt) || host.revokedAt !== null || !Array.isArray(root?.bindings) || root.bindings.length > 1024 || !Array.isArray(root?.commands) || root.commands.length > 64) throw invalid("heartbeat");
7502
7661
  const bindingIds = /* @__PURE__ */ new Set();
7503
7662
  const bindings = root.bindings.map((item) => {
7504
- const binding = record5(item);
7663
+ const binding = record6(item);
7505
7664
  if (!binding || typeof binding.bindingId !== "string" || typeof binding.appId !== "string" || binding.env !== "dev" && binding.env !== "prod" || typeof binding.offerId !== "string" || binding.hostId !== host.hostId || !Number.isSafeInteger(binding.generation) || Number(binding.generation) < 1 || binding.revokedAt !== null || bindingIds.has(binding.bindingId)) {
7506
7665
  throw invalid("binding");
7507
7666
  }
@@ -7511,10 +7670,10 @@ function parseSnapshot(value2) {
7511
7670
  const commandIds = /* @__PURE__ */ new Set();
7512
7671
  const commandSequences = /* @__PURE__ */ new Set();
7513
7672
  const commands = root.commands.map((item) => {
7514
- const command = record5(item);
7673
+ const command = record6(item);
7515
7674
  const binding = bindings.find((candidate) => candidate.bindingId === command?.bindingId);
7516
7675
  const sequenceKey = `${String(command?.instanceId)}:${String(command?.sequence)}`;
7517
- if (!command || typeof command.commandId !== "string" || !/^ccmd_[0-9a-f]{32}$/.test(command.commandId) || typeof command.instanceId !== "string" || typeof command.sessionId !== "string" || !/^csess_[0-9a-f]{32}$/.test(command.sessionId) || typeof command.appId !== "string" || command.env !== "dev" && command.env !== "prod" || command.hostId !== host.hostId || !binding || binding.appId !== command.appId || binding.generation !== command.bindingGeneration || !Number.isSafeInteger(command.sequence) || Number(command.sequence) < 1 || commandIds.has(command.commandId) || commandSequences.has(sequenceKey) || !["start", "prompt", "checkpoint_stop", "resume"].includes(String(command.kind)) || !record5(command.payload) || !Number.isSafeInteger(command.createdAt)) throw invalid("command");
7676
+ if (!command || typeof command.commandId !== "string" || !/^ccmd_[0-9a-f]{32}$/.test(command.commandId) || typeof command.instanceId !== "string" || typeof command.sessionId !== "string" || !/^csess_[0-9a-f]{32}$/.test(command.sessionId) || typeof command.appId !== "string" || command.env !== "dev" && command.env !== "prod" || command.hostId !== host.hostId || !binding || binding.appId !== command.appId || binding.generation !== command.bindingGeneration || !Number.isSafeInteger(command.sequence) || Number(command.sequence) < 1 || commandIds.has(command.commandId) || commandSequences.has(sequenceKey) || !["start", "prompt", "checkpoint_stop", "resume"].includes(String(command.kind)) || !record6(command.payload) || !Number.isSafeInteger(command.createdAt)) throw invalid("command");
7518
7677
  commandIds.add(command.commandId);
7519
7678
  commandSequences.add(sequenceKey);
7520
7679
  return command;
@@ -7523,10 +7682,10 @@ function parseSnapshot(value2) {
7523
7682
  }
7524
7683
  async function parseSource(value2) {
7525
7684
  const repositoryLimits = { maximumFiles: 1e5, maximumBytes: 80 * 1024 * 1024 };
7526
- const snapshot = record5(record5(value2)?.snapshot);
7685
+ const snapshot = record6(record6(value2)?.snapshot);
7527
7686
  if (!snapshot || typeof snapshot.repository !== "string" || typeof snapshot.commitSha !== "string" || typeof snapshot.treeDigest !== "string" || !Array.isArray(snapshot.files)) throw invalid("source");
7528
7687
  const files = snapshot.files.map((value22) => {
7529
- const file = record5(value22);
7688
+ const file = record6(value22);
7530
7689
  if (!file || typeof file.path !== "string" || typeof file.content !== "string") throw invalid("source file");
7531
7690
  return { path: file.path, content: file.content };
7532
7691
  });
@@ -7535,11 +7694,11 @@ async function parseSource(value2) {
7535
7694
  const aliases = /* @__PURE__ */ new Set();
7536
7695
  const references = [];
7537
7696
  for (const item of referencesValue) {
7538
- const reference = record5(item);
7697
+ const reference = record6(item);
7539
7698
  if (!reference || typeof reference.alias !== "string" || !/^[a-z][a-z0-9-]{0,39}$/.test(reference.alias) || aliases.has(reference.alias) || reference.alias === "primary" || typeof reference.repository !== "string" || typeof reference.commitSha !== "string" || typeof reference.treeDigest !== "string" || !Array.isArray(reference.files)) throw invalid("reference source");
7540
7699
  aliases.add(reference.alias);
7541
7700
  const referenceFiles = reference.files.map((entry) => {
7542
- const file = record5(entry);
7701
+ const file = record6(entry);
7543
7702
  if (!file || typeof file.path !== "string" || typeof file.content !== "string") throw invalid("reference source file");
7544
7703
  return { path: file.path, content: file.content };
7545
7704
  });
@@ -7554,31 +7713,31 @@ async function parseSource(value2) {
7554
7713
  return { ...source, treeDigest: digest, ...references.length ? { references } : {} };
7555
7714
  }
7556
7715
  function parseReview(value2) {
7557
- const review = record5(record5(value2)?.review);
7558
- if (!review || !["approved", "rejected"].includes(String(review.verdict)) || typeof review.reviewDigest !== "string" || !/^sha256:[0-9a-f]{64}$/.test(review.reviewDigest) || typeof review.provider !== "string" || !review.provider || typeof review.model !== "string" || !review.model || !Number.isSafeInteger(review.policyVersion) || Number(review.policyVersion) < 1) throw invalid("review");
7716
+ const review = record6(record6(value2)?.review);
7717
+ if (!review || !["approved", "rejected"].includes(String(review.verdict)) || typeof review.reviewDigest !== "string" || !/^sha256:[0-9a-f]{64}$/.test(review.reviewDigest) || typeof review.provider !== "string" || !review.provider || typeof review.model !== "string" || !review.model || !Number.isSafeInteger(review.policyVersion) || Number(review.policyVersion) < 1 || !Number.isSafeInteger(review.score) || Number(review.score) < 0 || Number(review.score) > 100 || typeof review.summary !== "string" || !Array.isArray(review.findings) || review.findings.length > 12) throw invalid("review");
7559
7718
  return review;
7560
7719
  }
7561
7720
  function parseCandidate(value2) {
7562
- const candidate = record5(record5(value2)?.candidate);
7721
+ const candidate = record6(record6(value2)?.candidate);
7563
7722
  if (!candidate || typeof candidate.candidateId !== "string" || !/^ccand_[0-9a-f]{32}$/.test(candidate.candidateId) || !["submitted", "approved", "published", "failed"].includes(String(candidate.status))) {
7564
7723
  throw invalid("candidate");
7565
7724
  }
7566
7725
  return { candidateId: candidate.candidateId, status: candidate.status };
7567
7726
  }
7568
7727
  function parseCollaborationSkills(value2) {
7569
- const items = record5(value2)?.skills;
7728
+ const items = record6(value2)?.skills;
7570
7729
  if (!Array.isArray(items) || items.length > 16) throw invalid("collaboration skills");
7571
7730
  const skillNames2 = /* @__PURE__ */ new Set();
7572
7731
  const toolNames = /* @__PURE__ */ new Set();
7573
7732
  return items.map((item) => {
7574
- const skill = record5(item);
7733
+ const skill = record6(item);
7575
7734
  if (!skill || !validManifestName(skill.name) || skillNames2.has(skill.name) || skill.instructions !== void 0 && (typeof skill.instructions !== "string" || utf8Bytes(skill.instructions) > 32e3) || !Array.isArray(skill.tools) || !skill.tools.length || skill.tools.length > 128) {
7576
7735
  throw invalid("collaboration skill");
7577
7736
  }
7578
7737
  skillNames2.add(skill.name);
7579
7738
  const tools = skill.tools.map((candidate) => {
7580
- const tool = record5(candidate);
7581
- const inputSchema = record5(tool?.inputSchema);
7739
+ const tool = record6(candidate);
7740
+ const inputSchema = record6(tool?.inputSchema);
7582
7741
  if (!tool || !validManifestName(tool.name) || toolNames.has(tool.name) || typeof tool.description !== "string" || utf8Bytes(tool.description) > 8e3 || !inputSchema || jsonBytes(inputSchema) > 64e3 || tool.concurrency !== void 0 && tool.concurrency !== "parallel") {
7583
7742
  throw invalid("collaboration tool");
7584
7743
  }
@@ -7603,12 +7762,12 @@ function parseCollaborationSkills(value2) {
7603
7762
  }
7604
7763
  function validateCollaborationToolRequest(value2) {
7605
7764
  validCommandId(value2.commandId);
7606
- if (typeof value2.toolCallId !== "string" || value2.toolCallId.length > 256 || !/^[^\s\u0000-\u001f\u007f]+$/.test(value2.toolCallId) || !validManifestName(value2.skill) || !validManifestName(value2.tool) || !record5(value2.input) || jsonBytes(value2.input) > 128e3) {
7765
+ if (typeof value2.toolCallId !== "string" || value2.toolCallId.length > 256 || !/^[^\s\u0000-\u001f\u007f]+$/.test(value2.toolCallId) || !validManifestName(value2.skill) || !validManifestName(value2.tool) || !record6(value2.input) || jsonBytes(value2.input) > 128e3) {
7607
7766
  throw new TypeError("invalid Code collaboration tool request");
7608
7767
  }
7609
7768
  }
7610
7769
  function parseCollaborationToolOutput(value2) {
7611
- const output = record5(record5(value2)?.output);
7770
+ const output = record6(record6(value2)?.output);
7612
7771
  if (!output || output.isError !== void 0 && typeof output.isError !== "boolean") {
7613
7772
  throw invalid("collaboration tool");
7614
7773
  }
@@ -7617,7 +7776,7 @@ function parseCollaborationToolOutput(value2) {
7617
7776
  return { content: output.content, ...output.isError === true ? { isError: true } : {} };
7618
7777
  }
7619
7778
  if (!Array.isArray(output.content) || output.content.length > 64 || jsonBytes(output.content) > 1e6 || !output.content.every((block2) => {
7620
- const item = record5(block2);
7779
+ const item = record6(block2);
7621
7780
  return item && ["text", "image", "audio", "document", "tool_use", "tool_result", "thinking"].includes(String(item.type));
7622
7781
  })) throw invalid("collaboration tool");
7623
7782
  return {
@@ -7650,17 +7809,48 @@ function jsonBytes(value2) {
7650
7809
  return Number.POSITIVE_INFINITY;
7651
7810
  }
7652
7811
  }
7653
- var record5 = (value2) => value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
7812
+ var record6 = (value2) => value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
7654
7813
  var invalid = (part) => new CodeRuntimeControlError(`invalid Code runtime ${part} response`, 502, "invalid_response");
7655
7814
  var RESERVED = /* @__PURE__ */ new Set([".git", ".odla", ".wrangler", "node_modules", "dist", "coverage"]);
7656
7815
  var SECRET = /^(?:\.env(?:\..+)?|\.dev\.vars|credentials(?:\..+)?\.json|dev-token(?:\..+)?\.json)$/i;
7657
7816
  var PATH = /^[A-Za-z0-9_@+.,-]+(?:\/[A-Za-z0-9_@+.,-]+)*$/;
7658
7817
  var FORBIDDEN = /^(?:GIT binary patch|Binary files |rename (?:from|to) |copy (?:from|to) |similarity index |old mode |new mode |deleted file mode 160000|new file mode 160000)/m;
7659
7818
  function stripPatchEnvelope(patch2) {
7660
- if (!/^\*\*\* (?:Begin|End) Patch\s*$/m.test(patch2)) return patch2;
7819
+ if (!/^\*\*\* (?:Begin|End) Patch\s*$/m.test(patch2)) return applyPatchDialectToDiff(patch2);
7661
7820
  const kept = patch2.split("\n").filter((line2) => !/^\*\*\* (?:Begin|End) Patch\s*$/.test(line2));
7662
7821
  const stripped = kept.join("\n");
7663
- return /^diff --git /m.test(stripped) ? stripped : patch2;
7822
+ if (/^diff --git /m.test(stripped)) return stripped;
7823
+ const translated = applyPatchDialectToDiff(stripped);
7824
+ return translated === stripped ? patch2 : translated;
7825
+ }
7826
+ function applyPatchDialectToDiff(patch2) {
7827
+ if (!/^\*\*\* (?:Update|Add|Delete) File: /m.test(patch2)) return patch2;
7828
+ const out = [];
7829
+ let open = false;
7830
+ for (const line2 of patch2.split("\n")) {
7831
+ const file = /^\*\*\* (Update|Add|Delete) File: (.+?)\s*$/.exec(line2);
7832
+ if (file) {
7833
+ const [, verb, raw] = file;
7834
+ const path = raw.trim();
7835
+ if (!PATH.test(path)) return patch2;
7836
+ out.push(`diff --git a/${path} b/${path}`);
7837
+ if (verb === "Add") out.push("new file mode 100644", "--- /dev/null", `+++ b/${path}`);
7838
+ else if (verb === "Delete") out.push(`--- a/${path}`, "+++ /dev/null");
7839
+ else out.push(`--- a/${path}`, `+++ b/${path}`);
7840
+ open = true;
7841
+ continue;
7842
+ }
7843
+ if (/^\*\*\* /.test(line2)) continue;
7844
+ if (!open) continue;
7845
+ if (/^@@/.test(line2)) {
7846
+ out.push("@@ -1 +1 @@");
7847
+ continue;
7848
+ }
7849
+ out.push(line2);
7850
+ }
7851
+ if (!open) return patch2;
7852
+ return `${out.join("\n").replace(/\n+$/, "")}
7853
+ `;
7664
7854
  }
7665
7855
  function validateCodePatch(rawPatch, maxBytes) {
7666
7856
  const patch2 = stripPatchEnvelope(rawPatch);
@@ -7713,17 +7903,20 @@ function resolveCodePath(workspaceDir, path) {
7713
7903
  if (target !== root && !target.startsWith(`${root}${sep3}`)) throw new TypeError("path escapes the staged workspace");
7714
7904
  return target;
7715
7905
  }
7906
+ function hasContextFreeHunk(patch2) {
7907
+ const bodies = patch2.split(/^@@.*$/m).slice(1);
7908
+ return bodies.some((body) => !body.split("\n").some((line2) => line2.startsWith(" ") && line2.trim().length > 0));
7909
+ }
7716
7910
  function describePatchFailure(patch2, detail) {
7717
7911
  const hunks = patch2.split("\n").filter((line2) => line2.startsWith("@@"));
7718
- const bodies = patch2.split(/^@@.*$/m).slice(1);
7719
- const contextless = bodies.some((body) => !body.split("\n").some((line2) => line2.startsWith(" ") && line2.trim().length > 0));
7720
- const hint = hunks.length > 0 && contextless ? " A hunk has no context lines; include at least one unchanged line above or below each change." : "";
7912
+ const hint = hunks.length > 0 && hasContextFreeHunk(patch2) ? " A hunk has no context lines; include at least one unchanged line above or below each change." : "";
7721
7913
  return `patch did not apply: ${detail}${hint}`;
7722
7914
  }
7723
7915
  async function applyCodePatch(workspaceDir, rawPatch, paths2) {
7724
7916
  const patch2 = stripPatchEnvelope(rawPatch);
7725
- await gitApply(workspaceDir, patch2, true);
7726
- await gitApply(workspaceDir, patch2, false);
7917
+ const zero = hasContextFreeHunk(patch2);
7918
+ await gitApply(workspaceDir, patch2, true, zero);
7919
+ await gitApply(workspaceDir, patch2, false, zero);
7727
7920
  for (const path of paths2) {
7728
7921
  try {
7729
7922
  const info = await lstat2(resolveCodePath(workspaceDir, path));
@@ -7735,9 +7928,16 @@ async function applyCodePatch(workspaceDir, rawPatch, paths2) {
7735
7928
  }
7736
7929
  }
7737
7930
  }
7738
- function gitApply(cwd, patch2, check) {
7931
+ function gitApply(cwd, patch2, check, unidiffZero = false) {
7739
7932
  return new Promise((accept, reject) => {
7740
- const args = ["apply", "--recount", "--whitespace=nowarn", ...check ? ["--check"] : [], "-"];
7933
+ const args = [
7934
+ "apply",
7935
+ "--recount",
7936
+ ...unidiffZero ? ["--unidiff-zero"] : [],
7937
+ "--whitespace=nowarn",
7938
+ ...check ? ["--check"] : [],
7939
+ "-"
7940
+ ];
7741
7941
  const child = spawn4("git", args, {
7742
7942
  cwd,
7743
7943
  shell: false,
@@ -7746,8 +7946,8 @@ function gitApply(cwd, patch2, check) {
7746
7946
  });
7747
7947
  let stderr2 = "";
7748
7948
  child.stderr.setEncoding("utf8");
7749
- child.stderr.on("data", (text22) => {
7750
- if (stderr2.length < 4e3) stderr2 += text22.slice(0, 4e3);
7949
+ child.stderr.on("data", (text4) => {
7950
+ if (stderr2.length < 4e3) stderr2 += text4.slice(0, 4e3);
7751
7951
  });
7752
7952
  child.once("error", reject);
7753
7953
  child.once("exit", (code) => code === 0 ? accept() : reject(new TypeError(describePatchFailure(patch2, stderr2.trim().slice(0, 500)))));
@@ -7993,7 +8193,7 @@ function validate2(input) {
7993
8193
  maximumFiles: policy.maximumFiles ?? 2e4,
7994
8194
  maximumBytes: policy.maximumBytes ?? 512 * 1024 * 1024
7995
8195
  };
7996
- if ([...result.testPathPrefixes, ...result.testPathSuffixes].some((rule) => !RULE.test(rule)) || !integer(result.maximumChangedTests, 0, 1e4) || !integer(result.maximumPatchBytes, 1, 4 * 1024 * 1024) || !integer(result.maximumFiles, 1, 1e5) || !integer(result.maximumBytes, 1, 2 * 1024 * 1024 * 1024)) {
8196
+ if ([...result.testPathPrefixes, ...result.testPathSuffixes].some((rule) => !RULE.test(rule)) || !integer2(result.maximumChangedTests, 0, 1e4) || !integer2(result.maximumPatchBytes, 1, 4 * 1024 * 1024) || !integer2(result.maximumFiles, 1, 1e5) || !integer2(result.maximumBytes, 1, 2 * 1024 * 1024 * 1024)) {
7997
8197
  throw new TypeError("clean verification policy exceeds its bounds");
7998
8198
  }
7999
8199
  return result;
@@ -8044,7 +8244,7 @@ function hashFile(path) {
8044
8244
  });
8045
8245
  }
8046
8246
  function checkedResult(result, maximumOutputBytes) {
8047
- if (!integer(result.exitCode, 0, 255) || !integer(result.durationMs, 0, 30 * 6e4) || typeof result.stdout !== "string" || typeof result.stderr !== "string" || typeof result.outputLimitExceeded !== "boolean" || typeof result.timedOut !== "boolean") {
8247
+ if (!integer2(result.exitCode, 0, 255) || !integer2(result.durationMs, 0, 30 * 6e4) || typeof result.stdout !== "string" || typeof result.stderr !== "string" || typeof result.outputLimitExceeded !== "boolean" || typeof result.timedOut !== "boolean") {
8048
8248
  throw new TypeError("recipe executor returned an invalid result");
8049
8249
  }
8050
8250
  const bytes = Buffer.byteLength(result.stdout) + Buffer.byteLength(result.stderr);
@@ -8094,7 +8294,7 @@ function digestJson(value2) {
8094
8294
  function digestBytes(value2) {
8095
8295
  return `sha256:${createHash22("sha256").update(value2).digest("hex")}`;
8096
8296
  }
8097
- function integer(value2, minimum, maximum) {
8297
+ function integer2(value2, minimum, maximum) {
8098
8298
  return Number.isSafeInteger(value2) && value2 >= minimum && value2 <= maximum;
8099
8299
  }
8100
8300
  async function prepareRuntimeCheckpoint(input) {
@@ -8121,9 +8321,9 @@ async function prepareRuntimeCheckpoint(input) {
8121
8321
  if (evidence.receipt.outcome === "passed") {
8122
8322
  verification = evidence.receipt;
8123
8323
  review = await input.review(patch2, verification);
8124
- note = review.verdict === "approved" ? "Clean verification and independent review passed" : "Clean verification passed; independent review rejected the candidate";
8324
+ note = describeReview(review);
8125
8325
  } else {
8126
- note = `Clean verification failed: ${evidence.receipt.recipes.filter((recipe2) => recipe2.status !== "passed").map((recipe2) => `${recipe2.recipeId}=${recipe2.status}`).join(", ")}`;
8326
+ note = describeGateFailure(evidence);
8127
8327
  }
8128
8328
  } catch (cause) {
8129
8329
  note = `Candidate verification or review failed closed: ${message(cause)}`;
@@ -8148,6 +8348,23 @@ async function prepareRuntimeCheckpoint(input) {
8148
8348
  });
8149
8349
  return { checkpoint, verification, review, note };
8150
8350
  }
8351
+ function describeReview(review) {
8352
+ const findings = review.findings.map((finding) => ` - [${finding.severity}] ${finding.detail}`).join("\n");
8353
+ const head = review.verdict === "approved" ? `Clean verification and independent review passed (score ${review.score}/100).` : `Clean verification passed; independent review REJECTED this candidate (score ${review.score}/100). Address the findings and checkpoint again.`;
8354
+ return [head, review.summary, findings].filter(Boolean).join("\n").slice(0, 4e3);
8355
+ }
8356
+ function describeGateFailure(evidence) {
8357
+ const failed = evidence.receipt.recipes.filter((recipe2) => recipe2.status !== "passed");
8358
+ const detail = failed.map((recipe2) => {
8359
+ const log = evidence.logs.find((entry) => entry.recipeId === recipe2.recipeId);
8360
+ const output = `${log?.stdout ?? ""}
8361
+ ${log?.stderr ?? ""}`.trim();
8362
+ return `${recipe2.recipeId}=${recipe2.status}${output ? `
8363
+ ${output.slice(0, 1500)}` : ""}`;
8364
+ }).join("\n\n");
8365
+ return `Clean verification failed. Fix this and checkpoint again:
8366
+ ${detail}`.slice(0, 4e3);
8367
+ }
8151
8368
  var message = (value2) => (value2 instanceof Error ? value2.message : String(value2)).slice(0, 500);
8152
8369
  var CodeRuntimeCheckpointManager = class {
8153
8370
  constructor(options) {
@@ -9166,8 +9383,14 @@ function optionalInteger(value2) {
9166
9383
  if (!Number.isSafeInteger(value2) || value2 < 1) throw new TypeError("line bounds must be positive integers");
9167
9384
  return value2;
9168
9385
  }
9386
+ var DEFAULT_FAILURE_REASON2 = {
9387
+ "tool denied by CaMeL policy": "tool denied by CaMeL policy",
9388
+ "review sessions are read-only": "review session is read-only; workspace changes are not permitted"
9389
+ };
9169
9390
  function response(request3, ok, content2, details) {
9170
- return { requestId: request3.requestId, ok, content: content2, ...details ? { details } : {} };
9391
+ if (ok) return { requestId: request3.requestId, ok, content: content2, ...details ? { details } : {} };
9392
+ const failureReason = typeof details?.failureReason === "string" && details.failureReason || DEFAULT_FAILURE_REASON2[content2] || content2 || "tool request failed; inspect the tool input and workspace state";
9393
+ return { requestId: request3.requestId, ok, content: content2, details: { ...details, failureReason } };
9171
9394
  }
9172
9395
  var cache = /* @__PURE__ */ new Map();
9173
9396
  function workspaceGraphs(workspaceDir, paths2) {
@@ -9743,120 +9966,6 @@ async function appendCodeRuntimeEvent(control, command, event, refs) {
9743
9966
  }
9744
9967
  var digestRuntimeValue = (value2) => `sha256:${createHash32("sha256").update(value2).digest("hex")}`;
9745
9968
  var runtimeErrorMessage = (value2) => value2 instanceof Error ? value2.message : String(value2);
9746
- var text3 = (value2, maximum) => {
9747
- if (typeof value2 !== "string") return void 0;
9748
- const bounded = value2.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g, " ").trim();
9749
- return bounded ? bounded.slice(0, maximum) : void 0;
9750
- };
9751
- var integer2 = (value2) => Number.isSafeInteger(value2) && Number(value2) >= 0 ? Number(value2) : void 0;
9752
- var record32 = (value2) => value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : void 0;
9753
- var excerpt = (value2, tail = false) => {
9754
- if (typeof value2 !== "string") return void 0;
9755
- const safe = value2.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g, " ");
9756
- const source = (tail ? safe.slice(-1e4) : safe.slice(0, 1e4)).trim();
9757
- if (!source) return void 0;
9758
- const lines = source.split("\n").filter((line2) => line2.trim()).map((line2) => line2.slice(0, 240));
9759
- const selected = tail ? lines.slice(-10) : lines.slice(0, 10);
9760
- return text3(selected.join("\n"), 2400);
9761
- };
9762
- var paths = (value2) => {
9763
- if (!Array.isArray(value2)) return void 0;
9764
- const items = value2.flatMap((item) => {
9765
- const path = text3(item, 1024);
9766
- return path ? [path] : [];
9767
- }).slice(0, 12);
9768
- return items.length ? items : void 0;
9769
- };
9770
- function patchStats(value2) {
9771
- if (typeof value2 !== "string") return {};
9772
- let additions = 0;
9773
- let deletions = 0;
9774
- for (const line2 of value2.slice(0, 262144).split("\n")) {
9775
- if (line2.startsWith("+++") || line2.startsWith("---")) continue;
9776
- if (line2.startsWith("+")) additions += 1;
9777
- else if (line2.startsWith("-")) deletions += 1;
9778
- }
9779
- return { ...additions ? { additions } : {}, ...deletions ? { deletions } : {} };
9780
- }
9781
- function searchResults(value2) {
9782
- if (typeof value2 !== "string") return void 0;
9783
- const results = value2.split("\n").flatMap((line2) => {
9784
- const match = /^([^:\n]{1,1024}):(\d+):\s?(.*)$/.exec(line2);
9785
- if (!match) return [];
9786
- const lineNumber = Number(match[2]);
9787
- const itemText = text3(match[3], 240);
9788
- if (!Number.isSafeInteger(lineNumber) || lineNumber < 1) return [];
9789
- return [{ path: match[1], line: lineNumber, ...itemText ? { text: itemText } : {} }];
9790
- }).slice(0, 5);
9791
- return results.length ? results : void 0;
9792
- }
9793
- function codeToolRequestPresentation(request3) {
9794
- const input = request3.input;
9795
- if (request3.tool === "sandbox.read") {
9796
- const path = text3(input.path, 1024);
9797
- if (!path) return void 0;
9798
- const startLine = integer2(input.startLine);
9799
- const endLine = integer2(input.endLine);
9800
- return { kind: "read", path, ...startLine ? { startLine } : {}, ...endLine ? { endLine } : {} };
9801
- }
9802
- if (request3.tool === "sandbox.list") {
9803
- const scope = text3(input.prefix, 1024);
9804
- return { kind: "list", ...scope ? { scope } : {} };
9805
- }
9806
- if (request3.tool === "sandbox.search" || request3.tool === "sandbox.overview" || request3.tool === "sandbox.where_is" || request3.tool === "sandbox.who_imports" || request3.tool === "sandbox.who_touches") {
9807
- const query = text3(input.query, 512);
9808
- const scope = request3.tool === "sandbox.search" ? text3(input.prefix, 1024) : void 0;
9809
- if (request3.tool === "sandbox.search" && !query) return void 0;
9810
- return { kind: "query", ...query ? { query } : {}, ...scope ? { scope } : {} };
9811
- }
9812
- if (request3.tool === "sandbox.apply_patch") {
9813
- return { kind: "patch", ...patchStats(input.patch) };
9814
- }
9815
- const recipeId = text3(input.recipeId, 120);
9816
- return recipeId ? { kind: "recipe", recipeId } : void 0;
9817
- }
9818
- function codeToolResultPresentation(request3, response2) {
9819
- const started = codeToolRequestPresentation(request3);
9820
- if (!started || !response2.ok) return started;
9821
- const details = record32(response2.details);
9822
- if (started.kind === "read") {
9823
- return {
9824
- ...started,
9825
- ...integer2(details?.startLine) ? { startLine: integer2(details?.startLine) } : {},
9826
- ...integer2(details?.endLine) ? { endLine: integer2(details?.endLine) } : {},
9827
- ...excerpt(response2.content) ? { excerpt: excerpt(response2.content) } : {}
9828
- };
9829
- }
9830
- if (started.kind === "list") {
9831
- const listed = response2.content.split("\n").filter((line2) => line2 && !line2.startsWith("\u2026") && !line2.startsWith("Workspace ")).map((line2) => text3(line2, 1024)).filter((line2) => Boolean(line2)).slice(0, 8);
9832
- return {
9833
- ...started,
9834
- ...integer2(details?.count) !== void 0 ? { count: integer2(details?.count) } : {},
9835
- ...listed.length ? { paths: listed } : {}
9836
- };
9837
- }
9838
- if (started.kind === "query") {
9839
- const results = request3.tool === "sandbox.search" ? searchResults(response2.content) : void 0;
9840
- const resultExcerpt = request3.tool === "sandbox.search" ? void 0 : excerpt(response2.content);
9841
- return {
9842
- ...started,
9843
- ...integer2(details?.count) !== void 0 ? { count: integer2(details?.count) } : {},
9844
- ...results ? { results } : {},
9845
- ...resultExcerpt ? { excerpt: resultExcerpt } : {}
9846
- };
9847
- }
9848
- if (started.kind === "patch") {
9849
- return { ...started, ...paths(details?.paths) ? { paths: paths(details?.paths) } : {} };
9850
- }
9851
- const output = response2.content.replace(/^Recipe [^\n]*\.?\s*/u, "");
9852
- return {
9853
- ...started,
9854
- ...integer2(details?.exitCode) !== void 0 ? { exitCode: integer2(details?.exitCode) } : {},
9855
- ...typeof details?.timedOut === "boolean" ? { timedOut: details.timedOut } : {},
9856
- ...typeof details?.outputLimitExceeded === "boolean" ? { outputLimitExceeded: details.outputLimitExceeded } : {},
9857
- ...excerpt(output, true) ? { excerpt: excerpt(output, true) } : {}
9858
- };
9859
- }
9860
9969
  function codeRuntimeAcknowledgementGate(signal) {
9861
9970
  let settle;
9862
9971
  let settled = false;
@@ -9874,6 +9983,55 @@ function codeRuntimeAcknowledgementGate(signal) {
9874
9983
  else signal.addEventListener("abort", onAbort, { once: true });
9875
9984
  return { ready, release };
9876
9985
  }
9986
+ function observeCodeRuntimeSessionSkills(command, skills, emit4) {
9987
+ return skills.map((skill) => ({
9988
+ ...skill,
9989
+ tools: skill.tools.map((tool) => {
9990
+ if (!tool.handler) return tool;
9991
+ const handler = tool.handler;
9992
+ return {
9993
+ ...tool,
9994
+ handler: async (input, context) => {
9995
+ const startedAt = Date.now();
9996
+ const operationId = digestRuntimeValue(
9997
+ `${command.commandId}:${skill.name}:${tool.name}:${context.toolCallId ?? "missing"}`
9998
+ );
9999
+ await emit4({
10000
+ type: "collaboration",
10001
+ phase: "started",
10002
+ skill: skill.name,
10003
+ tool: tool.name,
10004
+ operationId
10005
+ }).catch(() => void 0);
10006
+ try {
10007
+ const output = await handler(input, context);
10008
+ await emit4({
10009
+ type: "collaboration",
10010
+ phase: "completed",
10011
+ skill: skill.name,
10012
+ tool: tool.name,
10013
+ operationId,
10014
+ ok: output.isError !== true,
10015
+ durationMs: Date.now() - startedAt
10016
+ }).catch(() => void 0);
10017
+ return output;
10018
+ } catch (cause) {
10019
+ await emit4({
10020
+ type: "collaboration",
10021
+ phase: "completed",
10022
+ skill: skill.name,
10023
+ tool: tool.name,
10024
+ operationId,
10025
+ ok: false,
10026
+ durationMs: Date.now() - startedAt
10027
+ }).catch(() => void 0);
10028
+ throw cause;
10029
+ }
10030
+ }
10031
+ };
10032
+ })
10033
+ }));
10034
+ }
9877
10035
  var TheseusRuntimeEngine = class {
9878
10036
  constructor(options) {
9879
10037
  this.options = options;
@@ -10070,7 +10228,7 @@ var TheseusRuntimeEngine = class {
10070
10228
  event: (event) => this.#event(command, event, active.conversationRefs)
10071
10229
  });
10072
10230
  await this.#event(command, { type: "status", status: "running" }, active.conversationRefs);
10073
- const extraSkills = await sessionSkillsFor(this.options, command);
10231
+ const extraSkills = observeCodeRuntimeSessionSkills(command, await sessionSkillsFor(this.options, command), (event) => this.#event(command, event, active.conversationRefs));
10074
10232
  const result = await this.#attempt({
10075
10233
  inference,
10076
10234
  broker,
@@ -10109,36 +10267,11 @@ var TheseusRuntimeEngine = class {
10109
10267
  }
10110
10268
  /** Report every brokered effect as it starts and finishes. */
10111
10269
  #observed(command, active, broker) {
10112
- return {
10113
- execute: async (context, request3) => {
10114
- const startedAt = Date.now();
10115
- const operationId = digestRuntimeValue(`${command.commandId}:${request3.requestId}`);
10116
- const startedPresentation = codeToolRequestPresentation(request3);
10117
- await this.#event(
10118
- command,
10119
- {
10120
- type: "tool",
10121
- phase: "started",
10122
- tool: request3.tool,
10123
- operationId,
10124
- ...startedPresentation ? { presentation: startedPresentation } : {}
10125
- },
10126
- active.conversationRefs
10127
- ).catch(() => void 0);
10128
- const response2 = await broker.execute(context, request3);
10129
- const completedPresentation = codeToolResultPresentation(request3, response2);
10130
- await this.#event(command, {
10131
- type: "tool",
10132
- phase: "completed",
10133
- tool: request3.tool,
10134
- ok: response2.ok,
10135
- durationMs: Date.now() - startedAt,
10136
- operationId,
10137
- ...completedPresentation ? { presentation: completedPresentation } : {}
10138
- }, active.conversationRefs).catch(() => void 0);
10139
- return response2;
10140
- }
10141
- };
10270
+ return observedBroker({
10271
+ broker,
10272
+ operationIdFor: (requestId) => digestRuntimeValue(`${command.commandId}:${requestId}`),
10273
+ emit: (event) => this.#event(command, event, active.conversationRefs).catch(() => void 0)
10274
+ });
10142
10275
  }
10143
10276
  async #checkpoint(command) {
10144
10277
  const active = this.#active.get(command.sessionId);
@@ -10448,6 +10581,19 @@ function digestText(value2) {
10448
10581
  // src/code-runtime-config.ts
10449
10582
  var CODE_NODE_IMAGE = "node:24-alpine@sha256:a0b9bf06e4e6193cf7a0f58816cc935ff8c2a908f81e6f1a95432d679c54fbfd";
10450
10583
  var CODE_BUILD_RECIPES = Object.freeze([{
10584
+ id: "odla-code-gates",
10585
+ image: CODE_NODE_IMAGE,
10586
+ // Selects the repository's fast, no-capability gates from the same manifest
10587
+ // CI and `npm run preflight` read, so a new gate is picked up without a
10588
+ // second list to keep in sync. The container has no shell: this is argv.
10589
+ command: ["node", "scripts/recipe-gates.mjs"],
10590
+ timeoutMs: 18e4,
10591
+ maxOutputBytes: 1024 * 1024,
10592
+ cpus: 1,
10593
+ // check:secrets holds ~2,500 source files in memory at once.
10594
+ memory: "1g",
10595
+ pids: 128
10596
+ }, {
10451
10597
  id: "odla-code-contracts",
10452
10598
  image: CODE_NODE_IMAGE,
10453
10599
  command: [
@@ -10627,20 +10773,20 @@ async function runCodeRuntime(input) {
10627
10773
  }
10628
10774
  }
10629
10775
  function parseConnection(value2, appId, appEnv) {
10630
- const root = record6(value2);
10631
- const host = record6(root?.host);
10632
- const offer = record6(root?.offer);
10633
- const binding = record6(root?.binding);
10776
+ const root = record7(value2);
10777
+ const host = record7(root?.host);
10778
+ const offer = record7(root?.offer);
10779
+ const binding = record7(root?.binding);
10634
10780
  if (!root || typeof root.token !== "string" || !/^odla_code_host_[0-9a-f]{64}$/.test(root.token) || typeof root.resumed !== "boolean" || !host || !/^chost_[0-9a-f]{32}$/.test(String(host.hostId)) || typeof host.name !== "string" || !offer || !Number.isSafeInteger(offer.slots) || !binding || typeof binding.appId !== "string" || !binding.appId || appId && binding.appId !== appId || binding.env !== appEnv || !Number.isSafeInteger(binding.generation)) {
10635
10781
  throw new Error("connect Code host returned an invalid response");
10636
10782
  }
10637
10783
  return root;
10638
10784
  }
10639
10785
  function apiFailure(action2, status, value2) {
10640
- const message2 = record6(record6(value2)?.error)?.message;
10786
+ const message2 = record7(record7(value2)?.error)?.message;
10641
10787
  return `${action2} failed (${status})${typeof message2 === "string" ? `: ${message2}` : ""}`;
10642
10788
  }
10643
- function record6(value2) {
10789
+ function record7(value2) {
10644
10790
  return value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
10645
10791
  }
10646
10792
 
@@ -11146,6 +11292,14 @@ Usage:
11146
11292
  odla-ai ai models [--config odla.config.mjs] [--env dev] [--provider <id>] [--json]
11147
11293
  odla-ai config <diff|plan> [--config odla.config.mjs] [--email <odla-account>] [--json]
11148
11294
  odla-ai config apply --plan <plan.json> [--idempotency-key <key>] [--email <odla-account>] [--json]
11295
+ odla-ai promotion plan --file <promotion-plan.json> [--env dev] [--json]
11296
+ odla-ai promotion inspect <plan-id> [--env dev] [--json]
11297
+ odla-ai promotion status <plan-id> [--env dev] [--json]
11298
+ odla-ai promotion apply <plan-id> --approval <approval-id> [--idempotency-key <key>] [--env dev] [--json]
11299
+ odla-ai promotion rollback <plan-id> --approval <approval-id> [--idempotency-key <key>] [--env dev] [--json]
11300
+ odla-ai promotion next <plan-id> <operation-id> [--env dev] [--json]
11301
+ odla-ai promotion record <plan-id> <operation-id> <step-id> --file <step-receipt.json> [--env dev] [--json]
11302
+ odla-ai promotion cancel <plan-id> <operation-id> [--env dev] [--json]
11149
11303
  odla-ai operations get <operation-id> [--json]
11150
11304
  odla-ai operations wait <operation-id> [--interval <seconds>] [--timeout <seconds>] [--json]
11151
11305
  odla-ai calendar status [--env dev] [--email <odla-account>] [--json]
@@ -11312,6 +11466,11 @@ Commands:
11312
11466
  init Create a generic odla.config.mjs plus starter schema/rules files.
11313
11467
  doctor Validate and summarize the project config without network calls.
11314
11468
  config Diff Registry intent, freeze a CAS-bound plan, and conditionally apply its safe actions.
11469
+ promotion Plan and inspect exact selective-release bundles without target
11470
+ mutation, then queue and resume a human-approved apply or rollback
11471
+ from an enrolled device. Each target step is leased and receipt-
11472
+ journaled; approval remains bound to the immutable plan digest,
11473
+ target set, action, and expiry, so every mismatch fails closed.
11315
11474
  operations Inspect or wait on one exact, durable config-operation receipt.
11316
11475
  calendar Inspect, connect, or disconnect the live Google booking connection.
11317
11476
  app Archive (suspend, data retained), restore, export, import, or
@@ -12187,17 +12346,17 @@ function collectEntityFields(entity, parsed, allowClear) {
12187
12346
  if (entity === "task" && fields.column === "ready") fields.column = "todo";
12188
12347
  return fields;
12189
12348
  }
12190
- function statusCol(entity, record11) {
12191
- if (entity === "bug") return `${record11.status ?? ""}/${record11.severity ?? ""}`;
12349
+ function statusCol(entity, record12) {
12350
+ if (entity === "bug") return `${record12.status ?? ""}/${record12.severity ?? ""}`;
12192
12351
  if (entity === "task") {
12193
- const state2 = record11.column === "todo" ? "ready" : String(record11.column ?? "");
12194
- return record11.revision ? `${state2}; r${record11.revision}` : state2;
12352
+ const state2 = record12.column === "todo" ? "ready" : String(record12.column ?? "");
12353
+ return record12.revision ? `${state2}; r${record12.revision}` : state2;
12195
12354
  }
12196
- return String(record11.status ?? "");
12355
+ return String(record12.status ?? "");
12197
12356
  }
12198
- function referenceMarkup(entity, record11) {
12199
- const label = (record11.title?.trim() || `${entity} ${record11.id}`).replaceAll("]", ")");
12200
- return `@[${label}](pm:${entity}/${record11.id})`;
12357
+ function referenceMarkup(entity, record12) {
12358
+ const label = (record12.title?.trim() || `${entity} ${record12.id}`).replaceAll("]", ")");
12359
+ return `@[${label}](pm:${entity}/${record12.id})`;
12201
12360
  }
12202
12361
  var STUDIO_SECTION = {
12203
12362
  goal: "goals",
@@ -12211,13 +12370,13 @@ function studioRecordUrl(ctx, entity, id2) {
12211
12370
  ctx.platformUrl
12212
12371
  ).href;
12213
12372
  }
12214
- function studioRecordLink(ctx, entity, record11) {
12215
- const label = (record11.title?.trim() || `${entity} ${record11.id}`).replaceAll("]", ")");
12216
- return `[${label}](${studioRecordUrl(ctx, entity, record11.id)})`;
12373
+ function studioRecordLink(ctx, entity, record12) {
12374
+ const label = (record12.title?.trim() || `${entity} ${record12.id}`).replaceAll("]", ")");
12375
+ return `[${label}](${studioRecordUrl(ctx, entity, record12.id)})`;
12217
12376
  }
12218
- function printRecord(ctx, entity, record11) {
12377
+ function printRecord(ctx, entity, record12) {
12219
12378
  ctx.out.log(
12220
- `${record11.id} [${statusCol(entity, record11)}] ${record11.appId} ${studioRecordLink(ctx, entity, record11)}`
12379
+ `${record12.id} [${statusCol(entity, record12)}] ${record12.appId} ${studioRecordLink(ctx, entity, record12)}`
12221
12380
  );
12222
12381
  }
12223
12382
  function emit2(ctx, value2, human) {
@@ -12271,8 +12430,8 @@ async function pmAdd(ctx, entity, parsed) {
12271
12430
  input,
12272
12431
  mutationId: writeMutationId2(parsed)
12273
12432
  });
12274
- const record11 = { id: res.id, appId, title: String(input.title) };
12275
- emit2(ctx, res, () => ctx.out.log(`created ${entity}: ${studioRecordLink(ctx, entity, record11)}`));
12433
+ const record12 = { id: res.id, appId, title: String(input.title) };
12434
+ emit2(ctx, res, () => ctx.out.log(`created ${entity}: ${studioRecordLink(ctx, entity, record12)}`));
12276
12435
  }
12277
12436
  var UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
12278
12437
  var UUID_PREFIX = /^[0-9a-f-]{8,35}$/i;
@@ -12292,7 +12451,7 @@ async function resolvePmId(ctx, entity, supplied) {
12292
12451
  "GET",
12293
12452
  `/${entity}?limit=${limit}&offset=${offset}`
12294
12453
  );
12295
- matches.push(...page2.records.map((record11) => record11.id).filter((id2) => id2.toLowerCase().startsWith(prefix)));
12454
+ matches.push(...page2.records.map((record12) => record12.id).filter((id2) => id2.toLowerCase().startsWith(prefix)));
12296
12455
  offset += page2.records.length;
12297
12456
  if (matches.length > 1 || page2.records.length === 0 || offset >= page2.total) break;
12298
12457
  }
@@ -12306,17 +12465,17 @@ async function resolvePmId(ctx, entity, supplied) {
12306
12465
  }
12307
12466
  async function pmGet(ctx, entity, id2) {
12308
12467
  const resolved = await resolvePmId(ctx, entity, id2);
12309
- const { record: record11 } = await pmRequest(ctx, "GET", `/${entity}/${encodeURIComponent(resolved)}`);
12310
- emit2(ctx, record11, () => printRecord(ctx, entity, record11));
12468
+ const { record: record12 } = await pmRequest(ctx, "GET", `/${entity}/${encodeURIComponent(resolved)}`);
12469
+ emit2(ctx, record12, () => printRecord(ctx, entity, record12));
12311
12470
  }
12312
12471
  async function pmReference(ctx, entity, id2) {
12313
- const { record: record11 } = await pmRequest(
12472
+ const { record: record12 } = await pmRequest(
12314
12473
  ctx,
12315
12474
  "GET",
12316
12475
  `/${entity}/${encodeURIComponent(id2)}`
12317
12476
  );
12318
- const markup = referenceMarkup(entity, record11);
12319
- emit2(ctx, { kind: `pm:${entity}`, id: record11.id, label: record11.title ?? "", markup }, () => {
12477
+ const markup = referenceMarkup(entity, record12);
12478
+ emit2(ctx, { kind: `pm:${entity}`, id: record12.id, label: record12.title ?? "", markup }, () => {
12320
12479
  ctx.out.log(markup);
12321
12480
  });
12322
12481
  }
@@ -12401,16 +12560,16 @@ var PER_ENTITY = {
12401
12560
  decision: ["status", "body", "supersedesId"],
12402
12561
  bug: ["status", "severity", "description", "goalId", "assigneeId", "decisionId"]
12403
12562
  };
12404
- function leanRecord(entity, record11) {
12563
+ function leanRecord(entity, record12) {
12405
12564
  const out = {};
12406
12565
  for (const key of [...COMMON, ...PER_ENTITY[entity]]) {
12407
- const value2 = record11[key];
12566
+ const value2 = record12[key];
12408
12567
  if (value2 !== void 0 && value2 !== null) out[key] = value2;
12409
12568
  }
12410
12569
  return out;
12411
12570
  }
12412
12571
  function leanRecords(entity, records, verbose) {
12413
- return verbose ? records : records.map((record11) => leanRecord(entity, record11));
12572
+ return verbose ? records : records.map((record12) => leanRecord(entity, record12));
12414
12573
  }
12415
12574
 
12416
12575
  // src/pm-intake.ts
@@ -12443,16 +12602,18 @@ async function pmNext(ctx, parsed) {
12443
12602
  // One request for both live columns; the split below is over open work only.
12444
12603
  listFiltered(ctx, "task", appId, projectId, { column: `${READY_COLUMN},doing` })
12445
12604
  ]);
12446
- const ready = tasks.filter((record11) => record11.column === READY_COLUMN);
12447
- const doing = tasks.filter((record11) => record11.column === "doing");
12605
+ const ready = tasks.filter((record12) => record12.column === READY_COLUMN);
12606
+ const doing = tasks.filter((record12) => record12.column === "doing");
12448
12607
  const guidance = !goals.length ? "discuss alignment with the user before creating or claiming project work" : !ready.length ? 'refine a linked Backlog task and mark it Ready with "pm task ready <id>"' : `claim the top Ready task in one call: odla-ai pm start --app ${appId}`;
12608
+ const monitor = `odla-ai pm watch --app ${appId} --jsonl`;
12449
12609
  const result = {
12450
12610
  appId,
12451
12611
  projectId,
12452
12612
  openGoals: leanRecords("goal", goals, verbose),
12453
12613
  doing: leanRecords("task", doing, verbose),
12454
12614
  ready: leanRecords("task", ready, verbose),
12455
- next: guidance
12615
+ next: guidance,
12616
+ monitor
12456
12617
  };
12457
12618
  emit2(ctx, result, () => {
12458
12619
  ctx.out.log(`${appId}: goal-aligned work intake (read only)`);
@@ -12463,9 +12624,10 @@ async function pmNext(ctx, parsed) {
12463
12624
  ]) {
12464
12625
  ctx.out.log(`${label}:`);
12465
12626
  if (!records.length) ctx.out.log("- (none)");
12466
- else for (const record11 of records) printRecord(ctx, entity, record11);
12627
+ else for (const record12 of records) printRecord(ctx, entity, record12);
12467
12628
  }
12468
12629
  ctx.out.log(`next: ${guidance}`);
12630
+ ctx.out.log(`monitor: ${monitor}`);
12469
12631
  });
12470
12632
  }
12471
12633
  async function pmHandoff(ctx, parsed) {
@@ -12477,17 +12639,20 @@ async function pmHandoff(ctx, parsed) {
12477
12639
  listFiltered(ctx, "bug", appId, projectId, { status: OPEN_BUG_STATUSES })
12478
12640
  ]);
12479
12641
  const clean4 = !goals.length && !tasks.length && !bugs.length;
12642
+ const monitor = `odla-ai pm watch --app ${appId} --jsonl`;
12480
12643
  const result = {
12481
12644
  appId,
12482
12645
  projectId,
12483
12646
  unmetGoals: leanRecords("goal", goals, verbose),
12484
12647
  activeTasks: leanRecords("task", tasks, verbose),
12485
12648
  openBugs: leanRecords("bug", bugs, verbose),
12486
- clean: clean4
12649
+ clean: clean4,
12650
+ monitor
12487
12651
  };
12488
12652
  emit2(ctx, result, () => {
12489
12653
  if (clean4) {
12490
12654
  ctx.out.log(`${appId}: no unresolved PM work`);
12655
+ ctx.out.log(`monitor: ${monitor}`);
12491
12656
  return;
12492
12657
  }
12493
12658
  ctx.out.log(`${appId}: authoritative PM handoff`);
@@ -12498,8 +12663,9 @@ async function pmHandoff(ctx, parsed) {
12498
12663
  ]) {
12499
12664
  ctx.out.log(`${label}:`);
12500
12665
  if (!records.length) ctx.out.log("- (none)");
12501
- else for (const record11 of records) printRecord(ctx, entity, record11);
12666
+ else for (const record12 of records) printRecord(ctx, entity, record12);
12502
12667
  }
12668
+ ctx.out.log(`monitor: ${monitor}`);
12503
12669
  });
12504
12670
  }
12505
12671
 
@@ -12572,14 +12738,14 @@ async function pmStart(ctx, parsed) {
12572
12738
 
12573
12739
  // src/pm-links.ts
12574
12740
  async function pmLink(ctx, entity, id2) {
12575
- const { record: record11 } = await pmRequest(
12741
+ const { record: record12 } = await pmRequest(
12576
12742
  ctx,
12577
12743
  "GET",
12578
12744
  `/${entity}/${encodeURIComponent(id2)}`
12579
12745
  );
12580
- const url = studioRecordUrl(ctx, entity, record11.id);
12581
- const markdown = studioRecordLink(ctx, entity, record11);
12582
- emit2(ctx, { kind: entity, id: record11.id, label: record11.title ?? "", url, markdown }, () => {
12746
+ const url = studioRecordUrl(ctx, entity, record12.id);
12747
+ const markdown = studioRecordLink(ctx, entity, record12);
12748
+ emit2(ctx, { kind: entity, id: record12.id, label: record12.title ?? "", url, markdown }, () => {
12583
12749
  ctx.out.log(markdown);
12584
12750
  });
12585
12751
  }
@@ -12706,16 +12872,16 @@ async function page(ctx, appId, cursor) {
12706
12872
  }
12707
12873
  return data;
12708
12874
  }
12709
- function recordState(record11) {
12710
- if (record11.column) return record11.column === "todo" ? "ready" : record11.column;
12711
- return String(record11.status ?? "");
12875
+ function recordState(record12) {
12876
+ if (record12.column) return record12.column === "todo" ? "ready" : record12.column;
12877
+ return String(record12.status ?? "");
12712
12878
  }
12713
12879
  function eventRecord(event) {
12714
12880
  return event.payload.payload;
12715
12881
  }
12716
12882
  function eventLabel(event) {
12717
- const record11 = eventRecord(event);
12718
- if (record11) return String(record11.title ?? event.payload.entityId);
12883
+ const record12 = eventRecord(event);
12884
+ if (record12) return String(record12.title ?? event.payload.entityId);
12719
12885
  const body = event.payload.message?.body?.replace(/\s+/g, " ").trim();
12720
12886
  return body || event.payload.entityId;
12721
12887
  }
@@ -12723,10 +12889,10 @@ function report3(ctx, parsed, result) {
12723
12889
  if (ctx.json) ctx.out.log(JSON.stringify(result, null, 2));
12724
12890
  else if (parsed.options.jsonl !== true && result.found) {
12725
12891
  for (const event of result.events ?? []) {
12726
- const record11 = eventRecord(event);
12727
- const state2 = record11 ? recordState(record11) : "comment";
12892
+ const record12 = eventRecord(event);
12893
+ const state2 = record12 ? recordState(record12) : "comment";
12728
12894
  ctx.out.log(
12729
- `${event.id} ${event.type} ${state2}${record11?.revision ? `; r${record11.revision}` : ""} ${eventLabel(event)}`
12895
+ `${event.id} ${event.type} ${state2}${record12?.revision ? `; r${record12.revision}` : ""} ${eventLabel(event)}`
12730
12896
  );
12731
12897
  }
12732
12898
  }
@@ -12800,8 +12966,8 @@ async function pmWatch(ctx, parsed) {
12800
12966
  }
12801
12967
  firstSuccess = false;
12802
12968
  const matching = current.events.filter((event) => {
12803
- const record11 = eventRecord(event);
12804
- const state2 = record11 ? recordState(record11).toLowerCase() : "";
12969
+ const record12 = eventRecord(event);
12970
+ const state2 = record12 ? recordState(record12).toLowerCase() : "";
12805
12971
  return (!entity || event.payload.entityKind === entity) && (!action2 || event.payload.action === action2) && (!wantedState || state2 === wantedState || wantedState === "todo" && state2 === "ready") && (!by || event.actor.id === by) && (!self || event.actor.id !== self);
12806
12972
  });
12807
12973
  for (const event of matching) {
@@ -13232,17 +13398,17 @@ async function platformStatus(parsed, deps) {
13232
13398
  }
13233
13399
  }
13234
13400
  function isPlatformStatus(value2) {
13235
- if (!record7(value2) || value2.schemaVersion !== "odla.platform-status/v1") return false;
13236
- if (!record7(value2.verdict) || !Array.isArray(value2.verdict.reasons)) return false;
13237
- if (!record7(value2.catalog) || !record7(value2.summary)) return false;
13401
+ if (!record8(value2) || value2.schemaVersion !== "odla.platform-status/v1") return false;
13402
+ if (!record8(value2.verdict) || !Array.isArray(value2.verdict.reasons)) return false;
13403
+ if (!record8(value2.catalog) || !record8(value2.summary)) return false;
13238
13404
  return Array.isArray(value2.services) && Array.isArray(value2.nextActions);
13239
13405
  }
13240
13406
  function apiMessage(value2) {
13241
- if (!record7(value2)) return "request failed";
13242
- const error = record7(value2.error) ? value2.error : value2;
13407
+ if (!record8(value2)) return "request failed";
13408
+ const error = record8(value2.error) ? value2.error : value2;
13243
13409
  return typeof error.message === "string" ? error.message : typeof error.code === "string" ? error.code : "request failed";
13244
13410
  }
13245
- function record7(value2) {
13411
+ function record8(value2) {
13246
13412
  return !!value2 && typeof value2 === "object" && !Array.isArray(value2);
13247
13413
  }
13248
13414
 
@@ -13283,7 +13449,7 @@ function statusVerdict(reads) {
13283
13449
  severity: "degraded"
13284
13450
  });
13285
13451
  }
13286
- const performance = record8(reads.liveSync.body.performance) ? reads.liveSync.body.performance : null;
13452
+ const performance = record9(reads.liveSync.body.performance) ? reads.liveSync.body.performance : null;
13287
13453
  if (performance?.status === "unavailable") {
13288
13454
  reasons.push({
13289
13455
  source: "liveSync",
@@ -13364,7 +13530,7 @@ function statusVerdict(reads) {
13364
13530
  reasons
13365
13531
  };
13366
13532
  }
13367
- function record8(value2) {
13533
+ function record9(value2) {
13368
13534
  return Boolean(value2) && typeof value2 === "object" && !Array.isArray(value2);
13369
13535
  }
13370
13536
  function numeric2(value2) {
@@ -13392,7 +13558,7 @@ function printO11yStatus(status, out) {
13392
13558
  out.log(
13393
13559
  `o11y status ${status.scope.appId}/${status.scope.env} (${status.scope.minutes}m)`
13394
13560
  );
13395
- const routes = Array.isArray(status.application.body.routes) ? status.application.body.routes.filter(record9) : [];
13561
+ const routes = Array.isArray(status.application.body.routes) ? status.application.body.routes.filter(record10) : [];
13396
13562
  const requests = routes.reduce(
13397
13563
  (total, row) => total + numeric3(row.requests),
13398
13564
  0
@@ -13404,39 +13570,39 @@ function printO11yStatus(status, out) {
13404
13570
  out.log(
13405
13571
  `application ${status.application.httpStatus} ${requests} requests ${errors} errors`
13406
13572
  );
13407
- const versions = Array.isArray(status.applicationVersions.body.rows) ? status.applicationVersions.body.rows.filter(record9) : [];
13573
+ const versions = Array.isArray(status.applicationVersions.body.rows) ? status.applicationVersions.body.rows.filter(record10) : [];
13408
13574
  out.log(
13409
13575
  `application-versions ${status.applicationVersions.httpStatus} ${versions.length ? versions.slice(0, 5).map(
13410
13576
  (row) => `${String(row.value || "(unattributed)")}:${numeric3(row.requests)}`
13411
13577
  ).join(", ") : "none observed"}`
13412
13578
  );
13413
13579
  out.log(liveSyncLine(status.liveSync));
13414
- const canaryDurations = record9(status.canary.body.durationsMs) ? status.canary.body.durationsMs : {};
13580
+ const canaryDurations = record10(status.canary.body.durationsMs) ? status.canary.body.durationsMs : {};
13415
13581
  out.log(
13416
13582
  `canary ${status.canary.httpStatus} ${String(status.canary.body.status ?? status.canary.body.error ?? "unavailable")} ${optionalNumeric(canaryDurations.publishToVisibleMs)} publish-to-visible`
13417
13583
  );
13418
- const collectorIngest = record9(status.collector.body.ingest) ? status.collector.body.ingest : {};
13419
- const collectorStorage = record9(collectorIngest.storage) ? collectorIngest.storage : {};
13584
+ const collectorIngest = record10(status.collector.body.ingest) ? status.collector.body.ingest : {};
13585
+ const collectorStorage = record10(collectorIngest.storage) ? collectorIngest.storage : {};
13420
13586
  out.log(
13421
13587
  `collector ${status.collector.httpStatus} ${String(status.collector.body.status ?? status.collector.body.error ?? "unavailable")} ${numeric3(collectorStorage.affectedPoints)} affected points`
13422
13588
  );
13423
- const providerMetrics = record9(status.provider.body.metrics) ? status.provider.body.metrics : {};
13424
- const providerCapacity = record9(status.provider.body.capacity) ? status.provider.body.capacity : {};
13425
- const workerMemory = record9(providerCapacity.memory) ? providerCapacity.memory : {};
13589
+ const providerMetrics = record10(status.provider.body.metrics) ? status.provider.body.metrics : {};
13590
+ const providerCapacity = record10(status.provider.body.capacity) ? status.provider.body.capacity : {};
13591
+ const workerMemory = record10(providerCapacity.memory) ? providerCapacity.memory : {};
13426
13592
  out.log(
13427
13593
  `cloudflare ${status.provider.httpStatus} ${String(status.provider.body.status ?? status.provider.body.error ?? "unavailable")} ${numeric3(providerMetrics.requests)} invocations ${numeric3(providerMetrics.errors)} runtime errors ${optionalBytes(workerMemory.headroomBytes)} isolate memory headroom`
13428
13594
  );
13429
13595
  for (const line2 of providerCapacityLines(status.providerCapacity)) {
13430
13596
  out.log(line2);
13431
13597
  }
13432
- const coverage = record9(status.providerReconciliation.body.comparison) ? status.providerReconciliation.body.comparison : {};
13433
- const coverageCounts = record9(status.providerReconciliation.body.counts) ? status.providerReconciliation.body.counts : {};
13434
- const coverageBudget = record9(status.providerReconciliation.body.budget) ? status.providerReconciliation.body.budget : {};
13598
+ const coverage = record10(status.providerReconciliation.body.comparison) ? status.providerReconciliation.body.comparison : {};
13599
+ const coverageCounts = record10(status.providerReconciliation.body.counts) ? status.providerReconciliation.body.counts : {};
13600
+ const coverageBudget = record10(status.providerReconciliation.body.budget) ? status.providerReconciliation.body.budget : {};
13435
13601
  out.log(
13436
13602
  `request-coverage ${status.providerReconciliation.httpStatus} ${String(status.providerReconciliation.body.status ?? status.providerReconciliation.body.error ?? "unavailable")} ${optionalPercent(coverage.applicationCoverage)} application/provider ${numeric3(coverageCounts.applicationRequests)}/${numeric3(coverageCounts.providerRequests)} requests \xB1${optionalPercent(coverageBudget.maxRelativeError)} budget`
13437
13603
  );
13438
13604
  const providerPoints = Array.isArray(status.providerHistory.body.points) ? status.providerHistory.body.points.length : 0;
13439
- const providerFreshness = record9(status.providerHistory.body.freshness) ? status.providerHistory.body.freshness : {};
13605
+ const providerFreshness = record10(status.providerHistory.body.freshness) ? status.providerHistory.body.freshness : {};
13440
13606
  out.log(
13441
13607
  `cloudflare-history ${status.providerHistory.httpStatus} ${String(status.providerHistory.body.status ?? status.providerHistory.body.error ?? "unavailable")} ${providerPoints} snapshots ${optionalAge(providerFreshness.ageMs)} old`
13442
13608
  );
@@ -13445,17 +13611,17 @@ function printO11yStatus(status, out) {
13445
13611
  );
13446
13612
  }
13447
13613
  function providerCapacityLines(read3) {
13448
- const resources = record9(read3.body.resources) ? read3.body.resources : {};
13449
- const durableObjects = record9(resources.durableObjects) ? resources.durableObjects : {};
13450
- const periodic = record9(durableObjects.periodic) ? durableObjects.periodic : {};
13451
- const storage = record9(durableObjects.sqliteStorage) ? durableObjects.sqliteStorage : {};
13452
- const d1 = record9(resources.d1) ? resources.d1 : {};
13453
- const d1Activity = record9(d1.activity) ? d1.activity : {};
13454
- const d1Storage = record9(d1.storage) ? d1.storage : {};
13455
- const d1Latency = record9(d1Activity.latency) ? d1Activity.latency : {};
13456
- const r2 = record9(resources.r2) ? resources.r2 : {};
13457
- const r2Operations = record9(r2.operations) ? r2.operations : {};
13458
- const r2Storage = record9(r2.storage) ? r2.storage : {};
13614
+ const resources = record10(read3.body.resources) ? read3.body.resources : {};
13615
+ const durableObjects = record10(resources.durableObjects) ? resources.durableObjects : {};
13616
+ const periodic = record10(durableObjects.periodic) ? durableObjects.periodic : {};
13617
+ const storage = record10(durableObjects.sqliteStorage) ? durableObjects.sqliteStorage : {};
13618
+ const d1 = record10(resources.d1) ? resources.d1 : {};
13619
+ const d1Activity = record10(d1.activity) ? d1.activity : {};
13620
+ const d1Storage = record10(d1.storage) ? d1.storage : {};
13621
+ const d1Latency = record10(d1Activity.latency) ? d1Activity.latency : {};
13622
+ const r2 = record10(resources.r2) ? resources.r2 : {};
13623
+ const r2Operations = record10(r2.operations) ? r2.operations : {};
13624
+ const r2Storage = record10(r2.storage) ? r2.storage : {};
13459
13625
  const status = String(
13460
13626
  read3.body.status ?? read3.body.error ?? "unavailable"
13461
13627
  );
@@ -13466,11 +13632,11 @@ function providerCapacityLines(read3) {
13466
13632
  ];
13467
13633
  }
13468
13634
  function liveSyncLine(read3) {
13469
- const performance = record9(read3.body.performance) ? read3.body.performance : {};
13470
- const commitToSend = record9(performance.commitToSend) ? performance.commitToSend : {};
13635
+ const performance = record10(read3.body.performance) ? read3.body.performance : {};
13636
+ const commitToSend = record10(performance.commitToSend) ? performance.commitToSend : {};
13471
13637
  return `live-sync ${read3.httpStatus} ${String(read3.body.status ?? read3.body.error ?? "unavailable")} ${numeric3(read3.body.activeConnections)} active ${optionalNumeric(commitToSend.p95)} commit-to-send p95 ${numeric3(performance.sendFailures)} send failures`;
13472
13638
  }
13473
- function record9(value2) {
13639
+ function record10(value2) {
13474
13640
  return Boolean(value2) && typeof value2 === "object" && !Array.isArray(value2);
13475
13641
  }
13476
13642
  function numeric3(value2) {
@@ -13808,7 +13974,7 @@ async function monitorCommand(parsed, deps = {}) {
13808
13974
  if (action2 === "plan" || action2 === "apply") {
13809
13975
  const desired = monitoringWireConfig(context.cfg, env);
13810
13976
  const live = await request2(`${base}?env=${encodeURIComponent(env)}`, { headers }, doFetch);
13811
- const currentRevision = record10(live.config) ? string(live.config.revision) : null;
13977
+ const currentRevision = record11(live.config) ? string(live.config.revision) : null;
13812
13978
  const changed = currentRevision !== desired.revision;
13813
13979
  const plan = {
13814
13980
  schemaVersion: 1,
@@ -13853,7 +14019,7 @@ async function monitorCommand(parsed, deps = {}) {
13853
14019
  headers
13854
14020
  }, doFetch);
13855
14021
  emit3(result2, jsonOutput, out, () => {
13856
- const run = record10(result2.run) ? result2.run : {};
14022
+ const run = record11(result2.run) ? result2.run : {};
13857
14023
  out.log(`monitor run ${appId}/${env}/${probeId}: ${string(run.outcome) ?? "unknown"}${run.failure_code ? ` (${String(run.failure_code)})` : ""}`);
13858
14024
  });
13859
14025
  return;
@@ -13878,12 +14044,12 @@ async function request2(url, init, doFetch) {
13878
14044
  let body = {};
13879
14045
  try {
13880
14046
  const parsed = text4 ? JSON.parse(text4) : {};
13881
- body = record10(parsed) ? parsed : { value: parsed };
14047
+ body = record11(parsed) ? parsed : { value: parsed };
13882
14048
  } catch {
13883
14049
  body = { message: text4.slice(0, 500) };
13884
14050
  }
13885
14051
  if (!response2.ok) {
13886
- const error = record10(body.error) ? body.error : body;
14052
+ const error = record11(body.error) ? body.error : body;
13887
14053
  throw new Error(string(error.message) ?? string(error.code) ?? `monitor request failed (${response2.status})`);
13888
14054
  }
13889
14055
  return body;
@@ -13891,7 +14057,7 @@ async function request2(url, init, doFetch) {
13891
14057
  function printRead(action2, appId, env, result, out) {
13892
14058
  if (action2 === "status") {
13893
14059
  out.log(`monitor status ${appId}/${env}: ${String(result.overall ?? (result.configured === false ? "not configured" : "unknown"))}`);
13894
- const slos = Array.isArray(result.slos) ? result.slos.filter(record10) : [];
14060
+ const slos = Array.isArray(result.slos) ? result.slos.filter(record11) : [];
13895
14061
  for (const slo of slos) out.log(`slo ${String(slo.id)} ${String(slo.state)} ${percent(slo.observed)} observed ${percent(slo.budgetRemaining)} budget remaining`);
13896
14062
  const incidents = Array.isArray(result.openIncidents) ? result.openIncidents.length : 0;
13897
14063
  const gaps = Array.isArray(result.monitoringGaps) ? result.monitoringGaps.length : 0;
@@ -13900,20 +14066,20 @@ function printRead(action2, appId, env, result, out) {
13900
14066
  return;
13901
14067
  }
13902
14068
  if (action2 === "incidents") {
13903
- const incidents = Array.isArray(result.incidents) ? result.incidents.filter(record10) : [];
14069
+ const incidents = Array.isArray(result.incidents) ? result.incidents.filter(record11) : [];
13904
14070
  out.log(`monitor incidents ${appId}/${env}: ${incidents.length}`);
13905
14071
  for (const incident2 of incidents) out.log(`${String(incident2.state)} ${String(incident2.kind)} ${String(incident2.slo_id)} ${new Date(Number(incident2.opened_at)).toISOString()}`);
13906
14072
  return;
13907
14073
  }
13908
14074
  out.log(`monitor report ${appId}/${env}: ${String(result.period)} ${String(result.overall)}`);
13909
- const probes = Array.isArray(result.probes) ? result.probes.filter(record10) : [];
14075
+ const probes = Array.isArray(result.probes) ? result.probes.filter(record11) : [];
13910
14076
  for (const probe of probes) out.log(`probe ${String(probe.id)} ${Number(probe.good)} good ${Number(probe.bad)} bad ${Number(probe.unknown)} unknown`);
13911
14077
  }
13912
14078
  function emit3(value2, json, out, human) {
13913
14079
  if (json) out.log(JSON.stringify(value2, null, 2));
13914
14080
  else human();
13915
14081
  }
13916
- function record10(value2) {
14082
+ function record11(value2) {
13917
14083
  return value2 !== null && typeof value2 === "object" && !Array.isArray(value2);
13918
14084
  }
13919
14085
  function string(value2) {
@@ -14404,6 +14570,122 @@ async function provision(options) {
14404
14570
  }
14405
14571
  }
14406
14572
 
14573
+ // src/promotion-command.ts
14574
+ import { readFile as readFile5 } from "fs/promises";
14575
+ import { createAppsClient as createAppsClient4 } from "@odla-ai/apps";
14576
+
14577
+ // src/security-command-context.ts
14578
+ async function hostedSecurityContext(parsed, dependencies) {
14579
+ const configPath = stringOpt(parsed.options.config) ?? "odla.config.mjs";
14580
+ const cfg = await loadProjectConfig(configPath);
14581
+ const env = stringOpt(parsed.options.env) ?? (cfg.envs.includes("dev") ? "dev" : cfg.envs[0]);
14582
+ if (!env || !cfg.envs.includes(env)) {
14583
+ throw new Error(`env "${env ?? ""}" is not declared in ${configPath}`);
14584
+ }
14585
+ const platform = platformAudience(stringOpt(parsed.options.platform) ?? cfg.platformUrl);
14586
+ if (platformAudience(cfg.platformUrl) !== platform) {
14587
+ throw new Error("--platform cannot reuse a project developer token from another platform; update odla.config.mjs and authenticate there");
14588
+ }
14589
+ const doFetch = dependencies.fetch ?? fetch;
14590
+ const stdout = dependencies.stdout ?? console;
14591
+ const open = parsed.options.open === false ? false : parsed.options.open === true ? true : void 0;
14592
+ const token = await getDeveloperToken(
14593
+ cfg,
14594
+ { configPath, email: stringOpt(parsed.options.email), open, openApprovalUrl: dependencies.openUrl },
14595
+ doFetch,
14596
+ stdout,
14597
+ { optionalProjectCapabilities: ["app.manage"] }
14598
+ );
14599
+ return { platform, token, appId: cfg.app.id, env, fetch: doFetch, stdout };
14600
+ }
14601
+ function requiredSecurityPositional(parsed, index, label) {
14602
+ const value2 = parsed.positionals[index];
14603
+ if (!value2) throw new Error(`${label} is required`);
14604
+ return value2;
14605
+ }
14606
+ function securityProfile(value2) {
14607
+ if (value2 === void 0) return void 0;
14608
+ if (value2 === "odla" || value2 === "cloudflare-app" || value2 === "generic") return value2;
14609
+ throw new Error("--profile must be odla, cloudflare-app, or generic");
14610
+ }
14611
+
14612
+ // src/promotion-command.ts
14613
+ var render = (value2, json, out) => {
14614
+ if (json) out.log(JSON.stringify(value2));
14615
+ else out.log(JSON.stringify(value2, null, 2));
14616
+ };
14617
+ async function promotionCommand(parsed, dependencies) {
14618
+ const action2 = parsed.positionals[1];
14619
+ if (!action2 || !["plan", "inspect", "status", "apply", "rollback", "next", "record", "cancel"].includes(action2)) rejectWord(["promotion"], action2);
14620
+ assertArgs(parsed, ["config", "env", "platform", "email", "open", "json", "file", "approval", "idempotency-key"], 5);
14621
+ const context = await hostedSecurityContext(parsed, dependencies);
14622
+ const client = createAppsClient4({
14623
+ token: context.token,
14624
+ fetcher: { fetch: (request3, init) => {
14625
+ const internal = new URL(typeof request3 === "string" ? request3 : request3.url);
14626
+ return context.fetch(`${context.platform}${internal.pathname}${internal.search}`, init);
14627
+ } }
14628
+ });
14629
+ const json = parsed.options.json === true;
14630
+ if (action2 === "plan") {
14631
+ if (parsed.positionals[2]) throw new Error("promotion plan takes --file, not a positional plan id");
14632
+ const file = stringOpt(parsed.options.file);
14633
+ if (!file) throw new Error("--file <promotion-plan.json> is required");
14634
+ const source = JSON.parse(await readFile5(file, "utf8"));
14635
+ const plan2 = await client.createPromotionReleasePlan(context.appId, source);
14636
+ render(plan2, json, context.stdout);
14637
+ return;
14638
+ }
14639
+ const planId = requiredSecurityPositional(parsed, 2, "plan id");
14640
+ if (action2 === "inspect") {
14641
+ if (parsed.positionals[3]) throw new Error("promotion inspect takes only a plan id");
14642
+ const plan2 = await client.getPromotionReleasePlan(context.appId, planId);
14643
+ if (!plan2) throw new Error(`promotion release ${planId} was not found`);
14644
+ render(plan2, json, context.stdout);
14645
+ return;
14646
+ }
14647
+ if (action2 === "status") {
14648
+ if (parsed.positionals[3]) throw new Error("promotion status takes only a plan id");
14649
+ const status = await client.getPromotionReleaseStatus(context.appId, planId);
14650
+ if (!status) throw new Error(`promotion release ${planId} was not found`);
14651
+ render(status, json, context.stdout);
14652
+ return;
14653
+ }
14654
+ if (action2 === "next" || action2 === "cancel" || action2 === "record") {
14655
+ const operationId = requiredSecurityPositional(parsed, 3, "operation id");
14656
+ if (action2 === "next") {
14657
+ if (parsed.positionals[4]) throw new Error("promotion next takes only plan and operation ids");
14658
+ render(await client.claimPromotionReleaseWork(context.appId, planId, operationId), json, context.stdout);
14659
+ return;
14660
+ }
14661
+ if (action2 === "cancel") {
14662
+ if (parsed.positionals[4]) throw new Error("promotion cancel takes only plan and operation ids");
14663
+ render(await client.cancelPromotionReleaseOperation(context.appId, planId, operationId), json, context.stdout);
14664
+ return;
14665
+ }
14666
+ const stepId = requiredSecurityPositional(parsed, 4, "step id");
14667
+ const file = stringOpt(parsed.options.file);
14668
+ if (!file) throw new Error("--file <step-receipt.json> is required");
14669
+ const receipt = JSON.parse(await readFile5(file, "utf8"));
14670
+ render(await client.recordPromotionReleaseWork(context.appId, planId, operationId, stepId, receipt), json, context.stdout);
14671
+ return;
14672
+ }
14673
+ const approvalId = stringOpt(parsed.options.approval);
14674
+ if (parsed.positionals[3]) throw new Error(`promotion ${action2} takes only a plan id`);
14675
+ if (!approvalId) throw new Error(`--approval <approval-id> is required for promotion ${action2}`);
14676
+ const plan = await client.getPromotionReleasePlan(context.appId, planId);
14677
+ if (!plan) throw new Error(`promotion release ${planId} was not found`);
14678
+ if (plan.state !== "reviewable") throw new Error(`promotion release is ${plan.state}: ${plan.blockers.join("; ")}`);
14679
+ const operationAction = action2;
14680
+ const operation = await client.requestPromotionReleaseOperation(context.appId, planId, operationAction, {
14681
+ approvalId,
14682
+ planDigest: plan.planDigest,
14683
+ targetSetDigest: plan.targetSetDigest,
14684
+ idempotencyKey: stringOpt(parsed.options["idempotency-key"]) ?? `${operationAction}:${planId}`
14685
+ });
14686
+ render(operation, json, context.stdout);
14687
+ }
14688
+
14407
14689
  // src/record.ts
14408
14690
  import { appendFileSync } from "fs";
14409
14691
  import process18 from "process";
@@ -14691,7 +14973,7 @@ async function bySlug(ctx, slug) {
14691
14973
  "GET",
14692
14974
  `/runbook?app=${encodeURIComponent(ctx.appId)}&slug=${encodeURIComponent(slug)}&limit=1`
14693
14975
  );
14694
- const filtered = page2.records.find((record11) => record11.slug === slug);
14976
+ const filtered = page2.records.find((record12) => record12.slug === slug);
14695
14977
  if (filtered) return filtered;
14696
14978
  const limit = 100;
14697
14979
  for (let offset = 0; ; offset += limit) {
@@ -14700,7 +14982,7 @@ async function bySlug(ctx, slug) {
14700
14982
  "GET",
14701
14983
  `/runbook?app=${encodeURIComponent(ctx.appId)}&limit=${limit}&offset=${offset}`
14702
14984
  );
14703
- const found = fallback.records.find((record11) => record11.slug === slug);
14985
+ const found = fallback.records.find((record12) => record12.slug === slug);
14704
14986
  if (found) return found;
14705
14987
  if (!fallback.records.length || offset + fallback.records.length >= fallback.total) break;
14706
14988
  }
@@ -15500,41 +15782,6 @@ async function runbookCommand(parsed, deps = {}) {
15500
15782
  }
15501
15783
  }
15502
15784
 
15503
- // src/security-command-context.ts
15504
- async function hostedSecurityContext(parsed, dependencies) {
15505
- const configPath = stringOpt(parsed.options.config) ?? "odla.config.mjs";
15506
- const cfg = await loadProjectConfig(configPath);
15507
- const env = stringOpt(parsed.options.env) ?? (cfg.envs.includes("dev") ? "dev" : cfg.envs[0]);
15508
- if (!env || !cfg.envs.includes(env)) {
15509
- throw new Error(`env "${env ?? ""}" is not declared in ${configPath}`);
15510
- }
15511
- const platform = platformAudience(stringOpt(parsed.options.platform) ?? cfg.platformUrl);
15512
- if (platformAudience(cfg.platformUrl) !== platform) {
15513
- throw new Error("--platform cannot reuse a project developer token from another platform; update odla.config.mjs and authenticate there");
15514
- }
15515
- const doFetch = dependencies.fetch ?? fetch;
15516
- const stdout = dependencies.stdout ?? console;
15517
- const open = parsed.options.open === false ? false : parsed.options.open === true ? true : void 0;
15518
- const token = await getDeveloperToken(
15519
- cfg,
15520
- { configPath, email: stringOpt(parsed.options.email), open, openApprovalUrl: dependencies.openUrl },
15521
- doFetch,
15522
- stdout,
15523
- { optionalProjectCapabilities: ["app.manage"] }
15524
- );
15525
- return { platform, token, appId: cfg.app.id, env, fetch: doFetch, stdout };
15526
- }
15527
- function requiredSecurityPositional(parsed, index, label) {
15528
- const value2 = parsed.positionals[index];
15529
- if (!value2) throw new Error(`${label} is required`);
15530
- return value2;
15531
- }
15532
- function securityProfile(value2) {
15533
- if (value2 === void 0) return void 0;
15534
- if (value2 === "odla" || value2 === "cloudflare-app" || value2 === "generic") return value2;
15535
- throw new Error("--profile must be odla, cloudflare-app, or generic");
15536
- }
15537
-
15538
15785
  // src/security-command-output.ts
15539
15786
  function printHostedSecurityPlan(out, plan, appId) {
15540
15787
  out.log(`Hosted security plan for ${appId}/${plan.env}: ${plan.ready ? "ready" : "not ready"}`);
@@ -16272,6 +16519,10 @@ async function dispatchCli(argv, dependencies) {
16272
16519
  await securityCommand(parsed, runtime);
16273
16520
  return;
16274
16521
  }
16522
+ if (command === "promotion") {
16523
+ await promotionCommand(parsed, runtime);
16524
+ return;
16525
+ }
16275
16526
  if (command === "brand") {
16276
16527
  await brandCommand(parsed, runtime);
16277
16528
  return;
@@ -16436,4 +16687,4 @@ export {
16436
16687
  isTerminalHostedSecurityStatus,
16437
16688
  runCli
16438
16689
  };
16439
- //# sourceMappingURL=chunk-J6GIGX6T.js.map
16690
+ //# sourceMappingURL=chunk-BD5KIG63.js.map