@m8t-stack/cli 0.2.83 → 0.2.84
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 +933 -667
- package/dist/cli.js.map +1 -1
- package/package.json +2 -1
package/dist/cli.js
CHANGED
|
@@ -1467,7 +1467,7 @@ var init_enable_hosted_brain = __esm({
|
|
|
1467
1467
|
import { Builtins, Cli } from "clipanion";
|
|
1468
1468
|
|
|
1469
1469
|
// src/lib/package-version.ts
|
|
1470
|
-
var CLI_VERSION = "0.2.
|
|
1470
|
+
var CLI_VERSION = "0.2.84";
|
|
1471
1471
|
|
|
1472
1472
|
// src/lib/render-error.ts
|
|
1473
1473
|
init_errors();
|
|
@@ -3801,12 +3801,12 @@ function encodeURIPath(str4) {
|
|
|
3801
3801
|
return str4.replace(/[^A-Za-z0-9\-._~!$&'()*+,;=:@]+/g, encodeURIComponent);
|
|
3802
3802
|
}
|
|
3803
3803
|
var EMPTY = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.create(null));
|
|
3804
|
-
var createPathTagFunction = (pathEncoder = encodeURIPath) => function
|
|
3804
|
+
var createPathTagFunction = (pathEncoder = encodeURIPath) => function path47(statics, ...params) {
|
|
3805
3805
|
if (statics.length === 1)
|
|
3806
3806
|
return statics[0];
|
|
3807
3807
|
let postPath = false;
|
|
3808
3808
|
const invalidSegments = [];
|
|
3809
|
-
const
|
|
3809
|
+
const path48 = statics.reduce((previousValue, currentValue, index) => {
|
|
3810
3810
|
if (/[?#]/.test(currentValue)) {
|
|
3811
3811
|
postPath = true;
|
|
3812
3812
|
}
|
|
@@ -3823,7 +3823,7 @@ var createPathTagFunction = (pathEncoder = encodeURIPath) => function path48(sta
|
|
|
3823
3823
|
}
|
|
3824
3824
|
return previousValue + currentValue + (index === params.length ? "" : encoded);
|
|
3825
3825
|
}, "");
|
|
3826
|
-
const pathOnly =
|
|
3826
|
+
const pathOnly = path48.split(/[?#]/, 1)[0];
|
|
3827
3827
|
const invalidSegmentPattern = /(?<=^|\/)(?:\.|%2e){1,2}(?=\/|$)/gi;
|
|
3828
3828
|
let match;
|
|
3829
3829
|
while ((match = invalidSegmentPattern.exec(pathOnly)) !== null) {
|
|
@@ -3844,10 +3844,10 @@ var createPathTagFunction = (pathEncoder = encodeURIPath) => function path48(sta
|
|
|
3844
3844
|
}, "");
|
|
3845
3845
|
throw new OpenAIError(`Path parameters result in path with invalid segments:
|
|
3846
3846
|
${invalidSegments.map((e) => e.error).join("\n")}
|
|
3847
|
-
${
|
|
3847
|
+
${path48}
|
|
3848
3848
|
${underline}`);
|
|
3849
3849
|
}
|
|
3850
|
-
return
|
|
3850
|
+
return path48;
|
|
3851
3851
|
};
|
|
3852
3852
|
var path = /* @__PURE__ */ createPathTagFunction(encodeURIPath);
|
|
3853
3853
|
|
|
@@ -12298,9 +12298,9 @@ var OpenAI = class {
|
|
|
12298
12298
|
this.apiKey = token;
|
|
12299
12299
|
return true;
|
|
12300
12300
|
}
|
|
12301
|
-
buildURL(
|
|
12301
|
+
buildURL(path47, query, defaultBaseURL) {
|
|
12302
12302
|
const baseURL = !__classPrivateFieldGet(this, _OpenAI_instances, "m", _OpenAI_baseURLOverridden).call(this) && defaultBaseURL || this.baseURL;
|
|
12303
|
-
const url = isAbsoluteURL(
|
|
12303
|
+
const url = isAbsoluteURL(path47) ? new URL(path47) : new URL(baseURL + (baseURL.endsWith("/") && path47.startsWith("/") ? path47.slice(1) : path47));
|
|
12304
12304
|
const defaultQuery = this.defaultQuery();
|
|
12305
12305
|
const pathQuery = Object.fromEntries(url.searchParams);
|
|
12306
12306
|
if (!isEmptyObj(defaultQuery) || !isEmptyObj(pathQuery)) {
|
|
@@ -12330,24 +12330,24 @@ var OpenAI = class {
|
|
|
12330
12330
|
*/
|
|
12331
12331
|
async prepareRequest(request, { url, options }) {
|
|
12332
12332
|
}
|
|
12333
|
-
get(
|
|
12334
|
-
return this.methodRequest("get",
|
|
12333
|
+
get(path47, opts) {
|
|
12334
|
+
return this.methodRequest("get", path47, opts);
|
|
12335
12335
|
}
|
|
12336
|
-
post(
|
|
12337
|
-
return this.methodRequest("post",
|
|
12336
|
+
post(path47, opts) {
|
|
12337
|
+
return this.methodRequest("post", path47, opts);
|
|
12338
12338
|
}
|
|
12339
|
-
patch(
|
|
12340
|
-
return this.methodRequest("patch",
|
|
12339
|
+
patch(path47, opts) {
|
|
12340
|
+
return this.methodRequest("patch", path47, opts);
|
|
12341
12341
|
}
|
|
12342
|
-
put(
|
|
12343
|
-
return this.methodRequest("put",
|
|
12342
|
+
put(path47, opts) {
|
|
12343
|
+
return this.methodRequest("put", path47, opts);
|
|
12344
12344
|
}
|
|
12345
|
-
delete(
|
|
12346
|
-
return this.methodRequest("delete",
|
|
12345
|
+
delete(path47, opts) {
|
|
12346
|
+
return this.methodRequest("delete", path47, opts);
|
|
12347
12347
|
}
|
|
12348
|
-
methodRequest(method,
|
|
12348
|
+
methodRequest(method, path47, opts) {
|
|
12349
12349
|
return this.request(Promise.resolve(opts).then((opts2) => {
|
|
12350
|
-
return { method, path:
|
|
12350
|
+
return { method, path: path47, ...opts2 };
|
|
12351
12351
|
}));
|
|
12352
12352
|
}
|
|
12353
12353
|
request(options, remainingRetries = null) {
|
|
@@ -12472,8 +12472,8 @@ var OpenAI = class {
|
|
|
12472
12472
|
}));
|
|
12473
12473
|
return { response, options, controller, requestLogID, retryOfRequestLogID, startTime };
|
|
12474
12474
|
}
|
|
12475
|
-
getAPIList(
|
|
12476
|
-
return this.requestAPIList(Page2, opts && "then" in opts ? opts.then((opts2) => ({ method: "get", path:
|
|
12475
|
+
getAPIList(path47, Page2, opts) {
|
|
12476
|
+
return this.requestAPIList(Page2, opts && "then" in opts ? opts.then((opts2) => ({ method: "get", path: path47, ...opts2 })) : { method: "get", path: path47, ...opts });
|
|
12477
12477
|
}
|
|
12478
12478
|
requestAPIList(Page2, options) {
|
|
12479
12479
|
const request = this.makeRequest(options, null, void 0);
|
|
@@ -12567,8 +12567,8 @@ var OpenAI = class {
|
|
|
12567
12567
|
}
|
|
12568
12568
|
async buildRequest(inputOptions, { retryCount = 0 } = {}) {
|
|
12569
12569
|
const options = { ...inputOptions };
|
|
12570
|
-
const { method, path:
|
|
12571
|
-
const url = this.buildURL(
|
|
12570
|
+
const { method, path: path47, query, defaultBaseURL } = options;
|
|
12571
|
+
const url = this.buildURL(path47, query, defaultBaseURL);
|
|
12572
12572
|
if ("timeout" in options)
|
|
12573
12573
|
validatePositiveInteger("timeout", options.timeout);
|
|
12574
12574
|
options.timeout = options.timeout ?? this.timeout;
|
|
@@ -13633,10 +13633,10 @@ var BindListCommand = class extends M8tCommand {
|
|
|
13633
13633
|
const qs = new URLSearchParams();
|
|
13634
13634
|
if (this.channel) qs.set("channel", this.channel);
|
|
13635
13635
|
if (this.status) qs.set("status", this.status);
|
|
13636
|
-
const
|
|
13636
|
+
const path47 = qs.toString().length > 0 ? `/api/bindings?${qs.toString()}` : "/api/bindings";
|
|
13637
13637
|
const data = await apiCall(
|
|
13638
13638
|
{ gatewayUrl: ctx.gatewayUrl, gatewayClientId: ctx.gatewayClientId },
|
|
13639
|
-
{ method: "GET", path:
|
|
13639
|
+
{ method: "GET", path: path47 },
|
|
13640
13640
|
(msg) => this.context.stderr.write(msg + "\n")
|
|
13641
13641
|
);
|
|
13642
13642
|
if (mode === "json") {
|
|
@@ -14882,8 +14882,8 @@ ${r.stderr}`;
|
|
|
14882
14882
|
message: `gh api /repos/${slug} failed (exit ${r.exitCode.toString()}): ${(r.stderr || r.stdout).slice(0, 200)}`
|
|
14883
14883
|
});
|
|
14884
14884
|
},
|
|
14885
|
-
getFile: async (
|
|
14886
|
-
const r = await exec("gh", ["api", "-H", "Accept: application/vnd.github.raw+json", `/repos/${slug}/contents/${
|
|
14885
|
+
getFile: async (path47) => {
|
|
14886
|
+
const r = await exec("gh", ["api", "-H", "Accept: application/vnd.github.raw+json", `/repos/${slug}/contents/${path47}`]);
|
|
14887
14887
|
return r.exitCode === 0 ? r.stdout : null;
|
|
14888
14888
|
},
|
|
14889
14889
|
isEmpty: async () => {
|
|
@@ -16434,7 +16434,7 @@ function appRepoProbe(args) {
|
|
|
16434
16434
|
const res = await doFetch(`${GH_API}/repos/${args.repo}`, { headers: H, signal: AbortSignal.timeout(GH_REQUEST_TIMEOUT_MS) });
|
|
16435
16435
|
return res.status;
|
|
16436
16436
|
},
|
|
16437
|
-
getFile: (
|
|
16437
|
+
getFile: (path47) => readRepoFileViaApp({ token: args.token, repo: args.repo, path: path47, fetchImpl: args.fetchImpl }),
|
|
16438
16438
|
isEmpty: async () => {
|
|
16439
16439
|
const res = await doFetch(`${GH_API}/repos/${args.repo}/contents`, { headers: H, signal: AbortSignal.timeout(GH_REQUEST_TIMEOUT_MS) });
|
|
16440
16440
|
return res.status === 404;
|
|
@@ -20001,6 +20001,7 @@ import { DefaultAzureCredential as DefaultAzureCredential16 } from "@azure/ident
|
|
|
20001
20001
|
|
|
20002
20002
|
// src/lib/platform-update.ts
|
|
20003
20003
|
init_errors();
|
|
20004
|
+
import semver from "semver";
|
|
20004
20005
|
var DEFAULT_IMAGE_REPO = "ghcr.io/m8t-labs/m8t";
|
|
20005
20006
|
function parseImageRef2(ref) {
|
|
20006
20007
|
let rest = ref;
|
|
@@ -20055,10 +20056,22 @@ function compareSemver(a, b) {
|
|
|
20055
20056
|
}
|
|
20056
20057
|
return 0;
|
|
20057
20058
|
}
|
|
20059
|
+
function comparePlatformVersion(a, b) {
|
|
20060
|
+
const bare = (v) => v.trim().replace(/^platform-/, "").replace(/^v/, "");
|
|
20061
|
+
const va = semver.valid(bare(a));
|
|
20062
|
+
const vb = semver.valid(bare(b));
|
|
20063
|
+
if (!va || !vb) {
|
|
20064
|
+
throw new LocalCliError({
|
|
20065
|
+
code: "PLATFORM_BAD_SEMVER",
|
|
20066
|
+
message: `comparePlatformVersion needs platform versions, got '${a}' / '${b}'.`
|
|
20067
|
+
});
|
|
20068
|
+
}
|
|
20069
|
+
return semver.compare(va, vb);
|
|
20070
|
+
}
|
|
20058
20071
|
function pickNewestSemver(tags) {
|
|
20059
|
-
const
|
|
20060
|
-
if (
|
|
20061
|
-
return
|
|
20072
|
+
const semver2 = tags.filter(isSemverTag);
|
|
20073
|
+
if (semver2.length === 0) return null;
|
|
20074
|
+
return semver2.reduce((best, t) => compareSemver(t, best) > 0 ? t : best);
|
|
20062
20075
|
}
|
|
20063
20076
|
function parseContainerAppResourceId(id) {
|
|
20064
20077
|
const m = /\/subscriptions\/([^/]+)\/resourceGroups\/([^/]+)\/providers\/Microsoft\.App\/containerApps\/([^/]+)/i.exec(
|
|
@@ -20104,8 +20117,8 @@ async function fetchPublicTags(repo, fetchImpl = fetch) {
|
|
|
20104
20117
|
hint: "Pass a ghcr.io/<owner>/<name> repo, or use the BYOC private-ACR deploy flow."
|
|
20105
20118
|
});
|
|
20106
20119
|
}
|
|
20107
|
-
const
|
|
20108
|
-
const tokenRes = await fetchImpl(`https://ghcr.io/token?scope=repository:${
|
|
20120
|
+
const path47 = repo.replace(/^ghcr\.io\//, "");
|
|
20121
|
+
const tokenRes = await fetchImpl(`https://ghcr.io/token?scope=repository:${path47}:pull`);
|
|
20109
20122
|
if (!tokenRes.ok) {
|
|
20110
20123
|
throw new LocalCliError({
|
|
20111
20124
|
code: "PLATFORM_GHCR_TOKEN_FAILED",
|
|
@@ -20121,7 +20134,7 @@ async function fetchPublicTags(repo, fetchImpl = fetch) {
|
|
|
20121
20134
|
hint: "Make the package public (deploy/ghcr-package-visibility.md), then retry."
|
|
20122
20135
|
});
|
|
20123
20136
|
}
|
|
20124
|
-
const tagsRes = await fetchImpl(`https://ghcr.io/v2/${
|
|
20137
|
+
const tagsRes = await fetchImpl(`https://ghcr.io/v2/${path47}/tags/list`, {
|
|
20125
20138
|
headers: { Authorization: `Bearer ${token}` }
|
|
20126
20139
|
});
|
|
20127
20140
|
if (!tagsRes.ok) {
|
|
@@ -20298,6 +20311,8 @@ function entityToStamp(e) {
|
|
|
20298
20311
|
var RELEASES_REPO = "m8t-labs/m8t-releases";
|
|
20299
20312
|
var RELEASES_BASE = `https://github.com/${RELEASES_REPO}/releases`;
|
|
20300
20313
|
var CHANNEL_LATEST_URL = `${RELEASES_BASE}/latest/download/manifest.json`;
|
|
20314
|
+
var CANARY_POINTER_TAG = "canary";
|
|
20315
|
+
var CHANNEL_CANARY_URL = `${RELEASES_BASE}/download/${CANARY_POINTER_TAG}/manifest.json`;
|
|
20301
20316
|
function platformTag(version) {
|
|
20302
20317
|
const bare = version.trim().replace(/^platform-/, "").replace(/^v/, "");
|
|
20303
20318
|
return `platform-v${bare}`;
|
|
@@ -20309,13 +20324,46 @@ function releaseAssetUrl(tag, asset) {
|
|
|
20309
20324
|
return `${RELEASES_BASE}/download/${tag}/${asset}`;
|
|
20310
20325
|
}
|
|
20311
20326
|
|
|
20327
|
+
// ../../packages/platform-release/dist/esm/canary-version.js
|
|
20328
|
+
var CANARY_IDENTIFIER = "canary";
|
|
20329
|
+
var STABLE_CORE = String.raw`\d+\.\d+\.\d+`;
|
|
20330
|
+
var CANARY_SUFFIX = String.raw`-${CANARY_IDENTIFIER}\.(?:0|[1-9]\d*)`;
|
|
20331
|
+
var CANARY_VERSION_PATTERN = `^${STABLE_CORE}${CANARY_SUFFIX}$`;
|
|
20332
|
+
var PLATFORM_VERSION_PATTERN = `^${STABLE_CORE}(?:${CANARY_SUFFIX})?$`;
|
|
20333
|
+
var PLATFORM_TAG_PATTERN = `^platform-v${STABLE_CORE}(?:${CANARY_SUFFIX})?$`;
|
|
20334
|
+
var CANARY_VERSION_RE = new RegExp(CANARY_VERSION_PATTERN);
|
|
20335
|
+
var STABLE_CORE_RE = new RegExp(`^${STABLE_CORE}$`);
|
|
20336
|
+
|
|
20312
20337
|
// ../../packages/platform-release/dist/esm/apply-request.js
|
|
20313
20338
|
var APPLY_REQUEST_PK = "system";
|
|
20314
20339
|
var APPLY_REQUEST_RK = "apply-request";
|
|
20315
20340
|
var IN_FLIGHT = ["claimed", "applying"];
|
|
20341
|
+
var LEASE_MS = 30 * 60 * 1e3;
|
|
20342
|
+
var MAX_LEASE_TAKEOVERS = 2;
|
|
20343
|
+
var MAX_HEALTHY_IN_FLIGHT_MS = LEASE_MS * (MAX_LEASE_TAKEOVERS + 1);
|
|
20316
20344
|
function isInFlight(status) {
|
|
20317
20345
|
return IN_FLIGHT.includes(status);
|
|
20318
20346
|
}
|
|
20347
|
+
var BLOCKS_NEW_INTENT = ["pending", "claimed", "applying", "awaiting-engine-update"];
|
|
20348
|
+
function blocksNewIntent(status) {
|
|
20349
|
+
return BLOCKS_NEW_INTENT.includes(status);
|
|
20350
|
+
}
|
|
20351
|
+
function newIntent(target, provenance, nowIso) {
|
|
20352
|
+
return {
|
|
20353
|
+
schemaVersion: 1,
|
|
20354
|
+
target,
|
|
20355
|
+
provenance,
|
|
20356
|
+
status: "pending",
|
|
20357
|
+
phase: null,
|
|
20358
|
+
claimedBy: null,
|
|
20359
|
+
leaseUntil: null,
|
|
20360
|
+
attempt: 0,
|
|
20361
|
+
breaker: "none",
|
|
20362
|
+
result: null,
|
|
20363
|
+
createdAt: nowIso,
|
|
20364
|
+
updatedAt: nowIso
|
|
20365
|
+
};
|
|
20366
|
+
}
|
|
20319
20367
|
function applyRequestToEntity(r) {
|
|
20320
20368
|
return { partitionKey: APPLY_REQUEST_PK, rowKey: APPLY_REQUEST_RK, value: JSON.stringify(r), updatedAt: r.updatedAt };
|
|
20321
20369
|
}
|
|
@@ -20354,11 +20402,10 @@ function manifestSourceForVersionTag(channelUrl, version) {
|
|
|
20354
20402
|
const tag = platformTag(version);
|
|
20355
20403
|
const custom = channelUrl.trim();
|
|
20356
20404
|
if (!custom || custom === CHANNEL_LATEST_URL) return { channel: true, version: tag };
|
|
20357
|
-
|
|
20358
|
-
|
|
20359
|
-
}
|
|
20360
|
-
return { url: custom };
|
|
20405
|
+
const swapped = custom.replace(POINTER_SEGMENT, `/releases/download/${tag}/`);
|
|
20406
|
+
return { url: swapped };
|
|
20361
20407
|
}
|
|
20408
|
+
var POINTER_SEGMENT = /\/releases\/(?:latest\/download|download\/[^/]+)\//;
|
|
20362
20409
|
async function fetchManifest(source, deps = {}) {
|
|
20363
20410
|
const readFile9 = deps.readFile ?? ((p) => fs23.readFileSync(p, "utf8"));
|
|
20364
20411
|
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
@@ -21630,25 +21677,25 @@ function mergeThreeWay(ours, base, theirs) {
|
|
|
21630
21677
|
fs27.rmSync(dir, { recursive: true, force: true });
|
|
21631
21678
|
}
|
|
21632
21679
|
}
|
|
21633
|
-
var skip = (
|
|
21680
|
+
var skip = (path47, skipReason) => ({ path: path47, kind: "skip", skipReason });
|
|
21634
21681
|
function classifyCandidate(c) {
|
|
21635
|
-
const { path:
|
|
21636
|
-
if (theirs === base) return { path:
|
|
21682
|
+
const { path: path47, base, ours, theirs } = c;
|
|
21683
|
+
if (theirs === base) return { path: path47, kind: "noop" };
|
|
21637
21684
|
if (base === null) {
|
|
21638
|
-
if (theirs === null) return { path:
|
|
21639
|
-
if (ours === null) return { path:
|
|
21640
|
-
if (ours === theirs) return { path:
|
|
21641
|
-
return skip(
|
|
21685
|
+
if (theirs === null) return { path: path47, kind: "noop" };
|
|
21686
|
+
if (ours === null) return { path: path47, kind: "add", content: theirs };
|
|
21687
|
+
if (ours === theirs) return { path: path47, kind: "noop" };
|
|
21688
|
+
return skip(path47, "you already have a file at this path");
|
|
21642
21689
|
}
|
|
21643
21690
|
if (ours === null) {
|
|
21644
|
-
return theirs === null ? { path:
|
|
21691
|
+
return theirs === null ? { path: path47, kind: "noop" } : skip(path47, "you removed this file; upstream changed it");
|
|
21645
21692
|
}
|
|
21646
21693
|
if (theirs === null) {
|
|
21647
|
-
return ours === base ? { path:
|
|
21694
|
+
return ours === base ? { path: path47, kind: "delete" } : skip(path47, "you edited this file; upstream removed it");
|
|
21648
21695
|
}
|
|
21649
|
-
if (ours === base) return { path:
|
|
21696
|
+
if (ours === base) return { path: path47, kind: "update", content: theirs };
|
|
21650
21697
|
const m = mergeThreeWay(ours, base, theirs);
|
|
21651
|
-
return m.ok ? { path:
|
|
21698
|
+
return m.ok ? { path: path47, kind: "update", content: m.merged } : skip(path47, "your edits conflict with the update");
|
|
21652
21699
|
}
|
|
21653
21700
|
|
|
21654
21701
|
// src/lib/seed-pr-body.ts
|
|
@@ -21835,7 +21882,7 @@ function bindRepoApi(token, repo) {
|
|
|
21835
21882
|
openPr: (head, base, title, body) => openPullRequestViaApp({ token, repo, base, head, title, body }),
|
|
21836
21883
|
updatePr: (n, title, body) => updatePullRequestViaApp({ token, repo, number: n, title, body }),
|
|
21837
21884
|
closePr: (n, comment) => closePullRequestViaApp({ token, repo, number: n, comment }),
|
|
21838
|
-
readFileAtRef: (
|
|
21885
|
+
readFileAtRef: (path47, ref) => readRepoFileViaApp({ token, repo, path: path47, ref })
|
|
21839
21886
|
};
|
|
21840
21887
|
}
|
|
21841
21888
|
async function runSeedRefresh(args) {
|
|
@@ -22337,7 +22384,6 @@ function resolveHeadlessContextFromEnv(env) {
|
|
|
22337
22384
|
|
|
22338
22385
|
// src/lib/apply-request-store.ts
|
|
22339
22386
|
import { TableClient as TableClient4 } from "@azure/data-tables";
|
|
22340
|
-
var MAX_LEASE_TAKEOVERS = 2;
|
|
22341
22387
|
async function openApplyTable(opts) {
|
|
22342
22388
|
const { tableEndpoint } = await discoverStampStorage(opts);
|
|
22343
22389
|
return new TableClient4(tableEndpoint, "Metadata", opts.credential);
|
|
@@ -22423,32 +22469,59 @@ function assertForwardTarget(manifest) {
|
|
|
22423
22469
|
}
|
|
22424
22470
|
|
|
22425
22471
|
// src/lib/platform-self-update.ts
|
|
22426
|
-
import * as fs30 from "fs";
|
|
22427
|
-
import * as path32 from "path";
|
|
22428
22472
|
function toVTag2(v) {
|
|
22429
22473
|
return v.startsWith("v") ? v : `v${v}`;
|
|
22430
22474
|
}
|
|
22431
|
-
function
|
|
22432
|
-
if (!repoRoot) return null;
|
|
22433
|
-
try {
|
|
22434
|
-
const raw = fs30.readFileSync(path32.join(repoRoot, "installer", "version.json"), "utf8");
|
|
22435
|
-
const v = JSON.parse(raw).version;
|
|
22436
|
-
return typeof v === "string" && v.length > 0 ? v : null;
|
|
22437
|
-
} catch {
|
|
22438
|
-
return null;
|
|
22439
|
-
}
|
|
22440
|
-
}
|
|
22441
|
-
function needsEngineUpdate(manifest, runningVersion, bakedRelease) {
|
|
22475
|
+
function needsEngineUpdate(manifest, runningVersion, runningImage) {
|
|
22442
22476
|
if (runningVersion === "0.0.0-dev") return false;
|
|
22443
|
-
if (
|
|
22477
|
+
if (needsEngineImageHop(manifest, runningVersion, runningImage ?? null)) return true;
|
|
22444
22478
|
const running = toVTag2(runningVersion);
|
|
22445
22479
|
const min = toVTag2(manifest.components.cli.min);
|
|
22446
22480
|
return compareSemver(running, min) < 0;
|
|
22447
22481
|
}
|
|
22482
|
+
function needsPreClaimEngineUpdate(manifest, runningVersion, runningImage) {
|
|
22483
|
+
return needsEngineImageHop(manifest, runningVersion, runningImage ?? null);
|
|
22484
|
+
}
|
|
22485
|
+
function targetEngineImage(manifest) {
|
|
22486
|
+
const inst = manifest.components.installer;
|
|
22487
|
+
return `${inst.ref}:${inst.tag}`;
|
|
22488
|
+
}
|
|
22489
|
+
function ownJobName(env = process.env) {
|
|
22490
|
+
const name = (env.UPDATER_JOB_NAME ?? "").trim();
|
|
22491
|
+
return name.length > 0 ? name : null;
|
|
22492
|
+
}
|
|
22493
|
+
async function readOwnJobImage(opts) {
|
|
22494
|
+
const job = opts.jobName ?? ownJobName();
|
|
22495
|
+
if (!job) return null;
|
|
22496
|
+
const image = (await runAz([
|
|
22497
|
+
"containerapp",
|
|
22498
|
+
"job",
|
|
22499
|
+
"show",
|
|
22500
|
+
"-n",
|
|
22501
|
+
job,
|
|
22502
|
+
"-g",
|
|
22503
|
+
opts.resourceGroup,
|
|
22504
|
+
"--subscription",
|
|
22505
|
+
opts.subscriptionId,
|
|
22506
|
+
"--query",
|
|
22507
|
+
"properties.template.containers[0].image",
|
|
22508
|
+
"-o",
|
|
22509
|
+
"tsv",
|
|
22510
|
+
"--only-show-errors"
|
|
22511
|
+
])).trim();
|
|
22512
|
+
if (!image || image === "None") {
|
|
22513
|
+
throw new Error(`could not read the updater job's current image (job ${job}) \u2014 refusing to decide a self-update blind`);
|
|
22514
|
+
}
|
|
22515
|
+
return image;
|
|
22516
|
+
}
|
|
22517
|
+
function needsEngineImageHop(manifest, runningVersion, runningImage) {
|
|
22518
|
+
if (runningVersion === "0.0.0-dev") return false;
|
|
22519
|
+
if (runningImage === null || runningImage.trim().length === 0) return false;
|
|
22520
|
+
return runningImage.trim() !== targetEngineImage(manifest);
|
|
22521
|
+
}
|
|
22448
22522
|
async function updateOwnJobImage(opts) {
|
|
22449
|
-
const
|
|
22450
|
-
const
|
|
22451
|
-
const job = opts.jobName ?? process.env.UPDATER_JOB_NAME;
|
|
22523
|
+
const image = targetEngineImage(opts.manifest);
|
|
22524
|
+
const job = opts.jobName ?? ownJobName();
|
|
22452
22525
|
if (!job) throw new Error("UPDATER_JOB_NAME unset \u2014 cannot self-update the updater job image");
|
|
22453
22526
|
await runAz([
|
|
22454
22527
|
"containerapp",
|
|
@@ -22618,13 +22691,9 @@ async function readBreaker(client) {
|
|
|
22618
22691
|
|
|
22619
22692
|
// src/commands/platform/converge.ts
|
|
22620
22693
|
init_errors();
|
|
22621
|
-
function canonicalVersion(v) {
|
|
22622
|
-
const bare = v.replace(/^platform-/, "");
|
|
22623
|
-
return bare.startsWith("v") ? bare : `v${bare}`;
|
|
22624
|
-
}
|
|
22625
22694
|
function isForwardTarget(target, installed) {
|
|
22626
22695
|
if (!installed) return true;
|
|
22627
|
-
return
|
|
22696
|
+
return comparePlatformVersion(target, installed) >= 0;
|
|
22628
22697
|
}
|
|
22629
22698
|
async function failIfStillInFlight(client, now, error) {
|
|
22630
22699
|
const cur = await readApplyRequest(client);
|
|
@@ -22655,6 +22724,28 @@ var PlatformConvergeCommand = class extends M8tCommand {
|
|
|
22655
22724
|
subscriptionId: ctx.subscriptionId,
|
|
22656
22725
|
resourceGroup: ctx.resourceGroup
|
|
22657
22726
|
});
|
|
22727
|
+
let runningImage = null;
|
|
22728
|
+
const outstanding = await readApplyRequest(client);
|
|
22729
|
+
if (outstanding && blocksNewIntent(outstanding.status)) {
|
|
22730
|
+
runningImage = await readOwnJobImage({
|
|
22731
|
+
subscriptionId: ctx.subscriptionId,
|
|
22732
|
+
resourceGroup: ctx.resourceGroup
|
|
22733
|
+
});
|
|
22734
|
+
if (runningImage) {
|
|
22735
|
+
const preManifest = await fetchManifest(targetManifestSource(ctx, outstanding.target));
|
|
22736
|
+
if (needsPreClaimEngineUpdate(preManifest, CLI_VERSION, runningImage)) {
|
|
22737
|
+
log(
|
|
22738
|
+
`self-updating BEFORE claiming (running ${runningImage} \u2192 target ${targetEngineImage(preManifest)}); the next tick claims with the new engine.`
|
|
22739
|
+
);
|
|
22740
|
+
await updateOwnJobImage({
|
|
22741
|
+
subscriptionId: ctx.subscriptionId,
|
|
22742
|
+
resourceGroup: ctx.resourceGroup,
|
|
22743
|
+
manifest: preManifest
|
|
22744
|
+
});
|
|
22745
|
+
return 0;
|
|
22746
|
+
}
|
|
22747
|
+
}
|
|
22748
|
+
}
|
|
22658
22749
|
const claimed = await claimApplyRequest(client, executionId, now(), 30 * 60 * 1e3);
|
|
22659
22750
|
if (!claimed) {
|
|
22660
22751
|
log("no pending apply-request \u2014 nothing to converge.");
|
|
@@ -22689,10 +22780,9 @@ var PlatformConvergeCommand = class extends M8tCommand {
|
|
|
22689
22780
|
return 1;
|
|
22690
22781
|
}
|
|
22691
22782
|
const repoRoot = tryResolveRepoRoot();
|
|
22692
|
-
|
|
22693
|
-
if (needsEngineUpdate(manifest, CLI_VERSION, bakedRelease)) {
|
|
22783
|
+
if (needsEngineUpdate(manifest, CLI_VERSION, runningImage)) {
|
|
22694
22784
|
log(
|
|
22695
|
-
`self-updating the updater image (
|
|
22785
|
+
`self-updating the updater image (running ${runningImage ?? "(not the job)"} / engine ${CLI_VERSION} \u2192 target ${targetEngineImage(manifest)}, cli.min ${manifest.components.cli.min}).`
|
|
22696
22786
|
);
|
|
22697
22787
|
await updateOwnJobImage({
|
|
22698
22788
|
subscriptionId: ctx.subscriptionId,
|
|
@@ -22854,12 +22944,270 @@ function targetManifestSource(ctx, target) {
|
|
|
22854
22944
|
return manifestSourceForVersionTag(ctx.channelUrl, target);
|
|
22855
22945
|
}
|
|
22856
22946
|
|
|
22857
|
-
// src/commands/platform/
|
|
22858
|
-
import { readFileSync as readFileSync21 } from "fs";
|
|
22947
|
+
// src/commands/platform/clear-intent.ts
|
|
22859
22948
|
import { Command as Command37, Option as Option34 } from "clipanion";
|
|
22860
22949
|
import { DefaultAzureCredential as DefaultAzureCredential18, ManagedIdentityCredential as ManagedIdentityCredential2 } from "@azure/identity";
|
|
22861
22950
|
init_errors();
|
|
22862
22951
|
|
|
22952
|
+
// src/lib/apply-intent-clear.ts
|
|
22953
|
+
var CLEARED_BY_OPERATOR = "cleared by an operator via `m8t platform clear-intent`";
|
|
22954
|
+
function decideClear(row, nowIso, force) {
|
|
22955
|
+
if (!row) return { action: "none", reason: "there is no apply-request to clear." };
|
|
22956
|
+
if (!isInFlight(row.status) && row.status !== "pending" && row.status !== "awaiting-engine-update") {
|
|
22957
|
+
return { action: "none", reason: `the apply-request is already terminal (${row.status}) \u2014 a new intent can be written.` };
|
|
22958
|
+
}
|
|
22959
|
+
const leaseLive = isInFlight(row.status) && row.leaseUntil !== null && Date.parse(row.leaseUntil) > Date.parse(nowIso);
|
|
22960
|
+
if (leaseLive && !force) {
|
|
22961
|
+
return {
|
|
22962
|
+
action: "refuse",
|
|
22963
|
+
reason: `the apply-request is ${row.status} and its lease is still live until ${row.leaseUntil ?? "(unknown)"} \u2014 a converge may be running right now. Clearing it could start a second apply alongside the first. Wait for the lease to expire, or pass --force if you know the engine is gone.`
|
|
22964
|
+
};
|
|
22965
|
+
}
|
|
22966
|
+
const held = leaseLive ? " (lease still live \u2014 forced)" : "";
|
|
22967
|
+
return { action: "clear", reason: `clearing a ${row.status} apply-request for target ${row.target}${held}.` };
|
|
22968
|
+
}
|
|
22969
|
+
function clearedRow(row, nowIso) {
|
|
22970
|
+
return {
|
|
22971
|
+
...row,
|
|
22972
|
+
status: "failed",
|
|
22973
|
+
result: {
|
|
22974
|
+
appliedVersion: row.result?.appliedVersion ?? null,
|
|
22975
|
+
error: `${CLEARED_BY_OPERATOR} (was ${row.status}${row.phase ? `, phase "${row.phase}"` : ""})`
|
|
22976
|
+
},
|
|
22977
|
+
updatedAt: nowIso
|
|
22978
|
+
};
|
|
22979
|
+
}
|
|
22980
|
+
|
|
22981
|
+
// src/commands/platform/clear-intent.ts
|
|
22982
|
+
var PlatformClearIntentCommand = class extends M8tCommand {
|
|
22983
|
+
static paths = [["platform", "clear-intent"]];
|
|
22984
|
+
static usage = Command37.Usage({
|
|
22985
|
+
description: "Clear a stuck platform update request so a new one can be made.",
|
|
22986
|
+
details: "An update request that never settles blocks every later request, and the routines that would normally rescue it all run inside the updater itself \u2014 which is no help when the updater is what is stuck. This clears it from outside. Refuses while an update may still be running, unless --force.",
|
|
22987
|
+
examples: [
|
|
22988
|
+
["Clear a stuck request", "m8t platform clear-intent --resource-group rg-m8t --subscription <id>"],
|
|
22989
|
+
["Clear one whose lease is still live", "m8t platform clear-intent --resource-group rg-m8t --subscription <id> --force"]
|
|
22990
|
+
]
|
|
22991
|
+
});
|
|
22992
|
+
subscription = Option34.String("--subscription");
|
|
22993
|
+
resourceGroup = Option34.String("--resource-group");
|
|
22994
|
+
miClientId = Option34.String("--mi-client-id", { description: "Authenticate as this user-assigned managed identity instead of the ambient credential." });
|
|
22995
|
+
force = Option34.Boolean("--force", false, {
|
|
22996
|
+
description: "Clear even while the lease is live. Only when you know the engine that held it is gone."
|
|
22997
|
+
});
|
|
22998
|
+
output = Option34.String("--output");
|
|
22999
|
+
async executeCommand() {
|
|
23000
|
+
const mode = resolveOutputMode(this.output, this.context.stdout);
|
|
23001
|
+
const need = (v, flag) => {
|
|
23002
|
+
if (typeof v !== "string" || v.trim().length === 0) {
|
|
23003
|
+
throw new LocalCliError({ code: "PLATFORM_CLEAR_INTENT_ARG_MISSING", message: `${flag} is required.` });
|
|
23004
|
+
}
|
|
23005
|
+
return v.trim();
|
|
23006
|
+
};
|
|
23007
|
+
const credential2 = typeof this.miClientId === "string" && this.miClientId.trim().length > 0 ? new ManagedIdentityCredential2({ clientId: this.miClientId.trim() }) : new DefaultAzureCredential18();
|
|
23008
|
+
const client = await openApplyTable({
|
|
23009
|
+
credential: credential2,
|
|
23010
|
+
subscriptionId: need(this.subscription, "--subscription"),
|
|
23011
|
+
resourceGroup: need(this.resourceGroup, "--resource-group")
|
|
23012
|
+
});
|
|
23013
|
+
const row = await readApplyRequest(client);
|
|
23014
|
+
const decision = decideClear(row, (/* @__PURE__ */ new Date()).toISOString(), this.force);
|
|
23015
|
+
if (decision.action === "refuse") {
|
|
23016
|
+
throw new LocalCliError({
|
|
23017
|
+
code: "PLATFORM_CLEAR_INTENT_REFUSED",
|
|
23018
|
+
message: decision.reason,
|
|
23019
|
+
hint: "Re-run with --force once you have confirmed no converge is running."
|
|
23020
|
+
});
|
|
23021
|
+
}
|
|
23022
|
+
if (decision.action === "none" || !row) {
|
|
23023
|
+
this.context.stdout.write(
|
|
23024
|
+
mode === "json" ? renderJson({ cleared: false, reason: decision.reason }) + "\n" : `${decision.reason}
|
|
23025
|
+
`
|
|
23026
|
+
);
|
|
23027
|
+
return 0;
|
|
23028
|
+
}
|
|
23029
|
+
const next = clearedRow(row, (/* @__PURE__ */ new Date()).toISOString());
|
|
23030
|
+
await client.updateEntity(applyRequestToEntity(next), "Merge");
|
|
23031
|
+
const result2 = { cleared: true, previousStatus: row.status, target: row.target, reason: decision.reason };
|
|
23032
|
+
this.context.stdout.write(
|
|
23033
|
+
mode === "json" ? renderJson(result2) + "\n" : `cleared: ${row.status} \u2192 failed (target ${row.target}). A new update can now be requested.
|
|
23034
|
+
`
|
|
23035
|
+
);
|
|
23036
|
+
return 0;
|
|
23037
|
+
}
|
|
23038
|
+
};
|
|
23039
|
+
|
|
23040
|
+
// src/commands/platform/request-update.ts
|
|
23041
|
+
import { Command as Command38, Option as Option35 } from "clipanion";
|
|
23042
|
+
import { DefaultAzureCredential as DefaultAzureCredential19, ManagedIdentityCredential as ManagedIdentityCredential3 } from "@azure/identity";
|
|
23043
|
+
init_errors();
|
|
23044
|
+
|
|
23045
|
+
// src/lib/request-update-follow.ts
|
|
23046
|
+
var TERMINAL = {
|
|
23047
|
+
success: true,
|
|
23048
|
+
failed: false,
|
|
23049
|
+
"rolled-back": false,
|
|
23050
|
+
held: false
|
|
23051
|
+
};
|
|
23052
|
+
function isTerminal(status) {
|
|
23053
|
+
return status in TERMINAL;
|
|
23054
|
+
}
|
|
23055
|
+
function classifyPolledRow(row, target) {
|
|
23056
|
+
if (!row) return null;
|
|
23057
|
+
if (row.target !== target) return { kind: "not-ours", otherTarget: row.target };
|
|
23058
|
+
if (isTerminal(row.status)) return { kind: "settled", row };
|
|
23059
|
+
return { kind: "in-progress", where: positionLabel(row.status, row.phase) };
|
|
23060
|
+
}
|
|
23061
|
+
function positionLabel(status, phase) {
|
|
23062
|
+
return phase ? `${status} (${phase})` : status;
|
|
23063
|
+
}
|
|
23064
|
+
function outcomeExitCode(settled) {
|
|
23065
|
+
if (!settled) return 1;
|
|
23066
|
+
return TERMINAL[settled.status] ? 0 : 1;
|
|
23067
|
+
}
|
|
23068
|
+
function outcomeStatus(settled) {
|
|
23069
|
+
return settled?.status ?? "timed-out";
|
|
23070
|
+
}
|
|
23071
|
+
|
|
23072
|
+
// src/commands/platform/request-update.ts
|
|
23073
|
+
var PlatformRequestUpdateCommand = class extends M8tCommand {
|
|
23074
|
+
static paths = [["platform", "request-update"]];
|
|
23075
|
+
static usage = Command38.Usage({
|
|
23076
|
+
description: "Ask this installation's updater to converge to a version, exactly as the in-app button does.",
|
|
23077
|
+
details: "Writes the update request the updater job claims on its next tick. This is the ONLY privilege the requester holds \u2014 it does not deploy anything itself; the install's own updater fetches the release, applies it, health-gates it and rolls back on failure. With --wait, follows the request to a terminal state and exits non-zero if it did not succeed.",
|
|
23078
|
+
examples: [
|
|
23079
|
+
["Request an update", "m8t platform request-update --version 0.7.2 --resource-group rg-m8t --subscription <id>"],
|
|
23080
|
+
["Request it and wait", "m8t platform request-update --version 0.7.2 --wait --resource-group rg-m8t --subscription <id>"]
|
|
23081
|
+
]
|
|
23082
|
+
});
|
|
23083
|
+
version = Option35.String("--version", { description: "The platform version to converge to." });
|
|
23084
|
+
subscription = Option35.String("--subscription");
|
|
23085
|
+
resourceGroup = Option35.String("--resource-group");
|
|
23086
|
+
source = Option35.String("--source", "cd", { description: "Who is asking: cd | button | policy." });
|
|
23087
|
+
identity = Option35.String("--identity", "", { description: "Recorded on the request, for the audit trail." });
|
|
23088
|
+
miClientId = Option35.String("--mi-client-id");
|
|
23089
|
+
wait = Option35.Boolean("--wait", false, { description: "Follow the request until it settles." });
|
|
23090
|
+
/**
|
|
23091
|
+
* Follow an EXISTING request without writing a new one.
|
|
23092
|
+
*
|
|
23093
|
+
* Lets a caller write the request in one step and wait in another, which is
|
|
23094
|
+
* what makes the ordering provable: the row is a fact before anything is
|
|
23095
|
+
* started against it, instead of a background write racing a sleep.
|
|
23096
|
+
*/
|
|
23097
|
+
waitOnly = Option35.Boolean("--wait-only", false, { description: "Follow the current request without creating one." });
|
|
23098
|
+
timeoutMinutes = Option35.String("--timeout-minutes", "45");
|
|
23099
|
+
pollSeconds = Option35.String("--poll-seconds", "20");
|
|
23100
|
+
output = Option35.String("--output");
|
|
23101
|
+
async executeCommand() {
|
|
23102
|
+
const mode = resolveOutputMode(this.output, this.context.stdout);
|
|
23103
|
+
const need = (v, flag) => {
|
|
23104
|
+
if (typeof v !== "string" || v.trim().length === 0) {
|
|
23105
|
+
throw new LocalCliError({ code: "PLATFORM_REQUEST_UPDATE_ARG_MISSING", message: `${flag} is required.` });
|
|
23106
|
+
}
|
|
23107
|
+
return v.trim();
|
|
23108
|
+
};
|
|
23109
|
+
const target = need(this.version, "--version");
|
|
23110
|
+
const SOURCES2 = ["cd", "button", "policy"];
|
|
23111
|
+
if (!SOURCES2.includes(this.source)) {
|
|
23112
|
+
throw new LocalCliError({ code: "PLATFORM_REQUEST_UPDATE_BAD_SOURCE", message: `--source must be cd, button or policy; got '${this.source}'.` });
|
|
23113
|
+
}
|
|
23114
|
+
const source = this.source;
|
|
23115
|
+
const credential2 = typeof this.miClientId === "string" && this.miClientId.trim().length > 0 ? new ManagedIdentityCredential3({ clientId: this.miClientId.trim() }) : new DefaultAzureCredential19();
|
|
23116
|
+
const client = await openApplyTable({
|
|
23117
|
+
credential: credential2,
|
|
23118
|
+
subscriptionId: need(this.subscription, "--subscription"),
|
|
23119
|
+
resourceGroup: need(this.resourceGroup, "--resource-group")
|
|
23120
|
+
});
|
|
23121
|
+
const log = (m) => {
|
|
23122
|
+
this.context.stderr.write(`${m}
|
|
23123
|
+
`);
|
|
23124
|
+
};
|
|
23125
|
+
if (!this.waitOnly) {
|
|
23126
|
+
const existing = await readApplyRequest(client);
|
|
23127
|
+
if (existing && blocksNewIntent(existing.status)) {
|
|
23128
|
+
throw new LocalCliError({
|
|
23129
|
+
code: "PLATFORM_REQUEST_UPDATE_IN_PROGRESS",
|
|
23130
|
+
message: `an update request for ${existing.target} is already ${existing.status}.`,
|
|
23131
|
+
hint: "Wait for it to settle, or clear it with `m8t platform clear-intent` if nothing is advancing it."
|
|
23132
|
+
});
|
|
23133
|
+
}
|
|
23134
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
23135
|
+
const intent = newIntent(target, { source, identity: this.identity || source, at: now }, now);
|
|
23136
|
+
await client.upsertEntity(applyRequestToEntity(intent), "Replace");
|
|
23137
|
+
log(`requested update to ${target} (source ${source}).`);
|
|
23138
|
+
} else {
|
|
23139
|
+
log(`following the existing request for ${target}.`);
|
|
23140
|
+
}
|
|
23141
|
+
if (!this.wait && !this.waitOnly) {
|
|
23142
|
+
this.context.stdout.write(
|
|
23143
|
+
mode === "json" ? renderJson({ requested: true, target, waited: false }) + "\n" : `requested update to ${target}.
|
|
23144
|
+
`
|
|
23145
|
+
);
|
|
23146
|
+
return 0;
|
|
23147
|
+
}
|
|
23148
|
+
const settled = await this.follow(client, target, log);
|
|
23149
|
+
const result2 = {
|
|
23150
|
+
requested: true,
|
|
23151
|
+
target,
|
|
23152
|
+
waited: true,
|
|
23153
|
+
status: outcomeStatus(settled),
|
|
23154
|
+
error: settled?.result?.error ?? null
|
|
23155
|
+
};
|
|
23156
|
+
this.context.stdout.write(
|
|
23157
|
+
mode === "json" ? renderJson(result2) + "\n" : `${target}: ${result2.status}${result2.error ? ` \u2014 ${result2.error}` : ""}
|
|
23158
|
+
`
|
|
23159
|
+
);
|
|
23160
|
+
return outcomeExitCode(settled);
|
|
23161
|
+
}
|
|
23162
|
+
/**
|
|
23163
|
+
* Follow the request until it settles.
|
|
23164
|
+
*
|
|
23165
|
+
* `awaiting-engine-update` is explicitly NOT a failure and not a stall: the
|
|
23166
|
+
* updater parks a request there while it replaces its own image, so a converge
|
|
23167
|
+
* legitimately spans two ticks. Treating that as stuck would fail a build for
|
|
23168
|
+
* doing exactly what it is supposed to do.
|
|
23169
|
+
*/
|
|
23170
|
+
async follow(client, target, log) {
|
|
23171
|
+
const timeoutMs = Number(this.timeoutMinutes) * 60 * 1e3;
|
|
23172
|
+
const pollMs = Number(this.pollSeconds) * 1e3;
|
|
23173
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
|
|
23174
|
+
throw new LocalCliError({ code: "PLATFORM_REQUEST_UPDATE_BAD_TIMEOUT", message: `--timeout-minutes must be a positive number, got '${this.timeoutMinutes}'.` });
|
|
23175
|
+
}
|
|
23176
|
+
const deadline = Date.now() + timeoutMs;
|
|
23177
|
+
let lastReported = "";
|
|
23178
|
+
let consecutiveAbsent = 0;
|
|
23179
|
+
while (Date.now() < deadline) {
|
|
23180
|
+
await new Promise((r) => setTimeout(r, pollMs));
|
|
23181
|
+
const verdict = classifyPolledRow(await readApplyRequest(client), target);
|
|
23182
|
+
if (!verdict) {
|
|
23183
|
+
consecutiveAbsent += 1;
|
|
23184
|
+
if (consecutiveAbsent >= 3) {
|
|
23185
|
+
throw new LocalCliError({
|
|
23186
|
+
code: "PLATFORM_REQUEST_UPDATE_ROW_ABSENT",
|
|
23187
|
+
message: `no update request found for ${target} after ${String(consecutiveAbsent)} polls.`,
|
|
23188
|
+
hint: "Something removed the row after it was written. Check for a concurrent `clear-intent` or a competing requester."
|
|
23189
|
+
});
|
|
23190
|
+
}
|
|
23191
|
+
continue;
|
|
23192
|
+
}
|
|
23193
|
+
consecutiveAbsent = 0;
|
|
23194
|
+
if (verdict.kind === "settled") return verdict.row;
|
|
23195
|
+
const line2 = verdict.kind === "not-ours" ? ` (ignoring a request for ${verdict.otherTarget} \u2014 not the one we made)` : ` ${verdict.where}`;
|
|
23196
|
+
if (line2 !== lastReported) {
|
|
23197
|
+
log(line2);
|
|
23198
|
+
lastReported = line2;
|
|
23199
|
+
}
|
|
23200
|
+
}
|
|
23201
|
+
return null;
|
|
23202
|
+
}
|
|
23203
|
+
};
|
|
23204
|
+
|
|
23205
|
+
// src/commands/platform/seed-stamp.ts
|
|
23206
|
+
import { readFileSync as readFileSync20 } from "fs";
|
|
23207
|
+
import { Command as Command39, Option as Option36 } from "clipanion";
|
|
23208
|
+
import { DefaultAzureCredential as DefaultAzureCredential20, ManagedIdentityCredential as ManagedIdentityCredential4 } from "@azure/identity";
|
|
23209
|
+
init_errors();
|
|
23210
|
+
|
|
22863
23211
|
// src/lib/platform-stamp-seed.ts
|
|
22864
23212
|
var IMAGE_COMPONENTS = ["gateway", "codingAgent", "azureExecutor"];
|
|
22865
23213
|
var BARE_SEMVER = /^\d+\.\d+\.\d+$/;
|
|
@@ -22942,7 +23290,7 @@ function buildSeedStamp(d, cliVersion, nowIso) {
|
|
|
22942
23290
|
|
|
22943
23291
|
// src/commands/platform/seed-stamp.ts
|
|
22944
23292
|
async function seedStamp2(args) {
|
|
22945
|
-
const readFileImpl = args.readFileImpl ?? ((p) =>
|
|
23293
|
+
const readFileImpl = args.readFileImpl ?? ((p) => readFileSync20(p, "utf8"));
|
|
22946
23294
|
const readStampImpl = args.readStampImpl ?? readStamp;
|
|
22947
23295
|
const writeStampImpl = args.writeStampImpl ?? ((stamp2, o) => writeStamp({ ...o, stamp: stamp2 }));
|
|
22948
23296
|
const discoverImpl = args.discoverImpl ?? discoverStampStorage;
|
|
@@ -22988,15 +23336,15 @@ async function seedStamp2(args) {
|
|
|
22988
23336
|
}
|
|
22989
23337
|
var PlatformSeedStampCommand = class extends M8tCommand {
|
|
22990
23338
|
static paths = [["platform", "seed-stamp"]];
|
|
22991
|
-
static usage =
|
|
23339
|
+
static usage = Command39.Usage({
|
|
22992
23340
|
description: "INTERNAL: write the initial installed-state stamp from a build-time install descriptor.",
|
|
22993
23341
|
details: "Used by the cloud installer at the end of a from-zero install so the platform records which release it is running. Writes the stamp ONLY IF ABSENT \u2014 it never overwrites a stamp written by the converge engine, so a re-run or a container restart is harmless. Not a founder-facing command: to change what is installed, use 'm8t platform update'."
|
|
22994
23342
|
});
|
|
22995
|
-
descriptor =
|
|
22996
|
-
subscription =
|
|
22997
|
-
resourceGroup =
|
|
22998
|
-
miClientId =
|
|
22999
|
-
output =
|
|
23343
|
+
descriptor = Option36.String("--descriptor", { description: "Path to install-descriptor.json (baked into the installer image)." });
|
|
23344
|
+
subscription = Option36.String("--subscription");
|
|
23345
|
+
resourceGroup = Option36.String("--resource-group");
|
|
23346
|
+
miClientId = Option36.String("--mi-client-id", { description: "Authenticate as this user-assigned managed identity instead of the ambient credential." });
|
|
23347
|
+
output = Option36.String("--output");
|
|
23000
23348
|
async executeCommand() {
|
|
23001
23349
|
const mode = resolveOutputMode(this.output, this.context.stdout);
|
|
23002
23350
|
const need = (v, flag) => {
|
|
@@ -23009,7 +23357,7 @@ var PlatformSeedStampCommand = class extends M8tCommand {
|
|
|
23009
23357
|
this.context.stderr.write(`${m}
|
|
23010
23358
|
`);
|
|
23011
23359
|
};
|
|
23012
|
-
const credential2 = typeof this.miClientId === "string" && this.miClientId.trim().length > 0 ? new
|
|
23360
|
+
const credential2 = typeof this.miClientId === "string" && this.miClientId.trim().length > 0 ? new ManagedIdentityCredential4({ clientId: this.miClientId.trim() }) : new DefaultAzureCredential20();
|
|
23013
23361
|
const result2 = await seedStamp2({
|
|
23014
23362
|
descriptorPath: need(this.descriptor, "--descriptor"),
|
|
23015
23363
|
credential: credential2,
|
|
@@ -23027,105 +23375,9 @@ var PlatformSeedStampCommand = class extends M8tCommand {
|
|
|
23027
23375
|
}
|
|
23028
23376
|
};
|
|
23029
23377
|
|
|
23030
|
-
// src/commands/platform/stamp-build.ts
|
|
23031
|
-
import { Command as Command38, Option as Option35 } from "clipanion";
|
|
23032
|
-
import { DefaultAzureCredential as DefaultAzureCredential19, ManagedIdentityCredential as ManagedIdentityCredential3 } from "@azure/identity";
|
|
23033
|
-
init_errors();
|
|
23034
|
-
|
|
23035
|
-
// src/lib/platform-stamp-build.ts
|
|
23036
|
-
var BARE_SEMVER2 = /^\d+\.\d+\.\d+$/;
|
|
23037
|
-
function buildRunningBuildStamp(input) {
|
|
23038
|
-
if (!BARE_SEMVER2.test(input.version)) {
|
|
23039
|
-
throw new Error(
|
|
23040
|
-
`platform version must be bare X.Y.Z, got "${input.version}" \u2014 a build tag cannot be represented as a version.`
|
|
23041
|
-
);
|
|
23042
|
-
}
|
|
23043
|
-
return {
|
|
23044
|
-
schemaVersion: 1,
|
|
23045
|
-
platformVersion: platformTag(input.version),
|
|
23046
|
-
previousPlatformVersion: input.previousPlatformVersion,
|
|
23047
|
-
updatedAt: input.nowIso,
|
|
23048
|
-
lastResult: "success",
|
|
23049
|
-
cli: input.cliVersion,
|
|
23050
|
-
origin: "cd",
|
|
23051
|
-
components: {
|
|
23052
|
-
gateway: { tag: input.gatewayTag, digest: input.gatewayDigest, state: "managed" },
|
|
23053
|
-
codingAgent: { tag: "", digest: "", state: "external" },
|
|
23054
|
-
azureExecutor: { tag: "", digest: "", state: "external" },
|
|
23055
|
-
personas: input.personas,
|
|
23056
|
-
infra: { treeSha: input.infraTreeSha },
|
|
23057
|
-
...input.brainSeeds ? { brainSeeds: input.brainSeeds } : {}
|
|
23058
|
-
}
|
|
23059
|
-
};
|
|
23060
|
-
}
|
|
23061
|
-
|
|
23062
|
-
// src/commands/platform/stamp-build.ts
|
|
23063
|
-
var PlatformStampBuildCommand = class extends M8tCommand {
|
|
23064
|
-
static paths = [["platform", "stamp-build"]];
|
|
23065
|
-
static usage = Command38.Usage({
|
|
23066
|
-
description: "Record the currently running build as this install's platform version.",
|
|
23067
|
-
details: "For installs that are deployed continuously rather than from a published release. Unlike the install-time record, this overwrites on every run \u2014 the running build is the truth. Only components this writer deploys are reported; the rest are marked as managed elsewhere."
|
|
23068
|
-
});
|
|
23069
|
-
version = Option35.String("--version", { description: "The running build's own version, bare X.Y.Z." });
|
|
23070
|
-
gatewayTag = Option35.String("--gateway-tag", { description: "The tag of the gateway image this build deployed." });
|
|
23071
|
-
gatewayDigest = Option35.String("--gateway-digest", { description: "The digest of the gateway image this build deployed." });
|
|
23072
|
-
subscription = Option35.String("--subscription");
|
|
23073
|
-
resourceGroup = Option35.String("--resource-group");
|
|
23074
|
-
miClientId = Option35.String("--mi-client-id", { description: "Authenticate as this user-assigned managed identity instead of the ambient credential." });
|
|
23075
|
-
output = Option35.String("--output");
|
|
23076
|
-
async executeCommand() {
|
|
23077
|
-
const mode = resolveOutputMode(this.output, this.context.stdout);
|
|
23078
|
-
const need = (v, flag) => {
|
|
23079
|
-
if (typeof v !== "string" || v.trim().length === 0) {
|
|
23080
|
-
throw new LocalCliError({ code: "PLATFORM_STAMP_BUILD_ARG_MISSING", message: `${flag} is required.` });
|
|
23081
|
-
}
|
|
23082
|
-
return v.trim();
|
|
23083
|
-
};
|
|
23084
|
-
const onProgress = (m) => {
|
|
23085
|
-
this.context.stderr.write(`${m}
|
|
23086
|
-
`);
|
|
23087
|
-
};
|
|
23088
|
-
const credential2 = typeof this.miClientId === "string" && this.miClientId.trim().length > 0 ? new ManagedIdentityCredential3({ clientId: this.miClientId.trim() }) : new DefaultAzureCredential19();
|
|
23089
|
-
const ctx = {
|
|
23090
|
-
credential: credential2,
|
|
23091
|
-
subscriptionId: need(this.subscription, "--subscription"),
|
|
23092
|
-
resourceGroup: need(this.resourceGroup, "--resource-group")
|
|
23093
|
-
};
|
|
23094
|
-
const { accountName } = await discoverStampStorage(ctx);
|
|
23095
|
-
const existing = await readStampOutcome(ctx);
|
|
23096
|
-
if (existing.source === "unreadable") {
|
|
23097
|
-
throw new LocalCliError({
|
|
23098
|
-
code: "PLATFORM_STAMP_BUILD_PRIOR_UNREADABLE",
|
|
23099
|
-
message: "Could not read the existing platform stamp; refusing to overwrite it blind.",
|
|
23100
|
-
hint: "The running build is the truth about the CURRENT version, not about whether a previous one existed \u2014 retry once the prior record can be read."
|
|
23101
|
-
});
|
|
23102
|
-
}
|
|
23103
|
-
const previousPlatformVersion = existing.source === "explicit" ? existing.stamp.platformVersion : null;
|
|
23104
|
-
const priorComponents = existing.source === "explicit" ? existing.stamp.components : void 0;
|
|
23105
|
-
const stamp = buildRunningBuildStamp({
|
|
23106
|
-
version: need(this.version, "--version"),
|
|
23107
|
-
gatewayTag: need(this.gatewayTag, "--gateway-tag"),
|
|
23108
|
-
gatewayDigest: this.gatewayDigest ?? "",
|
|
23109
|
-
previousPlatformVersion,
|
|
23110
|
-
cliVersion: CLI_VERSION,
|
|
23111
|
-
nowIso: (/* @__PURE__ */ new Date()).toISOString(),
|
|
23112
|
-
personas: priorComponents?.personas ?? {},
|
|
23113
|
-
infraTreeSha: priorComponents?.infra.treeSha ?? "",
|
|
23114
|
-
...priorComponents?.brainSeeds ? { brainSeeds: priorComponents.brainSeeds } : {}
|
|
23115
|
-
});
|
|
23116
|
-
await writeStamp({ ...ctx, stamp, onProgress });
|
|
23117
|
-
const result2 = { platformVersion: stamp.platformVersion, previous: previousPlatformVersion, storageAccount: accountName };
|
|
23118
|
-
this.context.stdout.write(
|
|
23119
|
-
mode === "json" ? renderJson(result2) + "\n" : `platform stamp: ${result2.platformVersion} (previous ${result2.previous ?? "none"}, storage ${result2.storageAccount})
|
|
23120
|
-
`
|
|
23121
|
-
);
|
|
23122
|
-
return 0;
|
|
23123
|
-
}
|
|
23124
|
-
};
|
|
23125
|
-
|
|
23126
23378
|
// src/commands/platform/policy.ts
|
|
23127
|
-
import { Command as
|
|
23128
|
-
import { DefaultAzureCredential as
|
|
23379
|
+
import { Command as Command40, Option as Option37 } from "clipanion";
|
|
23380
|
+
import { DefaultAzureCredential as DefaultAzureCredential21, ManagedIdentityCredential as ManagedIdentityCredential5 } from "@azure/identity";
|
|
23129
23381
|
init_errors();
|
|
23130
23382
|
|
|
23131
23383
|
// src/lib/platform-policy.ts
|
|
@@ -23180,16 +23432,16 @@ async function readPolicy(opts) {
|
|
|
23180
23432
|
// src/commands/platform/policy.ts
|
|
23181
23433
|
var PlatformPolicyCommand = class extends M8tCommand {
|
|
23182
23434
|
static paths = [["platform", "policy"]];
|
|
23183
|
-
static usage =
|
|
23435
|
+
static usage = Command40.Usage({
|
|
23184
23436
|
description: "Show or set how this install handles available platform updates.",
|
|
23185
23437
|
details: "Modes: 'notify-only' shows updates but never applies them; 'auto-critical' (the default when unset) applies critical releases without asking; 'auto-all' applies every release. Use 'notify-only' where something else already controls what is deployed.",
|
|
23186
23438
|
examples: [["Show the current mode", "m8t platform policy"], ["Never apply automatically", "m8t platform policy --set notify-only"]]
|
|
23187
23439
|
});
|
|
23188
|
-
set =
|
|
23189
|
-
subscription =
|
|
23190
|
-
resourceGroup =
|
|
23191
|
-
miClientId =
|
|
23192
|
-
output =
|
|
23440
|
+
set = Option37.String("--set", { description: "notify-only | auto-critical | auto-all" });
|
|
23441
|
+
subscription = Option37.String("--subscription");
|
|
23442
|
+
resourceGroup = Option37.String("--resource-group");
|
|
23443
|
+
miClientId = Option37.String("--mi-client-id");
|
|
23444
|
+
output = Option37.String("--output");
|
|
23193
23445
|
async executeCommand() {
|
|
23194
23446
|
const mode = resolveOutputMode(this.output, this.context.stdout);
|
|
23195
23447
|
const need = (v, flag) => {
|
|
@@ -23202,7 +23454,7 @@ var PlatformPolicyCommand = class extends M8tCommand {
|
|
|
23202
23454
|
this.context.stderr.write(`${m}
|
|
23203
23455
|
`);
|
|
23204
23456
|
};
|
|
23205
|
-
const credential2 = typeof this.miClientId === "string" && this.miClientId.trim().length > 0 ? new
|
|
23457
|
+
const credential2 = typeof this.miClientId === "string" && this.miClientId.trim().length > 0 ? new ManagedIdentityCredential5({ clientId: this.miClientId.trim() }) : new DefaultAzureCredential21();
|
|
23206
23458
|
const ctx = {
|
|
23207
23459
|
credential: credential2,
|
|
23208
23460
|
subscriptionId: need(this.subscription, "--subscription"),
|
|
@@ -23235,7 +23487,7 @@ var PlatformPolicyCommand = class extends M8tCommand {
|
|
|
23235
23487
|
};
|
|
23236
23488
|
|
|
23237
23489
|
// src/commands/platform/enable-cost-report.ts
|
|
23238
|
-
import { Command as
|
|
23490
|
+
import { Command as Command41, Option as Option38 } from "clipanion";
|
|
23239
23491
|
|
|
23240
23492
|
// src/lib/wire-gateway-acs.ts
|
|
23241
23493
|
init_rbac();
|
|
@@ -23275,18 +23527,18 @@ async function wireGatewayForAcs(args) {
|
|
|
23275
23527
|
init_errors();
|
|
23276
23528
|
var PlatformEnableCostReportCommand = class extends M8tCommand {
|
|
23277
23529
|
static paths = [["platform", "enable-cost-report"]];
|
|
23278
|
-
static usage =
|
|
23530
|
+
static usage = Command41.Usage({
|
|
23279
23531
|
description: "Wire the deployed gateway to send the bi-weekly cost report via ACS Email.",
|
|
23280
23532
|
details: "Discovers the live gateway Container App, grants its managed identity Contributor at the ACS resource scope (authorising the ACS Email send), and sets M8T_ACS_ENDPOINT / M8T_ACS_SENDER / M8T_ENABLE_COST_REPORTER=1 on the gateway. Idempotent \u2014 safely re-runnable. ACS is created during the executor deploy; pass its endpoint, sender, and resource id (from that deploy or 'az communication list')."
|
|
23281
23533
|
});
|
|
23282
|
-
subscription =
|
|
23283
|
-
resourceGroup =
|
|
23534
|
+
subscription = Option38.String("--subscription");
|
|
23535
|
+
resourceGroup = Option38.String("--resource-group", {
|
|
23284
23536
|
description: "m8t resource group to disambiguate the gateway (multi-deployment subscriptions)."
|
|
23285
23537
|
});
|
|
23286
|
-
acsEndpoint =
|
|
23287
|
-
acsSender =
|
|
23288
|
-
acsResourceId =
|
|
23289
|
-
output =
|
|
23538
|
+
acsEndpoint = Option38.String("--acs-endpoint", { required: true, description: "ACS data-plane endpoint, e.g. https://acs-<name>.communication.azure.com/" });
|
|
23539
|
+
acsSender = Option38.String("--acs-sender", { required: true, description: "Managed-domain sender address, e.g. DoNotReply@<guid>.azurecomm.net" });
|
|
23540
|
+
acsResourceId = Option38.String("--acs-resource-id", { required: true, description: "ARM resource id of the acs-<name> Communication Service \u2014 the role-grant scope." });
|
|
23541
|
+
output = Option38.String("--output");
|
|
23290
23542
|
async executeCommand() {
|
|
23291
23543
|
const mode = resolveOutputMode(
|
|
23292
23544
|
this.output,
|
|
@@ -23360,45 +23612,45 @@ var PlatformEnableCostReportCommand = class extends M8tCommand {
|
|
|
23360
23612
|
};
|
|
23361
23613
|
|
|
23362
23614
|
// src/commands/platform/enable-auto-update.ts
|
|
23363
|
-
import { Command as
|
|
23615
|
+
import { Command as Command42, Option as Option39 } from "clipanion";
|
|
23364
23616
|
import { confirm as confirm6 } from "@inquirer/prompts";
|
|
23365
|
-
import { DefaultAzureCredential as
|
|
23617
|
+
import { DefaultAzureCredential as DefaultAzureCredential22 } from "@azure/identity";
|
|
23366
23618
|
init_errors();
|
|
23367
23619
|
var PlatformEnableAutoUpdateCommand = class extends M8tCommand {
|
|
23368
23620
|
static paths = [["platform", "enable-auto-update"]];
|
|
23369
|
-
static usage =
|
|
23621
|
+
static usage = Command42.Usage({
|
|
23370
23622
|
category: "Platform",
|
|
23371
23623
|
description: "Retrofit the auto-updater (MI + cron job + role assignments) onto an existing install.",
|
|
23372
23624
|
details: "For an install that predates the Platform Update Framework: recovers the deployment's resource-name suffix (from the stamped system/infra-params row, or by verified derivation from the live gateway), recovers the other bicep params from live state (WITHOUT changing the deployed gateway image), and re-runs deploy/main.bicep with provisionUpdater=true \u2014 which provisions the updater managed identity, the cron Container Apps Job, and every role assignment (Owner@RG + Foundry User@account + Storage Table + Storage Blob + AcrPull), all scoped to the resource group. On success, backfills system/infra-params so future converges never have to re-derive the suffix. Idempotent \u2014 safe to re-run."
|
|
23373
23625
|
});
|
|
23374
|
-
subscription =
|
|
23375
|
-
resourceGroup =
|
|
23626
|
+
subscription = Option39.String("--subscription");
|
|
23627
|
+
resourceGroup = Option39.String("--resource-group", {
|
|
23376
23628
|
description: "m8t resource group to disambiguate the gateway (multi-deployment subscriptions)."
|
|
23377
23629
|
});
|
|
23378
|
-
suffix =
|
|
23630
|
+
suffix = Option39.String("--suffix", {
|
|
23379
23631
|
description: "The existing deployment's resource-name suffix. Required when it cannot be recovered from system/infra-params or the live gateway."
|
|
23380
23632
|
});
|
|
23381
|
-
installerImage =
|
|
23633
|
+
installerImage = Option39.String("--installer-image", {
|
|
23382
23634
|
required: true,
|
|
23383
23635
|
description: "Updater CA-Job image ref (the converge engine at the current release). Required \u2014 an empty image would skip provisioning."
|
|
23384
23636
|
});
|
|
23385
|
-
updateCron =
|
|
23637
|
+
updateCron = Option39.String("--update-cron", {
|
|
23386
23638
|
description: "Cron schedule for the updater job (bicep default applies when omitted)."
|
|
23387
23639
|
});
|
|
23388
|
-
channelUrl =
|
|
23640
|
+
channelUrl = Option39.String("--channel-url", {
|
|
23389
23641
|
description: "Release-channel URL the updater job polls (bicep default applies when omitted)."
|
|
23390
23642
|
});
|
|
23391
|
-
location =
|
|
23643
|
+
location = Option39.String("--location", {
|
|
23392
23644
|
description: "Region for the updater identity + job. Defaults to the resource group's existing resources."
|
|
23393
23645
|
});
|
|
23394
|
-
foundryTracing =
|
|
23646
|
+
foundryTracing = Option39.String("--foundry-tracing", {
|
|
23395
23647
|
description: "project | account | skip. Pass the value the install was deployed with \u2014 omitting it lets the bicep default (project) switch tracing on."
|
|
23396
23648
|
});
|
|
23397
|
-
endpoint =
|
|
23649
|
+
endpoint = Option39.String("--endpoint", {
|
|
23398
23650
|
description: "Foundry project endpoint URL. Disambiguates the project in a multi-project subscription."
|
|
23399
23651
|
});
|
|
23400
|
-
yes =
|
|
23401
|
-
output =
|
|
23652
|
+
yes = Option39.Boolean("--yes", false);
|
|
23653
|
+
output = Option39.String("--output");
|
|
23402
23654
|
async executeCommand() {
|
|
23403
23655
|
const mode = resolveOutputMode(
|
|
23404
23656
|
this.output,
|
|
@@ -23417,7 +23669,7 @@ var PlatformEnableAutoUpdateCommand = class extends M8tCommand {
|
|
|
23417
23669
|
resourceGroup: this.resourceGroup
|
|
23418
23670
|
});
|
|
23419
23671
|
const { resourceGroup, name: gatewayName } = parseContainerAppResourceId(gw.containerAppResourceId);
|
|
23420
|
-
const credential2 = new
|
|
23672
|
+
const credential2 = new DefaultAzureCredential22();
|
|
23421
23673
|
const account = await getAzAccount();
|
|
23422
23674
|
const subscriptionId = this.subscription ?? account.subscriptionId;
|
|
23423
23675
|
const explicitSuffix = typeof this.suffix === "string" && this.suffix.length > 0 ? this.suffix : void 0;
|
|
@@ -23535,7 +23787,7 @@ var PlatformEnableAutoUpdateCommand = class extends M8tCommand {
|
|
|
23535
23787
|
};
|
|
23536
23788
|
|
|
23537
23789
|
// src/commands/deploy.ts
|
|
23538
|
-
import { Command as
|
|
23790
|
+
import { Command as Command43, Option as Option40 } from "clipanion";
|
|
23539
23791
|
|
|
23540
23792
|
// src/lib/app-reg.ts
|
|
23541
23793
|
init_esm();
|
|
@@ -23869,7 +24121,7 @@ async function patchRedirectUris(appObjectId, fqdn) {
|
|
|
23869
24121
|
init_errors();
|
|
23870
24122
|
|
|
23871
24123
|
// src/lib/whatif.ts
|
|
23872
|
-
import * as
|
|
24124
|
+
import * as path32 from "path";
|
|
23873
24125
|
|
|
23874
24126
|
// src/lib/identifier-patterns.ts
|
|
23875
24127
|
var IDENTIFIER_PATTERNS = [
|
|
@@ -23925,7 +24177,7 @@ function deriveResourceType(resourceId) {
|
|
|
23925
24177
|
return parts.join("/");
|
|
23926
24178
|
}
|
|
23927
24179
|
async function runWhatIf(opts) {
|
|
23928
|
-
const bicepPath =
|
|
24180
|
+
const bicepPath = path32.join(opts.repoRoot, "deploy", "main.bicep");
|
|
23929
24181
|
const out = await runAz([
|
|
23930
24182
|
"deployment",
|
|
23931
24183
|
"group",
|
|
@@ -24023,9 +24275,9 @@ function flattenDelta(delta, prefix = "") {
|
|
|
24023
24275
|
const out = [];
|
|
24024
24276
|
for (const d of delta) {
|
|
24025
24277
|
const segment = /^[0-9]+$/.test(d.path) ? `[${d.path}]` : prefix ? `.${d.path}` : d.path;
|
|
24026
|
-
const
|
|
24027
|
-
if (d.children && d.children.length > 0) out.push(...flattenDelta(d.children,
|
|
24028
|
-
else out.push({ ...d, path:
|
|
24278
|
+
const path47 = prefix ? `${prefix}${segment}` : d.path;
|
|
24279
|
+
if (d.children && d.children.length > 0) out.push(...flattenDelta(d.children, path47));
|
|
24280
|
+
else out.push({ ...d, path: path47 });
|
|
24029
24281
|
}
|
|
24030
24282
|
return out;
|
|
24031
24283
|
}
|
|
@@ -24075,52 +24327,63 @@ function classifyWhatIf(changes) {
|
|
|
24075
24327
|
var DEFAULT_IMAGE_REF = "ghcr.io/m8t-labs/m8t:latest";
|
|
24076
24328
|
var DeployCommand = class extends M8tCommand {
|
|
24077
24329
|
static paths = [["deploy"]];
|
|
24078
|
-
static usage =
|
|
24330
|
+
static usage = Command43.Usage({
|
|
24079
24331
|
description: "Deploy (or update) the m8t gateway/webapp stack via Bicep.",
|
|
24080
24332
|
details: "Ensures the Entra app reg (or pass --client-id to reuse an existing one \u2014 required if you can't create app regs), writes ~/.m8t/config.yaml, ensures the resource group, and runs deploy/main.bicep. The repo is located via ~/.m8t/repo-root."
|
|
24081
24333
|
});
|
|
24082
|
-
subscription =
|
|
24083
|
-
resourceGroup =
|
|
24084
|
-
location =
|
|
24085
|
-
suffix =
|
|
24086
|
-
imageRef =
|
|
24087
|
-
acrPullIdentity =
|
|
24088
|
-
acrResourceId =
|
|
24089
|
-
foundryEndpoint =
|
|
24090
|
-
foundryResourceId =
|
|
24091
|
-
foundryTracing =
|
|
24334
|
+
subscription = Option40.String("--subscription");
|
|
24335
|
+
resourceGroup = Option40.String("--resource-group", "rg-m8t-stack");
|
|
24336
|
+
location = Option40.String("--location", "eastus");
|
|
24337
|
+
suffix = Option40.String("--suffix", "");
|
|
24338
|
+
imageRef = Option40.String("--image-ref", DEFAULT_IMAGE_REF);
|
|
24339
|
+
acrPullIdentity = Option40.String("--acrpull-identity");
|
|
24340
|
+
acrResourceId = Option40.String("--acr-resource-id");
|
|
24341
|
+
foundryEndpoint = Option40.String("--foundry-endpoint");
|
|
24342
|
+
foundryResourceId = Option40.String("--foundry-resource-id");
|
|
24343
|
+
foundryTracing = Option40.String("--foundry-tracing");
|
|
24092
24344
|
// project | account | skip (bicep default: project)
|
|
24093
|
-
clientId =
|
|
24094
|
-
whatIf =
|
|
24345
|
+
clientId = Option40.String("--client-id");
|
|
24346
|
+
whatIf = Option40.Boolean("--what-if", false);
|
|
24095
24347
|
// Only meaningful with --what-if. Routes the comparison through the
|
|
24096
24348
|
// value-free renderers (see ./lib/whatif-redact.js) instead of the default
|
|
24097
24349
|
// before/after renderer. Defaults false so a local, interactive run keeps
|
|
24098
24350
|
// showing values — that is the whole diagnostic point of --what-if.
|
|
24099
24351
|
// Automation that forwards this output anywhere non-private (a CI log, an
|
|
24100
24352
|
// issue) MUST pass --redact.
|
|
24101
|
-
redact =
|
|
24102
|
-
output =
|
|
24353
|
+
redact = Option40.Boolean("--redact", false);
|
|
24354
|
+
output = Option40.String("--output");
|
|
24103
24355
|
// Subscription-scoped role assignments. Omitted ⇒ the template default (true).
|
|
24104
24356
|
// Pass false when deploying as a principal scoped to the resource group only:
|
|
24105
24357
|
// it cannot deploy at subscription scope, and those assignments persist
|
|
24106
24358
|
// idempotently from the initial deployment anyway.
|
|
24107
|
-
assignSubscriptionRoles =
|
|
24359
|
+
assignSubscriptionRoles = Option40.String("--assign-subscription-roles");
|
|
24360
|
+
/**
|
|
24361
|
+
* The installer image the updater Container-Apps Job runs.
|
|
24362
|
+
*
|
|
24363
|
+
* main.bicep only provisions the updater when an image is supplied
|
|
24364
|
+
* (`provisionUpdaterEffective = provisionUpdater && !empty(installerImage)`),
|
|
24365
|
+
* so a run that omits this describes a deployment WITHOUT an updater. For a
|
|
24366
|
+
* real deploy that is merely a skip; for a `--what-if` comparison it is worse
|
|
24367
|
+
* than that — the comparison proposes REMOVING an updater job that exists and
|
|
24368
|
+
* should, and reports it as drift on every single run.
|
|
24369
|
+
*/
|
|
24370
|
+
installerImage = Option40.String("--installer-image");
|
|
24108
24371
|
// Referee — all optional, undefined by default ⇒ the bicep defaults
|
|
24109
24372
|
// apply (dormant: gatewayCpu=0.25, gatewayMemory=0.5Gi, every referee/exam var
|
|
24110
24373
|
// empty). Only pass these when explicitly enabling the referee exam stack.
|
|
24111
|
-
gatewayCpu =
|
|
24112
|
-
gatewayMemory =
|
|
24113
|
-
refereeEnabled =
|
|
24114
|
-
refereeBrainRepos =
|
|
24115
|
-
refereeFeedRepo =
|
|
24116
|
-
refereeInstallationId =
|
|
24117
|
-
refereeWebhookHmacKvUri =
|
|
24118
|
-
examKvUri =
|
|
24119
|
-
examLaWorkspaceId =
|
|
24120
|
-
brainEvalDeployment =
|
|
24121
|
-
brainAppLogin =
|
|
24122
|
-
refereeCheckpointDir =
|
|
24123
|
-
examApiBase =
|
|
24374
|
+
gatewayCpu = Option40.String("--gateway-cpu");
|
|
24375
|
+
gatewayMemory = Option40.String("--gateway-memory");
|
|
24376
|
+
refereeEnabled = Option40.String("--referee-enabled");
|
|
24377
|
+
refereeBrainRepos = Option40.String("--referee-brain-repos");
|
|
24378
|
+
refereeFeedRepo = Option40.String("--referee-feed-repo");
|
|
24379
|
+
refereeInstallationId = Option40.String("--referee-installation-id");
|
|
24380
|
+
refereeWebhookHmacKvUri = Option40.String("--referee-webhook-hmac-kv-uri");
|
|
24381
|
+
examKvUri = Option40.String("--exam-kv-uri");
|
|
24382
|
+
examLaWorkspaceId = Option40.String("--exam-la-workspace-id");
|
|
24383
|
+
brainEvalDeployment = Option40.String("--brain-eval-deployment");
|
|
24384
|
+
brainAppLogin = Option40.String("--brain-app-login");
|
|
24385
|
+
refereeCheckpointDir = Option40.String("--referee-checkpoint-dir");
|
|
24386
|
+
examApiBase = Option40.String("--exam-api-base");
|
|
24124
24387
|
async executeCommand() {
|
|
24125
24388
|
const mode = resolveOutputMode(
|
|
24126
24389
|
this.output,
|
|
@@ -24182,7 +24445,8 @@ var DeployCommand = class extends M8tCommand {
|
|
|
24182
24445
|
brainAppLogin: this.brainAppLogin,
|
|
24183
24446
|
refereeCheckpointDir: this.refereeCheckpointDir,
|
|
24184
24447
|
examApiBase: this.examApiBase,
|
|
24185
|
-
...parseAssignSubscriptionRoles(this.assignSubscriptionRoles) === void 0 ? {} : { assignSubscriptionRoles: parseAssignSubscriptionRoles(this.assignSubscriptionRoles) }
|
|
24448
|
+
...parseAssignSubscriptionRoles(this.assignSubscriptionRoles) === void 0 ? {} : { assignSubscriptionRoles: parseAssignSubscriptionRoles(this.assignSubscriptionRoles) },
|
|
24449
|
+
...this.installerImage ? { installerImage: this.installerImage } : {}
|
|
24186
24450
|
});
|
|
24187
24451
|
const changes = await runWhatIf({ resourceGroup: this.resourceGroup, repoRoot: repoRoot2, params: params2 });
|
|
24188
24452
|
const classified = classifyWhatIf(changes);
|
|
@@ -24250,7 +24514,8 @@ var DeployCommand = class extends M8tCommand {
|
|
|
24250
24514
|
brainAppLogin: this.brainAppLogin,
|
|
24251
24515
|
refereeCheckpointDir: this.refereeCheckpointDir,
|
|
24252
24516
|
examApiBase: this.examApiBase,
|
|
24253
|
-
...parseAssignSubscriptionRoles(this.assignSubscriptionRoles) === void 0 ? {} : { assignSubscriptionRoles: parseAssignSubscriptionRoles(this.assignSubscriptionRoles) }
|
|
24517
|
+
...parseAssignSubscriptionRoles(this.assignSubscriptionRoles) === void 0 ? {} : { assignSubscriptionRoles: parseAssignSubscriptionRoles(this.assignSubscriptionRoles) },
|
|
24518
|
+
...this.installerImage ? { installerImage: this.installerImage } : {}
|
|
24254
24519
|
});
|
|
24255
24520
|
log("running Bicep deployment (~3-5 min)\u2026");
|
|
24256
24521
|
const outputs = await runBicepDeployment({
|
|
@@ -24299,7 +24564,7 @@ var DeployCommand = class extends M8tCommand {
|
|
|
24299
24564
|
|
|
24300
24565
|
// src/commands/eval/skill.ts
|
|
24301
24566
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
24302
|
-
import { Command as
|
|
24567
|
+
import { Command as Command44, Option as Option41 } from "clipanion";
|
|
24303
24568
|
init_errors();
|
|
24304
24569
|
var DECISIONS = /* @__PURE__ */ new Set(["promote", "reject", "needs_review"]);
|
|
24305
24570
|
var JUDGE_STATUSES = /* @__PURE__ */ new Set(["ok", "skipped", "unavailable"]);
|
|
@@ -24324,14 +24589,14 @@ function parseVerdict(stdout) {
|
|
|
24324
24589
|
}
|
|
24325
24590
|
var EvalSkillCommand = class extends M8tCommand {
|
|
24326
24591
|
static paths = [["eval", "skill"]];
|
|
24327
|
-
static usage =
|
|
24592
|
+
static usage = Command44.Usage({
|
|
24328
24593
|
description: "Vet one inbox skill candidate: promote / reject / needs_review. Shells out to the Python `brain-eval` core (override its path with $BRAIN_EVAL_BIN)."
|
|
24329
24594
|
});
|
|
24330
|
-
candidate =
|
|
24331
|
-
skillsDir =
|
|
24332
|
-
noJudge =
|
|
24333
|
-
deployment =
|
|
24334
|
-
output =
|
|
24595
|
+
candidate = Option41.String();
|
|
24596
|
+
skillsDir = Option41.String("--skills-dir");
|
|
24597
|
+
noJudge = Option41.Boolean("--no-judge", false);
|
|
24598
|
+
deployment = Option41.String("--deployment");
|
|
24599
|
+
output = Option41.String("--output");
|
|
24335
24600
|
executeCommand() {
|
|
24336
24601
|
return Promise.resolve(this._runCommand());
|
|
24337
24602
|
}
|
|
@@ -24388,9 +24653,9 @@ var EvalSkillCommand = class extends M8tCommand {
|
|
|
24388
24653
|
|
|
24389
24654
|
// src/commands/eval/exam.ts
|
|
24390
24655
|
import { spawnSync as spawnSync5 } from "child_process";
|
|
24391
|
-
import { writeFileSync as writeFileSync8, mkdirSync as mkdirSync6, readFileSync as
|
|
24392
|
-
import { join as
|
|
24393
|
-
import { Command as
|
|
24656
|
+
import { writeFileSync as writeFileSync8, mkdirSync as mkdirSync6, readFileSync as readFileSync21, existsSync as existsSync20, readdirSync as readdirSync3 } from "fs";
|
|
24657
|
+
import { join as join30 } from "path";
|
|
24658
|
+
import { Command as Command45, Option as Option42 } from "clipanion";
|
|
24394
24659
|
init_errors();
|
|
24395
24660
|
init_esm();
|
|
24396
24661
|
function parseArmToken(tok, opts) {
|
|
@@ -24571,9 +24836,9 @@ function resolveRefereeHome(refereeHomeOut, env) {
|
|
|
24571
24836
|
return null;
|
|
24572
24837
|
}
|
|
24573
24838
|
function resolveTaskSetDir(base, worker, version) {
|
|
24574
|
-
if (existsSync20(
|
|
24839
|
+
if (existsSync20(join30(base, version))) return version;
|
|
24575
24840
|
const prefixed = `${worker}-${version}`;
|
|
24576
|
-
if (existsSync20(
|
|
24841
|
+
if (existsSync20(join30(base, prefixed))) return prefixed;
|
|
24577
24842
|
if (version === "latest" && existsSync20(base)) {
|
|
24578
24843
|
const dirs = readdirSync3(base, { withFileTypes: true }).filter((d) => d.isDirectory() && d.name.startsWith(`${worker}-`)).map((d) => d.name).sort();
|
|
24579
24844
|
if (dirs.length > 0) return dirs[dirs.length - 1];
|
|
@@ -24589,11 +24854,11 @@ function readSealedTaskIds(taskSetVersion, refereeHomeOut, env = process.env) {
|
|
|
24589
24854
|
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)"
|
|
24590
24855
|
});
|
|
24591
24856
|
}
|
|
24592
|
-
const versionDir = resolveTaskSetDir(
|
|
24593
|
-
const manifestPath =
|
|
24857
|
+
const versionDir = resolveTaskSetDir(join30(home, "tasksets", worker), worker, version);
|
|
24858
|
+
const manifestPath = join30(home, "tasksets", worker, versionDir, "manifest.yaml");
|
|
24594
24859
|
let text;
|
|
24595
24860
|
try {
|
|
24596
|
-
text =
|
|
24861
|
+
text = readFileSync21(manifestPath, "utf-8");
|
|
24597
24862
|
} catch (e) {
|
|
24598
24863
|
throw new LocalCliError({
|
|
24599
24864
|
code: "EXAM_REDACTION_UNSAFE",
|
|
@@ -24620,24 +24885,24 @@ function buildPlan(args) {
|
|
|
24620
24885
|
}
|
|
24621
24886
|
var EvalExamCommand = class extends M8tCommand {
|
|
24622
24887
|
static paths = [["eval", "exam"]];
|
|
24623
|
-
static usage =
|
|
24888
|
+
static usage = Command45.Usage({
|
|
24624
24889
|
description: "Run a brain exam: impact A/B + dream-delta. Resolves the plan, then shells out to the Python `brain-exam` orchestrator (override its path with $BRAIN_EXAM_BIN). Renders an ExamVerdict: three-valued verdict + power note + per-task flips."
|
|
24625
24890
|
});
|
|
24626
|
-
worker =
|
|
24627
|
-
arms =
|
|
24628
|
-
taskSet =
|
|
24629
|
-
examType =
|
|
24630
|
-
skill =
|
|
24631
|
-
reps =
|
|
24632
|
-
probes =
|
|
24633
|
-
pool =
|
|
24634
|
-
out =
|
|
24635
|
-
dryRun =
|
|
24636
|
-
keepArms =
|
|
24637
|
-
allowStub =
|
|
24638
|
-
deployment =
|
|
24639
|
-
output =
|
|
24640
|
-
observeWaitS =
|
|
24891
|
+
worker = Option42.String();
|
|
24892
|
+
arms = Option42.String("--arms");
|
|
24893
|
+
taskSet = Option42.String("--task-set");
|
|
24894
|
+
examType = Option42.String("--exam-type");
|
|
24895
|
+
skill = Option42.String("--skill");
|
|
24896
|
+
reps = Option42.String("-n,--reps");
|
|
24897
|
+
probes = Option42.String("--probes");
|
|
24898
|
+
pool = Option42.String("--pool");
|
|
24899
|
+
out = Option42.String("--out");
|
|
24900
|
+
dryRun = Option42.Boolean("--dry-run", false);
|
|
24901
|
+
keepArms = Option42.Boolean("--keep-arms", false);
|
|
24902
|
+
allowStub = Option42.Boolean("--allow-stub", false);
|
|
24903
|
+
deployment = Option42.String("--deployment");
|
|
24904
|
+
output = Option42.String("--output");
|
|
24905
|
+
observeWaitS = Option42.String("--observe-wait-s");
|
|
24641
24906
|
async executeCommand() {
|
|
24642
24907
|
await Promise.resolve();
|
|
24643
24908
|
const worker = typeof this.worker === "string" ? this.worker : void 0;
|
|
@@ -24714,9 +24979,9 @@ var EvalExamCommand = class extends M8tCommand {
|
|
|
24714
24979
|
if (out !== void 0) {
|
|
24715
24980
|
const sealedTaskIds = taskSetVersion ? readSealedTaskIds(taskSetVersion, out) : /* @__PURE__ */ new Set();
|
|
24716
24981
|
mkdirSync6(out, { recursive: true });
|
|
24717
|
-
writeFileSync8(
|
|
24982
|
+
writeFileSync8(join30(out, "verdict.json"), JSON.stringify(verdict, null, 2));
|
|
24718
24983
|
const feed = redactForFeed(verdict, sealedTaskIds);
|
|
24719
|
-
writeFileSync8(
|
|
24984
|
+
writeFileSync8(join30(out, "feed.json"), JSON.stringify(feed, null, 2));
|
|
24720
24985
|
}
|
|
24721
24986
|
if (mode === "json") {
|
|
24722
24987
|
this.context.stdout.write(renderJson(verdict) + "\n");
|
|
@@ -24752,10 +25017,10 @@ var EvalExamCommand = class extends M8tCommand {
|
|
|
24752
25017
|
};
|
|
24753
25018
|
|
|
24754
25019
|
// src/commands/version.ts
|
|
24755
|
-
import { Command as
|
|
25020
|
+
import { Command as Command46, Option as Option43 } from "clipanion";
|
|
24756
25021
|
var VersionCommand = class extends M8tCommand {
|
|
24757
25022
|
static paths = [["version"], ["--version"], ["-v"]];
|
|
24758
|
-
static usage =
|
|
25023
|
+
static usage = Command46.Usage({
|
|
24759
25024
|
description: "Print the CLI version.",
|
|
24760
25025
|
details: "Prints the m8t CLI version. With --verbose, also prints Node version and platform.",
|
|
24761
25026
|
examples: [
|
|
@@ -24763,8 +25028,8 @@ var VersionCommand = class extends M8tCommand {
|
|
|
24763
25028
|
["Print as JSON", "$0 version --output json"]
|
|
24764
25029
|
]
|
|
24765
25030
|
});
|
|
24766
|
-
output =
|
|
24767
|
-
verbose =
|
|
25031
|
+
output = Option43.String("--output", { description: "pretty | json | auto (default)" });
|
|
25032
|
+
verbose = Option43.Boolean("--verbose", false);
|
|
24768
25033
|
executeCommand() {
|
|
24769
25034
|
const mode = resolveOutputMode(
|
|
24770
25035
|
this.output ?? "auto",
|
|
@@ -24795,18 +25060,18 @@ var VersionCommand = class extends M8tCommand {
|
|
|
24795
25060
|
};
|
|
24796
25061
|
|
|
24797
25062
|
// src/commands/whoami.ts
|
|
24798
|
-
import { Command as
|
|
25063
|
+
import { Command as Command47, Option as Option44 } from "clipanion";
|
|
24799
25064
|
var WhoamiCommand = class extends M8tCommand {
|
|
24800
25065
|
static paths = [["whoami"]];
|
|
24801
|
-
static usage =
|
|
25066
|
+
static usage = Command47.Usage({
|
|
24802
25067
|
description: "Show your identity + the gateway you'll talk to. Probes the backend."
|
|
24803
25068
|
});
|
|
24804
|
-
output =
|
|
24805
|
-
verbose =
|
|
24806
|
-
subscription =
|
|
25069
|
+
output = Option44.String("--output");
|
|
25070
|
+
verbose = Option44.Boolean("--verbose", false);
|
|
25071
|
+
subscription = Option44.String("--subscription", {
|
|
24807
25072
|
description: "Azure subscription ID to discover gateway in (defaults to active az subscription)."
|
|
24808
25073
|
});
|
|
24809
|
-
resourceGroup =
|
|
25074
|
+
resourceGroup = Option44.String("--resource-group", {
|
|
24810
25075
|
description: "m8t resource group to disambiguate the gateway (multi-deployment subscriptions)."
|
|
24811
25076
|
});
|
|
24812
25077
|
async executeCommand() {
|
|
@@ -24871,7 +25136,7 @@ var WhoamiCommand = class extends M8tCommand {
|
|
|
24871
25136
|
};
|
|
24872
25137
|
|
|
24873
25138
|
// src/commands/status.ts
|
|
24874
|
-
import { Command as
|
|
25139
|
+
import { Command as Command48, Option as Option45 } from "clipanion";
|
|
24875
25140
|
|
|
24876
25141
|
// src/lib/azd.ts
|
|
24877
25142
|
init_errors();
|
|
@@ -24936,10 +25201,10 @@ async function resolveLocalContext() {
|
|
|
24936
25201
|
// src/commands/status.ts
|
|
24937
25202
|
var StatusCommand = class extends M8tCommand {
|
|
24938
25203
|
static paths = [["status"]];
|
|
24939
|
-
static usage =
|
|
25204
|
+
static usage = Command48.Usage({
|
|
24940
25205
|
description: "Show the local m8t context: identity, config.yaml, gateway cache, azd mode."
|
|
24941
25206
|
});
|
|
24942
|
-
output =
|
|
25207
|
+
output = Option45.String("--output");
|
|
24943
25208
|
async executeCommand() {
|
|
24944
25209
|
const mode = resolveOutputMode(
|
|
24945
25210
|
this.output,
|
|
@@ -24977,11 +25242,11 @@ var StatusCommand = class extends M8tCommand {
|
|
|
24977
25242
|
};
|
|
24978
25243
|
|
|
24979
25244
|
// src/commands/doctor.ts
|
|
24980
|
-
import { Command as
|
|
24981
|
-
import { DefaultAzureCredential as
|
|
24982
|
-
import * as
|
|
25245
|
+
import { Command as Command49, Option as Option46 } from "clipanion";
|
|
25246
|
+
import { DefaultAzureCredential as DefaultAzureCredential23 } from "@azure/identity";
|
|
25247
|
+
import * as fs30 from "fs";
|
|
24983
25248
|
import * as os12 from "os";
|
|
24984
|
-
import * as
|
|
25249
|
+
import * as path33 from "path";
|
|
24985
25250
|
|
|
24986
25251
|
// src/lib/doctor-checks.ts
|
|
24987
25252
|
function checkAzSignedIn(az) {
|
|
@@ -25460,40 +25725,40 @@ async function resolveAccountLocation(accountId) {
|
|
|
25460
25725
|
}
|
|
25461
25726
|
}
|
|
25462
25727
|
function probeRepoRoot() {
|
|
25463
|
-
const marker =
|
|
25464
|
-
if (!
|
|
25728
|
+
const marker = path33.join(os12.homedir(), ".m8t", "repo-root");
|
|
25729
|
+
if (!fs30.existsSync(marker)) {
|
|
25465
25730
|
return { markerExists: false, path: null, isDir: false, isGitCheckout: false };
|
|
25466
25731
|
}
|
|
25467
25732
|
let repoPath;
|
|
25468
25733
|
try {
|
|
25469
|
-
repoPath =
|
|
25734
|
+
repoPath = fs30.readFileSync(marker, "utf8").trim();
|
|
25470
25735
|
} catch {
|
|
25471
25736
|
return { markerExists: true, path: null, isDir: false, isGitCheckout: false };
|
|
25472
25737
|
}
|
|
25473
25738
|
if (!repoPath) return { markerExists: true, path: null, isDir: false, isGitCheckout: false };
|
|
25474
25739
|
let isDir = false;
|
|
25475
25740
|
try {
|
|
25476
|
-
isDir =
|
|
25741
|
+
isDir = fs30.statSync(repoPath).isDirectory();
|
|
25477
25742
|
} catch {
|
|
25478
25743
|
isDir = false;
|
|
25479
25744
|
}
|
|
25480
|
-
const isGitCheckout = isDir &&
|
|
25745
|
+
const isGitCheckout = isDir && fs30.existsSync(path33.join(repoPath, ".git"));
|
|
25481
25746
|
return { markerExists: true, path: repoPath, isDir, isGitCheckout };
|
|
25482
25747
|
}
|
|
25483
25748
|
function probeLegacyStateDir() {
|
|
25484
25749
|
return {
|
|
25485
|
-
legacyExists:
|
|
25486
|
-
currentExists:
|
|
25750
|
+
legacyExists: fs30.existsSync(path33.join(os12.homedir(), ".m8t-stack")),
|
|
25751
|
+
currentExists: fs30.existsSync(path33.join(os12.homedir(), ".m8t"))
|
|
25487
25752
|
};
|
|
25488
25753
|
}
|
|
25489
25754
|
var DoctorCommand = class extends M8tCommand {
|
|
25490
25755
|
static paths = [["doctor"]];
|
|
25491
|
-
static usage =
|
|
25756
|
+
static usage = Command49.Usage({
|
|
25492
25757
|
description: "Diagnose the local m8t setup: az login, config.yaml, gateway, Foundry data-plane."
|
|
25493
25758
|
});
|
|
25494
|
-
output =
|
|
25495
|
-
agent =
|
|
25496
|
-
resourceGroup =
|
|
25759
|
+
output = Option46.String("--output");
|
|
25760
|
+
agent = Option46.String("--agent");
|
|
25761
|
+
resourceGroup = Option46.String("--resource-group", {
|
|
25497
25762
|
description: "m8t resource group to disambiguate the gateway (multi-deployment subscriptions)."
|
|
25498
25763
|
});
|
|
25499
25764
|
async executeCommand() {
|
|
@@ -25566,7 +25831,7 @@ var DoctorCommand = class extends M8tCommand {
|
|
|
25566
25831
|
let kvStatus = 0;
|
|
25567
25832
|
if (kv) {
|
|
25568
25833
|
try {
|
|
25569
|
-
const token = await new
|
|
25834
|
+
const token = await new DefaultAzureCredential23().getToken("https://vault.azure.net/.default");
|
|
25570
25835
|
const res = await fetch(`${kv.uri.replace(/\/$/, "")}/secrets?api-version=7.4&maxresults=1`, {
|
|
25571
25836
|
headers: { Authorization: `Bearer ${token.token}` }
|
|
25572
25837
|
});
|
|
@@ -25586,7 +25851,7 @@ var DoctorCommand = class extends M8tCommand {
|
|
|
25586
25851
|
if (typeof this.agent === "string" && this.agent) {
|
|
25587
25852
|
checking(`delivery grant for ${this.agent}`);
|
|
25588
25853
|
try {
|
|
25589
|
-
const credential2 = new
|
|
25854
|
+
const credential2 = new DefaultAzureCredential23();
|
|
25590
25855
|
const cur = await getAgentVersion({
|
|
25591
25856
|
credential: credential2,
|
|
25592
25857
|
projectEndpoint: foundry.projectEndpoint,
|
|
@@ -25629,11 +25894,11 @@ var DoctorCommand = class extends M8tCommand {
|
|
|
25629
25894
|
};
|
|
25630
25895
|
|
|
25631
25896
|
// src/commands/prereqs.ts
|
|
25632
|
-
import { Command as
|
|
25897
|
+
import { Command as Command50, Option as Option47 } from "clipanion";
|
|
25633
25898
|
init_errors();
|
|
25634
25899
|
|
|
25635
25900
|
// src/lib/prereq-deps.ts
|
|
25636
|
-
import { DefaultAzureCredential as
|
|
25901
|
+
import { DefaultAzureCredential as DefaultAzureCredential24 } from "@azure/identity";
|
|
25637
25902
|
|
|
25638
25903
|
// src/lib/bootstrap-preflight.ts
|
|
25639
25904
|
var ADMIN_DIRECTORY_ROLES = ["Global Administrator", "Application Administrator", "Cloud Application Administrator"];
|
|
@@ -25745,7 +26010,7 @@ function buildPrereqDeps(opts = {}) {
|
|
|
25745
26010
|
probeRedirectUri,
|
|
25746
26011
|
fixFoundryAccess,
|
|
25747
26012
|
fixKeyVaultAccess,
|
|
25748
|
-
credential: () => credentialSingleton2 ??= new
|
|
26013
|
+
credential: () => credentialSingleton2 ??= new DefaultAzureCredential24()
|
|
25749
26014
|
};
|
|
25750
26015
|
}
|
|
25751
26016
|
|
|
@@ -26335,7 +26600,7 @@ function renderVerdict(v) {
|
|
|
26335
26600
|
}
|
|
26336
26601
|
var PrereqsCommand = class extends M8tCommand {
|
|
26337
26602
|
static paths = [["prereqs"]];
|
|
26338
|
-
static usage =
|
|
26603
|
+
static usage = Command50.Usage({
|
|
26339
26604
|
description: "Check (and optionally fix) everything m8t needs \u2014 to install, or for you to use it.",
|
|
26340
26605
|
details: "Runs one of two phases. With no platform discoverable it checks INSTALL prerequisites: your Azure sign-in, subscription and directory rights, resource-provider registrations, soft-deleted Cognitive Services accounts (they hold their model quota until purged), and model quota. With a platform live it checks USAGE prerequisites for the signed-in account: the sign-in redirect URI, Foundry data-plane access, and Key Vault secrets access. Pass --fix to repair what is repairable, and --fix --for <upn> to set a teammate up (usage phase only). Read-only without --fix.",
|
|
26341
26606
|
examples: [
|
|
@@ -26346,15 +26611,15 @@ var PrereqsCommand = class extends M8tCommand {
|
|
|
26346
26611
|
["Set a teammate up (needs role-assignment rights)", "$0 prereqs --fix --for alice@contoso.com"]
|
|
26347
26612
|
]
|
|
26348
26613
|
});
|
|
26349
|
-
fix =
|
|
26350
|
-
for_ =
|
|
26351
|
-
phase =
|
|
26352
|
-
region =
|
|
26353
|
-
model =
|
|
26354
|
-
clientId =
|
|
26355
|
-
subscription =
|
|
26356
|
-
resourceGroup =
|
|
26357
|
-
output =
|
|
26614
|
+
fix = Option47.Boolean("--fix", false, { description: "Repair what is repairable. Without it the command only reports." });
|
|
26615
|
+
for_ = Option47.String("--for", { description: "UPN or object id of another person. Usage phase only." });
|
|
26616
|
+
phase = Option47.String("--phase", { description: "Force 'install' or 'usage' instead of auto-detecting." });
|
|
26617
|
+
region = Option47.String("--region", { description: "Target region. Enables the install-phase quota check, and judges soft-deleted accounts against the region you will install into (without it, they only warn)." });
|
|
26618
|
+
model = Option47.String("--model", { description: `Model whose quota the install needs (default ${INSTALL_REASONING_MODEL}).` });
|
|
26619
|
+
clientId = Option47.String("--client-id", { description: "A ready app registration, in place of directory-admin rights." });
|
|
26620
|
+
subscription = Option47.String("--subscription");
|
|
26621
|
+
resourceGroup = Option47.String("--resource-group");
|
|
26622
|
+
output = Option47.String("--output");
|
|
26358
26623
|
async executeCommand() {
|
|
26359
26624
|
const mode = resolveOutputMode(this.output, this.context.stdout);
|
|
26360
26625
|
const json = mode === "json";
|
|
@@ -26410,18 +26675,18 @@ var PrereqsCommand = class extends M8tCommand {
|
|
|
26410
26675
|
};
|
|
26411
26676
|
|
|
26412
26677
|
// src/commands/switch.ts
|
|
26413
|
-
import { Command as
|
|
26678
|
+
import { Command as Command51, Option as Option48 } from "clipanion";
|
|
26414
26679
|
|
|
26415
26680
|
// src/lib/profiles.ts
|
|
26416
|
-
import * as
|
|
26417
|
-
import * as
|
|
26681
|
+
import * as fs31 from "fs/promises";
|
|
26682
|
+
import * as path34 from "path";
|
|
26418
26683
|
import { parse as parseYaml12, stringify as stringifyYaml4 } from "yaml";
|
|
26419
26684
|
function profilesDir() {
|
|
26420
26685
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
26421
|
-
return
|
|
26686
|
+
return path34.join(home, ".m8t", "profiles");
|
|
26422
26687
|
}
|
|
26423
26688
|
function getProfilePath(name) {
|
|
26424
|
-
return
|
|
26689
|
+
return path34.join(profilesDir(), `${path34.basename(name)}.yaml`);
|
|
26425
26690
|
}
|
|
26426
26691
|
function slugifyTenant(domainOrId) {
|
|
26427
26692
|
const base = domainOrId.split(".")[0].toLowerCase();
|
|
@@ -26430,7 +26695,7 @@ function slugifyTenant(domainOrId) {
|
|
|
26430
26695
|
}
|
|
26431
26696
|
async function listProfiles() {
|
|
26432
26697
|
try {
|
|
26433
|
-
const entries = await
|
|
26698
|
+
const entries = await fs31.readdir(profilesDir());
|
|
26434
26699
|
return entries.filter((e) => e.endsWith(".yaml")).map((e) => e.replace(/\.yaml$/, "")).sort();
|
|
26435
26700
|
} catch (e) {
|
|
26436
26701
|
if (e.code === "ENOENT") return [];
|
|
@@ -26439,7 +26704,7 @@ async function listProfiles() {
|
|
|
26439
26704
|
}
|
|
26440
26705
|
async function readProfile(name) {
|
|
26441
26706
|
try {
|
|
26442
|
-
const raw = await
|
|
26707
|
+
const raw = await fs31.readFile(getProfilePath(name), "utf8");
|
|
26443
26708
|
const parsed = parseYaml12(raw);
|
|
26444
26709
|
if (!parsed || typeof parsed !== "object") return null;
|
|
26445
26710
|
return parsed;
|
|
@@ -26450,14 +26715,14 @@ async function readProfile(name) {
|
|
|
26450
26715
|
}
|
|
26451
26716
|
async function exists(p) {
|
|
26452
26717
|
try {
|
|
26453
|
-
await
|
|
26718
|
+
await fs31.stat(p);
|
|
26454
26719
|
return true;
|
|
26455
26720
|
} catch {
|
|
26456
26721
|
return false;
|
|
26457
26722
|
}
|
|
26458
26723
|
}
|
|
26459
26724
|
async function saveProfile(p) {
|
|
26460
|
-
await
|
|
26725
|
+
await fs31.mkdir(profilesDir(), { recursive: true });
|
|
26461
26726
|
let name = p.name;
|
|
26462
26727
|
let n = 2;
|
|
26463
26728
|
while (await exists(getProfilePath(name))) {
|
|
@@ -26466,8 +26731,8 @@ async function saveProfile(p) {
|
|
|
26466
26731
|
}
|
|
26467
26732
|
const target = getProfilePath(name);
|
|
26468
26733
|
const tmp = `${target}.tmp`;
|
|
26469
|
-
await
|
|
26470
|
-
await
|
|
26734
|
+
await fs31.writeFile(tmp, stringifyYaml4({ ...p, name }, { indent: 2 }), "utf8");
|
|
26735
|
+
await fs31.rename(tmp, target);
|
|
26471
26736
|
return name;
|
|
26472
26737
|
}
|
|
26473
26738
|
|
|
@@ -26550,14 +26815,14 @@ async function profileSwitch(name, asName) {
|
|
|
26550
26815
|
init_errors();
|
|
26551
26816
|
var SwitchCommand = class extends M8tCommand {
|
|
26552
26817
|
static paths = [["switch"]];
|
|
26553
|
-
static usage =
|
|
26818
|
+
static usage = Command51.Usage({
|
|
26554
26819
|
description: "Re-point local config at another deployment: --subscription <id|name> (discovery) or <profile>."
|
|
26555
26820
|
});
|
|
26556
|
-
profile =
|
|
26557
|
-
subscription =
|
|
26558
|
-
list =
|
|
26559
|
-
as =
|
|
26560
|
-
output =
|
|
26821
|
+
profile = Option48.String({ required: false });
|
|
26822
|
+
subscription = Option48.String("--subscription");
|
|
26823
|
+
list = Option48.Boolean("--list", false);
|
|
26824
|
+
as = Option48.String("--as");
|
|
26825
|
+
output = Option48.String("--output");
|
|
26561
26826
|
async executeCommand() {
|
|
26562
26827
|
const mode = resolveOutputMode(
|
|
26563
26828
|
this.output,
|
|
@@ -26614,7 +26879,7 @@ var SwitchCommand = class extends M8tCommand {
|
|
|
26614
26879
|
|
|
26615
26880
|
// src/commands/open.ts
|
|
26616
26881
|
import { spawn as spawn5 } from "child_process";
|
|
26617
|
-
import { Command as
|
|
26882
|
+
import { Command as Command52, Option as Option49 } from "clipanion";
|
|
26618
26883
|
|
|
26619
26884
|
// src/lib/open-targets.ts
|
|
26620
26885
|
init_errors();
|
|
@@ -26660,14 +26925,14 @@ function openUrl(url) {
|
|
|
26660
26925
|
}
|
|
26661
26926
|
var OpenCommand = class extends M8tCommand {
|
|
26662
26927
|
static paths = [["open"]];
|
|
26663
|
-
static usage =
|
|
26928
|
+
static usage = Command52.Usage({
|
|
26664
26929
|
description: "Open the deployed webapp (default), the Foundry portal, or the resource group.",
|
|
26665
26930
|
details: "Targets: webapp (deployed app, default) | foundry (ai.azure.com) | portal (resource group in the Azure portal). Pass --print to emit the URL instead of launching a browser (also the default when stdout isn't a TTY)."
|
|
26666
26931
|
});
|
|
26667
|
-
target =
|
|
26668
|
-
print =
|
|
26669
|
-
output =
|
|
26670
|
-
resourceGroup =
|
|
26932
|
+
target = Option49.String({ required: false });
|
|
26933
|
+
print = Option49.Boolean("--print", false);
|
|
26934
|
+
output = Option49.String("--output");
|
|
26935
|
+
resourceGroup = Option49.String("--resource-group", {
|
|
26671
26936
|
description: "m8t resource group to disambiguate the gateway (multi-deployment subscriptions)."
|
|
26672
26937
|
});
|
|
26673
26938
|
async executeCommand() {
|
|
@@ -26711,7 +26976,7 @@ var OpenCommand = class extends M8tCommand {
|
|
|
26711
26976
|
};
|
|
26712
26977
|
|
|
26713
26978
|
// src/commands/dream/run.ts
|
|
26714
|
-
import { Command as
|
|
26979
|
+
import { Command as Command53, Option as Option50 } from "clipanion";
|
|
26715
26980
|
import { AzureCliCredential } from "@azure/identity";
|
|
26716
26981
|
import { TableClient as TableClient7 } from "@azure/data-tables";
|
|
26717
26982
|
import { AIProjectClient as AIProjectClient3 } from "@azure/ai-projects";
|
|
@@ -27756,7 +28021,7 @@ function buildAdvancePlan(worker, cursor, physicalPks, consumedRowsByPk, failedT
|
|
|
27756
28021
|
// ../../packages/brain/engine/dist/esm/dream/writer.js
|
|
27757
28022
|
var API2 = "https://api.github.com";
|
|
27758
28023
|
var WRITER_ALLOWED_PREFIX = /^(memory|inbox|quarantine|artifacts)\//;
|
|
27759
|
-
var isAllowedWritePath = (
|
|
28024
|
+
var isAllowedWritePath = (path47, allowedPrefix) => allowedPrefix.test(path47) && !path47.split("/").includes("..");
|
|
27760
28025
|
var unquote = (s) => s.trim().replace(/^["']|["']$/g, "");
|
|
27761
28026
|
function parseFrontmatter(content) {
|
|
27762
28027
|
const m = /^---\r?\n([\s\S]*?)\r?\n---/.exec(content);
|
|
@@ -27799,8 +28064,8 @@ function makeGitDataWriter(args) {
|
|
|
27799
28064
|
if (args.allowedPathPrefix && !args.allowedPathPrefix.source.startsWith("^")) {
|
|
27800
28065
|
throw new Error(`makeGitDataWriter: allowedPathPrefix must be anchored with "^" (got /${args.allowedPathPrefix.source}/) \u2014 an unanchored regex would widen the B1 write-path allowlist`);
|
|
27801
28066
|
}
|
|
27802
|
-
async function gh(token, method,
|
|
27803
|
-
const res = await doFetch(`${API2}/repos/${repoPath}${
|
|
28067
|
+
async function gh(token, method, path47, body) {
|
|
28068
|
+
const res = await doFetch(`${API2}/repos/${repoPath}${path47}`, {
|
|
27804
28069
|
method,
|
|
27805
28070
|
headers: {
|
|
27806
28071
|
Authorization: `Bearer ${token}`,
|
|
@@ -27813,8 +28078,8 @@ function makeGitDataWriter(args) {
|
|
|
27813
28078
|
const text = await res.text();
|
|
27814
28079
|
return { status: res.status, ok: res.ok, json: text ? JSON.parse(text) : {} };
|
|
27815
28080
|
}
|
|
27816
|
-
async function readFileWith(token,
|
|
27817
|
-
const encodedPath =
|
|
28081
|
+
async function readFileWith(token, path47) {
|
|
28082
|
+
const encodedPath = path47.split("/").map(encodeURIComponent).join("/");
|
|
27818
28083
|
const r = await gh(token, "GET", `/contents/${encodedPath}?ref=${args.branch}`);
|
|
27819
28084
|
if (r.status === 404)
|
|
27820
28085
|
return null;
|
|
@@ -27830,9 +28095,9 @@ function makeGitDataWriter(args) {
|
|
|
27830
28095
|
throw new Error(`fetchTip: HTTP ${String(r.status)}`);
|
|
27831
28096
|
return r.json.object.sha;
|
|
27832
28097
|
},
|
|
27833
|
-
async readFile(
|
|
28098
|
+
async readFile(path47) {
|
|
27834
28099
|
const token = await args.mintToken();
|
|
27835
|
-
return readFileWith(token,
|
|
28100
|
+
return readFileWith(token, path47);
|
|
27836
28101
|
},
|
|
27837
28102
|
async listMemory() {
|
|
27838
28103
|
const token = await args.mintToken();
|
|
@@ -27841,9 +28106,9 @@ function makeGitDataWriter(args) {
|
|
|
27841
28106
|
return [];
|
|
27842
28107
|
const paths = r.json.tree.filter((e) => e.type === "blob" && e.path.startsWith("memory/") && e.path.endsWith(".md")).map((e) => e.path);
|
|
27843
28108
|
const out = [];
|
|
27844
|
-
for (const
|
|
27845
|
-
const content = await readFileWith(token,
|
|
27846
|
-
out.push({ path:
|
|
28109
|
+
for (const path47 of paths) {
|
|
28110
|
+
const content = await readFileWith(token, path47);
|
|
28111
|
+
out.push({ path: path47, frontmatter: content ? parseFrontmatter(content) : {} });
|
|
27847
28112
|
}
|
|
27848
28113
|
return out;
|
|
27849
28114
|
},
|
|
@@ -28282,7 +28547,7 @@ async function loadMemoryContext(brain) {
|
|
|
28282
28547
|
return {
|
|
28283
28548
|
files,
|
|
28284
28549
|
indexEntries,
|
|
28285
|
-
originOf: (
|
|
28550
|
+
originOf: (path47) => originByPath.get(path47) ?? "worker"
|
|
28286
28551
|
};
|
|
28287
28552
|
}
|
|
28288
28553
|
|
|
@@ -28303,14 +28568,14 @@ function checkEvidenceMembership(delta, harvested) {
|
|
|
28303
28568
|
}
|
|
28304
28569
|
var BatchAbort = class extends Error {
|
|
28305
28570
|
path;
|
|
28306
|
-
constructor(
|
|
28571
|
+
constructor(path47, message) {
|
|
28307
28572
|
super(message);
|
|
28308
|
-
this.path =
|
|
28573
|
+
this.path = path47;
|
|
28309
28574
|
this.name = "BatchAbort";
|
|
28310
28575
|
}
|
|
28311
28576
|
};
|
|
28312
|
-
var isIndexFile = (
|
|
28313
|
-
var isMemoryIndex = (
|
|
28577
|
+
var isIndexFile = (path47) => /(^|\/)[^/]*_index\.md$/.test(path47);
|
|
28578
|
+
var isMemoryIndex = (path47) => path47 === "memory/MEMORY.md";
|
|
28314
28579
|
function targetPath(delta) {
|
|
28315
28580
|
switch (delta.verb) {
|
|
28316
28581
|
case "new":
|
|
@@ -28327,29 +28592,29 @@ function targetPath(delta) {
|
|
|
28327
28592
|
}
|
|
28328
28593
|
async function checkOriginTier(delta, lookup) {
|
|
28329
28594
|
const evidence = evidenceOf(delta) ?? [];
|
|
28330
|
-
const
|
|
28331
|
-
if (
|
|
28595
|
+
const path47 = targetPath(delta);
|
|
28596
|
+
if (path47 === null)
|
|
28332
28597
|
return { ok: true };
|
|
28333
|
-
if (isIndexFile(
|
|
28334
|
-
return { ok: false, flagged: { kind: "flagged", path:
|
|
28598
|
+
if (isIndexFile(path47) && !isMemoryIndex(path47)) {
|
|
28599
|
+
return { ok: false, flagged: { kind: "flagged", path: path47, tension: `refused: ${path47} is an index file (only memory/MEMORY.md is editable)`, evidence } };
|
|
28335
28600
|
}
|
|
28336
|
-
const target = await lookup(
|
|
28337
|
-
const isStructural =
|
|
28601
|
+
const target = await lookup(path47);
|
|
28602
|
+
const isStructural = path47.startsWith("references/");
|
|
28338
28603
|
const origin = target?.frontmatter.origin ?? (isStructural ? "operator" : "worker");
|
|
28339
28604
|
const editable = origin === "worker" || origin === "dream";
|
|
28340
28605
|
if (editable)
|
|
28341
28606
|
return { ok: true };
|
|
28342
28607
|
const removesOperatorTarget = delta.verb === "retract" || delta.verb === "supersede" && delta.oldPath !== delta.newPath;
|
|
28343
28608
|
if (removesOperatorTarget) {
|
|
28344
|
-
throw new BatchAbort(
|
|
28609
|
+
throw new BatchAbort(path47, `supersede/retract OLD target ${path47} is origin: ${origin} \u2014 aborting batch (never half-apply)`);
|
|
28345
28610
|
}
|
|
28346
|
-
return { ok: false, flagged: { kind: "flagged", path:
|
|
28611
|
+
return { ok: false, flagged: { kind: "flagged", path: path47, tension: `operator-origin (${origin}); flag-only`, evidence } };
|
|
28347
28612
|
}
|
|
28348
28613
|
var ALLOWED_MEMORY = /^memory\/.+\.md$/;
|
|
28349
28614
|
var ALLOWED_INBOX = /^inbox\//;
|
|
28350
28615
|
var ALLOWED_QUARANTINE = /^quarantine\//;
|
|
28351
28616
|
var ALLOWED_FLAG = /^memory\//;
|
|
28352
|
-
var hasTraversal = (
|
|
28617
|
+
var hasTraversal = (path47) => path47.split("/").includes("..");
|
|
28353
28618
|
function checkPathAllowed(delta) {
|
|
28354
28619
|
const evidence = evidenceOf(delta) ?? [];
|
|
28355
28620
|
const reject = (detail) => ({ ok: false, rejected: { kind: "rejected", detail, evidence } });
|
|
@@ -28456,7 +28721,7 @@ ${inject}
|
|
|
28456
28721
|
---
|
|
28457
28722
|
` + body.slice(m[0].length);
|
|
28458
28723
|
}
|
|
28459
|
-
var indexLine = (
|
|
28724
|
+
var indexLine = (path47, title, date, tags) => `- \`${path47}\` \u2014 **${title}**: ${title}. (${date} \xB7 ${tags.join(", ")})`;
|
|
28460
28725
|
function splitIndex(index) {
|
|
28461
28726
|
const all = index.split("\n");
|
|
28462
28727
|
const firstLineIdx = all.findIndex((l) => l.startsWith("- `memory/"));
|
|
@@ -28629,16 +28894,16 @@ function defaultDreamSeams(opts = {}) {
|
|
|
28629
28894
|
const mem = await memory(deps.brain);
|
|
28630
28895
|
const harvested = harvestedIds(input);
|
|
28631
28896
|
const ctx = { readFile: (p) => deps.brain.readFile(p), at: deps.clock() };
|
|
28632
|
-
const lookup = (
|
|
28897
|
+
const lookup = (path47) => Promise.resolve(mem.files.find((f) => f.path === path47) ?? null);
|
|
28633
28898
|
const digest = [...pendingRejected];
|
|
28634
28899
|
let changes = [];
|
|
28635
28900
|
let indexEdit;
|
|
28636
28901
|
try {
|
|
28637
28902
|
for (const raw of deltas) {
|
|
28638
28903
|
const delta = forcePolicyQuarantine(raw);
|
|
28639
|
-
const
|
|
28640
|
-
if (!
|
|
28641
|
-
digest.push(
|
|
28904
|
+
const path47 = checkPathAllowed(delta);
|
|
28905
|
+
if (!path47.ok) {
|
|
28906
|
+
digest.push(path47.rejected);
|
|
28642
28907
|
continue;
|
|
28643
28908
|
}
|
|
28644
28909
|
const ev = checkEvidenceMembership(delta, harvested);
|
|
@@ -29005,28 +29270,28 @@ function redactTranscripts(input) {
|
|
|
29005
29270
|
}
|
|
29006
29271
|
var DreamRunCommand = class extends M8tCommand {
|
|
29007
29272
|
static paths = [["dream", "run"]];
|
|
29008
|
-
static usage =
|
|
29273
|
+
static usage = Command53.Usage({
|
|
29009
29274
|
description: "Dry-run the brain consumption pipeline for one worker (no model call, no writes). Pass --live to actually run it.",
|
|
29010
29275
|
details: "Builds AzureCliCredential + resolves the Foundry project, ledger table, and Log Analytics workspace, runs the consumption pipeline, and prints the skip-ledger, the partition invariant, and harvest stats. Transcripts are metadata-only unless --show-transcripts is passed.\n\nThe bare command is READ-ONLY. --live takes the other branch: a real model call and a commit to the worker's brain repo through a minted GitHub App token."
|
|
29011
29276
|
});
|
|
29012
|
-
worker =
|
|
29277
|
+
worker = Option50.String("--worker", { description: "Worker (canonical name) to harvest. Required." });
|
|
29013
29278
|
// Opting IN to the side effects, rather than opting out of them. This command's
|
|
29014
29279
|
// own help has always described a dry run, but the bare invocation used to take
|
|
29015
29280
|
// the live branch — a real model call and a commit to the brain repo — so anyone
|
|
29016
29281
|
// acting on `--help` got the opposite of what they read.
|
|
29017
|
-
live =
|
|
29018
|
-
dryRun =
|
|
29019
|
-
since =
|
|
29020
|
-
reset =
|
|
29021
|
-
showTranscripts =
|
|
29282
|
+
live = Option50.Boolean("--live", false, { description: "Actually run it: model call + commit to the brain repo." });
|
|
29283
|
+
dryRun = Option50.Boolean("--dry-run", false, { description: "Read-only harvest. This is the default; the flag is accepted for compatibility." });
|
|
29284
|
+
since = Option50.String("--since", { description: "ISO-8601 start override (rejected if malformed or future)." });
|
|
29285
|
+
reset = Option50.Boolean("--reset", false, { description: "Ignore the stored cursor; read from the beginning." });
|
|
29286
|
+
showTranscripts = Option50.Boolean("--show-transcripts", false, {
|
|
29022
29287
|
description: "Print transcript bodies (default: metadata only)."
|
|
29023
29288
|
});
|
|
29024
|
-
subscription =
|
|
29025
|
-
endpoint =
|
|
29026
|
-
storageAccount =
|
|
29289
|
+
subscription = Option50.String("--subscription");
|
|
29290
|
+
endpoint = Option50.String("--endpoint");
|
|
29291
|
+
storageAccount = Option50.String("--storage-account", {
|
|
29027
29292
|
description: "Ledger storage account name (skips tag-based discovery)"
|
|
29028
29293
|
});
|
|
29029
|
-
output =
|
|
29294
|
+
output = Option50.String("--output");
|
|
29030
29295
|
// Resolution seam — overridden by tests; built lazily at runtime otherwise.
|
|
29031
29296
|
deps;
|
|
29032
29297
|
async executeCommand() {
|
|
@@ -29377,7 +29642,7 @@ function defaultDeps(overrides) {
|
|
|
29377
29642
|
|
|
29378
29643
|
// src/commands/conversations/sweep.ts
|
|
29379
29644
|
import { createHash as createHash4 } from "crypto";
|
|
29380
|
-
import { Command as
|
|
29645
|
+
import { Command as Command54, Option as Option51 } from "clipanion";
|
|
29381
29646
|
import { AzureCliCredential as AzureCliCredential2 } from "@azure/identity";
|
|
29382
29647
|
import { TableClient as TableClient8 } from "@azure/data-tables";
|
|
29383
29648
|
import { AIProjectClient as AIProjectClient4 } from "@azure/ai-projects";
|
|
@@ -29503,7 +29768,7 @@ function defaultDeps2() {
|
|
|
29503
29768
|
}
|
|
29504
29769
|
var ConversationsSweepCommand = class extends M8tCommand {
|
|
29505
29770
|
static paths = [["conversations", "sweep"]];
|
|
29506
|
-
static usage =
|
|
29771
|
+
static usage = Command54.Usage({
|
|
29507
29772
|
category: "Conversations",
|
|
29508
29773
|
description: "Delete expired public-visitor conversations (dry run by default)",
|
|
29509
29774
|
details: `
|
|
@@ -29519,22 +29784,22 @@ var ConversationsSweepCommand = class extends M8tCommand {
|
|
|
29519
29784
|
["Delete, capped at 50", "m8t conversations sweep --delete --max 50"]
|
|
29520
29785
|
]
|
|
29521
29786
|
});
|
|
29522
|
-
doDelete =
|
|
29787
|
+
doDelete = Option51.Boolean("--delete", false, {
|
|
29523
29788
|
description: "Perform deletions (without this flag the command only reports)"
|
|
29524
29789
|
});
|
|
29525
|
-
principal =
|
|
29790
|
+
principal = Option51.String("--principal", {
|
|
29526
29791
|
description: "Service-principal oid whose end-user keys are known-ephemeral (required with --delete; a dry run without it reports candidates grouped by principal)"
|
|
29527
29792
|
});
|
|
29528
|
-
max =
|
|
29529
|
-
graceDays =
|
|
29793
|
+
max = Option51.String("--max", "200", { description: "Maximum deletions per run" });
|
|
29794
|
+
graceDays = Option51.String("--grace-days", "14", {
|
|
29530
29795
|
description: "Days past the 30-day key life before a conversation is eligible"
|
|
29531
29796
|
});
|
|
29532
|
-
lookbackDays =
|
|
29797
|
+
lookbackDays = Option51.String("--lookback-days", "180", {
|
|
29533
29798
|
description: "How far back to scan ledger activity for candidates"
|
|
29534
29799
|
});
|
|
29535
|
-
subscription =
|
|
29536
|
-
endpoint =
|
|
29537
|
-
storageAccount =
|
|
29800
|
+
subscription = Option51.String("--subscription", { description: "Azure subscription id override" });
|
|
29801
|
+
endpoint = Option51.String("--endpoint", { description: "Foundry project endpoint override" });
|
|
29802
|
+
storageAccount = Option51.String("--storage-account", {
|
|
29538
29803
|
description: "Ledger storage account name (skips tag-based discovery)"
|
|
29539
29804
|
});
|
|
29540
29805
|
deps = defaultDeps2();
|
|
@@ -29662,7 +29927,7 @@ var ConversationsSweepCommand = class extends M8tCommand {
|
|
|
29662
29927
|
};
|
|
29663
29928
|
|
|
29664
29929
|
// src/commands/foundry/create.ts
|
|
29665
|
-
import { Command as
|
|
29930
|
+
import { Command as Command55, Option as Option52 } from "clipanion";
|
|
29666
29931
|
|
|
29667
29932
|
// src/lib/foundry-create.ts
|
|
29668
29933
|
init_errors();
|
|
@@ -29900,7 +30165,7 @@ async function createFoundryProject(args) {
|
|
|
29900
30165
|
init_errors();
|
|
29901
30166
|
var FoundryCreateCommand = class extends M8tCommand {
|
|
29902
30167
|
static paths = [["foundry", "create"]];
|
|
29903
|
-
static usage =
|
|
30168
|
+
static usage = Command55.Usage({
|
|
29904
30169
|
description: "Create an AI Foundry (AIServices) account + project + model deployment from scratch.",
|
|
29905
30170
|
details: "Non-interactive and idempotent. Creates the AIServices account (custom subdomain + project management), a project, and a model deployment (default gpt-4.1-mini @ capacity 50). Region must be hosted-agent-eligible. Emits the project endpoint as structured output. Re-run is a clean no-op (account/project skipped if present; deployment capacity converges UP, never down).",
|
|
29906
30171
|
examples: [
|
|
@@ -29909,16 +30174,16 @@ var FoundryCreateCommand = class extends M8tCommand {
|
|
|
29909
30174
|
["Higher capacity for a reasoning model", "$0 foundry create --resource-group rg-m8t-stack --location eastus2 --model gpt-5-mini --capacity 250"]
|
|
29910
30175
|
]
|
|
29911
30176
|
});
|
|
29912
|
-
resourceGroup =
|
|
29913
|
-
location =
|
|
29914
|
-
account =
|
|
29915
|
-
project =
|
|
29916
|
-
model =
|
|
29917
|
-
modelVersion =
|
|
29918
|
-
capacity =
|
|
29919
|
-
subscription =
|
|
29920
|
-
skipQuotaCheck =
|
|
29921
|
-
output =
|
|
30177
|
+
resourceGroup = Option52.String("--resource-group");
|
|
30178
|
+
location = Option52.String("--location");
|
|
30179
|
+
account = Option52.String("--account");
|
|
30180
|
+
project = Option52.String("--project", "m8t");
|
|
30181
|
+
model = Option52.String("--model", "gpt-4.1-mini");
|
|
30182
|
+
modelVersion = Option52.String("--model-version", "2025-04-14");
|
|
30183
|
+
capacity = Option52.String("--capacity", "50");
|
|
30184
|
+
subscription = Option52.String("--subscription");
|
|
30185
|
+
skipQuotaCheck = Option52.Boolean("--skip-quota-check", false);
|
|
30186
|
+
output = Option52.String("--output");
|
|
29922
30187
|
async executeCommand() {
|
|
29923
30188
|
const mode = resolveOutputMode(
|
|
29924
30189
|
this.output,
|
|
@@ -29990,22 +30255,22 @@ var FoundryCreateCommand = class extends M8tCommand {
|
|
|
29990
30255
|
};
|
|
29991
30256
|
|
|
29992
30257
|
// src/commands/foundry/await-ready.ts
|
|
29993
|
-
import { Command as
|
|
30258
|
+
import { Command as Command56, Option as Option53 } from "clipanion";
|
|
29994
30259
|
import { AzureCliCredential as AzureCliCredential3 } from "@azure/identity";
|
|
29995
30260
|
init_errors();
|
|
29996
30261
|
var FoundryAwaitReadyCommand = class extends M8tCommand {
|
|
29997
30262
|
static paths = [["foundry", "await-ready"]];
|
|
29998
|
-
static usage =
|
|
30263
|
+
static usage = Command56.Usage({
|
|
29999
30264
|
description: "Wait until a freshly-created Foundry project's data plane reliably serves it.",
|
|
30000
30265
|
details: "Probes the project (GET /agents) until it returns 200 on a few consecutive tries, or fails clearly after a bounded budget. A newly-created account can serve intermittent 404 'Project not found' for minutes; run this after 'foundry create' and before deploying agents so the worker phase doesn't catch the unstable window.",
|
|
30001
30266
|
examples: [["Wait for a project to be ready", "$0 foundry await-ready --endpoint https://acc.services.ai.azure.com/api/projects/m8t"]]
|
|
30002
30267
|
});
|
|
30003
|
-
endpoint =
|
|
30004
|
-
consecutive =
|
|
30005
|
-
attempts =
|
|
30006
|
-
interval =
|
|
30007
|
-
subscription =
|
|
30008
|
-
output =
|
|
30268
|
+
endpoint = Option53.String("--endpoint");
|
|
30269
|
+
consecutive = Option53.String("--consecutive", "3");
|
|
30270
|
+
attempts = Option53.String("--attempts", "60");
|
|
30271
|
+
interval = Option53.String("--interval", "5");
|
|
30272
|
+
subscription = Option53.String("--subscription");
|
|
30273
|
+
output = Option53.String("--output");
|
|
30009
30274
|
async executeCommand() {
|
|
30010
30275
|
const mode = resolveOutputMode(this.output, this.context.stdout);
|
|
30011
30276
|
const endpoint = typeof this.endpoint === "string" ? this.endpoint : void 0;
|
|
@@ -30039,7 +30304,7 @@ var FoundryAwaitReadyCommand = class extends M8tCommand {
|
|
|
30039
30304
|
};
|
|
30040
30305
|
|
|
30041
30306
|
// src/commands/bootstrap/preflight.ts
|
|
30042
|
-
import { Command as
|
|
30307
|
+
import { Command as Command57, Option as Option54 } from "clipanion";
|
|
30043
30308
|
|
|
30044
30309
|
// ../../packages/telemetry-contract/artifact/tier-map.ts
|
|
30045
30310
|
var EVENT_TIERS = {
|
|
@@ -30065,9 +30330,9 @@ var DISCLOSURE_TIER1 = "Operational data. To support your installation, m8t rece
|
|
|
30065
30330
|
|
|
30066
30331
|
// ../../packages/telemetry-contract/src/endpoints.ts
|
|
30067
30332
|
var INGEST_BASE_URL = (process.env.M8T_INGEST_BASE_URL ?? "").trim() || "https://m8t-admin.wonderfuldesert-721e332f.eastus2.azurecontainerapps.io";
|
|
30068
|
-
function ingestUrl(
|
|
30333
|
+
function ingestUrl(path47) {
|
|
30069
30334
|
const base = INGEST_BASE_URL.replace(/\/+$/, "");
|
|
30070
|
-
return `${base}${
|
|
30335
|
+
return `${base}${path47.startsWith("/") ? path47 : `/${path47}`}`;
|
|
30071
30336
|
}
|
|
30072
30337
|
|
|
30073
30338
|
// src/commands/bootstrap/preflight.ts
|
|
@@ -30091,7 +30356,7 @@ function preflightRenderable(results) {
|
|
|
30091
30356
|
}
|
|
30092
30357
|
var BootstrapPreflightCommand = class extends M8tCommand {
|
|
30093
30358
|
static paths = [["bootstrap", "preflight"]];
|
|
30094
|
-
static usage =
|
|
30359
|
+
static usage = Command57.Usage({
|
|
30095
30360
|
description: "Loudly verify you can install m8t (Owner/UAA + directory admin) and hard-stop if not.",
|
|
30096
30361
|
details: "Step 1 of `m8t bootstrap`. Prints an unmissable admin-credentials notice, then checks: Owner or User Access Administrator at subscription scope (hard requirement), directory-admin capability to register the app (or pass --client-id), every Azure resource provider the install uses (registering any that are missing), soft-deleted Cognitive Services accounts (they keep their model quota until purged, so quota can read free and the model deployment still fail), and \u2014 with --location \u2014 model quota in the target region. Exits non-zero with the exact failing check + remedy. `m8t prereqs` runs the same substrate checks on their own.",
|
|
30097
30362
|
examples: [
|
|
@@ -30100,9 +30365,9 @@ var BootstrapPreflightCommand = class extends M8tCommand {
|
|
|
30100
30365
|
["BYO app registration (directory guests)", "$0 bootstrap preflight --client-id <appId>"]
|
|
30101
30366
|
]
|
|
30102
30367
|
});
|
|
30103
|
-
clientId =
|
|
30104
|
-
subscription =
|
|
30105
|
-
location =
|
|
30368
|
+
clientId = Option54.String("--client-id");
|
|
30369
|
+
subscription = Option54.String("--subscription");
|
|
30370
|
+
location = Option54.String("--location", {
|
|
30106
30371
|
description: "Target region. Enables the model-quota check \u2014 without it, quota is not verified."
|
|
30107
30372
|
});
|
|
30108
30373
|
async executeCommand() {
|
|
@@ -30199,10 +30464,10 @@ ${colors.error(" " + why)}
|
|
|
30199
30464
|
}
|
|
30200
30465
|
|
|
30201
30466
|
// src/commands/bootstrap/launch.ts
|
|
30202
|
-
import * as
|
|
30467
|
+
import * as fs34 from "fs";
|
|
30203
30468
|
import * as os15 from "os";
|
|
30204
|
-
import * as
|
|
30205
|
-
import { Command as
|
|
30469
|
+
import * as path37 from "path";
|
|
30470
|
+
import { Command as Command58, Option as Option55 } from "clipanion";
|
|
30206
30471
|
init_errors();
|
|
30207
30472
|
|
|
30208
30473
|
// src/lib/bootstrap-mi.ts
|
|
@@ -30358,9 +30623,9 @@ async function kickInstaller(s) {
|
|
|
30358
30623
|
|
|
30359
30624
|
// src/lib/bootstrap-status.ts
|
|
30360
30625
|
import { createHash as createHash6, randomUUID as randomUUID2 } from "crypto";
|
|
30361
|
-
import * as
|
|
30626
|
+
import * as fs32 from "fs/promises";
|
|
30362
30627
|
import * as os13 from "os";
|
|
30363
|
-
import * as
|
|
30628
|
+
import * as path35 from "path";
|
|
30364
30629
|
init_errors();
|
|
30365
30630
|
var STATUS_CONTAINER = "status";
|
|
30366
30631
|
var STATUS_BLOB = "status.json";
|
|
@@ -30399,7 +30664,7 @@ async function readStatusBlob(opts) {
|
|
|
30399
30664
|
cause: e
|
|
30400
30665
|
});
|
|
30401
30666
|
}
|
|
30402
|
-
const tmpFile =
|
|
30667
|
+
const tmpFile = path35.join(os13.tmpdir(), `m8t-status-${randomUUID2()}.json`);
|
|
30403
30668
|
try {
|
|
30404
30669
|
await runAz([
|
|
30405
30670
|
"storage",
|
|
@@ -30418,7 +30683,7 @@ async function readStatusBlob(opts) {
|
|
|
30418
30683
|
"--no-progress",
|
|
30419
30684
|
"--only-show-errors"
|
|
30420
30685
|
]);
|
|
30421
|
-
const raw = await
|
|
30686
|
+
const raw = await fs32.readFile(tmpFile, "utf8");
|
|
30422
30687
|
return JSON.parse(raw.trim());
|
|
30423
30688
|
} catch (e) {
|
|
30424
30689
|
throw new LocalCliError({
|
|
@@ -30428,23 +30693,23 @@ async function readStatusBlob(opts) {
|
|
|
30428
30693
|
cause: e
|
|
30429
30694
|
});
|
|
30430
30695
|
} finally {
|
|
30431
|
-
await
|
|
30696
|
+
await fs32.rm(tmpFile, { force: true });
|
|
30432
30697
|
}
|
|
30433
30698
|
}
|
|
30434
30699
|
|
|
30435
30700
|
// src/lib/bootstrap-state.ts
|
|
30436
|
-
import * as
|
|
30701
|
+
import * as fs33 from "fs/promises";
|
|
30437
30702
|
import * as os14 from "os";
|
|
30438
|
-
import * as
|
|
30703
|
+
import * as path36 from "path";
|
|
30439
30704
|
function stateDir(home) {
|
|
30440
|
-
return
|
|
30705
|
+
return path36.join(home, ".m8t");
|
|
30441
30706
|
}
|
|
30442
30707
|
function statePath(home) {
|
|
30443
|
-
return
|
|
30708
|
+
return path36.join(stateDir(home), "bootstrap.json");
|
|
30444
30709
|
}
|
|
30445
30710
|
async function readBootstrapState(home = os14.homedir()) {
|
|
30446
30711
|
try {
|
|
30447
|
-
const raw = await
|
|
30712
|
+
const raw = await fs33.readFile(statePath(home), "utf8");
|
|
30448
30713
|
return JSON.parse(raw);
|
|
30449
30714
|
} catch (e) {
|
|
30450
30715
|
if (e.code === "ENOENT") return null;
|
|
@@ -30452,10 +30717,10 @@ async function readBootstrapState(home = os14.homedir()) {
|
|
|
30452
30717
|
}
|
|
30453
30718
|
}
|
|
30454
30719
|
async function writeBootstrapState(state, home = os14.homedir()) {
|
|
30455
|
-
await
|
|
30720
|
+
await fs33.mkdir(stateDir(home), { recursive: true });
|
|
30456
30721
|
const tmp = `${statePath(home)}.tmp`;
|
|
30457
|
-
await
|
|
30458
|
-
await
|
|
30722
|
+
await fs33.writeFile(tmp, JSON.stringify(state, null, 2), "utf8");
|
|
30723
|
+
await fs33.rename(tmp, statePath(home));
|
|
30459
30724
|
}
|
|
30460
30725
|
|
|
30461
30726
|
// src/lib/bootstrap-occupancy.ts
|
|
@@ -30572,7 +30837,7 @@ var ACI_NAME = "m8t-installer";
|
|
|
30572
30837
|
var MI_NAME = "m8t-installer-mi";
|
|
30573
30838
|
var BootstrapLaunchCommand = class extends M8tCommand {
|
|
30574
30839
|
static paths = [["bootstrap", "launch"]];
|
|
30575
|
-
static usage =
|
|
30840
|
+
static usage = Command58.Usage({
|
|
30576
30841
|
description: "Create + authorize the installer managed identity, then kick the cloud installer.",
|
|
30577
30842
|
details: "Step 2 of `m8t bootstrap` (run after `preflight`). Ensures the resource group, creates the m8t app registration (or uses --client-id), creates a user-assigned managed identity granted Owner at subscription scope, and launches the published m8t-installer image as an ACI run-to-completion job under that identity. Writes ~/.m8t/bootstrap.json for `status` and `reap`, and threads your Azure object id so the installer can grant you the platform's data-plane roles itself.",
|
|
30578
30843
|
examples: [
|
|
@@ -30583,26 +30848,26 @@ var BootstrapLaunchCommand = class extends M8tCommand {
|
|
|
30583
30848
|
["Share a support contact", "$0 bootstrap launch --location eastus2 --contact-email you@example.com --company 'Acme'"]
|
|
30584
30849
|
]
|
|
30585
30850
|
});
|
|
30586
|
-
location =
|
|
30587
|
-
resourceGroup =
|
|
30588
|
-
clientId =
|
|
30589
|
-
subscription =
|
|
30590
|
-
installerTag =
|
|
30851
|
+
location = Option55.String("--location");
|
|
30852
|
+
resourceGroup = Option55.String("--resource-group");
|
|
30853
|
+
clientId = Option55.String("--client-id");
|
|
30854
|
+
subscription = Option55.String("--subscription");
|
|
30855
|
+
installerTag = Option55.String("--installer-tag");
|
|
30591
30856
|
// Full image ref override (registry + repo + tag) — an escape hatch when the
|
|
30592
30857
|
// default org/tag is wrong for the current CLI (e.g. a stale published build).
|
|
30593
30858
|
// Wins over --installer-tag / the pinned default.
|
|
30594
|
-
installerImage =
|
|
30595
|
-
gatewayImageRef =
|
|
30596
|
-
githubAppCreds =
|
|
30597
|
-
contactEmail =
|
|
30598
|
-
company =
|
|
30859
|
+
installerImage = Option55.String("--installer-image");
|
|
30860
|
+
gatewayImageRef = Option55.String("--gateway-image-ref");
|
|
30861
|
+
githubAppCreds = Option55.String("--github-app-creds");
|
|
30862
|
+
contactEmail = Option55.String("--contact-email", { description: "Share a contact email with m8t support. Not sent unless you pass it." });
|
|
30863
|
+
company = Option55.String("--company", { description: "Share your company name with m8t support. Not sent unless you pass it." });
|
|
30599
30864
|
// Value-carrying on purpose: a bare --force would be cargo-culted into
|
|
30600
30865
|
// runbooks and harness prompts and erode the protection, whereas a faithful
|
|
30601
30866
|
// paste can never accidentally carry the victim group's name. It AUTHORIZES
|
|
30602
30867
|
// the target; --resource-group is what CHOOSES it.
|
|
30603
|
-
reinstallInto =
|
|
30604
|
-
org =
|
|
30605
|
-
noBrains =
|
|
30868
|
+
reinstallInto = Option55.String("--reinstall-into", { description: "Consent to installing into --resource-group even though it already holds resources. Must match the target group's name." });
|
|
30869
|
+
org = Option55.String("--org", { description: "Assert the GitHub App on disk is installed on this org; refuses on a mismatch." });
|
|
30870
|
+
noBrains = Option55.Boolean("--no-brains", false, { description: "Install without brain-backed workers. For test and CI rigs; the supported install creates brains." });
|
|
30606
30871
|
async executeCommand() {
|
|
30607
30872
|
const location = typeof this.location === "string" ? this.location : void 0;
|
|
30608
30873
|
if (!location) {
|
|
@@ -30641,13 +30906,13 @@ var BootstrapLaunchCommand = class extends M8tCommand {
|
|
|
30641
30906
|
`);
|
|
30642
30907
|
return 0;
|
|
30643
30908
|
}
|
|
30644
|
-
const credsPath = typeof this.githubAppCreds === "string" ? this.githubAppCreds :
|
|
30909
|
+
const credsPath = typeof this.githubAppCreds === "string" ? this.githubAppCreds : path37.join(os15.homedir(), ".m8t", "github-app.json");
|
|
30645
30910
|
const skipBrains = this.noBrains === true;
|
|
30646
30911
|
const requestedOrg = typeof this.org === "string" ? this.org : void 0;
|
|
30647
30912
|
let githubApp;
|
|
30648
30913
|
if (skipBrains) {
|
|
30649
30914
|
out("installing without brain-backed workers; no GitHub App credentials will be used");
|
|
30650
|
-
} else if (!
|
|
30915
|
+
} else if (!fs34.existsSync(credsPath)) {
|
|
30651
30916
|
this.context.stderr.write(buildMissingCredsRefusal(credsPath));
|
|
30652
30917
|
throw new LocalCliError({
|
|
30653
30918
|
code: "GITHUB_APP_CREDS_MISSING",
|
|
@@ -30657,7 +30922,7 @@ var BootstrapLaunchCommand = class extends M8tCommand {
|
|
|
30657
30922
|
} else {
|
|
30658
30923
|
let parsed;
|
|
30659
30924
|
try {
|
|
30660
|
-
parsed = JSON.parse(
|
|
30925
|
+
parsed = JSON.parse(fs34.readFileSync(credsPath, "utf8"));
|
|
30661
30926
|
} catch {
|
|
30662
30927
|
throw new LocalCliError({
|
|
30663
30928
|
code: "GITHUB_APP_CREDS_INVALID",
|
|
@@ -30675,7 +30940,7 @@ var BootstrapLaunchCommand = class extends M8tCommand {
|
|
|
30675
30940
|
}
|
|
30676
30941
|
let pem;
|
|
30677
30942
|
try {
|
|
30678
|
-
pem =
|
|
30943
|
+
pem = fs34.readFileSync(parsed.pemPath, "utf8");
|
|
30679
30944
|
} catch {
|
|
30680
30945
|
throw new LocalCliError({
|
|
30681
30946
|
code: "GITHUB_APP_PEM_MISSING",
|
|
@@ -30763,7 +31028,7 @@ var BootstrapLaunchCommand = class extends M8tCommand {
|
|
|
30763
31028
|
};
|
|
30764
31029
|
|
|
30765
31030
|
// src/commands/bootstrap/status.ts
|
|
30766
|
-
import { Command as
|
|
31031
|
+
import { Command as Command60, Option as Option57 } from "clipanion";
|
|
30767
31032
|
init_errors();
|
|
30768
31033
|
|
|
30769
31034
|
// src/lib/bootstrap-aci-state.ts
|
|
@@ -30789,15 +31054,15 @@ async function getAciState(opts) {
|
|
|
30789
31054
|
}
|
|
30790
31055
|
|
|
30791
31056
|
// src/lib/bootstrap-finalize.ts
|
|
30792
|
-
import * as
|
|
31057
|
+
import * as fs38 from "fs/promises";
|
|
30793
31058
|
import * as os19 from "os";
|
|
30794
|
-
import * as
|
|
31059
|
+
import * as path43 from "path";
|
|
30795
31060
|
|
|
30796
31061
|
// src/lib/company-profile-seed.ts
|
|
30797
31062
|
import { spawn as spawn6 } from "child_process";
|
|
30798
|
-
import { closeSync, openSync, readFileSync as
|
|
31063
|
+
import { closeSync, openSync, readFileSync as readFileSync24 } from "fs";
|
|
30799
31064
|
import * as os16 from "os";
|
|
30800
|
-
import * as
|
|
31065
|
+
import * as path38 from "path";
|
|
30801
31066
|
init_errors();
|
|
30802
31067
|
|
|
30803
31068
|
// src/lib/onboarding-profile.ts
|
|
@@ -31522,9 +31787,9 @@ function composeFounderIdentityNote(id) {
|
|
|
31522
31787
|
|
|
31523
31788
|
// src/lib/company-profile-seed.ts
|
|
31524
31789
|
function readGithubAppCreds(credsPath) {
|
|
31525
|
-
const p = credsPath ??
|
|
31790
|
+
const p = credsPath ?? path38.join(os16.homedir(), ".m8t", "github-app.json");
|
|
31526
31791
|
try {
|
|
31527
|
-
return JSON.parse(
|
|
31792
|
+
return JSON.parse(readFileSync24(p, "utf8"));
|
|
31528
31793
|
} catch {
|
|
31529
31794
|
return null;
|
|
31530
31795
|
}
|
|
@@ -31593,7 +31858,7 @@ function upsertMemoryIndexOnce(existing, line2, targetPath2) {
|
|
|
31593
31858
|
async function applyProfileToBrain(args) {
|
|
31594
31859
|
const token = await mintInstallationTokenFromPem({
|
|
31595
31860
|
appId: args.appCreds.appId,
|
|
31596
|
-
privateKeyPem:
|
|
31861
|
+
privateKeyPem: readFileSync24(args.appCreds.pemPath, "utf8"),
|
|
31597
31862
|
installationId: args.appCreds.installationId,
|
|
31598
31863
|
fetchImpl: args.fetchImpl
|
|
31599
31864
|
});
|
|
@@ -31683,7 +31948,7 @@ async function applyProfileToBrains(args) {
|
|
|
31683
31948
|
}
|
|
31684
31949
|
}
|
|
31685
31950
|
function spawnDetachedSeedWatch() {
|
|
31686
|
-
const logPath =
|
|
31951
|
+
const logPath = path38.join(os16.homedir(), ".m8t", "seed-profile.log");
|
|
31687
31952
|
const fd = openSync(logPath, "a");
|
|
31688
31953
|
try {
|
|
31689
31954
|
const child = spawn6(process.execPath, [process.argv[1] ?? "", "bootstrap", "seed-profile", "--watch"], {
|
|
@@ -31761,16 +32026,16 @@ function renderInstallSummary(args) {
|
|
|
31761
32026
|
|
|
31762
32027
|
// src/lib/companion-install.ts
|
|
31763
32028
|
import { constants as constants2 } from "fs";
|
|
31764
|
-
import * as
|
|
31765
|
-
import * as
|
|
32029
|
+
import * as fs36 from "fs/promises";
|
|
32030
|
+
import * as path40 from "path";
|
|
31766
32031
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
31767
32032
|
import { execFile, spawn as spawn7 } from "child_process";
|
|
31768
32033
|
|
|
31769
32034
|
// src/lib/companion-artifact.ts
|
|
31770
32035
|
import { createHash as createHash7 } from "crypto";
|
|
31771
32036
|
import { constants } from "fs";
|
|
31772
|
-
import * as
|
|
31773
|
-
import * as
|
|
32037
|
+
import * as fs35 from "fs/promises";
|
|
32038
|
+
import * as path39 from "path";
|
|
31774
32039
|
var SHA256 = /^[a-f0-9]{64}$/u;
|
|
31775
32040
|
var VERSION2 = /^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$/u;
|
|
31776
32041
|
function exactKeys(value, expected) {
|
|
@@ -31778,23 +32043,23 @@ function exactKeys(value, expected) {
|
|
|
31778
32043
|
return actual.length === expected.length && actual.every((key2, index) => key2 === [...expected].sort()[index]);
|
|
31779
32044
|
}
|
|
31780
32045
|
function normalizedRelative(value) {
|
|
31781
|
-
if (value.length === 0 || value.includes("\\") || value.includes("\0") ||
|
|
32046
|
+
if (value.length === 0 || value.includes("\\") || value.includes("\0") || path39.posix.isAbsolute(value)) {
|
|
31782
32047
|
throw new Error("Artifact path must be a normalized relative POSIX path");
|
|
31783
32048
|
}
|
|
31784
|
-
const normalized =
|
|
32049
|
+
const normalized = path39.posix.normalize(value);
|
|
31785
32050
|
if (normalized !== value || normalized === "." || normalized === ".." || normalized.startsWith("../")) {
|
|
31786
32051
|
throw new Error("Artifact path escapes the payload root");
|
|
31787
32052
|
}
|
|
31788
32053
|
return value;
|
|
31789
32054
|
}
|
|
31790
32055
|
function validateLink(entryPath, target) {
|
|
31791
|
-
if (target.length === 0 || target.includes("\\") || target.includes("\0") ||
|
|
32056
|
+
if (target.length === 0 || target.includes("\\") || target.includes("\0") || path39.posix.isAbsolute(target)) {
|
|
31792
32057
|
throw new Error("Artifact symlink target must be relative");
|
|
31793
32058
|
}
|
|
31794
|
-
const resolved =
|
|
31795
|
-
|
|
32059
|
+
const resolved = path39.posix.normalize(
|
|
32060
|
+
path39.posix.join(path39.posix.dirname(entryPath), target)
|
|
31796
32061
|
);
|
|
31797
|
-
if (resolved === ".." || resolved.startsWith("../") ||
|
|
32062
|
+
if (resolved === ".." || resolved.startsWith("../") || path39.posix.isAbsolute(resolved)) {
|
|
31798
32063
|
throw new Error("Artifact symlink target escapes the payload root");
|
|
31799
32064
|
}
|
|
31800
32065
|
return target;
|
|
@@ -31875,17 +32140,17 @@ function parseArtifactManifest(value) {
|
|
|
31875
32140
|
};
|
|
31876
32141
|
}
|
|
31877
32142
|
async function sha256File2(filePath) {
|
|
31878
|
-
return createHash7("sha256").update(await
|
|
32143
|
+
return createHash7("sha256").update(await fs35.readFile(filePath)).digest("hex");
|
|
31879
32144
|
}
|
|
31880
32145
|
async function walk2(root, relative4 = "") {
|
|
31881
|
-
const directory =
|
|
31882
|
-
const children = await
|
|
32146
|
+
const directory = path39.join(root, ...relative4.split("/").filter(Boolean));
|
|
32147
|
+
const children = await fs35.readdir(directory, { withFileTypes: true });
|
|
31883
32148
|
const entries = [];
|
|
31884
32149
|
for (const child of children.sort((left, right) => left.name.localeCompare(right.name))) {
|
|
31885
32150
|
const childRelative = relative4 ? `${relative4}/${child.name}` : child.name;
|
|
31886
32151
|
normalizedRelative(childRelative);
|
|
31887
|
-
const childPath =
|
|
31888
|
-
const stat5 = await
|
|
32152
|
+
const childPath = path39.join(directory, child.name);
|
|
32153
|
+
const stat5 = await fs35.lstat(childPath);
|
|
31889
32154
|
if (stat5.isDirectory()) {
|
|
31890
32155
|
entries.push(...await walk2(root, childRelative));
|
|
31891
32156
|
} else if (stat5.isFile()) {
|
|
@@ -31897,7 +32162,7 @@ async function walk2(root, relative4 = "") {
|
|
|
31897
32162
|
sha256: await sha256File2(childPath)
|
|
31898
32163
|
});
|
|
31899
32164
|
} else if (stat5.isSymbolicLink()) {
|
|
31900
|
-
const target = await
|
|
32165
|
+
const target = await fs35.readlink(childPath);
|
|
31901
32166
|
entries.push({
|
|
31902
32167
|
type: "symlink",
|
|
31903
32168
|
path: childRelative,
|
|
@@ -31910,19 +32175,19 @@ async function walk2(root, relative4 = "") {
|
|
|
31910
32175
|
return entries;
|
|
31911
32176
|
}
|
|
31912
32177
|
async function ensureRealDirectory(root) {
|
|
31913
|
-
const stat5 = await
|
|
32178
|
+
const stat5 = await fs35.lstat(root);
|
|
31914
32179
|
if (stat5.isSymbolicLink()) throw new Error("Artifact root is a symbolic link");
|
|
31915
32180
|
if (!stat5.isDirectory()) throw new Error("Artifact root is not a directory");
|
|
31916
32181
|
}
|
|
31917
32182
|
async function validateResolvedLinks(root, entries) {
|
|
31918
|
-
const realRoot = await
|
|
32183
|
+
const realRoot = await fs35.realpath(root);
|
|
31919
32184
|
for (const entry of entries) {
|
|
31920
32185
|
if (entry.type !== "symlink") continue;
|
|
31921
32186
|
try {
|
|
31922
|
-
const linkPath =
|
|
31923
|
-
const resolved = await
|
|
31924
|
-
const relative4 =
|
|
31925
|
-
if (relative4 === ".." || relative4.startsWith(`..${
|
|
32187
|
+
const linkPath = path39.join(root, ...entry.path.split("/"));
|
|
32188
|
+
const resolved = await fs35.realpath(linkPath);
|
|
32189
|
+
const relative4 = path39.relative(realRoot, resolved);
|
|
32190
|
+
if (relative4 === ".." || relative4.startsWith(`..${path39.sep}`) || path39.isAbsolute(relative4)) {
|
|
31926
32191
|
throw new Error("Artifact symlink chain escapes the payload root");
|
|
31927
32192
|
}
|
|
31928
32193
|
} catch (error) {
|
|
@@ -31952,13 +32217,13 @@ async function buildArtifactManifest(payloadRoot, input) {
|
|
|
31952
32217
|
return manifest;
|
|
31953
32218
|
}
|
|
31954
32219
|
async function readArtifactManifest(manifestPath) {
|
|
31955
|
-
const before = await
|
|
32220
|
+
const before = await fs35.lstat(manifestPath);
|
|
31956
32221
|
if (before.isSymbolicLink() || !before.isFile()) {
|
|
31957
32222
|
throw new Error("Artifact manifest is a symbolic link or non-file");
|
|
31958
32223
|
}
|
|
31959
32224
|
let handle;
|
|
31960
32225
|
try {
|
|
31961
|
-
handle = await
|
|
32226
|
+
handle = await fs35.open(
|
|
31962
32227
|
manifestPath,
|
|
31963
32228
|
constants.O_RDONLY | constants.O_NOFOLLOW
|
|
31964
32229
|
);
|
|
@@ -31975,9 +32240,9 @@ async function readArtifactManifest(manifestPath) {
|
|
|
31975
32240
|
}
|
|
31976
32241
|
}
|
|
31977
32242
|
function ensureContainedEntry(root, entryPath) {
|
|
31978
|
-
const absolute =
|
|
31979
|
-
const relative4 =
|
|
31980
|
-
if (relative4.startsWith("..") ||
|
|
32243
|
+
const absolute = path39.join(root, ...entryPath.split("/"));
|
|
32244
|
+
const relative4 = path39.relative(root, absolute);
|
|
32245
|
+
if (relative4.startsWith("..") || path39.isAbsolute(relative4)) {
|
|
31981
32246
|
throw new Error("Artifact entry escapes payload root");
|
|
31982
32247
|
}
|
|
31983
32248
|
return absolute;
|
|
@@ -32016,27 +32281,27 @@ async function verifyArtifactPayload(payloadRoot, manifest) {
|
|
|
32016
32281
|
async function copyArtifactPayload(sourceRoot, targetRoot, manifest) {
|
|
32017
32282
|
await verifyArtifactSource(sourceRoot, manifest);
|
|
32018
32283
|
try {
|
|
32019
|
-
const targetStat = await
|
|
32284
|
+
const targetStat = await fs35.lstat(targetRoot);
|
|
32020
32285
|
if (targetStat.isSymbolicLink()) {
|
|
32021
32286
|
throw new Error("Install target is a symbolic link");
|
|
32022
32287
|
}
|
|
32023
32288
|
if (!targetStat.isDirectory()) throw new Error("Install target is not a directory");
|
|
32024
|
-
if ((await
|
|
32289
|
+
if ((await fs35.readdir(targetRoot)).length > 0) {
|
|
32025
32290
|
throw new Error("Install staging target is not empty");
|
|
32026
32291
|
}
|
|
32027
32292
|
} catch (error) {
|
|
32028
32293
|
if (error.code !== "ENOENT") throw error;
|
|
32029
|
-
await
|
|
32294
|
+
await fs35.mkdir(targetRoot, { recursive: false, mode: 448 });
|
|
32030
32295
|
}
|
|
32031
32296
|
for (const entry of manifest.entries) {
|
|
32032
32297
|
const source = ensureContainedEntry(sourceRoot, entry.path);
|
|
32033
32298
|
const target = ensureContainedEntry(targetRoot, entry.path);
|
|
32034
|
-
await
|
|
32299
|
+
await fs35.mkdir(path39.dirname(target), { recursive: true, mode: 448 });
|
|
32035
32300
|
if (entry.type === "file") {
|
|
32036
|
-
await
|
|
32037
|
-
await
|
|
32301
|
+
await fs35.copyFile(source, target);
|
|
32302
|
+
await fs35.chmod(target, entry.mode);
|
|
32038
32303
|
} else {
|
|
32039
|
-
await
|
|
32304
|
+
await fs35.symlink(entry.target, target);
|
|
32040
32305
|
}
|
|
32041
32306
|
}
|
|
32042
32307
|
await verifyArtifactPayload(targetRoot, manifest);
|
|
@@ -32075,17 +32340,17 @@ function execFileOutput(file, args) {
|
|
|
32075
32340
|
}
|
|
32076
32341
|
async function setCompanionStartAtLogin(input) {
|
|
32077
32342
|
if (input.platform === "darwin") {
|
|
32078
|
-
const launchAgents =
|
|
32079
|
-
const registration =
|
|
32343
|
+
const launchAgents = path40.join(input.homeDirectory, "Library", "LaunchAgents");
|
|
32344
|
+
const registration = path40.join(
|
|
32080
32345
|
launchAgents,
|
|
32081
32346
|
"com.m8t.companion.plist"
|
|
32082
32347
|
);
|
|
32083
32348
|
await assertNotSymlink(registration, "Start-at-login registration");
|
|
32084
32349
|
if (!input.enabled) {
|
|
32085
|
-
await
|
|
32350
|
+
await fs36.rm(registration, { force: true });
|
|
32086
32351
|
return;
|
|
32087
32352
|
}
|
|
32088
|
-
await
|
|
32353
|
+
await fs36.mkdir(launchAgents, { recursive: true, mode: 448 });
|
|
32089
32354
|
const plist = '<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n<plist version="1.0"><dict><key>Label</key><string>com.m8t.companion</string><key>ProgramArguments</key><array><string>' + xmlEscape(input.executable) + "</string></array><key>RunAtLoad</key><true/></dict></plist>\n";
|
|
32090
32355
|
await atomicWriteText(registration, plist, 384);
|
|
32091
32356
|
return;
|
|
@@ -32137,7 +32402,7 @@ async function setCompanionStartAtLogin(input) {
|
|
|
32137
32402
|
}
|
|
32138
32403
|
async function getCompanionStartAtLogin(input) {
|
|
32139
32404
|
if (input.platform === "darwin") {
|
|
32140
|
-
const registration =
|
|
32405
|
+
const registration = path40.join(
|
|
32141
32406
|
input.homeDirectory,
|
|
32142
32407
|
"Library",
|
|
32143
32408
|
"LaunchAgents",
|
|
@@ -32199,26 +32464,26 @@ function assertSupported(options) {
|
|
|
32199
32464
|
}
|
|
32200
32465
|
function companionInstallPaths(options) {
|
|
32201
32466
|
assertSupported(options);
|
|
32202
|
-
const companionState =
|
|
32467
|
+
const companionState = path40.join(
|
|
32203
32468
|
options.homeDirectory,
|
|
32204
32469
|
".m8t",
|
|
32205
32470
|
"companion"
|
|
32206
32471
|
);
|
|
32207
|
-
const targetRoot = options.platform === "darwin" ?
|
|
32472
|
+
const targetRoot = options.platform === "darwin" ? path40.join(
|
|
32208
32473
|
options.homeDirectory,
|
|
32209
32474
|
"Applications",
|
|
32210
32475
|
"m8t Companion.app"
|
|
32211
|
-
) :
|
|
32212
|
-
options.localAppData ??
|
|
32476
|
+
) : path40.join(
|
|
32477
|
+
options.localAppData ?? path40.join(options.homeDirectory, "AppData", "Local"),
|
|
32213
32478
|
"m8t",
|
|
32214
32479
|
"companion",
|
|
32215
32480
|
"app"
|
|
32216
32481
|
);
|
|
32217
32482
|
return {
|
|
32218
32483
|
targetRoot,
|
|
32219
|
-
installManifest:
|
|
32220
|
-
runtimeBinding:
|
|
32221
|
-
preferences:
|
|
32484
|
+
installManifest: path40.join(companionState, "install-v1.json"),
|
|
32485
|
+
runtimeBinding: path40.join(companionState, "runtime-v1.json"),
|
|
32486
|
+
preferences: path40.join(companionState, "preferences-v1.json")
|
|
32222
32487
|
};
|
|
32223
32488
|
}
|
|
32224
32489
|
function exactKeys2(value, keys) {
|
|
@@ -32229,7 +32494,7 @@ function parseInstallManifest(value) {
|
|
|
32229
32494
|
throw new Error("Install manifest schema is invalid");
|
|
32230
32495
|
}
|
|
32231
32496
|
const record = value;
|
|
32232
|
-
if (!exactKeys2(record, INSTALL_KEYS) || record.schemaVersion !== 1 || typeof record.version !== "string" || record.platform !== "darwin" && record.platform !== "win32" || record.architecture !== "arm64" && record.architecture !== "x64" || typeof record.entryRelativePath !== "string" || typeof record.artifactTreeSha256 !== "string" || !/^[a-f0-9]{64}$/u.test(record.artifactTreeSha256) || typeof record.ownedTargetRoot !== "string" || !
|
|
32497
|
+
if (!exactKeys2(record, INSTALL_KEYS) || record.schemaVersion !== 1 || typeof record.version !== "string" || record.platform !== "darwin" && record.platform !== "win32" || record.architecture !== "arm64" && record.architecture !== "x64" || typeof record.entryRelativePath !== "string" || typeof record.artifactTreeSha256 !== "string" || !/^[a-f0-9]{64}$/u.test(record.artifactTreeSha256) || typeof record.ownedTargetRoot !== "string" || !path40.isAbsolute(record.ownedTargetRoot)) {
|
|
32233
32498
|
throw new Error("Install manifest schema is invalid");
|
|
32234
32499
|
}
|
|
32235
32500
|
return record;
|
|
@@ -32239,7 +32504,7 @@ function parseRuntimeBinding(value, platform) {
|
|
|
32239
32504
|
throw new Error("Runtime binding schema is invalid");
|
|
32240
32505
|
}
|
|
32241
32506
|
const record = value;
|
|
32242
|
-
const paths = platform === "win32" ?
|
|
32507
|
+
const paths = platform === "win32" ? path40.win32 : path40.posix;
|
|
32243
32508
|
if (!exactKeys2(record, RUNTIME_KEYS) || record.schemaVersion !== 1 || typeof record.nodeExecutable !== "string" || !paths.isAbsolute(record.nodeExecutable) || typeof record.cliEntry !== "string" || !paths.isAbsolute(record.cliEntry) || typeof record.gatewayOrigin !== "string") {
|
|
32244
32509
|
throw new Error("Runtime binding schema is invalid");
|
|
32245
32510
|
}
|
|
@@ -32264,7 +32529,7 @@ function validateGatewayOrigin(value) {
|
|
|
32264
32529
|
}
|
|
32265
32530
|
async function assertNotSymlink(filePath, kind) {
|
|
32266
32531
|
try {
|
|
32267
|
-
if ((await
|
|
32532
|
+
if ((await fs36.lstat(filePath)).isSymbolicLink()) {
|
|
32268
32533
|
throw new Error(`${kind} is a symbolic link`);
|
|
32269
32534
|
}
|
|
32270
32535
|
} catch (error) {
|
|
@@ -32273,20 +32538,20 @@ async function assertNotSymlink(filePath, kind) {
|
|
|
32273
32538
|
}
|
|
32274
32539
|
}
|
|
32275
32540
|
async function assertOwnedDirectoryChain(anchor, targetDirectory) {
|
|
32276
|
-
const relative4 =
|
|
32277
|
-
if (relative4 === ".." || relative4.startsWith(`..${
|
|
32541
|
+
const relative4 = path40.relative(anchor, targetDirectory);
|
|
32542
|
+
if (relative4 === ".." || relative4.startsWith(`..${path40.sep}`) || path40.isAbsolute(relative4)) {
|
|
32278
32543
|
throw new Error("Companion owned directory escapes its trusted anchor");
|
|
32279
32544
|
}
|
|
32280
|
-
const segments = relative4.split(
|
|
32545
|
+
const segments = relative4.split(path40.sep).filter(Boolean);
|
|
32281
32546
|
let current = anchor;
|
|
32282
|
-
const anchorStatus = await
|
|
32547
|
+
const anchorStatus = await fs36.lstat(anchor);
|
|
32283
32548
|
if (anchorStatus.isSymbolicLink() || !anchorStatus.isDirectory()) {
|
|
32284
32549
|
throw new Error("Companion owned directory anchor is unsafe");
|
|
32285
32550
|
}
|
|
32286
32551
|
for (const segment of segments) {
|
|
32287
|
-
current =
|
|
32552
|
+
current = path40.join(current, segment);
|
|
32288
32553
|
try {
|
|
32289
|
-
const status = await
|
|
32554
|
+
const status = await fs36.lstat(current);
|
|
32290
32555
|
if (status.isSymbolicLink() || !status.isDirectory()) {
|
|
32291
32556
|
throw new Error("Companion owned directory contains a symbolic link");
|
|
32292
32557
|
}
|
|
@@ -32299,19 +32564,19 @@ async function assertOwnedDirectoryChain(anchor, targetDirectory) {
|
|
|
32299
32564
|
async function assertOwnedParents(options, paths) {
|
|
32300
32565
|
await assertOwnedDirectoryChain(
|
|
32301
32566
|
options.homeDirectory,
|
|
32302
|
-
|
|
32567
|
+
path40.dirname(paths.installManifest)
|
|
32303
32568
|
);
|
|
32304
|
-
const targetAnchor = options.platform === "win32" ? options.localAppData ??
|
|
32305
|
-
await assertOwnedDirectoryChain(targetAnchor,
|
|
32569
|
+
const targetAnchor = options.platform === "win32" ? options.localAppData ?? path40.join(options.homeDirectory, "AppData", "Local") : options.homeDirectory;
|
|
32570
|
+
await assertOwnedDirectoryChain(targetAnchor, path40.dirname(paths.targetRoot));
|
|
32306
32571
|
}
|
|
32307
32572
|
async function readRegularText(filePath, maxBytes) {
|
|
32308
|
-
const before = await
|
|
32573
|
+
const before = await fs36.lstat(filePath);
|
|
32309
32574
|
if (before.isSymbolicLink() || !before.isFile()) {
|
|
32310
32575
|
throw new Error("Companion state file is not a regular file");
|
|
32311
32576
|
}
|
|
32312
32577
|
let handle;
|
|
32313
32578
|
try {
|
|
32314
|
-
handle = await
|
|
32579
|
+
handle = await fs36.open(
|
|
32315
32580
|
filePath,
|
|
32316
32581
|
constants2.O_RDONLY | constants2.O_NOFOLLOW
|
|
32317
32582
|
);
|
|
@@ -32334,27 +32599,27 @@ async function atomicWriteJson(filePath, value) {
|
|
|
32334
32599
|
}
|
|
32335
32600
|
async function atomicWriteText(filePath, contents, mode) {
|
|
32336
32601
|
await assertNotSymlink(filePath, "Companion state file");
|
|
32337
|
-
await
|
|
32602
|
+
await fs36.mkdir(path40.dirname(filePath), {
|
|
32338
32603
|
recursive: true,
|
|
32339
32604
|
mode: 448
|
|
32340
32605
|
});
|
|
32341
32606
|
const temporary = `${filePath}.${randomUUID3()}.tmp`;
|
|
32342
32607
|
try {
|
|
32343
|
-
await
|
|
32608
|
+
await fs36.writeFile(temporary, contents, {
|
|
32344
32609
|
mode,
|
|
32345
32610
|
flag: "wx"
|
|
32346
32611
|
});
|
|
32347
|
-
await
|
|
32348
|
-
await
|
|
32612
|
+
await fs36.rename(temporary, filePath);
|
|
32613
|
+
await fs36.chmod(filePath, mode).catch(() => void 0);
|
|
32349
32614
|
} finally {
|
|
32350
|
-
await
|
|
32615
|
+
await fs36.rm(temporary, { force: true }).catch(() => void 0);
|
|
32351
32616
|
}
|
|
32352
32617
|
}
|
|
32353
32618
|
async function realRegularFile(filePath, executable) {
|
|
32354
|
-
const real = await
|
|
32355
|
-
const stat5 = await
|
|
32619
|
+
const real = await fs36.realpath(filePath);
|
|
32620
|
+
const stat5 = await fs36.stat(real);
|
|
32356
32621
|
if (!stat5.isFile()) throw new Error("Companion launch target is not a file");
|
|
32357
|
-
await
|
|
32622
|
+
await fs36.access(real, executable ? constants2.X_OK : constants2.R_OK);
|
|
32358
32623
|
return real;
|
|
32359
32624
|
}
|
|
32360
32625
|
function defaultLaunch(executable) {
|
|
@@ -32370,7 +32635,7 @@ async function companionIsRunning(platform, executable) {
|
|
|
32370
32635
|
if (platform !== "win32") return false;
|
|
32371
32636
|
let handle;
|
|
32372
32637
|
try {
|
|
32373
|
-
handle = await
|
|
32638
|
+
handle = await fs36.open(executable, "r+");
|
|
32374
32639
|
} catch (error) {
|
|
32375
32640
|
const code = error.code;
|
|
32376
32641
|
if (code === "ENOENT") return false;
|
|
@@ -32451,7 +32716,7 @@ async function statusCompanion(options) {
|
|
|
32451
32716
|
realRegularFile(runtime.nodeExecutable, options.platform !== "win32"),
|
|
32452
32717
|
realRegularFile(runtime.cliEntry, false)
|
|
32453
32718
|
]);
|
|
32454
|
-
const executable =
|
|
32719
|
+
const executable = path40.join(
|
|
32455
32720
|
paths.targetRoot,
|
|
32456
32721
|
...install.entryRelativePath.split("/")
|
|
32457
32722
|
);
|
|
@@ -32484,7 +32749,7 @@ async function snapshotFile(filePath) {
|
|
|
32484
32749
|
}
|
|
32485
32750
|
async function restoreFile(filePath, bytes) {
|
|
32486
32751
|
if (bytes === null) {
|
|
32487
|
-
await
|
|
32752
|
+
await fs36.rm(filePath, { force: true });
|
|
32488
32753
|
} else {
|
|
32489
32754
|
await atomicWriteJson(filePath, JSON.parse(bytes.toString("utf8")));
|
|
32490
32755
|
}
|
|
@@ -32499,8 +32764,8 @@ async function converge(options, force) {
|
|
|
32499
32764
|
if (artifactManifest.platform !== options.platform || artifactManifest.architecture !== options.architecture) {
|
|
32500
32765
|
throw new Error("Companion artifact does not match this OS and architecture");
|
|
32501
32766
|
}
|
|
32502
|
-
const payloadRoot =
|
|
32503
|
-
|
|
32767
|
+
const payloadRoot = path40.join(
|
|
32768
|
+
path40.dirname(options.artifactManifestPath),
|
|
32504
32769
|
"payload"
|
|
32505
32770
|
);
|
|
32506
32771
|
await verifyArtifactSource(payloadRoot, artifactManifest);
|
|
@@ -32520,7 +32785,7 @@ async function converge(options, force) {
|
|
|
32520
32785
|
if (priorInstalled) {
|
|
32521
32786
|
await assertCompanionNotRunning(
|
|
32522
32787
|
options,
|
|
32523
|
-
|
|
32788
|
+
path40.join(
|
|
32524
32789
|
priorInstalled.paths.targetRoot,
|
|
32525
32790
|
...priorInstalled.install.entryRelativePath.split("/")
|
|
32526
32791
|
)
|
|
@@ -32528,7 +32793,7 @@ async function converge(options, force) {
|
|
|
32528
32793
|
}
|
|
32529
32794
|
if (current.state === "not-installed") {
|
|
32530
32795
|
try {
|
|
32531
|
-
await
|
|
32796
|
+
await fs36.lstat(paths.targetRoot);
|
|
32532
32797
|
throw new Error(
|
|
32533
32798
|
"The fixed companion target exists without an owned install manifest"
|
|
32534
32799
|
);
|
|
@@ -32539,7 +32804,7 @@ async function converge(options, force) {
|
|
|
32539
32804
|
const stage = `${paths.targetRoot}.m8t-stage-${randomUUID3()}`;
|
|
32540
32805
|
const backup = `${paths.targetRoot}.m8t-backup-${randomUUID3()}`;
|
|
32541
32806
|
const copy = options.copyPayload ?? copyArtifactPayload;
|
|
32542
|
-
await
|
|
32807
|
+
await fs36.mkdir(path40.dirname(paths.targetRoot), {
|
|
32543
32808
|
recursive: true,
|
|
32544
32809
|
mode: 448
|
|
32545
32810
|
});
|
|
@@ -32556,12 +32821,12 @@ async function converge(options, force) {
|
|
|
32556
32821
|
try {
|
|
32557
32822
|
await copy(payloadRoot, stage, artifactManifest);
|
|
32558
32823
|
try {
|
|
32559
|
-
await
|
|
32824
|
+
await fs36.rename(paths.targetRoot, backup);
|
|
32560
32825
|
movedPrior = true;
|
|
32561
32826
|
} catch (error) {
|
|
32562
32827
|
if (error.code !== "ENOENT") throw error;
|
|
32563
32828
|
}
|
|
32564
|
-
await
|
|
32829
|
+
await fs36.rename(stage, paths.targetRoot);
|
|
32565
32830
|
installedStage = true;
|
|
32566
32831
|
const nodeExecutable = await realRegularFile(
|
|
32567
32832
|
options.nodeExecutable,
|
|
@@ -32603,7 +32868,7 @@ async function converge(options, force) {
|
|
|
32603
32868
|
await readClosedJson(paths.runtimeBinding),
|
|
32604
32869
|
options.platform
|
|
32605
32870
|
);
|
|
32606
|
-
const executable =
|
|
32871
|
+
const executable = path40.join(
|
|
32607
32872
|
paths.targetRoot,
|
|
32608
32873
|
...artifactManifest.entryRelativePath.split("/")
|
|
32609
32874
|
);
|
|
@@ -32613,7 +32878,7 @@ async function converge(options, force) {
|
|
|
32613
32878
|
platform: options.platform,
|
|
32614
32879
|
executable: ownedExecutable
|
|
32615
32880
|
}));
|
|
32616
|
-
priorLoginExecutable = priorInstalled ?
|
|
32881
|
+
priorLoginExecutable = priorInstalled ? path40.join(
|
|
32617
32882
|
priorInstalled.paths.targetRoot,
|
|
32618
32883
|
...priorInstalled.install.entryRelativePath.split("/")
|
|
32619
32884
|
) : executable;
|
|
@@ -32624,7 +32889,7 @@ async function converge(options, force) {
|
|
|
32624
32889
|
);
|
|
32625
32890
|
loginChanged = true;
|
|
32626
32891
|
await (options.launch ?? defaultLaunch)(executable);
|
|
32627
|
-
await
|
|
32892
|
+
await fs36.rm(backup, { recursive: true, force: true });
|
|
32628
32893
|
return {
|
|
32629
32894
|
state: "installed",
|
|
32630
32895
|
version: artifactManifest.version,
|
|
@@ -32638,15 +32903,15 @@ async function converge(options, force) {
|
|
|
32638
32903
|
() => void 0
|
|
32639
32904
|
);
|
|
32640
32905
|
}
|
|
32641
|
-
await
|
|
32906
|
+
await fs36.rm(stage, { recursive: true, force: true }).catch(() => void 0);
|
|
32642
32907
|
if (installedStage) {
|
|
32643
|
-
await
|
|
32908
|
+
await fs36.rm(paths.targetRoot, {
|
|
32644
32909
|
recursive: true,
|
|
32645
32910
|
force: true
|
|
32646
32911
|
}).catch(() => void 0);
|
|
32647
32912
|
}
|
|
32648
32913
|
if (movedPrior) {
|
|
32649
|
-
await
|
|
32914
|
+
await fs36.rename(backup, paths.targetRoot).catch(() => void 0);
|
|
32650
32915
|
}
|
|
32651
32916
|
await Promise.all([
|
|
32652
32917
|
restoreFile(paths.installManifest, snapshots[0]),
|
|
@@ -32672,14 +32937,14 @@ async function uninstallCompanion(options) {
|
|
|
32672
32937
|
if (install.ownedTargetRoot !== paths.targetRoot) {
|
|
32673
32938
|
throw new Error("Refusing to remove a non-owned companion target");
|
|
32674
32939
|
}
|
|
32675
|
-
const executable =
|
|
32940
|
+
const executable = path40.join(
|
|
32676
32941
|
paths.targetRoot,
|
|
32677
32942
|
...install.entryRelativePath.split("/")
|
|
32678
32943
|
);
|
|
32679
32944
|
await assertCompanionNotRunning(options, executable);
|
|
32680
32945
|
await (options.setStartAtLogin ?? (() => Promise.resolve()))(executable, false);
|
|
32681
32946
|
const remove = options.removeOwnedPath ?? (async (ownedPath, recursive) => {
|
|
32682
|
-
await
|
|
32947
|
+
await fs36.rm(ownedPath, { recursive, force: true });
|
|
32683
32948
|
});
|
|
32684
32949
|
await remove(paths.targetRoot, true);
|
|
32685
32950
|
await remove(paths.installManifest, false);
|
|
@@ -32690,8 +32955,8 @@ async function uninstallCompanion(options) {
|
|
|
32690
32955
|
|
|
32691
32956
|
// src/commands/companion/install.ts
|
|
32692
32957
|
import * as os18 from "os";
|
|
32693
|
-
import * as
|
|
32694
|
-
import { Command as
|
|
32958
|
+
import * as path42 from "path";
|
|
32959
|
+
import { Command as Command59, Option as Option56 } from "clipanion";
|
|
32695
32960
|
|
|
32696
32961
|
// src/lib/companion-channel.ts
|
|
32697
32962
|
async function readCompanionRelease(source = { url: CHANNEL_LATEST_URL }, deps = {}) {
|
|
@@ -32708,9 +32973,9 @@ async function readCompanionRelease(source = { url: CHANNEL_LATEST_URL }, deps =
|
|
|
32708
32973
|
// src/lib/companion-download.ts
|
|
32709
32974
|
import { createHash as createHash8 } from "crypto";
|
|
32710
32975
|
import { execFile as execFile2 } from "child_process";
|
|
32711
|
-
import * as
|
|
32976
|
+
import * as fs37 from "fs/promises";
|
|
32712
32977
|
import * as os17 from "os";
|
|
32713
|
-
import * as
|
|
32978
|
+
import * as path41 from "path";
|
|
32714
32979
|
init_errors();
|
|
32715
32980
|
var MAX_ASSET_BYTES = 512 * 1024 * 1024;
|
|
32716
32981
|
function extractArchive(archive, into) {
|
|
@@ -32763,20 +33028,20 @@ async function downloadCompanionArtifact(component, deps = {}) {
|
|
|
32763
33028
|
hint: "Nothing was unpacked. This is what a corrupted download or a substituted file looks like \u2014 retry, and report it if it persists."
|
|
32764
33029
|
});
|
|
32765
33030
|
}
|
|
32766
|
-
const root = await (deps.makeTemporaryDirectory ?? (() =>
|
|
33031
|
+
const root = await (deps.makeTemporaryDirectory ?? (() => fs37.mkdtemp(path41.join(os17.tmpdir(), "m8t-companion-"))))();
|
|
32767
33032
|
const dispose = async () => {
|
|
32768
|
-
await
|
|
33033
|
+
await fs37.rm(root, { recursive: true, force: true }).catch(() => void 0);
|
|
32769
33034
|
};
|
|
32770
33035
|
try {
|
|
32771
|
-
const archive =
|
|
32772
|
-
await
|
|
32773
|
-
const unpacked =
|
|
32774
|
-
await
|
|
33036
|
+
const archive = path41.join(root, pinned.asset);
|
|
33037
|
+
await fs37.writeFile(archive, bytes, { mode: 384 });
|
|
33038
|
+
const unpacked = path41.join(root, "unpacked");
|
|
33039
|
+
await fs37.mkdir(unpacked, { recursive: false, mode: 448 });
|
|
32775
33040
|
await (deps.extract ?? extractArchive)(archive, unpacked);
|
|
32776
|
-
await
|
|
33041
|
+
await fs37.rm(archive, { force: true });
|
|
32777
33042
|
return {
|
|
32778
33043
|
version: component.version,
|
|
32779
|
-
artifactManifestPath:
|
|
33044
|
+
artifactManifestPath: path41.join(unpacked, "artifact-v1.json"),
|
|
32780
33045
|
dispose
|
|
32781
33046
|
};
|
|
32782
33047
|
} catch (error) {
|
|
@@ -32807,7 +33072,7 @@ async function convergeCompanionFromChannel(converge2, options = {}) {
|
|
|
32807
33072
|
let artifactManifestPath;
|
|
32808
33073
|
let dispose = () => Promise.resolve();
|
|
32809
33074
|
if (stagedDirectory !== void 0) {
|
|
32810
|
-
artifactManifestPath =
|
|
33075
|
+
artifactManifestPath = path42.resolve(stagedDirectory, "artifact-v1.json");
|
|
32811
33076
|
} else {
|
|
32812
33077
|
const release = await readCompanionRelease(
|
|
32813
33078
|
platformVersion !== void 0 ? { channel: true, version: platformTag(platformVersion) } : { url: CHANNEL_LATEST_URL }
|
|
@@ -32849,7 +33114,7 @@ Version: ${state.version}
|
|
|
32849
33114
|
}
|
|
32850
33115
|
var CompanionInstallCommand = class extends M8tCommand {
|
|
32851
33116
|
static paths = [["companion", "install"]];
|
|
32852
|
-
static usage =
|
|
33117
|
+
static usage = Command59.Usage({
|
|
32853
33118
|
description: "Install the desktop companions for this user from the release channel.",
|
|
32854
33119
|
examples: [
|
|
32855
33120
|
["Install the released build", "$0 companion install"],
|
|
@@ -32859,10 +33124,10 @@ var CompanionInstallCommand = class extends M8tCommand {
|
|
|
32859
33124
|
]
|
|
32860
33125
|
]
|
|
32861
33126
|
});
|
|
32862
|
-
from =
|
|
33127
|
+
from = Option56.String("--from", {
|
|
32863
33128
|
description: "A locally staged build directory instead of the released one."
|
|
32864
33129
|
});
|
|
32865
|
-
resourceGroup =
|
|
33130
|
+
resourceGroup = Option56.String("--resource-group", {
|
|
32866
33131
|
description: "Which deployment to bind to, when the subscription holds more than one."
|
|
32867
33132
|
});
|
|
32868
33133
|
async executeCommand() {
|
|
@@ -32885,7 +33150,7 @@ function resolveRepoRootMarker(args) {
|
|
|
32885
33150
|
}
|
|
32886
33151
|
async function looksLikeCheckout(dir) {
|
|
32887
33152
|
try {
|
|
32888
|
-
return (await
|
|
33153
|
+
return (await fs38.stat(path43.join(dir, "brain-template"))).isDirectory();
|
|
32889
33154
|
} catch {
|
|
32890
33155
|
return false;
|
|
32891
33156
|
}
|
|
@@ -32904,18 +33169,18 @@ var defaultDeps3 = {
|
|
|
32904
33169
|
homedir: () => os19.homedir()
|
|
32905
33170
|
};
|
|
32906
33171
|
async function finalizeInstall(args, deps = defaultDeps3) {
|
|
32907
|
-
const markerDir =
|
|
32908
|
-
const markerPath =
|
|
33172
|
+
const markerDir = path43.join(deps.homedir(), ".m8t");
|
|
33173
|
+
const markerPath = path43.join(markerDir, "repo-root");
|
|
32909
33174
|
const cwd = process.cwd();
|
|
32910
|
-
const existing = await
|
|
33175
|
+
const existing = await fs38.readFile(markerPath, "utf8").then((s) => s.trim()).catch(() => null);
|
|
32911
33176
|
const repoRoot = resolveRepoRootMarker({
|
|
32912
33177
|
...args.repoRoot !== void 0 ? { explicit: args.repoRoot } : {},
|
|
32913
33178
|
cwd,
|
|
32914
33179
|
cwdIsCheckout: await looksLikeCheckout(cwd),
|
|
32915
33180
|
existing
|
|
32916
33181
|
});
|
|
32917
|
-
await
|
|
32918
|
-
await
|
|
33182
|
+
await fs38.mkdir(markerDir, { recursive: true });
|
|
33183
|
+
await fs38.writeFile(markerPath, `${repoRoot}
|
|
32919
33184
|
`, "utf8");
|
|
32920
33185
|
let webappUrl;
|
|
32921
33186
|
try {
|
|
@@ -32993,7 +33258,7 @@ async function finalizeInstall(args, deps = defaultDeps3) {
|
|
|
32993
33258
|
}
|
|
32994
33259
|
let brainOrg = null;
|
|
32995
33260
|
try {
|
|
32996
|
-
const credsRaw = await
|
|
33261
|
+
const credsRaw = await fs38.readFile(path43.join(markerDir, "github-app.json"), "utf8");
|
|
32997
33262
|
const creds = JSON.parse(credsRaw);
|
|
32998
33263
|
brainOrg = typeof creds.org === "string" ? creds.org : null;
|
|
32999
33264
|
} catch {
|
|
@@ -33078,7 +33343,7 @@ var BootstrapStatusCommand = class extends M8tCommand {
|
|
|
33078
33343
|
// runbooks and shakedown recipes that a founder may already be part-way
|
|
33079
33344
|
// through — it prints a deprecation notice and does the right thing.
|
|
33080
33345
|
static paths = [["bootstrap", "status"], ["bootstrap", "finish"]];
|
|
33081
|
-
static usage =
|
|
33346
|
+
static usage = Command60.Usage({
|
|
33082
33347
|
description: "Show the cloud installer's live status (phase, progress, result) \u2014 and finish the local setup when it lands.",
|
|
33083
33348
|
details: "Reads the durable status blob written by the installer. --watch polls until the install reaches done or failed.\n\nOn reaching done under --watch this also completes the local half of the install, which nothing else in the bootstrap path can do: it registers the webapp's sign-in redirect URI (the installer runs as a managed identity with no directory role, and at launch time the gateway FQDN did not exist yet), writes ~/.m8t/repo-root and the gateway discovery cache, and seeds your advisors' brains from the onboarding intake. Re-runnable \u2014 `m8t bootstrap finish` is a deprecated alias that does exactly this on an already-done install.",
|
|
33084
33349
|
examples: [
|
|
@@ -33087,12 +33352,12 @@ var BootstrapStatusCommand = class extends M8tCommand {
|
|
|
33087
33352
|
["Redo the local setup on a finished install", "$0 bootstrap status --finalize --repo-root /path/to/m8t"]
|
|
33088
33353
|
]
|
|
33089
33354
|
});
|
|
33090
|
-
watch =
|
|
33091
|
-
output =
|
|
33092
|
-
repoRoot =
|
|
33093
|
-
finalize =
|
|
33094
|
-
subscription =
|
|
33095
|
-
resourceGroup =
|
|
33355
|
+
watch = Option57.Boolean("--watch", false);
|
|
33356
|
+
output = Option57.String("--output");
|
|
33357
|
+
repoRoot = Option57.String("--repo-root", { description: "The m8t clone to point local tools at (default: the current directory)." });
|
|
33358
|
+
finalize = Option57.Boolean("--finalize", false, { description: "Complete the local setup against an already-done install, without watching." });
|
|
33359
|
+
subscription = Option57.String("--subscription");
|
|
33360
|
+
resourceGroup = Option57.String("--resource-group");
|
|
33096
33361
|
async executeCommand() {
|
|
33097
33362
|
const state = await readBootstrapState();
|
|
33098
33363
|
if (!state) {
|
|
@@ -33225,7 +33490,7 @@ function formatStatus(d) {
|
|
|
33225
33490
|
}
|
|
33226
33491
|
|
|
33227
33492
|
// src/commands/bootstrap/reap.ts
|
|
33228
|
-
import { Command as
|
|
33493
|
+
import { Command as Command61, Option as Option58 } from "clipanion";
|
|
33229
33494
|
init_errors();
|
|
33230
33495
|
|
|
33231
33496
|
// src/lib/bootstrap-reap.ts
|
|
@@ -33319,7 +33584,7 @@ async function reapInstaller(opts) {
|
|
|
33319
33584
|
// src/commands/bootstrap/reap.ts
|
|
33320
33585
|
var BootstrapReapCommand = class extends M8tCommand {
|
|
33321
33586
|
static paths = [["bootstrap", "reap"]];
|
|
33322
|
-
static usage =
|
|
33587
|
+
static usage = Command61.Usage({
|
|
33323
33588
|
description: "Tear down the installer scaffolding (ACI \u2192 MI \u2192 its role assignments) after a successful install.",
|
|
33324
33589
|
details: "Runs locally on the 'done' signal (the installer can't delete its own identity). The platform RG and the gateway's own assignments persist. A failed install is left intact for diagnosis unless --force.\n\n--sweep-orphans is a DIFFERENT and much broader mode: instead of reaping this install, it scans the WHOLE SUBSCRIPTION for m8t role assignments left behind by installs whose resources are gone \u2014 orphaned installer Owner-at-subscription-scope grants and orphaned gateway subscription-scope roles. It is a dry run that only lists what it found unless you also pass --yes, which deletes them.",
|
|
33325
33590
|
examples: [
|
|
@@ -33329,9 +33594,9 @@ var BootstrapReapCommand = class extends M8tCommand {
|
|
|
33329
33594
|
["\u2026and delete them", "$0 bootstrap reap --sweep-orphans --yes"]
|
|
33330
33595
|
]
|
|
33331
33596
|
});
|
|
33332
|
-
force =
|
|
33333
|
-
sweepOrphans =
|
|
33334
|
-
yes =
|
|
33597
|
+
force = Option58.Boolean("--force", false, { description: "Reap even if the install failed or never reported a status." });
|
|
33598
|
+
sweepOrphans = Option58.Boolean("--sweep-orphans", false, { description: "Subscription-wide: find m8t role assignments orphaned by earlier installs. Lists only, unless --yes." });
|
|
33599
|
+
yes = Option58.Boolean("--yes", false, { description: "With --sweep-orphans, actually delete what the sweep found." });
|
|
33335
33600
|
async executeCommand() {
|
|
33336
33601
|
if (this.sweepOrphans === true) {
|
|
33337
33602
|
const { subscriptionId: sub } = await getAzAccount();
|
|
@@ -33425,18 +33690,18 @@ Found ${String(total)} orphaned assignment(s) (${breakdown}) (dry-run). ${colors
|
|
|
33425
33690
|
};
|
|
33426
33691
|
|
|
33427
33692
|
// src/commands/bootstrap/ui.ts
|
|
33428
|
-
import * as
|
|
33693
|
+
import * as fs40 from "fs";
|
|
33429
33694
|
import * as os21 from "os";
|
|
33430
|
-
import * as
|
|
33431
|
-
import { Command as
|
|
33432
|
-
import { DefaultAzureCredential as
|
|
33695
|
+
import * as path45 from "path";
|
|
33696
|
+
import { Command as Command62, Option as Option59 } from "clipanion";
|
|
33697
|
+
import { DefaultAzureCredential as DefaultAzureCredential25 } from "@azure/identity";
|
|
33433
33698
|
init_errors();
|
|
33434
33699
|
|
|
33435
33700
|
// src/lib/bootstrap-ui.ts
|
|
33436
|
-
import * as
|
|
33701
|
+
import * as fs39 from "fs";
|
|
33437
33702
|
import * as net from "net";
|
|
33438
33703
|
import * as os20 from "os";
|
|
33439
|
-
import * as
|
|
33704
|
+
import * as path44 from "path";
|
|
33440
33705
|
import { randomBytes as randomBytes3 } from "crypto";
|
|
33441
33706
|
import { spawn as spawn8, spawnSync as spawnSync6 } from "child_process";
|
|
33442
33707
|
init_errors();
|
|
@@ -33624,11 +33889,11 @@ async function ensureFounderFoundryRole(args) {
|
|
|
33624
33889
|
});
|
|
33625
33890
|
}
|
|
33626
33891
|
function writeWebEnvLocal(args) {
|
|
33627
|
-
const envPath =
|
|
33892
|
+
const envPath = path44.join(args.repoRoot, "apps", "web", ".env.local");
|
|
33628
33893
|
let prior = "";
|
|
33629
|
-
if (
|
|
33630
|
-
prior =
|
|
33631
|
-
|
|
33894
|
+
if (fs39.existsSync(envPath)) {
|
|
33895
|
+
prior = fs39.readFileSync(envPath, "utf8");
|
|
33896
|
+
fs39.copyFileSync(envPath, envPath + ".bak");
|
|
33632
33897
|
}
|
|
33633
33898
|
const priorSecret = readValidInternalSecret(prior);
|
|
33634
33899
|
const internalSecret = priorSecret ?? (args.randomBytesImpl ?? randomBytes3)(32).toString("base64url");
|
|
@@ -33654,9 +33919,9 @@ function writeWebEnvLocal(args) {
|
|
|
33654
33919
|
"NEXT_PUBLIC_M8T_ONBOARDING=1",
|
|
33655
33920
|
""
|
|
33656
33921
|
].join("\n");
|
|
33657
|
-
|
|
33922
|
+
fs39.writeFileSync(envPath, body, { encoding: "utf8", mode: 384 });
|
|
33658
33923
|
try {
|
|
33659
|
-
|
|
33924
|
+
fs39.chmodSync(envPath, 384);
|
|
33660
33925
|
} catch {
|
|
33661
33926
|
}
|
|
33662
33927
|
return envPath;
|
|
@@ -33672,10 +33937,10 @@ function readValidInternalSecret(envText) {
|
|
|
33672
33937
|
return isValidInternalSecret(values[0]) ? values[0] : void 0;
|
|
33673
33938
|
}
|
|
33674
33939
|
function readWebInternalSecret(repoRoot) {
|
|
33675
|
-
const envPath =
|
|
33940
|
+
const envPath = path44.join(repoRoot, "apps", "web", ".env.local");
|
|
33676
33941
|
let secret;
|
|
33677
33942
|
try {
|
|
33678
|
-
secret = readValidInternalSecret(
|
|
33943
|
+
secret = readValidInternalSecret(fs39.readFileSync(envPath, "utf8"));
|
|
33679
33944
|
} catch {
|
|
33680
33945
|
secret = void 0;
|
|
33681
33946
|
}
|
|
@@ -33727,17 +33992,17 @@ async function installWebDeps(repoRoot) {
|
|
|
33727
33992
|
await runInherit("pnpm", ["install"], repoRoot, "BOOTSTRAP_UI_INSTALL_FAILED");
|
|
33728
33993
|
}
|
|
33729
33994
|
function onboardingUiPaths(home = os20.homedir()) {
|
|
33730
|
-
const dir =
|
|
33995
|
+
const dir = path44.join(home, ".m8t");
|
|
33731
33996
|
return {
|
|
33732
|
-
logPath:
|
|
33733
|
-
pidPath:
|
|
33997
|
+
logPath: path44.join(dir, "onboarding-ui.log"),
|
|
33998
|
+
pidPath: path44.join(dir, "onboarding-ui.pid")
|
|
33734
33999
|
};
|
|
33735
34000
|
}
|
|
33736
34001
|
function onboardingRelayPaths(home = os20.homedir()) {
|
|
33737
|
-
const dir =
|
|
34002
|
+
const dir = path44.join(home, ".m8t");
|
|
33738
34003
|
return {
|
|
33739
|
-
logPath:
|
|
33740
|
-
pidPath:
|
|
34004
|
+
logPath: path44.join(dir, "onboarding-relay.log"),
|
|
34005
|
+
pidPath: path44.join(dir, "onboarding-relay.pid")
|
|
33741
34006
|
};
|
|
33742
34007
|
}
|
|
33743
34008
|
function isLocalPortOpen(port) {
|
|
@@ -33759,7 +34024,7 @@ function isLocalPortOpen(port) {
|
|
|
33759
34024
|
}
|
|
33760
34025
|
function removePidFile(pidPath) {
|
|
33761
34026
|
try {
|
|
33762
|
-
|
|
34027
|
+
fs39.unlinkSync(pidPath);
|
|
33763
34028
|
} catch {
|
|
33764
34029
|
}
|
|
33765
34030
|
}
|
|
@@ -33772,7 +34037,7 @@ function parseManagedPid(text) {
|
|
|
33772
34037
|
function readLiveManagedPid(pidPath) {
|
|
33773
34038
|
let text;
|
|
33774
34039
|
try {
|
|
33775
|
-
text =
|
|
34040
|
+
text = fs39.readFileSync(pidPath, "utf8").trim();
|
|
33776
34041
|
} catch {
|
|
33777
34042
|
return null;
|
|
33778
34043
|
}
|
|
@@ -33811,8 +34076,8 @@ async function serveOnboardingUiDetached(args) {
|
|
|
33811
34076
|
});
|
|
33812
34077
|
}
|
|
33813
34078
|
if (managedPid != null) return { alreadyRunning: true, logPath };
|
|
33814
|
-
|
|
33815
|
-
const fd =
|
|
34079
|
+
fs39.mkdirSync(path44.dirname(logPath), { recursive: true });
|
|
34080
|
+
const fd = fs39.openSync(logPath, "a");
|
|
33816
34081
|
const child = spawn8("pnpm", ["--filter", "web", "dev"], {
|
|
33817
34082
|
cwd: args.repoRoot,
|
|
33818
34083
|
detached: true,
|
|
@@ -33821,7 +34086,7 @@ async function serveOnboardingUiDetached(args) {
|
|
|
33821
34086
|
// pnpm resolves to pnpm.cmd on Windows, which needs a shell to launch.
|
|
33822
34087
|
shell: process.platform === "win32"
|
|
33823
34088
|
});
|
|
33824
|
-
|
|
34089
|
+
fs39.closeSync(fd);
|
|
33825
34090
|
if (child.pid == null) {
|
|
33826
34091
|
throw new LocalCliError({
|
|
33827
34092
|
code: "BOOTSTRAP_UI_DEV_SPAWN_FAILED",
|
|
@@ -33830,7 +34095,7 @@ async function serveOnboardingUiDetached(args) {
|
|
|
33830
34095
|
});
|
|
33831
34096
|
}
|
|
33832
34097
|
child.unref();
|
|
33833
|
-
|
|
34098
|
+
fs39.writeFileSync(pidPath, String(child.pid), "utf8");
|
|
33834
34099
|
const deadline = Date.now() + 45e3;
|
|
33835
34100
|
const sleep5 = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
33836
34101
|
while (Date.now() < deadline) {
|
|
@@ -33862,8 +34127,8 @@ async function serveOnboardingRelayDetached(args) {
|
|
|
33862
34127
|
});
|
|
33863
34128
|
}
|
|
33864
34129
|
if (managedPid != null) return { alreadyRunning: true, logPath };
|
|
33865
|
-
|
|
33866
|
-
const fd =
|
|
34130
|
+
fs39.mkdirSync(path44.dirname(logPath), { recursive: true });
|
|
34131
|
+
const fd = fs39.openSync(logPath, "a");
|
|
33867
34132
|
const child = spawn8("pnpm", ["--filter", "web", "exec", "tsx", "voice-relay-entry.ts"], {
|
|
33868
34133
|
cwd: args.repoRoot,
|
|
33869
34134
|
detached: true,
|
|
@@ -33881,7 +34146,7 @@ async function serveOnboardingRelayDetached(args) {
|
|
|
33881
34146
|
// pnpm resolves to pnpm.cmd on Windows, which needs a shell to launch.
|
|
33882
34147
|
shell: process.platform === "win32"
|
|
33883
34148
|
});
|
|
33884
|
-
|
|
34149
|
+
fs39.closeSync(fd);
|
|
33885
34150
|
if (child.pid == null) {
|
|
33886
34151
|
throw new LocalCliError({
|
|
33887
34152
|
code: "BOOTSTRAP_UI_RELAY_SPAWN_FAILED",
|
|
@@ -33890,7 +34155,7 @@ async function serveOnboardingRelayDetached(args) {
|
|
|
33890
34155
|
});
|
|
33891
34156
|
}
|
|
33892
34157
|
child.unref();
|
|
33893
|
-
|
|
34158
|
+
fs39.writeFileSync(pidPath, String(child.pid), "utf8");
|
|
33894
34159
|
const deadline = Date.now() + 45e3;
|
|
33895
34160
|
const sleep5 = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
33896
34161
|
while (Date.now() < deadline) {
|
|
@@ -33912,7 +34177,7 @@ function autoOpenOnboardingUi(url, open3 = tryOpenUrl) {
|
|
|
33912
34177
|
function stopPidFile(pidPath) {
|
|
33913
34178
|
let pidStr;
|
|
33914
34179
|
try {
|
|
33915
|
-
pidStr =
|
|
34180
|
+
pidStr = fs39.readFileSync(pidPath, "utf8").trim();
|
|
33916
34181
|
} catch {
|
|
33917
34182
|
return false;
|
|
33918
34183
|
}
|
|
@@ -33929,7 +34194,7 @@ function stopPidFile(pidPath) {
|
|
|
33929
34194
|
}
|
|
33930
34195
|
}
|
|
33931
34196
|
try {
|
|
33932
|
-
|
|
34197
|
+
fs39.unlinkSync(pidPath);
|
|
33933
34198
|
} catch {
|
|
33934
34199
|
}
|
|
33935
34200
|
return true;
|
|
@@ -34256,7 +34521,7 @@ function renderDeployFailure(error) {
|
|
|
34256
34521
|
}
|
|
34257
34522
|
var BootstrapUiCommand = class extends M8tCommand {
|
|
34258
34523
|
static paths = [["bootstrap", "ui"]];
|
|
34259
|
-
static usage =
|
|
34524
|
+
static usage = Command62.Usage({
|
|
34260
34525
|
description: "Deploy Ezra + start the local onboarding chat UI in the background (returns immediately).",
|
|
34261
34526
|
details: [
|
|
34262
34527
|
"Run after `m8t bootstrap launch`, in parallel with `status --watch`. Waits for the cloud",
|
|
@@ -34277,16 +34542,16 @@ var BootstrapUiCommand = class extends M8tCommand {
|
|
|
34277
34542
|
["Experimental: start the voice relay (no effect on the text-only intake)", "$0 bootstrap ui --repo-root /path/to/m8t --voice"]
|
|
34278
34543
|
]
|
|
34279
34544
|
});
|
|
34280
|
-
repoRoot =
|
|
34281
|
-
port =
|
|
34282
|
-
endpoint =
|
|
34545
|
+
repoRoot = Option59.String("--repo-root");
|
|
34546
|
+
port = Option59.String("--port", "3000");
|
|
34547
|
+
endpoint = Option59.String("--endpoint", {
|
|
34283
34548
|
description: "Foundry project endpoint to target \u2014 overrides discovery when this install's resource group holds more than one Foundry project."
|
|
34284
34549
|
});
|
|
34285
|
-
prepOnly =
|
|
34286
|
-
skipInstall =
|
|
34287
|
-
stop =
|
|
34288
|
-
foreground =
|
|
34289
|
-
voice =
|
|
34550
|
+
prepOnly = Option59.Boolean("--prep-only", false);
|
|
34551
|
+
skipInstall = Option59.Boolean("--skip-install", false);
|
|
34552
|
+
stop = Option59.Boolean("--stop", false);
|
|
34553
|
+
foreground = Option59.Boolean("--foreground", false);
|
|
34554
|
+
voice = Option59.Boolean("--voice", false, {
|
|
34290
34555
|
description: "Experimental: when serving, starts the voice relay and writes the intake voice env var. The onboarding intake is text-only and is unaffected by this flag \u2014 no voice worker is registered for it."
|
|
34291
34556
|
});
|
|
34292
34557
|
async executeCommand() {
|
|
@@ -34326,10 +34591,10 @@ var BootstrapUiCommand = class extends M8tCommand {
|
|
|
34326
34591
|
this.context.stderr.write(` ${colors.dim(m)}
|
|
34327
34592
|
`);
|
|
34328
34593
|
};
|
|
34329
|
-
if (
|
|
34594
|
+
if (fs40.existsSync(path45.join(os21.homedir(), ".m8t", "config.yaml"))) {
|
|
34330
34595
|
out(colors.error("\u26A0 an existing ~/.m8t/config.yaml will override the onboarding app registration in apps/web \u2014 if Microsoft sign-in fails, move it aside and retry."));
|
|
34331
34596
|
}
|
|
34332
|
-
const credential2 = new
|
|
34597
|
+
const credential2 = new DefaultAzureCredential25();
|
|
34333
34598
|
const account = await getAzAccount();
|
|
34334
34599
|
assertNodeVersion();
|
|
34335
34600
|
out("waiting for Foundry (the installer's foundry-create phase)\u2026");
|
|
@@ -34458,10 +34723,10 @@ var BootstrapUiCommand = class extends M8tCommand {
|
|
|
34458
34723
|
};
|
|
34459
34724
|
|
|
34460
34725
|
// src/commands/bootstrap/seed-profile.ts
|
|
34461
|
-
import { Command as
|
|
34726
|
+
import { Command as Command63, Option as Option60 } from "clipanion";
|
|
34462
34727
|
var BootstrapSeedProfileCommand = class extends M8tCommand {
|
|
34463
34728
|
static paths = [["bootstrap", "seed-profile"]];
|
|
34464
|
-
static usage =
|
|
34729
|
+
static usage = Command63.Usage({
|
|
34465
34730
|
description: "Seed your advisors' brains with the founder + company profile from the onboarding intake.",
|
|
34466
34731
|
details: "Reads the latest onboarding conversation, renders memory/founder.md + memory/company-profile.md (+ their MEMORY.md index lines), and commits them to both <org>/stacey-brain and <org>/ezra-brain via the GitHub App. Idempotent. --watch polls until the founder finishes the intake.",
|
|
34467
34732
|
examples: [
|
|
@@ -34469,11 +34734,11 @@ var BootstrapSeedProfileCommand = class extends M8tCommand {
|
|
|
34469
34734
|
["Wait for the founder to finish", "$0 bootstrap seed-profile --watch"]
|
|
34470
34735
|
]
|
|
34471
34736
|
});
|
|
34472
|
-
endpoint =
|
|
34473
|
-
brain =
|
|
34474
|
-
watch =
|
|
34475
|
-
timeout =
|
|
34476
|
-
githubAppCreds =
|
|
34737
|
+
endpoint = Option60.String("--endpoint", { description: "Override the Foundry endpoint (else read from the install status)." });
|
|
34738
|
+
brain = Option60.String("--brain", { description: "Seed only this one brain repo, instead of both <org>/stacey-brain and <org>/ezra-brain." });
|
|
34739
|
+
watch = Option60.Boolean("--watch", false, { description: "Poll until the intake completes (or --timeout)." });
|
|
34740
|
+
timeout = Option60.String("--timeout", { description: "Watch timeout in minutes (default 20)." });
|
|
34741
|
+
githubAppCreds = Option60.String("--github-app-creds");
|
|
34477
34742
|
async executeCommand() {
|
|
34478
34743
|
const ctx = await resolveSeedContext({
|
|
34479
34744
|
endpointOverride: typeof this.endpoint === "string" ? this.endpoint : void 0,
|
|
@@ -34533,10 +34798,10 @@ var BootstrapSeedProfileCommand = class extends M8tCommand {
|
|
|
34533
34798
|
};
|
|
34534
34799
|
|
|
34535
34800
|
// src/commands/telemetry/enroll.ts
|
|
34536
|
-
import * as
|
|
34801
|
+
import * as fs41 from "fs";
|
|
34537
34802
|
import * as os22 from "os";
|
|
34538
|
-
import * as
|
|
34539
|
-
import { Command as
|
|
34803
|
+
import * as path46 from "path";
|
|
34804
|
+
import { Command as Command64, Option as Option61 } from "clipanion";
|
|
34540
34805
|
init_errors();
|
|
34541
34806
|
|
|
34542
34807
|
// src/lib/telemetry-enroll.ts
|
|
@@ -34618,7 +34883,7 @@ async function resolveKeyVaultName(containerAppResourceId) {
|
|
|
34618
34883
|
}
|
|
34619
34884
|
var TelemetryEnrollCommand = class extends M8tCommand {
|
|
34620
34885
|
static paths = [["telemetry", "enroll"]];
|
|
34621
|
-
static usage =
|
|
34886
|
+
static usage = Command64.Usage({
|
|
34622
34887
|
description: "Enroll this installation for operational telemetry (pre-existing installs).",
|
|
34623
34888
|
details: "Generates an instance id + ingest key from the m8t telemetry ingest and stores the key in your platform Key Vault, the same place the installer writes it on a fresh install. Your installation is identified only by that random instance id \u2014 no contact, company, or subscription details are sent unless you pass them explicitly. Idempotent: refuses if a key already exists.",
|
|
34624
34889
|
examples: [
|
|
@@ -34626,11 +34891,11 @@ var TelemetryEnrollCommand = class extends M8tCommand {
|
|
|
34626
34891
|
["Enroll and share a support contact", "$0 telemetry enroll --contact-email you@example.com --company 'Acme'"]
|
|
34627
34892
|
]
|
|
34628
34893
|
});
|
|
34629
|
-
company =
|
|
34630
|
-
contactEmail =
|
|
34631
|
-
subscription =
|
|
34632
|
-
resourceGroup =
|
|
34633
|
-
force =
|
|
34894
|
+
company = Option61.String("--company", { description: "Share your company name with m8t support. Not sent unless you pass it." });
|
|
34895
|
+
contactEmail = Option61.String("--contact-email", { description: "Share a contact email with m8t support. Not sent unless you pass it." });
|
|
34896
|
+
subscription = Option61.String("--subscription", { description: "Azure subscription id used to find your deployment. Never sent to m8t." });
|
|
34897
|
+
resourceGroup = Option61.String("--resource-group", { description: "Resource group to disambiguate discovery, if you have more than one m8t deployment." });
|
|
34898
|
+
force = Option61.Boolean("--force", false, { description: "Enroll even when a key is already stored. Use only when m8t support asks you to." });
|
|
34634
34899
|
async executeCommand() {
|
|
34635
34900
|
const account = await getAzAccount();
|
|
34636
34901
|
const subscriptionId = (typeof this.subscription === "string" ? this.subscription : void 0) ?? account.subscriptionId;
|
|
@@ -34663,13 +34928,13 @@ var TelemetryEnrollCommand = class extends M8tCommand {
|
|
|
34663
34928
|
...company ? { company } : {},
|
|
34664
34929
|
...contactEmail ? { contactEmail } : {}
|
|
34665
34930
|
});
|
|
34666
|
-
const keyDir =
|
|
34667
|
-
const keyFile =
|
|
34931
|
+
const keyDir = fs41.mkdtempSync(path46.join(os22.tmpdir(), "m8t-ingest-key-"));
|
|
34932
|
+
const keyFile = path46.join(keyDir, "key");
|
|
34668
34933
|
try {
|
|
34669
|
-
|
|
34934
|
+
fs41.writeFileSync(keyFile, ingestKey, { mode: 384 });
|
|
34670
34935
|
await runAz(["keyvault", "secret", "set", "--vault-name", kvName, "--name", INGEST_KEY_SECRET, "--file", keyFile, "--only-show-errors"]);
|
|
34671
34936
|
} finally {
|
|
34672
|
-
|
|
34937
|
+
fs41.rmSync(keyDir, { recursive: true, force: true });
|
|
34673
34938
|
}
|
|
34674
34939
|
this.context.stdout.write(
|
|
34675
34940
|
`${colors.success("\u2713")} enrolled (instance ${instanceId}); ingest key stored in Key Vault ${kvName}. The gateway picks it up on its next cycle.
|
|
@@ -34680,7 +34945,7 @@ var TelemetryEnrollCommand = class extends M8tCommand {
|
|
|
34680
34945
|
};
|
|
34681
34946
|
|
|
34682
34947
|
// src/commands/companion/bridge.ts
|
|
34683
|
-
import { Command as
|
|
34948
|
+
import { Command as Command65, Option as Option62 } from "clipanion";
|
|
34684
34949
|
|
|
34685
34950
|
// ../../packages/companion-bridge-contract/src/index.ts
|
|
34686
34951
|
var COMPANION_MESSAGE_MAX_CODE_POINTS = 32768;
|
|
@@ -36136,14 +36401,14 @@ async function runCompanionBridge(stdin, stdout, stderr, deps = defaultDeps4) {
|
|
|
36136
36401
|
return 3;
|
|
36137
36402
|
}
|
|
36138
36403
|
}
|
|
36139
|
-
var CompanionBridgeCommand = class extends
|
|
36404
|
+
var CompanionBridgeCommand = class extends Command65 {
|
|
36140
36405
|
static paths = [["companion", "_bridge"]];
|
|
36141
36406
|
/**
|
|
36142
36407
|
* One process serving many requests instead of one per request, so the
|
|
36143
36408
|
* session keeps its authenticated context between them. A CLI predating the
|
|
36144
36409
|
* flag rejects it outright, which is how the app knows to fall back.
|
|
36145
36410
|
*/
|
|
36146
|
-
serve =
|
|
36411
|
+
serve = Option62.Boolean("--serve", false);
|
|
36147
36412
|
async execute() {
|
|
36148
36413
|
if (this.serve) {
|
|
36149
36414
|
return runCompanionBridgeServe(
|
|
@@ -36161,7 +36426,7 @@ var CompanionBridgeCommand = class extends Command64 {
|
|
|
36161
36426
|
};
|
|
36162
36427
|
|
|
36163
36428
|
// src/commands/companion/status.ts
|
|
36164
|
-
import { Command as
|
|
36429
|
+
import { Command as Command66 } from "clipanion";
|
|
36165
36430
|
async function withTimeout(work, ms) {
|
|
36166
36431
|
let timer;
|
|
36167
36432
|
try {
|
|
@@ -36233,7 +36498,7 @@ Run: m8t companion install
|
|
|
36233
36498
|
}
|
|
36234
36499
|
var CompanionStatusCommand = class extends M8tCommand {
|
|
36235
36500
|
static paths = [["companion", "status"]];
|
|
36236
|
-
static usage =
|
|
36501
|
+
static usage = Command66.Usage({
|
|
36237
36502
|
description: "Verify the installed desktop companion without launching it."
|
|
36238
36503
|
});
|
|
36239
36504
|
async executeCommand() {
|
|
@@ -36247,7 +36512,7 @@ var CompanionStatusCommand = class extends M8tCommand {
|
|
|
36247
36512
|
};
|
|
36248
36513
|
|
|
36249
36514
|
// src/commands/companion/repair.ts
|
|
36250
|
-
import { Command as
|
|
36515
|
+
import { Command as Command67, Option as Option63 } from "clipanion";
|
|
36251
36516
|
async function runCompanionRepairCommand(stdout, repair) {
|
|
36252
36517
|
const state = await repair();
|
|
36253
36518
|
if (state.state === "not-released") {
|
|
@@ -36266,10 +36531,10 @@ async function runCompanionRepairCommand(stdout, repair) {
|
|
|
36266
36531
|
}
|
|
36267
36532
|
var CompanionRepairCommand = class extends M8tCommand {
|
|
36268
36533
|
static paths = [["companion", "repair"]];
|
|
36269
|
-
static usage =
|
|
36534
|
+
static usage = Command67.Usage({
|
|
36270
36535
|
description: "Restore the desktop companions and start-at-login state."
|
|
36271
36536
|
});
|
|
36272
|
-
resourceGroup =
|
|
36537
|
+
resourceGroup = Option63.String("--resource-group", {
|
|
36273
36538
|
description: "Which deployment to bind to, when the subscription holds more than one."
|
|
36274
36539
|
});
|
|
36275
36540
|
async executeCommand() {
|
|
@@ -36283,7 +36548,7 @@ var CompanionRepairCommand = class extends M8tCommand {
|
|
|
36283
36548
|
};
|
|
36284
36549
|
|
|
36285
36550
|
// src/commands/companion/uninstall.ts
|
|
36286
|
-
import { Command as
|
|
36551
|
+
import { Command as Command68 } from "clipanion";
|
|
36287
36552
|
async function runCompanionUninstallCommand(stdout, uninstall) {
|
|
36288
36553
|
const state = await uninstall();
|
|
36289
36554
|
if (state.state !== "not-installed") {
|
|
@@ -36295,7 +36560,7 @@ async function runCompanionUninstallCommand(stdout, uninstall) {
|
|
|
36295
36560
|
}
|
|
36296
36561
|
var CompanionUninstallCommand = class extends M8tCommand {
|
|
36297
36562
|
static paths = [["companion", "uninstall"]];
|
|
36298
|
-
static usage =
|
|
36563
|
+
static usage = Command68.Usage({
|
|
36299
36564
|
description: "Remove only this user's desktop companion installation."
|
|
36300
36565
|
});
|
|
36301
36566
|
async executeCommand() {
|
|
@@ -36352,8 +36617,9 @@ cli.register(AzureExecDeployCommand);
|
|
|
36352
36617
|
cli.register(PlatformStatusCommand);
|
|
36353
36618
|
cli.register(PlatformUpdateCommand);
|
|
36354
36619
|
cli.register(PlatformConvergeCommand);
|
|
36620
|
+
cli.register(PlatformClearIntentCommand);
|
|
36621
|
+
cli.register(PlatformRequestUpdateCommand);
|
|
36355
36622
|
cli.register(PlatformSeedStampCommand);
|
|
36356
|
-
cli.register(PlatformStampBuildCommand);
|
|
36357
36623
|
cli.register(PlatformPolicyCommand);
|
|
36358
36624
|
cli.register(PlatformEnableCostReportCommand);
|
|
36359
36625
|
cli.register(PlatformEnableAutoUpdateCommand);
|