@m8t-stack/cli 0.2.12 → 0.2.14
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 -168
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -781,7 +781,10 @@ var init_brain_yaml_mirror = __esm({
|
|
|
781
781
|
` enabled: true`,
|
|
782
782
|
` lifecycle: { inbox: 14d, stale: 30d, archive: 90d }`,
|
|
783
783
|
` artifactRetention: 30d`,
|
|
784
|
-
` digestRetention: 90d
|
|
784
|
+
` digestRetention: 90d`,
|
|
785
|
+
` costReport:`,
|
|
786
|
+
` enabled: true`,
|
|
787
|
+
` cadenceDays: 14`
|
|
785
788
|
].join("\n");
|
|
786
789
|
MIRROR_BANNER = [
|
|
787
790
|
`# \u2500\u2500 MIRROR \u2014 link record convenience copy. NOT the source of truth \u2014`,
|
|
@@ -1195,7 +1198,7 @@ var init_enable_hosted_brain = __esm({
|
|
|
1195
1198
|
import { Builtins, Cli } from "clipanion";
|
|
1196
1199
|
|
|
1197
1200
|
// src/lib/package-version.ts
|
|
1198
|
-
var CLI_VERSION = "0.2.
|
|
1201
|
+
var CLI_VERSION = "0.2.14";
|
|
1199
1202
|
|
|
1200
1203
|
// src/lib/render-error.ts
|
|
1201
1204
|
init_errors();
|
|
@@ -15064,10 +15067,9 @@ async function deployPromptAdvisor(args) {
|
|
|
15064
15067
|
const fillableFields = fm["fillable-fields"] ?? [];
|
|
15065
15068
|
const valuesMap = {};
|
|
15066
15069
|
for (const field of fillableFields) {
|
|
15067
|
-
if (field.default !== void 0)
|
|
15068
|
-
valuesMap[field.name] = field.default;
|
|
15069
|
-
}
|
|
15070
|
+
if (field.default !== void 0) valuesMap[field.name] = field.default;
|
|
15070
15071
|
}
|
|
15072
|
+
for (const [k, v] of Object.entries(args.fieldOverrides ?? {})) valuesMap[k] = v;
|
|
15071
15073
|
const instructions = renderPersonaBody(personaPath, valuesMap);
|
|
15072
15074
|
return createPromptVersion({
|
|
15073
15075
|
credential: args.credential,
|
|
@@ -17426,9 +17428,134 @@ var PlatformUpdateCommand = class extends M8tCommand {
|
|
|
17426
17428
|
}
|
|
17427
17429
|
};
|
|
17428
17430
|
|
|
17429
|
-
// src/commands/
|
|
17431
|
+
// src/commands/platform/enable-cost-report.ts
|
|
17430
17432
|
import { Command as Command33, Option as Option31 } from "clipanion";
|
|
17431
17433
|
|
|
17434
|
+
// src/lib/wire-gateway-acs.ts
|
|
17435
|
+
init_rbac();
|
|
17436
|
+
async function wireGatewayForAcs(args) {
|
|
17437
|
+
try {
|
|
17438
|
+
await args.az([
|
|
17439
|
+
"role",
|
|
17440
|
+
"assignment",
|
|
17441
|
+
"create",
|
|
17442
|
+
"--assignee-object-id",
|
|
17443
|
+
args.gatewayPrincipalId,
|
|
17444
|
+
"--assignee-principal-type",
|
|
17445
|
+
"ServicePrincipal",
|
|
17446
|
+
"--role",
|
|
17447
|
+
CONTRIBUTOR_ROLE_ID,
|
|
17448
|
+
"--scope",
|
|
17449
|
+
args.acsResourceId
|
|
17450
|
+
]);
|
|
17451
|
+
} catch (e) {
|
|
17452
|
+
if (!(e instanceof Error && /RoleAssignmentExists/i.test(e.message))) throw e;
|
|
17453
|
+
}
|
|
17454
|
+
await args.az([
|
|
17455
|
+
"containerapp",
|
|
17456
|
+
"update",
|
|
17457
|
+
"-n",
|
|
17458
|
+
args.gatewayApp,
|
|
17459
|
+
"-g",
|
|
17460
|
+
args.resourceGroup,
|
|
17461
|
+
"--set-env-vars",
|
|
17462
|
+
`M8T_ACS_ENDPOINT=${args.endpoint}`,
|
|
17463
|
+
`M8T_ACS_SENDER=${args.sender}`,
|
|
17464
|
+
"M8T_ENABLE_COST_REPORTER=1"
|
|
17465
|
+
]);
|
|
17466
|
+
}
|
|
17467
|
+
|
|
17468
|
+
// src/commands/platform/enable-cost-report.ts
|
|
17469
|
+
init_errors();
|
|
17470
|
+
var PlatformEnableCostReportCommand = class extends M8tCommand {
|
|
17471
|
+
static paths = [["platform", "enable-cost-report"]];
|
|
17472
|
+
static usage = Command33.Usage({
|
|
17473
|
+
description: "Wire the deployed gateway to send the bi-weekly cost report via ACS Email.",
|
|
17474
|
+
details: "Discovers the live gateway Container App, grants its managed identity Contributor at the ACS resource scope (authorising the ACS Email send), and sets M8T_ACS_ENDPOINT / M8T_ACS_SENDER / M8T_ENABLE_COST_REPORTER=1 on the gateway. Idempotent \u2014 safely re-runnable. ACS is created during the executor deploy; pass its endpoint, sender, and resource id (from that deploy or 'az communication list')."
|
|
17475
|
+
});
|
|
17476
|
+
subscription = Option31.String("--subscription");
|
|
17477
|
+
resourceGroup = Option31.String("--resource-group", {
|
|
17478
|
+
description: "m8t-stack resource group to disambiguate the gateway (multi-deployment subscriptions)."
|
|
17479
|
+
});
|
|
17480
|
+
acsEndpoint = Option31.String("--acs-endpoint", { required: true, description: "ACS data-plane endpoint, e.g. https://acs-<name>.communication.azure.com/" });
|
|
17481
|
+
acsSender = Option31.String("--acs-sender", { required: true, description: "Managed-domain sender address, e.g. DoNotReply@<guid>.azurecomm.net" });
|
|
17482
|
+
acsResourceId = Option31.String("--acs-resource-id", { required: true, description: "ARM resource id of the acs-<name> Communication Service \u2014 the role-grant scope." });
|
|
17483
|
+
output = Option31.String("--output");
|
|
17484
|
+
async executeCommand() {
|
|
17485
|
+
const mode = resolveOutputMode(
|
|
17486
|
+
this.output,
|
|
17487
|
+
this.context.stdout
|
|
17488
|
+
);
|
|
17489
|
+
const log = (msg) => {
|
|
17490
|
+
if (mode !== "json") this.context.stdout.write(msg + "\n");
|
|
17491
|
+
};
|
|
17492
|
+
const ctx = await resolveGatewayContext({
|
|
17493
|
+
interactive: mode !== "json",
|
|
17494
|
+
subscriptionId: this.subscription,
|
|
17495
|
+
resourceGroup: this.resourceGroup
|
|
17496
|
+
});
|
|
17497
|
+
const { resourceGroup, name } = parseContainerAppResourceId(ctx.containerAppResourceId);
|
|
17498
|
+
const gatewayPrincipalId = (await runAz([
|
|
17499
|
+
"containerapp",
|
|
17500
|
+
"show",
|
|
17501
|
+
"-n",
|
|
17502
|
+
name,
|
|
17503
|
+
"-g",
|
|
17504
|
+
resourceGroup,
|
|
17505
|
+
"--query",
|
|
17506
|
+
"identity.principalId",
|
|
17507
|
+
"-o",
|
|
17508
|
+
"tsv"
|
|
17509
|
+
])).trim();
|
|
17510
|
+
if (gatewayPrincipalId === "") {
|
|
17511
|
+
throw new LocalCliError({
|
|
17512
|
+
code: "GATEWAY_NO_MANAGED_IDENTITY",
|
|
17513
|
+
message: `Gateway '${name}' has no managed identity principalId to grant.`,
|
|
17514
|
+
hint: "Assign a system-assigned identity to the gateway Container App, then re-run."
|
|
17515
|
+
});
|
|
17516
|
+
}
|
|
17517
|
+
await wireGatewayForAcs({
|
|
17518
|
+
az: runAz,
|
|
17519
|
+
resourceGroup,
|
|
17520
|
+
acsResourceId: this.acsResourceId,
|
|
17521
|
+
gatewayApp: name,
|
|
17522
|
+
endpoint: this.acsEndpoint,
|
|
17523
|
+
sender: this.acsSender,
|
|
17524
|
+
gatewayPrincipalId
|
|
17525
|
+
});
|
|
17526
|
+
if (mode === "json") {
|
|
17527
|
+
this.context.stdout.write(
|
|
17528
|
+
renderJson({
|
|
17529
|
+
gateway: name,
|
|
17530
|
+
resourceGroup,
|
|
17531
|
+
roleGranted: "Contributor",
|
|
17532
|
+
scope: this.acsResourceId,
|
|
17533
|
+
envSet: {
|
|
17534
|
+
M8T_ACS_ENDPOINT: this.acsEndpoint,
|
|
17535
|
+
M8T_ACS_SENDER: this.acsSender,
|
|
17536
|
+
M8T_ENABLE_COST_REPORTER: "1"
|
|
17537
|
+
}
|
|
17538
|
+
}) + "\n"
|
|
17539
|
+
);
|
|
17540
|
+
return 0;
|
|
17541
|
+
}
|
|
17542
|
+
this.context.stdout.write(
|
|
17543
|
+
renderKeyValueBlock([
|
|
17544
|
+
{ key: "gateway", value: name },
|
|
17545
|
+
{ key: "role granted", value: `Contributor @ ${this.acsResourceId}` },
|
|
17546
|
+
{ key: "M8T_ACS_ENDPOINT", value: this.acsEndpoint },
|
|
17547
|
+
{ key: "M8T_ACS_SENDER", value: this.acsSender },
|
|
17548
|
+
{ key: "M8T_ENABLE_COST_REPORTER", value: "1" }
|
|
17549
|
+
]) + "\n"
|
|
17550
|
+
);
|
|
17551
|
+
log(colors.success("cost report enabled \u2014 the gateway will send it via ACS \u2713"));
|
|
17552
|
+
return 0;
|
|
17553
|
+
}
|
|
17554
|
+
};
|
|
17555
|
+
|
|
17556
|
+
// src/commands/deploy.ts
|
|
17557
|
+
import { Command as Command34, Option as Option32 } from "clipanion";
|
|
17558
|
+
|
|
17432
17559
|
// src/lib/app-reg.ts
|
|
17433
17560
|
init_errors();
|
|
17434
17561
|
var APP_NAME = "m8t-stack-webapp";
|
|
@@ -17961,24 +18088,24 @@ function classifyWhatIf(changes) {
|
|
|
17961
18088
|
var DEFAULT_IMAGE_REF = "ghcr.io/m8t-run/m8t:latest";
|
|
17962
18089
|
var DeployCommand = class extends M8tCommand {
|
|
17963
18090
|
static paths = [["deploy"]];
|
|
17964
|
-
static usage =
|
|
18091
|
+
static usage = Command34.Usage({
|
|
17965
18092
|
description: "Deploy (or update) the m8t gateway/webapp stack via Bicep.",
|
|
17966
18093
|
details: "Ensures the Entra app reg (or pass --client-id to reuse an existing one \u2014 required if you can't create app regs), writes ~/.m8t-stack/config.yaml, ensures the resource group, and runs deploy/main.bicep. The repo is located via ~/.m8t-stack/repo-root."
|
|
17967
18094
|
});
|
|
17968
|
-
subscription =
|
|
17969
|
-
resourceGroup =
|
|
17970
|
-
location =
|
|
17971
|
-
suffix =
|
|
17972
|
-
imageRef =
|
|
17973
|
-
acrPullIdentity =
|
|
17974
|
-
acrResourceId =
|
|
17975
|
-
foundryEndpoint =
|
|
17976
|
-
foundryResourceId =
|
|
17977
|
-
foundryTracing =
|
|
18095
|
+
subscription = Option32.String("--subscription");
|
|
18096
|
+
resourceGroup = Option32.String("--resource-group", "rg-m8t-stack");
|
|
18097
|
+
location = Option32.String("--location", "eastus");
|
|
18098
|
+
suffix = Option32.String("--suffix", "");
|
|
18099
|
+
imageRef = Option32.String("--image-ref", DEFAULT_IMAGE_REF);
|
|
18100
|
+
acrPullIdentity = Option32.String("--acrpull-identity");
|
|
18101
|
+
acrResourceId = Option32.String("--acr-resource-id");
|
|
18102
|
+
foundryEndpoint = Option32.String("--foundry-endpoint");
|
|
18103
|
+
foundryResourceId = Option32.String("--foundry-resource-id");
|
|
18104
|
+
foundryTracing = Option32.String("--foundry-tracing");
|
|
17978
18105
|
// project | account | skip (bicep default: project)
|
|
17979
|
-
clientId =
|
|
17980
|
-
whatIf =
|
|
17981
|
-
output =
|
|
18106
|
+
clientId = Option32.String("--client-id");
|
|
18107
|
+
whatIf = Option32.Boolean("--what-if", false);
|
|
18108
|
+
output = Option32.String("--output");
|
|
17982
18109
|
async executeCommand() {
|
|
17983
18110
|
const mode = resolveOutputMode(
|
|
17984
18111
|
this.output,
|
|
@@ -18092,7 +18219,7 @@ var DeployCommand = class extends M8tCommand {
|
|
|
18092
18219
|
|
|
18093
18220
|
// src/commands/eval/skill.ts
|
|
18094
18221
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
18095
|
-
import { Command as
|
|
18222
|
+
import { Command as Command35, Option as Option33 } from "clipanion";
|
|
18096
18223
|
init_errors();
|
|
18097
18224
|
var DECISIONS = /* @__PURE__ */ new Set(["promote", "reject", "needs_review"]);
|
|
18098
18225
|
var JUDGE_STATUSES = /* @__PURE__ */ new Set(["ok", "skipped", "unavailable"]);
|
|
@@ -18117,14 +18244,14 @@ function parseVerdict(stdout) {
|
|
|
18117
18244
|
}
|
|
18118
18245
|
var EvalSkillCommand = class extends M8tCommand {
|
|
18119
18246
|
static paths = [["eval", "skill"]];
|
|
18120
|
-
static usage =
|
|
18247
|
+
static usage = Command35.Usage({
|
|
18121
18248
|
description: "Vet one inbox skill candidate (Brain Faculties Eval F1): promote / reject / needs_review. Shells out to the Python `brain-eval` core (override its path with $BRAIN_EVAL_BIN)."
|
|
18122
18249
|
});
|
|
18123
|
-
candidate =
|
|
18124
|
-
skillsDir =
|
|
18125
|
-
noJudge =
|
|
18126
|
-
deployment =
|
|
18127
|
-
output =
|
|
18250
|
+
candidate = Option33.String();
|
|
18251
|
+
skillsDir = Option33.String("--skills-dir");
|
|
18252
|
+
noJudge = Option33.Boolean("--no-judge", false);
|
|
18253
|
+
deployment = Option33.String("--deployment");
|
|
18254
|
+
output = Option33.String("--output");
|
|
18128
18255
|
executeCommand() {
|
|
18129
18256
|
return Promise.resolve(this._runCommand());
|
|
18130
18257
|
}
|
|
@@ -18183,7 +18310,7 @@ var EvalSkillCommand = class extends M8tCommand {
|
|
|
18183
18310
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
18184
18311
|
import { writeFileSync as writeFileSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync13, existsSync as existsSync12, readdirSync } from "fs";
|
|
18185
18312
|
import { join as join19 } from "path";
|
|
18186
|
-
import { Command as
|
|
18313
|
+
import { Command as Command36, Option as Option34 } from "clipanion";
|
|
18187
18314
|
init_errors();
|
|
18188
18315
|
init_esm();
|
|
18189
18316
|
function parseArmToken(tok, opts) {
|
|
@@ -18397,23 +18524,23 @@ function buildPlan(args) {
|
|
|
18397
18524
|
}
|
|
18398
18525
|
var EvalExamCommand = class extends M8tCommand {
|
|
18399
18526
|
static paths = [["eval", "exam"]];
|
|
18400
|
-
static usage =
|
|
18527
|
+
static usage = Command36.Usage({
|
|
18401
18528
|
description: "Run a brain exam (Brain Referee E2-F2): impact A/B + dream-delta. Resolves the plan, then shells out to the Python `brain-exam` orchestrator (override its path with $BRAIN_EXAM_BIN). Renders an ExamVerdict: three-valued verdict + power note + per-task flips."
|
|
18402
18529
|
});
|
|
18403
|
-
worker =
|
|
18404
|
-
arms =
|
|
18405
|
-
taskSet =
|
|
18406
|
-
examType =
|
|
18407
|
-
reps =
|
|
18408
|
-
probes =
|
|
18409
|
-
pool =
|
|
18410
|
-
out =
|
|
18411
|
-
dryRun =
|
|
18412
|
-
keepArms =
|
|
18413
|
-
allowStub =
|
|
18414
|
-
deployment =
|
|
18415
|
-
output =
|
|
18416
|
-
observeWaitS =
|
|
18530
|
+
worker = Option34.String();
|
|
18531
|
+
arms = Option34.String("--arms");
|
|
18532
|
+
taskSet = Option34.String("--task-set");
|
|
18533
|
+
examType = Option34.String("--exam-type");
|
|
18534
|
+
reps = Option34.String("-n,--reps");
|
|
18535
|
+
probes = Option34.String("--probes");
|
|
18536
|
+
pool = Option34.String("--pool");
|
|
18537
|
+
out = Option34.String("--out");
|
|
18538
|
+
dryRun = Option34.Boolean("--dry-run", false);
|
|
18539
|
+
keepArms = Option34.Boolean("--keep-arms", false);
|
|
18540
|
+
allowStub = Option34.Boolean("--allow-stub", false);
|
|
18541
|
+
deployment = Option34.String("--deployment");
|
|
18542
|
+
output = Option34.String("--output");
|
|
18543
|
+
observeWaitS = Option34.String("--observe-wait-s");
|
|
18417
18544
|
async executeCommand() {
|
|
18418
18545
|
await Promise.resolve();
|
|
18419
18546
|
const worker = typeof this.worker === "string" ? this.worker : void 0;
|
|
@@ -18527,10 +18654,10 @@ var EvalExamCommand = class extends M8tCommand {
|
|
|
18527
18654
|
};
|
|
18528
18655
|
|
|
18529
18656
|
// src/commands/version.ts
|
|
18530
|
-
import { Command as
|
|
18657
|
+
import { Command as Command37, Option as Option35 } from "clipanion";
|
|
18531
18658
|
var VersionCommand = class extends M8tCommand {
|
|
18532
18659
|
static paths = [["version"], ["--version"], ["-v"]];
|
|
18533
|
-
static usage =
|
|
18660
|
+
static usage = Command37.Usage({
|
|
18534
18661
|
description: "Print the CLI version.",
|
|
18535
18662
|
details: "Prints the m8t CLI version. With --verbose, also prints Node version and platform.",
|
|
18536
18663
|
examples: [
|
|
@@ -18538,8 +18665,8 @@ var VersionCommand = class extends M8tCommand {
|
|
|
18538
18665
|
["Print as JSON", "$0 version --output json"]
|
|
18539
18666
|
]
|
|
18540
18667
|
});
|
|
18541
|
-
output =
|
|
18542
|
-
verbose =
|
|
18668
|
+
output = Option35.String("--output", { description: "pretty | json | auto (default)" });
|
|
18669
|
+
verbose = Option35.Boolean("--verbose", false);
|
|
18543
18670
|
executeCommand() {
|
|
18544
18671
|
const mode = resolveOutputMode(
|
|
18545
18672
|
this.output ?? "auto",
|
|
@@ -18570,18 +18697,18 @@ var VersionCommand = class extends M8tCommand {
|
|
|
18570
18697
|
};
|
|
18571
18698
|
|
|
18572
18699
|
// src/commands/whoami.ts
|
|
18573
|
-
import { Command as
|
|
18700
|
+
import { Command as Command38, Option as Option36 } from "clipanion";
|
|
18574
18701
|
var WhoamiCommand = class extends M8tCommand {
|
|
18575
18702
|
static paths = [["whoami"]];
|
|
18576
|
-
static usage =
|
|
18703
|
+
static usage = Command38.Usage({
|
|
18577
18704
|
description: "Show your identity + the gateway you'll talk to. Probes the backend."
|
|
18578
18705
|
});
|
|
18579
|
-
output =
|
|
18580
|
-
verbose =
|
|
18581
|
-
subscription =
|
|
18706
|
+
output = Option36.String("--output");
|
|
18707
|
+
verbose = Option36.Boolean("--verbose", false);
|
|
18708
|
+
subscription = Option36.String("--subscription", {
|
|
18582
18709
|
description: "Azure subscription ID to discover gateway in (defaults to active az subscription)."
|
|
18583
18710
|
});
|
|
18584
|
-
resourceGroup =
|
|
18711
|
+
resourceGroup = Option36.String("--resource-group", {
|
|
18585
18712
|
description: "m8t-stack resource group to disambiguate the gateway (multi-deployment subscriptions)."
|
|
18586
18713
|
});
|
|
18587
18714
|
async executeCommand() {
|
|
@@ -18646,7 +18773,7 @@ var WhoamiCommand = class extends M8tCommand {
|
|
|
18646
18773
|
};
|
|
18647
18774
|
|
|
18648
18775
|
// src/commands/status.ts
|
|
18649
|
-
import { Command as
|
|
18776
|
+
import { Command as Command39, Option as Option37 } from "clipanion";
|
|
18650
18777
|
|
|
18651
18778
|
// src/lib/azd.ts
|
|
18652
18779
|
init_errors();
|
|
@@ -18711,10 +18838,10 @@ async function resolveLocalContext() {
|
|
|
18711
18838
|
// src/commands/status.ts
|
|
18712
18839
|
var StatusCommand = class extends M8tCommand {
|
|
18713
18840
|
static paths = [["status"]];
|
|
18714
|
-
static usage =
|
|
18841
|
+
static usage = Command39.Usage({
|
|
18715
18842
|
description: "Show the local m8t context: identity, config.yaml, gateway cache, azd mode."
|
|
18716
18843
|
});
|
|
18717
|
-
output =
|
|
18844
|
+
output = Option37.String("--output");
|
|
18718
18845
|
async executeCommand() {
|
|
18719
18846
|
const mode = resolveOutputMode(
|
|
18720
18847
|
this.output,
|
|
@@ -18752,7 +18879,7 @@ var StatusCommand = class extends M8tCommand {
|
|
|
18752
18879
|
};
|
|
18753
18880
|
|
|
18754
18881
|
// src/commands/doctor.ts
|
|
18755
|
-
import { Command as
|
|
18882
|
+
import { Command as Command40, Option as Option38 } from "clipanion";
|
|
18756
18883
|
import { DefaultAzureCredential as DefaultAzureCredential16 } from "@azure/identity";
|
|
18757
18884
|
import * as fs19 from "fs";
|
|
18758
18885
|
import * as os9 from "os";
|
|
@@ -19003,12 +19130,12 @@ function probeRepoRoot() {
|
|
|
19003
19130
|
}
|
|
19004
19131
|
var DoctorCommand = class extends M8tCommand {
|
|
19005
19132
|
static paths = [["doctor"]];
|
|
19006
|
-
static usage =
|
|
19133
|
+
static usage = Command40.Usage({
|
|
19007
19134
|
description: "Diagnose the local m8t setup: az login, config.yaml, gateway, Foundry data-plane."
|
|
19008
19135
|
});
|
|
19009
|
-
output =
|
|
19010
|
-
agent =
|
|
19011
|
-
resourceGroup =
|
|
19136
|
+
output = Option38.String("--output");
|
|
19137
|
+
agent = Option38.String("--agent");
|
|
19138
|
+
resourceGroup = Option38.String("--resource-group", {
|
|
19012
19139
|
description: "m8t-stack resource group to disambiguate the gateway (multi-deployment subscriptions)."
|
|
19013
19140
|
});
|
|
19014
19141
|
async executeCommand() {
|
|
@@ -19124,7 +19251,7 @@ var DoctorCommand = class extends M8tCommand {
|
|
|
19124
19251
|
};
|
|
19125
19252
|
|
|
19126
19253
|
// src/commands/switch.ts
|
|
19127
|
-
import { Command as
|
|
19254
|
+
import { Command as Command41, Option as Option39 } from "clipanion";
|
|
19128
19255
|
|
|
19129
19256
|
// src/lib/profiles.ts
|
|
19130
19257
|
import * as fs20 from "fs/promises";
|
|
@@ -19264,14 +19391,14 @@ async function profileSwitch(name, asName) {
|
|
|
19264
19391
|
init_errors();
|
|
19265
19392
|
var SwitchCommand = class extends M8tCommand {
|
|
19266
19393
|
static paths = [["switch"]];
|
|
19267
|
-
static usage =
|
|
19394
|
+
static usage = Command41.Usage({
|
|
19268
19395
|
description: "Re-point local config at another deployment: --subscription <id|name> (discovery) or <profile>."
|
|
19269
19396
|
});
|
|
19270
|
-
profile =
|
|
19271
|
-
subscription =
|
|
19272
|
-
list =
|
|
19273
|
-
as =
|
|
19274
|
-
output =
|
|
19397
|
+
profile = Option39.String({ required: false });
|
|
19398
|
+
subscription = Option39.String("--subscription");
|
|
19399
|
+
list = Option39.Boolean("--list", false);
|
|
19400
|
+
as = Option39.String("--as");
|
|
19401
|
+
output = Option39.String("--output");
|
|
19275
19402
|
async executeCommand() {
|
|
19276
19403
|
const mode = resolveOutputMode(
|
|
19277
19404
|
this.output,
|
|
@@ -19328,7 +19455,7 @@ var SwitchCommand = class extends M8tCommand {
|
|
|
19328
19455
|
|
|
19329
19456
|
// src/commands/open.ts
|
|
19330
19457
|
import { spawn as spawn5 } from "child_process";
|
|
19331
|
-
import { Command as
|
|
19458
|
+
import { Command as Command42, Option as Option40 } from "clipanion";
|
|
19332
19459
|
|
|
19333
19460
|
// src/lib/open-targets.ts
|
|
19334
19461
|
init_errors();
|
|
@@ -19374,14 +19501,14 @@ function openUrl(url) {
|
|
|
19374
19501
|
}
|
|
19375
19502
|
var OpenCommand = class extends M8tCommand {
|
|
19376
19503
|
static paths = [["open"]];
|
|
19377
|
-
static usage =
|
|
19504
|
+
static usage = Command42.Usage({
|
|
19378
19505
|
description: "Open the deployed webapp (default), the Foundry portal, or the resource group.",
|
|
19379
19506
|
details: "Targets: webapp (deployed app, default) | foundry (ai.azure.com) | portal (resource group in the Azure portal). Pass --print to emit the URL instead of launching a browser (also the default when stdout isn't a TTY)."
|
|
19380
19507
|
});
|
|
19381
|
-
target =
|
|
19382
|
-
print =
|
|
19383
|
-
output =
|
|
19384
|
-
resourceGroup =
|
|
19508
|
+
target = Option40.String({ required: false });
|
|
19509
|
+
print = Option40.Boolean("--print", false);
|
|
19510
|
+
output = Option40.String("--output");
|
|
19511
|
+
resourceGroup = Option40.String("--resource-group", {
|
|
19385
19512
|
description: "m8t-stack resource group to disambiguate the gateway (multi-deployment subscriptions)."
|
|
19386
19513
|
});
|
|
19387
19514
|
async executeCommand() {
|
|
@@ -19425,7 +19552,7 @@ var OpenCommand = class extends M8tCommand {
|
|
|
19425
19552
|
};
|
|
19426
19553
|
|
|
19427
19554
|
// src/commands/dream/run.ts
|
|
19428
|
-
import { Command as
|
|
19555
|
+
import { Command as Command43, Option as Option41 } from "clipanion";
|
|
19429
19556
|
import { AzureCliCredential } from "@azure/identity";
|
|
19430
19557
|
import { TableClient as TableClient2 } from "@azure/data-tables";
|
|
19431
19558
|
import { AIProjectClient as AIProjectClient3 } from "@azure/ai-projects";
|
|
@@ -21442,14 +21569,17 @@ function parseDreamerConfig(rawYaml, env) {
|
|
|
21442
21569
|
};
|
|
21443
21570
|
}
|
|
21444
21571
|
|
|
21572
|
+
// ../../packages/brain/engine/dist/esm/cost-report/config.js
|
|
21573
|
+
import { parse as parseYaml11 } from "yaml";
|
|
21574
|
+
|
|
21445
21575
|
// ../../packages/brain/engine/dist/esm/librarian/codify/persistence-guard.js
|
|
21446
21576
|
var ZERO_WIDTH_RE = new RegExp("\u200B|\u200C|\u200D|\uFEFF", "g");
|
|
21447
21577
|
|
|
21448
21578
|
// ../../packages/brain/engine/dist/esm/librarian/janitor/frontmatter.js
|
|
21449
|
-
import { parse as
|
|
21579
|
+
import { parse as parseYaml12, stringify as stringifyYaml5 } from "yaml";
|
|
21450
21580
|
|
|
21451
21581
|
// ../../packages/brain/engine/dist/esm/librarian/config.js
|
|
21452
|
-
import { parse as
|
|
21582
|
+
import { parse as parseYaml13 } from "yaml";
|
|
21453
21583
|
|
|
21454
21584
|
// src/lib/dream-discovery.ts
|
|
21455
21585
|
init_http();
|
|
@@ -21566,20 +21696,20 @@ function redactTranscripts(input) {
|
|
|
21566
21696
|
}
|
|
21567
21697
|
var DreamRunCommand = class extends M8tCommand {
|
|
21568
21698
|
static paths = [["dream", "run"]];
|
|
21569
|
-
static usage =
|
|
21699
|
+
static usage = Command43.Usage({
|
|
21570
21700
|
description: "Dry-run the brain consumption pipeline for one worker (no model call, no writes).",
|
|
21571
21701
|
details: "Builds AzureCliCredential + resolves the Foundry project, ledger table, and Log Analytics workspace, runs the consumption pipeline, and prints the skip-ledger, the partition invariant, and harvest stats. Transcripts are metadata-only unless --show-transcripts is passed."
|
|
21572
21702
|
});
|
|
21573
|
-
worker =
|
|
21574
|
-
dryRun =
|
|
21575
|
-
since =
|
|
21576
|
-
reset =
|
|
21577
|
-
showTranscripts =
|
|
21703
|
+
worker = Option41.String("--worker", { description: "Worker (canonical name) to harvest. Required." });
|
|
21704
|
+
dryRun = Option41.Boolean("--dry-run", false, { description: "Read-only harvest; no model call, no writes." });
|
|
21705
|
+
since = Option41.String("--since", { description: "ISO-8601 start override (rejected if malformed or future)." });
|
|
21706
|
+
reset = Option41.Boolean("--reset", false, { description: "Ignore the stored cursor; read from the beginning." });
|
|
21707
|
+
showTranscripts = Option41.Boolean("--show-transcripts", false, {
|
|
21578
21708
|
description: "Print transcript bodies (default: metadata only)."
|
|
21579
21709
|
});
|
|
21580
|
-
subscription =
|
|
21581
|
-
endpoint =
|
|
21582
|
-
output =
|
|
21710
|
+
subscription = Option41.String("--subscription");
|
|
21711
|
+
endpoint = Option41.String("--endpoint");
|
|
21712
|
+
output = Option41.String("--output");
|
|
21583
21713
|
// Resolution seam — overridden by tests; built lazily at runtime otherwise.
|
|
21584
21714
|
deps;
|
|
21585
21715
|
async executeCommand() {
|
|
@@ -21927,7 +22057,7 @@ function defaultDeps(overrides) {
|
|
|
21927
22057
|
}
|
|
21928
22058
|
|
|
21929
22059
|
// src/commands/foundry/create.ts
|
|
21930
|
-
import { Command as
|
|
22060
|
+
import { Command as Command44, Option as Option42 } from "clipanion";
|
|
21931
22061
|
|
|
21932
22062
|
// src/lib/foundry-create.ts
|
|
21933
22063
|
init_errors();
|
|
@@ -22165,7 +22295,7 @@ async function createFoundryProject(args) {
|
|
|
22165
22295
|
init_errors();
|
|
22166
22296
|
var FoundryCreateCommand = class extends M8tCommand {
|
|
22167
22297
|
static paths = [["foundry", "create"]];
|
|
22168
|
-
static usage =
|
|
22298
|
+
static usage = Command44.Usage({
|
|
22169
22299
|
description: "Create an AI Foundry (AIServices) account + project + model deployment from scratch.",
|
|
22170
22300
|
details: "Non-interactive and idempotent. Creates the AIServices account (custom subdomain + project management), a project, and a model deployment (default gpt-4.1-mini @ capacity 50). Region must be hosted-agent-eligible. Emits the project endpoint as structured output. Re-run is a clean no-op (account/project skipped if present; deployment capacity converges UP, never down).",
|
|
22171
22301
|
examples: [
|
|
@@ -22174,16 +22304,16 @@ var FoundryCreateCommand = class extends M8tCommand {
|
|
|
22174
22304
|
["Higher capacity for a reasoning model", "$0 foundry create --resource-group rg-m8t-stack --location eastus2 --model gpt-5-mini --capacity 250"]
|
|
22175
22305
|
]
|
|
22176
22306
|
});
|
|
22177
|
-
resourceGroup =
|
|
22178
|
-
location =
|
|
22179
|
-
account =
|
|
22180
|
-
project =
|
|
22181
|
-
model =
|
|
22182
|
-
modelVersion =
|
|
22183
|
-
capacity =
|
|
22184
|
-
subscription =
|
|
22185
|
-
skipQuotaCheck =
|
|
22186
|
-
output =
|
|
22307
|
+
resourceGroup = Option42.String("--resource-group");
|
|
22308
|
+
location = Option42.String("--location");
|
|
22309
|
+
account = Option42.String("--account");
|
|
22310
|
+
project = Option42.String("--project", "m8t");
|
|
22311
|
+
model = Option42.String("--model", "gpt-4.1-mini");
|
|
22312
|
+
modelVersion = Option42.String("--model-version", "2025-04-14");
|
|
22313
|
+
capacity = Option42.String("--capacity", "50");
|
|
22314
|
+
subscription = Option42.String("--subscription");
|
|
22315
|
+
skipQuotaCheck = Option42.Boolean("--skip-quota-check", false);
|
|
22316
|
+
output = Option42.String("--output");
|
|
22187
22317
|
async executeCommand() {
|
|
22188
22318
|
const mode = resolveOutputMode(
|
|
22189
22319
|
this.output,
|
|
@@ -22255,22 +22385,22 @@ var FoundryCreateCommand = class extends M8tCommand {
|
|
|
22255
22385
|
};
|
|
22256
22386
|
|
|
22257
22387
|
// src/commands/foundry/await-ready.ts
|
|
22258
|
-
import { Command as
|
|
22388
|
+
import { Command as Command45, Option as Option43 } from "clipanion";
|
|
22259
22389
|
import { AzureCliCredential as AzureCliCredential2 } from "@azure/identity";
|
|
22260
22390
|
init_errors();
|
|
22261
22391
|
var FoundryAwaitReadyCommand = class extends M8tCommand {
|
|
22262
22392
|
static paths = [["foundry", "await-ready"]];
|
|
22263
|
-
static usage =
|
|
22393
|
+
static usage = Command45.Usage({
|
|
22264
22394
|
description: "Wait until a freshly-created Foundry project's data plane reliably serves it.",
|
|
22265
22395
|
details: "Probes the project (GET /agents) until it returns 200 on a few consecutive tries, or fails clearly after a bounded budget. A newly-created account can serve intermittent 404 'Project not found' for minutes; run this after 'foundry create' and before deploying agents so the worker phase doesn't catch the unstable window.",
|
|
22266
22396
|
examples: [["Wait for a project to be ready", "$0 foundry await-ready --endpoint https://acc.services.ai.azure.com/api/projects/m8t"]]
|
|
22267
22397
|
});
|
|
22268
|
-
endpoint =
|
|
22269
|
-
consecutive =
|
|
22270
|
-
attempts =
|
|
22271
|
-
interval =
|
|
22272
|
-
subscription =
|
|
22273
|
-
output =
|
|
22398
|
+
endpoint = Option43.String("--endpoint");
|
|
22399
|
+
consecutive = Option43.String("--consecutive", "3");
|
|
22400
|
+
attempts = Option43.String("--attempts", "60");
|
|
22401
|
+
interval = Option43.String("--interval", "5");
|
|
22402
|
+
subscription = Option43.String("--subscription");
|
|
22403
|
+
output = Option43.String("--output");
|
|
22274
22404
|
async executeCommand() {
|
|
22275
22405
|
const mode = resolveOutputMode(this.output, this.context.stdout);
|
|
22276
22406
|
const endpoint = typeof this.endpoint === "string" ? this.endpoint : void 0;
|
|
@@ -22304,7 +22434,7 @@ var FoundryAwaitReadyCommand = class extends M8tCommand {
|
|
|
22304
22434
|
};
|
|
22305
22435
|
|
|
22306
22436
|
// src/commands/bootstrap/preflight.ts
|
|
22307
|
-
import { Command as
|
|
22437
|
+
import { Command as Command46, Option as Option44 } from "clipanion";
|
|
22308
22438
|
init_errors();
|
|
22309
22439
|
|
|
22310
22440
|
// src/lib/bootstrap-preflight.ts
|
|
@@ -22378,7 +22508,7 @@ function buildPreflightBanner(who) {
|
|
|
22378
22508
|
// src/commands/bootstrap/preflight.ts
|
|
22379
22509
|
var BootstrapPreflightCommand = class extends M8tCommand {
|
|
22380
22510
|
static paths = [["bootstrap", "preflight"]];
|
|
22381
|
-
static usage =
|
|
22511
|
+
static usage = Command46.Usage({
|
|
22382
22512
|
description: "Loudly verify you can install m8t-stack (Owner/UAA + directory admin) and hard-stop if not.",
|
|
22383
22513
|
details: "Step 1 of `m8t bootstrap`. Prints an unmissable admin-credentials notice, then checks: Owner or User Access Administrator at subscription scope (hard requirement), directory-admin capability to register the app (or pass --client-id), and registers Microsoft.ContainerInstance. Exits non-zero with the exact failing check + remedy.",
|
|
22384
22514
|
examples: [
|
|
@@ -22386,8 +22516,8 @@ var BootstrapPreflightCommand = class extends M8tCommand {
|
|
|
22386
22516
|
["BYO app registration (directory guests)", "$0 bootstrap preflight --client-id <appId>"]
|
|
22387
22517
|
]
|
|
22388
22518
|
});
|
|
22389
|
-
clientId =
|
|
22390
|
-
subscription =
|
|
22519
|
+
clientId = Option44.String("--client-id");
|
|
22520
|
+
subscription = Option44.String("--subscription");
|
|
22391
22521
|
async executeCommand() {
|
|
22392
22522
|
const clientId = typeof this.clientId === "string" ? this.clientId : void 0;
|
|
22393
22523
|
const account = await getAzAccount();
|
|
@@ -22446,7 +22576,7 @@ ${colors.error(" " + why)}
|
|
|
22446
22576
|
import * as fs23 from "fs";
|
|
22447
22577
|
import * as os12 from "os";
|
|
22448
22578
|
import * as path24 from "path";
|
|
22449
|
-
import { Command as
|
|
22579
|
+
import { Command as Command47, Option as Option45 } from "clipanion";
|
|
22450
22580
|
init_errors();
|
|
22451
22581
|
|
|
22452
22582
|
// src/lib/bootstrap-mi.ts
|
|
@@ -22699,7 +22829,7 @@ var ACI_NAME = "m8t-installer";
|
|
|
22699
22829
|
var MI_NAME = "m8t-installer-mi";
|
|
22700
22830
|
var BootstrapLaunchCommand = class extends M8tCommand {
|
|
22701
22831
|
static paths = [["bootstrap", "launch"]];
|
|
22702
|
-
static usage =
|
|
22832
|
+
static usage = Command47.Usage({
|
|
22703
22833
|
description: "Create + authorize the installer managed identity, then kick the cloud installer.",
|
|
22704
22834
|
details: "Step 2 of `m8t bootstrap` (run after `preflight`). Ensures the resource group, creates the m8t-stack app registration (or uses --client-id), creates a user-assigned managed identity granted Owner at subscription scope, and launches the published m8t-installer image as an ACI run-to-completion job under that identity. Writes ~/.m8t-stack/bootstrap.json for `status`/`reap`/`finish`.",
|
|
22705
22835
|
examples: [
|
|
@@ -22708,13 +22838,13 @@ var BootstrapLaunchCommand = class extends M8tCommand {
|
|
|
22708
22838
|
["Pin a specific installer tag", "$0 bootstrap launch --location eastus2 --installer-tag v0.1.0"]
|
|
22709
22839
|
]
|
|
22710
22840
|
});
|
|
22711
|
-
location =
|
|
22712
|
-
resourceGroup =
|
|
22713
|
-
clientId =
|
|
22714
|
-
subscription =
|
|
22715
|
-
installerTag =
|
|
22716
|
-
gatewayImageRef =
|
|
22717
|
-
githubAppCreds =
|
|
22841
|
+
location = Option45.String("--location");
|
|
22842
|
+
resourceGroup = Option45.String("--resource-group");
|
|
22843
|
+
clientId = Option45.String("--client-id");
|
|
22844
|
+
subscription = Option45.String("--subscription");
|
|
22845
|
+
installerTag = Option45.String("--installer-tag");
|
|
22846
|
+
gatewayImageRef = Option45.String("--gateway-image-ref");
|
|
22847
|
+
githubAppCreds = Option45.String("--github-app-creds");
|
|
22718
22848
|
async executeCommand() {
|
|
22719
22849
|
const location = typeof this.location === "string" ? this.location : void 0;
|
|
22720
22850
|
if (!location) {
|
|
@@ -22815,7 +22945,7 @@ var BootstrapLaunchCommand = class extends M8tCommand {
|
|
|
22815
22945
|
};
|
|
22816
22946
|
|
|
22817
22947
|
// src/commands/bootstrap/status.ts
|
|
22818
|
-
import { Command as
|
|
22948
|
+
import { Command as Command48, Option as Option46 } from "clipanion";
|
|
22819
22949
|
init_errors();
|
|
22820
22950
|
|
|
22821
22951
|
// src/lib/bootstrap-aci-state.ts
|
|
@@ -22843,13 +22973,13 @@ async function getAciState(opts) {
|
|
|
22843
22973
|
// src/commands/bootstrap/status.ts
|
|
22844
22974
|
var BootstrapStatusCommand = class extends M8tCommand {
|
|
22845
22975
|
static paths = [["bootstrap", "status"]];
|
|
22846
|
-
static usage =
|
|
22976
|
+
static usage = Command48.Usage({
|
|
22847
22977
|
description: "Show the cloud installer's live status (phase, progress, result).",
|
|
22848
22978
|
details: "Reads the durable status blob written by the installer. --watch polls until the install reaches done or failed.",
|
|
22849
22979
|
examples: [["One read", "$0 bootstrap status"], ["Watch to completion", "$0 bootstrap status --watch"]]
|
|
22850
22980
|
});
|
|
22851
|
-
watch =
|
|
22852
|
-
output =
|
|
22981
|
+
watch = Option46.Boolean("--watch", false);
|
|
22982
|
+
output = Option46.String("--output");
|
|
22853
22983
|
async executeCommand() {
|
|
22854
22984
|
const state = await readBootstrapState();
|
|
22855
22985
|
if (!state) {
|
|
@@ -22920,7 +23050,7 @@ function formatStatus(d) {
|
|
|
22920
23050
|
}
|
|
22921
23051
|
|
|
22922
23052
|
// src/commands/bootstrap/reap.ts
|
|
22923
|
-
import { Command as
|
|
23053
|
+
import { Command as Command49, Option as Option47 } from "clipanion";
|
|
22924
23054
|
init_errors();
|
|
22925
23055
|
|
|
22926
23056
|
// src/lib/bootstrap-reap.ts
|
|
@@ -22996,14 +23126,14 @@ async function reapInstaller(opts) {
|
|
|
22996
23126
|
// src/commands/bootstrap/reap.ts
|
|
22997
23127
|
var BootstrapReapCommand = class extends M8tCommand {
|
|
22998
23128
|
static paths = [["bootstrap", "reap"]];
|
|
22999
|
-
static usage =
|
|
23129
|
+
static usage = Command49.Usage({
|
|
23000
23130
|
description: "Tear down the installer scaffolding (ACI \u2192 MI \u2192 its role assignments) after a successful install.",
|
|
23001
23131
|
details: "Runs locally on the 'done' signal (the installer can't delete its own identity). The platform RG and the gateway's own assignments persist. A failed install is left intact for diagnosis unless --force.",
|
|
23002
23132
|
examples: [["Reap after done", "$0 bootstrap reap"]]
|
|
23003
23133
|
});
|
|
23004
|
-
force =
|
|
23005
|
-
sweepOrphans =
|
|
23006
|
-
yes =
|
|
23134
|
+
force = Option47.Boolean("--force", false);
|
|
23135
|
+
sweepOrphans = Option47.Boolean("--sweep-orphans", false);
|
|
23136
|
+
yes = Option47.Boolean("--yes", false);
|
|
23007
23137
|
async executeCommand() {
|
|
23008
23138
|
if (this.sweepOrphans === true) {
|
|
23009
23139
|
const { subscriptionId: sub } = await getAzAccount();
|
|
@@ -23071,7 +23201,7 @@ Found ${String(found.length)} orphaned Owner@sub assignment(s) (dry-run). ${colo
|
|
|
23071
23201
|
import * as fs24 from "fs/promises";
|
|
23072
23202
|
import * as os14 from "os";
|
|
23073
23203
|
import * as path26 from "path";
|
|
23074
|
-
import { Command as
|
|
23204
|
+
import { Command as Command50, Option as Option48 } from "clipanion";
|
|
23075
23205
|
init_errors();
|
|
23076
23206
|
|
|
23077
23207
|
// src/lib/company-profile-seed.ts
|
|
@@ -23160,9 +23290,9 @@ function companyProfileBodyEquals(a, b) {
|
|
|
23160
23290
|
const strip = (s) => s.replace(/^(created|updated):.*$/gm, "").trim();
|
|
23161
23291
|
return strip(a) === strip(b);
|
|
23162
23292
|
}
|
|
23163
|
-
function upsertMemoryIndex(existing, line2) {
|
|
23293
|
+
function upsertMemoryIndex(existing, line2, targetPath2 = COMPANY_PROFILE_PATH) {
|
|
23164
23294
|
const lines = existing.split("\n");
|
|
23165
|
-
const existingIdx = lines.findIndex((l) => l.includes(`\`${
|
|
23295
|
+
const existingIdx = lines.findIndex((l) => l.includes(`\`${targetPath2}\``));
|
|
23166
23296
|
if (existingIdx >= 0) {
|
|
23167
23297
|
lines[existingIdx] = line2;
|
|
23168
23298
|
return lines.join("\n");
|
|
@@ -23174,6 +23304,88 @@ function upsertMemoryIndex(existing, line2) {
|
|
|
23174
23304
|
}
|
|
23175
23305
|
return existing.replace(/\s*$/, "\n\n") + line2 + "\n";
|
|
23176
23306
|
}
|
|
23307
|
+
var FOUNDER_RECORD_PATH = "memory/founder.md";
|
|
23308
|
+
var NOT_CAPTURED = "_not captured yet \u2014 add it anytime (run `m8t bootstrap seed-profile`, or just tell me)_";
|
|
23309
|
+
function renderFounderRecord(block, inputs, now = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
23310
|
+
const pick = (...vals) => vals.map((v) => v?.trim()).find(Boolean) ?? "";
|
|
23311
|
+
const founderName = pick(block.founder_name, inputs.azIdentity?.name);
|
|
23312
|
+
const founderEmail = pick(block.founder_email, inputs.azIdentity?.email);
|
|
23313
|
+
const advisorName = (block.advisor_name ?? "").trim();
|
|
23314
|
+
const advisorEmail = (block.advisor_email ?? "").trim();
|
|
23315
|
+
const subscription = (inputs.subscriptionId ?? "").trim();
|
|
23316
|
+
const teamSize = (block.team_size ?? "").trim();
|
|
23317
|
+
const advisorRendered = advisorName || advisorEmail ? [advisorName, advisorEmail ? `<${advisorEmail}>` : ""].filter(Boolean).join(" ") : NOT_CAPTURED;
|
|
23318
|
+
const founderMd = [
|
|
23319
|
+
`---`,
|
|
23320
|
+
`type: memory`,
|
|
23321
|
+
`title: "Founder & install context"`,
|
|
23322
|
+
`created: ${now}`,
|
|
23323
|
+
`updated: ${now}`,
|
|
23324
|
+
`tags: [founder, install-context, onboarding]`,
|
|
23325
|
+
`origin: operator`,
|
|
23326
|
+
`---`,
|
|
23327
|
+
``,
|
|
23328
|
+
`# Founder & install context`,
|
|
23329
|
+
``,
|
|
23330
|
+
`_Seeded at onboarding from your Azure identity + the questionnaire. Authoritative \u2014 read it; don't rewrite it (origin: operator)._`,
|
|
23331
|
+
``,
|
|
23332
|
+
`- **Founder:** ${founderName || NOT_CAPTURED}`,
|
|
23333
|
+
`- **Founder email (company_email):** ${founderEmail || NOT_CAPTURED}`,
|
|
23334
|
+
`- **Microsoft Startup Advisor (SA):** ${advisorRendered}`,
|
|
23335
|
+
`- **Azure subscription:** ${subscription || NOT_CAPTURED}`,
|
|
23336
|
+
`- **Team size:** ${teamSize || "\u2014"}`,
|
|
23337
|
+
``
|
|
23338
|
+
].join("\n");
|
|
23339
|
+
const idxAdvisor = advisorEmail || advisorName || "\u2014";
|
|
23340
|
+
const idxSub = subscription ? `${subscription.slice(0, 8)}\u2026` : "\u2014";
|
|
23341
|
+
const memoryIndexLine = `- \`${FOUNDER_RECORD_PATH}\` \u2014 **Founder & install context**: ${founderName || "founder"} \xB7 advisor ${idxAdvisor} \xB7 sub ${idxSub}. (seeded from onboarding)`;
|
|
23342
|
+
return { founderMd, memoryIndexLine };
|
|
23343
|
+
}
|
|
23344
|
+
function founderRecordBodyEquals(a, b) {
|
|
23345
|
+
const strip = (s) => s.replace(/^(created|updated):.*$/gm, "").trim();
|
|
23346
|
+
return strip(a) === strip(b);
|
|
23347
|
+
}
|
|
23348
|
+
|
|
23349
|
+
// src/lib/founder-identity.ts
|
|
23350
|
+
function deriveEmailCandidate(raw) {
|
|
23351
|
+
const mail = (raw.mail ?? "").trim();
|
|
23352
|
+
if (mail) return mail;
|
|
23353
|
+
const upn = (raw.upn ?? "").trim();
|
|
23354
|
+
if (!upn) return "";
|
|
23355
|
+
const ext = upn.indexOf("#EXT#");
|
|
23356
|
+
if (ext > 0) {
|
|
23357
|
+
const local = upn.slice(0, ext);
|
|
23358
|
+
const at = local.lastIndexOf("_");
|
|
23359
|
+
return at > 0 ? `${local.slice(0, at)}@${local.slice(at + 1)}` : "";
|
|
23360
|
+
}
|
|
23361
|
+
return upn.includes("@") ? upn : "";
|
|
23362
|
+
}
|
|
23363
|
+
async function getSignedInUserIdentity(runAzImpl = runAz) {
|
|
23364
|
+
try {
|
|
23365
|
+
const raw = await runAzImpl([
|
|
23366
|
+
"ad",
|
|
23367
|
+
"signed-in-user",
|
|
23368
|
+
"show",
|
|
23369
|
+
"--query",
|
|
23370
|
+
"{displayName:displayName, mail:mail, upn:userPrincipalName}",
|
|
23371
|
+
"-o",
|
|
23372
|
+
"json"
|
|
23373
|
+
]);
|
|
23374
|
+
const p = JSON.parse(raw);
|
|
23375
|
+
return { name: (p.displayName ?? "").trim(), email: deriveEmailCandidate({ mail: p.mail, upn: p.upn }) };
|
|
23376
|
+
} catch {
|
|
23377
|
+
return { name: "", email: "" };
|
|
23378
|
+
}
|
|
23379
|
+
}
|
|
23380
|
+
function composeFounderIdentityNote(id) {
|
|
23381
|
+
if (id.name && id.email) {
|
|
23382
|
+
return `You're speaking with **${id.name}**, signed in to Azure (their email looks like **${id.email}**). Open by confirming both, in your own voice \u2014 e.g. "I see you're signed in as ${id.name}, and I'll use ${id.email} for your advisor handoffs and cost reports \u2014 is that right, or should I change either?" Record exactly what they approve or correct.`;
|
|
23383
|
+
}
|
|
23384
|
+
if (id.name) {
|
|
23385
|
+
return `You're speaking with **${id.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).`;
|
|
23386
|
+
}
|
|
23387
|
+
return `Ask the founder their name and the best contact email to reach them (that's where advisor handoffs and cost reports go).`;
|
|
23388
|
+
}
|
|
23177
23389
|
|
|
23178
23390
|
// src/lib/company-profile-seed.ts
|
|
23179
23391
|
function readGithubAppCreds(credsPath) {
|
|
@@ -23188,18 +23400,21 @@ async function resolveSeedContext(opts) {
|
|
|
23188
23400
|
const appCreds = opts.appCredsOverride ?? readGithubAppCreds(opts.credsPath);
|
|
23189
23401
|
if (!appCreds) return null;
|
|
23190
23402
|
let endpoint = opts.endpointOverride;
|
|
23403
|
+
let subscriptionId = opts.subscriptionId;
|
|
23191
23404
|
if (!endpoint) {
|
|
23192
23405
|
const state = await readBootstrapState();
|
|
23193
23406
|
if (!state) {
|
|
23194
23407
|
throw new LocalCliError({ code: "BOOTSTRAP_NO_STATE", message: "No bootstrap state found.", hint: "Run 'm8t bootstrap launch' first, or pass --endpoint." });
|
|
23195
23408
|
}
|
|
23409
|
+
subscriptionId ??= state.subscriptionId;
|
|
23196
23410
|
const doc = await readStatusBlob({ saName: state.statusSaName, resourceGroup: state.resourceGroup, subscriptionId: state.subscriptionId });
|
|
23197
23411
|
endpoint = doc.result?.foundryEndpoint;
|
|
23198
23412
|
if (!endpoint) {
|
|
23199
23413
|
throw new LocalCliError({ code: "SEED_NO_ENDPOINT", message: "Could not resolve the Foundry endpoint from the install status.", hint: "Pass --endpoint <foundryEndpoint>." });
|
|
23200
23414
|
}
|
|
23201
23415
|
}
|
|
23202
|
-
|
|
23416
|
+
const brainRepos = opts.brainOverride ? [opts.brainOverride] : [`${appCreds.org}/stacey-brain`, `${appCreds.org}/azzy-brain`];
|
|
23417
|
+
return { endpoint, brainRepos, appCreds, subscriptionId };
|
|
23203
23418
|
}
|
|
23204
23419
|
async function applyProfileToBrain(args) {
|
|
23205
23420
|
const token = await mintInstallationTokenFromPem({
|
|
@@ -23208,20 +23423,31 @@ async function applyProfileToBrain(args) {
|
|
|
23208
23423
|
installationId: args.appCreds.installationId,
|
|
23209
23424
|
fetchImpl: args.fetchImpl
|
|
23210
23425
|
});
|
|
23211
|
-
const { profileMd, memoryIndexLine } = renderCompanyProfile(args.block, args.now);
|
|
23212
|
-
const
|
|
23213
|
-
|
|
23214
|
-
|
|
23215
|
-
|
|
23426
|
+
const { profileMd, memoryIndexLine: companyLine } = renderCompanyProfile(args.block, args.now);
|
|
23427
|
+
const { founderMd, memoryIndexLine: founderLine } = renderFounderRecord(
|
|
23428
|
+
args.block,
|
|
23429
|
+
{ subscriptionId: args.subscriptionId, azIdentity: args.azIdentity },
|
|
23430
|
+
args.now
|
|
23431
|
+
);
|
|
23432
|
+
const read = (p) => readRepoFileViaApp({ token, repo: args.brainRepo, path: p, fetchImpl: args.fetchImpl });
|
|
23433
|
+
const existingProfile = await read(COMPANY_PROFILE_PATH);
|
|
23434
|
+
const existingFounder = await read(FOUNDER_RECORD_PATH);
|
|
23435
|
+
const existingIndex = await read("memory/MEMORY.md") ?? DEFAULT_MEMORY_INDEX_HEADER;
|
|
23436
|
+
let nextIndex = upsertMemoryIndex(existingIndex, companyLine, COMPANY_PROFILE_PATH);
|
|
23437
|
+
nextIndex = upsertMemoryIndex(nextIndex, founderLine, FOUNDER_RECORD_PATH);
|
|
23438
|
+
const profileSame = existingProfile != null && companyProfileBodyEquals(existingProfile, profileMd);
|
|
23439
|
+
const founderSame = existingFounder != null && founderRecordBodyEquals(existingFounder, founderMd);
|
|
23440
|
+
if (profileSame && founderSame && nextIndex === existingIndex) {
|
|
23216
23441
|
return;
|
|
23217
23442
|
}
|
|
23218
23443
|
await commitFilesViaApp({
|
|
23219
23444
|
token,
|
|
23220
23445
|
repo: args.brainRepo,
|
|
23221
23446
|
branch: args.branch,
|
|
23222
|
-
message: "seed(brain): company profile from onboarding
|
|
23447
|
+
message: "seed(brain): founder + company profile from onboarding",
|
|
23223
23448
|
files: [
|
|
23224
23449
|
{ path: COMPANY_PROFILE_PATH, content: profileMd },
|
|
23450
|
+
{ path: FOUNDER_RECORD_PATH, content: founderMd },
|
|
23225
23451
|
{ path: "memory/MEMORY.md", content: nextIndex }
|
|
23226
23452
|
],
|
|
23227
23453
|
fetchImpl: args.fetchImpl
|
|
@@ -23241,20 +23467,31 @@ function spawnDetachedSeedWatch() {
|
|
|
23241
23467
|
}
|
|
23242
23468
|
}
|
|
23243
23469
|
async function reactiveSeedOnFinish(args) {
|
|
23244
|
-
const ctx = await resolveSeedContext({ endpointOverride: args.endpoint, appCredsOverride: args.appCredsOverride });
|
|
23470
|
+
const ctx = await resolveSeedContext({ endpointOverride: args.endpoint, appCredsOverride: args.appCredsOverride, subscriptionId: args.subscriptionId });
|
|
23245
23471
|
if (!ctx) return;
|
|
23246
23472
|
const token = await (args.getFoundryTokenImpl ?? getFoundryToken)();
|
|
23247
23473
|
const { hadIntake, block } = await findOnboardingProfile({ endpoint: ctx.endpoint, token, fetchImpl: args.fetchImpl });
|
|
23248
23474
|
if (block) {
|
|
23249
|
-
|
|
23250
|
-
|
|
23475
|
+
const azIdentity = args.azIdentity ?? await (args.getSignedInUserIdentityImpl ?? getSignedInUserIdentity)();
|
|
23476
|
+
for (const brainRepo of ctx.brainRepos) {
|
|
23477
|
+
await applyProfileToBrain({
|
|
23478
|
+
block,
|
|
23479
|
+
brainRepo,
|
|
23480
|
+
branch: "main",
|
|
23481
|
+
appCreds: ctx.appCreds,
|
|
23482
|
+
subscriptionId: ctx.subscriptionId,
|
|
23483
|
+
azIdentity,
|
|
23484
|
+
fetchImpl: args.fetchImpl
|
|
23485
|
+
});
|
|
23486
|
+
}
|
|
23487
|
+
args.stdout(`${colors.success("\u2713")} Your advisors now know your company + how to reach you (seeded ${ctx.brainRepos.join(", ")}).
|
|
23251
23488
|
`);
|
|
23252
23489
|
return;
|
|
23253
23490
|
}
|
|
23254
23491
|
if (!hadIntake) return;
|
|
23255
23492
|
(args.spawnWatch ?? spawnDetachedSeedWatch)();
|
|
23256
23493
|
args.stdout(
|
|
23257
|
-
`${colors.dim("\u2139
|
|
23494
|
+
`${colors.dim("\u2139 Your advisors will pick up your company profile when you finish the questionnaire (watching in the background).")}
|
|
23258
23495
|
${colors.hint("or run:")} m8t bootstrap seed-profile
|
|
23259
23496
|
`
|
|
23260
23497
|
);
|
|
@@ -23294,14 +23531,14 @@ function renderInstallSummary(args) {
|
|
|
23294
23531
|
// src/commands/bootstrap/finish.ts
|
|
23295
23532
|
var BootstrapFinishCommand = class extends M8tCommand {
|
|
23296
23533
|
static paths = [["bootstrap", "finish"]];
|
|
23297
|
-
static usage =
|
|
23534
|
+
static usage = Command50.Usage({
|
|
23298
23535
|
description: "Point your local tools at the now-live platform (repo-root marker, discovery cache, next steps).",
|
|
23299
23536
|
details: "Final step of `m8t bootstrap` (after the install reaches done). Writes ~/.m8t-stack/repo-root, points your local tools at the live gateway, and \u2014 if you completed the onboarding questionnaire \u2014 seeds your brain-backed advisor's brain with your company profile (best-effort; never blocks finish). Run `m8t bootstrap seed-profile` to seed manually later.",
|
|
23300
23537
|
examples: [["Finish local", "$0 bootstrap finish --repo-root /path/to/m8t"]]
|
|
23301
23538
|
});
|
|
23302
|
-
repoRoot =
|
|
23303
|
-
subscription =
|
|
23304
|
-
resourceGroup =
|
|
23539
|
+
repoRoot = Option48.String("--repo-root");
|
|
23540
|
+
subscription = Option48.String("--subscription");
|
|
23541
|
+
resourceGroup = Option48.String("--resource-group");
|
|
23305
23542
|
async executeCommand() {
|
|
23306
23543
|
const state = await readBootstrapState();
|
|
23307
23544
|
if (!state) {
|
|
@@ -23371,6 +23608,7 @@ ${colors.field("Then open a brand new chat/session")} \u2014 new skills + MCP se
|
|
|
23371
23608
|
try {
|
|
23372
23609
|
await reactiveSeedOnFinish({
|
|
23373
23610
|
endpoint: doc.result?.foundryEndpoint,
|
|
23611
|
+
subscriptionId,
|
|
23374
23612
|
stdout: (s) => this.context.stdout.write(s)
|
|
23375
23613
|
});
|
|
23376
23614
|
} catch (e) {
|
|
@@ -23387,7 +23625,7 @@ ${colors.field("Then open a brand new chat/session")} \u2014 new skills + MCP se
|
|
|
23387
23625
|
import * as fs26 from "fs";
|
|
23388
23626
|
import * as os16 from "os";
|
|
23389
23627
|
import * as path28 from "path";
|
|
23390
|
-
import { Command as
|
|
23628
|
+
import { Command as Command51, Option as Option49 } from "clipanion";
|
|
23391
23629
|
import { DefaultAzureCredential as DefaultAzureCredential17 } from "@azure/identity";
|
|
23392
23630
|
init_errors();
|
|
23393
23631
|
|
|
@@ -23617,7 +23855,8 @@ async function deploySimpleStacey(args) {
|
|
|
23617
23855
|
endpoint: args.endpoint,
|
|
23618
23856
|
repoRoot: args.repoRoot,
|
|
23619
23857
|
persona: SIMPLE_STACEY_PERSONA,
|
|
23620
|
-
agentName: SIMPLE_STACEY_AGENT
|
|
23858
|
+
agentName: SIMPLE_STACEY_AGENT,
|
|
23859
|
+
fieldOverrides: args.fieldOverrides
|
|
23621
23860
|
});
|
|
23622
23861
|
} catch (e) {
|
|
23623
23862
|
if (e && typeof e === "object" && "code" in e) {
|
|
@@ -23657,7 +23896,7 @@ async function deploySimpleStacey(args) {
|
|
|
23657
23896
|
// src/commands/bootstrap/ui.ts
|
|
23658
23897
|
var BootstrapUiCommand = class extends M8tCommand {
|
|
23659
23898
|
static paths = [["bootstrap", "ui"]];
|
|
23660
|
-
static usage =
|
|
23899
|
+
static usage = Command51.Usage({
|
|
23661
23900
|
description: "Deploy Simple Stacey + start the local onboarding chat UI in the background (returns immediately).",
|
|
23662
23901
|
details: [
|
|
23663
23902
|
"Run after `m8t bootstrap launch`, in parallel with `status --watch`. Waits for the cloud",
|
|
@@ -23675,15 +23914,15 @@ var BootstrapUiCommand = class extends M8tCommand {
|
|
|
23675
23914
|
["Foreground (blocking, old behaviour)", "$0 bootstrap ui --repo-root /path/to/m8t --foreground"]
|
|
23676
23915
|
]
|
|
23677
23916
|
});
|
|
23678
|
-
repoRoot =
|
|
23679
|
-
port =
|
|
23680
|
-
endpoint =
|
|
23917
|
+
repoRoot = Option49.String("--repo-root");
|
|
23918
|
+
port = Option49.String("--port", "3000");
|
|
23919
|
+
endpoint = Option49.String("--endpoint", {
|
|
23681
23920
|
description: "Foundry project endpoint to target \u2014 disambiguates when the subscription has multiple projects."
|
|
23682
23921
|
});
|
|
23683
|
-
prepOnly =
|
|
23684
|
-
skipInstall =
|
|
23685
|
-
stop =
|
|
23686
|
-
foreground =
|
|
23922
|
+
prepOnly = Option49.Boolean("--prep-only", false);
|
|
23923
|
+
skipInstall = Option49.Boolean("--skip-install", false);
|
|
23924
|
+
stop = Option49.Boolean("--stop", false);
|
|
23925
|
+
foreground = Option49.Boolean("--foreground", false);
|
|
23687
23926
|
async executeCommand() {
|
|
23688
23927
|
if (this.stop === true) {
|
|
23689
23928
|
const stopped = stopOnboardingUi();
|
|
@@ -23735,7 +23974,13 @@ var BootstrapUiCommand = class extends M8tCommand {
|
|
|
23735
23974
|
const oid = await getSignedInUserOid();
|
|
23736
23975
|
await ensureFounderFoundryRole({ credential: credential2, subscriptionId: state.subscriptionId, principalId: oid, accountScope });
|
|
23737
23976
|
out("deploying Simple Stacey (stacey-intake)\u2026");
|
|
23738
|
-
const
|
|
23977
|
+
const identity = await getSignedInUserIdentity();
|
|
23978
|
+
const version = await deploySimpleStacey({
|
|
23979
|
+
credential: credential2,
|
|
23980
|
+
endpoint,
|
|
23981
|
+
repoRoot,
|
|
23982
|
+
fieldOverrides: { founder_identity_note: composeFounderIdentityNote(identity) }
|
|
23983
|
+
});
|
|
23739
23984
|
const envPath = writeWebEnvLocal({
|
|
23740
23985
|
repoRoot,
|
|
23741
23986
|
tenantId: account.tenantId,
|
|
@@ -23784,22 +24029,22 @@ var BootstrapUiCommand = class extends M8tCommand {
|
|
|
23784
24029
|
};
|
|
23785
24030
|
|
|
23786
24031
|
// src/commands/bootstrap/seed-profile.ts
|
|
23787
|
-
import { Command as
|
|
24032
|
+
import { Command as Command52, Option as Option50 } from "clipanion";
|
|
23788
24033
|
var BootstrapSeedProfileCommand = class extends M8tCommand {
|
|
23789
24034
|
static paths = [["bootstrap", "seed-profile"]];
|
|
23790
|
-
static usage =
|
|
23791
|
-
description: "Seed
|
|
23792
|
-
details: "Reads the latest stacey-intake conversation, renders memory/company-profile.md (+
|
|
24035
|
+
static usage = Command52.Usage({
|
|
24036
|
+
description: "Seed your advisors' brains with the founder + company profile from the onboarding questionnaire.",
|
|
24037
|
+
details: "Reads the latest stacey-intake conversation, renders memory/founder.md + memory/company-profile.md (+ their MEMORY.md index lines), and commits them to both <org>/stacey-brain and <org>/azzy-brain via the GitHub App. Idempotent. --watch polls until the founder completes the questionnaire.",
|
|
23793
24038
|
examples: [
|
|
23794
24039
|
["Seed now (idempotent)", "$0 bootstrap seed-profile"],
|
|
23795
24040
|
["Wait for the founder to finish", "$0 bootstrap seed-profile --watch"]
|
|
23796
24041
|
]
|
|
23797
24042
|
});
|
|
23798
|
-
endpoint =
|
|
23799
|
-
brain =
|
|
23800
|
-
watch =
|
|
23801
|
-
timeout =
|
|
23802
|
-
githubAppCreds =
|
|
24043
|
+
endpoint = Option50.String("--endpoint", { description: "Override the Foundry endpoint (else read from the install status)." });
|
|
24044
|
+
brain = Option50.String("--brain", { description: "Override the brain repo (default <org>/stacey-brain)." });
|
|
24045
|
+
watch = Option50.Boolean("--watch", false, { description: "Poll until the questionnaire completes (or --timeout)." });
|
|
24046
|
+
timeout = Option50.String("--timeout", { description: "Watch timeout in minutes (default 20)." });
|
|
24047
|
+
githubAppCreds = Option50.String("--github-app-creds");
|
|
23803
24048
|
async executeCommand() {
|
|
23804
24049
|
const ctx = await resolveSeedContext({
|
|
23805
24050
|
endpointOverride: typeof this.endpoint === "string" ? this.endpoint : void 0,
|
|
@@ -23821,8 +24066,11 @@ var BootstrapSeedProfileCommand = class extends M8tCommand {
|
|
|
23821
24066
|
const token = await getFoundryToken();
|
|
23822
24067
|
const { hadIntake, block } = await findOnboardingProfile({ endpoint: ctx.endpoint, token });
|
|
23823
24068
|
if (block) {
|
|
23824
|
-
|
|
23825
|
-
|
|
24069
|
+
const azIdentity = await getSignedInUserIdentity();
|
|
24070
|
+
for (const brainRepo of ctx.brainRepos) {
|
|
24071
|
+
await applyProfileToBrain({ block, brainRepo, branch: "main", appCreds: ctx.appCreds, subscriptionId: ctx.subscriptionId, azIdentity });
|
|
24072
|
+
}
|
|
24073
|
+
this.context.stdout.write(`${colors.success("\u2713")} seeded your advisors' brains (${ctx.brainRepos.join(", ")}) from your questionnaire.
|
|
23826
24074
|
`);
|
|
23827
24075
|
return 0;
|
|
23828
24076
|
}
|
|
@@ -23881,6 +24129,7 @@ cli.register(CoderTeardownCommand);
|
|
|
23881
24129
|
cli.register(AzureExecDeployCommand);
|
|
23882
24130
|
cli.register(PlatformStatusCommand);
|
|
23883
24131
|
cli.register(PlatformUpdateCommand);
|
|
24132
|
+
cli.register(PlatformEnableCostReportCommand);
|
|
23884
24133
|
cli.register(DeployCommand);
|
|
23885
24134
|
cli.register(AgentDeployAdvisorCommand);
|
|
23886
24135
|
cli.register(AgentRemoveCommand);
|