@m8t-stack/cli 0.2.83 → 0.2.84

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
@@ -1467,7 +1467,7 @@ var init_enable_hosted_brain = __esm({
1467
1467
  import { Builtins, Cli } from "clipanion";
1468
1468
 
1469
1469
  // src/lib/package-version.ts
1470
- var CLI_VERSION = "0.2.83";
1470
+ var CLI_VERSION = "0.2.84";
1471
1471
 
1472
1472
  // src/lib/render-error.ts
1473
1473
  init_errors();
@@ -3801,12 +3801,12 @@ function encodeURIPath(str4) {
3801
3801
  return str4.replace(/[^A-Za-z0-9\-._~!$&'()*+,;=:@]+/g, encodeURIComponent);
3802
3802
  }
3803
3803
  var EMPTY = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.create(null));
3804
- var createPathTagFunction = (pathEncoder = encodeURIPath) => function path48(statics, ...params) {
3804
+ var createPathTagFunction = (pathEncoder = encodeURIPath) => function path47(statics, ...params) {
3805
3805
  if (statics.length === 1)
3806
3806
  return statics[0];
3807
3807
  let postPath = false;
3808
3808
  const invalidSegments = [];
3809
- const path49 = statics.reduce((previousValue, currentValue, index) => {
3809
+ const path48 = statics.reduce((previousValue, currentValue, index) => {
3810
3810
  if (/[?#]/.test(currentValue)) {
3811
3811
  postPath = true;
3812
3812
  }
@@ -3823,7 +3823,7 @@ var createPathTagFunction = (pathEncoder = encodeURIPath) => function path48(sta
3823
3823
  }
3824
3824
  return previousValue + currentValue + (index === params.length ? "" : encoded);
3825
3825
  }, "");
3826
- const pathOnly = path49.split(/[?#]/, 1)[0];
3826
+ const pathOnly = path48.split(/[?#]/, 1)[0];
3827
3827
  const invalidSegmentPattern = /(?<=^|\/)(?:\.|%2e){1,2}(?=\/|$)/gi;
3828
3828
  let match;
3829
3829
  while ((match = invalidSegmentPattern.exec(pathOnly)) !== null) {
@@ -3844,10 +3844,10 @@ var createPathTagFunction = (pathEncoder = encodeURIPath) => function path48(sta
3844
3844
  }, "");
3845
3845
  throw new OpenAIError(`Path parameters result in path with invalid segments:
3846
3846
  ${invalidSegments.map((e) => e.error).join("\n")}
3847
- ${path49}
3847
+ ${path48}
3848
3848
  ${underline}`);
3849
3849
  }
3850
- return path49;
3850
+ return path48;
3851
3851
  };
3852
3852
  var path = /* @__PURE__ */ createPathTagFunction(encodeURIPath);
3853
3853
 
@@ -12298,9 +12298,9 @@ var OpenAI = class {
12298
12298
  this.apiKey = token;
12299
12299
  return true;
12300
12300
  }
12301
- buildURL(path48, query, defaultBaseURL) {
12301
+ buildURL(path47, query, defaultBaseURL) {
12302
12302
  const baseURL = !__classPrivateFieldGet(this, _OpenAI_instances, "m", _OpenAI_baseURLOverridden).call(this) && defaultBaseURL || this.baseURL;
12303
- const url = isAbsoluteURL(path48) ? new URL(path48) : new URL(baseURL + (baseURL.endsWith("/") && path48.startsWith("/") ? path48.slice(1) : path48));
12303
+ const url = isAbsoluteURL(path47) ? new URL(path47) : new URL(baseURL + (baseURL.endsWith("/") && path47.startsWith("/") ? path47.slice(1) : path47));
12304
12304
  const defaultQuery = this.defaultQuery();
12305
12305
  const pathQuery = Object.fromEntries(url.searchParams);
12306
12306
  if (!isEmptyObj(defaultQuery) || !isEmptyObj(pathQuery)) {
@@ -12330,24 +12330,24 @@ var OpenAI = class {
12330
12330
  */
12331
12331
  async prepareRequest(request, { url, options }) {
12332
12332
  }
12333
- get(path48, opts) {
12334
- return this.methodRequest("get", path48, opts);
12333
+ get(path47, opts) {
12334
+ return this.methodRequest("get", path47, opts);
12335
12335
  }
12336
- post(path48, opts) {
12337
- return this.methodRequest("post", path48, opts);
12336
+ post(path47, opts) {
12337
+ return this.methodRequest("post", path47, opts);
12338
12338
  }
12339
- patch(path48, opts) {
12340
- return this.methodRequest("patch", path48, opts);
12339
+ patch(path47, opts) {
12340
+ return this.methodRequest("patch", path47, opts);
12341
12341
  }
12342
- put(path48, opts) {
12343
- return this.methodRequest("put", path48, opts);
12342
+ put(path47, opts) {
12343
+ return this.methodRequest("put", path47, opts);
12344
12344
  }
12345
- delete(path48, opts) {
12346
- return this.methodRequest("delete", path48, opts);
12345
+ delete(path47, opts) {
12346
+ return this.methodRequest("delete", path47, opts);
12347
12347
  }
12348
- methodRequest(method, path48, opts) {
12348
+ methodRequest(method, path47, opts) {
12349
12349
  return this.request(Promise.resolve(opts).then((opts2) => {
12350
- return { method, path: path48, ...opts2 };
12350
+ return { method, path: path47, ...opts2 };
12351
12351
  }));
12352
12352
  }
12353
12353
  request(options, remainingRetries = null) {
@@ -12472,8 +12472,8 @@ var OpenAI = class {
12472
12472
  }));
12473
12473
  return { response, options, controller, requestLogID, retryOfRequestLogID, startTime };
12474
12474
  }
12475
- getAPIList(path48, Page2, opts) {
12476
- return this.requestAPIList(Page2, opts && "then" in opts ? opts.then((opts2) => ({ method: "get", path: path48, ...opts2 })) : { method: "get", path: path48, ...opts });
12475
+ getAPIList(path47, Page2, opts) {
12476
+ return this.requestAPIList(Page2, opts && "then" in opts ? opts.then((opts2) => ({ method: "get", path: path47, ...opts2 })) : { method: "get", path: path47, ...opts });
12477
12477
  }
12478
12478
  requestAPIList(Page2, options) {
12479
12479
  const request = this.makeRequest(options, null, void 0);
@@ -12567,8 +12567,8 @@ var OpenAI = class {
12567
12567
  }
12568
12568
  async buildRequest(inputOptions, { retryCount = 0 } = {}) {
12569
12569
  const options = { ...inputOptions };
12570
- const { method, path: path48, query, defaultBaseURL } = options;
12571
- const url = this.buildURL(path48, query, defaultBaseURL);
12570
+ const { method, path: path47, query, defaultBaseURL } = options;
12571
+ const url = this.buildURL(path47, query, defaultBaseURL);
12572
12572
  if ("timeout" in options)
12573
12573
  validatePositiveInteger("timeout", options.timeout);
12574
12574
  options.timeout = options.timeout ?? this.timeout;
@@ -13633,10 +13633,10 @@ var BindListCommand = class extends M8tCommand {
13633
13633
  const qs = new URLSearchParams();
13634
13634
  if (this.channel) qs.set("channel", this.channel);
13635
13635
  if (this.status) qs.set("status", this.status);
13636
- const path48 = qs.toString().length > 0 ? `/api/bindings?${qs.toString()}` : "/api/bindings";
13636
+ const path47 = qs.toString().length > 0 ? `/api/bindings?${qs.toString()}` : "/api/bindings";
13637
13637
  const data = await apiCall(
13638
13638
  { gatewayUrl: ctx.gatewayUrl, gatewayClientId: ctx.gatewayClientId },
13639
- { method: "GET", path: path48 },
13639
+ { method: "GET", path: path47 },
13640
13640
  (msg) => this.context.stderr.write(msg + "\n")
13641
13641
  );
13642
13642
  if (mode === "json") {
@@ -14882,8 +14882,8 @@ ${r.stderr}`;
14882
14882
  message: `gh api /repos/${slug} failed (exit ${r.exitCode.toString()}): ${(r.stderr || r.stdout).slice(0, 200)}`
14883
14883
  });
14884
14884
  },
14885
- getFile: async (path48) => {
14886
- const r = await exec("gh", ["api", "-H", "Accept: application/vnd.github.raw+json", `/repos/${slug}/contents/${path48}`]);
14885
+ getFile: async (path47) => {
14886
+ const r = await exec("gh", ["api", "-H", "Accept: application/vnd.github.raw+json", `/repos/${slug}/contents/${path47}`]);
14887
14887
  return r.exitCode === 0 ? r.stdout : null;
14888
14888
  },
14889
14889
  isEmpty: async () => {
@@ -16434,7 +16434,7 @@ function appRepoProbe(args) {
16434
16434
  const res = await doFetch(`${GH_API}/repos/${args.repo}`, { headers: H, signal: AbortSignal.timeout(GH_REQUEST_TIMEOUT_MS) });
16435
16435
  return res.status;
16436
16436
  },
16437
- getFile: (path48) => readRepoFileViaApp({ token: args.token, repo: args.repo, path: path48, fetchImpl: args.fetchImpl }),
16437
+ getFile: (path47) => readRepoFileViaApp({ token: args.token, repo: args.repo, path: path47, fetchImpl: args.fetchImpl }),
16438
16438
  isEmpty: async () => {
16439
16439
  const res = await doFetch(`${GH_API}/repos/${args.repo}/contents`, { headers: H, signal: AbortSignal.timeout(GH_REQUEST_TIMEOUT_MS) });
16440
16440
  return res.status === 404;
@@ -20001,6 +20001,7 @@ import { DefaultAzureCredential as DefaultAzureCredential16 } from "@azure/ident
20001
20001
 
20002
20002
  // src/lib/platform-update.ts
20003
20003
  init_errors();
20004
+ import semver from "semver";
20004
20005
  var DEFAULT_IMAGE_REPO = "ghcr.io/m8t-labs/m8t";
20005
20006
  function parseImageRef2(ref) {
20006
20007
  let rest = ref;
@@ -20055,10 +20056,22 @@ function compareSemver(a, b) {
20055
20056
  }
20056
20057
  return 0;
20057
20058
  }
20059
+ function comparePlatformVersion(a, b) {
20060
+ const bare = (v) => v.trim().replace(/^platform-/, "").replace(/^v/, "");
20061
+ const va = semver.valid(bare(a));
20062
+ const vb = semver.valid(bare(b));
20063
+ if (!va || !vb) {
20064
+ throw new LocalCliError({
20065
+ code: "PLATFORM_BAD_SEMVER",
20066
+ message: `comparePlatformVersion needs platform versions, got '${a}' / '${b}'.`
20067
+ });
20068
+ }
20069
+ return semver.compare(va, vb);
20070
+ }
20058
20071
  function pickNewestSemver(tags) {
20059
- const semver = tags.filter(isSemverTag);
20060
- if (semver.length === 0) return null;
20061
- return semver.reduce((best, t) => compareSemver(t, best) > 0 ? t : best);
20072
+ const semver2 = tags.filter(isSemverTag);
20073
+ if (semver2.length === 0) return null;
20074
+ return semver2.reduce((best, t) => compareSemver(t, best) > 0 ? t : best);
20062
20075
  }
20063
20076
  function parseContainerAppResourceId(id) {
20064
20077
  const m = /\/subscriptions\/([^/]+)\/resourceGroups\/([^/]+)\/providers\/Microsoft\.App\/containerApps\/([^/]+)/i.exec(
@@ -20104,8 +20117,8 @@ async function fetchPublicTags(repo, fetchImpl = fetch) {
20104
20117
  hint: "Pass a ghcr.io/<owner>/<name> repo, or use the BYOC private-ACR deploy flow."
20105
20118
  });
20106
20119
  }
20107
- const path48 = repo.replace(/^ghcr\.io\//, "");
20108
- const tokenRes = await fetchImpl(`https://ghcr.io/token?scope=repository:${path48}:pull`);
20120
+ const path47 = repo.replace(/^ghcr\.io\//, "");
20121
+ const tokenRes = await fetchImpl(`https://ghcr.io/token?scope=repository:${path47}:pull`);
20109
20122
  if (!tokenRes.ok) {
20110
20123
  throw new LocalCliError({
20111
20124
  code: "PLATFORM_GHCR_TOKEN_FAILED",
@@ -20121,7 +20134,7 @@ async function fetchPublicTags(repo, fetchImpl = fetch) {
20121
20134
  hint: "Make the package public (deploy/ghcr-package-visibility.md), then retry."
20122
20135
  });
20123
20136
  }
20124
- const tagsRes = await fetchImpl(`https://ghcr.io/v2/${path48}/tags/list`, {
20137
+ const tagsRes = await fetchImpl(`https://ghcr.io/v2/${path47}/tags/list`, {
20125
20138
  headers: { Authorization: `Bearer ${token}` }
20126
20139
  });
20127
20140
  if (!tagsRes.ok) {
@@ -20298,6 +20311,8 @@ function entityToStamp(e) {
20298
20311
  var RELEASES_REPO = "m8t-labs/m8t-releases";
20299
20312
  var RELEASES_BASE = `https://github.com/${RELEASES_REPO}/releases`;
20300
20313
  var CHANNEL_LATEST_URL = `${RELEASES_BASE}/latest/download/manifest.json`;
20314
+ var CANARY_POINTER_TAG = "canary";
20315
+ var CHANNEL_CANARY_URL = `${RELEASES_BASE}/download/${CANARY_POINTER_TAG}/manifest.json`;
20301
20316
  function platformTag(version) {
20302
20317
  const bare = version.trim().replace(/^platform-/, "").replace(/^v/, "");
20303
20318
  return `platform-v${bare}`;
@@ -20309,13 +20324,46 @@ function releaseAssetUrl(tag, asset) {
20309
20324
  return `${RELEASES_BASE}/download/${tag}/${asset}`;
20310
20325
  }
20311
20326
 
20327
+ // ../../packages/platform-release/dist/esm/canary-version.js
20328
+ var CANARY_IDENTIFIER = "canary";
20329
+ var STABLE_CORE = String.raw`\d+\.\d+\.\d+`;
20330
+ var CANARY_SUFFIX = String.raw`-${CANARY_IDENTIFIER}\.(?:0|[1-9]\d*)`;
20331
+ var CANARY_VERSION_PATTERN = `^${STABLE_CORE}${CANARY_SUFFIX}$`;
20332
+ var PLATFORM_VERSION_PATTERN = `^${STABLE_CORE}(?:${CANARY_SUFFIX})?$`;
20333
+ var PLATFORM_TAG_PATTERN = `^platform-v${STABLE_CORE}(?:${CANARY_SUFFIX})?$`;
20334
+ var CANARY_VERSION_RE = new RegExp(CANARY_VERSION_PATTERN);
20335
+ var STABLE_CORE_RE = new RegExp(`^${STABLE_CORE}$`);
20336
+
20312
20337
  // ../../packages/platform-release/dist/esm/apply-request.js
20313
20338
  var APPLY_REQUEST_PK = "system";
20314
20339
  var APPLY_REQUEST_RK = "apply-request";
20315
20340
  var IN_FLIGHT = ["claimed", "applying"];
20341
+ var LEASE_MS = 30 * 60 * 1e3;
20342
+ var MAX_LEASE_TAKEOVERS = 2;
20343
+ var MAX_HEALTHY_IN_FLIGHT_MS = LEASE_MS * (MAX_LEASE_TAKEOVERS + 1);
20316
20344
  function isInFlight(status) {
20317
20345
  return IN_FLIGHT.includes(status);
20318
20346
  }
20347
+ var BLOCKS_NEW_INTENT = ["pending", "claimed", "applying", "awaiting-engine-update"];
20348
+ function blocksNewIntent(status) {
20349
+ return BLOCKS_NEW_INTENT.includes(status);
20350
+ }
20351
+ function newIntent(target, provenance, nowIso) {
20352
+ return {
20353
+ schemaVersion: 1,
20354
+ target,
20355
+ provenance,
20356
+ status: "pending",
20357
+ phase: null,
20358
+ claimedBy: null,
20359
+ leaseUntil: null,
20360
+ attempt: 0,
20361
+ breaker: "none",
20362
+ result: null,
20363
+ createdAt: nowIso,
20364
+ updatedAt: nowIso
20365
+ };
20366
+ }
20319
20367
  function applyRequestToEntity(r) {
20320
20368
  return { partitionKey: APPLY_REQUEST_PK, rowKey: APPLY_REQUEST_RK, value: JSON.stringify(r), updatedAt: r.updatedAt };
20321
20369
  }
@@ -20354,11 +20402,10 @@ function manifestSourceForVersionTag(channelUrl, version) {
20354
20402
  const tag = platformTag(version);
20355
20403
  const custom = channelUrl.trim();
20356
20404
  if (!custom || custom === CHANNEL_LATEST_URL) return { channel: true, version: tag };
20357
- if (custom.includes("/releases/latest/download/")) {
20358
- return { url: custom.replace("/releases/latest/download/", `/releases/download/${tag}/`) };
20359
- }
20360
- return { url: custom };
20405
+ const swapped = custom.replace(POINTER_SEGMENT, `/releases/download/${tag}/`);
20406
+ return { url: swapped };
20361
20407
  }
20408
+ var POINTER_SEGMENT = /\/releases\/(?:latest\/download|download\/[^/]+)\//;
20362
20409
  async function fetchManifest(source, deps = {}) {
20363
20410
  const readFile9 = deps.readFile ?? ((p) => fs23.readFileSync(p, "utf8"));
20364
20411
  const fetchImpl = deps.fetchImpl ?? fetch;
@@ -21630,25 +21677,25 @@ function mergeThreeWay(ours, base, theirs) {
21630
21677
  fs27.rmSync(dir, { recursive: true, force: true });
21631
21678
  }
21632
21679
  }
21633
- var skip = (path48, skipReason) => ({ path: path48, kind: "skip", skipReason });
21680
+ var skip = (path47, skipReason) => ({ path: path47, kind: "skip", skipReason });
21634
21681
  function classifyCandidate(c) {
21635
- const { path: path48, base, ours, theirs } = c;
21636
- if (theirs === base) return { path: path48, kind: "noop" };
21682
+ const { path: path47, base, ours, theirs } = c;
21683
+ if (theirs === base) return { path: path47, kind: "noop" };
21637
21684
  if (base === null) {
21638
- if (theirs === null) return { path: path48, kind: "noop" };
21639
- if (ours === null) return { path: path48, kind: "add", content: theirs };
21640
- if (ours === theirs) return { path: path48, kind: "noop" };
21641
- return skip(path48, "you already have a file at this path");
21685
+ if (theirs === null) return { path: path47, kind: "noop" };
21686
+ if (ours === null) return { path: path47, kind: "add", content: theirs };
21687
+ if (ours === theirs) return { path: path47, kind: "noop" };
21688
+ return skip(path47, "you already have a file at this path");
21642
21689
  }
21643
21690
  if (ours === null) {
21644
- return theirs === null ? { path: path48, kind: "noop" } : skip(path48, "you removed this file; upstream changed it");
21691
+ return theirs === null ? { path: path47, kind: "noop" } : skip(path47, "you removed this file; upstream changed it");
21645
21692
  }
21646
21693
  if (theirs === null) {
21647
- return ours === base ? { path: path48, kind: "delete" } : skip(path48, "you edited this file; upstream removed it");
21694
+ return ours === base ? { path: path47, kind: "delete" } : skip(path47, "you edited this file; upstream removed it");
21648
21695
  }
21649
- if (ours === base) return { path: path48, kind: "update", content: theirs };
21696
+ if (ours === base) return { path: path47, kind: "update", content: theirs };
21650
21697
  const m = mergeThreeWay(ours, base, theirs);
21651
- return m.ok ? { path: path48, kind: "update", content: m.merged } : skip(path48, "your edits conflict with the update");
21698
+ return m.ok ? { path: path47, kind: "update", content: m.merged } : skip(path47, "your edits conflict with the update");
21652
21699
  }
21653
21700
 
21654
21701
  // src/lib/seed-pr-body.ts
@@ -21835,7 +21882,7 @@ function bindRepoApi(token, repo) {
21835
21882
  openPr: (head, base, title, body) => openPullRequestViaApp({ token, repo, base, head, title, body }),
21836
21883
  updatePr: (n, title, body) => updatePullRequestViaApp({ token, repo, number: n, title, body }),
21837
21884
  closePr: (n, comment) => closePullRequestViaApp({ token, repo, number: n, comment }),
21838
- readFileAtRef: (path48, ref) => readRepoFileViaApp({ token, repo, path: path48, ref })
21885
+ readFileAtRef: (path47, ref) => readRepoFileViaApp({ token, repo, path: path47, ref })
21839
21886
  };
21840
21887
  }
21841
21888
  async function runSeedRefresh(args) {
@@ -22337,7 +22384,6 @@ function resolveHeadlessContextFromEnv(env) {
22337
22384
 
22338
22385
  // src/lib/apply-request-store.ts
22339
22386
  import { TableClient as TableClient4 } from "@azure/data-tables";
22340
- var MAX_LEASE_TAKEOVERS = 2;
22341
22387
  async function openApplyTable(opts) {
22342
22388
  const { tableEndpoint } = await discoverStampStorage(opts);
22343
22389
  return new TableClient4(tableEndpoint, "Metadata", opts.credential);
@@ -22423,32 +22469,59 @@ function assertForwardTarget(manifest) {
22423
22469
  }
22424
22470
 
22425
22471
  // src/lib/platform-self-update.ts
22426
- import * as fs30 from "fs";
22427
- import * as path32 from "path";
22428
22472
  function toVTag2(v) {
22429
22473
  return v.startsWith("v") ? v : `v${v}`;
22430
22474
  }
22431
- function readBakedReleaseVersion(repoRoot) {
22432
- if (!repoRoot) return null;
22433
- try {
22434
- const raw = fs30.readFileSync(path32.join(repoRoot, "installer", "version.json"), "utf8");
22435
- const v = JSON.parse(raw).version;
22436
- return typeof v === "string" && v.length > 0 ? v : null;
22437
- } catch {
22438
- return null;
22439
- }
22440
- }
22441
- function needsEngineUpdate(manifest, runningVersion, bakedRelease) {
22475
+ function needsEngineUpdate(manifest, runningVersion, runningImage) {
22442
22476
  if (runningVersion === "0.0.0-dev") return false;
22443
- if (bakedRelease != null && bakedRelease.length > 0 && bakedRelease !== manifest.components.installer.version) return true;
22477
+ if (needsEngineImageHop(manifest, runningVersion, runningImage ?? null)) return true;
22444
22478
  const running = toVTag2(runningVersion);
22445
22479
  const min = toVTag2(manifest.components.cli.min);
22446
22480
  return compareSemver(running, min) < 0;
22447
22481
  }
22482
+ function needsPreClaimEngineUpdate(manifest, runningVersion, runningImage) {
22483
+ return needsEngineImageHop(manifest, runningVersion, runningImage ?? null);
22484
+ }
22485
+ function targetEngineImage(manifest) {
22486
+ const inst = manifest.components.installer;
22487
+ return `${inst.ref}:${inst.tag}`;
22488
+ }
22489
+ function ownJobName(env = process.env) {
22490
+ const name = (env.UPDATER_JOB_NAME ?? "").trim();
22491
+ return name.length > 0 ? name : null;
22492
+ }
22493
+ async function readOwnJobImage(opts) {
22494
+ const job = opts.jobName ?? ownJobName();
22495
+ if (!job) return null;
22496
+ const image = (await runAz([
22497
+ "containerapp",
22498
+ "job",
22499
+ "show",
22500
+ "-n",
22501
+ job,
22502
+ "-g",
22503
+ opts.resourceGroup,
22504
+ "--subscription",
22505
+ opts.subscriptionId,
22506
+ "--query",
22507
+ "properties.template.containers[0].image",
22508
+ "-o",
22509
+ "tsv",
22510
+ "--only-show-errors"
22511
+ ])).trim();
22512
+ if (!image || image === "None") {
22513
+ throw new Error(`could not read the updater job's current image (job ${job}) \u2014 refusing to decide a self-update blind`);
22514
+ }
22515
+ return image;
22516
+ }
22517
+ function needsEngineImageHop(manifest, runningVersion, runningImage) {
22518
+ if (runningVersion === "0.0.0-dev") return false;
22519
+ if (runningImage === null || runningImage.trim().length === 0) return false;
22520
+ return runningImage.trim() !== targetEngineImage(manifest);
22521
+ }
22448
22522
  async function updateOwnJobImage(opts) {
22449
- const inst = opts.manifest.components.installer;
22450
- const image = `${inst.ref}:${inst.tag}`;
22451
- const job = opts.jobName ?? process.env.UPDATER_JOB_NAME;
22523
+ const image = targetEngineImage(opts.manifest);
22524
+ const job = opts.jobName ?? ownJobName();
22452
22525
  if (!job) throw new Error("UPDATER_JOB_NAME unset \u2014 cannot self-update the updater job image");
22453
22526
  await runAz([
22454
22527
  "containerapp",
@@ -22618,13 +22691,9 @@ async function readBreaker(client) {
22618
22691
 
22619
22692
  // src/commands/platform/converge.ts
22620
22693
  init_errors();
22621
- function canonicalVersion(v) {
22622
- const bare = v.replace(/^platform-/, "");
22623
- return bare.startsWith("v") ? bare : `v${bare}`;
22624
- }
22625
22694
  function isForwardTarget(target, installed) {
22626
22695
  if (!installed) return true;
22627
- return compareSemver(canonicalVersion(target), canonicalVersion(installed)) >= 0;
22696
+ return comparePlatformVersion(target, installed) >= 0;
22628
22697
  }
22629
22698
  async function failIfStillInFlight(client, now, error) {
22630
22699
  const cur = await readApplyRequest(client);
@@ -22655,6 +22724,28 @@ var PlatformConvergeCommand = class extends M8tCommand {
22655
22724
  subscriptionId: ctx.subscriptionId,
22656
22725
  resourceGroup: ctx.resourceGroup
22657
22726
  });
22727
+ let runningImage = null;
22728
+ const outstanding = await readApplyRequest(client);
22729
+ if (outstanding && blocksNewIntent(outstanding.status)) {
22730
+ runningImage = await readOwnJobImage({
22731
+ subscriptionId: ctx.subscriptionId,
22732
+ resourceGroup: ctx.resourceGroup
22733
+ });
22734
+ if (runningImage) {
22735
+ const preManifest = await fetchManifest(targetManifestSource(ctx, outstanding.target));
22736
+ if (needsPreClaimEngineUpdate(preManifest, CLI_VERSION, runningImage)) {
22737
+ log(
22738
+ `self-updating BEFORE claiming (running ${runningImage} \u2192 target ${targetEngineImage(preManifest)}); the next tick claims with the new engine.`
22739
+ );
22740
+ await updateOwnJobImage({
22741
+ subscriptionId: ctx.subscriptionId,
22742
+ resourceGroup: ctx.resourceGroup,
22743
+ manifest: preManifest
22744
+ });
22745
+ return 0;
22746
+ }
22747
+ }
22748
+ }
22658
22749
  const claimed = await claimApplyRequest(client, executionId, now(), 30 * 60 * 1e3);
22659
22750
  if (!claimed) {
22660
22751
  log("no pending apply-request \u2014 nothing to converge.");
@@ -22689,10 +22780,9 @@ var PlatformConvergeCommand = class extends M8tCommand {
22689
22780
  return 1;
22690
22781
  }
22691
22782
  const repoRoot = tryResolveRepoRoot();
22692
- const bakedRelease = readBakedReleaseVersion(repoRoot);
22693
- if (needsEngineUpdate(manifest, CLI_VERSION, bakedRelease)) {
22783
+ if (needsEngineUpdate(manifest, CLI_VERSION, runningImage)) {
22694
22784
  log(
22695
- `self-updating the updater image (baked release ${bakedRelease ?? "(none)"} / engine ${CLI_VERSION} \u2192 target installer ${manifest.components.installer.version}, cli.min ${manifest.components.cli.min}).`
22785
+ `self-updating the updater image (running ${runningImage ?? "(not the job)"} / engine ${CLI_VERSION} \u2192 target ${targetEngineImage(manifest)}, cli.min ${manifest.components.cli.min}).`
22696
22786
  );
22697
22787
  await updateOwnJobImage({
22698
22788
  subscriptionId: ctx.subscriptionId,
@@ -22854,12 +22944,270 @@ function targetManifestSource(ctx, target) {
22854
22944
  return manifestSourceForVersionTag(ctx.channelUrl, target);
22855
22945
  }
22856
22946
 
22857
- // src/commands/platform/seed-stamp.ts
22858
- import { readFileSync as readFileSync21 } from "fs";
22947
+ // src/commands/platform/clear-intent.ts
22859
22948
  import { Command as Command37, Option as Option34 } from "clipanion";
22860
22949
  import { DefaultAzureCredential as DefaultAzureCredential18, ManagedIdentityCredential as ManagedIdentityCredential2 } from "@azure/identity";
22861
22950
  init_errors();
22862
22951
 
22952
+ // src/lib/apply-intent-clear.ts
22953
+ var CLEARED_BY_OPERATOR = "cleared by an operator via `m8t platform clear-intent`";
22954
+ function decideClear(row, nowIso, force) {
22955
+ if (!row) return { action: "none", reason: "there is no apply-request to clear." };
22956
+ if (!isInFlight(row.status) && row.status !== "pending" && row.status !== "awaiting-engine-update") {
22957
+ return { action: "none", reason: `the apply-request is already terminal (${row.status}) \u2014 a new intent can be written.` };
22958
+ }
22959
+ const leaseLive = isInFlight(row.status) && row.leaseUntil !== null && Date.parse(row.leaseUntil) > Date.parse(nowIso);
22960
+ if (leaseLive && !force) {
22961
+ return {
22962
+ action: "refuse",
22963
+ reason: `the apply-request is ${row.status} and its lease is still live until ${row.leaseUntil ?? "(unknown)"} \u2014 a converge may be running right now. Clearing it could start a second apply alongside the first. Wait for the lease to expire, or pass --force if you know the engine is gone.`
22964
+ };
22965
+ }
22966
+ const held = leaseLive ? " (lease still live \u2014 forced)" : "";
22967
+ return { action: "clear", reason: `clearing a ${row.status} apply-request for target ${row.target}${held}.` };
22968
+ }
22969
+ function clearedRow(row, nowIso) {
22970
+ return {
22971
+ ...row,
22972
+ status: "failed",
22973
+ result: {
22974
+ appliedVersion: row.result?.appliedVersion ?? null,
22975
+ error: `${CLEARED_BY_OPERATOR} (was ${row.status}${row.phase ? `, phase "${row.phase}"` : ""})`
22976
+ },
22977
+ updatedAt: nowIso
22978
+ };
22979
+ }
22980
+
22981
+ // src/commands/platform/clear-intent.ts
22982
+ var PlatformClearIntentCommand = class extends M8tCommand {
22983
+ static paths = [["platform", "clear-intent"]];
22984
+ static usage = Command37.Usage({
22985
+ description: "Clear a stuck platform update request so a new one can be made.",
22986
+ details: "An update request that never settles blocks every later request, and the routines that would normally rescue it all run inside the updater itself \u2014 which is no help when the updater is what is stuck. This clears it from outside. Refuses while an update may still be running, unless --force.",
22987
+ examples: [
22988
+ ["Clear a stuck request", "m8t platform clear-intent --resource-group rg-m8t --subscription <id>"],
22989
+ ["Clear one whose lease is still live", "m8t platform clear-intent --resource-group rg-m8t --subscription <id> --force"]
22990
+ ]
22991
+ });
22992
+ subscription = Option34.String("--subscription");
22993
+ resourceGroup = Option34.String("--resource-group");
22994
+ miClientId = Option34.String("--mi-client-id", { description: "Authenticate as this user-assigned managed identity instead of the ambient credential." });
22995
+ force = Option34.Boolean("--force", false, {
22996
+ description: "Clear even while the lease is live. Only when you know the engine that held it is gone."
22997
+ });
22998
+ output = Option34.String("--output");
22999
+ async executeCommand() {
23000
+ const mode = resolveOutputMode(this.output, this.context.stdout);
23001
+ const need = (v, flag) => {
23002
+ if (typeof v !== "string" || v.trim().length === 0) {
23003
+ throw new LocalCliError({ code: "PLATFORM_CLEAR_INTENT_ARG_MISSING", message: `${flag} is required.` });
23004
+ }
23005
+ return v.trim();
23006
+ };
23007
+ const credential2 = typeof this.miClientId === "string" && this.miClientId.trim().length > 0 ? new ManagedIdentityCredential2({ clientId: this.miClientId.trim() }) : new DefaultAzureCredential18();
23008
+ const client = await openApplyTable({
23009
+ credential: credential2,
23010
+ subscriptionId: need(this.subscription, "--subscription"),
23011
+ resourceGroup: need(this.resourceGroup, "--resource-group")
23012
+ });
23013
+ const row = await readApplyRequest(client);
23014
+ const decision = decideClear(row, (/* @__PURE__ */ new Date()).toISOString(), this.force);
23015
+ if (decision.action === "refuse") {
23016
+ throw new LocalCliError({
23017
+ code: "PLATFORM_CLEAR_INTENT_REFUSED",
23018
+ message: decision.reason,
23019
+ hint: "Re-run with --force once you have confirmed no converge is running."
23020
+ });
23021
+ }
23022
+ if (decision.action === "none" || !row) {
23023
+ this.context.stdout.write(
23024
+ mode === "json" ? renderJson({ cleared: false, reason: decision.reason }) + "\n" : `${decision.reason}
23025
+ `
23026
+ );
23027
+ return 0;
23028
+ }
23029
+ const next = clearedRow(row, (/* @__PURE__ */ new Date()).toISOString());
23030
+ await client.updateEntity(applyRequestToEntity(next), "Merge");
23031
+ const result2 = { cleared: true, previousStatus: row.status, target: row.target, reason: decision.reason };
23032
+ this.context.stdout.write(
23033
+ mode === "json" ? renderJson(result2) + "\n" : `cleared: ${row.status} \u2192 failed (target ${row.target}). A new update can now be requested.
23034
+ `
23035
+ );
23036
+ return 0;
23037
+ }
23038
+ };
23039
+
23040
+ // src/commands/platform/request-update.ts
23041
+ import { Command as Command38, Option as Option35 } from "clipanion";
23042
+ import { DefaultAzureCredential as DefaultAzureCredential19, ManagedIdentityCredential as ManagedIdentityCredential3 } from "@azure/identity";
23043
+ init_errors();
23044
+
23045
+ // src/lib/request-update-follow.ts
23046
+ var TERMINAL = {
23047
+ success: true,
23048
+ failed: false,
23049
+ "rolled-back": false,
23050
+ held: false
23051
+ };
23052
+ function isTerminal(status) {
23053
+ return status in TERMINAL;
23054
+ }
23055
+ function classifyPolledRow(row, target) {
23056
+ if (!row) return null;
23057
+ if (row.target !== target) return { kind: "not-ours", otherTarget: row.target };
23058
+ if (isTerminal(row.status)) return { kind: "settled", row };
23059
+ return { kind: "in-progress", where: positionLabel(row.status, row.phase) };
23060
+ }
23061
+ function positionLabel(status, phase) {
23062
+ return phase ? `${status} (${phase})` : status;
23063
+ }
23064
+ function outcomeExitCode(settled) {
23065
+ if (!settled) return 1;
23066
+ return TERMINAL[settled.status] ? 0 : 1;
23067
+ }
23068
+ function outcomeStatus(settled) {
23069
+ return settled?.status ?? "timed-out";
23070
+ }
23071
+
23072
+ // src/commands/platform/request-update.ts
23073
+ var PlatformRequestUpdateCommand = class extends M8tCommand {
23074
+ static paths = [["platform", "request-update"]];
23075
+ static usage = Command38.Usage({
23076
+ description: "Ask this installation's updater to converge to a version, exactly as the in-app button does.",
23077
+ details: "Writes the update request the updater job claims on its next tick. This is the ONLY privilege the requester holds \u2014 it does not deploy anything itself; the install's own updater fetches the release, applies it, health-gates it and rolls back on failure. With --wait, follows the request to a terminal state and exits non-zero if it did not succeed.",
23078
+ examples: [
23079
+ ["Request an update", "m8t platform request-update --version 0.7.2 --resource-group rg-m8t --subscription <id>"],
23080
+ ["Request it and wait", "m8t platform request-update --version 0.7.2 --wait --resource-group rg-m8t --subscription <id>"]
23081
+ ]
23082
+ });
23083
+ version = Option35.String("--version", { description: "The platform version to converge to." });
23084
+ subscription = Option35.String("--subscription");
23085
+ resourceGroup = Option35.String("--resource-group");
23086
+ source = Option35.String("--source", "cd", { description: "Who is asking: cd | button | policy." });
23087
+ identity = Option35.String("--identity", "", { description: "Recorded on the request, for the audit trail." });
23088
+ miClientId = Option35.String("--mi-client-id");
23089
+ wait = Option35.Boolean("--wait", false, { description: "Follow the request until it settles." });
23090
+ /**
23091
+ * Follow an EXISTING request without writing a new one.
23092
+ *
23093
+ * Lets a caller write the request in one step and wait in another, which is
23094
+ * what makes the ordering provable: the row is a fact before anything is
23095
+ * started against it, instead of a background write racing a sleep.
23096
+ */
23097
+ waitOnly = Option35.Boolean("--wait-only", false, { description: "Follow the current request without creating one." });
23098
+ timeoutMinutes = Option35.String("--timeout-minutes", "45");
23099
+ pollSeconds = Option35.String("--poll-seconds", "20");
23100
+ output = Option35.String("--output");
23101
+ async executeCommand() {
23102
+ const mode = resolveOutputMode(this.output, this.context.stdout);
23103
+ const need = (v, flag) => {
23104
+ if (typeof v !== "string" || v.trim().length === 0) {
23105
+ throw new LocalCliError({ code: "PLATFORM_REQUEST_UPDATE_ARG_MISSING", message: `${flag} is required.` });
23106
+ }
23107
+ return v.trim();
23108
+ };
23109
+ const target = need(this.version, "--version");
23110
+ const SOURCES2 = ["cd", "button", "policy"];
23111
+ if (!SOURCES2.includes(this.source)) {
23112
+ throw new LocalCliError({ code: "PLATFORM_REQUEST_UPDATE_BAD_SOURCE", message: `--source must be cd, button or policy; got '${this.source}'.` });
23113
+ }
23114
+ const source = this.source;
23115
+ const credential2 = typeof this.miClientId === "string" && this.miClientId.trim().length > 0 ? new ManagedIdentityCredential3({ clientId: this.miClientId.trim() }) : new DefaultAzureCredential19();
23116
+ const client = await openApplyTable({
23117
+ credential: credential2,
23118
+ subscriptionId: need(this.subscription, "--subscription"),
23119
+ resourceGroup: need(this.resourceGroup, "--resource-group")
23120
+ });
23121
+ const log = (m) => {
23122
+ this.context.stderr.write(`${m}
23123
+ `);
23124
+ };
23125
+ if (!this.waitOnly) {
23126
+ const existing = await readApplyRequest(client);
23127
+ if (existing && blocksNewIntent(existing.status)) {
23128
+ throw new LocalCliError({
23129
+ code: "PLATFORM_REQUEST_UPDATE_IN_PROGRESS",
23130
+ message: `an update request for ${existing.target} is already ${existing.status}.`,
23131
+ hint: "Wait for it to settle, or clear it with `m8t platform clear-intent` if nothing is advancing it."
23132
+ });
23133
+ }
23134
+ const now = (/* @__PURE__ */ new Date()).toISOString();
23135
+ const intent = newIntent(target, { source, identity: this.identity || source, at: now }, now);
23136
+ await client.upsertEntity(applyRequestToEntity(intent), "Replace");
23137
+ log(`requested update to ${target} (source ${source}).`);
23138
+ } else {
23139
+ log(`following the existing request for ${target}.`);
23140
+ }
23141
+ if (!this.wait && !this.waitOnly) {
23142
+ this.context.stdout.write(
23143
+ mode === "json" ? renderJson({ requested: true, target, waited: false }) + "\n" : `requested update to ${target}.
23144
+ `
23145
+ );
23146
+ return 0;
23147
+ }
23148
+ const settled = await this.follow(client, target, log);
23149
+ const result2 = {
23150
+ requested: true,
23151
+ target,
23152
+ waited: true,
23153
+ status: outcomeStatus(settled),
23154
+ error: settled?.result?.error ?? null
23155
+ };
23156
+ this.context.stdout.write(
23157
+ mode === "json" ? renderJson(result2) + "\n" : `${target}: ${result2.status}${result2.error ? ` \u2014 ${result2.error}` : ""}
23158
+ `
23159
+ );
23160
+ return outcomeExitCode(settled);
23161
+ }
23162
+ /**
23163
+ * Follow the request until it settles.
23164
+ *
23165
+ * `awaiting-engine-update` is explicitly NOT a failure and not a stall: the
23166
+ * updater parks a request there while it replaces its own image, so a converge
23167
+ * legitimately spans two ticks. Treating that as stuck would fail a build for
23168
+ * doing exactly what it is supposed to do.
23169
+ */
23170
+ async follow(client, target, log) {
23171
+ const timeoutMs = Number(this.timeoutMinutes) * 60 * 1e3;
23172
+ const pollMs = Number(this.pollSeconds) * 1e3;
23173
+ if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
23174
+ throw new LocalCliError({ code: "PLATFORM_REQUEST_UPDATE_BAD_TIMEOUT", message: `--timeout-minutes must be a positive number, got '${this.timeoutMinutes}'.` });
23175
+ }
23176
+ const deadline = Date.now() + timeoutMs;
23177
+ let lastReported = "";
23178
+ let consecutiveAbsent = 0;
23179
+ while (Date.now() < deadline) {
23180
+ await new Promise((r) => setTimeout(r, pollMs));
23181
+ const verdict = classifyPolledRow(await readApplyRequest(client), target);
23182
+ if (!verdict) {
23183
+ consecutiveAbsent += 1;
23184
+ if (consecutiveAbsent >= 3) {
23185
+ throw new LocalCliError({
23186
+ code: "PLATFORM_REQUEST_UPDATE_ROW_ABSENT",
23187
+ message: `no update request found for ${target} after ${String(consecutiveAbsent)} polls.`,
23188
+ hint: "Something removed the row after it was written. Check for a concurrent `clear-intent` or a competing requester."
23189
+ });
23190
+ }
23191
+ continue;
23192
+ }
23193
+ consecutiveAbsent = 0;
23194
+ if (verdict.kind === "settled") return verdict.row;
23195
+ const line2 = verdict.kind === "not-ours" ? ` (ignoring a request for ${verdict.otherTarget} \u2014 not the one we made)` : ` ${verdict.where}`;
23196
+ if (line2 !== lastReported) {
23197
+ log(line2);
23198
+ lastReported = line2;
23199
+ }
23200
+ }
23201
+ return null;
23202
+ }
23203
+ };
23204
+
23205
+ // src/commands/platform/seed-stamp.ts
23206
+ import { readFileSync as readFileSync20 } from "fs";
23207
+ import { Command as Command39, Option as Option36 } from "clipanion";
23208
+ import { DefaultAzureCredential as DefaultAzureCredential20, ManagedIdentityCredential as ManagedIdentityCredential4 } from "@azure/identity";
23209
+ init_errors();
23210
+
22863
23211
  // src/lib/platform-stamp-seed.ts
22864
23212
  var IMAGE_COMPONENTS = ["gateway", "codingAgent", "azureExecutor"];
22865
23213
  var BARE_SEMVER = /^\d+\.\d+\.\d+$/;
@@ -22942,7 +23290,7 @@ function buildSeedStamp(d, cliVersion, nowIso) {
22942
23290
 
22943
23291
  // src/commands/platform/seed-stamp.ts
22944
23292
  async function seedStamp2(args) {
22945
- const readFileImpl = args.readFileImpl ?? ((p) => readFileSync21(p, "utf8"));
23293
+ const readFileImpl = args.readFileImpl ?? ((p) => readFileSync20(p, "utf8"));
22946
23294
  const readStampImpl = args.readStampImpl ?? readStamp;
22947
23295
  const writeStampImpl = args.writeStampImpl ?? ((stamp2, o) => writeStamp({ ...o, stamp: stamp2 }));
22948
23296
  const discoverImpl = args.discoverImpl ?? discoverStampStorage;
@@ -22988,15 +23336,15 @@ async function seedStamp2(args) {
22988
23336
  }
22989
23337
  var PlatformSeedStampCommand = class extends M8tCommand {
22990
23338
  static paths = [["platform", "seed-stamp"]];
22991
- static usage = Command37.Usage({
23339
+ static usage = Command39.Usage({
22992
23340
  description: "INTERNAL: write the initial installed-state stamp from a build-time install descriptor.",
22993
23341
  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'."
22994
23342
  });
22995
- descriptor = Option34.String("--descriptor", { description: "Path to install-descriptor.json (baked into the installer image)." });
22996
- subscription = Option34.String("--subscription");
22997
- resourceGroup = Option34.String("--resource-group");
22998
- miClientId = Option34.String("--mi-client-id", { description: "Authenticate as this user-assigned managed identity instead of the ambient credential." });
22999
- output = Option34.String("--output");
23343
+ descriptor = Option36.String("--descriptor", { description: "Path to install-descriptor.json (baked into the installer image)." });
23344
+ subscription = Option36.String("--subscription");
23345
+ resourceGroup = Option36.String("--resource-group");
23346
+ miClientId = Option36.String("--mi-client-id", { description: "Authenticate as this user-assigned managed identity instead of the ambient credential." });
23347
+ output = Option36.String("--output");
23000
23348
  async executeCommand() {
23001
23349
  const mode = resolveOutputMode(this.output, this.context.stdout);
23002
23350
  const need = (v, flag) => {
@@ -23009,7 +23357,7 @@ var PlatformSeedStampCommand = class extends M8tCommand {
23009
23357
  this.context.stderr.write(`${m}
23010
23358
  `);
23011
23359
  };
23012
- const credential2 = typeof this.miClientId === "string" && this.miClientId.trim().length > 0 ? new ManagedIdentityCredential2({ clientId: this.miClientId.trim() }) : new DefaultAzureCredential18();
23360
+ const credential2 = typeof this.miClientId === "string" && this.miClientId.trim().length > 0 ? new ManagedIdentityCredential4({ clientId: this.miClientId.trim() }) : new DefaultAzureCredential20();
23013
23361
  const result2 = await seedStamp2({
23014
23362
  descriptorPath: need(this.descriptor, "--descriptor"),
23015
23363
  credential: credential2,
@@ -23027,105 +23375,9 @@ var PlatformSeedStampCommand = class extends M8tCommand {
23027
23375
  }
23028
23376
  };
23029
23377
 
23030
- // src/commands/platform/stamp-build.ts
23031
- import { Command as Command38, Option as Option35 } from "clipanion";
23032
- import { DefaultAzureCredential as DefaultAzureCredential19, ManagedIdentityCredential as ManagedIdentityCredential3 } from "@azure/identity";
23033
- init_errors();
23034
-
23035
- // src/lib/platform-stamp-build.ts
23036
- var BARE_SEMVER2 = /^\d+\.\d+\.\d+$/;
23037
- function buildRunningBuildStamp(input) {
23038
- if (!BARE_SEMVER2.test(input.version)) {
23039
- throw new Error(
23040
- `platform version must be bare X.Y.Z, got "${input.version}" \u2014 a build tag cannot be represented as a version.`
23041
- );
23042
- }
23043
- return {
23044
- schemaVersion: 1,
23045
- platformVersion: platformTag(input.version),
23046
- previousPlatformVersion: input.previousPlatformVersion,
23047
- updatedAt: input.nowIso,
23048
- lastResult: "success",
23049
- cli: input.cliVersion,
23050
- origin: "cd",
23051
- components: {
23052
- gateway: { tag: input.gatewayTag, digest: input.gatewayDigest, state: "managed" },
23053
- codingAgent: { tag: "", digest: "", state: "external" },
23054
- azureExecutor: { tag: "", digest: "", state: "external" },
23055
- personas: input.personas,
23056
- infra: { treeSha: input.infraTreeSha },
23057
- ...input.brainSeeds ? { brainSeeds: input.brainSeeds } : {}
23058
- }
23059
- };
23060
- }
23061
-
23062
- // src/commands/platform/stamp-build.ts
23063
- var PlatformStampBuildCommand = class extends M8tCommand {
23064
- static paths = [["platform", "stamp-build"]];
23065
- static usage = Command38.Usage({
23066
- description: "Record the currently running build as this install's platform version.",
23067
- 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."
23068
- });
23069
- version = Option35.String("--version", { description: "The running build's own version, bare X.Y.Z." });
23070
- gatewayTag = Option35.String("--gateway-tag", { description: "The tag of the gateway image this build deployed." });
23071
- gatewayDigest = Option35.String("--gateway-digest", { description: "The digest of the gateway image this build deployed." });
23072
- subscription = Option35.String("--subscription");
23073
- resourceGroup = Option35.String("--resource-group");
23074
- miClientId = Option35.String("--mi-client-id", { description: "Authenticate as this user-assigned managed identity instead of the ambient credential." });
23075
- output = Option35.String("--output");
23076
- async executeCommand() {
23077
- const mode = resolveOutputMode(this.output, this.context.stdout);
23078
- const need = (v, flag) => {
23079
- if (typeof v !== "string" || v.trim().length === 0) {
23080
- throw new LocalCliError({ code: "PLATFORM_STAMP_BUILD_ARG_MISSING", message: `${flag} is required.` });
23081
- }
23082
- return v.trim();
23083
- };
23084
- const onProgress = (m) => {
23085
- this.context.stderr.write(`${m}
23086
- `);
23087
- };
23088
- const credential2 = typeof this.miClientId === "string" && this.miClientId.trim().length > 0 ? new ManagedIdentityCredential3({ clientId: this.miClientId.trim() }) : new DefaultAzureCredential19();
23089
- const ctx = {
23090
- credential: credential2,
23091
- subscriptionId: need(this.subscription, "--subscription"),
23092
- resourceGroup: need(this.resourceGroup, "--resource-group")
23093
- };
23094
- const { accountName } = await discoverStampStorage(ctx);
23095
- const existing = await readStampOutcome(ctx);
23096
- if (existing.source === "unreadable") {
23097
- throw new LocalCliError({
23098
- code: "PLATFORM_STAMP_BUILD_PRIOR_UNREADABLE",
23099
- message: "Could not read the existing platform stamp; refusing to overwrite it blind.",
23100
- hint: "The running build is the truth about the CURRENT version, not about whether a previous one existed \u2014 retry once the prior record can be read."
23101
- });
23102
- }
23103
- const previousPlatformVersion = existing.source === "explicit" ? existing.stamp.platformVersion : null;
23104
- const priorComponents = existing.source === "explicit" ? existing.stamp.components : void 0;
23105
- const stamp = buildRunningBuildStamp({
23106
- version: need(this.version, "--version"),
23107
- gatewayTag: need(this.gatewayTag, "--gateway-tag"),
23108
- gatewayDigest: this.gatewayDigest ?? "",
23109
- previousPlatformVersion,
23110
- cliVersion: CLI_VERSION,
23111
- nowIso: (/* @__PURE__ */ new Date()).toISOString(),
23112
- personas: priorComponents?.personas ?? {},
23113
- infraTreeSha: priorComponents?.infra.treeSha ?? "",
23114
- ...priorComponents?.brainSeeds ? { brainSeeds: priorComponents.brainSeeds } : {}
23115
- });
23116
- await writeStamp({ ...ctx, stamp, onProgress });
23117
- const result2 = { platformVersion: stamp.platformVersion, previous: previousPlatformVersion, storageAccount: accountName };
23118
- this.context.stdout.write(
23119
- mode === "json" ? renderJson(result2) + "\n" : `platform stamp: ${result2.platformVersion} (previous ${result2.previous ?? "none"}, storage ${result2.storageAccount})
23120
- `
23121
- );
23122
- return 0;
23123
- }
23124
- };
23125
-
23126
23378
  // src/commands/platform/policy.ts
23127
- import { Command as Command39, Option as Option36 } from "clipanion";
23128
- import { DefaultAzureCredential as DefaultAzureCredential20, ManagedIdentityCredential as ManagedIdentityCredential4 } from "@azure/identity";
23379
+ import { Command as Command40, Option as Option37 } from "clipanion";
23380
+ import { DefaultAzureCredential as DefaultAzureCredential21, ManagedIdentityCredential as ManagedIdentityCredential5 } from "@azure/identity";
23129
23381
  init_errors();
23130
23382
 
23131
23383
  // src/lib/platform-policy.ts
@@ -23180,16 +23432,16 @@ async function readPolicy(opts) {
23180
23432
  // src/commands/platform/policy.ts
23181
23433
  var PlatformPolicyCommand = class extends M8tCommand {
23182
23434
  static paths = [["platform", "policy"]];
23183
- static usage = Command39.Usage({
23435
+ static usage = Command40.Usage({
23184
23436
  description: "Show or set how this install handles available platform updates.",
23185
23437
  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.",
23186
23438
  examples: [["Show the current mode", "m8t platform policy"], ["Never apply automatically", "m8t platform policy --set notify-only"]]
23187
23439
  });
23188
- set = Option36.String("--set", { description: "notify-only | auto-critical | auto-all" });
23189
- subscription = Option36.String("--subscription");
23190
- resourceGroup = Option36.String("--resource-group");
23191
- miClientId = Option36.String("--mi-client-id");
23192
- output = Option36.String("--output");
23440
+ set = Option37.String("--set", { description: "notify-only | auto-critical | auto-all" });
23441
+ subscription = Option37.String("--subscription");
23442
+ resourceGroup = Option37.String("--resource-group");
23443
+ miClientId = Option37.String("--mi-client-id");
23444
+ output = Option37.String("--output");
23193
23445
  async executeCommand() {
23194
23446
  const mode = resolveOutputMode(this.output, this.context.stdout);
23195
23447
  const need = (v, flag) => {
@@ -23202,7 +23454,7 @@ var PlatformPolicyCommand = class extends M8tCommand {
23202
23454
  this.context.stderr.write(`${m}
23203
23455
  `);
23204
23456
  };
23205
- const credential2 = typeof this.miClientId === "string" && this.miClientId.trim().length > 0 ? new ManagedIdentityCredential4({ clientId: this.miClientId.trim() }) : new DefaultAzureCredential20();
23457
+ const credential2 = typeof this.miClientId === "string" && this.miClientId.trim().length > 0 ? new ManagedIdentityCredential5({ clientId: this.miClientId.trim() }) : new DefaultAzureCredential21();
23206
23458
  const ctx = {
23207
23459
  credential: credential2,
23208
23460
  subscriptionId: need(this.subscription, "--subscription"),
@@ -23235,7 +23487,7 @@ var PlatformPolicyCommand = class extends M8tCommand {
23235
23487
  };
23236
23488
 
23237
23489
  // src/commands/platform/enable-cost-report.ts
23238
- import { Command as Command40, Option as Option37 } from "clipanion";
23490
+ import { Command as Command41, Option as Option38 } from "clipanion";
23239
23491
 
23240
23492
  // src/lib/wire-gateway-acs.ts
23241
23493
  init_rbac();
@@ -23275,18 +23527,18 @@ async function wireGatewayForAcs(args) {
23275
23527
  init_errors();
23276
23528
  var PlatformEnableCostReportCommand = class extends M8tCommand {
23277
23529
  static paths = [["platform", "enable-cost-report"]];
23278
- static usage = Command40.Usage({
23530
+ static usage = Command41.Usage({
23279
23531
  description: "Wire the deployed gateway to send the bi-weekly cost report via ACS Email.",
23280
23532
  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')."
23281
23533
  });
23282
- subscription = Option37.String("--subscription");
23283
- resourceGroup = Option37.String("--resource-group", {
23534
+ subscription = Option38.String("--subscription");
23535
+ resourceGroup = Option38.String("--resource-group", {
23284
23536
  description: "m8t resource group to disambiguate the gateway (multi-deployment subscriptions)."
23285
23537
  });
23286
- acsEndpoint = Option37.String("--acs-endpoint", { required: true, description: "ACS data-plane endpoint, e.g. https://acs-<name>.communication.azure.com/" });
23287
- acsSender = Option37.String("--acs-sender", { required: true, description: "Managed-domain sender address, e.g. DoNotReply@<guid>.azurecomm.net" });
23288
- acsResourceId = Option37.String("--acs-resource-id", { required: true, description: "ARM resource id of the acs-<name> Communication Service \u2014 the role-grant scope." });
23289
- output = Option37.String("--output");
23538
+ acsEndpoint = Option38.String("--acs-endpoint", { required: true, description: "ACS data-plane endpoint, e.g. https://acs-<name>.communication.azure.com/" });
23539
+ acsSender = Option38.String("--acs-sender", { required: true, description: "Managed-domain sender address, e.g. DoNotReply@<guid>.azurecomm.net" });
23540
+ acsResourceId = Option38.String("--acs-resource-id", { required: true, description: "ARM resource id of the acs-<name> Communication Service \u2014 the role-grant scope." });
23541
+ output = Option38.String("--output");
23290
23542
  async executeCommand() {
23291
23543
  const mode = resolveOutputMode(
23292
23544
  this.output,
@@ -23360,45 +23612,45 @@ var PlatformEnableCostReportCommand = class extends M8tCommand {
23360
23612
  };
23361
23613
 
23362
23614
  // src/commands/platform/enable-auto-update.ts
23363
- import { Command as Command41, Option as Option38 } from "clipanion";
23615
+ import { Command as Command42, Option as Option39 } from "clipanion";
23364
23616
  import { confirm as confirm6 } from "@inquirer/prompts";
23365
- import { DefaultAzureCredential as DefaultAzureCredential21 } from "@azure/identity";
23617
+ import { DefaultAzureCredential as DefaultAzureCredential22 } from "@azure/identity";
23366
23618
  init_errors();
23367
23619
  var PlatformEnableAutoUpdateCommand = class extends M8tCommand {
23368
23620
  static paths = [["platform", "enable-auto-update"]];
23369
- static usage = Command41.Usage({
23621
+ static usage = Command42.Usage({
23370
23622
  category: "Platform",
23371
23623
  description: "Retrofit the auto-updater (MI + cron job + role assignments) onto an existing install.",
23372
23624
  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."
23373
23625
  });
23374
- subscription = Option38.String("--subscription");
23375
- resourceGroup = Option38.String("--resource-group", {
23626
+ subscription = Option39.String("--subscription");
23627
+ resourceGroup = Option39.String("--resource-group", {
23376
23628
  description: "m8t resource group to disambiguate the gateway (multi-deployment subscriptions)."
23377
23629
  });
23378
- suffix = Option38.String("--suffix", {
23630
+ suffix = Option39.String("--suffix", {
23379
23631
  description: "The existing deployment's resource-name suffix. Required when it cannot be recovered from system/infra-params or the live gateway."
23380
23632
  });
23381
- installerImage = Option38.String("--installer-image", {
23633
+ installerImage = Option39.String("--installer-image", {
23382
23634
  required: true,
23383
23635
  description: "Updater CA-Job image ref (the converge engine at the current release). Required \u2014 an empty image would skip provisioning."
23384
23636
  });
23385
- updateCron = Option38.String("--update-cron", {
23637
+ updateCron = Option39.String("--update-cron", {
23386
23638
  description: "Cron schedule for the updater job (bicep default applies when omitted)."
23387
23639
  });
23388
- channelUrl = Option38.String("--channel-url", {
23640
+ channelUrl = Option39.String("--channel-url", {
23389
23641
  description: "Release-channel URL the updater job polls (bicep default applies when omitted)."
23390
23642
  });
23391
- location = Option38.String("--location", {
23643
+ location = Option39.String("--location", {
23392
23644
  description: "Region for the updater identity + job. Defaults to the resource group's existing resources."
23393
23645
  });
23394
- foundryTracing = Option38.String("--foundry-tracing", {
23646
+ foundryTracing = Option39.String("--foundry-tracing", {
23395
23647
  description: "project | account | skip. Pass the value the install was deployed with \u2014 omitting it lets the bicep default (project) switch tracing on."
23396
23648
  });
23397
- endpoint = Option38.String("--endpoint", {
23649
+ endpoint = Option39.String("--endpoint", {
23398
23650
  description: "Foundry project endpoint URL. Disambiguates the project in a multi-project subscription."
23399
23651
  });
23400
- yes = Option38.Boolean("--yes", false);
23401
- output = Option38.String("--output");
23652
+ yes = Option39.Boolean("--yes", false);
23653
+ output = Option39.String("--output");
23402
23654
  async executeCommand() {
23403
23655
  const mode = resolveOutputMode(
23404
23656
  this.output,
@@ -23417,7 +23669,7 @@ var PlatformEnableAutoUpdateCommand = class extends M8tCommand {
23417
23669
  resourceGroup: this.resourceGroup
23418
23670
  });
23419
23671
  const { resourceGroup, name: gatewayName } = parseContainerAppResourceId(gw.containerAppResourceId);
23420
- const credential2 = new DefaultAzureCredential21();
23672
+ const credential2 = new DefaultAzureCredential22();
23421
23673
  const account = await getAzAccount();
23422
23674
  const subscriptionId = this.subscription ?? account.subscriptionId;
23423
23675
  const explicitSuffix = typeof this.suffix === "string" && this.suffix.length > 0 ? this.suffix : void 0;
@@ -23535,7 +23787,7 @@ var PlatformEnableAutoUpdateCommand = class extends M8tCommand {
23535
23787
  };
23536
23788
 
23537
23789
  // src/commands/deploy.ts
23538
- import { Command as Command42, Option as Option39 } from "clipanion";
23790
+ import { Command as Command43, Option as Option40 } from "clipanion";
23539
23791
 
23540
23792
  // src/lib/app-reg.ts
23541
23793
  init_esm();
@@ -23869,7 +24121,7 @@ async function patchRedirectUris(appObjectId, fqdn) {
23869
24121
  init_errors();
23870
24122
 
23871
24123
  // src/lib/whatif.ts
23872
- import * as path33 from "path";
24124
+ import * as path32 from "path";
23873
24125
 
23874
24126
  // src/lib/identifier-patterns.ts
23875
24127
  var IDENTIFIER_PATTERNS = [
@@ -23925,7 +24177,7 @@ function deriveResourceType(resourceId) {
23925
24177
  return parts.join("/");
23926
24178
  }
23927
24179
  async function runWhatIf(opts) {
23928
- const bicepPath = path33.join(opts.repoRoot, "deploy", "main.bicep");
24180
+ const bicepPath = path32.join(opts.repoRoot, "deploy", "main.bicep");
23929
24181
  const out = await runAz([
23930
24182
  "deployment",
23931
24183
  "group",
@@ -24023,9 +24275,9 @@ function flattenDelta(delta, prefix = "") {
24023
24275
  const out = [];
24024
24276
  for (const d of delta) {
24025
24277
  const segment = /^[0-9]+$/.test(d.path) ? `[${d.path}]` : prefix ? `.${d.path}` : d.path;
24026
- const path48 = prefix ? `${prefix}${segment}` : d.path;
24027
- if (d.children && d.children.length > 0) out.push(...flattenDelta(d.children, path48));
24028
- else out.push({ ...d, path: path48 });
24278
+ const path47 = prefix ? `${prefix}${segment}` : d.path;
24279
+ if (d.children && d.children.length > 0) out.push(...flattenDelta(d.children, path47));
24280
+ else out.push({ ...d, path: path47 });
24029
24281
  }
24030
24282
  return out;
24031
24283
  }
@@ -24075,52 +24327,63 @@ function classifyWhatIf(changes) {
24075
24327
  var DEFAULT_IMAGE_REF = "ghcr.io/m8t-labs/m8t:latest";
24076
24328
  var DeployCommand = class extends M8tCommand {
24077
24329
  static paths = [["deploy"]];
24078
- static usage = Command42.Usage({
24330
+ static usage = Command43.Usage({
24079
24331
  description: "Deploy (or update) the m8t gateway/webapp stack via Bicep.",
24080
24332
  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."
24081
24333
  });
24082
- subscription = Option39.String("--subscription");
24083
- resourceGroup = Option39.String("--resource-group", "rg-m8t-stack");
24084
- location = Option39.String("--location", "eastus");
24085
- suffix = Option39.String("--suffix", "");
24086
- imageRef = Option39.String("--image-ref", DEFAULT_IMAGE_REF);
24087
- acrPullIdentity = Option39.String("--acrpull-identity");
24088
- acrResourceId = Option39.String("--acr-resource-id");
24089
- foundryEndpoint = Option39.String("--foundry-endpoint");
24090
- foundryResourceId = Option39.String("--foundry-resource-id");
24091
- foundryTracing = Option39.String("--foundry-tracing");
24334
+ subscription = Option40.String("--subscription");
24335
+ resourceGroup = Option40.String("--resource-group", "rg-m8t-stack");
24336
+ location = Option40.String("--location", "eastus");
24337
+ suffix = Option40.String("--suffix", "");
24338
+ imageRef = Option40.String("--image-ref", DEFAULT_IMAGE_REF);
24339
+ acrPullIdentity = Option40.String("--acrpull-identity");
24340
+ acrResourceId = Option40.String("--acr-resource-id");
24341
+ foundryEndpoint = Option40.String("--foundry-endpoint");
24342
+ foundryResourceId = Option40.String("--foundry-resource-id");
24343
+ foundryTracing = Option40.String("--foundry-tracing");
24092
24344
  // project | account | skip (bicep default: project)
24093
- clientId = Option39.String("--client-id");
24094
- whatIf = Option39.Boolean("--what-if", false);
24345
+ clientId = Option40.String("--client-id");
24346
+ whatIf = Option40.Boolean("--what-if", false);
24095
24347
  // Only meaningful with --what-if. Routes the comparison through the
24096
24348
  // value-free renderers (see ./lib/whatif-redact.js) instead of the default
24097
24349
  // before/after renderer. Defaults false so a local, interactive run keeps
24098
24350
  // showing values — that is the whole diagnostic point of --what-if.
24099
24351
  // Automation that forwards this output anywhere non-private (a CI log, an
24100
24352
  // issue) MUST pass --redact.
24101
- redact = Option39.Boolean("--redact", false);
24102
- output = Option39.String("--output");
24353
+ redact = Option40.Boolean("--redact", false);
24354
+ output = Option40.String("--output");
24103
24355
  // Subscription-scoped role assignments. Omitted ⇒ the template default (true).
24104
24356
  // Pass false when deploying as a principal scoped to the resource group only:
24105
24357
  // it cannot deploy at subscription scope, and those assignments persist
24106
24358
  // idempotently from the initial deployment anyway.
24107
- assignSubscriptionRoles = Option39.String("--assign-subscription-roles");
24359
+ assignSubscriptionRoles = Option40.String("--assign-subscription-roles");
24360
+ /**
24361
+ * The installer image the updater Container-Apps Job runs.
24362
+ *
24363
+ * main.bicep only provisions the updater when an image is supplied
24364
+ * (`provisionUpdaterEffective = provisionUpdater && !empty(installerImage)`),
24365
+ * so a run that omits this describes a deployment WITHOUT an updater. For a
24366
+ * real deploy that is merely a skip; for a `--what-if` comparison it is worse
24367
+ * than that — the comparison proposes REMOVING an updater job that exists and
24368
+ * should, and reports it as drift on every single run.
24369
+ */
24370
+ installerImage = Option40.String("--installer-image");
24108
24371
  // Referee — all optional, undefined by default ⇒ the bicep defaults
24109
24372
  // apply (dormant: gatewayCpu=0.25, gatewayMemory=0.5Gi, every referee/exam var
24110
24373
  // empty). Only pass these when explicitly enabling the referee exam stack.
24111
- gatewayCpu = Option39.String("--gateway-cpu");
24112
- gatewayMemory = Option39.String("--gateway-memory");
24113
- refereeEnabled = Option39.String("--referee-enabled");
24114
- refereeBrainRepos = Option39.String("--referee-brain-repos");
24115
- refereeFeedRepo = Option39.String("--referee-feed-repo");
24116
- refereeInstallationId = Option39.String("--referee-installation-id");
24117
- refereeWebhookHmacKvUri = Option39.String("--referee-webhook-hmac-kv-uri");
24118
- examKvUri = Option39.String("--exam-kv-uri");
24119
- examLaWorkspaceId = Option39.String("--exam-la-workspace-id");
24120
- brainEvalDeployment = Option39.String("--brain-eval-deployment");
24121
- brainAppLogin = Option39.String("--brain-app-login");
24122
- refereeCheckpointDir = Option39.String("--referee-checkpoint-dir");
24123
- examApiBase = Option39.String("--exam-api-base");
24374
+ gatewayCpu = Option40.String("--gateway-cpu");
24375
+ gatewayMemory = Option40.String("--gateway-memory");
24376
+ refereeEnabled = Option40.String("--referee-enabled");
24377
+ refereeBrainRepos = Option40.String("--referee-brain-repos");
24378
+ refereeFeedRepo = Option40.String("--referee-feed-repo");
24379
+ refereeInstallationId = Option40.String("--referee-installation-id");
24380
+ refereeWebhookHmacKvUri = Option40.String("--referee-webhook-hmac-kv-uri");
24381
+ examKvUri = Option40.String("--exam-kv-uri");
24382
+ examLaWorkspaceId = Option40.String("--exam-la-workspace-id");
24383
+ brainEvalDeployment = Option40.String("--brain-eval-deployment");
24384
+ brainAppLogin = Option40.String("--brain-app-login");
24385
+ refereeCheckpointDir = Option40.String("--referee-checkpoint-dir");
24386
+ examApiBase = Option40.String("--exam-api-base");
24124
24387
  async executeCommand() {
24125
24388
  const mode = resolveOutputMode(
24126
24389
  this.output,
@@ -24182,7 +24445,8 @@ var DeployCommand = class extends M8tCommand {
24182
24445
  brainAppLogin: this.brainAppLogin,
24183
24446
  refereeCheckpointDir: this.refereeCheckpointDir,
24184
24447
  examApiBase: this.examApiBase,
24185
- ...parseAssignSubscriptionRoles(this.assignSubscriptionRoles) === void 0 ? {} : { assignSubscriptionRoles: parseAssignSubscriptionRoles(this.assignSubscriptionRoles) }
24448
+ ...parseAssignSubscriptionRoles(this.assignSubscriptionRoles) === void 0 ? {} : { assignSubscriptionRoles: parseAssignSubscriptionRoles(this.assignSubscriptionRoles) },
24449
+ ...this.installerImage ? { installerImage: this.installerImage } : {}
24186
24450
  });
24187
24451
  const changes = await runWhatIf({ resourceGroup: this.resourceGroup, repoRoot: repoRoot2, params: params2 });
24188
24452
  const classified = classifyWhatIf(changes);
@@ -24250,7 +24514,8 @@ var DeployCommand = class extends M8tCommand {
24250
24514
  brainAppLogin: this.brainAppLogin,
24251
24515
  refereeCheckpointDir: this.refereeCheckpointDir,
24252
24516
  examApiBase: this.examApiBase,
24253
- ...parseAssignSubscriptionRoles(this.assignSubscriptionRoles) === void 0 ? {} : { assignSubscriptionRoles: parseAssignSubscriptionRoles(this.assignSubscriptionRoles) }
24517
+ ...parseAssignSubscriptionRoles(this.assignSubscriptionRoles) === void 0 ? {} : { assignSubscriptionRoles: parseAssignSubscriptionRoles(this.assignSubscriptionRoles) },
24518
+ ...this.installerImage ? { installerImage: this.installerImage } : {}
24254
24519
  });
24255
24520
  log("running Bicep deployment (~3-5 min)\u2026");
24256
24521
  const outputs = await runBicepDeployment({
@@ -24299,7 +24564,7 @@ var DeployCommand = class extends M8tCommand {
24299
24564
 
24300
24565
  // src/commands/eval/skill.ts
24301
24566
  import { spawnSync as spawnSync4 } from "child_process";
24302
- import { Command as Command43, Option as Option40 } from "clipanion";
24567
+ import { Command as Command44, Option as Option41 } from "clipanion";
24303
24568
  init_errors();
24304
24569
  var DECISIONS = /* @__PURE__ */ new Set(["promote", "reject", "needs_review"]);
24305
24570
  var JUDGE_STATUSES = /* @__PURE__ */ new Set(["ok", "skipped", "unavailable"]);
@@ -24324,14 +24589,14 @@ function parseVerdict(stdout) {
24324
24589
  }
24325
24590
  var EvalSkillCommand = class extends M8tCommand {
24326
24591
  static paths = [["eval", "skill"]];
24327
- static usage = Command43.Usage({
24592
+ static usage = Command44.Usage({
24328
24593
  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)."
24329
24594
  });
24330
- candidate = Option40.String();
24331
- skillsDir = Option40.String("--skills-dir");
24332
- noJudge = Option40.Boolean("--no-judge", false);
24333
- deployment = Option40.String("--deployment");
24334
- output = Option40.String("--output");
24595
+ candidate = Option41.String();
24596
+ skillsDir = Option41.String("--skills-dir");
24597
+ noJudge = Option41.Boolean("--no-judge", false);
24598
+ deployment = Option41.String("--deployment");
24599
+ output = Option41.String("--output");
24335
24600
  executeCommand() {
24336
24601
  return Promise.resolve(this._runCommand());
24337
24602
  }
@@ -24388,9 +24653,9 @@ var EvalSkillCommand = class extends M8tCommand {
24388
24653
 
24389
24654
  // src/commands/eval/exam.ts
24390
24655
  import { spawnSync as spawnSync5 } from "child_process";
24391
- import { writeFileSync as writeFileSync8, mkdirSync as mkdirSync6, readFileSync as readFileSync22, existsSync as existsSync20, readdirSync as readdirSync3 } from "fs";
24392
- import { join as join31 } from "path";
24393
- import { Command as Command44, Option as Option41 } from "clipanion";
24656
+ import { writeFileSync as writeFileSync8, mkdirSync as mkdirSync6, readFileSync as readFileSync21, existsSync as existsSync20, readdirSync as readdirSync3 } from "fs";
24657
+ import { join as join30 } from "path";
24658
+ import { Command as Command45, Option as Option42 } from "clipanion";
24394
24659
  init_errors();
24395
24660
  init_esm();
24396
24661
  function parseArmToken(tok, opts) {
@@ -24571,9 +24836,9 @@ function resolveRefereeHome(refereeHomeOut, env) {
24571
24836
  return null;
24572
24837
  }
24573
24838
  function resolveTaskSetDir(base, worker, version) {
24574
- if (existsSync20(join31(base, version))) return version;
24839
+ if (existsSync20(join30(base, version))) return version;
24575
24840
  const prefixed = `${worker}-${version}`;
24576
- if (existsSync20(join31(base, prefixed))) return prefixed;
24841
+ if (existsSync20(join30(base, prefixed))) return prefixed;
24577
24842
  if (version === "latest" && existsSync20(base)) {
24578
24843
  const dirs = readdirSync3(base, { withFileTypes: true }).filter((d) => d.isDirectory() && d.name.startsWith(`${worker}-`)).map((d) => d.name).sort();
24579
24844
  if (dirs.length > 0) return dirs[dirs.length - 1];
@@ -24589,11 +24854,11 @@ function readSealedTaskIds(taskSetVersion, refereeHomeOut, env = process.env) {
24589
24854
  message: "cannot resolve the referee home to read the sealed-task manifest \u2014 set $REFEREE_HOME (mirroring the Python runner) so the feed can be redacted; refusing to emit a possibly-unredacted feed (Law-1)"
24590
24855
  });
24591
24856
  }
24592
- const versionDir = resolveTaskSetDir(join31(home, "tasksets", worker), worker, version);
24593
- const manifestPath = join31(home, "tasksets", worker, versionDir, "manifest.yaml");
24857
+ const versionDir = resolveTaskSetDir(join30(home, "tasksets", worker), worker, version);
24858
+ const manifestPath = join30(home, "tasksets", worker, versionDir, "manifest.yaml");
24594
24859
  let text;
24595
24860
  try {
24596
- text = readFileSync22(manifestPath, "utf-8");
24861
+ text = readFileSync21(manifestPath, "utf-8");
24597
24862
  } catch (e) {
24598
24863
  throw new LocalCliError({
24599
24864
  code: "EXAM_REDACTION_UNSAFE",
@@ -24620,24 +24885,24 @@ function buildPlan(args) {
24620
24885
  }
24621
24886
  var EvalExamCommand = class extends M8tCommand {
24622
24887
  static paths = [["eval", "exam"]];
24623
- static usage = Command44.Usage({
24888
+ static usage = Command45.Usage({
24624
24889
  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."
24625
24890
  });
24626
- worker = Option41.String();
24627
- arms = Option41.String("--arms");
24628
- taskSet = Option41.String("--task-set");
24629
- examType = Option41.String("--exam-type");
24630
- skill = Option41.String("--skill");
24631
- reps = Option41.String("-n,--reps");
24632
- probes = Option41.String("--probes");
24633
- pool = Option41.String("--pool");
24634
- out = Option41.String("--out");
24635
- dryRun = Option41.Boolean("--dry-run", false);
24636
- keepArms = Option41.Boolean("--keep-arms", false);
24637
- allowStub = Option41.Boolean("--allow-stub", false);
24638
- deployment = Option41.String("--deployment");
24639
- output = Option41.String("--output");
24640
- observeWaitS = Option41.String("--observe-wait-s");
24891
+ worker = Option42.String();
24892
+ arms = Option42.String("--arms");
24893
+ taskSet = Option42.String("--task-set");
24894
+ examType = Option42.String("--exam-type");
24895
+ skill = Option42.String("--skill");
24896
+ reps = Option42.String("-n,--reps");
24897
+ probes = Option42.String("--probes");
24898
+ pool = Option42.String("--pool");
24899
+ out = Option42.String("--out");
24900
+ dryRun = Option42.Boolean("--dry-run", false);
24901
+ keepArms = Option42.Boolean("--keep-arms", false);
24902
+ allowStub = Option42.Boolean("--allow-stub", false);
24903
+ deployment = Option42.String("--deployment");
24904
+ output = Option42.String("--output");
24905
+ observeWaitS = Option42.String("--observe-wait-s");
24641
24906
  async executeCommand() {
24642
24907
  await Promise.resolve();
24643
24908
  const worker = typeof this.worker === "string" ? this.worker : void 0;
@@ -24714,9 +24979,9 @@ var EvalExamCommand = class extends M8tCommand {
24714
24979
  if (out !== void 0) {
24715
24980
  const sealedTaskIds = taskSetVersion ? readSealedTaskIds(taskSetVersion, out) : /* @__PURE__ */ new Set();
24716
24981
  mkdirSync6(out, { recursive: true });
24717
- writeFileSync8(join31(out, "verdict.json"), JSON.stringify(verdict, null, 2));
24982
+ writeFileSync8(join30(out, "verdict.json"), JSON.stringify(verdict, null, 2));
24718
24983
  const feed = redactForFeed(verdict, sealedTaskIds);
24719
- writeFileSync8(join31(out, "feed.json"), JSON.stringify(feed, null, 2));
24984
+ writeFileSync8(join30(out, "feed.json"), JSON.stringify(feed, null, 2));
24720
24985
  }
24721
24986
  if (mode === "json") {
24722
24987
  this.context.stdout.write(renderJson(verdict) + "\n");
@@ -24752,10 +25017,10 @@ var EvalExamCommand = class extends M8tCommand {
24752
25017
  };
24753
25018
 
24754
25019
  // src/commands/version.ts
24755
- import { Command as Command45, Option as Option42 } from "clipanion";
25020
+ import { Command as Command46, Option as Option43 } from "clipanion";
24756
25021
  var VersionCommand = class extends M8tCommand {
24757
25022
  static paths = [["version"], ["--version"], ["-v"]];
24758
- static usage = Command45.Usage({
25023
+ static usage = Command46.Usage({
24759
25024
  description: "Print the CLI version.",
24760
25025
  details: "Prints the m8t CLI version. With --verbose, also prints Node version and platform.",
24761
25026
  examples: [
@@ -24763,8 +25028,8 @@ var VersionCommand = class extends M8tCommand {
24763
25028
  ["Print as JSON", "$0 version --output json"]
24764
25029
  ]
24765
25030
  });
24766
- output = Option42.String("--output", { description: "pretty | json | auto (default)" });
24767
- verbose = Option42.Boolean("--verbose", false);
25031
+ output = Option43.String("--output", { description: "pretty | json | auto (default)" });
25032
+ verbose = Option43.Boolean("--verbose", false);
24768
25033
  executeCommand() {
24769
25034
  const mode = resolveOutputMode(
24770
25035
  this.output ?? "auto",
@@ -24795,18 +25060,18 @@ var VersionCommand = class extends M8tCommand {
24795
25060
  };
24796
25061
 
24797
25062
  // src/commands/whoami.ts
24798
- import { Command as Command46, Option as Option43 } from "clipanion";
25063
+ import { Command as Command47, Option as Option44 } from "clipanion";
24799
25064
  var WhoamiCommand = class extends M8tCommand {
24800
25065
  static paths = [["whoami"]];
24801
- static usage = Command46.Usage({
25066
+ static usage = Command47.Usage({
24802
25067
  description: "Show your identity + the gateway you'll talk to. Probes the backend."
24803
25068
  });
24804
- output = Option43.String("--output");
24805
- verbose = Option43.Boolean("--verbose", false);
24806
- subscription = Option43.String("--subscription", {
25069
+ output = Option44.String("--output");
25070
+ verbose = Option44.Boolean("--verbose", false);
25071
+ subscription = Option44.String("--subscription", {
24807
25072
  description: "Azure subscription ID to discover gateway in (defaults to active az subscription)."
24808
25073
  });
24809
- resourceGroup = Option43.String("--resource-group", {
25074
+ resourceGroup = Option44.String("--resource-group", {
24810
25075
  description: "m8t resource group to disambiguate the gateway (multi-deployment subscriptions)."
24811
25076
  });
24812
25077
  async executeCommand() {
@@ -24871,7 +25136,7 @@ var WhoamiCommand = class extends M8tCommand {
24871
25136
  };
24872
25137
 
24873
25138
  // src/commands/status.ts
24874
- import { Command as Command47, Option as Option44 } from "clipanion";
25139
+ import { Command as Command48, Option as Option45 } from "clipanion";
24875
25140
 
24876
25141
  // src/lib/azd.ts
24877
25142
  init_errors();
@@ -24936,10 +25201,10 @@ async function resolveLocalContext() {
24936
25201
  // src/commands/status.ts
24937
25202
  var StatusCommand = class extends M8tCommand {
24938
25203
  static paths = [["status"]];
24939
- static usage = Command47.Usage({
25204
+ static usage = Command48.Usage({
24940
25205
  description: "Show the local m8t context: identity, config.yaml, gateway cache, azd mode."
24941
25206
  });
24942
- output = Option44.String("--output");
25207
+ output = Option45.String("--output");
24943
25208
  async executeCommand() {
24944
25209
  const mode = resolveOutputMode(
24945
25210
  this.output,
@@ -24977,11 +25242,11 @@ var StatusCommand = class extends M8tCommand {
24977
25242
  };
24978
25243
 
24979
25244
  // src/commands/doctor.ts
24980
- import { Command as Command48, Option as Option45 } from "clipanion";
24981
- import { DefaultAzureCredential as DefaultAzureCredential22 } from "@azure/identity";
24982
- import * as fs31 from "fs";
25245
+ import { Command as Command49, Option as Option46 } from "clipanion";
25246
+ import { DefaultAzureCredential as DefaultAzureCredential23 } from "@azure/identity";
25247
+ import * as fs30 from "fs";
24983
25248
  import * as os12 from "os";
24984
- import * as path34 from "path";
25249
+ import * as path33 from "path";
24985
25250
 
24986
25251
  // src/lib/doctor-checks.ts
24987
25252
  function checkAzSignedIn(az) {
@@ -25460,40 +25725,40 @@ async function resolveAccountLocation(accountId) {
25460
25725
  }
25461
25726
  }
25462
25727
  function probeRepoRoot() {
25463
- const marker = path34.join(os12.homedir(), ".m8t", "repo-root");
25464
- if (!fs31.existsSync(marker)) {
25728
+ const marker = path33.join(os12.homedir(), ".m8t", "repo-root");
25729
+ if (!fs30.existsSync(marker)) {
25465
25730
  return { markerExists: false, path: null, isDir: false, isGitCheckout: false };
25466
25731
  }
25467
25732
  let repoPath;
25468
25733
  try {
25469
- repoPath = fs31.readFileSync(marker, "utf8").trim();
25734
+ repoPath = fs30.readFileSync(marker, "utf8").trim();
25470
25735
  } catch {
25471
25736
  return { markerExists: true, path: null, isDir: false, isGitCheckout: false };
25472
25737
  }
25473
25738
  if (!repoPath) return { markerExists: true, path: null, isDir: false, isGitCheckout: false };
25474
25739
  let isDir = false;
25475
25740
  try {
25476
- isDir = fs31.statSync(repoPath).isDirectory();
25741
+ isDir = fs30.statSync(repoPath).isDirectory();
25477
25742
  } catch {
25478
25743
  isDir = false;
25479
25744
  }
25480
- const isGitCheckout = isDir && fs31.existsSync(path34.join(repoPath, ".git"));
25745
+ const isGitCheckout = isDir && fs30.existsSync(path33.join(repoPath, ".git"));
25481
25746
  return { markerExists: true, path: repoPath, isDir, isGitCheckout };
25482
25747
  }
25483
25748
  function probeLegacyStateDir() {
25484
25749
  return {
25485
- legacyExists: fs31.existsSync(path34.join(os12.homedir(), ".m8t-stack")),
25486
- currentExists: fs31.existsSync(path34.join(os12.homedir(), ".m8t"))
25750
+ legacyExists: fs30.existsSync(path33.join(os12.homedir(), ".m8t-stack")),
25751
+ currentExists: fs30.existsSync(path33.join(os12.homedir(), ".m8t"))
25487
25752
  };
25488
25753
  }
25489
25754
  var DoctorCommand = class extends M8tCommand {
25490
25755
  static paths = [["doctor"]];
25491
- static usage = Command48.Usage({
25756
+ static usage = Command49.Usage({
25492
25757
  description: "Diagnose the local m8t setup: az login, config.yaml, gateway, Foundry data-plane."
25493
25758
  });
25494
- output = Option45.String("--output");
25495
- agent = Option45.String("--agent");
25496
- resourceGroup = Option45.String("--resource-group", {
25759
+ output = Option46.String("--output");
25760
+ agent = Option46.String("--agent");
25761
+ resourceGroup = Option46.String("--resource-group", {
25497
25762
  description: "m8t resource group to disambiguate the gateway (multi-deployment subscriptions)."
25498
25763
  });
25499
25764
  async executeCommand() {
@@ -25566,7 +25831,7 @@ var DoctorCommand = class extends M8tCommand {
25566
25831
  let kvStatus = 0;
25567
25832
  if (kv) {
25568
25833
  try {
25569
- const token = await new DefaultAzureCredential22().getToken("https://vault.azure.net/.default");
25834
+ const token = await new DefaultAzureCredential23().getToken("https://vault.azure.net/.default");
25570
25835
  const res = await fetch(`${kv.uri.replace(/\/$/, "")}/secrets?api-version=7.4&maxresults=1`, {
25571
25836
  headers: { Authorization: `Bearer ${token.token}` }
25572
25837
  });
@@ -25586,7 +25851,7 @@ var DoctorCommand = class extends M8tCommand {
25586
25851
  if (typeof this.agent === "string" && this.agent) {
25587
25852
  checking(`delivery grant for ${this.agent}`);
25588
25853
  try {
25589
- const credential2 = new DefaultAzureCredential22();
25854
+ const credential2 = new DefaultAzureCredential23();
25590
25855
  const cur = await getAgentVersion({
25591
25856
  credential: credential2,
25592
25857
  projectEndpoint: foundry.projectEndpoint,
@@ -25629,11 +25894,11 @@ var DoctorCommand = class extends M8tCommand {
25629
25894
  };
25630
25895
 
25631
25896
  // src/commands/prereqs.ts
25632
- import { Command as Command49, Option as Option46 } from "clipanion";
25897
+ import { Command as Command50, Option as Option47 } from "clipanion";
25633
25898
  init_errors();
25634
25899
 
25635
25900
  // src/lib/prereq-deps.ts
25636
- import { DefaultAzureCredential as DefaultAzureCredential23 } from "@azure/identity";
25901
+ import { DefaultAzureCredential as DefaultAzureCredential24 } from "@azure/identity";
25637
25902
 
25638
25903
  // src/lib/bootstrap-preflight.ts
25639
25904
  var ADMIN_DIRECTORY_ROLES = ["Global Administrator", "Application Administrator", "Cloud Application Administrator"];
@@ -25745,7 +26010,7 @@ function buildPrereqDeps(opts = {}) {
25745
26010
  probeRedirectUri,
25746
26011
  fixFoundryAccess,
25747
26012
  fixKeyVaultAccess,
25748
- credential: () => credentialSingleton2 ??= new DefaultAzureCredential23()
26013
+ credential: () => credentialSingleton2 ??= new DefaultAzureCredential24()
25749
26014
  };
25750
26015
  }
25751
26016
 
@@ -26335,7 +26600,7 @@ function renderVerdict(v) {
26335
26600
  }
26336
26601
  var PrereqsCommand = class extends M8tCommand {
26337
26602
  static paths = [["prereqs"]];
26338
- static usage = Command49.Usage({
26603
+ static usage = Command50.Usage({
26339
26604
  description: "Check (and optionally fix) everything m8t needs \u2014 to install, or for you to use it.",
26340
26605
  details: "Runs one of two phases. With no platform discoverable it checks INSTALL prerequisites: your Azure sign-in, subscription and directory rights, resource-provider registrations, soft-deleted Cognitive Services accounts (they hold their model quota until purged), and model quota. With a platform live it checks USAGE prerequisites for the signed-in account: the sign-in redirect URI, Foundry data-plane access, and Key Vault secrets access. Pass --fix to repair what is repairable, and --fix --for <upn> to set a teammate up (usage phase only). Read-only without --fix.",
26341
26606
  examples: [
@@ -26346,15 +26611,15 @@ var PrereqsCommand = class extends M8tCommand {
26346
26611
  ["Set a teammate up (needs role-assignment rights)", "$0 prereqs --fix --for alice@contoso.com"]
26347
26612
  ]
26348
26613
  });
26349
- fix = Option46.Boolean("--fix", false, { description: "Repair what is repairable. Without it the command only reports." });
26350
- for_ = Option46.String("--for", { description: "UPN or object id of another person. Usage phase only." });
26351
- phase = Option46.String("--phase", { description: "Force 'install' or 'usage' instead of auto-detecting." });
26352
- region = Option46.String("--region", { description: "Target region. Enables the install-phase quota check, and judges soft-deleted accounts against the region you will install into (without it, they only warn)." });
26353
- model = Option46.String("--model", { description: `Model whose quota the install needs (default ${INSTALL_REASONING_MODEL}).` });
26354
- clientId = Option46.String("--client-id", { description: "A ready app registration, in place of directory-admin rights." });
26355
- subscription = Option46.String("--subscription");
26356
- resourceGroup = Option46.String("--resource-group");
26357
- output = Option46.String("--output");
26614
+ fix = Option47.Boolean("--fix", false, { description: "Repair what is repairable. Without it the command only reports." });
26615
+ for_ = Option47.String("--for", { description: "UPN or object id of another person. Usage phase only." });
26616
+ phase = Option47.String("--phase", { description: "Force 'install' or 'usage' instead of auto-detecting." });
26617
+ region = Option47.String("--region", { description: "Target region. Enables the install-phase quota check, and judges soft-deleted accounts against the region you will install into (without it, they only warn)." });
26618
+ model = Option47.String("--model", { description: `Model whose quota the install needs (default ${INSTALL_REASONING_MODEL}).` });
26619
+ clientId = Option47.String("--client-id", { description: "A ready app registration, in place of directory-admin rights." });
26620
+ subscription = Option47.String("--subscription");
26621
+ resourceGroup = Option47.String("--resource-group");
26622
+ output = Option47.String("--output");
26358
26623
  async executeCommand() {
26359
26624
  const mode = resolveOutputMode(this.output, this.context.stdout);
26360
26625
  const json = mode === "json";
@@ -26410,18 +26675,18 @@ var PrereqsCommand = class extends M8tCommand {
26410
26675
  };
26411
26676
 
26412
26677
  // src/commands/switch.ts
26413
- import { Command as Command50, Option as Option47 } from "clipanion";
26678
+ import { Command as Command51, Option as Option48 } from "clipanion";
26414
26679
 
26415
26680
  // src/lib/profiles.ts
26416
- import * as fs32 from "fs/promises";
26417
- import * as path35 from "path";
26681
+ import * as fs31 from "fs/promises";
26682
+ import * as path34 from "path";
26418
26683
  import { parse as parseYaml12, stringify as stringifyYaml4 } from "yaml";
26419
26684
  function profilesDir() {
26420
26685
  const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
26421
- return path35.join(home, ".m8t", "profiles");
26686
+ return path34.join(home, ".m8t", "profiles");
26422
26687
  }
26423
26688
  function getProfilePath(name) {
26424
- return path35.join(profilesDir(), `${path35.basename(name)}.yaml`);
26689
+ return path34.join(profilesDir(), `${path34.basename(name)}.yaml`);
26425
26690
  }
26426
26691
  function slugifyTenant(domainOrId) {
26427
26692
  const base = domainOrId.split(".")[0].toLowerCase();
@@ -26430,7 +26695,7 @@ function slugifyTenant(domainOrId) {
26430
26695
  }
26431
26696
  async function listProfiles() {
26432
26697
  try {
26433
- const entries = await fs32.readdir(profilesDir());
26698
+ const entries = await fs31.readdir(profilesDir());
26434
26699
  return entries.filter((e) => e.endsWith(".yaml")).map((e) => e.replace(/\.yaml$/, "")).sort();
26435
26700
  } catch (e) {
26436
26701
  if (e.code === "ENOENT") return [];
@@ -26439,7 +26704,7 @@ async function listProfiles() {
26439
26704
  }
26440
26705
  async function readProfile(name) {
26441
26706
  try {
26442
- const raw = await fs32.readFile(getProfilePath(name), "utf8");
26707
+ const raw = await fs31.readFile(getProfilePath(name), "utf8");
26443
26708
  const parsed = parseYaml12(raw);
26444
26709
  if (!parsed || typeof parsed !== "object") return null;
26445
26710
  return parsed;
@@ -26450,14 +26715,14 @@ async function readProfile(name) {
26450
26715
  }
26451
26716
  async function exists(p) {
26452
26717
  try {
26453
- await fs32.stat(p);
26718
+ await fs31.stat(p);
26454
26719
  return true;
26455
26720
  } catch {
26456
26721
  return false;
26457
26722
  }
26458
26723
  }
26459
26724
  async function saveProfile(p) {
26460
- await fs32.mkdir(profilesDir(), { recursive: true });
26725
+ await fs31.mkdir(profilesDir(), { recursive: true });
26461
26726
  let name = p.name;
26462
26727
  let n = 2;
26463
26728
  while (await exists(getProfilePath(name))) {
@@ -26466,8 +26731,8 @@ async function saveProfile(p) {
26466
26731
  }
26467
26732
  const target = getProfilePath(name);
26468
26733
  const tmp = `${target}.tmp`;
26469
- await fs32.writeFile(tmp, stringifyYaml4({ ...p, name }, { indent: 2 }), "utf8");
26470
- await fs32.rename(tmp, target);
26734
+ await fs31.writeFile(tmp, stringifyYaml4({ ...p, name }, { indent: 2 }), "utf8");
26735
+ await fs31.rename(tmp, target);
26471
26736
  return name;
26472
26737
  }
26473
26738
 
@@ -26550,14 +26815,14 @@ async function profileSwitch(name, asName) {
26550
26815
  init_errors();
26551
26816
  var SwitchCommand = class extends M8tCommand {
26552
26817
  static paths = [["switch"]];
26553
- static usage = Command50.Usage({
26818
+ static usage = Command51.Usage({
26554
26819
  description: "Re-point local config at another deployment: --subscription <id|name> (discovery) or <profile>."
26555
26820
  });
26556
- profile = Option47.String({ required: false });
26557
- subscription = Option47.String("--subscription");
26558
- list = Option47.Boolean("--list", false);
26559
- as = Option47.String("--as");
26560
- output = Option47.String("--output");
26821
+ profile = Option48.String({ required: false });
26822
+ subscription = Option48.String("--subscription");
26823
+ list = Option48.Boolean("--list", false);
26824
+ as = Option48.String("--as");
26825
+ output = Option48.String("--output");
26561
26826
  async executeCommand() {
26562
26827
  const mode = resolveOutputMode(
26563
26828
  this.output,
@@ -26614,7 +26879,7 @@ var SwitchCommand = class extends M8tCommand {
26614
26879
 
26615
26880
  // src/commands/open.ts
26616
26881
  import { spawn as spawn5 } from "child_process";
26617
- import { Command as Command51, Option as Option48 } from "clipanion";
26882
+ import { Command as Command52, Option as Option49 } from "clipanion";
26618
26883
 
26619
26884
  // src/lib/open-targets.ts
26620
26885
  init_errors();
@@ -26660,14 +26925,14 @@ function openUrl(url) {
26660
26925
  }
26661
26926
  var OpenCommand = class extends M8tCommand {
26662
26927
  static paths = [["open"]];
26663
- static usage = Command51.Usage({
26928
+ static usage = Command52.Usage({
26664
26929
  description: "Open the deployed webapp (default), the Foundry portal, or the resource group.",
26665
26930
  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)."
26666
26931
  });
26667
- target = Option48.String({ required: false });
26668
- print = Option48.Boolean("--print", false);
26669
- output = Option48.String("--output");
26670
- resourceGroup = Option48.String("--resource-group", {
26932
+ target = Option49.String({ required: false });
26933
+ print = Option49.Boolean("--print", false);
26934
+ output = Option49.String("--output");
26935
+ resourceGroup = Option49.String("--resource-group", {
26671
26936
  description: "m8t resource group to disambiguate the gateway (multi-deployment subscriptions)."
26672
26937
  });
26673
26938
  async executeCommand() {
@@ -26711,7 +26976,7 @@ var OpenCommand = class extends M8tCommand {
26711
26976
  };
26712
26977
 
26713
26978
  // src/commands/dream/run.ts
26714
- import { Command as Command52, Option as Option49 } from "clipanion";
26979
+ import { Command as Command53, Option as Option50 } from "clipanion";
26715
26980
  import { AzureCliCredential } from "@azure/identity";
26716
26981
  import { TableClient as TableClient7 } from "@azure/data-tables";
26717
26982
  import { AIProjectClient as AIProjectClient3 } from "@azure/ai-projects";
@@ -27756,7 +28021,7 @@ function buildAdvancePlan(worker, cursor, physicalPks, consumedRowsByPk, failedT
27756
28021
  // ../../packages/brain/engine/dist/esm/dream/writer.js
27757
28022
  var API2 = "https://api.github.com";
27758
28023
  var WRITER_ALLOWED_PREFIX = /^(memory|inbox|quarantine|artifacts)\//;
27759
- var isAllowedWritePath = (path48, allowedPrefix) => allowedPrefix.test(path48) && !path48.split("/").includes("..");
28024
+ var isAllowedWritePath = (path47, allowedPrefix) => allowedPrefix.test(path47) && !path47.split("/").includes("..");
27760
28025
  var unquote = (s) => s.trim().replace(/^["']|["']$/g, "");
27761
28026
  function parseFrontmatter(content) {
27762
28027
  const m = /^---\r?\n([\s\S]*?)\r?\n---/.exec(content);
@@ -27799,8 +28064,8 @@ function makeGitDataWriter(args) {
27799
28064
  if (args.allowedPathPrefix && !args.allowedPathPrefix.source.startsWith("^")) {
27800
28065
  throw new Error(`makeGitDataWriter: allowedPathPrefix must be anchored with "^" (got /${args.allowedPathPrefix.source}/) \u2014 an unanchored regex would widen the B1 write-path allowlist`);
27801
28066
  }
27802
- async function gh(token, method, path48, body) {
27803
- const res = await doFetch(`${API2}/repos/${repoPath}${path48}`, {
28067
+ async function gh(token, method, path47, body) {
28068
+ const res = await doFetch(`${API2}/repos/${repoPath}${path47}`, {
27804
28069
  method,
27805
28070
  headers: {
27806
28071
  Authorization: `Bearer ${token}`,
@@ -27813,8 +28078,8 @@ function makeGitDataWriter(args) {
27813
28078
  const text = await res.text();
27814
28079
  return { status: res.status, ok: res.ok, json: text ? JSON.parse(text) : {} };
27815
28080
  }
27816
- async function readFileWith(token, path48) {
27817
- const encodedPath = path48.split("/").map(encodeURIComponent).join("/");
28081
+ async function readFileWith(token, path47) {
28082
+ const encodedPath = path47.split("/").map(encodeURIComponent).join("/");
27818
28083
  const r = await gh(token, "GET", `/contents/${encodedPath}?ref=${args.branch}`);
27819
28084
  if (r.status === 404)
27820
28085
  return null;
@@ -27830,9 +28095,9 @@ function makeGitDataWriter(args) {
27830
28095
  throw new Error(`fetchTip: HTTP ${String(r.status)}`);
27831
28096
  return r.json.object.sha;
27832
28097
  },
27833
- async readFile(path48) {
28098
+ async readFile(path47) {
27834
28099
  const token = await args.mintToken();
27835
- return readFileWith(token, path48);
28100
+ return readFileWith(token, path47);
27836
28101
  },
27837
28102
  async listMemory() {
27838
28103
  const token = await args.mintToken();
@@ -27841,9 +28106,9 @@ function makeGitDataWriter(args) {
27841
28106
  return [];
27842
28107
  const paths = r.json.tree.filter((e) => e.type === "blob" && e.path.startsWith("memory/") && e.path.endsWith(".md")).map((e) => e.path);
27843
28108
  const out = [];
27844
- for (const path48 of paths) {
27845
- const content = await readFileWith(token, path48);
27846
- out.push({ path: path48, frontmatter: content ? parseFrontmatter(content) : {} });
28109
+ for (const path47 of paths) {
28110
+ const content = await readFileWith(token, path47);
28111
+ out.push({ path: path47, frontmatter: content ? parseFrontmatter(content) : {} });
27847
28112
  }
27848
28113
  return out;
27849
28114
  },
@@ -28282,7 +28547,7 @@ async function loadMemoryContext(brain) {
28282
28547
  return {
28283
28548
  files,
28284
28549
  indexEntries,
28285
- originOf: (path48) => originByPath.get(path48) ?? "worker"
28550
+ originOf: (path47) => originByPath.get(path47) ?? "worker"
28286
28551
  };
28287
28552
  }
28288
28553
 
@@ -28303,14 +28568,14 @@ function checkEvidenceMembership(delta, harvested) {
28303
28568
  }
28304
28569
  var BatchAbort = class extends Error {
28305
28570
  path;
28306
- constructor(path48, message) {
28571
+ constructor(path47, message) {
28307
28572
  super(message);
28308
- this.path = path48;
28573
+ this.path = path47;
28309
28574
  this.name = "BatchAbort";
28310
28575
  }
28311
28576
  };
28312
- var isIndexFile = (path48) => /(^|\/)[^/]*_index\.md$/.test(path48);
28313
- var isMemoryIndex = (path48) => path48 === "memory/MEMORY.md";
28577
+ var isIndexFile = (path47) => /(^|\/)[^/]*_index\.md$/.test(path47);
28578
+ var isMemoryIndex = (path47) => path47 === "memory/MEMORY.md";
28314
28579
  function targetPath(delta) {
28315
28580
  switch (delta.verb) {
28316
28581
  case "new":
@@ -28327,29 +28592,29 @@ function targetPath(delta) {
28327
28592
  }
28328
28593
  async function checkOriginTier(delta, lookup) {
28329
28594
  const evidence = evidenceOf(delta) ?? [];
28330
- const path48 = targetPath(delta);
28331
- if (path48 === null)
28595
+ const path47 = targetPath(delta);
28596
+ if (path47 === null)
28332
28597
  return { ok: true };
28333
- if (isIndexFile(path48) && !isMemoryIndex(path48)) {
28334
- return { ok: false, flagged: { kind: "flagged", path: path48, tension: `refused: ${path48} is an index file (only memory/MEMORY.md is editable)`, evidence } };
28598
+ if (isIndexFile(path47) && !isMemoryIndex(path47)) {
28599
+ return { ok: false, flagged: { kind: "flagged", path: path47, tension: `refused: ${path47} is an index file (only memory/MEMORY.md is editable)`, evidence } };
28335
28600
  }
28336
- const target = await lookup(path48);
28337
- const isStructural = path48.startsWith("references/");
28601
+ const target = await lookup(path47);
28602
+ const isStructural = path47.startsWith("references/");
28338
28603
  const origin = target?.frontmatter.origin ?? (isStructural ? "operator" : "worker");
28339
28604
  const editable = origin === "worker" || origin === "dream";
28340
28605
  if (editable)
28341
28606
  return { ok: true };
28342
28607
  const removesOperatorTarget = delta.verb === "retract" || delta.verb === "supersede" && delta.oldPath !== delta.newPath;
28343
28608
  if (removesOperatorTarget) {
28344
- throw new BatchAbort(path48, `supersede/retract OLD target ${path48} is origin: ${origin} \u2014 aborting batch (never half-apply)`);
28609
+ throw new BatchAbort(path47, `supersede/retract OLD target ${path47} is origin: ${origin} \u2014 aborting batch (never half-apply)`);
28345
28610
  }
28346
- return { ok: false, flagged: { kind: "flagged", path: path48, tension: `operator-origin (${origin}); flag-only`, evidence } };
28611
+ return { ok: false, flagged: { kind: "flagged", path: path47, tension: `operator-origin (${origin}); flag-only`, evidence } };
28347
28612
  }
28348
28613
  var ALLOWED_MEMORY = /^memory\/.+\.md$/;
28349
28614
  var ALLOWED_INBOX = /^inbox\//;
28350
28615
  var ALLOWED_QUARANTINE = /^quarantine\//;
28351
28616
  var ALLOWED_FLAG = /^memory\//;
28352
- var hasTraversal = (path48) => path48.split("/").includes("..");
28617
+ var hasTraversal = (path47) => path47.split("/").includes("..");
28353
28618
  function checkPathAllowed(delta) {
28354
28619
  const evidence = evidenceOf(delta) ?? [];
28355
28620
  const reject = (detail) => ({ ok: false, rejected: { kind: "rejected", detail, evidence } });
@@ -28456,7 +28721,7 @@ ${inject}
28456
28721
  ---
28457
28722
  ` + body.slice(m[0].length);
28458
28723
  }
28459
- var indexLine = (path48, title, date, tags) => `- \`${path48}\` \u2014 **${title}**: ${title}. (${date} \xB7 ${tags.join(", ")})`;
28724
+ var indexLine = (path47, title, date, tags) => `- \`${path47}\` \u2014 **${title}**: ${title}. (${date} \xB7 ${tags.join(", ")})`;
28460
28725
  function splitIndex(index) {
28461
28726
  const all = index.split("\n");
28462
28727
  const firstLineIdx = all.findIndex((l) => l.startsWith("- `memory/"));
@@ -28629,16 +28894,16 @@ function defaultDreamSeams(opts = {}) {
28629
28894
  const mem = await memory(deps.brain);
28630
28895
  const harvested = harvestedIds(input);
28631
28896
  const ctx = { readFile: (p) => deps.brain.readFile(p), at: deps.clock() };
28632
- const lookup = (path48) => Promise.resolve(mem.files.find((f) => f.path === path48) ?? null);
28897
+ const lookup = (path47) => Promise.resolve(mem.files.find((f) => f.path === path47) ?? null);
28633
28898
  const digest = [...pendingRejected];
28634
28899
  let changes = [];
28635
28900
  let indexEdit;
28636
28901
  try {
28637
28902
  for (const raw of deltas) {
28638
28903
  const delta = forcePolicyQuarantine(raw);
28639
- const path48 = checkPathAllowed(delta);
28640
- if (!path48.ok) {
28641
- digest.push(path48.rejected);
28904
+ const path47 = checkPathAllowed(delta);
28905
+ if (!path47.ok) {
28906
+ digest.push(path47.rejected);
28642
28907
  continue;
28643
28908
  }
28644
28909
  const ev = checkEvidenceMembership(delta, harvested);
@@ -29005,28 +29270,28 @@ function redactTranscripts(input) {
29005
29270
  }
29006
29271
  var DreamRunCommand = class extends M8tCommand {
29007
29272
  static paths = [["dream", "run"]];
29008
- static usage = Command52.Usage({
29273
+ static usage = Command53.Usage({
29009
29274
  description: "Dry-run the brain consumption pipeline for one worker (no model call, no writes). Pass --live to actually run it.",
29010
29275
  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.\n\nThe bare command is READ-ONLY. --live takes the other branch: a real model call and a commit to the worker's brain repo through a minted GitHub App token."
29011
29276
  });
29012
- worker = Option49.String("--worker", { description: "Worker (canonical name) to harvest. Required." });
29277
+ worker = Option50.String("--worker", { description: "Worker (canonical name) to harvest. Required." });
29013
29278
  // Opting IN to the side effects, rather than opting out of them. This command's
29014
29279
  // own help has always described a dry run, but the bare invocation used to take
29015
29280
  // the live branch — a real model call and a commit to the brain repo — so anyone
29016
29281
  // acting on `--help` got the opposite of what they read.
29017
- live = Option49.Boolean("--live", false, { description: "Actually run it: model call + commit to the brain repo." });
29018
- dryRun = Option49.Boolean("--dry-run", false, { description: "Read-only harvest. This is the default; the flag is accepted for compatibility." });
29019
- since = Option49.String("--since", { description: "ISO-8601 start override (rejected if malformed or future)." });
29020
- reset = Option49.Boolean("--reset", false, { description: "Ignore the stored cursor; read from the beginning." });
29021
- showTranscripts = Option49.Boolean("--show-transcripts", false, {
29282
+ live = Option50.Boolean("--live", false, { description: "Actually run it: model call + commit to the brain repo." });
29283
+ dryRun = Option50.Boolean("--dry-run", false, { description: "Read-only harvest. This is the default; the flag is accepted for compatibility." });
29284
+ since = Option50.String("--since", { description: "ISO-8601 start override (rejected if malformed or future)." });
29285
+ reset = Option50.Boolean("--reset", false, { description: "Ignore the stored cursor; read from the beginning." });
29286
+ showTranscripts = Option50.Boolean("--show-transcripts", false, {
29022
29287
  description: "Print transcript bodies (default: metadata only)."
29023
29288
  });
29024
- subscription = Option49.String("--subscription");
29025
- endpoint = Option49.String("--endpoint");
29026
- storageAccount = Option49.String("--storage-account", {
29289
+ subscription = Option50.String("--subscription");
29290
+ endpoint = Option50.String("--endpoint");
29291
+ storageAccount = Option50.String("--storage-account", {
29027
29292
  description: "Ledger storage account name (skips tag-based discovery)"
29028
29293
  });
29029
- output = Option49.String("--output");
29294
+ output = Option50.String("--output");
29030
29295
  // Resolution seam — overridden by tests; built lazily at runtime otherwise.
29031
29296
  deps;
29032
29297
  async executeCommand() {
@@ -29377,7 +29642,7 @@ function defaultDeps(overrides) {
29377
29642
 
29378
29643
  // src/commands/conversations/sweep.ts
29379
29644
  import { createHash as createHash4 } from "crypto";
29380
- import { Command as Command53, Option as Option50 } from "clipanion";
29645
+ import { Command as Command54, Option as Option51 } from "clipanion";
29381
29646
  import { AzureCliCredential as AzureCliCredential2 } from "@azure/identity";
29382
29647
  import { TableClient as TableClient8 } from "@azure/data-tables";
29383
29648
  import { AIProjectClient as AIProjectClient4 } from "@azure/ai-projects";
@@ -29503,7 +29768,7 @@ function defaultDeps2() {
29503
29768
  }
29504
29769
  var ConversationsSweepCommand = class extends M8tCommand {
29505
29770
  static paths = [["conversations", "sweep"]];
29506
- static usage = Command53.Usage({
29771
+ static usage = Command54.Usage({
29507
29772
  category: "Conversations",
29508
29773
  description: "Delete expired public-visitor conversations (dry run by default)",
29509
29774
  details: `
@@ -29519,22 +29784,22 @@ var ConversationsSweepCommand = class extends M8tCommand {
29519
29784
  ["Delete, capped at 50", "m8t conversations sweep --delete --max 50"]
29520
29785
  ]
29521
29786
  });
29522
- doDelete = Option50.Boolean("--delete", false, {
29787
+ doDelete = Option51.Boolean("--delete", false, {
29523
29788
  description: "Perform deletions (without this flag the command only reports)"
29524
29789
  });
29525
- principal = Option50.String("--principal", {
29790
+ principal = Option51.String("--principal", {
29526
29791
  description: "Service-principal oid whose end-user keys are known-ephemeral (required with --delete; a dry run without it reports candidates grouped by principal)"
29527
29792
  });
29528
- max = Option50.String("--max", "200", { description: "Maximum deletions per run" });
29529
- graceDays = Option50.String("--grace-days", "14", {
29793
+ max = Option51.String("--max", "200", { description: "Maximum deletions per run" });
29794
+ graceDays = Option51.String("--grace-days", "14", {
29530
29795
  description: "Days past the 30-day key life before a conversation is eligible"
29531
29796
  });
29532
- lookbackDays = Option50.String("--lookback-days", "180", {
29797
+ lookbackDays = Option51.String("--lookback-days", "180", {
29533
29798
  description: "How far back to scan ledger activity for candidates"
29534
29799
  });
29535
- subscription = Option50.String("--subscription", { description: "Azure subscription id override" });
29536
- endpoint = Option50.String("--endpoint", { description: "Foundry project endpoint override" });
29537
- storageAccount = Option50.String("--storage-account", {
29800
+ subscription = Option51.String("--subscription", { description: "Azure subscription id override" });
29801
+ endpoint = Option51.String("--endpoint", { description: "Foundry project endpoint override" });
29802
+ storageAccount = Option51.String("--storage-account", {
29538
29803
  description: "Ledger storage account name (skips tag-based discovery)"
29539
29804
  });
29540
29805
  deps = defaultDeps2();
@@ -29662,7 +29927,7 @@ var ConversationsSweepCommand = class extends M8tCommand {
29662
29927
  };
29663
29928
 
29664
29929
  // src/commands/foundry/create.ts
29665
- import { Command as Command54, Option as Option51 } from "clipanion";
29930
+ import { Command as Command55, Option as Option52 } from "clipanion";
29666
29931
 
29667
29932
  // src/lib/foundry-create.ts
29668
29933
  init_errors();
@@ -29900,7 +30165,7 @@ async function createFoundryProject(args) {
29900
30165
  init_errors();
29901
30166
  var FoundryCreateCommand = class extends M8tCommand {
29902
30167
  static paths = [["foundry", "create"]];
29903
- static usage = Command54.Usage({
30168
+ static usage = Command55.Usage({
29904
30169
  description: "Create an AI Foundry (AIServices) account + project + model deployment from scratch.",
29905
30170
  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).",
29906
30171
  examples: [
@@ -29909,16 +30174,16 @@ var FoundryCreateCommand = class extends M8tCommand {
29909
30174
  ["Higher capacity for a reasoning model", "$0 foundry create --resource-group rg-m8t-stack --location eastus2 --model gpt-5-mini --capacity 250"]
29910
30175
  ]
29911
30176
  });
29912
- resourceGroup = Option51.String("--resource-group");
29913
- location = Option51.String("--location");
29914
- account = Option51.String("--account");
29915
- project = Option51.String("--project", "m8t");
29916
- model = Option51.String("--model", "gpt-4.1-mini");
29917
- modelVersion = Option51.String("--model-version", "2025-04-14");
29918
- capacity = Option51.String("--capacity", "50");
29919
- subscription = Option51.String("--subscription");
29920
- skipQuotaCheck = Option51.Boolean("--skip-quota-check", false);
29921
- output = Option51.String("--output");
30177
+ resourceGroup = Option52.String("--resource-group");
30178
+ location = Option52.String("--location");
30179
+ account = Option52.String("--account");
30180
+ project = Option52.String("--project", "m8t");
30181
+ model = Option52.String("--model", "gpt-4.1-mini");
30182
+ modelVersion = Option52.String("--model-version", "2025-04-14");
30183
+ capacity = Option52.String("--capacity", "50");
30184
+ subscription = Option52.String("--subscription");
30185
+ skipQuotaCheck = Option52.Boolean("--skip-quota-check", false);
30186
+ output = Option52.String("--output");
29922
30187
  async executeCommand() {
29923
30188
  const mode = resolveOutputMode(
29924
30189
  this.output,
@@ -29990,22 +30255,22 @@ var FoundryCreateCommand = class extends M8tCommand {
29990
30255
  };
29991
30256
 
29992
30257
  // src/commands/foundry/await-ready.ts
29993
- import { Command as Command55, Option as Option52 } from "clipanion";
30258
+ import { Command as Command56, Option as Option53 } from "clipanion";
29994
30259
  import { AzureCliCredential as AzureCliCredential3 } from "@azure/identity";
29995
30260
  init_errors();
29996
30261
  var FoundryAwaitReadyCommand = class extends M8tCommand {
29997
30262
  static paths = [["foundry", "await-ready"]];
29998
- static usage = Command55.Usage({
30263
+ static usage = Command56.Usage({
29999
30264
  description: "Wait until a freshly-created Foundry project's data plane reliably serves it.",
30000
30265
  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.",
30001
30266
  examples: [["Wait for a project to be ready", "$0 foundry await-ready --endpoint https://acc.services.ai.azure.com/api/projects/m8t"]]
30002
30267
  });
30003
- endpoint = Option52.String("--endpoint");
30004
- consecutive = Option52.String("--consecutive", "3");
30005
- attempts = Option52.String("--attempts", "60");
30006
- interval = Option52.String("--interval", "5");
30007
- subscription = Option52.String("--subscription");
30008
- output = Option52.String("--output");
30268
+ endpoint = Option53.String("--endpoint");
30269
+ consecutive = Option53.String("--consecutive", "3");
30270
+ attempts = Option53.String("--attempts", "60");
30271
+ interval = Option53.String("--interval", "5");
30272
+ subscription = Option53.String("--subscription");
30273
+ output = Option53.String("--output");
30009
30274
  async executeCommand() {
30010
30275
  const mode = resolveOutputMode(this.output, this.context.stdout);
30011
30276
  const endpoint = typeof this.endpoint === "string" ? this.endpoint : void 0;
@@ -30039,7 +30304,7 @@ var FoundryAwaitReadyCommand = class extends M8tCommand {
30039
30304
  };
30040
30305
 
30041
30306
  // src/commands/bootstrap/preflight.ts
30042
- import { Command as Command56, Option as Option53 } from "clipanion";
30307
+ import { Command as Command57, Option as Option54 } from "clipanion";
30043
30308
 
30044
30309
  // ../../packages/telemetry-contract/artifact/tier-map.ts
30045
30310
  var EVENT_TIERS = {
@@ -30065,9 +30330,9 @@ var DISCLOSURE_TIER1 = "Operational data. To support your installation, m8t rece
30065
30330
 
30066
30331
  // ../../packages/telemetry-contract/src/endpoints.ts
30067
30332
  var INGEST_BASE_URL = (process.env.M8T_INGEST_BASE_URL ?? "").trim() || "https://m8t-admin.wonderfuldesert-721e332f.eastus2.azurecontainerapps.io";
30068
- function ingestUrl(path48) {
30333
+ function ingestUrl(path47) {
30069
30334
  const base = INGEST_BASE_URL.replace(/\/+$/, "");
30070
- return `${base}${path48.startsWith("/") ? path48 : `/${path48}`}`;
30335
+ return `${base}${path47.startsWith("/") ? path47 : `/${path47}`}`;
30071
30336
  }
30072
30337
 
30073
30338
  // src/commands/bootstrap/preflight.ts
@@ -30091,7 +30356,7 @@ function preflightRenderable(results) {
30091
30356
  }
30092
30357
  var BootstrapPreflightCommand = class extends M8tCommand {
30093
30358
  static paths = [["bootstrap", "preflight"]];
30094
- static usage = Command56.Usage({
30359
+ static usage = Command57.Usage({
30095
30360
  description: "Loudly verify you can install m8t (Owner/UAA + directory admin) and hard-stop if not.",
30096
30361
  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), every Azure resource provider the install uses (registering any that are missing), soft-deleted Cognitive Services accounts (they keep their model quota until purged, so quota can read free and the model deployment still fail), and \u2014 with --location \u2014 model quota in the target region. Exits non-zero with the exact failing check + remedy. `m8t prereqs` runs the same substrate checks on their own.",
30097
30362
  examples: [
@@ -30100,9 +30365,9 @@ var BootstrapPreflightCommand = class extends M8tCommand {
30100
30365
  ["BYO app registration (directory guests)", "$0 bootstrap preflight --client-id <appId>"]
30101
30366
  ]
30102
30367
  });
30103
- clientId = Option53.String("--client-id");
30104
- subscription = Option53.String("--subscription");
30105
- location = Option53.String("--location", {
30368
+ clientId = Option54.String("--client-id");
30369
+ subscription = Option54.String("--subscription");
30370
+ location = Option54.String("--location", {
30106
30371
  description: "Target region. Enables the model-quota check \u2014 without it, quota is not verified."
30107
30372
  });
30108
30373
  async executeCommand() {
@@ -30199,10 +30464,10 @@ ${colors.error(" " + why)}
30199
30464
  }
30200
30465
 
30201
30466
  // src/commands/bootstrap/launch.ts
30202
- import * as fs35 from "fs";
30467
+ import * as fs34 from "fs";
30203
30468
  import * as os15 from "os";
30204
- import * as path38 from "path";
30205
- import { Command as Command57, Option as Option54 } from "clipanion";
30469
+ import * as path37 from "path";
30470
+ import { Command as Command58, Option as Option55 } from "clipanion";
30206
30471
  init_errors();
30207
30472
 
30208
30473
  // src/lib/bootstrap-mi.ts
@@ -30358,9 +30623,9 @@ async function kickInstaller(s) {
30358
30623
 
30359
30624
  // src/lib/bootstrap-status.ts
30360
30625
  import { createHash as createHash6, randomUUID as randomUUID2 } from "crypto";
30361
- import * as fs33 from "fs/promises";
30626
+ import * as fs32 from "fs/promises";
30362
30627
  import * as os13 from "os";
30363
- import * as path36 from "path";
30628
+ import * as path35 from "path";
30364
30629
  init_errors();
30365
30630
  var STATUS_CONTAINER = "status";
30366
30631
  var STATUS_BLOB = "status.json";
@@ -30399,7 +30664,7 @@ async function readStatusBlob(opts) {
30399
30664
  cause: e
30400
30665
  });
30401
30666
  }
30402
- const tmpFile = path36.join(os13.tmpdir(), `m8t-status-${randomUUID2()}.json`);
30667
+ const tmpFile = path35.join(os13.tmpdir(), `m8t-status-${randomUUID2()}.json`);
30403
30668
  try {
30404
30669
  await runAz([
30405
30670
  "storage",
@@ -30418,7 +30683,7 @@ async function readStatusBlob(opts) {
30418
30683
  "--no-progress",
30419
30684
  "--only-show-errors"
30420
30685
  ]);
30421
- const raw = await fs33.readFile(tmpFile, "utf8");
30686
+ const raw = await fs32.readFile(tmpFile, "utf8");
30422
30687
  return JSON.parse(raw.trim());
30423
30688
  } catch (e) {
30424
30689
  throw new LocalCliError({
@@ -30428,23 +30693,23 @@ async function readStatusBlob(opts) {
30428
30693
  cause: e
30429
30694
  });
30430
30695
  } finally {
30431
- await fs33.rm(tmpFile, { force: true });
30696
+ await fs32.rm(tmpFile, { force: true });
30432
30697
  }
30433
30698
  }
30434
30699
 
30435
30700
  // src/lib/bootstrap-state.ts
30436
- import * as fs34 from "fs/promises";
30701
+ import * as fs33 from "fs/promises";
30437
30702
  import * as os14 from "os";
30438
- import * as path37 from "path";
30703
+ import * as path36 from "path";
30439
30704
  function stateDir(home) {
30440
- return path37.join(home, ".m8t");
30705
+ return path36.join(home, ".m8t");
30441
30706
  }
30442
30707
  function statePath(home) {
30443
- return path37.join(stateDir(home), "bootstrap.json");
30708
+ return path36.join(stateDir(home), "bootstrap.json");
30444
30709
  }
30445
30710
  async function readBootstrapState(home = os14.homedir()) {
30446
30711
  try {
30447
- const raw = await fs34.readFile(statePath(home), "utf8");
30712
+ const raw = await fs33.readFile(statePath(home), "utf8");
30448
30713
  return JSON.parse(raw);
30449
30714
  } catch (e) {
30450
30715
  if (e.code === "ENOENT") return null;
@@ -30452,10 +30717,10 @@ async function readBootstrapState(home = os14.homedir()) {
30452
30717
  }
30453
30718
  }
30454
30719
  async function writeBootstrapState(state, home = os14.homedir()) {
30455
- await fs34.mkdir(stateDir(home), { recursive: true });
30720
+ await fs33.mkdir(stateDir(home), { recursive: true });
30456
30721
  const tmp = `${statePath(home)}.tmp`;
30457
- await fs34.writeFile(tmp, JSON.stringify(state, null, 2), "utf8");
30458
- await fs34.rename(tmp, statePath(home));
30722
+ await fs33.writeFile(tmp, JSON.stringify(state, null, 2), "utf8");
30723
+ await fs33.rename(tmp, statePath(home));
30459
30724
  }
30460
30725
 
30461
30726
  // src/lib/bootstrap-occupancy.ts
@@ -30572,7 +30837,7 @@ var ACI_NAME = "m8t-installer";
30572
30837
  var MI_NAME = "m8t-installer-mi";
30573
30838
  var BootstrapLaunchCommand = class extends M8tCommand {
30574
30839
  static paths = [["bootstrap", "launch"]];
30575
- static usage = Command57.Usage({
30840
+ static usage = Command58.Usage({
30576
30841
  description: "Create + authorize the installer managed identity, then kick the cloud installer.",
30577
30842
  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` and `reap`, and threads your Azure object id so the installer can grant you the platform's data-plane roles itself.",
30578
30843
  examples: [
@@ -30583,26 +30848,26 @@ var BootstrapLaunchCommand = class extends M8tCommand {
30583
30848
  ["Share a support contact", "$0 bootstrap launch --location eastus2 --contact-email you@example.com --company 'Acme'"]
30584
30849
  ]
30585
30850
  });
30586
- location = Option54.String("--location");
30587
- resourceGroup = Option54.String("--resource-group");
30588
- clientId = Option54.String("--client-id");
30589
- subscription = Option54.String("--subscription");
30590
- installerTag = Option54.String("--installer-tag");
30851
+ location = Option55.String("--location");
30852
+ resourceGroup = Option55.String("--resource-group");
30853
+ clientId = Option55.String("--client-id");
30854
+ subscription = Option55.String("--subscription");
30855
+ installerTag = Option55.String("--installer-tag");
30591
30856
  // Full image ref override (registry + repo + tag) — an escape hatch when the
30592
30857
  // default org/tag is wrong for the current CLI (e.g. a stale published build).
30593
30858
  // Wins over --installer-tag / the pinned default.
30594
- installerImage = Option54.String("--installer-image");
30595
- gatewayImageRef = Option54.String("--gateway-image-ref");
30596
- githubAppCreds = Option54.String("--github-app-creds");
30597
- contactEmail = Option54.String("--contact-email", { description: "Share a contact email with m8t support. Not sent unless you pass it." });
30598
- company = Option54.String("--company", { description: "Share your company name with m8t support. Not sent unless you pass it." });
30859
+ installerImage = Option55.String("--installer-image");
30860
+ gatewayImageRef = Option55.String("--gateway-image-ref");
30861
+ githubAppCreds = Option55.String("--github-app-creds");
30862
+ contactEmail = Option55.String("--contact-email", { description: "Share a contact email with m8t support. Not sent unless you pass it." });
30863
+ company = Option55.String("--company", { description: "Share your company name with m8t support. Not sent unless you pass it." });
30599
30864
  // Value-carrying on purpose: a bare --force would be cargo-culted into
30600
30865
  // runbooks and harness prompts and erode the protection, whereas a faithful
30601
30866
  // paste can never accidentally carry the victim group's name. It AUTHORIZES
30602
30867
  // the target; --resource-group is what CHOOSES it.
30603
- reinstallInto = Option54.String("--reinstall-into", { description: "Consent to installing into --resource-group even though it already holds resources. Must match the target group's name." });
30604
- org = Option54.String("--org", { description: "Assert the GitHub App on disk is installed on this org; refuses on a mismatch." });
30605
- noBrains = Option54.Boolean("--no-brains", false, { description: "Install without brain-backed workers. For test and CI rigs; the supported install creates brains." });
30868
+ reinstallInto = Option55.String("--reinstall-into", { description: "Consent to installing into --resource-group even though it already holds resources. Must match the target group's name." });
30869
+ org = Option55.String("--org", { description: "Assert the GitHub App on disk is installed on this org; refuses on a mismatch." });
30870
+ noBrains = Option55.Boolean("--no-brains", false, { description: "Install without brain-backed workers. For test and CI rigs; the supported install creates brains." });
30606
30871
  async executeCommand() {
30607
30872
  const location = typeof this.location === "string" ? this.location : void 0;
30608
30873
  if (!location) {
@@ -30641,13 +30906,13 @@ var BootstrapLaunchCommand = class extends M8tCommand {
30641
30906
  `);
30642
30907
  return 0;
30643
30908
  }
30644
- const credsPath = typeof this.githubAppCreds === "string" ? this.githubAppCreds : path38.join(os15.homedir(), ".m8t", "github-app.json");
30909
+ const credsPath = typeof this.githubAppCreds === "string" ? this.githubAppCreds : path37.join(os15.homedir(), ".m8t", "github-app.json");
30645
30910
  const skipBrains = this.noBrains === true;
30646
30911
  const requestedOrg = typeof this.org === "string" ? this.org : void 0;
30647
30912
  let githubApp;
30648
30913
  if (skipBrains) {
30649
30914
  out("installing without brain-backed workers; no GitHub App credentials will be used");
30650
- } else if (!fs35.existsSync(credsPath)) {
30915
+ } else if (!fs34.existsSync(credsPath)) {
30651
30916
  this.context.stderr.write(buildMissingCredsRefusal(credsPath));
30652
30917
  throw new LocalCliError({
30653
30918
  code: "GITHUB_APP_CREDS_MISSING",
@@ -30657,7 +30922,7 @@ var BootstrapLaunchCommand = class extends M8tCommand {
30657
30922
  } else {
30658
30923
  let parsed;
30659
30924
  try {
30660
- parsed = JSON.parse(fs35.readFileSync(credsPath, "utf8"));
30925
+ parsed = JSON.parse(fs34.readFileSync(credsPath, "utf8"));
30661
30926
  } catch {
30662
30927
  throw new LocalCliError({
30663
30928
  code: "GITHUB_APP_CREDS_INVALID",
@@ -30675,7 +30940,7 @@ var BootstrapLaunchCommand = class extends M8tCommand {
30675
30940
  }
30676
30941
  let pem;
30677
30942
  try {
30678
- pem = fs35.readFileSync(parsed.pemPath, "utf8");
30943
+ pem = fs34.readFileSync(parsed.pemPath, "utf8");
30679
30944
  } catch {
30680
30945
  throw new LocalCliError({
30681
30946
  code: "GITHUB_APP_PEM_MISSING",
@@ -30763,7 +31028,7 @@ var BootstrapLaunchCommand = class extends M8tCommand {
30763
31028
  };
30764
31029
 
30765
31030
  // src/commands/bootstrap/status.ts
30766
- import { Command as Command59, Option as Option56 } from "clipanion";
31031
+ import { Command as Command60, Option as Option57 } from "clipanion";
30767
31032
  init_errors();
30768
31033
 
30769
31034
  // src/lib/bootstrap-aci-state.ts
@@ -30789,15 +31054,15 @@ async function getAciState(opts) {
30789
31054
  }
30790
31055
 
30791
31056
  // src/lib/bootstrap-finalize.ts
30792
- import * as fs39 from "fs/promises";
31057
+ import * as fs38 from "fs/promises";
30793
31058
  import * as os19 from "os";
30794
- import * as path44 from "path";
31059
+ import * as path43 from "path";
30795
31060
 
30796
31061
  // src/lib/company-profile-seed.ts
30797
31062
  import { spawn as spawn6 } from "child_process";
30798
- import { closeSync, openSync, readFileSync as readFileSync25 } from "fs";
31063
+ import { closeSync, openSync, readFileSync as readFileSync24 } from "fs";
30799
31064
  import * as os16 from "os";
30800
- import * as path39 from "path";
31065
+ import * as path38 from "path";
30801
31066
  init_errors();
30802
31067
 
30803
31068
  // src/lib/onboarding-profile.ts
@@ -31522,9 +31787,9 @@ function composeFounderIdentityNote(id) {
31522
31787
 
31523
31788
  // src/lib/company-profile-seed.ts
31524
31789
  function readGithubAppCreds(credsPath) {
31525
- const p = credsPath ?? path39.join(os16.homedir(), ".m8t", "github-app.json");
31790
+ const p = credsPath ?? path38.join(os16.homedir(), ".m8t", "github-app.json");
31526
31791
  try {
31527
- return JSON.parse(readFileSync25(p, "utf8"));
31792
+ return JSON.parse(readFileSync24(p, "utf8"));
31528
31793
  } catch {
31529
31794
  return null;
31530
31795
  }
@@ -31593,7 +31858,7 @@ function upsertMemoryIndexOnce(existing, line2, targetPath2) {
31593
31858
  async function applyProfileToBrain(args) {
31594
31859
  const token = await mintInstallationTokenFromPem({
31595
31860
  appId: args.appCreds.appId,
31596
- privateKeyPem: readFileSync25(args.appCreds.pemPath, "utf8"),
31861
+ privateKeyPem: readFileSync24(args.appCreds.pemPath, "utf8"),
31597
31862
  installationId: args.appCreds.installationId,
31598
31863
  fetchImpl: args.fetchImpl
31599
31864
  });
@@ -31683,7 +31948,7 @@ async function applyProfileToBrains(args) {
31683
31948
  }
31684
31949
  }
31685
31950
  function spawnDetachedSeedWatch() {
31686
- const logPath = path39.join(os16.homedir(), ".m8t", "seed-profile.log");
31951
+ const logPath = path38.join(os16.homedir(), ".m8t", "seed-profile.log");
31687
31952
  const fd = openSync(logPath, "a");
31688
31953
  try {
31689
31954
  const child = spawn6(process.execPath, [process.argv[1] ?? "", "bootstrap", "seed-profile", "--watch"], {
@@ -31761,16 +32026,16 @@ function renderInstallSummary(args) {
31761
32026
 
31762
32027
  // src/lib/companion-install.ts
31763
32028
  import { constants as constants2 } from "fs";
31764
- import * as fs37 from "fs/promises";
31765
- import * as path41 from "path";
32029
+ import * as fs36 from "fs/promises";
32030
+ import * as path40 from "path";
31766
32031
  import { randomUUID as randomUUID3 } from "crypto";
31767
32032
  import { execFile, spawn as spawn7 } from "child_process";
31768
32033
 
31769
32034
  // src/lib/companion-artifact.ts
31770
32035
  import { createHash as createHash7 } from "crypto";
31771
32036
  import { constants } from "fs";
31772
- import * as fs36 from "fs/promises";
31773
- import * as path40 from "path";
32037
+ import * as fs35 from "fs/promises";
32038
+ import * as path39 from "path";
31774
32039
  var SHA256 = /^[a-f0-9]{64}$/u;
31775
32040
  var VERSION2 = /^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$/u;
31776
32041
  function exactKeys(value, expected) {
@@ -31778,23 +32043,23 @@ function exactKeys(value, expected) {
31778
32043
  return actual.length === expected.length && actual.every((key2, index) => key2 === [...expected].sort()[index]);
31779
32044
  }
31780
32045
  function normalizedRelative(value) {
31781
- if (value.length === 0 || value.includes("\\") || value.includes("\0") || path40.posix.isAbsolute(value)) {
32046
+ if (value.length === 0 || value.includes("\\") || value.includes("\0") || path39.posix.isAbsolute(value)) {
31782
32047
  throw new Error("Artifact path must be a normalized relative POSIX path");
31783
32048
  }
31784
- const normalized = path40.posix.normalize(value);
32049
+ const normalized = path39.posix.normalize(value);
31785
32050
  if (normalized !== value || normalized === "." || normalized === ".." || normalized.startsWith("../")) {
31786
32051
  throw new Error("Artifact path escapes the payload root");
31787
32052
  }
31788
32053
  return value;
31789
32054
  }
31790
32055
  function validateLink(entryPath, target) {
31791
- if (target.length === 0 || target.includes("\\") || target.includes("\0") || path40.posix.isAbsolute(target)) {
32056
+ if (target.length === 0 || target.includes("\\") || target.includes("\0") || path39.posix.isAbsolute(target)) {
31792
32057
  throw new Error("Artifact symlink target must be relative");
31793
32058
  }
31794
- const resolved = path40.posix.normalize(
31795
- path40.posix.join(path40.posix.dirname(entryPath), target)
32059
+ const resolved = path39.posix.normalize(
32060
+ path39.posix.join(path39.posix.dirname(entryPath), target)
31796
32061
  );
31797
- if (resolved === ".." || resolved.startsWith("../") || path40.posix.isAbsolute(resolved)) {
32062
+ if (resolved === ".." || resolved.startsWith("../") || path39.posix.isAbsolute(resolved)) {
31798
32063
  throw new Error("Artifact symlink target escapes the payload root");
31799
32064
  }
31800
32065
  return target;
@@ -31875,17 +32140,17 @@ function parseArtifactManifest(value) {
31875
32140
  };
31876
32141
  }
31877
32142
  async function sha256File2(filePath) {
31878
- return createHash7("sha256").update(await fs36.readFile(filePath)).digest("hex");
32143
+ return createHash7("sha256").update(await fs35.readFile(filePath)).digest("hex");
31879
32144
  }
31880
32145
  async function walk2(root, relative4 = "") {
31881
- const directory = path40.join(root, ...relative4.split("/").filter(Boolean));
31882
- const children = await fs36.readdir(directory, { withFileTypes: true });
32146
+ const directory = path39.join(root, ...relative4.split("/").filter(Boolean));
32147
+ const children = await fs35.readdir(directory, { withFileTypes: true });
31883
32148
  const entries = [];
31884
32149
  for (const child of children.sort((left, right) => left.name.localeCompare(right.name))) {
31885
32150
  const childRelative = relative4 ? `${relative4}/${child.name}` : child.name;
31886
32151
  normalizedRelative(childRelative);
31887
- const childPath = path40.join(directory, child.name);
31888
- const stat5 = await fs36.lstat(childPath);
32152
+ const childPath = path39.join(directory, child.name);
32153
+ const stat5 = await fs35.lstat(childPath);
31889
32154
  if (stat5.isDirectory()) {
31890
32155
  entries.push(...await walk2(root, childRelative));
31891
32156
  } else if (stat5.isFile()) {
@@ -31897,7 +32162,7 @@ async function walk2(root, relative4 = "") {
31897
32162
  sha256: await sha256File2(childPath)
31898
32163
  });
31899
32164
  } else if (stat5.isSymbolicLink()) {
31900
- const target = await fs36.readlink(childPath);
32165
+ const target = await fs35.readlink(childPath);
31901
32166
  entries.push({
31902
32167
  type: "symlink",
31903
32168
  path: childRelative,
@@ -31910,19 +32175,19 @@ async function walk2(root, relative4 = "") {
31910
32175
  return entries;
31911
32176
  }
31912
32177
  async function ensureRealDirectory(root) {
31913
- const stat5 = await fs36.lstat(root);
32178
+ const stat5 = await fs35.lstat(root);
31914
32179
  if (stat5.isSymbolicLink()) throw new Error("Artifact root is a symbolic link");
31915
32180
  if (!stat5.isDirectory()) throw new Error("Artifact root is not a directory");
31916
32181
  }
31917
32182
  async function validateResolvedLinks(root, entries) {
31918
- const realRoot = await fs36.realpath(root);
32183
+ const realRoot = await fs35.realpath(root);
31919
32184
  for (const entry of entries) {
31920
32185
  if (entry.type !== "symlink") continue;
31921
32186
  try {
31922
- const linkPath = path40.join(root, ...entry.path.split("/"));
31923
- const resolved = await fs36.realpath(linkPath);
31924
- const relative4 = path40.relative(realRoot, resolved);
31925
- if (relative4 === ".." || relative4.startsWith(`..${path40.sep}`) || path40.isAbsolute(relative4)) {
32187
+ const linkPath = path39.join(root, ...entry.path.split("/"));
32188
+ const resolved = await fs35.realpath(linkPath);
32189
+ const relative4 = path39.relative(realRoot, resolved);
32190
+ if (relative4 === ".." || relative4.startsWith(`..${path39.sep}`) || path39.isAbsolute(relative4)) {
31926
32191
  throw new Error("Artifact symlink chain escapes the payload root");
31927
32192
  }
31928
32193
  } catch (error) {
@@ -31952,13 +32217,13 @@ async function buildArtifactManifest(payloadRoot, input) {
31952
32217
  return manifest;
31953
32218
  }
31954
32219
  async function readArtifactManifest(manifestPath) {
31955
- const before = await fs36.lstat(manifestPath);
32220
+ const before = await fs35.lstat(manifestPath);
31956
32221
  if (before.isSymbolicLink() || !before.isFile()) {
31957
32222
  throw new Error("Artifact manifest is a symbolic link or non-file");
31958
32223
  }
31959
32224
  let handle;
31960
32225
  try {
31961
- handle = await fs36.open(
32226
+ handle = await fs35.open(
31962
32227
  manifestPath,
31963
32228
  constants.O_RDONLY | constants.O_NOFOLLOW
31964
32229
  );
@@ -31975,9 +32240,9 @@ async function readArtifactManifest(manifestPath) {
31975
32240
  }
31976
32241
  }
31977
32242
  function ensureContainedEntry(root, entryPath) {
31978
- const absolute = path40.join(root, ...entryPath.split("/"));
31979
- const relative4 = path40.relative(root, absolute);
31980
- if (relative4.startsWith("..") || path40.isAbsolute(relative4)) {
32243
+ const absolute = path39.join(root, ...entryPath.split("/"));
32244
+ const relative4 = path39.relative(root, absolute);
32245
+ if (relative4.startsWith("..") || path39.isAbsolute(relative4)) {
31981
32246
  throw new Error("Artifact entry escapes payload root");
31982
32247
  }
31983
32248
  return absolute;
@@ -32016,27 +32281,27 @@ async function verifyArtifactPayload(payloadRoot, manifest) {
32016
32281
  async function copyArtifactPayload(sourceRoot, targetRoot, manifest) {
32017
32282
  await verifyArtifactSource(sourceRoot, manifest);
32018
32283
  try {
32019
- const targetStat = await fs36.lstat(targetRoot);
32284
+ const targetStat = await fs35.lstat(targetRoot);
32020
32285
  if (targetStat.isSymbolicLink()) {
32021
32286
  throw new Error("Install target is a symbolic link");
32022
32287
  }
32023
32288
  if (!targetStat.isDirectory()) throw new Error("Install target is not a directory");
32024
- if ((await fs36.readdir(targetRoot)).length > 0) {
32289
+ if ((await fs35.readdir(targetRoot)).length > 0) {
32025
32290
  throw new Error("Install staging target is not empty");
32026
32291
  }
32027
32292
  } catch (error) {
32028
32293
  if (error.code !== "ENOENT") throw error;
32029
- await fs36.mkdir(targetRoot, { recursive: false, mode: 448 });
32294
+ await fs35.mkdir(targetRoot, { recursive: false, mode: 448 });
32030
32295
  }
32031
32296
  for (const entry of manifest.entries) {
32032
32297
  const source = ensureContainedEntry(sourceRoot, entry.path);
32033
32298
  const target = ensureContainedEntry(targetRoot, entry.path);
32034
- await fs36.mkdir(path40.dirname(target), { recursive: true, mode: 448 });
32299
+ await fs35.mkdir(path39.dirname(target), { recursive: true, mode: 448 });
32035
32300
  if (entry.type === "file") {
32036
- await fs36.copyFile(source, target);
32037
- await fs36.chmod(target, entry.mode);
32301
+ await fs35.copyFile(source, target);
32302
+ await fs35.chmod(target, entry.mode);
32038
32303
  } else {
32039
- await fs36.symlink(entry.target, target);
32304
+ await fs35.symlink(entry.target, target);
32040
32305
  }
32041
32306
  }
32042
32307
  await verifyArtifactPayload(targetRoot, manifest);
@@ -32075,17 +32340,17 @@ function execFileOutput(file, args) {
32075
32340
  }
32076
32341
  async function setCompanionStartAtLogin(input) {
32077
32342
  if (input.platform === "darwin") {
32078
- const launchAgents = path41.join(input.homeDirectory, "Library", "LaunchAgents");
32079
- const registration = path41.join(
32343
+ const launchAgents = path40.join(input.homeDirectory, "Library", "LaunchAgents");
32344
+ const registration = path40.join(
32080
32345
  launchAgents,
32081
32346
  "com.m8t.companion.plist"
32082
32347
  );
32083
32348
  await assertNotSymlink(registration, "Start-at-login registration");
32084
32349
  if (!input.enabled) {
32085
- await fs37.rm(registration, { force: true });
32350
+ await fs36.rm(registration, { force: true });
32086
32351
  return;
32087
32352
  }
32088
- await fs37.mkdir(launchAgents, { recursive: true, mode: 448 });
32353
+ await fs36.mkdir(launchAgents, { recursive: true, mode: 448 });
32089
32354
  const plist = '<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n<plist version="1.0"><dict><key>Label</key><string>com.m8t.companion</string><key>ProgramArguments</key><array><string>' + xmlEscape(input.executable) + "</string></array><key>RunAtLoad</key><true/></dict></plist>\n";
32090
32355
  await atomicWriteText(registration, plist, 384);
32091
32356
  return;
@@ -32137,7 +32402,7 @@ async function setCompanionStartAtLogin(input) {
32137
32402
  }
32138
32403
  async function getCompanionStartAtLogin(input) {
32139
32404
  if (input.platform === "darwin") {
32140
- const registration = path41.join(
32405
+ const registration = path40.join(
32141
32406
  input.homeDirectory,
32142
32407
  "Library",
32143
32408
  "LaunchAgents",
@@ -32199,26 +32464,26 @@ function assertSupported(options) {
32199
32464
  }
32200
32465
  function companionInstallPaths(options) {
32201
32466
  assertSupported(options);
32202
- const companionState = path41.join(
32467
+ const companionState = path40.join(
32203
32468
  options.homeDirectory,
32204
32469
  ".m8t",
32205
32470
  "companion"
32206
32471
  );
32207
- const targetRoot = options.platform === "darwin" ? path41.join(
32472
+ const targetRoot = options.platform === "darwin" ? path40.join(
32208
32473
  options.homeDirectory,
32209
32474
  "Applications",
32210
32475
  "m8t Companion.app"
32211
- ) : path41.join(
32212
- options.localAppData ?? path41.join(options.homeDirectory, "AppData", "Local"),
32476
+ ) : path40.join(
32477
+ options.localAppData ?? path40.join(options.homeDirectory, "AppData", "Local"),
32213
32478
  "m8t",
32214
32479
  "companion",
32215
32480
  "app"
32216
32481
  );
32217
32482
  return {
32218
32483
  targetRoot,
32219
- installManifest: path41.join(companionState, "install-v1.json"),
32220
- runtimeBinding: path41.join(companionState, "runtime-v1.json"),
32221
- preferences: path41.join(companionState, "preferences-v1.json")
32484
+ installManifest: path40.join(companionState, "install-v1.json"),
32485
+ runtimeBinding: path40.join(companionState, "runtime-v1.json"),
32486
+ preferences: path40.join(companionState, "preferences-v1.json")
32222
32487
  };
32223
32488
  }
32224
32489
  function exactKeys2(value, keys) {
@@ -32229,7 +32494,7 @@ function parseInstallManifest(value) {
32229
32494
  throw new Error("Install manifest schema is invalid");
32230
32495
  }
32231
32496
  const record = value;
32232
- if (!exactKeys2(record, INSTALL_KEYS) || record.schemaVersion !== 1 || typeof record.version !== "string" || record.platform !== "darwin" && record.platform !== "win32" || record.architecture !== "arm64" && record.architecture !== "x64" || typeof record.entryRelativePath !== "string" || typeof record.artifactTreeSha256 !== "string" || !/^[a-f0-9]{64}$/u.test(record.artifactTreeSha256) || typeof record.ownedTargetRoot !== "string" || !path41.isAbsolute(record.ownedTargetRoot)) {
32497
+ if (!exactKeys2(record, INSTALL_KEYS) || record.schemaVersion !== 1 || typeof record.version !== "string" || record.platform !== "darwin" && record.platform !== "win32" || record.architecture !== "arm64" && record.architecture !== "x64" || typeof record.entryRelativePath !== "string" || typeof record.artifactTreeSha256 !== "string" || !/^[a-f0-9]{64}$/u.test(record.artifactTreeSha256) || typeof record.ownedTargetRoot !== "string" || !path40.isAbsolute(record.ownedTargetRoot)) {
32233
32498
  throw new Error("Install manifest schema is invalid");
32234
32499
  }
32235
32500
  return record;
@@ -32239,7 +32504,7 @@ function parseRuntimeBinding(value, platform) {
32239
32504
  throw new Error("Runtime binding schema is invalid");
32240
32505
  }
32241
32506
  const record = value;
32242
- const paths = platform === "win32" ? path41.win32 : path41.posix;
32507
+ const paths = platform === "win32" ? path40.win32 : path40.posix;
32243
32508
  if (!exactKeys2(record, RUNTIME_KEYS) || record.schemaVersion !== 1 || typeof record.nodeExecutable !== "string" || !paths.isAbsolute(record.nodeExecutable) || typeof record.cliEntry !== "string" || !paths.isAbsolute(record.cliEntry) || typeof record.gatewayOrigin !== "string") {
32244
32509
  throw new Error("Runtime binding schema is invalid");
32245
32510
  }
@@ -32264,7 +32529,7 @@ function validateGatewayOrigin(value) {
32264
32529
  }
32265
32530
  async function assertNotSymlink(filePath, kind) {
32266
32531
  try {
32267
- if ((await fs37.lstat(filePath)).isSymbolicLink()) {
32532
+ if ((await fs36.lstat(filePath)).isSymbolicLink()) {
32268
32533
  throw new Error(`${kind} is a symbolic link`);
32269
32534
  }
32270
32535
  } catch (error) {
@@ -32273,20 +32538,20 @@ async function assertNotSymlink(filePath, kind) {
32273
32538
  }
32274
32539
  }
32275
32540
  async function assertOwnedDirectoryChain(anchor, targetDirectory) {
32276
- const relative4 = path41.relative(anchor, targetDirectory);
32277
- if (relative4 === ".." || relative4.startsWith(`..${path41.sep}`) || path41.isAbsolute(relative4)) {
32541
+ const relative4 = path40.relative(anchor, targetDirectory);
32542
+ if (relative4 === ".." || relative4.startsWith(`..${path40.sep}`) || path40.isAbsolute(relative4)) {
32278
32543
  throw new Error("Companion owned directory escapes its trusted anchor");
32279
32544
  }
32280
- const segments = relative4.split(path41.sep).filter(Boolean);
32545
+ const segments = relative4.split(path40.sep).filter(Boolean);
32281
32546
  let current = anchor;
32282
- const anchorStatus = await fs37.lstat(anchor);
32547
+ const anchorStatus = await fs36.lstat(anchor);
32283
32548
  if (anchorStatus.isSymbolicLink() || !anchorStatus.isDirectory()) {
32284
32549
  throw new Error("Companion owned directory anchor is unsafe");
32285
32550
  }
32286
32551
  for (const segment of segments) {
32287
- current = path41.join(current, segment);
32552
+ current = path40.join(current, segment);
32288
32553
  try {
32289
- const status = await fs37.lstat(current);
32554
+ const status = await fs36.lstat(current);
32290
32555
  if (status.isSymbolicLink() || !status.isDirectory()) {
32291
32556
  throw new Error("Companion owned directory contains a symbolic link");
32292
32557
  }
@@ -32299,19 +32564,19 @@ async function assertOwnedDirectoryChain(anchor, targetDirectory) {
32299
32564
  async function assertOwnedParents(options, paths) {
32300
32565
  await assertOwnedDirectoryChain(
32301
32566
  options.homeDirectory,
32302
- path41.dirname(paths.installManifest)
32567
+ path40.dirname(paths.installManifest)
32303
32568
  );
32304
- const targetAnchor = options.platform === "win32" ? options.localAppData ?? path41.join(options.homeDirectory, "AppData", "Local") : options.homeDirectory;
32305
- await assertOwnedDirectoryChain(targetAnchor, path41.dirname(paths.targetRoot));
32569
+ const targetAnchor = options.platform === "win32" ? options.localAppData ?? path40.join(options.homeDirectory, "AppData", "Local") : options.homeDirectory;
32570
+ await assertOwnedDirectoryChain(targetAnchor, path40.dirname(paths.targetRoot));
32306
32571
  }
32307
32572
  async function readRegularText(filePath, maxBytes) {
32308
- const before = await fs37.lstat(filePath);
32573
+ const before = await fs36.lstat(filePath);
32309
32574
  if (before.isSymbolicLink() || !before.isFile()) {
32310
32575
  throw new Error("Companion state file is not a regular file");
32311
32576
  }
32312
32577
  let handle;
32313
32578
  try {
32314
- handle = await fs37.open(
32579
+ handle = await fs36.open(
32315
32580
  filePath,
32316
32581
  constants2.O_RDONLY | constants2.O_NOFOLLOW
32317
32582
  );
@@ -32334,27 +32599,27 @@ async function atomicWriteJson(filePath, value) {
32334
32599
  }
32335
32600
  async function atomicWriteText(filePath, contents, mode) {
32336
32601
  await assertNotSymlink(filePath, "Companion state file");
32337
- await fs37.mkdir(path41.dirname(filePath), {
32602
+ await fs36.mkdir(path40.dirname(filePath), {
32338
32603
  recursive: true,
32339
32604
  mode: 448
32340
32605
  });
32341
32606
  const temporary = `${filePath}.${randomUUID3()}.tmp`;
32342
32607
  try {
32343
- await fs37.writeFile(temporary, contents, {
32608
+ await fs36.writeFile(temporary, contents, {
32344
32609
  mode,
32345
32610
  flag: "wx"
32346
32611
  });
32347
- await fs37.rename(temporary, filePath);
32348
- await fs37.chmod(filePath, mode).catch(() => void 0);
32612
+ await fs36.rename(temporary, filePath);
32613
+ await fs36.chmod(filePath, mode).catch(() => void 0);
32349
32614
  } finally {
32350
- await fs37.rm(temporary, { force: true }).catch(() => void 0);
32615
+ await fs36.rm(temporary, { force: true }).catch(() => void 0);
32351
32616
  }
32352
32617
  }
32353
32618
  async function realRegularFile(filePath, executable) {
32354
- const real = await fs37.realpath(filePath);
32355
- const stat5 = await fs37.stat(real);
32619
+ const real = await fs36.realpath(filePath);
32620
+ const stat5 = await fs36.stat(real);
32356
32621
  if (!stat5.isFile()) throw new Error("Companion launch target is not a file");
32357
- await fs37.access(real, executable ? constants2.X_OK : constants2.R_OK);
32622
+ await fs36.access(real, executable ? constants2.X_OK : constants2.R_OK);
32358
32623
  return real;
32359
32624
  }
32360
32625
  function defaultLaunch(executable) {
@@ -32370,7 +32635,7 @@ async function companionIsRunning(platform, executable) {
32370
32635
  if (platform !== "win32") return false;
32371
32636
  let handle;
32372
32637
  try {
32373
- handle = await fs37.open(executable, "r+");
32638
+ handle = await fs36.open(executable, "r+");
32374
32639
  } catch (error) {
32375
32640
  const code = error.code;
32376
32641
  if (code === "ENOENT") return false;
@@ -32451,7 +32716,7 @@ async function statusCompanion(options) {
32451
32716
  realRegularFile(runtime.nodeExecutable, options.platform !== "win32"),
32452
32717
  realRegularFile(runtime.cliEntry, false)
32453
32718
  ]);
32454
- const executable = path41.join(
32719
+ const executable = path40.join(
32455
32720
  paths.targetRoot,
32456
32721
  ...install.entryRelativePath.split("/")
32457
32722
  );
@@ -32484,7 +32749,7 @@ async function snapshotFile(filePath) {
32484
32749
  }
32485
32750
  async function restoreFile(filePath, bytes) {
32486
32751
  if (bytes === null) {
32487
- await fs37.rm(filePath, { force: true });
32752
+ await fs36.rm(filePath, { force: true });
32488
32753
  } else {
32489
32754
  await atomicWriteJson(filePath, JSON.parse(bytes.toString("utf8")));
32490
32755
  }
@@ -32499,8 +32764,8 @@ async function converge(options, force) {
32499
32764
  if (artifactManifest.platform !== options.platform || artifactManifest.architecture !== options.architecture) {
32500
32765
  throw new Error("Companion artifact does not match this OS and architecture");
32501
32766
  }
32502
- const payloadRoot = path41.join(
32503
- path41.dirname(options.artifactManifestPath),
32767
+ const payloadRoot = path40.join(
32768
+ path40.dirname(options.artifactManifestPath),
32504
32769
  "payload"
32505
32770
  );
32506
32771
  await verifyArtifactSource(payloadRoot, artifactManifest);
@@ -32520,7 +32785,7 @@ async function converge(options, force) {
32520
32785
  if (priorInstalled) {
32521
32786
  await assertCompanionNotRunning(
32522
32787
  options,
32523
- path41.join(
32788
+ path40.join(
32524
32789
  priorInstalled.paths.targetRoot,
32525
32790
  ...priorInstalled.install.entryRelativePath.split("/")
32526
32791
  )
@@ -32528,7 +32793,7 @@ async function converge(options, force) {
32528
32793
  }
32529
32794
  if (current.state === "not-installed") {
32530
32795
  try {
32531
- await fs37.lstat(paths.targetRoot);
32796
+ await fs36.lstat(paths.targetRoot);
32532
32797
  throw new Error(
32533
32798
  "The fixed companion target exists without an owned install manifest"
32534
32799
  );
@@ -32539,7 +32804,7 @@ async function converge(options, force) {
32539
32804
  const stage = `${paths.targetRoot}.m8t-stage-${randomUUID3()}`;
32540
32805
  const backup = `${paths.targetRoot}.m8t-backup-${randomUUID3()}`;
32541
32806
  const copy = options.copyPayload ?? copyArtifactPayload;
32542
- await fs37.mkdir(path41.dirname(paths.targetRoot), {
32807
+ await fs36.mkdir(path40.dirname(paths.targetRoot), {
32543
32808
  recursive: true,
32544
32809
  mode: 448
32545
32810
  });
@@ -32556,12 +32821,12 @@ async function converge(options, force) {
32556
32821
  try {
32557
32822
  await copy(payloadRoot, stage, artifactManifest);
32558
32823
  try {
32559
- await fs37.rename(paths.targetRoot, backup);
32824
+ await fs36.rename(paths.targetRoot, backup);
32560
32825
  movedPrior = true;
32561
32826
  } catch (error) {
32562
32827
  if (error.code !== "ENOENT") throw error;
32563
32828
  }
32564
- await fs37.rename(stage, paths.targetRoot);
32829
+ await fs36.rename(stage, paths.targetRoot);
32565
32830
  installedStage = true;
32566
32831
  const nodeExecutable = await realRegularFile(
32567
32832
  options.nodeExecutable,
@@ -32603,7 +32868,7 @@ async function converge(options, force) {
32603
32868
  await readClosedJson(paths.runtimeBinding),
32604
32869
  options.platform
32605
32870
  );
32606
- const executable = path41.join(
32871
+ const executable = path40.join(
32607
32872
  paths.targetRoot,
32608
32873
  ...artifactManifest.entryRelativePath.split("/")
32609
32874
  );
@@ -32613,7 +32878,7 @@ async function converge(options, force) {
32613
32878
  platform: options.platform,
32614
32879
  executable: ownedExecutable
32615
32880
  }));
32616
- priorLoginExecutable = priorInstalled ? path41.join(
32881
+ priorLoginExecutable = priorInstalled ? path40.join(
32617
32882
  priorInstalled.paths.targetRoot,
32618
32883
  ...priorInstalled.install.entryRelativePath.split("/")
32619
32884
  ) : executable;
@@ -32624,7 +32889,7 @@ async function converge(options, force) {
32624
32889
  );
32625
32890
  loginChanged = true;
32626
32891
  await (options.launch ?? defaultLaunch)(executable);
32627
- await fs37.rm(backup, { recursive: true, force: true });
32892
+ await fs36.rm(backup, { recursive: true, force: true });
32628
32893
  return {
32629
32894
  state: "installed",
32630
32895
  version: artifactManifest.version,
@@ -32638,15 +32903,15 @@ async function converge(options, force) {
32638
32903
  () => void 0
32639
32904
  );
32640
32905
  }
32641
- await fs37.rm(stage, { recursive: true, force: true }).catch(() => void 0);
32906
+ await fs36.rm(stage, { recursive: true, force: true }).catch(() => void 0);
32642
32907
  if (installedStage) {
32643
- await fs37.rm(paths.targetRoot, {
32908
+ await fs36.rm(paths.targetRoot, {
32644
32909
  recursive: true,
32645
32910
  force: true
32646
32911
  }).catch(() => void 0);
32647
32912
  }
32648
32913
  if (movedPrior) {
32649
- await fs37.rename(backup, paths.targetRoot).catch(() => void 0);
32914
+ await fs36.rename(backup, paths.targetRoot).catch(() => void 0);
32650
32915
  }
32651
32916
  await Promise.all([
32652
32917
  restoreFile(paths.installManifest, snapshots[0]),
@@ -32672,14 +32937,14 @@ async function uninstallCompanion(options) {
32672
32937
  if (install.ownedTargetRoot !== paths.targetRoot) {
32673
32938
  throw new Error("Refusing to remove a non-owned companion target");
32674
32939
  }
32675
- const executable = path41.join(
32940
+ const executable = path40.join(
32676
32941
  paths.targetRoot,
32677
32942
  ...install.entryRelativePath.split("/")
32678
32943
  );
32679
32944
  await assertCompanionNotRunning(options, executable);
32680
32945
  await (options.setStartAtLogin ?? (() => Promise.resolve()))(executable, false);
32681
32946
  const remove = options.removeOwnedPath ?? (async (ownedPath, recursive) => {
32682
- await fs37.rm(ownedPath, { recursive, force: true });
32947
+ await fs36.rm(ownedPath, { recursive, force: true });
32683
32948
  });
32684
32949
  await remove(paths.targetRoot, true);
32685
32950
  await remove(paths.installManifest, false);
@@ -32690,8 +32955,8 @@ async function uninstallCompanion(options) {
32690
32955
 
32691
32956
  // src/commands/companion/install.ts
32692
32957
  import * as os18 from "os";
32693
- import * as path43 from "path";
32694
- import { Command as Command58, Option as Option55 } from "clipanion";
32958
+ import * as path42 from "path";
32959
+ import { Command as Command59, Option as Option56 } from "clipanion";
32695
32960
 
32696
32961
  // src/lib/companion-channel.ts
32697
32962
  async function readCompanionRelease(source = { url: CHANNEL_LATEST_URL }, deps = {}) {
@@ -32708,9 +32973,9 @@ async function readCompanionRelease(source = { url: CHANNEL_LATEST_URL }, deps =
32708
32973
  // src/lib/companion-download.ts
32709
32974
  import { createHash as createHash8 } from "crypto";
32710
32975
  import { execFile as execFile2 } from "child_process";
32711
- import * as fs38 from "fs/promises";
32976
+ import * as fs37 from "fs/promises";
32712
32977
  import * as os17 from "os";
32713
- import * as path42 from "path";
32978
+ import * as path41 from "path";
32714
32979
  init_errors();
32715
32980
  var MAX_ASSET_BYTES = 512 * 1024 * 1024;
32716
32981
  function extractArchive(archive, into) {
@@ -32763,20 +33028,20 @@ async function downloadCompanionArtifact(component, deps = {}) {
32763
33028
  hint: "Nothing was unpacked. This is what a corrupted download or a substituted file looks like \u2014 retry, and report it if it persists."
32764
33029
  });
32765
33030
  }
32766
- const root = await (deps.makeTemporaryDirectory ?? (() => fs38.mkdtemp(path42.join(os17.tmpdir(), "m8t-companion-"))))();
33031
+ const root = await (deps.makeTemporaryDirectory ?? (() => fs37.mkdtemp(path41.join(os17.tmpdir(), "m8t-companion-"))))();
32767
33032
  const dispose = async () => {
32768
- await fs38.rm(root, { recursive: true, force: true }).catch(() => void 0);
33033
+ await fs37.rm(root, { recursive: true, force: true }).catch(() => void 0);
32769
33034
  };
32770
33035
  try {
32771
- const archive = path42.join(root, pinned.asset);
32772
- await fs38.writeFile(archive, bytes, { mode: 384 });
32773
- const unpacked = path42.join(root, "unpacked");
32774
- await fs38.mkdir(unpacked, { recursive: false, mode: 448 });
33036
+ const archive = path41.join(root, pinned.asset);
33037
+ await fs37.writeFile(archive, bytes, { mode: 384 });
33038
+ const unpacked = path41.join(root, "unpacked");
33039
+ await fs37.mkdir(unpacked, { recursive: false, mode: 448 });
32775
33040
  await (deps.extract ?? extractArchive)(archive, unpacked);
32776
- await fs38.rm(archive, { force: true });
33041
+ await fs37.rm(archive, { force: true });
32777
33042
  return {
32778
33043
  version: component.version,
32779
- artifactManifestPath: path42.join(unpacked, "artifact-v1.json"),
33044
+ artifactManifestPath: path41.join(unpacked, "artifact-v1.json"),
32780
33045
  dispose
32781
33046
  };
32782
33047
  } catch (error) {
@@ -32807,7 +33072,7 @@ async function convergeCompanionFromChannel(converge2, options = {}) {
32807
33072
  let artifactManifestPath;
32808
33073
  let dispose = () => Promise.resolve();
32809
33074
  if (stagedDirectory !== void 0) {
32810
- artifactManifestPath = path43.resolve(stagedDirectory, "artifact-v1.json");
33075
+ artifactManifestPath = path42.resolve(stagedDirectory, "artifact-v1.json");
32811
33076
  } else {
32812
33077
  const release = await readCompanionRelease(
32813
33078
  platformVersion !== void 0 ? { channel: true, version: platformTag(platformVersion) } : { url: CHANNEL_LATEST_URL }
@@ -32849,7 +33114,7 @@ Version: ${state.version}
32849
33114
  }
32850
33115
  var CompanionInstallCommand = class extends M8tCommand {
32851
33116
  static paths = [["companion", "install"]];
32852
- static usage = Command58.Usage({
33117
+ static usage = Command59.Usage({
32853
33118
  description: "Install the desktop companions for this user from the release channel.",
32854
33119
  examples: [
32855
33120
  ["Install the released build", "$0 companion install"],
@@ -32859,10 +33124,10 @@ var CompanionInstallCommand = class extends M8tCommand {
32859
33124
  ]
32860
33125
  ]
32861
33126
  });
32862
- from = Option55.String("--from", {
33127
+ from = Option56.String("--from", {
32863
33128
  description: "A locally staged build directory instead of the released one."
32864
33129
  });
32865
- resourceGroup = Option55.String("--resource-group", {
33130
+ resourceGroup = Option56.String("--resource-group", {
32866
33131
  description: "Which deployment to bind to, when the subscription holds more than one."
32867
33132
  });
32868
33133
  async executeCommand() {
@@ -32885,7 +33150,7 @@ function resolveRepoRootMarker(args) {
32885
33150
  }
32886
33151
  async function looksLikeCheckout(dir) {
32887
33152
  try {
32888
- return (await fs39.stat(path44.join(dir, "brain-template"))).isDirectory();
33153
+ return (await fs38.stat(path43.join(dir, "brain-template"))).isDirectory();
32889
33154
  } catch {
32890
33155
  return false;
32891
33156
  }
@@ -32904,18 +33169,18 @@ var defaultDeps3 = {
32904
33169
  homedir: () => os19.homedir()
32905
33170
  };
32906
33171
  async function finalizeInstall(args, deps = defaultDeps3) {
32907
- const markerDir = path44.join(deps.homedir(), ".m8t");
32908
- const markerPath = path44.join(markerDir, "repo-root");
33172
+ const markerDir = path43.join(deps.homedir(), ".m8t");
33173
+ const markerPath = path43.join(markerDir, "repo-root");
32909
33174
  const cwd = process.cwd();
32910
- const existing = await fs39.readFile(markerPath, "utf8").then((s) => s.trim()).catch(() => null);
33175
+ const existing = await fs38.readFile(markerPath, "utf8").then((s) => s.trim()).catch(() => null);
32911
33176
  const repoRoot = resolveRepoRootMarker({
32912
33177
  ...args.repoRoot !== void 0 ? { explicit: args.repoRoot } : {},
32913
33178
  cwd,
32914
33179
  cwdIsCheckout: await looksLikeCheckout(cwd),
32915
33180
  existing
32916
33181
  });
32917
- await fs39.mkdir(markerDir, { recursive: true });
32918
- await fs39.writeFile(markerPath, `${repoRoot}
33182
+ await fs38.mkdir(markerDir, { recursive: true });
33183
+ await fs38.writeFile(markerPath, `${repoRoot}
32919
33184
  `, "utf8");
32920
33185
  let webappUrl;
32921
33186
  try {
@@ -32993,7 +33258,7 @@ async function finalizeInstall(args, deps = defaultDeps3) {
32993
33258
  }
32994
33259
  let brainOrg = null;
32995
33260
  try {
32996
- const credsRaw = await fs39.readFile(path44.join(markerDir, "github-app.json"), "utf8");
33261
+ const credsRaw = await fs38.readFile(path43.join(markerDir, "github-app.json"), "utf8");
32997
33262
  const creds = JSON.parse(credsRaw);
32998
33263
  brainOrg = typeof creds.org === "string" ? creds.org : null;
32999
33264
  } catch {
@@ -33078,7 +33343,7 @@ var BootstrapStatusCommand = class extends M8tCommand {
33078
33343
  // runbooks and shakedown recipes that a founder may already be part-way
33079
33344
  // through — it prints a deprecation notice and does the right thing.
33080
33345
  static paths = [["bootstrap", "status"], ["bootstrap", "finish"]];
33081
- static usage = Command59.Usage({
33346
+ static usage = Command60.Usage({
33082
33347
  description: "Show the cloud installer's live status (phase, progress, result) \u2014 and finish the local setup when it lands.",
33083
33348
  details: "Reads the durable status blob written by the installer. --watch polls until the install reaches done or failed.\n\nOn reaching done under --watch this also completes the local half of the install, which nothing else in the bootstrap path can do: it registers the webapp's sign-in redirect URI (the installer runs as a managed identity with no directory role, and at launch time the gateway FQDN did not exist yet), writes ~/.m8t/repo-root and the gateway discovery cache, and seeds your advisors' brains from the onboarding intake. Re-runnable \u2014 `m8t bootstrap finish` is a deprecated alias that does exactly this on an already-done install.",
33084
33349
  examples: [
@@ -33087,12 +33352,12 @@ var BootstrapStatusCommand = class extends M8tCommand {
33087
33352
  ["Redo the local setup on a finished install", "$0 bootstrap status --finalize --repo-root /path/to/m8t"]
33088
33353
  ]
33089
33354
  });
33090
- watch = Option56.Boolean("--watch", false);
33091
- output = Option56.String("--output");
33092
- repoRoot = Option56.String("--repo-root", { description: "The m8t clone to point local tools at (default: the current directory)." });
33093
- finalize = Option56.Boolean("--finalize", false, { description: "Complete the local setup against an already-done install, without watching." });
33094
- subscription = Option56.String("--subscription");
33095
- resourceGroup = Option56.String("--resource-group");
33355
+ watch = Option57.Boolean("--watch", false);
33356
+ output = Option57.String("--output");
33357
+ repoRoot = Option57.String("--repo-root", { description: "The m8t clone to point local tools at (default: the current directory)." });
33358
+ finalize = Option57.Boolean("--finalize", false, { description: "Complete the local setup against an already-done install, without watching." });
33359
+ subscription = Option57.String("--subscription");
33360
+ resourceGroup = Option57.String("--resource-group");
33096
33361
  async executeCommand() {
33097
33362
  const state = await readBootstrapState();
33098
33363
  if (!state) {
@@ -33225,7 +33490,7 @@ function formatStatus(d) {
33225
33490
  }
33226
33491
 
33227
33492
  // src/commands/bootstrap/reap.ts
33228
- import { Command as Command60, Option as Option57 } from "clipanion";
33493
+ import { Command as Command61, Option as Option58 } from "clipanion";
33229
33494
  init_errors();
33230
33495
 
33231
33496
  // src/lib/bootstrap-reap.ts
@@ -33319,7 +33584,7 @@ async function reapInstaller(opts) {
33319
33584
  // src/commands/bootstrap/reap.ts
33320
33585
  var BootstrapReapCommand = class extends M8tCommand {
33321
33586
  static paths = [["bootstrap", "reap"]];
33322
- static usage = Command60.Usage({
33587
+ static usage = Command61.Usage({
33323
33588
  description: "Tear down the installer scaffolding (ACI \u2192 MI \u2192 its role assignments) after a successful install.",
33324
33589
  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.\n\n--sweep-orphans is a DIFFERENT and much broader mode: instead of reaping this install, it scans the WHOLE SUBSCRIPTION for m8t role assignments left behind by installs whose resources are gone \u2014 orphaned installer Owner-at-subscription-scope grants and orphaned gateway subscription-scope roles. It is a dry run that only lists what it found unless you also pass --yes, which deletes them.",
33325
33590
  examples: [
@@ -33329,9 +33594,9 @@ var BootstrapReapCommand = class extends M8tCommand {
33329
33594
  ["\u2026and delete them", "$0 bootstrap reap --sweep-orphans --yes"]
33330
33595
  ]
33331
33596
  });
33332
- force = Option57.Boolean("--force", false, { description: "Reap even if the install failed or never reported a status." });
33333
- sweepOrphans = Option57.Boolean("--sweep-orphans", false, { description: "Subscription-wide: find m8t role assignments orphaned by earlier installs. Lists only, unless --yes." });
33334
- yes = Option57.Boolean("--yes", false, { description: "With --sweep-orphans, actually delete what the sweep found." });
33597
+ force = Option58.Boolean("--force", false, { description: "Reap even if the install failed or never reported a status." });
33598
+ sweepOrphans = Option58.Boolean("--sweep-orphans", false, { description: "Subscription-wide: find m8t role assignments orphaned by earlier installs. Lists only, unless --yes." });
33599
+ yes = Option58.Boolean("--yes", false, { description: "With --sweep-orphans, actually delete what the sweep found." });
33335
33600
  async executeCommand() {
33336
33601
  if (this.sweepOrphans === true) {
33337
33602
  const { subscriptionId: sub } = await getAzAccount();
@@ -33425,18 +33690,18 @@ Found ${String(total)} orphaned assignment(s) (${breakdown}) (dry-run). ${colors
33425
33690
  };
33426
33691
 
33427
33692
  // src/commands/bootstrap/ui.ts
33428
- import * as fs41 from "fs";
33693
+ import * as fs40 from "fs";
33429
33694
  import * as os21 from "os";
33430
- import * as path46 from "path";
33431
- import { Command as Command61, Option as Option58 } from "clipanion";
33432
- import { DefaultAzureCredential as DefaultAzureCredential24 } from "@azure/identity";
33695
+ import * as path45 from "path";
33696
+ import { Command as Command62, Option as Option59 } from "clipanion";
33697
+ import { DefaultAzureCredential as DefaultAzureCredential25 } from "@azure/identity";
33433
33698
  init_errors();
33434
33699
 
33435
33700
  // src/lib/bootstrap-ui.ts
33436
- import * as fs40 from "fs";
33701
+ import * as fs39 from "fs";
33437
33702
  import * as net from "net";
33438
33703
  import * as os20 from "os";
33439
- import * as path45 from "path";
33704
+ import * as path44 from "path";
33440
33705
  import { randomBytes as randomBytes3 } from "crypto";
33441
33706
  import { spawn as spawn8, spawnSync as spawnSync6 } from "child_process";
33442
33707
  init_errors();
@@ -33624,11 +33889,11 @@ async function ensureFounderFoundryRole(args) {
33624
33889
  });
33625
33890
  }
33626
33891
  function writeWebEnvLocal(args) {
33627
- const envPath = path45.join(args.repoRoot, "apps", "web", ".env.local");
33892
+ const envPath = path44.join(args.repoRoot, "apps", "web", ".env.local");
33628
33893
  let prior = "";
33629
- if (fs40.existsSync(envPath)) {
33630
- prior = fs40.readFileSync(envPath, "utf8");
33631
- fs40.copyFileSync(envPath, envPath + ".bak");
33894
+ if (fs39.existsSync(envPath)) {
33895
+ prior = fs39.readFileSync(envPath, "utf8");
33896
+ fs39.copyFileSync(envPath, envPath + ".bak");
33632
33897
  }
33633
33898
  const priorSecret = readValidInternalSecret(prior);
33634
33899
  const internalSecret = priorSecret ?? (args.randomBytesImpl ?? randomBytes3)(32).toString("base64url");
@@ -33654,9 +33919,9 @@ function writeWebEnvLocal(args) {
33654
33919
  "NEXT_PUBLIC_M8T_ONBOARDING=1",
33655
33920
  ""
33656
33921
  ].join("\n");
33657
- fs40.writeFileSync(envPath, body, { encoding: "utf8", mode: 384 });
33922
+ fs39.writeFileSync(envPath, body, { encoding: "utf8", mode: 384 });
33658
33923
  try {
33659
- fs40.chmodSync(envPath, 384);
33924
+ fs39.chmodSync(envPath, 384);
33660
33925
  } catch {
33661
33926
  }
33662
33927
  return envPath;
@@ -33672,10 +33937,10 @@ function readValidInternalSecret(envText) {
33672
33937
  return isValidInternalSecret(values[0]) ? values[0] : void 0;
33673
33938
  }
33674
33939
  function readWebInternalSecret(repoRoot) {
33675
- const envPath = path45.join(repoRoot, "apps", "web", ".env.local");
33940
+ const envPath = path44.join(repoRoot, "apps", "web", ".env.local");
33676
33941
  let secret;
33677
33942
  try {
33678
- secret = readValidInternalSecret(fs40.readFileSync(envPath, "utf8"));
33943
+ secret = readValidInternalSecret(fs39.readFileSync(envPath, "utf8"));
33679
33944
  } catch {
33680
33945
  secret = void 0;
33681
33946
  }
@@ -33727,17 +33992,17 @@ async function installWebDeps(repoRoot) {
33727
33992
  await runInherit("pnpm", ["install"], repoRoot, "BOOTSTRAP_UI_INSTALL_FAILED");
33728
33993
  }
33729
33994
  function onboardingUiPaths(home = os20.homedir()) {
33730
- const dir = path45.join(home, ".m8t");
33995
+ const dir = path44.join(home, ".m8t");
33731
33996
  return {
33732
- logPath: path45.join(dir, "onboarding-ui.log"),
33733
- pidPath: path45.join(dir, "onboarding-ui.pid")
33997
+ logPath: path44.join(dir, "onboarding-ui.log"),
33998
+ pidPath: path44.join(dir, "onboarding-ui.pid")
33734
33999
  };
33735
34000
  }
33736
34001
  function onboardingRelayPaths(home = os20.homedir()) {
33737
- const dir = path45.join(home, ".m8t");
34002
+ const dir = path44.join(home, ".m8t");
33738
34003
  return {
33739
- logPath: path45.join(dir, "onboarding-relay.log"),
33740
- pidPath: path45.join(dir, "onboarding-relay.pid")
34004
+ logPath: path44.join(dir, "onboarding-relay.log"),
34005
+ pidPath: path44.join(dir, "onboarding-relay.pid")
33741
34006
  };
33742
34007
  }
33743
34008
  function isLocalPortOpen(port) {
@@ -33759,7 +34024,7 @@ function isLocalPortOpen(port) {
33759
34024
  }
33760
34025
  function removePidFile(pidPath) {
33761
34026
  try {
33762
- fs40.unlinkSync(pidPath);
34027
+ fs39.unlinkSync(pidPath);
33763
34028
  } catch {
33764
34029
  }
33765
34030
  }
@@ -33772,7 +34037,7 @@ function parseManagedPid(text) {
33772
34037
  function readLiveManagedPid(pidPath) {
33773
34038
  let text;
33774
34039
  try {
33775
- text = fs40.readFileSync(pidPath, "utf8").trim();
34040
+ text = fs39.readFileSync(pidPath, "utf8").trim();
33776
34041
  } catch {
33777
34042
  return null;
33778
34043
  }
@@ -33811,8 +34076,8 @@ async function serveOnboardingUiDetached(args) {
33811
34076
  });
33812
34077
  }
33813
34078
  if (managedPid != null) return { alreadyRunning: true, logPath };
33814
- fs40.mkdirSync(path45.dirname(logPath), { recursive: true });
33815
- const fd = fs40.openSync(logPath, "a");
34079
+ fs39.mkdirSync(path44.dirname(logPath), { recursive: true });
34080
+ const fd = fs39.openSync(logPath, "a");
33816
34081
  const child = spawn8("pnpm", ["--filter", "web", "dev"], {
33817
34082
  cwd: args.repoRoot,
33818
34083
  detached: true,
@@ -33821,7 +34086,7 @@ async function serveOnboardingUiDetached(args) {
33821
34086
  // pnpm resolves to pnpm.cmd on Windows, which needs a shell to launch.
33822
34087
  shell: process.platform === "win32"
33823
34088
  });
33824
- fs40.closeSync(fd);
34089
+ fs39.closeSync(fd);
33825
34090
  if (child.pid == null) {
33826
34091
  throw new LocalCliError({
33827
34092
  code: "BOOTSTRAP_UI_DEV_SPAWN_FAILED",
@@ -33830,7 +34095,7 @@ async function serveOnboardingUiDetached(args) {
33830
34095
  });
33831
34096
  }
33832
34097
  child.unref();
33833
- fs40.writeFileSync(pidPath, String(child.pid), "utf8");
34098
+ fs39.writeFileSync(pidPath, String(child.pid), "utf8");
33834
34099
  const deadline = Date.now() + 45e3;
33835
34100
  const sleep5 = (ms) => new Promise((r) => setTimeout(r, ms));
33836
34101
  while (Date.now() < deadline) {
@@ -33862,8 +34127,8 @@ async function serveOnboardingRelayDetached(args) {
33862
34127
  });
33863
34128
  }
33864
34129
  if (managedPid != null) return { alreadyRunning: true, logPath };
33865
- fs40.mkdirSync(path45.dirname(logPath), { recursive: true });
33866
- const fd = fs40.openSync(logPath, "a");
34130
+ fs39.mkdirSync(path44.dirname(logPath), { recursive: true });
34131
+ const fd = fs39.openSync(logPath, "a");
33867
34132
  const child = spawn8("pnpm", ["--filter", "web", "exec", "tsx", "voice-relay-entry.ts"], {
33868
34133
  cwd: args.repoRoot,
33869
34134
  detached: true,
@@ -33881,7 +34146,7 @@ async function serveOnboardingRelayDetached(args) {
33881
34146
  // pnpm resolves to pnpm.cmd on Windows, which needs a shell to launch.
33882
34147
  shell: process.platform === "win32"
33883
34148
  });
33884
- fs40.closeSync(fd);
34149
+ fs39.closeSync(fd);
33885
34150
  if (child.pid == null) {
33886
34151
  throw new LocalCliError({
33887
34152
  code: "BOOTSTRAP_UI_RELAY_SPAWN_FAILED",
@@ -33890,7 +34155,7 @@ async function serveOnboardingRelayDetached(args) {
33890
34155
  });
33891
34156
  }
33892
34157
  child.unref();
33893
- fs40.writeFileSync(pidPath, String(child.pid), "utf8");
34158
+ fs39.writeFileSync(pidPath, String(child.pid), "utf8");
33894
34159
  const deadline = Date.now() + 45e3;
33895
34160
  const sleep5 = (ms) => new Promise((r) => setTimeout(r, ms));
33896
34161
  while (Date.now() < deadline) {
@@ -33912,7 +34177,7 @@ function autoOpenOnboardingUi(url, open3 = tryOpenUrl) {
33912
34177
  function stopPidFile(pidPath) {
33913
34178
  let pidStr;
33914
34179
  try {
33915
- pidStr = fs40.readFileSync(pidPath, "utf8").trim();
34180
+ pidStr = fs39.readFileSync(pidPath, "utf8").trim();
33916
34181
  } catch {
33917
34182
  return false;
33918
34183
  }
@@ -33929,7 +34194,7 @@ function stopPidFile(pidPath) {
33929
34194
  }
33930
34195
  }
33931
34196
  try {
33932
- fs40.unlinkSync(pidPath);
34197
+ fs39.unlinkSync(pidPath);
33933
34198
  } catch {
33934
34199
  }
33935
34200
  return true;
@@ -34256,7 +34521,7 @@ function renderDeployFailure(error) {
34256
34521
  }
34257
34522
  var BootstrapUiCommand = class extends M8tCommand {
34258
34523
  static paths = [["bootstrap", "ui"]];
34259
- static usage = Command61.Usage({
34524
+ static usage = Command62.Usage({
34260
34525
  description: "Deploy Ezra + start the local onboarding chat UI in the background (returns immediately).",
34261
34526
  details: [
34262
34527
  "Run after `m8t bootstrap launch`, in parallel with `status --watch`. Waits for the cloud",
@@ -34277,16 +34542,16 @@ var BootstrapUiCommand = class extends M8tCommand {
34277
34542
  ["Experimental: start the voice relay (no effect on the text-only intake)", "$0 bootstrap ui --repo-root /path/to/m8t --voice"]
34278
34543
  ]
34279
34544
  });
34280
- repoRoot = Option58.String("--repo-root");
34281
- port = Option58.String("--port", "3000");
34282
- endpoint = Option58.String("--endpoint", {
34545
+ repoRoot = Option59.String("--repo-root");
34546
+ port = Option59.String("--port", "3000");
34547
+ endpoint = Option59.String("--endpoint", {
34283
34548
  description: "Foundry project endpoint to target \u2014 overrides discovery when this install's resource group holds more than one Foundry project."
34284
34549
  });
34285
- prepOnly = Option58.Boolean("--prep-only", false);
34286
- skipInstall = Option58.Boolean("--skip-install", false);
34287
- stop = Option58.Boolean("--stop", false);
34288
- foreground = Option58.Boolean("--foreground", false);
34289
- voice = Option58.Boolean("--voice", false, {
34550
+ prepOnly = Option59.Boolean("--prep-only", false);
34551
+ skipInstall = Option59.Boolean("--skip-install", false);
34552
+ stop = Option59.Boolean("--stop", false);
34553
+ foreground = Option59.Boolean("--foreground", false);
34554
+ voice = Option59.Boolean("--voice", false, {
34290
34555
  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."
34291
34556
  });
34292
34557
  async executeCommand() {
@@ -34326,10 +34591,10 @@ var BootstrapUiCommand = class extends M8tCommand {
34326
34591
  this.context.stderr.write(` ${colors.dim(m)}
34327
34592
  `);
34328
34593
  };
34329
- if (fs41.existsSync(path46.join(os21.homedir(), ".m8t", "config.yaml"))) {
34594
+ if (fs40.existsSync(path45.join(os21.homedir(), ".m8t", "config.yaml"))) {
34330
34595
  out(colors.error("\u26A0 an existing ~/.m8t/config.yaml will override the onboarding app registration in apps/web \u2014 if Microsoft sign-in fails, move it aside and retry."));
34331
34596
  }
34332
- const credential2 = new DefaultAzureCredential24();
34597
+ const credential2 = new DefaultAzureCredential25();
34333
34598
  const account = await getAzAccount();
34334
34599
  assertNodeVersion();
34335
34600
  out("waiting for Foundry (the installer's foundry-create phase)\u2026");
@@ -34458,10 +34723,10 @@ var BootstrapUiCommand = class extends M8tCommand {
34458
34723
  };
34459
34724
 
34460
34725
  // src/commands/bootstrap/seed-profile.ts
34461
- import { Command as Command62, Option as Option59 } from "clipanion";
34726
+ import { Command as Command63, Option as Option60 } from "clipanion";
34462
34727
  var BootstrapSeedProfileCommand = class extends M8tCommand {
34463
34728
  static paths = [["bootstrap", "seed-profile"]];
34464
- static usage = Command62.Usage({
34729
+ static usage = Command63.Usage({
34465
34730
  description: "Seed your advisors' brains with the founder + company profile from the onboarding intake.",
34466
34731
  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>/ezra-brain via the GitHub App. Idempotent. --watch polls until the founder finishes the intake.",
34467
34732
  examples: [
@@ -34469,11 +34734,11 @@ var BootstrapSeedProfileCommand = class extends M8tCommand {
34469
34734
  ["Wait for the founder to finish", "$0 bootstrap seed-profile --watch"]
34470
34735
  ]
34471
34736
  });
34472
- endpoint = Option59.String("--endpoint", { description: "Override the Foundry endpoint (else read from the install status)." });
34473
- brain = Option59.String("--brain", { description: "Seed only this one brain repo, instead of both <org>/stacey-brain and <org>/ezra-brain." });
34474
- watch = Option59.Boolean("--watch", false, { description: "Poll until the intake completes (or --timeout)." });
34475
- timeout = Option59.String("--timeout", { description: "Watch timeout in minutes (default 20)." });
34476
- githubAppCreds = Option59.String("--github-app-creds");
34737
+ endpoint = Option60.String("--endpoint", { description: "Override the Foundry endpoint (else read from the install status)." });
34738
+ brain = Option60.String("--brain", { description: "Seed only this one brain repo, instead of both <org>/stacey-brain and <org>/ezra-brain." });
34739
+ watch = Option60.Boolean("--watch", false, { description: "Poll until the intake completes (or --timeout)." });
34740
+ timeout = Option60.String("--timeout", { description: "Watch timeout in minutes (default 20)." });
34741
+ githubAppCreds = Option60.String("--github-app-creds");
34477
34742
  async executeCommand() {
34478
34743
  const ctx = await resolveSeedContext({
34479
34744
  endpointOverride: typeof this.endpoint === "string" ? this.endpoint : void 0,
@@ -34533,10 +34798,10 @@ var BootstrapSeedProfileCommand = class extends M8tCommand {
34533
34798
  };
34534
34799
 
34535
34800
  // src/commands/telemetry/enroll.ts
34536
- import * as fs42 from "fs";
34801
+ import * as fs41 from "fs";
34537
34802
  import * as os22 from "os";
34538
- import * as path47 from "path";
34539
- import { Command as Command63, Option as Option60 } from "clipanion";
34803
+ import * as path46 from "path";
34804
+ import { Command as Command64, Option as Option61 } from "clipanion";
34540
34805
  init_errors();
34541
34806
 
34542
34807
  // src/lib/telemetry-enroll.ts
@@ -34618,7 +34883,7 @@ async function resolveKeyVaultName(containerAppResourceId) {
34618
34883
  }
34619
34884
  var TelemetryEnrollCommand = class extends M8tCommand {
34620
34885
  static paths = [["telemetry", "enroll"]];
34621
- static usage = Command63.Usage({
34886
+ static usage = Command64.Usage({
34622
34887
  description: "Enroll this installation for operational telemetry (pre-existing installs).",
34623
34888
  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.",
34624
34889
  examples: [
@@ -34626,11 +34891,11 @@ var TelemetryEnrollCommand = class extends M8tCommand {
34626
34891
  ["Enroll and share a support contact", "$0 telemetry enroll --contact-email you@example.com --company 'Acme'"]
34627
34892
  ]
34628
34893
  });
34629
- company = Option60.String("--company", { description: "Share your company name with m8t support. Not sent unless you pass it." });
34630
- contactEmail = Option60.String("--contact-email", { description: "Share a contact email with m8t support. Not sent unless you pass it." });
34631
- subscription = Option60.String("--subscription", { description: "Azure subscription id used to find your deployment. Never sent to m8t." });
34632
- resourceGroup = Option60.String("--resource-group", { description: "Resource group to disambiguate discovery, if you have more than one m8t deployment." });
34633
- force = Option60.Boolean("--force", false, { description: "Enroll even when a key is already stored. Use only when m8t support asks you to." });
34894
+ company = Option61.String("--company", { description: "Share your company name with m8t support. Not sent unless you pass it." });
34895
+ contactEmail = Option61.String("--contact-email", { description: "Share a contact email with m8t support. Not sent unless you pass it." });
34896
+ subscription = Option61.String("--subscription", { description: "Azure subscription id used to find your deployment. Never sent to m8t." });
34897
+ resourceGroup = Option61.String("--resource-group", { description: "Resource group to disambiguate discovery, if you have more than one m8t deployment." });
34898
+ force = Option61.Boolean("--force", false, { description: "Enroll even when a key is already stored. Use only when m8t support asks you to." });
34634
34899
  async executeCommand() {
34635
34900
  const account = await getAzAccount();
34636
34901
  const subscriptionId = (typeof this.subscription === "string" ? this.subscription : void 0) ?? account.subscriptionId;
@@ -34663,13 +34928,13 @@ var TelemetryEnrollCommand = class extends M8tCommand {
34663
34928
  ...company ? { company } : {},
34664
34929
  ...contactEmail ? { contactEmail } : {}
34665
34930
  });
34666
- const keyDir = fs42.mkdtempSync(path47.join(os22.tmpdir(), "m8t-ingest-key-"));
34667
- const keyFile = path47.join(keyDir, "key");
34931
+ const keyDir = fs41.mkdtempSync(path46.join(os22.tmpdir(), "m8t-ingest-key-"));
34932
+ const keyFile = path46.join(keyDir, "key");
34668
34933
  try {
34669
- fs42.writeFileSync(keyFile, ingestKey, { mode: 384 });
34934
+ fs41.writeFileSync(keyFile, ingestKey, { mode: 384 });
34670
34935
  await runAz(["keyvault", "secret", "set", "--vault-name", kvName, "--name", INGEST_KEY_SECRET, "--file", keyFile, "--only-show-errors"]);
34671
34936
  } finally {
34672
- fs42.rmSync(keyDir, { recursive: true, force: true });
34937
+ fs41.rmSync(keyDir, { recursive: true, force: true });
34673
34938
  }
34674
34939
  this.context.stdout.write(
34675
34940
  `${colors.success("\u2713")} enrolled (instance ${instanceId}); ingest key stored in Key Vault ${kvName}. The gateway picks it up on its next cycle.
@@ -34680,7 +34945,7 @@ var TelemetryEnrollCommand = class extends M8tCommand {
34680
34945
  };
34681
34946
 
34682
34947
  // src/commands/companion/bridge.ts
34683
- import { Command as Command64, Option as Option61 } from "clipanion";
34948
+ import { Command as Command65, Option as Option62 } from "clipanion";
34684
34949
 
34685
34950
  // ../../packages/companion-bridge-contract/src/index.ts
34686
34951
  var COMPANION_MESSAGE_MAX_CODE_POINTS = 32768;
@@ -36136,14 +36401,14 @@ async function runCompanionBridge(stdin, stdout, stderr, deps = defaultDeps4) {
36136
36401
  return 3;
36137
36402
  }
36138
36403
  }
36139
- var CompanionBridgeCommand = class extends Command64 {
36404
+ var CompanionBridgeCommand = class extends Command65 {
36140
36405
  static paths = [["companion", "_bridge"]];
36141
36406
  /**
36142
36407
  * One process serving many requests instead of one per request, so the
36143
36408
  * session keeps its authenticated context between them. A CLI predating the
36144
36409
  * flag rejects it outright, which is how the app knows to fall back.
36145
36410
  */
36146
- serve = Option61.Boolean("--serve", false);
36411
+ serve = Option62.Boolean("--serve", false);
36147
36412
  async execute() {
36148
36413
  if (this.serve) {
36149
36414
  return runCompanionBridgeServe(
@@ -36161,7 +36426,7 @@ var CompanionBridgeCommand = class extends Command64 {
36161
36426
  };
36162
36427
 
36163
36428
  // src/commands/companion/status.ts
36164
- import { Command as Command65 } from "clipanion";
36429
+ import { Command as Command66 } from "clipanion";
36165
36430
  async function withTimeout(work, ms) {
36166
36431
  let timer;
36167
36432
  try {
@@ -36233,7 +36498,7 @@ Run: m8t companion install
36233
36498
  }
36234
36499
  var CompanionStatusCommand = class extends M8tCommand {
36235
36500
  static paths = [["companion", "status"]];
36236
- static usage = Command65.Usage({
36501
+ static usage = Command66.Usage({
36237
36502
  description: "Verify the installed desktop companion without launching it."
36238
36503
  });
36239
36504
  async executeCommand() {
@@ -36247,7 +36512,7 @@ var CompanionStatusCommand = class extends M8tCommand {
36247
36512
  };
36248
36513
 
36249
36514
  // src/commands/companion/repair.ts
36250
- import { Command as Command66, Option as Option62 } from "clipanion";
36515
+ import { Command as Command67, Option as Option63 } from "clipanion";
36251
36516
  async function runCompanionRepairCommand(stdout, repair) {
36252
36517
  const state = await repair();
36253
36518
  if (state.state === "not-released") {
@@ -36266,10 +36531,10 @@ async function runCompanionRepairCommand(stdout, repair) {
36266
36531
  }
36267
36532
  var CompanionRepairCommand = class extends M8tCommand {
36268
36533
  static paths = [["companion", "repair"]];
36269
- static usage = Command66.Usage({
36534
+ static usage = Command67.Usage({
36270
36535
  description: "Restore the desktop companions and start-at-login state."
36271
36536
  });
36272
- resourceGroup = Option62.String("--resource-group", {
36537
+ resourceGroup = Option63.String("--resource-group", {
36273
36538
  description: "Which deployment to bind to, when the subscription holds more than one."
36274
36539
  });
36275
36540
  async executeCommand() {
@@ -36283,7 +36548,7 @@ var CompanionRepairCommand = class extends M8tCommand {
36283
36548
  };
36284
36549
 
36285
36550
  // src/commands/companion/uninstall.ts
36286
- import { Command as Command67 } from "clipanion";
36551
+ import { Command as Command68 } from "clipanion";
36287
36552
  async function runCompanionUninstallCommand(stdout, uninstall) {
36288
36553
  const state = await uninstall();
36289
36554
  if (state.state !== "not-installed") {
@@ -36295,7 +36560,7 @@ async function runCompanionUninstallCommand(stdout, uninstall) {
36295
36560
  }
36296
36561
  var CompanionUninstallCommand = class extends M8tCommand {
36297
36562
  static paths = [["companion", "uninstall"]];
36298
- static usage = Command67.Usage({
36563
+ static usage = Command68.Usage({
36299
36564
  description: "Remove only this user's desktop companion installation."
36300
36565
  });
36301
36566
  async executeCommand() {
@@ -36352,8 +36617,9 @@ cli.register(AzureExecDeployCommand);
36352
36617
  cli.register(PlatformStatusCommand);
36353
36618
  cli.register(PlatformUpdateCommand);
36354
36619
  cli.register(PlatformConvergeCommand);
36620
+ cli.register(PlatformClearIntentCommand);
36621
+ cli.register(PlatformRequestUpdateCommand);
36355
36622
  cli.register(PlatformSeedStampCommand);
36356
- cli.register(PlatformStampBuildCommand);
36357
36623
  cli.register(PlatformPolicyCommand);
36358
36624
  cli.register(PlatformEnableCostReportCommand);
36359
36625
  cli.register(PlatformEnableAutoUpdateCommand);