@m8t-stack/cli 0.2.36 → 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 +311 -36
- 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",
|
|
@@ -26216,8 +26216,8 @@ var BootstrapLaunchCommand = class extends M8tCommand {
|
|
|
26216
26216
|
examples: [
|
|
26217
26217
|
["Launch in eastus2", "$0 bootstrap launch --location eastus2"],
|
|
26218
26218
|
["BYO app registration", "$0 bootstrap launch --location eastus2 --client-id <appId>"],
|
|
26219
|
-
["Pin a specific installer tag", "$0 bootstrap launch --location eastus2 --installer-tag v0.1.
|
|
26220
|
-
["Override the full installer image ref", "$0 bootstrap launch --location eastus2 --installer-image ghcr.io/m8t-labs/m8t-installer:v0.1.
|
|
26219
|
+
["Pin a specific installer tag", "$0 bootstrap launch --location eastus2 --installer-tag v0.1.42"],
|
|
26220
|
+
["Override the full installer image ref", "$0 bootstrap launch --location eastus2 --installer-image ghcr.io/m8t-labs/m8t-installer:v0.1.42"],
|
|
26221
26221
|
["Share a support contact", "$0 bootstrap launch --location eastus2 --contact-email you@example.com --company 'Acme'"]
|
|
26222
26222
|
]
|
|
26223
26223
|
});
|
|
@@ -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) {
|
|
@@ -27629,12 +27631,13 @@ function writeWebEnvLocal(args) {
|
|
|
27629
27631
|
});
|
|
27630
27632
|
}
|
|
27631
27633
|
const body = [
|
|
27632
|
-
"# Written by `m8t bootstrap ui` \u2014 onboarding
|
|
27634
|
+
"# Written by `m8t bootstrap ui` \u2014 local onboarding run (Simple Stacey).",
|
|
27635
|
+
"# Text-first: the intake voice stack is off unless the run passed --voice.",
|
|
27633
27636
|
"# STORAGE unset \u2192 gateway boot skipped; the webapp forwards your MSAL token to Foundry.",
|
|
27634
27637
|
`AZURE_TENANT_ID=${args.tenantId}`,
|
|
27635
27638
|
`AZURE_CLIENT_ID=${args.clientId}`,
|
|
27636
27639
|
`FOUNDRY_PROJECT_ENDPOINT=${args.foundryEndpoint}`,
|
|
27637
|
-
"VOICE_RELAY_PUBLIC_URL=ws://localhost:8790",
|
|
27640
|
+
...args.voice ? ["VOICE_RELAY_PUBLIC_URL=ws://localhost:8790", "NEXT_PUBLIC_M8T_INTAKE_VOICE=1"] : [],
|
|
27638
27641
|
"STORAGE_ACCOUNT_NAME=",
|
|
27639
27642
|
`M8T_INTERNAL_SECRET=${internalSecret}`,
|
|
27640
27643
|
"M8T_SINGLE_GATEWAY_PROCESS=1",
|
|
@@ -27929,6 +27932,257 @@ function stopOnboardingUi(home = os17.homedir()) {
|
|
|
27929
27932
|
return uiStopped || relayStopped;
|
|
27930
27933
|
}
|
|
27931
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
|
+
|
|
27932
28186
|
// src/commands/bootstrap/ui.ts
|
|
27933
28187
|
function renderDeploySuccess(version, envPath) {
|
|
27934
28188
|
return `${colors.success("\u2713")} Simple Stacey is live (stacey-intake v${version}).
|
|
@@ -27951,8 +28205,9 @@ var BootstrapUiCommand = class extends M8tCommand {
|
|
|
27951
28205
|
details: [
|
|
27952
28206
|
"Run after `m8t bootstrap launch`, in parallel with `status --watch`. Waits for the cloud",
|
|
27953
28207
|
"installer's foundry-create phase, grants you Foundry data-plane access, deploys a no-brain",
|
|
27954
|
-
"Simple Stacey (stacey-intake), writes apps/web/.env.local (chat-only
|
|
27955
|
-
"starts the webapp detached so a coding agent can continue without opening
|
|
28208
|
+
"Simple Stacey (stacey-intake), writes apps/web/.env.local (chat-only unless --voice is set),",
|
|
28209
|
+
"installs deps, and starts the webapp detached so a coding agent can continue without opening",
|
|
28210
|
+
"a separate terminal.",
|
|
27956
28211
|
"",
|
|
27957
28212
|
"The command returns as soon as the server is ready (or after ~45 s if it is still compiling).",
|
|
27958
28213
|
"Use `--stop` to shut it down, `--foreground` to keep the old blocking behaviour."
|
|
@@ -27961,7 +28216,8 @@ var BootstrapUiCommand = class extends M8tCommand {
|
|
|
27961
28216
|
["Start the onboarding UI (backgrounds the server, returns)", "$0 bootstrap ui --repo-root /path/to/m8t"],
|
|
27962
28217
|
["Stop the running onboarding UI", "$0 bootstrap ui --stop"],
|
|
27963
28218
|
["Prep only (don't serve at all)", "$0 bootstrap ui --repo-root /path/to/m8t --prep-only"],
|
|
27964
|
-
["Foreground (blocking, old behaviour)", "$0 bootstrap ui --repo-root /path/to/m8t --foreground"]
|
|
28219
|
+
["Foreground (blocking, old behaviour)", "$0 bootstrap ui --repo-root /path/to/m8t --foreground"],
|
|
28220
|
+
["Experimental: enable the intake voice call", "$0 bootstrap ui --repo-root /path/to/m8t --voice"]
|
|
27965
28221
|
]
|
|
27966
28222
|
});
|
|
27967
28223
|
repoRoot = Option51.String("--repo-root");
|
|
@@ -27973,6 +28229,9 @@ var BootstrapUiCommand = class extends M8tCommand {
|
|
|
27973
28229
|
skipInstall = Option51.Boolean("--skip-install", false);
|
|
27974
28230
|
stop = Option51.Boolean("--stop", false);
|
|
27975
28231
|
foreground = Option51.Boolean("--foreground", false);
|
|
28232
|
+
voice = Option51.Boolean("--voice", false, {
|
|
28233
|
+
description: "Experimental/preview: enable the intake voice call and start the voice relay on :8790. Not a supported founder path \u2014 the intake is text-only by default."
|
|
28234
|
+
});
|
|
27976
28235
|
async executeCommand() {
|
|
27977
28236
|
if (this.stop === true) {
|
|
27978
28237
|
const stopped = stopOnboardingUi();
|
|
@@ -28025,13 +28284,24 @@ var BootstrapUiCommand = class extends M8tCommand {
|
|
|
28025
28284
|
await ensureFounderFoundryRole({ credential: credential2, subscriptionId: state.subscriptionId, principalId: oid, accountScope });
|
|
28026
28285
|
const identity = await getSignedInUserIdentity();
|
|
28027
28286
|
out("deploying Simple Stacey (stacey-intake) in the background...");
|
|
28028
|
-
const deployOutcome =
|
|
28029
|
-
|
|
28030
|
-
|
|
28031
|
-
|
|
28032
|
-
|
|
28033
|
-
|
|
28034
|
-
|
|
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(
|
|
28035
28305
|
(version) => ({ ok: true, version }),
|
|
28036
28306
|
(error) => ({ ok: false, error: error instanceof Error ? error : new Error(String(error)) })
|
|
28037
28307
|
);
|
|
@@ -28039,7 +28309,8 @@ var BootstrapUiCommand = class extends M8tCommand {
|
|
|
28039
28309
|
repoRoot,
|
|
28040
28310
|
tenantId: account.tenantId,
|
|
28041
28311
|
clientId: state.appRegClientId,
|
|
28042
|
-
foundryEndpoint: endpoint
|
|
28312
|
+
foundryEndpoint: endpoint,
|
|
28313
|
+
voice: this.voice === true
|
|
28043
28314
|
});
|
|
28044
28315
|
if (!this.skipInstall) {
|
|
28045
28316
|
out("installing apps/web dependencies (pnpm)\u2026");
|
|
@@ -28054,15 +28325,17 @@ var BootstrapUiCommand = class extends M8tCommand {
|
|
|
28054
28325
|
return 0;
|
|
28055
28326
|
}
|
|
28056
28327
|
if (this.foreground === true) {
|
|
28057
|
-
|
|
28058
|
-
|
|
28059
|
-
|
|
28060
|
-
|
|
28061
|
-
|
|
28062
|
-
|
|
28063
|
-
|
|
28064
|
-
|
|
28065
|
-
|
|
28328
|
+
if (this.voice === true) {
|
|
28329
|
+
out("starting the voice relay on :8790 in the background\u2026");
|
|
28330
|
+
await serveOnboardingRelayDetached({
|
|
28331
|
+
repoRoot,
|
|
28332
|
+
foundryEndpoint: endpoint,
|
|
28333
|
+
tenantId: account.tenantId,
|
|
28334
|
+
clientId: state.appRegClientId,
|
|
28335
|
+
webInternalBaseUrl: "http://localhost:3000"
|
|
28336
|
+
});
|
|
28337
|
+
out("voice relay on :8790");
|
|
28338
|
+
}
|
|
28066
28339
|
const outcome2 = await deployOutcome;
|
|
28067
28340
|
if (!outcome2.ok) {
|
|
28068
28341
|
this.context.stderr.write(renderDeployFailure(outcome2.error));
|
|
@@ -28073,15 +28346,17 @@ var BootstrapUiCommand = class extends M8tCommand {
|
|
|
28073
28346
|
await runInherit("pnpm", ["--filter", "web", "dev"], repoRoot, "BOOTSTRAP_UI_DEV_FAILED");
|
|
28074
28347
|
return 0;
|
|
28075
28348
|
}
|
|
28076
|
-
|
|
28077
|
-
|
|
28078
|
-
|
|
28079
|
-
|
|
28080
|
-
|
|
28081
|
-
|
|
28082
|
-
|
|
28083
|
-
|
|
28084
|
-
|
|
28349
|
+
if (this.voice === true) {
|
|
28350
|
+
out("starting the voice relay on :8790 in the background\u2026");
|
|
28351
|
+
await serveOnboardingRelayDetached({
|
|
28352
|
+
repoRoot,
|
|
28353
|
+
foundryEndpoint: endpoint,
|
|
28354
|
+
tenantId: account.tenantId,
|
|
28355
|
+
clientId: state.appRegClientId,
|
|
28356
|
+
webInternalBaseUrl: "http://localhost:3000"
|
|
28357
|
+
});
|
|
28358
|
+
out("voice relay on :8790");
|
|
28359
|
+
}
|
|
28085
28360
|
out("starting the webapp on :3000 in the background\u2026");
|
|
28086
28361
|
const { alreadyRunning, logPath } = await serveOnboardingUiDetached({ repoRoot, port: this.port });
|
|
28087
28362
|
if (alreadyRunning) {
|