@m8t-stack/cli 0.2.13 → 0.2.15

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/cli.js CHANGED
@@ -781,7 +781,10 @@ var init_brain_yaml_mirror = __esm({
781
781
  ` enabled: true`,
782
782
  ` lifecycle: { inbox: 14d, stale: 30d, archive: 90d }`,
783
783
  ` artifactRetention: 30d`,
784
- ` digestRetention: 90d`
784
+ ` digestRetention: 90d`,
785
+ ` costReport:`,
786
+ ` enabled: true`,
787
+ ` cadenceDays: 14`
785
788
  ].join("\n");
786
789
  MIRROR_BANNER = [
787
790
  `# \u2500\u2500 MIRROR \u2014 link record convenience copy. NOT the source of truth \u2014`,
@@ -1195,7 +1198,7 @@ var init_enable_hosted_brain = __esm({
1195
1198
  import { Builtins, Cli } from "clipanion";
1196
1199
 
1197
1200
  // src/lib/package-version.ts
1198
- var CLI_VERSION = "0.2.13";
1201
+ var CLI_VERSION = "0.2.15";
1199
1202
 
1200
1203
  // src/lib/render-error.ts
1201
1204
  init_errors();
@@ -13194,6 +13197,18 @@ async function ghAuthLoginDevice(exec = defaultGhExec) {
13194
13197
  });
13195
13198
  }
13196
13199
  }
13200
+ async function getGhToken(exec = defaultGhExec) {
13201
+ const r = await exec("gh", ["auth", "token"]);
13202
+ const tok = r.stdout.trim();
13203
+ if (r.exitCode !== 0 || !tok) {
13204
+ throw new LocalCliError({
13205
+ code: "GH_TOKEN_FAILED",
13206
+ message: `gh auth token failed (exit ${r.exitCode.toString()}): ${(r.stderr || r.stdout).slice(0, 200)}`,
13207
+ hint: "Run `gh auth login` to authenticate the GitHub CLI."
13208
+ });
13209
+ }
13210
+ return tok;
13211
+ }
13197
13212
  async function getRepoId(owner, repo, exec = defaultGhExec) {
13198
13213
  const r = await exec("gh", ["api", `/repos/${owner}/${repo}`, "--jq", ".id"]);
13199
13214
  if (r.exitCode !== 0) {
@@ -13297,6 +13312,34 @@ async function tryOpenUrl(url, exec = defaultGhExec) {
13297
13312
  } catch {
13298
13313
  }
13299
13314
  }
13315
+ function ghRepoProbe(args) {
13316
+ const exec = args.exec ?? defaultGhExec;
13317
+ const slug = `${args.owner}/${args.repo}`;
13318
+ return {
13319
+ repoStatus: async () => {
13320
+ const r = await exec("gh", ["api", "-i", `/repos/${slug}`]);
13321
+ const combined = `${r.stdout}
13322
+ ${r.stderr}`;
13323
+ const header = /^HTTP\/[\d.]+\s+(\d{3})/m.exec(combined);
13324
+ if (header) return Number(header[1]);
13325
+ const ghErr = /\(HTTP (\d{3})\)/.exec(combined);
13326
+ if (ghErr) return Number(ghErr[1]);
13327
+ if (r.exitCode === 0) return 200;
13328
+ throw new LocalCliError({
13329
+ code: "GH_REPO_PROBE_FAILED",
13330
+ message: `gh api /repos/${slug} failed (exit ${r.exitCode.toString()}): ${(r.stderr || r.stdout).slice(0, 200)}`
13331
+ });
13332
+ },
13333
+ getFile: async (path29) => {
13334
+ const r = await exec("gh", ["api", "-H", "Accept: application/vnd.github.raw+json", `/repos/${slug}/contents/${path29}`]);
13335
+ return r.exitCode === 0 ? r.stdout : null;
13336
+ },
13337
+ isEmpty: async () => {
13338
+ const r = await exec("gh", ["api", `/repos/${slug}/contents`]);
13339
+ return r.exitCode !== 0;
13340
+ }
13341
+ };
13342
+ }
13300
13343
 
13301
13344
  // src/commands/brain/app-create.ts
13302
13345
  init_errors();
@@ -13531,6 +13574,7 @@ import { readFileSync as readFileSync6 } from "fs";
13531
13574
  import * as fs10 from "fs";
13532
13575
  import * as os4 from "os";
13533
13576
  import * as path9 from "path";
13577
+ import * as readline2 from "readline/promises";
13534
13578
  import { DefaultAzureCredential as DefaultAzureCredential4 } from "@azure/identity";
13535
13579
  init_errors();
13536
13580
 
@@ -14062,6 +14106,20 @@ function materializeBrainTree(opts) {
14062
14106
  init_errors();
14063
14107
  init_esm2();
14064
14108
  import { spawn as spawn3 } from "child_process";
14109
+ import { parse as parseYaml5 } from "yaml";
14110
+ function isM8tBrainMarker(yamlText) {
14111
+ if (!yamlText.trim()) return false;
14112
+ let parsed;
14113
+ try {
14114
+ parsed = parseYaml5(yamlText);
14115
+ } catch {
14116
+ return false;
14117
+ }
14118
+ if (!parsed || typeof parsed !== "object") return false;
14119
+ const root = parsed;
14120
+ const isObj2 = (v) => typeof v === "object" && v !== null;
14121
+ return isObj2(root.engine) || isObj2(root.processes) || isObj2(root.link);
14122
+ }
14065
14123
  async function createBlankRepo(args) {
14066
14124
  const res = await fetch(`https://api.github.com/orgs/${args.org}/repos`, {
14067
14125
  method: "POST",
@@ -14192,8 +14250,119 @@ async function commitFilesViaApp(args) {
14192
14250
  });
14193
14251
  await api(`/git/refs/heads/${args.branch}`, { method: "PATCH", body: JSON.stringify({ sha: commit.sha }) });
14194
14252
  }
14253
+ async function probeRepoState(probe) {
14254
+ const status = await probe.repoStatus();
14255
+ if (status === 404) return "absent";
14256
+ if (status !== 200) {
14257
+ throw new LocalCliError({
14258
+ code: "GH_REPO_PROBE_FAILED",
14259
+ message: `GET repo returned HTTP ${status.toString()} (expected 200 or 404)`
14260
+ });
14261
+ }
14262
+ const marker = await probe.getFile(".m8t/brain.yaml");
14263
+ if (marker !== null && isM8tBrainMarker(marker)) return "m8t-brain";
14264
+ if (await probe.isEmpty()) return "empty";
14265
+ return "foreign";
14266
+ }
14267
+ function appRepoProbe(args) {
14268
+ const doFetch = args.fetchImpl ?? fetch;
14269
+ const H = ghHeaders(args.token);
14270
+ return {
14271
+ repoStatus: async () => {
14272
+ const res = await doFetch(`${GH_API}/repos/${args.repo}`, { headers: H, signal: AbortSignal.timeout(GH_REQUEST_TIMEOUT_MS) });
14273
+ return res.status;
14274
+ },
14275
+ getFile: (path29) => readRepoFileViaApp({ token: args.token, repo: args.repo, path: path29, fetchImpl: args.fetchImpl }),
14276
+ isEmpty: async () => {
14277
+ const res = await doFetch(`${GH_API}/repos/${args.repo}/contents`, { headers: H, signal: AbortSignal.timeout(GH_REQUEST_TIMEOUT_MS) });
14278
+ return res.status === 404;
14279
+ }
14280
+ };
14281
+ }
14282
+
14283
+ // src/lib/brain-repo-collision.ts
14284
+ init_errors();
14285
+ var DEFAULT_MAX_ATTEMPTS = 20;
14286
+ function actionForState(state) {
14287
+ switch (state) {
14288
+ case "absent":
14289
+ return "create";
14290
+ case "m8t-brain":
14291
+ return "reuse";
14292
+ case "empty":
14293
+ return "adopt";
14294
+ case "foreign":
14295
+ throw new LocalCliError({
14296
+ code: "FOREIGN_REPO_COLLISION",
14297
+ message: `A repo already exists but isn't an m8t brain.`
14298
+ });
14299
+ }
14300
+ }
14301
+ function candidate(base, n) {
14302
+ return n === 1 ? base : `${base}-${n.toString()}`;
14303
+ }
14304
+ async function scan(base, classify, accept, startAt, maxAttempts) {
14305
+ for (let n = startAt; n <= maxAttempts; n++) {
14306
+ const name = candidate(base, n);
14307
+ const state = await classify(name);
14308
+ if (accept(state)) return { repoName: name, state };
14309
+ }
14310
+ throw new LocalCliError({
14311
+ code: "REPO_NAME_SCAN_EXHAUSTED",
14312
+ message: `Could not find a free repo name for "${base}" after ${maxAttempts.toString()} attempts.`
14313
+ });
14314
+ }
14315
+ async function resolveRepoCollision(args) {
14316
+ const max = args.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;
14317
+ const state = await args.classify(args.repoName);
14318
+ if (args.force === "new") {
14319
+ const found = await scan(args.repoName, args.classify, (s) => s === "absent", 1, max);
14320
+ return { repoName: found.repoName, action: "create" };
14321
+ }
14322
+ if (args.force === "reuse") {
14323
+ return { repoName: args.repoName, action: actionForState(state) };
14324
+ }
14325
+ if (state === "absent") return { repoName: args.repoName, action: "create" };
14326
+ if (args.interactive && args.prompt) {
14327
+ const choice = await args.prompt({ repoName: args.repoName, state });
14328
+ if (choice === "abort") {
14329
+ throw new LocalCliError({ code: "BRAIN_CREATE_ABORTED", message: "Aborted by the operator." });
14330
+ }
14331
+ if (choice === "new") {
14332
+ const found = await scan(args.repoName, args.classify, (s) => s !== "foreign", 2, max);
14333
+ return { repoName: found.repoName, action: actionForState(found.state) };
14334
+ }
14335
+ return { repoName: args.repoName, action: actionForState(state) };
14336
+ }
14337
+ if (state === "foreign") {
14338
+ throw new LocalCliError({
14339
+ code: "FOREIGN_REPO_COLLISION",
14340
+ message: `A repo with this name already exists but isn't an m8t brain, so it won't be touched. Rename that repo or install into a different org, then re-run.`
14341
+ });
14342
+ }
14343
+ return { repoName: args.repoName, action: actionForState(state) };
14344
+ }
14195
14345
 
14196
14346
  // src/commands/brain/create.ts
14347
+ async function promptCollision(ctx, info) {
14348
+ const rl = readline2.createInterface({ input: ctx.stdin, output: ctx.stdout });
14349
+ try {
14350
+ if (info.state === "foreign") {
14351
+ const ans2 = (await rl.question(
14352
+ `A repo "${info.repoName}" already exists but isn't an m8t brain. Create a new "${info.repoName}-2" instead? [Y/n] (n aborts) `
14353
+ )).trim().toLowerCase();
14354
+ return ans2 === "" || ans2 === "y" || ans2 === "yes" ? "new" : "abort";
14355
+ }
14356
+ const ans = (await rl.question(
14357
+ `An m8t brain "${info.repoName}" already exists. Reuse it? [Y/n] (n creates "${info.repoName}-2", or "a" aborts) `
14358
+ )).trim().toLowerCase();
14359
+ if (ans === "" || ans === "y" || ans === "yes") return "reuse";
14360
+ if (ans === "a" || ans === "abort") return "abort";
14361
+ return "new";
14362
+ } finally {
14363
+ rl.close();
14364
+ }
14365
+ }
14197
14366
  function stageAsGitRepo(dir) {
14198
14367
  const steps = [
14199
14368
  { args: ["init", "-b", "main"], label: "git init" },
@@ -14236,6 +14405,8 @@ var BrainCreateCommand = class extends M8tCommand {
14236
14405
  appId = Option17.String("--app-id", { description: "GitHub App id (no-gh path); with --app-pem/--installation-id, create the repo via the App instead of gh." });
14237
14406
  appPem = Option17.String("--app-pem", { description: "Path to the App private-key PEM (no-gh path)." });
14238
14407
  installationId = Option17.String("--installation-id", { description: "Org installation id for the App (no-gh path)." });
14408
+ reuse = Option17.Boolean("--reuse", false, { description: "If the brain repo already exists, reuse it (non-interactive). Errors if the repo isn't a valid m8t brain." });
14409
+ newName = Option17.Boolean("--new", false, { description: "If the brain repo name is taken, create a fresh suffixed repo (e.g. <name>-2) instead of reusing." });
14239
14410
  async executeCommand() {
14240
14411
  const owner = typeof this.owner === "string" ? this.owner : void 0;
14241
14412
  const worker = typeof this.worker === "string" ? this.worker : void 0;
@@ -14300,59 +14471,95 @@ var BrainCreateCommand = class extends M8tCommand {
14300
14471
  const tmpDir = fs10.mkdtempSync(path9.join(os4.tmpdir(), `m8t-brain-create-${worker}-`));
14301
14472
  let result;
14302
14473
  let resolvedInstallationId = null;
14474
+ const force = this.reuse === true ? "reuse" : this.newName === true ? "new" : void 0;
14475
+ const interactive = !useAppPath && this.context.stdout.isTTY === true;
14476
+ let token;
14477
+ let classify;
14478
+ if (useAppPath) {
14479
+ token = await mintInstallationTokenFromPem({
14480
+ appId: appIdOpt,
14481
+ privateKeyPem: readFileSync6(appPemOpt, "utf8"),
14482
+ installationId: installationIdOpt
14483
+ });
14484
+ const tok = token;
14485
+ classify = (name) => probeRepoState(appRepoProbe({ token: tok, repo: `${owner}/${name}` }));
14486
+ } else {
14487
+ classify = (name) => probeRepoState(ghRepoProbe({ owner, repo: name }));
14488
+ }
14489
+ const decision = await resolveRepoCollision({
14490
+ repoName,
14491
+ classify,
14492
+ interactive,
14493
+ force,
14494
+ prompt: interactive ? (info) => promptCollision(
14495
+ { stdin: this.context.stdin, stdout: this.context.stdout },
14496
+ info
14497
+ ) : void 0
14498
+ });
14499
+ const finalName = decision.repoName;
14500
+ const needsPush = decision.action === "create" || decision.action === "adopt";
14501
+ if (finalName !== repoName) {
14502
+ this.context.stdout.write(`${colors.hint("note:")} using repo name ${colors.field(finalName)} (${decision.action}).
14503
+ `);
14504
+ }
14303
14505
  try {
14304
- materializeBrainTree({ templateSrc, destDir: tmpDir, seedDir });
14305
- this.context.stdout.write(
14306
- seedName ? `${colors.dim("\u2192")} copied brain-template/ + overlaid seed ${colors.field(seedName)} to ${tmpDir}
14506
+ if (needsPush) {
14507
+ materializeBrainTree({ templateSrc, destDir: tmpDir, seedDir });
14508
+ this.context.stdout.write(
14509
+ seedName ? `${colors.dim("\u2192")} copied brain-template/ + overlaid seed ${colors.field(seedName)} to ${tmpDir}
14307
14510
  ` : `${colors.dim("\u2192")} copied brain-template/ to ${tmpDir}
14308
14511
  `
14309
- );
14512
+ );
14513
+ }
14310
14514
  if (useAppPath) {
14311
- this.context.stdout.write(`${colors.dim("\u2192")} creating ${owner}/${repoName} via the GitHub App (no gh)\u2026
14515
+ const appToken = token ?? "";
14516
+ if (decision.action === "create") {
14517
+ this.context.stdout.write(`${colors.dim("\u2192")} creating ${owner}/${finalName} via the GitHub App (no gh)\u2026
14518
+ `);
14519
+ await createBlankRepo({ token: appToken, org: owner, name: finalName, private: !this.public_ });
14520
+ await pushSeed({ token: appToken, org: owner, name: finalName, branch, sourceDir: tmpDir });
14521
+ this.context.stdout.write(`${colors.success("\u2713")} repo created + seeded via the App
14522
+ `);
14523
+ } else if (decision.action === "adopt") {
14524
+ this.context.stdout.write(`${colors.dim("\u2192")} seeding the existing empty repo ${owner}/${finalName} via the GitHub App\u2026
14525
+ `);
14526
+ await pushSeed({ token: appToken, org: owner, name: finalName, branch, sourceDir: tmpDir });
14527
+ this.context.stdout.write(`${colors.success("\u2713")} empty repo seeded via the App
14528
+ `);
14529
+ } else {
14530
+ this.context.stdout.write(`${colors.success("\u2713")} reusing the existing brain ${owner}/${finalName}
14312
14531
  `);
14313
- const pem = readFileSync6(appPemOpt, "utf8");
14314
- const appJwt = signAppJwt({ appId: appIdOpt, privateKeyPem: pem });
14315
- const tokRes = await fetch(
14316
- `https://api.github.com/app/installations/${installationIdOpt}/access_tokens`,
14317
- {
14318
- method: "POST",
14319
- headers: {
14320
- Authorization: `Bearer ${appJwt}`,
14321
- Accept: "application/vnd.github+json",
14322
- "X-GitHub-Api-Version": "2022-11-28",
14323
- "User-Agent": "m8t"
14324
- }
14325
- }
14326
- );
14327
- if (!tokRes.ok) {
14328
- throw new LocalCliError({
14329
- code: "GH_APP_TOKEN_FAILED",
14330
- message: `mint installation token HTTP ${tokRes.status.toString()}: ${(await tokRes.text()).slice(0, 300)}`
14331
- });
14332
14532
  }
14333
- const token = (await tokRes.json()).token;
14334
- await createBlankRepo({ token, org: owner, name: repoName, private: !this.public_ });
14335
- await pushSeed({ token, org: owner, name: repoName, branch, sourceDir: tmpDir });
14336
14533
  resolvedInstallationId = installationIdOpt;
14337
- this.context.stdout.write(`${colors.success("\u2713")} repo created + seeded via the App
14338
- `);
14339
14534
  } else {
14340
- stageAsGitRepo(tmpDir);
14341
- this.context.stdout.write(`${colors.dim("\u2192")} creating repo ${owner}/${repoName} (${this.public_ ? "public" : "private"})\u2026
14535
+ if (decision.action === "create") {
14536
+ stageAsGitRepo(tmpDir);
14537
+ this.context.stdout.write(`${colors.dim("\u2192")} creating repo ${owner}/${finalName} (${this.public_ ? "public" : "private"})\u2026
14538
+ `);
14539
+ await createRepo({ owner, name: finalName, private: !this.public_, source: tmpDir });
14540
+ this.context.stdout.write(`${colors.success("\u2713")} repo created
14541
+ `);
14542
+ } else if (decision.action === "adopt") {
14543
+ this.context.stdout.write(`${colors.dim("\u2192")} seeding the existing empty repo ${owner}/${finalName}\u2026
14342
14544
  `);
14343
- await createRepo({ owner, name: repoName, private: !this.public_, source: tmpDir });
14344
- this.context.stdout.write(`${colors.success("\u2713")} repo created
14545
+ const ghToken = await getGhToken();
14546
+ await pushSeed({ token: ghToken, org: owner, name: finalName, branch, sourceDir: tmpDir });
14547
+ this.context.stdout.write(`${colors.success("\u2713")} empty repo seeded
14345
14548
  `);
14346
- const repoId = await getRepoId(owner, repoName);
14549
+ } else {
14550
+ this.context.stdout.write(`${colors.success("\u2713")} reusing the existing brain ${owner}/${finalName}
14551
+ `);
14552
+ }
14553
+ const repoId = await getRepoId(owner, finalName);
14347
14554
  const { slug, appId: secretAppId, privateKeyPem } = await readAppSecrets({ credential: credential2, kvUri });
14348
14555
  const initialJwt = signAppJwt({ appId: secretAppId, privateKeyPem });
14349
- resolvedInstallationId = await probeAppInstallation({ owner, repo: repoName, jwt: initialJwt });
14556
+ resolvedInstallationId = await probeAppInstallation({ owner, repo: finalName, jwt: initialJwt });
14350
14557
  if (resolvedInstallationId) {
14351
- this.context.stdout.write(` ${colors.success("\u2713")} App already installed on ${colors.field(`${owner}/${repoName}`)} (installation ${resolvedInstallationId}); skipping browser open.
14558
+ this.context.stdout.write(` ${colors.success("\u2713")} App already installed on ${colors.field(`${owner}/${finalName}`)} (installation ${resolvedInstallationId}); skipping browser open.
14352
14559
  `);
14353
14560
  } else {
14354
14561
  const url = installUrl(slug, repoId);
14355
- this.context.stdout.write(`${colors.field("\u2192")} Install the m8t-brain App on ${owner}/${repoName}:
14562
+ this.context.stdout.write(`${colors.field("\u2192")} Install the m8t-brain App on ${owner}/${finalName}:
14356
14563
  ${url}
14357
14564
  `);
14358
14565
  await tryOpenUrl(url);
@@ -14360,10 +14567,10 @@ var BrainCreateCommand = class extends M8tCommand {
14360
14567
  `);
14361
14568
  resolvedInstallationId = await pollForInstallation({
14362
14569
  owner,
14363
- repo: repoName,
14570
+ repo: finalName,
14364
14571
  // Mint fresh JWT each tick — App JWTs are 10-min TTL, poll defaults to 5 min
14365
14572
  // but the timeout is a soft default, so don't depend on the inequality.
14366
- probe: () => probeAppInstallation({ owner, repo: repoName, jwt: signAppJwt({ appId: secretAppId, privateKeyPem }) }),
14573
+ probe: () => probeAppInstallation({ owner, repo: finalName, jwt: signAppJwt({ appId: secretAppId, privateKeyPem }) }),
14367
14574
  onTick: (n) => {
14368
14575
  if (n % 5 === 0) this.context.stderr.write(` ${colors.dim(`\u2026still waiting (${(n * 2).toString()}s)`)}
14369
14576
  `);
@@ -14379,7 +14586,7 @@ var BrainCreateCommand = class extends M8tCommand {
14379
14586
  projectEndpoint: project.endpoint,
14380
14587
  projectArmId: `${project.accountScope}/projects/${project.projectName}`,
14381
14588
  agentName: worker,
14382
- repo: `${owner}/${repoName}`,
14589
+ repo: `${owner}/${finalName}`,
14383
14590
  branch,
14384
14591
  repoRoot,
14385
14592
  installationId: resolvedInstallationId,
@@ -14393,7 +14600,7 @@ var BrainCreateCommand = class extends M8tCommand {
14393
14600
  this.context.stdout.write(
14394
14601
  renderJson({
14395
14602
  worker,
14396
- repo: `${owner}/${repoName}`,
14603
+ repo: `${owner}/${finalName}`,
14397
14604
  branch,
14398
14605
  installationId: resolvedInstallationId,
14399
14606
  connectionName: result.connectionName,
@@ -14403,10 +14610,10 @@ var BrainCreateCommand = class extends M8tCommand {
14403
14610
  return 0;
14404
14611
  }
14405
14612
  this.context.stdout.write(
14406
- `${colors.success("\u2713")} created + linked ${colors.field(worker)} \u2194 ${colors.field(`${owner}/${repoName}`)} (agent version ${result.foundryVersion ?? ""}).
14613
+ `${colors.success("\u2713")} created + linked ${colors.field(worker)} \u2194 ${colors.field(`${owner}/${finalName}`)} (agent version ${result.foundryVersion ?? ""}).
14407
14614
  `
14408
14615
  );
14409
- this.context.stdout.write(` ${colors.hint("brain repo:")} https://github.com/${owner}/${repoName}
14616
+ this.context.stdout.write(` ${colors.hint("brain repo:")} https://github.com/${owner}/${finalName}
14410
14617
  `);
14411
14618
  this.context.stdout.write(` ${colors.hint("token:")} rotates lazily on every invoke (60min TTL, 10min safety margin).
14412
14619
  `);
@@ -15007,7 +15214,7 @@ init_errors();
15007
15214
  // src/lib/deploy-prompt-advisor.ts
15008
15215
  import * as fs12 from "fs";
15009
15216
  import * as path11 from "path";
15010
- import { parse as parseYaml5 } from "yaml";
15217
+ import { parse as parseYaml6 } from "yaml";
15011
15218
  init_foundry_agents();
15012
15219
  init_errors();
15013
15220
  function findPersonasRoot(hint) {
@@ -15035,7 +15242,7 @@ async function deployPromptAdvisor(args) {
15035
15242
  });
15036
15243
  }
15037
15244
  const fmMatch = /^---\n([\s\S]*?)\n---/.exec(raw);
15038
- const fm = fmMatch ? parseYaml5(fmMatch[1]) : {};
15245
+ const fm = fmMatch ? parseYaml6(fmMatch[1]) : {};
15039
15246
  const model = args.model ?? fm.targets?.foundry?.model;
15040
15247
  if (!model) {
15041
15248
  throw new LocalCliError({
@@ -15302,7 +15509,7 @@ async function awaitAgentQueryable(args) {
15302
15509
  init_errors();
15303
15510
  init_esm();
15304
15511
  import * as fs13 from "fs";
15305
- import { parse as parseYaml6 } from "yaml";
15512
+ import { parse as parseYaml7 } from "yaml";
15306
15513
  function readPersonaA2aCard(personaPath) {
15307
15514
  let raw;
15308
15515
  try {
@@ -15312,7 +15519,7 @@ function readPersonaA2aCard(personaPath) {
15312
15519
  }
15313
15520
  const fm = /^---\n([\s\S]*?)\n---/.exec(raw);
15314
15521
  if (!fm) throw new LocalCliError({ code: "PERSONA_NO_FRONTMATTER", message: `Persona '${personaPath}' has no frontmatter.` });
15315
- const front = parseYaml6(fm[1]);
15522
+ const front = parseYaml7(fm[1]);
15316
15523
  const role = typeof front.role === "string" ? front.role : "";
15317
15524
  const cardYaml = front.targets?.foundry?.["a2a-card"];
15318
15525
  if (!cardYaml || typeof cardYaml !== "object") {
@@ -15798,7 +16005,7 @@ init_errors();
15798
16005
  import * as fs15 from "fs";
15799
16006
  import * as os6 from "os";
15800
16007
  import * as path12 from "path";
15801
- import { parse as parseYaml7 } from "yaml";
16008
+ import { parse as parseYaml8 } from "yaml";
15802
16009
  var A2A_PATH = "/api/a2a/mcp";
15803
16010
  function resolveBridgeUrl(opts) {
15804
16011
  const env = opts.env ?? process.env;
@@ -15822,7 +16029,7 @@ function readConfigGatewayUrl(home) {
15822
16029
  const cfg = path12.join(home ?? os6.homedir(), ".m8t-stack", "config.yaml");
15823
16030
  if (!fs15.existsSync(cfg)) return void 0;
15824
16031
  try {
15825
- const o = parseYaml7(fs15.readFileSync(cfg, "utf8"));
16032
+ const o = parseYaml8(fs15.readFileSync(cfg, "utf8"));
15826
16033
  return typeof o.gatewayUrl === "string" ? o.gatewayUrl : void 0;
15827
16034
  } catch {
15828
16035
  return void 0;
@@ -16324,7 +16531,7 @@ async function deployHostedWorker(args) {
16324
16531
  // src/lib/persona.ts
16325
16532
  import * as fs17 from "fs";
16326
16533
  import * as path15 from "path";
16327
- import { parse as parseYaml8 } from "yaml";
16534
+ import { parse as parseYaml9 } from "yaml";
16328
16535
  function findRepoRoot(startDir) {
16329
16536
  let dir = path15.resolve(startDir);
16330
16537
  for (; ; ) {
@@ -16348,7 +16555,7 @@ function resolvePersona(persona, cwd = process.cwd()) {
16348
16555
  if (!match) return { persona, personaVersion: null };
16349
16556
  let fm = null;
16350
16557
  try {
16351
- fm = parseYaml8(match[1]);
16558
+ fm = parseYaml9(match[1]);
16352
16559
  } catch {
16353
16560
  return { persona, personaVersion: null };
16354
16561
  }
@@ -17425,9 +17632,134 @@ var PlatformUpdateCommand = class extends M8tCommand {
17425
17632
  }
17426
17633
  };
17427
17634
 
17428
- // src/commands/deploy.ts
17635
+ // src/commands/platform/enable-cost-report.ts
17429
17636
  import { Command as Command33, Option as Option31 } from "clipanion";
17430
17637
 
17638
+ // src/lib/wire-gateway-acs.ts
17639
+ init_rbac();
17640
+ async function wireGatewayForAcs(args) {
17641
+ try {
17642
+ await args.az([
17643
+ "role",
17644
+ "assignment",
17645
+ "create",
17646
+ "--assignee-object-id",
17647
+ args.gatewayPrincipalId,
17648
+ "--assignee-principal-type",
17649
+ "ServicePrincipal",
17650
+ "--role",
17651
+ CONTRIBUTOR_ROLE_ID,
17652
+ "--scope",
17653
+ args.acsResourceId
17654
+ ]);
17655
+ } catch (e) {
17656
+ if (!(e instanceof Error && /RoleAssignmentExists/i.test(e.message))) throw e;
17657
+ }
17658
+ await args.az([
17659
+ "containerapp",
17660
+ "update",
17661
+ "-n",
17662
+ args.gatewayApp,
17663
+ "-g",
17664
+ args.resourceGroup,
17665
+ "--set-env-vars",
17666
+ `M8T_ACS_ENDPOINT=${args.endpoint}`,
17667
+ `M8T_ACS_SENDER=${args.sender}`,
17668
+ "M8T_ENABLE_COST_REPORTER=1"
17669
+ ]);
17670
+ }
17671
+
17672
+ // src/commands/platform/enable-cost-report.ts
17673
+ init_errors();
17674
+ var PlatformEnableCostReportCommand = class extends M8tCommand {
17675
+ static paths = [["platform", "enable-cost-report"]];
17676
+ static usage = Command33.Usage({
17677
+ description: "Wire the deployed gateway to send the bi-weekly cost report via ACS Email.",
17678
+ details: "Discovers the live gateway Container App, grants its managed identity Contributor at the ACS resource scope (authorising the ACS Email send), and sets M8T_ACS_ENDPOINT / M8T_ACS_SENDER / M8T_ENABLE_COST_REPORTER=1 on the gateway. Idempotent \u2014 safely re-runnable. ACS is created during the executor deploy; pass its endpoint, sender, and resource id (from that deploy or 'az communication list')."
17679
+ });
17680
+ subscription = Option31.String("--subscription");
17681
+ resourceGroup = Option31.String("--resource-group", {
17682
+ description: "m8t-stack resource group to disambiguate the gateway (multi-deployment subscriptions)."
17683
+ });
17684
+ acsEndpoint = Option31.String("--acs-endpoint", { required: true, description: "ACS data-plane endpoint, e.g. https://acs-<name>.communication.azure.com/" });
17685
+ acsSender = Option31.String("--acs-sender", { required: true, description: "Managed-domain sender address, e.g. DoNotReply@<guid>.azurecomm.net" });
17686
+ acsResourceId = Option31.String("--acs-resource-id", { required: true, description: "ARM resource id of the acs-<name> Communication Service \u2014 the role-grant scope." });
17687
+ output = Option31.String("--output");
17688
+ async executeCommand() {
17689
+ const mode = resolveOutputMode(
17690
+ this.output,
17691
+ this.context.stdout
17692
+ );
17693
+ const log = (msg) => {
17694
+ if (mode !== "json") this.context.stdout.write(msg + "\n");
17695
+ };
17696
+ const ctx = await resolveGatewayContext({
17697
+ interactive: mode !== "json",
17698
+ subscriptionId: this.subscription,
17699
+ resourceGroup: this.resourceGroup
17700
+ });
17701
+ const { resourceGroup, name } = parseContainerAppResourceId(ctx.containerAppResourceId);
17702
+ const gatewayPrincipalId = (await runAz([
17703
+ "containerapp",
17704
+ "show",
17705
+ "-n",
17706
+ name,
17707
+ "-g",
17708
+ resourceGroup,
17709
+ "--query",
17710
+ "identity.principalId",
17711
+ "-o",
17712
+ "tsv"
17713
+ ])).trim();
17714
+ if (gatewayPrincipalId === "") {
17715
+ throw new LocalCliError({
17716
+ code: "GATEWAY_NO_MANAGED_IDENTITY",
17717
+ message: `Gateway '${name}' has no managed identity principalId to grant.`,
17718
+ hint: "Assign a system-assigned identity to the gateway Container App, then re-run."
17719
+ });
17720
+ }
17721
+ await wireGatewayForAcs({
17722
+ az: runAz,
17723
+ resourceGroup,
17724
+ acsResourceId: this.acsResourceId,
17725
+ gatewayApp: name,
17726
+ endpoint: this.acsEndpoint,
17727
+ sender: this.acsSender,
17728
+ gatewayPrincipalId
17729
+ });
17730
+ if (mode === "json") {
17731
+ this.context.stdout.write(
17732
+ renderJson({
17733
+ gateway: name,
17734
+ resourceGroup,
17735
+ roleGranted: "Contributor",
17736
+ scope: this.acsResourceId,
17737
+ envSet: {
17738
+ M8T_ACS_ENDPOINT: this.acsEndpoint,
17739
+ M8T_ACS_SENDER: this.acsSender,
17740
+ M8T_ENABLE_COST_REPORTER: "1"
17741
+ }
17742
+ }) + "\n"
17743
+ );
17744
+ return 0;
17745
+ }
17746
+ this.context.stdout.write(
17747
+ renderKeyValueBlock([
17748
+ { key: "gateway", value: name },
17749
+ { key: "role granted", value: `Contributor @ ${this.acsResourceId}` },
17750
+ { key: "M8T_ACS_ENDPOINT", value: this.acsEndpoint },
17751
+ { key: "M8T_ACS_SENDER", value: this.acsSender },
17752
+ { key: "M8T_ENABLE_COST_REPORTER", value: "1" }
17753
+ ]) + "\n"
17754
+ );
17755
+ log(colors.success("cost report enabled \u2014 the gateway will send it via ACS \u2713"));
17756
+ return 0;
17757
+ }
17758
+ };
17759
+
17760
+ // src/commands/deploy.ts
17761
+ import { Command as Command34, Option as Option32 } from "clipanion";
17762
+
17431
17763
  // src/lib/app-reg.ts
17432
17764
  init_errors();
17433
17765
  var APP_NAME = "m8t-stack-webapp";
@@ -17960,24 +18292,24 @@ function classifyWhatIf(changes) {
17960
18292
  var DEFAULT_IMAGE_REF = "ghcr.io/m8t-run/m8t:latest";
17961
18293
  var DeployCommand = class extends M8tCommand {
17962
18294
  static paths = [["deploy"]];
17963
- static usage = Command33.Usage({
18295
+ static usage = Command34.Usage({
17964
18296
  description: "Deploy (or update) the m8t gateway/webapp stack via Bicep.",
17965
18297
  details: "Ensures the Entra app reg (or pass --client-id to reuse an existing one \u2014 required if you can't create app regs), writes ~/.m8t-stack/config.yaml, ensures the resource group, and runs deploy/main.bicep. The repo is located via ~/.m8t-stack/repo-root."
17966
18298
  });
17967
- subscription = Option31.String("--subscription");
17968
- resourceGroup = Option31.String("--resource-group", "rg-m8t-stack");
17969
- location = Option31.String("--location", "eastus");
17970
- suffix = Option31.String("--suffix", "");
17971
- imageRef = Option31.String("--image-ref", DEFAULT_IMAGE_REF);
17972
- acrPullIdentity = Option31.String("--acrpull-identity");
17973
- acrResourceId = Option31.String("--acr-resource-id");
17974
- foundryEndpoint = Option31.String("--foundry-endpoint");
17975
- foundryResourceId = Option31.String("--foundry-resource-id");
17976
- foundryTracing = Option31.String("--foundry-tracing");
18299
+ subscription = Option32.String("--subscription");
18300
+ resourceGroup = Option32.String("--resource-group", "rg-m8t-stack");
18301
+ location = Option32.String("--location", "eastus");
18302
+ suffix = Option32.String("--suffix", "");
18303
+ imageRef = Option32.String("--image-ref", DEFAULT_IMAGE_REF);
18304
+ acrPullIdentity = Option32.String("--acrpull-identity");
18305
+ acrResourceId = Option32.String("--acr-resource-id");
18306
+ foundryEndpoint = Option32.String("--foundry-endpoint");
18307
+ foundryResourceId = Option32.String("--foundry-resource-id");
18308
+ foundryTracing = Option32.String("--foundry-tracing");
17977
18309
  // project | account | skip (bicep default: project)
17978
- clientId = Option31.String("--client-id");
17979
- whatIf = Option31.Boolean("--what-if", false);
17980
- output = Option31.String("--output");
18310
+ clientId = Option32.String("--client-id");
18311
+ whatIf = Option32.Boolean("--what-if", false);
18312
+ output = Option32.String("--output");
17981
18313
  async executeCommand() {
17982
18314
  const mode = resolveOutputMode(
17983
18315
  this.output,
@@ -18091,7 +18423,7 @@ var DeployCommand = class extends M8tCommand {
18091
18423
 
18092
18424
  // src/commands/eval/skill.ts
18093
18425
  import { spawnSync as spawnSync3 } from "child_process";
18094
- import { Command as Command34, Option as Option32 } from "clipanion";
18426
+ import { Command as Command35, Option as Option33 } from "clipanion";
18095
18427
  init_errors();
18096
18428
  var DECISIONS = /* @__PURE__ */ new Set(["promote", "reject", "needs_review"]);
18097
18429
  var JUDGE_STATUSES = /* @__PURE__ */ new Set(["ok", "skipped", "unavailable"]);
@@ -18116,21 +18448,21 @@ function parseVerdict(stdout) {
18116
18448
  }
18117
18449
  var EvalSkillCommand = class extends M8tCommand {
18118
18450
  static paths = [["eval", "skill"]];
18119
- static usage = Command34.Usage({
18451
+ static usage = Command35.Usage({
18120
18452
  description: "Vet one inbox skill candidate (Brain Faculties Eval F1): promote / reject / needs_review. Shells out to the Python `brain-eval` core (override its path with $BRAIN_EVAL_BIN)."
18121
18453
  });
18122
- candidate = Option32.String();
18123
- skillsDir = Option32.String("--skills-dir");
18124
- noJudge = Option32.Boolean("--no-judge", false);
18125
- deployment = Option32.String("--deployment");
18126
- output = Option32.String("--output");
18454
+ candidate = Option33.String();
18455
+ skillsDir = Option33.String("--skills-dir");
18456
+ noJudge = Option33.Boolean("--no-judge", false);
18457
+ deployment = Option33.String("--deployment");
18458
+ output = Option33.String("--output");
18127
18459
  executeCommand() {
18128
18460
  return Promise.resolve(this._runCommand());
18129
18461
  }
18130
18462
  _runCommand() {
18131
- const candidate = typeof this.candidate === "string" ? this.candidate : void 0;
18463
+ const candidate2 = typeof this.candidate === "string" ? this.candidate : void 0;
18132
18464
  const skillsDir = typeof this.skillsDir === "string" ? this.skillsDir : void 0;
18133
- if (!candidate) {
18465
+ if (!candidate2) {
18134
18466
  throw new LocalCliError({ code: "USAGE", message: "<path> positional argument is required" });
18135
18467
  }
18136
18468
  if (!skillsDir) {
@@ -18139,7 +18471,7 @@ var EvalSkillCommand = class extends M8tCommand {
18139
18471
  const outputFlag = this.output === "json" || this.output === "auto" || this.output === "pretty" ? this.output : "pretty";
18140
18472
  const mode = resolveOutputMode(outputFlag, this.context.stdout);
18141
18473
  const bin = process.env.BRAIN_EVAL_BIN ?? "brain-eval";
18142
- const args = ["skill", candidate, "--skills-dir", skillsDir, "--json"];
18474
+ const args = ["skill", candidate2, "--skills-dir", skillsDir, "--json"];
18143
18475
  if (this.noJudge === true) args.push("--no-judge");
18144
18476
  if (typeof this.deployment === "string") args.push("--deployment", this.deployment);
18145
18477
  const res = spawnSync3(bin, args, { encoding: "utf-8" });
@@ -18182,7 +18514,7 @@ var EvalSkillCommand = class extends M8tCommand {
18182
18514
  import { spawnSync as spawnSync4 } from "child_process";
18183
18515
  import { writeFileSync as writeFileSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync13, existsSync as existsSync12, readdirSync } from "fs";
18184
18516
  import { join as join19 } from "path";
18185
- import { Command as Command35, Option as Option33 } from "clipanion";
18517
+ import { Command as Command36, Option as Option34 } from "clipanion";
18186
18518
  init_errors();
18187
18519
  init_esm();
18188
18520
  function parseArmToken(tok, opts) {
@@ -18396,23 +18728,23 @@ function buildPlan(args) {
18396
18728
  }
18397
18729
  var EvalExamCommand = class extends M8tCommand {
18398
18730
  static paths = [["eval", "exam"]];
18399
- static usage = Command35.Usage({
18731
+ static usage = Command36.Usage({
18400
18732
  description: "Run a brain exam (Brain Referee E2-F2): impact A/B + dream-delta. Resolves the plan, then shells out to the Python `brain-exam` orchestrator (override its path with $BRAIN_EXAM_BIN). Renders an ExamVerdict: three-valued verdict + power note + per-task flips."
18401
18733
  });
18402
- worker = Option33.String();
18403
- arms = Option33.String("--arms");
18404
- taskSet = Option33.String("--task-set");
18405
- examType = Option33.String("--exam-type");
18406
- reps = Option33.String("-n,--reps");
18407
- probes = Option33.String("--probes");
18408
- pool = Option33.String("--pool");
18409
- out = Option33.String("--out");
18410
- dryRun = Option33.Boolean("--dry-run", false);
18411
- keepArms = Option33.Boolean("--keep-arms", false);
18412
- allowStub = Option33.Boolean("--allow-stub", false);
18413
- deployment = Option33.String("--deployment");
18414
- output = Option33.String("--output");
18415
- observeWaitS = Option33.String("--observe-wait-s");
18734
+ worker = Option34.String();
18735
+ arms = Option34.String("--arms");
18736
+ taskSet = Option34.String("--task-set");
18737
+ examType = Option34.String("--exam-type");
18738
+ reps = Option34.String("-n,--reps");
18739
+ probes = Option34.String("--probes");
18740
+ pool = Option34.String("--pool");
18741
+ out = Option34.String("--out");
18742
+ dryRun = Option34.Boolean("--dry-run", false);
18743
+ keepArms = Option34.Boolean("--keep-arms", false);
18744
+ allowStub = Option34.Boolean("--allow-stub", false);
18745
+ deployment = Option34.String("--deployment");
18746
+ output = Option34.String("--output");
18747
+ observeWaitS = Option34.String("--observe-wait-s");
18416
18748
  async executeCommand() {
18417
18749
  await Promise.resolve();
18418
18750
  const worker = typeof this.worker === "string" ? this.worker : void 0;
@@ -18526,10 +18858,10 @@ var EvalExamCommand = class extends M8tCommand {
18526
18858
  };
18527
18859
 
18528
18860
  // src/commands/version.ts
18529
- import { Command as Command36, Option as Option34 } from "clipanion";
18861
+ import { Command as Command37, Option as Option35 } from "clipanion";
18530
18862
  var VersionCommand = class extends M8tCommand {
18531
18863
  static paths = [["version"], ["--version"], ["-v"]];
18532
- static usage = Command36.Usage({
18864
+ static usage = Command37.Usage({
18533
18865
  description: "Print the CLI version.",
18534
18866
  details: "Prints the m8t CLI version. With --verbose, also prints Node version and platform.",
18535
18867
  examples: [
@@ -18537,8 +18869,8 @@ var VersionCommand = class extends M8tCommand {
18537
18869
  ["Print as JSON", "$0 version --output json"]
18538
18870
  ]
18539
18871
  });
18540
- output = Option34.String("--output", { description: "pretty | json | auto (default)" });
18541
- verbose = Option34.Boolean("--verbose", false);
18872
+ output = Option35.String("--output", { description: "pretty | json | auto (default)" });
18873
+ verbose = Option35.Boolean("--verbose", false);
18542
18874
  executeCommand() {
18543
18875
  const mode = resolveOutputMode(
18544
18876
  this.output ?? "auto",
@@ -18569,18 +18901,18 @@ var VersionCommand = class extends M8tCommand {
18569
18901
  };
18570
18902
 
18571
18903
  // src/commands/whoami.ts
18572
- import { Command as Command37, Option as Option35 } from "clipanion";
18904
+ import { Command as Command38, Option as Option36 } from "clipanion";
18573
18905
  var WhoamiCommand = class extends M8tCommand {
18574
18906
  static paths = [["whoami"]];
18575
- static usage = Command37.Usage({
18907
+ static usage = Command38.Usage({
18576
18908
  description: "Show your identity + the gateway you'll talk to. Probes the backend."
18577
18909
  });
18578
- output = Option35.String("--output");
18579
- verbose = Option35.Boolean("--verbose", false);
18580
- subscription = Option35.String("--subscription", {
18910
+ output = Option36.String("--output");
18911
+ verbose = Option36.Boolean("--verbose", false);
18912
+ subscription = Option36.String("--subscription", {
18581
18913
  description: "Azure subscription ID to discover gateway in (defaults to active az subscription)."
18582
18914
  });
18583
- resourceGroup = Option35.String("--resource-group", {
18915
+ resourceGroup = Option36.String("--resource-group", {
18584
18916
  description: "m8t-stack resource group to disambiguate the gateway (multi-deployment subscriptions)."
18585
18917
  });
18586
18918
  async executeCommand() {
@@ -18645,7 +18977,7 @@ var WhoamiCommand = class extends M8tCommand {
18645
18977
  };
18646
18978
 
18647
18979
  // src/commands/status.ts
18648
- import { Command as Command38, Option as Option36 } from "clipanion";
18980
+ import { Command as Command39, Option as Option37 } from "clipanion";
18649
18981
 
18650
18982
  // src/lib/azd.ts
18651
18983
  init_errors();
@@ -18710,10 +19042,10 @@ async function resolveLocalContext() {
18710
19042
  // src/commands/status.ts
18711
19043
  var StatusCommand = class extends M8tCommand {
18712
19044
  static paths = [["status"]];
18713
- static usage = Command38.Usage({
19045
+ static usage = Command39.Usage({
18714
19046
  description: "Show the local m8t context: identity, config.yaml, gateway cache, azd mode."
18715
19047
  });
18716
- output = Option36.String("--output");
19048
+ output = Option37.String("--output");
18717
19049
  async executeCommand() {
18718
19050
  const mode = resolveOutputMode(
18719
19051
  this.output,
@@ -18751,7 +19083,7 @@ var StatusCommand = class extends M8tCommand {
18751
19083
  };
18752
19084
 
18753
19085
  // src/commands/doctor.ts
18754
- import { Command as Command39, Option as Option37 } from "clipanion";
19086
+ import { Command as Command40, Option as Option38 } from "clipanion";
18755
19087
  import { DefaultAzureCredential as DefaultAzureCredential16 } from "@azure/identity";
18756
19088
  import * as fs19 from "fs";
18757
19089
  import * as os9 from "os";
@@ -19002,12 +19334,12 @@ function probeRepoRoot() {
19002
19334
  }
19003
19335
  var DoctorCommand = class extends M8tCommand {
19004
19336
  static paths = [["doctor"]];
19005
- static usage = Command39.Usage({
19337
+ static usage = Command40.Usage({
19006
19338
  description: "Diagnose the local m8t setup: az login, config.yaml, gateway, Foundry data-plane."
19007
19339
  });
19008
- output = Option37.String("--output");
19009
- agent = Option37.String("--agent");
19010
- resourceGroup = Option37.String("--resource-group", {
19340
+ output = Option38.String("--output");
19341
+ agent = Option38.String("--agent");
19342
+ resourceGroup = Option38.String("--resource-group", {
19011
19343
  description: "m8t-stack resource group to disambiguate the gateway (multi-deployment subscriptions)."
19012
19344
  });
19013
19345
  async executeCommand() {
@@ -19123,12 +19455,12 @@ var DoctorCommand = class extends M8tCommand {
19123
19455
  };
19124
19456
 
19125
19457
  // src/commands/switch.ts
19126
- import { Command as Command40, Option as Option38 } from "clipanion";
19458
+ import { Command as Command41, Option as Option39 } from "clipanion";
19127
19459
 
19128
19460
  // src/lib/profiles.ts
19129
19461
  import * as fs20 from "fs/promises";
19130
19462
  import * as path21 from "path";
19131
- import { parse as parseYaml9, stringify as stringifyYaml4 } from "yaml";
19463
+ import { parse as parseYaml10, stringify as stringifyYaml4 } from "yaml";
19132
19464
  function profilesDir() {
19133
19465
  const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
19134
19466
  return path21.join(home, ".m8t-stack", "profiles");
@@ -19153,7 +19485,7 @@ async function listProfiles() {
19153
19485
  async function readProfile(name) {
19154
19486
  try {
19155
19487
  const raw = await fs20.readFile(getProfilePath(name), "utf8");
19156
- const parsed = parseYaml9(raw);
19488
+ const parsed = parseYaml10(raw);
19157
19489
  if (!parsed || typeof parsed !== "object") return null;
19158
19490
  return parsed;
19159
19491
  } catch (e) {
@@ -19263,14 +19595,14 @@ async function profileSwitch(name, asName) {
19263
19595
  init_errors();
19264
19596
  var SwitchCommand = class extends M8tCommand {
19265
19597
  static paths = [["switch"]];
19266
- static usage = Command40.Usage({
19598
+ static usage = Command41.Usage({
19267
19599
  description: "Re-point local config at another deployment: --subscription <id|name> (discovery) or <profile>."
19268
19600
  });
19269
- profile = Option38.String({ required: false });
19270
- subscription = Option38.String("--subscription");
19271
- list = Option38.Boolean("--list", false);
19272
- as = Option38.String("--as");
19273
- output = Option38.String("--output");
19601
+ profile = Option39.String({ required: false });
19602
+ subscription = Option39.String("--subscription");
19603
+ list = Option39.Boolean("--list", false);
19604
+ as = Option39.String("--as");
19605
+ output = Option39.String("--output");
19274
19606
  async executeCommand() {
19275
19607
  const mode = resolveOutputMode(
19276
19608
  this.output,
@@ -19327,7 +19659,7 @@ var SwitchCommand = class extends M8tCommand {
19327
19659
 
19328
19660
  // src/commands/open.ts
19329
19661
  import { spawn as spawn5 } from "child_process";
19330
- import { Command as Command41, Option as Option39 } from "clipanion";
19662
+ import { Command as Command42, Option as Option40 } from "clipanion";
19331
19663
 
19332
19664
  // src/lib/open-targets.ts
19333
19665
  init_errors();
@@ -19373,14 +19705,14 @@ function openUrl(url) {
19373
19705
  }
19374
19706
  var OpenCommand = class extends M8tCommand {
19375
19707
  static paths = [["open"]];
19376
- static usage = Command41.Usage({
19708
+ static usage = Command42.Usage({
19377
19709
  description: "Open the deployed webapp (default), the Foundry portal, or the resource group.",
19378
19710
  details: "Targets: webapp (deployed app, default) | foundry (ai.azure.com) | portal (resource group in the Azure portal). Pass --print to emit the URL instead of launching a browser (also the default when stdout isn't a TTY)."
19379
19711
  });
19380
- target = Option39.String({ required: false });
19381
- print = Option39.Boolean("--print", false);
19382
- output = Option39.String("--output");
19383
- resourceGroup = Option39.String("--resource-group", {
19712
+ target = Option40.String({ required: false });
19713
+ print = Option40.Boolean("--print", false);
19714
+ output = Option40.String("--output");
19715
+ resourceGroup = Option40.String("--resource-group", {
19384
19716
  description: "m8t-stack resource group to disambiguate the gateway (multi-deployment subscriptions)."
19385
19717
  });
19386
19718
  async executeCommand() {
@@ -19424,7 +19756,7 @@ var OpenCommand = class extends M8tCommand {
19424
19756
  };
19425
19757
 
19426
19758
  // src/commands/dream/run.ts
19427
- import { Command as Command42, Option as Option40 } from "clipanion";
19759
+ import { Command as Command43, Option as Option41 } from "clipanion";
19428
19760
  import { AzureCliCredential } from "@azure/identity";
19429
19761
  import { TableClient as TableClient2 } from "@azure/data-tables";
19430
19762
  import { AIProjectClient as AIProjectClient3 } from "@azure/ai-projects";
@@ -20323,16 +20655,16 @@ function buildAdvancePlan(worker, cursor, physicalPks, consumedRowsByPk, failedT
20323
20655
  for (const pk of physicalPks) {
20324
20656
  const rowsForPk = consumedRowsByPk[pk] ?? [];
20325
20657
  const { ts, consumedRowKeys } = computeWatermark(rowsForPk, now.toISOString(), safetyLagSeconds);
20326
- let candidate = ts;
20658
+ let candidate2 = ts;
20327
20659
  const prior = Object.hasOwn(cursor.watermarks, pk) ? cursor.watermarks[pk].ts : void 0;
20328
20660
  if (prior)
20329
20661
  priorTsByPk[pk] = prior;
20330
- if (prior && candidate < prior)
20331
- candidate = prior;
20662
+ if (prior && candidate2 < prior)
20663
+ candidate2 = prior;
20332
20664
  const failed = failedTsByPk[pk];
20333
- if (failed && candidate >= failed)
20334
- candidate = justBefore(failed);
20335
- watermarks[pk] = { ts: candidate, consumedRowKeys };
20665
+ if (failed && candidate2 >= failed)
20666
+ candidate2 = justBefore(failed);
20667
+ watermarks[pk] = { ts: candidate2, consumedRowKeys };
20336
20668
  consumedKeysByPk[pk] = consumedRowKeys;
20337
20669
  }
20338
20670
  return {
@@ -20726,12 +21058,12 @@ function validateDelta(d) {
20726
21058
  }
20727
21059
  function extractJson(text) {
20728
21060
  const fenced = /```(?:json)?\s*([\s\S]*?)```/.exec(text);
20729
- const candidate = (fenced ? fenced[1] : text).trim();
20730
- const start = candidate.indexOf("{");
20731
- const end = candidate.lastIndexOf("}");
21061
+ const candidate2 = (fenced ? fenced[1] : text).trim();
21062
+ const start = candidate2.indexOf("{");
21063
+ const end = candidate2.lastIndexOf("}");
20732
21064
  if (start === -1 || end === -1 || end < start)
20733
21065
  throw new Error("no JSON object found");
20734
- return JSON.parse(candidate.slice(start, end + 1));
21066
+ return JSON.parse(candidate2.slice(start, end + 1));
20735
21067
  }
20736
21068
  async function propose(model, system, user, opts = {}) {
20737
21069
  const sleep2 = opts.sleep ?? defaultSleep2;
@@ -21311,14 +21643,14 @@ function narrowAdvance(src, kept) {
21311
21643
  for (const pk of Object.keys(src.watermarks)) {
21312
21644
  const rows = keptRowsByPk[pk] ?? [];
21313
21645
  const { ts, consumedRowKeys } = computeWatermark(rows, now, safetyLagSeconds);
21314
- let candidate = ts;
21646
+ let candidate2 = ts;
21315
21647
  const prior = priorTsByPk[pk];
21316
- if (prior && candidate < prior)
21317
- candidate = prior;
21648
+ if (prior && candidate2 < prior)
21649
+ candidate2 = prior;
21318
21650
  const failed = src.failedTsByPk[pk];
21319
- if (failed && candidate >= failed)
21320
- candidate = justBefore(failed);
21321
- watermarks[pk] = { ts: candidate, consumedRowKeys };
21651
+ if (failed && candidate2 >= failed)
21652
+ candidate2 = justBefore(failed);
21653
+ watermarks[pk] = { ts: candidate2, consumedRowKeys };
21322
21654
  consumedRowsByPk[pk] = consumedRowKeys;
21323
21655
  }
21324
21656
  return {
@@ -21420,7 +21752,7 @@ async function emitDigest(input, deps, digest) {
21420
21752
  }
21421
21753
 
21422
21754
  // ../../packages/brain/engine/dist/esm/dream/config.js
21423
- import { parse as parseYaml10 } from "yaml";
21755
+ import { parse as parseYaml11 } from "yaml";
21424
21756
  var DEFAULT_DREAM_MODEL = "gpt-5.4";
21425
21757
  function asCadence(v) {
21426
21758
  return v === "nightly" ? "nightly" : "off";
@@ -21428,7 +21760,7 @@ function asCadence(v) {
21428
21760
  function parseDreamerConfig(rawYaml, env) {
21429
21761
  let parsed;
21430
21762
  try {
21431
- parsed = parseYaml10(rawYaml);
21763
+ parsed = parseYaml11(rawYaml);
21432
21764
  } catch {
21433
21765
  return { enabled: false, cadence: "off", model: env.M8T_DREAM_MODEL ?? DEFAULT_DREAM_MODEL };
21434
21766
  }
@@ -21441,14 +21773,17 @@ function parseDreamerConfig(rawYaml, env) {
21441
21773
  };
21442
21774
  }
21443
21775
 
21776
+ // ../../packages/brain/engine/dist/esm/cost-report/config.js
21777
+ import { parse as parseYaml12 } from "yaml";
21778
+
21444
21779
  // ../../packages/brain/engine/dist/esm/librarian/codify/persistence-guard.js
21445
21780
  var ZERO_WIDTH_RE = new RegExp("\u200B|\u200C|\u200D|\uFEFF", "g");
21446
21781
 
21447
21782
  // ../../packages/brain/engine/dist/esm/librarian/janitor/frontmatter.js
21448
- import { parse as parseYaml11, stringify as stringifyYaml5 } from "yaml";
21783
+ import { parse as parseYaml13, stringify as stringifyYaml5 } from "yaml";
21449
21784
 
21450
21785
  // ../../packages/brain/engine/dist/esm/librarian/config.js
21451
- import { parse as parseYaml12 } from "yaml";
21786
+ import { parse as parseYaml14 } from "yaml";
21452
21787
 
21453
21788
  // src/lib/dream-discovery.ts
21454
21789
  init_http();
@@ -21565,20 +21900,20 @@ function redactTranscripts(input) {
21565
21900
  }
21566
21901
  var DreamRunCommand = class extends M8tCommand {
21567
21902
  static paths = [["dream", "run"]];
21568
- static usage = Command42.Usage({
21903
+ static usage = Command43.Usage({
21569
21904
  description: "Dry-run the brain consumption pipeline for one worker (no model call, no writes).",
21570
21905
  details: "Builds AzureCliCredential + resolves the Foundry project, ledger table, and Log Analytics workspace, runs the consumption pipeline, and prints the skip-ledger, the partition invariant, and harvest stats. Transcripts are metadata-only unless --show-transcripts is passed."
21571
21906
  });
21572
- worker = Option40.String("--worker", { description: "Worker (canonical name) to harvest. Required." });
21573
- dryRun = Option40.Boolean("--dry-run", false, { description: "Read-only harvest; no model call, no writes." });
21574
- since = Option40.String("--since", { description: "ISO-8601 start override (rejected if malformed or future)." });
21575
- reset = Option40.Boolean("--reset", false, { description: "Ignore the stored cursor; read from the beginning." });
21576
- showTranscripts = Option40.Boolean("--show-transcripts", false, {
21907
+ worker = Option41.String("--worker", { description: "Worker (canonical name) to harvest. Required." });
21908
+ dryRun = Option41.Boolean("--dry-run", false, { description: "Read-only harvest; no model call, no writes." });
21909
+ since = Option41.String("--since", { description: "ISO-8601 start override (rejected if malformed or future)." });
21910
+ reset = Option41.Boolean("--reset", false, { description: "Ignore the stored cursor; read from the beginning." });
21911
+ showTranscripts = Option41.Boolean("--show-transcripts", false, {
21577
21912
  description: "Print transcript bodies (default: metadata only)."
21578
21913
  });
21579
- subscription = Option40.String("--subscription");
21580
- endpoint = Option40.String("--endpoint");
21581
- output = Option40.String("--output");
21914
+ subscription = Option41.String("--subscription");
21915
+ endpoint = Option41.String("--endpoint");
21916
+ output = Option41.String("--output");
21582
21917
  // Resolution seam — overridden by tests; built lazily at runtime otherwise.
21583
21918
  deps;
21584
21919
  async executeCommand() {
@@ -21926,7 +22261,7 @@ function defaultDeps(overrides) {
21926
22261
  }
21927
22262
 
21928
22263
  // src/commands/foundry/create.ts
21929
- import { Command as Command43, Option as Option41 } from "clipanion";
22264
+ import { Command as Command44, Option as Option42 } from "clipanion";
21930
22265
 
21931
22266
  // src/lib/foundry-create.ts
21932
22267
  init_errors();
@@ -22164,7 +22499,7 @@ async function createFoundryProject(args) {
22164
22499
  init_errors();
22165
22500
  var FoundryCreateCommand = class extends M8tCommand {
22166
22501
  static paths = [["foundry", "create"]];
22167
- static usage = Command43.Usage({
22502
+ static usage = Command44.Usage({
22168
22503
  description: "Create an AI Foundry (AIServices) account + project + model deployment from scratch.",
22169
22504
  details: "Non-interactive and idempotent. Creates the AIServices account (custom subdomain + project management), a project, and a model deployment (default gpt-4.1-mini @ capacity 50). Region must be hosted-agent-eligible. Emits the project endpoint as structured output. Re-run is a clean no-op (account/project skipped if present; deployment capacity converges UP, never down).",
22170
22505
  examples: [
@@ -22173,16 +22508,16 @@ var FoundryCreateCommand = class extends M8tCommand {
22173
22508
  ["Higher capacity for a reasoning model", "$0 foundry create --resource-group rg-m8t-stack --location eastus2 --model gpt-5-mini --capacity 250"]
22174
22509
  ]
22175
22510
  });
22176
- resourceGroup = Option41.String("--resource-group");
22177
- location = Option41.String("--location");
22178
- account = Option41.String("--account");
22179
- project = Option41.String("--project", "m8t");
22180
- model = Option41.String("--model", "gpt-4.1-mini");
22181
- modelVersion = Option41.String("--model-version", "2025-04-14");
22182
- capacity = Option41.String("--capacity", "50");
22183
- subscription = Option41.String("--subscription");
22184
- skipQuotaCheck = Option41.Boolean("--skip-quota-check", false);
22185
- output = Option41.String("--output");
22511
+ resourceGroup = Option42.String("--resource-group");
22512
+ location = Option42.String("--location");
22513
+ account = Option42.String("--account");
22514
+ project = Option42.String("--project", "m8t");
22515
+ model = Option42.String("--model", "gpt-4.1-mini");
22516
+ modelVersion = Option42.String("--model-version", "2025-04-14");
22517
+ capacity = Option42.String("--capacity", "50");
22518
+ subscription = Option42.String("--subscription");
22519
+ skipQuotaCheck = Option42.Boolean("--skip-quota-check", false);
22520
+ output = Option42.String("--output");
22186
22521
  async executeCommand() {
22187
22522
  const mode = resolveOutputMode(
22188
22523
  this.output,
@@ -22254,22 +22589,22 @@ var FoundryCreateCommand = class extends M8tCommand {
22254
22589
  };
22255
22590
 
22256
22591
  // src/commands/foundry/await-ready.ts
22257
- import { Command as Command44, Option as Option42 } from "clipanion";
22592
+ import { Command as Command45, Option as Option43 } from "clipanion";
22258
22593
  import { AzureCliCredential as AzureCliCredential2 } from "@azure/identity";
22259
22594
  init_errors();
22260
22595
  var FoundryAwaitReadyCommand = class extends M8tCommand {
22261
22596
  static paths = [["foundry", "await-ready"]];
22262
- static usage = Command44.Usage({
22597
+ static usage = Command45.Usage({
22263
22598
  description: "Wait until a freshly-created Foundry project's data plane reliably serves it.",
22264
22599
  details: "Probes the project (GET /agents) until it returns 200 on a few consecutive tries, or fails clearly after a bounded budget. A newly-created account can serve intermittent 404 'Project not found' for minutes; run this after 'foundry create' and before deploying agents so the worker phase doesn't catch the unstable window.",
22265
22600
  examples: [["Wait for a project to be ready", "$0 foundry await-ready --endpoint https://acc.services.ai.azure.com/api/projects/m8t"]]
22266
22601
  });
22267
- endpoint = Option42.String("--endpoint");
22268
- consecutive = Option42.String("--consecutive", "3");
22269
- attempts = Option42.String("--attempts", "60");
22270
- interval = Option42.String("--interval", "5");
22271
- subscription = Option42.String("--subscription");
22272
- output = Option42.String("--output");
22602
+ endpoint = Option43.String("--endpoint");
22603
+ consecutive = Option43.String("--consecutive", "3");
22604
+ attempts = Option43.String("--attempts", "60");
22605
+ interval = Option43.String("--interval", "5");
22606
+ subscription = Option43.String("--subscription");
22607
+ output = Option43.String("--output");
22273
22608
  async executeCommand() {
22274
22609
  const mode = resolveOutputMode(this.output, this.context.stdout);
22275
22610
  const endpoint = typeof this.endpoint === "string" ? this.endpoint : void 0;
@@ -22303,7 +22638,7 @@ var FoundryAwaitReadyCommand = class extends M8tCommand {
22303
22638
  };
22304
22639
 
22305
22640
  // src/commands/bootstrap/preflight.ts
22306
- import { Command as Command45, Option as Option43 } from "clipanion";
22641
+ import { Command as Command46, Option as Option44 } from "clipanion";
22307
22642
  init_errors();
22308
22643
 
22309
22644
  // src/lib/bootstrap-preflight.ts
@@ -22377,7 +22712,7 @@ function buildPreflightBanner(who) {
22377
22712
  // src/commands/bootstrap/preflight.ts
22378
22713
  var BootstrapPreflightCommand = class extends M8tCommand {
22379
22714
  static paths = [["bootstrap", "preflight"]];
22380
- static usage = Command45.Usage({
22715
+ static usage = Command46.Usage({
22381
22716
  description: "Loudly verify you can install m8t-stack (Owner/UAA + directory admin) and hard-stop if not.",
22382
22717
  details: "Step 1 of `m8t bootstrap`. Prints an unmissable admin-credentials notice, then checks: Owner or User Access Administrator at subscription scope (hard requirement), directory-admin capability to register the app (or pass --client-id), and registers Microsoft.ContainerInstance. Exits non-zero with the exact failing check + remedy.",
22383
22718
  examples: [
@@ -22385,8 +22720,8 @@ var BootstrapPreflightCommand = class extends M8tCommand {
22385
22720
  ["BYO app registration (directory guests)", "$0 bootstrap preflight --client-id <appId>"]
22386
22721
  ]
22387
22722
  });
22388
- clientId = Option43.String("--client-id");
22389
- subscription = Option43.String("--subscription");
22723
+ clientId = Option44.String("--client-id");
22724
+ subscription = Option44.String("--subscription");
22390
22725
  async executeCommand() {
22391
22726
  const clientId = typeof this.clientId === "string" ? this.clientId : void 0;
22392
22727
  const account = await getAzAccount();
@@ -22445,7 +22780,7 @@ ${colors.error(" " + why)}
22445
22780
  import * as fs23 from "fs";
22446
22781
  import * as os12 from "os";
22447
22782
  import * as path24 from "path";
22448
- import { Command as Command46, Option as Option44 } from "clipanion";
22783
+ import { Command as Command47, Option as Option45 } from "clipanion";
22449
22784
  init_errors();
22450
22785
 
22451
22786
  // src/lib/bootstrap-mi.ts
@@ -22698,7 +23033,7 @@ var ACI_NAME = "m8t-installer";
22698
23033
  var MI_NAME = "m8t-installer-mi";
22699
23034
  var BootstrapLaunchCommand = class extends M8tCommand {
22700
23035
  static paths = [["bootstrap", "launch"]];
22701
- static usage = Command46.Usage({
23036
+ static usage = Command47.Usage({
22702
23037
  description: "Create + authorize the installer managed identity, then kick the cloud installer.",
22703
23038
  details: "Step 2 of `m8t bootstrap` (run after `preflight`). Ensures the resource group, creates the m8t-stack app registration (or uses --client-id), creates a user-assigned managed identity granted Owner at subscription scope, and launches the published m8t-installer image as an ACI run-to-completion job under that identity. Writes ~/.m8t-stack/bootstrap.json for `status`/`reap`/`finish`.",
22704
23039
  examples: [
@@ -22707,13 +23042,13 @@ var BootstrapLaunchCommand = class extends M8tCommand {
22707
23042
  ["Pin a specific installer tag", "$0 bootstrap launch --location eastus2 --installer-tag v0.1.0"]
22708
23043
  ]
22709
23044
  });
22710
- location = Option44.String("--location");
22711
- resourceGroup = Option44.String("--resource-group");
22712
- clientId = Option44.String("--client-id");
22713
- subscription = Option44.String("--subscription");
22714
- installerTag = Option44.String("--installer-tag");
22715
- gatewayImageRef = Option44.String("--gateway-image-ref");
22716
- githubAppCreds = Option44.String("--github-app-creds");
23045
+ location = Option45.String("--location");
23046
+ resourceGroup = Option45.String("--resource-group");
23047
+ clientId = Option45.String("--client-id");
23048
+ subscription = Option45.String("--subscription");
23049
+ installerTag = Option45.String("--installer-tag");
23050
+ gatewayImageRef = Option45.String("--gateway-image-ref");
23051
+ githubAppCreds = Option45.String("--github-app-creds");
22717
23052
  async executeCommand() {
22718
23053
  const location = typeof this.location === "string" ? this.location : void 0;
22719
23054
  if (!location) {
@@ -22814,7 +23149,7 @@ var BootstrapLaunchCommand = class extends M8tCommand {
22814
23149
  };
22815
23150
 
22816
23151
  // src/commands/bootstrap/status.ts
22817
- import { Command as Command47, Option as Option45 } from "clipanion";
23152
+ import { Command as Command48, Option as Option46 } from "clipanion";
22818
23153
  init_errors();
22819
23154
 
22820
23155
  // src/lib/bootstrap-aci-state.ts
@@ -22842,13 +23177,13 @@ async function getAciState(opts) {
22842
23177
  // src/commands/bootstrap/status.ts
22843
23178
  var BootstrapStatusCommand = class extends M8tCommand {
22844
23179
  static paths = [["bootstrap", "status"]];
22845
- static usage = Command47.Usage({
23180
+ static usage = Command48.Usage({
22846
23181
  description: "Show the cloud installer's live status (phase, progress, result).",
22847
23182
  details: "Reads the durable status blob written by the installer. --watch polls until the install reaches done or failed.",
22848
23183
  examples: [["One read", "$0 bootstrap status"], ["Watch to completion", "$0 bootstrap status --watch"]]
22849
23184
  });
22850
- watch = Option45.Boolean("--watch", false);
22851
- output = Option45.String("--output");
23185
+ watch = Option46.Boolean("--watch", false);
23186
+ output = Option46.String("--output");
22852
23187
  async executeCommand() {
22853
23188
  const state = await readBootstrapState();
22854
23189
  if (!state) {
@@ -22919,7 +23254,7 @@ function formatStatus(d) {
22919
23254
  }
22920
23255
 
22921
23256
  // src/commands/bootstrap/reap.ts
22922
- import { Command as Command48, Option as Option46 } from "clipanion";
23257
+ import { Command as Command49, Option as Option47 } from "clipanion";
22923
23258
  init_errors();
22924
23259
 
22925
23260
  // src/lib/bootstrap-reap.ts
@@ -22995,14 +23330,14 @@ async function reapInstaller(opts) {
22995
23330
  // src/commands/bootstrap/reap.ts
22996
23331
  var BootstrapReapCommand = class extends M8tCommand {
22997
23332
  static paths = [["bootstrap", "reap"]];
22998
- static usage = Command48.Usage({
23333
+ static usage = Command49.Usage({
22999
23334
  description: "Tear down the installer scaffolding (ACI \u2192 MI \u2192 its role assignments) after a successful install.",
23000
23335
  details: "Runs locally on the 'done' signal (the installer can't delete its own identity). The platform RG and the gateway's own assignments persist. A failed install is left intact for diagnosis unless --force.",
23001
23336
  examples: [["Reap after done", "$0 bootstrap reap"]]
23002
23337
  });
23003
- force = Option46.Boolean("--force", false);
23004
- sweepOrphans = Option46.Boolean("--sweep-orphans", false);
23005
- yes = Option46.Boolean("--yes", false);
23338
+ force = Option47.Boolean("--force", false);
23339
+ sweepOrphans = Option47.Boolean("--sweep-orphans", false);
23340
+ yes = Option47.Boolean("--yes", false);
23006
23341
  async executeCommand() {
23007
23342
  if (this.sweepOrphans === true) {
23008
23343
  const { subscriptionId: sub } = await getAzAccount();
@@ -23070,7 +23405,7 @@ Found ${String(found.length)} orphaned Owner@sub assignment(s) (dry-run). ${colo
23070
23405
  import * as fs24 from "fs/promises";
23071
23406
  import * as os14 from "os";
23072
23407
  import * as path26 from "path";
23073
- import { Command as Command49, Option as Option47 } from "clipanion";
23408
+ import { Command as Command50, Option as Option48 } from "clipanion";
23074
23409
  init_errors();
23075
23410
 
23076
23411
  // src/lib/company-profile-seed.ts
@@ -23400,14 +23735,14 @@ function renderInstallSummary(args) {
23400
23735
  // src/commands/bootstrap/finish.ts
23401
23736
  var BootstrapFinishCommand = class extends M8tCommand {
23402
23737
  static paths = [["bootstrap", "finish"]];
23403
- static usage = Command49.Usage({
23738
+ static usage = Command50.Usage({
23404
23739
  description: "Point your local tools at the now-live platform (repo-root marker, discovery cache, next steps).",
23405
23740
  details: "Final step of `m8t bootstrap` (after the install reaches done). Writes ~/.m8t-stack/repo-root, points your local tools at the live gateway, and \u2014 if you completed the onboarding questionnaire \u2014 seeds your brain-backed advisor's brain with your company profile (best-effort; never blocks finish). Run `m8t bootstrap seed-profile` to seed manually later.",
23406
23741
  examples: [["Finish local", "$0 bootstrap finish --repo-root /path/to/m8t"]]
23407
23742
  });
23408
- repoRoot = Option47.String("--repo-root");
23409
- subscription = Option47.String("--subscription");
23410
- resourceGroup = Option47.String("--resource-group");
23743
+ repoRoot = Option48.String("--repo-root");
23744
+ subscription = Option48.String("--subscription");
23745
+ resourceGroup = Option48.String("--resource-group");
23411
23746
  async executeCommand() {
23412
23747
  const state = await readBootstrapState();
23413
23748
  if (!state) {
@@ -23494,7 +23829,7 @@ ${colors.field("Then open a brand new chat/session")} \u2014 new skills + MCP se
23494
23829
  import * as fs26 from "fs";
23495
23830
  import * as os16 from "os";
23496
23831
  import * as path28 from "path";
23497
- import { Command as Command50, Option as Option48 } from "clipanion";
23832
+ import { Command as Command51, Option as Option49 } from "clipanion";
23498
23833
  import { DefaultAzureCredential as DefaultAzureCredential17 } from "@azure/identity";
23499
23834
  init_errors();
23500
23835
 
@@ -23765,7 +24100,7 @@ async function deploySimpleStacey(args) {
23765
24100
  // src/commands/bootstrap/ui.ts
23766
24101
  var BootstrapUiCommand = class extends M8tCommand {
23767
24102
  static paths = [["bootstrap", "ui"]];
23768
- static usage = Command50.Usage({
24103
+ static usage = Command51.Usage({
23769
24104
  description: "Deploy Simple Stacey + start the local onboarding chat UI in the background (returns immediately).",
23770
24105
  details: [
23771
24106
  "Run after `m8t bootstrap launch`, in parallel with `status --watch`. Waits for the cloud",
@@ -23783,15 +24118,15 @@ var BootstrapUiCommand = class extends M8tCommand {
23783
24118
  ["Foreground (blocking, old behaviour)", "$0 bootstrap ui --repo-root /path/to/m8t --foreground"]
23784
24119
  ]
23785
24120
  });
23786
- repoRoot = Option48.String("--repo-root");
23787
- port = Option48.String("--port", "3000");
23788
- endpoint = Option48.String("--endpoint", {
24121
+ repoRoot = Option49.String("--repo-root");
24122
+ port = Option49.String("--port", "3000");
24123
+ endpoint = Option49.String("--endpoint", {
23789
24124
  description: "Foundry project endpoint to target \u2014 disambiguates when the subscription has multiple projects."
23790
24125
  });
23791
- prepOnly = Option48.Boolean("--prep-only", false);
23792
- skipInstall = Option48.Boolean("--skip-install", false);
23793
- stop = Option48.Boolean("--stop", false);
23794
- foreground = Option48.Boolean("--foreground", false);
24126
+ prepOnly = Option49.Boolean("--prep-only", false);
24127
+ skipInstall = Option49.Boolean("--skip-install", false);
24128
+ stop = Option49.Boolean("--stop", false);
24129
+ foreground = Option49.Boolean("--foreground", false);
23795
24130
  async executeCommand() {
23796
24131
  if (this.stop === true) {
23797
24132
  const stopped = stopOnboardingUi();
@@ -23898,10 +24233,10 @@ var BootstrapUiCommand = class extends M8tCommand {
23898
24233
  };
23899
24234
 
23900
24235
  // src/commands/bootstrap/seed-profile.ts
23901
- import { Command as Command51, Option as Option49 } from "clipanion";
24236
+ import { Command as Command52, Option as Option50 } from "clipanion";
23902
24237
  var BootstrapSeedProfileCommand = class extends M8tCommand {
23903
24238
  static paths = [["bootstrap", "seed-profile"]];
23904
- static usage = Command51.Usage({
24239
+ static usage = Command52.Usage({
23905
24240
  description: "Seed your advisors' brains with the founder + company profile from the onboarding questionnaire.",
23906
24241
  details: "Reads the latest stacey-intake conversation, renders memory/founder.md + memory/company-profile.md (+ their MEMORY.md index lines), and commits them to both <org>/stacey-brain and <org>/azzy-brain via the GitHub App. Idempotent. --watch polls until the founder completes the questionnaire.",
23907
24242
  examples: [
@@ -23909,11 +24244,11 @@ var BootstrapSeedProfileCommand = class extends M8tCommand {
23909
24244
  ["Wait for the founder to finish", "$0 bootstrap seed-profile --watch"]
23910
24245
  ]
23911
24246
  });
23912
- endpoint = Option49.String("--endpoint", { description: "Override the Foundry endpoint (else read from the install status)." });
23913
- brain = Option49.String("--brain", { description: "Override the brain repo (default <org>/stacey-brain)." });
23914
- watch = Option49.Boolean("--watch", false, { description: "Poll until the questionnaire completes (or --timeout)." });
23915
- timeout = Option49.String("--timeout", { description: "Watch timeout in minutes (default 20)." });
23916
- githubAppCreds = Option49.String("--github-app-creds");
24247
+ endpoint = Option50.String("--endpoint", { description: "Override the Foundry endpoint (else read from the install status)." });
24248
+ brain = Option50.String("--brain", { description: "Override the brain repo (default <org>/stacey-brain)." });
24249
+ watch = Option50.Boolean("--watch", false, { description: "Poll until the questionnaire completes (or --timeout)." });
24250
+ timeout = Option50.String("--timeout", { description: "Watch timeout in minutes (default 20)." });
24251
+ githubAppCreds = Option50.String("--github-app-creds");
23917
24252
  async executeCommand() {
23918
24253
  const ctx = await resolveSeedContext({
23919
24254
  endpointOverride: typeof this.endpoint === "string" ? this.endpoint : void 0,
@@ -23998,6 +24333,7 @@ cli.register(CoderTeardownCommand);
23998
24333
  cli.register(AzureExecDeployCommand);
23999
24334
  cli.register(PlatformStatusCommand);
24000
24335
  cli.register(PlatformUpdateCommand);
24336
+ cli.register(PlatformEnableCostReportCommand);
24001
24337
  cli.register(DeployCommand);
24002
24338
  cli.register(AgentDeployAdvisorCommand);
24003
24339
  cli.register(AgentRemoveCommand);