@m8t-stack/cli 0.2.46 → 0.2.48

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
@@ -1329,7 +1329,7 @@ var init_enable_hosted_brain = __esm({
1329
1329
  import { Builtins, Cli } from "clipanion";
1330
1330
 
1331
1331
  // src/lib/package-version.ts
1332
- var CLI_VERSION = "0.2.46";
1332
+ var CLI_VERSION = "0.2.48";
1333
1333
 
1334
1334
  // src/lib/render-error.ts
1335
1335
  init_errors();
@@ -16225,19 +16225,135 @@ var BrainListCommand = class extends M8tCommand {
16225
16225
  }
16226
16226
  };
16227
16227
 
16228
- // src/commands/brain/show.ts
16228
+ // src/commands/brain/orgs.ts
16229
16229
  import { Command as Command21, Option as Option20 } from "clipanion";
16230
+
16231
+ // src/lib/github-orgs.ts
16232
+ var ORG_QUERY = "{ viewer { organizations(first:50) { nodes { login viewerCanAdminister enterpriseOwners(first:1) { totalCount } } } } }";
16233
+ function classifyOrgs(result) {
16234
+ if (!result.ok) return { verdict: "undetermined", candidates: [], orgs: [] };
16235
+ const orgs = result.orgs;
16236
+ if (orgs.length === 0) return { verdict: "no-orgs", candidates: [], orgs };
16237
+ const enterprise = orgs.filter((o) => o.enterprise);
16238
+ if (enterprise.length === 1) {
16239
+ return { verdict: "enterprise-single", selected: enterprise[0].login, candidates: enterprise, orgs };
16240
+ }
16241
+ if (enterprise.length > 1) {
16242
+ return { verdict: "enterprise-multiple", candidates: enterprise, orgs };
16243
+ }
16244
+ return { verdict: "no-enterprise", candidates: orgs, orgs };
16245
+ }
16246
+ async function fetchOrgGraph(exec = defaultGhExec) {
16247
+ const r = await exec("gh", ["api", "graphql", "-f", `query=${ORG_QUERY}`]);
16248
+ if (r.exitCode !== 0) {
16249
+ return { ok: false, reason: r.stderr.trim() || `gh exited ${r.exitCode.toString()}` };
16250
+ }
16251
+ let parsed;
16252
+ try {
16253
+ parsed = JSON.parse(r.stdout);
16254
+ } catch {
16255
+ return { ok: false, reason: "gh returned output that is not JSON" };
16256
+ }
16257
+ if (Array.isArray(parsed.errors) && parsed.errors.length > 0) {
16258
+ return { ok: false, reason: "the org query returned a partial result" };
16259
+ }
16260
+ const nodes = parsed.data?.viewer?.organizations?.nodes;
16261
+ if (!Array.isArray(nodes)) return { ok: false, reason: "unexpected response shape" };
16262
+ const orgs = [];
16263
+ for (const raw of nodes) {
16264
+ if (raw === null) return { ok: false, reason: "unexpected response shape" };
16265
+ const login = raw.login;
16266
+ const total = raw.enterpriseOwners?.totalCount;
16267
+ if (typeof login !== "string" || typeof total !== "number") {
16268
+ return { ok: false, reason: "unexpected response shape" };
16269
+ }
16270
+ orgs.push({ login, enterprise: total > 0, canAdminister: raw.viewerCanAdminister === true });
16271
+ }
16272
+ return { ok: true, orgs };
16273
+ }
16274
+
16275
+ // src/lib/github-orgs-copy.ts
16276
+ function enterpriseSingleNotice(org) {
16277
+ return `Using your GitHub Enterprise org ${org} for your workers' brains.`;
16278
+ }
16279
+ function enterpriseMultiplePrompt(logins) {
16280
+ return `You belong to more than one GitHub Enterprise org: ${logins.join(", ")}. Which one should your workers' brains live in?`;
16281
+ }
16282
+ function noEnterpriseNotice(selectedOrg) {
16283
+ return `No GitHub Enterprise org detected; if you have the Microsoft for Startups benefit, your workers' brains can live there - continuing with ${selectedOrg} for now.`;
16284
+ }
16285
+ function undeterminedNotice() {
16286
+ return `Could not check your GitHub orgs automatically - listing them instead.`;
16287
+ }
16288
+ function noOrgsRefusal() {
16289
+ return `Your workers' brains are created by a GitHub App, which can only make repositories in an organization, and this account belongs to none. Creating a free GitHub organization and then running \`m8t brain app-create --org <org>\` is enough.`;
16290
+ }
16291
+
16292
+ // src/commands/brain/orgs.ts
16293
+ var BrainOrgsCommand = class extends M8tCommand {
16294
+ static paths = [["brain", "orgs"]];
16295
+ static usage = Command21.Usage({
16296
+ description: "Show which GitHub org your workers' brains should live in.",
16297
+ details: "Read-only. Lists the organizations you belong to and prefers one linked to a GitHub Enterprise account. Advisory: `m8t brain app-create --org <org>` decides where the App is installed, so an explicit choice always wins.",
16298
+ examples: [
16299
+ ["Show the recommendation", "$0 brain orgs"],
16300
+ ["Machine-readable", "$0 brain orgs --output json"]
16301
+ ]
16302
+ });
16303
+ output = Option20.String("--output");
16304
+ async executeCommand() {
16305
+ const outputFlag = this.output === "json" || this.output === "auto" || this.output === "pretty" ? this.output : "pretty";
16306
+ const mode = resolveOutputMode(outputFlag, this.context.stdout);
16307
+ const classification = classifyOrgs(await fetchOrgGraph());
16308
+ if (mode === "json") {
16309
+ this.context.stdout.write(renderJson(classification) + "\n");
16310
+ return exitCodeFor(classification);
16311
+ }
16312
+ this.renderPretty(classification);
16313
+ return exitCodeFor(classification);
16314
+ }
16315
+ renderPretty(c) {
16316
+ const out = (s) => this.context.stdout.write(s + "\n");
16317
+ switch (c.verdict) {
16318
+ case "enterprise-single":
16319
+ out(`${colors.success("\u2713")} ${enterpriseSingleNotice(c.selected ?? "")}`);
16320
+ return;
16321
+ case "enterprise-multiple":
16322
+ out(enterpriseMultiplePrompt(c.candidates.map((o) => o.login)));
16323
+ return;
16324
+ case "no-enterprise":
16325
+ out(noEnterpriseNotice(c.candidates[0]?.login ?? ""));
16326
+ if (c.candidates.length > 1) {
16327
+ out(` ${colors.dim(`orgs: ${c.candidates.map((o) => o.login).join(", ")}`)}`);
16328
+ }
16329
+ return;
16330
+ case "undetermined":
16331
+ out(undeterminedNotice());
16332
+ return;
16333
+ case "no-orgs":
16334
+ this.context.stderr.write(`${colors.error("\u2717")} ${noOrgsRefusal()}
16335
+ `);
16336
+ return;
16337
+ }
16338
+ }
16339
+ };
16340
+ function exitCodeFor(c) {
16341
+ return c.verdict === "no-orgs" ? 1 : 0;
16342
+ }
16343
+
16344
+ // src/commands/brain/show.ts
16345
+ import { Command as Command22, Option as Option21 } from "clipanion";
16230
16346
  import { DefaultAzureCredential as DefaultAzureCredential7 } from "@azure/identity";
16231
16347
  init_errors();
16232
16348
  init_foundry_agent_get();
16233
16349
  init_esm();
16234
16350
  var BrainShowCommand = class extends M8tCommand {
16235
16351
  static paths = [["brain", "show"]];
16236
- static usage = Command21.Usage({ description: "Show a worker's brain link + connection diagnostics." });
16237
- worker = Option20.String();
16238
- subscription = Option20.String("--subscription");
16239
- endpoint = Option20.String("--endpoint");
16240
- output = Option20.String("--output");
16352
+ static usage = Command22.Usage({ description: "Show a worker's brain link + connection diagnostics." });
16353
+ worker = Option21.String();
16354
+ subscription = Option21.String("--subscription");
16355
+ endpoint = Option21.String("--endpoint");
16356
+ output = Option21.String("--output");
16241
16357
  async executeCommand() {
16242
16358
  const worker = typeof this.worker === "string" ? this.worker : void 0;
16243
16359
  if (!worker) {
@@ -16296,7 +16412,7 @@ var BrainShowCommand = class extends M8tCommand {
16296
16412
  };
16297
16413
 
16298
16414
  // src/commands/brain/unlink.ts
16299
- import { Command as Command22, Option as Option21 } from "clipanion";
16415
+ import { Command as Command23, Option as Option22 } from "clipanion";
16300
16416
  import { DefaultAzureCredential as DefaultAzureCredential8 } from "@azure/identity";
16301
16417
  init_errors();
16302
16418
 
@@ -16456,7 +16572,7 @@ ${text.slice(0, 300)}`
16456
16572
  // src/commands/brain/unlink.ts
16457
16573
  var BrainUnlinkCommand = class extends M8tCommand {
16458
16574
  static paths = [["brain", "unlink"]];
16459
- static usage = Command22.Usage({
16575
+ static usage = Command23.Usage({
16460
16576
  description: "Unlink a worker from its brain repo (cascade teardown).",
16461
16577
  details: "Re-deploys the agent without the brain loader + MCP tool, deletes the Foundry connection, and (unless --keep-app-install) uninstalls the GitHub App on the repo. The repo itself is NOT deleted.",
16462
16578
  examples: [
@@ -16464,13 +16580,13 @@ var BrainUnlinkCommand = class extends M8tCommand {
16464
16580
  ["Unlink but keep the App install", "$0 brain unlink cmo --yes --keep-app-install"]
16465
16581
  ]
16466
16582
  });
16467
- worker = Option21.String();
16468
- yes = Option21.Boolean("--yes", false);
16469
- keepAppInstall = Option21.Boolean("--keep-app-install", false);
16470
- kvUri = Option21.String("--kv-uri");
16471
- subscription = Option21.String("--subscription");
16472
- endpoint = Option21.String("--endpoint");
16473
- output = Option21.String("--output");
16583
+ worker = Option22.String();
16584
+ yes = Option22.Boolean("--yes", false);
16585
+ keepAppInstall = Option22.Boolean("--keep-app-install", false);
16586
+ kvUri = Option22.String("--kv-uri");
16587
+ subscription = Option22.String("--subscription");
16588
+ endpoint = Option22.String("--endpoint");
16589
+ output = Option22.String("--output");
16474
16590
  async executeCommand() {
16475
16591
  const worker = typeof this.worker === "string" ? this.worker : void 0;
16476
16592
  if (!worker) {
@@ -16560,7 +16676,7 @@ var BrainUnlinkCommand = class extends M8tCommand {
16560
16676
  };
16561
16677
 
16562
16678
  // src/commands/agent/deploy-advisor.ts
16563
- import { Command as Command23, Option as Option22 } from "clipanion";
16679
+ import { Command as Command24, Option as Option23 } from "clipanion";
16564
16680
  import { DefaultAzureCredential as DefaultAzureCredential9 } from "@azure/identity";
16565
16681
  init_errors();
16566
16682
 
@@ -16651,7 +16767,7 @@ async function deployPromptAdvisor(args) {
16651
16767
  // src/commands/agent/deploy-advisor.ts
16652
16768
  var AgentDeployAdvisorCommand = class extends M8tCommand {
16653
16769
  static paths = [["agent", "deploy-advisor"]];
16654
- static usage = Command23.Usage({
16770
+ static usage = Command24.Usage({
16655
16771
  description: "Deploy a brain-eligible prompt advisor headlessly from its persona frontmatter.",
16656
16772
  details: "Reads the persona frontmatter (model, reasoning effort, fillable-field defaults) from personas/<persona>/persona.md, renders the instructions, and creates a new Foundry prompt-agent version under <name>. Idempotent \u2014 re-running creates a new version. Used by the cloud installer to seed the default advisor worker set.",
16657
16773
  examples: [
@@ -16669,25 +16785,25 @@ var AgentDeployAdvisorCommand = class extends M8tCommand {
16669
16785
  ]
16670
16786
  ]
16671
16787
  });
16672
- persona = Option22.String("--persona", {
16788
+ persona = Option23.String("--persona", {
16673
16789
  description: "Persona directory name under personas/ (e.g. startup-advisor)."
16674
16790
  });
16675
- name = Option22.String("--name", {
16791
+ name = Option23.String("--name", {
16676
16792
  description: "The agent instance name to deploy as (e.g. stacey)."
16677
16793
  });
16678
- model = Option22.String("--model", {
16794
+ model = Option23.String("--model", {
16679
16795
  description: "Override the model from persona frontmatter."
16680
16796
  });
16681
- endpoint = Option22.String("--endpoint", {
16797
+ endpoint = Option23.String("--endpoint", {
16682
16798
  description: "Foundry project endpoint URL. If omitted, resolved from the subscription."
16683
16799
  });
16684
- subscription = Option22.String("--subscription", {
16800
+ subscription = Option23.String("--subscription", {
16685
16801
  description: "Azure subscription ID. Defaults to the current az account."
16686
16802
  });
16687
- repoRootFlag = Option22.String("--repo-root", {
16803
+ repoRootFlag = Option23.String("--repo-root", {
16688
16804
  description: "Path to the m8t repo checkout. Defaults to the ~/.m8t/repo-root marker."
16689
16805
  });
16690
- output = Option22.String("--output", {
16806
+ output = Option23.String("--output", {
16691
16807
  description: "Output format: pretty (default) or json."
16692
16808
  });
16693
16809
  async executeCommand() {
@@ -16753,7 +16869,7 @@ var AgentDeployAdvisorCommand = class extends M8tCommand {
16753
16869
  };
16754
16870
 
16755
16871
  // src/commands/agent/remove.ts
16756
- import { Command as Command24, Option as Option23 } from "clipanion";
16872
+ import { Command as Command25, Option as Option24 } from "clipanion";
16757
16873
  import { DefaultAzureCredential as DefaultAzureCredential10 } from "@azure/identity";
16758
16874
  init_errors();
16759
16875
 
@@ -17213,7 +17329,7 @@ function defaultRemoveAgentDeps(args) {
17213
17329
  // src/commands/agent/remove.ts
17214
17330
  var AgentRemoveCommand = class extends M8tCommand {
17215
17331
  static paths = [["agent", "remove"]];
17216
- static usage = Command24.Usage({
17332
+ static usage = Command25.Usage({
17217
17333
  description: "Cascade-remove an agent and all its associated resources.",
17218
17334
  details: "Removes, in order: channel bindings (table row + KV secret + conversations), a2a connection, brain connection (GitHub repo kept by default), the agent itself, and its local yaml. Idempotent and partial-failure resilient.",
17219
17335
  examples: [
@@ -17222,18 +17338,18 @@ var AgentRemoveCommand = class extends M8tCommand {
17222
17338
  ["Remove without touching bindings", "$0 agent remove my-agent --yes --keep-bindings"]
17223
17339
  ]
17224
17340
  });
17225
- name = Option23.String();
17226
- yes = Option23.Boolean("--yes", false);
17227
- keepBindings = Option23.Boolean("--keep-bindings", false);
17228
- keepA2a = Option23.Boolean("--keep-a2a", false);
17229
- deleteBrainRepo = Option23.Boolean("--delete-brain-repo", false);
17230
- endpoint = Option23.String("--endpoint");
17231
- subscription = Option23.String("--subscription");
17232
- kvUri = Option23.String("--kv-uri");
17233
- resourceGroup = Option23.String("--resource-group", {
17341
+ name = Option24.String();
17342
+ yes = Option24.Boolean("--yes", false);
17343
+ keepBindings = Option24.Boolean("--keep-bindings", false);
17344
+ keepA2a = Option24.Boolean("--keep-a2a", false);
17345
+ deleteBrainRepo = Option24.Boolean("--delete-brain-repo", false);
17346
+ endpoint = Option24.String("--endpoint");
17347
+ subscription = Option24.String("--subscription");
17348
+ kvUri = Option24.String("--kv-uri");
17349
+ resourceGroup = Option24.String("--resource-group", {
17234
17350
  description: "m8t resource group to disambiguate the gateway (multi-deployment subscriptions)."
17235
17351
  });
17236
- output = Option23.String("--output");
17352
+ output = Option24.String("--output");
17237
17353
  async executeCommand() {
17238
17354
  const name = typeof this.name === "string" ? this.name : void 0;
17239
17355
  if (!name) {
@@ -17348,7 +17464,7 @@ ${colors.success("\u2713")} removed ${colors.field(name)}.
17348
17464
 
17349
17465
  // src/commands/a2a/enable.ts
17350
17466
  import * as path14 from "path";
17351
- import { Command as Command25, Option as Option24 } from "clipanion";
17467
+ import { Command as Command26, Option as Option25 } from "clipanion";
17352
17468
  import { DefaultAzureCredential as DefaultAzureCredential11 } from "@azure/identity";
17353
17469
  init_errors();
17354
17470
 
@@ -17391,17 +17507,17 @@ function readConfigGatewayUrl(home) {
17391
17507
  // src/commands/a2a/enable.ts
17392
17508
  var A2aEnableCommand = class extends M8tCommand {
17393
17509
  static paths = [["a2a", "enable"]];
17394
- static usage = Command25.Usage({
17510
+ static usage = Command26.Usage({
17395
17511
  description: "Enable a worker for agent-to-agent delegation (caller + callee). Idempotent (rotates the bearer).",
17396
17512
  details: "Attaches the A2A tool[type:mcp] (discover_workers + invoke_worker), provisions a CustomKeys connection holding a freshly-minted bearer, and projects the persona's a2a-card + sha256(bearer) into Foundry agent metadata. The bridge then lists this worker in discover_workers and recognizes it as a caller by the bearer hash.",
17397
17513
  examples: [["Enable the cmo persona", "$0 a2a enable cmo --persona cmo --gateway-url https://<gateway-fqdn>"]]
17398
17514
  });
17399
- worker = Option24.String();
17400
- persona = Option24.String("--persona");
17401
- gatewayUrl = Option24.String("--gateway-url");
17402
- endpoint = Option24.String("--endpoint");
17403
- subscription = Option24.String("--subscription");
17404
- output = Option24.String("--output");
17515
+ worker = Option25.String();
17516
+ persona = Option25.String("--persona");
17517
+ gatewayUrl = Option25.String("--gateway-url");
17518
+ endpoint = Option25.String("--endpoint");
17519
+ subscription = Option25.String("--subscription");
17520
+ output = Option25.String("--output");
17405
17521
  async executeCommand() {
17406
17522
  const env = this.context.env;
17407
17523
  const outputFlag = this.output === "json" || this.output === "auto" || this.output === "pretty" ? this.output : "pretty";
@@ -17461,18 +17577,18 @@ var A2aEnableCommand = class extends M8tCommand {
17461
17577
  };
17462
17578
 
17463
17579
  // src/commands/a2a/disable.ts
17464
- import { Command as Command26, Option as Option25 } from "clipanion";
17580
+ import { Command as Command27, Option as Option26 } from "clipanion";
17465
17581
  import { DefaultAzureCredential as DefaultAzureCredential12 } from "@azure/identity";
17466
17582
  var A2aDisableCommand = class extends M8tCommand {
17467
17583
  static paths = [["a2a", "disable"]];
17468
- static usage = Command26.Usage({
17584
+ static usage = Command27.Usage({
17469
17585
  description: "Disable agent-to-agent delegation for a worker (remove tool + connection + metadata). Idempotent.",
17470
17586
  examples: [["Disable the cmo persona", "$0 a2a disable cmo"]]
17471
17587
  });
17472
- worker = Option25.String();
17473
- endpoint = Option25.String("--endpoint");
17474
- subscription = Option25.String("--subscription");
17475
- output = Option25.String("--output");
17588
+ worker = Option26.String();
17589
+ endpoint = Option26.String("--endpoint");
17590
+ subscription = Option26.String("--subscription");
17591
+ output = Option26.String("--output");
17476
17592
  async executeCommand() {
17477
17593
  const outputFlag = this.output === "json" || this.output === "auto" || this.output === "pretty" ? this.output : "pretty";
17478
17594
  const mode = resolveOutputMode(outputFlag, this.context.stdout);
@@ -17506,7 +17622,7 @@ var A2aDisableCommand = class extends M8tCommand {
17506
17622
  };
17507
17623
 
17508
17624
  // src/commands/architect/check.ts
17509
- import { Command as Command27 } from "clipanion";
17625
+ import { Command as Command28 } from "clipanion";
17510
17626
 
17511
17627
  // src/lib/architect-version.ts
17512
17628
  import { createHash as createHash2 } from "crypto";
@@ -17645,7 +17761,7 @@ function checkArchitectDrift() {
17645
17761
  // src/commands/architect/check.ts
17646
17762
  var ArchitectCheckCommand = class extends M8tCommand {
17647
17763
  static paths = [["architect-check"]];
17648
- static usage = Command27.Usage({
17764
+ static usage = Command28.Usage({
17649
17765
  description: "Verify the installed m8t-architect persona matches the repo source.",
17650
17766
  details: "Compares a render-time content hash (stored in a per-persona `<name>.m8t-skill.json` sidecar, checked across every host m8t can render into \u2014 Claude Code, VS Code Copilot Chat, GitHub Copilot CLI) against a fresh hash of <repo-root>/personas/m8t-architect/persona.md. Exits 0 when they match, 1 with remediation advice when they don't. Used as a pre-flight gate by the architect persona body and as a verification step in guides/install/m8t.md.",
17651
17767
  examples: [
@@ -17672,7 +17788,7 @@ var ArchitectCheckCommand = class extends M8tCommand {
17672
17788
  // src/commands/coder/deploy.ts
17673
17789
  init_esm2();
17674
17790
  import * as path17 from "path";
17675
- import { Command as Command28, Option as Option26 } from "clipanion";
17791
+ import { Command as Command29, Option as Option27 } from "clipanion";
17676
17792
  import { DefaultAzureCredential as DefaultAzureCredential13 } from "@azure/identity";
17677
17793
  init_errors();
17678
17794
  init_foundry_agent_get();
@@ -18086,7 +18202,7 @@ var DEFAULT_MODEL = "gpt-4.1-mini";
18086
18202
  var NAME_RE = /^[a-z0-9-]+$/;
18087
18203
  var CoderDeployCommand = class extends M8tCommand {
18088
18204
  static paths = [["coder", "deploy"]];
18089
- static usage = Command28.Usage({
18205
+ static usage = Command29.Usage({
18090
18206
  description: "Deploy the curated coding agent as a hosted Foundry worker.",
18091
18207
  details: "Creates a hosted agent version from a container image (defaults to the public GHCR image ghcr.io/m8t-labs/m8t-coding-agent). Post-2026-06-25 Foundry projects require an authenticated pull, so a public image is staged into the customer's Azure Container Registry first (created if missing, then `az acr import` \u2014 a server-side copy, no local build) and the agent is deployed from that ACR ref. Re-running with a newer --image-tag imports the new tag and rolls out a new agent version \u2014 that is how you update a worker's image. Override --image with a private ACR ref to bring your own registry.",
18092
18208
  examples: [
@@ -18095,22 +18211,22 @@ var CoderDeployCommand = class extends M8tCommand {
18095
18211
  ["Override the exec timeout", "$0 coder deploy my-coder --env M8T_CODER_EXEC_TIMEOUT_SECONDS=300"]
18096
18212
  ]
18097
18213
  });
18098
- name = Option26.String();
18099
- persona = Option26.String("--persona");
18100
- image = Option26.String("--image");
18101
- imageTag = Option26.String("--image-tag");
18102
- size = Option26.String("--size");
18103
- modelDeployment = Option26.String("--model-deployment");
18104
- env = Option26.Array("--env");
18105
- endpoint = Option26.String("--endpoint");
18106
- subscription = Option26.String("--subscription");
18107
- output = Option26.String("--output");
18108
- brain = Option26.String("--brain");
18109
- brainBranch = Option26.String("--branch");
18110
- brainKv = Option26.String("--brain-kv");
18111
- allowNonReasoning = Option26.Boolean("--allow-non-reasoning", false);
18112
- skipQuotaCheck = Option26.Boolean("--skip-quota-check", false);
18113
- gatewayUrl = Option26.String("--gateway-url", { description: "Base gateway URL for the a2a bridge (e.g. https://<gateway-fqdn>); enables this coder as an a2a target." });
18214
+ name = Option27.String();
18215
+ persona = Option27.String("--persona");
18216
+ image = Option27.String("--image");
18217
+ imageTag = Option27.String("--image-tag");
18218
+ size = Option27.String("--size");
18219
+ modelDeployment = Option27.String("--model-deployment");
18220
+ env = Option27.Array("--env");
18221
+ endpoint = Option27.String("--endpoint");
18222
+ subscription = Option27.String("--subscription");
18223
+ output = Option27.String("--output");
18224
+ brain = Option27.String("--brain");
18225
+ brainBranch = Option27.String("--branch");
18226
+ brainKv = Option27.String("--brain-kv");
18227
+ allowNonReasoning = Option27.Boolean("--allow-non-reasoning", false);
18228
+ skipQuotaCheck = Option27.Boolean("--skip-quota-check", false);
18229
+ gatewayUrl = Option27.String("--gateway-url", { description: "Base gateway URL for the a2a bridge (e.g. https://<gateway-fqdn>); enables this coder as an a2a target." });
18114
18230
  async executeCommand() {
18115
18231
  if (!NAME_RE.test(this.name)) {
18116
18232
  throw new LocalCliError({
@@ -18345,13 +18461,13 @@ var CoderDeployCommand = class extends M8tCommand {
18345
18461
 
18346
18462
  // src/commands/coder/teardown.ts
18347
18463
  import { confirm as confirm4 } from "@inquirer/prompts";
18348
- import { Command as Command29, Option as Option27 } from "clipanion";
18464
+ import { Command as Command30, Option as Option28 } from "clipanion";
18349
18465
  import { DefaultAzureCredential as DefaultAzureCredential14 } from "@azure/identity";
18350
18466
  init_foundry_agents();
18351
18467
  init_errors();
18352
18468
  var CoderTeardownCommand = class extends M8tCommand {
18353
18469
  static paths = [["coder", "teardown"]];
18354
- static usage = Command29.Usage({
18470
+ static usage = Command30.Usage({
18355
18471
  description: "Delete a deployed hosted coder (removes its container + identity + role assignment).",
18356
18472
  details: "Idempotent: tearing down a missing coder reports 'already gone'. Only the named agent is touched. Discovery self-heals on the next worker list.",
18357
18473
  examples: [
@@ -18359,11 +18475,11 @@ var CoderTeardownCommand = class extends M8tCommand {
18359
18475
  ["Skip the confirm (scripts)", "$0 coder teardown my-coder --yes"]
18360
18476
  ]
18361
18477
  });
18362
- name = Option27.String();
18363
- yes = Option27.Boolean("--yes", false);
18364
- endpoint = Option27.String("--endpoint");
18365
- subscription = Option27.String("--subscription");
18366
- output = Option27.String("--output");
18478
+ name = Option28.String();
18479
+ yes = Option28.Boolean("--yes", false);
18480
+ endpoint = Option28.String("--endpoint");
18481
+ subscription = Option28.String("--subscription");
18482
+ output = Option28.String("--output");
18367
18483
  async executeCommand() {
18368
18484
  const mode = resolveOutputMode(
18369
18485
  this.output,
@@ -18428,7 +18544,7 @@ var CoderTeardownCommand = class extends M8tCommand {
18428
18544
  // src/commands/azure-exec/deploy.ts
18429
18545
  init_esm2();
18430
18546
  import * as path18 from "path";
18431
- import { Command as Command30, Option as Option28 } from "clipanion";
18547
+ import { Command as Command31, Option as Option29 } from "clipanion";
18432
18548
  import { DefaultAzureCredential as DefaultAzureCredential15 } from "@azure/identity";
18433
18549
  init_errors();
18434
18550
  init_foundry_agent_get();
@@ -18490,7 +18606,7 @@ var DEFAULT_MODEL2 = "gpt-5-mini";
18490
18606
  var NAME_RE2 = /^[a-z0-9-]+$/;
18491
18607
  var AzureExecDeployCommand = class extends M8tCommand {
18492
18608
  static paths = [["azure-exec", "deploy"]];
18493
- static usage = Command30.Usage({
18609
+ static usage = Command31.Usage({
18494
18610
  description: "Deploy the Azure executor as a hosted Foundry worker (az CLI + tiered ops).",
18495
18611
  details: "Creates a hosted agent version from a container image (defaults to the public GHCR image ghcr.io/m8t-labs/m8t-azure-executor \u2014 no local build needed), grants its identity Foundry User + Contributor (at --scope) + Key Vault Secrets User (brain KV), polls to active, and a2a-enables it as a target. Override with --image/--image-tag for a bring-your-own-registry image (e.g. a private ACR ref, which must be pushed first). Contributor scope is REQUIRED \u2014 pass --scope or --resource-group. Pass --grant-access-admin to additionally grant User Access Administrator (enables human-approved Tier-2 role/delete ops). Post-2026-06-25 Foundry projects require an authenticated pull, so the public image (default ghcr.io/m8t-labs/m8t-azure-executor) is staged into the customer's Azure Container Registry first (created if missing, then `az acr import` \u2014 server-side, no local build) and deployed from that ACR ref; re-running with a newer --image-tag updates the image.",
18496
18612
  examples: [
@@ -18500,23 +18616,23 @@ var AzureExecDeployCommand = class extends M8tCommand {
18500
18616
  ]
18501
18617
  ]
18502
18618
  });
18503
- name = Option28.String();
18504
- image = Option28.String("--image");
18505
- imageTag = Option28.String("--image-tag");
18506
- size = Option28.String("--size");
18507
- scope = Option28.String("--scope");
18508
- resourceGroup = Option28.String("--resource-group");
18509
- modelDeployment = Option28.String("--model-deployment");
18510
- env = Option28.Array("--env");
18511
- brain = Option28.String("--brain");
18512
- kvUri = Option28.String("--kv-uri");
18513
- gatewayUrl = Option28.String("--gateway-url");
18514
- endpoint = Option28.String("--endpoint");
18515
- subscription = Option28.String("--subscription");
18516
- output = Option28.String("--output");
18517
- skipQuotaCheck = Option28.Boolean("--skip-quota-check", false);
18518
- grantAccessAdmin = Option28.Boolean("--grant-access-admin", false);
18519
- enableEmail = Option28.Boolean("--enable-email", false);
18619
+ name = Option29.String();
18620
+ image = Option29.String("--image");
18621
+ imageTag = Option29.String("--image-tag");
18622
+ size = Option29.String("--size");
18623
+ scope = Option29.String("--scope");
18624
+ resourceGroup = Option29.String("--resource-group");
18625
+ modelDeployment = Option29.String("--model-deployment");
18626
+ env = Option29.Array("--env");
18627
+ brain = Option29.String("--brain");
18628
+ kvUri = Option29.String("--kv-uri");
18629
+ gatewayUrl = Option29.String("--gateway-url");
18630
+ endpoint = Option29.String("--endpoint");
18631
+ subscription = Option29.String("--subscription");
18632
+ output = Option29.String("--output");
18633
+ skipQuotaCheck = Option29.Boolean("--skip-quota-check", false);
18634
+ grantAccessAdmin = Option29.Boolean("--grant-access-admin", false);
18635
+ enableEmail = Option29.Boolean("--enable-email", false);
18520
18636
  async executeCommand() {
18521
18637
  if (!NAME_RE2.test(this.name)) {
18522
18638
  throw new LocalCliError({
@@ -18761,7 +18877,7 @@ var AzureExecDeployCommand = class extends M8tCommand {
18761
18877
  };
18762
18878
 
18763
18879
  // src/commands/platform/status.ts
18764
- import { Command as Command31, Option as Option29 } from "clipanion";
18880
+ import { Command as Command32, Option as Option30 } from "clipanion";
18765
18881
  import { DefaultAzureCredential as DefaultAzureCredential16 } from "@azure/identity";
18766
18882
 
18767
18883
  // src/lib/platform-update.ts
@@ -19958,30 +20074,30 @@ async function applyPersona(a, ctx, opts) {
19958
20074
  // src/commands/platform/status.ts
19959
20075
  var PlatformStatusCommand = class extends M8tCommand {
19960
20076
  static paths = [["platform", "status"]];
19961
- static usage = Command31.Usage({
20077
+ static usage = Command32.Usage({
19962
20078
  description: "Show per-component platform drift against a release manifest.",
19963
20079
  details: "Fetches a release manifest (the current channel by default), reads the installed-state stamp, and reports each component's installed vs target version and drift status. Read-only \u2014 never writes the stamp, never converges anything (use 'm8t platform update' for that). --verify additionally probes the live gateway (image tag + /api/version) best-effort."
19964
20080
  });
19965
- subscription = Option29.String("--subscription");
19966
- resourceGroup = Option29.String("--resource-group", {
20081
+ subscription = Option30.String("--subscription");
20082
+ resourceGroup = Option30.String("--resource-group", {
19967
20083
  description: "m8t resource group to disambiguate the gateway (multi-deployment subscriptions)."
19968
20084
  });
19969
- to = Option29.String("--to", {
20085
+ to = Option30.String("--to", {
19970
20086
  description: "Check status against a pinned platform version (defaults to the current release channel)."
19971
20087
  });
19972
- contentDir = Option29.String("--content-dir", {
20088
+ contentDir = Option30.String("--content-dir", {
19973
20089
  description: "Path to a local m8t repo checkout (skips the tarball tree-SHA fetch)."
19974
20090
  });
19975
- manifestUrl = Option29.String("--manifest-url", {
20091
+ manifestUrl = Option30.String("--manifest-url", {
19976
20092
  description: "Fetch the release manifest from this URL instead of the release channel."
19977
20093
  });
19978
- manifestFile = Option29.String("--manifest-file", {
20094
+ manifestFile = Option30.String("--manifest-file", {
19979
20095
  description: "Read the release manifest from this local file instead of the release channel."
19980
20096
  });
19981
- verify = Option29.Boolean("--verify", false, {
20097
+ verify = Option30.Boolean("--verify", false, {
19982
20098
  description: "Additionally probe the live gateway (image tag + /api/version) and report stamp-vs-live."
19983
20099
  });
19984
- output = Option29.String("--output");
20100
+ output = Option30.String("--output");
19985
20101
  async executeCommand() {
19986
20102
  const mode = resolveOutputMode(
19987
20103
  this.output,
@@ -20099,7 +20215,7 @@ var PlatformStatusCommand = class extends M8tCommand {
20099
20215
  };
20100
20216
 
20101
20217
  // src/commands/platform/update.ts
20102
- import { Command as Command32, Option as Option30 } from "clipanion";
20218
+ import { Command as Command33, Option as Option31 } from "clipanion";
20103
20219
  import { confirm as confirm5 } from "@inquirer/prompts";
20104
20220
  import { DefaultAzureCredential as DefaultAzureCredential17 } from "@azure/identity";
20105
20221
 
@@ -20742,40 +20858,40 @@ function assertCliVersionOk(manifest, runningVersion, onWarn = () => {
20742
20858
  // src/commands/platform/update.ts
20743
20859
  var PlatformUpdateCommand = class extends M8tCommand {
20744
20860
  static paths = [["platform", "update"]];
20745
- static usage = Command32.Usage({
20861
+ static usage = Command33.Usage({
20746
20862
  description: "Converge the whole platform (gateway, hosted agents, personas, infra) to a release manifest.",
20747
20863
  details: "Fetches a release manifest (the current channel by default), diffs it against the installed-state stamp, and converges each changed component via its own executor: rolls the gateway/hosted-agent images, re-versions prompt personas (compose-preserving), and records infra state. A deploy/ tree drift is reported but NOT applied unless --force-infra is passed. Use --check to preview, --only to converge a single component, --yes to skip the confirmation prompt."
20748
20864
  });
20749
- subscription = Option30.String("--subscription");
20750
- resourceGroup = Option30.String("--resource-group", {
20865
+ subscription = Option31.String("--subscription");
20866
+ resourceGroup = Option31.String("--resource-group", {
20751
20867
  description: "m8t resource group to disambiguate the gateway (multi-deployment subscriptions)."
20752
20868
  });
20753
- to = Option30.String("--to", {
20869
+ to = Option31.String("--to", {
20754
20870
  description: "Pin the platform version to converge to (defaults to the current release channel)."
20755
20871
  });
20756
- only = Option30.String("--only", {
20872
+ only = Option31.String("--only", {
20757
20873
  description: "Converge only one component: infra | gateway | codingAgent | azureExecutor | personas | brainSeeds."
20758
20874
  });
20759
- check = Option30.Boolean("--check", false);
20760
- yes = Option30.Boolean("--yes", false);
20761
- skipInfra = Option30.Boolean("--skip-infra", false);
20762
- forceInfra = Option30.Boolean("--force-infra", false);
20763
- suffix = Option30.String("--suffix", {
20875
+ check = Option31.Boolean("--check", false);
20876
+ yes = Option31.Boolean("--yes", false);
20877
+ skipInfra = Option31.Boolean("--skip-infra", false);
20878
+ forceInfra = Option31.Boolean("--force-infra", false);
20879
+ suffix = Option31.String("--suffix", {
20764
20880
  description: "Required with --force-infra \u2014 the existing deployment's resource-name suffix (avoids provisioning duplicates)."
20765
20881
  });
20766
- contentDir = Option30.String("--content-dir", {
20882
+ contentDir = Option31.String("--content-dir", {
20767
20883
  description: "Path to a local m8t repo checkout (skips the tarball fetch + tree-drift check)."
20768
20884
  });
20769
- manifestUrl = Option30.String("--manifest-url", {
20885
+ manifestUrl = Option31.String("--manifest-url", {
20770
20886
  description: "Fetch the release manifest from this URL instead of the release channel."
20771
20887
  });
20772
- manifestFile = Option30.String("--manifest-file", {
20888
+ manifestFile = Option31.String("--manifest-file", {
20773
20889
  description: "Read the release manifest from this local file instead of the release channel."
20774
20890
  });
20775
- endpoint = Option30.String("--endpoint", {
20891
+ endpoint = Option31.String("--endpoint", {
20776
20892
  description: "Foundry project endpoint URL. Disambiguates the project in a multi-project subscription."
20777
20893
  });
20778
- output = Option30.String("--output");
20894
+ output = Option31.String("--output");
20779
20895
  async executeCommand() {
20780
20896
  const mode = resolveOutputMode(
20781
20897
  this.output,
@@ -20903,7 +21019,7 @@ var PlatformUpdateCommand = class extends M8tCommand {
20903
21019
  };
20904
21020
 
20905
21021
  // src/commands/platform/converge.ts
20906
- import { Command as Command33 } from "clipanion";
21022
+ import { Command as Command34 } from "clipanion";
20907
21023
 
20908
21024
  // src/lib/platform-converge-mi.ts
20909
21025
  import { ManagedIdentityCredential } from "@azure/identity";
@@ -21178,7 +21294,7 @@ async function failIfStillInFlight(client, now, error) {
21178
21294
  }
21179
21295
  var PlatformConvergeCommand = class extends M8tCommand {
21180
21296
  static paths = [["platform", "converge"]];
21181
- static usage = Command33.Usage({
21297
+ static usage = Command34.Usage({
21182
21298
  category: "Platform",
21183
21299
  description: "Headless updater-job driver: claim a pending apply-request and converge the platform to it.",
21184
21300
  details: "The Managed-Identity-authenticated entry point run by the updater Container Apps job. One invocation is one tick: it claims the pending apply-request row (if any), refuses a downgrade against the installed stamp, self-fetches and validates the target manifest, self-updates its own engine image when the manifest requires a newer CLI, then drives the converge engine behind the health-gate + auto-rollback. Reads its subscription/RG/endpoint/channel from env (MI_CLIENT_ID, SUBSCRIPTION_ID, RESOURCE_GROUP, FOUNDRY_ENDPOINT, M8T_UPDATE_CHANNEL_URL). Not intended for interactive use \u2014 the founder-facing path is 'm8t platform update'."
@@ -21394,7 +21510,7 @@ function targetManifestSource(ctx, target) {
21394
21510
 
21395
21511
  // src/commands/platform/seed-stamp.ts
21396
21512
  import { readFileSync as readFileSync17 } from "fs";
21397
- import { Command as Command34, Option as Option31 } from "clipanion";
21513
+ import { Command as Command35, Option as Option32 } from "clipanion";
21398
21514
  import { DefaultAzureCredential as DefaultAzureCredential18, ManagedIdentityCredential as ManagedIdentityCredential2 } from "@azure/identity";
21399
21515
  init_errors();
21400
21516
 
@@ -21526,15 +21642,15 @@ async function seedStamp2(args) {
21526
21642
  }
21527
21643
  var PlatformSeedStampCommand = class extends M8tCommand {
21528
21644
  static paths = [["platform", "seed-stamp"]];
21529
- static usage = Command34.Usage({
21645
+ static usage = Command35.Usage({
21530
21646
  description: "INTERNAL: write the initial installed-state stamp from a build-time install descriptor.",
21531
21647
  details: "Used by the cloud installer at the end of a from-zero install so the platform records which release it is running. Writes the stamp ONLY IF ABSENT \u2014 it never overwrites a stamp written by the converge engine, so a re-run or a container restart is harmless. Not a founder-facing command: to change what is installed, use 'm8t platform update'."
21532
21648
  });
21533
- descriptor = Option31.String("--descriptor", { description: "Path to install-descriptor.json (baked into the installer image)." });
21534
- subscription = Option31.String("--subscription");
21535
- resourceGroup = Option31.String("--resource-group");
21536
- miClientId = Option31.String("--mi-client-id", { description: "Authenticate as this user-assigned managed identity instead of the ambient credential." });
21537
- output = Option31.String("--output");
21649
+ descriptor = Option32.String("--descriptor", { description: "Path to install-descriptor.json (baked into the installer image)." });
21650
+ subscription = Option32.String("--subscription");
21651
+ resourceGroup = Option32.String("--resource-group");
21652
+ miClientId = Option32.String("--mi-client-id", { description: "Authenticate as this user-assigned managed identity instead of the ambient credential." });
21653
+ output = Option32.String("--output");
21538
21654
  async executeCommand() {
21539
21655
  const mode = resolveOutputMode(this.output, this.context.stdout);
21540
21656
  const need = (v, flag) => {
@@ -21566,7 +21682,7 @@ var PlatformSeedStampCommand = class extends M8tCommand {
21566
21682
  };
21567
21683
 
21568
21684
  // src/commands/platform/stamp-build.ts
21569
- import { Command as Command35, Option as Option32 } from "clipanion";
21685
+ import { Command as Command36, Option as Option33 } from "clipanion";
21570
21686
  import { DefaultAzureCredential as DefaultAzureCredential19, ManagedIdentityCredential as ManagedIdentityCredential3 } from "@azure/identity";
21571
21687
  init_errors();
21572
21688
 
@@ -21600,17 +21716,17 @@ function buildRunningBuildStamp(input) {
21600
21716
  // src/commands/platform/stamp-build.ts
21601
21717
  var PlatformStampBuildCommand = class extends M8tCommand {
21602
21718
  static paths = [["platform", "stamp-build"]];
21603
- static usage = Command35.Usage({
21719
+ static usage = Command36.Usage({
21604
21720
  description: "Record the currently running build as this install's platform version.",
21605
21721
  details: "For installs that are deployed continuously rather than from a published release. Unlike the install-time record, this overwrites on every run \u2014 the running build is the truth. Only components this writer deploys are reported; the rest are marked as managed elsewhere."
21606
21722
  });
21607
- version = Option32.String("--version", { description: "The running build's own version, bare X.Y.Z." });
21608
- gatewayTag = Option32.String("--gateway-tag", { description: "The tag of the gateway image this build deployed." });
21609
- gatewayDigest = Option32.String("--gateway-digest", { description: "The digest of the gateway image this build deployed." });
21610
- subscription = Option32.String("--subscription");
21611
- resourceGroup = Option32.String("--resource-group");
21612
- miClientId = Option32.String("--mi-client-id", { description: "Authenticate as this user-assigned managed identity instead of the ambient credential." });
21613
- output = Option32.String("--output");
21723
+ version = Option33.String("--version", { description: "The running build's own version, bare X.Y.Z." });
21724
+ gatewayTag = Option33.String("--gateway-tag", { description: "The tag of the gateway image this build deployed." });
21725
+ gatewayDigest = Option33.String("--gateway-digest", { description: "The digest of the gateway image this build deployed." });
21726
+ subscription = Option33.String("--subscription");
21727
+ resourceGroup = Option33.String("--resource-group");
21728
+ miClientId = Option33.String("--mi-client-id", { description: "Authenticate as this user-assigned managed identity instead of the ambient credential." });
21729
+ output = Option33.String("--output");
21614
21730
  async executeCommand() {
21615
21731
  const mode = resolveOutputMode(this.output, this.context.stdout);
21616
21732
  const need = (v, flag) => {
@@ -21662,7 +21778,7 @@ var PlatformStampBuildCommand = class extends M8tCommand {
21662
21778
  };
21663
21779
 
21664
21780
  // src/commands/platform/policy.ts
21665
- import { Command as Command36, Option as Option33 } from "clipanion";
21781
+ import { Command as Command37, Option as Option34 } from "clipanion";
21666
21782
  import { DefaultAzureCredential as DefaultAzureCredential20, ManagedIdentityCredential as ManagedIdentityCredential4 } from "@azure/identity";
21667
21783
  init_errors();
21668
21784
 
@@ -21718,16 +21834,16 @@ async function readPolicy(opts) {
21718
21834
  // src/commands/platform/policy.ts
21719
21835
  var PlatformPolicyCommand = class extends M8tCommand {
21720
21836
  static paths = [["platform", "policy"]];
21721
- static usage = Command36.Usage({
21837
+ static usage = Command37.Usage({
21722
21838
  description: "Show or set how this install handles available platform updates.",
21723
21839
  details: "Modes: 'notify-only' shows updates but never applies them; 'auto-critical' (the default when unset) applies critical releases without asking; 'auto-all' applies every release. Use 'notify-only' where something else already controls what is deployed.",
21724
21840
  examples: [["Show the current mode", "m8t platform policy"], ["Never apply automatically", "m8t platform policy --set notify-only"]]
21725
21841
  });
21726
- set = Option33.String("--set", { description: "notify-only | auto-critical | auto-all" });
21727
- subscription = Option33.String("--subscription");
21728
- resourceGroup = Option33.String("--resource-group");
21729
- miClientId = Option33.String("--mi-client-id");
21730
- output = Option33.String("--output");
21842
+ set = Option34.String("--set", { description: "notify-only | auto-critical | auto-all" });
21843
+ subscription = Option34.String("--subscription");
21844
+ resourceGroup = Option34.String("--resource-group");
21845
+ miClientId = Option34.String("--mi-client-id");
21846
+ output = Option34.String("--output");
21731
21847
  async executeCommand() {
21732
21848
  const mode = resolveOutputMode(this.output, this.context.stdout);
21733
21849
  const need = (v, flag) => {
@@ -21773,7 +21889,7 @@ var PlatformPolicyCommand = class extends M8tCommand {
21773
21889
  };
21774
21890
 
21775
21891
  // src/commands/platform/enable-cost-report.ts
21776
- import { Command as Command37, Option as Option34 } from "clipanion";
21892
+ import { Command as Command38, Option as Option35 } from "clipanion";
21777
21893
 
21778
21894
  // src/lib/wire-gateway-acs.ts
21779
21895
  init_rbac();
@@ -21813,18 +21929,18 @@ async function wireGatewayForAcs(args) {
21813
21929
  init_errors();
21814
21930
  var PlatformEnableCostReportCommand = class extends M8tCommand {
21815
21931
  static paths = [["platform", "enable-cost-report"]];
21816
- static usage = Command37.Usage({
21932
+ static usage = Command38.Usage({
21817
21933
  description: "Wire the deployed gateway to send the bi-weekly cost report via ACS Email.",
21818
21934
  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')."
21819
21935
  });
21820
- subscription = Option34.String("--subscription");
21821
- resourceGroup = Option34.String("--resource-group", {
21936
+ subscription = Option35.String("--subscription");
21937
+ resourceGroup = Option35.String("--resource-group", {
21822
21938
  description: "m8t resource group to disambiguate the gateway (multi-deployment subscriptions)."
21823
21939
  });
21824
- acsEndpoint = Option34.String("--acs-endpoint", { required: true, description: "ACS data-plane endpoint, e.g. https://acs-<name>.communication.azure.com/" });
21825
- acsSender = Option34.String("--acs-sender", { required: true, description: "Managed-domain sender address, e.g. DoNotReply@<guid>.azurecomm.net" });
21826
- acsResourceId = Option34.String("--acs-resource-id", { required: true, description: "ARM resource id of the acs-<name> Communication Service \u2014 the role-grant scope." });
21827
- output = Option34.String("--output");
21940
+ acsEndpoint = Option35.String("--acs-endpoint", { required: true, description: "ACS data-plane endpoint, e.g. https://acs-<name>.communication.azure.com/" });
21941
+ acsSender = Option35.String("--acs-sender", { required: true, description: "Managed-domain sender address, e.g. DoNotReply@<guid>.azurecomm.net" });
21942
+ acsResourceId = Option35.String("--acs-resource-id", { required: true, description: "ARM resource id of the acs-<name> Communication Service \u2014 the role-grant scope." });
21943
+ output = Option35.String("--output");
21828
21944
  async executeCommand() {
21829
21945
  const mode = resolveOutputMode(
21830
21946
  this.output,
@@ -21898,45 +22014,45 @@ var PlatformEnableCostReportCommand = class extends M8tCommand {
21898
22014
  };
21899
22015
 
21900
22016
  // src/commands/platform/enable-auto-update.ts
21901
- import { Command as Command38, Option as Option35 } from "clipanion";
22017
+ import { Command as Command39, Option as Option36 } from "clipanion";
21902
22018
  import { confirm as confirm6 } from "@inquirer/prompts";
21903
22019
  import { DefaultAzureCredential as DefaultAzureCredential21 } from "@azure/identity";
21904
22020
  init_errors();
21905
22021
  var PlatformEnableAutoUpdateCommand = class extends M8tCommand {
21906
22022
  static paths = [["platform", "enable-auto-update"]];
21907
- static usage = Command38.Usage({
22023
+ static usage = Command39.Usage({
21908
22024
  category: "Platform",
21909
22025
  description: "Retrofit the auto-updater (MI + cron job + role assignments) onto an existing install.",
21910
22026
  details: "For an install that predates the Platform Update Framework: recovers the deployment's resource-name suffix (from the stamped system/infra-params row, or by verified derivation from the live gateway), recovers the other bicep params from live state (WITHOUT changing the deployed gateway image), and re-runs deploy/main.bicep with provisionUpdater=true \u2014 which provisions the updater managed identity, the cron Container Apps Job, and every role assignment (Owner@RG + Foundry User@account + Storage Table + Storage Blob + AcrPull), all scoped to the resource group. On success, backfills system/infra-params so future converges never have to re-derive the suffix. Idempotent \u2014 safe to re-run."
21911
22027
  });
21912
- subscription = Option35.String("--subscription");
21913
- resourceGroup = Option35.String("--resource-group", {
22028
+ subscription = Option36.String("--subscription");
22029
+ resourceGroup = Option36.String("--resource-group", {
21914
22030
  description: "m8t resource group to disambiguate the gateway (multi-deployment subscriptions)."
21915
22031
  });
21916
- suffix = Option35.String("--suffix", {
22032
+ suffix = Option36.String("--suffix", {
21917
22033
  description: "The existing deployment's resource-name suffix. Required when it cannot be recovered from system/infra-params or the live gateway."
21918
22034
  });
21919
- installerImage = Option35.String("--installer-image", {
22035
+ installerImage = Option36.String("--installer-image", {
21920
22036
  required: true,
21921
22037
  description: "Updater CA-Job image ref (the converge engine at the current release). Required \u2014 an empty image would skip provisioning."
21922
22038
  });
21923
- updateCron = Option35.String("--update-cron", {
22039
+ updateCron = Option36.String("--update-cron", {
21924
22040
  description: "Cron schedule for the updater job (bicep default applies when omitted)."
21925
22041
  });
21926
- channelUrl = Option35.String("--channel-url", {
22042
+ channelUrl = Option36.String("--channel-url", {
21927
22043
  description: "Release-channel URL the updater job polls (bicep default applies when omitted)."
21928
22044
  });
21929
- location = Option35.String("--location", {
22045
+ location = Option36.String("--location", {
21930
22046
  description: "Region for the updater identity + job. Defaults to the resource group's existing resources."
21931
22047
  });
21932
- foundryTracing = Option35.String("--foundry-tracing", {
22048
+ foundryTracing = Option36.String("--foundry-tracing", {
21933
22049
  description: "project | account | skip. Pass the value the install was deployed with \u2014 omitting it lets the bicep default (project) switch tracing on."
21934
22050
  });
21935
- endpoint = Option35.String("--endpoint", {
22051
+ endpoint = Option36.String("--endpoint", {
21936
22052
  description: "Foundry project endpoint URL. Disambiguates the project in a multi-project subscription."
21937
22053
  });
21938
- yes = Option35.Boolean("--yes", false);
21939
- output = Option35.String("--output");
22054
+ yes = Option36.Boolean("--yes", false);
22055
+ output = Option36.String("--output");
21940
22056
  async executeCommand() {
21941
22057
  const mode = resolveOutputMode(
21942
22058
  this.output,
@@ -22073,7 +22189,7 @@ var PlatformEnableAutoUpdateCommand = class extends M8tCommand {
22073
22189
  };
22074
22190
 
22075
22191
  // src/commands/deploy.ts
22076
- import { Command as Command39, Option as Option36 } from "clipanion";
22192
+ import { Command as Command40, Option as Option37 } from "clipanion";
22077
22193
 
22078
22194
  // src/lib/app-reg.ts
22079
22195
  init_errors();
@@ -22321,6 +22437,17 @@ async function ensureGatewayRedirectUri(gatewayClientId, fqdn) {
22321
22437
  }
22322
22438
  await patchRedirectUris(appObjectId, fqdn);
22323
22439
  }
22440
+ async function resolveAppObjectIdForWrite(opts) {
22441
+ if (opts.appObjectId) return opts.appObjectId;
22442
+ if (!opts.clientId) return null;
22443
+ try {
22444
+ return await azJson(
22445
+ ["ad", "app", "show", "--id", opts.clientId, "--query", "id", "--output", "json"]
22446
+ ) ?? null;
22447
+ } catch {
22448
+ return null;
22449
+ }
22450
+ }
22324
22451
  async function patchRedirectUris(appObjectId, fqdn) {
22325
22452
  const targetUri = `https://${fqdn}`;
22326
22453
  const existing = await azJson(
@@ -22553,52 +22680,52 @@ function classifyWhatIf(changes) {
22553
22680
  var DEFAULT_IMAGE_REF = "ghcr.io/m8t-labs/m8t:latest";
22554
22681
  var DeployCommand = class extends M8tCommand {
22555
22682
  static paths = [["deploy"]];
22556
- static usage = Command39.Usage({
22683
+ static usage = Command40.Usage({
22557
22684
  description: "Deploy (or update) the m8t gateway/webapp stack via Bicep.",
22558
22685
  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/config.yaml, ensures the resource group, and runs deploy/main.bicep. The repo is located via ~/.m8t/repo-root."
22559
22686
  });
22560
- subscription = Option36.String("--subscription");
22561
- resourceGroup = Option36.String("--resource-group", "rg-m8t-stack");
22562
- location = Option36.String("--location", "eastus");
22563
- suffix = Option36.String("--suffix", "");
22564
- imageRef = Option36.String("--image-ref", DEFAULT_IMAGE_REF);
22565
- acrPullIdentity = Option36.String("--acrpull-identity");
22566
- acrResourceId = Option36.String("--acr-resource-id");
22567
- foundryEndpoint = Option36.String("--foundry-endpoint");
22568
- foundryResourceId = Option36.String("--foundry-resource-id");
22569
- foundryTracing = Option36.String("--foundry-tracing");
22687
+ subscription = Option37.String("--subscription");
22688
+ resourceGroup = Option37.String("--resource-group", "rg-m8t-stack");
22689
+ location = Option37.String("--location", "eastus");
22690
+ suffix = Option37.String("--suffix", "");
22691
+ imageRef = Option37.String("--image-ref", DEFAULT_IMAGE_REF);
22692
+ acrPullIdentity = Option37.String("--acrpull-identity");
22693
+ acrResourceId = Option37.String("--acr-resource-id");
22694
+ foundryEndpoint = Option37.String("--foundry-endpoint");
22695
+ foundryResourceId = Option37.String("--foundry-resource-id");
22696
+ foundryTracing = Option37.String("--foundry-tracing");
22570
22697
  // project | account | skip (bicep default: project)
22571
- clientId = Option36.String("--client-id");
22572
- whatIf = Option36.Boolean("--what-if", false);
22698
+ clientId = Option37.String("--client-id");
22699
+ whatIf = Option37.Boolean("--what-if", false);
22573
22700
  // Only meaningful with --what-if. Routes the comparison through the
22574
22701
  // value-free renderers (see ./lib/whatif-redact.js) instead of the default
22575
22702
  // before/after renderer. Defaults false so a local, interactive run keeps
22576
22703
  // showing values — that is the whole diagnostic point of --what-if.
22577
22704
  // Automation that forwards this output anywhere non-private (a CI log, an
22578
22705
  // issue) MUST pass --redact.
22579
- redact = Option36.Boolean("--redact", false);
22580
- output = Option36.String("--output");
22706
+ redact = Option37.Boolean("--redact", false);
22707
+ output = Option37.String("--output");
22581
22708
  // Subscription-scoped role assignments. Omitted ⇒ the template default (true).
22582
22709
  // Pass false when deploying as a principal scoped to the resource group only:
22583
22710
  // it cannot deploy at subscription scope, and those assignments persist
22584
22711
  // idempotently from the initial deployment anyway.
22585
- assignSubscriptionRoles = Option36.String("--assign-subscription-roles");
22712
+ assignSubscriptionRoles = Option37.String("--assign-subscription-roles");
22586
22713
  // Referee — all optional, undefined by default ⇒ the bicep defaults
22587
22714
  // apply (dormant: gatewayCpu=0.25, gatewayMemory=0.5Gi, every referee/exam var
22588
22715
  // empty). Only pass these when explicitly enabling the referee exam stack.
22589
- gatewayCpu = Option36.String("--gateway-cpu");
22590
- gatewayMemory = Option36.String("--gateway-memory");
22591
- refereeEnabled = Option36.String("--referee-enabled");
22592
- refereeBrainRepos = Option36.String("--referee-brain-repos");
22593
- refereeFeedRepo = Option36.String("--referee-feed-repo");
22594
- refereeInstallationId = Option36.String("--referee-installation-id");
22595
- refereeWebhookHmacKvUri = Option36.String("--referee-webhook-hmac-kv-uri");
22596
- examKvUri = Option36.String("--exam-kv-uri");
22597
- examLaWorkspaceId = Option36.String("--exam-la-workspace-id");
22598
- brainEvalDeployment = Option36.String("--brain-eval-deployment");
22599
- brainAppLogin = Option36.String("--brain-app-login");
22600
- refereeCheckpointDir = Option36.String("--referee-checkpoint-dir");
22601
- examApiBase = Option36.String("--exam-api-base");
22716
+ gatewayCpu = Option37.String("--gateway-cpu");
22717
+ gatewayMemory = Option37.String("--gateway-memory");
22718
+ refereeEnabled = Option37.String("--referee-enabled");
22719
+ refereeBrainRepos = Option37.String("--referee-brain-repos");
22720
+ refereeFeedRepo = Option37.String("--referee-feed-repo");
22721
+ refereeInstallationId = Option37.String("--referee-installation-id");
22722
+ refereeWebhookHmacKvUri = Option37.String("--referee-webhook-hmac-kv-uri");
22723
+ examKvUri = Option37.String("--exam-kv-uri");
22724
+ examLaWorkspaceId = Option37.String("--exam-la-workspace-id");
22725
+ brainEvalDeployment = Option37.String("--brain-eval-deployment");
22726
+ brainAppLogin = Option37.String("--brain-app-login");
22727
+ refereeCheckpointDir = Option37.String("--referee-checkpoint-dir");
22728
+ examApiBase = Option37.String("--exam-api-base");
22602
22729
  async executeCommand() {
22603
22730
  const mode = resolveOutputMode(
22604
22731
  this.output,
@@ -22684,9 +22811,6 @@ var DeployCommand = class extends M8tCommand {
22684
22811
  }
22685
22812
  log(this.clientId ? `using existing app reg ${this.clientId}` : "ensuring Entra app reg\u2026");
22686
22813
  const app = await ensureAppReg({ tenantId: account.tenantId, clientId: this.clientId });
22687
- if (app.appObjectId === null && this.clientId) {
22688
- log(colors.dim(" (BYO app reg \u2014 skipping Graph writes; ensure it has http://localhost:3000 + the deployed FQDN as SPA redirect URIs and Expose-an-API)"));
22689
- }
22690
22814
  await writeFoundryConfig({ tenantId: app.tenantId, clientId: app.clientId, projectEndpoint: foundryEndpoint });
22691
22815
  log(`ensuring resource group ${this.resourceGroup}\u2026`);
22692
22816
  await ensureResourceGroup(this.resourceGroup, this.location);
@@ -22732,8 +22856,16 @@ var DeployCommand = class extends M8tCommand {
22732
22856
  params,
22733
22857
  deploymentName: `m8t-deploy-${account.subscriptionId.slice(0, 8)}`
22734
22858
  });
22735
- if (app.appObjectId) {
22736
- await patchRedirectUris(app.appObjectId, outputs.containerAppFqdn);
22859
+ const writableAppObjectId = await resolveAppObjectIdForWrite({
22860
+ appObjectId: app.appObjectId,
22861
+ clientId: this.clientId
22862
+ });
22863
+ if (writableAppObjectId) {
22864
+ await patchRedirectUris(writableAppObjectId, outputs.containerAppFqdn);
22865
+ } else {
22866
+ log(colors.dim(
22867
+ ` (could not register the sign-in redirect URI automatically \u2014 add https://${outputs.containerAppFqdn} as an SPA redirect URI on app registration ${app.clientId}, or sign-in will fail with AADSTS50011)`
22868
+ ));
22737
22869
  }
22738
22870
  const webappUrl = `https://${outputs.containerAppFqdn}`;
22739
22871
  if (mode === "json") {
@@ -22758,7 +22890,7 @@ var DeployCommand = class extends M8tCommand {
22758
22890
 
22759
22891
  // src/commands/eval/skill.ts
22760
22892
  import { spawnSync as spawnSync4 } from "child_process";
22761
- import { Command as Command40, Option as Option37 } from "clipanion";
22893
+ import { Command as Command41, Option as Option38 } from "clipanion";
22762
22894
  init_errors();
22763
22895
  var DECISIONS = /* @__PURE__ */ new Set(["promote", "reject", "needs_review"]);
22764
22896
  var JUDGE_STATUSES = /* @__PURE__ */ new Set(["ok", "skipped", "unavailable"]);
@@ -22783,14 +22915,14 @@ function parseVerdict(stdout) {
22783
22915
  }
22784
22916
  var EvalSkillCommand = class extends M8tCommand {
22785
22917
  static paths = [["eval", "skill"]];
22786
- static usage = Command40.Usage({
22918
+ static usage = Command41.Usage({
22787
22919
  description: "Vet one inbox skill candidate: promote / reject / needs_review. Shells out to the Python `brain-eval` core (override its path with $BRAIN_EVAL_BIN)."
22788
22920
  });
22789
- candidate = Option37.String();
22790
- skillsDir = Option37.String("--skills-dir");
22791
- noJudge = Option37.Boolean("--no-judge", false);
22792
- deployment = Option37.String("--deployment");
22793
- output = Option37.String("--output");
22921
+ candidate = Option38.String();
22922
+ skillsDir = Option38.String("--skills-dir");
22923
+ noJudge = Option38.Boolean("--no-judge", false);
22924
+ deployment = Option38.String("--deployment");
22925
+ output = Option38.String("--output");
22794
22926
  executeCommand() {
22795
22927
  return Promise.resolve(this._runCommand());
22796
22928
  }
@@ -22849,7 +22981,7 @@ var EvalSkillCommand = class extends M8tCommand {
22849
22981
  import { spawnSync as spawnSync5 } from "child_process";
22850
22982
  import { writeFileSync as writeFileSync6, mkdirSync as mkdirSync5, readFileSync as readFileSync18, existsSync as existsSync15, readdirSync as readdirSync2 } from "fs";
22851
22983
  import { join as join27 } from "path";
22852
- import { Command as Command41, Option as Option38 } from "clipanion";
22984
+ import { Command as Command42, Option as Option39 } from "clipanion";
22853
22985
  init_errors();
22854
22986
  init_esm();
22855
22987
  function parseArmToken(tok, opts) {
@@ -23079,24 +23211,24 @@ function buildPlan(args) {
23079
23211
  }
23080
23212
  var EvalExamCommand = class extends M8tCommand {
23081
23213
  static paths = [["eval", "exam"]];
23082
- static usage = Command41.Usage({
23214
+ static usage = Command42.Usage({
23083
23215
  description: "Run a brain exam: 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."
23084
23216
  });
23085
- worker = Option38.String();
23086
- arms = Option38.String("--arms");
23087
- taskSet = Option38.String("--task-set");
23088
- examType = Option38.String("--exam-type");
23089
- skill = Option38.String("--skill");
23090
- reps = Option38.String("-n,--reps");
23091
- probes = Option38.String("--probes");
23092
- pool = Option38.String("--pool");
23093
- out = Option38.String("--out");
23094
- dryRun = Option38.Boolean("--dry-run", false);
23095
- keepArms = Option38.Boolean("--keep-arms", false);
23096
- allowStub = Option38.Boolean("--allow-stub", false);
23097
- deployment = Option38.String("--deployment");
23098
- output = Option38.String("--output");
23099
- observeWaitS = Option38.String("--observe-wait-s");
23217
+ worker = Option39.String();
23218
+ arms = Option39.String("--arms");
23219
+ taskSet = Option39.String("--task-set");
23220
+ examType = Option39.String("--exam-type");
23221
+ skill = Option39.String("--skill");
23222
+ reps = Option39.String("-n,--reps");
23223
+ probes = Option39.String("--probes");
23224
+ pool = Option39.String("--pool");
23225
+ out = Option39.String("--out");
23226
+ dryRun = Option39.Boolean("--dry-run", false);
23227
+ keepArms = Option39.Boolean("--keep-arms", false);
23228
+ allowStub = Option39.Boolean("--allow-stub", false);
23229
+ deployment = Option39.String("--deployment");
23230
+ output = Option39.String("--output");
23231
+ observeWaitS = Option39.String("--observe-wait-s");
23100
23232
  async executeCommand() {
23101
23233
  await Promise.resolve();
23102
23234
  const worker = typeof this.worker === "string" ? this.worker : void 0;
@@ -23211,10 +23343,10 @@ var EvalExamCommand = class extends M8tCommand {
23211
23343
  };
23212
23344
 
23213
23345
  // src/commands/version.ts
23214
- import { Command as Command42, Option as Option39 } from "clipanion";
23346
+ import { Command as Command43, Option as Option40 } from "clipanion";
23215
23347
  var VersionCommand = class extends M8tCommand {
23216
23348
  static paths = [["version"], ["--version"], ["-v"]];
23217
- static usage = Command42.Usage({
23349
+ static usage = Command43.Usage({
23218
23350
  description: "Print the CLI version.",
23219
23351
  details: "Prints the m8t CLI version. With --verbose, also prints Node version and platform.",
23220
23352
  examples: [
@@ -23222,8 +23354,8 @@ var VersionCommand = class extends M8tCommand {
23222
23354
  ["Print as JSON", "$0 version --output json"]
23223
23355
  ]
23224
23356
  });
23225
- output = Option39.String("--output", { description: "pretty | json | auto (default)" });
23226
- verbose = Option39.Boolean("--verbose", false);
23357
+ output = Option40.String("--output", { description: "pretty | json | auto (default)" });
23358
+ verbose = Option40.Boolean("--verbose", false);
23227
23359
  executeCommand() {
23228
23360
  const mode = resolveOutputMode(
23229
23361
  this.output ?? "auto",
@@ -23254,18 +23386,18 @@ var VersionCommand = class extends M8tCommand {
23254
23386
  };
23255
23387
 
23256
23388
  // src/commands/whoami.ts
23257
- import { Command as Command43, Option as Option40 } from "clipanion";
23389
+ import { Command as Command44, Option as Option41 } from "clipanion";
23258
23390
  var WhoamiCommand = class extends M8tCommand {
23259
23391
  static paths = [["whoami"]];
23260
- static usage = Command43.Usage({
23392
+ static usage = Command44.Usage({
23261
23393
  description: "Show your identity + the gateway you'll talk to. Probes the backend."
23262
23394
  });
23263
- output = Option40.String("--output");
23264
- verbose = Option40.Boolean("--verbose", false);
23265
- subscription = Option40.String("--subscription", {
23395
+ output = Option41.String("--output");
23396
+ verbose = Option41.Boolean("--verbose", false);
23397
+ subscription = Option41.String("--subscription", {
23266
23398
  description: "Azure subscription ID to discover gateway in (defaults to active az subscription)."
23267
23399
  });
23268
- resourceGroup = Option40.String("--resource-group", {
23400
+ resourceGroup = Option41.String("--resource-group", {
23269
23401
  description: "m8t resource group to disambiguate the gateway (multi-deployment subscriptions)."
23270
23402
  });
23271
23403
  async executeCommand() {
@@ -23330,7 +23462,7 @@ var WhoamiCommand = class extends M8tCommand {
23330
23462
  };
23331
23463
 
23332
23464
  // src/commands/status.ts
23333
- import { Command as Command44, Option as Option41 } from "clipanion";
23465
+ import { Command as Command45, Option as Option42 } from "clipanion";
23334
23466
 
23335
23467
  // src/lib/azd.ts
23336
23468
  init_errors();
@@ -23395,10 +23527,10 @@ async function resolveLocalContext() {
23395
23527
  // src/commands/status.ts
23396
23528
  var StatusCommand = class extends M8tCommand {
23397
23529
  static paths = [["status"]];
23398
- static usage = Command44.Usage({
23530
+ static usage = Command45.Usage({
23399
23531
  description: "Show the local m8t context: identity, config.yaml, gateway cache, azd mode."
23400
23532
  });
23401
- output = Option41.String("--output");
23533
+ output = Option42.String("--output");
23402
23534
  async executeCommand() {
23403
23535
  const mode = resolveOutputMode(
23404
23536
  this.output,
@@ -23436,7 +23568,7 @@ var StatusCommand = class extends M8tCommand {
23436
23568
  };
23437
23569
 
23438
23570
  // src/commands/doctor.ts
23439
- import { Command as Command45, Option as Option42 } from "clipanion";
23571
+ import { Command as Command46, Option as Option43 } from "clipanion";
23440
23572
  import { DefaultAzureCredential as DefaultAzureCredential22 } from "@azure/identity";
23441
23573
  import * as fs26 from "fs";
23442
23574
  import * as os11 from "os";
@@ -23712,12 +23844,12 @@ function probeLegacyStateDir() {
23712
23844
  }
23713
23845
  var DoctorCommand = class extends M8tCommand {
23714
23846
  static paths = [["doctor"]];
23715
- static usage = Command45.Usage({
23847
+ static usage = Command46.Usage({
23716
23848
  description: "Diagnose the local m8t setup: az login, config.yaml, gateway, Foundry data-plane."
23717
23849
  });
23718
- output = Option42.String("--output");
23719
- agent = Option42.String("--agent");
23720
- resourceGroup = Option42.String("--resource-group", {
23850
+ output = Option43.String("--output");
23851
+ agent = Option43.String("--agent");
23852
+ resourceGroup = Option43.String("--resource-group", {
23721
23853
  description: "m8t resource group to disambiguate the gateway (multi-deployment subscriptions)."
23722
23854
  });
23723
23855
  async executeCommand() {
@@ -23834,7 +23966,7 @@ var DoctorCommand = class extends M8tCommand {
23834
23966
  };
23835
23967
 
23836
23968
  // src/commands/switch.ts
23837
- import { Command as Command46, Option as Option43 } from "clipanion";
23969
+ import { Command as Command47, Option as Option44 } from "clipanion";
23838
23970
 
23839
23971
  // src/lib/profiles.ts
23840
23972
  import * as fs27 from "fs/promises";
@@ -23974,14 +24106,14 @@ async function profileSwitch(name, asName) {
23974
24106
  init_errors();
23975
24107
  var SwitchCommand = class extends M8tCommand {
23976
24108
  static paths = [["switch"]];
23977
- static usage = Command46.Usage({
24109
+ static usage = Command47.Usage({
23978
24110
  description: "Re-point local config at another deployment: --subscription <id|name> (discovery) or <profile>."
23979
24111
  });
23980
- profile = Option43.String({ required: false });
23981
- subscription = Option43.String("--subscription");
23982
- list = Option43.Boolean("--list", false);
23983
- as = Option43.String("--as");
23984
- output = Option43.String("--output");
24112
+ profile = Option44.String({ required: false });
24113
+ subscription = Option44.String("--subscription");
24114
+ list = Option44.Boolean("--list", false);
24115
+ as = Option44.String("--as");
24116
+ output = Option44.String("--output");
23985
24117
  async executeCommand() {
23986
24118
  const mode = resolveOutputMode(
23987
24119
  this.output,
@@ -24038,7 +24170,7 @@ var SwitchCommand = class extends M8tCommand {
24038
24170
 
24039
24171
  // src/commands/open.ts
24040
24172
  import { spawn as spawn5 } from "child_process";
24041
- import { Command as Command47, Option as Option44 } from "clipanion";
24173
+ import { Command as Command48, Option as Option45 } from "clipanion";
24042
24174
 
24043
24175
  // src/lib/open-targets.ts
24044
24176
  init_errors();
@@ -24084,14 +24216,14 @@ function openUrl(url) {
24084
24216
  }
24085
24217
  var OpenCommand = class extends M8tCommand {
24086
24218
  static paths = [["open"]];
24087
- static usage = Command47.Usage({
24219
+ static usage = Command48.Usage({
24088
24220
  description: "Open the deployed webapp (default), the Foundry portal, or the resource group.",
24089
24221
  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)."
24090
24222
  });
24091
- target = Option44.String({ required: false });
24092
- print = Option44.Boolean("--print", false);
24093
- output = Option44.String("--output");
24094
- resourceGroup = Option44.String("--resource-group", {
24223
+ target = Option45.String({ required: false });
24224
+ print = Option45.Boolean("--print", false);
24225
+ output = Option45.String("--output");
24226
+ resourceGroup = Option45.String("--resource-group", {
24095
24227
  description: "m8t resource group to disambiguate the gateway (multi-deployment subscriptions)."
24096
24228
  });
24097
24229
  async executeCommand() {
@@ -24135,7 +24267,7 @@ var OpenCommand = class extends M8tCommand {
24135
24267
  };
24136
24268
 
24137
24269
  // src/commands/dream/run.ts
24138
- import { Command as Command48, Option as Option45 } from "clipanion";
24270
+ import { Command as Command49, Option as Option46 } from "clipanion";
24139
24271
  import { AzureCliCredential } from "@azure/identity";
24140
24272
  import { TableClient as TableClient7 } from "@azure/data-tables";
24141
24273
  import { AIProjectClient as AIProjectClient3 } from "@azure/ai-projects";
@@ -26362,20 +26494,20 @@ function redactTranscripts(input) {
26362
26494
  }
26363
26495
  var DreamRunCommand = class extends M8tCommand {
26364
26496
  static paths = [["dream", "run"]];
26365
- static usage = Command48.Usage({
26497
+ static usage = Command49.Usage({
26366
26498
  description: "Dry-run the brain consumption pipeline for one worker (no model call, no writes).",
26367
26499
  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."
26368
26500
  });
26369
- worker = Option45.String("--worker", { description: "Worker (canonical name) to harvest. Required." });
26370
- dryRun = Option45.Boolean("--dry-run", false, { description: "Read-only harvest; no model call, no writes." });
26371
- since = Option45.String("--since", { description: "ISO-8601 start override (rejected if malformed or future)." });
26372
- reset = Option45.Boolean("--reset", false, { description: "Ignore the stored cursor; read from the beginning." });
26373
- showTranscripts = Option45.Boolean("--show-transcripts", false, {
26501
+ worker = Option46.String("--worker", { description: "Worker (canonical name) to harvest. Required." });
26502
+ dryRun = Option46.Boolean("--dry-run", false, { description: "Read-only harvest; no model call, no writes." });
26503
+ since = Option46.String("--since", { description: "ISO-8601 start override (rejected if malformed or future)." });
26504
+ reset = Option46.Boolean("--reset", false, { description: "Ignore the stored cursor; read from the beginning." });
26505
+ showTranscripts = Option46.Boolean("--show-transcripts", false, {
26374
26506
  description: "Print transcript bodies (default: metadata only)."
26375
26507
  });
26376
- subscription = Option45.String("--subscription");
26377
- endpoint = Option45.String("--endpoint");
26378
- output = Option45.String("--output");
26508
+ subscription = Option46.String("--subscription");
26509
+ endpoint = Option46.String("--endpoint");
26510
+ output = Option46.String("--output");
26379
26511
  // Resolution seam — overridden by tests; built lazily at runtime otherwise.
26380
26512
  deps;
26381
26513
  async executeCommand() {
@@ -26723,7 +26855,7 @@ function defaultDeps(overrides) {
26723
26855
  }
26724
26856
 
26725
26857
  // src/commands/foundry/create.ts
26726
- import { Command as Command49, Option as Option46 } from "clipanion";
26858
+ import { Command as Command50, Option as Option47 } from "clipanion";
26727
26859
 
26728
26860
  // src/lib/foundry-create.ts
26729
26861
  init_errors();
@@ -26961,7 +27093,7 @@ async function createFoundryProject(args) {
26961
27093
  init_errors();
26962
27094
  var FoundryCreateCommand = class extends M8tCommand {
26963
27095
  static paths = [["foundry", "create"]];
26964
- static usage = Command49.Usage({
27096
+ static usage = Command50.Usage({
26965
27097
  description: "Create an AI Foundry (AIServices) account + project + model deployment from scratch.",
26966
27098
  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).",
26967
27099
  examples: [
@@ -26970,16 +27102,16 @@ var FoundryCreateCommand = class extends M8tCommand {
26970
27102
  ["Higher capacity for a reasoning model", "$0 foundry create --resource-group rg-m8t-stack --location eastus2 --model gpt-5-mini --capacity 250"]
26971
27103
  ]
26972
27104
  });
26973
- resourceGroup = Option46.String("--resource-group");
26974
- location = Option46.String("--location");
26975
- account = Option46.String("--account");
26976
- project = Option46.String("--project", "m8t");
26977
- model = Option46.String("--model", "gpt-4.1-mini");
26978
- modelVersion = Option46.String("--model-version", "2025-04-14");
26979
- capacity = Option46.String("--capacity", "50");
26980
- subscription = Option46.String("--subscription");
26981
- skipQuotaCheck = Option46.Boolean("--skip-quota-check", false);
26982
- output = Option46.String("--output");
27105
+ resourceGroup = Option47.String("--resource-group");
27106
+ location = Option47.String("--location");
27107
+ account = Option47.String("--account");
27108
+ project = Option47.String("--project", "m8t");
27109
+ model = Option47.String("--model", "gpt-4.1-mini");
27110
+ modelVersion = Option47.String("--model-version", "2025-04-14");
27111
+ capacity = Option47.String("--capacity", "50");
27112
+ subscription = Option47.String("--subscription");
27113
+ skipQuotaCheck = Option47.Boolean("--skip-quota-check", false);
27114
+ output = Option47.String("--output");
26983
27115
  async executeCommand() {
26984
27116
  const mode = resolveOutputMode(
26985
27117
  this.output,
@@ -27051,22 +27183,22 @@ var FoundryCreateCommand = class extends M8tCommand {
27051
27183
  };
27052
27184
 
27053
27185
  // src/commands/foundry/await-ready.ts
27054
- import { Command as Command50, Option as Option47 } from "clipanion";
27186
+ import { Command as Command51, Option as Option48 } from "clipanion";
27055
27187
  import { AzureCliCredential as AzureCliCredential2 } from "@azure/identity";
27056
27188
  init_errors();
27057
27189
  var FoundryAwaitReadyCommand = class extends M8tCommand {
27058
27190
  static paths = [["foundry", "await-ready"]];
27059
- static usage = Command50.Usage({
27191
+ static usage = Command51.Usage({
27060
27192
  description: "Wait until a freshly-created Foundry project's data plane reliably serves it.",
27061
27193
  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.",
27062
27194
  examples: [["Wait for a project to be ready", "$0 foundry await-ready --endpoint https://acc.services.ai.azure.com/api/projects/m8t"]]
27063
27195
  });
27064
- endpoint = Option47.String("--endpoint");
27065
- consecutive = Option47.String("--consecutive", "3");
27066
- attempts = Option47.String("--attempts", "60");
27067
- interval = Option47.String("--interval", "5");
27068
- subscription = Option47.String("--subscription");
27069
- output = Option47.String("--output");
27196
+ endpoint = Option48.String("--endpoint");
27197
+ consecutive = Option48.String("--consecutive", "3");
27198
+ attempts = Option48.String("--attempts", "60");
27199
+ interval = Option48.String("--interval", "5");
27200
+ subscription = Option48.String("--subscription");
27201
+ output = Option48.String("--output");
27070
27202
  async executeCommand() {
27071
27203
  const mode = resolveOutputMode(this.output, this.context.stdout);
27072
27204
  const endpoint = typeof this.endpoint === "string" ? this.endpoint : void 0;
@@ -27100,7 +27232,7 @@ var FoundryAwaitReadyCommand = class extends M8tCommand {
27100
27232
  };
27101
27233
 
27102
27234
  // src/commands/bootstrap/preflight.ts
27103
- import { Command as Command51, Option as Option48 } from "clipanion";
27235
+ import { Command as Command52, Option as Option49 } from "clipanion";
27104
27236
 
27105
27237
  // ../../packages/telemetry-contract/artifact/tier-map.ts
27106
27238
  var EVENT_TIERS = {
@@ -27116,8 +27248,12 @@ var EVENT_TIERS = {
27116
27248
  };
27117
27249
  var EVENT_ENUM = Object.keys(EVENT_TIERS);
27118
27250
 
27251
+ // ../../packages/telemetry-contract/artifact/cadence.ts
27252
+ var HEARTBEAT_CADENCE_MS = 3 * 60 * 60 * 1e3;
27253
+ var HEARTBEAT_CADENCE_HOURS = HEARTBEAT_CADENCE_MS / (60 * 60 * 1e3);
27254
+
27119
27255
  // ../../packages/telemetry-contract/src/disclosure.ts
27120
- var DISCLOSURE_TIER1 = "Operational data. To support your installation, m8t receives limited operational data linked to it \u2014 installation and update events, installed versions, and service health signals. Your installation is identified only by a random installation ID we generate at setup \u2014 an opaque value with no information encoded in it. No name, email, company, or subscription information is sent in the enrollment record unless you explicitly choose to share contact details for support. At enrollment, we also verify a cloud identity token to confirm the request comes from a real cloud account; that token names the account making the request, and is otherwise discarded immediately and never stored. This is service data used only to operate and support the platform; it contains none of your content. Details: TELEMETRY.md.";
27256
+ var DISCLOSURE_TIER1 = "Operational data. To support your installation, m8t receives limited operational data linked to it \u2014 installation and update events, installed versions, and service health signals. Your installation is identified only by a random installation ID we generate at setup \u2014 an opaque value with no information encoded in it. No name, email, company, or subscription information is sent in the enrollment record unless you explicitly choose to share contact details for support. At enrollment, we also verify a cloud identity token to confirm the request comes from a real cloud account; that token names the account making the request, and is otherwise discarded immediately and never stored. This is service data used only to operate and support the platform; it contains none of your content. After setup, you can turn this off in the web app's Settings, under Privacy; update checks keep working. Details: TELEMETRY.md.";
27121
27257
 
27122
27258
  // ../../packages/telemetry-contract/src/endpoints.ts
27123
27259
  var INGEST_BASE_URL = (process.env.M8T_INGEST_BASE_URL ?? "").trim() || "https://m8t-admin.wonderfuldesert-721e332f.eastus2.azurecontainerapps.io";
@@ -27211,7 +27347,7 @@ function buildPreflightBanner(who) {
27211
27347
  // src/commands/bootstrap/preflight.ts
27212
27348
  var BootstrapPreflightCommand = class extends M8tCommand {
27213
27349
  static paths = [["bootstrap", "preflight"]];
27214
- static usage = Command51.Usage({
27350
+ static usage = Command52.Usage({
27215
27351
  description: "Loudly verify you can install m8t (Owner/UAA + directory admin) and hard-stop if not.",
27216
27352
  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.",
27217
27353
  examples: [
@@ -27219,8 +27355,8 @@ var BootstrapPreflightCommand = class extends M8tCommand {
27219
27355
  ["BYO app registration (directory guests)", "$0 bootstrap preflight --client-id <appId>"]
27220
27356
  ]
27221
27357
  });
27222
- clientId = Option48.String("--client-id");
27223
- subscription = Option48.String("--subscription");
27358
+ clientId = Option49.String("--client-id");
27359
+ subscription = Option49.String("--subscription");
27224
27360
  async executeCommand() {
27225
27361
  const clientId = typeof this.clientId === "string" ? this.clientId : void 0;
27226
27362
  const account = await getAzAccount();
@@ -27283,7 +27419,7 @@ ${colors.error(" " + why)}
27283
27419
  import * as fs30 from "fs";
27284
27420
  import * as os14 from "os";
27285
27421
  import * as path32 from "path";
27286
- import { Command as Command52, Option as Option49 } from "clipanion";
27422
+ import { Command as Command53, Option as Option50 } from "clipanion";
27287
27423
  init_errors();
27288
27424
 
27289
27425
  // src/lib/bootstrap-mi.ts
@@ -27387,6 +27523,7 @@ function buildAciCreateArgs(s) {
27387
27523
  ];
27388
27524
  if (s.gatewayImageRef) env.push(`GATEWAY_IMAGE_REF=${s.gatewayImageRef}`);
27389
27525
  if (s.foundryTracing) env.push(`FOUNDRY_TRACING=${s.foundryTracing}`);
27526
+ if (s.skipBrains) env.push("SKIP_BRAINS=true");
27390
27527
  if (s.updateChannelUrl) env.push(`M8T_UPDATE_CHANNEL_URL=${s.updateChannelUrl}`);
27391
27528
  if (s.enrollContactEmail) env.push(`M8T_ENROLL_CONTACT_EMAIL=${s.enrollContactEmail}`);
27392
27529
  if (s.enrollCompany) env.push(`M8T_ENROLL_COMPANY=${s.enrollCompany}`);
@@ -27622,15 +27759,36 @@ function buildOccupiedRefusal(args) {
27622
27759
  ].join("\n");
27623
27760
  }
27624
27761
 
27762
+ // src/lib/bootstrap-launch-guards.ts
27763
+ function buildMissingCredsRefusal(credsPath) {
27764
+ return `
27765
+ ${colors.error("\u2717")} No GitHub App credentials found at ${colors.field(credsPath)}.
27766
+ Your workers' brains are private repositories created through that App, so the install
27767
+ needs it before it starts.
27768
+
27769
+ ${colors.hint("fix:")} m8t brain app-create --org <org>
27770
+
27771
+ `;
27772
+ }
27773
+ function buildOrgMismatchRefusal(args) {
27774
+ return `
27775
+ ${colors.error("\u2717")} The GitHub App on disk is installed on ${colors.field(args.recorded)}, but this launch asked for ${colors.field(args.requested)}.
27776
+ Brains would land in ${args.recorded}, not ${args.requested}.
27777
+
27778
+ ${colors.hint("fix:")} m8t brain app-create --org ${args.requested}
27779
+
27780
+ `;
27781
+ }
27782
+
27625
27783
  // src/commands/bootstrap/launch.ts
27626
27784
  var DEFAULT_RG = "rg-m8t-stack";
27627
27785
  var DEFAULT_INSTALLER = "ghcr.io/m8t-labs/m8t-installer";
27628
- var DEFAULT_INSTALLER_TAG = "v0.1.43";
27786
+ var DEFAULT_INSTALLER_TAG = "v0.1.44";
27629
27787
  var ACI_NAME = "m8t-installer";
27630
27788
  var MI_NAME = "m8t-installer-mi";
27631
27789
  var BootstrapLaunchCommand = class extends M8tCommand {
27632
27790
  static paths = [["bootstrap", "launch"]];
27633
- static usage = Command52.Usage({
27791
+ static usage = Command53.Usage({
27634
27792
  description: "Create + authorize the installer managed identity, then kick the cloud installer.",
27635
27793
  details: "Step 2 of `m8t bootstrap` (run after `preflight`). Ensures the resource group, creates the m8t 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/bootstrap.json for `status`/`reap`/`finish`.",
27636
27794
  examples: [
@@ -27641,24 +27799,26 @@ var BootstrapLaunchCommand = class extends M8tCommand {
27641
27799
  ["Share a support contact", "$0 bootstrap launch --location eastus2 --contact-email you@example.com --company 'Acme'"]
27642
27800
  ]
27643
27801
  });
27644
- location = Option49.String("--location");
27645
- resourceGroup = Option49.String("--resource-group");
27646
- clientId = Option49.String("--client-id");
27647
- subscription = Option49.String("--subscription");
27648
- installerTag = Option49.String("--installer-tag");
27802
+ location = Option50.String("--location");
27803
+ resourceGroup = Option50.String("--resource-group");
27804
+ clientId = Option50.String("--client-id");
27805
+ subscription = Option50.String("--subscription");
27806
+ installerTag = Option50.String("--installer-tag");
27649
27807
  // Full image ref override (registry + repo + tag) — an escape hatch when the
27650
27808
  // default org/tag is wrong for the current CLI (e.g. a stale published build).
27651
27809
  // Wins over --installer-tag / the pinned default.
27652
- installerImage = Option49.String("--installer-image");
27653
- gatewayImageRef = Option49.String("--gateway-image-ref");
27654
- githubAppCreds = Option49.String("--github-app-creds");
27655
- contactEmail = Option49.String("--contact-email", { description: "Share a contact email with m8t support. Not sent unless you pass it." });
27656
- company = Option49.String("--company", { description: "Share your company name with m8t support. Not sent unless you pass it." });
27810
+ installerImage = Option50.String("--installer-image");
27811
+ gatewayImageRef = Option50.String("--gateway-image-ref");
27812
+ githubAppCreds = Option50.String("--github-app-creds");
27813
+ contactEmail = Option50.String("--contact-email", { description: "Share a contact email with m8t support. Not sent unless you pass it." });
27814
+ company = Option50.String("--company", { description: "Share your company name with m8t support. Not sent unless you pass it." });
27657
27815
  // Value-carrying on purpose: a bare --force would be cargo-culted into
27658
27816
  // runbooks and harness prompts and erode the protection, whereas a faithful
27659
27817
  // paste can never accidentally carry the victim group's name. It AUTHORIZES
27660
27818
  // the target; --resource-group is what CHOOSES it.
27661
- reinstallInto = Option49.String("--reinstall-into", { description: "Consent to installing into --resource-group even though it already holds resources. Must match the target group's name." });
27819
+ reinstallInto = Option50.String("--reinstall-into", { description: "Consent to installing into --resource-group even though it already holds resources. Must match the target group's name." });
27820
+ org = Option50.String("--org", { description: "Assert the GitHub App on disk is installed on this org; refuses on a mismatch." });
27821
+ noBrains = Option50.Boolean("--no-brains", false, { description: "Install without brain-backed workers. For test and CI rigs; the supported install creates brains." });
27662
27822
  async executeCommand() {
27663
27823
  const location = typeof this.location === "string" ? this.location : void 0;
27664
27824
  if (!location) {
@@ -27698,8 +27858,19 @@ var BootstrapLaunchCommand = class extends M8tCommand {
27698
27858
  return 0;
27699
27859
  }
27700
27860
  const credsPath = typeof this.githubAppCreds === "string" ? this.githubAppCreds : path32.join(os14.homedir(), ".m8t", "github-app.json");
27861
+ const skipBrains = this.noBrains === true;
27862
+ const requestedOrg = typeof this.org === "string" ? this.org : void 0;
27701
27863
  let githubApp;
27702
- if (fs30.existsSync(credsPath)) {
27864
+ if (skipBrains) {
27865
+ out("installing without brain-backed workers; no GitHub App credentials will be used");
27866
+ } else if (!fs30.existsSync(credsPath)) {
27867
+ this.context.stderr.write(buildMissingCredsRefusal(credsPath));
27868
+ throw new LocalCliError({
27869
+ code: "GITHUB_APP_CREDS_MISSING",
27870
+ message: `No GitHub App credentials at ${credsPath}.`,
27871
+ hint: "Run `m8t brain app-create --org <org>` first."
27872
+ });
27873
+ } else {
27703
27874
  let parsed;
27704
27875
  try {
27705
27876
  parsed = JSON.parse(fs30.readFileSync(credsPath, "utf8"));
@@ -27710,6 +27881,14 @@ var BootstrapLaunchCommand = class extends M8tCommand {
27710
27881
  hint: "Run `m8t brain app-create --org <org>` to regenerate."
27711
27882
  });
27712
27883
  }
27884
+ if (requestedOrg !== void 0 && requestedOrg.toLowerCase() !== parsed.org.toLowerCase()) {
27885
+ this.context.stderr.write(buildOrgMismatchRefusal({ requested: requestedOrg, recorded: parsed.org }));
27886
+ throw new LocalCliError({
27887
+ code: "GITHUB_APP_ORG_MISMATCH",
27888
+ message: `GitHub App creds are for '${parsed.org}', but --org named '${requestedOrg}'.`,
27889
+ hint: `Run \`m8t brain app-create --org ${requestedOrg}\` first.`
27890
+ });
27891
+ }
27713
27892
  let pem;
27714
27893
  try {
27715
27894
  pem = fs30.readFileSync(parsed.pemPath, "utf8");
@@ -27727,9 +27906,11 @@ var BootstrapLaunchCommand = class extends M8tCommand {
27727
27906
  installationId: parsed.installationId,
27728
27907
  pemB64: Buffer.from(pem).toString("base64")
27729
27908
  };
27909
+ const stillInstalled = await findValidBrainApp(credsPath, parsed.org);
27910
+ if (stillInstalled === null) {
27911
+ out(`warning: could not confirm the GitHub App is still installed on ${parsed.org} - continuing`);
27912
+ }
27730
27913
  out(`threading GitHub App creds for org ${parsed.org} (app ${parsed.appId})\u2026`);
27731
- } else {
27732
- out(`no GitHub App creds found at ${credsPath} \u2014 skipping (brain workers will not be deployed; run \`m8t brain app-create --org <org>\` first if you want them)`);
27733
27914
  }
27734
27915
  out("registering Microsoft.ContainerInstance\u2026");
27735
27916
  await registerContainerInstance(subscriptionId);
@@ -27773,6 +27954,7 @@ var BootstrapLaunchCommand = class extends M8tCommand {
27773
27954
  gatewayImageRef,
27774
27955
  foundryTracing: "skip",
27775
27956
  githubApp,
27957
+ ...skipBrains ? { skipBrains: true } : {},
27776
27958
  // Opt-in only. The signed-in UPN was previously seeded here automatically;
27777
27959
  // an installation is identified by its random instance id, and contact
27778
27960
  // details are sent only when the operator asks for them.
@@ -27790,7 +27972,7 @@ var BootstrapLaunchCommand = class extends M8tCommand {
27790
27972
  };
27791
27973
 
27792
27974
  // src/commands/bootstrap/status.ts
27793
- import { Command as Command53, Option as Option50 } from "clipanion";
27975
+ import { Command as Command54, Option as Option51 } from "clipanion";
27794
27976
  init_errors();
27795
27977
 
27796
27978
  // src/lib/bootstrap-aci-state.ts
@@ -27818,13 +28000,13 @@ async function getAciState(opts) {
27818
28000
  // src/commands/bootstrap/status.ts
27819
28001
  var BootstrapStatusCommand = class extends M8tCommand {
27820
28002
  static paths = [["bootstrap", "status"]];
27821
- static usage = Command53.Usage({
28003
+ static usage = Command54.Usage({
27822
28004
  description: "Show the cloud installer's live status (phase, progress, result).",
27823
28005
  details: "Reads the durable status blob written by the installer. --watch polls until the install reaches done or failed.",
27824
28006
  examples: [["One read", "$0 bootstrap status"], ["Watch to completion", "$0 bootstrap status --watch"]]
27825
28007
  });
27826
- watch = Option50.Boolean("--watch", false);
27827
- output = Option50.String("--output");
28008
+ watch = Option51.Boolean("--watch", false);
28009
+ output = Option51.String("--output");
27828
28010
  async executeCommand() {
27829
28011
  const state = await readBootstrapState();
27830
28012
  if (!state) {
@@ -27846,6 +28028,20 @@ var BootstrapStatusCommand = class extends M8tCommand {
27846
28028
  doc = await readStatusBlob({ saName: state.statusSaName, resourceGroup: state.resourceGroup, subscriptionId: state.subscriptionId });
27847
28029
  } catch (e) {
27848
28030
  if (watch && e instanceof LocalCliError && e.code === "BOOTSTRAP_STATUS_UNREADABLE") {
28031
+ const early = await getAciState({
28032
+ aciName: state.aciName,
28033
+ resourceGroup: state.resourceGroup,
28034
+ subscriptionId: state.subscriptionId
28035
+ }).catch(() => null);
28036
+ if (early?.terminated) {
28037
+ this.context.stderr.write(
28038
+ ` ${colors.error("\u2717")} the installer container has terminated (exit ${String(early.exitCode ?? "?")}) and never reported a status.
28039
+ ${colors.hint("inspect:")} az container logs -n ${state.aciName} -g ${state.resourceGroup}
28040
+ ${colors.hint("reap:")} m8t bootstrap reap --force
28041
+ `
28042
+ );
28043
+ return 1;
28044
+ }
27849
28045
  if (mode === "pretty") this.context.stderr.write(` ${colors.dim("waiting for the installer to start\u2026")}
27850
28046
  `);
27851
28047
  await sleep5(1e4);
@@ -27895,7 +28091,7 @@ function formatStatus(d) {
27895
28091
  }
27896
28092
 
27897
28093
  // src/commands/bootstrap/reap.ts
27898
- import { Command as Command54, Option as Option51 } from "clipanion";
28094
+ import { Command as Command55, Option as Option52 } from "clipanion";
27899
28095
  init_errors();
27900
28096
 
27901
28097
  // src/lib/bootstrap-reap.ts
@@ -27989,14 +28185,14 @@ async function reapInstaller(opts) {
27989
28185
  // src/commands/bootstrap/reap.ts
27990
28186
  var BootstrapReapCommand = class extends M8tCommand {
27991
28187
  static paths = [["bootstrap", "reap"]];
27992
- static usage = Command54.Usage({
28188
+ static usage = Command55.Usage({
27993
28189
  description: "Tear down the installer scaffolding (ACI \u2192 MI \u2192 its role assignments) after a successful install.",
27994
28190
  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.",
27995
28191
  examples: [["Reap after done", "$0 bootstrap reap"]]
27996
28192
  });
27997
- force = Option51.Boolean("--force", false);
27998
- sweepOrphans = Option51.Boolean("--sweep-orphans", false);
27999
- yes = Option51.Boolean("--yes", false);
28193
+ force = Option52.Boolean("--force", false);
28194
+ sweepOrphans = Option52.Boolean("--sweep-orphans", false);
28195
+ yes = Option52.Boolean("--yes", false);
28000
28196
  async executeCommand() {
28001
28197
  if (this.sweepOrphans === true) {
28002
28198
  const { subscriptionId: sub } = await getAzAccount();
@@ -28093,7 +28289,7 @@ Found ${String(total)} orphaned assignment(s) (${breakdown}) (dry-run). ${colors
28093
28289
  import * as fs31 from "fs/promises";
28094
28290
  import * as os16 from "os";
28095
28291
  import * as path34 from "path";
28096
- import { Command as Command55, Option as Option52 } from "clipanion";
28292
+ import { Command as Command56, Option as Option53 } from "clipanion";
28097
28293
  init_errors();
28098
28294
 
28099
28295
  // src/lib/company-profile-seed.ts
@@ -29058,14 +29254,14 @@ function renderInstallSummary(args) {
29058
29254
  // src/commands/bootstrap/finish.ts
29059
29255
  var BootstrapFinishCommand = class extends M8tCommand {
29060
29256
  static paths = [["bootstrap", "finish"]];
29061
- static usage = Command55.Usage({
29257
+ static usage = Command56.Usage({
29062
29258
  description: "Point your local tools at the now-live platform (repo-root marker, discovery cache, next steps).",
29063
29259
  details: "Final step of `m8t bootstrap` (after the install reaches done). Writes ~/.m8t/repo-root, points your local tools at the live gateway, and \u2014 if you completed the onboarding intake \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.",
29064
29260
  examples: [["Finish local", "$0 bootstrap finish --repo-root /path/to/m8t"]]
29065
29261
  });
29066
- repoRoot = Option52.String("--repo-root");
29067
- subscription = Option52.String("--subscription");
29068
- resourceGroup = Option52.String("--resource-group");
29262
+ repoRoot = Option53.String("--repo-root");
29263
+ subscription = Option53.String("--subscription");
29264
+ resourceGroup = Option53.String("--resource-group");
29069
29265
  async executeCommand() {
29070
29266
  const state = await readBootstrapState();
29071
29267
  if (!state) {
@@ -29168,7 +29364,7 @@ ${colors.field("Then open a brand new chat/session")} \u2014 new skills + MCP se
29168
29364
  import * as fs33 from "fs";
29169
29365
  import * as os18 from "os";
29170
29366
  import * as path36 from "path";
29171
- import { Command as Command56, Option as Option53 } from "clipanion";
29367
+ import { Command as Command57, Option as Option54 } from "clipanion";
29172
29368
  import { DefaultAzureCredential as DefaultAzureCredential23 } from "@azure/identity";
29173
29369
  init_errors();
29174
29370
 
@@ -29976,7 +30172,7 @@ function renderDeployFailure(error) {
29976
30172
  }
29977
30173
  var BootstrapUiCommand = class extends M8tCommand {
29978
30174
  static paths = [["bootstrap", "ui"]];
29979
- static usage = Command56.Usage({
30175
+ static usage = Command57.Usage({
29980
30176
  description: "Deploy Azzy + start the local onboarding chat UI in the background (returns immediately).",
29981
30177
  details: [
29982
30178
  "Run after `m8t bootstrap launch`, in parallel with `status --watch`. Waits for the cloud",
@@ -29997,16 +30193,16 @@ var BootstrapUiCommand = class extends M8tCommand {
29997
30193
  ["Experimental: start the voice relay (no effect on the text-only intake)", "$0 bootstrap ui --repo-root /path/to/m8t --voice"]
29998
30194
  ]
29999
30195
  });
30000
- repoRoot = Option53.String("--repo-root");
30001
- port = Option53.String("--port", "3000");
30002
- endpoint = Option53.String("--endpoint", {
30196
+ repoRoot = Option54.String("--repo-root");
30197
+ port = Option54.String("--port", "3000");
30198
+ endpoint = Option54.String("--endpoint", {
30003
30199
  description: "Foundry project endpoint to target \u2014 disambiguates when the subscription has multiple projects."
30004
30200
  });
30005
- prepOnly = Option53.Boolean("--prep-only", false);
30006
- skipInstall = Option53.Boolean("--skip-install", false);
30007
- stop = Option53.Boolean("--stop", false);
30008
- foreground = Option53.Boolean("--foreground", false);
30009
- voice = Option53.Boolean("--voice", false, {
30201
+ prepOnly = Option54.Boolean("--prep-only", false);
30202
+ skipInstall = Option54.Boolean("--skip-install", false);
30203
+ stop = Option54.Boolean("--stop", false);
30204
+ foreground = Option54.Boolean("--foreground", false);
30205
+ voice = Option54.Boolean("--voice", false, {
30010
30206
  description: "Experimental: when serving, starts the voice relay and writes the intake voice env var. The onboarding intake is text-only and is unaffected by this flag \u2014 no voice worker is registered for it."
30011
30207
  });
30012
30208
  async executeCommand() {
@@ -30168,10 +30364,10 @@ var BootstrapUiCommand = class extends M8tCommand {
30168
30364
  };
30169
30365
 
30170
30366
  // src/commands/bootstrap/seed-profile.ts
30171
- import { Command as Command57, Option as Option54 } from "clipanion";
30367
+ import { Command as Command58, Option as Option55 } from "clipanion";
30172
30368
  var BootstrapSeedProfileCommand = class extends M8tCommand {
30173
30369
  static paths = [["bootstrap", "seed-profile"]];
30174
- static usage = Command57.Usage({
30370
+ static usage = Command58.Usage({
30175
30371
  description: "Seed your advisors' brains with the founder + company profile from the onboarding intake.",
30176
30372
  details: "Reads the latest onboarding 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 finishes the intake.",
30177
30373
  examples: [
@@ -30179,11 +30375,11 @@ var BootstrapSeedProfileCommand = class extends M8tCommand {
30179
30375
  ["Wait for the founder to finish", "$0 bootstrap seed-profile --watch"]
30180
30376
  ]
30181
30377
  });
30182
- endpoint = Option54.String("--endpoint", { description: "Override the Foundry endpoint (else read from the install status)." });
30183
- brain = Option54.String("--brain", { description: "Seed only this one brain repo, instead of both <org>/stacey-brain and <org>/azzy-brain." });
30184
- watch = Option54.Boolean("--watch", false, { description: "Poll until the intake completes (or --timeout)." });
30185
- timeout = Option54.String("--timeout", { description: "Watch timeout in minutes (default 20)." });
30186
- githubAppCreds = Option54.String("--github-app-creds");
30378
+ endpoint = Option55.String("--endpoint", { description: "Override the Foundry endpoint (else read from the install status)." });
30379
+ brain = Option55.String("--brain", { description: "Seed only this one brain repo, instead of both <org>/stacey-brain and <org>/azzy-brain." });
30380
+ watch = Option55.Boolean("--watch", false, { description: "Poll until the intake completes (or --timeout)." });
30381
+ timeout = Option55.String("--timeout", { description: "Watch timeout in minutes (default 20)." });
30382
+ githubAppCreds = Option55.String("--github-app-creds");
30187
30383
  async executeCommand() {
30188
30384
  const ctx = await resolveSeedContext({
30189
30385
  endpointOverride: typeof this.endpoint === "string" ? this.endpoint : void 0,
@@ -30246,7 +30442,7 @@ var BootstrapSeedProfileCommand = class extends M8tCommand {
30246
30442
  import * as fs34 from "fs";
30247
30443
  import * as os19 from "os";
30248
30444
  import * as path37 from "path";
30249
- import { Command as Command58, Option as Option55 } from "clipanion";
30445
+ import { Command as Command59, Option as Option56 } from "clipanion";
30250
30446
  init_errors();
30251
30447
 
30252
30448
  // src/lib/telemetry-enroll.ts
@@ -30328,7 +30524,7 @@ async function resolveKeyVaultName(containerAppResourceId) {
30328
30524
  }
30329
30525
  var TelemetryEnrollCommand = class extends M8tCommand {
30330
30526
  static paths = [["telemetry", "enroll"]];
30331
- static usage = Command58.Usage({
30527
+ static usage = Command59.Usage({
30332
30528
  description: "Enroll this installation for operational telemetry (pre-existing installs).",
30333
30529
  details: "Generates an instance id + ingest key from the m8t telemetry ingest and stores the key in your platform Key Vault, the same place the installer writes it on a fresh install. Your installation is identified only by that random instance id \u2014 no contact, company, or subscription details are sent unless you pass them explicitly. Idempotent: refuses if a key already exists.",
30334
30530
  examples: [
@@ -30336,11 +30532,11 @@ var TelemetryEnrollCommand = class extends M8tCommand {
30336
30532
  ["Enroll and share a support contact", "$0 telemetry enroll --contact-email you@example.com --company 'Acme'"]
30337
30533
  ]
30338
30534
  });
30339
- company = Option55.String("--company", { description: "Share your company name with m8t support. Not sent unless you pass it." });
30340
- contactEmail = Option55.String("--contact-email", { description: "Share a contact email with m8t support. Not sent unless you pass it." });
30341
- subscription = Option55.String("--subscription", { description: "Azure subscription id used to find your deployment. Never sent to m8t." });
30342
- resourceGroup = Option55.String("--resource-group", { description: "Resource group to disambiguate discovery, if you have more than one m8t deployment." });
30343
- force = Option55.Boolean("--force", false, { description: "Enroll even when a key is already stored. Use only when m8t support asks you to." });
30535
+ company = Option56.String("--company", { description: "Share your company name with m8t support. Not sent unless you pass it." });
30536
+ contactEmail = Option56.String("--contact-email", { description: "Share a contact email with m8t support. Not sent unless you pass it." });
30537
+ subscription = Option56.String("--subscription", { description: "Azure subscription id used to find your deployment. Never sent to m8t." });
30538
+ resourceGroup = Option56.String("--resource-group", { description: "Resource group to disambiguate discovery, if you have more than one m8t deployment." });
30539
+ force = Option56.Boolean("--force", false, { description: "Enroll even when a key is already stored. Use only when m8t support asks you to." });
30344
30540
  async executeCommand() {
30345
30541
  const account = await getAzAccount();
30346
30542
  const subscriptionId = (typeof this.subscription === "string" ? this.subscription : void 0) ?? account.subscriptionId;
@@ -30421,6 +30617,7 @@ cli.register(BrainCheckAppCommand);
30421
30617
  cli.register(BrainCreateCommand);
30422
30618
  cli.register(BrainLinkCommand);
30423
30619
  cli.register(BrainListCommand);
30620
+ cli.register(BrainOrgsCommand);
30424
30621
  cli.register(BrainShowCommand);
30425
30622
  cli.register(BrainUnlinkCommand);
30426
30623
  cli.register(ArchitectCheckCommand);