@m8t-stack/cli 0.2.11 → 0.2.13

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 CHANGED
@@ -1195,7 +1195,7 @@ var init_enable_hosted_brain = __esm({
1195
1195
  import { Builtins, Cli } from "clipanion";
1196
1196
 
1197
1197
  // src/lib/package-version.ts
1198
- var CLI_VERSION = "0.2.11";
1198
+ var CLI_VERSION = "0.2.13";
1199
1199
 
1200
1200
  // src/lib/render-error.ts
1201
1201
  init_errors();
@@ -15064,10 +15064,9 @@ async function deployPromptAdvisor(args) {
15064
15064
  const fillableFields = fm["fillable-fields"] ?? [];
15065
15065
  const valuesMap = {};
15066
15066
  for (const field of fillableFields) {
15067
- if (field.default !== void 0) {
15068
- valuesMap[field.name] = field.default;
15069
- }
15067
+ if (field.default !== void 0) valuesMap[field.name] = field.default;
15070
15068
  }
15069
+ for (const [k, v] of Object.entries(args.fieldOverrides ?? {})) valuesMap[k] = v;
15071
15070
  const instructions = renderPersonaBody(personaPath, valuesMap);
15072
15071
  return createPromptVersion({
15073
15072
  credential: args.credential,
@@ -15196,6 +15195,109 @@ init_errors();
15196
15195
  init_foundry_agent_get();
15197
15196
  import { randomBytes as randomBytes2, createHash } from "crypto";
15198
15197
 
15198
+ // src/lib/data-plane-ready.ts
15199
+ init_errors();
15200
+ async function awaitDataPlaneReady(opts) {
15201
+ const consecutive = opts.consecutive ?? 3;
15202
+ const attempts = opts.attempts ?? 60;
15203
+ const intervalMs = opts.intervalMs ?? 5e3;
15204
+ const sleep2 = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
15205
+ let streak = 0;
15206
+ for (let i = 1; i <= attempts; i++) {
15207
+ const r = await opts.probe();
15208
+ if (r.ok) {
15209
+ streak++;
15210
+ opts.onProgress?.(`data-plane ok (${streak.toString()}/${consecutive.toString()})`);
15211
+ if (streak >= consecutive) return { ready: true, attempts: i };
15212
+ } else {
15213
+ const cls = classifyFoundryError({ status: r.status, message: r.message ?? "" });
15214
+ const forcedRetryable = r.status !== void 0 && (opts.retryableStatuses?.includes(r.status) ?? false);
15215
+ if (!forcedRetryable && !cls.retryable) {
15216
+ throw new LocalCliError({
15217
+ code: "FOUNDRY_NOT_READY_FATAL",
15218
+ message: `Foundry data plane returned a non-retryable error: ${cls.message}`,
15219
+ hint: "This is not a transient data-plane delay \u2014 check `az login`/permissions and the endpoint.",
15220
+ retryable: false
15221
+ });
15222
+ }
15223
+ streak = 0;
15224
+ opts.onProgress?.(`data-plane not ready (${forcedRetryable ? `status ${(r.status ?? 0).toString()}` : cls.category}), waiting\u2026`);
15225
+ }
15226
+ if (i < attempts) await sleep2(intervalMs);
15227
+ }
15228
+ return { ready: false, attempts };
15229
+ }
15230
+
15231
+ // src/lib/foundry-ready-probe.ts
15232
+ init_http();
15233
+ var FOUNDRY_SCOPE3 = "https://ai.azure.com/.default";
15234
+ function makeAgentsProbe(credential2, endpoint) {
15235
+ return async () => {
15236
+ try {
15237
+ const r = await authedJsonResult({
15238
+ credential: credential2,
15239
+ scope: FOUNDRY_SCOPE3,
15240
+ method: "GET",
15241
+ url: `${endpoint}/agents?api-version=v1`,
15242
+ okStatuses: [404, 500, 502, 503]
15243
+ // don't throw — return the status so the loop classifies it
15244
+ });
15245
+ if (r.status === 200) return { ok: true, status: 200, message: "" };
15246
+ const body = r.data?.error?.message ?? "";
15247
+ return { ok: false, status: r.status, message: `${r.status.toString()} ${body}`.trim() };
15248
+ } catch (e) {
15249
+ return { ok: false, message: e instanceof Error ? e.message : String(e) };
15250
+ }
15251
+ };
15252
+ }
15253
+ function makeAgentProbe(credential2, endpoint, agentName) {
15254
+ return async () => {
15255
+ try {
15256
+ const r = await authedJsonResult({
15257
+ credential: credential2,
15258
+ scope: FOUNDRY_SCOPE3,
15259
+ method: "GET",
15260
+ url: `${endpoint}/agents/${agentName}?api-version=v1`,
15261
+ okStatuses: [404, 500, 502, 503]
15262
+ // don't throw — return the status so the loop classifies it
15263
+ });
15264
+ if (r.status === 200) return { ok: true, status: 200, message: "" };
15265
+ const body = r.data?.error?.message ?? "";
15266
+ return { ok: false, status: r.status, message: `${r.status.toString()} ${body}`.trim() };
15267
+ } catch (e) {
15268
+ return { ok: false, message: e instanceof Error ? e.message : String(e) };
15269
+ }
15270
+ };
15271
+ }
15272
+
15273
+ // src/lib/agent-ready.ts
15274
+ init_errors();
15275
+ async function awaitAgentQueryable(args) {
15276
+ const attemptsMax = args.attempts ?? 40;
15277
+ const intervalMs = args.intervalMs ?? 3e3;
15278
+ const probe = args.probe ?? makeAgentProbe(args.credential, args.projectEndpoint, args.agentName);
15279
+ const { ready, attempts } = await awaitDataPlaneReady({
15280
+ probe,
15281
+ consecutive: args.consecutive ?? 2,
15282
+ attempts: attemptsMax,
15283
+ intervalMs,
15284
+ sleep: args.sleep,
15285
+ onProgress: args.onProgress,
15286
+ retryableStatuses: [404]
15287
+ });
15288
+ if (!ready) {
15289
+ const approxSec = Math.round(attemptsMax * intervalMs / 1e3);
15290
+ throw new LocalCliError({
15291
+ code: "AGENT_NOT_QUERYABLE",
15292
+ message: `Agent '${args.agentName}' did not become queryable within ${attempts.toString()} probes (~${approxSec.toString()}s) after deploy.`,
15293
+ hint: "Foundry agent registration propagates asynchronously after deploy; a retry usually clears it. Re-run shortly (e.g. 'm8t bootstrap launch' or 'm8t a2a enable <name>').",
15294
+ category: "data_plane_not_ready",
15295
+ retryable: false
15296
+ });
15297
+ }
15298
+ return { attempts };
15299
+ }
15300
+
15199
15301
  // src/lib/persona-a2a.ts
15200
15302
  init_errors();
15201
15303
  init_esm();
@@ -15251,6 +15353,13 @@ async function enableA2a(args) {
15251
15353
  const connectionName = `a2a-${args.agentName}`;
15252
15354
  progress("Reading persona a2a-card\u2026");
15253
15355
  const { serialized: a2aCardJson } = readPersonaA2aCard(args.personaPath);
15356
+ progress("Waiting for the agent to become queryable\u2026");
15357
+ await awaitAgentQueryable({
15358
+ credential: args.credential,
15359
+ projectEndpoint: args.projectEndpoint,
15360
+ agentName: args.agentName,
15361
+ onProgress: args.onProgress
15362
+ });
15254
15363
  progress("Reading current agent definition\u2026");
15255
15364
  const current = await getAgentVersion({ credential: args.credential, projectEndpoint: args.projectEndpoint, agentName: args.agentName });
15256
15365
  if (current.definition.kind === "hosted") {
@@ -22147,62 +22256,6 @@ var FoundryCreateCommand = class extends M8tCommand {
22147
22256
  // src/commands/foundry/await-ready.ts
22148
22257
  import { Command as Command44, Option as Option42 } from "clipanion";
22149
22258
  import { AzureCliCredential as AzureCliCredential2 } from "@azure/identity";
22150
-
22151
- // src/lib/data-plane-ready.ts
22152
- init_errors();
22153
- async function awaitDataPlaneReady(opts) {
22154
- const consecutive = opts.consecutive ?? 3;
22155
- const attempts = opts.attempts ?? 60;
22156
- const intervalMs = opts.intervalMs ?? 5e3;
22157
- const sleep2 = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
22158
- let streak = 0;
22159
- for (let i = 1; i <= attempts; i++) {
22160
- const r = await opts.probe();
22161
- if (r.ok) {
22162
- streak++;
22163
- opts.onProgress?.(`data-plane ok (${streak.toString()}/${consecutive.toString()})`);
22164
- if (streak >= consecutive) return { ready: true, attempts: i };
22165
- } else {
22166
- const cls = classifyFoundryError({ status: r.status, message: r.message ?? "" });
22167
- if (!cls.retryable) {
22168
- throw new LocalCliError({
22169
- code: "FOUNDRY_NOT_READY_FATAL",
22170
- message: `Foundry data plane returned a non-retryable error: ${cls.message}`,
22171
- hint: "This is not a transient data-plane delay \u2014 check `az login`/permissions and the endpoint."
22172
- });
22173
- }
22174
- streak = 0;
22175
- opts.onProgress?.(`data-plane not ready (${cls.category}), waiting\u2026`);
22176
- }
22177
- if (i < attempts) await sleep2(intervalMs);
22178
- }
22179
- return { ready: false, attempts };
22180
- }
22181
-
22182
- // src/lib/foundry-ready-probe.ts
22183
- init_http();
22184
- var FOUNDRY_SCOPE3 = "https://ai.azure.com/.default";
22185
- function makeAgentsProbe(credential2, endpoint) {
22186
- return async () => {
22187
- try {
22188
- const r = await authedJsonResult({
22189
- credential: credential2,
22190
- scope: FOUNDRY_SCOPE3,
22191
- method: "GET",
22192
- url: `${endpoint}/agents?api-version=v1`,
22193
- okStatuses: [404, 500, 502, 503]
22194
- // don't throw — return the status so the loop classifies it
22195
- });
22196
- if (r.status === 200) return { ok: true, status: 200, message: "" };
22197
- const body = r.data?.error?.message ?? "";
22198
- return { ok: false, status: r.status, message: `${r.status.toString()} ${body}`.trim() };
22199
- } catch (e) {
22200
- return { ok: false, message: e instanceof Error ? e.message : String(e) };
22201
- }
22202
- };
22203
- }
22204
-
22205
- // src/commands/foundry/await-ready.ts
22206
22259
  init_errors();
22207
22260
  var FoundryAwaitReadyCommand = class extends M8tCommand {
22208
22261
  static paths = [["foundry", "await-ready"]];
@@ -23106,9 +23159,9 @@ function companyProfileBodyEquals(a, b) {
23106
23159
  const strip = (s) => s.replace(/^(created|updated):.*$/gm, "").trim();
23107
23160
  return strip(a) === strip(b);
23108
23161
  }
23109
- function upsertMemoryIndex(existing, line2) {
23162
+ function upsertMemoryIndex(existing, line2, targetPath2 = COMPANY_PROFILE_PATH) {
23110
23163
  const lines = existing.split("\n");
23111
- const existingIdx = lines.findIndex((l) => l.includes(`\`${COMPANY_PROFILE_PATH}\``));
23164
+ const existingIdx = lines.findIndex((l) => l.includes(`\`${targetPath2}\``));
23112
23165
  if (existingIdx >= 0) {
23113
23166
  lines[existingIdx] = line2;
23114
23167
  return lines.join("\n");
@@ -23120,6 +23173,88 @@ function upsertMemoryIndex(existing, line2) {
23120
23173
  }
23121
23174
  return existing.replace(/\s*$/, "\n\n") + line2 + "\n";
23122
23175
  }
23176
+ var FOUNDER_RECORD_PATH = "memory/founder.md";
23177
+ var NOT_CAPTURED = "_not captured yet \u2014 add it anytime (run `m8t bootstrap seed-profile`, or just tell me)_";
23178
+ function renderFounderRecord(block, inputs, now = (/* @__PURE__ */ new Date()).toISOString()) {
23179
+ const pick = (...vals) => vals.map((v) => v?.trim()).find(Boolean) ?? "";
23180
+ const founderName = pick(block.founder_name, inputs.azIdentity?.name);
23181
+ const founderEmail = pick(block.founder_email, inputs.azIdentity?.email);
23182
+ const advisorName = (block.advisor_name ?? "").trim();
23183
+ const advisorEmail = (block.advisor_email ?? "").trim();
23184
+ const subscription = (inputs.subscriptionId ?? "").trim();
23185
+ const teamSize = (block.team_size ?? "").trim();
23186
+ const advisorRendered = advisorName || advisorEmail ? [advisorName, advisorEmail ? `<${advisorEmail}>` : ""].filter(Boolean).join(" ") : NOT_CAPTURED;
23187
+ const founderMd = [
23188
+ `---`,
23189
+ `type: memory`,
23190
+ `title: "Founder & install context"`,
23191
+ `created: ${now}`,
23192
+ `updated: ${now}`,
23193
+ `tags: [founder, install-context, onboarding]`,
23194
+ `origin: operator`,
23195
+ `---`,
23196
+ ``,
23197
+ `# Founder & install context`,
23198
+ ``,
23199
+ `_Seeded at onboarding from your Azure identity + the questionnaire. Authoritative \u2014 read it; don't rewrite it (origin: operator)._`,
23200
+ ``,
23201
+ `- **Founder:** ${founderName || NOT_CAPTURED}`,
23202
+ `- **Founder email (company_email):** ${founderEmail || NOT_CAPTURED}`,
23203
+ `- **Microsoft Startup Advisor (SA):** ${advisorRendered}`,
23204
+ `- **Azure subscription:** ${subscription || NOT_CAPTURED}`,
23205
+ `- **Team size:** ${teamSize || "\u2014"}`,
23206
+ ``
23207
+ ].join("\n");
23208
+ const idxAdvisor = advisorEmail || advisorName || "\u2014";
23209
+ const idxSub = subscription ? `${subscription.slice(0, 8)}\u2026` : "\u2014";
23210
+ const memoryIndexLine = `- \`${FOUNDER_RECORD_PATH}\` \u2014 **Founder & install context**: ${founderName || "founder"} \xB7 advisor ${idxAdvisor} \xB7 sub ${idxSub}. (seeded from onboarding)`;
23211
+ return { founderMd, memoryIndexLine };
23212
+ }
23213
+ function founderRecordBodyEquals(a, b) {
23214
+ const strip = (s) => s.replace(/^(created|updated):.*$/gm, "").trim();
23215
+ return strip(a) === strip(b);
23216
+ }
23217
+
23218
+ // src/lib/founder-identity.ts
23219
+ function deriveEmailCandidate(raw) {
23220
+ const mail = (raw.mail ?? "").trim();
23221
+ if (mail) return mail;
23222
+ const upn = (raw.upn ?? "").trim();
23223
+ if (!upn) return "";
23224
+ const ext = upn.indexOf("#EXT#");
23225
+ if (ext > 0) {
23226
+ const local = upn.slice(0, ext);
23227
+ const at = local.lastIndexOf("_");
23228
+ return at > 0 ? `${local.slice(0, at)}@${local.slice(at + 1)}` : "";
23229
+ }
23230
+ return upn.includes("@") ? upn : "";
23231
+ }
23232
+ async function getSignedInUserIdentity(runAzImpl = runAz) {
23233
+ try {
23234
+ const raw = await runAzImpl([
23235
+ "ad",
23236
+ "signed-in-user",
23237
+ "show",
23238
+ "--query",
23239
+ "{displayName:displayName, mail:mail, upn:userPrincipalName}",
23240
+ "-o",
23241
+ "json"
23242
+ ]);
23243
+ const p = JSON.parse(raw);
23244
+ return { name: (p.displayName ?? "").trim(), email: deriveEmailCandidate({ mail: p.mail, upn: p.upn }) };
23245
+ } catch {
23246
+ return { name: "", email: "" };
23247
+ }
23248
+ }
23249
+ function composeFounderIdentityNote(id) {
23250
+ if (id.name && id.email) {
23251
+ 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.`;
23252
+ }
23253
+ if (id.name) {
23254
+ 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).`;
23255
+ }
23256
+ return `Ask the founder their name and the best contact email to reach them (that's where advisor handoffs and cost reports go).`;
23257
+ }
23123
23258
 
23124
23259
  // src/lib/company-profile-seed.ts
23125
23260
  function readGithubAppCreds(credsPath) {
@@ -23134,18 +23269,21 @@ async function resolveSeedContext(opts) {
23134
23269
  const appCreds = opts.appCredsOverride ?? readGithubAppCreds(opts.credsPath);
23135
23270
  if (!appCreds) return null;
23136
23271
  let endpoint = opts.endpointOverride;
23272
+ let subscriptionId = opts.subscriptionId;
23137
23273
  if (!endpoint) {
23138
23274
  const state = await readBootstrapState();
23139
23275
  if (!state) {
23140
23276
  throw new LocalCliError({ code: "BOOTSTRAP_NO_STATE", message: "No bootstrap state found.", hint: "Run 'm8t bootstrap launch' first, or pass --endpoint." });
23141
23277
  }
23278
+ subscriptionId ??= state.subscriptionId;
23142
23279
  const doc = await readStatusBlob({ saName: state.statusSaName, resourceGroup: state.resourceGroup, subscriptionId: state.subscriptionId });
23143
23280
  endpoint = doc.result?.foundryEndpoint;
23144
23281
  if (!endpoint) {
23145
23282
  throw new LocalCliError({ code: "SEED_NO_ENDPOINT", message: "Could not resolve the Foundry endpoint from the install status.", hint: "Pass --endpoint <foundryEndpoint>." });
23146
23283
  }
23147
23284
  }
23148
- return { endpoint, brainRepo: opts.brainOverride ?? `${appCreds.org}/stacey-brain`, appCreds };
23285
+ const brainRepos = opts.brainOverride ? [opts.brainOverride] : [`${appCreds.org}/stacey-brain`, `${appCreds.org}/azzy-brain`];
23286
+ return { endpoint, brainRepos, appCreds, subscriptionId };
23149
23287
  }
23150
23288
  async function applyProfileToBrain(args) {
23151
23289
  const token = await mintInstallationTokenFromPem({
@@ -23154,20 +23292,31 @@ async function applyProfileToBrain(args) {
23154
23292
  installationId: args.appCreds.installationId,
23155
23293
  fetchImpl: args.fetchImpl
23156
23294
  });
23157
- const { profileMd, memoryIndexLine } = renderCompanyProfile(args.block, args.now);
23158
- const existingProfile = await readRepoFileViaApp({ token, repo: args.brainRepo, path: COMPANY_PROFILE_PATH, fetchImpl: args.fetchImpl });
23159
- const existingIndex = await readRepoFileViaApp({ token, repo: args.brainRepo, path: "memory/MEMORY.md", fetchImpl: args.fetchImpl }) ?? DEFAULT_MEMORY_INDEX_HEADER;
23160
- const nextIndex = upsertMemoryIndex(existingIndex, memoryIndexLine);
23161
- if (existingProfile && companyProfileBodyEquals(existingProfile, profileMd) && nextIndex === existingIndex) {
23295
+ const { profileMd, memoryIndexLine: companyLine } = renderCompanyProfile(args.block, args.now);
23296
+ const { founderMd, memoryIndexLine: founderLine } = renderFounderRecord(
23297
+ args.block,
23298
+ { subscriptionId: args.subscriptionId, azIdentity: args.azIdentity },
23299
+ args.now
23300
+ );
23301
+ const read = (p) => readRepoFileViaApp({ token, repo: args.brainRepo, path: p, fetchImpl: args.fetchImpl });
23302
+ const existingProfile = await read(COMPANY_PROFILE_PATH);
23303
+ const existingFounder = await read(FOUNDER_RECORD_PATH);
23304
+ const existingIndex = await read("memory/MEMORY.md") ?? DEFAULT_MEMORY_INDEX_HEADER;
23305
+ let nextIndex = upsertMemoryIndex(existingIndex, companyLine, COMPANY_PROFILE_PATH);
23306
+ nextIndex = upsertMemoryIndex(nextIndex, founderLine, FOUNDER_RECORD_PATH);
23307
+ const profileSame = existingProfile != null && companyProfileBodyEquals(existingProfile, profileMd);
23308
+ const founderSame = existingFounder != null && founderRecordBodyEquals(existingFounder, founderMd);
23309
+ if (profileSame && founderSame && nextIndex === existingIndex) {
23162
23310
  return;
23163
23311
  }
23164
23312
  await commitFilesViaApp({
23165
23313
  token,
23166
23314
  repo: args.brainRepo,
23167
23315
  branch: args.branch,
23168
- message: "seed(brain): company profile from onboarding questionnaire",
23316
+ message: "seed(brain): founder + company profile from onboarding",
23169
23317
  files: [
23170
23318
  { path: COMPANY_PROFILE_PATH, content: profileMd },
23319
+ { path: FOUNDER_RECORD_PATH, content: founderMd },
23171
23320
  { path: "memory/MEMORY.md", content: nextIndex }
23172
23321
  ],
23173
23322
  fetchImpl: args.fetchImpl
@@ -23187,20 +23336,31 @@ function spawnDetachedSeedWatch() {
23187
23336
  }
23188
23337
  }
23189
23338
  async function reactiveSeedOnFinish(args) {
23190
- const ctx = await resolveSeedContext({ endpointOverride: args.endpoint, appCredsOverride: args.appCredsOverride });
23339
+ const ctx = await resolveSeedContext({ endpointOverride: args.endpoint, appCredsOverride: args.appCredsOverride, subscriptionId: args.subscriptionId });
23191
23340
  if (!ctx) return;
23192
23341
  const token = await (args.getFoundryTokenImpl ?? getFoundryToken)();
23193
23342
  const { hadIntake, block } = await findOnboardingProfile({ endpoint: ctx.endpoint, token, fetchImpl: args.fetchImpl });
23194
23343
  if (block) {
23195
- await applyProfileToBrain({ block, brainRepo: ctx.brainRepo, branch: "main", appCreds: ctx.appCreds, fetchImpl: args.fetchImpl });
23196
- args.stdout(`${colors.success("\u2713")} Clever Stacey now knows your company (seeded ${ctx.brainRepo}).
23344
+ const azIdentity = args.azIdentity ?? await (args.getSignedInUserIdentityImpl ?? getSignedInUserIdentity)();
23345
+ for (const brainRepo of ctx.brainRepos) {
23346
+ await applyProfileToBrain({
23347
+ block,
23348
+ brainRepo,
23349
+ branch: "main",
23350
+ appCreds: ctx.appCreds,
23351
+ subscriptionId: ctx.subscriptionId,
23352
+ azIdentity,
23353
+ fetchImpl: args.fetchImpl
23354
+ });
23355
+ }
23356
+ args.stdout(`${colors.success("\u2713")} Your advisors now know your company + how to reach you (seeded ${ctx.brainRepos.join(", ")}).
23197
23357
  `);
23198
23358
  return;
23199
23359
  }
23200
23360
  if (!hadIntake) return;
23201
23361
  (args.spawnWatch ?? spawnDetachedSeedWatch)();
23202
23362
  args.stdout(
23203
- `${colors.dim("\u2139 Stacey will pick up your company profile when you finish the questionnaire (watching in the background).")}
23363
+ `${colors.dim("\u2139 Your advisors will pick up your company profile when you finish the questionnaire (watching in the background).")}
23204
23364
  ${colors.hint("or run:")} m8t bootstrap seed-profile
23205
23365
  `
23206
23366
  );
@@ -23317,6 +23477,7 @@ ${colors.field("Then open a brand new chat/session")} \u2014 new skills + MCP se
23317
23477
  try {
23318
23478
  await reactiveSeedOnFinish({
23319
23479
  endpoint: doc.result?.foundryEndpoint,
23480
+ subscriptionId,
23320
23481
  stdout: (s) => this.context.stdout.write(s)
23321
23482
  });
23322
23483
  } catch (e) {
@@ -23563,7 +23724,8 @@ async function deploySimpleStacey(args) {
23563
23724
  endpoint: args.endpoint,
23564
23725
  repoRoot: args.repoRoot,
23565
23726
  persona: SIMPLE_STACEY_PERSONA,
23566
- agentName: SIMPLE_STACEY_AGENT
23727
+ agentName: SIMPLE_STACEY_AGENT,
23728
+ fieldOverrides: args.fieldOverrides
23567
23729
  });
23568
23730
  } catch (e) {
23569
23731
  if (e && typeof e === "object" && "code" in e) {
@@ -23681,7 +23843,13 @@ var BootstrapUiCommand = class extends M8tCommand {
23681
23843
  const oid = await getSignedInUserOid();
23682
23844
  await ensureFounderFoundryRole({ credential: credential2, subscriptionId: state.subscriptionId, principalId: oid, accountScope });
23683
23845
  out("deploying Simple Stacey (stacey-intake)\u2026");
23684
- const version = await deploySimpleStacey({ credential: credential2, endpoint, repoRoot });
23846
+ const identity = await getSignedInUserIdentity();
23847
+ const version = await deploySimpleStacey({
23848
+ credential: credential2,
23849
+ endpoint,
23850
+ repoRoot,
23851
+ fieldOverrides: { founder_identity_note: composeFounderIdentityNote(identity) }
23852
+ });
23685
23853
  const envPath = writeWebEnvLocal({
23686
23854
  repoRoot,
23687
23855
  tenantId: account.tenantId,
@@ -23734,8 +23902,8 @@ import { Command as Command51, Option as Option49 } from "clipanion";
23734
23902
  var BootstrapSeedProfileCommand = class extends M8tCommand {
23735
23903
  static paths = [["bootstrap", "seed-profile"]];
23736
23904
  static usage = Command51.Usage({
23737
- description: "Seed Clever Stacey's brain with the company profile from the onboarding questionnaire.",
23738
- details: "Reads the latest stacey-intake conversation, renders memory/company-profile.md (+ its MEMORY.md index line), and commits both to <org>/stacey-brain via the GitHub App. Idempotent. --watch polls until the founder completes the questionnaire.",
23905
+ description: "Seed your advisors' brains with the founder + company profile from the onboarding questionnaire.",
23906
+ 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.",
23739
23907
  examples: [
23740
23908
  ["Seed now (idempotent)", "$0 bootstrap seed-profile"],
23741
23909
  ["Wait for the founder to finish", "$0 bootstrap seed-profile --watch"]
@@ -23767,8 +23935,11 @@ var BootstrapSeedProfileCommand = class extends M8tCommand {
23767
23935
  const token = await getFoundryToken();
23768
23936
  const { hadIntake, block } = await findOnboardingProfile({ endpoint: ctx.endpoint, token });
23769
23937
  if (block) {
23770
- await applyProfileToBrain({ block, brainRepo: ctx.brainRepo, branch: "main", appCreds: ctx.appCreds });
23771
- this.context.stdout.write(`${colors.success("\u2713")} seeded Clever Stacey's brain (${ctx.brainRepo}) from your questionnaire.
23938
+ const azIdentity = await getSignedInUserIdentity();
23939
+ for (const brainRepo of ctx.brainRepos) {
23940
+ await applyProfileToBrain({ block, brainRepo, branch: "main", appCreds: ctx.appCreds, subscriptionId: ctx.subscriptionId, azIdentity });
23941
+ }
23942
+ this.context.stdout.write(`${colors.success("\u2713")} seeded your advisors' brains (${ctx.brainRepos.join(", ")}) from your questionnaire.
23772
23943
  `);
23773
23944
  return 0;
23774
23945
  }