@m8t-stack/cli 0.2.10 → 0.2.12

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
@@ -650,19 +650,47 @@ var init_foundry_agent_get = __esm({
650
650
  });
651
651
 
652
652
  // src/lib/brain-yaml-mirror.ts
653
+ import { parse as parseYaml4 } from "yaml";
653
654
  function linkSection(args) {
654
655
  return [
655
656
  `link:`,
656
657
  ` repo: "${args.repo}"`,
657
658
  ` branch: ${args.branch}`,
658
659
  ` topology: per-worker`,
659
- ` schemaVersion: "1"`,
660
+ ` schemaVersion: "2"`,
660
661
  ` persona: "${args.persona}"`,
661
- ` agent: "${args.agent}"`,
662
+ ` agents:`,
663
+ ...args.agents.map((a) => ` - ${a}`),
662
664
  ``
663
665
  ].join("\n");
664
666
  }
667
+ function mergeAgents(prior, incoming) {
668
+ return prior.includes(incoming) ? prior : [...prior, incoming];
669
+ }
670
+ function readLinkAgents(existing) {
671
+ if (!existing) return [];
672
+ let parsed;
673
+ try {
674
+ parsed = parseYaml4(existing);
675
+ } catch {
676
+ return [];
677
+ }
678
+ if (!parsed || typeof parsed !== "object") return [];
679
+ const root = parsed;
680
+ const link = root.link && typeof root.link === "object" ? root.link : root;
681
+ const raw = Array.isArray(link.agents) ? link.agents : typeof link.agent === "string" ? [link.agent] : [];
682
+ const out = [];
683
+ for (const v of raw) {
684
+ const s = typeof v === "string" ? v.trim() : "";
685
+ if (!s) continue;
686
+ if (/^\{\{.*\}\}$/.test(s)) continue;
687
+ if (!out.includes(s)) out.push(s);
688
+ }
689
+ return out;
690
+ }
665
691
  function buildBrainYaml(existing, args) {
692
+ const agents = mergeAgents(readLinkAgents(existing), args.agent);
693
+ const link = linkSection({ repo: args.repo, branch: args.branch, persona: args.persona, agents });
666
694
  if (existing) {
667
695
  const hasAuthoritative = /^engine:/m.test(existing) || /^processes:/m.test(existing);
668
696
  if (hasAuthoritative) {
@@ -670,10 +698,10 @@ function buildBrainYaml(existing, args) {
670
698
  const linkIdx = existing.search(/^link:/m);
671
699
  const cut = mirrorIdx >= 0 ? mirrorIdx : linkIdx >= 0 ? linkIdx : existing.length;
672
700
  const authoritative = existing.slice(0, cut).replace(/\s*$/, "\n\n");
673
- return authoritative + MIRROR_BANNER + "\n" + linkSection(args);
701
+ return authoritative + MIRROR_BANNER + "\n" + link;
674
702
  }
675
703
  }
676
- return DEFAULT_AUTHORITATIVE + "\n\n" + MIRROR_BANNER + "\n" + linkSection(args);
704
+ return DEFAULT_AUTHORITATIVE + "\n\n" + MIRROR_BANNER + "\n" + link;
677
705
  }
678
706
  async function mirrorBrainYaml(args) {
679
707
  const minted = await mintInstallationToken({
@@ -683,58 +711,56 @@ async function mirrorBrainYaml(args) {
683
711
  repository: args.repo
684
712
  });
685
713
  const [owner, repoName] = args.repo.split("/");
686
- const getRes = await fetch(
687
- `https://api.github.com/repos/${owner}/${repoName}/contents/.m8t/brain.yaml`,
688
- {
689
- headers: {
690
- Authorization: `Bearer ${minted.token}`,
691
- Accept: "application/vnd.github+json",
692
- "X-GitHub-Api-Version": "2022-11-28"
693
- }
694
- }
695
- );
696
- let sha;
697
- let existing;
698
- if (getRes.ok) {
699
- const data = await getRes.json();
700
- sha = data.sha;
701
- if (typeof data.content === "string") {
702
- existing = Buffer.from(data.content, "base64").toString("utf8");
703
- }
704
- }
705
- const content = buildBrainYaml(existing, {
706
- repo: args.repo,
707
- branch: args.branch,
708
- persona: args.persona,
709
- agent: args.agent
710
- });
711
- const body = {
712
- message: "chore(brain): mirror .m8t/brain.yaml (m8t brain link)",
713
- content: Buffer.from(content, "utf8").toString("base64"),
714
- branch: args.branch,
715
- ...sha ? { sha } : {}
714
+ const url = `https://api.github.com/repos/${owner}/${repoName}/contents/.m8t/brain.yaml`;
715
+ const headers = {
716
+ Authorization: `Bearer ${minted.token}`,
717
+ Accept: "application/vnd.github+json",
718
+ "X-GitHub-Api-Version": "2022-11-28"
716
719
  };
717
- const putRes = await fetch(
718
- `https://api.github.com/repos/${owner}/${repoName}/contents/.m8t/brain.yaml`,
719
- {
720
+ const MAX_ATTEMPTS2 = 3;
721
+ for (let attempt = 1; attempt <= MAX_ATTEMPTS2; attempt++) {
722
+ const getRes = await fetch(url, { headers });
723
+ let sha;
724
+ let existing;
725
+ if (getRes.ok) {
726
+ const data = await getRes.json();
727
+ sha = data.sha;
728
+ if (typeof data.content === "string") {
729
+ existing = Buffer.from(data.content, "base64").toString("utf8");
730
+ }
731
+ }
732
+ const content = buildBrainYaml(existing, {
733
+ repo: args.repo,
734
+ branch: args.branch,
735
+ persona: args.persona,
736
+ agent: args.agent
737
+ });
738
+ const body = {
739
+ message: "chore(brain): mirror .m8t/brain.yaml (m8t brain link)",
740
+ content: Buffer.from(content, "utf8").toString("base64"),
741
+ branch: args.branch,
742
+ ...sha ? { sha } : {}
743
+ };
744
+ const putRes = await fetch(url, {
720
745
  method: "PUT",
721
- headers: {
722
- Authorization: `Bearer ${minted.token}`,
723
- Accept: "application/vnd.github+json",
724
- "X-GitHub-Api-Version": "2022-11-28",
725
- "Content-Type": "application/json"
726
- },
746
+ headers: { ...headers, "Content-Type": "application/json" },
727
747
  body: JSON.stringify(body)
728
- }
729
- );
730
- if (!putRes.ok) {
748
+ });
749
+ if (putRes.ok) return;
731
750
  const text = await putRes.text();
751
+ const retryable = putRes.status === 409 || putRes.status === 422;
752
+ if (retryable && attempt < MAX_ATTEMPTS2) continue;
753
+ const suffix = retryable ? ` after ${MAX_ATTEMPTS2.toString()} attempts` : "";
732
754
  throw new LocalCliError({
733
755
  code: "BRAIN_YAML_MIRROR_FAILED",
734
- message: `PUT .m8t/brain.yaml: HTTP ${putRes.status.toString()}
756
+ message: `PUT .m8t/brain.yaml: HTTP ${putRes.status.toString()}${suffix}
735
757
  ${text.slice(0, 300)}`
736
758
  });
737
759
  }
760
+ throw new LocalCliError({
761
+ code: "BRAIN_YAML_MIRROR_FAILED",
762
+ message: `PUT .m8t/brain.yaml: retry loop exited unexpectedly`
763
+ });
738
764
  }
739
765
  var DEFAULT_AUTHORITATIVE, MIRROR_BANNER;
740
766
  var init_brain_yaml_mirror = __esm({
@@ -1169,7 +1195,7 @@ var init_enable_hosted_brain = __esm({
1169
1195
  import { Builtins, Cli } from "clipanion";
1170
1196
 
1171
1197
  // src/lib/package-version.ts
1172
- var CLI_VERSION = "0.2.10";
1198
+ var CLI_VERSION = "0.2.12";
1173
1199
 
1174
1200
  // src/lib/render-error.ts
1175
1201
  init_errors();
@@ -13720,6 +13746,40 @@ ${LOADER_END}
13720
13746
  `;
13721
13747
  }
13722
13748
 
13749
+ // src/lib/a2a-snippet.ts
13750
+ var SNIPPET_START = "<!-- m8t:a2a:start -->";
13751
+ var SNIPPET_END = "<!-- m8t:a2a:end -->";
13752
+ var DELEGATE_SNIPPET = `${SNIPPET_START}
13753
+ ## Working with other workers
13754
+ You can delegate to other m8t workers. Before you do:
13755
+ 1. Call \`discover_workers\` to see who's available now \u2014 each entry's card says what
13756
+ the worker is for, when to delegate to it, and what it accepts and returns.
13757
+ 2. If one is a clear fit, call \`invoke_worker(target, task)\` \u2014 \`target\` is the name
13758
+ from the directory; \`task\` is a complete, self-contained instruction (the worker
13759
+ can't ask follow-ups mid-task).
13760
+ 3. If invoke_worker returns status "in_progress" with a taskId, the worker is taking
13761
+ a while \u2014 call \`check_delegation(taskId)\` to fetch the result, repeating until the
13762
+ status is no longer "in_progress".
13763
+ 4. Fold the worker's result into your own answer.
13764
+ Delegate only when another worker is genuinely better suited; otherwise answer
13765
+ directly. Don't re-delegate the same request in a loop.
13766
+ ${SNIPPET_END}`;
13767
+ function esc(s) {
13768
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
13769
+ }
13770
+ function stripSnippet(instructions) {
13771
+ const re = new RegExp(`\\n*${esc(SNIPPET_START)}[\\s\\S]*?${esc(SNIPPET_END)}\\n*`, "g");
13772
+ return instructions.replace(re, "\n").replace(/\s+$/, "");
13773
+ }
13774
+ function appendSnippet(instructions) {
13775
+ return `${stripSnippet(instructions).replace(/\s+$/, "")}
13776
+
13777
+ ${DELEGATE_SNIPPET}`;
13778
+ }
13779
+ function hasA2aSnippet(instructions) {
13780
+ return instructions.includes(SNIPPET_START);
13781
+ }
13782
+
13723
13783
  // src/lib/brain-link.ts
13724
13784
  init_foundry_agent_get();
13725
13785
  init_brain_yaml_mirror();
@@ -13812,7 +13872,10 @@ async function linkBrain(args) {
13812
13872
  progress("No local persona yaml \u2014 basing instructions on the deployed agent\u2026");
13813
13873
  base = current.definition.instructions ?? "";
13814
13874
  }
13815
- const instructionsWithLoader = appendBrainLoader(base, loader);
13875
+ let instructionsWithLoader = appendBrainLoader(base, loader);
13876
+ if (hasA2aSnippet(current.definition.instructions ?? "")) {
13877
+ instructionsWithLoader = appendSnippet(instructionsWithLoader);
13878
+ }
13816
13879
  const link = {
13817
13880
  repo: args.repo,
13818
13881
  branch: args.branch,
@@ -14944,7 +15007,7 @@ init_errors();
14944
15007
  // src/lib/deploy-prompt-advisor.ts
14945
15008
  import * as fs12 from "fs";
14946
15009
  import * as path11 from "path";
14947
- import { parse as parseYaml4 } from "yaml";
15010
+ import { parse as parseYaml5 } from "yaml";
14948
15011
  init_foundry_agents();
14949
15012
  init_errors();
14950
15013
  function findPersonasRoot(hint) {
@@ -14972,7 +15035,7 @@ async function deployPromptAdvisor(args) {
14972
15035
  });
14973
15036
  }
14974
15037
  const fmMatch = /^---\n([\s\S]*?)\n---/.exec(raw);
14975
- const fm = fmMatch ? parseYaml4(fmMatch[1]) : {};
15038
+ const fm = fmMatch ? parseYaml5(fmMatch[1]) : {};
14976
15039
  const model = args.model ?? fm.targets?.foundry?.model;
14977
15040
  if (!model) {
14978
15041
  throw new LocalCliError({
@@ -15133,11 +15196,114 @@ init_errors();
15133
15196
  init_foundry_agent_get();
15134
15197
  import { randomBytes as randomBytes2, createHash } from "crypto";
15135
15198
 
15199
+ // src/lib/data-plane-ready.ts
15200
+ init_errors();
15201
+ async function awaitDataPlaneReady(opts) {
15202
+ const consecutive = opts.consecutive ?? 3;
15203
+ const attempts = opts.attempts ?? 60;
15204
+ const intervalMs = opts.intervalMs ?? 5e3;
15205
+ const sleep2 = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
15206
+ let streak = 0;
15207
+ for (let i = 1; i <= attempts; i++) {
15208
+ const r = await opts.probe();
15209
+ if (r.ok) {
15210
+ streak++;
15211
+ opts.onProgress?.(`data-plane ok (${streak.toString()}/${consecutive.toString()})`);
15212
+ if (streak >= consecutive) return { ready: true, attempts: i };
15213
+ } else {
15214
+ const cls = classifyFoundryError({ status: r.status, message: r.message ?? "" });
15215
+ const forcedRetryable = r.status !== void 0 && (opts.retryableStatuses?.includes(r.status) ?? false);
15216
+ if (!forcedRetryable && !cls.retryable) {
15217
+ throw new LocalCliError({
15218
+ code: "FOUNDRY_NOT_READY_FATAL",
15219
+ message: `Foundry data plane returned a non-retryable error: ${cls.message}`,
15220
+ hint: "This is not a transient data-plane delay \u2014 check `az login`/permissions and the endpoint.",
15221
+ retryable: false
15222
+ });
15223
+ }
15224
+ streak = 0;
15225
+ opts.onProgress?.(`data-plane not ready (${forcedRetryable ? `status ${(r.status ?? 0).toString()}` : cls.category}), waiting\u2026`);
15226
+ }
15227
+ if (i < attempts) await sleep2(intervalMs);
15228
+ }
15229
+ return { ready: false, attempts };
15230
+ }
15231
+
15232
+ // src/lib/foundry-ready-probe.ts
15233
+ init_http();
15234
+ var FOUNDRY_SCOPE3 = "https://ai.azure.com/.default";
15235
+ function makeAgentsProbe(credential2, endpoint) {
15236
+ return async () => {
15237
+ try {
15238
+ const r = await authedJsonResult({
15239
+ credential: credential2,
15240
+ scope: FOUNDRY_SCOPE3,
15241
+ method: "GET",
15242
+ url: `${endpoint}/agents?api-version=v1`,
15243
+ okStatuses: [404, 500, 502, 503]
15244
+ // don't throw — return the status so the loop classifies it
15245
+ });
15246
+ if (r.status === 200) return { ok: true, status: 200, message: "" };
15247
+ const body = r.data?.error?.message ?? "";
15248
+ return { ok: false, status: r.status, message: `${r.status.toString()} ${body}`.trim() };
15249
+ } catch (e) {
15250
+ return { ok: false, message: e instanceof Error ? e.message : String(e) };
15251
+ }
15252
+ };
15253
+ }
15254
+ function makeAgentProbe(credential2, endpoint, agentName) {
15255
+ return async () => {
15256
+ try {
15257
+ const r = await authedJsonResult({
15258
+ credential: credential2,
15259
+ scope: FOUNDRY_SCOPE3,
15260
+ method: "GET",
15261
+ url: `${endpoint}/agents/${agentName}?api-version=v1`,
15262
+ okStatuses: [404, 500, 502, 503]
15263
+ // don't throw — return the status so the loop classifies it
15264
+ });
15265
+ if (r.status === 200) return { ok: true, status: 200, message: "" };
15266
+ const body = r.data?.error?.message ?? "";
15267
+ return { ok: false, status: r.status, message: `${r.status.toString()} ${body}`.trim() };
15268
+ } catch (e) {
15269
+ return { ok: false, message: e instanceof Error ? e.message : String(e) };
15270
+ }
15271
+ };
15272
+ }
15273
+
15274
+ // src/lib/agent-ready.ts
15275
+ init_errors();
15276
+ async function awaitAgentQueryable(args) {
15277
+ const attemptsMax = args.attempts ?? 40;
15278
+ const intervalMs = args.intervalMs ?? 3e3;
15279
+ const probe = args.probe ?? makeAgentProbe(args.credential, args.projectEndpoint, args.agentName);
15280
+ const { ready, attempts } = await awaitDataPlaneReady({
15281
+ probe,
15282
+ consecutive: args.consecutive ?? 2,
15283
+ attempts: attemptsMax,
15284
+ intervalMs,
15285
+ sleep: args.sleep,
15286
+ onProgress: args.onProgress,
15287
+ retryableStatuses: [404]
15288
+ });
15289
+ if (!ready) {
15290
+ const approxSec = Math.round(attemptsMax * intervalMs / 1e3);
15291
+ throw new LocalCliError({
15292
+ code: "AGENT_NOT_QUERYABLE",
15293
+ message: `Agent '${args.agentName}' did not become queryable within ${attempts.toString()} probes (~${approxSec.toString()}s) after deploy.`,
15294
+ hint: "Foundry agent registration propagates asynchronously after deploy; a retry usually clears it. Re-run shortly (e.g. 'm8t bootstrap launch' or 'm8t a2a enable <name>').",
15295
+ category: "data_plane_not_ready",
15296
+ retryable: false
15297
+ });
15298
+ }
15299
+ return { attempts };
15300
+ }
15301
+
15136
15302
  // src/lib/persona-a2a.ts
15137
15303
  init_errors();
15138
15304
  init_esm();
15139
15305
  import * as fs13 from "fs";
15140
- import { parse as parseYaml5 } from "yaml";
15306
+ import { parse as parseYaml6 } from "yaml";
15141
15307
  function readPersonaA2aCard(personaPath) {
15142
15308
  let raw;
15143
15309
  try {
@@ -15147,7 +15313,7 @@ function readPersonaA2aCard(personaPath) {
15147
15313
  }
15148
15314
  const fm = /^---\n([\s\S]*?)\n---/.exec(raw);
15149
15315
  if (!fm) throw new LocalCliError({ code: "PERSONA_NO_FRONTMATTER", message: `Persona '${personaPath}' has no frontmatter.` });
15150
- const front = parseYaml5(fm[1]);
15316
+ const front = parseYaml6(fm[1]);
15151
15317
  const role = typeof front.role === "string" ? front.role : "";
15152
15318
  const cardYaml = front.targets?.foundry?.["a2a-card"];
15153
15319
  if (!cardYaml || typeof cardYaml !== "object") {
@@ -15182,29 +15348,19 @@ var FOUNDRY_ARM_API3 = "2025-04-01-preview";
15182
15348
  var FOUNDRY_DATA_SCOPE3 = "https://ai.azure.com/.default";
15183
15349
  var ARM_SCOPE6 = "https://management.azure.com/.default";
15184
15350
  var A2A_TOOLS = ["discover_workers", "invoke_worker", "check_delegation"];
15185
- var SNIPPET_START = "<!-- m8t:a2a:start -->";
15186
- var SNIPPET_END = "<!-- m8t:a2a:end -->";
15187
- var DELEGATE_SNIPPET = `${SNIPPET_START}
15188
- ## Working with other workers
15189
- You can delegate to other m8t workers. Before you do:
15190
- 1. Call \`discover_workers\` to see who's available now \u2014 each entry's card says what
15191
- the worker is for, when to delegate to it, and what it accepts and returns.
15192
- 2. If one is a clear fit, call \`invoke_worker(target, task)\` \u2014 \`target\` is the name
15193
- from the directory; \`task\` is a complete, self-contained instruction (the worker
15194
- can't ask follow-ups mid-task).
15195
- 3. If invoke_worker returns status "in_progress" with a taskId, the worker is taking
15196
- a while \u2014 call \`check_delegation(taskId)\` to fetch the result, repeating until the
15197
- status is no longer "in_progress".
15198
- 4. Fold the worker's result into your own answer.
15199
- Delegate only when another worker is genuinely better suited; otherwise answer
15200
- directly. Don't re-delegate the same request in a loop.
15201
- ${SNIPPET_END}`;
15202
15351
  async function enableA2a(args) {
15203
15352
  const progress = args.onProgress ?? ((_m) => {
15204
15353
  });
15205
15354
  const connectionName = `a2a-${args.agentName}`;
15206
15355
  progress("Reading persona a2a-card\u2026");
15207
15356
  const { serialized: a2aCardJson } = readPersonaA2aCard(args.personaPath);
15357
+ progress("Waiting for the agent to become queryable\u2026");
15358
+ await awaitAgentQueryable({
15359
+ credential: args.credential,
15360
+ projectEndpoint: args.projectEndpoint,
15361
+ agentName: args.agentName,
15362
+ onProgress: args.onProgress
15363
+ });
15208
15364
  progress("Reading current agent definition\u2026");
15209
15365
  const current = await getAgentVersion({ credential: args.credential, projectEndpoint: args.projectEndpoint, agentName: args.agentName });
15210
15366
  if (current.definition.kind === "hosted") {
@@ -15257,15 +15413,6 @@ async function disableA2a(args) {
15257
15413
  await deleteConnection2({ credential: args.credential, projectArmId: args.projectArmId, connectionName });
15258
15414
  return { connectionName, foundryVersion };
15259
15415
  }
15260
- function appendSnippet(instructions) {
15261
- return `${stripSnippet(instructions).replace(/\s+$/, "")}
15262
-
15263
- ${DELEGATE_SNIPPET}`;
15264
- }
15265
- function stripSnippet(instructions) {
15266
- const re = new RegExp(`\\n*${esc(SNIPPET_START)}[\\s\\S]*?${esc(SNIPPET_END)}\\n*`, "g");
15267
- return instructions.replace(re, "\n").replace(/\s+$/, "");
15268
- }
15269
15416
  function withA2aTool(tools, bridgeUrl, connectionName) {
15270
15417
  const others = tools.filter(
15271
15418
  (t) => !(t.type === "mcp" && t.server_label === "a2a")
@@ -15275,9 +15422,6 @@ function withA2aTool(tools, bridgeUrl, connectionName) {
15275
15422
  { type: "mcp", server_label: "a2a", server_url: bridgeUrl, allowed_tools: A2A_TOOLS, require_approval: "never", project_connection_id: connectionName }
15276
15423
  ];
15277
15424
  }
15278
- function esc(s) {
15279
- return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
15280
- }
15281
15425
  async function putA2aConnection(args) {
15282
15426
  const token = await args.credential.getToken(ARM_SCOPE6);
15283
15427
  if (!token?.token) throw new LocalCliError({ code: "ARM_AUTH", message: "Could not acquire ARM token" });
@@ -15655,7 +15799,7 @@ init_errors();
15655
15799
  import * as fs15 from "fs";
15656
15800
  import * as os6 from "os";
15657
15801
  import * as path12 from "path";
15658
- import { parse as parseYaml6 } from "yaml";
15802
+ import { parse as parseYaml7 } from "yaml";
15659
15803
  var A2A_PATH = "/api/a2a/mcp";
15660
15804
  function resolveBridgeUrl(opts) {
15661
15805
  const env = opts.env ?? process.env;
@@ -15679,7 +15823,7 @@ function readConfigGatewayUrl(home) {
15679
15823
  const cfg = path12.join(home ?? os6.homedir(), ".m8t-stack", "config.yaml");
15680
15824
  if (!fs15.existsSync(cfg)) return void 0;
15681
15825
  try {
15682
- const o = parseYaml6(fs15.readFileSync(cfg, "utf8"));
15826
+ const o = parseYaml7(fs15.readFileSync(cfg, "utf8"));
15683
15827
  return typeof o.gatewayUrl === "string" ? o.gatewayUrl : void 0;
15684
15828
  } catch {
15685
15829
  return void 0;
@@ -16181,7 +16325,7 @@ async function deployHostedWorker(args) {
16181
16325
  // src/lib/persona.ts
16182
16326
  import * as fs17 from "fs";
16183
16327
  import * as path15 from "path";
16184
- import { parse as parseYaml7 } from "yaml";
16328
+ import { parse as parseYaml8 } from "yaml";
16185
16329
  function findRepoRoot(startDir) {
16186
16330
  let dir = path15.resolve(startDir);
16187
16331
  for (; ; ) {
@@ -16205,7 +16349,7 @@ function resolvePersona(persona, cwd = process.cwd()) {
16205
16349
  if (!match) return { persona, personaVersion: null };
16206
16350
  let fm = null;
16207
16351
  try {
16208
- fm = parseYaml7(match[1]);
16352
+ fm = parseYaml8(match[1]);
16209
16353
  } catch {
16210
16354
  return { persona, personaVersion: null };
16211
16355
  }
@@ -18985,7 +19129,7 @@ import { Command as Command40, Option as Option38 } from "clipanion";
18985
19129
  // src/lib/profiles.ts
18986
19130
  import * as fs20 from "fs/promises";
18987
19131
  import * as path21 from "path";
18988
- import { parse as parseYaml8, stringify as stringifyYaml4 } from "yaml";
19132
+ import { parse as parseYaml9, stringify as stringifyYaml4 } from "yaml";
18989
19133
  function profilesDir() {
18990
19134
  const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
18991
19135
  return path21.join(home, ".m8t-stack", "profiles");
@@ -19010,7 +19154,7 @@ async function listProfiles() {
19010
19154
  async function readProfile(name) {
19011
19155
  try {
19012
19156
  const raw = await fs20.readFile(getProfilePath(name), "utf8");
19013
- const parsed = parseYaml8(raw);
19157
+ const parsed = parseYaml9(raw);
19014
19158
  if (!parsed || typeof parsed !== "object") return null;
19015
19159
  return parsed;
19016
19160
  } catch (e) {
@@ -21277,7 +21421,7 @@ async function emitDigest(input, deps, digest) {
21277
21421
  }
21278
21422
 
21279
21423
  // ../../packages/brain/engine/dist/esm/dream/config.js
21280
- import { parse as parseYaml9 } from "yaml";
21424
+ import { parse as parseYaml10 } from "yaml";
21281
21425
  var DEFAULT_DREAM_MODEL = "gpt-5.4";
21282
21426
  function asCadence(v) {
21283
21427
  return v === "nightly" ? "nightly" : "off";
@@ -21285,7 +21429,7 @@ function asCadence(v) {
21285
21429
  function parseDreamerConfig(rawYaml, env) {
21286
21430
  let parsed;
21287
21431
  try {
21288
- parsed = parseYaml9(rawYaml);
21432
+ parsed = parseYaml10(rawYaml);
21289
21433
  } catch {
21290
21434
  return { enabled: false, cadence: "off", model: env.M8T_DREAM_MODEL ?? DEFAULT_DREAM_MODEL };
21291
21435
  }
@@ -21302,10 +21446,10 @@ function parseDreamerConfig(rawYaml, env) {
21302
21446
  var ZERO_WIDTH_RE = new RegExp("\u200B|\u200C|\u200D|\uFEFF", "g");
21303
21447
 
21304
21448
  // ../../packages/brain/engine/dist/esm/librarian/janitor/frontmatter.js
21305
- import { parse as parseYaml10, stringify as stringifyYaml5 } from "yaml";
21449
+ import { parse as parseYaml11, stringify as stringifyYaml5 } from "yaml";
21306
21450
 
21307
21451
  // ../../packages/brain/engine/dist/esm/librarian/config.js
21308
- import { parse as parseYaml11 } from "yaml";
21452
+ import { parse as parseYaml12 } from "yaml";
21309
21453
 
21310
21454
  // src/lib/dream-discovery.ts
21311
21455
  init_http();
@@ -22113,62 +22257,6 @@ var FoundryCreateCommand = class extends M8tCommand {
22113
22257
  // src/commands/foundry/await-ready.ts
22114
22258
  import { Command as Command44, Option as Option42 } from "clipanion";
22115
22259
  import { AzureCliCredential as AzureCliCredential2 } from "@azure/identity";
22116
-
22117
- // src/lib/data-plane-ready.ts
22118
- init_errors();
22119
- async function awaitDataPlaneReady(opts) {
22120
- const consecutive = opts.consecutive ?? 3;
22121
- const attempts = opts.attempts ?? 60;
22122
- const intervalMs = opts.intervalMs ?? 5e3;
22123
- const sleep2 = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
22124
- let streak = 0;
22125
- for (let i = 1; i <= attempts; i++) {
22126
- const r = await opts.probe();
22127
- if (r.ok) {
22128
- streak++;
22129
- opts.onProgress?.(`data-plane ok (${streak.toString()}/${consecutive.toString()})`);
22130
- if (streak >= consecutive) return { ready: true, attempts: i };
22131
- } else {
22132
- const cls = classifyFoundryError({ status: r.status, message: r.message ?? "" });
22133
- if (!cls.retryable) {
22134
- throw new LocalCliError({
22135
- code: "FOUNDRY_NOT_READY_FATAL",
22136
- message: `Foundry data plane returned a non-retryable error: ${cls.message}`,
22137
- hint: "This is not a transient data-plane delay \u2014 check `az login`/permissions and the endpoint."
22138
- });
22139
- }
22140
- streak = 0;
22141
- opts.onProgress?.(`data-plane not ready (${cls.category}), waiting\u2026`);
22142
- }
22143
- if (i < attempts) await sleep2(intervalMs);
22144
- }
22145
- return { ready: false, attempts };
22146
- }
22147
-
22148
- // src/lib/foundry-ready-probe.ts
22149
- init_http();
22150
- var FOUNDRY_SCOPE3 = "https://ai.azure.com/.default";
22151
- function makeAgentsProbe(credential2, endpoint) {
22152
- return async () => {
22153
- try {
22154
- const r = await authedJsonResult({
22155
- credential: credential2,
22156
- scope: FOUNDRY_SCOPE3,
22157
- method: "GET",
22158
- url: `${endpoint}/agents?api-version=v1`,
22159
- okStatuses: [404, 500, 502, 503]
22160
- // don't throw — return the status so the loop classifies it
22161
- });
22162
- if (r.status === 200) return { ok: true, status: 200, message: "" };
22163
- const body = r.data?.error?.message ?? "";
22164
- return { ok: false, status: r.status, message: `${r.status.toString()} ${body}`.trim() };
22165
- } catch (e) {
22166
- return { ok: false, message: e instanceof Error ? e.message : String(e) };
22167
- }
22168
- };
22169
- }
22170
-
22171
- // src/commands/foundry/await-ready.ts
22172
22260
  init_errors();
22173
22261
  var FoundryAwaitReadyCommand = class extends M8tCommand {
22174
22262
  static paths = [["foundry", "await-ready"]];