@m8t-stack/cli 0.2.34 → 0.2.35

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
@@ -1247,7 +1247,7 @@ var init_enable_hosted_brain = __esm({
1247
1247
  import { Builtins, Cli } from "clipanion";
1248
1248
 
1249
1249
  // src/lib/package-version.ts
1250
- var CLI_VERSION = "0.2.34";
1250
+ var CLI_VERSION = "0.2.35";
1251
1251
 
1252
1252
  // src/lib/render-error.ts
1253
1253
  init_errors();
@@ -1444,6 +1444,7 @@ var BACKEND_RULES = [
1444
1444
  var LOCAL_RULES = {
1445
1445
  AGENT_CREATE_VERSION_FAILED: "Re-run with `--verbose` for the full response body.",
1446
1446
  AGENT_CREATE_VERSION_NO_VERSION: "Foundry returned 2xx but no version \u2014 likely an API regression. Re-try; if it persists, file an issue.",
1447
+ AGENT_ENDPOINT_AUTH_PATCH_FAILED: "Re-run with `--verbose` for the full response body.",
1447
1448
  AGENT_GET_FAILED: "Re-run with `--verbose` for the full response body.",
1448
1449
  AGENT_NOT_FOUND: "Use `m8t brain create <name>` to create the worker first, OR run `m8t deploy <name>` to register an existing agent.",
1449
1450
  AGENT_REDEPLOY_FAILED: "Re-run with `--verbose` for the full response body.",
@@ -13917,8 +13918,27 @@ ${text.slice(0, 500)}` });
13917
13918
  }
13918
13919
  const data = await res.json();
13919
13920
  if (!data.version) throw new LocalCliError({ code: "AGENT_CREATE_VERSION_NO_VERSION", message: "createVersion returned no version" });
13921
+ await ensureAgentEndpointEntraIsolation(
13922
+ { credential: args.credential, projectEndpoint: args.projectEndpoint, agentName: args.agentName, extraHeaders: args.extraHeaders },
13923
+ fetchImpl
13924
+ );
13920
13925
  return data.version;
13921
13926
  }
13927
+ async function ensureAgentEndpointEntraIsolation(args, fetchImpl = fetch) {
13928
+ const token = await args.credential.getToken(FOUNDRY_DATA_SCOPE);
13929
+ if (!token?.token) throw new LocalCliError({ code: "FOUNDRY_AUTH", message: "Could not acquire Foundry data-plane token" });
13930
+ const url = `${args.projectEndpoint}/agents/${args.agentName}?api-version=v1`;
13931
+ const res = await fetchImpl(url, {
13932
+ method: "PATCH",
13933
+ headers: { Authorization: `Bearer ${token.token}`, "Content-Type": "application/json", ...args.extraHeaders ?? {} },
13934
+ body: JSON.stringify({ agent_endpoint: { authorization_schemes: [{ type: "Entra", isolation_key_source: { kind: "Entra" } }] } })
13935
+ });
13936
+ if (!res.ok) {
13937
+ const text = await res.text();
13938
+ throw new LocalCliError({ code: "AGENT_ENDPOINT_AUTH_PATCH_FAILED", message: `PATCH ${url}: HTTP ${res.status.toString()}
13939
+ ${text.slice(0, 500)}` });
13940
+ }
13941
+ }
13922
13942
 
13923
13943
  // src/lib/brain-link.ts
13924
13944
  init_brain_yaml_mirror();
@@ -15223,7 +15243,6 @@ import * as os5 from "os";
15223
15243
  import * as path11 from "path";
15224
15244
  init_foundry_agent_get();
15225
15245
  var FOUNDRY_ARM_API2 = "2025-04-01-preview";
15226
- var FOUNDRY_DATA_SCOPE2 = "https://ai.azure.com/.default";
15227
15246
  var ARM_SCOPE5 = "https://management.azure.com/.default";
15228
15247
  var GITHUB_APP_API = "https://api.github.com";
15229
15248
  async function unlinkBrain(args) {
@@ -15309,10 +15328,6 @@ function parseBrainMeta(raw) {
15309
15328
  }
15310
15329
  }
15311
15330
  async function createBrainStrippedVersion(args) {
15312
- const fndToken = await args.credential.getToken(FOUNDRY_DATA_SCOPE2);
15313
- if (!fndToken?.token) {
15314
- throw new LocalCliError({ code: "FOUNDRY_AUTH", message: "Could not acquire Foundry data-plane token" });
15315
- }
15316
15331
  const otherTools = (args.currentDefinition.tools ?? []).filter(
15317
15332
  (t) => !(t.type === "mcp" && t.server_label === "brain")
15318
15333
  );
@@ -15325,28 +15340,13 @@ async function createBrainStrippedVersion(args) {
15325
15340
  ...args.currentMetadata,
15326
15341
  brain: ""
15327
15342
  };
15328
- const url = `${args.projectEndpoint}/agents/${args.agentName}/versions?api-version=v1`;
15329
- const res = await fetch(url, {
15330
- method: "POST",
15331
- headers: { Authorization: `Bearer ${fndToken.token}`, "Content-Type": "application/json" },
15332
- body: JSON.stringify({ definition, metadata })
15343
+ return createAgentVersion({
15344
+ credential: args.credential,
15345
+ projectEndpoint: args.projectEndpoint,
15346
+ agentName: args.agentName,
15347
+ definition,
15348
+ metadata
15333
15349
  });
15334
- if (!res.ok) {
15335
- const text = await res.text();
15336
- throw new LocalCliError({
15337
- code: "AGENT_CREATE_VERSION_FAILED",
15338
- message: `POST ${url}: HTTP ${res.status.toString()}
15339
- ${text.slice(0, 500)}`
15340
- });
15341
- }
15342
- const data = await res.json();
15343
- if (!data.version) {
15344
- throw new LocalCliError({
15345
- code: "AGENT_REDEPLOY_NO_VERSION",
15346
- message: "createVersion returned no version"
15347
- });
15348
- }
15349
- return data.version;
15350
15350
  }
15351
15351
  async function deleteConnection(args) {
15352
15352
  const armToken = await args.credential.getToken(ARM_SCOPE5);
@@ -25668,7 +25668,7 @@ var EVENT_TIERS = {
25668
25668
  var EVENT_ENUM = Object.keys(EVENT_TIERS);
25669
25669
 
25670
25670
  // ../../packages/telemetry-contract/src/disclosure.ts
25671
- var DISCLOSURE_TIER1 = "Operational data. To support your installation, m8t receives limited operational data linked to it \u2014 installation and update events, installed versions, and service health signals, along with the company name and contact email you provide. At enrollment, we also verify a cloud identity token to confirm the request comes from a real cloud account; the token is discarded immediately and never stored. This is service data used only to operate and support the platform; it contains none of your content. Details: TELEMETRY.md.";
25671
+ var DISCLOSURE_TIER1 = "Operational data. To support your installation, m8t receives limited operational data linked to it \u2014 installation and update events, installed versions, and service health signals. Your installation is identified only by a random installation ID we generate at setup \u2014 an opaque value with no information encoded in it. No name, email, company, or subscription information is sent in the enrollment record unless you explicitly choose to share contact details for support. At enrollment, we also verify a cloud identity token to confirm the request comes from a real cloud account; that token names the account making the request, and is otherwise discarded immediately and never stored. This is service data used only to operate and support the platform; it contains none of your content. Details: TELEMETRY.md.";
25672
25672
 
25673
25673
  // ../../packages/telemetry-contract/src/endpoints.ts
25674
25674
  var INGEST_BASE_URL = (process.env.M8T_INGEST_BASE_URL ?? "").trim() || "https://m8t-admin.wonderfuldesert-721e332f.eastus2.azurecontainerapps.io";
@@ -25928,6 +25928,7 @@ function buildAciCreateArgs(s) {
25928
25928
  if (s.foundryTracing) env.push(`FOUNDRY_TRACING=${s.foundryTracing}`);
25929
25929
  if (s.updateChannelUrl) env.push(`M8T_UPDATE_CHANNEL_URL=${s.updateChannelUrl}`);
25930
25930
  if (s.enrollContactEmail) env.push(`M8T_ENROLL_CONTACT_EMAIL=${s.enrollContactEmail}`);
25931
+ if (s.enrollCompany) env.push(`M8T_ENROLL_COMPANY=${s.enrollCompany}`);
25931
25932
  if (s.githubApp) {
25932
25933
  const g = s.githubApp;
25933
25934
  env.push(
@@ -26078,7 +26079,7 @@ async function writeBootstrapState(state, home = os13.homedir()) {
26078
26079
  // src/commands/bootstrap/launch.ts
26079
26080
  var DEFAULT_RG = "rg-m8t-stack";
26080
26081
  var DEFAULT_INSTALLER = "ghcr.io/m8t-labs/m8t-installer";
26081
- var DEFAULT_INSTALLER_TAG = "v0.1.40";
26082
+ var DEFAULT_INSTALLER_TAG = "v0.1.41";
26082
26083
  var ACI_NAME = "m8t-installer";
26083
26084
  var MI_NAME = "m8t-installer-mi";
26084
26085
  var BootstrapLaunchCommand = class extends M8tCommand {
@@ -26090,7 +26091,8 @@ var BootstrapLaunchCommand = class extends M8tCommand {
26090
26091
  ["Launch in eastus2", "$0 bootstrap launch --location eastus2"],
26091
26092
  ["BYO app registration", "$0 bootstrap launch --location eastus2 --client-id <appId>"],
26092
26093
  ["Pin a specific installer tag", "$0 bootstrap launch --location eastus2 --installer-tag v0.1.33"],
26093
- ["Override the full installer image ref", "$0 bootstrap launch --location eastus2 --installer-image ghcr.io/m8t-labs/m8t-installer:v0.1.33"]
26094
+ ["Override the full installer image ref", "$0 bootstrap launch --location eastus2 --installer-image ghcr.io/m8t-labs/m8t-installer:v0.1.33"],
26095
+ ["Share a support contact", "$0 bootstrap launch --location eastus2 --contact-email you@example.com --company 'Acme'"]
26094
26096
  ]
26095
26097
  });
26096
26098
  location = Option47.String("--location");
@@ -26104,6 +26106,8 @@ var BootstrapLaunchCommand = class extends M8tCommand {
26104
26106
  installerImage = Option47.String("--installer-image");
26105
26107
  gatewayImageRef = Option47.String("--gateway-image-ref");
26106
26108
  githubAppCreds = Option47.String("--github-app-creds");
26109
+ contactEmail = Option47.String("--contact-email", { description: "Share a contact email with m8t support. Not sent unless you pass it." });
26110
+ company = Option47.String("--company", { description: "Share your company name with m8t support. Not sent unless you pass it." });
26107
26111
  async executeCommand() {
26108
26112
  const location = typeof this.location === "string" ? this.location : void 0;
26109
26113
  if (!location) {
@@ -26195,7 +26199,11 @@ var BootstrapLaunchCommand = class extends M8tCommand {
26195
26199
  gatewayImageRef,
26196
26200
  foundryTracing: "skip",
26197
26201
  githubApp,
26198
- enrollContactEmail: account.upn,
26202
+ // Opt-in only. The signed-in UPN was previously seeded here automatically;
26203
+ // an installation is identified by its random instance id, and contact
26204
+ // details are sent only when the operator asks for them.
26205
+ ...typeof this.contactEmail === "string" ? { enrollContactEmail: this.contactEmail } : {},
26206
+ ...typeof this.company === "string" ? { enrollCompany: this.company } : {},
26199
26207
  ...process.env.M8T_UPDATE_CHANNEL_URL ? { updateChannelUrl: process.env.M8T_UPDATE_CHANNEL_URL } : {}
26200
26208
  });
26201
26209
  this.context.stdout.write(
@@ -28040,13 +28048,13 @@ async function enroll(args) {
28040
28048
  const url = args.baseUrl ? `${args.baseUrl.replace(/\/+$/, "")}/api/ingest/enroll` : ingestUrl("/api/ingest/enroll");
28041
28049
  const retryDelayMs = args.retryDelayMs ?? 1e3;
28042
28050
  const token = await (args.tokenImpl ?? defaultToken)().catch(() => null);
28043
- const body = JSON.stringify({
28044
- schemaVersion: 1,
28045
- company: args.company,
28046
- contactEmail: args.contactEmail,
28047
- subscriptionId: args.subscriptionId,
28048
- proof: token ? { type: "entra-jwt", token } : null
28049
- });
28051
+ const payload = { schemaVersion: 1 };
28052
+ const company = args.company?.trim();
28053
+ if (company) payload.company = company;
28054
+ const contactEmail = args.contactEmail?.trim();
28055
+ if (contactEmail) payload.contactEmail = contactEmail;
28056
+ payload.proof = token ? { type: "entra-jwt", token } : null;
28057
+ const body = JSON.stringify(payload);
28050
28058
  let res;
28051
28059
  for (let attempt = 1; attempt <= 3; attempt++) {
28052
28060
  try {
@@ -28099,19 +28107,22 @@ var TelemetryEnrollCommand = class extends M8tCommand {
28099
28107
  static paths = [["telemetry", "enroll"]];
28100
28108
  static usage = Command56.Usage({
28101
28109
  description: "Enroll this installation for operational telemetry (pre-existing installs).",
28102
- details: "Mints 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. Idempotent: refuses if a key already exists unless --force.",
28103
- examples: [["Enroll", "$0 telemetry enroll"]]
28110
+ 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.",
28111
+ examples: [
28112
+ ["Enroll", "$0 telemetry enroll"],
28113
+ ["Enroll and share a support contact", "$0 telemetry enroll --contact-email you@example.com --company 'Acme'"]
28114
+ ]
28104
28115
  });
28105
- company = Option53.String("--company", { description: "Your company name (optional)." });
28106
- contactEmail = Option53.String("--contact-email", { description: "Contact email (default: your signed-in az UPN)." });
28107
- subscription = Option53.String("--subscription", { description: "Azure subscription id (default: your active az subscription)." });
28116
+ company = Option53.String("--company", { description: "Share your company name with m8t support. Not sent unless you pass it." });
28117
+ contactEmail = Option53.String("--contact-email", { description: "Share a contact email with m8t support. Not sent unless you pass it." });
28118
+ subscription = Option53.String("--subscription", { description: "Azure subscription id used to find your deployment. Never sent to m8t." });
28108
28119
  resourceGroup = Option53.String("--resource-group", { description: "Resource group to disambiguate discovery, if you have more than one m8t deployment." });
28109
- force = Option53.Boolean("--force", false, { description: "Re-enroll even if a key is already stored (mints a new instance id)." });
28120
+ force = Option53.Boolean("--force", false, { description: "Enroll even when a key is already stored. Use only when m8t support asks you to." });
28110
28121
  async executeCommand() {
28111
28122
  const account = await getAzAccount();
28112
28123
  const subscriptionId = (typeof this.subscription === "string" ? this.subscription : void 0) ?? account.subscriptionId;
28113
- const contactEmail = (typeof this.contactEmail === "string" ? this.contactEmail : void 0) ?? account.upn;
28114
- const company = (typeof this.company === "string" ? this.company : void 0) ?? "";
28124
+ const contactEmail = typeof this.contactEmail === "string" ? this.contactEmail : void 0;
28125
+ const company = typeof this.company === "string" ? this.company : void 0;
28115
28126
  const d = await discoverGateway({
28116
28127
  subscriptionId,
28117
28128
  interactive: false,
@@ -28127,14 +28138,18 @@ var TelemetryEnrollCommand = class extends M8tCommand {
28127
28138
  existing = "";
28128
28139
  }
28129
28140
  if (existing.trim()) {
28141
+ const wantedContact = contactEmail !== void 0 || company !== void 0;
28130
28142
  throw new LocalCliError({
28131
28143
  code: "TELEMETRY_ALREADY_ENROLLED",
28132
- message: "This installation is already enrolled.",
28133
- hint: "Pass --force to re-enroll (mints a new instance id)."
28144
+ message: wantedContact ? "This installation is already enrolled, so contact details can't be attached from here." : "This installation is already enrolled.",
28145
+ hint: "To add or change the contact details on your record, reach out through the channels in SUPPORT.md and we'll update it for you."
28134
28146
  });
28135
28147
  }
28136
28148
  }
28137
- const { instanceId, ingestKey } = await enroll({ company, contactEmail, subscriptionId });
28149
+ const { instanceId, ingestKey } = await enroll({
28150
+ ...company ? { company } : {},
28151
+ ...contactEmail ? { contactEmail } : {}
28152
+ });
28138
28153
  const keyDir = fs34.mkdtempSync(path37.join(os19.tmpdir(), "m8t-ingest-key-"));
28139
28154
  const keyFile = path37.join(keyDir, "key");
28140
28155
  try {