@odla-ai/cli 0.26.2 → 0.27.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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-4JWDJN3P.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
  }
@@ -312,6 +312,7 @@ async function freshHandshake(ctx, waitMs) {
312
312
  endpoint: ctx.cfg.platformUrl,
313
313
  email: ctx.email,
314
314
  label: `${ctx.cfg.app.id} provisioner`,
315
+ projectIds: [ctx.cfg.app.id],
315
316
  fetch: ctx.doFetch,
316
317
  waitMs,
317
318
  onCode: async ({ userCode, deviceCode, expiresIn, interval, verificationUriComplete }) => {
@@ -1444,8 +1445,8 @@ function credential(value2) {
1444
1445
  // src/calendar-poll.ts
1445
1446
  async function waitForCalendarPoll(milliseconds, signal) {
1446
1447
  if (signal?.aborted) throw signal.reason ?? new Error("calendar connection aborted");
1447
- await new Promise((resolve12, reject) => {
1448
- const timer = setTimeout(resolve12, milliseconds);
1448
+ await new Promise((resolve13, reject) => {
1449
+ const timer = setTimeout(resolve13, milliseconds);
1449
1450
  signal?.addEventListener("abort", () => {
1450
1451
  clearTimeout(timer);
1451
1452
  reject(signal.reason ?? new Error("calendar connection aborted"));
@@ -2083,7 +2084,7 @@ async function configOperationWait(options) {
2083
2084
  assertOperationId(options.operationId);
2084
2085
  const cfg = await loadProjectConfig(options.configPath);
2085
2086
  const client = await operationClient(cfg, options, "wait");
2086
- const wait2 = options.pollWait ?? ((ms) => new Promise((resolve12) => setTimeout(resolve12, ms)));
2087
+ const wait2 = options.pollWait ?? ((ms) => new Promise((resolve13) => setTimeout(resolve13, ms)));
2087
2088
  const now = () => (options.now?.() ?? /* @__PURE__ */ new Date()).getTime();
2088
2089
  const deadline = now() + (options.timeoutSeconds ?? DEFAULT_WAIT_SECONDS) * 1e3;
2089
2090
  const interval = (options.intervalSeconds ?? DEFAULT_INTERVAL_SECONDS) * 1e3;
@@ -3766,8 +3767,8 @@ function hostedPollTimeout(value2 = 10 * 6e4) {
3766
3767
  }
3767
3768
  async function waitForHostedPoll(milliseconds, signal) {
3768
3769
  if (signal?.aborted) throw signal.reason ?? new DOMException("aborted", "AbortError");
3769
- await new Promise((resolve12, reject) => {
3770
- const timer = setTimeout(resolve12, milliseconds);
3770
+ await new Promise((resolve13, reject) => {
3771
+ const timer = setTimeout(resolve13, milliseconds);
3771
3772
  signal?.addEventListener("abort", () => {
3772
3773
  clearTimeout(timer);
3773
3774
  reject(signal.reason ?? new DOMException("aborted", "AbortError"));
@@ -7513,6 +7514,7 @@ var COMMAND_SURFACE = {
7513
7514
  promote: {},
7514
7515
  owners: { list: {}, add: {}, remove: {} }
7515
7516
  },
7517
+ brand: { design: { unpack: {} } },
7516
7518
  calendar: { status: {}, calendars: {}, connect: {}, disconnect: {} },
7517
7519
  capabilities: {},
7518
7520
  code: { connect: {} },
@@ -8879,6 +8881,158 @@ async function appCommand(parsed, dependencies = {}) {
8879
8881
  else await appRestore(options);
8880
8882
  }
8881
8883
 
8884
+ // src/brand-command.ts
8885
+ import { mkdir as mkdir4, readFile as readFile3, writeFile as writeFile4 } from "fs/promises";
8886
+ import { dirname as dirname8, resolve as resolve12 } from "path";
8887
+
8888
+ // src/brand-design-unpack.ts
8889
+ import { gunzipSync } from "zlib";
8890
+ import {
8891
+ digestDesignBundle,
8892
+ parseDesignBundle,
8893
+ readDesignManifest,
8894
+ renderTokensCss
8895
+ } from "@odla-ai/brand";
8896
+ var EXTENSIONS = {
8897
+ "image/png": "png",
8898
+ "image/jpeg": "jpg",
8899
+ "image/gif": "gif",
8900
+ "image/webp": "webp",
8901
+ "image/svg+xml": "svg",
8902
+ "image/avif": "avif",
8903
+ "font/woff2": "woff2",
8904
+ "font/woff": "woff",
8905
+ "font/ttf": "ttf",
8906
+ "font/otf": "otf",
8907
+ "text/javascript": "js",
8908
+ "application/javascript": "js",
8909
+ "text/css": "css",
8910
+ "text/html": "html",
8911
+ "application/json": "json"
8912
+ };
8913
+ var encode = (text2) => new TextEncoder().encode(text2);
8914
+ function assetFileName(uuid, mime) {
8915
+ const ext = EXTENSIONS[mime.split(";")[0].trim().toLowerCase()] ?? "bin";
8916
+ return `${uuid.replace(/[^a-zA-Z0-9._-]/g, "_")}.${ext}`;
8917
+ }
8918
+ function decodePayload(data, compressed) {
8919
+ const raw = Buffer.from(data, "base64");
8920
+ return new Uint8Array(compressed ? gunzipSync(raw) : raw);
8921
+ }
8922
+ function rewriteReferences(template, assetPaths, pagePaths) {
8923
+ let out = template;
8924
+ for (const [uuid, path] of pagePaths) {
8925
+ out = out.split(`about:blank#${uuid}`).join(path);
8926
+ }
8927
+ for (const [uuid, path] of assetPaths) {
8928
+ out = out.split(uuid).join(path);
8929
+ }
8930
+ return out;
8931
+ }
8932
+ function tokensCss(digest) {
8933
+ if (Object.keys(digest.tokens.light).length === 0) return null;
8934
+ return renderTokensCss(digest.tokens.light, { dark: digest.tokens.dark });
8935
+ }
8936
+ function unpackDesign(html) {
8937
+ const bundle = parseDesignBundle(html);
8938
+ const manifest = readDesignManifest(html);
8939
+ const digest = digestDesignBundle(bundle);
8940
+ const pageUuids = new Set(bundle.pageOrder);
8941
+ const files = [];
8942
+ const failed = [];
8943
+ const assetPaths = /* @__PURE__ */ new Map();
8944
+ const pagePaths = /* @__PURE__ */ new Map();
8945
+ for (const [uuid, entry] of Object.entries(manifest)) {
8946
+ let bytes;
8947
+ try {
8948
+ bytes = decodePayload(entry.data, entry.compressed);
8949
+ } catch {
8950
+ failed.push(uuid);
8951
+ continue;
8952
+ }
8953
+ if (pageUuids.has(uuid)) {
8954
+ const path2 = `pages/${assetFileName(uuid, "text/html")}`;
8955
+ pagePaths.set(uuid, `./${path2}`);
8956
+ files.push({ path: path2, bytes });
8957
+ continue;
8958
+ }
8959
+ const path = `assets/${assetFileName(uuid, entry.mime)}`;
8960
+ assetPaths.set(uuid, `./${path}`);
8961
+ files.push({ path, bytes });
8962
+ }
8963
+ files.push({
8964
+ path: "index.html",
8965
+ bytes: encode(rewriteReferences(bundle.template, assetPaths, pagePaths))
8966
+ });
8967
+ files.push({ path: "digest.json", bytes: encode(`${JSON.stringify(digest, null, 2)}
8968
+ `) });
8969
+ const css = tokensCss(digest);
8970
+ if (css !== null) files.push({ path: "tokens.css", bytes: encode(css) });
8971
+ if (bundle.thumbnailSvg) files.push({ path: "thumbnail.svg", bytes: encode(bundle.thumbnailSvg) });
8972
+ return { files, digest, failed };
8973
+ }
8974
+ function describeUnpack(result, outDir) {
8975
+ const { digest } = result;
8976
+ const lines = [
8977
+ `Unpacked ${digest.title ? `"${digest.title}"` : "design"} into ${outDir}`,
8978
+ ` index.html the design, offline-runnable (${digest.templateBytes} bytes)`,
8979
+ ` assets/ ${digest.assetCount} embedded files (${digest.assetBytes} bytes)`,
8980
+ ` digest.json ${Object.keys(digest.tokens.light).length} --ui-* tokens, ${digest.props.length} props, ${digest.outline.length} headings`
8981
+ ];
8982
+ if (result.files.some((f) => f.path === "tokens.css"))
8983
+ lines.push(" tokens.css the design's tokens as an @odla-ai/ui theme sheet");
8984
+ if (digest.fonts.length > 0) lines.push(`Typefaces: ${digest.fonts.join(", ")}`);
8985
+ if (result.failed.length > 0)
8986
+ lines.push(`WARNING: ${result.failed.length} embedded asset(s) could not be decoded.`);
8987
+ return lines;
8988
+ }
8989
+
8990
+ // src/brand-command.ts
8991
+ var USAGE = "usage: odla-ai brand design unpack <bundle.html|-> [--out <dir>] [--json]";
8992
+ async function readBundle(source, deps) {
8993
+ if (source !== "-") return readFile3(resolve12(source), "utf8");
8994
+ const readStdin = deps.readStdin;
8995
+ if (!readStdin) throw new Error("reading a bundle from stdin is not supported here");
8996
+ return readStdin();
8997
+ }
8998
+ async function writeAll(result, outDir) {
8999
+ for (const file of result.files) {
9000
+ const target = resolve12(outDir, file.path);
9001
+ await mkdir4(dirname8(target), { recursive: true });
9002
+ await writeFile4(target, file.bytes);
9003
+ }
9004
+ }
9005
+ async function designUnpack(parsed, deps) {
9006
+ assertArgs(parsed, ["out", "json"], 4);
9007
+ const source = parsed.positionals[3];
9008
+ if (!source) throw new Error(USAGE);
9009
+ const outDir = resolve12(stringOpt(parsed.options.out) ?? "design");
9010
+ const result = unpackDesign(await readBundle(source, deps));
9011
+ await writeAll(result, outDir);
9012
+ const out = deps.stdout ?? console;
9013
+ if (parsed.options.json === true) {
9014
+ out.log(
9015
+ JSON.stringify({
9016
+ outDir,
9017
+ files: result.files.map((f) => f.path),
9018
+ failed: result.failed,
9019
+ digest: result.digest
9020
+ })
9021
+ );
9022
+ return;
9023
+ }
9024
+ for (const line of describeUnpack(result, outDir)) out.log(line);
9025
+ }
9026
+ async function brandCommand(parsed, deps) {
9027
+ const subject = parsed.positionals[1];
9028
+ const action2 = parsed.positionals[2];
9029
+ if (subject === "design" && action2 === "unpack") {
9030
+ await designUnpack(parsed, deps);
9031
+ return;
9032
+ }
9033
+ throw new Error(USAGE);
9034
+ }
9035
+
8882
9036
  // src/harness-options.ts
8883
9037
  function harnessList(parsed) {
8884
9038
  const selected = [
@@ -9255,10 +9409,8 @@ function requireName(parsed) {
9255
9409
  return name;
9256
9410
  }
9257
9411
 
9258
- // src/help.ts
9259
- function printHelp(output = console) {
9260
- output.log(`odla-ai
9261
-
9412
+ // src/help-usage.ts
9413
+ var USAGE_SECTION = `
9262
9414
  Start here:
9263
9415
  odla-ai runbook ask "<question>" The current procedure, from odla's own
9264
9416
  runbooks. Ask BEFORE searching the web or
@@ -9292,6 +9444,7 @@ Usage:
9292
9444
  odla-ai app owners list [--config odla.config.mjs] [--email <odla-account>] [--json]
9293
9445
  odla-ai app owners add <email> [--email <odla-account>] [--json]
9294
9446
  odla-ai app owners remove <email> [--email <odla-account>] [--json]
9447
+ odla-ai brand design unpack <bundle.html|-> [--out <dir>] [--json]
9295
9448
  odla-ai pm goal list [--app <id>] [--status <s>] [--q <text>] [--limit <n>] [--offset <n>] [--json]
9296
9449
  odla-ai pm task list [--app <id>] [--column <c>] [--goal <id>] [--assignee <id>] [--q <text>] [--limit <n>] [--offset <n>] [--json]
9297
9450
  odla-ai pm decision list [--app <id>] [--status <s>] [--q <text>] [--limit <n>] [--offset <n>] [--json]
@@ -9371,8 +9524,12 @@ Usage:
9371
9524
  odla-ai secrets push --env <env> [--config odla.config.mjs] [--dry-run] [--yes]
9372
9525
  odla-ai secrets set <name> --env <env> (--from-env <NAME>|--stdin) [--email <odla-account>] [--config odla.config.mjs] [--yes]
9373
9526
  odla-ai secrets set-clerk-key --env <env> (--from-env <NAME>|--stdin) [--email <odla-account>] [--config odla.config.mjs] [--yes]
9374
- odla-ai version
9527
+ odla-ai version`;
9375
9528
 
9529
+ // src/help.ts
9530
+ function printHelp(output = console) {
9531
+ output.log(`odla-ai
9532
+ ${USAGE_SECTION}
9376
9533
  Commands:
9377
9534
  agent Inspect durable agent wakeups and explicitly requeue a
9378
9535
  dead-lettered job; JSON output is stable for remote operators.
@@ -9821,7 +9978,7 @@ function jsonl(ctx, parsed, value2) {
9821
9978
  }
9822
9979
  async function discussWatch(ctx, topicId, parsed) {
9823
9980
  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)));
9981
+ const sleep = ctx.sleep ?? ((ms) => new Promise((resolve13) => setTimeout(resolve13, ms)));
9825
9982
  const now = ctx.now ?? Date.now;
9826
9983
  const intervalMs = (numberOpt2(parsed, "interval", DEFAULT_INTERVAL_MS / 1e3) ?? DEFAULT_INTERVAL_MS / 1e3) * 1e3;
9827
9984
  const timeoutSeconds = numberOpt2(parsed, "timeout");
@@ -12433,6 +12590,10 @@ async function runCli(argv = process.argv.slice(2), dependencies = {}) {
12433
12590
  await securityCommand(parsed, runtime);
12434
12591
  return;
12435
12592
  }
12593
+ if (command === "brand") {
12594
+ await brandCommand(parsed, runtime);
12595
+ return;
12596
+ }
12436
12597
  if (command === "pm") {
12437
12598
  await pmCommand(parsed, runtime);
12438
12599
  return;
@@ -12576,4 +12737,4 @@ export {
12576
12737
  exitCodeFor,
12577
12738
  runCli
12578
12739
  };
12579
- //# sourceMappingURL=chunk-MBZXWPZP.js.map
12740
+ //# sourceMappingURL=chunk-4JWDJN3P.js.map