@m8t-stack/cli 0.2.19 → 0.2.20

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
@@ -1227,7 +1227,7 @@ var init_enable_hosted_brain = __esm({
1227
1227
  import { Builtins, Cli } from "clipanion";
1228
1228
 
1229
1229
  // src/lib/package-version.ts
1230
- var CLI_VERSION = "0.2.19";
1230
+ var CLI_VERSION = "0.2.20";
1231
1231
 
1232
1232
  // src/lib/render-error.ts
1233
1233
  init_errors();
@@ -3326,12 +3326,12 @@ function encodeURIPath(str4) {
3326
3326
  return str4.replace(/[^A-Za-z0-9\-._~!$&'()*+,;=:@]+/g, encodeURIComponent);
3327
3327
  }
3328
3328
  var EMPTY = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.create(null));
3329
- var createPathTagFunction = (pathEncoder = encodeURIPath) => function path33(statics, ...params) {
3329
+ var createPathTagFunction = (pathEncoder = encodeURIPath) => function path37(statics, ...params) {
3330
3330
  if (statics.length === 1)
3331
3331
  return statics[0];
3332
3332
  let postPath = false;
3333
3333
  const invalidSegments = [];
3334
- const path34 = statics.reduce((previousValue, currentValue, index) => {
3334
+ const path38 = statics.reduce((previousValue, currentValue, index) => {
3335
3335
  if (/[?#]/.test(currentValue)) {
3336
3336
  postPath = true;
3337
3337
  }
@@ -3348,7 +3348,7 @@ var createPathTagFunction = (pathEncoder = encodeURIPath) => function path33(sta
3348
3348
  }
3349
3349
  return previousValue + currentValue + (index === params.length ? "" : encoded);
3350
3350
  }, "");
3351
- const pathOnly = path34.split(/[?#]/, 1)[0];
3351
+ const pathOnly = path38.split(/[?#]/, 1)[0];
3352
3352
  const invalidSegmentPattern = /(?<=^|\/)(?:\.|%2e){1,2}(?=\/|$)/gi;
3353
3353
  let match;
3354
3354
  while ((match = invalidSegmentPattern.exec(pathOnly)) !== null) {
@@ -3369,10 +3369,10 @@ var createPathTagFunction = (pathEncoder = encodeURIPath) => function path33(sta
3369
3369
  }, "");
3370
3370
  throw new OpenAIError(`Path parameters result in path with invalid segments:
3371
3371
  ${invalidSegments.map((e) => e.error).join("\n")}
3372
- ${path34}
3372
+ ${path38}
3373
3373
  ${underline}`);
3374
3374
  }
3375
- return path34;
3375
+ return path38;
3376
3376
  };
3377
3377
  var path = /* @__PURE__ */ createPathTagFunction(encodeURIPath);
3378
3378
 
@@ -10889,9 +10889,9 @@ var OpenAI = class {
10889
10889
  this.apiKey = token;
10890
10890
  return true;
10891
10891
  }
10892
- buildURL(path33, query, defaultBaseURL) {
10892
+ buildURL(path37, query, defaultBaseURL) {
10893
10893
  const baseURL = !__classPrivateFieldGet(this, _OpenAI_instances, "m", _OpenAI_baseURLOverridden).call(this) && defaultBaseURL || this.baseURL;
10894
- const url = isAbsoluteURL(path33) ? new URL(path33) : new URL(baseURL + (baseURL.endsWith("/") && path33.startsWith("/") ? path33.slice(1) : path33));
10894
+ const url = isAbsoluteURL(path37) ? new URL(path37) : new URL(baseURL + (baseURL.endsWith("/") && path37.startsWith("/") ? path37.slice(1) : path37));
10895
10895
  const defaultQuery = this.defaultQuery();
10896
10896
  const pathQuery = Object.fromEntries(url.searchParams);
10897
10897
  if (!isEmptyObj(defaultQuery) || !isEmptyObj(pathQuery)) {
@@ -10919,24 +10919,24 @@ var OpenAI = class {
10919
10919
  */
10920
10920
  async prepareRequest(request, { url, options }) {
10921
10921
  }
10922
- get(path33, opts) {
10923
- return this.methodRequest("get", path33, opts);
10922
+ get(path37, opts) {
10923
+ return this.methodRequest("get", path37, opts);
10924
10924
  }
10925
- post(path33, opts) {
10926
- return this.methodRequest("post", path33, opts);
10925
+ post(path37, opts) {
10926
+ return this.methodRequest("post", path37, opts);
10927
10927
  }
10928
- patch(path33, opts) {
10929
- return this.methodRequest("patch", path33, opts);
10928
+ patch(path37, opts) {
10929
+ return this.methodRequest("patch", path37, opts);
10930
10930
  }
10931
- put(path33, opts) {
10932
- return this.methodRequest("put", path33, opts);
10931
+ put(path37, opts) {
10932
+ return this.methodRequest("put", path37, opts);
10933
10933
  }
10934
- delete(path33, opts) {
10935
- return this.methodRequest("delete", path33, opts);
10934
+ delete(path37, opts) {
10935
+ return this.methodRequest("delete", path37, opts);
10936
10936
  }
10937
- methodRequest(method, path33, opts) {
10937
+ methodRequest(method, path37, opts) {
10938
10938
  return this.request(Promise.resolve(opts).then((opts2) => {
10939
- return { method, path: path33, ...opts2 };
10939
+ return { method, path: path37, ...opts2 };
10940
10940
  }));
10941
10941
  }
10942
10942
  request(options, remainingRetries = null) {
@@ -11058,8 +11058,8 @@ var OpenAI = class {
11058
11058
  }));
11059
11059
  return { response, options, controller, requestLogID, retryOfRequestLogID, startTime };
11060
11060
  }
11061
- getAPIList(path33, Page2, opts) {
11062
- return this.requestAPIList(Page2, opts && "then" in opts ? opts.then((opts2) => ({ method: "get", path: path33, ...opts2 })) : { method: "get", path: path33, ...opts });
11061
+ getAPIList(path37, Page2, opts) {
11062
+ return this.requestAPIList(Page2, opts && "then" in opts ? opts.then((opts2) => ({ method: "get", path: path37, ...opts2 })) : { method: "get", path: path37, ...opts });
11063
11063
  }
11064
11064
  requestAPIList(Page2, options) {
11065
11065
  const request = this.makeRequest(options, null, void 0);
@@ -11153,8 +11153,8 @@ var OpenAI = class {
11153
11153
  }
11154
11154
  async buildRequest(inputOptions, { retryCount = 0 } = {}) {
11155
11155
  const options = { ...inputOptions };
11156
- const { method, path: path33, query, defaultBaseURL } = options;
11157
- const url = this.buildURL(path33, query, defaultBaseURL);
11156
+ const { method, path: path37, query, defaultBaseURL } = options;
11157
+ const url = this.buildURL(path37, query, defaultBaseURL);
11158
11158
  if ("timeout" in options)
11159
11159
  validatePositiveInteger("timeout", options.timeout);
11160
11160
  options.timeout = options.timeout ?? this.timeout;
@@ -12156,10 +12156,10 @@ var BindListCommand = class extends M8tCommand {
12156
12156
  const qs = new URLSearchParams();
12157
12157
  if (this.channel) qs.set("channel", this.channel);
12158
12158
  if (this.status) qs.set("status", this.status);
12159
- const path33 = qs.toString().length > 0 ? `/api/bindings?${qs.toString()}` : "/api/bindings";
12159
+ const path37 = qs.toString().length > 0 ? `/api/bindings?${qs.toString()}` : "/api/bindings";
12160
12160
  const data = await apiCall(
12161
12161
  { gatewayUrl: ctx.gatewayUrl, gatewayClientId: ctx.gatewayClientId },
12162
- { method: "GET", path: path33 },
12162
+ { method: "GET", path: path37 },
12163
12163
  (msg) => this.context.stderr.write(msg + "\n")
12164
12164
  );
12165
12165
  if (mode === "json") {
@@ -13370,8 +13370,8 @@ ${r.stderr}`;
13370
13370
  message: `gh api /repos/${slug} failed (exit ${r.exitCode.toString()}): ${(r.stderr || r.stdout).slice(0, 200)}`
13371
13371
  });
13372
13372
  },
13373
- getFile: async (path33) => {
13374
- const r = await exec("gh", ["api", "-H", "Accept: application/vnd.github.raw+json", `/repos/${slug}/contents/${path33}`]);
13373
+ getFile: async (path37) => {
13374
+ const r = await exec("gh", ["api", "-H", "Accept: application/vnd.github.raw+json", `/repos/${slug}/contents/${path37}`]);
13375
13375
  return r.exitCode === 0 ? r.stdout : null;
13376
13376
  },
13377
13377
  isEmpty: async () => {
@@ -13615,11 +13615,11 @@ var BrainCheckAppCommand = class extends M8tCommand {
13615
13615
  // src/commands/brain/create.ts
13616
13616
  init_esm2();
13617
13617
  import { Command as Command18, Option as Option17 } from "clipanion";
13618
- import { spawnSync } from "child_process";
13618
+ import { execFileSync, spawnSync } from "child_process";
13619
13619
  import { readFileSync as readFileSync6 } from "fs";
13620
- import * as fs10 from "fs";
13620
+ import * as fs11 from "fs";
13621
13621
  import * as os4 from "os";
13622
- import * as path9 from "path";
13622
+ import * as path10 from "path";
13623
13623
  import * as readline2 from "readline/promises";
13624
13624
  import { DefaultAzureCredential as DefaultAzureCredential4 } from "@azure/identity";
13625
13625
  init_errors();
@@ -14135,11 +14135,66 @@ async function createBrainEnabledVersion(args) {
14135
14135
 
14136
14136
  // src/lib/brain-seed.ts
14137
14137
  init_errors();
14138
+ import * as fs10 from "fs";
14139
+ import * as path9 from "path";
14140
+
14141
+ // src/lib/seed-manifest.ts
14138
14142
  import * as fs9 from "fs";
14139
14143
  import * as path8 from "path";
14144
+ var SEED_MANIFEST_PATH = ".m8t/seed-manifest.json";
14145
+ var SEED_PATHS = ["skills", "references", "targets"];
14146
+ function isLineage(v) {
14147
+ if (!v || typeof v !== "object") return false;
14148
+ const l = v;
14149
+ return typeof l.name === "string" && typeof l.refreshedToCommit === "string" && typeof l.refreshedToVersion === "string" && Array.isArray(l.ownedPaths) && l.ownedPaths.every((p) => typeof p === "string");
14150
+ }
14151
+ function parseSeedManifest(text) {
14152
+ if (!text?.trim()) return null;
14153
+ let parsed;
14154
+ try {
14155
+ parsed = JSON.parse(text);
14156
+ } catch {
14157
+ return null;
14158
+ }
14159
+ if (!parsed || typeof parsed !== "object") return null;
14160
+ const m = parsed;
14161
+ if (m.schemaVersion !== 1 || !Array.isArray(m.seeds) || !m.seeds.every(isLineage)) return null;
14162
+ return { schemaVersion: 1, seeds: m.seeds };
14163
+ }
14164
+ function buildSeedManifest(seeds) {
14165
+ return { schemaVersion: 1, seeds };
14166
+ }
14167
+ function upsertLineage(manifest, lineage) {
14168
+ const prior = manifest?.seeds ?? [];
14169
+ const others = prior.filter((s) => s.name !== lineage.name);
14170
+ return { schemaVersion: 1, seeds: [...others, lineage].sort((a, b) => a.name.localeCompare(b.name)) };
14171
+ }
14172
+ function serializeSeedManifest(m) {
14173
+ return JSON.stringify(m, null, 2) + "\n";
14174
+ }
14175
+ function walkFiles(root, rel = "") {
14176
+ const abs = path8.join(root, rel);
14177
+ if (!fs9.existsSync(abs)) return [];
14178
+ const out = [];
14179
+ for (const entry of fs9.readdirSync(abs, { withFileTypes: true })) {
14180
+ const childRel = rel ? `${rel}/${entry.name}` : entry.name;
14181
+ if (entry.isDirectory()) out.push(...walkFiles(root, childRel));
14182
+ else if (entry.isFile()) out.push(childRel);
14183
+ }
14184
+ return out;
14185
+ }
14186
+ function deriveOwnedPaths(seedDir) {
14187
+ const owned = /* @__PURE__ */ new Set([SEED_MANIFEST_PATH]);
14188
+ for (const sub of SEED_PATHS) {
14189
+ for (const rel of walkFiles(path8.join(seedDir, sub))) owned.add(`${sub}/${rel}`);
14190
+ }
14191
+ return [...owned].sort((a, b) => a.localeCompare(b));
14192
+ }
14193
+
14194
+ // src/lib/brain-seed.ts
14140
14195
  function resolveSeed(name) {
14141
- const dir = path8.join(resolveRepoRoot(), "brain-seeds", name);
14142
- if (!fs9.existsSync(dir)) {
14196
+ const dir = path9.join(resolveRepoRoot(), "brain-seeds", name);
14197
+ if (!fs10.existsSync(dir)) {
14143
14198
  throw new LocalCliError({
14144
14199
  code: "SEED_NOT_FOUND",
14145
14200
  message: `--seed "${name}": no brain-seeds/${name}/ directory found.`,
@@ -14149,11 +14204,22 @@ function resolveSeed(name) {
14149
14204
  return dir;
14150
14205
  }
14151
14206
  function materializeBrainTree(opts) {
14152
- fs9.cpSync(opts.templateSrc, opts.destDir, { recursive: true });
14207
+ fs10.cpSync(opts.templateSrc, opts.destDir, { recursive: true });
14153
14208
  if (opts.seedDir) {
14154
- fs9.cpSync(opts.seedDir, opts.destDir, { recursive: true });
14209
+ fs10.cpSync(opts.seedDir, opts.destDir, { recursive: true });
14155
14210
  }
14156
14211
  }
14212
+ function writeSeedMarker(args) {
14213
+ const manifest = buildSeedManifest([{
14214
+ name: args.seedName,
14215
+ refreshedToCommit: args.refreshedToCommit,
14216
+ refreshedToVersion: args.version,
14217
+ ownedPaths: deriveOwnedPaths(args.seedDir)
14218
+ }]);
14219
+ const dest = path9.join(args.destDir, SEED_MANIFEST_PATH);
14220
+ fs10.mkdirSync(path9.dirname(dest), { recursive: true });
14221
+ fs10.writeFileSync(dest, serializeSeedManifest(manifest));
14222
+ }
14157
14223
 
14158
14224
  // src/lib/github-app-repo.ts
14159
14225
  init_errors();
@@ -14260,18 +14326,32 @@ async function mintInstallationTokenFromPem(args) {
14260
14326
  }
14261
14327
  async function readRepoFileViaApp(args) {
14262
14328
  const doFetch = args.fetchImpl ?? fetch;
14263
- const res = await doFetch(`${GH_API}/repos/${args.repo}/contents/${args.path}`, { headers: ghHeaders(args.token), signal: AbortSignal.timeout(GH_REQUEST_TIMEOUT_MS) });
14329
+ const q = args.ref ? `?ref=${encodeURIComponent(args.ref)}` : "";
14330
+ const res = await doFetch(`${GH_API}/repos/${args.repo}/contents/${args.path}${q}`, { headers: ghHeaders(args.token), signal: AbortSignal.timeout(GH_REQUEST_TIMEOUT_MS) });
14264
14331
  if (res.status === 404) return null;
14265
14332
  const text = await res.text();
14266
14333
  if (!res.ok) {
14267
14334
  throw new LocalCliError({
14268
14335
  code: "GH_APP_FILE_READ_FAILED",
14269
- message: `GET /repos/${args.repo}/contents/${args.path} HTTP ${res.status.toString()}: ${text.slice(0, 300)}`
14336
+ message: `GET /repos/${args.repo}/contents/${args.path}${q} HTTP ${res.status.toString()}: ${text.slice(0, 300)}`
14270
14337
  });
14271
14338
  }
14272
14339
  const data = JSON.parse(text);
14273
14340
  return Buffer.from(data.content ?? "", "base64").toString("utf8");
14274
14341
  }
14342
+ async function getInitialSeedCommitSha(args) {
14343
+ const doFetch = args.fetchImpl ?? fetch;
14344
+ const H = ghHeaders(args.token);
14345
+ const first = await doFetch(`${GH_API}/repos/${args.repo}/commits?per_page=1`, { headers: H, signal: AbortSignal.timeout(GH_REQUEST_TIMEOUT_MS) });
14346
+ if (!first.ok) return null;
14347
+ const link = first.headers.get("link");
14348
+ const lastUrl = /<([^>]+)>;\s*rel="last"/.exec(link ?? "")?.[1];
14349
+ const url = lastUrl ?? `${GH_API}/repos/${args.repo}/commits?per_page=1`;
14350
+ const res = await doFetch(url, { headers: H, signal: AbortSignal.timeout(GH_REQUEST_TIMEOUT_MS) });
14351
+ if (!res.ok) return null;
14352
+ const commits = JSON.parse(await res.text());
14353
+ return commits.length > 0 ? commits[commits.length - 1].sha ?? null : null;
14354
+ }
14275
14355
  async function commitFilesViaApp(args) {
14276
14356
  const doFetch = args.fetchImpl ?? fetch;
14277
14357
  const H = ghHeaders(args.token);
@@ -14289,19 +14369,68 @@ async function commitFilesViaApp(args) {
14289
14369
  const ref = await api(`/git/ref/heads/${args.branch}`);
14290
14370
  const baseCommitSha = ref.object.sha;
14291
14371
  const baseCommit = await api(`/git/commits/${baseCommitSha}`);
14292
- const blobs = await Promise.all(args.files.map((f) => api(`/git/blobs`, { method: "POST", body: JSON.stringify({ content: f.content, encoding: "utf-8" }) })));
14293
- const tree = await api(`/git/trees`, {
14372
+ const upserts = args.files.filter((f) => !("delete" in f));
14373
+ const blobs = await Promise.all(upserts.map((f) => api(`/git/blobs`, { method: "POST", body: JSON.stringify({ content: f.content, encoding: "utf-8" }) })));
14374
+ const tree = args.files.map((f) => "delete" in f ? { path: f.path, mode: "100644", type: "blob", sha: null } : { path: f.path, mode: "100644", type: "blob", sha: blobs[upserts.indexOf(f)].sha });
14375
+ const newTree = await api(`/git/trees`, { method: "POST", body: JSON.stringify({ base_tree: baseCommit.tree.sha, tree }) });
14376
+ const commit = await api(`/git/commits`, {
14294
14377
  method: "POST",
14295
- body: JSON.stringify({
14296
- base_tree: baseCommit.tree.sha,
14297
- tree: args.files.map((f, i) => ({ path: f.path, mode: "100644", type: "blob", sha: blobs[i].sha }))
14298
- })
14378
+ body: JSON.stringify({ message: args.message, tree: newTree.sha, parents: [baseCommitSha] })
14379
+ });
14380
+ await api(`/git/refs/heads/${args.branch}`, { method: "PATCH", body: JSON.stringify({ sha: commit.sha }) });
14381
+ }
14382
+ async function createBranchViaApp(args) {
14383
+ const doFetch = args.fetchImpl ?? fetch;
14384
+ const H = ghHeaders(args.token);
14385
+ const res = await doFetch(`${GH_API}/repos/${args.repo}/git/refs`, {
14386
+ method: "POST",
14387
+ headers: H,
14388
+ signal: AbortSignal.timeout(GH_REQUEST_TIMEOUT_MS),
14389
+ body: JSON.stringify({ ref: `refs/heads/${args.branch}`, sha: args.fromSha })
14390
+ });
14391
+ if (res.ok) return;
14392
+ if (res.status === 422) {
14393
+ const patch = await doFetch(`${GH_API}/repos/${args.repo}/git/refs/heads/${args.branch}`, {
14394
+ method: "PATCH",
14395
+ headers: H,
14396
+ signal: AbortSignal.timeout(GH_REQUEST_TIMEOUT_MS),
14397
+ body: JSON.stringify({ sha: args.fromSha, force: true })
14398
+ });
14399
+ if (patch.ok) return;
14400
+ throw new LocalCliError({
14401
+ code: "GH_APP_BRANCH_FAILED",
14402
+ message: `PATCH refs/heads/${args.branch} HTTP ${patch.status.toString()}: ${(await patch.text()).slice(0, 300)}`
14403
+ });
14404
+ }
14405
+ throw new LocalCliError({
14406
+ code: "GH_APP_BRANCH_FAILED",
14407
+ message: `POST /git/refs HTTP ${res.status.toString()}: ${(await res.text()).slice(0, 300)}`
14299
14408
  });
14409
+ }
14410
+ async function commitFilesFromBaseViaApp(args) {
14411
+ const doFetch = args.fetchImpl ?? fetch;
14412
+ const H = ghHeaders(args.token);
14413
+ const api = async (p, init) => {
14414
+ const res = await doFetch(`${GH_API}/repos/${args.repo}${p}`, init ? { ...init, headers: H, signal: AbortSignal.timeout(GH_REQUEST_TIMEOUT_MS) } : { headers: H, signal: AbortSignal.timeout(GH_REQUEST_TIMEOUT_MS) });
14415
+ const text = await res.text();
14416
+ if (!res.ok) {
14417
+ throw new LocalCliError({
14418
+ code: "GH_APP_COMMIT_FAILED",
14419
+ message: `${init?.method ?? "GET"} ${p} HTTP ${res.status.toString()}: ${text.slice(0, 300)}`
14420
+ });
14421
+ }
14422
+ return text ? JSON.parse(text) : {};
14423
+ };
14424
+ const baseCommit = await api(`/git/commits/${args.baseSha}`);
14425
+ const upserts = args.files.filter((f) => !("delete" in f));
14426
+ const blobs = await Promise.all(upserts.map((f) => api(`/git/blobs`, { method: "POST", body: JSON.stringify({ content: f.content, encoding: "utf-8" }) })));
14427
+ const tree = args.files.map((f) => "delete" in f ? { path: f.path, mode: "100644", type: "blob", sha: null } : { path: f.path, mode: "100644", type: "blob", sha: blobs[upserts.indexOf(f)].sha });
14428
+ const newTree = await api(`/git/trees`, { method: "POST", body: JSON.stringify({ base_tree: baseCommit.tree.sha, tree }) });
14300
14429
  const commit = await api(`/git/commits`, {
14301
14430
  method: "POST",
14302
- body: JSON.stringify({ message: args.message, tree: tree.sha, parents: [baseCommitSha] })
14431
+ body: JSON.stringify({ message: args.message, tree: newTree.sha, parents: [args.baseSha] })
14303
14432
  });
14304
- await api(`/git/refs/heads/${args.branch}`, { method: "PATCH", body: JSON.stringify({ sha: commit.sha }) });
14433
+ await createBranchViaApp({ token: args.token, repo: args.repo, branch: args.branch, fromSha: commit.sha, fetchImpl: args.fetchImpl });
14305
14434
  }
14306
14435
  async function probeRepoState(probe) {
14307
14436
  const status = await probe.repoStatus();
@@ -14325,13 +14454,66 @@ function appRepoProbe(args) {
14325
14454
  const res = await doFetch(`${GH_API}/repos/${args.repo}`, { headers: H, signal: AbortSignal.timeout(GH_REQUEST_TIMEOUT_MS) });
14326
14455
  return res.status;
14327
14456
  },
14328
- getFile: (path33) => readRepoFileViaApp({ token: args.token, repo: args.repo, path: path33, fetchImpl: args.fetchImpl }),
14457
+ getFile: (path37) => readRepoFileViaApp({ token: args.token, repo: args.repo, path: path37, fetchImpl: args.fetchImpl }),
14329
14458
  isEmpty: async () => {
14330
14459
  const res = await doFetch(`${GH_API}/repos/${args.repo}/contents`, { headers: H, signal: AbortSignal.timeout(GH_REQUEST_TIMEOUT_MS) });
14331
14460
  return res.status === 404;
14332
14461
  }
14333
14462
  };
14334
14463
  }
14464
+ async function openPullRequestViaApp(args) {
14465
+ const doFetch = args.fetchImpl ?? fetch;
14466
+ const res = await doFetch(`${GH_API}/repos/${args.repo}/pulls`, {
14467
+ method: "POST",
14468
+ headers: ghHeaders(args.token),
14469
+ signal: AbortSignal.timeout(GH_REQUEST_TIMEOUT_MS),
14470
+ body: JSON.stringify({ base: args.base, head: args.head, title: args.title, body: args.body })
14471
+ });
14472
+ const text = await res.text();
14473
+ if (!res.ok) throw new LocalCliError({ code: "GH_APP_PR_OPEN_FAILED", message: `POST /pulls HTTP ${res.status.toString()}: ${text.slice(0, 300)}` });
14474
+ const j = JSON.parse(text);
14475
+ return { number: j.number, htmlUrl: j.html_url };
14476
+ }
14477
+ async function findOpenPr(args) {
14478
+ const doFetch = args.fetchImpl ?? fetch;
14479
+ const owner = args.repo.split("/")[0];
14480
+ const res = await doFetch(`${GH_API}/repos/${args.repo}/pulls?state=open&head=${owner}:${args.head}`, { headers: ghHeaders(args.token), signal: AbortSignal.timeout(GH_REQUEST_TIMEOUT_MS) });
14481
+ if (!res.ok) return null;
14482
+ const list = JSON.parse(await res.text());
14483
+ return list.length > 0 ? { number: list[0].number, htmlUrl: list[0].html_url } : null;
14484
+ }
14485
+ async function updatePullRequestViaApp(args) {
14486
+ const doFetch = args.fetchImpl ?? fetch;
14487
+ const patch = {};
14488
+ if (args.title !== void 0) patch.title = args.title;
14489
+ if (args.body !== void 0) patch.body = args.body;
14490
+ const res = await doFetch(`${GH_API}/repos/${args.repo}/pulls/${args.number.toString()}`, {
14491
+ method: "PATCH",
14492
+ headers: ghHeaders(args.token),
14493
+ signal: AbortSignal.timeout(GH_REQUEST_TIMEOUT_MS),
14494
+ body: JSON.stringify(patch)
14495
+ });
14496
+ if (!res.ok) throw new LocalCliError({ code: "GH_APP_PR_UPDATE_FAILED", message: `PATCH /pulls/${args.number.toString()} HTTP ${res.status.toString()}: ${(await res.text()).slice(0, 300)}` });
14497
+ }
14498
+ async function closePullRequestViaApp(args) {
14499
+ const doFetch = args.fetchImpl ?? fetch;
14500
+ const H = ghHeaders(args.token);
14501
+ if (args.comment) {
14502
+ await doFetch(`${GH_API}/repos/${args.repo}/issues/${args.number.toString()}/comments`, {
14503
+ method: "POST",
14504
+ headers: H,
14505
+ signal: AbortSignal.timeout(GH_REQUEST_TIMEOUT_MS),
14506
+ body: JSON.stringify({ body: args.comment })
14507
+ });
14508
+ }
14509
+ const res = await doFetch(`${GH_API}/repos/${args.repo}/pulls/${args.number.toString()}`, {
14510
+ method: "PATCH",
14511
+ headers: H,
14512
+ signal: AbortSignal.timeout(GH_REQUEST_TIMEOUT_MS),
14513
+ body: JSON.stringify({ state: "closed" })
14514
+ });
14515
+ if (!res.ok) throw new LocalCliError({ code: "GH_APP_PR_CLOSE_FAILED", message: `PATCH /pulls/${args.number.toString()} HTTP ${res.status.toString()}: ${(await res.text()).slice(0, 300)}` });
14516
+ }
14335
14517
 
14336
14518
  // src/lib/brain-repo-collision.ts
14337
14519
  init_errors();
@@ -14513,15 +14695,15 @@ var BrainCreateCommand = class extends M8tCommand {
14513
14695
  agentEndpoint
14514
14696
  });
14515
14697
  const repoRoot = resolveRepoRoot();
14516
- const templateSrc = path9.join(repoRoot, "brain-template");
14517
- if (!fs10.existsSync(templateSrc)) {
14698
+ const templateSrc = path10.join(repoRoot, "brain-template");
14699
+ if (!fs11.existsSync(templateSrc)) {
14518
14700
  throw new LocalCliError({
14519
14701
  code: "TEMPLATE_MISSING",
14520
14702
  message: `brain-template/ missing at ${templateSrc}`,
14521
14703
  hint: "Ensure brain-template/ exists at the repo root (same level as apps/)."
14522
14704
  });
14523
14705
  }
14524
- const tmpDir = fs10.mkdtempSync(path9.join(os4.tmpdir(), `m8t-brain-create-${worker}-`));
14706
+ const tmpDir = fs11.mkdtempSync(path10.join(os4.tmpdir(), `m8t-brain-create-${worker}-`));
14525
14707
  let result;
14526
14708
  let resolvedInstallationId = null;
14527
14709
  const force = this.reuse === true ? "reuse" : this.newName === true ? "new" : void 0;
@@ -14558,6 +14740,10 @@ var BrainCreateCommand = class extends M8tCommand {
14558
14740
  try {
14559
14741
  if (needsPush) {
14560
14742
  materializeBrainTree({ templateSrc, destDir: tmpDir, seedDir });
14743
+ if (seedName && seedDir) {
14744
+ const headSha = execFileSync("git", ["rev-parse", "HEAD"], { cwd: repoRoot, encoding: "utf8" }).trim();
14745
+ writeSeedMarker({ destDir: tmpDir, seedName, seedDir, refreshedToCommit: headSha, version: "(scaffold)" });
14746
+ }
14561
14747
  this.context.stdout.write(
14562
14748
  seedName ? `${colors.dim("\u2192")} copied brain-template/ + overlaid seed ${colors.field(seedName)} to ${tmpDir}
14563
14749
  ` : `${colors.dim("\u2192")} copied brain-template/ to ${tmpDir}
@@ -14649,7 +14835,7 @@ var BrainCreateCommand = class extends M8tCommand {
14649
14835
  project
14650
14836
  });
14651
14837
  } finally {
14652
- fs10.rmSync(tmpDir, { recursive: true, force: true });
14838
+ fs11.rmSync(tmpDir, { recursive: true, force: true });
14653
14839
  }
14654
14840
  if (mode === "json") {
14655
14841
  this.context.stdout.write(
@@ -14986,9 +15172,9 @@ init_errors();
14986
15172
  // src/lib/brain-unlink.ts
14987
15173
  init_esm2();
14988
15174
  init_errors();
14989
- import * as fs11 from "fs";
15175
+ import * as fs12 from "fs";
14990
15176
  import * as os5 from "os";
14991
- import * as path10 from "path";
15177
+ import * as path11 from "path";
14992
15178
  init_foundry_agent_get();
14993
15179
  var FOUNDRY_ARM_API2 = "2025-04-01-preview";
14994
15180
  var FOUNDRY_DATA_SCOPE2 = "https://ai.azure.com/.default";
@@ -15019,15 +15205,15 @@ async function unlinkBrain(args) {
15019
15205
  if (yaml?.personaPath) {
15020
15206
  let personaPath = yaml.personaPath;
15021
15207
  if (!personaPath.startsWith("/")) {
15022
- const marker = path10.join(args.home ?? os5.homedir(), ".m8t-stack", "repo-root");
15023
- if (!fs11.existsSync(marker)) {
15208
+ const marker = path11.join(args.home ?? os5.homedir(), ".m8t-stack", "repo-root");
15209
+ if (!fs12.existsSync(marker)) {
15024
15210
  throw new LocalCliError({
15025
15211
  code: "PERSONA_PATH_NOT_ABSOLUTE",
15026
15212
  message: `personaPath '${personaPath}' is relative and the repo-root marker is missing.`,
15027
15213
  hint: "Re-run 'm8t install' from a fresh m8t-stack checkout (writes ~/.m8t-stack/repo-root) \u2014 or edit the personaPath to absolute."
15028
15214
  });
15029
15215
  }
15030
- personaPath = path10.join(fs11.readFileSync(marker, "utf8").trim(), personaPath);
15216
+ personaPath = path11.join(fs12.readFileSync(marker, "utf8").trim(), personaPath);
15031
15217
  }
15032
15218
  strippedInstructions = renderPersonaBody(personaPath, yaml.fillableFieldValues ?? {}, args.agentName);
15033
15219
  } else {
@@ -15267,27 +15453,27 @@ import { DefaultAzureCredential as DefaultAzureCredential9 } from "@azure/identi
15267
15453
  init_errors();
15268
15454
 
15269
15455
  // src/lib/deploy-prompt-advisor.ts
15270
- import * as fs12 from "fs";
15271
- import * as path11 from "path";
15456
+ import * as fs13 from "fs";
15457
+ import * as path12 from "path";
15272
15458
  import { parse as parseYaml6 } from "yaml";
15273
15459
  init_foundry_agents();
15274
15460
  init_errors();
15275
15461
  function findPersonasRoot(hint) {
15276
- let dir = path11.resolve(hint);
15277
- const fsRoot = path11.parse(dir).root;
15462
+ let dir = path12.resolve(hint);
15463
+ const fsRoot = path12.parse(dir).root;
15278
15464
  for (; ; ) {
15279
- if (fs12.existsSync(path11.join(dir, "personas"))) return dir;
15280
- const parent = path11.dirname(dir);
15465
+ if (fs13.existsSync(path12.join(dir, "personas"))) return dir;
15466
+ const parent = path12.dirname(dir);
15281
15467
  if (parent === dir || dir === fsRoot) return null;
15282
15468
  dir = parent;
15283
15469
  }
15284
15470
  }
15285
15471
  async function deployPromptAdvisor(args) {
15286
15472
  const resolvedRoot = findPersonasRoot(args.repoRoot);
15287
- const personaPath = resolvedRoot ? path11.join(resolvedRoot, "personas", args.persona, "persona.md") : path11.join(args.repoRoot, "personas", args.persona, "persona.md");
15473
+ const personaPath = resolvedRoot ? path12.join(resolvedRoot, "personas", args.persona, "persona.md") : path12.join(args.repoRoot, "personas", args.persona, "persona.md");
15288
15474
  let raw;
15289
15475
  try {
15290
- raw = fs12.readFileSync(personaPath, "utf8");
15476
+ raw = fs13.readFileSync(personaPath, "utf8");
15291
15477
  } catch (e) {
15292
15478
  throw new LocalCliError({
15293
15479
  code: "ADVISOR_PERSONA_MISSING",
@@ -15449,7 +15635,7 @@ init_errors();
15449
15635
  // src/lib/agent-remove.ts
15450
15636
  init_errors();
15451
15637
  init_foundry_agent_get();
15452
- import * as fs14 from "fs";
15638
+ import * as fs15 from "fs";
15453
15639
  import { spawnSync as spawnSync2 } from "child_process";
15454
15640
 
15455
15641
  // src/lib/a2a-enable.ts
@@ -15563,12 +15749,12 @@ async function awaitAgentQueryable(args) {
15563
15749
  // src/lib/persona-a2a.ts
15564
15750
  init_errors();
15565
15751
  init_esm();
15566
- import * as fs13 from "fs";
15752
+ import * as fs14 from "fs";
15567
15753
  import { parse as parseYaml7 } from "yaml";
15568
15754
  function readPersonaA2aCard(personaPath) {
15569
15755
  let raw;
15570
15756
  try {
15571
- raw = fs13.readFileSync(personaPath, "utf8");
15757
+ raw = fs14.readFileSync(personaPath, "utf8");
15572
15758
  } catch (e) {
15573
15759
  throw new LocalCliError({ code: "PERSONA_READ_FAILED", message: `Could not read persona '${personaPath}': ${e.message}` });
15574
15760
  }
@@ -15893,7 +16079,7 @@ function defaultRemoveAgentDeps(args) {
15893
16079
  },
15894
16080
  removeLocalYaml(agentName) {
15895
16081
  const p = agentYamlPath(agentName, home);
15896
- if (fs14.existsSync(p)) fs14.rmSync(p);
16082
+ if (fs15.existsSync(p)) fs15.rmSync(p);
15897
16083
  }
15898
16084
  };
15899
16085
  }
@@ -16035,16 +16221,16 @@ ${colors.success("\u2713")} removed ${colors.field(name)}.
16035
16221
  };
16036
16222
 
16037
16223
  // src/commands/a2a/enable.ts
16038
- import * as path13 from "path";
16224
+ import * as path14 from "path";
16039
16225
  import { Command as Command25, Option as Option24 } from "clipanion";
16040
16226
  import { DefaultAzureCredential as DefaultAzureCredential11 } from "@azure/identity";
16041
16227
  init_errors();
16042
16228
 
16043
16229
  // src/lib/bridge-url.ts
16044
16230
  init_errors();
16045
- import * as fs15 from "fs";
16231
+ import * as fs16 from "fs";
16046
16232
  import * as os6 from "os";
16047
- import * as path12 from "path";
16233
+ import * as path13 from "path";
16048
16234
  import { parse as parseYaml8 } from "yaml";
16049
16235
  var A2A_PATH = "/api/a2a/mcp";
16050
16236
  function resolveBridgeUrl(opts) {
@@ -16066,10 +16252,10 @@ function clean(v) {
16066
16252
  return t.length ? t : void 0;
16067
16253
  }
16068
16254
  function readConfigGatewayUrl(home) {
16069
- const cfg = path12.join(home ?? os6.homedir(), ".m8t-stack", "config.yaml");
16070
- if (!fs15.existsSync(cfg)) return void 0;
16255
+ const cfg = path13.join(home ?? os6.homedir(), ".m8t-stack", "config.yaml");
16256
+ if (!fs16.existsSync(cfg)) return void 0;
16071
16257
  try {
16072
- const o = parseYaml8(fs15.readFileSync(cfg, "utf8"));
16258
+ const o = parseYaml8(fs16.readFileSync(cfg, "utf8"));
16073
16259
  return typeof o.gatewayUrl === "string" ? o.gatewayUrl : void 0;
16074
16260
  } catch {
16075
16261
  return void 0;
@@ -16138,11 +16324,11 @@ var A2aEnableCommand = class extends M8tCommand {
16138
16324
  resolvePersonaPath() {
16139
16325
  if (typeof this.persona === "string" && this.persona.length > 0) {
16140
16326
  if (this.persona.includes("/") || this.persona.endsWith(".md")) return this.persona;
16141
- return path13.join(resolveRepoRoot(), "personas", this.persona, "persona.md");
16327
+ return path14.join(resolveRepoRoot(), "personas", this.persona, "persona.md");
16142
16328
  }
16143
16329
  const yaml = readAgentYaml(this.worker);
16144
16330
  if (yaml?.personaPath) {
16145
- return yaml.personaPath.startsWith("/") ? yaml.personaPath : path13.join(resolveRepoRoot(), yaml.personaPath);
16331
+ return yaml.personaPath.startsWith("/") ? yaml.personaPath : path14.join(resolveRepoRoot(), yaml.personaPath);
16146
16332
  }
16147
16333
  throw new LocalCliError({ code: "A2A_NO_PERSONA", message: `Could not resolve a persona for '${this.worker}'. Pass --persona <name>.` });
16148
16334
  }
@@ -16198,12 +16384,12 @@ import { Command as Command27 } from "clipanion";
16198
16384
 
16199
16385
  // src/lib/architect-version.ts
16200
16386
  import { createHash as createHash2 } from "crypto";
16201
- import * as fs16 from "fs";
16387
+ import * as fs17 from "fs";
16202
16388
  import * as os7 from "os";
16203
- import * as path14 from "path";
16389
+ import * as path15 from "path";
16204
16390
  function readVersionFrontmatter(file) {
16205
- if (!fs16.existsSync(file)) return "";
16206
- const text = fs16.readFileSync(file, "utf8");
16391
+ if (!fs17.existsSync(file)) return "";
16392
+ const text = fs17.readFileSync(file, "utf8");
16207
16393
  if (!text.startsWith("---")) return "";
16208
16394
  const closeIdx = text.indexOf("\n---", 3);
16209
16395
  if (closeIdx < 0) return "";
@@ -16212,23 +16398,23 @@ function readVersionFrontmatter(file) {
16212
16398
  return m ? m[1].trim() : "";
16213
16399
  }
16214
16400
  function sha256File(filePath) {
16215
- return createHash2("sha256").update(fs16.readFileSync(filePath)).digest("hex");
16401
+ return createHash2("sha256").update(fs17.readFileSync(filePath)).digest("hex");
16216
16402
  }
16217
16403
  function checkArchitectDrift() {
16218
- const sourcePath = path14.join(
16404
+ const sourcePath = path15.join(
16219
16405
  resolveRepoRoot(),
16220
16406
  "personas",
16221
16407
  "m8t-architect",
16222
16408
  "persona.md"
16223
16409
  );
16224
- const sidecarPath = path14.join(
16410
+ const sidecarPath = path15.join(
16225
16411
  os7.homedir(),
16226
16412
  ".claude",
16227
16413
  "skills",
16228
16414
  "m8t-architect",
16229
16415
  ".m8t-skill.json"
16230
16416
  );
16231
- if (!fs16.existsSync(sourcePath)) {
16417
+ if (!fs17.existsSync(sourcePath)) {
16232
16418
  return {
16233
16419
  match: false,
16234
16420
  sourceVersion: "",
@@ -16238,9 +16424,9 @@ function checkArchitectDrift() {
16238
16424
  }
16239
16425
  const sourceVersion = readVersionFrontmatter(sourcePath);
16240
16426
  let sidecar = null;
16241
- if (fs16.existsSync(sidecarPath)) {
16427
+ if (fs17.existsSync(sidecarPath)) {
16242
16428
  try {
16243
- const raw = JSON.parse(fs16.readFileSync(sidecarPath, "utf8"));
16429
+ const raw = JSON.parse(fs17.readFileSync(sidecarPath, "utf8"));
16244
16430
  if (raw !== null && typeof raw === "object") {
16245
16431
  const r = raw;
16246
16432
  sidecar = {
@@ -16303,7 +16489,7 @@ var ArchitectCheckCommand = class extends M8tCommand {
16303
16489
 
16304
16490
  // src/commands/coder/deploy.ts
16305
16491
  init_esm2();
16306
- import * as path16 from "path";
16492
+ import * as path17 from "path";
16307
16493
  import { Command as Command28, Option as Option26 } from "clipanion";
16308
16494
  import { DefaultAzureCredential as DefaultAzureCredential13 } from "@azure/identity";
16309
16495
  init_errors();
@@ -16570,14 +16756,14 @@ async function deployHostedWorker(args) {
16570
16756
  }
16571
16757
 
16572
16758
  // src/lib/persona.ts
16573
- import * as fs17 from "fs";
16574
- import * as path15 from "path";
16759
+ import * as fs18 from "fs";
16760
+ import * as path16 from "path";
16575
16761
  import { parse as parseYaml9 } from "yaml";
16576
16762
  function findRepoRoot(startDir) {
16577
- let dir = path15.resolve(startDir);
16763
+ let dir = path16.resolve(startDir);
16578
16764
  for (; ; ) {
16579
- if (fs17.existsSync(path15.join(dir, "personas"))) return dir;
16580
- const parent = path15.dirname(dir);
16765
+ if (fs18.existsSync(path16.join(dir, "personas"))) return dir;
16766
+ const parent = path16.dirname(dir);
16581
16767
  if (parent === dir) return null;
16582
16768
  dir = parent;
16583
16769
  }
@@ -16585,10 +16771,10 @@ function findRepoRoot(startDir) {
16585
16771
  function resolvePersona(persona, cwd = process.cwd()) {
16586
16772
  const root = findRepoRoot(cwd);
16587
16773
  if (!root) return { persona, personaVersion: null };
16588
- const file = path15.join(root, "personas", persona, "persona.md");
16774
+ const file = path16.join(root, "personas", persona, "persona.md");
16589
16775
  let raw;
16590
16776
  try {
16591
- raw = fs17.readFileSync(file, "utf-8");
16777
+ raw = fs18.readFileSync(file, "utf-8");
16592
16778
  } catch {
16593
16779
  return { persona, personaVersion: null };
16594
16780
  }
@@ -16925,7 +17111,7 @@ var CoderDeployCommand = class extends M8tCommand {
16925
17111
  projectEndpoint: project.endpoint,
16926
17112
  projectArmId: `${project.accountScope}/projects/${project.projectName}`,
16927
17113
  agentName: this.name,
16928
- personaPath: path16.join(resolveRepoRoot(), "personas", personaName, "persona.md"),
17114
+ personaPath: path17.join(resolveRepoRoot(), "personas", personaName, "persona.md"),
16929
17115
  bridgeUrl,
16930
17116
  onProgress
16931
17117
  });
@@ -17051,7 +17237,7 @@ var CoderTeardownCommand = class extends M8tCommand {
17051
17237
 
17052
17238
  // src/commands/azure-exec/deploy.ts
17053
17239
  init_esm2();
17054
- import * as path17 from "path";
17240
+ import * as path18 from "path";
17055
17241
  import { Command as Command30, Option as Option28 } from "clipanion";
17056
17242
  import { DefaultAzureCredential as DefaultAzureCredential15 } from "@azure/identity";
17057
17243
  init_errors();
@@ -17321,7 +17507,7 @@ var AzureExecDeployCommand = class extends M8tCommand {
17321
17507
  kvUri
17322
17508
  });
17323
17509
  onProgress?.("a2a-enabling as a target\u2026");
17324
- const personaPath = path17.join(resolveRepoRoot(), "personas", "azure-executor", "persona.md");
17510
+ const personaPath = path18.join(resolveRepoRoot(), "personas", "azure-executor", "persona.md");
17325
17511
  const bridgeUrl = resolveBridgeUrl({
17326
17512
  flag: typeof this.gatewayUrl === "string" ? this.gatewayUrl : void 0,
17327
17513
  env: processEnv
@@ -17463,8 +17649,8 @@ async function fetchPublicTags(repo, fetchImpl = fetch) {
17463
17649
  hint: "Pass a ghcr.io/<owner>/<name> repo, or use the BYOC private-ACR deploy flow."
17464
17650
  });
17465
17651
  }
17466
- const path33 = repo.replace(/^ghcr\.io\//, "");
17467
- const tokenRes = await fetchImpl(`https://ghcr.io/token?scope=repository:${path33}:pull`);
17652
+ const path37 = repo.replace(/^ghcr\.io\//, "");
17653
+ const tokenRes = await fetchImpl(`https://ghcr.io/token?scope=repository:${path37}:pull`);
17468
17654
  if (!tokenRes.ok) {
17469
17655
  throw new LocalCliError({
17470
17656
  code: "PLATFORM_GHCR_TOKEN_FAILED",
@@ -17480,7 +17666,7 @@ async function fetchPublicTags(repo, fetchImpl = fetch) {
17480
17666
  hint: "Make the package public (deploy/ghcr-package-visibility.md), then retry."
17481
17667
  });
17482
17668
  }
17483
- const tagsRes = await fetchImpl(`https://ghcr.io/v2/${path33}/tags/list`, {
17669
+ const tagsRes = await fetchImpl(`https://ghcr.io/v2/${path37}/tags/list`, {
17484
17670
  headers: { Authorization: `Bearer ${token}` }
17485
17671
  });
17486
17672
  if (!tagsRes.ok) {
@@ -17494,7 +17680,7 @@ async function fetchPublicTags(repo, fetchImpl = fetch) {
17494
17680
  }
17495
17681
 
17496
17682
  // src/lib/release-channel.ts
17497
- import * as fs18 from "fs";
17683
+ import * as fs19 from "fs";
17498
17684
 
17499
17685
  // ../../packages/platform-release/dist/esm/manifest.js
17500
17686
  var SEVERITIES = ["critical", "recommended", "optional"];
@@ -17661,7 +17847,7 @@ function manifestSourceForVersionTag(channelUrl, version) {
17661
17847
  return { url: custom };
17662
17848
  }
17663
17849
  async function fetchManifest(source, deps = {}) {
17664
- const readFile8 = deps.readFile ?? ((p) => fs18.readFileSync(p, "utf8"));
17850
+ const readFile8 = deps.readFile ?? ((p) => fs19.readFileSync(p, "utf8"));
17665
17851
  const fetchImpl = deps.fetchImpl ?? fetch;
17666
17852
  const ghToken = deps.ghToken ?? getGhToken;
17667
17853
  let raw;
@@ -17707,10 +17893,10 @@ async function fetchManifest(source, deps = {}) {
17707
17893
  }
17708
17894
 
17709
17895
  // src/lib/release-content.ts
17710
- import * as fs19 from "fs";
17896
+ import * as fs20 from "fs";
17711
17897
  import * as os8 from "os";
17712
- import * as path18 from "path";
17713
- import { execFileSync } from "child_process";
17898
+ import * as path19 from "path";
17899
+ import { execFileSync as execFileSync2 } from "child_process";
17714
17900
  init_errors();
17715
17901
  var OWNER_REPO = "m8t-run/m8t";
17716
17902
  function parseTreeResponse(body) {
@@ -17748,15 +17934,15 @@ function verifyPersonaTrees(manifest, tree) {
17748
17934
  }
17749
17935
  async function resolveReleaseContent(manifest, opts = {}) {
17750
17936
  if (opts.contentDir) {
17751
- if (!fs19.existsSync(path18.join(opts.contentDir, "personas"))) {
17937
+ if (!fs20.existsSync(path19.join(opts.contentDir, "personas"))) {
17752
17938
  throw new LocalCliError({ code: "PLATFORM_CONTENT_DIR_INVALID", message: `--content-dir '${opts.contentDir}' has no personas/ \u2014 not a repo checkout.` });
17753
17939
  }
17754
17940
  return opts.contentDir;
17755
17941
  }
17756
17942
  const commit = manifest.platform.commit;
17757
- const cacheRoot = opts.cacheRoot ?? path18.join(os8.homedir(), ".m8t-stack", "cache");
17758
- const dest = path18.join(cacheRoot, `release-${commit}`);
17759
- if (fs19.existsSync(path18.join(dest, "personas"))) return dest;
17943
+ const cacheRoot = opts.cacheRoot ?? path19.join(os8.homedir(), ".m8t-stack", "cache");
17944
+ const dest = path19.join(cacheRoot, `release-${commit}`);
17945
+ if (fs20.existsSync(path19.join(dest, "personas"))) return dest;
17760
17946
  const fetchImpl = opts.fetchImpl ?? fetch;
17761
17947
  const ghToken = opts.ghToken ?? getGhToken;
17762
17948
  let token;
@@ -17770,19 +17956,19 @@ async function resolveReleaseContent(manifest, opts = {}) {
17770
17956
  if (!res.ok) {
17771
17957
  throw new LocalCliError({ code: "PLATFORM_TARBALL_FETCH_FAILED", message: `GET ${url} \u2192 HTTP ${res.status.toString()}.` });
17772
17958
  }
17773
- fs19.mkdirSync(cacheRoot, { recursive: true });
17774
- const tmp = fs19.mkdtempSync(path18.join(cacheRoot, `.dl-${commit.slice(0, 8)}-`));
17959
+ fs20.mkdirSync(cacheRoot, { recursive: true });
17960
+ const tmp = fs20.mkdtempSync(path19.join(cacheRoot, `.dl-${commit.slice(0, 8)}-`));
17775
17961
  try {
17776
- const tgz = path18.join(tmp, "src.tar.gz");
17777
- fs19.writeFileSync(tgz, Buffer.from(await res.arrayBuffer()));
17778
- const unpacked = path18.join(tmp, "unpacked");
17779
- fs19.mkdirSync(unpacked);
17962
+ const tgz = path19.join(tmp, "src.tar.gz");
17963
+ fs20.writeFileSync(tgz, Buffer.from(await res.arrayBuffer()));
17964
+ const unpacked = path19.join(tmp, "unpacked");
17965
+ fs20.mkdirSync(unpacked);
17780
17966
  extractTarGz(tgz, unpacked);
17781
17967
  try {
17782
- fs19.renameSync(unpacked, dest);
17968
+ fs20.renameSync(unpacked, dest);
17783
17969
  } catch (e) {
17784
17970
  const err = e;
17785
- const isBenignRace = (err.code === "EEXIST" || err.code === "ENOTEMPTY") && fs19.existsSync(path18.join(dest, "personas"));
17971
+ const isBenignRace = (err.code === "EEXIST" || err.code === "ENOTEMPTY") && fs20.existsSync(path19.join(dest, "personas"));
17786
17972
  if (!isBenignRace) {
17787
17973
  throw new LocalCliError({
17788
17974
  code: "PLATFORM_CACHE_PUBLISH_FAILED",
@@ -17791,12 +17977,12 @@ async function resolveReleaseContent(manifest, opts = {}) {
17791
17977
  }
17792
17978
  }
17793
17979
  } finally {
17794
- fs19.rmSync(tmp, { recursive: true, force: true });
17980
+ fs20.rmSync(tmp, { recursive: true, force: true });
17795
17981
  }
17796
17982
  return dest;
17797
17983
  }
17798
17984
  function extractTarGz(tgz, into) {
17799
- execFileSync("tar", ["-xzf", tgz, "-C", into, "--strip-components=1"]);
17985
+ execFileSync2("tar", ["-xzf", tgz, "-C", into, "--strip-components=1"]);
17800
17986
  }
17801
17987
 
17802
17988
  // src/lib/platform-stamp.ts
@@ -17918,14 +18104,14 @@ function sleep2(ms) {
17918
18104
  }
17919
18105
 
17920
18106
  // src/lib/platform-converge.ts
17921
- import * as fs21 from "fs";
17922
- import * as path20 from "path";
18107
+ import * as fs22 from "fs";
18108
+ import * as path21 from "path";
17923
18109
  import { parse as parseYaml10 } from "yaml";
17924
18110
 
17925
18111
  // src/lib/deploy.ts
17926
- import * as fs20 from "fs/promises";
18112
+ import * as fs21 from "fs/promises";
17927
18113
  import * as os9 from "os";
17928
- import * as path19 from "path";
18114
+ import * as path20 from "path";
17929
18115
  init_errors();
17930
18116
  var FOUNDRY_TRACING_MODES = ["project", "account", "skip"];
17931
18117
  function parseFoundryTracingMode(v) {
@@ -17973,9 +18159,9 @@ function buildBicepParams(p) {
17973
18159
  return params;
17974
18160
  }
17975
18161
  async function resolveRepoRoot2(home = os9.homedir()) {
17976
- const marker = path19.join(home, ".m8t-stack", "repo-root");
18162
+ const marker = path20.join(home, ".m8t-stack", "repo-root");
17977
18163
  try {
17978
- const root = (await fs20.readFile(marker, "utf8")).trim();
18164
+ const root = (await fs21.readFile(marker, "utf8")).trim();
17979
18165
  if (!root) throw new Error("empty");
17980
18166
  return root;
17981
18167
  } catch {
@@ -18052,7 +18238,7 @@ function resolveAcrPullIdentity(opts) {
18052
18238
  return opts.explicit ?? "";
18053
18239
  }
18054
18240
  async function runBicepDeployment(opts) {
18055
- const bicepPath = path19.join(opts.repoRoot, "deploy", "main.bicep");
18241
+ const bicepPath = path20.join(opts.repoRoot, "deploy", "main.bicep");
18056
18242
  const result = JSON.parse(
18057
18243
  await runAz([
18058
18244
  "deployment",
@@ -18123,7 +18309,16 @@ function sortObj(o) {
18123
18309
  }
18124
18310
 
18125
18311
  // src/lib/platform-converge.ts
18126
- var ORDER = ["infra", "gateway", "codingAgent", "azureExecutor", "personas"];
18312
+ var ORDER = ["infra", "gateway", "codingAgent", "azureExecutor", "personas", "brainSeeds"];
18313
+ function seedSetRev(manifest) {
18314
+ const items = manifest.components.brainSeeds.items;
18315
+ const parts = [];
18316
+ for (const name of Object.keys(items).sort()) {
18317
+ const subs = items[name].subtrees;
18318
+ for (const sub of Object.keys(subs).sort()) parts.push(`${name}:${sub}:${subs[sub] ?? "-"}`);
18319
+ }
18320
+ return parts.join("|");
18321
+ }
18127
18322
  function infraTargetSha(manifest, tree) {
18128
18323
  return manifest.components.infra?.treeSha ?? tree.treeShaOf("deploy") ?? "";
18129
18324
  }
@@ -18159,6 +18354,16 @@ function diffPlan(manifest, stamp, tree, opts = {}) {
18159
18354
  }
18160
18355
  continue;
18161
18356
  }
18357
+ if (component === "brainSeeds") {
18358
+ const to = seedSetRev(manifest);
18359
+ const from2 = stamp?.components.brainSeeds?.seedRev ?? null;
18360
+ const targeted = opts.only === "brainSeeds";
18361
+ if (adopt) actions.push({ component, reason: "adopt", from: from2, to });
18362
+ else if (targeted) actions.push({ component, reason: from2 === to ? "forced" : "changed", from: from2, to });
18363
+ else if (from2 !== to) actions.push({ component, reason: "changed", from: from2, to });
18364
+ else skipped.push({ component, reason: "up-to-date" });
18365
+ continue;
18366
+ }
18162
18367
  const img = manifest.components[component];
18163
18368
  const cur = stamp?.components[component];
18164
18369
  if (cur?.state === "external") {
@@ -18202,6 +18407,7 @@ function installedValueOf(stamp, component, personaName) {
18202
18407
  if (!personaName || !Object.hasOwn(stamp.components.personas, personaName)) return "-";
18203
18408
  return stamp.components.personas[personaName].treeSha;
18204
18409
  }
18410
+ if (component === "brainSeeds") return stamp.components.brainSeeds?.seedRev ?? "-";
18205
18411
  return stamp.components[component].tag;
18206
18412
  }
18207
18413
  function targetValueOf(manifest, tree, component, personaName) {
@@ -18210,6 +18416,7 @@ function targetValueOf(manifest, tree, component, personaName) {
18210
18416
  if (!personaName || !Object.hasOwn(manifest.components.personas.items, personaName)) return "-";
18211
18417
  return manifest.components.personas.items[personaName].treeSha;
18212
18418
  }
18419
+ if (component === "brainSeeds") return seedSetRev(manifest) || "-";
18213
18420
  return manifest.components[component].tag;
18214
18421
  }
18215
18422
  async function applyPlan(plan, deps, ctx) {
@@ -18230,6 +18437,18 @@ async function applyPlan(plan, deps, ctx) {
18230
18437
  continue;
18231
18438
  }
18232
18439
  stamp.components[a.component] = { ...r, state: "managed" };
18440
+ } else if (a.component === "brainSeeds") {
18441
+ if (!deps.applySeedRefresh) {
18442
+ ctx.onProgress?.("brainSeeds: seed refresh is not supported by this driver (CLI-only in v1) \u2014 skipped.");
18443
+ continue;
18444
+ }
18445
+ const r = await deps.applySeedRefresh(a, ctx);
18446
+ ctx.onProgress?.(`brainSeeds: delivered to ${r.delivered.toString()} repo(s), ${r.noop.toString()} already current.`);
18447
+ if (!r.converged) {
18448
+ ctx.onProgress?.("brainSeeds: not fully delivered (no Key Vault, or some repos failed) \u2014 stamp NOT advanced; will retry next converge.");
18449
+ continue;
18450
+ }
18451
+ stamp.components.brainSeeds = { seedRev: a.to };
18233
18452
  } else {
18234
18453
  if (!a.personaName) {
18235
18454
  throw new LocalCliError({ code: "PLATFORM_PERSONA_NO_NAME", message: "persona action missing personaName" });
@@ -18282,7 +18501,14 @@ function seedStamp(prior, manifest, plan) {
18282
18501
  updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
18283
18502
  lastResult: "partial",
18284
18503
  cli: "",
18285
- components: { gateway: blankImg(), codingAgent: blankImg(), azureExecutor: blankImg(), personas: {}, infra: { treeSha: "" } }
18504
+ components: {
18505
+ gateway: blankImg(),
18506
+ codingAgent: blankImg(),
18507
+ azureExecutor: blankImg(),
18508
+ personas: {},
18509
+ infra: { treeSha: "" },
18510
+ brainSeeds: { seedRev: "" }
18511
+ }
18286
18512
  };
18287
18513
  }
18288
18514
  async function applyGatewayImage(a, ctx, gatewayResourceId) {
@@ -18376,7 +18602,7 @@ async function applyAgentImage(a, ctx, opts) {
18376
18602
  function declaredFillableFields(personaPath) {
18377
18603
  let raw;
18378
18604
  try {
18379
- raw = fs21.readFileSync(personaPath, "utf8");
18605
+ raw = fs22.readFileSync(personaPath, "utf8");
18380
18606
  } catch {
18381
18607
  return [];
18382
18608
  }
@@ -18402,7 +18628,7 @@ function injectAndRender(personaPath, values, agentName) {
18402
18628
  function loaderText(loaderPath) {
18403
18629
  if (!loaderPath) return null;
18404
18630
  try {
18405
- return fs21.readFileSync(loaderPath, "utf8");
18631
+ return fs22.readFileSync(loaderPath, "utf8");
18406
18632
  } catch {
18407
18633
  return null;
18408
18634
  }
@@ -18419,7 +18645,7 @@ function brainRepoOf(current) {
18419
18645
  }
18420
18646
  async function applyPersona(a, ctx, opts) {
18421
18647
  const current = await getAgentVersion({ credential: ctx.credential, projectEndpoint: opts.project.endpoint, agentName: opts.agentName });
18422
- const personaPath = path20.join(opts.personaDir, "persona.md");
18648
+ const personaPath = path21.join(opts.personaDir, "persona.md");
18423
18649
  const yamlValues = readAgentYaml(opts.agentName)?.fillableFieldValues ?? null;
18424
18650
  const values = resolveFillableValues(current, yamlValues);
18425
18651
  const declared = declaredFillableFields(personaPath);
@@ -18618,7 +18844,7 @@ import { confirm as confirm5 } from "@inquirer/prompts";
18618
18844
  import { DefaultAzureCredential as DefaultAzureCredential17 } from "@azure/identity";
18619
18845
 
18620
18846
  // src/lib/platform-converge-cli.ts
18621
- import * as path21 from "path";
18847
+ import * as path25 from "path";
18622
18848
 
18623
18849
  // src/lib/platform-infra-params.ts
18624
18850
  import { TableClient as TableClient2 } from "@azure/data-tables";
@@ -18673,6 +18899,356 @@ async function deriveSuffixVerified(opts) {
18673
18899
 
18674
18900
  // src/lib/platform-converge-cli.ts
18675
18901
  init_errors();
18902
+
18903
+ // src/lib/seed-refresh-driver.ts
18904
+ init_esm2();
18905
+ import * as path24 from "path";
18906
+
18907
+ // src/lib/seed-refresh.ts
18908
+ init_errors();
18909
+ import * as fs24 from "fs";
18910
+ import * as path23 from "path";
18911
+
18912
+ // src/lib/seed-merge.ts
18913
+ import * as fs23 from "fs";
18914
+ import * as os10 from "os";
18915
+ import * as path22 from "path";
18916
+ import { spawnSync as spawnSync3 } from "child_process";
18917
+ function isProbablyText(s) {
18918
+ return !s.includes("\0");
18919
+ }
18920
+ function mergeThreeWay(ours, base, theirs) {
18921
+ if (![ours, base, theirs].every(isProbablyText)) {
18922
+ return { ok: false, merged: "" };
18923
+ }
18924
+ const lf = (s) => s.replace(/\r\n/g, "\n");
18925
+ const dir = fs23.mkdtempSync(path22.join(os10.tmpdir(), "seed-merge-"));
18926
+ try {
18927
+ const o = path22.join(dir, "ours");
18928
+ const b = path22.join(dir, "base");
18929
+ const t = path22.join(dir, "theirs");
18930
+ fs23.writeFileSync(o, lf(ours));
18931
+ fs23.writeFileSync(b, lf(base));
18932
+ fs23.writeFileSync(t, lf(theirs));
18933
+ const res = spawnSync3(
18934
+ "git",
18935
+ ["merge-file", "-p", "--diff3", o, b, t],
18936
+ {
18937
+ encoding: "utf8",
18938
+ maxBuffer: 32 * 1024 * 1024
18939
+ }
18940
+ );
18941
+ if (res.status === 0) {
18942
+ return { ok: true, merged: res.stdout };
18943
+ }
18944
+ return { ok: false, merged: "" };
18945
+ } finally {
18946
+ fs23.rmSync(dir, { recursive: true, force: true });
18947
+ }
18948
+ }
18949
+ var skip = (path37, skipReason) => ({ path: path37, kind: "skip", skipReason });
18950
+ function classifyCandidate(c) {
18951
+ const { path: path37, base, ours, theirs } = c;
18952
+ if (theirs === base) return { path: path37, kind: "noop" };
18953
+ if (base === null) {
18954
+ if (theirs === null) return { path: path37, kind: "noop" };
18955
+ if (ours === null) return { path: path37, kind: "add", content: theirs };
18956
+ if (ours === theirs) return { path: path37, kind: "noop" };
18957
+ return skip(path37, "you already have a file at this path");
18958
+ }
18959
+ if (ours === null) {
18960
+ return theirs === null ? { path: path37, kind: "noop" } : skip(path37, "you removed this file; upstream changed it");
18961
+ }
18962
+ if (theirs === null) {
18963
+ return ours === base ? { path: path37, kind: "delete" } : skip(path37, "you edited this file; upstream removed it");
18964
+ }
18965
+ if (ours === base) return { path: path37, kind: "update", content: theirs };
18966
+ const m = mergeThreeWay(ours, base, theirs);
18967
+ return m.ok ? { path: path37, kind: "update", content: m.merged } : skip(path37, "your edits conflict with the update");
18968
+ }
18969
+
18970
+ // src/lib/seed-pr-body.ts
18971
+ function composeSeedPrTitle(s) {
18972
+ return `Update your ${s.advisorLabel}'s built-in skills & guides (${s.version})`;
18973
+ }
18974
+ var basename = (p) => p.split("/").filter(Boolean).slice(-2).join("/");
18975
+ function composeSeedPrBody(s) {
18976
+ const lines = [];
18977
+ lines.push(`This refreshes the skills and reference guides that came built into your ${s.advisorLabel}, bringing them up to date with platform release **${s.version}**.`);
18978
+ lines.push("");
18979
+ if (s.updated.length || s.added.length || s.deleted.length) {
18980
+ lines.push("**What changed**");
18981
+ if (s.updated.length) lines.push(`- \u270F\uFE0F Updated ${s.updated.length.toString()}: ${s.updated.map(basename).join(", ")}`);
18982
+ if (s.added.length) lines.push(`- \u2795 Added ${s.added.length.toString()}: ${s.added.map(basename).join(", ")}`);
18983
+ if (s.deleted.length) lines.push(`- \u{1F5D1}\uFE0F Removed ${s.deleted.length.toString()}: ${s.deleted.map(basename).join(", ")}`);
18984
+ lines.push("");
18985
+ }
18986
+ lines.push("**Your own content is untouched.** Only built-in files change here \u2014 nothing you or your advisor wrote (your memory, your inbox, skills your advisor learned on its own) is modified.");
18987
+ if (s.skipped.length) {
18988
+ lines.push("");
18989
+ lines.push(`**${s.skipped.length.toString()} file(s) were left as-is** because you've customized them and we won't overwrite your edits. To take an update anyway, open that file in the latest release and copy the changes over by hand:`);
18990
+ for (const sk of s.skipped) lines.push(`- \`${sk.path}\` \u2014 ${sk.skipReason}`);
18991
+ }
18992
+ lines.push("");
18993
+ lines.push("Your advisor's review workflow will check this PR automatically. Merge whenever you're ready.");
18994
+ lines.push("");
18995
+ lines.push(`\u2014 Opened by the m8t platform \xB7 release ${s.version}${s.notesUrl ? ` \xB7 [release notes](${s.notesUrl})` : ""}`);
18996
+ return lines.join("\n");
18997
+ }
18998
+
18999
+ // src/lib/seed-refresh.ts
19000
+ function readIf(dir, rel) {
19001
+ if (!dir) return null;
19002
+ const abs = path23.join(dir, rel);
19003
+ return fs24.existsSync(abs) ? fs24.readFileSync(abs, "utf8") : null;
19004
+ }
19005
+ async function assembleCandidates(args) {
19006
+ const paths = /* @__PURE__ */ new Set([...args.lineage?.ownedPaths ?? [], ...args.trees.ownedAtTheirs]);
19007
+ const out = [];
19008
+ for (const p of [...paths].sort((a, b) => a.localeCompare(b))) {
19009
+ out.push({ path: p, base: readIf(args.trees.baseDir, p), theirs: readIf(args.trees.theirsDir, p), ours: await args.source.readOurs(p) });
19010
+ }
19011
+ return out;
19012
+ }
19013
+ function assertNoDanglingIndexRefs(finalPaths, repoHas, indexBodies) {
19014
+ const refRe = /skills\/[^)\s]+\/SKILL\.md/g;
19015
+ for (const idx of indexBodies) {
19016
+ for (const m of idx.body.matchAll(refRe)) {
19017
+ const ref = m[0];
19018
+ if (!finalPaths.has(ref) && !repoHas(ref)) {
19019
+ throw new LocalCliError({
19020
+ code: "PLATFORM_SEED_INDEX_DANGLING",
19021
+ message: `Refusing to open a PR: ${idx.path} would reference a missing skill '${ref}'. The brain loader only opens indexed paths.`
19022
+ });
19023
+ }
19024
+ }
19025
+ }
19026
+ }
19027
+ async function refreshBrainRepo(args) {
19028
+ const cands = await assembleCandidates({ lineage: args.lineage, trees: args.trees, source: args.source, seedName: args.seedName });
19029
+ const outcomes = cands.map(classifyCandidate);
19030
+ const files = [];
19031
+ const updated = [];
19032
+ const added = [];
19033
+ const deleted = [];
19034
+ const skipped = [];
19035
+ const indexBodies = [];
19036
+ const finalPaths = /* @__PURE__ */ new Set();
19037
+ for (const o of outcomes) {
19038
+ if (o.path === SEED_MANIFEST_PATH) continue;
19039
+ if (o.kind === "update") {
19040
+ files.push({ path: o.path, content: o.content ?? "" });
19041
+ updated.push(o.path);
19042
+ finalPaths.add(o.path);
19043
+ } else if (o.kind === "add") {
19044
+ files.push({ path: o.path, content: o.content ?? "" });
19045
+ added.push(o.path);
19046
+ finalPaths.add(o.path);
19047
+ } else if (o.kind === "delete") {
19048
+ files.push({ path: o.path, delete: true });
19049
+ deleted.push(o.path);
19050
+ } else if (o.kind === "skip") {
19051
+ skipped.push({ path: o.path, skipReason: o.skipReason ?? "left as-is" });
19052
+ }
19053
+ if (o.path.endsWith("/_index.md") && (o.kind === "update" || o.kind === "add")) {
19054
+ indexBodies.push({ path: o.path, body: o.content ?? "" });
19055
+ }
19056
+ }
19057
+ const contentChanged = updated.length + added.length + deleted.length > 0;
19058
+ if (!contentChanged) {
19059
+ return { repo: args.repo, prUrl: null, action: "noop", updated, added, deleted, skipped };
19060
+ }
19061
+ const ownedNow = new Set(args.trees.ownedAtTheirs);
19062
+ assertNoDanglingIndexRefs(finalPaths, (p) => ownedNow.has(p), indexBodies);
19063
+ const newOwned = deriveOwnedPaths(args.trees.theirsDir);
19064
+ const nextManifest = upsertLineage(
19065
+ args.priorManifest ?? (args.lineage ? { schemaVersion: 1, seeds: [args.lineage] } : null),
19066
+ {
19067
+ name: args.seedName,
19068
+ refreshedToCommit: args.targetCommit ?? "",
19069
+ refreshedToVersion: args.version,
19070
+ ownedPaths: newOwned
19071
+ }
19072
+ );
19073
+ files.push({ path: SEED_MANIFEST_PATH, content: serializeSeedManifest(nextManifest) });
19074
+ for (const sb of args.supersedeBranches ?? []) {
19075
+ if (sb === args.branch) continue;
19076
+ const stale = await args.api.findOpenPr(sb);
19077
+ if (stale) await args.api.closePr(stale.number, `superseded by the newer update on \`${args.branch}\`.`);
19078
+ }
19079
+ const opened = await args.api.findOpenPr(args.branch);
19080
+ const headSha = await args.api.getHeadSha(args.base);
19081
+ await args.api.commitFromBase(files, args.branch, headSha, `chore(seed): refresh built-in skills & guides (${args.version})`);
19082
+ const summary = {
19083
+ advisorLabel: args.advisorLabel,
19084
+ version: args.version,
19085
+ notesUrl: args.notesUrl,
19086
+ repo: args.repo,
19087
+ updated,
19088
+ added,
19089
+ deleted,
19090
+ skipped
19091
+ };
19092
+ const title = composeSeedPrTitle(summary);
19093
+ const body = composeSeedPrBody(summary);
19094
+ if (opened) {
19095
+ await args.api.updatePr(opened.number, title, body);
19096
+ return { repo: args.repo, prUrl: opened.htmlUrl, action: "updated", updated, added, deleted, skipped };
19097
+ }
19098
+ const pr = await args.api.openPr(args.branch, args.base, title, body);
19099
+ return { repo: args.repo, prUrl: pr.htmlUrl, action: args.lineage ? "opened" : "bootstrapped", updated, added, deleted, skipped };
19100
+ }
19101
+
19102
+ // src/lib/seed-refresh-driver.ts
19103
+ var PERSONA_SEED_MAP = {
19104
+ "startup-advisor": "startup-advisor",
19105
+ "azure-advisor": "azure-advisor"
19106
+ };
19107
+ var ADVISOR_LABEL = {
19108
+ "startup-advisor": "Startup Advisor",
19109
+ "azure-advisor": "Azure Advisor"
19110
+ };
19111
+ function dedupeBrainRepos(agents) {
19112
+ const byRepo = /* @__PURE__ */ new Map();
19113
+ for (const a of agents) {
19114
+ const raw = a.metadata.brain;
19115
+ if (!raw) continue;
19116
+ let repo;
19117
+ let installationId;
19118
+ try {
19119
+ const parsed = JSON.parse(raw);
19120
+ repo = parsed.repo;
19121
+ installationId = parsed.installationId;
19122
+ } catch {
19123
+ repo = void 0;
19124
+ installationId = void 0;
19125
+ }
19126
+ if (!repo || !installationId) continue;
19127
+ const seedName = a.metadata.persona ? PERSONA_SEED_MAP[a.metadata.persona] ?? null : null;
19128
+ if (!byRepo.has(repo)) byRepo.set(repo, { repo, seedName, installationId });
19129
+ }
19130
+ return [...byRepo.values()];
19131
+ }
19132
+ function seedContentDir(contentRoot, manifest, seedName) {
19133
+ const items = manifest.components.brainSeeds.items;
19134
+ if (!Object.hasOwn(items, seedName)) return null;
19135
+ return path24.join(contentRoot, items[seedName].path);
19136
+ }
19137
+ function bindRepoApi(token, repo) {
19138
+ return {
19139
+ getDefaultBranch: () => Promise.resolve("main"),
19140
+ getHeadSha: async (branch) => {
19141
+ const res = await fetch(`https://api.github.com/repos/${repo}/git/ref/heads/${branch}`, {
19142
+ headers: { Authorization: `token ${token}`, Accept: "application/vnd.github+json", "User-Agent": "m8t" }
19143
+ });
19144
+ const j = await res.json();
19145
+ return j.object?.sha ?? "";
19146
+ },
19147
+ findOpenPr: (head) => findOpenPr({ token, repo, head }),
19148
+ commitFromBase: (files, branch, baseSha, message) => commitFilesFromBaseViaApp({ token, repo, branch, baseSha, files, message }),
19149
+ openPr: (head, base, title, body) => openPullRequestViaApp({ token, repo, base, head, title, body }),
19150
+ updatePr: (n, title, body) => updatePullRequestViaApp({ token, repo, number: n, title, body }),
19151
+ closePr: (n, comment) => closePullRequestViaApp({ token, repo, number: n, comment }),
19152
+ readFileAtRef: (path37, ref) => readRepoFileViaApp({ token, repo, path: path37, ref })
19153
+ };
19154
+ }
19155
+ async function runSeedRefresh(args) {
19156
+ const targetCommit = args.manifest.platform.commit;
19157
+ const theirsRoot = await resolveReleaseContent(args.manifest, {});
19158
+ const repos = dedupeBrainRepos(args.agents);
19159
+ const results = [];
19160
+ let delivered = 0;
19161
+ let noop2 = 0;
19162
+ let failed = 0;
19163
+ for (const ref of repos) {
19164
+ try {
19165
+ const minted = await mintInstallationToken({
19166
+ credential: args.credential,
19167
+ kvUri: args.kvUri,
19168
+ installationId: ref.installationId,
19169
+ repository: ref.repo,
19170
+ permissions: { contents: "write", pull_requests: "write" }
19171
+ });
19172
+ const token = minted.token;
19173
+ const probe = appRepoProbe({ token, repo: ref.repo });
19174
+ const state = await probeRepoState(probe);
19175
+ if (state !== "m8t-brain") {
19176
+ args.onWarn?.(`${ref.repo}: not a reachable m8t brain (${state}) \u2014 skipped.`);
19177
+ continue;
19178
+ }
19179
+ const markerText = await readRepoFileViaApp({ token, repo: ref.repo, path: SEED_MANIFEST_PATH });
19180
+ const marker = parseSeedManifest(markerText);
19181
+ const seedName = ref.seedName ?? marker?.seeds[0]?.name ?? null;
19182
+ if (!seedName) {
19183
+ args.onWarn?.(`${ref.repo}: cannot determine seed lineage \u2014 skipped.`);
19184
+ continue;
19185
+ }
19186
+ const theirsDir = seedContentDir(theirsRoot, args.manifest, seedName);
19187
+ if (!theirsDir) {
19188
+ args.onWarn?.(`${ref.repo}: seed '${seedName}' is not in this release \u2014 skipped.`);
19189
+ continue;
19190
+ }
19191
+ const advisorLabel = ADVISOR_LABEL[seedName] ?? seedName;
19192
+ let lineage = marker?.seeds.find((s) => s.name === seedName) ?? null;
19193
+ let baseDir = null;
19194
+ if (lineage) {
19195
+ try {
19196
+ const baseRoot = await resolveReleaseContent(
19197
+ { ...args.manifest, platform: { ...args.manifest.platform, commit: lineage.refreshedToCommit } },
19198
+ {}
19199
+ );
19200
+ baseDir = seedContentDir(baseRoot, args.manifest, seedName);
19201
+ } catch {
19202
+ baseDir = null;
19203
+ args.onWarn?.(`${ref.repo}: base rev ${lineage.refreshedToCommit} unfetchable \u2014 falling back to marker-only re-adopt.`);
19204
+ lineage = null;
19205
+ }
19206
+ } else {
19207
+ const initSha = await getInitialSeedCommitSha({ token, repo: ref.repo });
19208
+ if (initSha) {
19209
+ try {
19210
+ const baseRoot = await resolveReleaseContent(
19211
+ { ...args.manifest, platform: { ...args.manifest.platform, commit: initSha } },
19212
+ {}
19213
+ );
19214
+ baseDir = seedContentDir(baseRoot, args.manifest, seedName);
19215
+ lineage = baseDir ? { name: seedName, refreshedToCommit: initSha, refreshedToVersion: "(bootstrap)", ownedPaths: deriveOwnedPaths(baseDir) } : null;
19216
+ } catch {
19217
+ baseDir = null;
19218
+ }
19219
+ }
19220
+ }
19221
+ const trees = { baseDir, theirsDir, ownedAtTheirs: deriveOwnedPaths(theirsDir) };
19222
+ const source = { readOurs: (p) => readRepoFileViaApp({ token, repo: ref.repo, path: p }) };
19223
+ const res = await refreshBrainRepo({
19224
+ repo: ref.repo,
19225
+ branch: `m8t/seed-update-${args.version}`,
19226
+ base: "main",
19227
+ version: args.version,
19228
+ notesUrl: args.manifest.platform.notesUrl,
19229
+ advisorLabel,
19230
+ seedName,
19231
+ lineage,
19232
+ trees,
19233
+ source,
19234
+ api: bindRepoApi(token, ref.repo),
19235
+ targetCommit,
19236
+ priorManifest: marker
19237
+ });
19238
+ results.push(res);
19239
+ if (res.action === "noop") noop2++;
19240
+ else delivered++;
19241
+ args.onProgress?.(`${ref.repo}: ${res.action}${res.prUrl ? ` \u2192 ${res.prUrl}` : ""}`);
19242
+ } catch (e) {
19243
+ failed++;
19244
+ args.onWarn?.(`${ref.repo}: seed refresh failed \u2014 ${e.message}; skipped this repo.`);
19245
+ continue;
19246
+ }
19247
+ }
19248
+ return { delivered, noop: noop2, failed, results };
19249
+ }
19250
+
19251
+ // src/lib/platform-converge-cli.ts
18676
19252
  var HOSTED_AGENT_PERSONA_DIR = {
18677
19253
  codingAgent: "coding-agent",
18678
19254
  azureExecutor: "azure-executor"
@@ -18686,7 +19262,7 @@ async function buildConvergeDeps(args) {
18686
19262
  const persona = a.metadata.persona;
18687
19263
  if (persona) discovered[persona] = a.name;
18688
19264
  }
18689
- const loaderPath = path21.join(args.contentDir, "targets/foundry/brain-loader.md");
19265
+ const loaderPath = path25.join(args.contentDir, "targets/foundry/brain-loader.md");
18690
19266
  return {
18691
19267
  async applyPersona(a, ctx) {
18692
19268
  const personaName = a.personaName;
@@ -18702,7 +19278,7 @@ async function buildConvergeDeps(args) {
18702
19278
  return applyPersona(a, ctx, {
18703
19279
  agentName,
18704
19280
  project: args.project,
18705
- personaDir: path21.join(ctx.contentDir, personaItem.path),
19281
+ personaDir: path25.join(ctx.contentDir, personaItem.path),
18706
19282
  loaderPath
18707
19283
  });
18708
19284
  },
@@ -18804,6 +19380,31 @@ async function buildConvergeDeps(args) {
18804
19380
  },
18805
19381
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
18806
19382
  });
19383
+ },
19384
+ async applySeedRefresh(_a3, ctx) {
19385
+ let kvUri;
19386
+ try {
19387
+ kvUri = discoverKvUri(process.env);
19388
+ } catch {
19389
+ kvUri = void 0;
19390
+ }
19391
+ if (!kvUri) {
19392
+ warn("brainSeeds: no Key Vault URI (set AZURE_KEYVAULT_URI) \u2014 skipping seed refresh.");
19393
+ return { delivered: 0, noop: 0, converged: false };
19394
+ }
19395
+ const { delivered, noop: noop2, failed } = await runSeedRefresh({
19396
+ credential: args.credential,
19397
+ kvUri,
19398
+ manifest: ctx.manifest,
19399
+ agents: discoveredAgents,
19400
+ version: ctx.manifest.platform.version,
19401
+ onProgress: args.onProgress,
19402
+ onWarn: args.onWarn
19403
+ });
19404
+ if (failed > 0) {
19405
+ warn(`brainSeeds: ${failed.toString()} repo(s) failed to receive a seed update \u2014 re-run 'm8t platform update --only brainSeeds' to retry.`);
19406
+ }
19407
+ return { delivered, noop: noop2, converged: failed === 0 };
18807
19408
  }
18808
19409
  };
18809
19410
  }
@@ -18843,7 +19444,7 @@ var PlatformUpdateCommand = class extends M8tCommand {
18843
19444
  description: "Pin the platform version to converge to (defaults to the current release channel)."
18844
19445
  });
18845
19446
  only = Option30.String("--only", {
18846
- description: "Converge only one component: infra | gateway | codingAgent | azureExecutor | personas."
19447
+ description: "Converge only one component: infra | gateway | codingAgent | azureExecutor | personas | brainSeeds."
18847
19448
  });
18848
19449
  check = Option30.Boolean("--check", false);
18849
19450
  yes = Option30.Boolean("--yes", false);
@@ -19057,15 +19658,15 @@ async function patchApplyRequest(client, mutate) {
19057
19658
  }
19058
19659
 
19059
19660
  // src/lib/platform-self-update.ts
19060
- import * as fs22 from "fs";
19061
- import * as path22 from "path";
19661
+ import * as fs25 from "fs";
19662
+ import * as path26 from "path";
19062
19663
  function toVTag2(v) {
19063
19664
  return v.startsWith("v") ? v : `v${v}`;
19064
19665
  }
19065
19666
  function readBakedReleaseVersion(repoRoot) {
19066
19667
  if (!repoRoot) return null;
19067
19668
  try {
19068
- const raw = fs22.readFileSync(path22.join(repoRoot, "installer", "version.json"), "utf8");
19669
+ const raw = fs25.readFileSync(path26.join(repoRoot, "installer", "version.json"), "utf8");
19069
19670
  const v = JSON.parse(raw).version;
19070
19671
  return typeof v === "string" && v.length > 0 ? v : null;
19071
19672
  } catch {
@@ -20020,7 +20621,7 @@ async function patchRedirectUris(appObjectId, fqdn) {
20020
20621
  init_errors();
20021
20622
 
20022
20623
  // src/lib/whatif.ts
20023
- import * as path23 from "path";
20624
+ import * as path27 from "path";
20024
20625
  function deriveResourceType(resourceId) {
20025
20626
  if (resourceId.startsWith("[")) return "";
20026
20627
  const afterProviders = resourceId.split("/providers/")[1];
@@ -20031,7 +20632,7 @@ function deriveResourceType(resourceId) {
20031
20632
  return parts.join("/");
20032
20633
  }
20033
20634
  async function runWhatIf(opts) {
20034
- const bicepPath = path23.join(opts.repoRoot, "deploy", "main.bicep");
20635
+ const bicepPath = path27.join(opts.repoRoot, "deploy", "main.bicep");
20035
20636
  const out = await runAz([
20036
20637
  "deployment",
20037
20638
  "group",
@@ -20096,9 +20697,9 @@ function flattenDelta(delta, prefix = "") {
20096
20697
  const out = [];
20097
20698
  for (const d of delta) {
20098
20699
  const segment = /^[0-9]+$/.test(d.path) ? `[${d.path}]` : prefix ? `.${d.path}` : d.path;
20099
- const path33 = prefix ? `${prefix}${segment}` : d.path;
20100
- if (d.children && d.children.length > 0) out.push(...flattenDelta(d.children, path33));
20101
- else out.push({ ...d, path: path33 });
20700
+ const path37 = prefix ? `${prefix}${segment}` : d.path;
20701
+ if (d.children && d.children.length > 0) out.push(...flattenDelta(d.children, path37));
20702
+ else out.push({ ...d, path: path37 });
20102
20703
  }
20103
20704
  return out;
20104
20705
  }
@@ -20320,7 +20921,7 @@ var DeployCommand = class extends M8tCommand {
20320
20921
  };
20321
20922
 
20322
20923
  // src/commands/eval/skill.ts
20323
- import { spawnSync as spawnSync3 } from "child_process";
20924
+ import { spawnSync as spawnSync4 } from "child_process";
20324
20925
  import { Command as Command37, Option as Option34 } from "clipanion";
20325
20926
  init_errors();
20326
20927
  var DECISIONS = /* @__PURE__ */ new Set(["promote", "reject", "needs_review"]);
@@ -20372,7 +20973,7 @@ var EvalSkillCommand = class extends M8tCommand {
20372
20973
  const args = ["skill", candidate2, "--skills-dir", skillsDir, "--json"];
20373
20974
  if (this.noJudge === true) args.push("--no-judge");
20374
20975
  if (typeof this.deployment === "string") args.push("--deployment", this.deployment);
20375
- const res = spawnSync3(bin, args, { encoding: "utf-8" });
20976
+ const res = spawnSync4(bin, args, { encoding: "utf-8" });
20376
20977
  if (res.error) {
20377
20978
  throw new LocalCliError({
20378
20979
  code: "BRAIN_EVAL_SPAWN",
@@ -20409,9 +21010,9 @@ var EvalSkillCommand = class extends M8tCommand {
20409
21010
  };
20410
21011
 
20411
21012
  // src/commands/eval/exam.ts
20412
- import { spawnSync as spawnSync4 } from "child_process";
20413
- import { writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync16, existsSync as existsSync13, readdirSync } from "fs";
20414
- import { join as join23 } from "path";
21013
+ import { spawnSync as spawnSync5 } from "child_process";
21014
+ import { writeFileSync as writeFileSync6, mkdirSync as mkdirSync5, readFileSync as readFileSync17, existsSync as existsSync15, readdirSync as readdirSync2 } from "fs";
21015
+ import { join as join27 } from "path";
20415
21016
  import { Command as Command38, Option as Option35 } from "clipanion";
20416
21017
  init_errors();
20417
21018
  init_esm();
@@ -20593,11 +21194,11 @@ function resolveRefereeHome(refereeHomeOut, env) {
20593
21194
  return null;
20594
21195
  }
20595
21196
  function resolveTaskSetDir(base, worker, version) {
20596
- if (existsSync13(join23(base, version))) return version;
21197
+ if (existsSync15(join27(base, version))) return version;
20597
21198
  const prefixed = `${worker}-${version}`;
20598
- if (existsSync13(join23(base, prefixed))) return prefixed;
20599
- if (version === "latest" && existsSync13(base)) {
20600
- const dirs = readdirSync(base, { withFileTypes: true }).filter((d) => d.isDirectory() && d.name.startsWith(`${worker}-`)).map((d) => d.name).sort();
21199
+ if (existsSync15(join27(base, prefixed))) return prefixed;
21200
+ if (version === "latest" && existsSync15(base)) {
21201
+ const dirs = readdirSync2(base, { withFileTypes: true }).filter((d) => d.isDirectory() && d.name.startsWith(`${worker}-`)).map((d) => d.name).sort();
20601
21202
  if (dirs.length > 0) return dirs[dirs.length - 1];
20602
21203
  }
20603
21204
  return version;
@@ -20611,11 +21212,11 @@ function readSealedTaskIds(taskSetVersion, refereeHomeOut, env = process.env) {
20611
21212
  message: "cannot resolve the referee home to read the sealed-task manifest \u2014 set $REFEREE_HOME (mirroring the Python runner) so the feed can be redacted; refusing to emit a possibly-unredacted feed (Law-1)"
20612
21213
  });
20613
21214
  }
20614
- const versionDir = resolveTaskSetDir(join23(home, "tasksets", worker), worker, version);
20615
- const manifestPath = join23(home, "tasksets", worker, versionDir, "manifest.yaml");
21215
+ const versionDir = resolveTaskSetDir(join27(home, "tasksets", worker), worker, version);
21216
+ const manifestPath = join27(home, "tasksets", worker, versionDir, "manifest.yaml");
20616
21217
  let text;
20617
21218
  try {
20618
- text = readFileSync16(manifestPath, "utf-8");
21219
+ text = readFileSync17(manifestPath, "utf-8");
20619
21220
  } catch (e) {
20620
21221
  throw new LocalCliError({
20621
21222
  code: "EXAM_REDACTION_UNSAFE",
@@ -20722,7 +21323,7 @@ var EvalExamCommand = class extends M8tCommand {
20722
21323
  return 0;
20723
21324
  }
20724
21325
  const bin = process.env.BRAIN_EXAM_BIN ?? "brain-exam";
20725
- const res = spawnSync4(bin, ["run", "--plan", "-", "--json"], { encoding: "utf-8", input: renderJson(plan) });
21326
+ const res = spawnSync5(bin, ["run", "--plan", "-", "--json"], { encoding: "utf-8", input: renderJson(plan) });
20726
21327
  if (res.error) {
20727
21328
  throw new LocalCliError({
20728
21329
  code: "EXAM_SPAWN",
@@ -20735,10 +21336,10 @@ var EvalExamCommand = class extends M8tCommand {
20735
21336
  const verdict = parseExamVerdict(res.stdout);
20736
21337
  if (out !== void 0) {
20737
21338
  const sealedTaskIds = taskSetVersion ? readSealedTaskIds(taskSetVersion, out) : /* @__PURE__ */ new Set();
20738
- mkdirSync4(out, { recursive: true });
20739
- writeFileSync4(join23(out, "verdict.json"), JSON.stringify(verdict, null, 2));
21339
+ mkdirSync5(out, { recursive: true });
21340
+ writeFileSync6(join27(out, "verdict.json"), JSON.stringify(verdict, null, 2));
20740
21341
  const feed = redactForFeed(verdict, sealedTaskIds);
20741
- writeFileSync4(join23(out, "feed.json"), JSON.stringify(feed, null, 2));
21342
+ writeFileSync6(join27(out, "feed.json"), JSON.stringify(feed, null, 2));
20742
21343
  }
20743
21344
  if (mode === "json") {
20744
21345
  this.context.stdout.write(renderJson(verdict) + "\n");
@@ -21001,9 +21602,9 @@ var StatusCommand = class extends M8tCommand {
21001
21602
  // src/commands/doctor.ts
21002
21603
  import { Command as Command42, Option as Option39 } from "clipanion";
21003
21604
  import { DefaultAzureCredential as DefaultAzureCredential19 } from "@azure/identity";
21004
- import * as fs23 from "fs";
21005
- import * as os10 from "os";
21006
- import * as path24 from "path";
21605
+ import * as fs26 from "fs";
21606
+ import * as os11 from "os";
21607
+ import * as path28 from "path";
21007
21608
 
21008
21609
  // src/lib/doctor-checks.ts
21009
21610
  function checkAzSignedIn(az) {
@@ -21228,24 +21829,24 @@ async function resolveAccountLocation(accountId) {
21228
21829
  }
21229
21830
  }
21230
21831
  function probeRepoRoot() {
21231
- const marker = path24.join(os10.homedir(), ".m8t-stack", "repo-root");
21232
- if (!fs23.existsSync(marker)) {
21832
+ const marker = path28.join(os11.homedir(), ".m8t-stack", "repo-root");
21833
+ if (!fs26.existsSync(marker)) {
21233
21834
  return { markerExists: false, path: null, isDir: false, isGitCheckout: false };
21234
21835
  }
21235
21836
  let repoPath;
21236
21837
  try {
21237
- repoPath = fs23.readFileSync(marker, "utf8").trim();
21838
+ repoPath = fs26.readFileSync(marker, "utf8").trim();
21238
21839
  } catch {
21239
21840
  return { markerExists: true, path: null, isDir: false, isGitCheckout: false };
21240
21841
  }
21241
21842
  if (!repoPath) return { markerExists: true, path: null, isDir: false, isGitCheckout: false };
21242
21843
  let isDir = false;
21243
21844
  try {
21244
- isDir = fs23.statSync(repoPath).isDirectory();
21845
+ isDir = fs26.statSync(repoPath).isDirectory();
21245
21846
  } catch {
21246
21847
  isDir = false;
21247
21848
  }
21248
- const isGitCheckout = isDir && fs23.existsSync(path24.join(repoPath, ".git"));
21849
+ const isGitCheckout = isDir && fs26.existsSync(path28.join(repoPath, ".git"));
21249
21850
  return { markerExists: true, path: repoPath, isDir, isGitCheckout };
21250
21851
  }
21251
21852
  var DoctorCommand = class extends M8tCommand {
@@ -21374,15 +21975,15 @@ var DoctorCommand = class extends M8tCommand {
21374
21975
  import { Command as Command43, Option as Option40 } from "clipanion";
21375
21976
 
21376
21977
  // src/lib/profiles.ts
21377
- import * as fs24 from "fs/promises";
21378
- import * as path25 from "path";
21978
+ import * as fs27 from "fs/promises";
21979
+ import * as path29 from "path";
21379
21980
  import { parse as parseYaml11, stringify as stringifyYaml4 } from "yaml";
21380
21981
  function profilesDir() {
21381
21982
  const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
21382
- return path25.join(home, ".m8t-stack", "profiles");
21983
+ return path29.join(home, ".m8t-stack", "profiles");
21383
21984
  }
21384
21985
  function getProfilePath(name) {
21385
- return path25.join(profilesDir(), `${path25.basename(name)}.yaml`);
21986
+ return path29.join(profilesDir(), `${path29.basename(name)}.yaml`);
21386
21987
  }
21387
21988
  function slugifyTenant(domainOrId) {
21388
21989
  const base = domainOrId.split(".")[0].toLowerCase();
@@ -21391,7 +21992,7 @@ function slugifyTenant(domainOrId) {
21391
21992
  }
21392
21993
  async function listProfiles() {
21393
21994
  try {
21394
- const entries = await fs24.readdir(profilesDir());
21995
+ const entries = await fs27.readdir(profilesDir());
21395
21996
  return entries.filter((e) => e.endsWith(".yaml")).map((e) => e.replace(/\.yaml$/, "")).sort();
21396
21997
  } catch (e) {
21397
21998
  if (e.code === "ENOENT") return [];
@@ -21400,7 +22001,7 @@ async function listProfiles() {
21400
22001
  }
21401
22002
  async function readProfile(name) {
21402
22003
  try {
21403
- const raw = await fs24.readFile(getProfilePath(name), "utf8");
22004
+ const raw = await fs27.readFile(getProfilePath(name), "utf8");
21404
22005
  const parsed = parseYaml11(raw);
21405
22006
  if (!parsed || typeof parsed !== "object") return null;
21406
22007
  return parsed;
@@ -21411,14 +22012,14 @@ async function readProfile(name) {
21411
22012
  }
21412
22013
  async function exists(p) {
21413
22014
  try {
21414
- await fs24.stat(p);
22015
+ await fs27.stat(p);
21415
22016
  return true;
21416
22017
  } catch {
21417
22018
  return false;
21418
22019
  }
21419
22020
  }
21420
22021
  async function saveProfile(p) {
21421
- await fs24.mkdir(profilesDir(), { recursive: true });
22022
+ await fs27.mkdir(profilesDir(), { recursive: true });
21422
22023
  let name = p.name;
21423
22024
  let n = 2;
21424
22025
  while (await exists(getProfilePath(name))) {
@@ -21427,8 +22028,8 @@ async function saveProfile(p) {
21427
22028
  }
21428
22029
  const target = getProfilePath(name);
21429
22030
  const tmp = `${target}.tmp`;
21430
- await fs24.writeFile(tmp, stringifyYaml4({ ...p, name }, { indent: 2 }), "utf8");
21431
- await fs24.rename(tmp, target);
22031
+ await fs27.writeFile(tmp, stringifyYaml4({ ...p, name }, { indent: 2 }), "utf8");
22032
+ await fs27.rename(tmp, target);
21432
22033
  return name;
21433
22034
  }
21434
22035
 
@@ -21814,6 +22415,8 @@ function odataFilter(worker, f) {
21814
22415
  parts.unshift(`PartitionKey eq '${esc2(worker)}'`);
21815
22416
  if (f.source !== "all")
21816
22417
  parts.push(`source eq '${esc2(f.source)}'`);
22418
+ if (f.foundryConversationId)
22419
+ parts.push(`foundryConversationId eq '${esc2(f.foundryConversationId)}'`);
21817
22420
  return parts.join(" and ");
21818
22421
  }
21819
22422
  async function fetchLedgerRows(filters, client) {
@@ -22597,7 +23200,7 @@ function buildAdvancePlan(worker, cursor, physicalPks, consumedRowsByPk, failedT
22597
23200
  // ../../packages/brain/engine/dist/esm/dream/writer.js
22598
23201
  var API2 = "https://api.github.com";
22599
23202
  var WRITER_ALLOWED_PREFIX = /^(memory|inbox|quarantine|artifacts)\//;
22600
- var isAllowedWritePath = (path33, allowedPrefix) => allowedPrefix.test(path33) && !path33.split("/").includes("..");
23203
+ var isAllowedWritePath = (path37, allowedPrefix) => allowedPrefix.test(path37) && !path37.split("/").includes("..");
22601
23204
  var unquote = (s) => s.trim().replace(/^["']|["']$/g, "");
22602
23205
  function parseFrontmatter(content) {
22603
23206
  const m = /^---\n([\s\S]*?)\n---/.exec(content);
@@ -22640,8 +23243,8 @@ function makeGitDataWriter(args) {
22640
23243
  if (args.allowedPathPrefix && !args.allowedPathPrefix.source.startsWith("^")) {
22641
23244
  throw new Error(`makeGitDataWriter: allowedPathPrefix must be anchored with "^" (got /${args.allowedPathPrefix.source}/) \u2014 an unanchored regex would widen the B1 write-path allowlist`);
22642
23245
  }
22643
- async function gh(token, method, path33, body) {
22644
- const res = await doFetch(`${API2}/repos/${repoPath}${path33}`, {
23246
+ async function gh(token, method, path37, body) {
23247
+ const res = await doFetch(`${API2}/repos/${repoPath}${path37}`, {
22645
23248
  method,
22646
23249
  headers: {
22647
23250
  Authorization: `Bearer ${token}`,
@@ -22654,8 +23257,8 @@ function makeGitDataWriter(args) {
22654
23257
  const text = await res.text();
22655
23258
  return { status: res.status, ok: res.ok, json: text ? JSON.parse(text) : {} };
22656
23259
  }
22657
- async function readFileWith(token, path33) {
22658
- const encodedPath = path33.split("/").map(encodeURIComponent).join("/");
23260
+ async function readFileWith(token, path37) {
23261
+ const encodedPath = path37.split("/").map(encodeURIComponent).join("/");
22659
23262
  const r = await gh(token, "GET", `/contents/${encodedPath}?ref=${args.branch}`);
22660
23263
  if (r.status === 404)
22661
23264
  return null;
@@ -22671,9 +23274,9 @@ function makeGitDataWriter(args) {
22671
23274
  throw new Error(`fetchTip: HTTP ${String(r.status)}`);
22672
23275
  return r.json.object.sha;
22673
23276
  },
22674
- async readFile(path33) {
23277
+ async readFile(path37) {
22675
23278
  const token = await args.mintToken();
22676
- return readFileWith(token, path33);
23279
+ return readFileWith(token, path37);
22677
23280
  },
22678
23281
  async listMemory() {
22679
23282
  const token = await args.mintToken();
@@ -22682,9 +23285,9 @@ function makeGitDataWriter(args) {
22682
23285
  return [];
22683
23286
  const paths = r.json.tree.filter((e) => e.type === "blob" && e.path.startsWith("memory/") && e.path.endsWith(".md")).map((e) => e.path);
22684
23287
  const out = [];
22685
- for (const path33 of paths) {
22686
- const content = await readFileWith(token, path33);
22687
- out.push({ path: path33, frontmatter: content ? parseFrontmatter(content) : {} });
23288
+ for (const path37 of paths) {
23289
+ const content = await readFileWith(token, path37);
23290
+ out.push({ path: path37, frontmatter: content ? parseFrontmatter(content) : {} });
22688
23291
  }
22689
23292
  return out;
22690
23293
  },
@@ -23123,7 +23726,7 @@ async function loadMemoryContext(brain) {
23123
23726
  return {
23124
23727
  files,
23125
23728
  indexEntries,
23126
- originOf: (path33) => originByPath.get(path33) ?? "worker"
23729
+ originOf: (path37) => originByPath.get(path37) ?? "worker"
23127
23730
  };
23128
23731
  }
23129
23732
 
@@ -23144,14 +23747,14 @@ function checkEvidenceMembership(delta, harvested) {
23144
23747
  }
23145
23748
  var BatchAbort = class extends Error {
23146
23749
  path;
23147
- constructor(path33, message) {
23750
+ constructor(path37, message) {
23148
23751
  super(message);
23149
- this.path = path33;
23752
+ this.path = path37;
23150
23753
  this.name = "BatchAbort";
23151
23754
  }
23152
23755
  };
23153
- var isIndexFile = (path33) => /(^|\/)[^/]*_index\.md$/.test(path33);
23154
- var isMemoryIndex = (path33) => path33 === "memory/MEMORY.md";
23756
+ var isIndexFile = (path37) => /(^|\/)[^/]*_index\.md$/.test(path37);
23757
+ var isMemoryIndex = (path37) => path37 === "memory/MEMORY.md";
23155
23758
  function targetPath(delta) {
23156
23759
  switch (delta.verb) {
23157
23760
  case "new":
@@ -23168,29 +23771,29 @@ function targetPath(delta) {
23168
23771
  }
23169
23772
  async function checkOriginTier(delta, lookup) {
23170
23773
  const evidence = evidenceOf(delta) ?? [];
23171
- const path33 = targetPath(delta);
23172
- if (path33 === null)
23774
+ const path37 = targetPath(delta);
23775
+ if (path37 === null)
23173
23776
  return { ok: true };
23174
- if (isIndexFile(path33) && !isMemoryIndex(path33)) {
23175
- return { ok: false, flagged: { kind: "flagged", path: path33, tension: `refused: ${path33} is an index file (only memory/MEMORY.md is editable)`, evidence } };
23777
+ if (isIndexFile(path37) && !isMemoryIndex(path37)) {
23778
+ return { ok: false, flagged: { kind: "flagged", path: path37, tension: `refused: ${path37} is an index file (only memory/MEMORY.md is editable)`, evidence } };
23176
23779
  }
23177
- const target = await lookup(path33);
23178
- const isStructural = path33.startsWith("references/");
23780
+ const target = await lookup(path37);
23781
+ const isStructural = path37.startsWith("references/");
23179
23782
  const origin = target?.frontmatter.origin ?? (isStructural ? "operator" : "worker");
23180
23783
  const editable = origin === "worker" || origin === "dream";
23181
23784
  if (editable)
23182
23785
  return { ok: true };
23183
23786
  const removesOperatorTarget = delta.verb === "retract" || delta.verb === "supersede" && delta.oldPath !== delta.newPath;
23184
23787
  if (removesOperatorTarget) {
23185
- throw new BatchAbort(path33, `supersede/retract OLD target ${path33} is origin: ${origin} \u2014 aborting batch (never half-apply)`);
23788
+ throw new BatchAbort(path37, `supersede/retract OLD target ${path37} is origin: ${origin} \u2014 aborting batch (never half-apply)`);
23186
23789
  }
23187
- return { ok: false, flagged: { kind: "flagged", path: path33, tension: `operator-origin (${origin}); flag-only`, evidence } };
23790
+ return { ok: false, flagged: { kind: "flagged", path: path37, tension: `operator-origin (${origin}); flag-only`, evidence } };
23188
23791
  }
23189
23792
  var ALLOWED_MEMORY = /^memory\/.+\.md$/;
23190
23793
  var ALLOWED_INBOX = /^inbox\//;
23191
23794
  var ALLOWED_QUARANTINE = /^quarantine\//;
23192
23795
  var ALLOWED_FLAG = /^memory\//;
23193
- var hasTraversal = (path33) => path33.split("/").includes("..");
23796
+ var hasTraversal = (path37) => path37.split("/").includes("..");
23194
23797
  function checkPathAllowed(delta) {
23195
23798
  const evidence = evidenceOf(delta) ?? [];
23196
23799
  const reject = (detail) => ({ ok: false, rejected: { kind: "rejected", detail, evidence } });
@@ -23297,7 +23900,7 @@ ${inject}
23297
23900
  ---
23298
23901
  `);
23299
23902
  }
23300
- var indexLine = (path33, title, date, tags) => `- \`${path33}\` \u2014 **${title}**: ${title}. (${date} \xB7 ${tags.join(", ")})`;
23903
+ var indexLine = (path37, title, date, tags) => `- \`${path37}\` \u2014 **${title}**: ${title}. (${date} \xB7 ${tags.join(", ")})`;
23301
23904
  function splitIndex(index) {
23302
23905
  const all = index.split("\n");
23303
23906
  const firstLineIdx = all.findIndex((l) => l.startsWith("- `memory/"));
@@ -23470,16 +24073,16 @@ function defaultDreamSeams(opts = {}) {
23470
24073
  const mem = await memory(deps.brain);
23471
24074
  const harvested = harvestedIds(input);
23472
24075
  const ctx = { readFile: (p) => deps.brain.readFile(p), at: deps.clock() };
23473
- const lookup = (path33) => Promise.resolve(mem.files.find((f) => f.path === path33) ?? null);
24076
+ const lookup = (path37) => Promise.resolve(mem.files.find((f) => f.path === path37) ?? null);
23474
24077
  const digest = [...pendingRejected];
23475
24078
  let changes = [];
23476
24079
  let indexEdit;
23477
24080
  try {
23478
24081
  for (const raw of deltas) {
23479
24082
  const delta = forcePolicyQuarantine(raw);
23480
- const path33 = checkPathAllowed(delta);
23481
- if (!path33.ok) {
23482
- digest.push(path33.rejected);
24083
+ const path37 = checkPathAllowed(delta);
24084
+ if (!path37.ok) {
24085
+ digest.push(path37.rejected);
23483
24086
  continue;
23484
24087
  }
23485
24088
  const ev = checkEvidenceMembership(delta, harvested);
@@ -24699,9 +25302,9 @@ ${colors.error(" " + why)}
24699
25302
  }
24700
25303
 
24701
25304
  // src/commands/bootstrap/launch.ts
24702
- import * as fs27 from "fs";
24703
- import * as os13 from "os";
24704
- import * as path28 from "path";
25305
+ import * as fs30 from "fs";
25306
+ import * as os14 from "os";
25307
+ import * as path32 from "path";
24705
25308
  import { Command as Command49, Option as Option46 } from "clipanion";
24706
25309
  init_errors();
24707
25310
 
@@ -24847,9 +25450,9 @@ async function kickInstaller(s) {
24847
25450
 
24848
25451
  // src/lib/bootstrap-status.ts
24849
25452
  import { createHash as createHash4, randomUUID as randomUUID2 } from "crypto";
24850
- import * as fs25 from "fs/promises";
24851
- import * as os11 from "os";
24852
- import * as path26 from "path";
25453
+ import * as fs28 from "fs/promises";
25454
+ import * as os12 from "os";
25455
+ import * as path30 from "path";
24853
25456
  init_errors();
24854
25457
  var STATUS_CONTAINER = "status";
24855
25458
  var STATUS_BLOB = "status.json";
@@ -24888,7 +25491,7 @@ async function readStatusBlob(opts) {
24888
25491
  cause: e
24889
25492
  });
24890
25493
  }
24891
- const tmpFile = path26.join(os11.tmpdir(), `m8t-status-${randomUUID2()}.json`);
25494
+ const tmpFile = path30.join(os12.tmpdir(), `m8t-status-${randomUUID2()}.json`);
24892
25495
  try {
24893
25496
  await runAz([
24894
25497
  "storage",
@@ -24907,7 +25510,7 @@ async function readStatusBlob(opts) {
24907
25510
  "--no-progress",
24908
25511
  "--only-show-errors"
24909
25512
  ]);
24910
- const raw = await fs25.readFile(tmpFile, "utf8");
25513
+ const raw = await fs28.readFile(tmpFile, "utf8");
24911
25514
  return JSON.parse(raw.trim());
24912
25515
  } catch (e) {
24913
25516
  throw new LocalCliError({
@@ -24917,34 +25520,34 @@ async function readStatusBlob(opts) {
24917
25520
  cause: e
24918
25521
  });
24919
25522
  } finally {
24920
- await fs25.rm(tmpFile, { force: true });
25523
+ await fs28.rm(tmpFile, { force: true });
24921
25524
  }
24922
25525
  }
24923
25526
 
24924
25527
  // src/lib/bootstrap-state.ts
24925
- import * as fs26 from "fs/promises";
24926
- import * as os12 from "os";
24927
- import * as path27 from "path";
25528
+ import * as fs29 from "fs/promises";
25529
+ import * as os13 from "os";
25530
+ import * as path31 from "path";
24928
25531
  function stateDir(home) {
24929
- return path27.join(home, ".m8t-stack");
25532
+ return path31.join(home, ".m8t-stack");
24930
25533
  }
24931
25534
  function statePath(home) {
24932
- return path27.join(stateDir(home), "bootstrap.json");
25535
+ return path31.join(stateDir(home), "bootstrap.json");
24933
25536
  }
24934
- async function readBootstrapState(home = os12.homedir()) {
25537
+ async function readBootstrapState(home = os13.homedir()) {
24935
25538
  try {
24936
- const raw = await fs26.readFile(statePath(home), "utf8");
25539
+ const raw = await fs29.readFile(statePath(home), "utf8");
24937
25540
  return JSON.parse(raw);
24938
25541
  } catch (e) {
24939
25542
  if (e.code === "ENOENT") return null;
24940
25543
  throw e;
24941
25544
  }
24942
25545
  }
24943
- async function writeBootstrapState(state, home = os12.homedir()) {
24944
- await fs26.mkdir(stateDir(home), { recursive: true });
25546
+ async function writeBootstrapState(state, home = os13.homedir()) {
25547
+ await fs29.mkdir(stateDir(home), { recursive: true });
24945
25548
  const tmp = `${statePath(home)}.tmp`;
24946
- await fs26.writeFile(tmp, JSON.stringify(state, null, 2), "utf8");
24947
- await fs26.rename(tmp, statePath(home));
25549
+ await fs29.writeFile(tmp, JSON.stringify(state, null, 2), "utf8");
25550
+ await fs29.rename(tmp, statePath(home));
24948
25551
  }
24949
25552
 
24950
25553
  // src/commands/bootstrap/launch.ts
@@ -24984,12 +25587,12 @@ var BootstrapLaunchCommand = class extends M8tCommand {
24984
25587
  const subscriptionId = (typeof this.subscription === "string" ? this.subscription : void 0) ?? account.subscriptionId;
24985
25588
  const out = (m) => this.context.stderr.write(` ${colors.dim(m)}
24986
25589
  `);
24987
- const credsPath = typeof this.githubAppCreds === "string" ? this.githubAppCreds : path28.join(os13.homedir(), ".m8t-stack", "github-app.json");
25590
+ const credsPath = typeof this.githubAppCreds === "string" ? this.githubAppCreds : path32.join(os14.homedir(), ".m8t-stack", "github-app.json");
24988
25591
  let githubApp;
24989
- if (fs27.existsSync(credsPath)) {
25592
+ if (fs30.existsSync(credsPath)) {
24990
25593
  let parsed;
24991
25594
  try {
24992
- parsed = JSON.parse(fs27.readFileSync(credsPath, "utf8"));
25595
+ parsed = JSON.parse(fs30.readFileSync(credsPath, "utf8"));
24993
25596
  } catch {
24994
25597
  throw new LocalCliError({
24995
25598
  code: "GITHUB_APP_CREDS_INVALID",
@@ -24999,7 +25602,7 @@ var BootstrapLaunchCommand = class extends M8tCommand {
24999
25602
  }
25000
25603
  let pem;
25001
25604
  try {
25002
- pem = fs27.readFileSync(parsed.pemPath, "utf8");
25605
+ pem = fs30.readFileSync(parsed.pemPath, "utf8");
25003
25606
  } catch {
25004
25607
  throw new LocalCliError({
25005
25608
  code: "GITHUB_APP_PEM_MISSING",
@@ -25324,17 +25927,17 @@ Found ${String(found.length)} orphaned Owner@sub assignment(s) (dry-run). ${colo
25324
25927
  };
25325
25928
 
25326
25929
  // src/commands/bootstrap/finish.ts
25327
- import * as fs28 from "fs/promises";
25328
- import * as os15 from "os";
25329
- import * as path30 from "path";
25930
+ import * as fs31 from "fs/promises";
25931
+ import * as os16 from "os";
25932
+ import * as path34 from "path";
25330
25933
  import { Command as Command52, Option as Option49 } from "clipanion";
25331
25934
  init_errors();
25332
25935
 
25333
25936
  // src/lib/company-profile-seed.ts
25334
25937
  import { spawn as spawn6 } from "child_process";
25335
- import { closeSync, openSync, readFileSync as readFileSync19 } from "fs";
25336
- import * as os14 from "os";
25337
- import * as path29 from "path";
25938
+ import { closeSync, openSync, readFileSync as readFileSync20 } from "fs";
25939
+ import * as os15 from "os";
25940
+ import * as path33 from "path";
25338
25941
  init_errors();
25339
25942
 
25340
25943
  // src/lib/onboarding-profile.ts
@@ -25515,9 +26118,9 @@ function composeFounderIdentityNote(id) {
25515
26118
 
25516
26119
  // src/lib/company-profile-seed.ts
25517
26120
  function readGithubAppCreds(credsPath) {
25518
- const p = credsPath ?? path29.join(os14.homedir(), ".m8t-stack", "github-app.json");
26121
+ const p = credsPath ?? path33.join(os15.homedir(), ".m8t-stack", "github-app.json");
25519
26122
  try {
25520
- return JSON.parse(readFileSync19(p, "utf8"));
26123
+ return JSON.parse(readFileSync20(p, "utf8"));
25521
26124
  } catch {
25522
26125
  return null;
25523
26126
  }
@@ -25545,7 +26148,7 @@ async function resolveSeedContext(opts) {
25545
26148
  async function applyProfileToBrain(args) {
25546
26149
  const token = await mintInstallationTokenFromPem({
25547
26150
  appId: args.appCreds.appId,
25548
- privateKeyPem: readFileSync19(args.appCreds.pemPath, "utf8"),
26151
+ privateKeyPem: readFileSync20(args.appCreds.pemPath, "utf8"),
25549
26152
  installationId: args.appCreds.installationId,
25550
26153
  fetchImpl: args.fetchImpl
25551
26154
  });
@@ -25580,7 +26183,7 @@ async function applyProfileToBrain(args) {
25580
26183
  });
25581
26184
  }
25582
26185
  function spawnDetachedSeedWatch() {
25583
- const logPath = path29.join(os14.homedir(), ".m8t-stack", "seed-profile.log");
26186
+ const logPath = path33.join(os15.homedir(), ".m8t-stack", "seed-profile.log");
25584
26187
  const fd = openSync(logPath, "a");
25585
26188
  try {
25586
26189
  const child = spawn6(process.execPath, [process.argv[1] ?? "", "bootstrap", "seed-profile", "--watch"], {
@@ -25679,9 +26282,9 @@ var BootstrapFinishCommand = class extends M8tCommand {
25679
26282
  });
25680
26283
  }
25681
26284
  const repoRoot = (typeof this.repoRoot === "string" ? this.repoRoot : void 0) ?? process.cwd();
25682
- const markerDir = path30.join(os15.homedir(), ".m8t-stack");
25683
- await fs28.mkdir(markerDir, { recursive: true });
25684
- await fs28.writeFile(path30.join(markerDir, "repo-root"), `${repoRoot}
26285
+ const markerDir = path34.join(os16.homedir(), ".m8t-stack");
26286
+ await fs31.mkdir(markerDir, { recursive: true });
26287
+ await fs31.writeFile(path34.join(markerDir, "repo-root"), `${repoRoot}
25685
26288
  `, "utf8");
25686
26289
  const subscriptionId = (typeof this.subscription === "string" ? this.subscription : void 0) ?? state.subscriptionId;
25687
26290
  const resourceGroup = (typeof this.resourceGroup === "string" ? this.resourceGroup : void 0) ?? state.resourceGroup;
@@ -25717,7 +26320,7 @@ var BootstrapFinishCommand = class extends M8tCommand {
25717
26320
  }
25718
26321
  let brainOrg = null;
25719
26322
  try {
25720
- const credsRaw = await fs28.readFile(path30.join(markerDir, "github-app.json"), "utf8");
26323
+ const credsRaw = await fs31.readFile(path34.join(markerDir, "github-app.json"), "utf8");
25721
26324
  const creds = JSON.parse(credsRaw);
25722
26325
  brainOrg = typeof creds.org === "string" ? creds.org : null;
25723
26326
  } catch {
@@ -25748,18 +26351,18 @@ ${colors.field("Then open a brand new chat/session")} \u2014 new skills + MCP se
25748
26351
  };
25749
26352
 
25750
26353
  // src/commands/bootstrap/ui.ts
25751
- import * as fs30 from "fs";
25752
- import * as os17 from "os";
25753
- import * as path32 from "path";
26354
+ import * as fs33 from "fs";
26355
+ import * as os18 from "os";
26356
+ import * as path36 from "path";
25754
26357
  import { Command as Command53, Option as Option50 } from "clipanion";
25755
26358
  import { DefaultAzureCredential as DefaultAzureCredential20 } from "@azure/identity";
25756
26359
  init_errors();
25757
26360
 
25758
26361
  // src/lib/bootstrap-ui.ts
25759
- import * as fs29 from "fs";
26362
+ import * as fs32 from "fs";
25760
26363
  import * as net from "net";
25761
- import * as os16 from "os";
25762
- import * as path31 from "path";
26364
+ import * as os17 from "os";
26365
+ import * as path35 from "path";
25763
26366
  import { spawn as spawn7 } from "child_process";
25764
26367
  init_errors();
25765
26368
  init_rbac();
@@ -25826,9 +26429,9 @@ async function ensureFounderFoundryRole(args) {
25826
26429
  });
25827
26430
  }
25828
26431
  function writeWebEnvLocal(args) {
25829
- const envPath = path31.join(args.repoRoot, "apps", "web", ".env.local");
25830
- if (fs29.existsSync(envPath)) {
25831
- fs29.copyFileSync(envPath, envPath + ".bak");
26432
+ const envPath = path35.join(args.repoRoot, "apps", "web", ".env.local");
26433
+ if (fs32.existsSync(envPath)) {
26434
+ fs32.copyFileSync(envPath, envPath + ".bak");
25832
26435
  }
25833
26436
  const body = [
25834
26437
  "# Written by `m8t bootstrap ui` \u2014 onboarding chat-only run (Simple Stacey).",
@@ -25842,7 +26445,7 @@ function writeWebEnvLocal(args) {
25842
26445
  "NEXT_PUBLIC_M8T_ONBOARDING=1",
25843
26446
  ""
25844
26447
  ].join("\n");
25845
- fs29.writeFileSync(envPath, body, "utf8");
26448
+ fs32.writeFileSync(envPath, body, "utf8");
25846
26449
  return envPath;
25847
26450
  }
25848
26451
  function assertNodeVersion(versionString = process.version) {
@@ -25883,11 +26486,11 @@ async function installWebDeps(repoRoot) {
25883
26486
  });
25884
26487
  await runInherit("pnpm", ["install"], repoRoot, "BOOTSTRAP_UI_INSTALL_FAILED");
25885
26488
  }
25886
- function onboardingUiPaths(home = os16.homedir()) {
25887
- const dir = path31.join(home, ".m8t-stack");
26489
+ function onboardingUiPaths(home = os17.homedir()) {
26490
+ const dir = path35.join(home, ".m8t-stack");
25888
26491
  return {
25889
- logPath: path31.join(dir, "onboarding-ui.log"),
25890
- pidPath: path31.join(dir, "onboarding-ui.pid")
26492
+ logPath: path35.join(dir, "onboarding-ui.log"),
26493
+ pidPath: path35.join(dir, "onboarding-ui.pid")
25891
26494
  };
25892
26495
  }
25893
26496
  async function serveOnboardingUiDetached(args) {
@@ -25911,8 +26514,8 @@ async function serveOnboardingUiDetached(args) {
25911
26514
  if (await isPortOpen()) {
25912
26515
  return { alreadyRunning: true, logPath };
25913
26516
  }
25914
- fs29.mkdirSync(path31.dirname(logPath), { recursive: true });
25915
- const fd = fs29.openSync(logPath, "a");
26517
+ fs32.mkdirSync(path35.dirname(logPath), { recursive: true });
26518
+ const fd = fs32.openSync(logPath, "a");
25916
26519
  const child = spawn7("pnpm", ["--filter", "web", "dev"], {
25917
26520
  cwd: args.repoRoot,
25918
26521
  detached: true,
@@ -25920,7 +26523,7 @@ async function serveOnboardingUiDetached(args) {
25920
26523
  env: { ...process.env, PORT: args.port },
25921
26524
  shell: false
25922
26525
  });
25923
- fs29.closeSync(fd);
26526
+ fs32.closeSync(fd);
25924
26527
  if (child.pid == null) {
25925
26528
  throw new LocalCliError({
25926
26529
  code: "BOOTSTRAP_UI_DEV_SPAWN_FAILED",
@@ -25929,7 +26532,7 @@ async function serveOnboardingUiDetached(args) {
25929
26532
  });
25930
26533
  }
25931
26534
  child.unref();
25932
- fs29.writeFileSync(pidPath, String(child.pid), "utf8");
26535
+ fs32.writeFileSync(pidPath, String(child.pid), "utf8");
25933
26536
  const deadline = Date.now() + 45e3;
25934
26537
  const sleep3 = (ms) => new Promise((r) => setTimeout(r, ms));
25935
26538
  while (Date.now() < deadline) {
@@ -25948,11 +26551,11 @@ function autoOpenOnboardingUi(url, open = tryOpenUrl) {
25948
26551
  } catch {
25949
26552
  }
25950
26553
  }
25951
- function stopOnboardingUi(home = os16.homedir()) {
26554
+ function stopOnboardingUi(home = os17.homedir()) {
25952
26555
  const { pidPath } = onboardingUiPaths(home);
25953
26556
  let pidStr;
25954
26557
  try {
25955
- pidStr = fs29.readFileSync(pidPath, "utf8").trim();
26558
+ pidStr = fs32.readFileSync(pidPath, "utf8").trim();
25956
26559
  } catch {
25957
26560
  return false;
25958
26561
  }
@@ -25965,7 +26568,7 @@ function stopOnboardingUi(home = os16.homedir()) {
25965
26568
  }
25966
26569
  }
25967
26570
  try {
25968
- fs29.unlinkSync(pidPath);
26571
+ fs32.unlinkSync(pidPath);
25969
26572
  } catch {
25970
26573
  }
25971
26574
  return true;
@@ -26081,7 +26684,7 @@ var BootstrapUiCommand = class extends M8tCommand {
26081
26684
  this.context.stderr.write(` ${colors.dim(m)}
26082
26685
  `);
26083
26686
  };
26084
- if (fs30.existsSync(path32.join(os17.homedir(), ".m8t-stack", "config.yaml"))) {
26687
+ if (fs33.existsSync(path36.join(os18.homedir(), ".m8t-stack", "config.yaml"))) {
26085
26688
  out(colors.error("\u26A0 an existing ~/.m8t-stack/config.yaml will override the onboarding app registration in apps/web \u2014 if Microsoft sign-in fails, move it aside and retry."));
26086
26689
  }
26087
26690
  const credential2 = new DefaultAzureCredential20();