@m8t-stack/cli 0.2.28 → 0.2.30
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 +575 -247
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
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.
|
|
1250
|
+
var CLI_VERSION = "0.2.30";
|
|
1251
1251
|
|
|
1252
1252
|
// src/lib/render-error.ts
|
|
1253
1253
|
init_errors();
|
|
@@ -1335,7 +1335,7 @@ var BACKEND_RULES = [
|
|
|
1335
1335
|
reason: "unknown_channel",
|
|
1336
1336
|
hint: () => "channel must be one of: telegram, slack, teams."
|
|
1337
1337
|
},
|
|
1338
|
-
// BAD_REQUEST —
|
|
1338
|
+
// BAD_REQUEST — binding-validation reasons
|
|
1339
1339
|
{
|
|
1340
1340
|
code: "BAD_REQUEST",
|
|
1341
1341
|
reason: "no_adapter_registered",
|
|
@@ -1391,13 +1391,13 @@ var BACKEND_RULES = [
|
|
|
1391
1391
|
return `no binding '${bindingId}' found. Run 'm8t bind list' to see all bindings.`;
|
|
1392
1392
|
}
|
|
1393
1393
|
},
|
|
1394
|
-
// BAD_REQUEST —
|
|
1394
|
+
// BAD_REQUEST — webhook-registration rejection
|
|
1395
1395
|
{
|
|
1396
1396
|
code: "BAD_REQUEST",
|
|
1397
1397
|
reason: "webhook_registration_rejected",
|
|
1398
1398
|
hint: () => "Telegram rejected the bot token. Double-check the token from BotFather and that it isn't revoked."
|
|
1399
1399
|
},
|
|
1400
|
-
// UPSTREAM_FAILED —
|
|
1400
|
+
// UPSTREAM_FAILED — webhook-registration transient failure
|
|
1401
1401
|
{
|
|
1402
1402
|
code: "UPSTREAM_FAILED",
|
|
1403
1403
|
reason: "webhook_registration_failed",
|
|
@@ -1442,51 +1442,32 @@ var BACKEND_RULES = [
|
|
|
1442
1442
|
}
|
|
1443
1443
|
];
|
|
1444
1444
|
var LOCAL_RULES = {
|
|
1445
|
-
// Task 12 — foundry-agent-get
|
|
1446
1445
|
AGENT_CREATE_VERSION_FAILED: "Re-run with `--verbose` for the full response body.",
|
|
1447
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.",
|
|
1448
1447
|
AGENT_GET_FAILED: "Re-run with `--verbose` for the full response body.",
|
|
1449
1448
|
AGENT_NOT_FOUND: "Use `m8t brain create <name>` to create the worker first, OR run `m8t deploy <name>` to register an existing agent.",
|
|
1450
|
-
// Task 14 — brain-unlink
|
|
1451
1449
|
AGENT_REDEPLOY_FAILED: "Re-run with `--verbose` for the full response body.",
|
|
1452
1450
|
AGENT_REDEPLOY_NO_VERSION: "Foundry returned 2xx but no version. Re-try; if it persists, file an issue.",
|
|
1453
|
-
// Task 10/13/14
|
|
1454
1451
|
AGENT_YAML_NOT_FOUND: "Deploy the worker via `m8t deploy <name>` or the architect first.",
|
|
1455
|
-
// Task 16 — brain link command
|
|
1456
1452
|
APP_HEALTH_FAILED: "Run `m8t brain check-app` for details, then re-run this command.",
|
|
1457
|
-
// Task 14 — brain-unlink
|
|
1458
1453
|
APP_UNINSTALL_FAILED: "GitHub App-uninstall DELETE failed. Re-run with `--keep-app-install` if you want to skip this step.",
|
|
1459
|
-
// Task 13 — brain-link
|
|
1460
1454
|
ARM_AUTH: "Run `az login` and retry.",
|
|
1461
|
-
//
|
|
1455
|
+
// m8t brain create: stageAsGitRepo step
|
|
1462
1456
|
BRAIN_GIT_INIT_FAILED: "If git is not installed, install it. Otherwise re-run with --verbose.",
|
|
1463
|
-
// Task 14 — brain-unlink
|
|
1464
1457
|
BRAIN_NOT_LINKED: "The worker has no brain link. Use `m8t brain link` or `m8t brain create` first.",
|
|
1465
|
-
// Task 13 — brain-link
|
|
1466
1458
|
BRAIN_YAML_MIRROR_FAILED: "GitHub Contents API PUT failed. Verify the App has `contents: write` permission on the repo.",
|
|
1467
|
-
// Task 13 — brain-link
|
|
1468
1459
|
CONN_CREATE_FAILED: "Foundry connection PUT failed. Verify Cognitive Services Contributor role on the project.",
|
|
1469
|
-
// Task 14 — brain-unlink
|
|
1470
1460
|
CONN_DELETE_FAILED: "Foundry connection DELETE failed. Verify your ARM subscription has Contributor on the project.",
|
|
1471
|
-
// Task 13 — brain-link
|
|
1472
1461
|
CONN_GET_FAILED: "Foundry connection GET failed. Verify your ARM subscription has access to the project.",
|
|
1473
|
-
//
|
|
1462
|
+
// rename pending: should be FOUNDRY_AUTH_FAILED
|
|
1474
1463
|
FOUNDRY_AUTH: "Run `az login` and retry.",
|
|
1475
|
-
// Task 12 — foundry-agent-get
|
|
1476
1464
|
FOUNDRY_AUTH_FAILED: "Run `az login` and retry.",
|
|
1477
|
-
// Task 15+16
|
|
1478
1465
|
KV_URI_NOT_FOUND: "Pass `--kv-uri` or set `AZURE_KEYVAULT_URI` / `KEYVAULT_URI`.",
|
|
1479
|
-
// Task 13 — brain-link
|
|
1480
1466
|
LINK_NO_INSTALLATION_ID: "Internal error \u2014 the CLI command must poll for the installation id before calling linkBrain. Report at https://github.com/m8t/m8t/issues.",
|
|
1481
|
-
// Task 16 — brain link command
|
|
1482
1467
|
M8T_REPO_ROOT_MISSING: "Re-run `m8t install` from a fresh m8t checkout \u2014 the post-install hook writes ~/.m8t/repo-root.",
|
|
1483
|
-
// Task 14 — persona-render
|
|
1484
1468
|
PERSONA_PATH_NOT_ABSOLUTE: "The persona path in ~/.m8t/foundry/<worker>.yaml must be absolute. Re-deploy the worker via the architect.",
|
|
1485
|
-
// Task 9 — persona-render
|
|
1486
1469
|
PERSONA_PLACEHOLDER_UNSATISFIED: "Re-deploy the worker via the architect to repopulate fillableFieldValues, OR edit ~/.m8t/foundry/<worker>.yaml manually.",
|
|
1487
|
-
// Task 9 — persona-render
|
|
1488
1470
|
PERSONA_READ_FAILED: "Verify the persona path in ~/.m8t/foundry/<worker>.yaml; the architect should have populated it at deploy time.",
|
|
1489
|
-
// ── pre-existing entries ──────────────────────────────────────────────────
|
|
1490
1471
|
AUTH_NOT_SIGNED_IN: "you are not signed in to Azure \u2014 run 'az login' first.",
|
|
1491
1472
|
AUTH_EXPIRED: "your Azure login expired \u2014 run 'az login' to re-authenticate.",
|
|
1492
1473
|
AUTH_WRONG_TENANT: "your active Azure session may be in a different tenant \u2014 run 'az login --tenant <id>'.",
|
|
@@ -11524,7 +11505,7 @@ function redactAzArgs(args) {
|
|
|
11524
11505
|
}
|
|
11525
11506
|
function runAz(args) {
|
|
11526
11507
|
return new Promise((resolve3, reject) => {
|
|
11527
|
-
const proc = spawn("az", args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
11508
|
+
const proc = spawn("az", args, { stdio: ["ignore", "pipe", "pipe"], shell: process.platform === "win32" });
|
|
11528
11509
|
const out = [];
|
|
11529
11510
|
const err = [];
|
|
11530
11511
|
proc.stdout.on("data", (d) => out.push(d));
|
|
@@ -13391,9 +13372,9 @@ async function probeAppInstallation(args) {
|
|
|
13391
13372
|
${body.slice(0, 300)}`);
|
|
13392
13373
|
}
|
|
13393
13374
|
async function tryOpenUrl(url, exec = defaultGhExec) {
|
|
13394
|
-
const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
13375
|
+
const [cmd, args] = process.platform === "darwin" ? ["open", [url]] : process.platform === "win32" ? ["cmd", ["/c", "start", "", url]] : ["xdg-open", [url]];
|
|
13395
13376
|
try {
|
|
13396
|
-
await exec(cmd,
|
|
13377
|
+
await exec(cmd, args);
|
|
13397
13378
|
} catch {
|
|
13398
13379
|
}
|
|
13399
13380
|
}
|
|
@@ -13825,7 +13806,7 @@ function renderPersonaBody(personaPath, fillableFieldValues, instanceName) {
|
|
|
13825
13806
|
message: `Could not read persona file '${personaPath}': ${e.message}`
|
|
13826
13807
|
});
|
|
13827
13808
|
}
|
|
13828
|
-
const fmMatch = /^---\n[\s\S]*?\n
|
|
13809
|
+
const fmMatch = /^---\r?\n[\s\S]*?\r?\n---(?:\r?\n)+/.exec(raw);
|
|
13829
13810
|
const body = fmMatch ? raw.slice(fmMatch[0].length) : raw;
|
|
13830
13811
|
let rendered = body;
|
|
13831
13812
|
for (const [name, value] of Object.entries(fillableFieldValues)) {
|
|
@@ -14280,8 +14261,8 @@ function isM8tBrainMarker(yamlText) {
|
|
|
14280
14261
|
}
|
|
14281
14262
|
if (!parsed || typeof parsed !== "object") return false;
|
|
14282
14263
|
const root = parsed;
|
|
14283
|
-
const
|
|
14284
|
-
return
|
|
14264
|
+
const isObj4 = (v) => typeof v === "object" && v !== null;
|
|
14265
|
+
return isObj4(root.engine) || isObj4(root.processes) || isObj4(root.link);
|
|
14285
14266
|
}
|
|
14286
14267
|
async function createBlankRepo(args) {
|
|
14287
14268
|
const res = await fetch(`https://api.github.com/orgs/${args.org}/repos`, {
|
|
@@ -15547,7 +15528,7 @@ async function deployPromptAdvisor(args) {
|
|
|
15547
15528
|
cause: e
|
|
15548
15529
|
});
|
|
15549
15530
|
}
|
|
15550
|
-
const fmMatch = /^---\n([\s\S]*?)\n---/.exec(raw);
|
|
15531
|
+
const fmMatch = /^---\r?\n([\s\S]*?)\r?\n---/.exec(raw);
|
|
15551
15532
|
const fm = fmMatch ? parseYaml6(fmMatch[1]) : {};
|
|
15552
15533
|
const model = args.model ?? fm.targets?.foundry?.model;
|
|
15553
15534
|
if (!model) {
|
|
@@ -15823,7 +15804,7 @@ function readPersonaA2aCard(personaPath) {
|
|
|
15823
15804
|
} catch (e) {
|
|
15824
15805
|
throw new LocalCliError({ code: "PERSONA_READ_FAILED", message: `Could not read persona '${personaPath}': ${e.message}` });
|
|
15825
15806
|
}
|
|
15826
|
-
const fm = /^---\n([\s\S]*?)\n---/.exec(raw);
|
|
15807
|
+
const fm = /^---\r?\n([\s\S]*?)\r?\n---/.exec(raw);
|
|
15827
15808
|
if (!fm) throw new LocalCliError({ code: "PERSONA_NO_FRONTMATTER", message: `Persona '${personaPath}' has no frontmatter.` });
|
|
15828
15809
|
const front = parseYaml7(fm[1]);
|
|
15829
15810
|
const role = typeof front.role === "string" ? front.role : "";
|
|
@@ -16899,7 +16880,7 @@ function resolvePersona(persona, cwd = process.cwd()) {
|
|
|
16899
16880
|
} catch {
|
|
16900
16881
|
return { persona, personaVersion: null };
|
|
16901
16882
|
}
|
|
16902
|
-
const match = /^---\n([\s\S]*?)\n---/.exec(raw);
|
|
16883
|
+
const match = /^---\r?\n([\s\S]*?)\r?\n---/.exec(raw);
|
|
16903
16884
|
if (!match) return { persona, personaVersion: null };
|
|
16904
16885
|
let fm = null;
|
|
16905
16886
|
try {
|
|
@@ -18727,7 +18708,7 @@ function declaredFillableFields(personaPath) {
|
|
|
18727
18708
|
} catch {
|
|
18728
18709
|
return [];
|
|
18729
18710
|
}
|
|
18730
|
-
const fmMatch = /^---\n([\s\S]*?)\n---/.exec(raw);
|
|
18711
|
+
const fmMatch = /^---\r?\n([\s\S]*?)\r?\n---/.exec(raw);
|
|
18731
18712
|
if (!fmMatch) return [];
|
|
18732
18713
|
try {
|
|
18733
18714
|
const fm = parseYaml10(fmMatch[1]);
|
|
@@ -20202,8 +20183,181 @@ function targetManifestSource(ctx, target) {
|
|
|
20202
20183
|
return manifestSourceForVersionTag(ctx.channelUrl, target);
|
|
20203
20184
|
}
|
|
20204
20185
|
|
|
20205
|
-
// src/commands/platform/
|
|
20186
|
+
// src/commands/platform/seed-stamp.ts
|
|
20187
|
+
import { readFileSync as readFileSync17 } from "fs";
|
|
20206
20188
|
import { Command as Command34, Option as Option31 } from "clipanion";
|
|
20189
|
+
import { DefaultAzureCredential as DefaultAzureCredential18, ManagedIdentityCredential as ManagedIdentityCredential2 } from "@azure/identity";
|
|
20190
|
+
init_errors();
|
|
20191
|
+
|
|
20192
|
+
// src/lib/platform-stamp-seed.ts
|
|
20193
|
+
var IMAGE_COMPONENTS = ["gateway", "codingAgent", "azureExecutor"];
|
|
20194
|
+
var BARE_SEMVER = /^\d+\.\d+\.\d+$/;
|
|
20195
|
+
function isObj3(v) {
|
|
20196
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
20197
|
+
}
|
|
20198
|
+
function validateDescriptor(raw) {
|
|
20199
|
+
const errors = [];
|
|
20200
|
+
if (!isObj3(raw)) return ["descriptor is not an object"];
|
|
20201
|
+
if (raw.schemaVersion !== 1) errors.push("schemaVersion must be the integer 1");
|
|
20202
|
+
if (typeof raw.platformVersion !== "string" || !BARE_SEMVER.test(raw.platformVersion)) {
|
|
20203
|
+
errors.push(`platformVersion must be a bare X.Y.Z release version, got ${JSON.stringify(raw.platformVersion)}`);
|
|
20204
|
+
}
|
|
20205
|
+
if (!isObj3(raw.generatedFrom)) {
|
|
20206
|
+
errors.push("generatedFrom is required");
|
|
20207
|
+
} else {
|
|
20208
|
+
if (typeof raw.generatedFrom.commit !== "string") {
|
|
20209
|
+
errors.push("generatedFrom.commit is required");
|
|
20210
|
+
}
|
|
20211
|
+
if (typeof raw.generatedFrom.generatedAt !== "string") {
|
|
20212
|
+
errors.push("generatedFrom.generatedAt is required");
|
|
20213
|
+
}
|
|
20214
|
+
}
|
|
20215
|
+
const images = raw.images;
|
|
20216
|
+
if (!isObj3(images)) {
|
|
20217
|
+
errors.push("images is required");
|
|
20218
|
+
} else {
|
|
20219
|
+
for (const key2 of IMAGE_COMPONENTS) {
|
|
20220
|
+
const img = images[key2];
|
|
20221
|
+
if (!isObj3(img)) {
|
|
20222
|
+
errors.push(`images.${key2} is required`);
|
|
20223
|
+
continue;
|
|
20224
|
+
}
|
|
20225
|
+
if (typeof img.ref !== "string" || img.ref.length === 0) errors.push(`images.${key2}.ref is required`);
|
|
20226
|
+
if (typeof img.tag !== "string" || img.tag.length === 0) errors.push(`images.${key2}.tag is required`);
|
|
20227
|
+
if (typeof img.digest !== "string") errors.push(`images.${key2}.digest must be a string (may be empty)`);
|
|
20228
|
+
}
|
|
20229
|
+
}
|
|
20230
|
+
const content = raw.content;
|
|
20231
|
+
if (content !== void 0) {
|
|
20232
|
+
if (!isObj3(content)) {
|
|
20233
|
+
errors.push("content must be an object when present");
|
|
20234
|
+
} else {
|
|
20235
|
+
if (!isObj3(content.personas)) errors.push("content.personas must be an object");
|
|
20236
|
+
if (typeof content.infra !== "string") errors.push("content.infra must be a string");
|
|
20237
|
+
if (typeof content.brainSeedsRev !== "string") errors.push("content.brainSeedsRev must be a string");
|
|
20238
|
+
}
|
|
20239
|
+
}
|
|
20240
|
+
return errors;
|
|
20241
|
+
}
|
|
20242
|
+
function buildSeedStamp(d, cliVersion, nowIso) {
|
|
20243
|
+
const img = (k) => ({
|
|
20244
|
+
tag: d.images[k].tag,
|
|
20245
|
+
digest: d.images[k].digest,
|
|
20246
|
+
state: "managed"
|
|
20247
|
+
});
|
|
20248
|
+
const personas = {};
|
|
20249
|
+
for (const [name, treeSha] of Object.entries(d.content?.personas ?? {})) {
|
|
20250
|
+
personas[name] = { treeSha, foundryVersion: "" };
|
|
20251
|
+
}
|
|
20252
|
+
const stamp = {
|
|
20253
|
+
schemaVersion: 1,
|
|
20254
|
+
platformVersion: platformTag(d.platformVersion),
|
|
20255
|
+
previousPlatformVersion: null,
|
|
20256
|
+
updatedAt: nowIso,
|
|
20257
|
+
lastResult: "success",
|
|
20258
|
+
cli: cliVersion,
|
|
20259
|
+
origin: "install-seed",
|
|
20260
|
+
components: {
|
|
20261
|
+
gateway: img("gateway"),
|
|
20262
|
+
codingAgent: img("codingAgent"),
|
|
20263
|
+
azureExecutor: img("azureExecutor"),
|
|
20264
|
+
personas,
|
|
20265
|
+
infra: { treeSha: d.content?.infra ?? "" }
|
|
20266
|
+
}
|
|
20267
|
+
};
|
|
20268
|
+
if (d.content?.brainSeedsRev) stamp.components.brainSeeds = { seedRev: d.content.brainSeedsRev };
|
|
20269
|
+
return stamp;
|
|
20270
|
+
}
|
|
20271
|
+
|
|
20272
|
+
// src/commands/platform/seed-stamp.ts
|
|
20273
|
+
async function seedStamp2(args) {
|
|
20274
|
+
const readFileImpl = args.readFileImpl ?? ((p) => readFileSync17(p, "utf8"));
|
|
20275
|
+
const readStampImpl = args.readStampImpl ?? readStamp;
|
|
20276
|
+
const writeStampImpl = args.writeStampImpl ?? ((stamp2, o) => writeStamp({ ...o, stamp: stamp2 }));
|
|
20277
|
+
const discoverImpl = args.discoverImpl ?? discoverStampStorage;
|
|
20278
|
+
const ctx = { credential: args.credential, subscriptionId: args.subscriptionId, resourceGroup: args.resourceGroup };
|
|
20279
|
+
let raw;
|
|
20280
|
+
try {
|
|
20281
|
+
raw = JSON.parse(readFileImpl(args.descriptorPath));
|
|
20282
|
+
} catch (e) {
|
|
20283
|
+
throw new LocalCliError({
|
|
20284
|
+
code: "PLATFORM_SEED_DESCRIPTOR_UNREADABLE",
|
|
20285
|
+
message: `Cannot read the install descriptor at ${args.descriptorPath}.`,
|
|
20286
|
+
hint: "The descriptor is generated at installer-image build time (scripts/install-descriptor-gen.mjs). An image built without that step cannot seed a stamp.",
|
|
20287
|
+
cause: e
|
|
20288
|
+
});
|
|
20289
|
+
}
|
|
20290
|
+
const errors = validateDescriptor(raw);
|
|
20291
|
+
if (errors.length > 0) {
|
|
20292
|
+
throw new LocalCliError({
|
|
20293
|
+
code: "PLATFORM_SEED_DESCRIPTOR_INVALID",
|
|
20294
|
+
message: `The install descriptor at ${args.descriptorPath} is not valid: ${errors.join("; ")}.`,
|
|
20295
|
+
hint: "Regenerate it with scripts/install-descriptor-gen.mjs."
|
|
20296
|
+
});
|
|
20297
|
+
}
|
|
20298
|
+
const descriptor = raw;
|
|
20299
|
+
const { accountName } = await discoverImpl(ctx);
|
|
20300
|
+
const existing = await readStampImpl(ctx);
|
|
20301
|
+
if (existing) {
|
|
20302
|
+
args.onProgress?.(`platform stamp already present (${existing.platformVersion}) \u2014 leaving it untouched.`);
|
|
20303
|
+
return { outcome: "already-stamped", platformVersion: existing.platformVersion, storageAccount: accountName };
|
|
20304
|
+
}
|
|
20305
|
+
const stamp = buildSeedStamp(descriptor, CLI_VERSION, args.nowIso ?? (/* @__PURE__ */ new Date()).toISOString());
|
|
20306
|
+
await writeStampImpl(stamp, { ...ctx, onProgress: args.onProgress });
|
|
20307
|
+
return {
|
|
20308
|
+
outcome: descriptor.content ? "seeded" : "seeded-partial",
|
|
20309
|
+
platformVersion: stamp.platformVersion,
|
|
20310
|
+
storageAccount: accountName,
|
|
20311
|
+
components: {
|
|
20312
|
+
gateway: stamp.components.gateway.tag,
|
|
20313
|
+
codingAgent: stamp.components.codingAgent.tag,
|
|
20314
|
+
azureExecutor: stamp.components.azureExecutor.tag
|
|
20315
|
+
}
|
|
20316
|
+
};
|
|
20317
|
+
}
|
|
20318
|
+
var PlatformSeedStampCommand = class extends M8tCommand {
|
|
20319
|
+
static paths = [["platform", "seed-stamp"]];
|
|
20320
|
+
static usage = Command34.Usage({
|
|
20321
|
+
description: "INTERNAL: write the initial installed-state stamp from a build-time install descriptor.",
|
|
20322
|
+
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'."
|
|
20323
|
+
});
|
|
20324
|
+
descriptor = Option31.String("--descriptor", { description: "Path to install-descriptor.json (baked into the installer image)." });
|
|
20325
|
+
subscription = Option31.String("--subscription");
|
|
20326
|
+
resourceGroup = Option31.String("--resource-group");
|
|
20327
|
+
miClientId = Option31.String("--mi-client-id", { description: "Authenticate as this user-assigned managed identity instead of the ambient credential." });
|
|
20328
|
+
output = Option31.String("--output");
|
|
20329
|
+
async executeCommand() {
|
|
20330
|
+
const mode = resolveOutputMode(this.output, this.context.stdout);
|
|
20331
|
+
const need = (v, flag) => {
|
|
20332
|
+
if (typeof v !== "string" || v.trim().length === 0) {
|
|
20333
|
+
throw new LocalCliError({ code: "PLATFORM_SEED_ARG_MISSING", message: `${flag} is required.` });
|
|
20334
|
+
}
|
|
20335
|
+
return v.trim();
|
|
20336
|
+
};
|
|
20337
|
+
const onProgress = (m) => {
|
|
20338
|
+
this.context.stderr.write(`${m}
|
|
20339
|
+
`);
|
|
20340
|
+
};
|
|
20341
|
+
const credential2 = typeof this.miClientId === "string" && this.miClientId.trim().length > 0 ? new ManagedIdentityCredential2({ clientId: this.miClientId.trim() }) : new DefaultAzureCredential18();
|
|
20342
|
+
const result = await seedStamp2({
|
|
20343
|
+
descriptorPath: need(this.descriptor, "--descriptor"),
|
|
20344
|
+
credential: credential2,
|
|
20345
|
+
subscriptionId: need(this.subscription, "--subscription"),
|
|
20346
|
+
resourceGroup: need(this.resourceGroup, "--resource-group"),
|
|
20347
|
+
onProgress
|
|
20348
|
+
});
|
|
20349
|
+
if (mode === "json") {
|
|
20350
|
+
this.context.stdout.write(renderJson(result) + "\n");
|
|
20351
|
+
} else {
|
|
20352
|
+
this.context.stdout.write(`${result.outcome}: ${result.platformVersion} (storage ${result.storageAccount})
|
|
20353
|
+
`);
|
|
20354
|
+
}
|
|
20355
|
+
return 0;
|
|
20356
|
+
}
|
|
20357
|
+
};
|
|
20358
|
+
|
|
20359
|
+
// src/commands/platform/enable-cost-report.ts
|
|
20360
|
+
import { Command as Command35, Option as Option32 } from "clipanion";
|
|
20207
20361
|
|
|
20208
20362
|
// src/lib/wire-gateway-acs.ts
|
|
20209
20363
|
init_rbac();
|
|
@@ -20243,18 +20397,18 @@ async function wireGatewayForAcs(args) {
|
|
|
20243
20397
|
init_errors();
|
|
20244
20398
|
var PlatformEnableCostReportCommand = class extends M8tCommand {
|
|
20245
20399
|
static paths = [["platform", "enable-cost-report"]];
|
|
20246
|
-
static usage =
|
|
20400
|
+
static usage = Command35.Usage({
|
|
20247
20401
|
description: "Wire the deployed gateway to send the bi-weekly cost report via ACS Email.",
|
|
20248
20402
|
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')."
|
|
20249
20403
|
});
|
|
20250
|
-
subscription =
|
|
20251
|
-
resourceGroup =
|
|
20404
|
+
subscription = Option32.String("--subscription");
|
|
20405
|
+
resourceGroup = Option32.String("--resource-group", {
|
|
20252
20406
|
description: "m8t resource group to disambiguate the gateway (multi-deployment subscriptions)."
|
|
20253
20407
|
});
|
|
20254
|
-
acsEndpoint =
|
|
20255
|
-
acsSender =
|
|
20256
|
-
acsResourceId =
|
|
20257
|
-
output =
|
|
20408
|
+
acsEndpoint = Option32.String("--acs-endpoint", { required: true, description: "ACS data-plane endpoint, e.g. https://acs-<name>.communication.azure.com/" });
|
|
20409
|
+
acsSender = Option32.String("--acs-sender", { required: true, description: "Managed-domain sender address, e.g. DoNotReply@<guid>.azurecomm.net" });
|
|
20410
|
+
acsResourceId = Option32.String("--acs-resource-id", { required: true, description: "ARM resource id of the acs-<name> Communication Service \u2014 the role-grant scope." });
|
|
20411
|
+
output = Option32.String("--output");
|
|
20258
20412
|
async executeCommand() {
|
|
20259
20413
|
const mode = resolveOutputMode(
|
|
20260
20414
|
this.output,
|
|
@@ -20328,39 +20482,39 @@ var PlatformEnableCostReportCommand = class extends M8tCommand {
|
|
|
20328
20482
|
};
|
|
20329
20483
|
|
|
20330
20484
|
// src/commands/platform/enable-auto-update.ts
|
|
20331
|
-
import { Command as
|
|
20485
|
+
import { Command as Command36, Option as Option33 } from "clipanion";
|
|
20332
20486
|
import { confirm as confirm6 } from "@inquirer/prompts";
|
|
20333
|
-
import { DefaultAzureCredential as
|
|
20487
|
+
import { DefaultAzureCredential as DefaultAzureCredential19 } from "@azure/identity";
|
|
20334
20488
|
init_errors();
|
|
20335
20489
|
var PlatformEnableAutoUpdateCommand = class extends M8tCommand {
|
|
20336
20490
|
static paths = [["platform", "enable-auto-update"]];
|
|
20337
|
-
static usage =
|
|
20491
|
+
static usage = Command36.Usage({
|
|
20338
20492
|
category: "Platform",
|
|
20339
20493
|
description: "Retrofit the auto-updater (MI + cron job + role assignments) onto an existing install.",
|
|
20340
20494
|
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."
|
|
20341
20495
|
});
|
|
20342
|
-
subscription =
|
|
20343
|
-
resourceGroup =
|
|
20496
|
+
subscription = Option33.String("--subscription");
|
|
20497
|
+
resourceGroup = Option33.String("--resource-group", {
|
|
20344
20498
|
description: "m8t resource group to disambiguate the gateway (multi-deployment subscriptions)."
|
|
20345
20499
|
});
|
|
20346
|
-
suffix =
|
|
20500
|
+
suffix = Option33.String("--suffix", {
|
|
20347
20501
|
description: "The existing deployment's resource-name suffix. Required when it cannot be recovered from system/infra-params or the live gateway."
|
|
20348
20502
|
});
|
|
20349
|
-
installerImage =
|
|
20503
|
+
installerImage = Option33.String("--installer-image", {
|
|
20350
20504
|
required: true,
|
|
20351
20505
|
description: "Updater CA-Job image ref (the converge engine at the current release). Required \u2014 an empty image would skip provisioning."
|
|
20352
20506
|
});
|
|
20353
|
-
updateCron =
|
|
20507
|
+
updateCron = Option33.String("--update-cron", {
|
|
20354
20508
|
description: "Cron schedule for the updater job (bicep default applies when omitted)."
|
|
20355
20509
|
});
|
|
20356
|
-
channelUrl =
|
|
20510
|
+
channelUrl = Option33.String("--channel-url", {
|
|
20357
20511
|
description: "Release-channel URL the updater job polls (bicep default applies when omitted)."
|
|
20358
20512
|
});
|
|
20359
|
-
endpoint =
|
|
20513
|
+
endpoint = Option33.String("--endpoint", {
|
|
20360
20514
|
description: "Foundry project endpoint URL. Disambiguates the project in a multi-project subscription."
|
|
20361
20515
|
});
|
|
20362
|
-
yes =
|
|
20363
|
-
output =
|
|
20516
|
+
yes = Option33.Boolean("--yes", false);
|
|
20517
|
+
output = Option33.String("--output");
|
|
20364
20518
|
async executeCommand() {
|
|
20365
20519
|
const mode = resolveOutputMode(
|
|
20366
20520
|
this.output,
|
|
@@ -20379,7 +20533,7 @@ var PlatformEnableAutoUpdateCommand = class extends M8tCommand {
|
|
|
20379
20533
|
resourceGroup: this.resourceGroup
|
|
20380
20534
|
});
|
|
20381
20535
|
const { resourceGroup, name: gatewayName } = parseContainerAppResourceId(gw.containerAppResourceId);
|
|
20382
|
-
const credential2 = new
|
|
20536
|
+
const credential2 = new DefaultAzureCredential19();
|
|
20383
20537
|
const account = await getAzAccount();
|
|
20384
20538
|
const subscriptionId = this.subscription ?? account.subscriptionId;
|
|
20385
20539
|
const explicitSuffix = typeof this.suffix === "string" && this.suffix.length > 0 ? this.suffix : void 0;
|
|
@@ -20481,7 +20635,7 @@ var PlatformEnableAutoUpdateCommand = class extends M8tCommand {
|
|
|
20481
20635
|
};
|
|
20482
20636
|
|
|
20483
20637
|
// src/commands/deploy.ts
|
|
20484
|
-
import { Command as
|
|
20638
|
+
import { Command as Command37, Option as Option34 } from "clipanion";
|
|
20485
20639
|
|
|
20486
20640
|
// src/lib/app-reg.ts
|
|
20487
20641
|
init_errors();
|
|
@@ -20883,40 +21037,40 @@ function classifyWhatIf(changes) {
|
|
|
20883
21037
|
var DEFAULT_IMAGE_REF = "ghcr.io/m8t-labs/m8t:latest";
|
|
20884
21038
|
var DeployCommand = class extends M8tCommand {
|
|
20885
21039
|
static paths = [["deploy"]];
|
|
20886
|
-
static usage =
|
|
21040
|
+
static usage = Command37.Usage({
|
|
20887
21041
|
description: "Deploy (or update) the m8t gateway/webapp stack via Bicep.",
|
|
20888
21042
|
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."
|
|
20889
21043
|
});
|
|
20890
|
-
subscription =
|
|
20891
|
-
resourceGroup =
|
|
20892
|
-
location =
|
|
20893
|
-
suffix =
|
|
20894
|
-
imageRef =
|
|
20895
|
-
acrPullIdentity =
|
|
20896
|
-
acrResourceId =
|
|
20897
|
-
foundryEndpoint =
|
|
20898
|
-
foundryResourceId =
|
|
20899
|
-
foundryTracing =
|
|
21044
|
+
subscription = Option34.String("--subscription");
|
|
21045
|
+
resourceGroup = Option34.String("--resource-group", "rg-m8t-stack");
|
|
21046
|
+
location = Option34.String("--location", "eastus");
|
|
21047
|
+
suffix = Option34.String("--suffix", "");
|
|
21048
|
+
imageRef = Option34.String("--image-ref", DEFAULT_IMAGE_REF);
|
|
21049
|
+
acrPullIdentity = Option34.String("--acrpull-identity");
|
|
21050
|
+
acrResourceId = Option34.String("--acr-resource-id");
|
|
21051
|
+
foundryEndpoint = Option34.String("--foundry-endpoint");
|
|
21052
|
+
foundryResourceId = Option34.String("--foundry-resource-id");
|
|
21053
|
+
foundryTracing = Option34.String("--foundry-tracing");
|
|
20900
21054
|
// project | account | skip (bicep default: project)
|
|
20901
|
-
clientId =
|
|
20902
|
-
whatIf =
|
|
20903
|
-
output =
|
|
20904
|
-
// Referee
|
|
21055
|
+
clientId = Option34.String("--client-id");
|
|
21056
|
+
whatIf = Option34.Boolean("--what-if", false);
|
|
21057
|
+
output = Option34.String("--output");
|
|
21058
|
+
// Referee — all optional, undefined by default ⇒ the bicep defaults
|
|
20905
21059
|
// apply (dormant: gatewayCpu=0.25, gatewayMemory=0.5Gi, every referee/exam var
|
|
20906
21060
|
// empty). Only pass these when explicitly enabling the referee exam stack.
|
|
20907
|
-
gatewayCpu =
|
|
20908
|
-
gatewayMemory =
|
|
20909
|
-
refereeEnabled =
|
|
20910
|
-
refereeBrainRepos =
|
|
20911
|
-
refereeFeedRepo =
|
|
20912
|
-
refereeInstallationId =
|
|
20913
|
-
refereeWebhookHmacKvUri =
|
|
20914
|
-
examKvUri =
|
|
20915
|
-
examLaWorkspaceId =
|
|
20916
|
-
brainEvalDeployment =
|
|
20917
|
-
brainAppLogin =
|
|
20918
|
-
refereeCheckpointDir =
|
|
20919
|
-
examApiBase =
|
|
21061
|
+
gatewayCpu = Option34.String("--gateway-cpu");
|
|
21062
|
+
gatewayMemory = Option34.String("--gateway-memory");
|
|
21063
|
+
refereeEnabled = Option34.String("--referee-enabled");
|
|
21064
|
+
refereeBrainRepos = Option34.String("--referee-brain-repos");
|
|
21065
|
+
refereeFeedRepo = Option34.String("--referee-feed-repo");
|
|
21066
|
+
refereeInstallationId = Option34.String("--referee-installation-id");
|
|
21067
|
+
refereeWebhookHmacKvUri = Option34.String("--referee-webhook-hmac-kv-uri");
|
|
21068
|
+
examKvUri = Option34.String("--exam-kv-uri");
|
|
21069
|
+
examLaWorkspaceId = Option34.String("--exam-la-workspace-id");
|
|
21070
|
+
brainEvalDeployment = Option34.String("--brain-eval-deployment");
|
|
21071
|
+
brainAppLogin = Option34.String("--brain-app-login");
|
|
21072
|
+
refereeCheckpointDir = Option34.String("--referee-checkpoint-dir");
|
|
21073
|
+
examApiBase = Option34.String("--exam-api-base");
|
|
20920
21074
|
async executeCommand() {
|
|
20921
21075
|
const mode = resolveOutputMode(
|
|
20922
21076
|
this.output,
|
|
@@ -21056,7 +21210,7 @@ var DeployCommand = class extends M8tCommand {
|
|
|
21056
21210
|
|
|
21057
21211
|
// src/commands/eval/skill.ts
|
|
21058
21212
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
21059
|
-
import { Command as
|
|
21213
|
+
import { Command as Command38, Option as Option35 } from "clipanion";
|
|
21060
21214
|
init_errors();
|
|
21061
21215
|
var DECISIONS = /* @__PURE__ */ new Set(["promote", "reject", "needs_review"]);
|
|
21062
21216
|
var JUDGE_STATUSES = /* @__PURE__ */ new Set(["ok", "skipped", "unavailable"]);
|
|
@@ -21081,14 +21235,14 @@ function parseVerdict(stdout) {
|
|
|
21081
21235
|
}
|
|
21082
21236
|
var EvalSkillCommand = class extends M8tCommand {
|
|
21083
21237
|
static paths = [["eval", "skill"]];
|
|
21084
|
-
static usage =
|
|
21238
|
+
static usage = Command38.Usage({
|
|
21085
21239
|
description: "Vet one inbox skill candidate (Brain Faculties Eval F1): promote / reject / needs_review. Shells out to the Python `brain-eval` core (override its path with $BRAIN_EVAL_BIN)."
|
|
21086
21240
|
});
|
|
21087
|
-
candidate =
|
|
21088
|
-
skillsDir =
|
|
21089
|
-
noJudge =
|
|
21090
|
-
deployment =
|
|
21091
|
-
output =
|
|
21241
|
+
candidate = Option35.String();
|
|
21242
|
+
skillsDir = Option35.String("--skills-dir");
|
|
21243
|
+
noJudge = Option35.Boolean("--no-judge", false);
|
|
21244
|
+
deployment = Option35.String("--deployment");
|
|
21245
|
+
output = Option35.String("--output");
|
|
21092
21246
|
executeCommand() {
|
|
21093
21247
|
return Promise.resolve(this._runCommand());
|
|
21094
21248
|
}
|
|
@@ -21145,9 +21299,9 @@ var EvalSkillCommand = class extends M8tCommand {
|
|
|
21145
21299
|
|
|
21146
21300
|
// src/commands/eval/exam.ts
|
|
21147
21301
|
import { spawnSync as spawnSync5 } from "child_process";
|
|
21148
|
-
import { writeFileSync as writeFileSync6, mkdirSync as mkdirSync5, readFileSync as
|
|
21302
|
+
import { writeFileSync as writeFileSync6, mkdirSync as mkdirSync5, readFileSync as readFileSync18, existsSync as existsSync15, readdirSync as readdirSync2 } from "fs";
|
|
21149
21303
|
import { join as join27 } from "path";
|
|
21150
|
-
import { Command as
|
|
21304
|
+
import { Command as Command39, Option as Option36 } from "clipanion";
|
|
21151
21305
|
init_errors();
|
|
21152
21306
|
init_esm();
|
|
21153
21307
|
function parseArmToken(tok, opts) {
|
|
@@ -21350,7 +21504,7 @@ function readSealedTaskIds(taskSetVersion, refereeHomeOut, env = process.env) {
|
|
|
21350
21504
|
const manifestPath = join27(home, "tasksets", worker, versionDir, "manifest.yaml");
|
|
21351
21505
|
let text;
|
|
21352
21506
|
try {
|
|
21353
|
-
text =
|
|
21507
|
+
text = readFileSync18(manifestPath, "utf-8");
|
|
21354
21508
|
} catch (e) {
|
|
21355
21509
|
throw new LocalCliError({
|
|
21356
21510
|
code: "EXAM_REDACTION_UNSAFE",
|
|
@@ -21377,24 +21531,24 @@ function buildPlan(args) {
|
|
|
21377
21531
|
}
|
|
21378
21532
|
var EvalExamCommand = class extends M8tCommand {
|
|
21379
21533
|
static paths = [["eval", "exam"]];
|
|
21380
|
-
static usage =
|
|
21534
|
+
static usage = Command39.Usage({
|
|
21381
21535
|
description: "Run a brain exam (Brain Referee E2-F2): 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."
|
|
21382
21536
|
});
|
|
21383
|
-
worker =
|
|
21384
|
-
arms =
|
|
21385
|
-
taskSet =
|
|
21386
|
-
examType =
|
|
21387
|
-
skill =
|
|
21388
|
-
reps =
|
|
21389
|
-
probes =
|
|
21390
|
-
pool =
|
|
21391
|
-
out =
|
|
21392
|
-
dryRun =
|
|
21393
|
-
keepArms =
|
|
21394
|
-
allowStub =
|
|
21395
|
-
deployment =
|
|
21396
|
-
output =
|
|
21397
|
-
observeWaitS =
|
|
21537
|
+
worker = Option36.String();
|
|
21538
|
+
arms = Option36.String("--arms");
|
|
21539
|
+
taskSet = Option36.String("--task-set");
|
|
21540
|
+
examType = Option36.String("--exam-type");
|
|
21541
|
+
skill = Option36.String("--skill");
|
|
21542
|
+
reps = Option36.String("-n,--reps");
|
|
21543
|
+
probes = Option36.String("--probes");
|
|
21544
|
+
pool = Option36.String("--pool");
|
|
21545
|
+
out = Option36.String("--out");
|
|
21546
|
+
dryRun = Option36.Boolean("--dry-run", false);
|
|
21547
|
+
keepArms = Option36.Boolean("--keep-arms", false);
|
|
21548
|
+
allowStub = Option36.Boolean("--allow-stub", false);
|
|
21549
|
+
deployment = Option36.String("--deployment");
|
|
21550
|
+
output = Option36.String("--output");
|
|
21551
|
+
observeWaitS = Option36.String("--observe-wait-s");
|
|
21398
21552
|
async executeCommand() {
|
|
21399
21553
|
await Promise.resolve();
|
|
21400
21554
|
const worker = typeof this.worker === "string" ? this.worker : void 0;
|
|
@@ -21509,10 +21663,10 @@ var EvalExamCommand = class extends M8tCommand {
|
|
|
21509
21663
|
};
|
|
21510
21664
|
|
|
21511
21665
|
// src/commands/version.ts
|
|
21512
|
-
import { Command as
|
|
21666
|
+
import { Command as Command40, Option as Option37 } from "clipanion";
|
|
21513
21667
|
var VersionCommand = class extends M8tCommand {
|
|
21514
21668
|
static paths = [["version"], ["--version"], ["-v"]];
|
|
21515
|
-
static usage =
|
|
21669
|
+
static usage = Command40.Usage({
|
|
21516
21670
|
description: "Print the CLI version.",
|
|
21517
21671
|
details: "Prints the m8t CLI version. With --verbose, also prints Node version and platform.",
|
|
21518
21672
|
examples: [
|
|
@@ -21520,8 +21674,8 @@ var VersionCommand = class extends M8tCommand {
|
|
|
21520
21674
|
["Print as JSON", "$0 version --output json"]
|
|
21521
21675
|
]
|
|
21522
21676
|
});
|
|
21523
|
-
output =
|
|
21524
|
-
verbose =
|
|
21677
|
+
output = Option37.String("--output", { description: "pretty | json | auto (default)" });
|
|
21678
|
+
verbose = Option37.Boolean("--verbose", false);
|
|
21525
21679
|
executeCommand() {
|
|
21526
21680
|
const mode = resolveOutputMode(
|
|
21527
21681
|
this.output ?? "auto",
|
|
@@ -21552,18 +21706,18 @@ var VersionCommand = class extends M8tCommand {
|
|
|
21552
21706
|
};
|
|
21553
21707
|
|
|
21554
21708
|
// src/commands/whoami.ts
|
|
21555
|
-
import { Command as
|
|
21709
|
+
import { Command as Command41, Option as Option38 } from "clipanion";
|
|
21556
21710
|
var WhoamiCommand = class extends M8tCommand {
|
|
21557
21711
|
static paths = [["whoami"]];
|
|
21558
|
-
static usage =
|
|
21712
|
+
static usage = Command41.Usage({
|
|
21559
21713
|
description: "Show your identity + the gateway you'll talk to. Probes the backend."
|
|
21560
21714
|
});
|
|
21561
|
-
output =
|
|
21562
|
-
verbose =
|
|
21563
|
-
subscription =
|
|
21715
|
+
output = Option38.String("--output");
|
|
21716
|
+
verbose = Option38.Boolean("--verbose", false);
|
|
21717
|
+
subscription = Option38.String("--subscription", {
|
|
21564
21718
|
description: "Azure subscription ID to discover gateway in (defaults to active az subscription)."
|
|
21565
21719
|
});
|
|
21566
|
-
resourceGroup =
|
|
21720
|
+
resourceGroup = Option38.String("--resource-group", {
|
|
21567
21721
|
description: "m8t resource group to disambiguate the gateway (multi-deployment subscriptions)."
|
|
21568
21722
|
});
|
|
21569
21723
|
async executeCommand() {
|
|
@@ -21628,14 +21782,14 @@ var WhoamiCommand = class extends M8tCommand {
|
|
|
21628
21782
|
};
|
|
21629
21783
|
|
|
21630
21784
|
// src/commands/status.ts
|
|
21631
|
-
import { Command as
|
|
21785
|
+
import { Command as Command42, Option as Option39 } from "clipanion";
|
|
21632
21786
|
|
|
21633
21787
|
// src/lib/azd.ts
|
|
21634
21788
|
init_errors();
|
|
21635
21789
|
import { spawn as spawn4 } from "child_process";
|
|
21636
21790
|
function runAzd(args) {
|
|
21637
21791
|
return new Promise((resolve3, reject) => {
|
|
21638
|
-
const proc = spawn4("azd", args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
21792
|
+
const proc = spawn4("azd", args, { stdio: ["ignore", "pipe", "pipe"], shell: process.platform === "win32" });
|
|
21639
21793
|
const out = [];
|
|
21640
21794
|
const err = [];
|
|
21641
21795
|
proc.stdout.on("data", (d) => out.push(d));
|
|
@@ -21693,10 +21847,10 @@ async function resolveLocalContext() {
|
|
|
21693
21847
|
// src/commands/status.ts
|
|
21694
21848
|
var StatusCommand = class extends M8tCommand {
|
|
21695
21849
|
static paths = [["status"]];
|
|
21696
|
-
static usage =
|
|
21850
|
+
static usage = Command42.Usage({
|
|
21697
21851
|
description: "Show the local m8t context: identity, config.yaml, gateway cache, azd mode."
|
|
21698
21852
|
});
|
|
21699
|
-
output =
|
|
21853
|
+
output = Option39.String("--output");
|
|
21700
21854
|
async executeCommand() {
|
|
21701
21855
|
const mode = resolveOutputMode(
|
|
21702
21856
|
this.output,
|
|
@@ -21734,8 +21888,8 @@ var StatusCommand = class extends M8tCommand {
|
|
|
21734
21888
|
};
|
|
21735
21889
|
|
|
21736
21890
|
// src/commands/doctor.ts
|
|
21737
|
-
import { Command as
|
|
21738
|
-
import { DefaultAzureCredential as
|
|
21891
|
+
import { Command as Command43, Option as Option40 } from "clipanion";
|
|
21892
|
+
import { DefaultAzureCredential as DefaultAzureCredential20 } from "@azure/identity";
|
|
21739
21893
|
import * as fs26 from "fs";
|
|
21740
21894
|
import * as os11 from "os";
|
|
21741
21895
|
import * as path28 from "path";
|
|
@@ -22010,12 +22164,12 @@ function probeLegacyStateDir() {
|
|
|
22010
22164
|
}
|
|
22011
22165
|
var DoctorCommand = class extends M8tCommand {
|
|
22012
22166
|
static paths = [["doctor"]];
|
|
22013
|
-
static usage =
|
|
22167
|
+
static usage = Command43.Usage({
|
|
22014
22168
|
description: "Diagnose the local m8t setup: az login, config.yaml, gateway, Foundry data-plane."
|
|
22015
22169
|
});
|
|
22016
|
-
output =
|
|
22017
|
-
agent =
|
|
22018
|
-
resourceGroup =
|
|
22170
|
+
output = Option40.String("--output");
|
|
22171
|
+
agent = Option40.String("--agent");
|
|
22172
|
+
resourceGroup = Option40.String("--resource-group", {
|
|
22019
22173
|
description: "m8t resource group to disambiguate the gateway (multi-deployment subscriptions)."
|
|
22020
22174
|
});
|
|
22021
22175
|
async executeCommand() {
|
|
@@ -22089,7 +22243,7 @@ var DoctorCommand = class extends M8tCommand {
|
|
|
22089
22243
|
if (typeof this.agent === "string" && this.agent) {
|
|
22090
22244
|
checking(`delivery grant for ${this.agent}`);
|
|
22091
22245
|
try {
|
|
22092
|
-
const credential2 = new
|
|
22246
|
+
const credential2 = new DefaultAzureCredential20();
|
|
22093
22247
|
const cur = await getAgentVersion({
|
|
22094
22248
|
credential: credential2,
|
|
22095
22249
|
projectEndpoint: foundry.projectEndpoint,
|
|
@@ -22132,7 +22286,7 @@ var DoctorCommand = class extends M8tCommand {
|
|
|
22132
22286
|
};
|
|
22133
22287
|
|
|
22134
22288
|
// src/commands/switch.ts
|
|
22135
|
-
import { Command as
|
|
22289
|
+
import { Command as Command44, Option as Option41 } from "clipanion";
|
|
22136
22290
|
|
|
22137
22291
|
// src/lib/profiles.ts
|
|
22138
22292
|
import * as fs27 from "fs/promises";
|
|
@@ -22272,14 +22426,14 @@ async function profileSwitch(name, asName) {
|
|
|
22272
22426
|
init_errors();
|
|
22273
22427
|
var SwitchCommand = class extends M8tCommand {
|
|
22274
22428
|
static paths = [["switch"]];
|
|
22275
|
-
static usage =
|
|
22429
|
+
static usage = Command44.Usage({
|
|
22276
22430
|
description: "Re-point local config at another deployment: --subscription <id|name> (discovery) or <profile>."
|
|
22277
22431
|
});
|
|
22278
|
-
profile =
|
|
22279
|
-
subscription =
|
|
22280
|
-
list =
|
|
22281
|
-
as =
|
|
22282
|
-
output =
|
|
22432
|
+
profile = Option41.String({ required: false });
|
|
22433
|
+
subscription = Option41.String("--subscription");
|
|
22434
|
+
list = Option41.Boolean("--list", false);
|
|
22435
|
+
as = Option41.String("--as");
|
|
22436
|
+
output = Option41.String("--output");
|
|
22283
22437
|
async executeCommand() {
|
|
22284
22438
|
const mode = resolveOutputMode(
|
|
22285
22439
|
this.output,
|
|
@@ -22336,7 +22490,7 @@ var SwitchCommand = class extends M8tCommand {
|
|
|
22336
22490
|
|
|
22337
22491
|
// src/commands/open.ts
|
|
22338
22492
|
import { spawn as spawn5 } from "child_process";
|
|
22339
|
-
import { Command as
|
|
22493
|
+
import { Command as Command45, Option as Option42 } from "clipanion";
|
|
22340
22494
|
|
|
22341
22495
|
// src/lib/open-targets.ts
|
|
22342
22496
|
init_errors();
|
|
@@ -22382,14 +22536,14 @@ function openUrl(url) {
|
|
|
22382
22536
|
}
|
|
22383
22537
|
var OpenCommand = class extends M8tCommand {
|
|
22384
22538
|
static paths = [["open"]];
|
|
22385
|
-
static usage =
|
|
22539
|
+
static usage = Command45.Usage({
|
|
22386
22540
|
description: "Open the deployed webapp (default), the Foundry portal, or the resource group.",
|
|
22387
22541
|
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)."
|
|
22388
22542
|
});
|
|
22389
|
-
target =
|
|
22390
|
-
print =
|
|
22391
|
-
output =
|
|
22392
|
-
resourceGroup =
|
|
22543
|
+
target = Option42.String({ required: false });
|
|
22544
|
+
print = Option42.Boolean("--print", false);
|
|
22545
|
+
output = Option42.String("--output");
|
|
22546
|
+
resourceGroup = Option42.String("--resource-group", {
|
|
22393
22547
|
description: "m8t resource group to disambiguate the gateway (multi-deployment subscriptions)."
|
|
22394
22548
|
});
|
|
22395
22549
|
async executeCommand() {
|
|
@@ -22433,7 +22587,7 @@ var OpenCommand = class extends M8tCommand {
|
|
|
22433
22587
|
};
|
|
22434
22588
|
|
|
22435
22589
|
// src/commands/dream/run.ts
|
|
22436
|
-
import { Command as
|
|
22590
|
+
import { Command as Command46, Option as Option43 } from "clipanion";
|
|
22437
22591
|
import { AzureCliCredential } from "@azure/identity";
|
|
22438
22592
|
import { TableClient as TableClient5 } from "@azure/data-tables";
|
|
22439
22593
|
import { AIProjectClient as AIProjectClient3 } from "@azure/ai-projects";
|
|
@@ -22778,7 +22932,7 @@ var TableCursor = class {
|
|
|
22778
22932
|
* Point-read the canonical worker's cursor row. Catches BOTH the
|
|
22779
22933
|
* missing-table (TableNotFound) and missing-row (ResourceNotFound) 404s and
|
|
22780
22934
|
* returns an absent (from-the-beginning) cursor WITHOUT creating the table or
|
|
22781
|
-
* writing anything
|
|
22935
|
+
* writing anything.
|
|
22782
22936
|
* Any other error (e.g. 403 RBAC) propagates raw.
|
|
22783
22937
|
*/
|
|
22784
22938
|
async read(worker) {
|
|
@@ -22804,9 +22958,9 @@ var TableCursor = class {
|
|
|
22804
22958
|
}
|
|
22805
22959
|
/**
|
|
22806
22960
|
* Persist the cursor for the canonical worker. This is the ONLY place that
|
|
22807
|
-
* creates the BrainDreamCursor table
|
|
22808
|
-
* TableAlreadyExists race is benign. The non-dry
|
|
22809
|
-
*
|
|
22961
|
+
* creates the BrainDreamCursor table; a
|
|
22962
|
+
* TableAlreadyExists race is benign. The non-dry path calls this, already
|
|
22963
|
+
* wired and unit-tested. The per-PK watermark map is serialized to JSON
|
|
22810
22964
|
* (Table cells are scalar — same rationale as agent-ledger's `artifacts`).
|
|
22811
22965
|
*/
|
|
22812
22966
|
async advance(worker, cursor) {
|
|
@@ -22939,6 +23093,35 @@ function makeLedgerSource(read) {
|
|
|
22939
23093
|
// ../../packages/brain/engine/dist/esm/conversation-source.js
|
|
22940
23094
|
var TRANSIENT = 500;
|
|
22941
23095
|
var MAX_ATTEMPTS = 5;
|
|
23096
|
+
var VOICE_PREFIX = "[[m8t:voice-transcript]] ";
|
|
23097
|
+
var MAX_VOICE_HEADER_BYTES = 4096;
|
|
23098
|
+
function isVoiceEnvelope(value) {
|
|
23099
|
+
if (typeof value !== "object" || value === null)
|
|
23100
|
+
return false;
|
|
23101
|
+
const item = value;
|
|
23102
|
+
return item.v === 1 && typeof item.callId === "string" && item.callId.length > 0 && typeof item.startedAt === "string" && item.startedAt.length > 0 && typeof item.endedAt === "string" && item.endedAt.length > 0 && typeof item.turnAt === "string" && item.turnAt.length > 0;
|
|
23103
|
+
}
|
|
23104
|
+
function stripVoiceEnvelope(value) {
|
|
23105
|
+
if (!value.startsWith(VOICE_PREFIX))
|
|
23106
|
+
return value;
|
|
23107
|
+
const newline = value.indexOf("\n");
|
|
23108
|
+
if (newline < VOICE_PREFIX.length)
|
|
23109
|
+
return value;
|
|
23110
|
+
const header = value.slice(VOICE_PREFIX.length, newline);
|
|
23111
|
+
if (new TextEncoder().encode(header).byteLength > MAX_VOICE_HEADER_BYTES || header.length % 4 === 1 || !/^[A-Za-z0-9_-]+$/.test(header))
|
|
23112
|
+
return value;
|
|
23113
|
+
try {
|
|
23114
|
+
const padded = header.replaceAll("-", "+").replaceAll("_", "/") + "=".repeat((4 - header.length % 4) % 4);
|
|
23115
|
+
const bytes = Uint8Array.from(Buffer.from(padded, "base64"));
|
|
23116
|
+
if (Buffer.from(bytes).toString("base64url") !== header)
|
|
23117
|
+
return value;
|
|
23118
|
+
const json = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
23119
|
+
const parsed = JSON.parse(json);
|
|
23120
|
+
return isVoiceEnvelope(parsed) ? value.slice(newline + 1) : value;
|
|
23121
|
+
} catch {
|
|
23122
|
+
return value;
|
|
23123
|
+
}
|
|
23124
|
+
}
|
|
22942
23125
|
function statusOf(e) {
|
|
22943
23126
|
const err = e;
|
|
22944
23127
|
return err?.statusCode ?? err?.status;
|
|
@@ -22954,7 +23137,7 @@ function mapItems(raw) {
|
|
|
22954
23137
|
continue;
|
|
22955
23138
|
if (item.role !== "user" && item.role !== "assistant")
|
|
22956
23139
|
continue;
|
|
22957
|
-
const text = Array.isArray(item.content) ? item.content.map((c) => typeof c.text === "string" ? c.text : "").filter(Boolean).join("\n\n") : "";
|
|
23140
|
+
const text = Array.isArray(item.content) ? stripVoiceEnvelope(item.content.map((c) => typeof c.text === "string" && c.text.length > 0 ? c.text : typeof c.transcript === "string" && c.transcript.length > 0 ? c.transcript : "").filter(Boolean).join("\n\n")) : "";
|
|
22958
23141
|
const at = typeof item.created_at === "number" ? new Date(item.created_at * 1e3).toISOString() : void 0;
|
|
22959
23142
|
acc.push(at ? { role: item.role, text, at } : { role: item.role, text });
|
|
22960
23143
|
}
|
|
@@ -22988,7 +23171,7 @@ function makeConversationSource(client, opts = {}) {
|
|
|
22988
23171
|
throw new ConvFetchError("terminal", `exhausted retries reading ${conversationId}`);
|
|
22989
23172
|
},
|
|
22990
23173
|
/**
|
|
22991
|
-
* The a2a recovery gate's data source (
|
|
23174
|
+
* The a2a recovery gate's data source (Option A). Reads the
|
|
22992
23175
|
* conversation's own `metadata.app` so the recovery path can HARD-gate on the
|
|
22993
23176
|
* real app tag rather than emit-time ledger tagging. Degrades to null on any
|
|
22994
23177
|
* error → the caller treats an un-provable a2a conv as ungated (skipped).
|
|
@@ -23272,7 +23455,7 @@ async function runPipeline(args) {
|
|
|
23272
23455
|
consumed,
|
|
23273
23456
|
recovered,
|
|
23274
23457
|
skipped,
|
|
23275
|
-
// Wall-clock elapsed around the awaited live I/O
|
|
23458
|
+
// Wall-clock elapsed around the awaited live I/O — measured from the
|
|
23276
23459
|
// real/injected monotonic clock, NOT the pure `now` (which never moves within a run).
|
|
23277
23460
|
latencyMs: Math.round(monotonicNow() - t0)
|
|
23278
23461
|
};
|
|
@@ -23393,11 +23576,11 @@ var WRITER_ALLOWED_PREFIX = /^(memory|inbox|quarantine|artifacts)\//;
|
|
|
23393
23576
|
var isAllowedWritePath = (path37, allowedPrefix) => allowedPrefix.test(path37) && !path37.split("/").includes("..");
|
|
23394
23577
|
var unquote = (s) => s.trim().replace(/^["']|["']$/g, "");
|
|
23395
23578
|
function parseFrontmatter(content) {
|
|
23396
|
-
const m = /^---\n([\s\S]*?)\n---/.exec(content);
|
|
23579
|
+
const m = /^---\r?\n([\s\S]*?)\r?\n---/.exec(content);
|
|
23397
23580
|
if (!m)
|
|
23398
23581
|
return {};
|
|
23399
23582
|
const fm = {};
|
|
23400
|
-
const lines = m[1].split(
|
|
23583
|
+
const lines = m[1].split(/\r?\n/);
|
|
23401
23584
|
let pendingKey = null;
|
|
23402
23585
|
for (const line2 of lines) {
|
|
23403
23586
|
const item = /^\s+-\s+(.*)$/.exec(line2);
|
|
@@ -24075,7 +24258,7 @@ function frontmatter(fields) {
|
|
|
24075
24258
|
return lines.join("\n");
|
|
24076
24259
|
}
|
|
24077
24260
|
function injectFrontmatter(body, fields) {
|
|
24078
|
-
const m = /^---\n([\s\S]*?)\n---\n?/.exec(body);
|
|
24261
|
+
const m = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/.exec(body);
|
|
24079
24262
|
const inject = Object.entries(fields).map(([k, v]) => Array.isArray(v) ? `${k}:
|
|
24080
24263
|
${v.map((i) => ` - ${i}`).join("\n")}` : `${k}: ${v}`).join("\n");
|
|
24081
24264
|
if (!m)
|
|
@@ -24084,11 +24267,11 @@ ${inject}
|
|
|
24084
24267
|
---
|
|
24085
24268
|
${body}`;
|
|
24086
24269
|
const block = m[1].replace(/\s*$/, "");
|
|
24087
|
-
return
|
|
24270
|
+
return `---
|
|
24088
24271
|
${block}
|
|
24089
24272
|
${inject}
|
|
24090
24273
|
---
|
|
24091
|
-
`);
|
|
24274
|
+
` + body.slice(m[0].length);
|
|
24092
24275
|
}
|
|
24093
24276
|
var indexLine = (path37, title, date, tags) => `- \`${path37}\` \u2014 **${title}**: ${title}. (${date} \xB7 ${tags.join(", ")})`;
|
|
24094
24277
|
function splitIndex(index) {
|
|
@@ -24248,7 +24431,7 @@ function defaultDreamSeams(opts = {}) {
|
|
|
24248
24431
|
const user = buildUserPrompt(input, mem.files);
|
|
24249
24432
|
const res = await propose(deps.model, system, user, {
|
|
24250
24433
|
...opts.sleep ? { sleep: opts.sleep } : {},
|
|
24251
|
-
// The configured model NAME for the cost digest
|
|
24434
|
+
// The configured model NAME for the cost digest. Without
|
|
24252
24435
|
// this, propose falls back to its default and every cost line mis-reports
|
|
24253
24436
|
// the model an operator actually configured (e.g. gpt-5-mini → "gpt-5.4").
|
|
24254
24437
|
...deps.modelName ? { model: deps.modelName } : {}
|
|
@@ -24631,20 +24814,20 @@ function redactTranscripts(input) {
|
|
|
24631
24814
|
}
|
|
24632
24815
|
var DreamRunCommand = class extends M8tCommand {
|
|
24633
24816
|
static paths = [["dream", "run"]];
|
|
24634
|
-
static usage =
|
|
24817
|
+
static usage = Command46.Usage({
|
|
24635
24818
|
description: "Dry-run the brain consumption pipeline for one worker (no model call, no writes).",
|
|
24636
24819
|
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."
|
|
24637
24820
|
});
|
|
24638
|
-
worker =
|
|
24639
|
-
dryRun =
|
|
24640
|
-
since =
|
|
24641
|
-
reset =
|
|
24642
|
-
showTranscripts =
|
|
24821
|
+
worker = Option43.String("--worker", { description: "Worker (canonical name) to harvest. Required." });
|
|
24822
|
+
dryRun = Option43.Boolean("--dry-run", false, { description: "Read-only harvest; no model call, no writes." });
|
|
24823
|
+
since = Option43.String("--since", { description: "ISO-8601 start override (rejected if malformed or future)." });
|
|
24824
|
+
reset = Option43.Boolean("--reset", false, { description: "Ignore the stored cursor; read from the beginning." });
|
|
24825
|
+
showTranscripts = Option43.Boolean("--show-transcripts", false, {
|
|
24643
24826
|
description: "Print transcript bodies (default: metadata only)."
|
|
24644
24827
|
});
|
|
24645
|
-
subscription =
|
|
24646
|
-
endpoint =
|
|
24647
|
-
output =
|
|
24828
|
+
subscription = Option43.String("--subscription");
|
|
24829
|
+
endpoint = Option43.String("--endpoint");
|
|
24830
|
+
output = Option43.String("--output");
|
|
24648
24831
|
// Resolution seam — overridden by tests; built lazily at runtime otherwise.
|
|
24649
24832
|
deps;
|
|
24650
24833
|
async executeCommand() {
|
|
@@ -24900,7 +25083,7 @@ async function buildWriteDeps(context, credential2, cursor) {
|
|
|
24900
25083
|
return {
|
|
24901
25084
|
model: makeFoundryModelClient(openai, model),
|
|
24902
25085
|
modelName: model,
|
|
24903
|
-
// surface the resolved name for the cost digest
|
|
25086
|
+
// surface the resolved name for the cost digest
|
|
24904
25087
|
brain,
|
|
24905
25088
|
cursor,
|
|
24906
25089
|
clock: () => /* @__PURE__ */ new Date(),
|
|
@@ -24992,7 +25175,7 @@ function defaultDeps(overrides) {
|
|
|
24992
25175
|
}
|
|
24993
25176
|
|
|
24994
25177
|
// src/commands/foundry/create.ts
|
|
24995
|
-
import { Command as
|
|
25178
|
+
import { Command as Command47, Option as Option44 } from "clipanion";
|
|
24996
25179
|
|
|
24997
25180
|
// src/lib/foundry-create.ts
|
|
24998
25181
|
init_errors();
|
|
@@ -25230,7 +25413,7 @@ async function createFoundryProject(args) {
|
|
|
25230
25413
|
init_errors();
|
|
25231
25414
|
var FoundryCreateCommand = class extends M8tCommand {
|
|
25232
25415
|
static paths = [["foundry", "create"]];
|
|
25233
|
-
static usage =
|
|
25416
|
+
static usage = Command47.Usage({
|
|
25234
25417
|
description: "Create an AI Foundry (AIServices) account + project + model deployment from scratch.",
|
|
25235
25418
|
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).",
|
|
25236
25419
|
examples: [
|
|
@@ -25239,16 +25422,16 @@ var FoundryCreateCommand = class extends M8tCommand {
|
|
|
25239
25422
|
["Higher capacity for a reasoning model", "$0 foundry create --resource-group rg-m8t-stack --location eastus2 --model gpt-5-mini --capacity 250"]
|
|
25240
25423
|
]
|
|
25241
25424
|
});
|
|
25242
|
-
resourceGroup =
|
|
25243
|
-
location =
|
|
25244
|
-
account =
|
|
25245
|
-
project =
|
|
25246
|
-
model =
|
|
25247
|
-
modelVersion =
|
|
25248
|
-
capacity =
|
|
25249
|
-
subscription =
|
|
25250
|
-
skipQuotaCheck =
|
|
25251
|
-
output =
|
|
25425
|
+
resourceGroup = Option44.String("--resource-group");
|
|
25426
|
+
location = Option44.String("--location");
|
|
25427
|
+
account = Option44.String("--account");
|
|
25428
|
+
project = Option44.String("--project", "m8t");
|
|
25429
|
+
model = Option44.String("--model", "gpt-4.1-mini");
|
|
25430
|
+
modelVersion = Option44.String("--model-version", "2025-04-14");
|
|
25431
|
+
capacity = Option44.String("--capacity", "50");
|
|
25432
|
+
subscription = Option44.String("--subscription");
|
|
25433
|
+
skipQuotaCheck = Option44.Boolean("--skip-quota-check", false);
|
|
25434
|
+
output = Option44.String("--output");
|
|
25252
25435
|
async executeCommand() {
|
|
25253
25436
|
const mode = resolveOutputMode(
|
|
25254
25437
|
this.output,
|
|
@@ -25320,22 +25503,22 @@ var FoundryCreateCommand = class extends M8tCommand {
|
|
|
25320
25503
|
};
|
|
25321
25504
|
|
|
25322
25505
|
// src/commands/foundry/await-ready.ts
|
|
25323
|
-
import { Command as
|
|
25506
|
+
import { Command as Command48, Option as Option45 } from "clipanion";
|
|
25324
25507
|
import { AzureCliCredential as AzureCliCredential2 } from "@azure/identity";
|
|
25325
25508
|
init_errors();
|
|
25326
25509
|
var FoundryAwaitReadyCommand = class extends M8tCommand {
|
|
25327
25510
|
static paths = [["foundry", "await-ready"]];
|
|
25328
|
-
static usage =
|
|
25511
|
+
static usage = Command48.Usage({
|
|
25329
25512
|
description: "Wait until a freshly-created Foundry project's data plane reliably serves it.",
|
|
25330
25513
|
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.",
|
|
25331
25514
|
examples: [["Wait for a project to be ready", "$0 foundry await-ready --endpoint https://acc.services.ai.azure.com/api/projects/m8t"]]
|
|
25332
25515
|
});
|
|
25333
|
-
endpoint =
|
|
25334
|
-
consecutive =
|
|
25335
|
-
attempts =
|
|
25336
|
-
interval =
|
|
25337
|
-
subscription =
|
|
25338
|
-
output =
|
|
25516
|
+
endpoint = Option45.String("--endpoint");
|
|
25517
|
+
consecutive = Option45.String("--consecutive", "3");
|
|
25518
|
+
attempts = Option45.String("--attempts", "60");
|
|
25519
|
+
interval = Option45.String("--interval", "5");
|
|
25520
|
+
subscription = Option45.String("--subscription");
|
|
25521
|
+
output = Option45.String("--output");
|
|
25339
25522
|
async executeCommand() {
|
|
25340
25523
|
const mode = resolveOutputMode(this.output, this.context.stdout);
|
|
25341
25524
|
const endpoint = typeof this.endpoint === "string" ? this.endpoint : void 0;
|
|
@@ -25369,7 +25552,33 @@ var FoundryAwaitReadyCommand = class extends M8tCommand {
|
|
|
25369
25552
|
};
|
|
25370
25553
|
|
|
25371
25554
|
// src/commands/bootstrap/preflight.ts
|
|
25372
|
-
import { Command as
|
|
25555
|
+
import { Command as Command49, Option as Option46 } from "clipanion";
|
|
25556
|
+
|
|
25557
|
+
// ../../packages/telemetry-contract/artifact/tier-map.ts
|
|
25558
|
+
var EVENT_TIERS = {
|
|
25559
|
+
"enrolled": 1,
|
|
25560
|
+
"install-started": 1,
|
|
25561
|
+
"install-succeeded": 1,
|
|
25562
|
+
"install-failed": 1,
|
|
25563
|
+
"heartbeat": 1,
|
|
25564
|
+
"update-applied": 1,
|
|
25565
|
+
"update-failed": 1,
|
|
25566
|
+
"consent-changed": 1
|
|
25567
|
+
// extended additively for tier-2 usage events: "usage-rollup": 2
|
|
25568
|
+
};
|
|
25569
|
+
var EVENT_ENUM = Object.keys(EVENT_TIERS);
|
|
25570
|
+
|
|
25571
|
+
// ../../packages/telemetry-contract/src/disclosure.ts
|
|
25572
|
+
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. This is service data used only to operate and support the platform; it contains none of your content. Details: TELEMETRY.md.";
|
|
25573
|
+
|
|
25574
|
+
// ../../packages/telemetry-contract/src/endpoints.ts
|
|
25575
|
+
var INGEST_BASE_URL = (process.env.M8T_INGEST_BASE_URL ?? "").trim() || "https://m8t-admin.wonderfuldesert-721e332f.eastus2.azurecontainerapps.io";
|
|
25576
|
+
function ingestUrl(path37) {
|
|
25577
|
+
const base = INGEST_BASE_URL.replace(/\/+$/, "");
|
|
25578
|
+
return `${base}${path37.startsWith("/") ? path37 : `/${path37}`}`;
|
|
25579
|
+
}
|
|
25580
|
+
|
|
25581
|
+
// src/commands/bootstrap/preflight.ts
|
|
25373
25582
|
init_errors();
|
|
25374
25583
|
|
|
25375
25584
|
// src/lib/bootstrap-preflight.ts
|
|
@@ -25443,7 +25652,7 @@ function buildPreflightBanner(who) {
|
|
|
25443
25652
|
// src/commands/bootstrap/preflight.ts
|
|
25444
25653
|
var BootstrapPreflightCommand = class extends M8tCommand {
|
|
25445
25654
|
static paths = [["bootstrap", "preflight"]];
|
|
25446
|
-
static usage =
|
|
25655
|
+
static usage = Command49.Usage({
|
|
25447
25656
|
description: "Loudly verify you can install m8t (Owner/UAA + directory admin) and hard-stop if not.",
|
|
25448
25657
|
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), and registers Microsoft.ContainerInstance. Exits non-zero with the exact failing check + remedy.",
|
|
25449
25658
|
examples: [
|
|
@@ -25451,14 +25660,17 @@ var BootstrapPreflightCommand = class extends M8tCommand {
|
|
|
25451
25660
|
["BYO app registration (directory guests)", "$0 bootstrap preflight --client-id <appId>"]
|
|
25452
25661
|
]
|
|
25453
25662
|
});
|
|
25454
|
-
clientId =
|
|
25455
|
-
subscription =
|
|
25663
|
+
clientId = Option46.String("--client-id");
|
|
25664
|
+
subscription = Option46.String("--subscription");
|
|
25456
25665
|
async executeCommand() {
|
|
25457
25666
|
const clientId = typeof this.clientId === "string" ? this.clientId : void 0;
|
|
25458
25667
|
const account = await getAzAccount();
|
|
25459
25668
|
const subscriptionId = (typeof this.subscription === "string" ? this.subscription : void 0) ?? account.subscriptionId;
|
|
25460
25669
|
const oid = await getCallerObjectId();
|
|
25461
25670
|
this.context.stdout.write(buildPreflightBanner({ upn: account.upn, tenantId: account.tenantId, subscriptionId }) + "\n");
|
|
25671
|
+
this.context.stdout.write(`
|
|
25672
|
+
${colors.dim(DISCLOSURE_TIER1)}
|
|
25673
|
+
`);
|
|
25462
25674
|
this.context.stdout.write("Checking your access\u2026\n");
|
|
25463
25675
|
const sub = await checkSubScopeAdmin(oid, subscriptionId);
|
|
25464
25676
|
this.context.stdout.write(line(sub.ok, `${sub.role ?? "Owner/UAA"} at subscription scope`, "resource + role-assignment rights"));
|
|
@@ -25511,7 +25723,7 @@ ${colors.error(" " + why)}
|
|
|
25511
25723
|
import * as fs30 from "fs";
|
|
25512
25724
|
import * as os14 from "os";
|
|
25513
25725
|
import * as path32 from "path";
|
|
25514
|
-
import { Command as
|
|
25726
|
+
import { Command as Command50, Option as Option47 } from "clipanion";
|
|
25515
25727
|
init_errors();
|
|
25516
25728
|
|
|
25517
25729
|
// src/lib/bootstrap-mi.ts
|
|
@@ -25610,6 +25822,7 @@ function buildAciCreateArgs(s) {
|
|
|
25610
25822
|
];
|
|
25611
25823
|
if (s.gatewayImageRef) env.push(`GATEWAY_IMAGE_REF=${s.gatewayImageRef}`);
|
|
25612
25824
|
if (s.foundryTracing) env.push(`FOUNDRY_TRACING=${s.foundryTracing}`);
|
|
25825
|
+
if (s.enrollContactEmail) env.push(`M8T_ENROLL_CONTACT_EMAIL=${s.enrollContactEmail}`);
|
|
25613
25826
|
if (s.githubApp) {
|
|
25614
25827
|
const g = s.githubApp;
|
|
25615
25828
|
env.push(
|
|
@@ -25760,12 +25973,12 @@ async function writeBootstrapState(state, home = os13.homedir()) {
|
|
|
25760
25973
|
// src/commands/bootstrap/launch.ts
|
|
25761
25974
|
var DEFAULT_RG = "rg-m8t-stack";
|
|
25762
25975
|
var DEFAULT_INSTALLER = "ghcr.io/m8t-labs/m8t-installer";
|
|
25763
|
-
var DEFAULT_INSTALLER_TAG = "v0.1.
|
|
25976
|
+
var DEFAULT_INSTALLER_TAG = "v0.1.36";
|
|
25764
25977
|
var ACI_NAME = "m8t-installer";
|
|
25765
25978
|
var MI_NAME = "m8t-installer-mi";
|
|
25766
25979
|
var BootstrapLaunchCommand = class extends M8tCommand {
|
|
25767
25980
|
static paths = [["bootstrap", "launch"]];
|
|
25768
|
-
static usage =
|
|
25981
|
+
static usage = Command50.Usage({
|
|
25769
25982
|
description: "Create + authorize the installer managed identity, then kick the cloud installer.",
|
|
25770
25983
|
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`/`reap`/`finish`.",
|
|
25771
25984
|
examples: [
|
|
@@ -25775,17 +25988,17 @@ var BootstrapLaunchCommand = class extends M8tCommand {
|
|
|
25775
25988
|
["Override the full installer image ref", "$0 bootstrap launch --location eastus2 --installer-image ghcr.io/m8t-labs/m8t-installer:v0.1.33"]
|
|
25776
25989
|
]
|
|
25777
25990
|
});
|
|
25778
|
-
location =
|
|
25779
|
-
resourceGroup =
|
|
25780
|
-
clientId =
|
|
25781
|
-
subscription =
|
|
25782
|
-
installerTag =
|
|
25991
|
+
location = Option47.String("--location");
|
|
25992
|
+
resourceGroup = Option47.String("--resource-group");
|
|
25993
|
+
clientId = Option47.String("--client-id");
|
|
25994
|
+
subscription = Option47.String("--subscription");
|
|
25995
|
+
installerTag = Option47.String("--installer-tag");
|
|
25783
25996
|
// Full image ref override (registry + repo + tag) — an escape hatch when the
|
|
25784
25997
|
// default org/tag is wrong for the current CLI (e.g. a stale published build).
|
|
25785
25998
|
// Wins over --installer-tag / the pinned default.
|
|
25786
|
-
installerImage =
|
|
25787
|
-
gatewayImageRef =
|
|
25788
|
-
githubAppCreds =
|
|
25999
|
+
installerImage = Option47.String("--installer-image");
|
|
26000
|
+
gatewayImageRef = Option47.String("--gateway-image-ref");
|
|
26001
|
+
githubAppCreds = Option47.String("--github-app-creds");
|
|
25789
26002
|
async executeCommand() {
|
|
25790
26003
|
const location = typeof this.location === "string" ? this.location : void 0;
|
|
25791
26004
|
if (!location) {
|
|
@@ -25876,7 +26089,8 @@ var BootstrapLaunchCommand = class extends M8tCommand {
|
|
|
25876
26089
|
image: installerImage,
|
|
25877
26090
|
gatewayImageRef,
|
|
25878
26091
|
foundryTracing: "skip",
|
|
25879
|
-
githubApp
|
|
26092
|
+
githubApp,
|
|
26093
|
+
enrollContactEmail: account.upn
|
|
25880
26094
|
});
|
|
25881
26095
|
this.context.stdout.write(
|
|
25882
26096
|
`${colors.success("\u2713")} installer launched in ${colors.field(resourceGroup)} (${location}).
|
|
@@ -25888,7 +26102,7 @@ var BootstrapLaunchCommand = class extends M8tCommand {
|
|
|
25888
26102
|
};
|
|
25889
26103
|
|
|
25890
26104
|
// src/commands/bootstrap/status.ts
|
|
25891
|
-
import { Command as
|
|
26105
|
+
import { Command as Command51, Option as Option48 } from "clipanion";
|
|
25892
26106
|
init_errors();
|
|
25893
26107
|
|
|
25894
26108
|
// src/lib/bootstrap-aci-state.ts
|
|
@@ -25916,13 +26130,13 @@ async function getAciState(opts) {
|
|
|
25916
26130
|
// src/commands/bootstrap/status.ts
|
|
25917
26131
|
var BootstrapStatusCommand = class extends M8tCommand {
|
|
25918
26132
|
static paths = [["bootstrap", "status"]];
|
|
25919
|
-
static usage =
|
|
26133
|
+
static usage = Command51.Usage({
|
|
25920
26134
|
description: "Show the cloud installer's live status (phase, progress, result).",
|
|
25921
26135
|
details: "Reads the durable status blob written by the installer. --watch polls until the install reaches done or failed.",
|
|
25922
26136
|
examples: [["One read", "$0 bootstrap status"], ["Watch to completion", "$0 bootstrap status --watch"]]
|
|
25923
26137
|
});
|
|
25924
|
-
watch =
|
|
25925
|
-
output =
|
|
26138
|
+
watch = Option48.Boolean("--watch", false);
|
|
26139
|
+
output = Option48.String("--output");
|
|
25926
26140
|
async executeCommand() {
|
|
25927
26141
|
const state = await readBootstrapState();
|
|
25928
26142
|
if (!state) {
|
|
@@ -25993,7 +26207,7 @@ function formatStatus(d) {
|
|
|
25993
26207
|
}
|
|
25994
26208
|
|
|
25995
26209
|
// src/commands/bootstrap/reap.ts
|
|
25996
|
-
import { Command as
|
|
26210
|
+
import { Command as Command52, Option as Option49 } from "clipanion";
|
|
25997
26211
|
init_errors();
|
|
25998
26212
|
|
|
25999
26213
|
// src/lib/bootstrap-reap.ts
|
|
@@ -26087,14 +26301,14 @@ async function reapInstaller(opts) {
|
|
|
26087
26301
|
// src/commands/bootstrap/reap.ts
|
|
26088
26302
|
var BootstrapReapCommand = class extends M8tCommand {
|
|
26089
26303
|
static paths = [["bootstrap", "reap"]];
|
|
26090
|
-
static usage =
|
|
26304
|
+
static usage = Command52.Usage({
|
|
26091
26305
|
description: "Tear down the installer scaffolding (ACI \u2192 MI \u2192 its role assignments) after a successful install.",
|
|
26092
26306
|
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.",
|
|
26093
26307
|
examples: [["Reap after done", "$0 bootstrap reap"]]
|
|
26094
26308
|
});
|
|
26095
|
-
force =
|
|
26096
|
-
sweepOrphans =
|
|
26097
|
-
yes =
|
|
26309
|
+
force = Option49.Boolean("--force", false);
|
|
26310
|
+
sweepOrphans = Option49.Boolean("--sweep-orphans", false);
|
|
26311
|
+
yes = Option49.Boolean("--yes", false);
|
|
26098
26312
|
async executeCommand() {
|
|
26099
26313
|
if (this.sweepOrphans === true) {
|
|
26100
26314
|
const { subscriptionId: sub } = await getAzAccount();
|
|
@@ -26191,12 +26405,12 @@ Found ${String(total)} orphaned assignment(s) (${breakdown}) (dry-run). ${colors
|
|
|
26191
26405
|
import * as fs31 from "fs/promises";
|
|
26192
26406
|
import * as os16 from "os";
|
|
26193
26407
|
import * as path34 from "path";
|
|
26194
|
-
import { Command as
|
|
26408
|
+
import { Command as Command53, Option as Option50 } from "clipanion";
|
|
26195
26409
|
init_errors();
|
|
26196
26410
|
|
|
26197
26411
|
// src/lib/company-profile-seed.ts
|
|
26198
26412
|
import { spawn as spawn6 } from "child_process";
|
|
26199
|
-
import { closeSync, openSync, readFileSync as
|
|
26413
|
+
import { closeSync, openSync, readFileSync as readFileSync21 } from "fs";
|
|
26200
26414
|
import * as os15 from "os";
|
|
26201
26415
|
import * as path33 from "path";
|
|
26202
26416
|
init_errors();
|
|
@@ -26381,7 +26595,7 @@ function composeFounderIdentityNote(id) {
|
|
|
26381
26595
|
function readGithubAppCreds(credsPath) {
|
|
26382
26596
|
const p = credsPath ?? path33.join(os15.homedir(), ".m8t", "github-app.json");
|
|
26383
26597
|
try {
|
|
26384
|
-
return JSON.parse(
|
|
26598
|
+
return JSON.parse(readFileSync21(p, "utf8"));
|
|
26385
26599
|
} catch {
|
|
26386
26600
|
return null;
|
|
26387
26601
|
}
|
|
@@ -26409,7 +26623,7 @@ async function resolveSeedContext(opts) {
|
|
|
26409
26623
|
async function applyProfileToBrain(args) {
|
|
26410
26624
|
const token = await mintInstallationTokenFromPem({
|
|
26411
26625
|
appId: args.appCreds.appId,
|
|
26412
|
-
privateKeyPem:
|
|
26626
|
+
privateKeyPem: readFileSync21(args.appCreds.pemPath, "utf8"),
|
|
26413
26627
|
installationId: args.appCreds.installationId,
|
|
26414
26628
|
fetchImpl: args.fetchImpl
|
|
26415
26629
|
});
|
|
@@ -26521,14 +26735,14 @@ function renderInstallSummary(args) {
|
|
|
26521
26735
|
// src/commands/bootstrap/finish.ts
|
|
26522
26736
|
var BootstrapFinishCommand = class extends M8tCommand {
|
|
26523
26737
|
static paths = [["bootstrap", "finish"]];
|
|
26524
|
-
static usage =
|
|
26738
|
+
static usage = Command53.Usage({
|
|
26525
26739
|
description: "Point your local tools at the now-live platform (repo-root marker, discovery cache, next steps).",
|
|
26526
26740
|
details: "Final step of `m8t bootstrap` (after the install reaches done). Writes ~/.m8t/repo-root, points your local tools at the live gateway, and \u2014 if you completed the onboarding questionnaire \u2014 seeds your brain-backed advisor's brain with your company profile (best-effort; never blocks finish). Run `m8t bootstrap seed-profile` to seed manually later.",
|
|
26527
26741
|
examples: [["Finish local", "$0 bootstrap finish --repo-root /path/to/m8t"]]
|
|
26528
26742
|
});
|
|
26529
|
-
repoRoot =
|
|
26530
|
-
subscription =
|
|
26531
|
-
resourceGroup =
|
|
26743
|
+
repoRoot = Option50.String("--repo-root");
|
|
26744
|
+
subscription = Option50.String("--subscription");
|
|
26745
|
+
resourceGroup = Option50.String("--resource-group");
|
|
26532
26746
|
async executeCommand() {
|
|
26533
26747
|
const state = await readBootstrapState();
|
|
26534
26748
|
if (!state) {
|
|
@@ -26631,8 +26845,8 @@ ${colors.field("Then open a brand new chat/session")} \u2014 new skills + MCP se
|
|
|
26631
26845
|
import * as fs33 from "fs";
|
|
26632
26846
|
import * as os18 from "os";
|
|
26633
26847
|
import * as path36 from "path";
|
|
26634
|
-
import { Command as
|
|
26635
|
-
import { DefaultAzureCredential as
|
|
26848
|
+
import { Command as Command54, Option as Option51 } from "clipanion";
|
|
26849
|
+
import { DefaultAzureCredential as DefaultAzureCredential21 } from "@azure/identity";
|
|
26636
26850
|
init_errors();
|
|
26637
26851
|
|
|
26638
26852
|
// src/lib/bootstrap-ui.ts
|
|
@@ -26640,7 +26854,7 @@ import * as fs32 from "fs";
|
|
|
26640
26854
|
import * as net from "net";
|
|
26641
26855
|
import * as os17 from "os";
|
|
26642
26856
|
import * as path35 from "path";
|
|
26643
|
-
import { spawn as spawn7 } from "child_process";
|
|
26857
|
+
import { spawn as spawn7, spawnSync as spawnSync6 } from "child_process";
|
|
26644
26858
|
init_errors();
|
|
26645
26859
|
init_rbac();
|
|
26646
26860
|
|
|
@@ -26906,7 +27120,8 @@ async function serveOnboardingUiDetached(args) {
|
|
|
26906
27120
|
detached: true,
|
|
26907
27121
|
stdio: ["ignore", fd, fd],
|
|
26908
27122
|
env: { ...process.env, PORT: args.port },
|
|
26909
|
-
shell
|
|
27123
|
+
// pnpm resolves to pnpm.cmd on Windows, which needs a shell to launch.
|
|
27124
|
+
shell: process.platform === "win32"
|
|
26910
27125
|
});
|
|
26911
27126
|
fs32.closeSync(fd);
|
|
26912
27127
|
if (child.pid == null) {
|
|
@@ -26946,7 +27161,8 @@ async function serveOnboardingRelayDetached(args) {
|
|
|
26946
27161
|
RELAY_ALLOWED_ORIGINS: "http://localhost:3000",
|
|
26947
27162
|
RELAY_PORT: "8790"
|
|
26948
27163
|
},
|
|
26949
|
-
shell
|
|
27164
|
+
// pnpm resolves to pnpm.cmd on Windows, which needs a shell to launch.
|
|
27165
|
+
shell: process.platform === "win32"
|
|
26950
27166
|
});
|
|
26951
27167
|
fs32.closeSync(fd);
|
|
26952
27168
|
if (child.pid == null) {
|
|
@@ -26985,10 +27201,14 @@ function stopPidFile(pidPath) {
|
|
|
26985
27201
|
}
|
|
26986
27202
|
const pid = Number(pidStr);
|
|
26987
27203
|
if (!Number.isNaN(pid) && pid > 0) {
|
|
26988
|
-
|
|
26989
|
-
|
|
26990
|
-
}
|
|
26991
|
-
|
|
27204
|
+
if (process.platform === "win32") {
|
|
27205
|
+
spawnSync6("taskkill", ["/pid", String(pid), "/T", "/F"], { stdio: "ignore" });
|
|
27206
|
+
} else {
|
|
27207
|
+
try {
|
|
27208
|
+
process.kill(-pid, "SIGTERM");
|
|
27209
|
+
} catch (e) {
|
|
27210
|
+
if (e.code !== "ESRCH") throw e;
|
|
27211
|
+
}
|
|
26992
27212
|
}
|
|
26993
27213
|
}
|
|
26994
27214
|
try {
|
|
@@ -27020,7 +27240,7 @@ function renderDeployFailure(error) {
|
|
|
27020
27240
|
}
|
|
27021
27241
|
var BootstrapUiCommand = class extends M8tCommand {
|
|
27022
27242
|
static paths = [["bootstrap", "ui"]];
|
|
27023
|
-
static usage =
|
|
27243
|
+
static usage = Command54.Usage({
|
|
27024
27244
|
description: "Deploy Simple Stacey + start the local onboarding chat UI in the background (returns immediately).",
|
|
27025
27245
|
details: [
|
|
27026
27246
|
"Run after `m8t bootstrap launch`, in parallel with `status --watch`. Waits for the cloud",
|
|
@@ -27038,15 +27258,15 @@ var BootstrapUiCommand = class extends M8tCommand {
|
|
|
27038
27258
|
["Foreground (blocking, old behaviour)", "$0 bootstrap ui --repo-root /path/to/m8t --foreground"]
|
|
27039
27259
|
]
|
|
27040
27260
|
});
|
|
27041
|
-
repoRoot =
|
|
27042
|
-
port =
|
|
27043
|
-
endpoint =
|
|
27261
|
+
repoRoot = Option51.String("--repo-root");
|
|
27262
|
+
port = Option51.String("--port", "3000");
|
|
27263
|
+
endpoint = Option51.String("--endpoint", {
|
|
27044
27264
|
description: "Foundry project endpoint to target \u2014 disambiguates when the subscription has multiple projects."
|
|
27045
27265
|
});
|
|
27046
|
-
prepOnly =
|
|
27047
|
-
skipInstall =
|
|
27048
|
-
stop =
|
|
27049
|
-
foreground =
|
|
27266
|
+
prepOnly = Option51.Boolean("--prep-only", false);
|
|
27267
|
+
skipInstall = Option51.Boolean("--skip-install", false);
|
|
27268
|
+
stop = Option51.Boolean("--stop", false);
|
|
27269
|
+
foreground = Option51.Boolean("--foreground", false);
|
|
27050
27270
|
async executeCommand() {
|
|
27051
27271
|
if (this.stop === true) {
|
|
27052
27272
|
const stopped = stopOnboardingUi();
|
|
@@ -27082,7 +27302,7 @@ var BootstrapUiCommand = class extends M8tCommand {
|
|
|
27082
27302
|
if (fs33.existsSync(path36.join(os18.homedir(), ".m8t", "config.yaml"))) {
|
|
27083
27303
|
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."));
|
|
27084
27304
|
}
|
|
27085
|
-
const credential2 = new
|
|
27305
|
+
const credential2 = new DefaultAzureCredential21();
|
|
27086
27306
|
const account = await getAzAccount();
|
|
27087
27307
|
assertNodeVersion();
|
|
27088
27308
|
out("waiting for Foundry (the installer's foundry-create phase)\u2026");
|
|
@@ -27180,10 +27400,10 @@ var BootstrapUiCommand = class extends M8tCommand {
|
|
|
27180
27400
|
};
|
|
27181
27401
|
|
|
27182
27402
|
// src/commands/bootstrap/seed-profile.ts
|
|
27183
|
-
import { Command as
|
|
27403
|
+
import { Command as Command55, Option as Option52 } from "clipanion";
|
|
27184
27404
|
var BootstrapSeedProfileCommand = class extends M8tCommand {
|
|
27185
27405
|
static paths = [["bootstrap", "seed-profile"]];
|
|
27186
|
-
static usage =
|
|
27406
|
+
static usage = Command55.Usage({
|
|
27187
27407
|
description: "Seed your advisors' brains with the founder + company profile from the onboarding questionnaire.",
|
|
27188
27408
|
details: "Reads the latest stacey-intake conversation, renders memory/founder.md + memory/company-profile.md (+ their MEMORY.md index lines), and commits them to both <org>/stacey-brain and <org>/azzy-brain via the GitHub App. Idempotent. --watch polls until the founder completes the questionnaire.",
|
|
27189
27409
|
examples: [
|
|
@@ -27191,11 +27411,11 @@ var BootstrapSeedProfileCommand = class extends M8tCommand {
|
|
|
27191
27411
|
["Wait for the founder to finish", "$0 bootstrap seed-profile --watch"]
|
|
27192
27412
|
]
|
|
27193
27413
|
});
|
|
27194
|
-
endpoint =
|
|
27195
|
-
brain =
|
|
27196
|
-
watch =
|
|
27197
|
-
timeout =
|
|
27198
|
-
githubAppCreds =
|
|
27414
|
+
endpoint = Option52.String("--endpoint", { description: "Override the Foundry endpoint (else read from the install status)." });
|
|
27415
|
+
brain = Option52.String("--brain", { description: "Override the brain repo (default <org>/stacey-brain)." });
|
|
27416
|
+
watch = Option52.Boolean("--watch", false, { description: "Poll until the questionnaire completes (or --timeout)." });
|
|
27417
|
+
timeout = Option52.String("--timeout", { description: "Watch timeout in minutes (default 20)." });
|
|
27418
|
+
githubAppCreds = Option52.String("--github-app-creds");
|
|
27199
27419
|
async executeCommand() {
|
|
27200
27420
|
const ctx = await resolveSeedContext({
|
|
27201
27421
|
endpointOverride: typeof this.endpoint === "string" ? this.endpoint : void 0,
|
|
@@ -27240,6 +27460,112 @@ var BootstrapSeedProfileCommand = class extends M8tCommand {
|
|
|
27240
27460
|
}
|
|
27241
27461
|
};
|
|
27242
27462
|
|
|
27463
|
+
// src/commands/telemetry/enroll.ts
|
|
27464
|
+
import { Command as Command56, Option as Option53 } from "clipanion";
|
|
27465
|
+
init_errors();
|
|
27466
|
+
|
|
27467
|
+
// src/lib/telemetry-enroll.ts
|
|
27468
|
+
init_errors();
|
|
27469
|
+
async function enroll(args) {
|
|
27470
|
+
const f = args.fetchImpl ?? fetch;
|
|
27471
|
+
const url = args.baseUrl ? `${args.baseUrl.replace(/\/+$/, "")}/api/ingest/enroll` : ingestUrl("/api/ingest/enroll");
|
|
27472
|
+
let res;
|
|
27473
|
+
try {
|
|
27474
|
+
res = await f(url, {
|
|
27475
|
+
method: "POST",
|
|
27476
|
+
headers: { "content-type": "application/json" },
|
|
27477
|
+
body: JSON.stringify({ schemaVersion: 1, company: args.company, contactEmail: args.contactEmail, subscriptionId: args.subscriptionId, proof: null })
|
|
27478
|
+
});
|
|
27479
|
+
} catch (e) {
|
|
27480
|
+
throw new LocalCliError({ code: "TELEMETRY_ENROLL_UNREACHABLE", message: `Could not reach the telemetry ingest to enroll: ${e instanceof Error ? e.message : String(e)}` });
|
|
27481
|
+
}
|
|
27482
|
+
if (!res.ok) {
|
|
27483
|
+
const body = await res.text().catch(() => "");
|
|
27484
|
+
throw new LocalCliError({ code: "TELEMETRY_ENROLL_FAILED", message: `Enroll failed (HTTP ${res.status.toString()}): ${body}` });
|
|
27485
|
+
}
|
|
27486
|
+
const json = await res.json();
|
|
27487
|
+
if (!json.instanceId || !json.ingestKey) {
|
|
27488
|
+
throw new LocalCliError({ code: "TELEMETRY_ENROLL_BAD_RESPONSE", message: "Enroll response missing instanceId/ingestKey." });
|
|
27489
|
+
}
|
|
27490
|
+
return { instanceId: json.instanceId, ingestKey: json.ingestKey };
|
|
27491
|
+
}
|
|
27492
|
+
|
|
27493
|
+
// src/commands/telemetry/enroll.ts
|
|
27494
|
+
var INGEST_KEY_SECRET = "m8t-ingest-key";
|
|
27495
|
+
async function resolveKeyVaultName(containerAppResourceId) {
|
|
27496
|
+
const kvUri = (await runAz([
|
|
27497
|
+
"containerapp",
|
|
27498
|
+
"show",
|
|
27499
|
+
"--ids",
|
|
27500
|
+
containerAppResourceId,
|
|
27501
|
+
"--query",
|
|
27502
|
+
"properties.template.containers[0].env[?name=='KEY_VAULT_URI'].value | [0]",
|
|
27503
|
+
"-o",
|
|
27504
|
+
"tsv"
|
|
27505
|
+
])).trim();
|
|
27506
|
+
if (!kvUri) {
|
|
27507
|
+
throw new LocalCliError({
|
|
27508
|
+
code: "TELEMETRY_ENROLL_NO_KV",
|
|
27509
|
+
message: "Could not resolve the platform Key Vault: the gateway Container App has no KEY_VAULT_URI env var.",
|
|
27510
|
+
hint: "Verify the deployment via 'az containerapp show --ids <id> --query properties.template.containers[0].env'."
|
|
27511
|
+
});
|
|
27512
|
+
}
|
|
27513
|
+
const host = new URL(kvUri).hostname;
|
|
27514
|
+
const name = host.split(".")[0];
|
|
27515
|
+
if (!name) {
|
|
27516
|
+
throw new LocalCliError({ code: "TELEMETRY_ENROLL_BAD_KV_URI", message: `Could not parse a Key Vault name from KEY_VAULT_URI '${kvUri}'.` });
|
|
27517
|
+
}
|
|
27518
|
+
return name;
|
|
27519
|
+
}
|
|
27520
|
+
var TelemetryEnrollCommand = class extends M8tCommand {
|
|
27521
|
+
static paths = [["telemetry", "enroll"]];
|
|
27522
|
+
static usage = Command56.Usage({
|
|
27523
|
+
description: "Enroll this installation for operational telemetry (pre-existing installs).",
|
|
27524
|
+
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.",
|
|
27525
|
+
examples: [["Enroll", "$0 telemetry enroll"]]
|
|
27526
|
+
});
|
|
27527
|
+
company = Option53.String("--company", { description: "Your company name (optional)." });
|
|
27528
|
+
contactEmail = Option53.String("--contact-email", { description: "Contact email (default: your signed-in az UPN)." });
|
|
27529
|
+
subscription = Option53.String("--subscription", { description: "Azure subscription id (default: your active az subscription)." });
|
|
27530
|
+
resourceGroup = Option53.String("--resource-group", { description: "Resource group to disambiguate discovery, if you have more than one m8t deployment." });
|
|
27531
|
+
force = Option53.Boolean("--force", false, { description: "Re-enroll even if a key is already stored (mints a new instance id)." });
|
|
27532
|
+
async executeCommand() {
|
|
27533
|
+
const account = await getAzAccount();
|
|
27534
|
+
const subscriptionId = (typeof this.subscription === "string" ? this.subscription : void 0) ?? account.subscriptionId;
|
|
27535
|
+
const contactEmail = (typeof this.contactEmail === "string" ? this.contactEmail : void 0) ?? account.upn;
|
|
27536
|
+
const company = (typeof this.company === "string" ? this.company : void 0) ?? "";
|
|
27537
|
+
const d = await discoverGateway({
|
|
27538
|
+
subscriptionId,
|
|
27539
|
+
interactive: false,
|
|
27540
|
+
resourceGroup: typeof this.resourceGroup === "string" ? this.resourceGroup : void 0
|
|
27541
|
+
});
|
|
27542
|
+
const kvName = await resolveKeyVaultName(d.containerAppResourceId);
|
|
27543
|
+
if (this.force !== true) {
|
|
27544
|
+
let existing = "";
|
|
27545
|
+
try {
|
|
27546
|
+
existing = await runAz(["keyvault", "secret", "show", "--vault-name", kvName, "--name", INGEST_KEY_SECRET, "--query", "value", "-o", "tsv"]);
|
|
27547
|
+
} catch (e) {
|
|
27548
|
+
rethrowIfAzUnavailable(e);
|
|
27549
|
+
existing = "";
|
|
27550
|
+
}
|
|
27551
|
+
if (existing.trim()) {
|
|
27552
|
+
throw new LocalCliError({
|
|
27553
|
+
code: "TELEMETRY_ALREADY_ENROLLED",
|
|
27554
|
+
message: "This installation is already enrolled.",
|
|
27555
|
+
hint: "Pass --force to re-enroll (mints a new instance id)."
|
|
27556
|
+
});
|
|
27557
|
+
}
|
|
27558
|
+
}
|
|
27559
|
+
const { instanceId, ingestKey } = await enroll({ company, contactEmail, subscriptionId });
|
|
27560
|
+
await runAz(["keyvault", "secret", "set", "--vault-name", kvName, "--name", INGEST_KEY_SECRET, "--value", ingestKey, "--only-show-errors"]);
|
|
27561
|
+
this.context.stdout.write(
|
|
27562
|
+
`${colors.success("\u2713")} enrolled (instance ${instanceId}); ingest key stored in Key Vault ${kvName}. The gateway picks it up on its next cycle.
|
|
27563
|
+
`
|
|
27564
|
+
);
|
|
27565
|
+
return 0;
|
|
27566
|
+
}
|
|
27567
|
+
};
|
|
27568
|
+
|
|
27243
27569
|
// src/cli.ts
|
|
27244
27570
|
var cli = new Cli({
|
|
27245
27571
|
binaryName: "m8t",
|
|
@@ -27281,6 +27607,7 @@ cli.register(AzureExecDeployCommand);
|
|
|
27281
27607
|
cli.register(PlatformStatusCommand);
|
|
27282
27608
|
cli.register(PlatformUpdateCommand);
|
|
27283
27609
|
cli.register(PlatformConvergeCommand);
|
|
27610
|
+
cli.register(PlatformSeedStampCommand);
|
|
27284
27611
|
cli.register(PlatformEnableCostReportCommand);
|
|
27285
27612
|
cli.register(PlatformEnableAutoUpdateCommand);
|
|
27286
27613
|
cli.register(DeployCommand);
|
|
@@ -27300,6 +27627,7 @@ cli.register(BootstrapReapCommand);
|
|
|
27300
27627
|
cli.register(BootstrapFinishCommand);
|
|
27301
27628
|
cli.register(BootstrapUiCommand);
|
|
27302
27629
|
cli.register(BootstrapSeedProfileCommand);
|
|
27630
|
+
cli.register(TelemetryEnrollCommand);
|
|
27303
27631
|
async function main() {
|
|
27304
27632
|
try {
|
|
27305
27633
|
return await cli.run(process.argv.slice(2));
|