@odla-ai/cli 0.26.2 → 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.
package/dist/bin.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  exitCodeFor,
4
4
  redactSecrets,
5
5
  runCli
6
- } from "./chunk-MBZXWPZP.js";
6
+ } from "./chunk-DS64H4FY.js";
7
7
 
8
8
  // src/bin.ts
9
9
  runCli().catch((err) => {
@@ -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
  }
@@ -1444,8 +1444,8 @@ function credential(value2) {
1444
1444
  // src/calendar-poll.ts
1445
1445
  async function waitForCalendarPoll(milliseconds, signal) {
1446
1446
  if (signal?.aborted) throw signal.reason ?? new Error("calendar connection aborted");
1447
- await new Promise((resolve12, reject) => {
1448
- const timer = setTimeout(resolve12, milliseconds);
1447
+ await new Promise((resolve13, reject) => {
1448
+ const timer = setTimeout(resolve13, milliseconds);
1449
1449
  signal?.addEventListener("abort", () => {
1450
1450
  clearTimeout(timer);
1451
1451
  reject(signal.reason ?? new Error("calendar connection aborted"));
@@ -2083,7 +2083,7 @@ async function configOperationWait(options) {
2083
2083
  assertOperationId(options.operationId);
2084
2084
  const cfg = await loadProjectConfig(options.configPath);
2085
2085
  const client = await operationClient(cfg, options, "wait");
2086
- const wait2 = options.pollWait ?? ((ms) => new Promise((resolve12) => setTimeout(resolve12, ms)));
2086
+ const wait2 = options.pollWait ?? ((ms) => new Promise((resolve13) => setTimeout(resolve13, ms)));
2087
2087
  const now = () => (options.now?.() ?? /* @__PURE__ */ new Date()).getTime();
2088
2088
  const deadline = now() + (options.timeoutSeconds ?? DEFAULT_WAIT_SECONDS) * 1e3;
2089
2089
  const interval = (options.intervalSeconds ?? DEFAULT_INTERVAL_SECONDS) * 1e3;
@@ -3766,8 +3766,8 @@ function hostedPollTimeout(value2 = 10 * 6e4) {
3766
3766
  }
3767
3767
  async function waitForHostedPoll(milliseconds, signal) {
3768
3768
  if (signal?.aborted) throw signal.reason ?? new DOMException("aborted", "AbortError");
3769
- await new Promise((resolve12, reject) => {
3770
- const timer = setTimeout(resolve12, milliseconds);
3769
+ await new Promise((resolve13, reject) => {
3770
+ const timer = setTimeout(resolve13, milliseconds);
3771
3771
  signal?.addEventListener("abort", () => {
3772
3772
  clearTimeout(timer);
3773
3773
  reject(signal.reason ?? new DOMException("aborted", "AbortError"));
@@ -7513,6 +7513,7 @@ var COMMAND_SURFACE = {
7513
7513
  promote: {},
7514
7514
  owners: { list: {}, add: {}, remove: {} }
7515
7515
  },
7516
+ brand: { design: { unpack: {} } },
7516
7517
  calendar: { status: {}, calendars: {}, connect: {}, disconnect: {} },
7517
7518
  capabilities: {},
7518
7519
  code: { connect: {} },
@@ -8879,6 +8880,158 @@ async function appCommand(parsed, dependencies = {}) {
8879
8880
  else await appRestore(options);
8880
8881
  }
8881
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
+
8882
9035
  // src/harness-options.ts
8883
9036
  function harnessList(parsed) {
8884
9037
  const selected = [
@@ -9255,10 +9408,8 @@ function requireName(parsed) {
9255
9408
  return name;
9256
9409
  }
9257
9410
 
9258
- // src/help.ts
9259
- function printHelp(output = console) {
9260
- output.log(`odla-ai
9261
-
9411
+ // src/help-usage.ts
9412
+ var USAGE_SECTION = `
9262
9413
  Start here:
9263
9414
  odla-ai runbook ask "<question>" The current procedure, from odla's own
9264
9415
  runbooks. Ask BEFORE searching the web or
@@ -9292,6 +9443,7 @@ Usage:
9292
9443
  odla-ai app owners list [--config odla.config.mjs] [--email <odla-account>] [--json]
9293
9444
  odla-ai app owners add <email> [--email <odla-account>] [--json]
9294
9445
  odla-ai app owners remove <email> [--email <odla-account>] [--json]
9446
+ odla-ai brand design unpack <bundle.html|-> [--out <dir>] [--json]
9295
9447
  odla-ai pm goal list [--app <id>] [--status <s>] [--q <text>] [--limit <n>] [--offset <n>] [--json]
9296
9448
  odla-ai pm task list [--app <id>] [--column <c>] [--goal <id>] [--assignee <id>] [--q <text>] [--limit <n>] [--offset <n>] [--json]
9297
9449
  odla-ai pm decision list [--app <id>] [--status <s>] [--q <text>] [--limit <n>] [--offset <n>] [--json]
@@ -9371,8 +9523,12 @@ Usage:
9371
9523
  odla-ai secrets push --env <env> [--config odla.config.mjs] [--dry-run] [--yes]
9372
9524
  odla-ai secrets set <name> --env <env> (--from-env <NAME>|--stdin) [--email <odla-account>] [--config odla.config.mjs] [--yes]
9373
9525
  odla-ai secrets set-clerk-key --env <env> (--from-env <NAME>|--stdin) [--email <odla-account>] [--config odla.config.mjs] [--yes]
9374
- odla-ai version
9526
+ odla-ai version`;
9375
9527
 
9528
+ // src/help.ts
9529
+ function printHelp(output = console) {
9530
+ output.log(`odla-ai
9531
+ ${USAGE_SECTION}
9376
9532
  Commands:
9377
9533
  agent Inspect durable agent wakeups and explicitly requeue a
9378
9534
  dead-lettered job; JSON output is stable for remote operators.
@@ -9821,7 +9977,7 @@ function jsonl(ctx, parsed, value2) {
9821
9977
  }
9822
9978
  async function discussWatch(ctx, topicId, parsed) {
9823
9979
  if (ctx.json && parsed.options.jsonl === true) throw new Error("--json and --jsonl cannot be combined");
9824
- const sleep = ctx.sleep ?? ((ms) => new Promise((resolve12) => setTimeout(resolve12, ms)));
9980
+ const sleep = ctx.sleep ?? ((ms) => new Promise((resolve13) => setTimeout(resolve13, ms)));
9825
9981
  const now = ctx.now ?? Date.now;
9826
9982
  const intervalMs = (numberOpt2(parsed, "interval", DEFAULT_INTERVAL_MS / 1e3) ?? DEFAULT_INTERVAL_MS / 1e3) * 1e3;
9827
9983
  const timeoutSeconds = numberOpt2(parsed, "timeout");
@@ -12433,6 +12589,10 @@ async function runCli(argv = process.argv.slice(2), dependencies = {}) {
12433
12589
  await securityCommand(parsed, runtime);
12434
12590
  return;
12435
12591
  }
12592
+ if (command === "brand") {
12593
+ await brandCommand(parsed, runtime);
12594
+ return;
12595
+ }
12436
12596
  if (command === "pm") {
12437
12597
  await pmCommand(parsed, runtime);
12438
12598
  return;
@@ -12576,4 +12736,4 @@ export {
12576
12736
  exitCodeFor,
12577
12737
  runCli
12578
12738
  };
12579
- //# sourceMappingURL=chunk-MBZXWPZP.js.map
12739
+ //# sourceMappingURL=chunk-DS64H4FY.js.map