@m8t-stack/cli 0.2.44 → 0.2.45
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 +417 -233
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1310,7 +1310,7 @@ var init_enable_hosted_brain = __esm({
|
|
|
1310
1310
|
import { Builtins, Cli } from "clipanion";
|
|
1311
1311
|
|
|
1312
1312
|
// src/lib/package-version.ts
|
|
1313
|
-
var CLI_VERSION = "0.2.
|
|
1313
|
+
var CLI_VERSION = "0.2.45";
|
|
1314
1314
|
|
|
1315
1315
|
// src/lib/render-error.ts
|
|
1316
1316
|
init_errors();
|
|
@@ -18056,6 +18056,7 @@ var DEFAULT_IMAGE = "m8t-coding-agent";
|
|
|
18056
18056
|
var DEFAULT_TAG = "v0.1.2";
|
|
18057
18057
|
var DEFAULT_MODEL = "gpt-4.1-mini";
|
|
18058
18058
|
var NAME_RE = /^[a-z0-9-]+$/;
|
|
18059
|
+
var PUBLIC_PRODUCT_AGENTS = /* @__PURE__ */ new Set(["stacey", "azzy"]);
|
|
18059
18060
|
var CoderDeployCommand = class extends M8tCommand {
|
|
18060
18061
|
static paths = [["coder", "deploy"]];
|
|
18061
18062
|
static usage = Command28.Usage({
|
|
@@ -18188,7 +18189,14 @@ var CoderDeployCommand = class extends M8tCommand {
|
|
|
18188
18189
|
cpu: preset.cpu,
|
|
18189
18190
|
memory: preset.memory,
|
|
18190
18191
|
env,
|
|
18191
|
-
metadata: {
|
|
18192
|
+
metadata: {
|
|
18193
|
+
...currentMetadata,
|
|
18194
|
+
source: "m8t",
|
|
18195
|
+
kind: "hosted",
|
|
18196
|
+
persona: personaName,
|
|
18197
|
+
personaVersion,
|
|
18198
|
+
productVisibility: PUBLIC_PRODUCT_AGENTS.has(this.name) ? "public" : "internal"
|
|
18199
|
+
},
|
|
18192
18200
|
onProgress
|
|
18193
18201
|
});
|
|
18194
18202
|
if (typeof this.brain === "string") {
|
|
@@ -18396,6 +18404,7 @@ import * as path18 from "path";
|
|
|
18396
18404
|
import { Command as Command30, Option as Option28 } from "clipanion";
|
|
18397
18405
|
import { DefaultAzureCredential as DefaultAzureCredential15 } from "@azure/identity";
|
|
18398
18406
|
init_errors();
|
|
18407
|
+
init_foundry_agent_get();
|
|
18399
18408
|
init_rbac();
|
|
18400
18409
|
|
|
18401
18410
|
// src/lib/acs-provision.ts
|
|
@@ -18542,6 +18551,12 @@ var AzureExecDeployCommand = class extends M8tCommand {
|
|
|
18542
18551
|
interactive,
|
|
18543
18552
|
endpoint: this.endpoint
|
|
18544
18553
|
});
|
|
18554
|
+
let currentMetadata = {};
|
|
18555
|
+
try {
|
|
18556
|
+
const current = await getAgentVersion({ credential: credential2, projectEndpoint: project.endpoint, agentName: this.name });
|
|
18557
|
+
currentMetadata = { ...current.metadata ?? {} };
|
|
18558
|
+
} catch {
|
|
18559
|
+
}
|
|
18545
18560
|
const staged = await stagePublicImageIfNeeded({ image: requestedImage, project });
|
|
18546
18561
|
for (const n of staged.notes) {
|
|
18547
18562
|
this.context.stderr.write(`${colors.hint("note:")} ${n}
|
|
@@ -18635,7 +18650,7 @@ var AzureExecDeployCommand = class extends M8tCommand {
|
|
|
18635
18650
|
cpu: preset.cpu,
|
|
18636
18651
|
memory: preset.memory,
|
|
18637
18652
|
env,
|
|
18638
|
-
metadata: { source: "m8t", kind: "hosted", persona: personaName, personaVersion },
|
|
18653
|
+
metadata: { ...currentMetadata, source: "m8t", kind: "hosted", persona: personaName, personaVersion, productVisibility: "internal" },
|
|
18639
18654
|
onProgress
|
|
18640
18655
|
});
|
|
18641
18656
|
onProgress?.(`granting Contributor at ${grantScope}\u2026`);
|
|
@@ -28057,6 +28072,34 @@ import * as path33 from "path";
|
|
|
28057
28072
|
init_errors();
|
|
28058
28073
|
|
|
28059
28074
|
// src/lib/onboarding-profile.ts
|
|
28075
|
+
function describeBlockRejection(reason) {
|
|
28076
|
+
switch (reason) {
|
|
28077
|
+
case "unknown-schema-version":
|
|
28078
|
+
return "the onboarding block's schema_version was missing or unrecognized";
|
|
28079
|
+
case "unexpected-key":
|
|
28080
|
+
return "the onboarding JSON carried a field it shouldn't have";
|
|
28081
|
+
case "missing-key":
|
|
28082
|
+
return "the onboarding block was missing a required field";
|
|
28083
|
+
case "non-string-value":
|
|
28084
|
+
return "the onboarding block held a value of the wrong type";
|
|
28085
|
+
case "disallowed-value":
|
|
28086
|
+
return "an onboarding block field held a value outside its allowed set";
|
|
28087
|
+
case "too-many-pending-requests":
|
|
28088
|
+
return "the onboarding block listed more pending requests than the one allowed";
|
|
28089
|
+
case "malformed-json":
|
|
28090
|
+
return "the onboarding block's JSON could not be safely parsed \u2014 check for duplicate keys, excessive nesting, or a syntax error";
|
|
28091
|
+
case "multiple-artifacts":
|
|
28092
|
+
return "more than one onboarding block was found in your onboarding conversation";
|
|
28093
|
+
case "unreadable-fences":
|
|
28094
|
+
return "the message's code fences could not be reliably delimited, so any onboarding block inside them could not be safely read";
|
|
28095
|
+
case "mistagged-fence":
|
|
28096
|
+
return "the onboarding block was inside a code fence that wasn't tagged json, so it could not be safely read";
|
|
28097
|
+
case "unfenced-artifact":
|
|
28098
|
+
return "the onboarding block appeared outside of any code fence, so it could not be safely read";
|
|
28099
|
+
case "no-artifact":
|
|
28100
|
+
return "no onboarding block was found";
|
|
28101
|
+
}
|
|
28102
|
+
}
|
|
28060
28103
|
var COMPANY_PROFILE_PATH = "memory/company-profile.md";
|
|
28061
28104
|
var DEFAULT_MEMORY_INDEX_HEADER = [
|
|
28062
28105
|
`# Memory index`,
|
|
@@ -28178,24 +28221,96 @@ function hasValidUniqueJsonKeys(source) {
|
|
|
28178
28221
|
return false;
|
|
28179
28222
|
}
|
|
28180
28223
|
}
|
|
28224
|
+
var V3_BLOCK_KEYS = ["schema_version", "founder", "company", "advisor_email", "pending_requests"];
|
|
28225
|
+
var V3_FOUNDER_KEYS = ["name", "email", "azure_identity_note"];
|
|
28226
|
+
var V3_COMPANY_KEYS = ["name", "one_liner"];
|
|
28227
|
+
var V3_ADDRESS_KEYS = ["address", "city", "postal_code", "country"];
|
|
28228
|
+
var V3_REQUEST_KEYS = ["type", "model", "region", "consent", "company_address"];
|
|
28229
|
+
function exactStringRecord(value, keys) {
|
|
28230
|
+
if (!isRecord(value)) return "non-string-value";
|
|
28231
|
+
const present = new Set(Object.keys(value));
|
|
28232
|
+
for (const key2 of keys) if (!present.has(key2)) return "missing-key";
|
|
28233
|
+
if (present.size !== keys.length) return "unexpected-key";
|
|
28234
|
+
for (const key2 of keys) if (typeof value[key2] !== "string") return "non-string-value";
|
|
28235
|
+
return null;
|
|
28236
|
+
}
|
|
28237
|
+
function canonicalPendingRequests(value) {
|
|
28238
|
+
if (!Array.isArray(value)) return { ok: false, reason: "non-string-value" };
|
|
28239
|
+
if (value.length > 1) return { ok: false, reason: "too-many-pending-requests" };
|
|
28240
|
+
const requests = [];
|
|
28241
|
+
for (const entry of value) {
|
|
28242
|
+
if (!isRecord(entry)) return { ok: false, reason: "non-string-value" };
|
|
28243
|
+
const present = new Set(Object.keys(entry));
|
|
28244
|
+
for (const key2 of V3_REQUEST_KEYS) {
|
|
28245
|
+
if (!present.has(key2)) return { ok: false, reason: "missing-key" };
|
|
28246
|
+
}
|
|
28247
|
+
if (present.size !== V3_REQUEST_KEYS.length) return { ok: false, reason: "unexpected-key" };
|
|
28248
|
+
if (entry.type !== "quota") return { ok: false, reason: "disallowed-value" };
|
|
28249
|
+
if (entry.consent !== "submit" && entry.consent !== "prepare") return { ok: false, reason: "disallowed-value" };
|
|
28250
|
+
if (typeof entry.model !== "string" || typeof entry.region !== "string") {
|
|
28251
|
+
return { ok: false, reason: "non-string-value" };
|
|
28252
|
+
}
|
|
28253
|
+
if (entry.company_address !== null) {
|
|
28254
|
+
const bad = exactStringRecord(entry.company_address, V3_ADDRESS_KEYS);
|
|
28255
|
+
if (bad) return { ok: false, reason: bad };
|
|
28256
|
+
}
|
|
28257
|
+
requests.push(entry);
|
|
28258
|
+
}
|
|
28259
|
+
return { ok: true, requests };
|
|
28260
|
+
}
|
|
28261
|
+
function canonicalV3Block(value) {
|
|
28262
|
+
const present = new Set(Object.keys(value));
|
|
28263
|
+
for (const key2 of V3_BLOCK_KEYS) if (!present.has(key2)) return { ok: false, reason: "missing-key" };
|
|
28264
|
+
if (present.size !== V3_BLOCK_KEYS.length) return { ok: false, reason: "unexpected-key" };
|
|
28265
|
+
const founderBad = exactStringRecord(value.founder, V3_FOUNDER_KEYS);
|
|
28266
|
+
if (founderBad) return { ok: false, reason: founderBad };
|
|
28267
|
+
const companyBad = exactStringRecord(value.company, V3_COMPANY_KEYS);
|
|
28268
|
+
if (companyBad) return { ok: false, reason: companyBad };
|
|
28269
|
+
if (value.advisor_email !== null && typeof value.advisor_email !== "string") {
|
|
28270
|
+
return { ok: false, reason: "non-string-value" };
|
|
28271
|
+
}
|
|
28272
|
+
const requests = canonicalPendingRequests(value.pending_requests);
|
|
28273
|
+
if (!requests.ok) return requests;
|
|
28274
|
+
const founder = value.founder;
|
|
28275
|
+
const company = value.company;
|
|
28276
|
+
return {
|
|
28277
|
+
ok: true,
|
|
28278
|
+
block: {
|
|
28279
|
+
schema_version: "3",
|
|
28280
|
+
founder_name: founder.name,
|
|
28281
|
+
founder_email: founder.email,
|
|
28282
|
+
azure_identity_note: founder.azure_identity_note,
|
|
28283
|
+
company_name: company.name,
|
|
28284
|
+
context: company.one_liner,
|
|
28285
|
+
advisor_name: "",
|
|
28286
|
+
advisor_email: typeof value.advisor_email === "string" ? value.advisor_email : "",
|
|
28287
|
+
pending_requests: requests.requests
|
|
28288
|
+
}
|
|
28289
|
+
};
|
|
28290
|
+
}
|
|
28181
28291
|
function canonicalBlock(value) {
|
|
28182
|
-
if (!isRecord(value)) return
|
|
28183
|
-
|
|
28184
|
-
|
|
28185
|
-
|
|
28186
|
-
if (value.schema_version !== "2") return null;
|
|
28292
|
+
if (!isRecord(value)) return { ok: false, reason: "non-string-value" };
|
|
28293
|
+
if (value.schema_version === "3") return canonicalV3Block(value);
|
|
28294
|
+
if (value.schema_version !== "2") return { ok: false, reason: "unknown-schema-version" };
|
|
28295
|
+
const keys = new Set(Object.keys(value));
|
|
28187
28296
|
for (const key2 of ONBOARDING_BLOCK_KEYS) {
|
|
28188
|
-
if (
|
|
28297
|
+
if (!keys.has(key2)) return { ok: false, reason: "missing-key" };
|
|
28189
28298
|
}
|
|
28190
|
-
return
|
|
28299
|
+
if (keys.size !== ONBOARDING_BLOCK_KEYS.length) return { ok: false, reason: "unexpected-key" };
|
|
28300
|
+
for (const key2 of ONBOARDING_BLOCK_KEYS) {
|
|
28301
|
+
if (typeof value[key2] !== "string") return { ok: false, reason: "non-string-value" };
|
|
28302
|
+
}
|
|
28303
|
+
return { ok: true, block: value };
|
|
28191
28304
|
}
|
|
28192
|
-
function
|
|
28305
|
+
function parseOnboardingArtifactResult(machineText) {
|
|
28193
28306
|
const fencePattern = /^```([^\r\n]*)\r?\n([\s\S]*?)^```[ \t]*(?=\r?$)/gm;
|
|
28194
28307
|
const fences = [...machineText.matchAll(fencePattern)];
|
|
28195
28308
|
const jsonFenceStarts = [...machineText.matchAll(/^```[ \t]*json[ \t]*\r?$/gm)];
|
|
28196
28309
|
const matchedJsonFences = fences.filter((match) => match[1].trim() === "json");
|
|
28197
|
-
if (jsonFenceStarts.length !== matchedJsonFences.length) return
|
|
28198
|
-
if (fences.some((match) => match[1].trim() !== "json" && /"m8t_onboarding"\s*:/.test(match[2])))
|
|
28310
|
+
if (jsonFenceStarts.length !== matchedJsonFences.length) return { ok: false, reason: "unreadable-fences" };
|
|
28311
|
+
if (fences.some((match) => match[1].trim() !== "json" && /"m8t_onboarding"\s*:/.test(match[2]))) {
|
|
28312
|
+
return { ok: false, reason: "mistagged-fence" };
|
|
28313
|
+
}
|
|
28199
28314
|
let outsideFences = "";
|
|
28200
28315
|
let previousEnd = 0;
|
|
28201
28316
|
for (const fence of fences) {
|
|
@@ -28204,43 +28319,48 @@ function parseOnboardingArtifact(machineText) {
|
|
|
28204
28319
|
previousEnd = start + fence[0].length;
|
|
28205
28320
|
}
|
|
28206
28321
|
outsideFences += machineText.slice(previousEnd);
|
|
28207
|
-
if (/"m8t_onboarding"\s*:/.test(outsideFences)) return
|
|
28322
|
+
if (/"m8t_onboarding"\s*:/.test(outsideFences)) return { ok: false, reason: "unfenced-artifact" };
|
|
28208
28323
|
const artifacts = [];
|
|
28209
28324
|
for (const fence of matchedJsonFences) {
|
|
28210
28325
|
const json = fence[2].trim();
|
|
28211
28326
|
let parsed;
|
|
28212
28327
|
if (!hasValidUniqueJsonKeys(json)) {
|
|
28213
|
-
if (json.includes("m8t_onboarding")) return
|
|
28328
|
+
if (json.includes("m8t_onboarding")) return { ok: false, reason: "malformed-json" };
|
|
28214
28329
|
continue;
|
|
28215
28330
|
}
|
|
28216
28331
|
try {
|
|
28217
28332
|
parsed = JSON.parse(json);
|
|
28218
28333
|
} catch {
|
|
28219
|
-
if (json.includes("m8t_onboarding")) return
|
|
28334
|
+
if (json.includes("m8t_onboarding")) return { ok: false, reason: "malformed-json" };
|
|
28220
28335
|
continue;
|
|
28221
28336
|
}
|
|
28222
28337
|
if (!isRecord(parsed) || !Object.hasOwn(parsed, "m8t_onboarding")) continue;
|
|
28223
|
-
if (Object.keys(parsed).length !== 1) return
|
|
28224
|
-
const
|
|
28225
|
-
if (!
|
|
28338
|
+
if (Object.keys(parsed).length !== 1) return { ok: false, reason: "unexpected-key" };
|
|
28339
|
+
const outcome = canonicalBlock(parsed.m8t_onboarding);
|
|
28340
|
+
if (!outcome.ok) return outcome;
|
|
28226
28341
|
const start = fence.index;
|
|
28227
|
-
artifacts.push({ block, start, end: start + fence[0].length });
|
|
28342
|
+
artifacts.push({ block: outcome.block, start, end: start + fence[0].length });
|
|
28228
28343
|
}
|
|
28229
|
-
if (artifacts.length
|
|
28344
|
+
if (artifacts.length === 0) return { ok: false, reason: "no-artifact" };
|
|
28345
|
+
if (artifacts.length > 1) return { ok: false, reason: "multiple-artifacts" };
|
|
28230
28346
|
const artifact = artifacts[0];
|
|
28231
28347
|
const before = machineText.slice(0, artifact.start).trimEnd();
|
|
28232
28348
|
const after = machineText.slice(artifact.end).trimStart();
|
|
28233
28349
|
return {
|
|
28234
|
-
|
|
28235
|
-
|
|
28236
|
-
|
|
28350
|
+
ok: true,
|
|
28351
|
+
artifact: {
|
|
28352
|
+
block: artifact.block,
|
|
28353
|
+
machineText,
|
|
28354
|
+
speechText: [before, after].filter((part) => part.length > 0).join("\n").trim()
|
|
28355
|
+
}
|
|
28237
28356
|
};
|
|
28238
28357
|
}
|
|
28239
28358
|
var EMPTY_PROFILE_RESULT = {
|
|
28240
28359
|
hadIntake: false,
|
|
28241
28360
|
block: null,
|
|
28242
28361
|
machineText: null,
|
|
28243
|
-
speechText: null
|
|
28362
|
+
speechText: null,
|
|
28363
|
+
rejection: null
|
|
28244
28364
|
};
|
|
28245
28365
|
async function readCursorPages(args) {
|
|
28246
28366
|
const all = [];
|
|
@@ -28314,7 +28434,7 @@ async function findOnboardingProfile(args) {
|
|
|
28314
28434
|
const conversations = orderNewest(listed.flatMap((value, ordinal) => {
|
|
28315
28435
|
if (!isRecord(value) || typeof value.id !== "string" || value.id.length === 0 || !isRecord(value.metadata)) return [];
|
|
28316
28436
|
const metadata = value.metadata;
|
|
28317
|
-
if (metadata.app !== "m8t-webapp" || metadata.agent !== "
|
|
28437
|
+
if (metadata.app !== "m8t-webapp" || metadata.agent !== "azzy-intake") return [];
|
|
28318
28438
|
return [{
|
|
28319
28439
|
id: value.id,
|
|
28320
28440
|
createdAt: timestamp(value.created_at) !== Number.NEGATIVE_INFINITY ? timestamp(value.created_at) : timestamp(metadata.createdAt),
|
|
@@ -28328,14 +28448,14 @@ async function findOnboardingProfile(args) {
|
|
|
28328
28448
|
headers: H,
|
|
28329
28449
|
fetchImpl: doFetch
|
|
28330
28450
|
});
|
|
28331
|
-
if (!items) return { hadIntake: true, block: null, machineText: null, speechText: null };
|
|
28451
|
+
if (!items) return { hadIntake: true, block: null, machineText: null, speechText: null, rejection: null };
|
|
28332
28452
|
const assistantItems = orderNewest(items.flatMap((value, ordinal) => {
|
|
28333
28453
|
if (!isRecord(value) || value.type !== "message" || value.role !== "assistant" || !Array.isArray(value.content)) return [];
|
|
28334
28454
|
const id = typeof value.id === "string" ? value.id : "";
|
|
28335
28455
|
return [{ value, id, createdAt: timestamp(value.created_at), ordinal }];
|
|
28336
28456
|
}));
|
|
28337
28457
|
const artifacts = [];
|
|
28338
|
-
let
|
|
28458
|
+
let rejection = null;
|
|
28339
28459
|
for (const item of assistantItems) {
|
|
28340
28460
|
const content = item.value.content;
|
|
28341
28461
|
const machineText = content.flatMap((part) => {
|
|
@@ -28344,23 +28464,32 @@ async function findOnboardingProfile(args) {
|
|
|
28344
28464
|
if (typeof part.transcript === "string") return [part.transcript];
|
|
28345
28465
|
return [];
|
|
28346
28466
|
}).join("\n");
|
|
28347
|
-
const
|
|
28348
|
-
if (
|
|
28349
|
-
else if (machineText.includes("m8t_onboarding"))
|
|
28467
|
+
const result = parseOnboardingArtifactResult(machineText);
|
|
28468
|
+
if (result.ok) artifacts.push(result.artifact);
|
|
28469
|
+
else if (machineText.includes("m8t_onboarding")) rejection ??= result.reason;
|
|
28350
28470
|
}
|
|
28351
|
-
if (
|
|
28352
|
-
return {
|
|
28471
|
+
if (artifacts.length === 0) {
|
|
28472
|
+
return {
|
|
28473
|
+
hadIntake: true,
|
|
28474
|
+
block: null,
|
|
28475
|
+
machineText: null,
|
|
28476
|
+
speechText: null,
|
|
28477
|
+
rejection: rejection ?? "no-artifact"
|
|
28478
|
+
};
|
|
28353
28479
|
}
|
|
28354
28480
|
const artifact = artifacts[0];
|
|
28355
28481
|
return {
|
|
28356
28482
|
hadIntake: true,
|
|
28357
28483
|
block: artifact.block,
|
|
28358
28484
|
machineText: artifact.machineText,
|
|
28359
|
-
speechText: artifact.speechText
|
|
28485
|
+
speechText: artifact.speechText,
|
|
28486
|
+
rejection: null,
|
|
28487
|
+
...artifacts.length > 1 ? { supersededCount: artifacts.length - 1 } : {}
|
|
28360
28488
|
};
|
|
28361
28489
|
}
|
|
28490
|
+
var dash = (v) => v?.trim() ? v.trim() : "\u2014";
|
|
28491
|
+
var bullet = (label, value) => value === void 0 ? [] : [`- **${label}:** ${dash(value)}`];
|
|
28362
28492
|
function renderCompanyProfile(block, now = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
28363
|
-
const dash = (v) => v?.trim() ? v.trim() : "\u2014";
|
|
28364
28493
|
const profileMd = [
|
|
28365
28494
|
`---`,
|
|
28366
28495
|
`type: memory`,
|
|
@@ -28375,22 +28504,30 @@ function renderCompanyProfile(block, now = (/* @__PURE__ */ new Date()).toISOStr
|
|
|
28375
28504
|
``,
|
|
28376
28505
|
`_Seeded from the onboarding questionnaire._`,
|
|
28377
28506
|
``,
|
|
28378
|
-
|
|
28379
|
-
|
|
28380
|
-
|
|
28381
|
-
|
|
28507
|
+
...bullet("Company", block.company_name),
|
|
28508
|
+
...bullet("Stage", block.company_stage),
|
|
28509
|
+
...bullet("ICP", block.icp),
|
|
28510
|
+
...bullet("Industry", block.industry),
|
|
28511
|
+
...bullet("Team size", block.team_size),
|
|
28382
28512
|
``,
|
|
28383
28513
|
`## Context`,
|
|
28384
28514
|
``,
|
|
28385
|
-
block.context.trim(),
|
|
28515
|
+
(block.context ?? "").trim(),
|
|
28386
28516
|
``
|
|
28387
28517
|
].join("\n");
|
|
28388
|
-
const bits = [
|
|
28389
|
-
|
|
28518
|
+
const bits = [
|
|
28519
|
+
block.company_name?.trim(),
|
|
28520
|
+
block.company_stage?.trim(),
|
|
28521
|
+
block.industry?.trim(),
|
|
28522
|
+
block.icp?.trim() ? `ICP ${block.icp.trim()}` : void 0
|
|
28523
|
+
].filter(Boolean).join(" \xB7 ");
|
|
28524
|
+
const summary = bits || (block.schema_version === "3" ? "no details captured at intake" : "");
|
|
28525
|
+
const memoryIndexLine = `- \`${COMPANY_PROFILE_PATH}\` \u2014 **Company profile**: ${summary}. (seeded from onboarding)`;
|
|
28390
28526
|
return { profileMd, memoryIndexLine };
|
|
28391
28527
|
}
|
|
28392
28528
|
var FOUNDER_RECORD_PATH = "memory/founder.md";
|
|
28393
|
-
var NOT_CAPTURED = "_not captured yet \u2014
|
|
28529
|
+
var NOT_CAPTURED = "_not captured yet \u2014 just tell me and I'll add it_";
|
|
28530
|
+
var REGION_UNKNOWN_AT_INTAKE = "_not known at intake \u2014 filled in when the request is filed_";
|
|
28394
28531
|
function renderFounderRecord(block, inputs, now = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
28395
28532
|
const pick = (...vals) => vals.map((v) => v?.trim()).find(Boolean) ?? "";
|
|
28396
28533
|
const founderName = pick(block.founder_name, inputs.azIdentity?.name);
|
|
@@ -28398,8 +28535,29 @@ function renderFounderRecord(block, inputs, now = (/* @__PURE__ */ new Date()).t
|
|
|
28398
28535
|
const advisorName = (block.advisor_name ?? "").trim();
|
|
28399
28536
|
const advisorEmail = (block.advisor_email ?? "").trim();
|
|
28400
28537
|
const subscription = (inputs.subscriptionId ?? "").trim();
|
|
28401
|
-
const teamSize = (block.team_size ?? "").trim();
|
|
28402
28538
|
const advisorRendered = advisorName || advisorEmail ? [advisorName, advisorEmail ? `<${advisorEmail}>` : ""].filter(Boolean).join(" ") : NOT_CAPTURED;
|
|
28539
|
+
const request = block.pending_requests?.[0];
|
|
28540
|
+
const requestLines = request === void 0 ? [] : (() => {
|
|
28541
|
+
const modelLabel = request.model.trim() ? `\`${request.model.trim()}\`` : "(model not recorded)";
|
|
28542
|
+
const consentLabel = request.consent === "submit" ? "submit the request" : "prepare it only, don't submit";
|
|
28543
|
+
const addressLine = request.company_address === null ? "not provided \u2014 the founder skipped it" : [
|
|
28544
|
+
request.company_address.address,
|
|
28545
|
+
request.company_address.city,
|
|
28546
|
+
request.company_address.postal_code,
|
|
28547
|
+
request.company_address.country
|
|
28548
|
+
].map((part) => part.trim()).filter(Boolean).join(", ") || "not provided";
|
|
28549
|
+
return [
|
|
28550
|
+
``,
|
|
28551
|
+
`## Requested at onboarding`,
|
|
28552
|
+
``,
|
|
28553
|
+
`_The founder asked for this during setup. Act on it when they bring it up._`,
|
|
28554
|
+
``,
|
|
28555
|
+
`- **What:** ${request.type} increase for ${modelLabel}`,
|
|
28556
|
+
`- **Region:** ${request.region.trim() || REGION_UNKNOWN_AT_INTAKE}`,
|
|
28557
|
+
`- **Consent:** ${consentLabel}`,
|
|
28558
|
+
`- **Company address:** ${addressLine}`
|
|
28559
|
+
];
|
|
28560
|
+
})();
|
|
28403
28561
|
const founderMd = [
|
|
28404
28562
|
`---`,
|
|
28405
28563
|
`type: memory`,
|
|
@@ -28418,7 +28576,8 @@ function renderFounderRecord(block, inputs, now = (/* @__PURE__ */ new Date()).t
|
|
|
28418
28576
|
`- **Founder email (company_email):** ${founderEmail || NOT_CAPTURED}`,
|
|
28419
28577
|
`- **Microsoft Startup Advisor (SA):** ${advisorRendered}`,
|
|
28420
28578
|
`- **Azure subscription:** ${subscription || NOT_CAPTURED}`,
|
|
28421
|
-
|
|
28579
|
+
...bullet("Team size", block.team_size),
|
|
28580
|
+
...requestLines,
|
|
28422
28581
|
``
|
|
28423
28582
|
].join("\n");
|
|
28424
28583
|
const idxAdvisor = advisorEmail || advisorName || "\u2014";
|
|
@@ -28427,7 +28586,168 @@ function renderFounderRecord(block, inputs, now = (/* @__PURE__ */ new Date()).t
|
|
|
28427
28586
|
return { founderMd, memoryIndexLine };
|
|
28428
28587
|
}
|
|
28429
28588
|
|
|
28589
|
+
// src/lib/model-cascade.ts
|
|
28590
|
+
var WHITELIST = [
|
|
28591
|
+
{ model: "gpt-5.6-luna", format: "OpenAI", version: "2026-07-09", capacity: 100 },
|
|
28592
|
+
{ model: "gpt-5.6-sol", format: "OpenAI", version: "2026-07-09", capacity: 100 },
|
|
28593
|
+
{ model: "gpt-5.6-terra", format: "OpenAI", version: "2026-07-09", capacity: 100 },
|
|
28594
|
+
{ model: "gpt-5.4", format: "OpenAI", version: "2026-03-05", capacity: 100 },
|
|
28595
|
+
{ model: "grok-4.3", format: "xAI", version: "1", capacity: 100 },
|
|
28596
|
+
{ model: "gpt-4.1-mini", format: "OpenAI", version: "2025-04-14", capacity: 50 }
|
|
28597
|
+
];
|
|
28598
|
+
var GLOBAL_STANDARD = "GlobalStandard";
|
|
28599
|
+
function planCascade(whitelist, catalog, quota) {
|
|
28600
|
+
if (!catalog.ok) {
|
|
28601
|
+
return {
|
|
28602
|
+
candidates: [],
|
|
28603
|
+
skipped: whitelist.map((r) => ({ model: r.model, outcome: "catalog-unverified", detail: catalog.error }))
|
|
28604
|
+
};
|
|
28605
|
+
}
|
|
28606
|
+
const rowsByName = /* @__PURE__ */ new Map();
|
|
28607
|
+
for (const row of catalog.rows) {
|
|
28608
|
+
const list = rowsByName.get(row.name);
|
|
28609
|
+
if (list) list.push(row);
|
|
28610
|
+
else rowsByName.set(row.name, [row]);
|
|
28611
|
+
}
|
|
28612
|
+
const candidates = [];
|
|
28613
|
+
const skipped = [];
|
|
28614
|
+
for (const rung of whitelist) {
|
|
28615
|
+
const rows = rowsByName.get(rung.model);
|
|
28616
|
+
if (!rows || rows.length === 0) {
|
|
28617
|
+
skipped.push({ model: rung.model, outcome: "not-in-catalog" });
|
|
28618
|
+
continue;
|
|
28619
|
+
}
|
|
28620
|
+
const agentRows = rows.filter((r) => r.agentsV2);
|
|
28621
|
+
if (agentRows.length === 0) {
|
|
28622
|
+
skipped.push({ model: rung.model, outcome: "not-agent-eligible" });
|
|
28623
|
+
continue;
|
|
28624
|
+
}
|
|
28625
|
+
if (!agentRows.some((r) => r.skus.includes(GLOBAL_STANDARD))) {
|
|
28626
|
+
skipped.push({ model: rung.model, outcome: "no-global-standard" });
|
|
28627
|
+
continue;
|
|
28628
|
+
}
|
|
28629
|
+
if (modelQuotaVerdict(quota, rung.model).verdict === "no_quota") {
|
|
28630
|
+
skipped.push({ model: rung.model, outcome: "no-quota" });
|
|
28631
|
+
continue;
|
|
28632
|
+
}
|
|
28633
|
+
candidates.push(rung);
|
|
28634
|
+
}
|
|
28635
|
+
return { candidates, skipped };
|
|
28636
|
+
}
|
|
28637
|
+
var QUOTA_RE = /insufficient\s*quota|not enough quota|quota limit|quota\b[^.]{0,40}exceed|exceed\w*\b[^.]{0,40}quota|capacity[^.]{0,40}exceed|exceed\w*\b[^.]{0,40}capacity/i;
|
|
28638
|
+
var REGION_RE = /not available in|not supported in|NotAvailableInRegion|InvalidResourceLocation/i;
|
|
28639
|
+
var CONFLICT_RE = /\bconflict\b|\b409\b/i;
|
|
28640
|
+
function classifyDeployError(message) {
|
|
28641
|
+
if (QUOTA_RE.test(message)) return "deploy-rejected-quota";
|
|
28642
|
+
if (REGION_RE.test(message)) return "deploy-rejected-region";
|
|
28643
|
+
return "deploy-unverified";
|
|
28644
|
+
}
|
|
28645
|
+
async function walkCascade(whitelist, plan, deploy, opts) {
|
|
28646
|
+
const outcomes = /* @__PURE__ */ new Map();
|
|
28647
|
+
for (const s of plan.skipped) outcomes.set(s.model, s);
|
|
28648
|
+
let chosen = null;
|
|
28649
|
+
let aborted = false;
|
|
28650
|
+
for (const rung of plan.candidates) {
|
|
28651
|
+
if (chosen) break;
|
|
28652
|
+
if (opts.now() >= opts.deadlineAt) {
|
|
28653
|
+
aborted = true;
|
|
28654
|
+
break;
|
|
28655
|
+
}
|
|
28656
|
+
let row;
|
|
28657
|
+
try {
|
|
28658
|
+
await deploy(rung);
|
|
28659
|
+
row = { model: rung.model, outcome: "deployed" };
|
|
28660
|
+
chosen = rung;
|
|
28661
|
+
} catch (e) {
|
|
28662
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
28663
|
+
if (CONFLICT_RE.test(msg)) {
|
|
28664
|
+
try {
|
|
28665
|
+
await deploy(rung);
|
|
28666
|
+
row = { model: rung.model, outcome: "deployed" };
|
|
28667
|
+
chosen = rung;
|
|
28668
|
+
} catch (e2) {
|
|
28669
|
+
const msg2 = e2 instanceof Error ? e2.message : String(e2);
|
|
28670
|
+
row = {
|
|
28671
|
+
model: rung.model,
|
|
28672
|
+
outcome: CONFLICT_RE.test(msg2) ? "deploy-unverified" : classifyDeployError(msg2),
|
|
28673
|
+
detail: msg2
|
|
28674
|
+
};
|
|
28675
|
+
}
|
|
28676
|
+
} else {
|
|
28677
|
+
row = { model: rung.model, outcome: classifyDeployError(msg), detail: msg };
|
|
28678
|
+
}
|
|
28679
|
+
}
|
|
28680
|
+
outcomes.set(rung.model, row);
|
|
28681
|
+
opts.onRung?.(row.model, row.outcome);
|
|
28682
|
+
}
|
|
28683
|
+
const trace = whitelist.map(
|
|
28684
|
+
(r) => outcomes.get(r.model) ?? { model: r.model, outcome: aborted ? "aborted-deadline" : "not-reached" }
|
|
28685
|
+
);
|
|
28686
|
+
return { chosen, trace };
|
|
28687
|
+
}
|
|
28688
|
+
var QUOTA_INVITATION = "You can offer to help request that quota.";
|
|
28689
|
+
var CERTAIN_UNAVAILABLE = /* @__PURE__ */ new Set([
|
|
28690
|
+
"not-in-catalog",
|
|
28691
|
+
"not-agent-eligible",
|
|
28692
|
+
"no-global-standard",
|
|
28693
|
+
"deploy-rejected-region"
|
|
28694
|
+
]);
|
|
28695
|
+
var QUOTA_BLOCKED = /* @__PURE__ */ new Set(["no-quota", "deploy-rejected-quota"]);
|
|
28696
|
+
function decideNote(whitelist, result) {
|
|
28697
|
+
const chosenIdx = result.chosen ? whitelist.findIndex((r) => r.model === result.chosen?.model) : whitelist.length;
|
|
28698
|
+
const better = result.trace.slice(0, Math.max(chosenIdx, 0));
|
|
28699
|
+
const runningModel = result.chosen?.model ?? null;
|
|
28700
|
+
if (chosenIdx === 0) {
|
|
28701
|
+
return { status: "top", runningModel, pitchModel: null, unavailableAbovePitch: [] };
|
|
28702
|
+
}
|
|
28703
|
+
const pitch = better.find((t) => QUOTA_BLOCKED.has(t.outcome));
|
|
28704
|
+
if (pitch) {
|
|
28705
|
+
const pitchIdx = better.findIndex((t) => t.model === pitch.model);
|
|
28706
|
+
return {
|
|
28707
|
+
status: "lesser-quota",
|
|
28708
|
+
runningModel,
|
|
28709
|
+
pitchModel: pitch.model,
|
|
28710
|
+
unavailableAbovePitch: better.slice(0, pitchIdx).filter((t) => CERTAIN_UNAVAILABLE.has(t.outcome)).map((t) => t.model)
|
|
28711
|
+
};
|
|
28712
|
+
}
|
|
28713
|
+
const allCertain = better.length > 0 && better.every((t) => CERTAIN_UNAVAILABLE.has(t.outcome));
|
|
28714
|
+
return {
|
|
28715
|
+
status: allCertain ? "lesser-unavailable" : "lesser-unverified",
|
|
28716
|
+
runningModel,
|
|
28717
|
+
pitchModel: null,
|
|
28718
|
+
unavailableAbovePitch: []
|
|
28719
|
+
};
|
|
28720
|
+
}
|
|
28721
|
+
var listNames = (names) => names.length <= 1 ? names[0] ?? "" : `${names.slice(0, -1).join(", ")} and ${names[names.length - 1]}`;
|
|
28722
|
+
function renderChosenModelNote(d) {
|
|
28723
|
+
const subject = d.runningModel ? `You are running on ${d.runningModel}.` : "You are running on this install's default model.";
|
|
28724
|
+
switch (d.status) {
|
|
28725
|
+
case "top":
|
|
28726
|
+
return `${subject} That is the best available model for this install.`;
|
|
28727
|
+
case "lesser-quota": {
|
|
28728
|
+
const aside = d.unavailableAbovePitch.length > 0 ? ` ${listNames(d.unavailableAbovePitch)} ${d.unavailableAbovePitch.length > 1 ? "are" : "is"} not offered for this install.` : "";
|
|
28729
|
+
return `${subject} A stronger model, ${d.pitchModel ?? ""}, is offered here, but this subscription has no quota for it.${aside} ${QUOTA_INVITATION}`;
|
|
28730
|
+
}
|
|
28731
|
+
case "lesser-unavailable":
|
|
28732
|
+
return `${subject} No stronger model is offered for this install right now.`;
|
|
28733
|
+
case "lesser-unverified":
|
|
28734
|
+
return `${subject} It was not possible to check which stronger models this subscription can run, so do not make claims about what is or is not available.`;
|
|
28735
|
+
}
|
|
28736
|
+
}
|
|
28737
|
+
|
|
28430
28738
|
// src/lib/founder-identity.ts
|
|
28739
|
+
var INVENTORY_INVITATION = "You can offer to walk the founder through these resources.";
|
|
28740
|
+
var NOTE_INVITATIONS = [QUOTA_INVITATION, INVENTORY_INVITATION];
|
|
28741
|
+
function escapeRegExp(value) {
|
|
28742
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
28743
|
+
}
|
|
28744
|
+
function stripNoteInvitations(value) {
|
|
28745
|
+
let out = value;
|
|
28746
|
+
for (const sentence of NOTE_INVITATIONS) {
|
|
28747
|
+
out = out.replace(new RegExp(escapeRegExp(sentence), "gi"), " ");
|
|
28748
|
+
}
|
|
28749
|
+
return out.replace(/\s{2,}/g, " ").trim();
|
|
28750
|
+
}
|
|
28431
28751
|
function deriveEmailCandidate(raw) {
|
|
28432
28752
|
const mail = (raw.mail ?? "").trim();
|
|
28433
28753
|
if (mail) return mail;
|
|
@@ -28459,11 +28779,13 @@ async function getSignedInUserIdentity(runAzImpl = runAz) {
|
|
|
28459
28779
|
}
|
|
28460
28780
|
}
|
|
28461
28781
|
function composeFounderIdentityNote(id) {
|
|
28462
|
-
|
|
28463
|
-
|
|
28782
|
+
const name = stripNoteInvitations(id.name);
|
|
28783
|
+
const email = stripNoteInvitations(id.email);
|
|
28784
|
+
if (name && email) {
|
|
28785
|
+
return `You're speaking with **${name}**, signed in to Azure (their email looks like **${email}**). Open by confirming both, in your own voice \u2014 e.g. "I see you're signed in as ${name}, and I'll use ${email} for your advisor handoffs and cost reports \u2014 is that right, or should I change either?" Record exactly what they approve or correct.`;
|
|
28464
28786
|
}
|
|
28465
|
-
if (
|
|
28466
|
-
return `You're speaking with **${
|
|
28787
|
+
if (name) {
|
|
28788
|
+
return `You're speaking with **${name}** (signed in to Azure). Confirm their name, then ask for the best contact email to reach them (that's where advisor handoffs and cost reports go).`;
|
|
28467
28789
|
}
|
|
28468
28790
|
return `Ask the founder their name and the best contact email to reach them (that's where advisor handoffs and cost reports go).`;
|
|
28469
28791
|
}
|
|
@@ -28663,7 +28985,7 @@ async function reactiveSeedOnFinish(args) {
|
|
|
28663
28985
|
if (!hadIntake) return;
|
|
28664
28986
|
(args.spawnWatch ?? spawnDetachedSeedWatch)();
|
|
28665
28987
|
args.stdout(
|
|
28666
|
-
`${colors.dim("\u2139 Your advisors will pick up your company profile when you finish the
|
|
28988
|
+
`${colors.dim("\u2139 Your advisors will pick up your company profile when you finish the intake (watching in the background).")}
|
|
28667
28989
|
${colors.hint("or run:")} m8t bootstrap seed-profile
|
|
28668
28990
|
`
|
|
28669
28991
|
);
|
|
@@ -28705,7 +29027,7 @@ var BootstrapFinishCommand = class extends M8tCommand {
|
|
|
28705
29027
|
static paths = [["bootstrap", "finish"]];
|
|
28706
29028
|
static usage = Command55.Usage({
|
|
28707
29029
|
description: "Point your local tools at the now-live platform (repo-root marker, discovery cache, next steps).",
|
|
28708
|
-
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
|
|
29030
|
+
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 intake \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.",
|
|
28709
29031
|
examples: [["Finish local", "$0 bootstrap finish --repo-root /path/to/m8t"]]
|
|
28710
29032
|
});
|
|
28711
29033
|
repoRoot = Option52.String("--repo-root");
|
|
@@ -28827,17 +29149,17 @@ import { spawn as spawn7, spawnSync as spawnSync6 } from "child_process";
|
|
|
28827
29149
|
init_errors();
|
|
28828
29150
|
init_rbac();
|
|
28829
29151
|
|
|
28830
|
-
// src/lib/
|
|
28831
|
-
var
|
|
28832
|
-
var
|
|
28833
|
-
async function
|
|
29152
|
+
// src/lib/intake-agent.ts
|
|
29153
|
+
var INTAKE_PERSONA = "azure-advisor-intake";
|
|
29154
|
+
var INTAKE_AGENT = "azzy-intake";
|
|
29155
|
+
async function deployIntakeAgent(args) {
|
|
28834
29156
|
try {
|
|
28835
29157
|
return await deployPromptAdvisor({
|
|
28836
29158
|
credential: args.credential,
|
|
28837
29159
|
endpoint: args.endpoint,
|
|
28838
29160
|
repoRoot: args.repoRoot,
|
|
28839
|
-
persona:
|
|
28840
|
-
agentName:
|
|
29161
|
+
persona: INTAKE_PERSONA,
|
|
29162
|
+
agentName: INTAKE_AGENT,
|
|
28841
29163
|
model: args.model,
|
|
28842
29164
|
fieldOverrides: args.fieldOverrides
|
|
28843
29165
|
});
|
|
@@ -28847,7 +29169,7 @@ async function deploySimpleStacey(args) {
|
|
|
28847
29169
|
if (err.code === "ADVISOR_PERSONA_MISSING") {
|
|
28848
29170
|
const { LocalCliError: LocalCliError2 } = await Promise.resolve().then(() => (init_errors(), errors_exports));
|
|
28849
29171
|
throw new LocalCliError2({
|
|
28850
|
-
code: "
|
|
29172
|
+
code: "INTAKE_PERSONA_MISSING",
|
|
28851
29173
|
message: err.message,
|
|
28852
29174
|
hint: err.hint,
|
|
28853
29175
|
cause: err.cause
|
|
@@ -28856,7 +29178,7 @@ async function deploySimpleStacey(args) {
|
|
|
28856
29178
|
if (err.code === "ADVISOR_NO_MODEL") {
|
|
28857
29179
|
const { LocalCliError: LocalCliError2 } = await Promise.resolve().then(() => (init_errors(), errors_exports));
|
|
28858
29180
|
throw new LocalCliError2({
|
|
28859
|
-
code: "
|
|
29181
|
+
code: "INTAKE_NO_MODEL",
|
|
28860
29182
|
message: err.message,
|
|
28861
29183
|
hint: err.hint,
|
|
28862
29184
|
cause: err.cause
|
|
@@ -28865,7 +29187,7 @@ async function deploySimpleStacey(args) {
|
|
|
28865
29187
|
if (err.code === "ADVISOR_BAD_EFFORT") {
|
|
28866
29188
|
const { LocalCliError: LocalCliError2 } = await Promise.resolve().then(() => (init_errors(), errors_exports));
|
|
28867
29189
|
throw new LocalCliError2({
|
|
28868
|
-
code: "
|
|
29190
|
+
code: "INTAKE_BAD_EFFORT",
|
|
28869
29191
|
message: err.message,
|
|
28870
29192
|
hint: err.hint,
|
|
28871
29193
|
cause: err.cause
|
|
@@ -28897,13 +29219,13 @@ function isAuthorizationShapedError(error) {
|
|
|
28897
29219
|
}
|
|
28898
29220
|
return false;
|
|
28899
29221
|
}
|
|
28900
|
-
async function
|
|
29222
|
+
async function deployIntakeAgentWithRetry(args) {
|
|
28901
29223
|
const maxWaitMs = args.maxWaitMs ?? 3e5;
|
|
28902
29224
|
const intervalMs = args.intervalMs ?? 1e4;
|
|
28903
29225
|
const deadline = Date.now() + maxWaitMs;
|
|
28904
29226
|
for (; ; ) {
|
|
28905
29227
|
try {
|
|
28906
|
-
return await
|
|
29228
|
+
return await deployIntakeAgent({
|
|
28907
29229
|
credential: args.credential,
|
|
28908
29230
|
endpoint: args.endpoint,
|
|
28909
29231
|
repoRoot: args.repoRoot,
|
|
@@ -28916,7 +29238,7 @@ async function deploySimpleStaceyWithRetry(args) {
|
|
|
28916
29238
|
if (remainingMs <= 0) {
|
|
28917
29239
|
throw new LocalCliError({
|
|
28918
29240
|
code: "BOOTSTRAP_UI_ROLE_PROPAGATION_TIMEOUT",
|
|
28919
|
-
message: "Timed out waiting for Azure role propagation before deploying
|
|
29241
|
+
message: "Timed out waiting for Azure role propagation before deploying the intake agent.",
|
|
28920
29242
|
hint: "Azure role propagation can take a few minutes - re-run 'm8t bootstrap ui' (idempotent).",
|
|
28921
29243
|
cause: error
|
|
28922
29244
|
});
|
|
@@ -28946,7 +29268,7 @@ async function resolveFoundryEndpointWithWait(args, opts = {}) {
|
|
|
28946
29268
|
if (e instanceof LocalCliError && e.code === "FOUNDRY_PROJECT_MULTIPLE") {
|
|
28947
29269
|
throw new LocalCliError({
|
|
28948
29270
|
code: "BOOTSTRAP_UI_MULTIPLE_PROJECTS",
|
|
28949
|
-
message: `${e.message} bootstrap ui can't pick one safely (it must not deploy
|
|
29271
|
+
message: `${e.message} bootstrap ui can't pick one safely (it must not deploy the intake agent into the wrong project).`,
|
|
28950
29272
|
hint: `Re-run with the throwaway project's endpoint, e.g. 'm8t bootstrap ui --repo-root "$(pwd)" --endpoint https://<account>.services.ai.azure.com/api/projects/m8t'. The installer prints it in 'm8t bootstrap status'.`,
|
|
28951
29273
|
cause: e
|
|
28952
29274
|
});
|
|
@@ -29003,7 +29325,7 @@ function writeWebEnvLocal(args) {
|
|
|
29003
29325
|
});
|
|
29004
29326
|
}
|
|
29005
29327
|
const body = [
|
|
29006
|
-
"# Written by `m8t bootstrap ui` \u2014 local onboarding run (
|
|
29328
|
+
"# Written by `m8t bootstrap ui` \u2014 local onboarding run (the onboarding intake agent).",
|
|
29007
29329
|
"# Text-first: the intake voice stack is off unless the run passed --voice.",
|
|
29008
29330
|
"# STORAGE unset \u2192 gateway boot skipped; the webapp forwards your MSAL token to Foundry.",
|
|
29009
29331
|
`AZURE_TENANT_ID=${args.tenantId}`,
|
|
@@ -29344,154 +29666,6 @@ async function listAgentModels(region) {
|
|
|
29344
29666
|
}
|
|
29345
29667
|
}
|
|
29346
29668
|
|
|
29347
|
-
// src/lib/model-cascade.ts
|
|
29348
|
-
var WHITELIST = [
|
|
29349
|
-
{ model: "gpt-5.6-luna", format: "OpenAI", version: "2026-07-09", capacity: 100 },
|
|
29350
|
-
{ model: "gpt-5.6-sol", format: "OpenAI", version: "2026-07-09", capacity: 100 },
|
|
29351
|
-
{ model: "gpt-5.6-terra", format: "OpenAI", version: "2026-07-09", capacity: 100 },
|
|
29352
|
-
{ model: "gpt-5.4", format: "OpenAI", version: "2026-03-05", capacity: 100 },
|
|
29353
|
-
{ model: "grok-4.3", format: "xAI", version: "1", capacity: 100 },
|
|
29354
|
-
{ model: "gpt-4.1-mini", format: "OpenAI", version: "2025-04-14", capacity: 50 }
|
|
29355
|
-
];
|
|
29356
|
-
var GLOBAL_STANDARD = "GlobalStandard";
|
|
29357
|
-
function planCascade(whitelist, catalog, quota) {
|
|
29358
|
-
if (!catalog.ok) {
|
|
29359
|
-
return {
|
|
29360
|
-
candidates: [],
|
|
29361
|
-
skipped: whitelist.map((r) => ({ model: r.model, outcome: "catalog-unverified", detail: catalog.error }))
|
|
29362
|
-
};
|
|
29363
|
-
}
|
|
29364
|
-
const rowsByName = /* @__PURE__ */ new Map();
|
|
29365
|
-
for (const row of catalog.rows) {
|
|
29366
|
-
const list = rowsByName.get(row.name);
|
|
29367
|
-
if (list) list.push(row);
|
|
29368
|
-
else rowsByName.set(row.name, [row]);
|
|
29369
|
-
}
|
|
29370
|
-
const candidates = [];
|
|
29371
|
-
const skipped = [];
|
|
29372
|
-
for (const rung of whitelist) {
|
|
29373
|
-
const rows = rowsByName.get(rung.model);
|
|
29374
|
-
if (!rows || rows.length === 0) {
|
|
29375
|
-
skipped.push({ model: rung.model, outcome: "not-in-catalog" });
|
|
29376
|
-
continue;
|
|
29377
|
-
}
|
|
29378
|
-
const agentRows = rows.filter((r) => r.agentsV2);
|
|
29379
|
-
if (agentRows.length === 0) {
|
|
29380
|
-
skipped.push({ model: rung.model, outcome: "not-agent-eligible" });
|
|
29381
|
-
continue;
|
|
29382
|
-
}
|
|
29383
|
-
if (!agentRows.some((r) => r.skus.includes(GLOBAL_STANDARD))) {
|
|
29384
|
-
skipped.push({ model: rung.model, outcome: "no-global-standard" });
|
|
29385
|
-
continue;
|
|
29386
|
-
}
|
|
29387
|
-
if (modelQuotaVerdict(quota, rung.model).verdict === "no_quota") {
|
|
29388
|
-
skipped.push({ model: rung.model, outcome: "no-quota" });
|
|
29389
|
-
continue;
|
|
29390
|
-
}
|
|
29391
|
-
candidates.push(rung);
|
|
29392
|
-
}
|
|
29393
|
-
return { candidates, skipped };
|
|
29394
|
-
}
|
|
29395
|
-
var QUOTA_RE = /insufficient\s*quota|not enough quota|quota limit|quota\b[^.]{0,40}exceed|exceed\w*\b[^.]{0,40}quota|capacity[^.]{0,40}exceed|exceed\w*\b[^.]{0,40}capacity/i;
|
|
29396
|
-
var REGION_RE = /not available in|not supported in|NotAvailableInRegion|InvalidResourceLocation/i;
|
|
29397
|
-
var CONFLICT_RE = /\bconflict\b|\b409\b/i;
|
|
29398
|
-
function classifyDeployError(message) {
|
|
29399
|
-
if (QUOTA_RE.test(message)) return "deploy-rejected-quota";
|
|
29400
|
-
if (REGION_RE.test(message)) return "deploy-rejected-region";
|
|
29401
|
-
return "deploy-unverified";
|
|
29402
|
-
}
|
|
29403
|
-
async function walkCascade(whitelist, plan, deploy, opts) {
|
|
29404
|
-
const outcomes = /* @__PURE__ */ new Map();
|
|
29405
|
-
for (const s of plan.skipped) outcomes.set(s.model, s);
|
|
29406
|
-
let chosen = null;
|
|
29407
|
-
let aborted = false;
|
|
29408
|
-
for (const rung of plan.candidates) {
|
|
29409
|
-
if (chosen) break;
|
|
29410
|
-
if (opts.now() >= opts.deadlineAt) {
|
|
29411
|
-
aborted = true;
|
|
29412
|
-
break;
|
|
29413
|
-
}
|
|
29414
|
-
let row;
|
|
29415
|
-
try {
|
|
29416
|
-
await deploy(rung);
|
|
29417
|
-
row = { model: rung.model, outcome: "deployed" };
|
|
29418
|
-
chosen = rung;
|
|
29419
|
-
} catch (e) {
|
|
29420
|
-
const msg = e instanceof Error ? e.message : String(e);
|
|
29421
|
-
if (CONFLICT_RE.test(msg)) {
|
|
29422
|
-
try {
|
|
29423
|
-
await deploy(rung);
|
|
29424
|
-
row = { model: rung.model, outcome: "deployed" };
|
|
29425
|
-
chosen = rung;
|
|
29426
|
-
} catch (e2) {
|
|
29427
|
-
const msg2 = e2 instanceof Error ? e2.message : String(e2);
|
|
29428
|
-
row = {
|
|
29429
|
-
model: rung.model,
|
|
29430
|
-
outcome: CONFLICT_RE.test(msg2) ? "deploy-unverified" : classifyDeployError(msg2),
|
|
29431
|
-
detail: msg2
|
|
29432
|
-
};
|
|
29433
|
-
}
|
|
29434
|
-
} else {
|
|
29435
|
-
row = { model: rung.model, outcome: classifyDeployError(msg), detail: msg };
|
|
29436
|
-
}
|
|
29437
|
-
}
|
|
29438
|
-
outcomes.set(rung.model, row);
|
|
29439
|
-
opts.onRung?.(row.model, row.outcome);
|
|
29440
|
-
}
|
|
29441
|
-
const trace = whitelist.map(
|
|
29442
|
-
(r) => outcomes.get(r.model) ?? { model: r.model, outcome: aborted ? "aborted-deadline" : "not-reached" }
|
|
29443
|
-
);
|
|
29444
|
-
return { chosen, trace };
|
|
29445
|
-
}
|
|
29446
|
-
var CERTAIN_UNAVAILABLE = /* @__PURE__ */ new Set([
|
|
29447
|
-
"not-in-catalog",
|
|
29448
|
-
"not-agent-eligible",
|
|
29449
|
-
"no-global-standard",
|
|
29450
|
-
"deploy-rejected-region"
|
|
29451
|
-
]);
|
|
29452
|
-
var QUOTA_BLOCKED = /* @__PURE__ */ new Set(["no-quota", "deploy-rejected-quota"]);
|
|
29453
|
-
function decideNote(whitelist, result) {
|
|
29454
|
-
const chosenIdx = result.chosen ? whitelist.findIndex((r) => r.model === result.chosen?.model) : whitelist.length;
|
|
29455
|
-
const better = result.trace.slice(0, Math.max(chosenIdx, 0));
|
|
29456
|
-
const runningModel = result.chosen?.model ?? null;
|
|
29457
|
-
if (chosenIdx === 0) {
|
|
29458
|
-
return { status: "top", runningModel, pitchModel: null, unavailableAbovePitch: [] };
|
|
29459
|
-
}
|
|
29460
|
-
const pitch = better.find((t) => QUOTA_BLOCKED.has(t.outcome));
|
|
29461
|
-
if (pitch) {
|
|
29462
|
-
const pitchIdx = better.findIndex((t) => t.model === pitch.model);
|
|
29463
|
-
return {
|
|
29464
|
-
status: "lesser-quota",
|
|
29465
|
-
runningModel,
|
|
29466
|
-
pitchModel: pitch.model,
|
|
29467
|
-
unavailableAbovePitch: better.slice(0, pitchIdx).filter((t) => CERTAIN_UNAVAILABLE.has(t.outcome)).map((t) => t.model)
|
|
29468
|
-
};
|
|
29469
|
-
}
|
|
29470
|
-
const allCertain = better.length > 0 && better.every((t) => CERTAIN_UNAVAILABLE.has(t.outcome));
|
|
29471
|
-
return {
|
|
29472
|
-
status: allCertain ? "lesser-unavailable" : "lesser-unverified",
|
|
29473
|
-
runningModel,
|
|
29474
|
-
pitchModel: null,
|
|
29475
|
-
unavailableAbovePitch: []
|
|
29476
|
-
};
|
|
29477
|
-
}
|
|
29478
|
-
var listNames = (names) => names.length <= 1 ? names[0] ?? "" : `${names.slice(0, -1).join(", ")} and ${names[names.length - 1]}`;
|
|
29479
|
-
function renderChosenModelNote(d) {
|
|
29480
|
-
const subject = d.runningModel ? `You are running on ${d.runningModel}.` : "You are running on this install's default model.";
|
|
29481
|
-
switch (d.status) {
|
|
29482
|
-
case "top":
|
|
29483
|
-
return `${subject} That is the best available model for this install.`;
|
|
29484
|
-
case "lesser-quota": {
|
|
29485
|
-
const aside = d.unavailableAbovePitch.length > 0 ? ` ${listNames(d.unavailableAbovePitch)} ${d.unavailableAbovePitch.length > 1 ? "are" : "is"} not offered for this install.` : "";
|
|
29486
|
-
return `${subject} A stronger model, ${d.pitchModel ?? ""}, is offered here, but this subscription has no quota for it.${aside} You can offer to help request that quota.`;
|
|
29487
|
-
}
|
|
29488
|
-
case "lesser-unavailable":
|
|
29489
|
-
return `${subject} No stronger model is offered for this install right now.`;
|
|
29490
|
-
case "lesser-unverified":
|
|
29491
|
-
return `${subject} It was not possible to check which stronger models this subscription can run, so do not make claims about what is or is not available.`;
|
|
29492
|
-
}
|
|
29493
|
-
}
|
|
29494
|
-
|
|
29495
29669
|
// src/lib/intake-model.ts
|
|
29496
29670
|
var DEFAULT_DEADLINE_MS = 18e4;
|
|
29497
29671
|
var SCOPE_RE = /\/resourceGroups\/([^/]+)\/providers\/Microsoft\.CognitiveServices\/accounts\/([^/]+)/i;
|
|
@@ -29564,7 +29738,7 @@ async function resolveIntakeModel(args) {
|
|
|
29564
29738
|
|
|
29565
29739
|
// src/lib/inventory-summary.ts
|
|
29566
29740
|
var HEAVY_THRESHOLD = 10;
|
|
29567
|
-
var
|
|
29741
|
+
var INVENTORY_INVITATION2 = "You can offer to walk the founder through these resources.";
|
|
29568
29742
|
var NOTABLE_TYPES = {
|
|
29569
29743
|
// storage
|
|
29570
29744
|
"microsoft.storage/storageaccounts": "storage accounts",
|
|
@@ -29694,7 +29868,7 @@ function regionAgeClause(s) {
|
|
|
29694
29868
|
}
|
|
29695
29869
|
function renderInventoryNote(summary) {
|
|
29696
29870
|
const body = summary.notableCount === 0 ? `${LEAD} There are no notable pre-existing resources.` : `${LEAD} ${piecesClause(summary)}${regionAgeClause(summary)}.`;
|
|
29697
|
-
return summary.verdict === "heavy" ? `${body} ${
|
|
29871
|
+
return summary.verdict === "heavy" ? `${body} ${INVENTORY_INVITATION2}` : body;
|
|
29698
29872
|
}
|
|
29699
29873
|
|
|
29700
29874
|
// src/lib/subscription-inventory.ts
|
|
@@ -29753,27 +29927,28 @@ async function resolveSubscriptionInventory(args) {
|
|
|
29753
29927
|
|
|
29754
29928
|
// src/commands/bootstrap/ui.ts
|
|
29755
29929
|
function renderDeploySuccess(version, envPath) {
|
|
29756
|
-
return `${colors.success("\u2713")}
|
|
29930
|
+
return `${colors.success("\u2713")} Azzy is live (${INTAKE_AGENT} v${version}).
|
|
29757
29931
|
env: ${envPath}
|
|
29758
|
-
Opening ${colors.field("http://localhost:3000")} in your browser \u2192 Sign in with Microsoft \u2192 chat with
|
|
29932
|
+
Opening ${colors.field("http://localhost:3000")} in your browser \u2192 Sign in with Microsoft \u2192 chat with Azzy.
|
|
29759
29933
|
${colors.dim("(If it doesn't open, browse to http://localhost:3000 yourself.)")}
|
|
29760
29934
|
${colors.dim("First turn may say 'warming up' for a few minutes while access propagates \u2014 that's expected.")}
|
|
29761
29935
|
`;
|
|
29762
29936
|
}
|
|
29763
29937
|
function renderDeployFailure(error) {
|
|
29764
29938
|
const hint = error instanceof LocalCliError && error.hint ? error.hint : "Re-run 'm8t bootstrap ui' (idempotent).";
|
|
29765
|
-
return `${colors.error("\u2717")}
|
|
29939
|
+
return `${colors.error("\u2717")} Azzy deploy failed: ${error.message}
|
|
29766
29940
|
${colors.hint(hint)}
|
|
29767
29941
|
`;
|
|
29768
29942
|
}
|
|
29769
29943
|
var BootstrapUiCommand = class extends M8tCommand {
|
|
29770
29944
|
static paths = [["bootstrap", "ui"]];
|
|
29771
29945
|
static usage = Command56.Usage({
|
|
29772
|
-
description: "Deploy
|
|
29946
|
+
description: "Deploy Azzy + start the local onboarding chat UI in the background (returns immediately).",
|
|
29773
29947
|
details: [
|
|
29774
29948
|
"Run after `m8t bootstrap launch`, in parallel with `status --watch`. Waits for the cloud",
|
|
29775
|
-
"installer's foundry-create phase, grants you Foundry data-plane access, deploys
|
|
29776
|
-
"
|
|
29949
|
+
"installer's foundry-create phase, grants you Foundry data-plane access, deploys the no-brain",
|
|
29950
|
+
"onboarding intake agent (azzy-intake), writes apps/web/.env.local (voice relay config is added",
|
|
29951
|
+
"only when --voice is set \u2014 see --voice for what that does and does not affect),",
|
|
29777
29952
|
"installs deps, and starts the webapp detached so a coding agent can continue without opening",
|
|
29778
29953
|
"a separate terminal.",
|
|
29779
29954
|
"",
|
|
@@ -29785,7 +29960,7 @@ var BootstrapUiCommand = class extends M8tCommand {
|
|
|
29785
29960
|
["Stop the running onboarding UI", "$0 bootstrap ui --stop"],
|
|
29786
29961
|
["Prep only (don't serve at all)", "$0 bootstrap ui --repo-root /path/to/m8t --prep-only"],
|
|
29787
29962
|
["Foreground (blocking, old behaviour)", "$0 bootstrap ui --repo-root /path/to/m8t --foreground"],
|
|
29788
|
-
["Experimental:
|
|
29963
|
+
["Experimental: start the voice relay (no effect on the text-only intake)", "$0 bootstrap ui --repo-root /path/to/m8t --voice"]
|
|
29789
29964
|
]
|
|
29790
29965
|
});
|
|
29791
29966
|
repoRoot = Option53.String("--repo-root");
|
|
@@ -29798,7 +29973,7 @@ var BootstrapUiCommand = class extends M8tCommand {
|
|
|
29798
29973
|
stop = Option53.Boolean("--stop", false);
|
|
29799
29974
|
foreground = Option53.Boolean("--foreground", false);
|
|
29800
29975
|
voice = Option53.Boolean("--voice", false, {
|
|
29801
|
-
description: "Experimental
|
|
29976
|
+
description: "Experimental: when serving, starts the voice relay and writes the intake voice env var. The onboarding intake is text-only and is unaffected by this flag \u2014 no voice worker is registered for it."
|
|
29802
29977
|
});
|
|
29803
29978
|
async executeCommand() {
|
|
29804
29979
|
if (this.stop === true) {
|
|
@@ -29851,7 +30026,7 @@ var BootstrapUiCommand = class extends M8tCommand {
|
|
|
29851
30026
|
const oid = await getSignedInUserOid();
|
|
29852
30027
|
await ensureFounderFoundryRole({ credential: credential2, subscriptionId: state.subscriptionId, principalId: oid, accountScope });
|
|
29853
30028
|
const identity = await getSignedInUserIdentity();
|
|
29854
|
-
out("deploying
|
|
30029
|
+
out("deploying the intake agent (azzy-intake) in the background...");
|
|
29855
30030
|
const deployOutcome = (async () => {
|
|
29856
30031
|
const [choice, inventory] = await Promise.all([
|
|
29857
30032
|
resolveIntakeModel({
|
|
@@ -29865,7 +30040,7 @@ var BootstrapUiCommand = class extends M8tCommand {
|
|
|
29865
30040
|
onNarrate: out
|
|
29866
30041
|
})
|
|
29867
30042
|
]);
|
|
29868
|
-
return
|
|
30043
|
+
return deployIntakeAgentWithRetry({
|
|
29869
30044
|
credential: credential2,
|
|
29870
30045
|
endpoint,
|
|
29871
30046
|
repoRoot,
|
|
@@ -29963,16 +30138,16 @@ import { Command as Command57, Option as Option54 } from "clipanion";
|
|
|
29963
30138
|
var BootstrapSeedProfileCommand = class extends M8tCommand {
|
|
29964
30139
|
static paths = [["bootstrap", "seed-profile"]];
|
|
29965
30140
|
static usage = Command57.Usage({
|
|
29966
|
-
description: "Seed your advisors' brains with the founder + company profile from the onboarding
|
|
29967
|
-
details: "Reads the latest
|
|
30141
|
+
description: "Seed your advisors' brains with the founder + company profile from the onboarding intake.",
|
|
30142
|
+
details: "Reads the latest onboarding 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 finishes the intake.",
|
|
29968
30143
|
examples: [
|
|
29969
30144
|
["Seed now (idempotent)", "$0 bootstrap seed-profile"],
|
|
29970
30145
|
["Wait for the founder to finish", "$0 bootstrap seed-profile --watch"]
|
|
29971
30146
|
]
|
|
29972
30147
|
});
|
|
29973
30148
|
endpoint = Option54.String("--endpoint", { description: "Override the Foundry endpoint (else read from the install status)." });
|
|
29974
|
-
brain = Option54.String("--brain", { description: "
|
|
29975
|
-
watch = Option54.Boolean("--watch", false, { description: "Poll until the
|
|
30149
|
+
brain = Option54.String("--brain", { description: "Seed only this one brain repo, instead of both <org>/stacey-brain and <org>/azzy-brain." });
|
|
30150
|
+
watch = Option54.Boolean("--watch", false, { description: "Poll until the intake completes (or --timeout)." });
|
|
29976
30151
|
timeout = Option54.String("--timeout", { description: "Watch timeout in minutes (default 20)." });
|
|
29977
30152
|
githubAppCreds = Option54.String("--github-app-creds");
|
|
29978
30153
|
async executeCommand() {
|
|
@@ -29994,7 +30169,7 @@ var BootstrapSeedProfileCommand = class extends M8tCommand {
|
|
|
29994
30169
|
const sleep5 = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
29995
30170
|
for (; ; ) {
|
|
29996
30171
|
const token = await getFoundryToken();
|
|
29997
|
-
const { hadIntake, block } = await findOnboardingProfile({ endpoint: ctx.endpoint, token });
|
|
30172
|
+
const { hadIntake, block, rejection } = await findOnboardingProfile({ endpoint: ctx.endpoint, token });
|
|
29998
30173
|
if (block) {
|
|
29999
30174
|
const azIdentity = await getSignedInUserIdentity();
|
|
30000
30175
|
await applyProfileToBrains({
|
|
@@ -30005,19 +30180,28 @@ var BootstrapSeedProfileCommand = class extends M8tCommand {
|
|
|
30005
30180
|
subscriptionId: ctx.subscriptionId,
|
|
30006
30181
|
azIdentity
|
|
30007
30182
|
});
|
|
30008
|
-
this.context.stdout.write(`${colors.success("\u2713")} seeded your advisors' brains (${ctx.brainRepos.join(", ")}) from your
|
|
30183
|
+
this.context.stdout.write(`${colors.success("\u2713")} seeded your advisors' brains (${ctx.brainRepos.join(", ")}) from your intake.
|
|
30009
30184
|
`);
|
|
30010
30185
|
return 0;
|
|
30011
30186
|
}
|
|
30012
30187
|
if (!watch || Date.now() >= deadline) {
|
|
30188
|
+
if (rejection !== null && rejection !== "no-artifact") {
|
|
30189
|
+
this.context.stderr.write(
|
|
30190
|
+
` ${colors.dim(`found an onboarding block but could not read it \u2014 ${describeBlockRejection(rejection)}.`)}
|
|
30191
|
+
${colors.hint("fix:")} delete this onboarding conversation in the Azure AI Foundry portal, then redo the intake and run: m8t bootstrap seed-profile
|
|
30192
|
+
`
|
|
30193
|
+
);
|
|
30194
|
+
return 3;
|
|
30195
|
+
}
|
|
30196
|
+
const why = hadIntake ? "intake not complete yet \u2014 no m8t_onboarding block found." : "no onboarding intake found.";
|
|
30013
30197
|
this.context.stderr.write(
|
|
30014
|
-
` ${colors.dim(
|
|
30198
|
+
` ${colors.dim(why)}
|
|
30015
30199
|
${colors.hint("retry:")} m8t bootstrap seed-profile
|
|
30016
30200
|
`
|
|
30017
30201
|
);
|
|
30018
30202
|
return 3;
|
|
30019
30203
|
}
|
|
30020
|
-
this.context.stderr.write(` ${colors.dim("waiting for the
|
|
30204
|
+
this.context.stderr.write(` ${colors.dim("waiting for the intake to complete\u2026")}
|
|
30021
30205
|
`);
|
|
30022
30206
|
await sleep5(2e4);
|
|
30023
30207
|
}
|