@m8t-stack/cli 0.2.14 → 0.2.16
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 +290 -78
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -197,6 +197,13 @@ var init_brain_eval = __esm({
|
|
|
197
197
|
}
|
|
198
198
|
});
|
|
199
199
|
|
|
200
|
+
// ../../packages/api-contract/dist/esm/founder-benchmark.js
|
|
201
|
+
var init_founder_benchmark = __esm({
|
|
202
|
+
"../../packages/api-contract/dist/esm/founder-benchmark.js"() {
|
|
203
|
+
"use strict";
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
|
|
200
207
|
// ../../packages/api-contract/dist/esm/index.js
|
|
201
208
|
var init_esm = __esm({
|
|
202
209
|
"../../packages/api-contract/dist/esm/index.js"() {
|
|
@@ -212,6 +219,7 @@ var init_esm = __esm({
|
|
|
212
219
|
init_brain_link();
|
|
213
220
|
init_a2a_card();
|
|
214
221
|
init_brain_eval();
|
|
222
|
+
init_founder_benchmark();
|
|
215
223
|
}
|
|
216
224
|
});
|
|
217
225
|
|
|
@@ -1198,7 +1206,7 @@ var init_enable_hosted_brain = __esm({
|
|
|
1198
1206
|
import { Builtins, Cli } from "clipanion";
|
|
1199
1207
|
|
|
1200
1208
|
// src/lib/package-version.ts
|
|
1201
|
-
var CLI_VERSION = "0.2.
|
|
1209
|
+
var CLI_VERSION = "0.2.16";
|
|
1202
1210
|
|
|
1203
1211
|
// src/lib/render-error.ts
|
|
1204
1212
|
init_errors();
|
|
@@ -13197,6 +13205,18 @@ async function ghAuthLoginDevice(exec = defaultGhExec) {
|
|
|
13197
13205
|
});
|
|
13198
13206
|
}
|
|
13199
13207
|
}
|
|
13208
|
+
async function getGhToken(exec = defaultGhExec) {
|
|
13209
|
+
const r = await exec("gh", ["auth", "token"]);
|
|
13210
|
+
const tok = r.stdout.trim();
|
|
13211
|
+
if (r.exitCode !== 0 || !tok) {
|
|
13212
|
+
throw new LocalCliError({
|
|
13213
|
+
code: "GH_TOKEN_FAILED",
|
|
13214
|
+
message: `gh auth token failed (exit ${r.exitCode.toString()}): ${(r.stderr || r.stdout).slice(0, 200)}`,
|
|
13215
|
+
hint: "Run `gh auth login` to authenticate the GitHub CLI."
|
|
13216
|
+
});
|
|
13217
|
+
}
|
|
13218
|
+
return tok;
|
|
13219
|
+
}
|
|
13200
13220
|
async function getRepoId(owner, repo, exec = defaultGhExec) {
|
|
13201
13221
|
const r = await exec("gh", ["api", `/repos/${owner}/${repo}`, "--jq", ".id"]);
|
|
13202
13222
|
if (r.exitCode !== 0) {
|
|
@@ -13300,6 +13320,34 @@ async function tryOpenUrl(url, exec = defaultGhExec) {
|
|
|
13300
13320
|
} catch {
|
|
13301
13321
|
}
|
|
13302
13322
|
}
|
|
13323
|
+
function ghRepoProbe(args) {
|
|
13324
|
+
const exec = args.exec ?? defaultGhExec;
|
|
13325
|
+
const slug = `${args.owner}/${args.repo}`;
|
|
13326
|
+
return {
|
|
13327
|
+
repoStatus: async () => {
|
|
13328
|
+
const r = await exec("gh", ["api", "-i", `/repos/${slug}`]);
|
|
13329
|
+
const combined = `${r.stdout}
|
|
13330
|
+
${r.stderr}`;
|
|
13331
|
+
const header = /^HTTP\/[\d.]+\s+(\d{3})/m.exec(combined);
|
|
13332
|
+
if (header) return Number(header[1]);
|
|
13333
|
+
const ghErr = /\(HTTP (\d{3})\)/.exec(combined);
|
|
13334
|
+
if (ghErr) return Number(ghErr[1]);
|
|
13335
|
+
if (r.exitCode === 0) return 200;
|
|
13336
|
+
throw new LocalCliError({
|
|
13337
|
+
code: "GH_REPO_PROBE_FAILED",
|
|
13338
|
+
message: `gh api /repos/${slug} failed (exit ${r.exitCode.toString()}): ${(r.stderr || r.stdout).slice(0, 200)}`
|
|
13339
|
+
});
|
|
13340
|
+
},
|
|
13341
|
+
getFile: async (path29) => {
|
|
13342
|
+
const r = await exec("gh", ["api", "-H", "Accept: application/vnd.github.raw+json", `/repos/${slug}/contents/${path29}`]);
|
|
13343
|
+
return r.exitCode === 0 ? r.stdout : null;
|
|
13344
|
+
},
|
|
13345
|
+
isEmpty: async () => {
|
|
13346
|
+
const r = await exec("gh", ["api", `/repos/${slug}/contents`]);
|
|
13347
|
+
return r.exitCode !== 0;
|
|
13348
|
+
}
|
|
13349
|
+
};
|
|
13350
|
+
}
|
|
13303
13351
|
|
|
13304
13352
|
// src/commands/brain/app-create.ts
|
|
13305
13353
|
init_errors();
|
|
@@ -13534,6 +13582,7 @@ import { readFileSync as readFileSync6 } from "fs";
|
|
|
13534
13582
|
import * as fs10 from "fs";
|
|
13535
13583
|
import * as os4 from "os";
|
|
13536
13584
|
import * as path9 from "path";
|
|
13585
|
+
import * as readline2 from "readline/promises";
|
|
13537
13586
|
import { DefaultAzureCredential as DefaultAzureCredential4 } from "@azure/identity";
|
|
13538
13587
|
init_errors();
|
|
13539
13588
|
|
|
@@ -14065,6 +14114,20 @@ function materializeBrainTree(opts) {
|
|
|
14065
14114
|
init_errors();
|
|
14066
14115
|
init_esm2();
|
|
14067
14116
|
import { spawn as spawn3 } from "child_process";
|
|
14117
|
+
import { parse as parseYaml5 } from "yaml";
|
|
14118
|
+
function isM8tBrainMarker(yamlText) {
|
|
14119
|
+
if (!yamlText.trim()) return false;
|
|
14120
|
+
let parsed;
|
|
14121
|
+
try {
|
|
14122
|
+
parsed = parseYaml5(yamlText);
|
|
14123
|
+
} catch {
|
|
14124
|
+
return false;
|
|
14125
|
+
}
|
|
14126
|
+
if (!parsed || typeof parsed !== "object") return false;
|
|
14127
|
+
const root = parsed;
|
|
14128
|
+
const isObj2 = (v) => typeof v === "object" && v !== null;
|
|
14129
|
+
return isObj2(root.engine) || isObj2(root.processes) || isObj2(root.link);
|
|
14130
|
+
}
|
|
14068
14131
|
async function createBlankRepo(args) {
|
|
14069
14132
|
const res = await fetch(`https://api.github.com/orgs/${args.org}/repos`, {
|
|
14070
14133
|
method: "POST",
|
|
@@ -14195,8 +14258,119 @@ async function commitFilesViaApp(args) {
|
|
|
14195
14258
|
});
|
|
14196
14259
|
await api(`/git/refs/heads/${args.branch}`, { method: "PATCH", body: JSON.stringify({ sha: commit.sha }) });
|
|
14197
14260
|
}
|
|
14261
|
+
async function probeRepoState(probe) {
|
|
14262
|
+
const status = await probe.repoStatus();
|
|
14263
|
+
if (status === 404) return "absent";
|
|
14264
|
+
if (status !== 200) {
|
|
14265
|
+
throw new LocalCliError({
|
|
14266
|
+
code: "GH_REPO_PROBE_FAILED",
|
|
14267
|
+
message: `GET repo returned HTTP ${status.toString()} (expected 200 or 404)`
|
|
14268
|
+
});
|
|
14269
|
+
}
|
|
14270
|
+
const marker = await probe.getFile(".m8t/brain.yaml");
|
|
14271
|
+
if (marker !== null && isM8tBrainMarker(marker)) return "m8t-brain";
|
|
14272
|
+
if (await probe.isEmpty()) return "empty";
|
|
14273
|
+
return "foreign";
|
|
14274
|
+
}
|
|
14275
|
+
function appRepoProbe(args) {
|
|
14276
|
+
const doFetch = args.fetchImpl ?? fetch;
|
|
14277
|
+
const H = ghHeaders(args.token);
|
|
14278
|
+
return {
|
|
14279
|
+
repoStatus: async () => {
|
|
14280
|
+
const res = await doFetch(`${GH_API}/repos/${args.repo}`, { headers: H, signal: AbortSignal.timeout(GH_REQUEST_TIMEOUT_MS) });
|
|
14281
|
+
return res.status;
|
|
14282
|
+
},
|
|
14283
|
+
getFile: (path29) => readRepoFileViaApp({ token: args.token, repo: args.repo, path: path29, fetchImpl: args.fetchImpl }),
|
|
14284
|
+
isEmpty: async () => {
|
|
14285
|
+
const res = await doFetch(`${GH_API}/repos/${args.repo}/contents`, { headers: H, signal: AbortSignal.timeout(GH_REQUEST_TIMEOUT_MS) });
|
|
14286
|
+
return res.status === 404;
|
|
14287
|
+
}
|
|
14288
|
+
};
|
|
14289
|
+
}
|
|
14290
|
+
|
|
14291
|
+
// src/lib/brain-repo-collision.ts
|
|
14292
|
+
init_errors();
|
|
14293
|
+
var DEFAULT_MAX_ATTEMPTS = 20;
|
|
14294
|
+
function actionForState(state) {
|
|
14295
|
+
switch (state) {
|
|
14296
|
+
case "absent":
|
|
14297
|
+
return "create";
|
|
14298
|
+
case "m8t-brain":
|
|
14299
|
+
return "reuse";
|
|
14300
|
+
case "empty":
|
|
14301
|
+
return "adopt";
|
|
14302
|
+
case "foreign":
|
|
14303
|
+
throw new LocalCliError({
|
|
14304
|
+
code: "FOREIGN_REPO_COLLISION",
|
|
14305
|
+
message: `A repo already exists but isn't an m8t brain.`
|
|
14306
|
+
});
|
|
14307
|
+
}
|
|
14308
|
+
}
|
|
14309
|
+
function candidate(base, n) {
|
|
14310
|
+
return n === 1 ? base : `${base}-${n.toString()}`;
|
|
14311
|
+
}
|
|
14312
|
+
async function scan(base, classify, accept, startAt, maxAttempts) {
|
|
14313
|
+
for (let n = startAt; n <= maxAttempts; n++) {
|
|
14314
|
+
const name = candidate(base, n);
|
|
14315
|
+
const state = await classify(name);
|
|
14316
|
+
if (accept(state)) return { repoName: name, state };
|
|
14317
|
+
}
|
|
14318
|
+
throw new LocalCliError({
|
|
14319
|
+
code: "REPO_NAME_SCAN_EXHAUSTED",
|
|
14320
|
+
message: `Could not find a free repo name for "${base}" after ${maxAttempts.toString()} attempts.`
|
|
14321
|
+
});
|
|
14322
|
+
}
|
|
14323
|
+
async function resolveRepoCollision(args) {
|
|
14324
|
+
const max = args.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;
|
|
14325
|
+
const state = await args.classify(args.repoName);
|
|
14326
|
+
if (args.force === "new") {
|
|
14327
|
+
const found = await scan(args.repoName, args.classify, (s) => s === "absent", 1, max);
|
|
14328
|
+
return { repoName: found.repoName, action: "create" };
|
|
14329
|
+
}
|
|
14330
|
+
if (args.force === "reuse") {
|
|
14331
|
+
return { repoName: args.repoName, action: actionForState(state) };
|
|
14332
|
+
}
|
|
14333
|
+
if (state === "absent") return { repoName: args.repoName, action: "create" };
|
|
14334
|
+
if (args.interactive && args.prompt) {
|
|
14335
|
+
const choice = await args.prompt({ repoName: args.repoName, state });
|
|
14336
|
+
if (choice === "abort") {
|
|
14337
|
+
throw new LocalCliError({ code: "BRAIN_CREATE_ABORTED", message: "Aborted by the operator." });
|
|
14338
|
+
}
|
|
14339
|
+
if (choice === "new") {
|
|
14340
|
+
const found = await scan(args.repoName, args.classify, (s) => s !== "foreign", 2, max);
|
|
14341
|
+
return { repoName: found.repoName, action: actionForState(found.state) };
|
|
14342
|
+
}
|
|
14343
|
+
return { repoName: args.repoName, action: actionForState(state) };
|
|
14344
|
+
}
|
|
14345
|
+
if (state === "foreign") {
|
|
14346
|
+
throw new LocalCliError({
|
|
14347
|
+
code: "FOREIGN_REPO_COLLISION",
|
|
14348
|
+
message: `A repo with this name already exists but isn't an m8t brain, so it won't be touched. Rename that repo or install into a different org, then re-run.`
|
|
14349
|
+
});
|
|
14350
|
+
}
|
|
14351
|
+
return { repoName: args.repoName, action: actionForState(state) };
|
|
14352
|
+
}
|
|
14198
14353
|
|
|
14199
14354
|
// src/commands/brain/create.ts
|
|
14355
|
+
async function promptCollision(ctx, info) {
|
|
14356
|
+
const rl = readline2.createInterface({ input: ctx.stdin, output: ctx.stdout });
|
|
14357
|
+
try {
|
|
14358
|
+
if (info.state === "foreign") {
|
|
14359
|
+
const ans2 = (await rl.question(
|
|
14360
|
+
`A repo "${info.repoName}" already exists but isn't an m8t brain. Create a new "${info.repoName}-2" instead? [Y/n] (n aborts) `
|
|
14361
|
+
)).trim().toLowerCase();
|
|
14362
|
+
return ans2 === "" || ans2 === "y" || ans2 === "yes" ? "new" : "abort";
|
|
14363
|
+
}
|
|
14364
|
+
const ans = (await rl.question(
|
|
14365
|
+
`An m8t brain "${info.repoName}" already exists. Reuse it? [Y/n] (n creates "${info.repoName}-2", or "a" aborts) `
|
|
14366
|
+
)).trim().toLowerCase();
|
|
14367
|
+
if (ans === "" || ans === "y" || ans === "yes") return "reuse";
|
|
14368
|
+
if (ans === "a" || ans === "abort") return "abort";
|
|
14369
|
+
return "new";
|
|
14370
|
+
} finally {
|
|
14371
|
+
rl.close();
|
|
14372
|
+
}
|
|
14373
|
+
}
|
|
14200
14374
|
function stageAsGitRepo(dir) {
|
|
14201
14375
|
const steps = [
|
|
14202
14376
|
{ args: ["init", "-b", "main"], label: "git init" },
|
|
@@ -14239,6 +14413,8 @@ var BrainCreateCommand = class extends M8tCommand {
|
|
|
14239
14413
|
appId = Option17.String("--app-id", { description: "GitHub App id (no-gh path); with --app-pem/--installation-id, create the repo via the App instead of gh." });
|
|
14240
14414
|
appPem = Option17.String("--app-pem", { description: "Path to the App private-key PEM (no-gh path)." });
|
|
14241
14415
|
installationId = Option17.String("--installation-id", { description: "Org installation id for the App (no-gh path)." });
|
|
14416
|
+
reuse = Option17.Boolean("--reuse", false, { description: "If the brain repo already exists, reuse it (non-interactive). Errors if the repo isn't a valid m8t brain." });
|
|
14417
|
+
newName = Option17.Boolean("--new", false, { description: "If the brain repo name is taken, create a fresh suffixed repo (e.g. <name>-2) instead of reusing." });
|
|
14242
14418
|
async executeCommand() {
|
|
14243
14419
|
const owner = typeof this.owner === "string" ? this.owner : void 0;
|
|
14244
14420
|
const worker = typeof this.worker === "string" ? this.worker : void 0;
|
|
@@ -14303,59 +14479,95 @@ var BrainCreateCommand = class extends M8tCommand {
|
|
|
14303
14479
|
const tmpDir = fs10.mkdtempSync(path9.join(os4.tmpdir(), `m8t-brain-create-${worker}-`));
|
|
14304
14480
|
let result;
|
|
14305
14481
|
let resolvedInstallationId = null;
|
|
14482
|
+
const force = this.reuse === true ? "reuse" : this.newName === true ? "new" : void 0;
|
|
14483
|
+
const interactive = !useAppPath && this.context.stdout.isTTY === true;
|
|
14484
|
+
let token;
|
|
14485
|
+
let classify;
|
|
14486
|
+
if (useAppPath) {
|
|
14487
|
+
token = await mintInstallationTokenFromPem({
|
|
14488
|
+
appId: appIdOpt,
|
|
14489
|
+
privateKeyPem: readFileSync6(appPemOpt, "utf8"),
|
|
14490
|
+
installationId: installationIdOpt
|
|
14491
|
+
});
|
|
14492
|
+
const tok = token;
|
|
14493
|
+
classify = (name) => probeRepoState(appRepoProbe({ token: tok, repo: `${owner}/${name}` }));
|
|
14494
|
+
} else {
|
|
14495
|
+
classify = (name) => probeRepoState(ghRepoProbe({ owner, repo: name }));
|
|
14496
|
+
}
|
|
14497
|
+
const decision = await resolveRepoCollision({
|
|
14498
|
+
repoName,
|
|
14499
|
+
classify,
|
|
14500
|
+
interactive,
|
|
14501
|
+
force,
|
|
14502
|
+
prompt: interactive ? (info) => promptCollision(
|
|
14503
|
+
{ stdin: this.context.stdin, stdout: this.context.stdout },
|
|
14504
|
+
info
|
|
14505
|
+
) : void 0
|
|
14506
|
+
});
|
|
14507
|
+
const finalName = decision.repoName;
|
|
14508
|
+
const needsPush = decision.action === "create" || decision.action === "adopt";
|
|
14509
|
+
if (finalName !== repoName) {
|
|
14510
|
+
this.context.stdout.write(`${colors.hint("note:")} using repo name ${colors.field(finalName)} (${decision.action}).
|
|
14511
|
+
`);
|
|
14512
|
+
}
|
|
14306
14513
|
try {
|
|
14307
|
-
|
|
14308
|
-
|
|
14309
|
-
|
|
14514
|
+
if (needsPush) {
|
|
14515
|
+
materializeBrainTree({ templateSrc, destDir: tmpDir, seedDir });
|
|
14516
|
+
this.context.stdout.write(
|
|
14517
|
+
seedName ? `${colors.dim("\u2192")} copied brain-template/ + overlaid seed ${colors.field(seedName)} to ${tmpDir}
|
|
14310
14518
|
` : `${colors.dim("\u2192")} copied brain-template/ to ${tmpDir}
|
|
14311
14519
|
`
|
|
14312
|
-
|
|
14520
|
+
);
|
|
14521
|
+
}
|
|
14313
14522
|
if (useAppPath) {
|
|
14314
|
-
|
|
14523
|
+
const appToken = token ?? "";
|
|
14524
|
+
if (decision.action === "create") {
|
|
14525
|
+
this.context.stdout.write(`${colors.dim("\u2192")} creating ${owner}/${finalName} via the GitHub App (no gh)\u2026
|
|
14526
|
+
`);
|
|
14527
|
+
await createBlankRepo({ token: appToken, org: owner, name: finalName, private: !this.public_ });
|
|
14528
|
+
await pushSeed({ token: appToken, org: owner, name: finalName, branch, sourceDir: tmpDir });
|
|
14529
|
+
this.context.stdout.write(`${colors.success("\u2713")} repo created + seeded via the App
|
|
14530
|
+
`);
|
|
14531
|
+
} else if (decision.action === "adopt") {
|
|
14532
|
+
this.context.stdout.write(`${colors.dim("\u2192")} seeding the existing empty repo ${owner}/${finalName} via the GitHub App\u2026
|
|
14533
|
+
`);
|
|
14534
|
+
await pushSeed({ token: appToken, org: owner, name: finalName, branch, sourceDir: tmpDir });
|
|
14535
|
+
this.context.stdout.write(`${colors.success("\u2713")} empty repo seeded via the App
|
|
14536
|
+
`);
|
|
14537
|
+
} else {
|
|
14538
|
+
this.context.stdout.write(`${colors.success("\u2713")} reusing the existing brain ${owner}/${finalName}
|
|
14315
14539
|
`);
|
|
14316
|
-
const pem = readFileSync6(appPemOpt, "utf8");
|
|
14317
|
-
const appJwt = signAppJwt({ appId: appIdOpt, privateKeyPem: pem });
|
|
14318
|
-
const tokRes = await fetch(
|
|
14319
|
-
`https://api.github.com/app/installations/${installationIdOpt}/access_tokens`,
|
|
14320
|
-
{
|
|
14321
|
-
method: "POST",
|
|
14322
|
-
headers: {
|
|
14323
|
-
Authorization: `Bearer ${appJwt}`,
|
|
14324
|
-
Accept: "application/vnd.github+json",
|
|
14325
|
-
"X-GitHub-Api-Version": "2022-11-28",
|
|
14326
|
-
"User-Agent": "m8t"
|
|
14327
|
-
}
|
|
14328
|
-
}
|
|
14329
|
-
);
|
|
14330
|
-
if (!tokRes.ok) {
|
|
14331
|
-
throw new LocalCliError({
|
|
14332
|
-
code: "GH_APP_TOKEN_FAILED",
|
|
14333
|
-
message: `mint installation token HTTP ${tokRes.status.toString()}: ${(await tokRes.text()).slice(0, 300)}`
|
|
14334
|
-
});
|
|
14335
14540
|
}
|
|
14336
|
-
const token = (await tokRes.json()).token;
|
|
14337
|
-
await createBlankRepo({ token, org: owner, name: repoName, private: !this.public_ });
|
|
14338
|
-
await pushSeed({ token, org: owner, name: repoName, branch, sourceDir: tmpDir });
|
|
14339
14541
|
resolvedInstallationId = installationIdOpt;
|
|
14340
|
-
this.context.stdout.write(`${colors.success("\u2713")} repo created + seeded via the App
|
|
14341
|
-
`);
|
|
14342
14542
|
} else {
|
|
14343
|
-
|
|
14344
|
-
|
|
14543
|
+
if (decision.action === "create") {
|
|
14544
|
+
stageAsGitRepo(tmpDir);
|
|
14545
|
+
this.context.stdout.write(`${colors.dim("\u2192")} creating repo ${owner}/${finalName} (${this.public_ ? "public" : "private"})\u2026
|
|
14546
|
+
`);
|
|
14547
|
+
await createRepo({ owner, name: finalName, private: !this.public_, source: tmpDir });
|
|
14548
|
+
this.context.stdout.write(`${colors.success("\u2713")} repo created
|
|
14549
|
+
`);
|
|
14550
|
+
} else if (decision.action === "adopt") {
|
|
14551
|
+
this.context.stdout.write(`${colors.dim("\u2192")} seeding the existing empty repo ${owner}/${finalName}\u2026
|
|
14345
14552
|
`);
|
|
14346
|
-
|
|
14347
|
-
|
|
14553
|
+
const ghToken = await getGhToken();
|
|
14554
|
+
await pushSeed({ token: ghToken, org: owner, name: finalName, branch, sourceDir: tmpDir });
|
|
14555
|
+
this.context.stdout.write(`${colors.success("\u2713")} empty repo seeded
|
|
14348
14556
|
`);
|
|
14349
|
-
|
|
14557
|
+
} else {
|
|
14558
|
+
this.context.stdout.write(`${colors.success("\u2713")} reusing the existing brain ${owner}/${finalName}
|
|
14559
|
+
`);
|
|
14560
|
+
}
|
|
14561
|
+
const repoId = await getRepoId(owner, finalName);
|
|
14350
14562
|
const { slug, appId: secretAppId, privateKeyPem } = await readAppSecrets({ credential: credential2, kvUri });
|
|
14351
14563
|
const initialJwt = signAppJwt({ appId: secretAppId, privateKeyPem });
|
|
14352
|
-
resolvedInstallationId = await probeAppInstallation({ owner, repo:
|
|
14564
|
+
resolvedInstallationId = await probeAppInstallation({ owner, repo: finalName, jwt: initialJwt });
|
|
14353
14565
|
if (resolvedInstallationId) {
|
|
14354
|
-
this.context.stdout.write(` ${colors.success("\u2713")} App already installed on ${colors.field(`${owner}/${
|
|
14566
|
+
this.context.stdout.write(` ${colors.success("\u2713")} App already installed on ${colors.field(`${owner}/${finalName}`)} (installation ${resolvedInstallationId}); skipping browser open.
|
|
14355
14567
|
`);
|
|
14356
14568
|
} else {
|
|
14357
14569
|
const url = installUrl(slug, repoId);
|
|
14358
|
-
this.context.stdout.write(`${colors.field("\u2192")} Install the m8t-brain App on ${owner}/${
|
|
14570
|
+
this.context.stdout.write(`${colors.field("\u2192")} Install the m8t-brain App on ${owner}/${finalName}:
|
|
14359
14571
|
${url}
|
|
14360
14572
|
`);
|
|
14361
14573
|
await tryOpenUrl(url);
|
|
@@ -14363,10 +14575,10 @@ var BrainCreateCommand = class extends M8tCommand {
|
|
|
14363
14575
|
`);
|
|
14364
14576
|
resolvedInstallationId = await pollForInstallation({
|
|
14365
14577
|
owner,
|
|
14366
|
-
repo:
|
|
14578
|
+
repo: finalName,
|
|
14367
14579
|
// Mint fresh JWT each tick — App JWTs are 10-min TTL, poll defaults to 5 min
|
|
14368
14580
|
// but the timeout is a soft default, so don't depend on the inequality.
|
|
14369
|
-
probe: () => probeAppInstallation({ owner, repo:
|
|
14581
|
+
probe: () => probeAppInstallation({ owner, repo: finalName, jwt: signAppJwt({ appId: secretAppId, privateKeyPem }) }),
|
|
14370
14582
|
onTick: (n) => {
|
|
14371
14583
|
if (n % 5 === 0) this.context.stderr.write(` ${colors.dim(`\u2026still waiting (${(n * 2).toString()}s)`)}
|
|
14372
14584
|
`);
|
|
@@ -14382,7 +14594,7 @@ var BrainCreateCommand = class extends M8tCommand {
|
|
|
14382
14594
|
projectEndpoint: project.endpoint,
|
|
14383
14595
|
projectArmId: `${project.accountScope}/projects/${project.projectName}`,
|
|
14384
14596
|
agentName: worker,
|
|
14385
|
-
repo: `${owner}/${
|
|
14597
|
+
repo: `${owner}/${finalName}`,
|
|
14386
14598
|
branch,
|
|
14387
14599
|
repoRoot,
|
|
14388
14600
|
installationId: resolvedInstallationId,
|
|
@@ -14396,7 +14608,7 @@ var BrainCreateCommand = class extends M8tCommand {
|
|
|
14396
14608
|
this.context.stdout.write(
|
|
14397
14609
|
renderJson({
|
|
14398
14610
|
worker,
|
|
14399
|
-
repo: `${owner}/${
|
|
14611
|
+
repo: `${owner}/${finalName}`,
|
|
14400
14612
|
branch,
|
|
14401
14613
|
installationId: resolvedInstallationId,
|
|
14402
14614
|
connectionName: result.connectionName,
|
|
@@ -14406,10 +14618,10 @@ var BrainCreateCommand = class extends M8tCommand {
|
|
|
14406
14618
|
return 0;
|
|
14407
14619
|
}
|
|
14408
14620
|
this.context.stdout.write(
|
|
14409
|
-
`${colors.success("\u2713")} created + linked ${colors.field(worker)} \u2194 ${colors.field(`${owner}/${
|
|
14621
|
+
`${colors.success("\u2713")} created + linked ${colors.field(worker)} \u2194 ${colors.field(`${owner}/${finalName}`)} (agent version ${result.foundryVersion ?? ""}).
|
|
14410
14622
|
`
|
|
14411
14623
|
);
|
|
14412
|
-
this.context.stdout.write(` ${colors.hint("brain repo:")} https://github.com/${owner}/${
|
|
14624
|
+
this.context.stdout.write(` ${colors.hint("brain repo:")} https://github.com/${owner}/${finalName}
|
|
14413
14625
|
`);
|
|
14414
14626
|
this.context.stdout.write(` ${colors.hint("token:")} rotates lazily on every invoke (60min TTL, 10min safety margin).
|
|
14415
14627
|
`);
|
|
@@ -15010,7 +15222,7 @@ init_errors();
|
|
|
15010
15222
|
// src/lib/deploy-prompt-advisor.ts
|
|
15011
15223
|
import * as fs12 from "fs";
|
|
15012
15224
|
import * as path11 from "path";
|
|
15013
|
-
import { parse as
|
|
15225
|
+
import { parse as parseYaml6 } from "yaml";
|
|
15014
15226
|
init_foundry_agents();
|
|
15015
15227
|
init_errors();
|
|
15016
15228
|
function findPersonasRoot(hint) {
|
|
@@ -15038,7 +15250,7 @@ async function deployPromptAdvisor(args) {
|
|
|
15038
15250
|
});
|
|
15039
15251
|
}
|
|
15040
15252
|
const fmMatch = /^---\n([\s\S]*?)\n---/.exec(raw);
|
|
15041
|
-
const fm = fmMatch ?
|
|
15253
|
+
const fm = fmMatch ? parseYaml6(fmMatch[1]) : {};
|
|
15042
15254
|
const model = args.model ?? fm.targets?.foundry?.model;
|
|
15043
15255
|
if (!model) {
|
|
15044
15256
|
throw new LocalCliError({
|
|
@@ -15305,7 +15517,7 @@ async function awaitAgentQueryable(args) {
|
|
|
15305
15517
|
init_errors();
|
|
15306
15518
|
init_esm();
|
|
15307
15519
|
import * as fs13 from "fs";
|
|
15308
|
-
import { parse as
|
|
15520
|
+
import { parse as parseYaml7 } from "yaml";
|
|
15309
15521
|
function readPersonaA2aCard(personaPath) {
|
|
15310
15522
|
let raw;
|
|
15311
15523
|
try {
|
|
@@ -15315,7 +15527,7 @@ function readPersonaA2aCard(personaPath) {
|
|
|
15315
15527
|
}
|
|
15316
15528
|
const fm = /^---\n([\s\S]*?)\n---/.exec(raw);
|
|
15317
15529
|
if (!fm) throw new LocalCliError({ code: "PERSONA_NO_FRONTMATTER", message: `Persona '${personaPath}' has no frontmatter.` });
|
|
15318
|
-
const front =
|
|
15530
|
+
const front = parseYaml7(fm[1]);
|
|
15319
15531
|
const role = typeof front.role === "string" ? front.role : "";
|
|
15320
15532
|
const cardYaml = front.targets?.foundry?.["a2a-card"];
|
|
15321
15533
|
if (!cardYaml || typeof cardYaml !== "object") {
|
|
@@ -15801,7 +16013,7 @@ init_errors();
|
|
|
15801
16013
|
import * as fs15 from "fs";
|
|
15802
16014
|
import * as os6 from "os";
|
|
15803
16015
|
import * as path12 from "path";
|
|
15804
|
-
import { parse as
|
|
16016
|
+
import { parse as parseYaml8 } from "yaml";
|
|
15805
16017
|
var A2A_PATH = "/api/a2a/mcp";
|
|
15806
16018
|
function resolveBridgeUrl(opts) {
|
|
15807
16019
|
const env = opts.env ?? process.env;
|
|
@@ -15825,7 +16037,7 @@ function readConfigGatewayUrl(home) {
|
|
|
15825
16037
|
const cfg = path12.join(home ?? os6.homedir(), ".m8t-stack", "config.yaml");
|
|
15826
16038
|
if (!fs15.existsSync(cfg)) return void 0;
|
|
15827
16039
|
try {
|
|
15828
|
-
const o =
|
|
16040
|
+
const o = parseYaml8(fs15.readFileSync(cfg, "utf8"));
|
|
15829
16041
|
return typeof o.gatewayUrl === "string" ? o.gatewayUrl : void 0;
|
|
15830
16042
|
} catch {
|
|
15831
16043
|
return void 0;
|
|
@@ -16327,7 +16539,7 @@ async function deployHostedWorker(args) {
|
|
|
16327
16539
|
// src/lib/persona.ts
|
|
16328
16540
|
import * as fs17 from "fs";
|
|
16329
16541
|
import * as path15 from "path";
|
|
16330
|
-
import { parse as
|
|
16542
|
+
import { parse as parseYaml9 } from "yaml";
|
|
16331
16543
|
function findRepoRoot(startDir) {
|
|
16332
16544
|
let dir = path15.resolve(startDir);
|
|
16333
16545
|
for (; ; ) {
|
|
@@ -16351,7 +16563,7 @@ function resolvePersona(persona, cwd = process.cwd()) {
|
|
|
16351
16563
|
if (!match) return { persona, personaVersion: null };
|
|
16352
16564
|
let fm = null;
|
|
16353
16565
|
try {
|
|
16354
|
-
fm =
|
|
16566
|
+
fm = parseYaml9(match[1]);
|
|
16355
16567
|
} catch {
|
|
16356
16568
|
return { persona, personaVersion: null };
|
|
16357
16569
|
}
|
|
@@ -18256,9 +18468,9 @@ var EvalSkillCommand = class extends M8tCommand {
|
|
|
18256
18468
|
return Promise.resolve(this._runCommand());
|
|
18257
18469
|
}
|
|
18258
18470
|
_runCommand() {
|
|
18259
|
-
const
|
|
18471
|
+
const candidate2 = typeof this.candidate === "string" ? this.candidate : void 0;
|
|
18260
18472
|
const skillsDir = typeof this.skillsDir === "string" ? this.skillsDir : void 0;
|
|
18261
|
-
if (!
|
|
18473
|
+
if (!candidate2) {
|
|
18262
18474
|
throw new LocalCliError({ code: "USAGE", message: "<path> positional argument is required" });
|
|
18263
18475
|
}
|
|
18264
18476
|
if (!skillsDir) {
|
|
@@ -18267,7 +18479,7 @@ var EvalSkillCommand = class extends M8tCommand {
|
|
|
18267
18479
|
const outputFlag = this.output === "json" || this.output === "auto" || this.output === "pretty" ? this.output : "pretty";
|
|
18268
18480
|
const mode = resolveOutputMode(outputFlag, this.context.stdout);
|
|
18269
18481
|
const bin = process.env.BRAIN_EVAL_BIN ?? "brain-eval";
|
|
18270
|
-
const args = ["skill",
|
|
18482
|
+
const args = ["skill", candidate2, "--skills-dir", skillsDir, "--json"];
|
|
18271
18483
|
if (this.noJudge === true) args.push("--no-judge");
|
|
18272
18484
|
if (typeof this.deployment === "string") args.push("--deployment", this.deployment);
|
|
18273
18485
|
const res = spawnSync3(bin, args, { encoding: "utf-8" });
|
|
@@ -19256,7 +19468,7 @@ import { Command as Command41, Option as Option39 } from "clipanion";
|
|
|
19256
19468
|
// src/lib/profiles.ts
|
|
19257
19469
|
import * as fs20 from "fs/promises";
|
|
19258
19470
|
import * as path21 from "path";
|
|
19259
|
-
import { parse as
|
|
19471
|
+
import { parse as parseYaml10, stringify as stringifyYaml4 } from "yaml";
|
|
19260
19472
|
function profilesDir() {
|
|
19261
19473
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
19262
19474
|
return path21.join(home, ".m8t-stack", "profiles");
|
|
@@ -19281,7 +19493,7 @@ async function listProfiles() {
|
|
|
19281
19493
|
async function readProfile(name) {
|
|
19282
19494
|
try {
|
|
19283
19495
|
const raw = await fs20.readFile(getProfilePath(name), "utf8");
|
|
19284
|
-
const parsed =
|
|
19496
|
+
const parsed = parseYaml10(raw);
|
|
19285
19497
|
if (!parsed || typeof parsed !== "object") return null;
|
|
19286
19498
|
return parsed;
|
|
19287
19499
|
} catch (e) {
|
|
@@ -20451,16 +20663,16 @@ function buildAdvancePlan(worker, cursor, physicalPks, consumedRowsByPk, failedT
|
|
|
20451
20663
|
for (const pk of physicalPks) {
|
|
20452
20664
|
const rowsForPk = consumedRowsByPk[pk] ?? [];
|
|
20453
20665
|
const { ts, consumedRowKeys } = computeWatermark(rowsForPk, now.toISOString(), safetyLagSeconds);
|
|
20454
|
-
let
|
|
20666
|
+
let candidate2 = ts;
|
|
20455
20667
|
const prior = Object.hasOwn(cursor.watermarks, pk) ? cursor.watermarks[pk].ts : void 0;
|
|
20456
20668
|
if (prior)
|
|
20457
20669
|
priorTsByPk[pk] = prior;
|
|
20458
|
-
if (prior &&
|
|
20459
|
-
|
|
20670
|
+
if (prior && candidate2 < prior)
|
|
20671
|
+
candidate2 = prior;
|
|
20460
20672
|
const failed = failedTsByPk[pk];
|
|
20461
|
-
if (failed &&
|
|
20462
|
-
|
|
20463
|
-
watermarks[pk] = { ts:
|
|
20673
|
+
if (failed && candidate2 >= failed)
|
|
20674
|
+
candidate2 = justBefore(failed);
|
|
20675
|
+
watermarks[pk] = { ts: candidate2, consumedRowKeys };
|
|
20464
20676
|
consumedKeysByPk[pk] = consumedRowKeys;
|
|
20465
20677
|
}
|
|
20466
20678
|
return {
|
|
@@ -20854,12 +21066,12 @@ function validateDelta(d) {
|
|
|
20854
21066
|
}
|
|
20855
21067
|
function extractJson(text) {
|
|
20856
21068
|
const fenced = /```(?:json)?\s*([\s\S]*?)```/.exec(text);
|
|
20857
|
-
const
|
|
20858
|
-
const start =
|
|
20859
|
-
const end =
|
|
21069
|
+
const candidate2 = (fenced ? fenced[1] : text).trim();
|
|
21070
|
+
const start = candidate2.indexOf("{");
|
|
21071
|
+
const end = candidate2.lastIndexOf("}");
|
|
20860
21072
|
if (start === -1 || end === -1 || end < start)
|
|
20861
21073
|
throw new Error("no JSON object found");
|
|
20862
|
-
return JSON.parse(
|
|
21074
|
+
return JSON.parse(candidate2.slice(start, end + 1));
|
|
20863
21075
|
}
|
|
20864
21076
|
async function propose(model, system, user, opts = {}) {
|
|
20865
21077
|
const sleep2 = opts.sleep ?? defaultSleep2;
|
|
@@ -21439,14 +21651,14 @@ function narrowAdvance(src, kept) {
|
|
|
21439
21651
|
for (const pk of Object.keys(src.watermarks)) {
|
|
21440
21652
|
const rows = keptRowsByPk[pk] ?? [];
|
|
21441
21653
|
const { ts, consumedRowKeys } = computeWatermark(rows, now, safetyLagSeconds);
|
|
21442
|
-
let
|
|
21654
|
+
let candidate2 = ts;
|
|
21443
21655
|
const prior = priorTsByPk[pk];
|
|
21444
|
-
if (prior &&
|
|
21445
|
-
|
|
21656
|
+
if (prior && candidate2 < prior)
|
|
21657
|
+
candidate2 = prior;
|
|
21446
21658
|
const failed = src.failedTsByPk[pk];
|
|
21447
|
-
if (failed &&
|
|
21448
|
-
|
|
21449
|
-
watermarks[pk] = { ts:
|
|
21659
|
+
if (failed && candidate2 >= failed)
|
|
21660
|
+
candidate2 = justBefore(failed);
|
|
21661
|
+
watermarks[pk] = { ts: candidate2, consumedRowKeys };
|
|
21450
21662
|
consumedRowsByPk[pk] = consumedRowKeys;
|
|
21451
21663
|
}
|
|
21452
21664
|
return {
|
|
@@ -21548,7 +21760,7 @@ async function emitDigest(input, deps, digest) {
|
|
|
21548
21760
|
}
|
|
21549
21761
|
|
|
21550
21762
|
// ../../packages/brain/engine/dist/esm/dream/config.js
|
|
21551
|
-
import { parse as
|
|
21763
|
+
import { parse as parseYaml11 } from "yaml";
|
|
21552
21764
|
var DEFAULT_DREAM_MODEL = "gpt-5.4";
|
|
21553
21765
|
function asCadence(v) {
|
|
21554
21766
|
return v === "nightly" ? "nightly" : "off";
|
|
@@ -21556,7 +21768,7 @@ function asCadence(v) {
|
|
|
21556
21768
|
function parseDreamerConfig(rawYaml, env) {
|
|
21557
21769
|
let parsed;
|
|
21558
21770
|
try {
|
|
21559
|
-
parsed =
|
|
21771
|
+
parsed = parseYaml11(rawYaml);
|
|
21560
21772
|
} catch {
|
|
21561
21773
|
return { enabled: false, cadence: "off", model: env.M8T_DREAM_MODEL ?? DEFAULT_DREAM_MODEL };
|
|
21562
21774
|
}
|
|
@@ -21570,16 +21782,16 @@ function parseDreamerConfig(rawYaml, env) {
|
|
|
21570
21782
|
}
|
|
21571
21783
|
|
|
21572
21784
|
// ../../packages/brain/engine/dist/esm/cost-report/config.js
|
|
21573
|
-
import { parse as
|
|
21785
|
+
import { parse as parseYaml12 } from "yaml";
|
|
21574
21786
|
|
|
21575
21787
|
// ../../packages/brain/engine/dist/esm/librarian/codify/persistence-guard.js
|
|
21576
21788
|
var ZERO_WIDTH_RE = new RegExp("\u200B|\u200C|\u200D|\uFEFF", "g");
|
|
21577
21789
|
|
|
21578
21790
|
// ../../packages/brain/engine/dist/esm/librarian/janitor/frontmatter.js
|
|
21579
|
-
import { parse as
|
|
21791
|
+
import { parse as parseYaml13, stringify as stringifyYaml5 } from "yaml";
|
|
21580
21792
|
|
|
21581
21793
|
// ../../packages/brain/engine/dist/esm/librarian/config.js
|
|
21582
|
-
import { parse as
|
|
21794
|
+
import { parse as parseYaml14 } from "yaml";
|
|
21583
21795
|
|
|
21584
21796
|
// src/lib/dream-discovery.ts
|
|
21585
21797
|
init_http();
|