@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 +236 -148
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
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: "
|
|
660
|
+
` schemaVersion: "2"`,
|
|
660
661
|
` persona: "${args.persona}"`,
|
|
661
|
-
`
|
|
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" +
|
|
701
|
+
return authoritative + MIRROR_BANNER + "\n" + link;
|
|
674
702
|
}
|
|
675
703
|
}
|
|
676
|
-
return DEFAULT_AUTHORITATIVE + "\n\n" + MIRROR_BANNER + "\n" +
|
|
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
|
|
687
|
-
|
|
688
|
-
{
|
|
689
|
-
|
|
690
|
-
|
|
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
|
|
718
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
|
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 ?
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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"]];
|