@odla-ai/cli 0.26.1 → 0.27.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.
@@ -138,7 +138,7 @@ import process2 from "process";
138
138
  async function openUrl(url, options = {}) {
139
139
  const command = openerFor(options.platform ?? process2.platform);
140
140
  const doSpawn = options.spawnImpl ?? spawn;
141
- await new Promise((resolve12, reject) => {
141
+ await new Promise((resolve13, reject) => {
142
142
  const child = doSpawn(command.cmd, [...command.args, url], {
143
143
  stdio: "ignore",
144
144
  detached: true
@@ -146,7 +146,7 @@ async function openUrl(url, options = {}) {
146
146
  child.once("error", reject);
147
147
  child.once("spawn", () => {
148
148
  child.unref();
149
- resolve12();
149
+ resolve13();
150
150
  });
151
151
  });
152
152
  }
@@ -439,7 +439,6 @@ function audienceBoundEnvToken(token, platform) {
439
439
  }
440
440
  var SCOPE_PURPOSE = {
441
441
  "platform:status:read": "read the platform fleet health and deployment snapshot",
442
- "platform:chat:credential:write": "rotate the built-in Discussion responder credential",
443
442
  "app:config:read": "compare checked-in intent with an exact-id app Registry configuration",
444
443
  "app:config:write": "apply or inspect one revision-bound configuration operation for an app you own",
445
444
  "platform:runbook:write": "add or edit odla's operational runbooks",
@@ -1445,8 +1444,8 @@ function credential(value2) {
1445
1444
  // src/calendar-poll.ts
1446
1445
  async function waitForCalendarPoll(milliseconds, signal) {
1447
1446
  if (signal?.aborted) throw signal.reason ?? new Error("calendar connection aborted");
1448
- await new Promise((resolve12, reject) => {
1449
- const timer = setTimeout(resolve12, milliseconds);
1447
+ await new Promise((resolve13, reject) => {
1448
+ const timer = setTimeout(resolve13, milliseconds);
1450
1449
  signal?.addEventListener("abort", () => {
1451
1450
  clearTimeout(timer);
1452
1451
  reject(signal.reason ?? new Error("calendar connection aborted"));
@@ -1837,9 +1836,9 @@ function canonicalValue(value2) {
1837
1836
  }
1838
1837
  if (Array.isArray(value2)) return value2.map(canonicalValue);
1839
1838
  if (value2 && typeof value2 === "object") {
1840
- const record11 = value2;
1839
+ const record10 = value2;
1841
1840
  return Object.fromEntries(
1842
- Object.keys(record11).filter((key) => record11[key] !== void 0).sort().map((key) => [key, canonicalValue(record11[key])])
1841
+ Object.keys(record10).filter((key) => record10[key] !== void 0).sort().map((key) => [key, canonicalValue(record10[key])])
1843
1842
  );
1844
1843
  }
1845
1844
  throw new TypeError("canonical JSON rejects unsupported values");
@@ -2084,7 +2083,7 @@ async function configOperationWait(options) {
2084
2083
  assertOperationId(options.operationId);
2085
2084
  const cfg = await loadProjectConfig(options.configPath);
2086
2085
  const client = await operationClient(cfg, options, "wait");
2087
- const wait2 = options.pollWait ?? ((ms) => new Promise((resolve12) => setTimeout(resolve12, ms)));
2086
+ const wait2 = options.pollWait ?? ((ms) => new Promise((resolve13) => setTimeout(resolve13, ms)));
2088
2087
  const now = () => (options.now?.() ?? /* @__PURE__ */ new Date()).getTime();
2089
2088
  const deadline = now() + (options.timeoutSeconds ?? DEFAULT_WAIT_SECONDS) * 1e3;
2090
2089
  const interval = (options.intervalSeconds ?? DEFAULT_INTERVAL_SECONDS) * 1e3;
@@ -3767,8 +3766,8 @@ function hostedPollTimeout(value2 = 10 * 6e4) {
3767
3766
  }
3768
3767
  async function waitForHostedPoll(milliseconds, signal) {
3769
3768
  if (signal?.aborted) throw signal.reason ?? new DOMException("aborted", "AbortError");
3770
- await new Promise((resolve12, reject) => {
3771
- const timer = setTimeout(resolve12, milliseconds);
3769
+ await new Promise((resolve13, reject) => {
3770
+ const timer = setTimeout(resolve13, milliseconds);
3772
3771
  signal?.addEventListener("abort", () => {
3773
3772
  clearTimeout(timer);
3774
3773
  reject(signal.reason ?? new DOMException("aborted", "AbortError"));
@@ -4397,8 +4396,8 @@ async function materializeGitTree(source, commitSha, options = {}) {
4397
4396
  const maxFiles = options.maxFiles ?? 2e4;
4398
4397
  const maxBytes = options.maxBytes ?? 512 * 1024 * 1024;
4399
4398
  const inventory = (await gitOutput(sourceDir, ["ls-tree", "-rz", commitSha], 16 * 1024 * 1024)).toString("utf8").split("\0").filter(Boolean);
4400
- const entries = inventory.flatMap((record11) => {
4401
- const match = /^(100644|100755) blob ([0-9a-f]{40,64})\t([\s\S]+)$/.exec(record11);
4399
+ const entries = inventory.flatMap((record10) => {
4400
+ const match = /^(100644|100755) blob ([0-9a-f]{40,64})\t([\s\S]+)$/.exec(record10);
4402
4401
  return match && allowedWorkspacePath(match[3]) ? [{ mode: match[1], hash: match[2], path: match[3] }] : [];
4403
4402
  });
4404
4403
  if (entries.length > maxFiles) throw new Error(`workspace exceeds ${maxFiles} files`);
@@ -4646,8 +4645,8 @@ function normalize(value2) {
4646
4645
  if (Array.isArray(value2)) return value2.map(normalize);
4647
4646
  if (value2 instanceof Uint8Array) return { $bytes: [...value2] };
4648
4647
  if (typeof value2 === "object") {
4649
- const record11 = value2;
4650
- return Object.fromEntries(Object.keys(record11).filter((key) => record11[key] !== void 0).sort().map((key) => [key, normalize(record11[key])]));
4648
+ const record10 = value2;
4649
+ return Object.fromEntries(Object.keys(record10).filter((key) => record10[key] !== void 0).sort().map((key) => [key, normalize(record10[key])]));
4651
4650
  }
4652
4651
  throw new CamelError("state_conflict", "Canonical JSON rejects unsupported values.");
4653
4652
  }
@@ -7514,6 +7513,7 @@ var COMMAND_SURFACE = {
7514
7513
  promote: {},
7515
7514
  owners: { list: {}, add: {}, remove: {} }
7516
7515
  },
7516
+ brand: { design: { unpack: {} } },
7517
7517
  calendar: { status: {}, calendars: {}, connect: {}, disconnect: {} },
7518
7518
  capabilities: {},
7519
7519
  code: { connect: {} },
@@ -7537,8 +7537,7 @@ var COMMAND_SURFACE = {
7537
7537
  o11y: { status: {} },
7538
7538
  operations: { get: {}, wait: {} },
7539
7539
  platform: {
7540
- status: {},
7541
- "chat-credentials": { rotate: {} }
7540
+ status: {}
7542
7541
  },
7543
7542
  pm: {
7544
7543
  ...PM_ENTITIES,
@@ -8881,6 +8880,158 @@ async function appCommand(parsed, dependencies = {}) {
8881
8880
  else await appRestore(options);
8882
8881
  }
8883
8882
 
8883
+ // src/brand-command.ts
8884
+ import { mkdir as mkdir4, readFile as readFile3, writeFile as writeFile4 } from "fs/promises";
8885
+ import { dirname as dirname8, resolve as resolve12 } from "path";
8886
+
8887
+ // src/brand-design-unpack.ts
8888
+ import { gunzipSync } from "zlib";
8889
+ import {
8890
+ digestDesignBundle,
8891
+ parseDesignBundle,
8892
+ readDesignManifest,
8893
+ renderTokensCss
8894
+ } from "@odla-ai/brand";
8895
+ var EXTENSIONS = {
8896
+ "image/png": "png",
8897
+ "image/jpeg": "jpg",
8898
+ "image/gif": "gif",
8899
+ "image/webp": "webp",
8900
+ "image/svg+xml": "svg",
8901
+ "image/avif": "avif",
8902
+ "font/woff2": "woff2",
8903
+ "font/woff": "woff",
8904
+ "font/ttf": "ttf",
8905
+ "font/otf": "otf",
8906
+ "text/javascript": "js",
8907
+ "application/javascript": "js",
8908
+ "text/css": "css",
8909
+ "text/html": "html",
8910
+ "application/json": "json"
8911
+ };
8912
+ var encode = (text2) => new TextEncoder().encode(text2);
8913
+ function assetFileName(uuid, mime) {
8914
+ const ext = EXTENSIONS[mime.split(";")[0].trim().toLowerCase()] ?? "bin";
8915
+ return `${uuid.replace(/[^a-zA-Z0-9._-]/g, "_")}.${ext}`;
8916
+ }
8917
+ function decodePayload(data, compressed) {
8918
+ const raw = Buffer.from(data, "base64");
8919
+ return new Uint8Array(compressed ? gunzipSync(raw) : raw);
8920
+ }
8921
+ function rewriteReferences(template, assetPaths, pagePaths) {
8922
+ let out = template;
8923
+ for (const [uuid, path] of pagePaths) {
8924
+ out = out.split(`about:blank#${uuid}`).join(path);
8925
+ }
8926
+ for (const [uuid, path] of assetPaths) {
8927
+ out = out.split(uuid).join(path);
8928
+ }
8929
+ return out;
8930
+ }
8931
+ function tokensCss(digest) {
8932
+ if (Object.keys(digest.tokens.light).length === 0) return null;
8933
+ return renderTokensCss(digest.tokens.light, { dark: digest.tokens.dark });
8934
+ }
8935
+ function unpackDesign(html) {
8936
+ const bundle = parseDesignBundle(html);
8937
+ const manifest = readDesignManifest(html);
8938
+ const digest = digestDesignBundle(bundle);
8939
+ const pageUuids = new Set(bundle.pageOrder);
8940
+ const files = [];
8941
+ const failed = [];
8942
+ const assetPaths = /* @__PURE__ */ new Map();
8943
+ const pagePaths = /* @__PURE__ */ new Map();
8944
+ for (const [uuid, entry] of Object.entries(manifest)) {
8945
+ let bytes;
8946
+ try {
8947
+ bytes = decodePayload(entry.data, entry.compressed);
8948
+ } catch {
8949
+ failed.push(uuid);
8950
+ continue;
8951
+ }
8952
+ if (pageUuids.has(uuid)) {
8953
+ const path2 = `pages/${assetFileName(uuid, "text/html")}`;
8954
+ pagePaths.set(uuid, `./${path2}`);
8955
+ files.push({ path: path2, bytes });
8956
+ continue;
8957
+ }
8958
+ const path = `assets/${assetFileName(uuid, entry.mime)}`;
8959
+ assetPaths.set(uuid, `./${path}`);
8960
+ files.push({ path, bytes });
8961
+ }
8962
+ files.push({
8963
+ path: "index.html",
8964
+ bytes: encode(rewriteReferences(bundle.template, assetPaths, pagePaths))
8965
+ });
8966
+ files.push({ path: "digest.json", bytes: encode(`${JSON.stringify(digest, null, 2)}
8967
+ `) });
8968
+ const css = tokensCss(digest);
8969
+ if (css !== null) files.push({ path: "tokens.css", bytes: encode(css) });
8970
+ if (bundle.thumbnailSvg) files.push({ path: "thumbnail.svg", bytes: encode(bundle.thumbnailSvg) });
8971
+ return { files, digest, failed };
8972
+ }
8973
+ function describeUnpack(result, outDir) {
8974
+ const { digest } = result;
8975
+ const lines = [
8976
+ `Unpacked ${digest.title ? `"${digest.title}"` : "design"} into ${outDir}`,
8977
+ ` index.html the design, offline-runnable (${digest.templateBytes} bytes)`,
8978
+ ` assets/ ${digest.assetCount} embedded files (${digest.assetBytes} bytes)`,
8979
+ ` digest.json ${Object.keys(digest.tokens.light).length} --ui-* tokens, ${digest.props.length} props, ${digest.outline.length} headings`
8980
+ ];
8981
+ if (result.files.some((f) => f.path === "tokens.css"))
8982
+ lines.push(" tokens.css the design's tokens as an @odla-ai/ui theme sheet");
8983
+ if (digest.fonts.length > 0) lines.push(`Typefaces: ${digest.fonts.join(", ")}`);
8984
+ if (result.failed.length > 0)
8985
+ lines.push(`WARNING: ${result.failed.length} embedded asset(s) could not be decoded.`);
8986
+ return lines;
8987
+ }
8988
+
8989
+ // src/brand-command.ts
8990
+ var USAGE = "usage: odla-ai brand design unpack <bundle.html|-> [--out <dir>] [--json]";
8991
+ async function readBundle(source, deps) {
8992
+ if (source !== "-") return readFile3(resolve12(source), "utf8");
8993
+ const readStdin = deps.readStdin;
8994
+ if (!readStdin) throw new Error("reading a bundle from stdin is not supported here");
8995
+ return readStdin();
8996
+ }
8997
+ async function writeAll(result, outDir) {
8998
+ for (const file of result.files) {
8999
+ const target = resolve12(outDir, file.path);
9000
+ await mkdir4(dirname8(target), { recursive: true });
9001
+ await writeFile4(target, file.bytes);
9002
+ }
9003
+ }
9004
+ async function designUnpack(parsed, deps) {
9005
+ assertArgs(parsed, ["out", "json"], 4);
9006
+ const source = parsed.positionals[3];
9007
+ if (!source) throw new Error(USAGE);
9008
+ const outDir = resolve12(stringOpt(parsed.options.out) ?? "design");
9009
+ const result = unpackDesign(await readBundle(source, deps));
9010
+ await writeAll(result, outDir);
9011
+ const out = deps.stdout ?? console;
9012
+ if (parsed.options.json === true) {
9013
+ out.log(
9014
+ JSON.stringify({
9015
+ outDir,
9016
+ files: result.files.map((f) => f.path),
9017
+ failed: result.failed,
9018
+ digest: result.digest
9019
+ })
9020
+ );
9021
+ return;
9022
+ }
9023
+ for (const line of describeUnpack(result, outDir)) out.log(line);
9024
+ }
9025
+ async function brandCommand(parsed, deps) {
9026
+ const subject = parsed.positionals[1];
9027
+ const action2 = parsed.positionals[2];
9028
+ if (subject === "design" && action2 === "unpack") {
9029
+ await designUnpack(parsed, deps);
9030
+ return;
9031
+ }
9032
+ throw new Error(USAGE);
9033
+ }
9034
+
8884
9035
  // src/harness-options.ts
8885
9036
  function harnessList(parsed) {
8886
9037
  const selected = [
@@ -9257,10 +9408,8 @@ function requireName(parsed) {
9257
9408
  return name;
9258
9409
  }
9259
9410
 
9260
- // src/help.ts
9261
- function printHelp(output = console) {
9262
- output.log(`odla-ai
9263
-
9411
+ // src/help-usage.ts
9412
+ var USAGE_SECTION = `
9264
9413
  Start here:
9265
9414
  odla-ai runbook ask "<question>" The current procedure, from odla's own
9266
9415
  runbooks. Ask BEFORE searching the web or
@@ -9294,6 +9443,7 @@ Usage:
9294
9443
  odla-ai app owners list [--config odla.config.mjs] [--email <odla-account>] [--json]
9295
9444
  odla-ai app owners add <email> [--email <odla-account>] [--json]
9296
9445
  odla-ai app owners remove <email> [--email <odla-account>] [--json]
9446
+ odla-ai brand design unpack <bundle.html|-> [--out <dir>] [--json]
9297
9447
  odla-ai pm goal list [--app <id>] [--status <s>] [--q <text>] [--limit <n>] [--offset <n>] [--json]
9298
9448
  odla-ai pm task list [--app <id>] [--column <c>] [--goal <id>] [--assignee <id>] [--q <text>] [--limit <n>] [--offset <n>] [--json]
9299
9449
  odla-ai pm decision list [--app <id>] [--status <s>] [--q <text>] [--limit <n>] [--offset <n>] [--json]
@@ -9329,7 +9479,6 @@ Usage:
9329
9479
  odla-ai context remove <name> --yes [--json]
9330
9480
  odla-ai o11y status [--app <id>] [--context <name>] [--platform https://odla.ai] [--env prod] [--minutes 60] [--json]
9331
9481
  odla-ai platform status [--context <name>] [--platform https://odla.ai] [--email <odla-account>] [--json]
9332
- odla-ai platform chat-credentials rotate [--context <name>] [--email <odla-account>] [--wrangler-config <path>] [--expected-version <id>] [--json] --yes
9333
9482
  odla-ai whoami [--context <name>] [--platform https://odla.ai] [--json]
9334
9483
  odla-ai runbook ask "<question>" [--app <id>] [--all] [--json]
9335
9484
  odla-ai runbook search "<question>" [--app <id>] [--all] [--limit <n>] [--json]
@@ -9374,8 +9523,12 @@ Usage:
9374
9523
  odla-ai secrets push --env <env> [--config odla.config.mjs] [--dry-run] [--yes]
9375
9524
  odla-ai secrets set <name> --env <env> (--from-env <NAME>|--stdin) [--email <odla-account>] [--config odla.config.mjs] [--yes]
9376
9525
  odla-ai secrets set-clerk-key --env <env> (--from-env <NAME>|--stdin) [--email <odla-account>] [--config odla.config.mjs] [--yes]
9377
- odla-ai version
9526
+ odla-ai version`;
9378
9527
 
9528
+ // src/help.ts
9529
+ function printHelp(output = console) {
9530
+ output.log(`odla-ai
9531
+ ${USAGE_SECTION}
9379
9532
  Commands:
9380
9533
  agent Inspect durable agent wakeups and explicitly requeue a
9381
9534
  dead-lettered job; JSON output is stable for remote operators.
@@ -9824,7 +9977,7 @@ function jsonl(ctx, parsed, value2) {
9824
9977
  }
9825
9978
  async function discussWatch(ctx, topicId, parsed) {
9826
9979
  if (ctx.json && parsed.options.jsonl === true) throw new Error("--json and --jsonl cannot be combined");
9827
- const sleep = ctx.sleep ?? ((ms) => new Promise((resolve12) => setTimeout(resolve12, ms)));
9980
+ const sleep = ctx.sleep ?? ((ms) => new Promise((resolve13) => setTimeout(resolve13, ms)));
9828
9981
  const now = ctx.now ?? Date.now;
9829
9982
  const intervalMs = (numberOpt2(parsed, "interval", DEFAULT_INTERVAL_MS / 1e3) ?? DEFAULT_INTERVAL_MS / 1e3) * 1e3;
9830
9983
  const timeoutSeconds = numberOpt2(parsed, "timeout");
@@ -10162,8 +10315,8 @@ async function pmAdd(ctx, entity, parsed) {
10162
10315
  emit2(ctx, res, () => ctx.out.log(`created ${entity} ${res.id}`));
10163
10316
  }
10164
10317
  async function pmGet(ctx, entity, id) {
10165
- const { record: record11 } = await pmRequest(ctx, "GET", `/${entity}/${encodeURIComponent(id)}`);
10166
- emit2(ctx, record11, () => printRecord(ctx, entity, record11));
10318
+ const { record: record10 } = await pmRequest(ctx, "GET", `/${entity}/${encodeURIComponent(id)}`);
10319
+ emit2(ctx, record10, () => printRecord(ctx, entity, record10));
10167
10320
  }
10168
10321
  async function pmSet(ctx, entity, id, parsed) {
10169
10322
  const patch2 = collectEntityFields(entity, parsed, true);
@@ -10208,9 +10361,9 @@ async function pmHandoff(ctx, parsed) {
10208
10361
  ]);
10209
10362
  const handoff = {
10210
10363
  appId,
10211
- unmetGoals: goals.filter((record11) => record11.status !== "met"),
10212
- activeTasks: tasks.filter((record11) => record11.column !== "done"),
10213
- openBugs: bugs.filter((record11) => record11.status !== "fixed" && record11.status !== "wontfix")
10364
+ unmetGoals: goals.filter((record10) => record10.status !== "met"),
10365
+ activeTasks: tasks.filter((record10) => record10.column !== "done"),
10366
+ openBugs: bugs.filter((record10) => record10.status !== "fixed" && record10.status !== "wontfix")
10214
10367
  };
10215
10368
  const result = {
10216
10369
  ...handoff,
@@ -10229,10 +10382,10 @@ async function pmHandoff(ctx, parsed) {
10229
10382
  ]) {
10230
10383
  ctx.out.log(`${label}:`);
10231
10384
  if (!records.length) ctx.out.log("- (none)");
10232
- else for (const record11 of records) printRecord(
10385
+ else for (const record10 of records) printRecord(
10233
10386
  ctx,
10234
10387
  label === "unmet goals" ? "goal" : label === "active tasks" ? "task" : "bug",
10235
- record11
10388
+ record10
10236
10389
  );
10237
10390
  }
10238
10391
  });
@@ -10423,167 +10576,12 @@ function age(input) {
10423
10576
  return `${Math.round(input / 6e4)}m`;
10424
10577
  }
10425
10578
 
10426
- // src/platform-chat-credential-command.ts
10427
- import process12 from "process";
10428
- async function rotatePlatformChatCredential(parsed, deps) {
10429
- assertArgs(
10430
- parsed,
10431
- [
10432
- "config",
10433
- "context",
10434
- "platform",
10435
- "token",
10436
- "email",
10437
- "open",
10438
- "json",
10439
- "yes",
10440
- "wrangler-config",
10441
- "expected-version"
10442
- ],
10443
- 3
10444
- );
10445
- if (parsed.options.yes !== true) {
10446
- throw new Error(
10447
- "platform chat-credentials rotate changes the production chat secret; pass --yes"
10448
- );
10449
- }
10450
- const context = await resolveOperatorContext(parsed, {
10451
- allowMissingConfig: true
10452
- });
10453
- const platform = context.platform.value;
10454
- const doFetch = deps.fetch ?? fetch;
10455
- const out = deps.stdout ?? console;
10456
- const run = deps.runner ?? defaultRunner;
10457
- const cwd = process12.cwd();
10458
- const wranglerConfig = stringOpt(parsed.options["wrangler-config"]) ?? "packages/chat-agent/wrangler.jsonc";
10459
- if (!await wranglerLoggedIn(run, cwd)) {
10460
- throw new Error(
10461
- 'Wrangler is not authenticated; run "npx wrangler login" and retry'
10462
- );
10463
- }
10464
- const priorHealth = await doFetch(`${platform}/health/services/chat`);
10465
- const priorVersion = priorHealth.headers.get("x-odla-worker-version-id");
10466
- await priorHealth.body?.cancel().catch(() => {
10467
- });
10468
- if (!priorVersion) {
10469
- throw new Error(
10470
- "chat health did not identify its current Worker version; refusing to rotate"
10471
- );
10472
- }
10473
- const expectedVersion = stringOpt(parsed.options["expected-version"]);
10474
- if (expectedVersion && priorVersion !== expectedVersion) {
10475
- throw new Error(
10476
- `chat health answered from version ${priorVersion}; expected ${expectedVersion}`
10477
- );
10478
- }
10479
- const token = await resolveAdminPlatformToken({
10480
- platform,
10481
- scope: "platform:chat:credential:write",
10482
- token: stringOpt(parsed.options.token),
10483
- tokenFile: context.credentials.scopedTokenFile,
10484
- email: stringOpt(parsed.options.email),
10485
- open: parsed.options.open === false ? false : parsed.options.open === true ? true : void 0,
10486
- fetch: doFetch,
10487
- stdout: out,
10488
- openApprovalUrl: deps.openUrl,
10489
- label: "odla CLI (rotate built-in Discussion responder)"
10490
- });
10491
- const mintedResponse = await doFetch(
10492
- `${platform}/registry/platform/chat-credentials/rotate`,
10493
- {
10494
- method: "POST",
10495
- headers: { authorization: `Bearer ${token}` }
10496
- }
10497
- );
10498
- const minted = await mintedResponse.json().catch(() => null);
10499
- if (!mintedResponse.ok) {
10500
- throw new Error(
10501
- `mint Discussion credential failed (HTTP ${mintedResponse.status}): ${apiMessage(minted)}`
10502
- );
10503
- }
10504
- if (!isPlatformChatCredential(minted)) {
10505
- throw new Error(
10506
- "platform returned an invalid odla.platform-chat-credential/v1 envelope"
10507
- );
10508
- }
10509
- const put = await wranglerPutSecret(run, {
10510
- name: "ODLA_BOT_TOKENS",
10511
- value: JSON.stringify({
10512
- [minted.appId]: { [minted.principalId]: minted.key }
10513
- }),
10514
- configPath: wranglerConfig,
10515
- cwd
10516
- });
10517
- if (put.code !== 0) {
10518
- throw new Error(
10519
- "Wrangler could not replace ODLA_BOT_TOKENS; the new scoped key was not activated"
10520
- );
10521
- }
10522
- const version = await waitForRotatedChatHealth({
10523
- fetch: doFetch,
10524
- platform,
10525
- priorVersion,
10526
- wait: deps.pollWait
10527
- });
10528
- const result = {
10529
- schemaVersion: "odla.platform-chat-credential-rotation/v1",
10530
- appId: minted.appId,
10531
- appIncarnation: minted.appIncarnation,
10532
- principalId: minted.principalId,
10533
- health: { ok: true, service: "odla-chat-agent", version }
10534
- };
10535
- if (parsed.options.json === true) {
10536
- out.log(JSON.stringify(result, null, 2));
10537
- } else {
10538
- out.log(
10539
- `rotated ${result.appId} ${result.principalId} ${result.health.version}`
10540
- );
10541
- }
10542
- }
10543
- async function waitForRotatedChatHealth(opts) {
10544
- const wait2 = opts.wait ?? ((milliseconds) => new Promise((resolve12) => setTimeout(resolve12, milliseconds)));
10545
- let lastStatus = 0;
10546
- let lastVersion = null;
10547
- let lastError = "private_service_unready";
10548
- for (let attempt = 0; attempt < 60; attempt++) {
10549
- const response2 = await opts.fetch(
10550
- `${opts.platform}/health/services/chat`
10551
- );
10552
- const body = await response2.json().catch(() => null);
10553
- const version = response2.headers.get("x-odla-worker-version-id");
10554
- if (response2.ok && record7(body) && body.ok === true && body.service === "odla-chat-agent" && version && version !== opts.priorVersion) {
10555
- return version;
10556
- }
10557
- lastStatus = response2.status;
10558
- lastVersion = version;
10559
- lastError = record7(body) && typeof body.error === "string" ? body.error : "private_service_unready";
10560
- if (attempt < 59) await wait2(5e3);
10561
- }
10562
- throw new Error(
10563
- `chat health did not converge on the rotated Worker deployment (HTTP ${lastStatus}, version ${lastVersion ?? "unknown"}, ${lastError})`
10564
- );
10565
- }
10566
- function isPlatformChatCredential(value2) {
10567
- return record7(value2) && value2.schemaVersion === "odla.platform-chat-credential/v1" && value2.appId === "odla-pm" && typeof value2.appIncarnation === "string" && value2.appIncarnation.length > 0 && value2.principalId === "agent_odla" && typeof value2.key === "string" && value2.key.startsWith("odla_sk_");
10568
- }
10569
- function apiMessage(value2) {
10570
- if (!record7(value2)) return "request failed";
10571
- const error = record7(value2.error) ? value2.error : value2;
10572
- return typeof error.message === "string" ? error.message : typeof error.code === "string" ? error.code : "request failed";
10573
- }
10574
- function record7(value2) {
10575
- return !!value2 && typeof value2 === "object" && !Array.isArray(value2);
10576
- }
10577
-
10578
10579
  // src/platform-command.ts
10579
10580
  async function platformCommand(parsed, deps = {}) {
10580
10581
  const action2 = parsed.positionals[1];
10581
10582
  if (action2 === "status") {
10582
10583
  return platformStatus(parsed, deps);
10583
10584
  }
10584
- if (action2 === "chat-credentials" && parsed.positionals[2] === "rotate") {
10585
- return rotatePlatformChatCredential(parsed, deps);
10586
- }
10587
10585
  throw new Error(
10588
10586
  `unknown platform action "${[
10589
10587
  action2,
@@ -10621,7 +10619,7 @@ async function platformStatus(parsed, deps) {
10621
10619
  const body = await response2.json().catch(() => null);
10622
10620
  if (!response2.ok) {
10623
10621
  throw new Error(
10624
- `read platform status failed (HTTP ${response2.status}): ${apiMessage2(body)}`
10622
+ `read platform status failed (HTTP ${response2.status}): ${apiMessage(body)}`
10625
10623
  );
10626
10624
  }
10627
10625
  if (!isPlatformStatus(body)) {
@@ -10634,17 +10632,17 @@ async function platformStatus(parsed, deps) {
10634
10632
  }
10635
10633
  }
10636
10634
  function isPlatformStatus(value2) {
10637
- if (!record8(value2) || value2.schemaVersion !== "odla.platform-status/v1") return false;
10638
- if (!record8(value2.verdict) || !Array.isArray(value2.verdict.reasons)) return false;
10639
- if (!record8(value2.catalog) || !record8(value2.summary)) return false;
10635
+ if (!record7(value2) || value2.schemaVersion !== "odla.platform-status/v1") return false;
10636
+ if (!record7(value2.verdict) || !Array.isArray(value2.verdict.reasons)) return false;
10637
+ if (!record7(value2.catalog) || !record7(value2.summary)) return false;
10640
10638
  return Array.isArray(value2.services) && Array.isArray(value2.nextActions);
10641
10639
  }
10642
- function apiMessage2(value2) {
10643
- if (!record8(value2)) return "request failed";
10644
- const error = record8(value2.error) ? value2.error : value2;
10640
+ function apiMessage(value2) {
10641
+ if (!record7(value2)) return "request failed";
10642
+ const error = record7(value2.error) ? value2.error : value2;
10645
10643
  return typeof error.message === "string" ? error.message : typeof error.code === "string" ? error.code : "request failed";
10646
10644
  }
10647
- function record8(value2) {
10645
+ function record7(value2) {
10648
10646
  return !!value2 && typeof value2 === "object" && !Array.isArray(value2);
10649
10647
  }
10650
10648
 
@@ -10685,7 +10683,7 @@ function statusVerdict(reads) {
10685
10683
  severity: "degraded"
10686
10684
  });
10687
10685
  }
10688
- const performance = record9(reads.liveSync.body.performance) ? reads.liveSync.body.performance : null;
10686
+ const performance = record8(reads.liveSync.body.performance) ? reads.liveSync.body.performance : null;
10689
10687
  if (performance?.status === "unavailable") {
10690
10688
  reasons.push({
10691
10689
  source: "liveSync",
@@ -10766,7 +10764,7 @@ function statusVerdict(reads) {
10766
10764
  reasons
10767
10765
  };
10768
10766
  }
10769
- function record9(value2) {
10767
+ function record8(value2) {
10770
10768
  return Boolean(value2) && typeof value2 === "object" && !Array.isArray(value2);
10771
10769
  }
10772
10770
  function numeric2(value2) {
@@ -10794,7 +10792,7 @@ function printO11yStatus(status, out) {
10794
10792
  out.log(
10795
10793
  `o11y status ${status.scope.appId}/${status.scope.env} (${status.scope.minutes}m)`
10796
10794
  );
10797
- const routes = Array.isArray(status.application.body.routes) ? status.application.body.routes.filter(record10) : [];
10795
+ const routes = Array.isArray(status.application.body.routes) ? status.application.body.routes.filter(record9) : [];
10798
10796
  const requests = routes.reduce(
10799
10797
  (total, row) => total + numeric3(row.requests),
10800
10798
  0
@@ -10806,39 +10804,39 @@ function printO11yStatus(status, out) {
10806
10804
  out.log(
10807
10805
  `application ${status.application.httpStatus} ${requests} requests ${errors} errors`
10808
10806
  );
10809
- const versions = Array.isArray(status.applicationVersions.body.rows) ? status.applicationVersions.body.rows.filter(record10) : [];
10807
+ const versions = Array.isArray(status.applicationVersions.body.rows) ? status.applicationVersions.body.rows.filter(record9) : [];
10810
10808
  out.log(
10811
10809
  `application-versions ${status.applicationVersions.httpStatus} ${versions.length ? versions.slice(0, 5).map(
10812
10810
  (row) => `${String(row.value || "(unattributed)")}:${numeric3(row.requests)}`
10813
10811
  ).join(", ") : "none observed"}`
10814
10812
  );
10815
10813
  out.log(liveSyncLine(status.liveSync));
10816
- const canaryDurations = record10(status.canary.body.durationsMs) ? status.canary.body.durationsMs : {};
10814
+ const canaryDurations = record9(status.canary.body.durationsMs) ? status.canary.body.durationsMs : {};
10817
10815
  out.log(
10818
10816
  `canary ${status.canary.httpStatus} ${String(status.canary.body.status ?? status.canary.body.error ?? "unavailable")} ${optionalNumeric(canaryDurations.publishToVisibleMs)} publish-to-visible`
10819
10817
  );
10820
- const collectorIngest = record10(status.collector.body.ingest) ? status.collector.body.ingest : {};
10821
- const collectorStorage = record10(collectorIngest.storage) ? collectorIngest.storage : {};
10818
+ const collectorIngest = record9(status.collector.body.ingest) ? status.collector.body.ingest : {};
10819
+ const collectorStorage = record9(collectorIngest.storage) ? collectorIngest.storage : {};
10822
10820
  out.log(
10823
10821
  `collector ${status.collector.httpStatus} ${String(status.collector.body.status ?? status.collector.body.error ?? "unavailable")} ${numeric3(collectorStorage.affectedPoints)} affected points`
10824
10822
  );
10825
- const providerMetrics = record10(status.provider.body.metrics) ? status.provider.body.metrics : {};
10826
- const providerCapacity = record10(status.provider.body.capacity) ? status.provider.body.capacity : {};
10827
- const workerMemory = record10(providerCapacity.memory) ? providerCapacity.memory : {};
10823
+ const providerMetrics = record9(status.provider.body.metrics) ? status.provider.body.metrics : {};
10824
+ const providerCapacity = record9(status.provider.body.capacity) ? status.provider.body.capacity : {};
10825
+ const workerMemory = record9(providerCapacity.memory) ? providerCapacity.memory : {};
10828
10826
  out.log(
10829
10827
  `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`
10830
10828
  );
10831
10829
  for (const line of providerCapacityLines(status.providerCapacity)) {
10832
10830
  out.log(line);
10833
10831
  }
10834
- const coverage = record10(status.providerReconciliation.body.comparison) ? status.providerReconciliation.body.comparison : {};
10835
- const coverageCounts = record10(status.providerReconciliation.body.counts) ? status.providerReconciliation.body.counts : {};
10836
- const coverageBudget = record10(status.providerReconciliation.body.budget) ? status.providerReconciliation.body.budget : {};
10832
+ const coverage = record9(status.providerReconciliation.body.comparison) ? status.providerReconciliation.body.comparison : {};
10833
+ const coverageCounts = record9(status.providerReconciliation.body.counts) ? status.providerReconciliation.body.counts : {};
10834
+ const coverageBudget = record9(status.providerReconciliation.body.budget) ? status.providerReconciliation.body.budget : {};
10837
10835
  out.log(
10838
10836
  `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`
10839
10837
  );
10840
10838
  const providerPoints = Array.isArray(status.providerHistory.body.points) ? status.providerHistory.body.points.length : 0;
10841
- const providerFreshness = record10(status.providerHistory.body.freshness) ? status.providerHistory.body.freshness : {};
10839
+ const providerFreshness = record9(status.providerHistory.body.freshness) ? status.providerHistory.body.freshness : {};
10842
10840
  out.log(
10843
10841
  `cloudflare-history ${status.providerHistory.httpStatus} ${String(status.providerHistory.body.status ?? status.providerHistory.body.error ?? "unavailable")} ${providerPoints} snapshots ${optionalAge(providerFreshness.ageMs)} old`
10844
10842
  );
@@ -10847,17 +10845,17 @@ function printO11yStatus(status, out) {
10847
10845
  );
10848
10846
  }
10849
10847
  function providerCapacityLines(read3) {
10850
- const resources = record10(read3.body.resources) ? read3.body.resources : {};
10851
- const durableObjects = record10(resources.durableObjects) ? resources.durableObjects : {};
10852
- const periodic = record10(durableObjects.periodic) ? durableObjects.periodic : {};
10853
- const storage = record10(durableObjects.sqliteStorage) ? durableObjects.sqliteStorage : {};
10854
- const d1 = record10(resources.d1) ? resources.d1 : {};
10855
- const d1Activity = record10(d1.activity) ? d1.activity : {};
10856
- const d1Storage = record10(d1.storage) ? d1.storage : {};
10857
- const d1Latency = record10(d1Activity.latency) ? d1Activity.latency : {};
10858
- const r2 = record10(resources.r2) ? resources.r2 : {};
10859
- const r2Operations = record10(r2.operations) ? r2.operations : {};
10860
- const r2Storage = record10(r2.storage) ? r2.storage : {};
10848
+ const resources = record9(read3.body.resources) ? read3.body.resources : {};
10849
+ const durableObjects = record9(resources.durableObjects) ? resources.durableObjects : {};
10850
+ const periodic = record9(durableObjects.periodic) ? durableObjects.periodic : {};
10851
+ const storage = record9(durableObjects.sqliteStorage) ? durableObjects.sqliteStorage : {};
10852
+ const d1 = record9(resources.d1) ? resources.d1 : {};
10853
+ const d1Activity = record9(d1.activity) ? d1.activity : {};
10854
+ const d1Storage = record9(d1.storage) ? d1.storage : {};
10855
+ const d1Latency = record9(d1Activity.latency) ? d1Activity.latency : {};
10856
+ const r2 = record9(resources.r2) ? resources.r2 : {};
10857
+ const r2Operations = record9(r2.operations) ? r2.operations : {};
10858
+ const r2Storage = record9(r2.storage) ? r2.storage : {};
10861
10859
  const status = String(
10862
10860
  read3.body.status ?? read3.body.error ?? "unavailable"
10863
10861
  );
@@ -10868,11 +10866,11 @@ function providerCapacityLines(read3) {
10868
10866
  ];
10869
10867
  }
10870
10868
  function liveSyncLine(read3) {
10871
- const performance = record10(read3.body.performance) ? read3.body.performance : {};
10872
- const commitToSend = record10(performance.commitToSend) ? performance.commitToSend : {};
10869
+ const performance = record9(read3.body.performance) ? read3.body.performance : {};
10870
+ const commitToSend = record9(performance.commitToSend) ? performance.commitToSend : {};
10873
10871
  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`;
10874
10872
  }
10875
- function record10(value2) {
10873
+ function record9(value2) {
10876
10874
  return Boolean(value2) && typeof value2 === "object" && !Array.isArray(value2);
10877
10875
  }
10878
10876
  function numeric3(value2) {
@@ -11056,9 +11054,9 @@ async function read2(url, headers, doFetch) {
11056
11054
 
11057
11055
  // src/record.ts
11058
11056
  import { appendFileSync } from "fs";
11059
- import process13 from "process";
11057
+ import process12 from "process";
11060
11058
  function recordInvocation(parsed) {
11061
- const file = process13.env.ODLA_CLI_RECORD;
11059
+ const file = process12.env.ODLA_CLI_RECORD;
11062
11060
  if (!file) return;
11063
11061
  try {
11064
11062
  const entry = {
@@ -11730,9 +11728,9 @@ import { spawnSync } from "child_process";
11730
11728
  import { mkdtempSync, readFileSync as readFileSync13, rmSync as rmSync2, writeFileSync as writeFileSync4 } from "fs";
11731
11729
  import { tmpdir as tmpdir4 } from "os";
11732
11730
  import { join as join15 } from "path";
11733
- import process14 from "process";
11731
+ import process13 from "process";
11734
11732
  var EDITOR_ENV = ["ODLA_EDITOR", "VISUAL", "EDITOR"];
11735
- function resolveEditor(env = process14.env) {
11733
+ function resolveEditor(env = process13.env) {
11736
11734
  for (const name of EDITOR_ENV) {
11737
11735
  const value2 = env[name];
11738
11736
  if (value2 && value2.trim()) return value2.trim();
@@ -11746,8 +11744,8 @@ function defaultRun(command, path) {
11746
11744
  return result.status ?? 0;
11747
11745
  }
11748
11746
  function editText(initial, slug, deps = {}) {
11749
- const env = deps.env ?? process14.env;
11750
- const interactive = deps.interactive ?? (() => Boolean(process14.stdin.isTTY));
11747
+ const env = deps.env ?? process13.env;
11748
+ const interactive = deps.interactive ?? (() => Boolean(process13.stdin.isTTY));
11751
11749
  const editor = resolveEditor(env);
11752
11750
  if (!editor)
11753
11751
  throw new Error(
@@ -12591,6 +12589,10 @@ async function runCli(argv = process.argv.slice(2), dependencies = {}) {
12591
12589
  await securityCommand(parsed, runtime);
12592
12590
  return;
12593
12591
  }
12592
+ if (command === "brand") {
12593
+ await brandCommand(parsed, runtime);
12594
+ return;
12595
+ }
12594
12596
  if (command === "pm") {
12595
12597
  await pmCommand(parsed, runtime);
12596
12598
  return;
@@ -12734,4 +12736,4 @@ export {
12734
12736
  exitCodeFor,
12735
12737
  runCli
12736
12738
  };
12737
- //# sourceMappingURL=chunk-ZAZBUURZ.js.map
12739
+ //# sourceMappingURL=chunk-DS64H4FY.js.map