@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.
package/dist/index.cjs CHANGED
@@ -314,7 +314,7 @@ var import_node_process2 = __toESM(require("process"), 1);
314
314
  async function openUrl(url, options = {}) {
315
315
  const command = openerFor(options.platform ?? import_node_process2.default.platform);
316
316
  const doSpawn = options.spawnImpl ?? import_node_child_process.spawn;
317
- await new Promise((resolve12, reject) => {
317
+ await new Promise((resolve13, reject) => {
318
318
  const child = doSpawn(command.cmd, [...command.args, url], {
319
319
  stdio: "ignore",
320
320
  detached: true
@@ -322,7 +322,7 @@ async function openUrl(url, options = {}) {
322
322
  child.once("error", reject);
323
323
  child.once("spawn", () => {
324
324
  child.unref();
325
- resolve12();
325
+ resolve13();
326
326
  });
327
327
  });
328
328
  }
@@ -560,7 +560,6 @@ function audienceBoundEnvToken(token, platform) {
560
560
  }
561
561
  var SCOPE_PURPOSE = {
562
562
  "platform:status:read": "read the platform fleet health and deployment snapshot",
563
- "platform:chat:credential:write": "rotate the built-in Discussion responder credential",
564
563
  "app:config:read": "compare checked-in intent with an exact-id app Registry configuration",
565
564
  "app:config:write": "apply or inspect one revision-bound configuration operation for an app you own",
566
565
  "platform:runbook:write": "add or edit odla's operational runbooks",
@@ -2244,6 +2243,153 @@ async function appCommand(parsed, dependencies = {}) {
2244
2243
  else await appRestore(options);
2245
2244
  }
2246
2245
 
2246
+ // src/brand-command.ts
2247
+ var import_promises2 = require("fs/promises");
2248
+ var import_node_path7 = require("path");
2249
+
2250
+ // src/brand-design-unpack.ts
2251
+ var import_node_zlib = require("zlib");
2252
+ var import_brand = require("@odla-ai/brand");
2253
+ var EXTENSIONS = {
2254
+ "image/png": "png",
2255
+ "image/jpeg": "jpg",
2256
+ "image/gif": "gif",
2257
+ "image/webp": "webp",
2258
+ "image/svg+xml": "svg",
2259
+ "image/avif": "avif",
2260
+ "font/woff2": "woff2",
2261
+ "font/woff": "woff",
2262
+ "font/ttf": "ttf",
2263
+ "font/otf": "otf",
2264
+ "text/javascript": "js",
2265
+ "application/javascript": "js",
2266
+ "text/css": "css",
2267
+ "text/html": "html",
2268
+ "application/json": "json"
2269
+ };
2270
+ var encode = (text2) => new TextEncoder().encode(text2);
2271
+ function assetFileName(uuid, mime) {
2272
+ const ext = EXTENSIONS[mime.split(";")[0].trim().toLowerCase()] ?? "bin";
2273
+ return `${uuid.replace(/[^a-zA-Z0-9._-]/g, "_")}.${ext}`;
2274
+ }
2275
+ function decodePayload(data, compressed) {
2276
+ const raw = Buffer.from(data, "base64");
2277
+ return new Uint8Array(compressed ? (0, import_node_zlib.gunzipSync)(raw) : raw);
2278
+ }
2279
+ function rewriteReferences(template, assetPaths, pagePaths) {
2280
+ let out = template;
2281
+ for (const [uuid, path] of pagePaths) {
2282
+ out = out.split(`about:blank#${uuid}`).join(path);
2283
+ }
2284
+ for (const [uuid, path] of assetPaths) {
2285
+ out = out.split(uuid).join(path);
2286
+ }
2287
+ return out;
2288
+ }
2289
+ function tokensCss(digest) {
2290
+ if (Object.keys(digest.tokens.light).length === 0) return null;
2291
+ return (0, import_brand.renderTokensCss)(digest.tokens.light, { dark: digest.tokens.dark });
2292
+ }
2293
+ function unpackDesign(html) {
2294
+ const bundle = (0, import_brand.parseDesignBundle)(html);
2295
+ const manifest = (0, import_brand.readDesignManifest)(html);
2296
+ const digest = (0, import_brand.digestDesignBundle)(bundle);
2297
+ const pageUuids = new Set(bundle.pageOrder);
2298
+ const files = [];
2299
+ const failed = [];
2300
+ const assetPaths = /* @__PURE__ */ new Map();
2301
+ const pagePaths = /* @__PURE__ */ new Map();
2302
+ for (const [uuid, entry] of Object.entries(manifest)) {
2303
+ let bytes;
2304
+ try {
2305
+ bytes = decodePayload(entry.data, entry.compressed);
2306
+ } catch {
2307
+ failed.push(uuid);
2308
+ continue;
2309
+ }
2310
+ if (pageUuids.has(uuid)) {
2311
+ const path2 = `pages/${assetFileName(uuid, "text/html")}`;
2312
+ pagePaths.set(uuid, `./${path2}`);
2313
+ files.push({ path: path2, bytes });
2314
+ continue;
2315
+ }
2316
+ const path = `assets/${assetFileName(uuid, entry.mime)}`;
2317
+ assetPaths.set(uuid, `./${path}`);
2318
+ files.push({ path, bytes });
2319
+ }
2320
+ files.push({
2321
+ path: "index.html",
2322
+ bytes: encode(rewriteReferences(bundle.template, assetPaths, pagePaths))
2323
+ });
2324
+ files.push({ path: "digest.json", bytes: encode(`${JSON.stringify(digest, null, 2)}
2325
+ `) });
2326
+ const css = tokensCss(digest);
2327
+ if (css !== null) files.push({ path: "tokens.css", bytes: encode(css) });
2328
+ if (bundle.thumbnailSvg) files.push({ path: "thumbnail.svg", bytes: encode(bundle.thumbnailSvg) });
2329
+ return { files, digest, failed };
2330
+ }
2331
+ function describeUnpack(result, outDir) {
2332
+ const { digest } = result;
2333
+ const lines = [
2334
+ `Unpacked ${digest.title ? `"${digest.title}"` : "design"} into ${outDir}`,
2335
+ ` index.html the design, offline-runnable (${digest.templateBytes} bytes)`,
2336
+ ` assets/ ${digest.assetCount} embedded files (${digest.assetBytes} bytes)`,
2337
+ ` digest.json ${Object.keys(digest.tokens.light).length} --ui-* tokens, ${digest.props.length} props, ${digest.outline.length} headings`
2338
+ ];
2339
+ if (result.files.some((f) => f.path === "tokens.css"))
2340
+ lines.push(" tokens.css the design's tokens as an @odla-ai/ui theme sheet");
2341
+ if (digest.fonts.length > 0) lines.push(`Typefaces: ${digest.fonts.join(", ")}`);
2342
+ if (result.failed.length > 0)
2343
+ lines.push(`WARNING: ${result.failed.length} embedded asset(s) could not be decoded.`);
2344
+ return lines;
2345
+ }
2346
+
2347
+ // src/brand-command.ts
2348
+ var USAGE = "usage: odla-ai brand design unpack <bundle.html|-> [--out <dir>] [--json]";
2349
+ async function readBundle(source, deps) {
2350
+ if (source !== "-") return (0, import_promises2.readFile)((0, import_node_path7.resolve)(source), "utf8");
2351
+ const readStdin = deps.readStdin;
2352
+ if (!readStdin) throw new Error("reading a bundle from stdin is not supported here");
2353
+ return readStdin();
2354
+ }
2355
+ async function writeAll(result, outDir) {
2356
+ for (const file of result.files) {
2357
+ const target = (0, import_node_path7.resolve)(outDir, file.path);
2358
+ await (0, import_promises2.mkdir)((0, import_node_path7.dirname)(target), { recursive: true });
2359
+ await (0, import_promises2.writeFile)(target, file.bytes);
2360
+ }
2361
+ }
2362
+ async function designUnpack(parsed, deps) {
2363
+ assertArgs(parsed, ["out", "json"], 4);
2364
+ const source = parsed.positionals[3];
2365
+ if (!source) throw new Error(USAGE);
2366
+ const outDir = (0, import_node_path7.resolve)(stringOpt(parsed.options.out) ?? "design");
2367
+ const result = unpackDesign(await readBundle(source, deps));
2368
+ await writeAll(result, outDir);
2369
+ const out = deps.stdout ?? console;
2370
+ if (parsed.options.json === true) {
2371
+ out.log(
2372
+ JSON.stringify({
2373
+ outDir,
2374
+ files: result.files.map((f) => f.path),
2375
+ failed: result.failed,
2376
+ digest: result.digest
2377
+ })
2378
+ );
2379
+ return;
2380
+ }
2381
+ for (const line of describeUnpack(result, outDir)) out.log(line);
2382
+ }
2383
+ async function brandCommand(parsed, deps) {
2384
+ const subject = parsed.positionals[1];
2385
+ const action2 = parsed.positionals[2];
2386
+ if (subject === "design" && action2 === "unpack") {
2387
+ await designUnpack(parsed, deps);
2388
+ return;
2389
+ }
2390
+ throw new Error(USAGE);
2391
+ }
2392
+
2247
2393
  // src/calendar-errors.ts
2248
2394
  var PLATFORM_NOT_READY_CODES = /* @__PURE__ */ new Set([
2249
2395
  "calendar_google_oauth_not_configured",
@@ -2517,8 +2663,8 @@ function credential(value2) {
2517
2663
  // src/calendar-poll.ts
2518
2664
  async function waitForCalendarPoll(milliseconds, signal) {
2519
2665
  if (signal?.aborted) throw signal.reason ?? new Error("calendar connection aborted");
2520
- await new Promise((resolve12, reject) => {
2521
- const timer = setTimeout(resolve12, milliseconds);
2666
+ await new Promise((resolve13, reject) => {
2667
+ const timer = setTimeout(resolve13, milliseconds);
2522
2668
  signal?.addEventListener("abort", () => {
2523
2669
  clearTimeout(timer);
2524
2670
  reject(signal.reason ?? new Error("calendar connection aborted"));
@@ -2772,7 +2918,7 @@ function printGroup(out, heading, items) {
2772
2918
 
2773
2919
  // src/config-operation-command.ts
2774
2920
  var import_apps6 = require("@odla-ai/apps");
2775
- var import_node_path7 = require("path");
2921
+ var import_node_path8 = require("path");
2776
2922
 
2777
2923
  // src/version.ts
2778
2924
  var import_node_fs9 = require("fs");
@@ -2811,9 +2957,9 @@ function canonicalValue(value2) {
2811
2957
  }
2812
2958
  if (Array.isArray(value2)) return value2.map(canonicalValue);
2813
2959
  if (value2 && typeof value2 === "object") {
2814
- const record11 = value2;
2960
+ const record10 = value2;
2815
2961
  return Object.fromEntries(
2816
- Object.keys(record11).filter((key) => record11[key] !== void 0).sort().map((key) => [key, canonicalValue(record11[key])])
2962
+ Object.keys(record10).filter((key) => record10[key] !== void 0).sort().map((key) => [key, canonicalValue(record10[key])])
2817
2963
  );
2818
2964
  }
2819
2965
  throw new TypeError("canonical JSON rejects unsupported values");
@@ -3151,7 +3297,7 @@ async function configOperationWait(options) {
3151
3297
  assertOperationId(options.operationId);
3152
3298
  const cfg = await loadProjectConfig(options.configPath);
3153
3299
  const client = await operationClient(cfg, options, "wait");
3154
- const wait2 = options.pollWait ?? ((ms) => new Promise((resolve12) => setTimeout(resolve12, ms)));
3300
+ const wait2 = options.pollWait ?? ((ms) => new Promise((resolve13) => setTimeout(resolve13, ms)));
3155
3301
  const now = () => (options.now?.() ?? /* @__PURE__ */ new Date()).getTime();
3156
3302
  const deadline = now() + (options.timeoutSeconds ?? DEFAULT_WAIT_SECONDS) * 1e3;
3157
3303
  const interval = (options.intervalSeconds ?? DEFAULT_INTERVAL_SECONDS) * 1e3;
@@ -3182,7 +3328,7 @@ async function operationClient(cfg, options, purpose) {
3182
3328
  platform: cfg.platformUrl,
3183
3329
  scope: "app:config:write",
3184
3330
  token: options.token,
3185
- tokenFile: (0, import_node_path7.join)(cfg.rootDir, ".odla", "admin-token.local.json"),
3331
+ tokenFile: (0, import_node_path8.join)(cfg.rootDir, ".odla", "admin-token.local.json"),
3186
3332
  rootDir: cfg.rootDir,
3187
3333
  email: options.email,
3188
3334
  open: options.open,
@@ -3237,7 +3383,7 @@ function record3(value2) {
3237
3383
 
3238
3384
  // src/config-reconcile-command.ts
3239
3385
  var import_apps8 = require("@odla-ai/apps");
3240
- var import_node_path8 = require("path");
3386
+ var import_node_path9 = require("path");
3241
3387
 
3242
3388
  // src/config-reconcile.ts
3243
3389
  var import_apps7 = require("@odla-ai/apps");
@@ -3533,7 +3679,7 @@ async function inspectConfig(options) {
3533
3679
  platform: cfg.platformUrl,
3534
3680
  scope: "app:config:read",
3535
3681
  token: options.token,
3536
- tokenFile: (0, import_node_path8.join)(cfg.rootDir, ".odla", "admin-token.local.json"),
3682
+ tokenFile: (0, import_node_path9.join)(cfg.rootDir, ".odla", "admin-token.local.json"),
3537
3683
  rootDir: cfg.rootDir,
3538
3684
  email: options.email,
3539
3685
  open: options.open,
@@ -3666,12 +3812,12 @@ function quoteArg2(value2) {
3666
3812
  // src/doctor-checks.ts
3667
3813
  var import_node_child_process3 = require("child_process");
3668
3814
  var import_node_fs12 = require("fs");
3669
- var import_node_path10 = require("path");
3815
+ var import_node_path11 = require("path");
3670
3816
 
3671
3817
  // src/wrangler.ts
3672
3818
  var import_node_child_process2 = require("child_process");
3673
3819
  var import_node_fs11 = require("fs");
3674
- var import_node_path9 = require("path");
3820
+ var import_node_path10 = require("path");
3675
3821
  var defaultRunner = (cmd, args, opts) => new Promise((resolvePromise, reject) => {
3676
3822
  const child = (0, import_node_child_process2.spawn)(cmd, args, { cwd: opts?.cwd, stdio: ["pipe", "pipe", "pipe"] });
3677
3823
  let stdout = "";
@@ -3685,7 +3831,7 @@ var defaultRunner = (cmd, args, opts) => new Promise((resolvePromise, reject) =>
3685
3831
  var WRANGLER_CONFIG_FILES = ["wrangler.jsonc", "wrangler.json", "wrangler.toml"];
3686
3832
  function findWranglerConfig(rootDir) {
3687
3833
  for (const name of WRANGLER_CONFIG_FILES) {
3688
- const path = (0, import_node_path9.join)(rootDir, name);
3834
+ const path = (0, import_node_path10.join)(rootDir, name);
3689
3835
  if ((0, import_node_fs11.existsSync)(path)) return path;
3690
3836
  }
3691
3837
  return null;
@@ -3798,10 +3944,10 @@ function wranglerWarnings(rootDir) {
3798
3944
  for (const { label, block } of blocks) {
3799
3945
  const assets = block.assets;
3800
3946
  if (assets?.directory) {
3801
- const dir = (0, import_node_path10.resolve)(rootDir, assets.directory);
3802
- if (dir === (0, import_node_path10.resolve)(rootDir)) {
3947
+ const dir = (0, import_node_path11.resolve)(rootDir, assets.directory);
3948
+ if (dir === (0, import_node_path11.resolve)(rootDir)) {
3803
3949
  warnings.push(`${label}assets.directory is the project root \u2014 point it at a dedicated build dir (wrangler dev fails with "spawn EBADF")`);
3804
- } else if ((0, import_node_fs12.existsSync)((0, import_node_path10.join)(dir, "node_modules"))) {
3950
+ } else if ((0, import_node_fs12.existsSync)((0, import_node_path11.join)(dir, "node_modules"))) {
3805
3951
  warnings.push(`${label}assets.directory contains node_modules \u2014 wrangler dev's watcher will exhaust file descriptors`);
3806
3952
  }
3807
3953
  }
@@ -3836,7 +3982,7 @@ function o11yProjectWarnings(rootDir) {
3836
3982
  warnings.push("cannot verify o11y Worker instrumentation \u2014 add a parseable wrangler.jsonc/json config");
3837
3983
  return warnings;
3838
3984
  }
3839
- const main = typeof config.main === "string" ? (0, import_node_path10.resolve)(rootDir, config.main) : null;
3985
+ const main = typeof config.main === "string" ? (0, import_node_path11.resolve)(rootDir, config.main) : null;
3840
3986
  if (!main || !(0, import_node_fs12.existsSync)(main)) {
3841
3987
  warnings.push("cannot verify o11y Worker instrumentation \u2014 wrangler main is missing or unreadable");
3842
3988
  } else {
@@ -3866,7 +4012,7 @@ function calendarProjectWarnings(rootDir) {
3866
4012
  }
3867
4013
  function readPackageJson(rootDir) {
3868
4014
  try {
3869
- return JSON.parse((0, import_node_fs12.readFileSync)((0, import_node_path10.join)(rootDir, "package.json"), "utf8"));
4015
+ return JSON.parse((0, import_node_fs12.readFileSync)((0, import_node_path11.join)(rootDir, "package.json"), "utf8"));
3870
4016
  } catch {
3871
4017
  return null;
3872
4018
  }
@@ -4094,12 +4240,12 @@ function harnessOption(value2, flag) {
4094
4240
 
4095
4241
  // src/init.ts
4096
4242
  var import_node_fs13 = require("fs");
4097
- var import_node_path11 = require("path");
4243
+ var import_node_path12 = require("path");
4098
4244
  var import_apps9 = require("@odla-ai/apps");
4099
4245
  function initProject(options) {
4100
4246
  const out = options.stdout ?? console;
4101
- const rootDir = (0, import_node_path11.resolve)(options.rootDir ?? process.cwd());
4102
- const configPath = (0, import_node_path11.resolve)(rootDir, options.configPath ?? "odla.config.mjs");
4247
+ const rootDir = (0, import_node_path12.resolve)(options.rootDir ?? process.cwd());
4248
+ const configPath = (0, import_node_path12.resolve)(rootDir, options.configPath ?? "odla.config.mjs");
4103
4249
  if ((0, import_node_fs13.existsSync)(configPath) && !options.force) {
4104
4250
  throw new Error(`${configPath} already exists. Pass --force to overwrite.`);
4105
4251
  }
@@ -4116,12 +4262,12 @@ function initProject(options) {
4116
4262
  }
4117
4263
  }
4118
4264
  const aiProvider = options.aiProvider ?? "anthropic";
4119
- (0, import_node_fs13.mkdirSync)((0, import_node_path11.dirname)(configPath), { recursive: true });
4120
- (0, import_node_fs13.mkdirSync)((0, import_node_path11.resolve)(rootDir, "src/odla"), { recursive: true });
4121
- (0, import_node_fs13.mkdirSync)((0, import_node_path11.resolve)(rootDir, ".odla"), { recursive: true });
4265
+ (0, import_node_fs13.mkdirSync)((0, import_node_path12.dirname)(configPath), { recursive: true });
4266
+ (0, import_node_fs13.mkdirSync)((0, import_node_path12.resolve)(rootDir, "src/odla"), { recursive: true });
4267
+ (0, import_node_fs13.mkdirSync)((0, import_node_path12.resolve)(rootDir, ".odla"), { recursive: true });
4122
4268
  (0, import_node_fs13.writeFileSync)(configPath, configTemplate({ appId: options.appId, name: options.name, envs, services, aiProvider }));
4123
- writeIfMissing((0, import_node_path11.resolve)(rootDir, "src/odla/schema.mjs"), schemaTemplate());
4124
- writeIfMissing((0, import_node_path11.resolve)(rootDir, "src/odla/rules.mjs"), rulesTemplate());
4269
+ writeIfMissing((0, import_node_path12.resolve)(rootDir, "src/odla/schema.mjs"), schemaTemplate());
4270
+ writeIfMissing((0, import_node_path12.resolve)(rootDir, "src/odla/rules.mjs"), rulesTemplate());
4125
4271
  ensureGitignore(rootDir);
4126
4272
  out.log(`created ${relativeDisplay(configPath, rootDir)}`);
4127
4273
  out.log("created src/odla/schema.mjs and src/odla/rules.mjs");
@@ -4362,7 +4508,7 @@ async function resolveVaultWrite(options) {
4362
4508
  // src/skill.ts
4363
4509
  var import_node_fs14 = require("fs");
4364
4510
  var import_node_os2 = require("os");
4365
- var import_node_path12 = require("path");
4511
+ var import_node_path13 = require("path");
4366
4512
  var import_node_url2 = require("url");
4367
4513
 
4368
4514
  // src/skill-adapters.ts
@@ -4441,8 +4587,8 @@ function installSkill(options = {}) {
4441
4587
  const files = listFiles(sourceDir);
4442
4588
  if (files.length === 0) throw new Error(`no bundled skills found at ${sourceDir}`);
4443
4589
  const harnesses = normalizeHarnesses(options.harnesses, options.global === true);
4444
- const root = (0, import_node_path12.resolve)(options.dir ?? process.cwd());
4445
- const home = (0, import_node_path12.resolve)(options.homeDir ?? (0, import_node_os2.homedir)());
4590
+ const root = (0, import_node_path13.resolve)(options.dir ?? process.cwd());
4591
+ const home = (0, import_node_path13.resolve)(options.homeDir ?? (0, import_node_os2.homedir)());
4446
4592
  const plans = /* @__PURE__ */ new Map();
4447
4593
  const targets = /* @__PURE__ */ new Map();
4448
4594
  const rememberTarget = (harness, target) => {
@@ -4456,48 +4602,48 @@ function installSkill(options = {}) {
4456
4602
  plans.set(target, { target, content: content2, boundary, managedMerge });
4457
4603
  };
4458
4604
  const planSkillTree = (targetDir2, boundary = root) => {
4459
- for (const rel of files) plan((0, import_node_path12.join)(targetDir2, rel), (0, import_node_fs14.readFileSync)((0, import_node_path12.join)(sourceDir, rel), "utf8"), false, boundary);
4605
+ for (const rel of files) plan((0, import_node_path13.join)(targetDir2, rel), (0, import_node_fs14.readFileSync)((0, import_node_path13.join)(sourceDir, rel), "utf8"), false, boundary);
4460
4606
  };
4461
4607
  let targetDir;
4462
4608
  if (options.global) {
4463
- const claudeRoot = (0, import_node_path12.join)(home, ".claude", "skills");
4464
- const codexRoot = (0, import_node_path12.resolve)(options.codexHomeDir ?? process.env.CODEX_HOME ?? (0, import_node_path12.join)(home, ".codex"), "skills");
4609
+ const claudeRoot = (0, import_node_path13.join)(home, ".claude", "skills");
4610
+ const codexRoot = (0, import_node_path13.resolve)(options.codexHomeDir ?? process.env.CODEX_HOME ?? (0, import_node_path13.join)(home, ".codex"), "skills");
4465
4611
  targetDir = harnesses[0] === "codex" ? codexRoot : claudeRoot;
4466
4612
  for (const harness of harnesses) {
4467
4613
  const skillRoot = harness === "claude" ? claudeRoot : codexRoot;
4468
- planSkillTree(skillRoot, harness === "claude" ? home : (0, import_node_path12.dirname)((0, import_node_path12.dirname)(codexRoot)));
4614
+ planSkillTree(skillRoot, harness === "claude" ? home : (0, import_node_path13.dirname)((0, import_node_path13.dirname)(codexRoot)));
4469
4615
  rememberTarget(harness, skillRoot);
4470
4616
  }
4471
4617
  } else {
4472
- const sharedRoot = (0, import_node_path12.join)(root, ".agents", "skills");
4618
+ const sharedRoot = (0, import_node_path13.join)(root, ".agents", "skills");
4473
4619
  planSkillTree(sharedRoot);
4474
- const claudeRoot = (0, import_node_path12.join)(root, ".claude", "skills");
4620
+ const claudeRoot = (0, import_node_path13.join)(root, ".claude", "skills");
4475
4621
  targetDir = harnesses.includes("claude") ? claudeRoot : sharedRoot;
4476
4622
  for (const harness of harnesses) rememberTarget(harness, sharedRoot);
4477
4623
  if (harnesses.includes("claude")) {
4478
4624
  for (const skill of skillNames(files)) {
4479
- const canonical = (0, import_node_fs14.readFileSync)((0, import_node_path12.join)(sourceDir, skill, "SKILL.md"), "utf8");
4480
- plan((0, import_node_path12.join)(claudeRoot, skill, "SKILL.md"), claudeAdapter(skill, canonical));
4625
+ const canonical = (0, import_node_fs14.readFileSync)((0, import_node_path13.join)(sourceDir, skill, "SKILL.md"), "utf8");
4626
+ plan((0, import_node_path13.join)(claudeRoot, skill, "SKILL.md"), claudeAdapter(skill, canonical));
4481
4627
  }
4482
4628
  rememberTarget("claude", claudeRoot);
4483
4629
  }
4484
4630
  if (harnesses.includes("cursor")) {
4485
- const cursorRule = (0, import_node_path12.join)(root, ".cursor", "rules", "odla.mdc");
4631
+ const cursorRule = (0, import_node_path13.join)(root, ".cursor", "rules", "odla.mdc");
4486
4632
  plan(cursorRule, CURSOR_RULE);
4487
4633
  rememberTarget("cursor", cursorRule);
4488
4634
  }
4489
4635
  if (harnesses.includes("agents")) {
4490
- const agentsFile = (0, import_node_path12.join)(root, "AGENTS.md");
4636
+ const agentsFile = (0, import_node_path13.join)(root, "AGENTS.md");
4491
4637
  plan(agentsFile, managedFileContent(agentsFile, PROJECT_INSTRUCTIONS, options.force === true, root), true);
4492
4638
  rememberTarget("agents", agentsFile);
4493
4639
  }
4494
4640
  if (harnesses.includes("copilot")) {
4495
- const copilotFile = (0, import_node_path12.join)(root, ".github", "copilot-instructions.md");
4641
+ const copilotFile = (0, import_node_path13.join)(root, ".github", "copilot-instructions.md");
4496
4642
  plan(copilotFile, managedFileContent(copilotFile, PROJECT_INSTRUCTIONS, options.force === true, root), true);
4497
4643
  rememberTarget("copilot", copilotFile);
4498
4644
  }
4499
4645
  if (harnesses.includes("gemini")) {
4500
- const geminiFile = (0, import_node_path12.join)(root, "GEMINI.md");
4646
+ const geminiFile = (0, import_node_path13.join)(root, "GEMINI.md");
4501
4647
  plan(geminiFile, managedFileContent(geminiFile, PROJECT_INSTRUCTIONS, options.force === true, root), true);
4502
4648
  rememberTarget("gemini", geminiFile);
4503
4649
  }
@@ -4533,7 +4679,7 @@ ${conflicts.map((f) => ` - ${f}`).join("\n")}`
4533
4679
  }
4534
4680
  for (const file of plans.values()) {
4535
4681
  if (!(0, import_node_fs14.existsSync)(file.target) || (0, import_node_fs14.readFileSync)(file.target, "utf8") !== file.content) {
4536
- (0, import_node_fs14.mkdirSync)((0, import_node_path12.dirname)(file.target), { recursive: true });
4682
+ (0, import_node_fs14.mkdirSync)((0, import_node_path13.dirname)(file.target), { recursive: true });
4537
4683
  (0, import_node_fs14.writeFileSync)(file.target, file.content);
4538
4684
  }
4539
4685
  }
@@ -4553,7 +4699,7 @@ ${conflicts.map((f) => ` - ${f}`).join("\n")}`
4553
4699
  };
4554
4700
  }
4555
4701
  function pathsUnder(root, paths) {
4556
- return [...paths].map((path) => (0, import_node_path12.relative)(root, path)).filter((path) => path !== ".." && !path.startsWith(`..${import_node_path12.sep}`) && !(0, import_node_path12.isAbsolute)(path)).sort();
4702
+ return [...paths].map((path) => (0, import_node_path13.relative)(root, path)).filter((path) => path !== ".." && !path.startsWith(`..${import_node_path13.sep}`) && !(0, import_node_path13.isAbsolute)(path)).sort();
4557
4703
  }
4558
4704
  function normalizeHarnesses(values, global) {
4559
4705
  const requested = values?.length ? values : ["claude"];
@@ -4598,13 +4744,13 @@ function managedFileContent(path, block, force, boundary) {
4598
4744
  return `${current.slice(0, startAt)}${block}${current.slice(afterEnd)}`;
4599
4745
  }
4600
4746
  function symlinkedComponent(boundary, target) {
4601
- const rel = (0, import_node_path12.relative)(boundary, target);
4602
- if (rel === ".." || rel.startsWith(`..${import_node_path12.sep}`) || (0, import_node_path12.isAbsolute)(rel)) {
4747
+ const rel = (0, import_node_path13.relative)(boundary, target);
4748
+ if (rel === ".." || rel.startsWith(`..${import_node_path13.sep}`) || (0, import_node_path13.isAbsolute)(rel)) {
4603
4749
  throw new Error(`agent setup target escapes its install root: ${target}`);
4604
4750
  }
4605
4751
  let current = boundary;
4606
- for (const part of rel.split(import_node_path12.sep).filter(Boolean)) {
4607
- current = (0, import_node_path12.join)(current, part);
4752
+ for (const part of rel.split(import_node_path13.sep).filter(Boolean)) {
4753
+ current = (0, import_node_path13.join)(current, part);
4608
4754
  try {
4609
4755
  if ((0, import_node_fs14.lstatSync)(current).isSymbolicLink()) return current;
4610
4756
  } catch (error) {
@@ -4621,9 +4767,9 @@ function listFiles(dir) {
4621
4767
  const results = [];
4622
4768
  const walk = (current) => {
4623
4769
  for (const entry of (0, import_node_fs14.readdirSync)(current, { withFileTypes: true })) {
4624
- const path = (0, import_node_path12.join)(current, entry.name);
4770
+ const path = (0, import_node_path13.join)(current, entry.name);
4625
4771
  if (entry.isDirectory()) walk(path);
4626
- else results.push((0, import_node_path12.relative)(dir, path));
4772
+ else results.push((0, import_node_path13.relative)(dir, path));
4627
4773
  }
4628
4774
  };
4629
4775
  walk(dir);
@@ -4935,7 +5081,7 @@ async function projectCommand(command, parsed, deps) {
4935
5081
  // src/code-connect.ts
4936
5082
  var import_node_fs15 = require("fs");
4937
5083
  var import_node_os4 = require("os");
4938
- var import_node_path14 = require("path");
5084
+ var import_node_path15 = require("path");
4939
5085
 
4940
5086
  // ../harness/dist/chunk-QTUEF2HZ.js
4941
5087
  var HARNESS_PROTOCOL_VERSION = 1;
@@ -5021,15 +5167,15 @@ function encodeAgentInput(message2) {
5021
5167
  // ../harness/dist/chunk-PHXQH4YM.js
5022
5168
  var import_child_process = require("child_process");
5023
5169
  var import_fs = require("fs");
5024
- var import_promises2 = require("fs/promises");
5170
+ var import_promises3 = require("fs/promises");
5025
5171
  var import_path = require("path");
5026
5172
  var import_process = require("process");
5027
- var import_promises3 = require("fs/promises");
5173
+ var import_promises4 = require("fs/promises");
5028
5174
  var import_os = require("os");
5029
5175
  var import_path2 = require("path");
5030
5176
  var import_child_process2 = require("child_process");
5031
5177
  var import_path3 = require("path");
5032
- var import_promises4 = require("fs/promises");
5178
+ var import_promises5 = require("fs/promises");
5033
5179
  var import_os2 = require("os");
5034
5180
  var import_path4 = require("path");
5035
5181
  var import_child_process3 = require("child_process");
@@ -5040,7 +5186,7 @@ function assertPinnedImage(image) {
5040
5186
  async function commandAvailable(engine) {
5041
5187
  for (const directory of (process.env.PATH ?? "").split(import_path.delimiter).filter(Boolean)) {
5042
5188
  try {
5043
- await (0, import_promises2.access)((0, import_path.join)(directory, engine), import_fs.constants.X_OK);
5189
+ await (0, import_promises3.access)((0, import_path.join)(directory, engine), import_fs.constants.X_OK);
5044
5190
  return true;
5045
5191
  } catch {
5046
5192
  }
@@ -5326,18 +5472,18 @@ async function gitBlobs(cwd, entries, maxBytes) {
5326
5472
  }
5327
5473
  async function materializeGitTree(source, commitSha, options = {}) {
5328
5474
  if (!/^[0-9a-f]{40}$/.test(commitSha)) throw new TypeError("Git tree requires an exact commit SHA");
5329
- const sourceDir = await (0, import_promises3.realpath)((0, import_path2.resolve)(source));
5475
+ const sourceDir = await (0, import_promises4.realpath)((0, import_path2.resolve)(source));
5330
5476
  const maxFiles = options.maxFiles ?? 2e4;
5331
5477
  const maxBytes = options.maxBytes ?? 512 * 1024 * 1024;
5332
5478
  const inventory = (await gitOutput(sourceDir, ["ls-tree", "-rz", commitSha], 16 * 1024 * 1024)).toString("utf8").split("\0").filter(Boolean);
5333
- const entries = inventory.flatMap((record11) => {
5334
- const match = /^(100644|100755) blob ([0-9a-f]{40,64})\t([\s\S]+)$/.exec(record11);
5479
+ const entries = inventory.flatMap((record10) => {
5480
+ const match = /^(100644|100755) blob ([0-9a-f]{40,64})\t([\s\S]+)$/.exec(record10);
5335
5481
  return match && allowedWorkspacePath(match[3]) ? [{ mode: match[1], hash: match[2], path: match[3] }] : [];
5336
5482
  });
5337
5483
  if (entries.length > maxFiles) throw new Error(`workspace exceeds ${maxFiles} files`);
5338
- const root = await (0, import_promises3.mkdtemp)((0, import_path2.join)(options.tempRoot ?? (0, import_os.tmpdir)(), "odla-git-tree-"));
5484
+ const root = await (0, import_promises4.mkdtemp)((0, import_path2.join)(options.tempRoot ?? (0, import_os.tmpdir)(), "odla-git-tree-"));
5339
5485
  const targetRoot = (0, import_path2.join)(root, "source");
5340
- await (0, import_promises3.mkdir)(targetRoot);
5486
+ await (0, import_promises4.mkdir)(targetRoot);
5341
5487
  let byteCount = 0;
5342
5488
  try {
5343
5489
  const blobs = await gitBlobs(sourceDir, entries, maxBytes);
@@ -5347,18 +5493,18 @@ async function materializeGitTree(source, commitSha, options = {}) {
5347
5493
  if (byteCount > maxBytes) throw new Error(`workspace exceeds ${maxBytes} bytes`);
5348
5494
  const target = (0, import_path2.resolve)(targetRoot, entry.path);
5349
5495
  if (!target.startsWith(`${(0, import_path2.resolve)(targetRoot)}${import_path2.sep}`)) throw new TypeError("Git tree path escapes workspace");
5350
- await (0, import_promises3.mkdir)((0, import_path2.resolve)(target, ".."), { recursive: true });
5351
- await (0, import_promises3.writeFile)(target, content2, { flag: "wx", mode: entry.mode === "100755" ? 493 : 420 });
5496
+ await (0, import_promises4.mkdir)((0, import_path2.resolve)(target, ".."), { recursive: true });
5497
+ await (0, import_promises4.writeFile)(target, content2, { flag: "wx", mode: entry.mode === "100755" ? 493 : 420 });
5352
5498
  }
5353
5499
  return {
5354
5500
  root,
5355
5501
  sourceDir: targetRoot,
5356
5502
  fileCount: entries.length,
5357
5503
  byteCount,
5358
- cleanup: () => (0, import_promises3.rm)(root, { recursive: true, force: true })
5504
+ cleanup: () => (0, import_promises4.rm)(root, { recursive: true, force: true })
5359
5505
  };
5360
5506
  } catch (error) {
5361
- await (0, import_promises3.rm)(root, { recursive: true, force: true });
5507
+ await (0, import_promises4.rm)(root, { recursive: true, force: true });
5362
5508
  throw error;
5363
5509
  }
5364
5510
  }
@@ -5366,7 +5512,7 @@ async function sourceFiles(sourceDir, maxFiles, maxBytes) {
5366
5512
  const files = [];
5367
5513
  let bytes = 0;
5368
5514
  const walk = async (dir) => {
5369
- for (const entry of await (0, import_promises4.readdir)(dir, { withFileTypes: true })) {
5515
+ for (const entry of await (0, import_promises5.readdir)(dir, { withFileTypes: true })) {
5370
5516
  if (entry.isDirectory() && SKIP_WORKSPACE_DIRS.has(entry.name)) continue;
5371
5517
  if (!entry.isDirectory() && SECRET_WORKSPACE_FILE.test(entry.name)) continue;
5372
5518
  const path = (0, import_path4.join)(dir, entry.name);
@@ -5376,7 +5522,7 @@ async function sourceFiles(sourceDir, maxFiles, maxBytes) {
5376
5522
  continue;
5377
5523
  }
5378
5524
  if (!entry.isFile()) continue;
5379
- const metadata2 = await (0, import_promises4.stat)(path);
5525
+ const metadata2 = await (0, import_promises5.stat)(path);
5380
5526
  bytes += metadata2.size;
5381
5527
  if (files.length + 1 > maxFiles) throw new Error(`workspace exceeds ${maxFiles} files`);
5382
5528
  if (bytes > maxBytes) throw new Error(`workspace exceeds ${maxBytes} bytes`);
@@ -5425,7 +5571,7 @@ async function gitSourceFiles(sourceDir, maxFiles, maxBytes) {
5425
5571
  if (!source.startsWith(`${root}${import_path4.sep}`)) throw new TypeError("git file path escapes workspace");
5426
5572
  let metadata2;
5427
5573
  try {
5428
- metadata2 = await (0, import_promises4.lstat)(source);
5574
+ metadata2 = await (0, import_promises5.lstat)(source);
5429
5575
  } catch (error) {
5430
5576
  if (error.code === "ENOENT") continue;
5431
5577
  throw error;
@@ -5440,9 +5586,9 @@ async function gitSourceFiles(sourceDir, maxFiles, maxBytes) {
5440
5586
  async function copyTree(files, destination) {
5441
5587
  for (const file of files) {
5442
5588
  const target = (0, import_path4.join)(destination, file.relativePath);
5443
- await (0, import_promises4.mkdir)((0, import_path4.resolve)(target, ".."), { recursive: true });
5444
- await (0, import_promises4.copyFile)(file.source, target);
5445
- await (0, import_promises4.chmod)(target, file.mode);
5589
+ await (0, import_promises5.mkdir)((0, import_path4.resolve)(target, ".."), { recursive: true });
5590
+ await (0, import_promises5.copyFile)(file.source, target);
5591
+ await (0, import_promises5.chmod)(target, file.mode);
5446
5592
  }
5447
5593
  }
5448
5594
  async function captureGitDiff(root, maxBytes) {
@@ -5479,13 +5625,13 @@ async function captureGitDiff(root, maxBytes) {
5479
5625
  return Buffer.concat(stdout).toString("utf8").replaceAll("a/baseline/", "a/").replaceAll("a/workspace/", "a/").replaceAll("b/baseline/", "b/").replaceAll("b/workspace/", "b/").replaceAll("--- a/baseline", "--- a").replaceAll("+++ b/workspace", "+++ b");
5480
5626
  }
5481
5627
  async function stageWorkspace(source, options = {}) {
5482
- const sourceDir = await (0, import_promises4.realpath)((0, import_path4.resolve)(source));
5483
- const sourceStat = await (0, import_promises4.stat)(sourceDir);
5628
+ const sourceDir = await (0, import_promises5.realpath)((0, import_path4.resolve)(source));
5629
+ const sourceStat = await (0, import_promises5.stat)(sourceDir);
5484
5630
  if (!sourceStat.isDirectory()) throw new TypeError("workspace source must be a directory");
5485
- const root = await (0, import_promises4.mkdtemp)((0, import_path4.join)(options.tempRoot ?? (0, import_os2.tmpdir)(), "odla-harness-"));
5631
+ const root = await (0, import_promises5.mkdtemp)((0, import_path4.join)(options.tempRoot ?? (0, import_os2.tmpdir)(), "odla-harness-"));
5486
5632
  const baselineDir = (0, import_path4.join)(root, "baseline");
5487
5633
  const workspaceDir = (0, import_path4.join)(root, "workspace");
5488
- await Promise.all([(0, import_promises4.mkdir)(baselineDir), (0, import_promises4.mkdir)(workspaceDir)]);
5634
+ await Promise.all([(0, import_promises5.mkdir)(baselineDir), (0, import_promises5.mkdir)(workspaceDir)]);
5489
5635
  try {
5490
5636
  const maxFiles = options.maxFiles ?? 2e4;
5491
5637
  const maxBytes = options.maxBytes ?? 512 * 1024 * 1024;
@@ -5498,26 +5644,26 @@ async function stageWorkspace(source, options = {}) {
5498
5644
  fileCount: files.length,
5499
5645
  byteCount: files.reduce((sum, file) => sum + file.bytes, 0),
5500
5646
  patch: (maxBytes2) => captureGitDiff(root, maxBytes2),
5501
- cleanup: () => (0, import_promises4.rm)(root, { recursive: true, force: true })
5647
+ cleanup: () => (0, import_promises5.rm)(root, { recursive: true, force: true })
5502
5648
  };
5503
5649
  } catch (error) {
5504
- await (0, import_promises4.rm)(root, { recursive: true, force: true });
5650
+ await (0, import_promises5.rm)(root, { recursive: true, force: true });
5505
5651
  throw error;
5506
5652
  }
5507
5653
  }
5508
5654
  async function stageWorkspacePair(baselineSource, workspaceSource, options = {}) {
5509
- const baselineDirSource = await (0, import_promises4.realpath)((0, import_path4.resolve)(baselineSource));
5510
- const workspaceDirSource = await (0, import_promises4.realpath)((0, import_path4.resolve)(workspaceSource));
5655
+ const baselineDirSource = await (0, import_promises5.realpath)((0, import_path4.resolve)(baselineSource));
5656
+ const workspaceDirSource = await (0, import_promises5.realpath)((0, import_path4.resolve)(workspaceSource));
5511
5657
  const maxFiles = options.maxFiles ?? 2e4;
5512
5658
  const maxBytes = options.maxBytes ?? 512 * 1024 * 1024;
5513
5659
  const [baselineFiles, workspaceFiles] = await Promise.all([
5514
5660
  sourceFiles(baselineDirSource, maxFiles, maxBytes),
5515
5661
  sourceFiles(workspaceDirSource, maxFiles, maxBytes)
5516
5662
  ]);
5517
- const root = await (0, import_promises4.mkdtemp)((0, import_path4.join)(options.tempRoot ?? (0, import_os2.tmpdir)(), "odla-harness-"));
5663
+ const root = await (0, import_promises5.mkdtemp)((0, import_path4.join)(options.tempRoot ?? (0, import_os2.tmpdir)(), "odla-harness-"));
5518
5664
  const baselineDir = (0, import_path4.join)(root, "baseline");
5519
5665
  const workspaceDir = (0, import_path4.join)(root, "workspace");
5520
- await Promise.all([(0, import_promises4.mkdir)(baselineDir), (0, import_promises4.mkdir)(workspaceDir)]);
5666
+ await Promise.all([(0, import_promises5.mkdir)(baselineDir), (0, import_promises5.mkdir)(workspaceDir)]);
5521
5667
  try {
5522
5668
  await Promise.all([copyTree(baselineFiles, baselineDir), copyTree(workspaceFiles, workspaceDir)]);
5523
5669
  return {
@@ -5527,17 +5673,17 @@ async function stageWorkspacePair(baselineSource, workspaceSource, options = {})
5527
5673
  fileCount: workspaceFiles.length,
5528
5674
  byteCount: workspaceFiles.reduce((sum, file) => sum + file.bytes, 0),
5529
5675
  patch: (maxPatchBytes) => captureGitDiff(root, maxPatchBytes),
5530
- cleanup: () => (0, import_promises4.rm)(root, { recursive: true, force: true })
5676
+ cleanup: () => (0, import_promises5.rm)(root, { recursive: true, force: true })
5531
5677
  };
5532
5678
  } catch (error) {
5533
- await (0, import_promises4.rm)(root, { recursive: true, force: true });
5679
+ await (0, import_promises5.rm)(root, { recursive: true, force: true });
5534
5680
  throw error;
5535
5681
  }
5536
5682
  }
5537
5683
 
5538
5684
  // ../harness/dist/chunk-GMVZ4LZH.js
5539
5685
  var import_crypto = require("crypto");
5540
- var import_promises5 = require("fs/promises");
5686
+ var import_promises6 = require("fs/promises");
5541
5687
  var import_path5 = require("path");
5542
5688
 
5543
5689
  // ../camel/dist/chunk-7FHPOQVP.js
@@ -5579,8 +5725,8 @@ function normalize(value2) {
5579
5725
  if (Array.isArray(value2)) return value2.map(normalize);
5580
5726
  if (value2 instanceof Uint8Array) return { $bytes: [...value2] };
5581
5727
  if (typeof value2 === "object") {
5582
- const record11 = value2;
5583
- return Object.fromEntries(Object.keys(record11).filter((key) => record11[key] !== void 0).sort().map((key) => [key, normalize(record11[key])]));
5728
+ const record10 = value2;
5729
+ return Object.fromEntries(Object.keys(record10).filter((key) => record10[key] !== void 0).sort().map((key) => [key, normalize(record10[key])]));
5584
5730
  }
5585
5731
  throw new CamelError("state_conflict", "Canonical JSON rejects unsupported values.");
5586
5732
  }
@@ -5874,19 +6020,19 @@ function validateSnapshot(snapshot, limits) {
5874
6020
 
5875
6021
  // ../harness/dist/chunk-GMVZ4LZH.js
5876
6022
  var import_child_process4 = require("child_process");
5877
- var import_promises6 = require("fs/promises");
6023
+ var import_promises7 = require("fs/promises");
5878
6024
  var import_path6 = require("path");
5879
6025
  var import_child_process5 = require("child_process");
5880
6026
  var import_process2 = require("process");
5881
6027
  var import_crypto2 = require("crypto");
5882
6028
  var import_crypto3 = require("crypto");
5883
6029
  var import_fs2 = require("fs");
5884
- var import_promises7 = require("fs/promises");
5885
- var import_path7 = require("path");
5886
6030
  var import_promises8 = require("fs/promises");
6031
+ var import_path7 = require("path");
6032
+ var import_promises9 = require("fs/promises");
5887
6033
  var import_os3 = require("os");
5888
6034
  var import_path8 = require("path");
5889
- var import_promises9 = require("fs/promises");
6035
+ var import_promises10 = require("fs/promises");
5890
6036
  var import_path9 = require("path");
5891
6037
 
5892
6038
  // ../camel/dist/chunk-LAXU2AVK.js
@@ -6170,7 +6316,7 @@ var import_crypto4 = require("crypto");
6170
6316
  async function digestStagedWorkspace(root, limits) {
6171
6317
  const files = [];
6172
6318
  const walk = async (directory) => {
6173
- const entries = await (0, import_promises5.readdir)(directory, { withFileTypes: true });
6319
+ const entries = await (0, import_promises6.readdir)(directory, { withFileTypes: true });
6174
6320
  for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
6175
6321
  if (entry.isSymbolicLink()) throw new TypeError("workspace digest refuses symbolic links");
6176
6322
  const target = (0, import_path5.resolve)(directory, entry.name);
@@ -6185,7 +6331,7 @@ async function digestStagedWorkspace(root, limits) {
6185
6331
  const hash = (0, import_crypto.createHash)("sha256");
6186
6332
  let bytes = 0;
6187
6333
  for (const file of files.sort((left, right) => left.path.localeCompare(right.path))) {
6188
- const content2 = await (0, import_promises5.readFile)(file.target);
6334
+ const content2 = await (0, import_promises6.readFile)(file.target);
6189
6335
  bytes += Buffer.byteLength(file.path) + content2.byteLength;
6190
6336
  if (bytes > limits.maxBytes) throw new TypeError("workspace digest exceeds its byte bound");
6191
6337
  hash.update(`${Buffer.byteLength(file.path)}:${file.path}:${content2.byteLength}:`);
@@ -6511,7 +6657,7 @@ async function applyCodePatch(workspaceDir, patch2, paths) {
6511
6657
  await gitApply(workspaceDir, patch2, false);
6512
6658
  for (const path of paths) {
6513
6659
  try {
6514
- const info = await (0, import_promises6.lstat)(resolveCodePath(workspaceDir, path));
6660
+ const info = await (0, import_promises7.lstat)(resolveCodePath(workspaceDir, path));
6515
6661
  if (info.isSymbolicLink() || !info.isFile() && !info.isDirectory()) {
6516
6662
  throw new TypeError("patch created a non-regular workspace entry");
6517
6663
  }
@@ -6802,7 +6948,7 @@ async function inspectArtifacts(workspaceDir, recipe2) {
6802
6948
  for (const artifact of recipe2.expectedArtifacts ?? []) {
6803
6949
  try {
6804
6950
  const path = (0, import_path7.join)(workspaceDir, artifact.path);
6805
- const info = await (0, import_promises7.lstat)(path);
6951
+ const info = await (0, import_promises8.lstat)(path);
6806
6952
  if (!info.isFile() || info.isSymbolicLink()) {
6807
6953
  receipts.push({ artifactId: artifact.id, status: "invalid", bytes: null, digest: null });
6808
6954
  } else if (info.size > artifact.maximumBytes) {
@@ -6983,9 +7129,9 @@ var RESERVED2 = /* @__PURE__ */ new Set([".git", ".odla", ".wrangler", "node_mod
6983
7129
  var SECRET2 = /^(?:\.env(?:\..+)?|\.dev\.vars|credentials(?:\..+)?\.json|dev-token(?:\..+)?\.json)$/i;
6984
7130
  async function materializeCodeRuntimeSource(snapshot, tempRoot = (0, import_os3.tmpdir)()) {
6985
7131
  if (!snapshot.files.length || snapshot.files.length > 1e4) throw new TypeError("Code source file count is invalid");
6986
- const root = await (0, import_promises8.mkdtemp)((0, import_path8.join)(tempRoot, "odla-code-source-"));
7132
+ const root = await (0, import_promises9.mkdtemp)((0, import_path8.join)(tempRoot, "odla-code-source-"));
6987
7133
  const sourceDir = (0, import_path8.join)(root, "source");
6988
- await (0, import_promises8.mkdir)(sourceDir);
7134
+ await (0, import_promises9.mkdir)(sourceDir);
6989
7135
  const seen = /* @__PURE__ */ new Set();
6990
7136
  let bytes = 0;
6991
7137
  try {
@@ -6997,8 +7143,8 @@ async function materializeCodeRuntimeSource(snapshot, tempRoot = (0, import_os3.
6997
7143
  if (bytes > 16 * 1024 * 1024) throw new TypeError("Code source exceeds its byte bound");
6998
7144
  const target = (0, import_path8.resolve)(sourceDir, file.path);
6999
7145
  if (!target.startsWith(`${(0, import_path8.resolve)(sourceDir)}${import_path8.sep}`)) throw new TypeError("Code source path escapes its root");
7000
- await (0, import_promises8.mkdir)((0, import_path8.dirname)(target), { recursive: true });
7001
- await (0, import_promises8.writeFile)(target, file.content, { flag: "wx", mode: 420 });
7146
+ await (0, import_promises9.mkdir)((0, import_path8.dirname)(target), { recursive: true });
7147
+ await (0, import_promises9.writeFile)(target, file.content, { flag: "wx", mode: 420 });
7002
7148
  }
7003
7149
  for (const reference of snapshot.references ?? []) {
7004
7150
  validateAlias(reference.alias);
@@ -7012,13 +7158,13 @@ async function materializeCodeRuntimeSource(snapshot, tempRoot = (0, import_os3.
7012
7158
  if (bytes > 80 * 1024 * 1024) throw new TypeError("Code source set exceeds its byte bound");
7013
7159
  const target = (0, import_path8.resolve)(sourceDir, path);
7014
7160
  if (!target.startsWith(`${(0, import_path8.resolve)(sourceDir)}${import_path8.sep}`)) throw new TypeError("Code reference path escapes its root");
7015
- await (0, import_promises8.mkdir)((0, import_path8.dirname)(target), { recursive: true });
7016
- await (0, import_promises8.writeFile)(target, file.content, { flag: "wx", mode: 292 });
7161
+ await (0, import_promises9.mkdir)((0, import_path8.dirname)(target), { recursive: true });
7162
+ await (0, import_promises9.writeFile)(target, file.content, { flag: "wx", mode: 292 });
7017
7163
  }
7018
7164
  }
7019
- return { sourceDir, cleanup: () => (0, import_promises8.rm)(root, { recursive: true, force: true }) };
7165
+ return { sourceDir, cleanup: () => (0, import_promises9.rm)(root, { recursive: true, force: true }) };
7020
7166
  } catch (cause) {
7021
- await (0, import_promises8.rm)(root, { recursive: true, force: true });
7167
+ await (0, import_promises9.rm)(root, { recursive: true, force: true });
7022
7168
  throw cause;
7023
7169
  }
7024
7170
  }
@@ -7039,8 +7185,8 @@ async function attachCodeRuntimeReferences(workspace, references) {
7039
7185
  for (const root of [workspace.baselineDir, workspace.workspaceDir]) {
7040
7186
  const target = (0, import_path8.resolve)(root, path);
7041
7187
  if (!target.startsWith(`${(0, import_path8.resolve)(root)}${import_path8.sep}`)) throw new TypeError("Code reference path escapes its root");
7042
- await (0, import_promises8.mkdir)((0, import_path8.dirname)(target), { recursive: true });
7043
- await (0, import_promises8.writeFile)(target, file.content, { flag: "wx", mode: 292 });
7188
+ await (0, import_promises9.mkdir)((0, import_path8.dirname)(target), { recursive: true });
7189
+ await (0, import_promises9.writeFile)(target, file.content, { flag: "wx", mode: 292 });
7044
7190
  }
7045
7191
  }
7046
7192
  }
@@ -7226,11 +7372,11 @@ async function read(context, request2, options, policy) {
7226
7372
  const allowed = await policy.read(policyContext(context, request2, options, { paths, path, startLine, endLine }));
7227
7373
  if (!allowed) return response(request2, false, "tool denied by CaMeL policy");
7228
7374
  const target = resolveCodePath(context.workspaceDir, path);
7229
- const info = await (0, import_promises9.stat)(target);
7375
+ const info = await (0, import_promises10.stat)(target);
7230
7376
  if (!info.isFile() || info.size > Math.max(options.maxReadBytes ?? 128 * 1024, 2 * 1024 * 1024)) {
7231
7377
  throw new TypeError("file is not a bounded regular source file");
7232
7378
  }
7233
- const source = await (0, import_promises9.readFile)(target);
7379
+ const source = await (0, import_promises10.readFile)(target);
7234
7380
  if (source.includes(0)) throw new TypeError("binary files are not readable through this tool");
7235
7381
  const lines = source.toString("utf8").split("\n");
7236
7382
  const content2 = lines.slice(startLine - 1, endLine).join("\n");
@@ -7307,7 +7453,7 @@ function policyContext(context, request2, options, extra) {
7307
7453
  async function registeredFiles(root, limit) {
7308
7454
  const paths = [];
7309
7455
  const walk = async (directory) => {
7310
- for (const entry of await (0, import_promises9.readdir)(directory, { withFileTypes: true })) {
7456
+ for (const entry of await (0, import_promises10.readdir)(directory, { withFileTypes: true })) {
7311
7457
  if (entry.isSymbolicLink()) throw new TypeError("workspace contains a symbolic link");
7312
7458
  const target = (0, import_path9.resolve)(directory, entry.name);
7313
7459
  if (entry.isDirectory()) await walk(target);
@@ -7906,8 +8052,8 @@ function hostedPollTimeout(value2 = 10 * 6e4) {
7906
8052
  }
7907
8053
  async function waitForHostedPoll(milliseconds, signal) {
7908
8054
  if (signal?.aborted) throw signal.reason ?? new DOMException("aborted", "AbortError");
7909
- await new Promise((resolve12, reject) => {
7910
- const timer = setTimeout(resolve12, milliseconds);
8055
+ await new Promise((resolve13, reject) => {
8056
+ const timer = setTimeout(resolve13, milliseconds);
7911
8057
  signal?.addEventListener("abort", () => {
7912
8058
  clearTimeout(timer);
7913
8059
  reject(signal.reason ?? new DOMException("aborted", "AbortError"));
@@ -8092,9 +8238,9 @@ function digestText(value2) {
8092
8238
  // src/code-images.ts
8093
8239
  var import_node_child_process6 = require("child_process");
8094
8240
  var import_node_crypto3 = require("crypto");
8095
- var import_promises10 = require("fs/promises");
8241
+ var import_promises11 = require("fs/promises");
8096
8242
  var import_node_os3 = require("os");
8097
- var import_node_path13 = require("path");
8243
+ var import_node_path14 = require("path");
8098
8244
  var import_node_url3 = require("url");
8099
8245
 
8100
8246
  // src/code-runtime-config.ts
@@ -8174,16 +8320,16 @@ function embeddedPiAssetPath() {
8174
8320
  return (0, import_node_url3.fileURLToPath)(new URL("./runtime/pi-agent.js", importMetaUrl));
8175
8321
  }
8176
8322
  async function embeddedPiImageName() {
8177
- const bundle = await (0, import_promises10.readFile)(embeddedPiAssetPath()).catch(() => {
8323
+ const bundle = await (0, import_promises11.readFile)(embeddedPiAssetPath()).catch(() => {
8178
8324
  throw new Error("CLI-embedded Pi runtime is missing; reinstall this exact @odla-ai/cli version");
8179
8325
  });
8180
8326
  return `odla-ai/pi-agent:embedded-sha256-${(0, import_node_crypto3.createHash)("sha256").update(bundle).digest("hex")}`;
8181
8327
  }
8182
8328
  async function buildEmbeddedPiImage(engine, image, run) {
8183
- const context = await (0, import_promises10.mkdtemp)((0, import_node_path13.join)((0, import_node_os3.tmpdir)(), "odla-code-pi-"));
8329
+ const context = await (0, import_promises11.mkdtemp)((0, import_node_path14.join)((0, import_node_os3.tmpdir)(), "odla-code-pi-"));
8184
8330
  try {
8185
- await (0, import_promises10.copyFile)(embeddedPiAssetPath(), (0, import_node_path13.join)(context, "pi-agent.js"));
8186
- await (0, import_promises10.writeFile)((0, import_node_path13.join)(context, "Dockerfile"), [
8331
+ await (0, import_promises11.copyFile)(embeddedPiAssetPath(), (0, import_node_path14.join)(context, "pi-agent.js"));
8332
+ await (0, import_promises11.writeFile)((0, import_node_path14.join)(context, "Dockerfile"), [
8187
8333
  `FROM ${CODE_NODE_IMAGE}`,
8188
8334
  "COPY pi-agent.js /opt/odla/pi-agent.js",
8189
8335
  "WORKDIR /workspace",
@@ -8192,14 +8338,14 @@ async function buildEmbeddedPiImage(engine, image, run) {
8192
8338
  ].join("\n"), { mode: 384 });
8193
8339
  await run(engine, ["build", "--tag", image, context], "inherit");
8194
8340
  } finally {
8195
- await (0, import_promises10.rm)(context, { recursive: true, force: true });
8341
+ await (0, import_promises11.rm)(context, { recursive: true, force: true });
8196
8342
  }
8197
8343
  }
8198
8344
 
8199
8345
  // src/code-connect.ts
8200
8346
  async function codeConnect(options) {
8201
8347
  const cwd = options.cwd ?? process.cwd();
8202
- const configPath = (0, import_node_path14.resolve)(cwd, options.configPath);
8348
+ const configPath = (0, import_node_path15.resolve)(cwd, options.configPath);
8203
8349
  const cfg = (0, import_node_fs15.existsSync)(configPath) ? await loadProjectConfig(configPath) : null;
8204
8350
  const requestedAppId = options.appId?.trim();
8205
8351
  if (requestedAppId && !/^[a-z0-9][a-z0-9-]{1,62}$/.test(requestedAppId)) {
@@ -8568,10 +8714,8 @@ function requireName(parsed) {
8568
8714
  return name;
8569
8715
  }
8570
8716
 
8571
- // src/help.ts
8572
- function printHelp(output = console) {
8573
- output.log(`odla-ai
8574
-
8717
+ // src/help-usage.ts
8718
+ var USAGE_SECTION = `
8575
8719
  Start here:
8576
8720
  odla-ai runbook ask "<question>" The current procedure, from odla's own
8577
8721
  runbooks. Ask BEFORE searching the web or
@@ -8605,6 +8749,7 @@ Usage:
8605
8749
  odla-ai app owners list [--config odla.config.mjs] [--email <odla-account>] [--json]
8606
8750
  odla-ai app owners add <email> [--email <odla-account>] [--json]
8607
8751
  odla-ai app owners remove <email> [--email <odla-account>] [--json]
8752
+ odla-ai brand design unpack <bundle.html|-> [--out <dir>] [--json]
8608
8753
  odla-ai pm goal list [--app <id>] [--status <s>] [--q <text>] [--limit <n>] [--offset <n>] [--json]
8609
8754
  odla-ai pm task list [--app <id>] [--column <c>] [--goal <id>] [--assignee <id>] [--q <text>] [--limit <n>] [--offset <n>] [--json]
8610
8755
  odla-ai pm decision list [--app <id>] [--status <s>] [--q <text>] [--limit <n>] [--offset <n>] [--json]
@@ -8640,7 +8785,6 @@ Usage:
8640
8785
  odla-ai context remove <name> --yes [--json]
8641
8786
  odla-ai o11y status [--app <id>] [--context <name>] [--platform https://odla.ai] [--env prod] [--minutes 60] [--json]
8642
8787
  odla-ai platform status [--context <name>] [--platform https://odla.ai] [--email <odla-account>] [--json]
8643
- odla-ai platform chat-credentials rotate [--context <name>] [--email <odla-account>] [--wrangler-config <path>] [--expected-version <id>] [--json] --yes
8644
8788
  odla-ai whoami [--context <name>] [--platform https://odla.ai] [--json]
8645
8789
  odla-ai runbook ask "<question>" [--app <id>] [--all] [--json]
8646
8790
  odla-ai runbook search "<question>" [--app <id>] [--all] [--limit <n>] [--json]
@@ -8685,8 +8829,12 @@ Usage:
8685
8829
  odla-ai secrets push --env <env> [--config odla.config.mjs] [--dry-run] [--yes]
8686
8830
  odla-ai secrets set <name> --env <env> (--from-env <NAME>|--stdin) [--email <odla-account>] [--config odla.config.mjs] [--yes]
8687
8831
  odla-ai secrets set-clerk-key --env <env> (--from-env <NAME>|--stdin) [--email <odla-account>] [--config odla.config.mjs] [--yes]
8688
- odla-ai version
8832
+ odla-ai version`;
8689
8833
 
8834
+ // src/help.ts
8835
+ function printHelp(output = console) {
8836
+ output.log(`odla-ai
8837
+ ${USAGE_SECTION}
8690
8838
  Commands:
8691
8839
  agent Inspect durable agent wakeups and explicitly requeue a
8692
8840
  dead-lettered job; JSON output is stable for remote operators.
@@ -9135,7 +9283,7 @@ function jsonl(ctx, parsed, value2) {
9135
9283
  }
9136
9284
  async function discussWatch(ctx, topicId, parsed) {
9137
9285
  if (ctx.json && parsed.options.jsonl === true) throw new Error("--json and --jsonl cannot be combined");
9138
- const sleep = ctx.sleep ?? ((ms) => new Promise((resolve12) => setTimeout(resolve12, ms)));
9286
+ const sleep = ctx.sleep ?? ((ms) => new Promise((resolve13) => setTimeout(resolve13, ms)));
9139
9287
  const now = ctx.now ?? Date.now;
9140
9288
  const intervalMs = (numberOpt2(parsed, "interval", DEFAULT_INTERVAL_MS / 1e3) ?? DEFAULT_INTERVAL_MS / 1e3) * 1e3;
9141
9289
  const timeoutSeconds = numberOpt2(parsed, "timeout");
@@ -9473,8 +9621,8 @@ async function pmAdd(ctx, entity, parsed) {
9473
9621
  emit2(ctx, res, () => ctx.out.log(`created ${entity} ${res.id}`));
9474
9622
  }
9475
9623
  async function pmGet(ctx, entity, id) {
9476
- const { record: record11 } = await pmRequest(ctx, "GET", `/${entity}/${encodeURIComponent(id)}`);
9477
- emit2(ctx, record11, () => printRecord(ctx, entity, record11));
9624
+ const { record: record10 } = await pmRequest(ctx, "GET", `/${entity}/${encodeURIComponent(id)}`);
9625
+ emit2(ctx, record10, () => printRecord(ctx, entity, record10));
9478
9626
  }
9479
9627
  async function pmSet(ctx, entity, id, parsed) {
9480
9628
  const patch2 = collectEntityFields(entity, parsed, true);
@@ -9519,9 +9667,9 @@ async function pmHandoff(ctx, parsed) {
9519
9667
  ]);
9520
9668
  const handoff = {
9521
9669
  appId,
9522
- unmetGoals: goals.filter((record11) => record11.status !== "met"),
9523
- activeTasks: tasks.filter((record11) => record11.column !== "done"),
9524
- openBugs: bugs.filter((record11) => record11.status !== "fixed" && record11.status !== "wontfix")
9670
+ unmetGoals: goals.filter((record10) => record10.status !== "met"),
9671
+ activeTasks: tasks.filter((record10) => record10.column !== "done"),
9672
+ openBugs: bugs.filter((record10) => record10.status !== "fixed" && record10.status !== "wontfix")
9525
9673
  };
9526
9674
  const result = {
9527
9675
  ...handoff,
@@ -9540,10 +9688,10 @@ async function pmHandoff(ctx, parsed) {
9540
9688
  ]) {
9541
9689
  ctx.out.log(`${label}:`);
9542
9690
  if (!records.length) ctx.out.log("- (none)");
9543
- else for (const record11 of records) printRecord(
9691
+ else for (const record10 of records) printRecord(
9544
9692
  ctx,
9545
9693
  label === "unmet goals" ? "goal" : label === "active tasks" ? "task" : "bug",
9546
- record11
9694
+ record10
9547
9695
  );
9548
9696
  }
9549
9697
  });
@@ -9734,167 +9882,12 @@ function age(input) {
9734
9882
  return `${Math.round(input / 6e4)}m`;
9735
9883
  }
9736
9884
 
9737
- // src/platform-chat-credential-command.ts
9738
- var import_node_process10 = __toESM(require("process"), 1);
9739
- async function rotatePlatformChatCredential(parsed, deps) {
9740
- assertArgs(
9741
- parsed,
9742
- [
9743
- "config",
9744
- "context",
9745
- "platform",
9746
- "token",
9747
- "email",
9748
- "open",
9749
- "json",
9750
- "yes",
9751
- "wrangler-config",
9752
- "expected-version"
9753
- ],
9754
- 3
9755
- );
9756
- if (parsed.options.yes !== true) {
9757
- throw new Error(
9758
- "platform chat-credentials rotate changes the production chat secret; pass --yes"
9759
- );
9760
- }
9761
- const context = await resolveOperatorContext(parsed, {
9762
- allowMissingConfig: true
9763
- });
9764
- const platform = context.platform.value;
9765
- const doFetch = deps.fetch ?? fetch;
9766
- const out = deps.stdout ?? console;
9767
- const run = deps.runner ?? defaultRunner;
9768
- const cwd = import_node_process10.default.cwd();
9769
- const wranglerConfig = stringOpt(parsed.options["wrangler-config"]) ?? "packages/chat-agent/wrangler.jsonc";
9770
- if (!await wranglerLoggedIn(run, cwd)) {
9771
- throw new Error(
9772
- 'Wrangler is not authenticated; run "npx wrangler login" and retry'
9773
- );
9774
- }
9775
- const priorHealth = await doFetch(`${platform}/health/services/chat`);
9776
- const priorVersion = priorHealth.headers.get("x-odla-worker-version-id");
9777
- await priorHealth.body?.cancel().catch(() => {
9778
- });
9779
- if (!priorVersion) {
9780
- throw new Error(
9781
- "chat health did not identify its current Worker version; refusing to rotate"
9782
- );
9783
- }
9784
- const expectedVersion = stringOpt(parsed.options["expected-version"]);
9785
- if (expectedVersion && priorVersion !== expectedVersion) {
9786
- throw new Error(
9787
- `chat health answered from version ${priorVersion}; expected ${expectedVersion}`
9788
- );
9789
- }
9790
- const token = await resolveAdminPlatformToken({
9791
- platform,
9792
- scope: "platform:chat:credential:write",
9793
- token: stringOpt(parsed.options.token),
9794
- tokenFile: context.credentials.scopedTokenFile,
9795
- email: stringOpt(parsed.options.email),
9796
- open: parsed.options.open === false ? false : parsed.options.open === true ? true : void 0,
9797
- fetch: doFetch,
9798
- stdout: out,
9799
- openApprovalUrl: deps.openUrl,
9800
- label: "odla CLI (rotate built-in Discussion responder)"
9801
- });
9802
- const mintedResponse = await doFetch(
9803
- `${platform}/registry/platform/chat-credentials/rotate`,
9804
- {
9805
- method: "POST",
9806
- headers: { authorization: `Bearer ${token}` }
9807
- }
9808
- );
9809
- const minted = await mintedResponse.json().catch(() => null);
9810
- if (!mintedResponse.ok) {
9811
- throw new Error(
9812
- `mint Discussion credential failed (HTTP ${mintedResponse.status}): ${apiMessage(minted)}`
9813
- );
9814
- }
9815
- if (!isPlatformChatCredential(minted)) {
9816
- throw new Error(
9817
- "platform returned an invalid odla.platform-chat-credential/v1 envelope"
9818
- );
9819
- }
9820
- const put = await wranglerPutSecret(run, {
9821
- name: "ODLA_BOT_TOKENS",
9822
- value: JSON.stringify({
9823
- [minted.appId]: { [minted.principalId]: minted.key }
9824
- }),
9825
- configPath: wranglerConfig,
9826
- cwd
9827
- });
9828
- if (put.code !== 0) {
9829
- throw new Error(
9830
- "Wrangler could not replace ODLA_BOT_TOKENS; the new scoped key was not activated"
9831
- );
9832
- }
9833
- const version = await waitForRotatedChatHealth({
9834
- fetch: doFetch,
9835
- platform,
9836
- priorVersion,
9837
- wait: deps.pollWait
9838
- });
9839
- const result = {
9840
- schemaVersion: "odla.platform-chat-credential-rotation/v1",
9841
- appId: minted.appId,
9842
- appIncarnation: minted.appIncarnation,
9843
- principalId: minted.principalId,
9844
- health: { ok: true, service: "odla-chat-agent", version }
9845
- };
9846
- if (parsed.options.json === true) {
9847
- out.log(JSON.stringify(result, null, 2));
9848
- } else {
9849
- out.log(
9850
- `rotated ${result.appId} ${result.principalId} ${result.health.version}`
9851
- );
9852
- }
9853
- }
9854
- async function waitForRotatedChatHealth(opts) {
9855
- const wait2 = opts.wait ?? ((milliseconds) => new Promise((resolve12) => setTimeout(resolve12, milliseconds)));
9856
- let lastStatus = 0;
9857
- let lastVersion = null;
9858
- let lastError = "private_service_unready";
9859
- for (let attempt = 0; attempt < 60; attempt++) {
9860
- const response2 = await opts.fetch(
9861
- `${opts.platform}/health/services/chat`
9862
- );
9863
- const body = await response2.json().catch(() => null);
9864
- const version = response2.headers.get("x-odla-worker-version-id");
9865
- if (response2.ok && record7(body) && body.ok === true && body.service === "odla-chat-agent" && version && version !== opts.priorVersion) {
9866
- return version;
9867
- }
9868
- lastStatus = response2.status;
9869
- lastVersion = version;
9870
- lastError = record7(body) && typeof body.error === "string" ? body.error : "private_service_unready";
9871
- if (attempt < 59) await wait2(5e3);
9872
- }
9873
- throw new Error(
9874
- `chat health did not converge on the rotated Worker deployment (HTTP ${lastStatus}, version ${lastVersion ?? "unknown"}, ${lastError})`
9875
- );
9876
- }
9877
- function isPlatformChatCredential(value2) {
9878
- 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_");
9879
- }
9880
- function apiMessage(value2) {
9881
- if (!record7(value2)) return "request failed";
9882
- const error = record7(value2.error) ? value2.error : value2;
9883
- return typeof error.message === "string" ? error.message : typeof error.code === "string" ? error.code : "request failed";
9884
- }
9885
- function record7(value2) {
9886
- return !!value2 && typeof value2 === "object" && !Array.isArray(value2);
9887
- }
9888
-
9889
9885
  // src/platform-command.ts
9890
9886
  async function platformCommand(parsed, deps = {}) {
9891
9887
  const action2 = parsed.positionals[1];
9892
9888
  if (action2 === "status") {
9893
9889
  return platformStatus(parsed, deps);
9894
9890
  }
9895
- if (action2 === "chat-credentials" && parsed.positionals[2] === "rotate") {
9896
- return rotatePlatformChatCredential(parsed, deps);
9897
- }
9898
9891
  throw new Error(
9899
9892
  `unknown platform action "${[
9900
9893
  action2,
@@ -9932,7 +9925,7 @@ async function platformStatus(parsed, deps) {
9932
9925
  const body = await response2.json().catch(() => null);
9933
9926
  if (!response2.ok) {
9934
9927
  throw new Error(
9935
- `read platform status failed (HTTP ${response2.status}): ${apiMessage2(body)}`
9928
+ `read platform status failed (HTTP ${response2.status}): ${apiMessage(body)}`
9936
9929
  );
9937
9930
  }
9938
9931
  if (!isPlatformStatus(body)) {
@@ -9945,17 +9938,17 @@ async function platformStatus(parsed, deps) {
9945
9938
  }
9946
9939
  }
9947
9940
  function isPlatformStatus(value2) {
9948
- if (!record8(value2) || value2.schemaVersion !== "odla.platform-status/v1") return false;
9949
- if (!record8(value2.verdict) || !Array.isArray(value2.verdict.reasons)) return false;
9950
- if (!record8(value2.catalog) || !record8(value2.summary)) return false;
9941
+ if (!record7(value2) || value2.schemaVersion !== "odla.platform-status/v1") return false;
9942
+ if (!record7(value2.verdict) || !Array.isArray(value2.verdict.reasons)) return false;
9943
+ if (!record7(value2.catalog) || !record7(value2.summary)) return false;
9951
9944
  return Array.isArray(value2.services) && Array.isArray(value2.nextActions);
9952
9945
  }
9953
- function apiMessage2(value2) {
9954
- if (!record8(value2)) return "request failed";
9955
- const error = record8(value2.error) ? value2.error : value2;
9946
+ function apiMessage(value2) {
9947
+ if (!record7(value2)) return "request failed";
9948
+ const error = record7(value2.error) ? value2.error : value2;
9956
9949
  return typeof error.message === "string" ? error.message : typeof error.code === "string" ? error.code : "request failed";
9957
9950
  }
9958
- function record8(value2) {
9951
+ function record7(value2) {
9959
9952
  return !!value2 && typeof value2 === "object" && !Array.isArray(value2);
9960
9953
  }
9961
9954
 
@@ -9996,7 +9989,7 @@ function statusVerdict(reads) {
9996
9989
  severity: "degraded"
9997
9990
  });
9998
9991
  }
9999
- const performance = record9(reads.liveSync.body.performance) ? reads.liveSync.body.performance : null;
9992
+ const performance = record8(reads.liveSync.body.performance) ? reads.liveSync.body.performance : null;
10000
9993
  if (performance?.status === "unavailable") {
10001
9994
  reasons.push({
10002
9995
  source: "liveSync",
@@ -10077,7 +10070,7 @@ function statusVerdict(reads) {
10077
10070
  reasons
10078
10071
  };
10079
10072
  }
10080
- function record9(value2) {
10073
+ function record8(value2) {
10081
10074
  return Boolean(value2) && typeof value2 === "object" && !Array.isArray(value2);
10082
10075
  }
10083
10076
  function numeric2(value2) {
@@ -10105,7 +10098,7 @@ function printO11yStatus(status, out) {
10105
10098
  out.log(
10106
10099
  `o11y status ${status.scope.appId}/${status.scope.env} (${status.scope.minutes}m)`
10107
10100
  );
10108
- const routes = Array.isArray(status.application.body.routes) ? status.application.body.routes.filter(record10) : [];
10101
+ const routes = Array.isArray(status.application.body.routes) ? status.application.body.routes.filter(record9) : [];
10109
10102
  const requests = routes.reduce(
10110
10103
  (total, row) => total + numeric3(row.requests),
10111
10104
  0
@@ -10117,39 +10110,39 @@ function printO11yStatus(status, out) {
10117
10110
  out.log(
10118
10111
  `application ${status.application.httpStatus} ${requests} requests ${errors} errors`
10119
10112
  );
10120
- const versions = Array.isArray(status.applicationVersions.body.rows) ? status.applicationVersions.body.rows.filter(record10) : [];
10113
+ const versions = Array.isArray(status.applicationVersions.body.rows) ? status.applicationVersions.body.rows.filter(record9) : [];
10121
10114
  out.log(
10122
10115
  `application-versions ${status.applicationVersions.httpStatus} ${versions.length ? versions.slice(0, 5).map(
10123
10116
  (row) => `${String(row.value || "(unattributed)")}:${numeric3(row.requests)}`
10124
10117
  ).join(", ") : "none observed"}`
10125
10118
  );
10126
10119
  out.log(liveSyncLine(status.liveSync));
10127
- const canaryDurations = record10(status.canary.body.durationsMs) ? status.canary.body.durationsMs : {};
10120
+ const canaryDurations = record9(status.canary.body.durationsMs) ? status.canary.body.durationsMs : {};
10128
10121
  out.log(
10129
10122
  `canary ${status.canary.httpStatus} ${String(status.canary.body.status ?? status.canary.body.error ?? "unavailable")} ${optionalNumeric(canaryDurations.publishToVisibleMs)} publish-to-visible`
10130
10123
  );
10131
- const collectorIngest = record10(status.collector.body.ingest) ? status.collector.body.ingest : {};
10132
- const collectorStorage = record10(collectorIngest.storage) ? collectorIngest.storage : {};
10124
+ const collectorIngest = record9(status.collector.body.ingest) ? status.collector.body.ingest : {};
10125
+ const collectorStorage = record9(collectorIngest.storage) ? collectorIngest.storage : {};
10133
10126
  out.log(
10134
10127
  `collector ${status.collector.httpStatus} ${String(status.collector.body.status ?? status.collector.body.error ?? "unavailable")} ${numeric3(collectorStorage.affectedPoints)} affected points`
10135
10128
  );
10136
- const providerMetrics = record10(status.provider.body.metrics) ? status.provider.body.metrics : {};
10137
- const providerCapacity = record10(status.provider.body.capacity) ? status.provider.body.capacity : {};
10138
- const workerMemory = record10(providerCapacity.memory) ? providerCapacity.memory : {};
10129
+ const providerMetrics = record9(status.provider.body.metrics) ? status.provider.body.metrics : {};
10130
+ const providerCapacity = record9(status.provider.body.capacity) ? status.provider.body.capacity : {};
10131
+ const workerMemory = record9(providerCapacity.memory) ? providerCapacity.memory : {};
10139
10132
  out.log(
10140
10133
  `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`
10141
10134
  );
10142
10135
  for (const line of providerCapacityLines(status.providerCapacity)) {
10143
10136
  out.log(line);
10144
10137
  }
10145
- const coverage = record10(status.providerReconciliation.body.comparison) ? status.providerReconciliation.body.comparison : {};
10146
- const coverageCounts = record10(status.providerReconciliation.body.counts) ? status.providerReconciliation.body.counts : {};
10147
- const coverageBudget = record10(status.providerReconciliation.body.budget) ? status.providerReconciliation.body.budget : {};
10138
+ const coverage = record9(status.providerReconciliation.body.comparison) ? status.providerReconciliation.body.comparison : {};
10139
+ const coverageCounts = record9(status.providerReconciliation.body.counts) ? status.providerReconciliation.body.counts : {};
10140
+ const coverageBudget = record9(status.providerReconciliation.body.budget) ? status.providerReconciliation.body.budget : {};
10148
10141
  out.log(
10149
10142
  `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`
10150
10143
  );
10151
10144
  const providerPoints = Array.isArray(status.providerHistory.body.points) ? status.providerHistory.body.points.length : 0;
10152
- const providerFreshness = record10(status.providerHistory.body.freshness) ? status.providerHistory.body.freshness : {};
10145
+ const providerFreshness = record9(status.providerHistory.body.freshness) ? status.providerHistory.body.freshness : {};
10153
10146
  out.log(
10154
10147
  `cloudflare-history ${status.providerHistory.httpStatus} ${String(status.providerHistory.body.status ?? status.providerHistory.body.error ?? "unavailable")} ${providerPoints} snapshots ${optionalAge(providerFreshness.ageMs)} old`
10155
10148
  );
@@ -10158,17 +10151,17 @@ function printO11yStatus(status, out) {
10158
10151
  );
10159
10152
  }
10160
10153
  function providerCapacityLines(read3) {
10161
- const resources = record10(read3.body.resources) ? read3.body.resources : {};
10162
- const durableObjects = record10(resources.durableObjects) ? resources.durableObjects : {};
10163
- const periodic = record10(durableObjects.periodic) ? durableObjects.periodic : {};
10164
- const storage = record10(durableObjects.sqliteStorage) ? durableObjects.sqliteStorage : {};
10165
- const d1 = record10(resources.d1) ? resources.d1 : {};
10166
- const d1Activity = record10(d1.activity) ? d1.activity : {};
10167
- const d1Storage = record10(d1.storage) ? d1.storage : {};
10168
- const d1Latency = record10(d1Activity.latency) ? d1Activity.latency : {};
10169
- const r2 = record10(resources.r2) ? resources.r2 : {};
10170
- const r2Operations = record10(r2.operations) ? r2.operations : {};
10171
- const r2Storage = record10(r2.storage) ? r2.storage : {};
10154
+ const resources = record9(read3.body.resources) ? read3.body.resources : {};
10155
+ const durableObjects = record9(resources.durableObjects) ? resources.durableObjects : {};
10156
+ const periodic = record9(durableObjects.periodic) ? durableObjects.periodic : {};
10157
+ const storage = record9(durableObjects.sqliteStorage) ? durableObjects.sqliteStorage : {};
10158
+ const d1 = record9(resources.d1) ? resources.d1 : {};
10159
+ const d1Activity = record9(d1.activity) ? d1.activity : {};
10160
+ const d1Storage = record9(d1.storage) ? d1.storage : {};
10161
+ const d1Latency = record9(d1Activity.latency) ? d1Activity.latency : {};
10162
+ const r2 = record9(resources.r2) ? resources.r2 : {};
10163
+ const r2Operations = record9(r2.operations) ? r2.operations : {};
10164
+ const r2Storage = record9(r2.storage) ? r2.storage : {};
10172
10165
  const status = String(
10173
10166
  read3.body.status ?? read3.body.error ?? "unavailable"
10174
10167
  );
@@ -10179,11 +10172,11 @@ function providerCapacityLines(read3) {
10179
10172
  ];
10180
10173
  }
10181
10174
  function liveSyncLine(read3) {
10182
- const performance = record10(read3.body.performance) ? read3.body.performance : {};
10183
- const commitToSend = record10(performance.commitToSend) ? performance.commitToSend : {};
10175
+ const performance = record9(read3.body.performance) ? read3.body.performance : {};
10176
+ const commitToSend = record9(performance.commitToSend) ? performance.commitToSend : {};
10184
10177
  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`;
10185
10178
  }
10186
- function record10(value2) {
10179
+ function record9(value2) {
10187
10180
  return Boolean(value2) && typeof value2 === "object" && !Array.isArray(value2);
10188
10181
  }
10189
10182
  function numeric3(value2) {
@@ -10368,7 +10361,7 @@ async function read2(url, headers, doFetch) {
10368
10361
  // src/provision.ts
10369
10362
  var import_apps12 = require("@odla-ai/apps");
10370
10363
  var import_ai3 = require("@odla-ai/ai");
10371
- var import_node_process11 = __toESM(require("process"), 1);
10364
+ var import_node_process10 = __toESM(require("process"), 1);
10372
10365
 
10373
10366
  // src/integration-provision.ts
10374
10367
  var import_db3 = require("@odla-ai/db");
@@ -10675,7 +10668,7 @@ ${env}: credentials are already saved; retry "odla-ai secrets push --env ${env}$
10675
10668
  await provisionIntegrationSeeds(doFetch, cfg.dbEndpoint, tenantId, dbKey, database.integrations, env, out);
10676
10669
  }
10677
10670
  if (cfg.services.includes("ai") && cfg.ai?.provider && cfg.ai.keyEnv) {
10678
- const key = import_node_process11.default.env[cfg.ai.keyEnv];
10671
+ const key = import_node_process10.default.env[cfg.ai.keyEnv];
10679
10672
  if (key) {
10680
10673
  const secretName = cfg.ai.secretName ?? defaultSecretName(cfg.ai.provider);
10681
10674
  await (0, import_ai3.putSecret)({ endpoint: cfg.dbEndpoint, token, fetch: doFetch }, tenantId, secretName, key);
@@ -10717,7 +10710,7 @@ ${env}: credentials are already saved; retry "odla-ai secrets push --env ${env}$
10717
10710
 
10718
10711
  // src/record.ts
10719
10712
  var import_node_fs16 = require("fs");
10720
- var import_node_process12 = __toESM(require("process"), 1);
10713
+ var import_node_process11 = __toESM(require("process"), 1);
10721
10714
 
10722
10715
  // src/surface.ts
10723
10716
  var PM_ACTIONS = {
@@ -10762,6 +10755,7 @@ var COMMAND_SURFACE = {
10762
10755
  promote: {},
10763
10756
  owners: { list: {}, add: {}, remove: {} }
10764
10757
  },
10758
+ brand: { design: { unpack: {} } },
10765
10759
  calendar: { status: {}, calendars: {}, connect: {}, disconnect: {} },
10766
10760
  capabilities: {},
10767
10761
  code: { connect: {} },
@@ -10785,8 +10779,7 @@ var COMMAND_SURFACE = {
10785
10779
  o11y: { status: {} },
10786
10780
  operations: { get: {}, wait: {} },
10787
10781
  platform: {
10788
- status: {},
10789
- "chat-credentials": { rotate: {} }
10782
+ status: {}
10790
10783
  },
10791
10784
  pm: {
10792
10785
  ...PM_ENTITIES,
@@ -10875,7 +10868,7 @@ function surfacePaths(node = COMMAND_SURFACE, prefix = []) {
10875
10868
 
10876
10869
  // src/record.ts
10877
10870
  function recordInvocation(parsed) {
10878
- const file = import_node_process12.default.env.ODLA_CLI_RECORD;
10871
+ const file = import_node_process11.default.env.ODLA_CLI_RECORD;
10879
10872
  if (!file) return;
10880
10873
  try {
10881
10874
  const entry = {
@@ -11068,7 +11061,7 @@ async function runbookRemove(ctx, slug) {
11068
11061
 
11069
11062
  // src/runbook-import.ts
11070
11063
  var import_node_fs18 = require("fs");
11071
- var import_node_path15 = require("path");
11064
+ var import_node_path16 = require("path");
11072
11065
  function parseRunbook(text2, slug) {
11073
11066
  let rest = text2;
11074
11067
  const meta = {};
@@ -11097,8 +11090,8 @@ function readRunbookDir(dir) {
11097
11090
  const files = (0, import_node_fs18.readdirSync)(dir).filter((f) => f.endsWith(".md")).sort();
11098
11091
  if (!files.length) throw new Error(`no .md files in ${dir}`);
11099
11092
  return files.map((file) => {
11100
- const slug = (0, import_node_path15.basename)(file, ".md");
11101
- const parsed = parseRunbook((0, import_node_fs18.readFileSync)((0, import_node_path15.join)(dir, file), "utf8"), slug);
11093
+ const slug = (0, import_node_path16.basename)(file, ".md");
11094
+ const parsed = parseRunbook((0, import_node_fs18.readFileSync)((0, import_node_path16.join)(dir, file), "utf8"), slug);
11102
11095
  return { file, slug, ...parsed, words: parsed.body.split(/\s+/).filter(Boolean).length };
11103
11096
  });
11104
11097
  }
@@ -11172,7 +11165,7 @@ async function upsert(ctx, r, visibility) {
11172
11165
  // src/runbook-impact.ts
11173
11166
  var import_node_child_process7 = require("child_process");
11174
11167
  var import_node_fs19 = require("fs");
11175
- var import_node_path16 = require("path");
11168
+ var import_node_path17 = require("path");
11176
11169
 
11177
11170
  // src/runbook-impact-scan.ts
11178
11171
  var DECL = /^[+-]\s*export\s+(?:declare\s+)?(?:default\s+)?(?:abstract\s+)?(?:async\s+)?(?:const|let|var|function|class|interface|type|enum)\s+([A-Za-z_$][\w$]*)/;
@@ -11341,7 +11334,7 @@ ${body.split("\n").map((line) => `+${line}`).join("\n")}
11341
11334
  }
11342
11335
  function manifestLabeller(root) {
11343
11336
  return (workspace) => {
11344
- const manifest = (0, import_node_path16.join)(root, workspace, "package.json");
11337
+ const manifest = (0, import_node_path17.join)(root, workspace, "package.json");
11345
11338
  if (!(0, import_node_fs19.existsSync)(manifest)) return void 0;
11346
11339
  try {
11347
11340
  const name = JSON.parse((0, import_node_fs19.readFileSync)(manifest, "utf8")).name;
@@ -11411,7 +11404,7 @@ function report3(ctx, impacts) {
11411
11404
  async function runbookImpact(ctx, options, deps = {}) {
11412
11405
  const cwd = deps.cwd ?? process.cwd();
11413
11406
  const runGit = deps.runGit ?? gitRunner(cwd);
11414
- const read3 = deps.readRepoFile ?? ((path) => (0, import_node_fs19.readFileSync)((0, import_node_path16.join)(cwd, path), "utf8"));
11407
+ const read3 = deps.readRepoFile ?? ((path) => (0, import_node_fs19.readFileSync)((0, import_node_path17.join)(cwd, path), "utf8"));
11415
11408
  const surfaces = changedSurfaces(collectDiff(runGit, options.base, read3), manifestLabeller(cwd));
11416
11409
  if (!surfaces.length) {
11417
11410
  return ctx.out.log(
@@ -11546,10 +11539,10 @@ async function runbookComment(ctx, slug, body) {
11546
11539
  var import_node_child_process8 = require("child_process");
11547
11540
  var import_node_fs20 = require("fs");
11548
11541
  var import_node_os5 = require("os");
11549
- var import_node_path17 = require("path");
11550
- var import_node_process13 = __toESM(require("process"), 1);
11542
+ var import_node_path18 = require("path");
11543
+ var import_node_process12 = __toESM(require("process"), 1);
11551
11544
  var EDITOR_ENV = ["ODLA_EDITOR", "VISUAL", "EDITOR"];
11552
- function resolveEditor(env = import_node_process13.default.env) {
11545
+ function resolveEditor(env = import_node_process12.default.env) {
11553
11546
  for (const name of EDITOR_ENV) {
11554
11547
  const value2 = env[name];
11555
11548
  if (value2 && value2.trim()) return value2.trim();
@@ -11563,8 +11556,8 @@ function defaultRun(command, path) {
11563
11556
  return result.status ?? 0;
11564
11557
  }
11565
11558
  function editText(initial, slug, deps = {}) {
11566
- const env = deps.env ?? import_node_process13.default.env;
11567
- const interactive = deps.interactive ?? (() => Boolean(import_node_process13.default.stdin.isTTY));
11559
+ const env = deps.env ?? import_node_process12.default.env;
11560
+ const interactive = deps.interactive ?? (() => Boolean(import_node_process12.default.stdin.isTTY));
11568
11561
  const editor = resolveEditor(env);
11569
11562
  if (!editor)
11570
11563
  throw new Error(
@@ -11572,8 +11565,8 @@ function editText(initial, slug, deps = {}) {
11572
11565
  );
11573
11566
  if (!interactive())
11574
11567
  throw new Error(`cannot open an editor without a terminal \u2014 pass --file <path> or --body "\u2026" instead`);
11575
- const dir = (0, import_node_fs20.mkdtempSync)((0, import_node_path17.join)((0, import_node_os5.tmpdir)(), "odla-runbook-"));
11576
- const file = (0, import_node_path17.join)(dir, `${slug}.md`);
11568
+ const dir = (0, import_node_fs20.mkdtempSync)((0, import_node_path18.join)((0, import_node_os5.tmpdir)(), "odla-runbook-"));
11569
+ const file = (0, import_node_path18.join)(dir, `${slug}.md`);
11577
11570
  try {
11578
11571
  (0, import_node_fs20.writeFileSync)(file, initial, { mode: 384 });
11579
11572
  const code = defaultRunOrInjected(deps)(editor, file);
@@ -11915,7 +11908,7 @@ async function runbookCommand(parsed, deps = {}) {
11915
11908
  }
11916
11909
 
11917
11910
  // src/security-command-context.ts
11918
- var import_promises11 = require("readline/promises");
11911
+ var import_promises12 = require("readline/promises");
11919
11912
  async function hostedSecurityContext(parsed, dependencies) {
11920
11913
  const configPath = stringOpt(parsed.options.config) ?? "odla.config.mjs";
11921
11914
  const cfg = await loadProjectConfig(configPath);
@@ -11941,7 +11934,7 @@ async function hostedSecurityContext(parsed, dependencies) {
11941
11934
  async function interactiveConfirmation(message2, dependencies) {
11942
11935
  if (dependencies.confirm) return dependencies.confirm(message2);
11943
11936
  if (!process.stdin.isTTY || !process.stdout.isTTY) return false;
11944
- const prompt = (0, import_promises11.createInterface)({ input: process.stdin, output: process.stdout });
11937
+ const prompt = (0, import_promises12.createInterface)({ input: process.stdin, output: process.stdout });
11945
11938
  try {
11946
11939
  const answer = await prompt.question(`${message2} [y/N] `);
11947
11940
  return /^y(?:es)?$/i.test(answer.trim());
@@ -12068,7 +12061,7 @@ function hostedSeverity(value2, flag) {
12068
12061
  var import_security2 = require("@odla-ai/security");
12069
12062
 
12070
12063
  // src/security.ts
12071
- var import_node_path18 = require("path");
12064
+ var import_node_path19 = require("path");
12072
12065
  var import_security = require("@odla-ai/security");
12073
12066
  var import_node3 = require("@odla-ai/security/node");
12074
12067
  async function runHostedSecurity(options) {
@@ -12080,9 +12073,9 @@ async function runHostedSecurity(options) {
12080
12073
  const appId = selfAudit ? "odla-ai" : cfg.app.id;
12081
12074
  const env = selfAudit ? "prod" : selectEnv(options.env, cfg.envs, cfg.configPath, cfg.rootDir);
12082
12075
  const platform = options.platform ?? cfg?.platformUrl ?? "https://odla.ai";
12083
- const target = (0, import_node_path18.resolve)(options.target ?? cfg?.rootDir ?? ".");
12084
- const output = (0, import_node_path18.resolve)(options.out ?? (0, import_node_path18.resolve)(target, ".odla/security/hosted"));
12085
- const outputRelative = (0, import_node_path18.relative)(target, output).split(import_node_path18.sep).join("/");
12076
+ const target = (0, import_node_path19.resolve)(options.target ?? cfg?.rootDir ?? ".");
12077
+ const output = (0, import_node_path19.resolve)(options.out ?? (0, import_node_path19.resolve)(target, ".odla/security/hosted"));
12078
+ const outputRelative = (0, import_node_path19.relative)(target, output).split(import_node_path19.sep).join("/");
12086
12079
  if (!outputRelative) throw new Error("Hosted security output cannot be the repository root");
12087
12080
  const profile = profileFor(options.profile ?? "odla", options.maxHuntTasks ?? 12);
12088
12081
  const tokenRequest = {
@@ -12094,7 +12087,7 @@ async function runHostedSecurity(options) {
12094
12087
  };
12095
12088
  const token = await injectedToken(options, tokenRequest);
12096
12089
  const snapshot = await (0, import_node3.snapshotDirectory)(target, {
12097
- exclude: !outputRelative.startsWith("../") && !(0, import_node_path18.isAbsolute)(outputRelative) ? [outputRelative] : []
12090
+ exclude: !outputRelative.startsWith("../") && !(0, import_node_path19.isAbsolute)(outputRelative) ? [outputRelative] : []
12098
12091
  });
12099
12092
  const hosted = await (0, import_security.createPlatformSecurityReasoners)({
12100
12093
  platform,
@@ -12112,7 +12105,7 @@ async function runHostedSecurity(options) {
12112
12105
  });
12113
12106
  const harness = (0, import_security.createSecurityHarness)({
12114
12107
  profile,
12115
- store: new import_node3.FileRunStore((0, import_node_path18.resolve)(output, "state")),
12108
+ store: new import_node3.FileRunStore((0, import_node_path19.resolve)(output, "state")),
12116
12109
  discoveryReasoner: hosted.discoveryReasoner,
12117
12110
  validationReasoner: hosted.validationReasoner,
12118
12111
  policy: {
@@ -12136,7 +12129,7 @@ async function runHostedSecurity(options) {
12136
12129
  function selectEnv(requested, declared, configPath, rootDir) {
12137
12130
  const env = requested ?? (declared.includes("dev") ? "dev" : declared[0]);
12138
12131
  if (!env || !declared.includes(env)) {
12139
- const shown = (0, import_node_path18.relative)(rootDir, configPath) || configPath;
12132
+ const shown = (0, import_node_path19.relative)(rootDir, configPath) || configPath;
12140
12133
  throw new Error(`env "${env ?? ""}" is not declared in ${shown}`);
12141
12134
  }
12142
12135
  return env;
@@ -12165,7 +12158,7 @@ function printSummary(out, appId, env, run, report4, output) {
12165
12158
  out.log(` coverage: ${report4.coverageStatus} ${complete}/${report4.coverage.length} blocked=${report4.metrics.blockedCells} shallow=${report4.metrics.shallowCells} unscheduled=${report4.metrics.unscheduledCells} budget_exhausted=${report4.metrics.budgetExhaustedCells}`);
12166
12159
  if (report4.callBudget) out.log(` calls: discovery=${formatBudget(report4.callBudget.discovery)} validation=${formatBudget(report4.callBudget.validation)}`);
12167
12160
  out.log(` findings: confirmed=${report4.metrics.confirmed} needs_reproduction=${report4.metrics.needsReproduction} candidates=${report4.metrics.candidates}`);
12168
- out.log(` report: ${(0, import_node_path18.resolve)(output, "REPORT.md")}`);
12161
+ out.log(` report: ${(0, import_node_path19.resolve)(output, "REPORT.md")}`);
12169
12162
  }
12170
12163
  function formatBudget(usage) {
12171
12164
  return usage ? `${usage.usedCalls}/${usage.maxCalls} skipped=${usage.skippedCalls}` : "caller-managed";
@@ -12677,6 +12670,10 @@ async function runCli(argv = process.argv.slice(2), dependencies = {}) {
12677
12670
  await securityCommand(parsed, runtime);
12678
12671
  return;
12679
12672
  }
12673
+ if (command === "brand") {
12674
+ await brandCommand(parsed, runtime);
12675
+ return;
12676
+ }
12680
12677
  if (command === "pm") {
12681
12678
  await pmCommand(parsed, runtime);
12682
12679
  return;