@m8t-stack/cli 0.2.37 → 0.2.38
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 +274 -10
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1298,7 +1298,7 @@ var init_enable_hosted_brain = __esm({
|
|
|
1298
1298
|
import { Builtins, Cli } from "clipanion";
|
|
1299
1299
|
|
|
1300
1300
|
// src/lib/package-version.ts
|
|
1301
|
-
var CLI_VERSION = "0.2.
|
|
1301
|
+
var CLI_VERSION = "0.2.38";
|
|
1302
1302
|
|
|
1303
1303
|
// src/lib/render-error.ts
|
|
1304
1304
|
init_errors();
|
|
@@ -16963,7 +16963,7 @@ async function listModelQuota(region) {
|
|
|
16963
16963
|
function usageModelName(usageName) {
|
|
16964
16964
|
return usageName.split(".").slice(2).join(".");
|
|
16965
16965
|
}
|
|
16966
|
-
var REASONING_USAGE_RE = /gpt-5|o[1-9]/i;
|
|
16966
|
+
var REASONING_USAGE_RE = /gpt-5|o[1-9]|grok-4/i;
|
|
16967
16967
|
function isReasoningModel(modelDeployment) {
|
|
16968
16968
|
return REASONING_USAGE_RE.test(modelDeployment);
|
|
16969
16969
|
}
|
|
@@ -25476,7 +25476,7 @@ async function ensureDeployment(args) {
|
|
|
25476
25476
|
"--model-version",
|
|
25477
25477
|
args.modelVersion,
|
|
25478
25478
|
"--model-format",
|
|
25479
|
-
"OpenAI",
|
|
25479
|
+
args.format ?? "OpenAI",
|
|
25480
25480
|
"--sku-name",
|
|
25481
25481
|
"GlobalStandard",
|
|
25482
25482
|
"--sku-capacity",
|
|
@@ -27466,6 +27466,7 @@ async function deploySimpleStacey(args) {
|
|
|
27466
27466
|
repoRoot: args.repoRoot,
|
|
27467
27467
|
persona: SIMPLE_STACEY_PERSONA,
|
|
27468
27468
|
agentName: SIMPLE_STACEY_AGENT,
|
|
27469
|
+
model: args.model,
|
|
27469
27470
|
fieldOverrides: args.fieldOverrides
|
|
27470
27471
|
});
|
|
27471
27472
|
} catch (e) {
|
|
@@ -27534,6 +27535,7 @@ async function deploySimpleStaceyWithRetry(args) {
|
|
|
27534
27535
|
credential: args.credential,
|
|
27535
27536
|
endpoint: args.endpoint,
|
|
27536
27537
|
repoRoot: args.repoRoot,
|
|
27538
|
+
model: args.model,
|
|
27537
27539
|
fieldOverrides: args.fieldOverrides
|
|
27538
27540
|
});
|
|
27539
27541
|
} catch (error) {
|
|
@@ -27930,6 +27932,257 @@ function stopOnboardingUi(home = os17.homedir()) {
|
|
|
27930
27932
|
return uiStopped || relayStopped;
|
|
27931
27933
|
}
|
|
27932
27934
|
|
|
27935
|
+
// src/lib/model-catalog.ts
|
|
27936
|
+
async function listAgentModels(region) {
|
|
27937
|
+
let out;
|
|
27938
|
+
try {
|
|
27939
|
+
out = await runAz(["cognitiveservices", "model", "list", "-l", region, "--output", "json"]);
|
|
27940
|
+
} catch (e) {
|
|
27941
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
27942
|
+
const denied = /AuthorizationFailed|Forbidden|\b403\b|does not have authorization/i.test(msg);
|
|
27943
|
+
return { ok: false, error: denied ? "denied" : "unavailable" };
|
|
27944
|
+
}
|
|
27945
|
+
let raw;
|
|
27946
|
+
try {
|
|
27947
|
+
raw = JSON.parse(out);
|
|
27948
|
+
} catch {
|
|
27949
|
+
return { ok: false, error: "malformed" };
|
|
27950
|
+
}
|
|
27951
|
+
if (!Array.isArray(raw) || raw.some((e) => typeof e !== "object" || e === null)) {
|
|
27952
|
+
return { ok: false, error: "malformed" };
|
|
27953
|
+
}
|
|
27954
|
+
try {
|
|
27955
|
+
const rows = raw.map((e) => ({
|
|
27956
|
+
format: e.model?.format ?? "",
|
|
27957
|
+
name: e.model?.name ?? "",
|
|
27958
|
+
version: e.model?.version ?? "",
|
|
27959
|
+
skus: [...new Set((e.model?.skus ?? []).map((s) => s.name ?? "").filter(Boolean))],
|
|
27960
|
+
agentsV2: e.model?.capabilities?.agentsV2 === "true"
|
|
27961
|
+
}));
|
|
27962
|
+
return { ok: true, rows };
|
|
27963
|
+
} catch {
|
|
27964
|
+
return { ok: false, error: "malformed" };
|
|
27965
|
+
}
|
|
27966
|
+
}
|
|
27967
|
+
|
|
27968
|
+
// src/lib/model-cascade.ts
|
|
27969
|
+
var WHITELIST = [
|
|
27970
|
+
{ model: "gpt-5.6-luna", format: "OpenAI", version: "2026-07-09", capacity: 100 },
|
|
27971
|
+
{ model: "gpt-5.6-sol", format: "OpenAI", version: "2026-07-09", capacity: 100 },
|
|
27972
|
+
{ model: "gpt-5.6-terra", format: "OpenAI", version: "2026-07-09", capacity: 100 },
|
|
27973
|
+
{ model: "gpt-5.4", format: "OpenAI", version: "2026-03-05", capacity: 100 },
|
|
27974
|
+
{ model: "grok-4.3", format: "xAI", version: "1", capacity: 100 },
|
|
27975
|
+
{ model: "gpt-4.1-mini", format: "OpenAI", version: "2025-04-14", capacity: 50 }
|
|
27976
|
+
];
|
|
27977
|
+
var GLOBAL_STANDARD = "GlobalStandard";
|
|
27978
|
+
function planCascade(whitelist, catalog, quota) {
|
|
27979
|
+
if (!catalog.ok) {
|
|
27980
|
+
return {
|
|
27981
|
+
candidates: [],
|
|
27982
|
+
skipped: whitelist.map((r) => ({ model: r.model, outcome: "catalog-unverified", detail: catalog.error }))
|
|
27983
|
+
};
|
|
27984
|
+
}
|
|
27985
|
+
const rowsByName = /* @__PURE__ */ new Map();
|
|
27986
|
+
for (const row of catalog.rows) {
|
|
27987
|
+
const list = rowsByName.get(row.name);
|
|
27988
|
+
if (list) list.push(row);
|
|
27989
|
+
else rowsByName.set(row.name, [row]);
|
|
27990
|
+
}
|
|
27991
|
+
const candidates = [];
|
|
27992
|
+
const skipped = [];
|
|
27993
|
+
for (const rung of whitelist) {
|
|
27994
|
+
const rows = rowsByName.get(rung.model);
|
|
27995
|
+
if (!rows || rows.length === 0) {
|
|
27996
|
+
skipped.push({ model: rung.model, outcome: "not-in-catalog" });
|
|
27997
|
+
continue;
|
|
27998
|
+
}
|
|
27999
|
+
const agentRows = rows.filter((r) => r.agentsV2);
|
|
28000
|
+
if (agentRows.length === 0) {
|
|
28001
|
+
skipped.push({ model: rung.model, outcome: "not-agent-eligible" });
|
|
28002
|
+
continue;
|
|
28003
|
+
}
|
|
28004
|
+
if (!agentRows.some((r) => r.skus.includes(GLOBAL_STANDARD))) {
|
|
28005
|
+
skipped.push({ model: rung.model, outcome: "no-global-standard" });
|
|
28006
|
+
continue;
|
|
28007
|
+
}
|
|
28008
|
+
if (modelQuotaVerdict(quota, rung.model).verdict === "no_quota") {
|
|
28009
|
+
skipped.push({ model: rung.model, outcome: "no-quota" });
|
|
28010
|
+
continue;
|
|
28011
|
+
}
|
|
28012
|
+
candidates.push(rung);
|
|
28013
|
+
}
|
|
28014
|
+
return { candidates, skipped };
|
|
28015
|
+
}
|
|
28016
|
+
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;
|
|
28017
|
+
var REGION_RE = /not available in|not supported in|NotAvailableInRegion|InvalidResourceLocation/i;
|
|
28018
|
+
var CONFLICT_RE = /\bconflict\b|\b409\b/i;
|
|
28019
|
+
function classifyDeployError(message) {
|
|
28020
|
+
if (QUOTA_RE.test(message)) return "deploy-rejected-quota";
|
|
28021
|
+
if (REGION_RE.test(message)) return "deploy-rejected-region";
|
|
28022
|
+
return "deploy-unverified";
|
|
28023
|
+
}
|
|
28024
|
+
async function walkCascade(whitelist, plan, deploy, opts) {
|
|
28025
|
+
const outcomes = /* @__PURE__ */ new Map();
|
|
28026
|
+
for (const s of plan.skipped) outcomes.set(s.model, s);
|
|
28027
|
+
let chosen = null;
|
|
28028
|
+
let aborted = false;
|
|
28029
|
+
for (const rung of plan.candidates) {
|
|
28030
|
+
if (chosen) break;
|
|
28031
|
+
if (opts.now() >= opts.deadlineAt) {
|
|
28032
|
+
aborted = true;
|
|
28033
|
+
break;
|
|
28034
|
+
}
|
|
28035
|
+
let row;
|
|
28036
|
+
try {
|
|
28037
|
+
await deploy(rung);
|
|
28038
|
+
row = { model: rung.model, outcome: "deployed" };
|
|
28039
|
+
chosen = rung;
|
|
28040
|
+
} catch (e) {
|
|
28041
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
28042
|
+
if (CONFLICT_RE.test(msg)) {
|
|
28043
|
+
try {
|
|
28044
|
+
await deploy(rung);
|
|
28045
|
+
row = { model: rung.model, outcome: "deployed" };
|
|
28046
|
+
chosen = rung;
|
|
28047
|
+
} catch (e2) {
|
|
28048
|
+
const msg2 = e2 instanceof Error ? e2.message : String(e2);
|
|
28049
|
+
row = {
|
|
28050
|
+
model: rung.model,
|
|
28051
|
+
outcome: CONFLICT_RE.test(msg2) ? "deploy-unverified" : classifyDeployError(msg2),
|
|
28052
|
+
detail: msg2
|
|
28053
|
+
};
|
|
28054
|
+
}
|
|
28055
|
+
} else {
|
|
28056
|
+
row = { model: rung.model, outcome: classifyDeployError(msg), detail: msg };
|
|
28057
|
+
}
|
|
28058
|
+
}
|
|
28059
|
+
outcomes.set(rung.model, row);
|
|
28060
|
+
opts.onRung?.(row.model, row.outcome);
|
|
28061
|
+
}
|
|
28062
|
+
const trace = whitelist.map(
|
|
28063
|
+
(r) => outcomes.get(r.model) ?? { model: r.model, outcome: aborted ? "aborted-deadline" : "not-reached" }
|
|
28064
|
+
);
|
|
28065
|
+
return { chosen, trace };
|
|
28066
|
+
}
|
|
28067
|
+
var CERTAIN_UNAVAILABLE = /* @__PURE__ */ new Set([
|
|
28068
|
+
"not-in-catalog",
|
|
28069
|
+
"not-agent-eligible",
|
|
28070
|
+
"no-global-standard",
|
|
28071
|
+
"deploy-rejected-region"
|
|
28072
|
+
]);
|
|
28073
|
+
var QUOTA_BLOCKED = /* @__PURE__ */ new Set(["no-quota", "deploy-rejected-quota"]);
|
|
28074
|
+
function decideNote(whitelist, result) {
|
|
28075
|
+
const chosenIdx = result.chosen ? whitelist.findIndex((r) => r.model === result.chosen?.model) : whitelist.length;
|
|
28076
|
+
const better = result.trace.slice(0, Math.max(chosenIdx, 0));
|
|
28077
|
+
const runningModel = result.chosen?.model ?? null;
|
|
28078
|
+
if (chosenIdx === 0) {
|
|
28079
|
+
return { status: "top", runningModel, pitchModel: null, unavailableAbovePitch: [] };
|
|
28080
|
+
}
|
|
28081
|
+
const pitch = better.find((t) => QUOTA_BLOCKED.has(t.outcome));
|
|
28082
|
+
if (pitch) {
|
|
28083
|
+
const pitchIdx = better.findIndex((t) => t.model === pitch.model);
|
|
28084
|
+
return {
|
|
28085
|
+
status: "lesser-quota",
|
|
28086
|
+
runningModel,
|
|
28087
|
+
pitchModel: pitch.model,
|
|
28088
|
+
unavailableAbovePitch: better.slice(0, pitchIdx).filter((t) => CERTAIN_UNAVAILABLE.has(t.outcome)).map((t) => t.model)
|
|
28089
|
+
};
|
|
28090
|
+
}
|
|
28091
|
+
const allCertain = better.length > 0 && better.every((t) => CERTAIN_UNAVAILABLE.has(t.outcome));
|
|
28092
|
+
return {
|
|
28093
|
+
status: allCertain ? "lesser-unavailable" : "lesser-unverified",
|
|
28094
|
+
runningModel,
|
|
28095
|
+
pitchModel: null,
|
|
28096
|
+
unavailableAbovePitch: []
|
|
28097
|
+
};
|
|
28098
|
+
}
|
|
28099
|
+
var listNames = (names) => names.length <= 1 ? names[0] ?? "" : `${names.slice(0, -1).join(", ")} and ${names[names.length - 1]}`;
|
|
28100
|
+
function renderChosenModelNote(d) {
|
|
28101
|
+
const subject = d.runningModel ? `You are running on ${d.runningModel}.` : "You are running on this install's default model.";
|
|
28102
|
+
switch (d.status) {
|
|
28103
|
+
case "top":
|
|
28104
|
+
return `${subject} That is the best available model for this install.`;
|
|
28105
|
+
case "lesser-quota": {
|
|
28106
|
+
const aside = d.unavailableAbovePitch.length > 0 ? ` ${listNames(d.unavailableAbovePitch)} ${d.unavailableAbovePitch.length > 1 ? "are" : "is"} not offered for this install.` : "";
|
|
28107
|
+
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.`;
|
|
28108
|
+
}
|
|
28109
|
+
case "lesser-unavailable":
|
|
28110
|
+
return `${subject} No stronger model is offered for this install right now.`;
|
|
28111
|
+
case "lesser-unverified":
|
|
28112
|
+
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.`;
|
|
28113
|
+
}
|
|
28114
|
+
}
|
|
28115
|
+
|
|
28116
|
+
// src/lib/intake-model.ts
|
|
28117
|
+
var DEFAULT_DEADLINE_MS = 18e4;
|
|
28118
|
+
var SCOPE_RE = /\/resourceGroups\/([^/]+)\/providers\/Microsoft\.CognitiveServices\/accounts\/([^/]+)/i;
|
|
28119
|
+
function parseAccountScope(scope) {
|
|
28120
|
+
const m = SCOPE_RE.exec(scope);
|
|
28121
|
+
return m ? { resourceGroup: m[1], account: m[2] } : null;
|
|
28122
|
+
}
|
|
28123
|
+
function narrate(model, outcome, region) {
|
|
28124
|
+
if (outcome === "deployed") return `${model} - ready`;
|
|
28125
|
+
return `${model} - not available for your subscription in ${region}`;
|
|
28126
|
+
}
|
|
28127
|
+
async function accountRegion(account, resourceGroup, fallback) {
|
|
28128
|
+
try {
|
|
28129
|
+
const out = await runAz([
|
|
28130
|
+
"cognitiveservices",
|
|
28131
|
+
"account",
|
|
28132
|
+
"show",
|
|
28133
|
+
"--name",
|
|
28134
|
+
account,
|
|
28135
|
+
"--resource-group",
|
|
28136
|
+
resourceGroup,
|
|
28137
|
+
"--query",
|
|
28138
|
+
"location",
|
|
28139
|
+
"-o",
|
|
28140
|
+
"tsv"
|
|
28141
|
+
]);
|
|
28142
|
+
return out.trim() || fallback;
|
|
28143
|
+
} catch {
|
|
28144
|
+
return fallback;
|
|
28145
|
+
}
|
|
28146
|
+
}
|
|
28147
|
+
async function resolveIntakeModel(args) {
|
|
28148
|
+
const floorTrace = (outcome, detail) => WHITELIST.map((r) => ({ model: r.model, outcome, ...detail === void 0 ? {} : { detail } }));
|
|
28149
|
+
const degradeToFloor = (detail) => {
|
|
28150
|
+
const trace = floorTrace("catalog-unverified", detail);
|
|
28151
|
+
return { model: void 0, note: renderChosenModelNote(decideNote(WHITELIST, { chosen: null, trace })), trace };
|
|
28152
|
+
};
|
|
28153
|
+
const parsed = parseAccountScope(args.accountScope);
|
|
28154
|
+
if (!parsed) return degradeToFloor(`unparseable account scope: ${args.accountScope}`);
|
|
28155
|
+
try {
|
|
28156
|
+
const region = await accountRegion(parsed.account, parsed.resourceGroup, args.fallbackRegion);
|
|
28157
|
+
args.onNarrate?.("choosing the best model your subscription can run...");
|
|
28158
|
+
const [catalog, quota] = await Promise.all([listAgentModels(region), listModelQuota(region)]);
|
|
28159
|
+
const plan = planCascade(WHITELIST, catalog, quota);
|
|
28160
|
+
const deploy = async (rung) => {
|
|
28161
|
+
await ensureDeployment({
|
|
28162
|
+
account: parsed.account,
|
|
28163
|
+
resourceGroup: parsed.resourceGroup,
|
|
28164
|
+
model: rung.model,
|
|
28165
|
+
modelVersion: rung.version,
|
|
28166
|
+
capacity: rung.capacity,
|
|
28167
|
+
format: rung.format
|
|
28168
|
+
});
|
|
28169
|
+
};
|
|
28170
|
+
const start = Date.now();
|
|
28171
|
+
const result = await walkCascade(WHITELIST, plan, deploy, {
|
|
28172
|
+
now: () => Date.now(),
|
|
28173
|
+
deadlineAt: start + (args.deadlineMs ?? DEFAULT_DEADLINE_MS),
|
|
28174
|
+
onRung: (model, outcome) => args.onNarrate?.(narrate(model, outcome, region))
|
|
28175
|
+
});
|
|
28176
|
+
return {
|
|
28177
|
+
model: result.chosen?.model,
|
|
28178
|
+
note: renderChosenModelNote(decideNote(WHITELIST, result)),
|
|
28179
|
+
trace: result.trace
|
|
28180
|
+
};
|
|
28181
|
+
} catch (e) {
|
|
28182
|
+
return degradeToFloor(e instanceof Error ? e.message : String(e));
|
|
28183
|
+
}
|
|
28184
|
+
}
|
|
28185
|
+
|
|
27933
28186
|
// src/commands/bootstrap/ui.ts
|
|
27934
28187
|
function renderDeploySuccess(version, envPath) {
|
|
27935
28188
|
return `${colors.success("\u2713")} Simple Stacey is live (stacey-intake v${version}).
|
|
@@ -28031,13 +28284,24 @@ var BootstrapUiCommand = class extends M8tCommand {
|
|
|
28031
28284
|
await ensureFounderFoundryRole({ credential: credential2, subscriptionId: state.subscriptionId, principalId: oid, accountScope });
|
|
28032
28285
|
const identity = await getSignedInUserIdentity();
|
|
28033
28286
|
out("deploying Simple Stacey (stacey-intake) in the background...");
|
|
28034
|
-
const deployOutcome =
|
|
28035
|
-
|
|
28036
|
-
|
|
28037
|
-
|
|
28038
|
-
|
|
28039
|
-
|
|
28040
|
-
|
|
28287
|
+
const deployOutcome = (async () => {
|
|
28288
|
+
const choice = await resolveIntakeModel({
|
|
28289
|
+
accountScope,
|
|
28290
|
+
fallbackRegion: state.location,
|
|
28291
|
+
onNarrate: out
|
|
28292
|
+
});
|
|
28293
|
+
return deploySimpleStaceyWithRetry({
|
|
28294
|
+
credential: credential2,
|
|
28295
|
+
endpoint,
|
|
28296
|
+
repoRoot,
|
|
28297
|
+
model: choice.model,
|
|
28298
|
+
fieldOverrides: {
|
|
28299
|
+
founder_identity_note: composeFounderIdentityNote(identity),
|
|
28300
|
+
chosen_model_note: choice.note
|
|
28301
|
+
},
|
|
28302
|
+
onWait: out
|
|
28303
|
+
});
|
|
28304
|
+
})().then(
|
|
28041
28305
|
(version) => ({ ok: true, version }),
|
|
28042
28306
|
(error) => ({ ok: false, error: error instanceof Error ? error : new Error(String(error)) })
|
|
28043
28307
|
);
|