@mutmutco/cli 3.4.0 → 3.6.0
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/main.cjs +67 -45
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -4529,9 +4529,16 @@ function buildSessionStartPlan(verbs) {
|
|
|
4529
4529
|
]
|
|
4530
4530
|
};
|
|
4531
4531
|
}
|
|
4532
|
-
|
|
4532
|
+
var WIN32_TRAMPOLINE = "const{spawn}=require('node:child_process');const a=JSON.parse(process.argv[1]);const c=spawn(a.cmd,a.args,{stdio:'ignore',windowsHide:true,cwd:a.cwd});c.on('exit',x=>process.exit(x??0));c.on('error',()=>process.exit(1));";
|
|
4533
|
+
function spawnDetachedSelf(args, deps, opts = {}) {
|
|
4533
4534
|
try {
|
|
4534
|
-
|
|
4535
|
+
const platform2 = deps.platform ?? process.platform;
|
|
4536
|
+
if (platform2 === "win32") {
|
|
4537
|
+
const payload = JSON.stringify({ cmd: deps.execPath, args: [deps.scriptPath, ...args], cwd: opts.cwd });
|
|
4538
|
+
deps.spawn(deps.execPath, ["-e", WIN32_TRAMPOLINE, payload], { detached: true, stdio: "ignore", windowsHide: true }).unref();
|
|
4539
|
+
return;
|
|
4540
|
+
}
|
|
4541
|
+
deps.spawn(deps.execPath, [deps.scriptPath, ...args], { detached: true, stdio: "ignore", windowsHide: true, ...opts.cwd ? { cwd: opts.cwd } : {} }).unref();
|
|
4535
4542
|
} catch {
|
|
4536
4543
|
}
|
|
4537
4544
|
}
|
|
@@ -10904,7 +10911,7 @@ async function retireRcRuntime(deps, ctx, model, deployStatus, releasedRcSha) {
|
|
|
10904
10911
|
}
|
|
10905
10912
|
async function runTenantRedeploy(deps, options) {
|
|
10906
10913
|
const { stage: stage2 } = options;
|
|
10907
|
-
const ref = options.ref ?? stage2;
|
|
10914
|
+
const ref = options.ref ?? (stage2 === "dev" ? "development" : stage2);
|
|
10908
10915
|
const watch = options.watch ?? false;
|
|
10909
10916
|
const repo = options.repo;
|
|
10910
10917
|
const [owner, name] = repo.split("/");
|
|
@@ -12893,7 +12900,7 @@ function runtimeSecretStreamGap(stage2, meta, presentSecrets) {
|
|
|
12893
12900
|
for (const name of stageRequiredSecrets(stage2, meta).map(materializedRuntimeSecretName)) {
|
|
12894
12901
|
if (seen.has(name)) continue;
|
|
12895
12902
|
seen.add(name);
|
|
12896
|
-
if (!streamed.has(name) && presentSecrets.has(stageKey(stage2, name))) gap.push(name);
|
|
12903
|
+
if (!streamed.has(name) && (presentSecrets.has(stageKey(stage2, name)) || presentSecrets.has(name))) gap.push(name);
|
|
12897
12904
|
}
|
|
12898
12905
|
return gap;
|
|
12899
12906
|
}
|
|
@@ -13137,9 +13144,11 @@ async function buildV2Doctor(repoOrSlug, deps) {
|
|
|
13137
13144
|
return [stage2, { required, ok: required ? await deps.hasDeployState(slug, stage2) : true }];
|
|
13138
13145
|
})));
|
|
13139
13146
|
const secrets = Object.fromEntries(STAGES.map((stage2) => {
|
|
13140
|
-
const
|
|
13141
|
-
const
|
|
13142
|
-
const
|
|
13147
|
+
const names = stageInTrack(meta, stage2) ? stageRequiredSecrets(stage2, meta) : [];
|
|
13148
|
+
const satisfied = (key) => presentSecrets.has(stageKey(stage2, key)) || !key.includes("/") && presentSecrets.has(key);
|
|
13149
|
+
const required = names.map((key) => stageKey(stage2, key));
|
|
13150
|
+
const present = names.filter(satisfied).map((key) => stageKey(stage2, key));
|
|
13151
|
+
const missing = names.filter((key) => !satisfied(key)).map((key) => stageKey(stage2, key));
|
|
13143
13152
|
return [stage2, { required, present, missing }];
|
|
13144
13153
|
}));
|
|
13145
13154
|
const runtimeSecretStreamWarnings = Object.fromEntries(STAGES.map((stage2) => [
|
|
@@ -13268,7 +13277,6 @@ var DEFAULT_DOMAINS = ["mutatismutandis.co", "mutmut.co"];
|
|
|
13268
13277
|
var DEFAULT_CALLBACK_PATH = "/api/auth/callback";
|
|
13269
13278
|
var ENV_PREFIXES = ["", "dev", "rc"];
|
|
13270
13279
|
var LOOPBACK = ["http://localhost", "http://127.0.0.1"];
|
|
13271
|
-
var SSM_ENVS = ["dev", "rc", "main"];
|
|
13272
13280
|
var SSM_NAMES = ["GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET"];
|
|
13273
13281
|
var uniq = (xs) => [...new Set(xs)];
|
|
13274
13282
|
function defaultSubdomain2(slug) {
|
|
@@ -13299,7 +13307,7 @@ function expectedRedirectUris(cfg) {
|
|
|
13299
13307
|
]);
|
|
13300
13308
|
}
|
|
13301
13309
|
function oauthSsmKeys() {
|
|
13302
|
-
return
|
|
13310
|
+
return [...SSM_NAMES];
|
|
13303
13311
|
}
|
|
13304
13312
|
function parseOauthClientJson(input) {
|
|
13305
13313
|
let parsed;
|
|
@@ -13373,11 +13381,20 @@ function parseSecretsCatalogVar(raw) {
|
|
|
13373
13381
|
throw new Error("project set: secrets must be a map keyed by canonical KEY");
|
|
13374
13382
|
}
|
|
13375
13383
|
const nonEmpty = (v) => typeof v === "string" && v.trim().length > 0;
|
|
13384
|
+
const overrideMapKey = /^([A-Z_][A-Z0-9_]*)@(dev|rc|main)$/;
|
|
13376
13385
|
for (const [mapKey, value] of Object.entries(parsed)) {
|
|
13377
13386
|
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error(`project set: secrets["${mapKey}"] must be an object`);
|
|
13378
13387
|
const e = value;
|
|
13379
|
-
if (typeof e.key !== "string" || !SECRET_ENV_NAME_RE.test(e.key)
|
|
13380
|
-
throw new Error(`project set: secrets["${mapKey}"].key must
|
|
13388
|
+
if (typeof e.key !== "string" || !SECRET_ENV_NAME_RE.test(e.key)) {
|
|
13389
|
+
throw new Error(`project set: secrets["${mapKey}"].key must be an env-name (UPPER_SNAKE)`);
|
|
13390
|
+
}
|
|
13391
|
+
const override = overrideMapKey.exec(mapKey);
|
|
13392
|
+
if (override) {
|
|
13393
|
+
if (e.key !== override[1] || !Array.isArray(e.stages) || e.stages.length !== 1 || e.stages[0] !== override[2]) {
|
|
13394
|
+
throw new Error(`project set: secrets["${mapKey}"] is an override entry (#2528) \u2014 key must be ${override[1]} and stages exactly ["${override[2]}"]`);
|
|
13395
|
+
}
|
|
13396
|
+
} else if (e.key !== mapKey) {
|
|
13397
|
+
throw new Error(`project set: secrets["${mapKey}"].key must equal the map key (or use the KEY@<stage> override form, #2528)`);
|
|
13381
13398
|
}
|
|
13382
13399
|
if (!nonEmpty(e.purpose) || !nonEmpty(e.group) || !nonEmpty(e.owner)) throw new Error(`project set: secrets["${mapKey}"] needs non-empty purpose, group, owner`);
|
|
13383
13400
|
if (e.provider !== void 0 && !nonEmpty(e.provider)) throw new Error(`project set: secrets["${mapKey}"].provider must be a non-empty string`);
|
|
@@ -13924,8 +13941,7 @@ function classifyTier(_slug, key) {
|
|
|
13924
13941
|
return key.slice(0, slash) === PROJECT_TIER_SEGMENT ? "project" : "org";
|
|
13925
13942
|
}
|
|
13926
13943
|
function secretParamName(slug, key) {
|
|
13927
|
-
|
|
13928
|
-
return `${SSM_ROOT}/${slug}/${rel}`;
|
|
13944
|
+
return `${SSM_ROOT}/${slug}/${key}`;
|
|
13929
13945
|
}
|
|
13930
13946
|
function formatSecretList(items) {
|
|
13931
13947
|
if (!items.length) return "no secrets";
|
|
@@ -13944,10 +13960,10 @@ function vaultPointer(slug) {
|
|
|
13944
13960
|
org: [`/mmi-future/{shared,cloudflare,mmi-hub,...}/* (org-infra, master-gated)`]
|
|
13945
13961
|
},
|
|
13946
13962
|
stages: ["dev", "rc", "main"],
|
|
13947
|
-
// Google OAuth is one client per repo
|
|
13948
|
-
//
|
|
13963
|
+
// Google OAuth is one client per repo = ONE stageless value pair at the slug root (#2244/#2528);
|
|
13964
|
+
// every stage (and local) reads the same pair. The staged {dev,rc,main}/GOOGLE_* shape is retired.
|
|
13949
13965
|
wellKnown: {
|
|
13950
|
-
googleOAuth: ["
|
|
13966
|
+
googleOAuth: ["GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET"]
|
|
13951
13967
|
}
|
|
13952
13968
|
};
|
|
13953
13969
|
}
|
|
@@ -14203,8 +14219,9 @@ function formatCatalog(r) {
|
|
|
14203
14219
|
return lines.join("\n");
|
|
14204
14220
|
}
|
|
14205
14221
|
function formatDrift(d) {
|
|
14206
|
-
|
|
14207
|
-
|
|
14222
|
+
const shadows = d.stagedShadow ?? [];
|
|
14223
|
+
if (d.ok && !shadows.length) return "vault doctor: zero drift \u2014 SSM matches the catalog.";
|
|
14224
|
+
const lines = [d.ok ? "vault doctor: zero drift \u2014 SSM matches the catalog. Advisories:" : "vault doctor: drift found", ""];
|
|
14208
14225
|
const section = (title, rows) => {
|
|
14209
14226
|
if (!rows.length) return;
|
|
14210
14227
|
lines.push(`${title} (${rows.length}):`, ...rows.map((r) => ` - ${r}`), "");
|
|
@@ -14213,6 +14230,10 @@ function formatDrift(d) {
|
|
|
14213
14230
|
section("ORPHAN in SSM, undeclared \u2014 declare or delete", d.orphan.map((o) => o.path));
|
|
14214
14231
|
section("OFF-SCHEME path", d.offScheme.map((o) => `${o.path} (${o.reason})`));
|
|
14215
14232
|
section("STAGE-SPLIT \u2014 collapse to one shared key", (d.stageSplit ?? []).map((s) => `${s.slug}/${s.leaf} split across ${s.stages.join("/")}`));
|
|
14233
|
+
section(
|
|
14234
|
+
"STAGED SHADOW \u2014 the staged override WINS its stage over the stageless canonical (#2522)",
|
|
14235
|
+
shadows.map((s) => `${s.path} shadows ${s.canonicalPath}${s.declared ? "" : " (UNDECLARED residue \u2014 triage per #2526)"}`)
|
|
14236
|
+
);
|
|
14216
14237
|
section("DUPLICATE org-infra secret", d.duplicate.map((dup) => `${dup.logical}: ${dup.paths.join(" , ")}`));
|
|
14217
14238
|
return lines.join("\n").trimEnd();
|
|
14218
14239
|
}
|
|
@@ -14317,10 +14338,11 @@ async function secretsPreflight(deps, opts) {
|
|
|
14317
14338
|
}
|
|
14318
14339
|
const { secrets } = await res.json();
|
|
14319
14340
|
const present = new Set((secrets ?? []).map((s) => s.key));
|
|
14320
|
-
const
|
|
14321
|
-
|
|
14341
|
+
const missing = opts.required.filter(
|
|
14342
|
+
(key) => !present.has(stageKey2(opts.stage, key)) && !(key.includes("/") ? false : present.has(key))
|
|
14343
|
+
);
|
|
14322
14344
|
if (missing.length) {
|
|
14323
|
-
deps.log(`missing ${missing.join(", ")}`);
|
|
14345
|
+
deps.log(`missing ${missing.map((key) => key.includes("/") ? key : `${stageKey2(opts.stage, key)} (and no stageless ${key})`).join(", ")}`);
|
|
14324
14346
|
return false;
|
|
14325
14347
|
}
|
|
14326
14348
|
deps.log(`all required ${opts.stage} secret names are present`);
|
|
@@ -14352,7 +14374,8 @@ async function secretsGet(deps, key, opts) {
|
|
|
14352
14374
|
);
|
|
14353
14375
|
return false;
|
|
14354
14376
|
}
|
|
14355
|
-
const { value } = await res.json();
|
|
14377
|
+
const { value, notes } = await res.json();
|
|
14378
|
+
for (const note of notes ?? []) deps.err(`note: ${note}`);
|
|
14356
14379
|
deps.log(value ?? "");
|
|
14357
14380
|
return true;
|
|
14358
14381
|
}
|
|
@@ -14432,6 +14455,8 @@ async function putSecret(deps, key, value, opts) {
|
|
|
14432
14455
|
);
|
|
14433
14456
|
return false;
|
|
14434
14457
|
}
|
|
14458
|
+
const { warnings } = await res.json();
|
|
14459
|
+
for (const warning of warnings ?? []) deps.err(`warning: ${warning}`);
|
|
14435
14460
|
const provider = providerForSecretKey(key);
|
|
14436
14461
|
if (provider) {
|
|
14437
14462
|
const result = await verifySecretValue(deps, key, value, opts);
|
|
@@ -14827,7 +14852,7 @@ function registerSecretsCommands(program3) {
|
|
|
14827
14852
|
const ok = await secretsVerify(d, key, o);
|
|
14828
14853
|
if (!ok) process.exitCode = 1;
|
|
14829
14854
|
}));
|
|
14830
|
-
secrets.command("set <key>").description("write/rotate a secret; value
|
|
14855
|
+
secrets.command("set <key>").description("write/rotate a secret; value from stdin (never an argument). DECLARE-FIRST (#2528): the key must be a declared catalog coordinate \u2014 bare <KEY> = the stageless canonical, <stage>/<KEY> = a declared per-stage override; undeclared writes are rejected with the fix").option("--repo <owner/repo>", "target repo (defaults to the current repo)").action((key, o) => withSecrets(async (d) => {
|
|
14831
14856
|
const ok = await secretsSet(d, key, o);
|
|
14832
14857
|
if (!ok) process.exitCode = 1;
|
|
14833
14858
|
}));
|
|
@@ -17144,6 +17169,14 @@ ${stderr}`);
|
|
|
17144
17169
|
return false;
|
|
17145
17170
|
}
|
|
17146
17171
|
}
|
|
17172
|
+
function healBannerLine(bin, token, refSupported) {
|
|
17173
|
+
const installVerb = token === "codex" ? "add" : "install";
|
|
17174
|
+
return refSupported ? ` \u21BB reinstalling the MMI plugin via \`${bin} plugin\` (marketplace remove \u2192 add --ref main \u2192 ${installVerb})\u2026` : ` \u21BB reinstalling the MMI plugin via \`${bin} plugin\` (marketplace remove \u2192 add \u2192 ${installVerb}; release ref pinned by the marketplace manifest)\u2026`;
|
|
17175
|
+
}
|
|
17176
|
+
function refAbsenceNote(bin, refSupported) {
|
|
17177
|
+
return refSupported ? "" : `
|
|
17178
|
+
Note: \`${bin}\` has no \`--ref\` option; the marketplace manifest pins the released branch, so none is needed (#2516).`;
|
|
17179
|
+
}
|
|
17147
17180
|
async function applyPluginHeal(token, surface, log, opts) {
|
|
17148
17181
|
if (!opts?.force && surfaceToken(surface) !== token) return false;
|
|
17149
17182
|
const descriptor = PLUGIN_SURFACE_HEAL[token];
|
|
@@ -17152,13 +17185,8 @@ async function applyPluginHeal(token, surface, log, opts) {
|
|
|
17152
17185
|
const bin = descriptor.pluginRunner === "codex" ? "codex" : "claude";
|
|
17153
17186
|
const runner = descriptor.pluginRunner === "codex" ? runCodexPlugin : runClaudePlugin;
|
|
17154
17187
|
const refSupported = await marketplaceAddRefSupported(bin);
|
|
17155
|
-
const { steps
|
|
17156
|
-
log(
|
|
17157
|
-
refSupported ? ` \u21BB reinstalling the MMI plugin via \`${bin} plugin\` (marketplace remove \u2192 add --ref main \u2192 ${token === "codex" ? "add" : "install"})\u2026` : ` \u21BB reinstalling the MMI plugin via \`${bin} plugin\` (marketplace remove \u2192 add \u2192 ${token === "codex" ? "add" : "install"})\u2026`
|
|
17158
|
-
);
|
|
17159
|
-
if (strippedRef) {
|
|
17160
|
-
log(` \u26A0 \`${bin}\` has no \`--ref\` option \u2014 cloning the default branch; update \`${bin}\` to pin the released \`main\` branch (#2080)`);
|
|
17161
|
-
}
|
|
17188
|
+
const { steps } = adaptHealStepsForRefSupport(tableSteps, refSupported);
|
|
17189
|
+
log(healBannerLine(bin, token, refSupported));
|
|
17162
17190
|
for (const step of steps) {
|
|
17163
17191
|
if (healStepAborts(step, await runner([...step.args]))) return false;
|
|
17164
17192
|
}
|
|
@@ -18679,8 +18707,7 @@ async function runPluginHeal(surface = detectSurface(process.env)) {
|
|
|
18679
18707
|
const bin = descriptor.pluginRunner === "codex" ? "codex" : "claude";
|
|
18680
18708
|
const refSupported = await marketplaceAddRefSupported(bin);
|
|
18681
18709
|
const recovery = refSupported ? descriptor.recovery : recoveryWithoutRef(descriptor.recovery);
|
|
18682
|
-
const note = refSupported
|
|
18683
|
-
Note: \`${bin}\` has no \`--ref\` option here; update \`${bin}\` to pin the released \`main\` branch.`;
|
|
18710
|
+
const note = refAbsenceNote(bin, refSupported);
|
|
18684
18711
|
console.log(` \u2717 Auto-heal failed or was skipped. Run manually:
|
|
18685
18712
|
${recovery}${note}`);
|
|
18686
18713
|
}
|
|
@@ -19186,12 +19213,7 @@ function scheduleRelatedDiscovery(o) {
|
|
|
19186
19213
|
try {
|
|
19187
19214
|
const args = ["issue", "discover-related", "--number", String(o.number), "--title", o.title, "--body", o.body];
|
|
19188
19215
|
if (o.repo) args.push("--repo", o.repo);
|
|
19189
|
-
(
|
|
19190
|
-
detached: true,
|
|
19191
|
-
stdio: "ignore",
|
|
19192
|
-
windowsHide: true,
|
|
19193
|
-
cwd: process.cwd()
|
|
19194
|
-
}).unref();
|
|
19216
|
+
spawnDetachedSelf(args, { spawn: import_node_child_process12.spawn, execPath: process.execPath, scriptPath: process.argv[1] }, { cwd: process.cwd() });
|
|
19195
19217
|
} catch {
|
|
19196
19218
|
}
|
|
19197
19219
|
}
|
|
@@ -19242,8 +19264,8 @@ tenant.command("readiness <owner/repo> <stage>").description("alias for tenant s
|
|
|
19242
19264
|
console.log(JSON.stringify(result, null, 2));
|
|
19243
19265
|
if (result.publicProbe?.ok === false) process.exitCode = 1;
|
|
19244
19266
|
});
|
|
19245
|
-
tenant.command("redeploy <owner/repo> <stage>").description("re-dispatch the central tenant-deploy.yml for an already-promoted ref (no re-tag/merge); train-authority gated").option("--ref <ref>", "ref to deploy (defaults to the stage branch rc/main \u2014 the promoted ref)").option("--watch", "block on the dispatched run and report its outcome (gh run watch --exit-status)").option("--json", "machine-readable output").action(async (repo, stage2, o) => {
|
|
19246
|
-
if (stage2 !== "rc" && stage2 !== "main") return fail("tenant redeploy: <stage> must be rc or main");
|
|
19267
|
+
tenant.command("redeploy <owner/repo> <stage>").description("re-dispatch the central tenant-deploy.yml for an already-promoted ref (no re-tag/merge); train-authority gated").option("--ref <ref>", "ref to deploy (defaults to the stage branch rc/main, or `development` for dev \u2014 the promoted/staging ref)").option("--watch", "block on the dispatched run and report its outcome (gh run watch --exit-status)").option("--json", "machine-readable output").action(async (repo, stage2, o) => {
|
|
19268
|
+
if (stage2 !== "dev" && stage2 !== "rc" && stage2 !== "main") return fail("tenant redeploy: <stage> must be dev, rc, or main");
|
|
19247
19269
|
try {
|
|
19248
19270
|
const result = await runTenantRedeploy(trainApplyDeps(), { repo, stage: stage2, ref: o.ref, watch: o.watch });
|
|
19249
19271
|
return printLine(o.json ? JSON.stringify(result, null, 2) : renderTenantRedeploy(result));
|
|
@@ -19704,7 +19726,7 @@ SSM cred params (under /mmi-future/${slug}/):`);
|
|
|
19704
19726
|
ssm.forEach((k) => console.log(` ${k}`));
|
|
19705
19727
|
console.log("\nProvision/repair the Console client per docs/Guides/oauth-provision.md; store creds with `mmi-cli oauth set-creds`.");
|
|
19706
19728
|
});
|
|
19707
|
-
oauth.command("set-creds").description('store the OAuth client into the canonical
|
|
19729
|
+
oauth.command("set-creds").description('store the OAuth client into the canonical stageless GOOGLE_CLIENT_ID/SECRET pair (pipe the Console "Download JSON" on stdin)').option("--repo <owner/repo>", "target repo (defaults to the current repo)").action(async (o) => {
|
|
19708
19730
|
const raw = await readStdin();
|
|
19709
19731
|
if (!raw.trim()) {
|
|
19710
19732
|
return fail("oauth set-creds: pipe the Google client JSON on stdin \u2014 e.g.\n mmi-cli oauth set-creds --repo <owner/repo> < client.json");
|
|
@@ -19723,10 +19745,10 @@ oauth.command("set-creds").description('store the OAuth client into the canonica
|
|
|
19723
19745
|
return;
|
|
19724
19746
|
}
|
|
19725
19747
|
}
|
|
19726
|
-
console.log(`OAuth client stored in
|
|
19748
|
+
console.log(`OAuth client stored in the ${oauthSsmKeys().length} canonical stageless keys. Run \`mmi-cli oauth verify\` to confirm the client is port-agnostic.`);
|
|
19727
19749
|
});
|
|
19728
19750
|
});
|
|
19729
|
-
oauth.command("verify").description("probe Google authorize with an arbitrary port (:9123) to confirm the client is port-agnostic").option("--repo <owner/repo>", "target repo (defaults to the current repo)").option("--client-id <id>", "OAuth client_id (else read
|
|
19751
|
+
oauth.command("verify").description("probe Google authorize with an arbitrary port (:9123) to confirm the client is port-agnostic").option("--repo <owner/repo>", "target repo (defaults to the current repo)").option("--client-id <id>", "OAuth client_id (else read the stageless GOOGLE_CLIENT_ID from SSM)").option("--json", "machine-readable output").action(async (o) => {
|
|
19730
19752
|
const cfg = await loadConfig();
|
|
19731
19753
|
const slug = (o.repo ? o.repo.split("/").pop() : cfg.project ?? await repoSlug()).toLowerCase();
|
|
19732
19754
|
const meta = await fetchProjectBySlug(slug, registryClientDeps(cfg));
|
|
@@ -19739,11 +19761,11 @@ oauth.command("verify").description("probe Google authorize with an arbitrary po
|
|
|
19739
19761
|
let clientId = o.clientId;
|
|
19740
19762
|
if (!clientId) {
|
|
19741
19763
|
await withSecrets(async (d) => {
|
|
19742
|
-
clientId = await fetchSecretValue(d, "
|
|
19764
|
+
clientId = await fetchSecretValue(d, "GOOGLE_CLIENT_ID", { repo: o.repo }) ?? void 0;
|
|
19743
19765
|
});
|
|
19744
19766
|
}
|
|
19745
19767
|
if (!clientId) {
|
|
19746
|
-
return failGraceful("oauth verify: no client_id (pass --client-id, or provision the repo so
|
|
19768
|
+
return failGraceful("oauth verify: no client_id (pass --client-id, or provision the repo so GOOGLE_CLIENT_ID exists)");
|
|
19747
19769
|
}
|
|
19748
19770
|
const redirectUri = probeRedirectUri(oc.callbackPath);
|
|
19749
19771
|
let body = "";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mutmutco/cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.6.0",
|
|
4
4
|
"description": "MMI Future CLI — the org dev toolbox (board, registry, keyless secrets, release train, bootstrap, doctor) and the cross-IDE engine the plugin's session-start hook drives.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "UNLICENSED",
|