@m8t-stack/cli 0.2.19 → 0.2.21
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 +1006 -279
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1157,6 +1157,10 @@ async function enableHostedBrain(args) {
|
|
|
1157
1157
|
memory: def.memory,
|
|
1158
1158
|
env,
|
|
1159
1159
|
metadata: {
|
|
1160
|
+
// Spread the current metadata first so unmanaged keys (a2a, a2aCard, …)
|
|
1161
|
+
// survive the relink version; the managed fields are re-asserted over the
|
|
1162
|
+
// spread, and createCoderVersion applies the `brain` arg last.
|
|
1163
|
+
...current.metadata,
|
|
1160
1164
|
source: "m8t-stack-POC",
|
|
1161
1165
|
kind: "hosted",
|
|
1162
1166
|
persona: current.metadata?.persona ?? "coding-agent",
|
|
@@ -1227,7 +1231,7 @@ var init_enable_hosted_brain = __esm({
|
|
|
1227
1231
|
import { Builtins, Cli } from "clipanion";
|
|
1228
1232
|
|
|
1229
1233
|
// src/lib/package-version.ts
|
|
1230
|
-
var CLI_VERSION = "0.2.
|
|
1234
|
+
var CLI_VERSION = "0.2.21";
|
|
1231
1235
|
|
|
1232
1236
|
// src/lib/render-error.ts
|
|
1233
1237
|
init_errors();
|
|
@@ -3326,12 +3330,12 @@ function encodeURIPath(str4) {
|
|
|
3326
3330
|
return str4.replace(/[^A-Za-z0-9\-._~!$&'()*+,;=:@]+/g, encodeURIComponent);
|
|
3327
3331
|
}
|
|
3328
3332
|
var EMPTY = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.create(null));
|
|
3329
|
-
var createPathTagFunction = (pathEncoder = encodeURIPath) => function
|
|
3333
|
+
var createPathTagFunction = (pathEncoder = encodeURIPath) => function path37(statics, ...params) {
|
|
3330
3334
|
if (statics.length === 1)
|
|
3331
3335
|
return statics[0];
|
|
3332
3336
|
let postPath = false;
|
|
3333
3337
|
const invalidSegments = [];
|
|
3334
|
-
const
|
|
3338
|
+
const path38 = statics.reduce((previousValue, currentValue, index) => {
|
|
3335
3339
|
if (/[?#]/.test(currentValue)) {
|
|
3336
3340
|
postPath = true;
|
|
3337
3341
|
}
|
|
@@ -3348,7 +3352,7 @@ var createPathTagFunction = (pathEncoder = encodeURIPath) => function path33(sta
|
|
|
3348
3352
|
}
|
|
3349
3353
|
return previousValue + currentValue + (index === params.length ? "" : encoded);
|
|
3350
3354
|
}, "");
|
|
3351
|
-
const pathOnly =
|
|
3355
|
+
const pathOnly = path38.split(/[?#]/, 1)[0];
|
|
3352
3356
|
const invalidSegmentPattern = /(?<=^|\/)(?:\.|%2e){1,2}(?=\/|$)/gi;
|
|
3353
3357
|
let match;
|
|
3354
3358
|
while ((match = invalidSegmentPattern.exec(pathOnly)) !== null) {
|
|
@@ -3369,10 +3373,10 @@ var createPathTagFunction = (pathEncoder = encodeURIPath) => function path33(sta
|
|
|
3369
3373
|
}, "");
|
|
3370
3374
|
throw new OpenAIError(`Path parameters result in path with invalid segments:
|
|
3371
3375
|
${invalidSegments.map((e) => e.error).join("\n")}
|
|
3372
|
-
${
|
|
3376
|
+
${path38}
|
|
3373
3377
|
${underline}`);
|
|
3374
3378
|
}
|
|
3375
|
-
return
|
|
3379
|
+
return path38;
|
|
3376
3380
|
};
|
|
3377
3381
|
var path = /* @__PURE__ */ createPathTagFunction(encodeURIPath);
|
|
3378
3382
|
|
|
@@ -10889,9 +10893,9 @@ var OpenAI = class {
|
|
|
10889
10893
|
this.apiKey = token;
|
|
10890
10894
|
return true;
|
|
10891
10895
|
}
|
|
10892
|
-
buildURL(
|
|
10896
|
+
buildURL(path37, query, defaultBaseURL) {
|
|
10893
10897
|
const baseURL = !__classPrivateFieldGet(this, _OpenAI_instances, "m", _OpenAI_baseURLOverridden).call(this) && defaultBaseURL || this.baseURL;
|
|
10894
|
-
const url = isAbsoluteURL(
|
|
10898
|
+
const url = isAbsoluteURL(path37) ? new URL(path37) : new URL(baseURL + (baseURL.endsWith("/") && path37.startsWith("/") ? path37.slice(1) : path37));
|
|
10895
10899
|
const defaultQuery = this.defaultQuery();
|
|
10896
10900
|
const pathQuery = Object.fromEntries(url.searchParams);
|
|
10897
10901
|
if (!isEmptyObj(defaultQuery) || !isEmptyObj(pathQuery)) {
|
|
@@ -10919,24 +10923,24 @@ var OpenAI = class {
|
|
|
10919
10923
|
*/
|
|
10920
10924
|
async prepareRequest(request, { url, options }) {
|
|
10921
10925
|
}
|
|
10922
|
-
get(
|
|
10923
|
-
return this.methodRequest("get",
|
|
10926
|
+
get(path37, opts) {
|
|
10927
|
+
return this.methodRequest("get", path37, opts);
|
|
10924
10928
|
}
|
|
10925
|
-
post(
|
|
10926
|
-
return this.methodRequest("post",
|
|
10929
|
+
post(path37, opts) {
|
|
10930
|
+
return this.methodRequest("post", path37, opts);
|
|
10927
10931
|
}
|
|
10928
|
-
patch(
|
|
10929
|
-
return this.methodRequest("patch",
|
|
10932
|
+
patch(path37, opts) {
|
|
10933
|
+
return this.methodRequest("patch", path37, opts);
|
|
10930
10934
|
}
|
|
10931
|
-
put(
|
|
10932
|
-
return this.methodRequest("put",
|
|
10935
|
+
put(path37, opts) {
|
|
10936
|
+
return this.methodRequest("put", path37, opts);
|
|
10933
10937
|
}
|
|
10934
|
-
delete(
|
|
10935
|
-
return this.methodRequest("delete",
|
|
10938
|
+
delete(path37, opts) {
|
|
10939
|
+
return this.methodRequest("delete", path37, opts);
|
|
10936
10940
|
}
|
|
10937
|
-
methodRequest(method,
|
|
10941
|
+
methodRequest(method, path37, opts) {
|
|
10938
10942
|
return this.request(Promise.resolve(opts).then((opts2) => {
|
|
10939
|
-
return { method, path:
|
|
10943
|
+
return { method, path: path37, ...opts2 };
|
|
10940
10944
|
}));
|
|
10941
10945
|
}
|
|
10942
10946
|
request(options, remainingRetries = null) {
|
|
@@ -11058,8 +11062,8 @@ var OpenAI = class {
|
|
|
11058
11062
|
}));
|
|
11059
11063
|
return { response, options, controller, requestLogID, retryOfRequestLogID, startTime };
|
|
11060
11064
|
}
|
|
11061
|
-
getAPIList(
|
|
11062
|
-
return this.requestAPIList(Page2, opts && "then" in opts ? opts.then((opts2) => ({ method: "get", path:
|
|
11065
|
+
getAPIList(path37, Page2, opts) {
|
|
11066
|
+
return this.requestAPIList(Page2, opts && "then" in opts ? opts.then((opts2) => ({ method: "get", path: path37, ...opts2 })) : { method: "get", path: path37, ...opts });
|
|
11063
11067
|
}
|
|
11064
11068
|
requestAPIList(Page2, options) {
|
|
11065
11069
|
const request = this.makeRequest(options, null, void 0);
|
|
@@ -11153,8 +11157,8 @@ var OpenAI = class {
|
|
|
11153
11157
|
}
|
|
11154
11158
|
async buildRequest(inputOptions, { retryCount = 0 } = {}) {
|
|
11155
11159
|
const options = { ...inputOptions };
|
|
11156
|
-
const { method, path:
|
|
11157
|
-
const url = this.buildURL(
|
|
11160
|
+
const { method, path: path37, query, defaultBaseURL } = options;
|
|
11161
|
+
const url = this.buildURL(path37, query, defaultBaseURL);
|
|
11158
11162
|
if ("timeout" in options)
|
|
11159
11163
|
validatePositiveInteger("timeout", options.timeout);
|
|
11160
11164
|
options.timeout = options.timeout ?? this.timeout;
|
|
@@ -12156,10 +12160,10 @@ var BindListCommand = class extends M8tCommand {
|
|
|
12156
12160
|
const qs = new URLSearchParams();
|
|
12157
12161
|
if (this.channel) qs.set("channel", this.channel);
|
|
12158
12162
|
if (this.status) qs.set("status", this.status);
|
|
12159
|
-
const
|
|
12163
|
+
const path37 = qs.toString().length > 0 ? `/api/bindings?${qs.toString()}` : "/api/bindings";
|
|
12160
12164
|
const data = await apiCall(
|
|
12161
12165
|
{ gatewayUrl: ctx.gatewayUrl, gatewayClientId: ctx.gatewayClientId },
|
|
12162
|
-
{ method: "GET", path:
|
|
12166
|
+
{ method: "GET", path: path37 },
|
|
12163
12167
|
(msg) => this.context.stderr.write(msg + "\n")
|
|
12164
12168
|
);
|
|
12165
12169
|
if (mode === "json") {
|
|
@@ -13370,8 +13374,8 @@ ${r.stderr}`;
|
|
|
13370
13374
|
message: `gh api /repos/${slug} failed (exit ${r.exitCode.toString()}): ${(r.stderr || r.stdout).slice(0, 200)}`
|
|
13371
13375
|
});
|
|
13372
13376
|
},
|
|
13373
|
-
getFile: async (
|
|
13374
|
-
const r = await exec("gh", ["api", "-H", "Accept: application/vnd.github.raw+json", `/repos/${slug}/contents/${
|
|
13377
|
+
getFile: async (path37) => {
|
|
13378
|
+
const r = await exec("gh", ["api", "-H", "Accept: application/vnd.github.raw+json", `/repos/${slug}/contents/${path37}`]);
|
|
13375
13379
|
return r.exitCode === 0 ? r.stdout : null;
|
|
13376
13380
|
},
|
|
13377
13381
|
isEmpty: async () => {
|
|
@@ -13615,11 +13619,11 @@ var BrainCheckAppCommand = class extends M8tCommand {
|
|
|
13615
13619
|
// src/commands/brain/create.ts
|
|
13616
13620
|
init_esm2();
|
|
13617
13621
|
import { Command as Command18, Option as Option17 } from "clipanion";
|
|
13618
|
-
import { spawnSync } from "child_process";
|
|
13622
|
+
import { execFileSync, spawnSync } from "child_process";
|
|
13619
13623
|
import { readFileSync as readFileSync6 } from "fs";
|
|
13620
|
-
import * as
|
|
13624
|
+
import * as fs11 from "fs";
|
|
13621
13625
|
import * as os4 from "os";
|
|
13622
|
-
import * as
|
|
13626
|
+
import * as path10 from "path";
|
|
13623
13627
|
import * as readline2 from "readline/promises";
|
|
13624
13628
|
import { DefaultAzureCredential as DefaultAzureCredential4 } from "@azure/identity";
|
|
13625
13629
|
init_errors();
|
|
@@ -14135,11 +14139,66 @@ async function createBrainEnabledVersion(args) {
|
|
|
14135
14139
|
|
|
14136
14140
|
// src/lib/brain-seed.ts
|
|
14137
14141
|
init_errors();
|
|
14142
|
+
import * as fs10 from "fs";
|
|
14143
|
+
import * as path9 from "path";
|
|
14144
|
+
|
|
14145
|
+
// src/lib/seed-manifest.ts
|
|
14138
14146
|
import * as fs9 from "fs";
|
|
14139
14147
|
import * as path8 from "path";
|
|
14148
|
+
var SEED_MANIFEST_PATH = ".m8t/seed-manifest.json";
|
|
14149
|
+
var SEED_PATHS = ["skills", "references", "targets"];
|
|
14150
|
+
function isLineage(v) {
|
|
14151
|
+
if (!v || typeof v !== "object") return false;
|
|
14152
|
+
const l = v;
|
|
14153
|
+
return typeof l.name === "string" && typeof l.refreshedToCommit === "string" && typeof l.refreshedToVersion === "string" && Array.isArray(l.ownedPaths) && l.ownedPaths.every((p) => typeof p === "string");
|
|
14154
|
+
}
|
|
14155
|
+
function parseSeedManifest(text) {
|
|
14156
|
+
if (!text?.trim()) return null;
|
|
14157
|
+
let parsed;
|
|
14158
|
+
try {
|
|
14159
|
+
parsed = JSON.parse(text);
|
|
14160
|
+
} catch {
|
|
14161
|
+
return null;
|
|
14162
|
+
}
|
|
14163
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
14164
|
+
const m = parsed;
|
|
14165
|
+
if (m.schemaVersion !== 1 || !Array.isArray(m.seeds) || !m.seeds.every(isLineage)) return null;
|
|
14166
|
+
return { schemaVersion: 1, seeds: m.seeds };
|
|
14167
|
+
}
|
|
14168
|
+
function buildSeedManifest(seeds) {
|
|
14169
|
+
return { schemaVersion: 1, seeds };
|
|
14170
|
+
}
|
|
14171
|
+
function upsertLineage(manifest, lineage) {
|
|
14172
|
+
const prior = manifest?.seeds ?? [];
|
|
14173
|
+
const others = prior.filter((s) => s.name !== lineage.name);
|
|
14174
|
+
return { schemaVersion: 1, seeds: [...others, lineage].sort((a, b) => a.name.localeCompare(b.name)) };
|
|
14175
|
+
}
|
|
14176
|
+
function serializeSeedManifest(m) {
|
|
14177
|
+
return JSON.stringify(m, null, 2) + "\n";
|
|
14178
|
+
}
|
|
14179
|
+
function walkFiles(root, rel = "") {
|
|
14180
|
+
const abs = path8.join(root, rel);
|
|
14181
|
+
if (!fs9.existsSync(abs)) return [];
|
|
14182
|
+
const out = [];
|
|
14183
|
+
for (const entry of fs9.readdirSync(abs, { withFileTypes: true })) {
|
|
14184
|
+
const childRel = rel ? `${rel}/${entry.name}` : entry.name;
|
|
14185
|
+
if (entry.isDirectory()) out.push(...walkFiles(root, childRel));
|
|
14186
|
+
else if (entry.isFile()) out.push(childRel);
|
|
14187
|
+
}
|
|
14188
|
+
return out;
|
|
14189
|
+
}
|
|
14190
|
+
function deriveOwnedPaths(seedDir) {
|
|
14191
|
+
const owned = /* @__PURE__ */ new Set([SEED_MANIFEST_PATH]);
|
|
14192
|
+
for (const sub of SEED_PATHS) {
|
|
14193
|
+
for (const rel of walkFiles(path8.join(seedDir, sub))) owned.add(`${sub}/${rel}`);
|
|
14194
|
+
}
|
|
14195
|
+
return [...owned].sort((a, b) => a.localeCompare(b));
|
|
14196
|
+
}
|
|
14197
|
+
|
|
14198
|
+
// src/lib/brain-seed.ts
|
|
14140
14199
|
function resolveSeed(name) {
|
|
14141
|
-
const dir =
|
|
14142
|
-
if (!
|
|
14200
|
+
const dir = path9.join(resolveRepoRoot(), "brain-seeds", name);
|
|
14201
|
+
if (!fs10.existsSync(dir)) {
|
|
14143
14202
|
throw new LocalCliError({
|
|
14144
14203
|
code: "SEED_NOT_FOUND",
|
|
14145
14204
|
message: `--seed "${name}": no brain-seeds/${name}/ directory found.`,
|
|
@@ -14149,11 +14208,22 @@ function resolveSeed(name) {
|
|
|
14149
14208
|
return dir;
|
|
14150
14209
|
}
|
|
14151
14210
|
function materializeBrainTree(opts) {
|
|
14152
|
-
|
|
14211
|
+
fs10.cpSync(opts.templateSrc, opts.destDir, { recursive: true });
|
|
14153
14212
|
if (opts.seedDir) {
|
|
14154
|
-
|
|
14213
|
+
fs10.cpSync(opts.seedDir, opts.destDir, { recursive: true });
|
|
14155
14214
|
}
|
|
14156
14215
|
}
|
|
14216
|
+
function writeSeedMarker(args) {
|
|
14217
|
+
const manifest = buildSeedManifest([{
|
|
14218
|
+
name: args.seedName,
|
|
14219
|
+
refreshedToCommit: args.refreshedToCommit,
|
|
14220
|
+
refreshedToVersion: args.version,
|
|
14221
|
+
ownedPaths: deriveOwnedPaths(args.seedDir)
|
|
14222
|
+
}]);
|
|
14223
|
+
const dest = path9.join(args.destDir, SEED_MANIFEST_PATH);
|
|
14224
|
+
fs10.mkdirSync(path9.dirname(dest), { recursive: true });
|
|
14225
|
+
fs10.writeFileSync(dest, serializeSeedManifest(manifest));
|
|
14226
|
+
}
|
|
14157
14227
|
|
|
14158
14228
|
// src/lib/github-app-repo.ts
|
|
14159
14229
|
init_errors();
|
|
@@ -14260,18 +14330,32 @@ async function mintInstallationTokenFromPem(args) {
|
|
|
14260
14330
|
}
|
|
14261
14331
|
async function readRepoFileViaApp(args) {
|
|
14262
14332
|
const doFetch = args.fetchImpl ?? fetch;
|
|
14263
|
-
const
|
|
14333
|
+
const q = args.ref ? `?ref=${encodeURIComponent(args.ref)}` : "";
|
|
14334
|
+
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
14335
|
if (res.status === 404) return null;
|
|
14265
14336
|
const text = await res.text();
|
|
14266
14337
|
if (!res.ok) {
|
|
14267
14338
|
throw new LocalCliError({
|
|
14268
14339
|
code: "GH_APP_FILE_READ_FAILED",
|
|
14269
|
-
message: `GET /repos/${args.repo}/contents/${args.path} HTTP ${res.status.toString()}: ${text.slice(0, 300)}`
|
|
14340
|
+
message: `GET /repos/${args.repo}/contents/${args.path}${q} HTTP ${res.status.toString()}: ${text.slice(0, 300)}`
|
|
14270
14341
|
});
|
|
14271
14342
|
}
|
|
14272
14343
|
const data = JSON.parse(text);
|
|
14273
14344
|
return Buffer.from(data.content ?? "", "base64").toString("utf8");
|
|
14274
14345
|
}
|
|
14346
|
+
async function getInitialSeedCommitSha(args) {
|
|
14347
|
+
const doFetch = args.fetchImpl ?? fetch;
|
|
14348
|
+
const H = ghHeaders(args.token);
|
|
14349
|
+
const first = await doFetch(`${GH_API}/repos/${args.repo}/commits?per_page=1`, { headers: H, signal: AbortSignal.timeout(GH_REQUEST_TIMEOUT_MS) });
|
|
14350
|
+
if (!first.ok) return null;
|
|
14351
|
+
const link = first.headers.get("link");
|
|
14352
|
+
const lastUrl = /<([^>]+)>;\s*rel="last"/.exec(link ?? "")?.[1];
|
|
14353
|
+
const url = lastUrl ?? `${GH_API}/repos/${args.repo}/commits?per_page=1`;
|
|
14354
|
+
const res = await doFetch(url, { headers: H, signal: AbortSignal.timeout(GH_REQUEST_TIMEOUT_MS) });
|
|
14355
|
+
if (!res.ok) return null;
|
|
14356
|
+
const commits = JSON.parse(await res.text());
|
|
14357
|
+
return commits.length > 0 ? commits[commits.length - 1].sha ?? null : null;
|
|
14358
|
+
}
|
|
14275
14359
|
async function commitFilesViaApp(args) {
|
|
14276
14360
|
const doFetch = args.fetchImpl ?? fetch;
|
|
14277
14361
|
const H = ghHeaders(args.token);
|
|
@@ -14289,19 +14373,68 @@ async function commitFilesViaApp(args) {
|
|
|
14289
14373
|
const ref = await api(`/git/ref/heads/${args.branch}`);
|
|
14290
14374
|
const baseCommitSha = ref.object.sha;
|
|
14291
14375
|
const baseCommit = await api(`/git/commits/${baseCommitSha}`);
|
|
14292
|
-
const
|
|
14293
|
-
const
|
|
14376
|
+
const upserts = args.files.filter((f) => !("delete" in f));
|
|
14377
|
+
const blobs = await Promise.all(upserts.map((f) => api(`/git/blobs`, { method: "POST", body: JSON.stringify({ content: f.content, encoding: "utf-8" }) })));
|
|
14378
|
+
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 });
|
|
14379
|
+
const newTree = await api(`/git/trees`, { method: "POST", body: JSON.stringify({ base_tree: baseCommit.tree.sha, tree }) });
|
|
14380
|
+
const commit = await api(`/git/commits`, {
|
|
14294
14381
|
method: "POST",
|
|
14295
|
-
body: JSON.stringify({
|
|
14296
|
-
|
|
14297
|
-
|
|
14298
|
-
|
|
14382
|
+
body: JSON.stringify({ message: args.message, tree: newTree.sha, parents: [baseCommitSha] })
|
|
14383
|
+
});
|
|
14384
|
+
await api(`/git/refs/heads/${args.branch}`, { method: "PATCH", body: JSON.stringify({ sha: commit.sha }) });
|
|
14385
|
+
}
|
|
14386
|
+
async function createBranchViaApp(args) {
|
|
14387
|
+
const doFetch = args.fetchImpl ?? fetch;
|
|
14388
|
+
const H = ghHeaders(args.token);
|
|
14389
|
+
const res = await doFetch(`${GH_API}/repos/${args.repo}/git/refs`, {
|
|
14390
|
+
method: "POST",
|
|
14391
|
+
headers: H,
|
|
14392
|
+
signal: AbortSignal.timeout(GH_REQUEST_TIMEOUT_MS),
|
|
14393
|
+
body: JSON.stringify({ ref: `refs/heads/${args.branch}`, sha: args.fromSha })
|
|
14394
|
+
});
|
|
14395
|
+
if (res.ok) return;
|
|
14396
|
+
if (res.status === 422) {
|
|
14397
|
+
const patch = await doFetch(`${GH_API}/repos/${args.repo}/git/refs/heads/${args.branch}`, {
|
|
14398
|
+
method: "PATCH",
|
|
14399
|
+
headers: H,
|
|
14400
|
+
signal: AbortSignal.timeout(GH_REQUEST_TIMEOUT_MS),
|
|
14401
|
+
body: JSON.stringify({ sha: args.fromSha, force: true })
|
|
14402
|
+
});
|
|
14403
|
+
if (patch.ok) return;
|
|
14404
|
+
throw new LocalCliError({
|
|
14405
|
+
code: "GH_APP_BRANCH_FAILED",
|
|
14406
|
+
message: `PATCH refs/heads/${args.branch} HTTP ${patch.status.toString()}: ${(await patch.text()).slice(0, 300)}`
|
|
14407
|
+
});
|
|
14408
|
+
}
|
|
14409
|
+
throw new LocalCliError({
|
|
14410
|
+
code: "GH_APP_BRANCH_FAILED",
|
|
14411
|
+
message: `POST /git/refs HTTP ${res.status.toString()}: ${(await res.text()).slice(0, 300)}`
|
|
14299
14412
|
});
|
|
14413
|
+
}
|
|
14414
|
+
async function commitFilesFromBaseViaApp(args) {
|
|
14415
|
+
const doFetch = args.fetchImpl ?? fetch;
|
|
14416
|
+
const H = ghHeaders(args.token);
|
|
14417
|
+
const api = async (p, init) => {
|
|
14418
|
+
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) });
|
|
14419
|
+
const text = await res.text();
|
|
14420
|
+
if (!res.ok) {
|
|
14421
|
+
throw new LocalCliError({
|
|
14422
|
+
code: "GH_APP_COMMIT_FAILED",
|
|
14423
|
+
message: `${init?.method ?? "GET"} ${p} HTTP ${res.status.toString()}: ${text.slice(0, 300)}`
|
|
14424
|
+
});
|
|
14425
|
+
}
|
|
14426
|
+
return text ? JSON.parse(text) : {};
|
|
14427
|
+
};
|
|
14428
|
+
const baseCommit = await api(`/git/commits/${args.baseSha}`);
|
|
14429
|
+
const upserts = args.files.filter((f) => !("delete" in f));
|
|
14430
|
+
const blobs = await Promise.all(upserts.map((f) => api(`/git/blobs`, { method: "POST", body: JSON.stringify({ content: f.content, encoding: "utf-8" }) })));
|
|
14431
|
+
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 });
|
|
14432
|
+
const newTree = await api(`/git/trees`, { method: "POST", body: JSON.stringify({ base_tree: baseCommit.tree.sha, tree }) });
|
|
14300
14433
|
const commit = await api(`/git/commits`, {
|
|
14301
14434
|
method: "POST",
|
|
14302
|
-
body: JSON.stringify({ message: args.message, tree:
|
|
14435
|
+
body: JSON.stringify({ message: args.message, tree: newTree.sha, parents: [args.baseSha] })
|
|
14303
14436
|
});
|
|
14304
|
-
await
|
|
14437
|
+
await createBranchViaApp({ token: args.token, repo: args.repo, branch: args.branch, fromSha: commit.sha, fetchImpl: args.fetchImpl });
|
|
14305
14438
|
}
|
|
14306
14439
|
async function probeRepoState(probe) {
|
|
14307
14440
|
const status = await probe.repoStatus();
|
|
@@ -14325,13 +14458,66 @@ function appRepoProbe(args) {
|
|
|
14325
14458
|
const res = await doFetch(`${GH_API}/repos/${args.repo}`, { headers: H, signal: AbortSignal.timeout(GH_REQUEST_TIMEOUT_MS) });
|
|
14326
14459
|
return res.status;
|
|
14327
14460
|
},
|
|
14328
|
-
getFile: (
|
|
14461
|
+
getFile: (path37) => readRepoFileViaApp({ token: args.token, repo: args.repo, path: path37, fetchImpl: args.fetchImpl }),
|
|
14329
14462
|
isEmpty: async () => {
|
|
14330
14463
|
const res = await doFetch(`${GH_API}/repos/${args.repo}/contents`, { headers: H, signal: AbortSignal.timeout(GH_REQUEST_TIMEOUT_MS) });
|
|
14331
14464
|
return res.status === 404;
|
|
14332
14465
|
}
|
|
14333
14466
|
};
|
|
14334
14467
|
}
|
|
14468
|
+
async function openPullRequestViaApp(args) {
|
|
14469
|
+
const doFetch = args.fetchImpl ?? fetch;
|
|
14470
|
+
const res = await doFetch(`${GH_API}/repos/${args.repo}/pulls`, {
|
|
14471
|
+
method: "POST",
|
|
14472
|
+
headers: ghHeaders(args.token),
|
|
14473
|
+
signal: AbortSignal.timeout(GH_REQUEST_TIMEOUT_MS),
|
|
14474
|
+
body: JSON.stringify({ base: args.base, head: args.head, title: args.title, body: args.body })
|
|
14475
|
+
});
|
|
14476
|
+
const text = await res.text();
|
|
14477
|
+
if (!res.ok) throw new LocalCliError({ code: "GH_APP_PR_OPEN_FAILED", message: `POST /pulls HTTP ${res.status.toString()}: ${text.slice(0, 300)}` });
|
|
14478
|
+
const j = JSON.parse(text);
|
|
14479
|
+
return { number: j.number, htmlUrl: j.html_url };
|
|
14480
|
+
}
|
|
14481
|
+
async function findOpenPr(args) {
|
|
14482
|
+
const doFetch = args.fetchImpl ?? fetch;
|
|
14483
|
+
const owner = args.repo.split("/")[0];
|
|
14484
|
+
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) });
|
|
14485
|
+
if (!res.ok) return null;
|
|
14486
|
+
const list = JSON.parse(await res.text());
|
|
14487
|
+
return list.length > 0 ? { number: list[0].number, htmlUrl: list[0].html_url } : null;
|
|
14488
|
+
}
|
|
14489
|
+
async function updatePullRequestViaApp(args) {
|
|
14490
|
+
const doFetch = args.fetchImpl ?? fetch;
|
|
14491
|
+
const patch = {};
|
|
14492
|
+
if (args.title !== void 0) patch.title = args.title;
|
|
14493
|
+
if (args.body !== void 0) patch.body = args.body;
|
|
14494
|
+
const res = await doFetch(`${GH_API}/repos/${args.repo}/pulls/${args.number.toString()}`, {
|
|
14495
|
+
method: "PATCH",
|
|
14496
|
+
headers: ghHeaders(args.token),
|
|
14497
|
+
signal: AbortSignal.timeout(GH_REQUEST_TIMEOUT_MS),
|
|
14498
|
+
body: JSON.stringify(patch)
|
|
14499
|
+
});
|
|
14500
|
+
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)}` });
|
|
14501
|
+
}
|
|
14502
|
+
async function closePullRequestViaApp(args) {
|
|
14503
|
+
const doFetch = args.fetchImpl ?? fetch;
|
|
14504
|
+
const H = ghHeaders(args.token);
|
|
14505
|
+
if (args.comment) {
|
|
14506
|
+
await doFetch(`${GH_API}/repos/${args.repo}/issues/${args.number.toString()}/comments`, {
|
|
14507
|
+
method: "POST",
|
|
14508
|
+
headers: H,
|
|
14509
|
+
signal: AbortSignal.timeout(GH_REQUEST_TIMEOUT_MS),
|
|
14510
|
+
body: JSON.stringify({ body: args.comment })
|
|
14511
|
+
});
|
|
14512
|
+
}
|
|
14513
|
+
const res = await doFetch(`${GH_API}/repos/${args.repo}/pulls/${args.number.toString()}`, {
|
|
14514
|
+
method: "PATCH",
|
|
14515
|
+
headers: H,
|
|
14516
|
+
signal: AbortSignal.timeout(GH_REQUEST_TIMEOUT_MS),
|
|
14517
|
+
body: JSON.stringify({ state: "closed" })
|
|
14518
|
+
});
|
|
14519
|
+
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)}` });
|
|
14520
|
+
}
|
|
14335
14521
|
|
|
14336
14522
|
// src/lib/brain-repo-collision.ts
|
|
14337
14523
|
init_errors();
|
|
@@ -14513,15 +14699,15 @@ var BrainCreateCommand = class extends M8tCommand {
|
|
|
14513
14699
|
agentEndpoint
|
|
14514
14700
|
});
|
|
14515
14701
|
const repoRoot = resolveRepoRoot();
|
|
14516
|
-
const templateSrc =
|
|
14517
|
-
if (!
|
|
14702
|
+
const templateSrc = path10.join(repoRoot, "brain-template");
|
|
14703
|
+
if (!fs11.existsSync(templateSrc)) {
|
|
14518
14704
|
throw new LocalCliError({
|
|
14519
14705
|
code: "TEMPLATE_MISSING",
|
|
14520
14706
|
message: `brain-template/ missing at ${templateSrc}`,
|
|
14521
14707
|
hint: "Ensure brain-template/ exists at the repo root (same level as apps/)."
|
|
14522
14708
|
});
|
|
14523
14709
|
}
|
|
14524
|
-
const tmpDir =
|
|
14710
|
+
const tmpDir = fs11.mkdtempSync(path10.join(os4.tmpdir(), `m8t-brain-create-${worker}-`));
|
|
14525
14711
|
let result;
|
|
14526
14712
|
let resolvedInstallationId = null;
|
|
14527
14713
|
const force = this.reuse === true ? "reuse" : this.newName === true ? "new" : void 0;
|
|
@@ -14558,6 +14744,10 @@ var BrainCreateCommand = class extends M8tCommand {
|
|
|
14558
14744
|
try {
|
|
14559
14745
|
if (needsPush) {
|
|
14560
14746
|
materializeBrainTree({ templateSrc, destDir: tmpDir, seedDir });
|
|
14747
|
+
if (seedName && seedDir) {
|
|
14748
|
+
const headSha = execFileSync("git", ["rev-parse", "HEAD"], { cwd: repoRoot, encoding: "utf8" }).trim();
|
|
14749
|
+
writeSeedMarker({ destDir: tmpDir, seedName, seedDir, refreshedToCommit: headSha, version: "(scaffold)" });
|
|
14750
|
+
}
|
|
14561
14751
|
this.context.stdout.write(
|
|
14562
14752
|
seedName ? `${colors.dim("\u2192")} copied brain-template/ + overlaid seed ${colors.field(seedName)} to ${tmpDir}
|
|
14563
14753
|
` : `${colors.dim("\u2192")} copied brain-template/ to ${tmpDir}
|
|
@@ -14649,7 +14839,7 @@ var BrainCreateCommand = class extends M8tCommand {
|
|
|
14649
14839
|
project
|
|
14650
14840
|
});
|
|
14651
14841
|
} finally {
|
|
14652
|
-
|
|
14842
|
+
fs11.rmSync(tmpDir, { recursive: true, force: true });
|
|
14653
14843
|
}
|
|
14654
14844
|
if (mode === "json") {
|
|
14655
14845
|
this.context.stdout.write(
|
|
@@ -14986,9 +15176,9 @@ init_errors();
|
|
|
14986
15176
|
// src/lib/brain-unlink.ts
|
|
14987
15177
|
init_esm2();
|
|
14988
15178
|
init_errors();
|
|
14989
|
-
import * as
|
|
15179
|
+
import * as fs12 from "fs";
|
|
14990
15180
|
import * as os5 from "os";
|
|
14991
|
-
import * as
|
|
15181
|
+
import * as path11 from "path";
|
|
14992
15182
|
init_foundry_agent_get();
|
|
14993
15183
|
var FOUNDRY_ARM_API2 = "2025-04-01-preview";
|
|
14994
15184
|
var FOUNDRY_DATA_SCOPE2 = "https://ai.azure.com/.default";
|
|
@@ -15019,15 +15209,15 @@ async function unlinkBrain(args) {
|
|
|
15019
15209
|
if (yaml?.personaPath) {
|
|
15020
15210
|
let personaPath = yaml.personaPath;
|
|
15021
15211
|
if (!personaPath.startsWith("/")) {
|
|
15022
|
-
const marker =
|
|
15023
|
-
if (!
|
|
15212
|
+
const marker = path11.join(args.home ?? os5.homedir(), ".m8t-stack", "repo-root");
|
|
15213
|
+
if (!fs12.existsSync(marker)) {
|
|
15024
15214
|
throw new LocalCliError({
|
|
15025
15215
|
code: "PERSONA_PATH_NOT_ABSOLUTE",
|
|
15026
15216
|
message: `personaPath '${personaPath}' is relative and the repo-root marker is missing.`,
|
|
15027
15217
|
hint: "Re-run 'm8t install' from a fresh m8t-stack checkout (writes ~/.m8t-stack/repo-root) \u2014 or edit the personaPath to absolute."
|
|
15028
15218
|
});
|
|
15029
15219
|
}
|
|
15030
|
-
personaPath =
|
|
15220
|
+
personaPath = path11.join(fs12.readFileSync(marker, "utf8").trim(), personaPath);
|
|
15031
15221
|
}
|
|
15032
15222
|
strippedInstructions = renderPersonaBody(personaPath, yaml.fillableFieldValues ?? {}, args.agentName);
|
|
15033
15223
|
} else {
|
|
@@ -15267,27 +15457,27 @@ import { DefaultAzureCredential as DefaultAzureCredential9 } from "@azure/identi
|
|
|
15267
15457
|
init_errors();
|
|
15268
15458
|
|
|
15269
15459
|
// src/lib/deploy-prompt-advisor.ts
|
|
15270
|
-
import * as
|
|
15271
|
-
import * as
|
|
15460
|
+
import * as fs13 from "fs";
|
|
15461
|
+
import * as path12 from "path";
|
|
15272
15462
|
import { parse as parseYaml6 } from "yaml";
|
|
15273
15463
|
init_foundry_agents();
|
|
15274
15464
|
init_errors();
|
|
15275
15465
|
function findPersonasRoot(hint) {
|
|
15276
|
-
let dir =
|
|
15277
|
-
const fsRoot =
|
|
15466
|
+
let dir = path12.resolve(hint);
|
|
15467
|
+
const fsRoot = path12.parse(dir).root;
|
|
15278
15468
|
for (; ; ) {
|
|
15279
|
-
if (
|
|
15280
|
-
const parent =
|
|
15469
|
+
if (fs13.existsSync(path12.join(dir, "personas"))) return dir;
|
|
15470
|
+
const parent = path12.dirname(dir);
|
|
15281
15471
|
if (parent === dir || dir === fsRoot) return null;
|
|
15282
15472
|
dir = parent;
|
|
15283
15473
|
}
|
|
15284
15474
|
}
|
|
15285
15475
|
async function deployPromptAdvisor(args) {
|
|
15286
15476
|
const resolvedRoot = findPersonasRoot(args.repoRoot);
|
|
15287
|
-
const personaPath = resolvedRoot ?
|
|
15477
|
+
const personaPath = resolvedRoot ? path12.join(resolvedRoot, "personas", args.persona, "persona.md") : path12.join(args.repoRoot, "personas", args.persona, "persona.md");
|
|
15288
15478
|
let raw;
|
|
15289
15479
|
try {
|
|
15290
|
-
raw =
|
|
15480
|
+
raw = fs13.readFileSync(personaPath, "utf8");
|
|
15291
15481
|
} catch (e) {
|
|
15292
15482
|
throw new LocalCliError({
|
|
15293
15483
|
code: "ADVISOR_PERSONA_MISSING",
|
|
@@ -15449,7 +15639,7 @@ init_errors();
|
|
|
15449
15639
|
// src/lib/agent-remove.ts
|
|
15450
15640
|
init_errors();
|
|
15451
15641
|
init_foundry_agent_get();
|
|
15452
|
-
import * as
|
|
15642
|
+
import * as fs15 from "fs";
|
|
15453
15643
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
15454
15644
|
|
|
15455
15645
|
// src/lib/a2a-enable.ts
|
|
@@ -15563,12 +15753,12 @@ async function awaitAgentQueryable(args) {
|
|
|
15563
15753
|
// src/lib/persona-a2a.ts
|
|
15564
15754
|
init_errors();
|
|
15565
15755
|
init_esm();
|
|
15566
|
-
import * as
|
|
15756
|
+
import * as fs14 from "fs";
|
|
15567
15757
|
import { parse as parseYaml7 } from "yaml";
|
|
15568
15758
|
function readPersonaA2aCard(personaPath) {
|
|
15569
15759
|
let raw;
|
|
15570
15760
|
try {
|
|
15571
|
-
raw =
|
|
15761
|
+
raw = fs14.readFileSync(personaPath, "utf8");
|
|
15572
15762
|
} catch (e) {
|
|
15573
15763
|
throw new LocalCliError({ code: "PERSONA_READ_FAILED", message: `Could not read persona '${personaPath}': ${e.message}` });
|
|
15574
15764
|
}
|
|
@@ -15893,7 +16083,7 @@ function defaultRemoveAgentDeps(args) {
|
|
|
15893
16083
|
},
|
|
15894
16084
|
removeLocalYaml(agentName) {
|
|
15895
16085
|
const p = agentYamlPath(agentName, home);
|
|
15896
|
-
if (
|
|
16086
|
+
if (fs15.existsSync(p)) fs15.rmSync(p);
|
|
15897
16087
|
}
|
|
15898
16088
|
};
|
|
15899
16089
|
}
|
|
@@ -16035,16 +16225,16 @@ ${colors.success("\u2713")} removed ${colors.field(name)}.
|
|
|
16035
16225
|
};
|
|
16036
16226
|
|
|
16037
16227
|
// src/commands/a2a/enable.ts
|
|
16038
|
-
import * as
|
|
16228
|
+
import * as path14 from "path";
|
|
16039
16229
|
import { Command as Command25, Option as Option24 } from "clipanion";
|
|
16040
16230
|
import { DefaultAzureCredential as DefaultAzureCredential11 } from "@azure/identity";
|
|
16041
16231
|
init_errors();
|
|
16042
16232
|
|
|
16043
16233
|
// src/lib/bridge-url.ts
|
|
16044
16234
|
init_errors();
|
|
16045
|
-
import * as
|
|
16235
|
+
import * as fs16 from "fs";
|
|
16046
16236
|
import * as os6 from "os";
|
|
16047
|
-
import * as
|
|
16237
|
+
import * as path13 from "path";
|
|
16048
16238
|
import { parse as parseYaml8 } from "yaml";
|
|
16049
16239
|
var A2A_PATH = "/api/a2a/mcp";
|
|
16050
16240
|
function resolveBridgeUrl(opts) {
|
|
@@ -16066,10 +16256,10 @@ function clean(v) {
|
|
|
16066
16256
|
return t.length ? t : void 0;
|
|
16067
16257
|
}
|
|
16068
16258
|
function readConfigGatewayUrl(home) {
|
|
16069
|
-
const cfg =
|
|
16070
|
-
if (!
|
|
16259
|
+
const cfg = path13.join(home ?? os6.homedir(), ".m8t-stack", "config.yaml");
|
|
16260
|
+
if (!fs16.existsSync(cfg)) return void 0;
|
|
16071
16261
|
try {
|
|
16072
|
-
const o = parseYaml8(
|
|
16262
|
+
const o = parseYaml8(fs16.readFileSync(cfg, "utf8"));
|
|
16073
16263
|
return typeof o.gatewayUrl === "string" ? o.gatewayUrl : void 0;
|
|
16074
16264
|
} catch {
|
|
16075
16265
|
return void 0;
|
|
@@ -16138,11 +16328,11 @@ var A2aEnableCommand = class extends M8tCommand {
|
|
|
16138
16328
|
resolvePersonaPath() {
|
|
16139
16329
|
if (typeof this.persona === "string" && this.persona.length > 0) {
|
|
16140
16330
|
if (this.persona.includes("/") || this.persona.endsWith(".md")) return this.persona;
|
|
16141
|
-
return
|
|
16331
|
+
return path14.join(resolveRepoRoot(), "personas", this.persona, "persona.md");
|
|
16142
16332
|
}
|
|
16143
16333
|
const yaml = readAgentYaml(this.worker);
|
|
16144
16334
|
if (yaml?.personaPath) {
|
|
16145
|
-
return yaml.personaPath.startsWith("/") ? yaml.personaPath :
|
|
16335
|
+
return yaml.personaPath.startsWith("/") ? yaml.personaPath : path14.join(resolveRepoRoot(), yaml.personaPath);
|
|
16146
16336
|
}
|
|
16147
16337
|
throw new LocalCliError({ code: "A2A_NO_PERSONA", message: `Could not resolve a persona for '${this.worker}'. Pass --persona <name>.` });
|
|
16148
16338
|
}
|
|
@@ -16198,12 +16388,12 @@ import { Command as Command27 } from "clipanion";
|
|
|
16198
16388
|
|
|
16199
16389
|
// src/lib/architect-version.ts
|
|
16200
16390
|
import { createHash as createHash2 } from "crypto";
|
|
16201
|
-
import * as
|
|
16391
|
+
import * as fs17 from "fs";
|
|
16202
16392
|
import * as os7 from "os";
|
|
16203
|
-
import * as
|
|
16393
|
+
import * as path15 from "path";
|
|
16204
16394
|
function readVersionFrontmatter(file) {
|
|
16205
|
-
if (!
|
|
16206
|
-
const text =
|
|
16395
|
+
if (!fs17.existsSync(file)) return "";
|
|
16396
|
+
const text = fs17.readFileSync(file, "utf8");
|
|
16207
16397
|
if (!text.startsWith("---")) return "";
|
|
16208
16398
|
const closeIdx = text.indexOf("\n---", 3);
|
|
16209
16399
|
if (closeIdx < 0) return "";
|
|
@@ -16212,23 +16402,23 @@ function readVersionFrontmatter(file) {
|
|
|
16212
16402
|
return m ? m[1].trim() : "";
|
|
16213
16403
|
}
|
|
16214
16404
|
function sha256File(filePath) {
|
|
16215
|
-
return createHash2("sha256").update(
|
|
16405
|
+
return createHash2("sha256").update(fs17.readFileSync(filePath)).digest("hex");
|
|
16216
16406
|
}
|
|
16217
16407
|
function checkArchitectDrift() {
|
|
16218
|
-
const sourcePath =
|
|
16408
|
+
const sourcePath = path15.join(
|
|
16219
16409
|
resolveRepoRoot(),
|
|
16220
16410
|
"personas",
|
|
16221
16411
|
"m8t-architect",
|
|
16222
16412
|
"persona.md"
|
|
16223
16413
|
);
|
|
16224
|
-
const sidecarPath =
|
|
16414
|
+
const sidecarPath = path15.join(
|
|
16225
16415
|
os7.homedir(),
|
|
16226
16416
|
".claude",
|
|
16227
16417
|
"skills",
|
|
16228
16418
|
"m8t-architect",
|
|
16229
16419
|
".m8t-skill.json"
|
|
16230
16420
|
);
|
|
16231
|
-
if (!
|
|
16421
|
+
if (!fs17.existsSync(sourcePath)) {
|
|
16232
16422
|
return {
|
|
16233
16423
|
match: false,
|
|
16234
16424
|
sourceVersion: "",
|
|
@@ -16238,9 +16428,9 @@ function checkArchitectDrift() {
|
|
|
16238
16428
|
}
|
|
16239
16429
|
const sourceVersion = readVersionFrontmatter(sourcePath);
|
|
16240
16430
|
let sidecar = null;
|
|
16241
|
-
if (
|
|
16431
|
+
if (fs17.existsSync(sidecarPath)) {
|
|
16242
16432
|
try {
|
|
16243
|
-
const raw = JSON.parse(
|
|
16433
|
+
const raw = JSON.parse(fs17.readFileSync(sidecarPath, "utf8"));
|
|
16244
16434
|
if (raw !== null && typeof raw === "object") {
|
|
16245
16435
|
const r = raw;
|
|
16246
16436
|
sidecar = {
|
|
@@ -16303,7 +16493,7 @@ var ArchitectCheckCommand = class extends M8tCommand {
|
|
|
16303
16493
|
|
|
16304
16494
|
// src/commands/coder/deploy.ts
|
|
16305
16495
|
init_esm2();
|
|
16306
|
-
import * as
|
|
16496
|
+
import * as path17 from "path";
|
|
16307
16497
|
import { Command as Command28, Option as Option26 } from "clipanion";
|
|
16308
16498
|
import { DefaultAzureCredential as DefaultAzureCredential13 } from "@azure/identity";
|
|
16309
16499
|
init_errors();
|
|
@@ -16570,14 +16760,14 @@ async function deployHostedWorker(args) {
|
|
|
16570
16760
|
}
|
|
16571
16761
|
|
|
16572
16762
|
// src/lib/persona.ts
|
|
16573
|
-
import * as
|
|
16574
|
-
import * as
|
|
16763
|
+
import * as fs18 from "fs";
|
|
16764
|
+
import * as path16 from "path";
|
|
16575
16765
|
import { parse as parseYaml9 } from "yaml";
|
|
16576
16766
|
function findRepoRoot(startDir) {
|
|
16577
|
-
let dir =
|
|
16767
|
+
let dir = path16.resolve(startDir);
|
|
16578
16768
|
for (; ; ) {
|
|
16579
|
-
if (
|
|
16580
|
-
const parent =
|
|
16769
|
+
if (fs18.existsSync(path16.join(dir, "personas"))) return dir;
|
|
16770
|
+
const parent = path16.dirname(dir);
|
|
16581
16771
|
if (parent === dir) return null;
|
|
16582
16772
|
dir = parent;
|
|
16583
16773
|
}
|
|
@@ -16585,10 +16775,10 @@ function findRepoRoot(startDir) {
|
|
|
16585
16775
|
function resolvePersona(persona, cwd = process.cwd()) {
|
|
16586
16776
|
const root = findRepoRoot(cwd);
|
|
16587
16777
|
if (!root) return { persona, personaVersion: null };
|
|
16588
|
-
const file =
|
|
16778
|
+
const file = path16.join(root, "personas", persona, "persona.md");
|
|
16589
16779
|
let raw;
|
|
16590
16780
|
try {
|
|
16591
|
-
raw =
|
|
16781
|
+
raw = fs18.readFileSync(file, "utf-8");
|
|
16592
16782
|
} catch {
|
|
16593
16783
|
return { persona, personaVersion: null };
|
|
16594
16784
|
}
|
|
@@ -16925,7 +17115,7 @@ var CoderDeployCommand = class extends M8tCommand {
|
|
|
16925
17115
|
projectEndpoint: project.endpoint,
|
|
16926
17116
|
projectArmId: `${project.accountScope}/projects/${project.projectName}`,
|
|
16927
17117
|
agentName: this.name,
|
|
16928
|
-
personaPath:
|
|
17118
|
+
personaPath: path17.join(resolveRepoRoot(), "personas", personaName, "persona.md"),
|
|
16929
17119
|
bridgeUrl,
|
|
16930
17120
|
onProgress
|
|
16931
17121
|
});
|
|
@@ -17051,7 +17241,7 @@ var CoderTeardownCommand = class extends M8tCommand {
|
|
|
17051
17241
|
|
|
17052
17242
|
// src/commands/azure-exec/deploy.ts
|
|
17053
17243
|
init_esm2();
|
|
17054
|
-
import * as
|
|
17244
|
+
import * as path18 from "path";
|
|
17055
17245
|
import { Command as Command30, Option as Option28 } from "clipanion";
|
|
17056
17246
|
import { DefaultAzureCredential as DefaultAzureCredential15 } from "@azure/identity";
|
|
17057
17247
|
init_errors();
|
|
@@ -17321,7 +17511,7 @@ var AzureExecDeployCommand = class extends M8tCommand {
|
|
|
17321
17511
|
kvUri
|
|
17322
17512
|
});
|
|
17323
17513
|
onProgress?.("a2a-enabling as a target\u2026");
|
|
17324
|
-
const personaPath =
|
|
17514
|
+
const personaPath = path18.join(resolveRepoRoot(), "personas", "azure-executor", "persona.md");
|
|
17325
17515
|
const bridgeUrl = resolveBridgeUrl({
|
|
17326
17516
|
flag: typeof this.gatewayUrl === "string" ? this.gatewayUrl : void 0,
|
|
17327
17517
|
env: processEnv
|
|
@@ -17463,8 +17653,8 @@ async function fetchPublicTags(repo, fetchImpl = fetch) {
|
|
|
17463
17653
|
hint: "Pass a ghcr.io/<owner>/<name> repo, or use the BYOC private-ACR deploy flow."
|
|
17464
17654
|
});
|
|
17465
17655
|
}
|
|
17466
|
-
const
|
|
17467
|
-
const tokenRes = await fetchImpl(`https://ghcr.io/token?scope=repository:${
|
|
17656
|
+
const path37 = repo.replace(/^ghcr\.io\//, "");
|
|
17657
|
+
const tokenRes = await fetchImpl(`https://ghcr.io/token?scope=repository:${path37}:pull`);
|
|
17468
17658
|
if (!tokenRes.ok) {
|
|
17469
17659
|
throw new LocalCliError({
|
|
17470
17660
|
code: "PLATFORM_GHCR_TOKEN_FAILED",
|
|
@@ -17480,7 +17670,7 @@ async function fetchPublicTags(repo, fetchImpl = fetch) {
|
|
|
17480
17670
|
hint: "Make the package public (deploy/ghcr-package-visibility.md), then retry."
|
|
17481
17671
|
});
|
|
17482
17672
|
}
|
|
17483
|
-
const tagsRes = await fetchImpl(`https://ghcr.io/v2/${
|
|
17673
|
+
const tagsRes = await fetchImpl(`https://ghcr.io/v2/${path37}/tags/list`, {
|
|
17484
17674
|
headers: { Authorization: `Bearer ${token}` }
|
|
17485
17675
|
});
|
|
17486
17676
|
if (!tagsRes.ok) {
|
|
@@ -17494,7 +17684,7 @@ async function fetchPublicTags(repo, fetchImpl = fetch) {
|
|
|
17494
17684
|
}
|
|
17495
17685
|
|
|
17496
17686
|
// src/lib/release-channel.ts
|
|
17497
|
-
import * as
|
|
17687
|
+
import * as fs19 from "fs";
|
|
17498
17688
|
|
|
17499
17689
|
// ../../packages/platform-release/dist/esm/manifest.js
|
|
17500
17690
|
var SEVERITIES = ["critical", "recommended", "optional"];
|
|
@@ -17661,7 +17851,7 @@ function manifestSourceForVersionTag(channelUrl, version) {
|
|
|
17661
17851
|
return { url: custom };
|
|
17662
17852
|
}
|
|
17663
17853
|
async function fetchManifest(source, deps = {}) {
|
|
17664
|
-
const readFile8 = deps.readFile ?? ((p) =>
|
|
17854
|
+
const readFile8 = deps.readFile ?? ((p) => fs19.readFileSync(p, "utf8"));
|
|
17665
17855
|
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
17666
17856
|
const ghToken = deps.ghToken ?? getGhToken;
|
|
17667
17857
|
let raw;
|
|
@@ -17707,10 +17897,10 @@ async function fetchManifest(source, deps = {}) {
|
|
|
17707
17897
|
}
|
|
17708
17898
|
|
|
17709
17899
|
// src/lib/release-content.ts
|
|
17710
|
-
import * as
|
|
17900
|
+
import * as fs20 from "fs";
|
|
17711
17901
|
import * as os8 from "os";
|
|
17712
|
-
import * as
|
|
17713
|
-
import { execFileSync } from "child_process";
|
|
17902
|
+
import * as path19 from "path";
|
|
17903
|
+
import { execFileSync as execFileSync2 } from "child_process";
|
|
17714
17904
|
init_errors();
|
|
17715
17905
|
var OWNER_REPO = "m8t-run/m8t";
|
|
17716
17906
|
function parseTreeResponse(body) {
|
|
@@ -17748,15 +17938,15 @@ function verifyPersonaTrees(manifest, tree) {
|
|
|
17748
17938
|
}
|
|
17749
17939
|
async function resolveReleaseContent(manifest, opts = {}) {
|
|
17750
17940
|
if (opts.contentDir) {
|
|
17751
|
-
if (!
|
|
17941
|
+
if (!fs20.existsSync(path19.join(opts.contentDir, "personas"))) {
|
|
17752
17942
|
throw new LocalCliError({ code: "PLATFORM_CONTENT_DIR_INVALID", message: `--content-dir '${opts.contentDir}' has no personas/ \u2014 not a repo checkout.` });
|
|
17753
17943
|
}
|
|
17754
17944
|
return opts.contentDir;
|
|
17755
17945
|
}
|
|
17756
17946
|
const commit = manifest.platform.commit;
|
|
17757
|
-
const cacheRoot = opts.cacheRoot ??
|
|
17758
|
-
const dest =
|
|
17759
|
-
if (
|
|
17947
|
+
const cacheRoot = opts.cacheRoot ?? path19.join(os8.homedir(), ".m8t-stack", "cache");
|
|
17948
|
+
const dest = path19.join(cacheRoot, `release-${commit}`);
|
|
17949
|
+
if (fs20.existsSync(path19.join(dest, "personas"))) return dest;
|
|
17760
17950
|
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
17761
17951
|
const ghToken = opts.ghToken ?? getGhToken;
|
|
17762
17952
|
let token;
|
|
@@ -17770,19 +17960,19 @@ async function resolveReleaseContent(manifest, opts = {}) {
|
|
|
17770
17960
|
if (!res.ok) {
|
|
17771
17961
|
throw new LocalCliError({ code: "PLATFORM_TARBALL_FETCH_FAILED", message: `GET ${url} \u2192 HTTP ${res.status.toString()}.` });
|
|
17772
17962
|
}
|
|
17773
|
-
|
|
17774
|
-
const tmp =
|
|
17963
|
+
fs20.mkdirSync(cacheRoot, { recursive: true });
|
|
17964
|
+
const tmp = fs20.mkdtempSync(path19.join(cacheRoot, `.dl-${commit.slice(0, 8)}-`));
|
|
17775
17965
|
try {
|
|
17776
|
-
const tgz =
|
|
17777
|
-
|
|
17778
|
-
const unpacked =
|
|
17779
|
-
|
|
17966
|
+
const tgz = path19.join(tmp, "src.tar.gz");
|
|
17967
|
+
fs20.writeFileSync(tgz, Buffer.from(await res.arrayBuffer()));
|
|
17968
|
+
const unpacked = path19.join(tmp, "unpacked");
|
|
17969
|
+
fs20.mkdirSync(unpacked);
|
|
17780
17970
|
extractTarGz(tgz, unpacked);
|
|
17781
17971
|
try {
|
|
17782
|
-
|
|
17972
|
+
fs20.renameSync(unpacked, dest);
|
|
17783
17973
|
} catch (e) {
|
|
17784
17974
|
const err = e;
|
|
17785
|
-
const isBenignRace = (err.code === "EEXIST" || err.code === "ENOTEMPTY") &&
|
|
17975
|
+
const isBenignRace = (err.code === "EEXIST" || err.code === "ENOTEMPTY") && fs20.existsSync(path19.join(dest, "personas"));
|
|
17786
17976
|
if (!isBenignRace) {
|
|
17787
17977
|
throw new LocalCliError({
|
|
17788
17978
|
code: "PLATFORM_CACHE_PUBLISH_FAILED",
|
|
@@ -17791,12 +17981,12 @@ async function resolveReleaseContent(manifest, opts = {}) {
|
|
|
17791
17981
|
}
|
|
17792
17982
|
}
|
|
17793
17983
|
} finally {
|
|
17794
|
-
|
|
17984
|
+
fs20.rmSync(tmp, { recursive: true, force: true });
|
|
17795
17985
|
}
|
|
17796
17986
|
return dest;
|
|
17797
17987
|
}
|
|
17798
17988
|
function extractTarGz(tgz, into) {
|
|
17799
|
-
|
|
17989
|
+
execFileSync2("tar", ["-xzf", tgz, "-C", into, "--strip-components=1"]);
|
|
17800
17990
|
}
|
|
17801
17991
|
|
|
17802
17992
|
// src/lib/platform-stamp.ts
|
|
@@ -17918,14 +18108,14 @@ function sleep2(ms) {
|
|
|
17918
18108
|
}
|
|
17919
18109
|
|
|
17920
18110
|
// src/lib/platform-converge.ts
|
|
17921
|
-
import * as
|
|
17922
|
-
import * as
|
|
18111
|
+
import * as fs22 from "fs";
|
|
18112
|
+
import * as path21 from "path";
|
|
17923
18113
|
import { parse as parseYaml10 } from "yaml";
|
|
17924
18114
|
|
|
17925
18115
|
// src/lib/deploy.ts
|
|
17926
|
-
import * as
|
|
18116
|
+
import * as fs21 from "fs/promises";
|
|
17927
18117
|
import * as os9 from "os";
|
|
17928
|
-
import * as
|
|
18118
|
+
import * as path20 from "path";
|
|
17929
18119
|
init_errors();
|
|
17930
18120
|
var FOUNDRY_TRACING_MODES = ["project", "account", "skip"];
|
|
17931
18121
|
function parseFoundryTracingMode(v) {
|
|
@@ -17973,9 +18163,9 @@ function buildBicepParams(p) {
|
|
|
17973
18163
|
return params;
|
|
17974
18164
|
}
|
|
17975
18165
|
async function resolveRepoRoot2(home = os9.homedir()) {
|
|
17976
|
-
const marker =
|
|
18166
|
+
const marker = path20.join(home, ".m8t-stack", "repo-root");
|
|
17977
18167
|
try {
|
|
17978
|
-
const root = (await
|
|
18168
|
+
const root = (await fs21.readFile(marker, "utf8")).trim();
|
|
17979
18169
|
if (!root) throw new Error("empty");
|
|
17980
18170
|
return root;
|
|
17981
18171
|
} catch {
|
|
@@ -18052,7 +18242,7 @@ function resolveAcrPullIdentity(opts) {
|
|
|
18052
18242
|
return opts.explicit ?? "";
|
|
18053
18243
|
}
|
|
18054
18244
|
async function runBicepDeployment(opts) {
|
|
18055
|
-
const bicepPath =
|
|
18245
|
+
const bicepPath = path20.join(opts.repoRoot, "deploy", "main.bicep");
|
|
18056
18246
|
const result = JSON.parse(
|
|
18057
18247
|
await runAz([
|
|
18058
18248
|
"deployment",
|
|
@@ -18123,7 +18313,16 @@ function sortObj(o) {
|
|
|
18123
18313
|
}
|
|
18124
18314
|
|
|
18125
18315
|
// src/lib/platform-converge.ts
|
|
18126
|
-
var ORDER = ["infra", "gateway", "codingAgent", "azureExecutor", "personas"];
|
|
18316
|
+
var ORDER = ["infra", "gateway", "codingAgent", "azureExecutor", "personas", "brainSeeds"];
|
|
18317
|
+
function seedSetRev(manifest) {
|
|
18318
|
+
const items = manifest.components.brainSeeds.items;
|
|
18319
|
+
const parts = [];
|
|
18320
|
+
for (const name of Object.keys(items).sort()) {
|
|
18321
|
+
const subs = items[name].subtrees;
|
|
18322
|
+
for (const sub of Object.keys(subs).sort()) parts.push(`${name}:${sub}:${subs[sub] ?? "-"}`);
|
|
18323
|
+
}
|
|
18324
|
+
return parts.join("|");
|
|
18325
|
+
}
|
|
18127
18326
|
function infraTargetSha(manifest, tree) {
|
|
18128
18327
|
return manifest.components.infra?.treeSha ?? tree.treeShaOf("deploy") ?? "";
|
|
18129
18328
|
}
|
|
@@ -18159,6 +18358,16 @@ function diffPlan(manifest, stamp, tree, opts = {}) {
|
|
|
18159
18358
|
}
|
|
18160
18359
|
continue;
|
|
18161
18360
|
}
|
|
18361
|
+
if (component === "brainSeeds") {
|
|
18362
|
+
const to = seedSetRev(manifest);
|
|
18363
|
+
const from2 = stamp?.components.brainSeeds?.seedRev ?? null;
|
|
18364
|
+
const targeted = opts.only === "brainSeeds";
|
|
18365
|
+
if (adopt) actions.push({ component, reason: "adopt", from: from2, to });
|
|
18366
|
+
else if (targeted) actions.push({ component, reason: from2 === to ? "forced" : "changed", from: from2, to });
|
|
18367
|
+
else if (from2 !== to) actions.push({ component, reason: "changed", from: from2, to });
|
|
18368
|
+
else skipped.push({ component, reason: "up-to-date" });
|
|
18369
|
+
continue;
|
|
18370
|
+
}
|
|
18162
18371
|
const img = manifest.components[component];
|
|
18163
18372
|
const cur = stamp?.components[component];
|
|
18164
18373
|
if (cur?.state === "external") {
|
|
@@ -18202,6 +18411,7 @@ function installedValueOf(stamp, component, personaName) {
|
|
|
18202
18411
|
if (!personaName || !Object.hasOwn(stamp.components.personas, personaName)) return "-";
|
|
18203
18412
|
return stamp.components.personas[personaName].treeSha;
|
|
18204
18413
|
}
|
|
18414
|
+
if (component === "brainSeeds") return stamp.components.brainSeeds?.seedRev ?? "-";
|
|
18205
18415
|
return stamp.components[component].tag;
|
|
18206
18416
|
}
|
|
18207
18417
|
function targetValueOf(manifest, tree, component, personaName) {
|
|
@@ -18210,6 +18420,7 @@ function targetValueOf(manifest, tree, component, personaName) {
|
|
|
18210
18420
|
if (!personaName || !Object.hasOwn(manifest.components.personas.items, personaName)) return "-";
|
|
18211
18421
|
return manifest.components.personas.items[personaName].treeSha;
|
|
18212
18422
|
}
|
|
18423
|
+
if (component === "brainSeeds") return seedSetRev(manifest) || "-";
|
|
18213
18424
|
return manifest.components[component].tag;
|
|
18214
18425
|
}
|
|
18215
18426
|
async function applyPlan(plan, deps, ctx) {
|
|
@@ -18230,6 +18441,18 @@ async function applyPlan(plan, deps, ctx) {
|
|
|
18230
18441
|
continue;
|
|
18231
18442
|
}
|
|
18232
18443
|
stamp.components[a.component] = { ...r, state: "managed" };
|
|
18444
|
+
} else if (a.component === "brainSeeds") {
|
|
18445
|
+
if (!deps.applySeedRefresh) {
|
|
18446
|
+
ctx.onProgress?.("brainSeeds: seed refresh is not supported by this driver (CLI-only in v1) \u2014 skipped.");
|
|
18447
|
+
continue;
|
|
18448
|
+
}
|
|
18449
|
+
const r = await deps.applySeedRefresh(a, ctx);
|
|
18450
|
+
ctx.onProgress?.(`brainSeeds: delivered to ${r.delivered.toString()} repo(s), ${r.noop.toString()} already current.`);
|
|
18451
|
+
if (!r.converged) {
|
|
18452
|
+
ctx.onProgress?.("brainSeeds: not fully delivered (no Key Vault, or some repos failed) \u2014 stamp NOT advanced; will retry next converge.");
|
|
18453
|
+
continue;
|
|
18454
|
+
}
|
|
18455
|
+
stamp.components.brainSeeds = { seedRev: a.to };
|
|
18233
18456
|
} else {
|
|
18234
18457
|
if (!a.personaName) {
|
|
18235
18458
|
throw new LocalCliError({ code: "PLATFORM_PERSONA_NO_NAME", message: "persona action missing personaName" });
|
|
@@ -18282,7 +18505,14 @@ function seedStamp(prior, manifest, plan) {
|
|
|
18282
18505
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
18283
18506
|
lastResult: "partial",
|
|
18284
18507
|
cli: "",
|
|
18285
|
-
components: {
|
|
18508
|
+
components: {
|
|
18509
|
+
gateway: blankImg(),
|
|
18510
|
+
codingAgent: blankImg(),
|
|
18511
|
+
azureExecutor: blankImg(),
|
|
18512
|
+
personas: {},
|
|
18513
|
+
infra: { treeSha: "" },
|
|
18514
|
+
brainSeeds: { seedRev: "" }
|
|
18515
|
+
}
|
|
18286
18516
|
};
|
|
18287
18517
|
}
|
|
18288
18518
|
async function applyGatewayImage(a, ctx, gatewayResourceId) {
|
|
@@ -18376,7 +18606,7 @@ async function applyAgentImage(a, ctx, opts) {
|
|
|
18376
18606
|
function declaredFillableFields(personaPath) {
|
|
18377
18607
|
let raw;
|
|
18378
18608
|
try {
|
|
18379
|
-
raw =
|
|
18609
|
+
raw = fs22.readFileSync(personaPath, "utf8");
|
|
18380
18610
|
} catch {
|
|
18381
18611
|
return [];
|
|
18382
18612
|
}
|
|
@@ -18402,7 +18632,7 @@ function injectAndRender(personaPath, values, agentName) {
|
|
|
18402
18632
|
function loaderText(loaderPath) {
|
|
18403
18633
|
if (!loaderPath) return null;
|
|
18404
18634
|
try {
|
|
18405
|
-
return
|
|
18635
|
+
return fs22.readFileSync(loaderPath, "utf8");
|
|
18406
18636
|
} catch {
|
|
18407
18637
|
return null;
|
|
18408
18638
|
}
|
|
@@ -18419,7 +18649,7 @@ function brainRepoOf(current) {
|
|
|
18419
18649
|
}
|
|
18420
18650
|
async function applyPersona(a, ctx, opts) {
|
|
18421
18651
|
const current = await getAgentVersion({ credential: ctx.credential, projectEndpoint: opts.project.endpoint, agentName: opts.agentName });
|
|
18422
|
-
const personaPath =
|
|
18652
|
+
const personaPath = path21.join(opts.personaDir, "persona.md");
|
|
18423
18653
|
const yamlValues = readAgentYaml(opts.agentName)?.fillableFieldValues ?? null;
|
|
18424
18654
|
const values = resolveFillableValues(current, yamlValues);
|
|
18425
18655
|
const declared = declaredFillableFields(personaPath);
|
|
@@ -18618,7 +18848,7 @@ import { confirm as confirm5 } from "@inquirer/prompts";
|
|
|
18618
18848
|
import { DefaultAzureCredential as DefaultAzureCredential17 } from "@azure/identity";
|
|
18619
18849
|
|
|
18620
18850
|
// src/lib/platform-converge-cli.ts
|
|
18621
|
-
import * as
|
|
18851
|
+
import * as path25 from "path";
|
|
18622
18852
|
|
|
18623
18853
|
// src/lib/platform-infra-params.ts
|
|
18624
18854
|
import { TableClient as TableClient2 } from "@azure/data-tables";
|
|
@@ -18673,6 +18903,356 @@ async function deriveSuffixVerified(opts) {
|
|
|
18673
18903
|
|
|
18674
18904
|
// src/lib/platform-converge-cli.ts
|
|
18675
18905
|
init_errors();
|
|
18906
|
+
|
|
18907
|
+
// src/lib/seed-refresh-driver.ts
|
|
18908
|
+
init_esm2();
|
|
18909
|
+
import * as path24 from "path";
|
|
18910
|
+
|
|
18911
|
+
// src/lib/seed-refresh.ts
|
|
18912
|
+
init_errors();
|
|
18913
|
+
import * as fs24 from "fs";
|
|
18914
|
+
import * as path23 from "path";
|
|
18915
|
+
|
|
18916
|
+
// src/lib/seed-merge.ts
|
|
18917
|
+
import * as fs23 from "fs";
|
|
18918
|
+
import * as os10 from "os";
|
|
18919
|
+
import * as path22 from "path";
|
|
18920
|
+
import { spawnSync as spawnSync3 } from "child_process";
|
|
18921
|
+
function isProbablyText(s) {
|
|
18922
|
+
return !s.includes("\0");
|
|
18923
|
+
}
|
|
18924
|
+
function mergeThreeWay(ours, base, theirs) {
|
|
18925
|
+
if (![ours, base, theirs].every(isProbablyText)) {
|
|
18926
|
+
return { ok: false, merged: "" };
|
|
18927
|
+
}
|
|
18928
|
+
const lf = (s) => s.replace(/\r\n/g, "\n");
|
|
18929
|
+
const dir = fs23.mkdtempSync(path22.join(os10.tmpdir(), "seed-merge-"));
|
|
18930
|
+
try {
|
|
18931
|
+
const o = path22.join(dir, "ours");
|
|
18932
|
+
const b = path22.join(dir, "base");
|
|
18933
|
+
const t = path22.join(dir, "theirs");
|
|
18934
|
+
fs23.writeFileSync(o, lf(ours));
|
|
18935
|
+
fs23.writeFileSync(b, lf(base));
|
|
18936
|
+
fs23.writeFileSync(t, lf(theirs));
|
|
18937
|
+
const res = spawnSync3(
|
|
18938
|
+
"git",
|
|
18939
|
+
["merge-file", "-p", "--diff3", o, b, t],
|
|
18940
|
+
{
|
|
18941
|
+
encoding: "utf8",
|
|
18942
|
+
maxBuffer: 32 * 1024 * 1024
|
|
18943
|
+
}
|
|
18944
|
+
);
|
|
18945
|
+
if (res.status === 0) {
|
|
18946
|
+
return { ok: true, merged: res.stdout };
|
|
18947
|
+
}
|
|
18948
|
+
return { ok: false, merged: "" };
|
|
18949
|
+
} finally {
|
|
18950
|
+
fs23.rmSync(dir, { recursive: true, force: true });
|
|
18951
|
+
}
|
|
18952
|
+
}
|
|
18953
|
+
var skip = (path37, skipReason) => ({ path: path37, kind: "skip", skipReason });
|
|
18954
|
+
function classifyCandidate(c) {
|
|
18955
|
+
const { path: path37, base, ours, theirs } = c;
|
|
18956
|
+
if (theirs === base) return { path: path37, kind: "noop" };
|
|
18957
|
+
if (base === null) {
|
|
18958
|
+
if (theirs === null) return { path: path37, kind: "noop" };
|
|
18959
|
+
if (ours === null) return { path: path37, kind: "add", content: theirs };
|
|
18960
|
+
if (ours === theirs) return { path: path37, kind: "noop" };
|
|
18961
|
+
return skip(path37, "you already have a file at this path");
|
|
18962
|
+
}
|
|
18963
|
+
if (ours === null) {
|
|
18964
|
+
return theirs === null ? { path: path37, kind: "noop" } : skip(path37, "you removed this file; upstream changed it");
|
|
18965
|
+
}
|
|
18966
|
+
if (theirs === null) {
|
|
18967
|
+
return ours === base ? { path: path37, kind: "delete" } : skip(path37, "you edited this file; upstream removed it");
|
|
18968
|
+
}
|
|
18969
|
+
if (ours === base) return { path: path37, kind: "update", content: theirs };
|
|
18970
|
+
const m = mergeThreeWay(ours, base, theirs);
|
|
18971
|
+
return m.ok ? { path: path37, kind: "update", content: m.merged } : skip(path37, "your edits conflict with the update");
|
|
18972
|
+
}
|
|
18973
|
+
|
|
18974
|
+
// src/lib/seed-pr-body.ts
|
|
18975
|
+
function composeSeedPrTitle(s) {
|
|
18976
|
+
return `Update your ${s.advisorLabel}'s built-in skills & guides (${s.version})`;
|
|
18977
|
+
}
|
|
18978
|
+
var basename = (p) => p.split("/").filter(Boolean).slice(-2).join("/");
|
|
18979
|
+
function composeSeedPrBody(s) {
|
|
18980
|
+
const lines = [];
|
|
18981
|
+
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}**.`);
|
|
18982
|
+
lines.push("");
|
|
18983
|
+
if (s.updated.length || s.added.length || s.deleted.length) {
|
|
18984
|
+
lines.push("**What changed**");
|
|
18985
|
+
if (s.updated.length) lines.push(`- \u270F\uFE0F Updated ${s.updated.length.toString()}: ${s.updated.map(basename).join(", ")}`);
|
|
18986
|
+
if (s.added.length) lines.push(`- \u2795 Added ${s.added.length.toString()}: ${s.added.map(basename).join(", ")}`);
|
|
18987
|
+
if (s.deleted.length) lines.push(`- \u{1F5D1}\uFE0F Removed ${s.deleted.length.toString()}: ${s.deleted.map(basename).join(", ")}`);
|
|
18988
|
+
lines.push("");
|
|
18989
|
+
}
|
|
18990
|
+
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.");
|
|
18991
|
+
if (s.skipped.length) {
|
|
18992
|
+
lines.push("");
|
|
18993
|
+
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:`);
|
|
18994
|
+
for (const sk of s.skipped) lines.push(`- \`${sk.path}\` \u2014 ${sk.skipReason}`);
|
|
18995
|
+
}
|
|
18996
|
+
lines.push("");
|
|
18997
|
+
lines.push("Your advisor's review workflow will check this PR automatically. Merge whenever you're ready.");
|
|
18998
|
+
lines.push("");
|
|
18999
|
+
lines.push(`\u2014 Opened by the m8t platform \xB7 release ${s.version}${s.notesUrl ? ` \xB7 [release notes](${s.notesUrl})` : ""}`);
|
|
19000
|
+
return lines.join("\n");
|
|
19001
|
+
}
|
|
19002
|
+
|
|
19003
|
+
// src/lib/seed-refresh.ts
|
|
19004
|
+
function readIf(dir, rel) {
|
|
19005
|
+
if (!dir) return null;
|
|
19006
|
+
const abs = path23.join(dir, rel);
|
|
19007
|
+
return fs24.existsSync(abs) ? fs24.readFileSync(abs, "utf8") : null;
|
|
19008
|
+
}
|
|
19009
|
+
async function assembleCandidates(args) {
|
|
19010
|
+
const paths = /* @__PURE__ */ new Set([...args.lineage?.ownedPaths ?? [], ...args.trees.ownedAtTheirs]);
|
|
19011
|
+
const out = [];
|
|
19012
|
+
for (const p of [...paths].sort((a, b) => a.localeCompare(b))) {
|
|
19013
|
+
out.push({ path: p, base: readIf(args.trees.baseDir, p), theirs: readIf(args.trees.theirsDir, p), ours: await args.source.readOurs(p) });
|
|
19014
|
+
}
|
|
19015
|
+
return out;
|
|
19016
|
+
}
|
|
19017
|
+
function assertNoDanglingIndexRefs(finalPaths, repoHas, indexBodies) {
|
|
19018
|
+
const refRe = /skills\/[^)\s]+\/SKILL\.md/g;
|
|
19019
|
+
for (const idx of indexBodies) {
|
|
19020
|
+
for (const m of idx.body.matchAll(refRe)) {
|
|
19021
|
+
const ref = m[0];
|
|
19022
|
+
if (!finalPaths.has(ref) && !repoHas(ref)) {
|
|
19023
|
+
throw new LocalCliError({
|
|
19024
|
+
code: "PLATFORM_SEED_INDEX_DANGLING",
|
|
19025
|
+
message: `Refusing to open a PR: ${idx.path} would reference a missing skill '${ref}'. The brain loader only opens indexed paths.`
|
|
19026
|
+
});
|
|
19027
|
+
}
|
|
19028
|
+
}
|
|
19029
|
+
}
|
|
19030
|
+
}
|
|
19031
|
+
async function refreshBrainRepo(args) {
|
|
19032
|
+
const cands = await assembleCandidates({ lineage: args.lineage, trees: args.trees, source: args.source, seedName: args.seedName });
|
|
19033
|
+
const outcomes = cands.map(classifyCandidate);
|
|
19034
|
+
const files = [];
|
|
19035
|
+
const updated = [];
|
|
19036
|
+
const added = [];
|
|
19037
|
+
const deleted = [];
|
|
19038
|
+
const skipped = [];
|
|
19039
|
+
const indexBodies = [];
|
|
19040
|
+
const finalPaths = /* @__PURE__ */ new Set();
|
|
19041
|
+
for (const o of outcomes) {
|
|
19042
|
+
if (o.path === SEED_MANIFEST_PATH) continue;
|
|
19043
|
+
if (o.kind === "update") {
|
|
19044
|
+
files.push({ path: o.path, content: o.content ?? "" });
|
|
19045
|
+
updated.push(o.path);
|
|
19046
|
+
finalPaths.add(o.path);
|
|
19047
|
+
} else if (o.kind === "add") {
|
|
19048
|
+
files.push({ path: o.path, content: o.content ?? "" });
|
|
19049
|
+
added.push(o.path);
|
|
19050
|
+
finalPaths.add(o.path);
|
|
19051
|
+
} else if (o.kind === "delete") {
|
|
19052
|
+
files.push({ path: o.path, delete: true });
|
|
19053
|
+
deleted.push(o.path);
|
|
19054
|
+
} else if (o.kind === "skip") {
|
|
19055
|
+
skipped.push({ path: o.path, skipReason: o.skipReason ?? "left as-is" });
|
|
19056
|
+
}
|
|
19057
|
+
if (o.path.endsWith("/_index.md") && (o.kind === "update" || o.kind === "add")) {
|
|
19058
|
+
indexBodies.push({ path: o.path, body: o.content ?? "" });
|
|
19059
|
+
}
|
|
19060
|
+
}
|
|
19061
|
+
const contentChanged = updated.length + added.length + deleted.length > 0;
|
|
19062
|
+
if (!contentChanged) {
|
|
19063
|
+
return { repo: args.repo, prUrl: null, action: "noop", updated, added, deleted, skipped };
|
|
19064
|
+
}
|
|
19065
|
+
const ownedNow = new Set(args.trees.ownedAtTheirs);
|
|
19066
|
+
assertNoDanglingIndexRefs(finalPaths, (p) => ownedNow.has(p), indexBodies);
|
|
19067
|
+
const newOwned = deriveOwnedPaths(args.trees.theirsDir);
|
|
19068
|
+
const nextManifest = upsertLineage(
|
|
19069
|
+
args.priorManifest ?? (args.lineage ? { schemaVersion: 1, seeds: [args.lineage] } : null),
|
|
19070
|
+
{
|
|
19071
|
+
name: args.seedName,
|
|
19072
|
+
refreshedToCommit: args.targetCommit ?? "",
|
|
19073
|
+
refreshedToVersion: args.version,
|
|
19074
|
+
ownedPaths: newOwned
|
|
19075
|
+
}
|
|
19076
|
+
);
|
|
19077
|
+
files.push({ path: SEED_MANIFEST_PATH, content: serializeSeedManifest(nextManifest) });
|
|
19078
|
+
for (const sb of args.supersedeBranches ?? []) {
|
|
19079
|
+
if (sb === args.branch) continue;
|
|
19080
|
+
const stale = await args.api.findOpenPr(sb);
|
|
19081
|
+
if (stale) await args.api.closePr(stale.number, `superseded by the newer update on \`${args.branch}\`.`);
|
|
19082
|
+
}
|
|
19083
|
+
const opened = await args.api.findOpenPr(args.branch);
|
|
19084
|
+
const headSha = await args.api.getHeadSha(args.base);
|
|
19085
|
+
await args.api.commitFromBase(files, args.branch, headSha, `chore(seed): refresh built-in skills & guides (${args.version})`);
|
|
19086
|
+
const summary = {
|
|
19087
|
+
advisorLabel: args.advisorLabel,
|
|
19088
|
+
version: args.version,
|
|
19089
|
+
notesUrl: args.notesUrl,
|
|
19090
|
+
repo: args.repo,
|
|
19091
|
+
updated,
|
|
19092
|
+
added,
|
|
19093
|
+
deleted,
|
|
19094
|
+
skipped
|
|
19095
|
+
};
|
|
19096
|
+
const title = composeSeedPrTitle(summary);
|
|
19097
|
+
const body = composeSeedPrBody(summary);
|
|
19098
|
+
if (opened) {
|
|
19099
|
+
await args.api.updatePr(opened.number, title, body);
|
|
19100
|
+
return { repo: args.repo, prUrl: opened.htmlUrl, action: "updated", updated, added, deleted, skipped };
|
|
19101
|
+
}
|
|
19102
|
+
const pr = await args.api.openPr(args.branch, args.base, title, body);
|
|
19103
|
+
return { repo: args.repo, prUrl: pr.htmlUrl, action: args.lineage ? "opened" : "bootstrapped", updated, added, deleted, skipped };
|
|
19104
|
+
}
|
|
19105
|
+
|
|
19106
|
+
// src/lib/seed-refresh-driver.ts
|
|
19107
|
+
var PERSONA_SEED_MAP = {
|
|
19108
|
+
"startup-advisor": "startup-advisor",
|
|
19109
|
+
"azure-advisor": "azure-advisor"
|
|
19110
|
+
};
|
|
19111
|
+
var ADVISOR_LABEL = {
|
|
19112
|
+
"startup-advisor": "Startup Advisor",
|
|
19113
|
+
"azure-advisor": "Azure Advisor"
|
|
19114
|
+
};
|
|
19115
|
+
function dedupeBrainRepos(agents) {
|
|
19116
|
+
const byRepo = /* @__PURE__ */ new Map();
|
|
19117
|
+
for (const a of agents) {
|
|
19118
|
+
const raw = a.metadata.brain;
|
|
19119
|
+
if (!raw) continue;
|
|
19120
|
+
let repo;
|
|
19121
|
+
let installationId;
|
|
19122
|
+
try {
|
|
19123
|
+
const parsed = JSON.parse(raw);
|
|
19124
|
+
repo = parsed.repo;
|
|
19125
|
+
installationId = parsed.installationId;
|
|
19126
|
+
} catch {
|
|
19127
|
+
repo = void 0;
|
|
19128
|
+
installationId = void 0;
|
|
19129
|
+
}
|
|
19130
|
+
if (!repo || !installationId) continue;
|
|
19131
|
+
const seedName = a.metadata.persona ? PERSONA_SEED_MAP[a.metadata.persona] ?? null : null;
|
|
19132
|
+
if (!byRepo.has(repo)) byRepo.set(repo, { repo, seedName, installationId });
|
|
19133
|
+
}
|
|
19134
|
+
return [...byRepo.values()];
|
|
19135
|
+
}
|
|
19136
|
+
function seedContentDir(contentRoot, manifest, seedName) {
|
|
19137
|
+
const items = manifest.components.brainSeeds.items;
|
|
19138
|
+
if (!Object.hasOwn(items, seedName)) return null;
|
|
19139
|
+
return path24.join(contentRoot, items[seedName].path);
|
|
19140
|
+
}
|
|
19141
|
+
function bindRepoApi(token, repo) {
|
|
19142
|
+
return {
|
|
19143
|
+
getDefaultBranch: () => Promise.resolve("main"),
|
|
19144
|
+
getHeadSha: async (branch) => {
|
|
19145
|
+
const res = await fetch(`https://api.github.com/repos/${repo}/git/ref/heads/${branch}`, {
|
|
19146
|
+
headers: { Authorization: `token ${token}`, Accept: "application/vnd.github+json", "User-Agent": "m8t" }
|
|
19147
|
+
});
|
|
19148
|
+
const j = await res.json();
|
|
19149
|
+
return j.object?.sha ?? "";
|
|
19150
|
+
},
|
|
19151
|
+
findOpenPr: (head) => findOpenPr({ token, repo, head }),
|
|
19152
|
+
commitFromBase: (files, branch, baseSha, message) => commitFilesFromBaseViaApp({ token, repo, branch, baseSha, files, message }),
|
|
19153
|
+
openPr: (head, base, title, body) => openPullRequestViaApp({ token, repo, base, head, title, body }),
|
|
19154
|
+
updatePr: (n, title, body) => updatePullRequestViaApp({ token, repo, number: n, title, body }),
|
|
19155
|
+
closePr: (n, comment) => closePullRequestViaApp({ token, repo, number: n, comment }),
|
|
19156
|
+
readFileAtRef: (path37, ref) => readRepoFileViaApp({ token, repo, path: path37, ref })
|
|
19157
|
+
};
|
|
19158
|
+
}
|
|
19159
|
+
async function runSeedRefresh(args) {
|
|
19160
|
+
const targetCommit = args.manifest.platform.commit;
|
|
19161
|
+
const theirsRoot = await resolveReleaseContent(args.manifest, {});
|
|
19162
|
+
const repos = dedupeBrainRepos(args.agents);
|
|
19163
|
+
const results = [];
|
|
19164
|
+
let delivered = 0;
|
|
19165
|
+
let noop2 = 0;
|
|
19166
|
+
let failed = 0;
|
|
19167
|
+
for (const ref of repos) {
|
|
19168
|
+
try {
|
|
19169
|
+
const minted = await mintInstallationToken({
|
|
19170
|
+
credential: args.credential,
|
|
19171
|
+
kvUri: args.kvUri,
|
|
19172
|
+
installationId: ref.installationId,
|
|
19173
|
+
repository: ref.repo,
|
|
19174
|
+
permissions: { contents: "write", pull_requests: "write" }
|
|
19175
|
+
});
|
|
19176
|
+
const token = minted.token;
|
|
19177
|
+
const probe = appRepoProbe({ token, repo: ref.repo });
|
|
19178
|
+
const state = await probeRepoState(probe);
|
|
19179
|
+
if (state !== "m8t-brain") {
|
|
19180
|
+
args.onWarn?.(`${ref.repo}: not a reachable m8t brain (${state}) \u2014 skipped.`);
|
|
19181
|
+
continue;
|
|
19182
|
+
}
|
|
19183
|
+
const markerText = await readRepoFileViaApp({ token, repo: ref.repo, path: SEED_MANIFEST_PATH });
|
|
19184
|
+
const marker = parseSeedManifest(markerText);
|
|
19185
|
+
const seedName = ref.seedName ?? marker?.seeds[0]?.name ?? null;
|
|
19186
|
+
if (!seedName) {
|
|
19187
|
+
args.onWarn?.(`${ref.repo}: cannot determine seed lineage \u2014 skipped.`);
|
|
19188
|
+
continue;
|
|
19189
|
+
}
|
|
19190
|
+
const theirsDir = seedContentDir(theirsRoot, args.manifest, seedName);
|
|
19191
|
+
if (!theirsDir) {
|
|
19192
|
+
args.onWarn?.(`${ref.repo}: seed '${seedName}' is not in this release \u2014 skipped.`);
|
|
19193
|
+
continue;
|
|
19194
|
+
}
|
|
19195
|
+
const advisorLabel = ADVISOR_LABEL[seedName] ?? seedName;
|
|
19196
|
+
let lineage = marker?.seeds.find((s) => s.name === seedName) ?? null;
|
|
19197
|
+
let baseDir = null;
|
|
19198
|
+
if (lineage) {
|
|
19199
|
+
try {
|
|
19200
|
+
const baseRoot = await resolveReleaseContent(
|
|
19201
|
+
{ ...args.manifest, platform: { ...args.manifest.platform, commit: lineage.refreshedToCommit } },
|
|
19202
|
+
{}
|
|
19203
|
+
);
|
|
19204
|
+
baseDir = seedContentDir(baseRoot, args.manifest, seedName);
|
|
19205
|
+
} catch {
|
|
19206
|
+
baseDir = null;
|
|
19207
|
+
args.onWarn?.(`${ref.repo}: base rev ${lineage.refreshedToCommit} unfetchable \u2014 falling back to marker-only re-adopt.`);
|
|
19208
|
+
lineage = null;
|
|
19209
|
+
}
|
|
19210
|
+
} else {
|
|
19211
|
+
const initSha = await getInitialSeedCommitSha({ token, repo: ref.repo });
|
|
19212
|
+
if (initSha) {
|
|
19213
|
+
try {
|
|
19214
|
+
const baseRoot = await resolveReleaseContent(
|
|
19215
|
+
{ ...args.manifest, platform: { ...args.manifest.platform, commit: initSha } },
|
|
19216
|
+
{}
|
|
19217
|
+
);
|
|
19218
|
+
baseDir = seedContentDir(baseRoot, args.manifest, seedName);
|
|
19219
|
+
lineage = baseDir ? { name: seedName, refreshedToCommit: initSha, refreshedToVersion: "(bootstrap)", ownedPaths: deriveOwnedPaths(baseDir) } : null;
|
|
19220
|
+
} catch {
|
|
19221
|
+
baseDir = null;
|
|
19222
|
+
}
|
|
19223
|
+
}
|
|
19224
|
+
}
|
|
19225
|
+
const trees = { baseDir, theirsDir, ownedAtTheirs: deriveOwnedPaths(theirsDir) };
|
|
19226
|
+
const source = { readOurs: (p) => readRepoFileViaApp({ token, repo: ref.repo, path: p }) };
|
|
19227
|
+
const res = await refreshBrainRepo({
|
|
19228
|
+
repo: ref.repo,
|
|
19229
|
+
branch: `m8t/seed-update-${args.version}`,
|
|
19230
|
+
base: "main",
|
|
19231
|
+
version: args.version,
|
|
19232
|
+
notesUrl: args.manifest.platform.notesUrl,
|
|
19233
|
+
advisorLabel,
|
|
19234
|
+
seedName,
|
|
19235
|
+
lineage,
|
|
19236
|
+
trees,
|
|
19237
|
+
source,
|
|
19238
|
+
api: bindRepoApi(token, ref.repo),
|
|
19239
|
+
targetCommit,
|
|
19240
|
+
priorManifest: marker
|
|
19241
|
+
});
|
|
19242
|
+
results.push(res);
|
|
19243
|
+
if (res.action === "noop") noop2++;
|
|
19244
|
+
else delivered++;
|
|
19245
|
+
args.onProgress?.(`${ref.repo}: ${res.action}${res.prUrl ? ` \u2192 ${res.prUrl}` : ""}`);
|
|
19246
|
+
} catch (e) {
|
|
19247
|
+
failed++;
|
|
19248
|
+
args.onWarn?.(`${ref.repo}: seed refresh failed \u2014 ${e.message}; skipped this repo.`);
|
|
19249
|
+
continue;
|
|
19250
|
+
}
|
|
19251
|
+
}
|
|
19252
|
+
return { delivered, noop: noop2, failed, results };
|
|
19253
|
+
}
|
|
19254
|
+
|
|
19255
|
+
// src/lib/platform-converge-cli.ts
|
|
18676
19256
|
var HOSTED_AGENT_PERSONA_DIR = {
|
|
18677
19257
|
codingAgent: "coding-agent",
|
|
18678
19258
|
azureExecutor: "azure-executor"
|
|
@@ -18686,7 +19266,7 @@ async function buildConvergeDeps(args) {
|
|
|
18686
19266
|
const persona = a.metadata.persona;
|
|
18687
19267
|
if (persona) discovered[persona] = a.name;
|
|
18688
19268
|
}
|
|
18689
|
-
const loaderPath =
|
|
19269
|
+
const loaderPath = path25.join(args.contentDir, "targets/foundry/brain-loader.md");
|
|
18690
19270
|
return {
|
|
18691
19271
|
async applyPersona(a, ctx) {
|
|
18692
19272
|
const personaName = a.personaName;
|
|
@@ -18702,7 +19282,7 @@ async function buildConvergeDeps(args) {
|
|
|
18702
19282
|
return applyPersona(a, ctx, {
|
|
18703
19283
|
agentName,
|
|
18704
19284
|
project: args.project,
|
|
18705
|
-
personaDir:
|
|
19285
|
+
personaDir: path25.join(ctx.contentDir, personaItem.path),
|
|
18706
19286
|
loaderPath
|
|
18707
19287
|
});
|
|
18708
19288
|
},
|
|
@@ -18804,6 +19384,31 @@ async function buildConvergeDeps(args) {
|
|
|
18804
19384
|
},
|
|
18805
19385
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
18806
19386
|
});
|
|
19387
|
+
},
|
|
19388
|
+
async applySeedRefresh(_a3, ctx) {
|
|
19389
|
+
let kvUri;
|
|
19390
|
+
try {
|
|
19391
|
+
kvUri = discoverKvUri(process.env);
|
|
19392
|
+
} catch {
|
|
19393
|
+
kvUri = void 0;
|
|
19394
|
+
}
|
|
19395
|
+
if (!kvUri) {
|
|
19396
|
+
warn("brainSeeds: no Key Vault URI (set AZURE_KEYVAULT_URI) \u2014 skipping seed refresh.");
|
|
19397
|
+
return { delivered: 0, noop: 0, converged: false };
|
|
19398
|
+
}
|
|
19399
|
+
const { delivered, noop: noop2, failed } = await runSeedRefresh({
|
|
19400
|
+
credential: args.credential,
|
|
19401
|
+
kvUri,
|
|
19402
|
+
manifest: ctx.manifest,
|
|
19403
|
+
agents: discoveredAgents,
|
|
19404
|
+
version: ctx.manifest.platform.version,
|
|
19405
|
+
onProgress: args.onProgress,
|
|
19406
|
+
onWarn: args.onWarn
|
|
19407
|
+
});
|
|
19408
|
+
if (failed > 0) {
|
|
19409
|
+
warn(`brainSeeds: ${failed.toString()} repo(s) failed to receive a seed update \u2014 re-run 'm8t platform update --only brainSeeds' to retry.`);
|
|
19410
|
+
}
|
|
19411
|
+
return { delivered, noop: noop2, converged: failed === 0 };
|
|
18807
19412
|
}
|
|
18808
19413
|
};
|
|
18809
19414
|
}
|
|
@@ -18843,7 +19448,7 @@ var PlatformUpdateCommand = class extends M8tCommand {
|
|
|
18843
19448
|
description: "Pin the platform version to converge to (defaults to the current release channel)."
|
|
18844
19449
|
});
|
|
18845
19450
|
only = Option30.String("--only", {
|
|
18846
|
-
description: "Converge only one component: infra | gateway | codingAgent | azureExecutor | personas."
|
|
19451
|
+
description: "Converge only one component: infra | gateway | codingAgent | azureExecutor | personas | brainSeeds."
|
|
18847
19452
|
});
|
|
18848
19453
|
check = Option30.Boolean("--check", false);
|
|
18849
19454
|
yes = Option30.Boolean("--yes", false);
|
|
@@ -19057,15 +19662,15 @@ async function patchApplyRequest(client, mutate) {
|
|
|
19057
19662
|
}
|
|
19058
19663
|
|
|
19059
19664
|
// src/lib/platform-self-update.ts
|
|
19060
|
-
import * as
|
|
19061
|
-
import * as
|
|
19665
|
+
import * as fs25 from "fs";
|
|
19666
|
+
import * as path26 from "path";
|
|
19062
19667
|
function toVTag2(v) {
|
|
19063
19668
|
return v.startsWith("v") ? v : `v${v}`;
|
|
19064
19669
|
}
|
|
19065
19670
|
function readBakedReleaseVersion(repoRoot) {
|
|
19066
19671
|
if (!repoRoot) return null;
|
|
19067
19672
|
try {
|
|
19068
|
-
const raw =
|
|
19673
|
+
const raw = fs25.readFileSync(path26.join(repoRoot, "installer", "version.json"), "utf8");
|
|
19069
19674
|
const v = JSON.parse(raw).version;
|
|
19070
19675
|
return typeof v === "string" && v.length > 0 ? v : null;
|
|
19071
19676
|
} catch {
|
|
@@ -20020,7 +20625,7 @@ async function patchRedirectUris(appObjectId, fqdn) {
|
|
|
20020
20625
|
init_errors();
|
|
20021
20626
|
|
|
20022
20627
|
// src/lib/whatif.ts
|
|
20023
|
-
import * as
|
|
20628
|
+
import * as path27 from "path";
|
|
20024
20629
|
function deriveResourceType(resourceId) {
|
|
20025
20630
|
if (resourceId.startsWith("[")) return "";
|
|
20026
20631
|
const afterProviders = resourceId.split("/providers/")[1];
|
|
@@ -20031,7 +20636,7 @@ function deriveResourceType(resourceId) {
|
|
|
20031
20636
|
return parts.join("/");
|
|
20032
20637
|
}
|
|
20033
20638
|
async function runWhatIf(opts) {
|
|
20034
|
-
const bicepPath =
|
|
20639
|
+
const bicepPath = path27.join(opts.repoRoot, "deploy", "main.bicep");
|
|
20035
20640
|
const out = await runAz([
|
|
20036
20641
|
"deployment",
|
|
20037
20642
|
"group",
|
|
@@ -20096,9 +20701,9 @@ function flattenDelta(delta, prefix = "") {
|
|
|
20096
20701
|
const out = [];
|
|
20097
20702
|
for (const d of delta) {
|
|
20098
20703
|
const segment = /^[0-9]+$/.test(d.path) ? `[${d.path}]` : prefix ? `.${d.path}` : d.path;
|
|
20099
|
-
const
|
|
20100
|
-
if (d.children && d.children.length > 0) out.push(...flattenDelta(d.children,
|
|
20101
|
-
else out.push({ ...d, path:
|
|
20704
|
+
const path37 = prefix ? `${prefix}${segment}` : d.path;
|
|
20705
|
+
if (d.children && d.children.length > 0) out.push(...flattenDelta(d.children, path37));
|
|
20706
|
+
else out.push({ ...d, path: path37 });
|
|
20102
20707
|
}
|
|
20103
20708
|
return out;
|
|
20104
20709
|
}
|
|
@@ -20320,7 +20925,7 @@ var DeployCommand = class extends M8tCommand {
|
|
|
20320
20925
|
};
|
|
20321
20926
|
|
|
20322
20927
|
// src/commands/eval/skill.ts
|
|
20323
|
-
import { spawnSync as
|
|
20928
|
+
import { spawnSync as spawnSync4 } from "child_process";
|
|
20324
20929
|
import { Command as Command37, Option as Option34 } from "clipanion";
|
|
20325
20930
|
init_errors();
|
|
20326
20931
|
var DECISIONS = /* @__PURE__ */ new Set(["promote", "reject", "needs_review"]);
|
|
@@ -20372,7 +20977,7 @@ var EvalSkillCommand = class extends M8tCommand {
|
|
|
20372
20977
|
const args = ["skill", candidate2, "--skills-dir", skillsDir, "--json"];
|
|
20373
20978
|
if (this.noJudge === true) args.push("--no-judge");
|
|
20374
20979
|
if (typeof this.deployment === "string") args.push("--deployment", this.deployment);
|
|
20375
|
-
const res =
|
|
20980
|
+
const res = spawnSync4(bin, args, { encoding: "utf-8" });
|
|
20376
20981
|
if (res.error) {
|
|
20377
20982
|
throw new LocalCliError({
|
|
20378
20983
|
code: "BRAIN_EVAL_SPAWN",
|
|
@@ -20409,9 +21014,9 @@ var EvalSkillCommand = class extends M8tCommand {
|
|
|
20409
21014
|
};
|
|
20410
21015
|
|
|
20411
21016
|
// src/commands/eval/exam.ts
|
|
20412
|
-
import { spawnSync as
|
|
20413
|
-
import { writeFileSync as
|
|
20414
|
-
import { join as
|
|
21017
|
+
import { spawnSync as spawnSync5 } from "child_process";
|
|
21018
|
+
import { writeFileSync as writeFileSync6, mkdirSync as mkdirSync5, readFileSync as readFileSync17, existsSync as existsSync15, readdirSync as readdirSync2 } from "fs";
|
|
21019
|
+
import { join as join27 } from "path";
|
|
20415
21020
|
import { Command as Command38, Option as Option35 } from "clipanion";
|
|
20416
21021
|
init_errors();
|
|
20417
21022
|
init_esm();
|
|
@@ -20593,11 +21198,11 @@ function resolveRefereeHome(refereeHomeOut, env) {
|
|
|
20593
21198
|
return null;
|
|
20594
21199
|
}
|
|
20595
21200
|
function resolveTaskSetDir(base, worker, version) {
|
|
20596
|
-
if (
|
|
21201
|
+
if (existsSync15(join27(base, version))) return version;
|
|
20597
21202
|
const prefixed = `${worker}-${version}`;
|
|
20598
|
-
if (
|
|
20599
|
-
if (version === "latest" &&
|
|
20600
|
-
const dirs =
|
|
21203
|
+
if (existsSync15(join27(base, prefixed))) return prefixed;
|
|
21204
|
+
if (version === "latest" && existsSync15(base)) {
|
|
21205
|
+
const dirs = readdirSync2(base, { withFileTypes: true }).filter((d) => d.isDirectory() && d.name.startsWith(`${worker}-`)).map((d) => d.name).sort();
|
|
20601
21206
|
if (dirs.length > 0) return dirs[dirs.length - 1];
|
|
20602
21207
|
}
|
|
20603
21208
|
return version;
|
|
@@ -20611,11 +21216,11 @@ function readSealedTaskIds(taskSetVersion, refereeHomeOut, env = process.env) {
|
|
|
20611
21216
|
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
21217
|
});
|
|
20613
21218
|
}
|
|
20614
|
-
const versionDir = resolveTaskSetDir(
|
|
20615
|
-
const manifestPath =
|
|
21219
|
+
const versionDir = resolveTaskSetDir(join27(home, "tasksets", worker), worker, version);
|
|
21220
|
+
const manifestPath = join27(home, "tasksets", worker, versionDir, "manifest.yaml");
|
|
20616
21221
|
let text;
|
|
20617
21222
|
try {
|
|
20618
|
-
text =
|
|
21223
|
+
text = readFileSync17(manifestPath, "utf-8");
|
|
20619
21224
|
} catch (e) {
|
|
20620
21225
|
throw new LocalCliError({
|
|
20621
21226
|
code: "EXAM_REDACTION_UNSAFE",
|
|
@@ -20722,7 +21327,7 @@ var EvalExamCommand = class extends M8tCommand {
|
|
|
20722
21327
|
return 0;
|
|
20723
21328
|
}
|
|
20724
21329
|
const bin = process.env.BRAIN_EXAM_BIN ?? "brain-exam";
|
|
20725
|
-
const res =
|
|
21330
|
+
const res = spawnSync5(bin, ["run", "--plan", "-", "--json"], { encoding: "utf-8", input: renderJson(plan) });
|
|
20726
21331
|
if (res.error) {
|
|
20727
21332
|
throw new LocalCliError({
|
|
20728
21333
|
code: "EXAM_SPAWN",
|
|
@@ -20735,10 +21340,10 @@ var EvalExamCommand = class extends M8tCommand {
|
|
|
20735
21340
|
const verdict = parseExamVerdict(res.stdout);
|
|
20736
21341
|
if (out !== void 0) {
|
|
20737
21342
|
const sealedTaskIds = taskSetVersion ? readSealedTaskIds(taskSetVersion, out) : /* @__PURE__ */ new Set();
|
|
20738
|
-
|
|
20739
|
-
|
|
21343
|
+
mkdirSync5(out, { recursive: true });
|
|
21344
|
+
writeFileSync6(join27(out, "verdict.json"), JSON.stringify(verdict, null, 2));
|
|
20740
21345
|
const feed = redactForFeed(verdict, sealedTaskIds);
|
|
20741
|
-
|
|
21346
|
+
writeFileSync6(join27(out, "feed.json"), JSON.stringify(feed, null, 2));
|
|
20742
21347
|
}
|
|
20743
21348
|
if (mode === "json") {
|
|
20744
21349
|
this.context.stdout.write(renderJson(verdict) + "\n");
|
|
@@ -21001,9 +21606,9 @@ var StatusCommand = class extends M8tCommand {
|
|
|
21001
21606
|
// src/commands/doctor.ts
|
|
21002
21607
|
import { Command as Command42, Option as Option39 } from "clipanion";
|
|
21003
21608
|
import { DefaultAzureCredential as DefaultAzureCredential19 } from "@azure/identity";
|
|
21004
|
-
import * as
|
|
21005
|
-
import * as
|
|
21006
|
-
import * as
|
|
21609
|
+
import * as fs26 from "fs";
|
|
21610
|
+
import * as os11 from "os";
|
|
21611
|
+
import * as path28 from "path";
|
|
21007
21612
|
|
|
21008
21613
|
// src/lib/doctor-checks.ts
|
|
21009
21614
|
function checkAzSignedIn(az) {
|
|
@@ -21228,24 +21833,24 @@ async function resolveAccountLocation(accountId) {
|
|
|
21228
21833
|
}
|
|
21229
21834
|
}
|
|
21230
21835
|
function probeRepoRoot() {
|
|
21231
|
-
const marker =
|
|
21232
|
-
if (!
|
|
21836
|
+
const marker = path28.join(os11.homedir(), ".m8t-stack", "repo-root");
|
|
21837
|
+
if (!fs26.existsSync(marker)) {
|
|
21233
21838
|
return { markerExists: false, path: null, isDir: false, isGitCheckout: false };
|
|
21234
21839
|
}
|
|
21235
21840
|
let repoPath;
|
|
21236
21841
|
try {
|
|
21237
|
-
repoPath =
|
|
21842
|
+
repoPath = fs26.readFileSync(marker, "utf8").trim();
|
|
21238
21843
|
} catch {
|
|
21239
21844
|
return { markerExists: true, path: null, isDir: false, isGitCheckout: false };
|
|
21240
21845
|
}
|
|
21241
21846
|
if (!repoPath) return { markerExists: true, path: null, isDir: false, isGitCheckout: false };
|
|
21242
21847
|
let isDir = false;
|
|
21243
21848
|
try {
|
|
21244
|
-
isDir =
|
|
21849
|
+
isDir = fs26.statSync(repoPath).isDirectory();
|
|
21245
21850
|
} catch {
|
|
21246
21851
|
isDir = false;
|
|
21247
21852
|
}
|
|
21248
|
-
const isGitCheckout = isDir &&
|
|
21853
|
+
const isGitCheckout = isDir && fs26.existsSync(path28.join(repoPath, ".git"));
|
|
21249
21854
|
return { markerExists: true, path: repoPath, isDir, isGitCheckout };
|
|
21250
21855
|
}
|
|
21251
21856
|
var DoctorCommand = class extends M8tCommand {
|
|
@@ -21374,15 +21979,15 @@ var DoctorCommand = class extends M8tCommand {
|
|
|
21374
21979
|
import { Command as Command43, Option as Option40 } from "clipanion";
|
|
21375
21980
|
|
|
21376
21981
|
// src/lib/profiles.ts
|
|
21377
|
-
import * as
|
|
21378
|
-
import * as
|
|
21982
|
+
import * as fs27 from "fs/promises";
|
|
21983
|
+
import * as path29 from "path";
|
|
21379
21984
|
import { parse as parseYaml11, stringify as stringifyYaml4 } from "yaml";
|
|
21380
21985
|
function profilesDir() {
|
|
21381
21986
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
21382
|
-
return
|
|
21987
|
+
return path29.join(home, ".m8t-stack", "profiles");
|
|
21383
21988
|
}
|
|
21384
21989
|
function getProfilePath(name) {
|
|
21385
|
-
return
|
|
21990
|
+
return path29.join(profilesDir(), `${path29.basename(name)}.yaml`);
|
|
21386
21991
|
}
|
|
21387
21992
|
function slugifyTenant(domainOrId) {
|
|
21388
21993
|
const base = domainOrId.split(".")[0].toLowerCase();
|
|
@@ -21391,7 +21996,7 @@ function slugifyTenant(domainOrId) {
|
|
|
21391
21996
|
}
|
|
21392
21997
|
async function listProfiles() {
|
|
21393
21998
|
try {
|
|
21394
|
-
const entries = await
|
|
21999
|
+
const entries = await fs27.readdir(profilesDir());
|
|
21395
22000
|
return entries.filter((e) => e.endsWith(".yaml")).map((e) => e.replace(/\.yaml$/, "")).sort();
|
|
21396
22001
|
} catch (e) {
|
|
21397
22002
|
if (e.code === "ENOENT") return [];
|
|
@@ -21400,7 +22005,7 @@ async function listProfiles() {
|
|
|
21400
22005
|
}
|
|
21401
22006
|
async function readProfile(name) {
|
|
21402
22007
|
try {
|
|
21403
|
-
const raw = await
|
|
22008
|
+
const raw = await fs27.readFile(getProfilePath(name), "utf8");
|
|
21404
22009
|
const parsed = parseYaml11(raw);
|
|
21405
22010
|
if (!parsed || typeof parsed !== "object") return null;
|
|
21406
22011
|
return parsed;
|
|
@@ -21411,14 +22016,14 @@ async function readProfile(name) {
|
|
|
21411
22016
|
}
|
|
21412
22017
|
async function exists(p) {
|
|
21413
22018
|
try {
|
|
21414
|
-
await
|
|
22019
|
+
await fs27.stat(p);
|
|
21415
22020
|
return true;
|
|
21416
22021
|
} catch {
|
|
21417
22022
|
return false;
|
|
21418
22023
|
}
|
|
21419
22024
|
}
|
|
21420
22025
|
async function saveProfile(p) {
|
|
21421
|
-
await
|
|
22026
|
+
await fs27.mkdir(profilesDir(), { recursive: true });
|
|
21422
22027
|
let name = p.name;
|
|
21423
22028
|
let n = 2;
|
|
21424
22029
|
while (await exists(getProfilePath(name))) {
|
|
@@ -21427,8 +22032,8 @@ async function saveProfile(p) {
|
|
|
21427
22032
|
}
|
|
21428
22033
|
const target = getProfilePath(name);
|
|
21429
22034
|
const tmp = `${target}.tmp`;
|
|
21430
|
-
await
|
|
21431
|
-
await
|
|
22035
|
+
await fs27.writeFile(tmp, stringifyYaml4({ ...p, name }, { indent: 2 }), "utf8");
|
|
22036
|
+
await fs27.rename(tmp, target);
|
|
21432
22037
|
return name;
|
|
21433
22038
|
}
|
|
21434
22039
|
|
|
@@ -21814,6 +22419,8 @@ function odataFilter(worker, f) {
|
|
|
21814
22419
|
parts.unshift(`PartitionKey eq '${esc2(worker)}'`);
|
|
21815
22420
|
if (f.source !== "all")
|
|
21816
22421
|
parts.push(`source eq '${esc2(f.source)}'`);
|
|
22422
|
+
if (f.foundryConversationId)
|
|
22423
|
+
parts.push(`foundryConversationId eq '${esc2(f.foundryConversationId)}'`);
|
|
21817
22424
|
return parts.join(" and ");
|
|
21818
22425
|
}
|
|
21819
22426
|
async function fetchLedgerRows(filters, client) {
|
|
@@ -21965,7 +22572,7 @@ init_errors();
|
|
|
21965
22572
|
// ../../packages/brain/engine/dist/esm/types.js
|
|
21966
22573
|
var ENGINE_VERSION = "0.1.0";
|
|
21967
22574
|
var DEFAULT_SAFETY_LAG_SECONDS = 3600;
|
|
21968
|
-
var SOURCES = ["webapp", "a2a", "mcp", "telegram"];
|
|
22575
|
+
var SOURCES = ["webapp", "a2a", "mcp", "telegram", "voice-relay"];
|
|
21969
22576
|
var WORKER_ALIASES = { "azure-advisor": "azzy" };
|
|
21970
22577
|
function canonicalWorker(pk) {
|
|
21971
22578
|
const lower = pk.toLowerCase();
|
|
@@ -22029,9 +22636,11 @@ var TableCursor = class {
|
|
|
22029
22636
|
throw e;
|
|
22030
22637
|
}
|
|
22031
22638
|
const watermarks = row.watermarks ? JSON.parse(row.watermarks) : {};
|
|
22639
|
+
const fetchFailures = row.fetchFailures ? JSON.parse(row.fetchFailures) : void 0;
|
|
22032
22640
|
return {
|
|
22033
22641
|
worker: canonical,
|
|
22034
22642
|
watermarks,
|
|
22643
|
+
...fetchFailures && Object.keys(fetchFailures).length > 0 ? { fetchFailures } : {},
|
|
22035
22644
|
safetyLagSeconds: row.safetyLagSeconds ?? DEFAULT_SAFETY_LAG_SECONDS,
|
|
22036
22645
|
engineVersion: row.engineVersion ?? ENGINE_VERSION,
|
|
22037
22646
|
...row.lastDreamAt ? { lastDreamAt: row.lastDreamAt } : {}
|
|
@@ -22054,9 +22663,12 @@ var TableCursor = class {
|
|
|
22054
22663
|
safetyLagSeconds: cursor.safetyLagSeconds,
|
|
22055
22664
|
engineVersion: cursor.engineVersion
|
|
22056
22665
|
};
|
|
22666
|
+
if (cursor.fetchFailures && Object.keys(cursor.fetchFailures).length > 0) {
|
|
22667
|
+
entity.fetchFailures = JSON.stringify(cursor.fetchFailures);
|
|
22668
|
+
}
|
|
22057
22669
|
if (cursor.lastDreamAt)
|
|
22058
22670
|
entity.lastDreamAt = cursor.lastDreamAt;
|
|
22059
|
-
await this.client.upsertEntity(entity);
|
|
22671
|
+
await this.client.upsertEntity(entity, "Replace");
|
|
22060
22672
|
}
|
|
22061
22673
|
async ensureTable() {
|
|
22062
22674
|
try {
|
|
@@ -22092,9 +22704,22 @@ function computeWatermark(rows, now, safetyLagSeconds) {
|
|
|
22092
22704
|
}
|
|
22093
22705
|
async function commitCursorAdvance(plan, cursor) {
|
|
22094
22706
|
const prior = await cursor.read(plan.worker);
|
|
22707
|
+
const watermarks = {};
|
|
22708
|
+
for (const [pk, watermark] of Object.entries(plan.watermarks)) {
|
|
22709
|
+
const priorWatermark = Object.hasOwn(prior.watermarks, pk) ? prior.watermarks[pk] : void 0;
|
|
22710
|
+
if (priorWatermark && watermark.ts <= priorWatermark.ts) {
|
|
22711
|
+
watermarks[pk] = {
|
|
22712
|
+
ts: watermark.ts,
|
|
22713
|
+
consumedRowKeys: [.../* @__PURE__ */ new Set([...priorWatermark.consumedRowKeys, ...watermark.consumedRowKeys])]
|
|
22714
|
+
};
|
|
22715
|
+
} else {
|
|
22716
|
+
watermarks[pk] = watermark;
|
|
22717
|
+
}
|
|
22718
|
+
}
|
|
22095
22719
|
const next = {
|
|
22096
22720
|
worker: plan.worker,
|
|
22097
|
-
watermarks
|
|
22721
|
+
watermarks,
|
|
22722
|
+
...plan.fetchFailures && Object.keys(plan.fetchFailures).length > 0 ? { fetchFailures: plan.fetchFailures } : {},
|
|
22098
22723
|
safetyLagSeconds: prior.safetyLagSeconds || DEFAULT_SAFETY_LAG_SECONDS,
|
|
22099
22724
|
engineVersion: ENGINE_VERSION,
|
|
22100
22725
|
lastDreamAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -22348,6 +22973,7 @@ function normalize(group, items, enrichment) {
|
|
|
22348
22973
|
|
|
22349
22974
|
// ../../packages/brain/engine/dist/esm/pipeline.js
|
|
22350
22975
|
var isKnownSource = (s) => SOURCES.includes(s);
|
|
22976
|
+
var MAX_CONV_FETCH_ATTEMPTS = 3;
|
|
22351
22977
|
async function runPipeline(args) {
|
|
22352
22978
|
const { worker, sources, now, since, reset } = args;
|
|
22353
22979
|
const monotonicNow = args.monotonicNow ?? Date.now;
|
|
@@ -22374,6 +23000,7 @@ async function runPipeline(args) {
|
|
|
22374
23000
|
let recovered = 0;
|
|
22375
23001
|
const consumedRowsByPk = {};
|
|
22376
23002
|
const failedTsByPk = {};
|
|
23003
|
+
const newFailures = {};
|
|
22377
23004
|
const window2 = windowFor(rows, now, since);
|
|
22378
23005
|
for (const g of groups) {
|
|
22379
23006
|
const pk = g.worker;
|
|
@@ -22464,8 +23091,17 @@ async function runPipeline(args) {
|
|
|
22464
23091
|
else
|
|
22465
23092
|
recovered += 1;
|
|
22466
23093
|
} else {
|
|
22467
|
-
|
|
22468
|
-
if (outcome === "conv-fetch-failed"
|
|
23094
|
+
let lastError = fetchError?.message;
|
|
23095
|
+
if (outcome === "conv-fetch-failed") {
|
|
23096
|
+
const id = conversationId ?? "";
|
|
23097
|
+
const next = (cursor.fetchFailures?.[id] ?? 0) + 1;
|
|
23098
|
+
newFailures[id] = next;
|
|
23099
|
+
if (next >= MAX_CONV_FETCH_ATTEMPTS) {
|
|
23100
|
+
lastError = `terminal after ${String(next)} cycles \u2014 watermark released`;
|
|
23101
|
+
}
|
|
23102
|
+
}
|
|
23103
|
+
skips.addSkip(outcome, sampleId(g), lastError);
|
|
23104
|
+
if (outcome === "auth-failed" || outcome === "conv-fetch-failed" && conversationId && newFailures[conversationId] < MAX_CONV_FETCH_ATTEMPTS) {
|
|
22469
23105
|
const cur = failedTsByPk[pk];
|
|
22470
23106
|
if (!cur || g.startedAt < cur)
|
|
22471
23107
|
failedTsByPk[pk] = g.startedAt;
|
|
@@ -22485,7 +23121,7 @@ async function runPipeline(args) {
|
|
|
22485
23121
|
latencyMs: Math.round(monotonicNow() - t0)
|
|
22486
23122
|
};
|
|
22487
23123
|
assertInvariant(stats, groups.length);
|
|
22488
|
-
const advance = buildAdvancePlan(target, cursor, physicalPks, consumedRowsByPk, failedTsByPk, now, safetyLag);
|
|
23124
|
+
const advance = buildAdvancePlan(target, cursor, physicalPks, consumedRowsByPk, failedTsByPk, newFailures, now, safetyLag);
|
|
22489
23125
|
const out = {
|
|
22490
23126
|
worker: target,
|
|
22491
23127
|
window: window2,
|
|
@@ -22564,7 +23200,7 @@ function windowFor(rows, now, since) {
|
|
|
22564
23200
|
from = r.eventTimestamp;
|
|
22565
23201
|
return { from, to };
|
|
22566
23202
|
}
|
|
22567
|
-
function buildAdvancePlan(worker, cursor, physicalPks, consumedRowsByPk, failedTsByPk, now, safetyLagSeconds) {
|
|
23203
|
+
function buildAdvancePlan(worker, cursor, physicalPks, consumedRowsByPk, failedTsByPk, fetchFailures, now, safetyLagSeconds) {
|
|
22568
23204
|
const watermarks = {};
|
|
22569
23205
|
const consumedKeysByPk = {};
|
|
22570
23206
|
const priorTsByPk = {};
|
|
@@ -22588,6 +23224,7 @@ function buildAdvancePlan(worker, cursor, physicalPks, consumedRowsByPk, failedT
|
|
|
22588
23224
|
watermarks,
|
|
22589
23225
|
consumedRowsByPk: consumedKeysByPk,
|
|
22590
23226
|
failedTsByPk,
|
|
23227
|
+
...Object.keys(fetchFailures).length > 0 ? { fetchFailures } : {},
|
|
22591
23228
|
now: now.toISOString(),
|
|
22592
23229
|
safetyLagSeconds,
|
|
22593
23230
|
priorTsByPk
|
|
@@ -22597,7 +23234,7 @@ function buildAdvancePlan(worker, cursor, physicalPks, consumedRowsByPk, failedT
|
|
|
22597
23234
|
// ../../packages/brain/engine/dist/esm/dream/writer.js
|
|
22598
23235
|
var API2 = "https://api.github.com";
|
|
22599
23236
|
var WRITER_ALLOWED_PREFIX = /^(memory|inbox|quarantine|artifacts)\//;
|
|
22600
|
-
var isAllowedWritePath = (
|
|
23237
|
+
var isAllowedWritePath = (path37, allowedPrefix) => allowedPrefix.test(path37) && !path37.split("/").includes("..");
|
|
22601
23238
|
var unquote = (s) => s.trim().replace(/^["']|["']$/g, "");
|
|
22602
23239
|
function parseFrontmatter(content) {
|
|
22603
23240
|
const m = /^---\n([\s\S]*?)\n---/.exec(content);
|
|
@@ -22640,8 +23277,8 @@ function makeGitDataWriter(args) {
|
|
|
22640
23277
|
if (args.allowedPathPrefix && !args.allowedPathPrefix.source.startsWith("^")) {
|
|
22641
23278
|
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
23279
|
}
|
|
22643
|
-
async function gh(token, method,
|
|
22644
|
-
const res = await doFetch(`${API2}/repos/${repoPath}${
|
|
23280
|
+
async function gh(token, method, path37, body) {
|
|
23281
|
+
const res = await doFetch(`${API2}/repos/${repoPath}${path37}`, {
|
|
22645
23282
|
method,
|
|
22646
23283
|
headers: {
|
|
22647
23284
|
Authorization: `Bearer ${token}`,
|
|
@@ -22654,8 +23291,8 @@ function makeGitDataWriter(args) {
|
|
|
22654
23291
|
const text = await res.text();
|
|
22655
23292
|
return { status: res.status, ok: res.ok, json: text ? JSON.parse(text) : {} };
|
|
22656
23293
|
}
|
|
22657
|
-
async function readFileWith(token,
|
|
22658
|
-
const encodedPath =
|
|
23294
|
+
async function readFileWith(token, path37) {
|
|
23295
|
+
const encodedPath = path37.split("/").map(encodeURIComponent).join("/");
|
|
22659
23296
|
const r = await gh(token, "GET", `/contents/${encodedPath}?ref=${args.branch}`);
|
|
22660
23297
|
if (r.status === 404)
|
|
22661
23298
|
return null;
|
|
@@ -22671,9 +23308,9 @@ function makeGitDataWriter(args) {
|
|
|
22671
23308
|
throw new Error(`fetchTip: HTTP ${String(r.status)}`);
|
|
22672
23309
|
return r.json.object.sha;
|
|
22673
23310
|
},
|
|
22674
|
-
async readFile(
|
|
23311
|
+
async readFile(path37) {
|
|
22675
23312
|
const token = await args.mintToken();
|
|
22676
|
-
return readFileWith(token,
|
|
23313
|
+
return readFileWith(token, path37);
|
|
22677
23314
|
},
|
|
22678
23315
|
async listMemory() {
|
|
22679
23316
|
const token = await args.mintToken();
|
|
@@ -22682,9 +23319,9 @@ function makeGitDataWriter(args) {
|
|
|
22682
23319
|
return [];
|
|
22683
23320
|
const paths = r.json.tree.filter((e) => e.type === "blob" && e.path.startsWith("memory/") && e.path.endsWith(".md")).map((e) => e.path);
|
|
22684
23321
|
const out = [];
|
|
22685
|
-
for (const
|
|
22686
|
-
const content = await readFileWith(token,
|
|
22687
|
-
out.push({ path:
|
|
23322
|
+
for (const path37 of paths) {
|
|
23323
|
+
const content = await readFileWith(token, path37);
|
|
23324
|
+
out.push({ path: path37, frontmatter: content ? parseFrontmatter(content) : {} });
|
|
22688
23325
|
}
|
|
22689
23326
|
return out;
|
|
22690
23327
|
},
|
|
@@ -23123,7 +23760,7 @@ async function loadMemoryContext(brain) {
|
|
|
23123
23760
|
return {
|
|
23124
23761
|
files,
|
|
23125
23762
|
indexEntries,
|
|
23126
|
-
originOf: (
|
|
23763
|
+
originOf: (path37) => originByPath.get(path37) ?? "worker"
|
|
23127
23764
|
};
|
|
23128
23765
|
}
|
|
23129
23766
|
|
|
@@ -23144,14 +23781,14 @@ function checkEvidenceMembership(delta, harvested) {
|
|
|
23144
23781
|
}
|
|
23145
23782
|
var BatchAbort = class extends Error {
|
|
23146
23783
|
path;
|
|
23147
|
-
constructor(
|
|
23784
|
+
constructor(path37, message) {
|
|
23148
23785
|
super(message);
|
|
23149
|
-
this.path =
|
|
23786
|
+
this.path = path37;
|
|
23150
23787
|
this.name = "BatchAbort";
|
|
23151
23788
|
}
|
|
23152
23789
|
};
|
|
23153
|
-
var isIndexFile = (
|
|
23154
|
-
var isMemoryIndex = (
|
|
23790
|
+
var isIndexFile = (path37) => /(^|\/)[^/]*_index\.md$/.test(path37);
|
|
23791
|
+
var isMemoryIndex = (path37) => path37 === "memory/MEMORY.md";
|
|
23155
23792
|
function targetPath(delta) {
|
|
23156
23793
|
switch (delta.verb) {
|
|
23157
23794
|
case "new":
|
|
@@ -23168,29 +23805,29 @@ function targetPath(delta) {
|
|
|
23168
23805
|
}
|
|
23169
23806
|
async function checkOriginTier(delta, lookup) {
|
|
23170
23807
|
const evidence = evidenceOf(delta) ?? [];
|
|
23171
|
-
const
|
|
23172
|
-
if (
|
|
23808
|
+
const path37 = targetPath(delta);
|
|
23809
|
+
if (path37 === null)
|
|
23173
23810
|
return { ok: true };
|
|
23174
|
-
if (isIndexFile(
|
|
23175
|
-
return { ok: false, flagged: { kind: "flagged", path:
|
|
23811
|
+
if (isIndexFile(path37) && !isMemoryIndex(path37)) {
|
|
23812
|
+
return { ok: false, flagged: { kind: "flagged", path: path37, tension: `refused: ${path37} is an index file (only memory/MEMORY.md is editable)`, evidence } };
|
|
23176
23813
|
}
|
|
23177
|
-
const target = await lookup(
|
|
23178
|
-
const isStructural =
|
|
23814
|
+
const target = await lookup(path37);
|
|
23815
|
+
const isStructural = path37.startsWith("references/");
|
|
23179
23816
|
const origin = target?.frontmatter.origin ?? (isStructural ? "operator" : "worker");
|
|
23180
23817
|
const editable = origin === "worker" || origin === "dream";
|
|
23181
23818
|
if (editable)
|
|
23182
23819
|
return { ok: true };
|
|
23183
23820
|
const removesOperatorTarget = delta.verb === "retract" || delta.verb === "supersede" && delta.oldPath !== delta.newPath;
|
|
23184
23821
|
if (removesOperatorTarget) {
|
|
23185
|
-
throw new BatchAbort(
|
|
23822
|
+
throw new BatchAbort(path37, `supersede/retract OLD target ${path37} is origin: ${origin} \u2014 aborting batch (never half-apply)`);
|
|
23186
23823
|
}
|
|
23187
|
-
return { ok: false, flagged: { kind: "flagged", path:
|
|
23824
|
+
return { ok: false, flagged: { kind: "flagged", path: path37, tension: `operator-origin (${origin}); flag-only`, evidence } };
|
|
23188
23825
|
}
|
|
23189
23826
|
var ALLOWED_MEMORY = /^memory\/.+\.md$/;
|
|
23190
23827
|
var ALLOWED_INBOX = /^inbox\//;
|
|
23191
23828
|
var ALLOWED_QUARANTINE = /^quarantine\//;
|
|
23192
23829
|
var ALLOWED_FLAG = /^memory\//;
|
|
23193
|
-
var hasTraversal = (
|
|
23830
|
+
var hasTraversal = (path37) => path37.split("/").includes("..");
|
|
23194
23831
|
function checkPathAllowed(delta) {
|
|
23195
23832
|
const evidence = evidenceOf(delta) ?? [];
|
|
23196
23833
|
const reject = (detail) => ({ ok: false, rejected: { kind: "rejected", detail, evidence } });
|
|
@@ -23297,7 +23934,7 @@ ${inject}
|
|
|
23297
23934
|
---
|
|
23298
23935
|
`);
|
|
23299
23936
|
}
|
|
23300
|
-
var indexLine = (
|
|
23937
|
+
var indexLine = (path37, title, date, tags) => `- \`${path37}\` \u2014 **${title}**: ${title}. (${date} \xB7 ${tags.join(", ")})`;
|
|
23301
23938
|
function splitIndex(index) {
|
|
23302
23939
|
const all = index.split("\n");
|
|
23303
23940
|
const firstLineIdx = all.findIndex((l) => l.startsWith("- `memory/"));
|
|
@@ -23470,16 +24107,16 @@ function defaultDreamSeams(opts = {}) {
|
|
|
23470
24107
|
const mem = await memory(deps.brain);
|
|
23471
24108
|
const harvested = harvestedIds(input);
|
|
23472
24109
|
const ctx = { readFile: (p) => deps.brain.readFile(p), at: deps.clock() };
|
|
23473
|
-
const lookup = (
|
|
24110
|
+
const lookup = (path37) => Promise.resolve(mem.files.find((f) => f.path === path37) ?? null);
|
|
23474
24111
|
const digest = [...pendingRejected];
|
|
23475
24112
|
let changes = [];
|
|
23476
24113
|
let indexEdit;
|
|
23477
24114
|
try {
|
|
23478
24115
|
for (const raw of deltas) {
|
|
23479
24116
|
const delta = forcePolicyQuarantine(raw);
|
|
23480
|
-
const
|
|
23481
|
-
if (!
|
|
23482
|
-
digest.push(
|
|
24117
|
+
const path37 = checkPathAllowed(delta);
|
|
24118
|
+
if (!path37.ok) {
|
|
24119
|
+
digest.push(path37.rejected);
|
|
23483
24120
|
continue;
|
|
23484
24121
|
}
|
|
23485
24122
|
const ev = checkEvidenceMembership(delta, harvested);
|
|
@@ -23580,6 +24217,7 @@ function narrowAdvance(src, kept) {
|
|
|
23580
24217
|
watermarks,
|
|
23581
24218
|
consumedRowsByPk,
|
|
23582
24219
|
failedTsByPk: src.failedTsByPk,
|
|
24220
|
+
...src.fetchFailures ? { fetchFailures: src.fetchFailures } : {},
|
|
23583
24221
|
now,
|
|
23584
24222
|
safetyLagSeconds,
|
|
23585
24223
|
priorTsByPk
|
|
@@ -23597,7 +24235,13 @@ function filterAdvance(src, keptRowsByPk) {
|
|
|
23597
24235
|
consumedRowsByPk[pk] = (src.consumedRowsByPk[pk] ?? []).filter((rk) => keep.has(rk));
|
|
23598
24236
|
watermarks[pk] = { ts: wm.ts, consumedRowKeys: wm.consumedRowKeys.filter((rk) => keep.has(rk)) };
|
|
23599
24237
|
}
|
|
23600
|
-
return {
|
|
24238
|
+
return {
|
|
24239
|
+
worker: src.worker,
|
|
24240
|
+
watermarks,
|
|
24241
|
+
consumedRowsByPk,
|
|
24242
|
+
failedTsByPk: src.failedTsByPk,
|
|
24243
|
+
...src.fetchFailures ? { fetchFailures: src.fetchFailures } : {}
|
|
24244
|
+
};
|
|
23601
24245
|
}
|
|
23602
24246
|
|
|
23603
24247
|
// ../../packages/brain/engine/dist/esm/dream/index.js
|
|
@@ -23615,6 +24259,18 @@ async function runDream(input, deps, seams = defaultDreamSeams()) {
|
|
|
23615
24259
|
});
|
|
23616
24260
|
}
|
|
23617
24261
|
input = capped;
|
|
24262
|
+
if (input.conversations.length === 0) {
|
|
24263
|
+
await commitCursorAdvance(input.advance, deps.cursor);
|
|
24264
|
+
deps.logger.info({
|
|
24265
|
+
at: "runDream",
|
|
24266
|
+
worker: input.worker,
|
|
24267
|
+
terminal: "no-corpus",
|
|
24268
|
+
skipped: input.stats.skipped,
|
|
24269
|
+
advanced: true,
|
|
24270
|
+
skipLedger: input.skipLedger.map((s) => `${s.reason}:${String(s.count)}`)
|
|
24271
|
+
});
|
|
24272
|
+
return { worker: input.worker, applied: [], digest, advanced: true };
|
|
24273
|
+
}
|
|
23618
24274
|
const proposed = await seams.propose(input, deps);
|
|
23619
24275
|
digest.push({ kind: "cost", model: proposed.cost.model, inputTokens: proposed.cost.inputTokens, outputTokens: proposed.cost.outputTokens, ms: proposed.cost.ms });
|
|
23620
24276
|
if (!proposed.deltas) {
|
|
@@ -24699,9 +25355,9 @@ ${colors.error(" " + why)}
|
|
|
24699
25355
|
}
|
|
24700
25356
|
|
|
24701
25357
|
// src/commands/bootstrap/launch.ts
|
|
24702
|
-
import * as
|
|
24703
|
-
import * as
|
|
24704
|
-
import * as
|
|
25358
|
+
import * as fs30 from "fs";
|
|
25359
|
+
import * as os14 from "os";
|
|
25360
|
+
import * as path32 from "path";
|
|
24705
25361
|
import { Command as Command49, Option as Option46 } from "clipanion";
|
|
24706
25362
|
init_errors();
|
|
24707
25363
|
|
|
@@ -24847,9 +25503,9 @@ async function kickInstaller(s) {
|
|
|
24847
25503
|
|
|
24848
25504
|
// src/lib/bootstrap-status.ts
|
|
24849
25505
|
import { createHash as createHash4, randomUUID as randomUUID2 } from "crypto";
|
|
24850
|
-
import * as
|
|
24851
|
-
import * as
|
|
24852
|
-
import * as
|
|
25506
|
+
import * as fs28 from "fs/promises";
|
|
25507
|
+
import * as os12 from "os";
|
|
25508
|
+
import * as path30 from "path";
|
|
24853
25509
|
init_errors();
|
|
24854
25510
|
var STATUS_CONTAINER = "status";
|
|
24855
25511
|
var STATUS_BLOB = "status.json";
|
|
@@ -24888,7 +25544,7 @@ async function readStatusBlob(opts) {
|
|
|
24888
25544
|
cause: e
|
|
24889
25545
|
});
|
|
24890
25546
|
}
|
|
24891
|
-
const tmpFile =
|
|
25547
|
+
const tmpFile = path30.join(os12.tmpdir(), `m8t-status-${randomUUID2()}.json`);
|
|
24892
25548
|
try {
|
|
24893
25549
|
await runAz([
|
|
24894
25550
|
"storage",
|
|
@@ -24907,7 +25563,7 @@ async function readStatusBlob(opts) {
|
|
|
24907
25563
|
"--no-progress",
|
|
24908
25564
|
"--only-show-errors"
|
|
24909
25565
|
]);
|
|
24910
|
-
const raw = await
|
|
25566
|
+
const raw = await fs28.readFile(tmpFile, "utf8");
|
|
24911
25567
|
return JSON.parse(raw.trim());
|
|
24912
25568
|
} catch (e) {
|
|
24913
25569
|
throw new LocalCliError({
|
|
@@ -24917,34 +25573,34 @@ async function readStatusBlob(opts) {
|
|
|
24917
25573
|
cause: e
|
|
24918
25574
|
});
|
|
24919
25575
|
} finally {
|
|
24920
|
-
await
|
|
25576
|
+
await fs28.rm(tmpFile, { force: true });
|
|
24921
25577
|
}
|
|
24922
25578
|
}
|
|
24923
25579
|
|
|
24924
25580
|
// src/lib/bootstrap-state.ts
|
|
24925
|
-
import * as
|
|
24926
|
-
import * as
|
|
24927
|
-
import * as
|
|
25581
|
+
import * as fs29 from "fs/promises";
|
|
25582
|
+
import * as os13 from "os";
|
|
25583
|
+
import * as path31 from "path";
|
|
24928
25584
|
function stateDir(home) {
|
|
24929
|
-
return
|
|
25585
|
+
return path31.join(home, ".m8t-stack");
|
|
24930
25586
|
}
|
|
24931
25587
|
function statePath(home) {
|
|
24932
|
-
return
|
|
25588
|
+
return path31.join(stateDir(home), "bootstrap.json");
|
|
24933
25589
|
}
|
|
24934
|
-
async function readBootstrapState(home =
|
|
25590
|
+
async function readBootstrapState(home = os13.homedir()) {
|
|
24935
25591
|
try {
|
|
24936
|
-
const raw = await
|
|
25592
|
+
const raw = await fs29.readFile(statePath(home), "utf8");
|
|
24937
25593
|
return JSON.parse(raw);
|
|
24938
25594
|
} catch (e) {
|
|
24939
25595
|
if (e.code === "ENOENT") return null;
|
|
24940
25596
|
throw e;
|
|
24941
25597
|
}
|
|
24942
25598
|
}
|
|
24943
|
-
async function writeBootstrapState(state, home =
|
|
24944
|
-
await
|
|
25599
|
+
async function writeBootstrapState(state, home = os13.homedir()) {
|
|
25600
|
+
await fs29.mkdir(stateDir(home), { recursive: true });
|
|
24945
25601
|
const tmp = `${statePath(home)}.tmp`;
|
|
24946
|
-
await
|
|
24947
|
-
await
|
|
25602
|
+
await fs29.writeFile(tmp, JSON.stringify(state, null, 2), "utf8");
|
|
25603
|
+
await fs29.rename(tmp, statePath(home));
|
|
24948
25604
|
}
|
|
24949
25605
|
|
|
24950
25606
|
// src/commands/bootstrap/launch.ts
|
|
@@ -24984,12 +25640,12 @@ var BootstrapLaunchCommand = class extends M8tCommand {
|
|
|
24984
25640
|
const subscriptionId = (typeof this.subscription === "string" ? this.subscription : void 0) ?? account.subscriptionId;
|
|
24985
25641
|
const out = (m) => this.context.stderr.write(` ${colors.dim(m)}
|
|
24986
25642
|
`);
|
|
24987
|
-
const credsPath = typeof this.githubAppCreds === "string" ? this.githubAppCreds :
|
|
25643
|
+
const credsPath = typeof this.githubAppCreds === "string" ? this.githubAppCreds : path32.join(os14.homedir(), ".m8t-stack", "github-app.json");
|
|
24988
25644
|
let githubApp;
|
|
24989
|
-
if (
|
|
25645
|
+
if (fs30.existsSync(credsPath)) {
|
|
24990
25646
|
let parsed;
|
|
24991
25647
|
try {
|
|
24992
|
-
parsed = JSON.parse(
|
|
25648
|
+
parsed = JSON.parse(fs30.readFileSync(credsPath, "utf8"));
|
|
24993
25649
|
} catch {
|
|
24994
25650
|
throw new LocalCliError({
|
|
24995
25651
|
code: "GITHUB_APP_CREDS_INVALID",
|
|
@@ -24999,7 +25655,7 @@ var BootstrapLaunchCommand = class extends M8tCommand {
|
|
|
24999
25655
|
}
|
|
25000
25656
|
let pem;
|
|
25001
25657
|
try {
|
|
25002
|
-
pem =
|
|
25658
|
+
pem = fs30.readFileSync(parsed.pemPath, "utf8");
|
|
25003
25659
|
} catch {
|
|
25004
25660
|
throw new LocalCliError({
|
|
25005
25661
|
code: "GITHUB_APP_PEM_MISSING",
|
|
@@ -25324,17 +25980,17 @@ Found ${String(found.length)} orphaned Owner@sub assignment(s) (dry-run). ${colo
|
|
|
25324
25980
|
};
|
|
25325
25981
|
|
|
25326
25982
|
// src/commands/bootstrap/finish.ts
|
|
25327
|
-
import * as
|
|
25328
|
-
import * as
|
|
25329
|
-
import * as
|
|
25983
|
+
import * as fs31 from "fs/promises";
|
|
25984
|
+
import * as os16 from "os";
|
|
25985
|
+
import * as path34 from "path";
|
|
25330
25986
|
import { Command as Command52, Option as Option49 } from "clipanion";
|
|
25331
25987
|
init_errors();
|
|
25332
25988
|
|
|
25333
25989
|
// src/lib/company-profile-seed.ts
|
|
25334
25990
|
import { spawn as spawn6 } from "child_process";
|
|
25335
|
-
import { closeSync, openSync, readFileSync as
|
|
25336
|
-
import * as
|
|
25337
|
-
import * as
|
|
25991
|
+
import { closeSync, openSync, readFileSync as readFileSync20 } from "fs";
|
|
25992
|
+
import * as os15 from "os";
|
|
25993
|
+
import * as path33 from "path";
|
|
25338
25994
|
init_errors();
|
|
25339
25995
|
|
|
25340
25996
|
// src/lib/onboarding-profile.ts
|
|
@@ -25515,9 +26171,9 @@ function composeFounderIdentityNote(id) {
|
|
|
25515
26171
|
|
|
25516
26172
|
// src/lib/company-profile-seed.ts
|
|
25517
26173
|
function readGithubAppCreds(credsPath) {
|
|
25518
|
-
const p = credsPath ??
|
|
26174
|
+
const p = credsPath ?? path33.join(os15.homedir(), ".m8t-stack", "github-app.json");
|
|
25519
26175
|
try {
|
|
25520
|
-
return JSON.parse(
|
|
26176
|
+
return JSON.parse(readFileSync20(p, "utf8"));
|
|
25521
26177
|
} catch {
|
|
25522
26178
|
return null;
|
|
25523
26179
|
}
|
|
@@ -25545,7 +26201,7 @@ async function resolveSeedContext(opts) {
|
|
|
25545
26201
|
async function applyProfileToBrain(args) {
|
|
25546
26202
|
const token = await mintInstallationTokenFromPem({
|
|
25547
26203
|
appId: args.appCreds.appId,
|
|
25548
|
-
privateKeyPem:
|
|
26204
|
+
privateKeyPem: readFileSync20(args.appCreds.pemPath, "utf8"),
|
|
25549
26205
|
installationId: args.appCreds.installationId,
|
|
25550
26206
|
fetchImpl: args.fetchImpl
|
|
25551
26207
|
});
|
|
@@ -25580,7 +26236,7 @@ async function applyProfileToBrain(args) {
|
|
|
25580
26236
|
});
|
|
25581
26237
|
}
|
|
25582
26238
|
function spawnDetachedSeedWatch() {
|
|
25583
|
-
const logPath =
|
|
26239
|
+
const logPath = path33.join(os15.homedir(), ".m8t-stack", "seed-profile.log");
|
|
25584
26240
|
const fd = openSync(logPath, "a");
|
|
25585
26241
|
try {
|
|
25586
26242
|
const child = spawn6(process.execPath, [process.argv[1] ?? "", "bootstrap", "seed-profile", "--watch"], {
|
|
@@ -25679,9 +26335,9 @@ var BootstrapFinishCommand = class extends M8tCommand {
|
|
|
25679
26335
|
});
|
|
25680
26336
|
}
|
|
25681
26337
|
const repoRoot = (typeof this.repoRoot === "string" ? this.repoRoot : void 0) ?? process.cwd();
|
|
25682
|
-
const markerDir =
|
|
25683
|
-
await
|
|
25684
|
-
await
|
|
26338
|
+
const markerDir = path34.join(os16.homedir(), ".m8t-stack");
|
|
26339
|
+
await fs31.mkdir(markerDir, { recursive: true });
|
|
26340
|
+
await fs31.writeFile(path34.join(markerDir, "repo-root"), `${repoRoot}
|
|
25685
26341
|
`, "utf8");
|
|
25686
26342
|
const subscriptionId = (typeof this.subscription === "string" ? this.subscription : void 0) ?? state.subscriptionId;
|
|
25687
26343
|
const resourceGroup = (typeof this.resourceGroup === "string" ? this.resourceGroup : void 0) ?? state.resourceGroup;
|
|
@@ -25717,7 +26373,7 @@ var BootstrapFinishCommand = class extends M8tCommand {
|
|
|
25717
26373
|
}
|
|
25718
26374
|
let brainOrg = null;
|
|
25719
26375
|
try {
|
|
25720
|
-
const credsRaw = await
|
|
26376
|
+
const credsRaw = await fs31.readFile(path34.join(markerDir, "github-app.json"), "utf8");
|
|
25721
26377
|
const creds = JSON.parse(credsRaw);
|
|
25722
26378
|
brainOrg = typeof creds.org === "string" ? creds.org : null;
|
|
25723
26379
|
} catch {
|
|
@@ -25748,18 +26404,18 @@ ${colors.field("Then open a brand new chat/session")} \u2014 new skills + MCP se
|
|
|
25748
26404
|
};
|
|
25749
26405
|
|
|
25750
26406
|
// src/commands/bootstrap/ui.ts
|
|
25751
|
-
import * as
|
|
25752
|
-
import * as
|
|
25753
|
-
import * as
|
|
26407
|
+
import * as fs33 from "fs";
|
|
26408
|
+
import * as os18 from "os";
|
|
26409
|
+
import * as path36 from "path";
|
|
25754
26410
|
import { Command as Command53, Option as Option50 } from "clipanion";
|
|
25755
26411
|
import { DefaultAzureCredential as DefaultAzureCredential20 } from "@azure/identity";
|
|
25756
26412
|
init_errors();
|
|
25757
26413
|
|
|
25758
26414
|
// src/lib/bootstrap-ui.ts
|
|
25759
|
-
import * as
|
|
26415
|
+
import * as fs32 from "fs";
|
|
25760
26416
|
import * as net from "net";
|
|
25761
|
-
import * as
|
|
25762
|
-
import * as
|
|
26417
|
+
import * as os17 from "os";
|
|
26418
|
+
import * as path35 from "path";
|
|
25763
26419
|
import { spawn as spawn7 } from "child_process";
|
|
25764
26420
|
init_errors();
|
|
25765
26421
|
init_rbac();
|
|
@@ -25826,9 +26482,9 @@ async function ensureFounderFoundryRole(args) {
|
|
|
25826
26482
|
});
|
|
25827
26483
|
}
|
|
25828
26484
|
function writeWebEnvLocal(args) {
|
|
25829
|
-
const envPath =
|
|
25830
|
-
if (
|
|
25831
|
-
|
|
26485
|
+
const envPath = path35.join(args.repoRoot, "apps", "web", ".env.local");
|
|
26486
|
+
if (fs32.existsSync(envPath)) {
|
|
26487
|
+
fs32.copyFileSync(envPath, envPath + ".bak");
|
|
25832
26488
|
}
|
|
25833
26489
|
const body = [
|
|
25834
26490
|
"# Written by `m8t bootstrap ui` \u2014 onboarding chat-only run (Simple Stacey).",
|
|
@@ -25836,13 +26492,14 @@ function writeWebEnvLocal(args) {
|
|
|
25836
26492
|
`AZURE_TENANT_ID=${args.tenantId}`,
|
|
25837
26493
|
`AZURE_CLIENT_ID=${args.clientId}`,
|
|
25838
26494
|
`FOUNDRY_PROJECT_ENDPOINT=${args.foundryEndpoint}`,
|
|
26495
|
+
"VOICE_RELAY_PUBLIC_URL=ws://localhost:8790",
|
|
25839
26496
|
"STORAGE_ACCOUNT_NAME=",
|
|
25840
26497
|
"M8T_DISABLE_WORKER=1",
|
|
25841
26498
|
"M8T_ONBOARDING=1",
|
|
25842
26499
|
"NEXT_PUBLIC_M8T_ONBOARDING=1",
|
|
25843
26500
|
""
|
|
25844
26501
|
].join("\n");
|
|
25845
|
-
|
|
26502
|
+
fs32.writeFileSync(envPath, body, "utf8");
|
|
25846
26503
|
return envPath;
|
|
25847
26504
|
}
|
|
25848
26505
|
function assertNodeVersion(versionString = process.version) {
|
|
@@ -25883,18 +26540,23 @@ async function installWebDeps(repoRoot) {
|
|
|
25883
26540
|
});
|
|
25884
26541
|
await runInherit("pnpm", ["install"], repoRoot, "BOOTSTRAP_UI_INSTALL_FAILED");
|
|
25885
26542
|
}
|
|
25886
|
-
function onboardingUiPaths(home =
|
|
25887
|
-
const dir =
|
|
26543
|
+
function onboardingUiPaths(home = os17.homedir()) {
|
|
26544
|
+
const dir = path35.join(home, ".m8t-stack");
|
|
25888
26545
|
return {
|
|
25889
|
-
logPath:
|
|
25890
|
-
pidPath:
|
|
26546
|
+
logPath: path35.join(dir, "onboarding-ui.log"),
|
|
26547
|
+
pidPath: path35.join(dir, "onboarding-ui.pid")
|
|
25891
26548
|
};
|
|
25892
26549
|
}
|
|
25893
|
-
|
|
25894
|
-
const
|
|
25895
|
-
|
|
25896
|
-
|
|
25897
|
-
|
|
26550
|
+
function onboardingRelayPaths(home = os17.homedir()) {
|
|
26551
|
+
const dir = path35.join(home, ".m8t-stack");
|
|
26552
|
+
return {
|
|
26553
|
+
logPath: path35.join(dir, "onboarding-relay.log"),
|
|
26554
|
+
pidPath: path35.join(dir, "onboarding-relay.pid")
|
|
26555
|
+
};
|
|
26556
|
+
}
|
|
26557
|
+
function isLocalPortOpen(port) {
|
|
26558
|
+
return new Promise((resolve3) => {
|
|
26559
|
+
const s = net.createConnection({ host: "127.0.0.1", port });
|
|
25898
26560
|
s.setTimeout(1e3);
|
|
25899
26561
|
s.on("connect", () => {
|
|
25900
26562
|
s.destroy();
|
|
@@ -25908,11 +26570,16 @@ async function serveOnboardingUiDetached(args) {
|
|
|
25908
26570
|
resolve3(false);
|
|
25909
26571
|
});
|
|
25910
26572
|
});
|
|
26573
|
+
}
|
|
26574
|
+
async function serveOnboardingUiDetached(args) {
|
|
26575
|
+
const { logPath, pidPath } = onboardingUiPaths();
|
|
26576
|
+
const portNum = Number(args.port);
|
|
26577
|
+
const isPortOpen = () => isLocalPortOpen(portNum);
|
|
25911
26578
|
if (await isPortOpen()) {
|
|
25912
26579
|
return { alreadyRunning: true, logPath };
|
|
25913
26580
|
}
|
|
25914
|
-
|
|
25915
|
-
const fd =
|
|
26581
|
+
fs32.mkdirSync(path35.dirname(logPath), { recursive: true });
|
|
26582
|
+
const fd = fs32.openSync(logPath, "a");
|
|
25916
26583
|
const child = spawn7("pnpm", ["--filter", "web", "dev"], {
|
|
25917
26584
|
cwd: args.repoRoot,
|
|
25918
26585
|
detached: true,
|
|
@@ -25920,7 +26587,7 @@ async function serveOnboardingUiDetached(args) {
|
|
|
25920
26587
|
env: { ...process.env, PORT: args.port },
|
|
25921
26588
|
shell: false
|
|
25922
26589
|
});
|
|
25923
|
-
|
|
26590
|
+
fs32.closeSync(fd);
|
|
25924
26591
|
if (child.pid == null) {
|
|
25925
26592
|
throw new LocalCliError({
|
|
25926
26593
|
code: "BOOTSTRAP_UI_DEV_SPAWN_FAILED",
|
|
@@ -25929,7 +26596,7 @@ async function serveOnboardingUiDetached(args) {
|
|
|
25929
26596
|
});
|
|
25930
26597
|
}
|
|
25931
26598
|
child.unref();
|
|
25932
|
-
|
|
26599
|
+
fs32.writeFileSync(pidPath, String(child.pid), "utf8");
|
|
25933
26600
|
const deadline = Date.now() + 45e3;
|
|
25934
26601
|
const sleep3 = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
25935
26602
|
while (Date.now() < deadline) {
|
|
@@ -25938,6 +26605,46 @@ async function serveOnboardingUiDetached(args) {
|
|
|
25938
26605
|
}
|
|
25939
26606
|
return { alreadyRunning: false, logPath };
|
|
25940
26607
|
}
|
|
26608
|
+
async function serveOnboardingRelayDetached(args) {
|
|
26609
|
+
const { logPath, pidPath } = onboardingRelayPaths();
|
|
26610
|
+
const portNum = 8790;
|
|
26611
|
+
if (await isLocalPortOpen(portNum)) {
|
|
26612
|
+
return { alreadyRunning: true, logPath };
|
|
26613
|
+
}
|
|
26614
|
+
fs32.mkdirSync(path35.dirname(logPath), { recursive: true });
|
|
26615
|
+
const fd = fs32.openSync(logPath, "a");
|
|
26616
|
+
const child = spawn7("pnpm", ["--filter", "web", "exec", "tsx", "voice-relay-entry.ts"], {
|
|
26617
|
+
cwd: args.repoRoot,
|
|
26618
|
+
detached: true,
|
|
26619
|
+
stdio: ["ignore", fd, fd],
|
|
26620
|
+
env: {
|
|
26621
|
+
...process.env,
|
|
26622
|
+
FOUNDRY_PROJECT_ENDPOINT: args.foundryEndpoint,
|
|
26623
|
+
AZURE_TENANT_ID: args.tenantId,
|
|
26624
|
+
AZURE_CLIENT_ID: args.clientId,
|
|
26625
|
+
RELAY_ALLOWED_ORIGINS: "http://localhost:3000",
|
|
26626
|
+
RELAY_PORT: "8790"
|
|
26627
|
+
},
|
|
26628
|
+
shell: false
|
|
26629
|
+
});
|
|
26630
|
+
fs32.closeSync(fd);
|
|
26631
|
+
if (child.pid == null) {
|
|
26632
|
+
throw new LocalCliError({
|
|
26633
|
+
code: "BOOTSTRAP_UI_RELAY_SPAWN_FAILED",
|
|
26634
|
+
message: "Could not start the voice relay (pnpm did not spawn).",
|
|
26635
|
+
hint: "Check that pnpm + Node 20+ are installed; see the log at " + logPath + "."
|
|
26636
|
+
});
|
|
26637
|
+
}
|
|
26638
|
+
child.unref();
|
|
26639
|
+
fs32.writeFileSync(pidPath, String(child.pid), "utf8");
|
|
26640
|
+
const deadline = Date.now() + 45e3;
|
|
26641
|
+
const sleep3 = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
26642
|
+
while (Date.now() < deadline) {
|
|
26643
|
+
await sleep3(500);
|
|
26644
|
+
if (await isLocalPortOpen(portNum)) break;
|
|
26645
|
+
}
|
|
26646
|
+
return { alreadyRunning: false, logPath };
|
|
26647
|
+
}
|
|
25941
26648
|
function autoOpenOnboardingUi(url, open = tryOpenUrl) {
|
|
25942
26649
|
try {
|
|
25943
26650
|
const result = open(url);
|
|
@@ -25948,11 +26655,10 @@ function autoOpenOnboardingUi(url, open = tryOpenUrl) {
|
|
|
25948
26655
|
} catch {
|
|
25949
26656
|
}
|
|
25950
26657
|
}
|
|
25951
|
-
function
|
|
25952
|
-
const { pidPath } = onboardingUiPaths(home);
|
|
26658
|
+
function stopPidFile(pidPath) {
|
|
25953
26659
|
let pidStr;
|
|
25954
26660
|
try {
|
|
25955
|
-
pidStr =
|
|
26661
|
+
pidStr = fs32.readFileSync(pidPath, "utf8").trim();
|
|
25956
26662
|
} catch {
|
|
25957
26663
|
return false;
|
|
25958
26664
|
}
|
|
@@ -25965,11 +26671,16 @@ function stopOnboardingUi(home = os16.homedir()) {
|
|
|
25965
26671
|
}
|
|
25966
26672
|
}
|
|
25967
26673
|
try {
|
|
25968
|
-
|
|
26674
|
+
fs32.unlinkSync(pidPath);
|
|
25969
26675
|
} catch {
|
|
25970
26676
|
}
|
|
25971
26677
|
return true;
|
|
25972
26678
|
}
|
|
26679
|
+
function stopOnboardingUi(home = os17.homedir()) {
|
|
26680
|
+
const uiStopped = stopPidFile(onboardingUiPaths(home).pidPath);
|
|
26681
|
+
const relayStopped = stopPidFile(onboardingRelayPaths(home).pidPath);
|
|
26682
|
+
return uiStopped || relayStopped;
|
|
26683
|
+
}
|
|
25973
26684
|
|
|
25974
26685
|
// src/lib/simple-stacey.ts
|
|
25975
26686
|
var SIMPLE_STACEY_PERSONA = "startup-advisor-intake";
|
|
@@ -26081,7 +26792,7 @@ var BootstrapUiCommand = class extends M8tCommand {
|
|
|
26081
26792
|
this.context.stderr.write(` ${colors.dim(m)}
|
|
26082
26793
|
`);
|
|
26083
26794
|
};
|
|
26084
|
-
if (
|
|
26795
|
+
if (fs33.existsSync(path36.join(os18.homedir(), ".m8t-stack", "config.yaml"))) {
|
|
26085
26796
|
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
26797
|
}
|
|
26087
26798
|
const credential2 = new DefaultAzureCredential20();
|
|
@@ -26131,10 +26842,26 @@ var BootstrapUiCommand = class extends M8tCommand {
|
|
|
26131
26842
|
return 0;
|
|
26132
26843
|
}
|
|
26133
26844
|
if (this.foreground === true) {
|
|
26845
|
+
out("starting the voice relay on :8790 in the background\u2026");
|
|
26846
|
+
await serveOnboardingRelayDetached({
|
|
26847
|
+
repoRoot,
|
|
26848
|
+
foundryEndpoint: endpoint,
|
|
26849
|
+
tenantId: account.tenantId,
|
|
26850
|
+
clientId: state.appRegClientId
|
|
26851
|
+
});
|
|
26852
|
+
out("voice relay on :8790");
|
|
26134
26853
|
out("starting the webapp on :3000 (Ctrl-C to stop)\u2026");
|
|
26135
26854
|
await runInherit("pnpm", ["--filter", "web", "dev"], repoRoot, "BOOTSTRAP_UI_DEV_FAILED");
|
|
26136
26855
|
return 0;
|
|
26137
26856
|
}
|
|
26857
|
+
out("starting the voice relay on :8790 in the background\u2026");
|
|
26858
|
+
await serveOnboardingRelayDetached({
|
|
26859
|
+
repoRoot,
|
|
26860
|
+
foundryEndpoint: endpoint,
|
|
26861
|
+
tenantId: account.tenantId,
|
|
26862
|
+
clientId: state.appRegClientId
|
|
26863
|
+
});
|
|
26864
|
+
out("voice relay on :8790");
|
|
26138
26865
|
out("starting the webapp on :3000 in the background\u2026");
|
|
26139
26866
|
const { alreadyRunning, logPath } = await serveOnboardingUiDetached({ repoRoot, port: this.port });
|
|
26140
26867
|
if (alreadyRunning) {
|