@m8t-stack/cli 0.2.76 → 0.2.78

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/README.md CHANGED
@@ -85,7 +85,7 @@ m8t companion uninstall # remove the app, the login item, and the records
85
85
  their own software with their own version: each platform release names the companion build
86
86
  it carries, and these commands fetch it, check it against the digest the release pinned,
87
87
  and verify every file of what they wrote. See
88
- [`guides/install/companion.md`](../../guides/install/companion.md).
88
+ [`guides/install/companion.md`](https://github.com/m8t-labs/ezra/blob/main/guides/install/companion.md).
89
89
 
90
90
  ### `--subscription <id>` flag
91
91
 
package/dist/cli.js CHANGED
@@ -1390,7 +1390,7 @@ var init_enable_hosted_brain = __esm({
1390
1390
  import { Builtins, Cli } from "clipanion";
1391
1391
 
1392
1392
  // src/lib/package-version.ts
1393
- var CLI_VERSION = "0.2.76";
1393
+ var CLI_VERSION = "0.2.78";
1394
1394
 
1395
1395
  // src/lib/render-error.ts
1396
1396
  init_errors();
@@ -15005,6 +15005,21 @@ function tryResolveRepoRoot() {
15005
15005
  const root = fs5.readFileSync(marker, "utf8").trim();
15006
15006
  return root.length > 0 ? root : null;
15007
15007
  }
15008
+ function assertPlatformCheckout(repoRoot, operation, needs = ["personas"]) {
15009
+ const missing = needs.filter((d) => !fs5.existsSync(path6.join(repoRoot, d)));
15010
+ if (missing.length === 0) return;
15011
+ const isAgentRepo = fs5.existsSync(path6.join(repoRoot, "agent", "persona.md"));
15012
+ throw new LocalCliError({
15013
+ code: "PLATFORM_CHECKOUT_REQUIRED",
15014
+ message: `${operation} needs a platform checkout, but ~/.m8t/repo-root points at '${repoRoot}', which has no ${missing.join("/ or ")}/.` + (isAgentRepo ? " That path is the agent repository \u2014 it carries the install runbook, not the platform." : ""),
15015
+ hint: "This operation reads platform content that is not published today, so it is maintainer-side for now. Your installation still updates itself: the auto-update rail applies published releases without needing any checkout."
15016
+ });
15017
+ }
15018
+ function resolvePlatformRepoRoot(operation, needs) {
15019
+ const root = resolveRepoRoot();
15020
+ assertPlatformCheckout(root, operation, needs);
15021
+ return root;
15022
+ }
15008
15023
  function resolveRepoRoot() {
15009
15024
  const root = tryResolveRepoRoot();
15010
15025
  if (root === null) {
@@ -16049,7 +16064,7 @@ async function derivePin(args) {
16049
16064
 
16050
16065
  // src/lib/brain-seed.ts
16051
16066
  function resolveSeed(name) {
16052
- const root = resolveRepoRoot();
16067
+ const root = resolvePlatformRepoRoot("Seeding a brain", ["brain-seeds"]);
16053
16068
  const dir = path13.join(root, "brain-seeds", name);
16054
16069
  if (!fs13.existsSync(dir)) {
16055
16070
  throw new LocalCliError({
@@ -16651,7 +16666,7 @@ var BrainCreateCommand = class extends M8tCommand {
16651
16666
  endpoint: typeof this.endpoint === "string" ? this.endpoint : void 0,
16652
16667
  agentEndpoint
16653
16668
  });
16654
- const repoRoot = resolveRepoRoot();
16669
+ const repoRoot = resolvePlatformRepoRoot("'m8t brain create'", ["brain-template"]);
16655
16670
  const templateSrc = path14.join(repoRoot, "brain-template");
16656
16671
  if (!fs14.existsSync(templateSrc)) {
16657
16672
  throw new LocalCliError({
@@ -16953,7 +16968,7 @@ var BrainLinkCommand = class extends M8tCommand {
16953
16968
  agentName: this.worker,
16954
16969
  repo,
16955
16970
  branch,
16956
- repoRoot: resolveRepoRoot(),
16971
+ repoRoot: resolvePlatformRepoRoot("'m8t brain link'"),
16957
16972
  installationId,
16958
16973
  // Clipanion leaves a truthy Option descriptor here until argv is parsed
16959
16974
  // (tests set the literal boolean). `!== true` keeps the idempotent default
@@ -17722,7 +17737,7 @@ var AgentDeployAdvisorCommand = class extends M8tCommand {
17722
17737
  interactive,
17723
17738
  endpoint: typeof this.endpoint === "string" ? this.endpoint : void 0
17724
17739
  });
17725
- const repoRoot = (typeof this.repoRootFlag === "string" ? this.repoRootFlag : void 0) ?? resolveRepoRoot();
17740
+ const repoRoot = (typeof this.repoRootFlag === "string" ? this.repoRootFlag : void 0) ?? resolvePlatformRepoRoot("'m8t agent deploy-advisor'");
17726
17741
  onProgress?.(`deploying advisor '${persona}' as '${agentName}'\u2026`);
17727
17742
  const version = await deployPromptAdvisor({
17728
17743
  credential: credential2,
@@ -18448,11 +18463,11 @@ var A2aEnableCommand = class extends M8tCommand {
18448
18463
  resolvePersonaPath() {
18449
18464
  if (typeof this.persona === "string" && this.persona.length > 0) {
18450
18465
  if (this.persona.includes("/") || this.persona.endsWith(".md")) return this.persona;
18451
- return path18.join(resolveRepoRoot(), "personas", this.persona, "persona.md");
18466
+ return path18.join(resolvePlatformRepoRoot("'m8t a2a enable'"), "personas", this.persona, "persona.md");
18452
18467
  }
18453
18468
  const yaml = readAgentYaml(this.worker);
18454
18469
  if (yaml?.personaPath) {
18455
- return yaml.personaPath.startsWith("/") ? yaml.personaPath : path18.join(resolveRepoRoot(), yaml.personaPath);
18470
+ return yaml.personaPath.startsWith("/") ? yaml.personaPath : path18.join(resolvePlatformRepoRoot("'m8t a2a enable'"), yaml.personaPath);
18456
18471
  }
18457
18472
  throw new LocalCliError({ code: "A2A_NO_PERSONA", message: `Could not resolve a persona for '${this.worker}'. Pass --persona <name>.` });
18458
18473
  }
@@ -18587,7 +18602,7 @@ function resolveSidecar() {
18587
18602
  }
18588
18603
  function checkArchitectDrift() {
18589
18604
  const sourcePath = path19.join(
18590
- resolveRepoRoot(),
18605
+ resolvePlatformRepoRoot("Rendering the architect skill"),
18591
18606
  "personas",
18592
18607
  "m8t-architect",
18593
18608
  "persona.md"
@@ -19424,7 +19439,7 @@ var CoderDeployCommand = class extends M8tCommand {
19424
19439
  projectEndpoint: project.endpoint,
19425
19440
  projectArmId: `${project.accountScope}/projects/${project.projectName}`,
19426
19441
  agentName: this.name,
19427
- personaPath: path23.join(resolveRepoRoot(), "personas", personaName, "persona.md"),
19442
+ personaPath: path23.join(resolvePlatformRepoRoot("'m8t coder deploy'"), "personas", personaName, "persona.md"),
19428
19443
  bridgeUrl,
19429
19444
  onProgress
19430
19445
  });
@@ -19827,7 +19842,7 @@ var AzureExecDeployCommand = class extends M8tCommand {
19827
19842
  kvUri
19828
19843
  });
19829
19844
  onProgress?.("a2a-enabling as a target\u2026");
19830
- const personaPath = path24.join(resolveRepoRoot(), "personas", "azure-executor", "persona.md");
19845
+ const personaPath = path24.join(resolvePlatformRepoRoot("'m8t azure-exec deploy'"), "personas", "azure-executor", "persona.md");
19831
19846
  const bridgeUrl = resolveBridgeUrl({
19832
19847
  flag: typeof this.gatewayUrl === "string" ? this.gatewayUrl : void 0,
19833
19848
  env: processEnv
@@ -20184,16 +20199,18 @@ function entityToStamp(e) {
20184
20199
  }
20185
20200
 
20186
20201
  // ../../packages/platform-release/dist/esm/channel-url.js
20187
- var CHANNEL_LATEST_URL = "https://github.com/m8t-labs/m8t/releases/latest/download/manifest.json";
20202
+ var RELEASES_REPO = "m8t-labs/m8t-releases";
20203
+ var RELEASES_BASE = `https://github.com/${RELEASES_REPO}/releases`;
20204
+ var CHANNEL_LATEST_URL = `${RELEASES_BASE}/latest/download/manifest.json`;
20188
20205
  function platformTag(version) {
20189
20206
  const bare = version.trim().replace(/^platform-/, "").replace(/^v/, "");
20190
20207
  return `platform-v${bare}`;
20191
20208
  }
20192
20209
  function channelUrlForVersion(version) {
20193
- return `https://github.com/m8t-labs/m8t/releases/download/${platformTag(version)}/manifest.json`;
20210
+ return `${RELEASES_BASE}/download/${platformTag(version)}/manifest.json`;
20194
20211
  }
20195
20212
  function releaseAssetUrl(tag, asset) {
20196
- return `https://github.com/m8t-labs/m8t/releases/download/${tag}/${asset}`;
20213
+ return `${RELEASES_BASE}/download/${tag}/${asset}`;
20197
20214
  }
20198
20215
 
20199
20216
  // ../../packages/platform-release/dist/esm/apply-request.js
@@ -20298,6 +20315,11 @@ import * as os9 from "os";
20298
20315
  import * as path25 from "path";
20299
20316
  init_errors();
20300
20317
  var OWNER_REPO = "m8t-labs/m8t";
20318
+ function platformRepoUnavailable(what, url, status) {
20319
+ return `${what} needs access to ${OWNER_REPO}, which answered HTTP ${status.toString()} (${url}).
20320
+ That repository is private, so this command is maintainer-side for now.
20321
+ Your installation still updates itself: the auto-update rail applies published releases from the channel without reading this repository.`;
20322
+ }
20301
20323
  function parseTreeResponse(body) {
20302
20324
  const map = /* @__PURE__ */ new Map();
20303
20325
  for (const e of body.tree ?? []) if (e.type === "tree") map.set(e.path, e.sha);
@@ -20317,7 +20339,10 @@ async function fetchRepoTree(commit, deps = {}) {
20317
20339
  headers: { Accept: "application/vnd.github+json", ...token ? { Authorization: `Bearer ${token}` } : {} }
20318
20340
  });
20319
20341
  if (!res.ok) {
20320
- throw new LocalCliError({ code: "PLATFORM_TREE_FETCH_FAILED", message: `GET ${url} \u2192 HTTP ${res.status.toString()}.` });
20342
+ throw new LocalCliError({
20343
+ code: "PLATFORM_TREE_FETCH_FAILED",
20344
+ message: platformRepoUnavailable("Verifying persona trees", url, res.status)
20345
+ });
20321
20346
  }
20322
20347
  return parseTreeResponse(await res.json());
20323
20348
  }
@@ -20358,7 +20383,10 @@ async function resolveReleaseContent(manifest, opts = {}) {
20358
20383
  const url = `https://api.github.com/repos/${OWNER_REPO}/tarball/${commit}`;
20359
20384
  const res = await fetchImpl(url, { headers: token ? { Authorization: `Bearer ${token}` } : {} });
20360
20385
  if (!res.ok) {
20361
- throw new LocalCliError({ code: "PLATFORM_TARBALL_FETCH_FAILED", message: `GET ${url} \u2192 HTTP ${res.status.toString()}.` });
20386
+ throw new LocalCliError({
20387
+ code: "PLATFORM_TARBALL_FETCH_FAILED",
20388
+ message: platformRepoUnavailable("Resolving release content", url, res.status)
20389
+ });
20362
20390
  }
20363
20391
  fs24.mkdirSync(cacheRoot, { recursive: true });
20364
20392
  const tmp = fs24.mkdtempSync(path25.join(cacheRoot, `.dl-${commit.slice(0, 8)}-`));
@@ -20601,10 +20629,10 @@ function buildBicepParams(p) {
20601
20629
  }
20602
20630
  async function resolveRepoRoot2(home = os10.homedir()) {
20603
20631
  const marker = path26.join(home, ".m8t", "repo-root");
20632
+ let root;
20604
20633
  try {
20605
- const root = (await fs25.readFile(marker, "utf8")).trim();
20634
+ root = (await fs25.readFile(marker, "utf8")).trim();
20606
20635
  if (!root) throw new Error("empty");
20607
- return root;
20608
20636
  } catch {
20609
20637
  throw new LocalCliError({
20610
20638
  code: "DEPLOY_NO_REPO_ROOT",
@@ -20612,6 +20640,8 @@ async function resolveRepoRoot2(home = os10.homedir()) {
20612
20640
  hint: "Run 'm8t install' from an m8t checkout (it writes the marker), or run 'm8t deploy' from the repo."
20613
20641
  });
20614
20642
  }
20643
+ assertPlatformCheckout(root, "'m8t deploy'", ["deploy"]);
20644
+ return root;
20615
20645
  }
20616
20646
  async function resolveFoundryResourceId(endpoint, explicit) {
20617
20647
  if (explicit) return explicit;
@@ -22277,6 +22307,25 @@ async function patchApplyRequest(client, mutate) {
22277
22307
  await client.updateEntity({ ...applyRequestToEntity(next), etag: cur.etag }, "Merge", { etag: cur.etag });
22278
22308
  }
22279
22309
 
22310
+ // src/lib/rail-preconditions.ts
22311
+ init_errors();
22312
+ function assertBakedContentPresent(repoRoot) {
22313
+ if (repoRoot !== null) return;
22314
+ throw new LocalCliError({
22315
+ code: "UPDATER_IMAGE_MALFORMED",
22316
+ message: "the updater job found no ~/.m8t/repo-root marker, so it has no baked release content. Every installer image writes that marker at build time, so this image is malformed.",
22317
+ hint: "Re-pull the updater job's image from the installer reference in the target manifest \u2014 the job self-updates to it on the next tick \u2014 or reinstall the platform. This job never fetches content from the platform repository: that repository is private and the job holds no token."
22318
+ });
22319
+ }
22320
+ function assertForwardTarget(manifest) {
22321
+ if (typeof manifest.components.infra?.treeSha === "string" && manifest.components.infra.treeSha.length > 0) return;
22322
+ throw new LocalCliError({
22323
+ code: "MANIFEST_NOT_A_FORWARD_TARGET",
22324
+ message: `manifest ${manifest.platform.version} carries no components.infra.treeSha, so the updater job cannot determine the infra target without reading the platform repository.`,
22325
+ hint: "Cuts from 0.7.0 onward always carry infra.treeSha. Target a current release: a manifest this old is not a valid target for an automatic update."
22326
+ });
22327
+ }
22328
+
22280
22329
  // src/lib/platform-self-update.ts
22281
22330
  import * as fs30 from "fs";
22282
22331
  import * as path32 from "path";
@@ -22421,10 +22470,12 @@ async function rollbackOrHold(args, notify, error) {
22421
22470
  async function reconvergeToPrevious(args, previousVersion) {
22422
22471
  const fetchManifestImpl = args.fetchManifestImpl ?? fetchManifest;
22423
22472
  const resolveContentImpl = args.resolveReleaseContentImpl ?? resolveReleaseContent;
22424
- const fetchTreeImpl = args.fetchRepoTreeImpl ?? fetchRepoTree;
22425
22473
  const prevManifest = await fetchManifestImpl(manifestSourceForVersionTag(args.channelUrl ?? "", previousVersion));
22426
- const contentDir = await resolveContentImpl(prevManifest, args.repoRoot ? { contentDir: args.repoRoot } : {});
22427
- const tree = prevManifest.components.infra?.treeSha ? { treeShaOf: () => void 0 } : await fetchTreeImpl(prevManifest.platform.commit);
22474
+ const repoRoot = args.repoRoot ?? null;
22475
+ assertBakedContentPresent(repoRoot);
22476
+ assertForwardTarget(prevManifest);
22477
+ const contentDir = await resolveContentImpl(prevManifest, { contentDir: repoRoot });
22478
+ const tree = { treeShaOf: () => void 0 };
22428
22479
  const liveStamp = await args.deps.readStamp();
22429
22480
  const rollbackPlan = diffPlan(prevManifest, liveStamp, tree);
22430
22481
  const rollbackCtx = { ...args.ctx, manifest: prevManifest, contentDir };
@@ -22573,8 +22624,10 @@ var PlatformConvergeCommand = class extends M8tCommand {
22573
22624
  interactive: false,
22574
22625
  endpoint: ctx.endpoint
22575
22626
  });
22576
- const contentDir = await resolveReleaseContentWithAgents(manifest, repoRoot ? { contentDir: repoRoot } : {});
22577
- const tree = manifest.components.infra?.treeSha ? { treeShaOf: () => void 0 } : await fetchRepoTree(manifest.platform.commit);
22627
+ assertBakedContentPresent(repoRoot);
22628
+ const contentDir = await resolveReleaseContentWithAgents(manifest, { contentDir: repoRoot });
22629
+ assertForwardTarget(manifest);
22630
+ const tree = { treeShaOf: () => void 0 };
22578
22631
  const suffix = await this.recoverSuffix(ctx);
22579
22632
  const gatewayResourceId = await this.resolveGatewayResourceId(ctx, suffix);
22580
22633
  deps = await buildConvergeDeps({
@@ -30060,7 +30113,7 @@ ${colors.error("\u2717")} The GitHub App on disk is installed on ${colors.field(
30060
30113
  // src/commands/bootstrap/launch.ts
30061
30114
  var DEFAULT_RG = "rg-m8t-stack";
30062
30115
  var DEFAULT_INSTALLER = "ghcr.io/m8t-labs/m8t-installer";
30063
- var DEFAULT_INSTALLER_TAG = "v0.1.60";
30116
+ var DEFAULT_INSTALLER_TAG = "v0.1.61";
30064
30117
  var ACI_NAME = "m8t-installer";
30065
30118
  var MI_NAME = "m8t-installer-mi";
30066
30119
  var BootstrapLaunchCommand = class extends M8tCommand {