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