@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/bin.cjs CHANGED
@@ -246,7 +246,7 @@ var import_node_process2 = __toESM(require("process"), 1);
246
246
  async function openUrl(url, options = {}) {
247
247
  const command = openerFor(options.platform ?? import_node_process2.default.platform);
248
248
  const doSpawn = options.spawnImpl ?? import_node_child_process.spawn;
249
- await new Promise((resolve12, reject) => {
249
+ await new Promise((resolve13, reject) => {
250
250
  const child = doSpawn(command.cmd, [...command.args, url], {
251
251
  stdio: "ignore",
252
252
  detached: true
@@ -254,7 +254,7 @@ async function openUrl(url, options = {}) {
254
254
  child.once("error", reject);
255
255
  child.once("spawn", () => {
256
256
  child.unref();
257
- resolve12();
257
+ resolve13();
258
258
  });
259
259
  });
260
260
  }
@@ -492,7 +492,6 @@ function audienceBoundEnvToken(token, platform) {
492
492
  }
493
493
  var SCOPE_PURPOSE = {
494
494
  "platform:status:read": "read the platform fleet health and deployment snapshot",
495
- "platform:chat:credential:write": "rotate the built-in Discussion responder credential",
496
495
  "app:config:read": "compare checked-in intent with an exact-id app Registry configuration",
497
496
  "app:config:write": "apply or inspect one revision-bound configuration operation for an app you own",
498
497
  "platform:runbook:write": "add or edit odla's operational runbooks",
@@ -2176,6 +2175,153 @@ async function appCommand(parsed, dependencies = {}) {
2176
2175
  else await appRestore(options);
2177
2176
  }
2178
2177
 
2178
+ // src/brand-command.ts
2179
+ var import_promises2 = require("fs/promises");
2180
+ var import_node_path7 = require("path");
2181
+
2182
+ // src/brand-design-unpack.ts
2183
+ var import_node_zlib = require("zlib");
2184
+ var import_brand = require("@odla-ai/brand");
2185
+ var EXTENSIONS = {
2186
+ "image/png": "png",
2187
+ "image/jpeg": "jpg",
2188
+ "image/gif": "gif",
2189
+ "image/webp": "webp",
2190
+ "image/svg+xml": "svg",
2191
+ "image/avif": "avif",
2192
+ "font/woff2": "woff2",
2193
+ "font/woff": "woff",
2194
+ "font/ttf": "ttf",
2195
+ "font/otf": "otf",
2196
+ "text/javascript": "js",
2197
+ "application/javascript": "js",
2198
+ "text/css": "css",
2199
+ "text/html": "html",
2200
+ "application/json": "json"
2201
+ };
2202
+ var encode = (text2) => new TextEncoder().encode(text2);
2203
+ function assetFileName(uuid, mime) {
2204
+ const ext = EXTENSIONS[mime.split(";")[0].trim().toLowerCase()] ?? "bin";
2205
+ return `${uuid.replace(/[^a-zA-Z0-9._-]/g, "_")}.${ext}`;
2206
+ }
2207
+ function decodePayload(data, compressed) {
2208
+ const raw = Buffer.from(data, "base64");
2209
+ return new Uint8Array(compressed ? (0, import_node_zlib.gunzipSync)(raw) : raw);
2210
+ }
2211
+ function rewriteReferences(template, assetPaths, pagePaths) {
2212
+ let out = template;
2213
+ for (const [uuid, path] of pagePaths) {
2214
+ out = out.split(`about:blank#${uuid}`).join(path);
2215
+ }
2216
+ for (const [uuid, path] of assetPaths) {
2217
+ out = out.split(uuid).join(path);
2218
+ }
2219
+ return out;
2220
+ }
2221
+ function tokensCss(digest) {
2222
+ if (Object.keys(digest.tokens.light).length === 0) return null;
2223
+ return (0, import_brand.renderTokensCss)(digest.tokens.light, { dark: digest.tokens.dark });
2224
+ }
2225
+ function unpackDesign(html) {
2226
+ const bundle = (0, import_brand.parseDesignBundle)(html);
2227
+ const manifest = (0, import_brand.readDesignManifest)(html);
2228
+ const digest = (0, import_brand.digestDesignBundle)(bundle);
2229
+ const pageUuids = new Set(bundle.pageOrder);
2230
+ const files = [];
2231
+ const failed = [];
2232
+ const assetPaths = /* @__PURE__ */ new Map();
2233
+ const pagePaths = /* @__PURE__ */ new Map();
2234
+ for (const [uuid, entry] of Object.entries(manifest)) {
2235
+ let bytes;
2236
+ try {
2237
+ bytes = decodePayload(entry.data, entry.compressed);
2238
+ } catch {
2239
+ failed.push(uuid);
2240
+ continue;
2241
+ }
2242
+ if (pageUuids.has(uuid)) {
2243
+ const path2 = `pages/${assetFileName(uuid, "text/html")}`;
2244
+ pagePaths.set(uuid, `./${path2}`);
2245
+ files.push({ path: path2, bytes });
2246
+ continue;
2247
+ }
2248
+ const path = `assets/${assetFileName(uuid, entry.mime)}`;
2249
+ assetPaths.set(uuid, `./${path}`);
2250
+ files.push({ path, bytes });
2251
+ }
2252
+ files.push({
2253
+ path: "index.html",
2254
+ bytes: encode(rewriteReferences(bundle.template, assetPaths, pagePaths))
2255
+ });
2256
+ files.push({ path: "digest.json", bytes: encode(`${JSON.stringify(digest, null, 2)}
2257
+ `) });
2258
+ const css = tokensCss(digest);
2259
+ if (css !== null) files.push({ path: "tokens.css", bytes: encode(css) });
2260
+ if (bundle.thumbnailSvg) files.push({ path: "thumbnail.svg", bytes: encode(bundle.thumbnailSvg) });
2261
+ return { files, digest, failed };
2262
+ }
2263
+ function describeUnpack(result, outDir) {
2264
+ const { digest } = result;
2265
+ const lines = [
2266
+ `Unpacked ${digest.title ? `"${digest.title}"` : "design"} into ${outDir}`,
2267
+ ` index.html the design, offline-runnable (${digest.templateBytes} bytes)`,
2268
+ ` assets/ ${digest.assetCount} embedded files (${digest.assetBytes} bytes)`,
2269
+ ` digest.json ${Object.keys(digest.tokens.light).length} --ui-* tokens, ${digest.props.length} props, ${digest.outline.length} headings`
2270
+ ];
2271
+ if (result.files.some((f) => f.path === "tokens.css"))
2272
+ lines.push(" tokens.css the design's tokens as an @odla-ai/ui theme sheet");
2273
+ if (digest.fonts.length > 0) lines.push(`Typefaces: ${digest.fonts.join(", ")}`);
2274
+ if (result.failed.length > 0)
2275
+ lines.push(`WARNING: ${result.failed.length} embedded asset(s) could not be decoded.`);
2276
+ return lines;
2277
+ }
2278
+
2279
+ // src/brand-command.ts
2280
+ var USAGE = "usage: odla-ai brand design unpack <bundle.html|-> [--out <dir>] [--json]";
2281
+ async function readBundle(source, deps) {
2282
+ if (source !== "-") return (0, import_promises2.readFile)((0, import_node_path7.resolve)(source), "utf8");
2283
+ const readStdin = deps.readStdin;
2284
+ if (!readStdin) throw new Error("reading a bundle from stdin is not supported here");
2285
+ return readStdin();
2286
+ }
2287
+ async function writeAll(result, outDir) {
2288
+ for (const file of result.files) {
2289
+ const target = (0, import_node_path7.resolve)(outDir, file.path);
2290
+ await (0, import_promises2.mkdir)((0, import_node_path7.dirname)(target), { recursive: true });
2291
+ await (0, import_promises2.writeFile)(target, file.bytes);
2292
+ }
2293
+ }
2294
+ async function designUnpack(parsed, deps) {
2295
+ assertArgs(parsed, ["out", "json"], 4);
2296
+ const source = parsed.positionals[3];
2297
+ if (!source) throw new Error(USAGE);
2298
+ const outDir = (0, import_node_path7.resolve)(stringOpt(parsed.options.out) ?? "design");
2299
+ const result = unpackDesign(await readBundle(source, deps));
2300
+ await writeAll(result, outDir);
2301
+ const out = deps.stdout ?? console;
2302
+ if (parsed.options.json === true) {
2303
+ out.log(
2304
+ JSON.stringify({
2305
+ outDir,
2306
+ files: result.files.map((f) => f.path),
2307
+ failed: result.failed,
2308
+ digest: result.digest
2309
+ })
2310
+ );
2311
+ return;
2312
+ }
2313
+ for (const line of describeUnpack(result, outDir)) out.log(line);
2314
+ }
2315
+ async function brandCommand(parsed, deps) {
2316
+ const subject = parsed.positionals[1];
2317
+ const action2 = parsed.positionals[2];
2318
+ if (subject === "design" && action2 === "unpack") {
2319
+ await designUnpack(parsed, deps);
2320
+ return;
2321
+ }
2322
+ throw new Error(USAGE);
2323
+ }
2324
+
2179
2325
  // src/calendar-errors.ts
2180
2326
  var PLATFORM_NOT_READY_CODES = /* @__PURE__ */ new Set([
2181
2327
  "calendar_google_oauth_not_configured",
@@ -2449,8 +2595,8 @@ function credential(value2) {
2449
2595
  // src/calendar-poll.ts
2450
2596
  async function waitForCalendarPoll(milliseconds, signal) {
2451
2597
  if (signal?.aborted) throw signal.reason ?? new Error("calendar connection aborted");
2452
- await new Promise((resolve12, reject) => {
2453
- const timer = setTimeout(resolve12, milliseconds);
2598
+ await new Promise((resolve13, reject) => {
2599
+ const timer = setTimeout(resolve13, milliseconds);
2454
2600
  signal?.addEventListener("abort", () => {
2455
2601
  clearTimeout(timer);
2456
2602
  reject(signal.reason ?? new Error("calendar connection aborted"));
@@ -2704,7 +2850,7 @@ function printGroup(out, heading, items) {
2704
2850
 
2705
2851
  // src/config-operation-command.ts
2706
2852
  var import_apps6 = require("@odla-ai/apps");
2707
- var import_node_path7 = require("path");
2853
+ var import_node_path8 = require("path");
2708
2854
 
2709
2855
  // src/version.ts
2710
2856
  var import_node_fs9 = require("fs");
@@ -2743,9 +2889,9 @@ function canonicalValue(value2) {
2743
2889
  }
2744
2890
  if (Array.isArray(value2)) return value2.map(canonicalValue);
2745
2891
  if (value2 && typeof value2 === "object") {
2746
- const record11 = value2;
2892
+ const record10 = value2;
2747
2893
  return Object.fromEntries(
2748
- Object.keys(record11).filter((key) => record11[key] !== void 0).sort().map((key) => [key, canonicalValue(record11[key])])
2894
+ Object.keys(record10).filter((key) => record10[key] !== void 0).sort().map((key) => [key, canonicalValue(record10[key])])
2749
2895
  );
2750
2896
  }
2751
2897
  throw new TypeError("canonical JSON rejects unsupported values");
@@ -3083,7 +3229,7 @@ async function configOperationWait(options) {
3083
3229
  assertOperationId(options.operationId);
3084
3230
  const cfg = await loadProjectConfig(options.configPath);
3085
3231
  const client = await operationClient(cfg, options, "wait");
3086
- const wait2 = options.pollWait ?? ((ms) => new Promise((resolve12) => setTimeout(resolve12, ms)));
3232
+ const wait2 = options.pollWait ?? ((ms) => new Promise((resolve13) => setTimeout(resolve13, ms)));
3087
3233
  const now = () => (options.now?.() ?? /* @__PURE__ */ new Date()).getTime();
3088
3234
  const deadline = now() + (options.timeoutSeconds ?? DEFAULT_WAIT_SECONDS) * 1e3;
3089
3235
  const interval = (options.intervalSeconds ?? DEFAULT_INTERVAL_SECONDS) * 1e3;
@@ -3114,7 +3260,7 @@ async function operationClient(cfg, options, purpose) {
3114
3260
  platform: cfg.platformUrl,
3115
3261
  scope: "app:config:write",
3116
3262
  token: options.token,
3117
- tokenFile: (0, import_node_path7.join)(cfg.rootDir, ".odla", "admin-token.local.json"),
3263
+ tokenFile: (0, import_node_path8.join)(cfg.rootDir, ".odla", "admin-token.local.json"),
3118
3264
  rootDir: cfg.rootDir,
3119
3265
  email: options.email,
3120
3266
  open: options.open,
@@ -3169,7 +3315,7 @@ function record3(value2) {
3169
3315
 
3170
3316
  // src/config-reconcile-command.ts
3171
3317
  var import_apps8 = require("@odla-ai/apps");
3172
- var import_node_path8 = require("path");
3318
+ var import_node_path9 = require("path");
3173
3319
 
3174
3320
  // src/config-reconcile.ts
3175
3321
  var import_apps7 = require("@odla-ai/apps");
@@ -3465,7 +3611,7 @@ async function inspectConfig(options) {
3465
3611
  platform: cfg.platformUrl,
3466
3612
  scope: "app:config:read",
3467
3613
  token: options.token,
3468
- tokenFile: (0, import_node_path8.join)(cfg.rootDir, ".odla", "admin-token.local.json"),
3614
+ tokenFile: (0, import_node_path9.join)(cfg.rootDir, ".odla", "admin-token.local.json"),
3469
3615
  rootDir: cfg.rootDir,
3470
3616
  email: options.email,
3471
3617
  open: options.open,
@@ -3598,12 +3744,12 @@ function quoteArg2(value2) {
3598
3744
  // src/doctor-checks.ts
3599
3745
  var import_node_child_process3 = require("child_process");
3600
3746
  var import_node_fs12 = require("fs");
3601
- var import_node_path10 = require("path");
3747
+ var import_node_path11 = require("path");
3602
3748
 
3603
3749
  // src/wrangler.ts
3604
3750
  var import_node_child_process2 = require("child_process");
3605
3751
  var import_node_fs11 = require("fs");
3606
- var import_node_path9 = require("path");
3752
+ var import_node_path10 = require("path");
3607
3753
  var defaultRunner = (cmd, args, opts) => new Promise((resolvePromise, reject) => {
3608
3754
  const child = (0, import_node_child_process2.spawn)(cmd, args, { cwd: opts?.cwd, stdio: ["pipe", "pipe", "pipe"] });
3609
3755
  let stdout = "";
@@ -3617,7 +3763,7 @@ var defaultRunner = (cmd, args, opts) => new Promise((resolvePromise, reject) =>
3617
3763
  var WRANGLER_CONFIG_FILES = ["wrangler.jsonc", "wrangler.json", "wrangler.toml"];
3618
3764
  function findWranglerConfig(rootDir) {
3619
3765
  for (const name of WRANGLER_CONFIG_FILES) {
3620
- const path = (0, import_node_path9.join)(rootDir, name);
3766
+ const path = (0, import_node_path10.join)(rootDir, name);
3621
3767
  if ((0, import_node_fs11.existsSync)(path)) return path;
3622
3768
  }
3623
3769
  return null;
@@ -3730,10 +3876,10 @@ function wranglerWarnings(rootDir) {
3730
3876
  for (const { label, block } of blocks) {
3731
3877
  const assets = block.assets;
3732
3878
  if (assets?.directory) {
3733
- const dir = (0, import_node_path10.resolve)(rootDir, assets.directory);
3734
- if (dir === (0, import_node_path10.resolve)(rootDir)) {
3879
+ const dir = (0, import_node_path11.resolve)(rootDir, assets.directory);
3880
+ if (dir === (0, import_node_path11.resolve)(rootDir)) {
3735
3881
  warnings.push(`${label}assets.directory is the project root \u2014 point it at a dedicated build dir (wrangler dev fails with "spawn EBADF")`);
3736
- } else if ((0, import_node_fs12.existsSync)((0, import_node_path10.join)(dir, "node_modules"))) {
3882
+ } else if ((0, import_node_fs12.existsSync)((0, import_node_path11.join)(dir, "node_modules"))) {
3737
3883
  warnings.push(`${label}assets.directory contains node_modules \u2014 wrangler dev's watcher will exhaust file descriptors`);
3738
3884
  }
3739
3885
  }
@@ -3768,7 +3914,7 @@ function o11yProjectWarnings(rootDir) {
3768
3914
  warnings.push("cannot verify o11y Worker instrumentation \u2014 add a parseable wrangler.jsonc/json config");
3769
3915
  return warnings;
3770
3916
  }
3771
- const main = typeof config.main === "string" ? (0, import_node_path10.resolve)(rootDir, config.main) : null;
3917
+ const main = typeof config.main === "string" ? (0, import_node_path11.resolve)(rootDir, config.main) : null;
3772
3918
  if (!main || !(0, import_node_fs12.existsSync)(main)) {
3773
3919
  warnings.push("cannot verify o11y Worker instrumentation \u2014 wrangler main is missing or unreadable");
3774
3920
  } else {
@@ -3798,7 +3944,7 @@ function calendarProjectWarnings(rootDir) {
3798
3944
  }
3799
3945
  function readPackageJson(rootDir) {
3800
3946
  try {
3801
- return JSON.parse((0, import_node_fs12.readFileSync)((0, import_node_path10.join)(rootDir, "package.json"), "utf8"));
3947
+ return JSON.parse((0, import_node_fs12.readFileSync)((0, import_node_path11.join)(rootDir, "package.json"), "utf8"));
3802
3948
  } catch {
3803
3949
  return null;
3804
3950
  }
@@ -4026,12 +4172,12 @@ function harnessOption(value2, flag) {
4026
4172
 
4027
4173
  // src/init.ts
4028
4174
  var import_node_fs13 = require("fs");
4029
- var import_node_path11 = require("path");
4175
+ var import_node_path12 = require("path");
4030
4176
  var import_apps9 = require("@odla-ai/apps");
4031
4177
  function initProject(options) {
4032
4178
  const out = options.stdout ?? console;
4033
- const rootDir = (0, import_node_path11.resolve)(options.rootDir ?? process.cwd());
4034
- const configPath = (0, import_node_path11.resolve)(rootDir, options.configPath ?? "odla.config.mjs");
4179
+ const rootDir = (0, import_node_path12.resolve)(options.rootDir ?? process.cwd());
4180
+ const configPath = (0, import_node_path12.resolve)(rootDir, options.configPath ?? "odla.config.mjs");
4035
4181
  if ((0, import_node_fs13.existsSync)(configPath) && !options.force) {
4036
4182
  throw new Error(`${configPath} already exists. Pass --force to overwrite.`);
4037
4183
  }
@@ -4048,12 +4194,12 @@ function initProject(options) {
4048
4194
  }
4049
4195
  }
4050
4196
  const aiProvider = options.aiProvider ?? "anthropic";
4051
- (0, import_node_fs13.mkdirSync)((0, import_node_path11.dirname)(configPath), { recursive: true });
4052
- (0, import_node_fs13.mkdirSync)((0, import_node_path11.resolve)(rootDir, "src/odla"), { recursive: true });
4053
- (0, import_node_fs13.mkdirSync)((0, import_node_path11.resolve)(rootDir, ".odla"), { recursive: true });
4197
+ (0, import_node_fs13.mkdirSync)((0, import_node_path12.dirname)(configPath), { recursive: true });
4198
+ (0, import_node_fs13.mkdirSync)((0, import_node_path12.resolve)(rootDir, "src/odla"), { recursive: true });
4199
+ (0, import_node_fs13.mkdirSync)((0, import_node_path12.resolve)(rootDir, ".odla"), { recursive: true });
4054
4200
  (0, import_node_fs13.writeFileSync)(configPath, configTemplate({ appId: options.appId, name: options.name, envs, services, aiProvider }));
4055
- writeIfMissing((0, import_node_path11.resolve)(rootDir, "src/odla/schema.mjs"), schemaTemplate());
4056
- writeIfMissing((0, import_node_path11.resolve)(rootDir, "src/odla/rules.mjs"), rulesTemplate());
4201
+ writeIfMissing((0, import_node_path12.resolve)(rootDir, "src/odla/schema.mjs"), schemaTemplate());
4202
+ writeIfMissing((0, import_node_path12.resolve)(rootDir, "src/odla/rules.mjs"), rulesTemplate());
4057
4203
  ensureGitignore(rootDir);
4058
4204
  out.log(`created ${relativeDisplay(configPath, rootDir)}`);
4059
4205
  out.log("created src/odla/schema.mjs and src/odla/rules.mjs");
@@ -4294,7 +4440,7 @@ async function resolveVaultWrite(options) {
4294
4440
  // src/skill.ts
4295
4441
  var import_node_fs14 = require("fs");
4296
4442
  var import_node_os2 = require("os");
4297
- var import_node_path12 = require("path");
4443
+ var import_node_path13 = require("path");
4298
4444
  var import_node_url2 = require("url");
4299
4445
 
4300
4446
  // src/skill-adapters.ts
@@ -4373,8 +4519,8 @@ function installSkill(options = {}) {
4373
4519
  const files = listFiles(sourceDir);
4374
4520
  if (files.length === 0) throw new Error(`no bundled skills found at ${sourceDir}`);
4375
4521
  const harnesses = normalizeHarnesses(options.harnesses, options.global === true);
4376
- const root = (0, import_node_path12.resolve)(options.dir ?? process.cwd());
4377
- const home = (0, import_node_path12.resolve)(options.homeDir ?? (0, import_node_os2.homedir)());
4522
+ const root = (0, import_node_path13.resolve)(options.dir ?? process.cwd());
4523
+ const home = (0, import_node_path13.resolve)(options.homeDir ?? (0, import_node_os2.homedir)());
4378
4524
  const plans = /* @__PURE__ */ new Map();
4379
4525
  const targets = /* @__PURE__ */ new Map();
4380
4526
  const rememberTarget = (harness, target) => {
@@ -4388,48 +4534,48 @@ function installSkill(options = {}) {
4388
4534
  plans.set(target, { target, content: content2, boundary, managedMerge });
4389
4535
  };
4390
4536
  const planSkillTree = (targetDir2, boundary = root) => {
4391
- 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);
4537
+ 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);
4392
4538
  };
4393
4539
  let targetDir;
4394
4540
  if (options.global) {
4395
- const claudeRoot = (0, import_node_path12.join)(home, ".claude", "skills");
4396
- const codexRoot = (0, import_node_path12.resolve)(options.codexHomeDir ?? process.env.CODEX_HOME ?? (0, import_node_path12.join)(home, ".codex"), "skills");
4541
+ const claudeRoot = (0, import_node_path13.join)(home, ".claude", "skills");
4542
+ const codexRoot = (0, import_node_path13.resolve)(options.codexHomeDir ?? process.env.CODEX_HOME ?? (0, import_node_path13.join)(home, ".codex"), "skills");
4397
4543
  targetDir = harnesses[0] === "codex" ? codexRoot : claudeRoot;
4398
4544
  for (const harness of harnesses) {
4399
4545
  const skillRoot = harness === "claude" ? claudeRoot : codexRoot;
4400
- planSkillTree(skillRoot, harness === "claude" ? home : (0, import_node_path12.dirname)((0, import_node_path12.dirname)(codexRoot)));
4546
+ planSkillTree(skillRoot, harness === "claude" ? home : (0, import_node_path13.dirname)((0, import_node_path13.dirname)(codexRoot)));
4401
4547
  rememberTarget(harness, skillRoot);
4402
4548
  }
4403
4549
  } else {
4404
- const sharedRoot = (0, import_node_path12.join)(root, ".agents", "skills");
4550
+ const sharedRoot = (0, import_node_path13.join)(root, ".agents", "skills");
4405
4551
  planSkillTree(sharedRoot);
4406
- const claudeRoot = (0, import_node_path12.join)(root, ".claude", "skills");
4552
+ const claudeRoot = (0, import_node_path13.join)(root, ".claude", "skills");
4407
4553
  targetDir = harnesses.includes("claude") ? claudeRoot : sharedRoot;
4408
4554
  for (const harness of harnesses) rememberTarget(harness, sharedRoot);
4409
4555
  if (harnesses.includes("claude")) {
4410
4556
  for (const skill of skillNames(files)) {
4411
- const canonical = (0, import_node_fs14.readFileSync)((0, import_node_path12.join)(sourceDir, skill, "SKILL.md"), "utf8");
4412
- plan((0, import_node_path12.join)(claudeRoot, skill, "SKILL.md"), claudeAdapter(skill, canonical));
4557
+ const canonical = (0, import_node_fs14.readFileSync)((0, import_node_path13.join)(sourceDir, skill, "SKILL.md"), "utf8");
4558
+ plan((0, import_node_path13.join)(claudeRoot, skill, "SKILL.md"), claudeAdapter(skill, canonical));
4413
4559
  }
4414
4560
  rememberTarget("claude", claudeRoot);
4415
4561
  }
4416
4562
  if (harnesses.includes("cursor")) {
4417
- const cursorRule = (0, import_node_path12.join)(root, ".cursor", "rules", "odla.mdc");
4563
+ const cursorRule = (0, import_node_path13.join)(root, ".cursor", "rules", "odla.mdc");
4418
4564
  plan(cursorRule, CURSOR_RULE);
4419
4565
  rememberTarget("cursor", cursorRule);
4420
4566
  }
4421
4567
  if (harnesses.includes("agents")) {
4422
- const agentsFile = (0, import_node_path12.join)(root, "AGENTS.md");
4568
+ const agentsFile = (0, import_node_path13.join)(root, "AGENTS.md");
4423
4569
  plan(agentsFile, managedFileContent(agentsFile, PROJECT_INSTRUCTIONS, options.force === true, root), true);
4424
4570
  rememberTarget("agents", agentsFile);
4425
4571
  }
4426
4572
  if (harnesses.includes("copilot")) {
4427
- const copilotFile = (0, import_node_path12.join)(root, ".github", "copilot-instructions.md");
4573
+ const copilotFile = (0, import_node_path13.join)(root, ".github", "copilot-instructions.md");
4428
4574
  plan(copilotFile, managedFileContent(copilotFile, PROJECT_INSTRUCTIONS, options.force === true, root), true);
4429
4575
  rememberTarget("copilot", copilotFile);
4430
4576
  }
4431
4577
  if (harnesses.includes("gemini")) {
4432
- const geminiFile = (0, import_node_path12.join)(root, "GEMINI.md");
4578
+ const geminiFile = (0, import_node_path13.join)(root, "GEMINI.md");
4433
4579
  plan(geminiFile, managedFileContent(geminiFile, PROJECT_INSTRUCTIONS, options.force === true, root), true);
4434
4580
  rememberTarget("gemini", geminiFile);
4435
4581
  }
@@ -4465,7 +4611,7 @@ ${conflicts.map((f) => ` - ${f}`).join("\n")}`
4465
4611
  }
4466
4612
  for (const file of plans.values()) {
4467
4613
  if (!(0, import_node_fs14.existsSync)(file.target) || (0, import_node_fs14.readFileSync)(file.target, "utf8") !== file.content) {
4468
- (0, import_node_fs14.mkdirSync)((0, import_node_path12.dirname)(file.target), { recursive: true });
4614
+ (0, import_node_fs14.mkdirSync)((0, import_node_path13.dirname)(file.target), { recursive: true });
4469
4615
  (0, import_node_fs14.writeFileSync)(file.target, file.content);
4470
4616
  }
4471
4617
  }
@@ -4485,7 +4631,7 @@ ${conflicts.map((f) => ` - ${f}`).join("\n")}`
4485
4631
  };
4486
4632
  }
4487
4633
  function pathsUnder(root, paths) {
4488
- 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();
4634
+ 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();
4489
4635
  }
4490
4636
  function normalizeHarnesses(values, global) {
4491
4637
  const requested = values?.length ? values : ["claude"];
@@ -4530,13 +4676,13 @@ function managedFileContent(path, block, force, boundary) {
4530
4676
  return `${current.slice(0, startAt)}${block}${current.slice(afterEnd)}`;
4531
4677
  }
4532
4678
  function symlinkedComponent(boundary, target) {
4533
- const rel = (0, import_node_path12.relative)(boundary, target);
4534
- if (rel === ".." || rel.startsWith(`..${import_node_path12.sep}`) || (0, import_node_path12.isAbsolute)(rel)) {
4679
+ const rel = (0, import_node_path13.relative)(boundary, target);
4680
+ if (rel === ".." || rel.startsWith(`..${import_node_path13.sep}`) || (0, import_node_path13.isAbsolute)(rel)) {
4535
4681
  throw new Error(`agent setup target escapes its install root: ${target}`);
4536
4682
  }
4537
4683
  let current = boundary;
4538
- for (const part of rel.split(import_node_path12.sep).filter(Boolean)) {
4539
- current = (0, import_node_path12.join)(current, part);
4684
+ for (const part of rel.split(import_node_path13.sep).filter(Boolean)) {
4685
+ current = (0, import_node_path13.join)(current, part);
4540
4686
  try {
4541
4687
  if ((0, import_node_fs14.lstatSync)(current).isSymbolicLink()) return current;
4542
4688
  } catch (error) {
@@ -4553,9 +4699,9 @@ function listFiles(dir) {
4553
4699
  const results = [];
4554
4700
  const walk = (current) => {
4555
4701
  for (const entry of (0, import_node_fs14.readdirSync)(current, { withFileTypes: true })) {
4556
- const path = (0, import_node_path12.join)(current, entry.name);
4702
+ const path = (0, import_node_path13.join)(current, entry.name);
4557
4703
  if (entry.isDirectory()) walk(path);
4558
- else results.push((0, import_node_path12.relative)(dir, path));
4704
+ else results.push((0, import_node_path13.relative)(dir, path));
4559
4705
  }
4560
4706
  };
4561
4707
  walk(dir);
@@ -4867,7 +5013,7 @@ async function projectCommand(command, parsed, deps) {
4867
5013
  // src/code-connect.ts
4868
5014
  var import_node_fs15 = require("fs");
4869
5015
  var import_node_os4 = require("os");
4870
- var import_node_path14 = require("path");
5016
+ var import_node_path15 = require("path");
4871
5017
 
4872
5018
  // ../harness/dist/chunk-QTUEF2HZ.js
4873
5019
  var HARNESS_PROTOCOL_VERSION = 1;
@@ -4953,15 +5099,15 @@ function encodeAgentInput(message2) {
4953
5099
  // ../harness/dist/chunk-PHXQH4YM.js
4954
5100
  var import_child_process = require("child_process");
4955
5101
  var import_fs = require("fs");
4956
- var import_promises2 = require("fs/promises");
5102
+ var import_promises3 = require("fs/promises");
4957
5103
  var import_path = require("path");
4958
5104
  var import_process = require("process");
4959
- var import_promises3 = require("fs/promises");
5105
+ var import_promises4 = require("fs/promises");
4960
5106
  var import_os = require("os");
4961
5107
  var import_path2 = require("path");
4962
5108
  var import_child_process2 = require("child_process");
4963
5109
  var import_path3 = require("path");
4964
- var import_promises4 = require("fs/promises");
5110
+ var import_promises5 = require("fs/promises");
4965
5111
  var import_os2 = require("os");
4966
5112
  var import_path4 = require("path");
4967
5113
  var import_child_process3 = require("child_process");
@@ -4972,7 +5118,7 @@ function assertPinnedImage(image) {
4972
5118
  async function commandAvailable(engine) {
4973
5119
  for (const directory of (process.env.PATH ?? "").split(import_path.delimiter).filter(Boolean)) {
4974
5120
  try {
4975
- await (0, import_promises2.access)((0, import_path.join)(directory, engine), import_fs.constants.X_OK);
5121
+ await (0, import_promises3.access)((0, import_path.join)(directory, engine), import_fs.constants.X_OK);
4976
5122
  return true;
4977
5123
  } catch {
4978
5124
  }
@@ -5258,18 +5404,18 @@ async function gitBlobs(cwd, entries, maxBytes) {
5258
5404
  }
5259
5405
  async function materializeGitTree(source, commitSha, options = {}) {
5260
5406
  if (!/^[0-9a-f]{40}$/.test(commitSha)) throw new TypeError("Git tree requires an exact commit SHA");
5261
- const sourceDir = await (0, import_promises3.realpath)((0, import_path2.resolve)(source));
5407
+ const sourceDir = await (0, import_promises4.realpath)((0, import_path2.resolve)(source));
5262
5408
  const maxFiles = options.maxFiles ?? 2e4;
5263
5409
  const maxBytes = options.maxBytes ?? 512 * 1024 * 1024;
5264
5410
  const inventory = (await gitOutput(sourceDir, ["ls-tree", "-rz", commitSha], 16 * 1024 * 1024)).toString("utf8").split("\0").filter(Boolean);
5265
- const entries = inventory.flatMap((record11) => {
5266
- const match = /^(100644|100755) blob ([0-9a-f]{40,64})\t([\s\S]+)$/.exec(record11);
5411
+ const entries = inventory.flatMap((record10) => {
5412
+ const match = /^(100644|100755) blob ([0-9a-f]{40,64})\t([\s\S]+)$/.exec(record10);
5267
5413
  return match && allowedWorkspacePath(match[3]) ? [{ mode: match[1], hash: match[2], path: match[3] }] : [];
5268
5414
  });
5269
5415
  if (entries.length > maxFiles) throw new Error(`workspace exceeds ${maxFiles} files`);
5270
- const root = await (0, import_promises3.mkdtemp)((0, import_path2.join)(options.tempRoot ?? (0, import_os.tmpdir)(), "odla-git-tree-"));
5416
+ const root = await (0, import_promises4.mkdtemp)((0, import_path2.join)(options.tempRoot ?? (0, import_os.tmpdir)(), "odla-git-tree-"));
5271
5417
  const targetRoot = (0, import_path2.join)(root, "source");
5272
- await (0, import_promises3.mkdir)(targetRoot);
5418
+ await (0, import_promises4.mkdir)(targetRoot);
5273
5419
  let byteCount = 0;
5274
5420
  try {
5275
5421
  const blobs = await gitBlobs(sourceDir, entries, maxBytes);
@@ -5279,18 +5425,18 @@ async function materializeGitTree(source, commitSha, options = {}) {
5279
5425
  if (byteCount > maxBytes) throw new Error(`workspace exceeds ${maxBytes} bytes`);
5280
5426
  const target = (0, import_path2.resolve)(targetRoot, entry.path);
5281
5427
  if (!target.startsWith(`${(0, import_path2.resolve)(targetRoot)}${import_path2.sep}`)) throw new TypeError("Git tree path escapes workspace");
5282
- await (0, import_promises3.mkdir)((0, import_path2.resolve)(target, ".."), { recursive: true });
5283
- await (0, import_promises3.writeFile)(target, content2, { flag: "wx", mode: entry.mode === "100755" ? 493 : 420 });
5428
+ await (0, import_promises4.mkdir)((0, import_path2.resolve)(target, ".."), { recursive: true });
5429
+ await (0, import_promises4.writeFile)(target, content2, { flag: "wx", mode: entry.mode === "100755" ? 493 : 420 });
5284
5430
  }
5285
5431
  return {
5286
5432
  root,
5287
5433
  sourceDir: targetRoot,
5288
5434
  fileCount: entries.length,
5289
5435
  byteCount,
5290
- cleanup: () => (0, import_promises3.rm)(root, { recursive: true, force: true })
5436
+ cleanup: () => (0, import_promises4.rm)(root, { recursive: true, force: true })
5291
5437
  };
5292
5438
  } catch (error) {
5293
- await (0, import_promises3.rm)(root, { recursive: true, force: true });
5439
+ await (0, import_promises4.rm)(root, { recursive: true, force: true });
5294
5440
  throw error;
5295
5441
  }
5296
5442
  }
@@ -5298,7 +5444,7 @@ async function sourceFiles(sourceDir, maxFiles, maxBytes) {
5298
5444
  const files = [];
5299
5445
  let bytes = 0;
5300
5446
  const walk = async (dir) => {
5301
- for (const entry of await (0, import_promises4.readdir)(dir, { withFileTypes: true })) {
5447
+ for (const entry of await (0, import_promises5.readdir)(dir, { withFileTypes: true })) {
5302
5448
  if (entry.isDirectory() && SKIP_WORKSPACE_DIRS.has(entry.name)) continue;
5303
5449
  if (!entry.isDirectory() && SECRET_WORKSPACE_FILE.test(entry.name)) continue;
5304
5450
  const path = (0, import_path4.join)(dir, entry.name);
@@ -5308,7 +5454,7 @@ async function sourceFiles(sourceDir, maxFiles, maxBytes) {
5308
5454
  continue;
5309
5455
  }
5310
5456
  if (!entry.isFile()) continue;
5311
- const metadata2 = await (0, import_promises4.stat)(path);
5457
+ const metadata2 = await (0, import_promises5.stat)(path);
5312
5458
  bytes += metadata2.size;
5313
5459
  if (files.length + 1 > maxFiles) throw new Error(`workspace exceeds ${maxFiles} files`);
5314
5460
  if (bytes > maxBytes) throw new Error(`workspace exceeds ${maxBytes} bytes`);
@@ -5357,7 +5503,7 @@ async function gitSourceFiles(sourceDir, maxFiles, maxBytes) {
5357
5503
  if (!source.startsWith(`${root}${import_path4.sep}`)) throw new TypeError("git file path escapes workspace");
5358
5504
  let metadata2;
5359
5505
  try {
5360
- metadata2 = await (0, import_promises4.lstat)(source);
5506
+ metadata2 = await (0, import_promises5.lstat)(source);
5361
5507
  } catch (error) {
5362
5508
  if (error.code === "ENOENT") continue;
5363
5509
  throw error;
@@ -5372,9 +5518,9 @@ async function gitSourceFiles(sourceDir, maxFiles, maxBytes) {
5372
5518
  async function copyTree(files, destination) {
5373
5519
  for (const file of files) {
5374
5520
  const target = (0, import_path4.join)(destination, file.relativePath);
5375
- await (0, import_promises4.mkdir)((0, import_path4.resolve)(target, ".."), { recursive: true });
5376
- await (0, import_promises4.copyFile)(file.source, target);
5377
- await (0, import_promises4.chmod)(target, file.mode);
5521
+ await (0, import_promises5.mkdir)((0, import_path4.resolve)(target, ".."), { recursive: true });
5522
+ await (0, import_promises5.copyFile)(file.source, target);
5523
+ await (0, import_promises5.chmod)(target, file.mode);
5378
5524
  }
5379
5525
  }
5380
5526
  async function captureGitDiff(root, maxBytes) {
@@ -5411,13 +5557,13 @@ async function captureGitDiff(root, maxBytes) {
5411
5557
  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");
5412
5558
  }
5413
5559
  async function stageWorkspace(source, options = {}) {
5414
- const sourceDir = await (0, import_promises4.realpath)((0, import_path4.resolve)(source));
5415
- const sourceStat = await (0, import_promises4.stat)(sourceDir);
5560
+ const sourceDir = await (0, import_promises5.realpath)((0, import_path4.resolve)(source));
5561
+ const sourceStat = await (0, import_promises5.stat)(sourceDir);
5416
5562
  if (!sourceStat.isDirectory()) throw new TypeError("workspace source must be a directory");
5417
- const root = await (0, import_promises4.mkdtemp)((0, import_path4.join)(options.tempRoot ?? (0, import_os2.tmpdir)(), "odla-harness-"));
5563
+ const root = await (0, import_promises5.mkdtemp)((0, import_path4.join)(options.tempRoot ?? (0, import_os2.tmpdir)(), "odla-harness-"));
5418
5564
  const baselineDir = (0, import_path4.join)(root, "baseline");
5419
5565
  const workspaceDir = (0, import_path4.join)(root, "workspace");
5420
- await Promise.all([(0, import_promises4.mkdir)(baselineDir), (0, import_promises4.mkdir)(workspaceDir)]);
5566
+ await Promise.all([(0, import_promises5.mkdir)(baselineDir), (0, import_promises5.mkdir)(workspaceDir)]);
5421
5567
  try {
5422
5568
  const maxFiles = options.maxFiles ?? 2e4;
5423
5569
  const maxBytes = options.maxBytes ?? 512 * 1024 * 1024;
@@ -5430,26 +5576,26 @@ async function stageWorkspace(source, options = {}) {
5430
5576
  fileCount: files.length,
5431
5577
  byteCount: files.reduce((sum, file) => sum + file.bytes, 0),
5432
5578
  patch: (maxBytes2) => captureGitDiff(root, maxBytes2),
5433
- cleanup: () => (0, import_promises4.rm)(root, { recursive: true, force: true })
5579
+ cleanup: () => (0, import_promises5.rm)(root, { recursive: true, force: true })
5434
5580
  };
5435
5581
  } catch (error) {
5436
- await (0, import_promises4.rm)(root, { recursive: true, force: true });
5582
+ await (0, import_promises5.rm)(root, { recursive: true, force: true });
5437
5583
  throw error;
5438
5584
  }
5439
5585
  }
5440
5586
  async function stageWorkspacePair(baselineSource, workspaceSource, options = {}) {
5441
- const baselineDirSource = await (0, import_promises4.realpath)((0, import_path4.resolve)(baselineSource));
5442
- const workspaceDirSource = await (0, import_promises4.realpath)((0, import_path4.resolve)(workspaceSource));
5587
+ const baselineDirSource = await (0, import_promises5.realpath)((0, import_path4.resolve)(baselineSource));
5588
+ const workspaceDirSource = await (0, import_promises5.realpath)((0, import_path4.resolve)(workspaceSource));
5443
5589
  const maxFiles = options.maxFiles ?? 2e4;
5444
5590
  const maxBytes = options.maxBytes ?? 512 * 1024 * 1024;
5445
5591
  const [baselineFiles, workspaceFiles] = await Promise.all([
5446
5592
  sourceFiles(baselineDirSource, maxFiles, maxBytes),
5447
5593
  sourceFiles(workspaceDirSource, maxFiles, maxBytes)
5448
5594
  ]);
5449
- const root = await (0, import_promises4.mkdtemp)((0, import_path4.join)(options.tempRoot ?? (0, import_os2.tmpdir)(), "odla-harness-"));
5595
+ const root = await (0, import_promises5.mkdtemp)((0, import_path4.join)(options.tempRoot ?? (0, import_os2.tmpdir)(), "odla-harness-"));
5450
5596
  const baselineDir = (0, import_path4.join)(root, "baseline");
5451
5597
  const workspaceDir = (0, import_path4.join)(root, "workspace");
5452
- await Promise.all([(0, import_promises4.mkdir)(baselineDir), (0, import_promises4.mkdir)(workspaceDir)]);
5598
+ await Promise.all([(0, import_promises5.mkdir)(baselineDir), (0, import_promises5.mkdir)(workspaceDir)]);
5453
5599
  try {
5454
5600
  await Promise.all([copyTree(baselineFiles, baselineDir), copyTree(workspaceFiles, workspaceDir)]);
5455
5601
  return {
@@ -5459,17 +5605,17 @@ async function stageWorkspacePair(baselineSource, workspaceSource, options = {})
5459
5605
  fileCount: workspaceFiles.length,
5460
5606
  byteCount: workspaceFiles.reduce((sum, file) => sum + file.bytes, 0),
5461
5607
  patch: (maxPatchBytes) => captureGitDiff(root, maxPatchBytes),
5462
- cleanup: () => (0, import_promises4.rm)(root, { recursive: true, force: true })
5608
+ cleanup: () => (0, import_promises5.rm)(root, { recursive: true, force: true })
5463
5609
  };
5464
5610
  } catch (error) {
5465
- await (0, import_promises4.rm)(root, { recursive: true, force: true });
5611
+ await (0, import_promises5.rm)(root, { recursive: true, force: true });
5466
5612
  throw error;
5467
5613
  }
5468
5614
  }
5469
5615
 
5470
5616
  // ../harness/dist/chunk-GMVZ4LZH.js
5471
5617
  var import_crypto = require("crypto");
5472
- var import_promises5 = require("fs/promises");
5618
+ var import_promises6 = require("fs/promises");
5473
5619
  var import_path5 = require("path");
5474
5620
 
5475
5621
  // ../camel/dist/chunk-7FHPOQVP.js
@@ -5511,8 +5657,8 @@ function normalize(value2) {
5511
5657
  if (Array.isArray(value2)) return value2.map(normalize);
5512
5658
  if (value2 instanceof Uint8Array) return { $bytes: [...value2] };
5513
5659
  if (typeof value2 === "object") {
5514
- const record11 = value2;
5515
- return Object.fromEntries(Object.keys(record11).filter((key) => record11[key] !== void 0).sort().map((key) => [key, normalize(record11[key])]));
5660
+ const record10 = value2;
5661
+ return Object.fromEntries(Object.keys(record10).filter((key) => record10[key] !== void 0).sort().map((key) => [key, normalize(record10[key])]));
5516
5662
  }
5517
5663
  throw new CamelError("state_conflict", "Canonical JSON rejects unsupported values.");
5518
5664
  }
@@ -5806,19 +5952,19 @@ function validateSnapshot(snapshot, limits) {
5806
5952
 
5807
5953
  // ../harness/dist/chunk-GMVZ4LZH.js
5808
5954
  var import_child_process4 = require("child_process");
5809
- var import_promises6 = require("fs/promises");
5955
+ var import_promises7 = require("fs/promises");
5810
5956
  var import_path6 = require("path");
5811
5957
  var import_child_process5 = require("child_process");
5812
5958
  var import_process2 = require("process");
5813
5959
  var import_crypto2 = require("crypto");
5814
5960
  var import_crypto3 = require("crypto");
5815
5961
  var import_fs2 = require("fs");
5816
- var import_promises7 = require("fs/promises");
5817
- var import_path7 = require("path");
5818
5962
  var import_promises8 = require("fs/promises");
5963
+ var import_path7 = require("path");
5964
+ var import_promises9 = require("fs/promises");
5819
5965
  var import_os3 = require("os");
5820
5966
  var import_path8 = require("path");
5821
- var import_promises9 = require("fs/promises");
5967
+ var import_promises10 = require("fs/promises");
5822
5968
  var import_path9 = require("path");
5823
5969
 
5824
5970
  // ../camel/dist/chunk-LAXU2AVK.js
@@ -6102,7 +6248,7 @@ var import_crypto4 = require("crypto");
6102
6248
  async function digestStagedWorkspace(root, limits) {
6103
6249
  const files = [];
6104
6250
  const walk = async (directory) => {
6105
- const entries = await (0, import_promises5.readdir)(directory, { withFileTypes: true });
6251
+ const entries = await (0, import_promises6.readdir)(directory, { withFileTypes: true });
6106
6252
  for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
6107
6253
  if (entry.isSymbolicLink()) throw new TypeError("workspace digest refuses symbolic links");
6108
6254
  const target = (0, import_path5.resolve)(directory, entry.name);
@@ -6117,7 +6263,7 @@ async function digestStagedWorkspace(root, limits) {
6117
6263
  const hash = (0, import_crypto.createHash)("sha256");
6118
6264
  let bytes = 0;
6119
6265
  for (const file of files.sort((left, right) => left.path.localeCompare(right.path))) {
6120
- const content2 = await (0, import_promises5.readFile)(file.target);
6266
+ const content2 = await (0, import_promises6.readFile)(file.target);
6121
6267
  bytes += Buffer.byteLength(file.path) + content2.byteLength;
6122
6268
  if (bytes > limits.maxBytes) throw new TypeError("workspace digest exceeds its byte bound");
6123
6269
  hash.update(`${Buffer.byteLength(file.path)}:${file.path}:${content2.byteLength}:`);
@@ -6443,7 +6589,7 @@ async function applyCodePatch(workspaceDir, patch2, paths) {
6443
6589
  await gitApply(workspaceDir, patch2, false);
6444
6590
  for (const path of paths) {
6445
6591
  try {
6446
- const info = await (0, import_promises6.lstat)(resolveCodePath(workspaceDir, path));
6592
+ const info = await (0, import_promises7.lstat)(resolveCodePath(workspaceDir, path));
6447
6593
  if (info.isSymbolicLink() || !info.isFile() && !info.isDirectory()) {
6448
6594
  throw new TypeError("patch created a non-regular workspace entry");
6449
6595
  }
@@ -6734,7 +6880,7 @@ async function inspectArtifacts(workspaceDir, recipe2) {
6734
6880
  for (const artifact of recipe2.expectedArtifacts ?? []) {
6735
6881
  try {
6736
6882
  const path = (0, import_path7.join)(workspaceDir, artifact.path);
6737
- const info = await (0, import_promises7.lstat)(path);
6883
+ const info = await (0, import_promises8.lstat)(path);
6738
6884
  if (!info.isFile() || info.isSymbolicLink()) {
6739
6885
  receipts.push({ artifactId: artifact.id, status: "invalid", bytes: null, digest: null });
6740
6886
  } else if (info.size > artifact.maximumBytes) {
@@ -6915,9 +7061,9 @@ var RESERVED2 = /* @__PURE__ */ new Set([".git", ".odla", ".wrangler", "node_mod
6915
7061
  var SECRET2 = /^(?:\.env(?:\..+)?|\.dev\.vars|credentials(?:\..+)?\.json|dev-token(?:\..+)?\.json)$/i;
6916
7062
  async function materializeCodeRuntimeSource(snapshot, tempRoot = (0, import_os3.tmpdir)()) {
6917
7063
  if (!snapshot.files.length || snapshot.files.length > 1e4) throw new TypeError("Code source file count is invalid");
6918
- const root = await (0, import_promises8.mkdtemp)((0, import_path8.join)(tempRoot, "odla-code-source-"));
7064
+ const root = await (0, import_promises9.mkdtemp)((0, import_path8.join)(tempRoot, "odla-code-source-"));
6919
7065
  const sourceDir = (0, import_path8.join)(root, "source");
6920
- await (0, import_promises8.mkdir)(sourceDir);
7066
+ await (0, import_promises9.mkdir)(sourceDir);
6921
7067
  const seen = /* @__PURE__ */ new Set();
6922
7068
  let bytes = 0;
6923
7069
  try {
@@ -6929,8 +7075,8 @@ async function materializeCodeRuntimeSource(snapshot, tempRoot = (0, import_os3.
6929
7075
  if (bytes > 16 * 1024 * 1024) throw new TypeError("Code source exceeds its byte bound");
6930
7076
  const target = (0, import_path8.resolve)(sourceDir, file.path);
6931
7077
  if (!target.startsWith(`${(0, import_path8.resolve)(sourceDir)}${import_path8.sep}`)) throw new TypeError("Code source path escapes its root");
6932
- await (0, import_promises8.mkdir)((0, import_path8.dirname)(target), { recursive: true });
6933
- await (0, import_promises8.writeFile)(target, file.content, { flag: "wx", mode: 420 });
7078
+ await (0, import_promises9.mkdir)((0, import_path8.dirname)(target), { recursive: true });
7079
+ await (0, import_promises9.writeFile)(target, file.content, { flag: "wx", mode: 420 });
6934
7080
  }
6935
7081
  for (const reference of snapshot.references ?? []) {
6936
7082
  validateAlias(reference.alias);
@@ -6944,13 +7090,13 @@ async function materializeCodeRuntimeSource(snapshot, tempRoot = (0, import_os3.
6944
7090
  if (bytes > 80 * 1024 * 1024) throw new TypeError("Code source set exceeds its byte bound");
6945
7091
  const target = (0, import_path8.resolve)(sourceDir, path);
6946
7092
  if (!target.startsWith(`${(0, import_path8.resolve)(sourceDir)}${import_path8.sep}`)) throw new TypeError("Code reference path escapes its root");
6947
- await (0, import_promises8.mkdir)((0, import_path8.dirname)(target), { recursive: true });
6948
- await (0, import_promises8.writeFile)(target, file.content, { flag: "wx", mode: 292 });
7093
+ await (0, import_promises9.mkdir)((0, import_path8.dirname)(target), { recursive: true });
7094
+ await (0, import_promises9.writeFile)(target, file.content, { flag: "wx", mode: 292 });
6949
7095
  }
6950
7096
  }
6951
- return { sourceDir, cleanup: () => (0, import_promises8.rm)(root, { recursive: true, force: true }) };
7097
+ return { sourceDir, cleanup: () => (0, import_promises9.rm)(root, { recursive: true, force: true }) };
6952
7098
  } catch (cause) {
6953
- await (0, import_promises8.rm)(root, { recursive: true, force: true });
7099
+ await (0, import_promises9.rm)(root, { recursive: true, force: true });
6954
7100
  throw cause;
6955
7101
  }
6956
7102
  }
@@ -6971,8 +7117,8 @@ async function attachCodeRuntimeReferences(workspace, references) {
6971
7117
  for (const root of [workspace.baselineDir, workspace.workspaceDir]) {
6972
7118
  const target = (0, import_path8.resolve)(root, path);
6973
7119
  if (!target.startsWith(`${(0, import_path8.resolve)(root)}${import_path8.sep}`)) throw new TypeError("Code reference path escapes its root");
6974
- await (0, import_promises8.mkdir)((0, import_path8.dirname)(target), { recursive: true });
6975
- await (0, import_promises8.writeFile)(target, file.content, { flag: "wx", mode: 292 });
7120
+ await (0, import_promises9.mkdir)((0, import_path8.dirname)(target), { recursive: true });
7121
+ await (0, import_promises9.writeFile)(target, file.content, { flag: "wx", mode: 292 });
6976
7122
  }
6977
7123
  }
6978
7124
  }
@@ -7158,11 +7304,11 @@ async function read(context, request2, options, policy) {
7158
7304
  const allowed = await policy.read(policyContext(context, request2, options, { paths, path, startLine, endLine }));
7159
7305
  if (!allowed) return response(request2, false, "tool denied by CaMeL policy");
7160
7306
  const target = resolveCodePath(context.workspaceDir, path);
7161
- const info = await (0, import_promises9.stat)(target);
7307
+ const info = await (0, import_promises10.stat)(target);
7162
7308
  if (!info.isFile() || info.size > Math.max(options.maxReadBytes ?? 128 * 1024, 2 * 1024 * 1024)) {
7163
7309
  throw new TypeError("file is not a bounded regular source file");
7164
7310
  }
7165
- const source = await (0, import_promises9.readFile)(target);
7311
+ const source = await (0, import_promises10.readFile)(target);
7166
7312
  if (source.includes(0)) throw new TypeError("binary files are not readable through this tool");
7167
7313
  const lines = source.toString("utf8").split("\n");
7168
7314
  const content2 = lines.slice(startLine - 1, endLine).join("\n");
@@ -7239,7 +7385,7 @@ function policyContext(context, request2, options, extra) {
7239
7385
  async function registeredFiles(root, limit) {
7240
7386
  const paths = [];
7241
7387
  const walk = async (directory) => {
7242
- for (const entry of await (0, import_promises9.readdir)(directory, { withFileTypes: true })) {
7388
+ for (const entry of await (0, import_promises10.readdir)(directory, { withFileTypes: true })) {
7243
7389
  if (entry.isSymbolicLink()) throw new TypeError("workspace contains a symbolic link");
7244
7390
  const target = (0, import_path9.resolve)(directory, entry.name);
7245
7391
  if (entry.isDirectory()) await walk(target);
@@ -7838,8 +7984,8 @@ function hostedPollTimeout(value2 = 10 * 6e4) {
7838
7984
  }
7839
7985
  async function waitForHostedPoll(milliseconds, signal) {
7840
7986
  if (signal?.aborted) throw signal.reason ?? new DOMException("aborted", "AbortError");
7841
- await new Promise((resolve12, reject) => {
7842
- const timer = setTimeout(resolve12, milliseconds);
7987
+ await new Promise((resolve13, reject) => {
7988
+ const timer = setTimeout(resolve13, milliseconds);
7843
7989
  signal?.addEventListener("abort", () => {
7844
7990
  clearTimeout(timer);
7845
7991
  reject(signal.reason ?? new DOMException("aborted", "AbortError"));
@@ -8024,9 +8170,9 @@ function digestText(value2) {
8024
8170
  // src/code-images.ts
8025
8171
  var import_node_child_process6 = require("child_process");
8026
8172
  var import_node_crypto3 = require("crypto");
8027
- var import_promises10 = require("fs/promises");
8173
+ var import_promises11 = require("fs/promises");
8028
8174
  var import_node_os3 = require("os");
8029
- var import_node_path13 = require("path");
8175
+ var import_node_path14 = require("path");
8030
8176
  var import_node_url3 = require("url");
8031
8177
 
8032
8178
  // src/code-runtime-config.ts
@@ -8106,16 +8252,16 @@ function embeddedPiAssetPath() {
8106
8252
  return (0, import_node_url3.fileURLToPath)(new URL("./runtime/pi-agent.js", importMetaUrl));
8107
8253
  }
8108
8254
  async function embeddedPiImageName() {
8109
- const bundle = await (0, import_promises10.readFile)(embeddedPiAssetPath()).catch(() => {
8255
+ const bundle = await (0, import_promises11.readFile)(embeddedPiAssetPath()).catch(() => {
8110
8256
  throw new Error("CLI-embedded Pi runtime is missing; reinstall this exact @odla-ai/cli version");
8111
8257
  });
8112
8258
  return `odla-ai/pi-agent:embedded-sha256-${(0, import_node_crypto3.createHash)("sha256").update(bundle).digest("hex")}`;
8113
8259
  }
8114
8260
  async function buildEmbeddedPiImage(engine, image, run) {
8115
- const context = await (0, import_promises10.mkdtemp)((0, import_node_path13.join)((0, import_node_os3.tmpdir)(), "odla-code-pi-"));
8261
+ const context = await (0, import_promises11.mkdtemp)((0, import_node_path14.join)((0, import_node_os3.tmpdir)(), "odla-code-pi-"));
8116
8262
  try {
8117
- await (0, import_promises10.copyFile)(embeddedPiAssetPath(), (0, import_node_path13.join)(context, "pi-agent.js"));
8118
- await (0, import_promises10.writeFile)((0, import_node_path13.join)(context, "Dockerfile"), [
8263
+ await (0, import_promises11.copyFile)(embeddedPiAssetPath(), (0, import_node_path14.join)(context, "pi-agent.js"));
8264
+ await (0, import_promises11.writeFile)((0, import_node_path14.join)(context, "Dockerfile"), [
8119
8265
  `FROM ${CODE_NODE_IMAGE}`,
8120
8266
  "COPY pi-agent.js /opt/odla/pi-agent.js",
8121
8267
  "WORKDIR /workspace",
@@ -8124,14 +8270,14 @@ async function buildEmbeddedPiImage(engine, image, run) {
8124
8270
  ].join("\n"), { mode: 384 });
8125
8271
  await run(engine, ["build", "--tag", image, context], "inherit");
8126
8272
  } finally {
8127
- await (0, import_promises10.rm)(context, { recursive: true, force: true });
8273
+ await (0, import_promises11.rm)(context, { recursive: true, force: true });
8128
8274
  }
8129
8275
  }
8130
8276
 
8131
8277
  // src/code-connect.ts
8132
8278
  async function codeConnect(options) {
8133
8279
  const cwd = options.cwd ?? process.cwd();
8134
- const configPath = (0, import_node_path14.resolve)(cwd, options.configPath);
8280
+ const configPath = (0, import_node_path15.resolve)(cwd, options.configPath);
8135
8281
  const cfg = (0, import_node_fs15.existsSync)(configPath) ? await loadProjectConfig(configPath) : null;
8136
8282
  const requestedAppId = options.appId?.trim();
8137
8283
  if (requestedAppId && !/^[a-z0-9][a-z0-9-]{1,62}$/.test(requestedAppId)) {
@@ -8500,10 +8646,8 @@ function requireName(parsed) {
8500
8646
  return name;
8501
8647
  }
8502
8648
 
8503
- // src/help.ts
8504
- function printHelp(output = console) {
8505
- output.log(`odla-ai
8506
-
8649
+ // src/help-usage.ts
8650
+ var USAGE_SECTION = `
8507
8651
  Start here:
8508
8652
  odla-ai runbook ask "<question>" The current procedure, from odla's own
8509
8653
  runbooks. Ask BEFORE searching the web or
@@ -8537,6 +8681,7 @@ Usage:
8537
8681
  odla-ai app owners list [--config odla.config.mjs] [--email <odla-account>] [--json]
8538
8682
  odla-ai app owners add <email> [--email <odla-account>] [--json]
8539
8683
  odla-ai app owners remove <email> [--email <odla-account>] [--json]
8684
+ odla-ai brand design unpack <bundle.html|-> [--out <dir>] [--json]
8540
8685
  odla-ai pm goal list [--app <id>] [--status <s>] [--q <text>] [--limit <n>] [--offset <n>] [--json]
8541
8686
  odla-ai pm task list [--app <id>] [--column <c>] [--goal <id>] [--assignee <id>] [--q <text>] [--limit <n>] [--offset <n>] [--json]
8542
8687
  odla-ai pm decision list [--app <id>] [--status <s>] [--q <text>] [--limit <n>] [--offset <n>] [--json]
@@ -8572,7 +8717,6 @@ Usage:
8572
8717
  odla-ai context remove <name> --yes [--json]
8573
8718
  odla-ai o11y status [--app <id>] [--context <name>] [--platform https://odla.ai] [--env prod] [--minutes 60] [--json]
8574
8719
  odla-ai platform status [--context <name>] [--platform https://odla.ai] [--email <odla-account>] [--json]
8575
- odla-ai platform chat-credentials rotate [--context <name>] [--email <odla-account>] [--wrangler-config <path>] [--expected-version <id>] [--json] --yes
8576
8720
  odla-ai whoami [--context <name>] [--platform https://odla.ai] [--json]
8577
8721
  odla-ai runbook ask "<question>" [--app <id>] [--all] [--json]
8578
8722
  odla-ai runbook search "<question>" [--app <id>] [--all] [--limit <n>] [--json]
@@ -8617,8 +8761,12 @@ Usage:
8617
8761
  odla-ai secrets push --env <env> [--config odla.config.mjs] [--dry-run] [--yes]
8618
8762
  odla-ai secrets set <name> --env <env> (--from-env <NAME>|--stdin) [--email <odla-account>] [--config odla.config.mjs] [--yes]
8619
8763
  odla-ai secrets set-clerk-key --env <env> (--from-env <NAME>|--stdin) [--email <odla-account>] [--config odla.config.mjs] [--yes]
8620
- odla-ai version
8764
+ odla-ai version`;
8621
8765
 
8766
+ // src/help.ts
8767
+ function printHelp(output = console) {
8768
+ output.log(`odla-ai
8769
+ ${USAGE_SECTION}
8622
8770
  Commands:
8623
8771
  agent Inspect durable agent wakeups and explicitly requeue a
8624
8772
  dead-lettered job; JSON output is stable for remote operators.
@@ -9067,7 +9215,7 @@ function jsonl(ctx, parsed, value2) {
9067
9215
  }
9068
9216
  async function discussWatch(ctx, topicId, parsed) {
9069
9217
  if (ctx.json && parsed.options.jsonl === true) throw new Error("--json and --jsonl cannot be combined");
9070
- const sleep = ctx.sleep ?? ((ms) => new Promise((resolve12) => setTimeout(resolve12, ms)));
9218
+ const sleep = ctx.sleep ?? ((ms) => new Promise((resolve13) => setTimeout(resolve13, ms)));
9071
9219
  const now = ctx.now ?? Date.now;
9072
9220
  const intervalMs = (numberOpt2(parsed, "interval", DEFAULT_INTERVAL_MS / 1e3) ?? DEFAULT_INTERVAL_MS / 1e3) * 1e3;
9073
9221
  const timeoutSeconds = numberOpt2(parsed, "timeout");
@@ -9405,8 +9553,8 @@ async function pmAdd(ctx, entity, parsed) {
9405
9553
  emit2(ctx, res, () => ctx.out.log(`created ${entity} ${res.id}`));
9406
9554
  }
9407
9555
  async function pmGet(ctx, entity, id) {
9408
- const { record: record11 } = await pmRequest(ctx, "GET", `/${entity}/${encodeURIComponent(id)}`);
9409
- emit2(ctx, record11, () => printRecord(ctx, entity, record11));
9556
+ const { record: record10 } = await pmRequest(ctx, "GET", `/${entity}/${encodeURIComponent(id)}`);
9557
+ emit2(ctx, record10, () => printRecord(ctx, entity, record10));
9410
9558
  }
9411
9559
  async function pmSet(ctx, entity, id, parsed) {
9412
9560
  const patch2 = collectEntityFields(entity, parsed, true);
@@ -9451,9 +9599,9 @@ async function pmHandoff(ctx, parsed) {
9451
9599
  ]);
9452
9600
  const handoff = {
9453
9601
  appId,
9454
- unmetGoals: goals.filter((record11) => record11.status !== "met"),
9455
- activeTasks: tasks.filter((record11) => record11.column !== "done"),
9456
- openBugs: bugs.filter((record11) => record11.status !== "fixed" && record11.status !== "wontfix")
9602
+ unmetGoals: goals.filter((record10) => record10.status !== "met"),
9603
+ activeTasks: tasks.filter((record10) => record10.column !== "done"),
9604
+ openBugs: bugs.filter((record10) => record10.status !== "fixed" && record10.status !== "wontfix")
9457
9605
  };
9458
9606
  const result = {
9459
9607
  ...handoff,
@@ -9472,10 +9620,10 @@ async function pmHandoff(ctx, parsed) {
9472
9620
  ]) {
9473
9621
  ctx.out.log(`${label}:`);
9474
9622
  if (!records.length) ctx.out.log("- (none)");
9475
- else for (const record11 of records) printRecord(
9623
+ else for (const record10 of records) printRecord(
9476
9624
  ctx,
9477
9625
  label === "unmet goals" ? "goal" : label === "active tasks" ? "task" : "bug",
9478
- record11
9626
+ record10
9479
9627
  );
9480
9628
  }
9481
9629
  });
@@ -9666,167 +9814,12 @@ function age(input) {
9666
9814
  return `${Math.round(input / 6e4)}m`;
9667
9815
  }
9668
9816
 
9669
- // src/platform-chat-credential-command.ts
9670
- var import_node_process10 = __toESM(require("process"), 1);
9671
- async function rotatePlatformChatCredential(parsed, deps) {
9672
- assertArgs(
9673
- parsed,
9674
- [
9675
- "config",
9676
- "context",
9677
- "platform",
9678
- "token",
9679
- "email",
9680
- "open",
9681
- "json",
9682
- "yes",
9683
- "wrangler-config",
9684
- "expected-version"
9685
- ],
9686
- 3
9687
- );
9688
- if (parsed.options.yes !== true) {
9689
- throw new Error(
9690
- "platform chat-credentials rotate changes the production chat secret; pass --yes"
9691
- );
9692
- }
9693
- const context = await resolveOperatorContext(parsed, {
9694
- allowMissingConfig: true
9695
- });
9696
- const platform = context.platform.value;
9697
- const doFetch = deps.fetch ?? fetch;
9698
- const out = deps.stdout ?? console;
9699
- const run = deps.runner ?? defaultRunner;
9700
- const cwd = import_node_process10.default.cwd();
9701
- const wranglerConfig = stringOpt(parsed.options["wrangler-config"]) ?? "packages/chat-agent/wrangler.jsonc";
9702
- if (!await wranglerLoggedIn(run, cwd)) {
9703
- throw new Error(
9704
- 'Wrangler is not authenticated; run "npx wrangler login" and retry'
9705
- );
9706
- }
9707
- const priorHealth = await doFetch(`${platform}/health/services/chat`);
9708
- const priorVersion = priorHealth.headers.get("x-odla-worker-version-id");
9709
- await priorHealth.body?.cancel().catch(() => {
9710
- });
9711
- if (!priorVersion) {
9712
- throw new Error(
9713
- "chat health did not identify its current Worker version; refusing to rotate"
9714
- );
9715
- }
9716
- const expectedVersion = stringOpt(parsed.options["expected-version"]);
9717
- if (expectedVersion && priorVersion !== expectedVersion) {
9718
- throw new Error(
9719
- `chat health answered from version ${priorVersion}; expected ${expectedVersion}`
9720
- );
9721
- }
9722
- const token = await resolveAdminPlatformToken({
9723
- platform,
9724
- scope: "platform:chat:credential:write",
9725
- token: stringOpt(parsed.options.token),
9726
- tokenFile: context.credentials.scopedTokenFile,
9727
- email: stringOpt(parsed.options.email),
9728
- open: parsed.options.open === false ? false : parsed.options.open === true ? true : void 0,
9729
- fetch: doFetch,
9730
- stdout: out,
9731
- openApprovalUrl: deps.openUrl,
9732
- label: "odla CLI (rotate built-in Discussion responder)"
9733
- });
9734
- const mintedResponse = await doFetch(
9735
- `${platform}/registry/platform/chat-credentials/rotate`,
9736
- {
9737
- method: "POST",
9738
- headers: { authorization: `Bearer ${token}` }
9739
- }
9740
- );
9741
- const minted = await mintedResponse.json().catch(() => null);
9742
- if (!mintedResponse.ok) {
9743
- throw new Error(
9744
- `mint Discussion credential failed (HTTP ${mintedResponse.status}): ${apiMessage(minted)}`
9745
- );
9746
- }
9747
- if (!isPlatformChatCredential(minted)) {
9748
- throw new Error(
9749
- "platform returned an invalid odla.platform-chat-credential/v1 envelope"
9750
- );
9751
- }
9752
- const put = await wranglerPutSecret(run, {
9753
- name: "ODLA_BOT_TOKENS",
9754
- value: JSON.stringify({
9755
- [minted.appId]: { [minted.principalId]: minted.key }
9756
- }),
9757
- configPath: wranglerConfig,
9758
- cwd
9759
- });
9760
- if (put.code !== 0) {
9761
- throw new Error(
9762
- "Wrangler could not replace ODLA_BOT_TOKENS; the new scoped key was not activated"
9763
- );
9764
- }
9765
- const version = await waitForRotatedChatHealth({
9766
- fetch: doFetch,
9767
- platform,
9768
- priorVersion,
9769
- wait: deps.pollWait
9770
- });
9771
- const result = {
9772
- schemaVersion: "odla.platform-chat-credential-rotation/v1",
9773
- appId: minted.appId,
9774
- appIncarnation: minted.appIncarnation,
9775
- principalId: minted.principalId,
9776
- health: { ok: true, service: "odla-chat-agent", version }
9777
- };
9778
- if (parsed.options.json === true) {
9779
- out.log(JSON.stringify(result, null, 2));
9780
- } else {
9781
- out.log(
9782
- `rotated ${result.appId} ${result.principalId} ${result.health.version}`
9783
- );
9784
- }
9785
- }
9786
- async function waitForRotatedChatHealth(opts) {
9787
- const wait2 = opts.wait ?? ((milliseconds) => new Promise((resolve12) => setTimeout(resolve12, milliseconds)));
9788
- let lastStatus = 0;
9789
- let lastVersion = null;
9790
- let lastError = "private_service_unready";
9791
- for (let attempt = 0; attempt < 60; attempt++) {
9792
- const response2 = await opts.fetch(
9793
- `${opts.platform}/health/services/chat`
9794
- );
9795
- const body = await response2.json().catch(() => null);
9796
- const version = response2.headers.get("x-odla-worker-version-id");
9797
- if (response2.ok && record7(body) && body.ok === true && body.service === "odla-chat-agent" && version && version !== opts.priorVersion) {
9798
- return version;
9799
- }
9800
- lastStatus = response2.status;
9801
- lastVersion = version;
9802
- lastError = record7(body) && typeof body.error === "string" ? body.error : "private_service_unready";
9803
- if (attempt < 59) await wait2(5e3);
9804
- }
9805
- throw new Error(
9806
- `chat health did not converge on the rotated Worker deployment (HTTP ${lastStatus}, version ${lastVersion ?? "unknown"}, ${lastError})`
9807
- );
9808
- }
9809
- function isPlatformChatCredential(value2) {
9810
- 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_");
9811
- }
9812
- function apiMessage(value2) {
9813
- if (!record7(value2)) return "request failed";
9814
- const error = record7(value2.error) ? value2.error : value2;
9815
- return typeof error.message === "string" ? error.message : typeof error.code === "string" ? error.code : "request failed";
9816
- }
9817
- function record7(value2) {
9818
- return !!value2 && typeof value2 === "object" && !Array.isArray(value2);
9819
- }
9820
-
9821
9817
  // src/platform-command.ts
9822
9818
  async function platformCommand(parsed, deps = {}) {
9823
9819
  const action2 = parsed.positionals[1];
9824
9820
  if (action2 === "status") {
9825
9821
  return platformStatus(parsed, deps);
9826
9822
  }
9827
- if (action2 === "chat-credentials" && parsed.positionals[2] === "rotate") {
9828
- return rotatePlatformChatCredential(parsed, deps);
9829
- }
9830
9823
  throw new Error(
9831
9824
  `unknown platform action "${[
9832
9825
  action2,
@@ -9864,7 +9857,7 @@ async function platformStatus(parsed, deps) {
9864
9857
  const body = await response2.json().catch(() => null);
9865
9858
  if (!response2.ok) {
9866
9859
  throw new Error(
9867
- `read platform status failed (HTTP ${response2.status}): ${apiMessage2(body)}`
9860
+ `read platform status failed (HTTP ${response2.status}): ${apiMessage(body)}`
9868
9861
  );
9869
9862
  }
9870
9863
  if (!isPlatformStatus(body)) {
@@ -9877,17 +9870,17 @@ async function platformStatus(parsed, deps) {
9877
9870
  }
9878
9871
  }
9879
9872
  function isPlatformStatus(value2) {
9880
- if (!record8(value2) || value2.schemaVersion !== "odla.platform-status/v1") return false;
9881
- if (!record8(value2.verdict) || !Array.isArray(value2.verdict.reasons)) return false;
9882
- if (!record8(value2.catalog) || !record8(value2.summary)) return false;
9873
+ if (!record7(value2) || value2.schemaVersion !== "odla.platform-status/v1") return false;
9874
+ if (!record7(value2.verdict) || !Array.isArray(value2.verdict.reasons)) return false;
9875
+ if (!record7(value2.catalog) || !record7(value2.summary)) return false;
9883
9876
  return Array.isArray(value2.services) && Array.isArray(value2.nextActions);
9884
9877
  }
9885
- function apiMessage2(value2) {
9886
- if (!record8(value2)) return "request failed";
9887
- const error = record8(value2.error) ? value2.error : value2;
9878
+ function apiMessage(value2) {
9879
+ if (!record7(value2)) return "request failed";
9880
+ const error = record7(value2.error) ? value2.error : value2;
9888
9881
  return typeof error.message === "string" ? error.message : typeof error.code === "string" ? error.code : "request failed";
9889
9882
  }
9890
- function record8(value2) {
9883
+ function record7(value2) {
9891
9884
  return !!value2 && typeof value2 === "object" && !Array.isArray(value2);
9892
9885
  }
9893
9886
 
@@ -9928,7 +9921,7 @@ function statusVerdict(reads) {
9928
9921
  severity: "degraded"
9929
9922
  });
9930
9923
  }
9931
- const performance = record9(reads.liveSync.body.performance) ? reads.liveSync.body.performance : null;
9924
+ const performance = record8(reads.liveSync.body.performance) ? reads.liveSync.body.performance : null;
9932
9925
  if (performance?.status === "unavailable") {
9933
9926
  reasons.push({
9934
9927
  source: "liveSync",
@@ -10009,7 +10002,7 @@ function statusVerdict(reads) {
10009
10002
  reasons
10010
10003
  };
10011
10004
  }
10012
- function record9(value2) {
10005
+ function record8(value2) {
10013
10006
  return Boolean(value2) && typeof value2 === "object" && !Array.isArray(value2);
10014
10007
  }
10015
10008
  function numeric2(value2) {
@@ -10037,7 +10030,7 @@ function printO11yStatus(status, out) {
10037
10030
  out.log(
10038
10031
  `o11y status ${status.scope.appId}/${status.scope.env} (${status.scope.minutes}m)`
10039
10032
  );
10040
- const routes = Array.isArray(status.application.body.routes) ? status.application.body.routes.filter(record10) : [];
10033
+ const routes = Array.isArray(status.application.body.routes) ? status.application.body.routes.filter(record9) : [];
10041
10034
  const requests = routes.reduce(
10042
10035
  (total, row) => total + numeric3(row.requests),
10043
10036
  0
@@ -10049,39 +10042,39 @@ function printO11yStatus(status, out) {
10049
10042
  out.log(
10050
10043
  `application ${status.application.httpStatus} ${requests} requests ${errors} errors`
10051
10044
  );
10052
- const versions = Array.isArray(status.applicationVersions.body.rows) ? status.applicationVersions.body.rows.filter(record10) : [];
10045
+ const versions = Array.isArray(status.applicationVersions.body.rows) ? status.applicationVersions.body.rows.filter(record9) : [];
10053
10046
  out.log(
10054
10047
  `application-versions ${status.applicationVersions.httpStatus} ${versions.length ? versions.slice(0, 5).map(
10055
10048
  (row) => `${String(row.value || "(unattributed)")}:${numeric3(row.requests)}`
10056
10049
  ).join(", ") : "none observed"}`
10057
10050
  );
10058
10051
  out.log(liveSyncLine(status.liveSync));
10059
- const canaryDurations = record10(status.canary.body.durationsMs) ? status.canary.body.durationsMs : {};
10052
+ const canaryDurations = record9(status.canary.body.durationsMs) ? status.canary.body.durationsMs : {};
10060
10053
  out.log(
10061
10054
  `canary ${status.canary.httpStatus} ${String(status.canary.body.status ?? status.canary.body.error ?? "unavailable")} ${optionalNumeric(canaryDurations.publishToVisibleMs)} publish-to-visible`
10062
10055
  );
10063
- const collectorIngest = record10(status.collector.body.ingest) ? status.collector.body.ingest : {};
10064
- const collectorStorage = record10(collectorIngest.storage) ? collectorIngest.storage : {};
10056
+ const collectorIngest = record9(status.collector.body.ingest) ? status.collector.body.ingest : {};
10057
+ const collectorStorage = record9(collectorIngest.storage) ? collectorIngest.storage : {};
10065
10058
  out.log(
10066
10059
  `collector ${status.collector.httpStatus} ${String(status.collector.body.status ?? status.collector.body.error ?? "unavailable")} ${numeric3(collectorStorage.affectedPoints)} affected points`
10067
10060
  );
10068
- const providerMetrics = record10(status.provider.body.metrics) ? status.provider.body.metrics : {};
10069
- const providerCapacity = record10(status.provider.body.capacity) ? status.provider.body.capacity : {};
10070
- const workerMemory = record10(providerCapacity.memory) ? providerCapacity.memory : {};
10061
+ const providerMetrics = record9(status.provider.body.metrics) ? status.provider.body.metrics : {};
10062
+ const providerCapacity = record9(status.provider.body.capacity) ? status.provider.body.capacity : {};
10063
+ const workerMemory = record9(providerCapacity.memory) ? providerCapacity.memory : {};
10071
10064
  out.log(
10072
10065
  `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`
10073
10066
  );
10074
10067
  for (const line of providerCapacityLines(status.providerCapacity)) {
10075
10068
  out.log(line);
10076
10069
  }
10077
- const coverage = record10(status.providerReconciliation.body.comparison) ? status.providerReconciliation.body.comparison : {};
10078
- const coverageCounts = record10(status.providerReconciliation.body.counts) ? status.providerReconciliation.body.counts : {};
10079
- const coverageBudget = record10(status.providerReconciliation.body.budget) ? status.providerReconciliation.body.budget : {};
10070
+ const coverage = record9(status.providerReconciliation.body.comparison) ? status.providerReconciliation.body.comparison : {};
10071
+ const coverageCounts = record9(status.providerReconciliation.body.counts) ? status.providerReconciliation.body.counts : {};
10072
+ const coverageBudget = record9(status.providerReconciliation.body.budget) ? status.providerReconciliation.body.budget : {};
10080
10073
  out.log(
10081
10074
  `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`
10082
10075
  );
10083
10076
  const providerPoints = Array.isArray(status.providerHistory.body.points) ? status.providerHistory.body.points.length : 0;
10084
- const providerFreshness = record10(status.providerHistory.body.freshness) ? status.providerHistory.body.freshness : {};
10077
+ const providerFreshness = record9(status.providerHistory.body.freshness) ? status.providerHistory.body.freshness : {};
10085
10078
  out.log(
10086
10079
  `cloudflare-history ${status.providerHistory.httpStatus} ${String(status.providerHistory.body.status ?? status.providerHistory.body.error ?? "unavailable")} ${providerPoints} snapshots ${optionalAge(providerFreshness.ageMs)} old`
10087
10080
  );
@@ -10090,17 +10083,17 @@ function printO11yStatus(status, out) {
10090
10083
  );
10091
10084
  }
10092
10085
  function providerCapacityLines(read3) {
10093
- const resources = record10(read3.body.resources) ? read3.body.resources : {};
10094
- const durableObjects = record10(resources.durableObjects) ? resources.durableObjects : {};
10095
- const periodic = record10(durableObjects.periodic) ? durableObjects.periodic : {};
10096
- const storage = record10(durableObjects.sqliteStorage) ? durableObjects.sqliteStorage : {};
10097
- const d1 = record10(resources.d1) ? resources.d1 : {};
10098
- const d1Activity = record10(d1.activity) ? d1.activity : {};
10099
- const d1Storage = record10(d1.storage) ? d1.storage : {};
10100
- const d1Latency = record10(d1Activity.latency) ? d1Activity.latency : {};
10101
- const r2 = record10(resources.r2) ? resources.r2 : {};
10102
- const r2Operations = record10(r2.operations) ? r2.operations : {};
10103
- const r2Storage = record10(r2.storage) ? r2.storage : {};
10086
+ const resources = record9(read3.body.resources) ? read3.body.resources : {};
10087
+ const durableObjects = record9(resources.durableObjects) ? resources.durableObjects : {};
10088
+ const periodic = record9(durableObjects.periodic) ? durableObjects.periodic : {};
10089
+ const storage = record9(durableObjects.sqliteStorage) ? durableObjects.sqliteStorage : {};
10090
+ const d1 = record9(resources.d1) ? resources.d1 : {};
10091
+ const d1Activity = record9(d1.activity) ? d1.activity : {};
10092
+ const d1Storage = record9(d1.storage) ? d1.storage : {};
10093
+ const d1Latency = record9(d1Activity.latency) ? d1Activity.latency : {};
10094
+ const r2 = record9(resources.r2) ? resources.r2 : {};
10095
+ const r2Operations = record9(r2.operations) ? r2.operations : {};
10096
+ const r2Storage = record9(r2.storage) ? r2.storage : {};
10104
10097
  const status = String(
10105
10098
  read3.body.status ?? read3.body.error ?? "unavailable"
10106
10099
  );
@@ -10111,11 +10104,11 @@ function providerCapacityLines(read3) {
10111
10104
  ];
10112
10105
  }
10113
10106
  function liveSyncLine(read3) {
10114
- const performance = record10(read3.body.performance) ? read3.body.performance : {};
10115
- const commitToSend = record10(performance.commitToSend) ? performance.commitToSend : {};
10107
+ const performance = record9(read3.body.performance) ? read3.body.performance : {};
10108
+ const commitToSend = record9(performance.commitToSend) ? performance.commitToSend : {};
10116
10109
  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`;
10117
10110
  }
10118
- function record10(value2) {
10111
+ function record9(value2) {
10119
10112
  return Boolean(value2) && typeof value2 === "object" && !Array.isArray(value2);
10120
10113
  }
10121
10114
  function numeric3(value2) {
@@ -10300,7 +10293,7 @@ async function read2(url, headers, doFetch) {
10300
10293
  // src/provision.ts
10301
10294
  var import_apps12 = require("@odla-ai/apps");
10302
10295
  var import_ai3 = require("@odla-ai/ai");
10303
- var import_node_process11 = __toESM(require("process"), 1);
10296
+ var import_node_process10 = __toESM(require("process"), 1);
10304
10297
 
10305
10298
  // src/integration-provision.ts
10306
10299
  var import_db3 = require("@odla-ai/db");
@@ -10607,7 +10600,7 @@ ${env}: credentials are already saved; retry "odla-ai secrets push --env ${env}$
10607
10600
  await provisionIntegrationSeeds(doFetch, cfg.dbEndpoint, tenantId, dbKey, database.integrations, env, out);
10608
10601
  }
10609
10602
  if (cfg.services.includes("ai") && cfg.ai?.provider && cfg.ai.keyEnv) {
10610
- const key = import_node_process11.default.env[cfg.ai.keyEnv];
10603
+ const key = import_node_process10.default.env[cfg.ai.keyEnv];
10611
10604
  if (key) {
10612
10605
  const secretName = cfg.ai.secretName ?? defaultSecretName(cfg.ai.provider);
10613
10606
  await (0, import_ai3.putSecret)({ endpoint: cfg.dbEndpoint, token, fetch: doFetch }, tenantId, secretName, key);
@@ -10649,7 +10642,7 @@ ${env}: credentials are already saved; retry "odla-ai secrets push --env ${env}$
10649
10642
 
10650
10643
  // src/record.ts
10651
10644
  var import_node_fs16 = require("fs");
10652
- var import_node_process12 = __toESM(require("process"), 1);
10645
+ var import_node_process11 = __toESM(require("process"), 1);
10653
10646
 
10654
10647
  // src/surface.ts
10655
10648
  var PM_ACTIONS = {
@@ -10694,6 +10687,7 @@ var COMMAND_SURFACE = {
10694
10687
  promote: {},
10695
10688
  owners: { list: {}, add: {}, remove: {} }
10696
10689
  },
10690
+ brand: { design: { unpack: {} } },
10697
10691
  calendar: { status: {}, calendars: {}, connect: {}, disconnect: {} },
10698
10692
  capabilities: {},
10699
10693
  code: { connect: {} },
@@ -10717,8 +10711,7 @@ var COMMAND_SURFACE = {
10717
10711
  o11y: { status: {} },
10718
10712
  operations: { get: {}, wait: {} },
10719
10713
  platform: {
10720
- status: {},
10721
- "chat-credentials": { rotate: {} }
10714
+ status: {}
10722
10715
  },
10723
10716
  pm: {
10724
10717
  ...PM_ENTITIES,
@@ -10798,7 +10791,7 @@ function invocationPath(words2) {
10798
10791
 
10799
10792
  // src/record.ts
10800
10793
  function recordInvocation(parsed) {
10801
- const file = import_node_process12.default.env.ODLA_CLI_RECORD;
10794
+ const file = import_node_process11.default.env.ODLA_CLI_RECORD;
10802
10795
  if (!file) return;
10803
10796
  try {
10804
10797
  const entry = {
@@ -10991,7 +10984,7 @@ async function runbookRemove(ctx, slug) {
10991
10984
 
10992
10985
  // src/runbook-import.ts
10993
10986
  var import_node_fs18 = require("fs");
10994
- var import_node_path15 = require("path");
10987
+ var import_node_path16 = require("path");
10995
10988
  function parseRunbook(text2, slug) {
10996
10989
  let rest = text2;
10997
10990
  const meta = {};
@@ -11020,8 +11013,8 @@ function readRunbookDir(dir) {
11020
11013
  const files = (0, import_node_fs18.readdirSync)(dir).filter((f) => f.endsWith(".md")).sort();
11021
11014
  if (!files.length) throw new Error(`no .md files in ${dir}`);
11022
11015
  return files.map((file) => {
11023
- const slug = (0, import_node_path15.basename)(file, ".md");
11024
- const parsed = parseRunbook((0, import_node_fs18.readFileSync)((0, import_node_path15.join)(dir, file), "utf8"), slug);
11016
+ const slug = (0, import_node_path16.basename)(file, ".md");
11017
+ const parsed = parseRunbook((0, import_node_fs18.readFileSync)((0, import_node_path16.join)(dir, file), "utf8"), slug);
11025
11018
  return { file, slug, ...parsed, words: parsed.body.split(/\s+/).filter(Boolean).length };
11026
11019
  });
11027
11020
  }
@@ -11095,7 +11088,7 @@ async function upsert(ctx, r, visibility) {
11095
11088
  // src/runbook-impact.ts
11096
11089
  var import_node_child_process7 = require("child_process");
11097
11090
  var import_node_fs19 = require("fs");
11098
- var import_node_path16 = require("path");
11091
+ var import_node_path17 = require("path");
11099
11092
 
11100
11093
  // src/runbook-impact-scan.ts
11101
11094
  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$]*)/;
@@ -11264,7 +11257,7 @@ ${body.split("\n").map((line) => `+${line}`).join("\n")}
11264
11257
  }
11265
11258
  function manifestLabeller(root) {
11266
11259
  return (workspace) => {
11267
- const manifest = (0, import_node_path16.join)(root, workspace, "package.json");
11260
+ const manifest = (0, import_node_path17.join)(root, workspace, "package.json");
11268
11261
  if (!(0, import_node_fs19.existsSync)(manifest)) return void 0;
11269
11262
  try {
11270
11263
  const name = JSON.parse((0, import_node_fs19.readFileSync)(manifest, "utf8")).name;
@@ -11334,7 +11327,7 @@ function report3(ctx, impacts) {
11334
11327
  async function runbookImpact(ctx, options, deps = {}) {
11335
11328
  const cwd = deps.cwd ?? process.cwd();
11336
11329
  const runGit = deps.runGit ?? gitRunner(cwd);
11337
- const read3 = deps.readRepoFile ?? ((path) => (0, import_node_fs19.readFileSync)((0, import_node_path16.join)(cwd, path), "utf8"));
11330
+ const read3 = deps.readRepoFile ?? ((path) => (0, import_node_fs19.readFileSync)((0, import_node_path17.join)(cwd, path), "utf8"));
11338
11331
  const surfaces = changedSurfaces(collectDiff(runGit, options.base, read3), manifestLabeller(cwd));
11339
11332
  if (!surfaces.length) {
11340
11333
  return ctx.out.log(
@@ -11469,10 +11462,10 @@ async function runbookComment(ctx, slug, body) {
11469
11462
  var import_node_child_process8 = require("child_process");
11470
11463
  var import_node_fs20 = require("fs");
11471
11464
  var import_node_os5 = require("os");
11472
- var import_node_path17 = require("path");
11473
- var import_node_process13 = __toESM(require("process"), 1);
11465
+ var import_node_path18 = require("path");
11466
+ var import_node_process12 = __toESM(require("process"), 1);
11474
11467
  var EDITOR_ENV = ["ODLA_EDITOR", "VISUAL", "EDITOR"];
11475
- function resolveEditor(env = import_node_process13.default.env) {
11468
+ function resolveEditor(env = import_node_process12.default.env) {
11476
11469
  for (const name of EDITOR_ENV) {
11477
11470
  const value2 = env[name];
11478
11471
  if (value2 && value2.trim()) return value2.trim();
@@ -11486,8 +11479,8 @@ function defaultRun(command, path) {
11486
11479
  return result.status ?? 0;
11487
11480
  }
11488
11481
  function editText(initial, slug, deps = {}) {
11489
- const env = deps.env ?? import_node_process13.default.env;
11490
- const interactive = deps.interactive ?? (() => Boolean(import_node_process13.default.stdin.isTTY));
11482
+ const env = deps.env ?? import_node_process12.default.env;
11483
+ const interactive = deps.interactive ?? (() => Boolean(import_node_process12.default.stdin.isTTY));
11491
11484
  const editor = resolveEditor(env);
11492
11485
  if (!editor)
11493
11486
  throw new Error(
@@ -11495,8 +11488,8 @@ function editText(initial, slug, deps = {}) {
11495
11488
  );
11496
11489
  if (!interactive())
11497
11490
  throw new Error(`cannot open an editor without a terminal \u2014 pass --file <path> or --body "\u2026" instead`);
11498
- const dir = (0, import_node_fs20.mkdtempSync)((0, import_node_path17.join)((0, import_node_os5.tmpdir)(), "odla-runbook-"));
11499
- const file = (0, import_node_path17.join)(dir, `${slug}.md`);
11491
+ const dir = (0, import_node_fs20.mkdtempSync)((0, import_node_path18.join)((0, import_node_os5.tmpdir)(), "odla-runbook-"));
11492
+ const file = (0, import_node_path18.join)(dir, `${slug}.md`);
11500
11493
  try {
11501
11494
  (0, import_node_fs20.writeFileSync)(file, initial, { mode: 384 });
11502
11495
  const code = defaultRunOrInjected(deps)(editor, file);
@@ -11838,7 +11831,7 @@ async function runbookCommand(parsed, deps = {}) {
11838
11831
  }
11839
11832
 
11840
11833
  // src/security-command-context.ts
11841
- var import_promises11 = require("readline/promises");
11834
+ var import_promises12 = require("readline/promises");
11842
11835
  async function hostedSecurityContext(parsed, dependencies) {
11843
11836
  const configPath = stringOpt(parsed.options.config) ?? "odla.config.mjs";
11844
11837
  const cfg = await loadProjectConfig(configPath);
@@ -11864,7 +11857,7 @@ async function hostedSecurityContext(parsed, dependencies) {
11864
11857
  async function interactiveConfirmation(message2, dependencies) {
11865
11858
  if (dependencies.confirm) return dependencies.confirm(message2);
11866
11859
  if (!process.stdin.isTTY || !process.stdout.isTTY) return false;
11867
- const prompt = (0, import_promises11.createInterface)({ input: process.stdin, output: process.stdout });
11860
+ const prompt = (0, import_promises12.createInterface)({ input: process.stdin, output: process.stdout });
11868
11861
  try {
11869
11862
  const answer = await prompt.question(`${message2} [y/N] `);
11870
11863
  return /^y(?:es)?$/i.test(answer.trim());
@@ -11991,7 +11984,7 @@ function hostedSeverity(value2, flag) {
11991
11984
  var import_security2 = require("@odla-ai/security");
11992
11985
 
11993
11986
  // src/security.ts
11994
- var import_node_path18 = require("path");
11987
+ var import_node_path19 = require("path");
11995
11988
  var import_security = require("@odla-ai/security");
11996
11989
  var import_node3 = require("@odla-ai/security/node");
11997
11990
  async function runHostedSecurity(options) {
@@ -12003,9 +11996,9 @@ async function runHostedSecurity(options) {
12003
11996
  const appId = selfAudit ? "odla-ai" : cfg.app.id;
12004
11997
  const env = selfAudit ? "prod" : selectEnv(options.env, cfg.envs, cfg.configPath, cfg.rootDir);
12005
11998
  const platform = options.platform ?? cfg?.platformUrl ?? "https://odla.ai";
12006
- const target = (0, import_node_path18.resolve)(options.target ?? cfg?.rootDir ?? ".");
12007
- const output = (0, import_node_path18.resolve)(options.out ?? (0, import_node_path18.resolve)(target, ".odla/security/hosted"));
12008
- const outputRelative = (0, import_node_path18.relative)(target, output).split(import_node_path18.sep).join("/");
11999
+ const target = (0, import_node_path19.resolve)(options.target ?? cfg?.rootDir ?? ".");
12000
+ const output = (0, import_node_path19.resolve)(options.out ?? (0, import_node_path19.resolve)(target, ".odla/security/hosted"));
12001
+ const outputRelative = (0, import_node_path19.relative)(target, output).split(import_node_path19.sep).join("/");
12009
12002
  if (!outputRelative) throw new Error("Hosted security output cannot be the repository root");
12010
12003
  const profile = profileFor(options.profile ?? "odla", options.maxHuntTasks ?? 12);
12011
12004
  const tokenRequest = {
@@ -12017,7 +12010,7 @@ async function runHostedSecurity(options) {
12017
12010
  };
12018
12011
  const token = await injectedToken(options, tokenRequest);
12019
12012
  const snapshot = await (0, import_node3.snapshotDirectory)(target, {
12020
- exclude: !outputRelative.startsWith("../") && !(0, import_node_path18.isAbsolute)(outputRelative) ? [outputRelative] : []
12013
+ exclude: !outputRelative.startsWith("../") && !(0, import_node_path19.isAbsolute)(outputRelative) ? [outputRelative] : []
12021
12014
  });
12022
12015
  const hosted = await (0, import_security.createPlatformSecurityReasoners)({
12023
12016
  platform,
@@ -12035,7 +12028,7 @@ async function runHostedSecurity(options) {
12035
12028
  });
12036
12029
  const harness = (0, import_security.createSecurityHarness)({
12037
12030
  profile,
12038
- store: new import_node3.FileRunStore((0, import_node_path18.resolve)(output, "state")),
12031
+ store: new import_node3.FileRunStore((0, import_node_path19.resolve)(output, "state")),
12039
12032
  discoveryReasoner: hosted.discoveryReasoner,
12040
12033
  validationReasoner: hosted.validationReasoner,
12041
12034
  policy: {
@@ -12059,7 +12052,7 @@ async function runHostedSecurity(options) {
12059
12052
  function selectEnv(requested, declared, configPath, rootDir) {
12060
12053
  const env = requested ?? (declared.includes("dev") ? "dev" : declared[0]);
12061
12054
  if (!env || !declared.includes(env)) {
12062
- const shown = (0, import_node_path18.relative)(rootDir, configPath) || configPath;
12055
+ const shown = (0, import_node_path19.relative)(rootDir, configPath) || configPath;
12063
12056
  throw new Error(`env "${env ?? ""}" is not declared in ${shown}`);
12064
12057
  }
12065
12058
  return env;
@@ -12088,7 +12081,7 @@ function printSummary(out, appId, env, run, report4, output) {
12088
12081
  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}`);
12089
12082
  if (report4.callBudget) out.log(` calls: discovery=${formatBudget(report4.callBudget.discovery)} validation=${formatBudget(report4.callBudget.validation)}`);
12090
12083
  out.log(` findings: confirmed=${report4.metrics.confirmed} needs_reproduction=${report4.metrics.needsReproduction} candidates=${report4.metrics.candidates}`);
12091
- out.log(` report: ${(0, import_node_path18.resolve)(output, "REPORT.md")}`);
12084
+ out.log(` report: ${(0, import_node_path19.resolve)(output, "REPORT.md")}`);
12092
12085
  }
12093
12086
  function formatBudget(usage) {
12094
12087
  return usage ? `${usage.usedCalls}/${usage.maxCalls} skipped=${usage.skippedCalls}` : "caller-managed";
@@ -12589,6 +12582,10 @@ async function runCli(argv = process.argv.slice(2), dependencies = {}) {
12589
12582
  await securityCommand(parsed, runtime);
12590
12583
  return;
12591
12584
  }
12585
+ if (command === "brand") {
12586
+ await brandCommand(parsed, runtime);
12587
+ return;
12588
+ }
12592
12589
  if (command === "pm") {
12593
12590
  await pmCommand(parsed, runtime);
12594
12591
  return;