@mutmutco/cli 4.3.45 → 4.3.47
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/README.md +1 -1
- package/dist/main.cjs +2183 -1946
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -5,6 +5,14 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __esm = (fn, res, err) => function __init() {
|
|
9
|
+
if (err) throw err[0];
|
|
10
|
+
try {
|
|
11
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
12
|
+
} catch (e) {
|
|
13
|
+
throw err = [e], e;
|
|
14
|
+
}
|
|
15
|
+
};
|
|
8
16
|
var __export = (target, all) => {
|
|
9
17
|
for (var name in all)
|
|
10
18
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -27,306 +35,1403 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
27
35
|
));
|
|
28
36
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
37
|
|
|
30
|
-
// src/
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
isOrgRegisteredRepo: () => isOrgRegisteredRepo,
|
|
41
|
-
parseInvalidChoiceError: () => parseInvalidChoiceError,
|
|
42
|
-
positionalTargetForm: () => positionalTargetForm,
|
|
43
|
-
registryClientDeps: () => registryClientDeps,
|
|
44
|
-
repoSlug: () => repoSlug,
|
|
45
|
-
suggestCommandPath: () => suggestCommandPath,
|
|
46
|
-
unknownCommandCandidates: () => unknownCommandCandidates
|
|
47
|
-
});
|
|
48
|
-
module.exports = __toCommonJS(index_exports);
|
|
49
|
-
|
|
50
|
-
// node_modules/commander/lib/error.js
|
|
51
|
-
var CommanderError = class extends Error {
|
|
52
|
-
/**
|
|
53
|
-
* Constructs the CommanderError class
|
|
54
|
-
* @param {number} exitCode suggested exit code which could be used with process.exit
|
|
55
|
-
* @param {string} code an id string representing the error
|
|
56
|
-
* @param {string} message human-readable description of the error
|
|
57
|
-
*/
|
|
58
|
-
constructor(exitCode, code, message2) {
|
|
59
|
-
super(message2);
|
|
60
|
-
Error.captureStackTrace(this, this.constructor);
|
|
61
|
-
this.name = this.constructor.name;
|
|
62
|
-
this.code = code;
|
|
63
|
-
this.exitCode = exitCode;
|
|
64
|
-
this.nestedError = void 0;
|
|
65
|
-
}
|
|
66
|
-
};
|
|
67
|
-
var InvalidArgumentError = class extends CommanderError {
|
|
68
|
-
/**
|
|
69
|
-
* Constructs the InvalidArgumentError class
|
|
70
|
-
* @param {string} [message] explanation of why argument is invalid
|
|
71
|
-
*/
|
|
72
|
-
constructor(message2) {
|
|
73
|
-
super(1, "commander.invalidArgument", message2);
|
|
74
|
-
Error.captureStackTrace(this, this.constructor);
|
|
75
|
-
this.name = this.constructor.name;
|
|
76
|
-
}
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
// node_modules/commander/lib/argument.js
|
|
80
|
-
var Argument = class {
|
|
81
|
-
/**
|
|
82
|
-
* Initialize a new command argument with the given name and description.
|
|
83
|
-
* The default is that the argument is required, and you can explicitly
|
|
84
|
-
* indicate this with <> around the name. Put [] around the name for an optional argument.
|
|
85
|
-
*
|
|
86
|
-
* @param {string} name
|
|
87
|
-
* @param {string} [description]
|
|
88
|
-
*/
|
|
89
|
-
constructor(name, description) {
|
|
90
|
-
this.description = description || "";
|
|
91
|
-
this.variadic = false;
|
|
92
|
-
this.parseArg = void 0;
|
|
93
|
-
this.defaultValue = void 0;
|
|
94
|
-
this.defaultValueDescription = void 0;
|
|
95
|
-
this.argChoices = void 0;
|
|
96
|
-
switch (name[0]) {
|
|
97
|
-
case "<":
|
|
98
|
-
this.required = true;
|
|
99
|
-
this._name = name.slice(1, -1);
|
|
100
|
-
break;
|
|
101
|
-
case "[":
|
|
102
|
-
this.required = false;
|
|
103
|
-
this._name = name.slice(1, -1);
|
|
104
|
-
break;
|
|
105
|
-
default:
|
|
106
|
-
this.required = true;
|
|
107
|
-
this._name = name;
|
|
108
|
-
break;
|
|
109
|
-
}
|
|
110
|
-
if (this._name.endsWith("...")) {
|
|
111
|
-
this.variadic = true;
|
|
112
|
-
this._name = this._name.slice(0, -3);
|
|
38
|
+
// src/clean-exit.ts
|
|
39
|
+
function globalDispatcher() {
|
|
40
|
+
return globalThis[UNDICI_GLOBAL_DISPATCHER_SYMBOL];
|
|
41
|
+
}
|
|
42
|
+
function destroyHttpPool() {
|
|
43
|
+
try {
|
|
44
|
+
const dispatcher = globalDispatcher();
|
|
45
|
+
if (dispatcher?.destroy) {
|
|
46
|
+
void dispatcher.destroy();
|
|
47
|
+
return true;
|
|
113
48
|
}
|
|
49
|
+
} catch {
|
|
114
50
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
async function closeHttpPool() {
|
|
54
|
+
const dispatcher = globalDispatcher();
|
|
55
|
+
if (!dispatcher) return;
|
|
56
|
+
if (dispatcher === closingDispatcher && closingDispatcherPromise) {
|
|
57
|
+
await closingDispatcherPromise;
|
|
58
|
+
return;
|
|
122
59
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
60
|
+
closingDispatcher = dispatcher;
|
|
61
|
+
closingDispatcherPromise = (async () => {
|
|
62
|
+
try {
|
|
63
|
+
if (dispatcher.close) await dispatcher.close();
|
|
64
|
+
else if (dispatcher.destroy) await dispatcher.destroy();
|
|
65
|
+
} catch {
|
|
66
|
+
try {
|
|
67
|
+
if (dispatcher.destroy) await dispatcher.destroy();
|
|
68
|
+
} catch {
|
|
69
|
+
}
|
|
129
70
|
}
|
|
130
|
-
|
|
131
|
-
|
|
71
|
+
})();
|
|
72
|
+
await closingDispatcherPromise;
|
|
73
|
+
}
|
|
74
|
+
function hardExit(code) {
|
|
75
|
+
destroyHttpPool();
|
|
76
|
+
process.exit(code);
|
|
77
|
+
}
|
|
78
|
+
function flushStream(stream) {
|
|
79
|
+
return new Promise((resolve7) => {
|
|
80
|
+
try {
|
|
81
|
+
stream.write("", () => resolve7());
|
|
82
|
+
} catch {
|
|
83
|
+
resolve7();
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
async function flushStdio(timeoutMs = STDIO_FLUSH_TIMEOUT_MS) {
|
|
88
|
+
await Promise.race([
|
|
89
|
+
Promise.all([flushStream(process.stdout), flushStream(process.stderr)]),
|
|
90
|
+
new Promise((resolve7) => {
|
|
91
|
+
setTimeout(resolve7, timeoutMs).unref?.();
|
|
92
|
+
})
|
|
93
|
+
]);
|
|
94
|
+
}
|
|
95
|
+
async function cleanExit(code) {
|
|
96
|
+
process.exitCode = code;
|
|
97
|
+
await closeHttpPool();
|
|
98
|
+
await flushStdio();
|
|
99
|
+
await new Promise((resolve7) => setImmediate(resolve7));
|
|
100
|
+
return void 0;
|
|
101
|
+
}
|
|
102
|
+
async function finishCliRun(watchdogMs = CLI_EXIT_WATCHDOG_MS) {
|
|
103
|
+
const timer = setTimeout(() => {
|
|
104
|
+
console.error(
|
|
105
|
+
`mmi-cli: command finished but the process did not exit within ${watchdogMs}ms \u2014 a handle leaked (${describeActiveHandles()}); forcing exit (#2904). Please report this.`
|
|
106
|
+
);
|
|
107
|
+
void flushStdio().finally(() => process.exit(typeof process.exitCode === "number" ? process.exitCode : 0));
|
|
108
|
+
}, watchdogMs);
|
|
109
|
+
timer.unref?.();
|
|
110
|
+
await closeHttpPool();
|
|
111
|
+
}
|
|
112
|
+
function describeActiveHandles() {
|
|
113
|
+
let summary;
|
|
114
|
+
try {
|
|
115
|
+
const counts = /* @__PURE__ */ new Map();
|
|
116
|
+
for (const type of process.getActiveResourcesInfo()) counts.set(type, (counts.get(type) ?? 0) + 1);
|
|
117
|
+
summary = [...counts.entries()].sort().map(([type, n]) => n > 1 ? `${type}\xD7${n}` : type).join(", ") || "none reported";
|
|
118
|
+
} catch {
|
|
119
|
+
summary = "unavailable";
|
|
132
120
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
* @param {string} [description]
|
|
138
|
-
* @return {Argument}
|
|
139
|
-
*/
|
|
140
|
-
default(value, description) {
|
|
141
|
-
this.defaultValue = value;
|
|
142
|
-
this.defaultValueDescription = description;
|
|
143
|
-
return this;
|
|
121
|
+
try {
|
|
122
|
+
const children = (process._getActiveHandles?.() ?? []).filter((h) => h?.constructor?.name === "ChildProcess").map((h) => `${h.spawnfile ?? "?"}(pid=${h.pid ?? "?"})`);
|
|
123
|
+
if (children.length) summary += `; live children: ${children.join(", ")}`;
|
|
124
|
+
} catch {
|
|
144
125
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
126
|
+
return summary;
|
|
127
|
+
}
|
|
128
|
+
async function failGraceful(msg) {
|
|
129
|
+
console.error(`mmi-cli ${msg}`);
|
|
130
|
+
return cleanExit(1);
|
|
131
|
+
}
|
|
132
|
+
var UNDICI_GLOBAL_DISPATCHER_SYMBOL, closingDispatcher, closingDispatcherPromise, STDIO_FLUSH_TIMEOUT_MS, CLI_EXIT_WATCHDOG_MS;
|
|
133
|
+
var init_clean_exit = __esm({
|
|
134
|
+
"src/clean-exit.ts"() {
|
|
135
|
+
"use strict";
|
|
136
|
+
UNDICI_GLOBAL_DISPATCHER_SYMBOL = Object.getOwnPropertySymbols(globalThis).find(
|
|
137
|
+
(s) => s.description === "undici.globalDispatcher.1" || s.description?.startsWith("undici.globalDispatcher.")
|
|
138
|
+
) ?? /* @__PURE__ */ Symbol.for("undici.globalDispatcher.1");
|
|
139
|
+
STDIO_FLUSH_TIMEOUT_MS = 2e3;
|
|
140
|
+
CLI_EXIT_WATCHDOG_MS = (() => {
|
|
141
|
+
const testOverride = Number(process.env.MMI_CLI_TEST_EXIT_WATCHDOG_MS);
|
|
142
|
+
return process.env.NODE_ENV === "test" && Number.isFinite(testOverride) && testOverride >= 25 ? testOverride : 1e4;
|
|
143
|
+
})();
|
|
154
144
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
`Allowed choices are ${this.argChoices.join(", ")}.`
|
|
167
|
-
);
|
|
168
|
-
}
|
|
169
|
-
if (this.variadic) {
|
|
170
|
-
return this._collectValue(arg, previous);
|
|
171
|
-
}
|
|
172
|
-
return arg;
|
|
173
|
-
};
|
|
174
|
-
return this;
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// src/hub-url.ts
|
|
148
|
+
function defaultHubUrl() {
|
|
149
|
+
return process.env.MMI_HUB_URL || DEFAULT_HUB_URL;
|
|
150
|
+
}
|
|
151
|
+
var DEFAULT_HUB_URL;
|
|
152
|
+
var init_hub_url = __esm({
|
|
153
|
+
"src/hub-url.ts"() {
|
|
154
|
+
"use strict";
|
|
155
|
+
DEFAULT_HUB_URL = "https://tqxxwzftic.execute-api.eu-central-1.amazonaws.com";
|
|
175
156
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
// ../infra/compat.mjs
|
|
160
|
+
function parseSemver(s) {
|
|
161
|
+
if (typeof s !== "string") return null;
|
|
162
|
+
const m = /^(\d+)\.(\d+)\.(\d+)(?:[-+]|$)/.exec(s.trim());
|
|
163
|
+
if (!m) return null;
|
|
164
|
+
return { major: Number(m[1]), minor: Number(m[2]), patch: Number(m[3]) };
|
|
165
|
+
}
|
|
166
|
+
function versionAtLeast(v, min) {
|
|
167
|
+
const a = parseSemver(v);
|
|
168
|
+
const b = parseSemver(min);
|
|
169
|
+
if (!a || !b) return false;
|
|
170
|
+
if (a.major !== b.major) return a.major > b.major;
|
|
171
|
+
if (a.minor !== b.minor) return a.minor > b.minor;
|
|
172
|
+
return a.patch >= b.patch;
|
|
173
|
+
}
|
|
174
|
+
var CLIENT_VERSION_HEADER;
|
|
175
|
+
var init_compat = __esm({
|
|
176
|
+
"../infra/compat.mjs"() {
|
|
177
|
+
"use strict";
|
|
178
|
+
CLIENT_VERSION_HEADER = "x-client-version";
|
|
184
179
|
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// src/client-version.ts
|
|
183
|
+
function resolveClientVersionManifestCandidates(distDir = __dirname) {
|
|
184
|
+
return [
|
|
185
|
+
(0, import_node_path2.join)(distDir, "..", "..", ".claude-plugin", "plugin.json"),
|
|
186
|
+
(0, import_node_path2.join)(distDir, "..", "package.json")
|
|
187
|
+
];
|
|
188
|
+
}
|
|
189
|
+
function readVersionFromManifest(path2) {
|
|
190
|
+
try {
|
|
191
|
+
const version = JSON.parse((0, import_node_fs2.readFileSync)(path2, "utf8")).version;
|
|
192
|
+
return typeof version === "string" && version.trim() ? version.trim() : null;
|
|
193
|
+
} catch {
|
|
194
|
+
return null;
|
|
193
195
|
}
|
|
194
|
-
};
|
|
195
|
-
function humanReadableArgName(arg) {
|
|
196
|
-
const nameOutput = arg.name() + (arg.variadic === true ? "..." : "");
|
|
197
|
-
return arg.required ? "<" + nameOutput + ">" : "[" + nameOutput + "]";
|
|
198
196
|
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
var import_node_path = __toESM(require("node:path"), 1);
|
|
204
|
-
var import_node_fs = __toESM(require("node:fs"), 1);
|
|
205
|
-
var import_node_process = __toESM(require("node:process"), 1);
|
|
206
|
-
var import_node_util2 = require("node:util");
|
|
207
|
-
|
|
208
|
-
// node_modules/commander/lib/help.js
|
|
209
|
-
var import_node_util = require("node:util");
|
|
210
|
-
var Help = class {
|
|
211
|
-
constructor() {
|
|
212
|
-
this.helpWidth = void 0;
|
|
213
|
-
this.minWidthToWrap = 40;
|
|
214
|
-
this.sortSubcommands = false;
|
|
215
|
-
this.sortOptions = false;
|
|
216
|
-
this.showGlobalOptions = false;
|
|
197
|
+
function resolveClientVersion() {
|
|
198
|
+
for (const manifest of resolveClientVersionManifestCandidates()) {
|
|
199
|
+
const version = readVersionFromManifest(manifest);
|
|
200
|
+
if (version) return version;
|
|
217
201
|
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
202
|
+
return "0.0.0";
|
|
203
|
+
}
|
|
204
|
+
function clientVersionHeaders() {
|
|
205
|
+
return { [CLIENT_VERSION_HEADER]: resolveClientVersion() };
|
|
206
|
+
}
|
|
207
|
+
function upgradeRequiredError(res, body) {
|
|
208
|
+
const minVersion = body && typeof body === "object" && typeof body.minVersion === "string" ? body.minVersion : "a newer version";
|
|
209
|
+
return `Hub requires mmi-cli >= ${minVersion} \u2014 run mmi-cli doctor (installed ${resolveClientVersion()})`;
|
|
210
|
+
}
|
|
211
|
+
var import_node_fs2, import_node_path2;
|
|
212
|
+
var init_client_version = __esm({
|
|
213
|
+
"src/client-version.ts"() {
|
|
214
|
+
"use strict";
|
|
215
|
+
import_node_fs2 = require("node:fs");
|
|
216
|
+
import_node_path2 = require("node:path");
|
|
217
|
+
init_compat();
|
|
228
218
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
// src/error-codes.ts
|
|
222
|
+
function buildErrorEnvelope(message2, payload) {
|
|
223
|
+
const env = { error_code: payload.code, message: message2 };
|
|
224
|
+
if (payload.offending_flag !== void 0) env.offending_flag = payload.offending_flag;
|
|
225
|
+
if (payload.expected !== void 0) env.expected = payload.expected;
|
|
226
|
+
if (payload.did_you_mean !== void 0) env.did_you_mean = payload.did_you_mean;
|
|
227
|
+
if (payload.corrected_command !== void 0) env.corrected_command = payload.corrected_command;
|
|
228
|
+
if (payload.current_parent !== void 0) env.current_parent = payload.current_parent;
|
|
229
|
+
if (payload.issue_ref !== void 0) env.issue_ref = payload.issue_ref;
|
|
230
|
+
if (payload.board_status !== void 0) env.board_status = payload.board_status;
|
|
231
|
+
return env;
|
|
232
|
+
}
|
|
233
|
+
function formatErrorEnvelope(message2, payload) {
|
|
234
|
+
return JSON.stringify(buildErrorEnvelope(message2, payload));
|
|
235
|
+
}
|
|
236
|
+
function levenshtein(a, b) {
|
|
237
|
+
if (a === b) return 0;
|
|
238
|
+
if (a.length === 0) return b.length;
|
|
239
|
+
if (b.length === 0) return a.length;
|
|
240
|
+
let prev = Array.from({ length: b.length + 1 }, (_, i) => i);
|
|
241
|
+
let curr = new Array(b.length + 1);
|
|
242
|
+
for (let i = 1; i <= a.length; i++) {
|
|
243
|
+
curr[0] = i;
|
|
244
|
+
for (let j = 1; j <= b.length; j++) {
|
|
245
|
+
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
246
|
+
curr[j] = Math.min(curr[j - 1] + 1, prev[j] + 1, prev[j - 1] + cost);
|
|
245
247
|
}
|
|
246
|
-
|
|
248
|
+
[prev, curr] = [curr, prev];
|
|
247
249
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
const
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
250
|
+
return prev[b.length];
|
|
251
|
+
}
|
|
252
|
+
function didYouMean(input, candidates) {
|
|
253
|
+
const strip = (s) => s.replace(/^-+/, "");
|
|
254
|
+
const target = strip(input);
|
|
255
|
+
if (!target) return void 0;
|
|
256
|
+
let best;
|
|
257
|
+
for (const candidate of candidates) {
|
|
258
|
+
const cand = strip(candidate);
|
|
259
|
+
if (!cand) continue;
|
|
260
|
+
if (cand === target) continue;
|
|
261
|
+
if (cand === `${target}-file` || target === `${cand}-file`) continue;
|
|
262
|
+
const distance = levenshtein(target, cand);
|
|
263
|
+
const prefix = cand.startsWith(target) || target.startsWith(cand);
|
|
264
|
+
const threshold = Math.max(2, Math.ceil(cand.length * 0.4));
|
|
265
|
+
if (!prefix && distance > threshold) continue;
|
|
266
|
+
const better = !best || distance < best.distance || distance === best.distance && prefix && !best.prefix;
|
|
267
|
+
if (better) best = { flag: candidate, distance, prefix };
|
|
260
268
|
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
269
|
+
return best?.flag;
|
|
270
|
+
}
|
|
271
|
+
var ERROR_CODES, ERROR_CODE_REFERENCE;
|
|
272
|
+
var init_error_codes = __esm({
|
|
273
|
+
"src/error-codes.ts"() {
|
|
274
|
+
"use strict";
|
|
275
|
+
ERROR_CODES = {
|
|
276
|
+
/** A required flag was not supplied (e.g. `issue create` without `--priority`). */
|
|
277
|
+
ERR_MISSING_FLAG: "ERR_MISSING_FLAG",
|
|
278
|
+
/** Two mutually-exclusive flags were both supplied (e.g. `--title` with `--title-file`). */
|
|
279
|
+
ERR_CONFLICTING_FLAGS: "ERR_CONFLICTING_FLAGS",
|
|
280
|
+
/** A flag was supplied but its resolved value is empty (e.g. an empty `--title-file` or empty stdin). */
|
|
281
|
+
ERR_EMPTY_INPUT: "ERR_EMPTY_INPUT",
|
|
282
|
+
/** A supplied value has the right source but an invalid shape (e.g. a title with line breaks). */
|
|
283
|
+
ERR_INVALID_INPUT: "ERR_INVALID_INPUT",
|
|
284
|
+
/** A flag's value is outside its allowed set (e.g. `--priority nope`). */
|
|
285
|
+
ERR_BAD_ENUM: "ERR_BAD_ENUM",
|
|
286
|
+
/** An unknown flag or subcommand — usually a typo; carries a `did_you_mean`. */
|
|
287
|
+
ERR_UNKNOWN_FLAG: "ERR_UNKNOWN_FLAG",
|
|
288
|
+
/** A positional argument was passed to a command that does not take it (e.g. `oracle board read 496`,
|
|
289
|
+
* a whole-board read given an issue number). Carries a `corrected_command` when exactly one sibling
|
|
290
|
+
* answers the same verb positionally (#6354). */
|
|
291
|
+
ERR_EXCESS_ARGUMENT: "ERR_EXCESS_ARGUMENT",
|
|
292
|
+
/** A referenced resource (issue, repo, board item) does not exist. */
|
|
293
|
+
ERR_NOT_FOUND: "ERR_NOT_FOUND",
|
|
294
|
+
/** Missing / rejected credentials on a path that needs auth. */
|
|
295
|
+
ERR_NO_AUTH: "ERR_NO_AUTH",
|
|
296
|
+
/** The operation partially succeeded (some units done, some failed). */
|
|
297
|
+
ERR_PARTIAL: "ERR_PARTIAL",
|
|
298
|
+
/** The request was well-formed and every referent resolved, but the target's CURRENT STATE forbids the
|
|
299
|
+
* mutation (HTTP 409 semantics) — e.g. reparenting an issue that already has a parent. Deliberately not
|
|
300
|
+
* one code per API constraint: retry is futile until the named state is changed, and that is the fact a
|
|
301
|
+
* caller has to act on, whichever rule produced it. */
|
|
302
|
+
ERR_STATE_CONFLICT: "ERR_STATE_CONFLICT"
|
|
303
|
+
};
|
|
304
|
+
ERROR_CODE_REFERENCE = [
|
|
305
|
+
{
|
|
306
|
+
code: ERROR_CODES.ERR_MISSING_FLAG,
|
|
307
|
+
meaning: "A required flag was not supplied.",
|
|
308
|
+
typical_fix: "Run `mmi-cli explain <command>` and retry with the required flag."
|
|
309
|
+
},
|
|
310
|
+
{
|
|
311
|
+
code: ERROR_CODES.ERR_CONFLICTING_FLAGS,
|
|
312
|
+
meaning: "Two mutually-exclusive flags were supplied together.",
|
|
313
|
+
typical_fix: "Pass only one of the conflicting flags (see `offending_flag`) and retry."
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
code: ERROR_CODES.ERR_EMPTY_INPUT,
|
|
317
|
+
meaning: "A flag was supplied but resolved to an empty value (e.g. an empty file or empty stdin).",
|
|
318
|
+
typical_fix: "Provide non-empty content for the flag in `offending_flag` (a file with text, or a real pipe/heredoc for stdin)."
|
|
319
|
+
},
|
|
320
|
+
{
|
|
321
|
+
code: ERROR_CODES.ERR_INVALID_INPUT,
|
|
322
|
+
meaning: "A supplied value has an invalid shape for the flag.",
|
|
323
|
+
typical_fix: "Correct the value named by `offending_flag` and retry."
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
code: ERROR_CODES.ERR_BAD_ENUM,
|
|
327
|
+
meaning: "A flag value is outside the allowed enum.",
|
|
328
|
+
typical_fix: "Use one of the values in `expected`; casing and separators are often normalized by the CLI when supported."
|
|
329
|
+
},
|
|
330
|
+
{
|
|
331
|
+
code: ERROR_CODES.ERR_UNKNOWN_FLAG,
|
|
332
|
+
meaning: "A flag or subcommand is not known to this CLI version.",
|
|
333
|
+
typical_fix: "Check `did_you_mean`, route with `mmi-cli commands --json`, then inspect exact detail with `mmi-cli explain <command> --json`; update the CLI if it should exist."
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
code: ERROR_CODES.ERR_EXCESS_ARGUMENT,
|
|
337
|
+
meaning: "A positional argument was supplied to a command that takes none (or fewer).",
|
|
338
|
+
typical_fix: "Run the command named by `corrected_command`; otherwise drop the extra argument and select the target with the flags in `mmi-cli explain <command> --json`."
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
code: ERROR_CODES.ERR_NOT_FOUND,
|
|
342
|
+
meaning: "The referenced issue, PR, repo, board item, or other resource was not found.",
|
|
343
|
+
typical_fix: "Verify the identifier and repo, then rerun with an explicit `--repo <owner/repo>` when local repo detection is ambiguous."
|
|
344
|
+
},
|
|
345
|
+
{
|
|
346
|
+
code: ERROR_CODES.ERR_NO_AUTH,
|
|
347
|
+
meaning: "The command needs credentials that are missing, expired, or rejected.",
|
|
348
|
+
typical_fix: "Run `mmi-cli doctor --self` or refresh the relevant GitHub/Hub session before retrying."
|
|
349
|
+
},
|
|
350
|
+
{
|
|
351
|
+
code: ERROR_CODES.ERR_PARTIAL,
|
|
352
|
+
meaning: "A batch operation completed some units and failed others.",
|
|
353
|
+
typical_fix: "Read the per-unit results, fix the failed inputs, and rerun only the failed units."
|
|
354
|
+
},
|
|
355
|
+
{
|
|
356
|
+
code: ERROR_CODES.ERR_STATE_CONFLICT,
|
|
357
|
+
meaning: "The request was valid and every referent resolved, but the target resource's current state forbids it.",
|
|
358
|
+
typical_fix: "A plain retry fails identically. Read the state field the envelope names (e.g. `current_parent`), change that state deliberately with the command that owns it, then retry."
|
|
283
359
|
}
|
|
284
|
-
|
|
285
|
-
if (this.sortOptions) {
|
|
286
|
-
visibleOptions.sort(this.compareOptions);
|
|
287
|
-
}
|
|
288
|
-
return visibleOptions;
|
|
289
|
-
}
|
|
290
|
-
/**
|
|
291
|
-
* Get an array of the visible global options. (Not including help.)
|
|
292
|
-
*
|
|
293
|
-
* @param {Command} cmd
|
|
294
|
-
* @returns {Option[]}
|
|
295
|
-
*/
|
|
296
|
-
visibleGlobalOptions(cmd) {
|
|
297
|
-
if (!this.showGlobalOptions) return [];
|
|
298
|
-
const globalOptions = [];
|
|
299
|
-
for (let ancestorCmd = cmd.parent; ancestorCmd; ancestorCmd = ancestorCmd.parent) {
|
|
300
|
-
const visibleOptions = ancestorCmd.options.filter(
|
|
301
|
-
(option) => !option.hidden
|
|
302
|
-
);
|
|
303
|
-
globalOptions.push(...visibleOptions);
|
|
304
|
-
}
|
|
305
|
-
if (this.sortOptions) {
|
|
306
|
-
globalOptions.sort(this.compareOptions);
|
|
307
|
-
}
|
|
308
|
-
return globalOptions;
|
|
360
|
+
];
|
|
309
361
|
}
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
}
|
|
322
|
-
if (cmd.registeredArguments.find((argument) => argument.description)) {
|
|
323
|
-
return cmd.registeredArguments;
|
|
324
|
-
}
|
|
325
|
-
return [];
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
// src/github-client.ts
|
|
365
|
+
function classifyGhTokenExecFailure(e) {
|
|
366
|
+
const err = e;
|
|
367
|
+
const stderr = typeof err?.stderr === "string" ? err.stderr.trim() : "";
|
|
368
|
+
const detail = (stderr || err?.message || String(e)).replace(/\s+/g, " ").slice(0, 200);
|
|
369
|
+
if (err?.code === "ENOENT") return { state: "absent", detail: "gh is not installed on PATH" };
|
|
370
|
+
if (err?.killed === true || (err?.signal ?? null) !== null) return { state: "failed", detail: `gh auth token did not complete (${detail})` };
|
|
371
|
+
if (/not logged (in|into)|no oauth token|authentication token not found|gh auth login/i.test(`${stderr} ${err?.message ?? ""}`)) {
|
|
372
|
+
return { state: "absent", detail: "gh is installed but not logged in" };
|
|
326
373
|
}
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
374
|
+
return { state: "failed", detail };
|
|
375
|
+
}
|
|
376
|
+
async function githubTokenRead() {
|
|
377
|
+
if (process.env.GH_TOKEN) return { state: "ok", token: process.env.GH_TOKEN };
|
|
378
|
+
if (process.env.GITHUB_TOKEN) return { state: "ok", token: process.env.GITHUB_TOKEN };
|
|
379
|
+
cachedGhCliTokenRead ??= execFileP("gh", ["auth", "token"]).then(({ stdout }) => {
|
|
380
|
+
const token = stdout.trim();
|
|
381
|
+
return token ? { state: "ok", token } : { state: "absent", detail: "`gh auth token` exited 0 without printing a token" };
|
|
382
|
+
}).catch((e) => classifyGhTokenExecFailure(e));
|
|
383
|
+
return cachedGhCliTokenRead;
|
|
384
|
+
}
|
|
385
|
+
async function githubToken() {
|
|
386
|
+
const read = await githubTokenRead();
|
|
387
|
+
if (read.state === "failed") {
|
|
388
|
+
throw new GitHubApiError(
|
|
389
|
+
`GitHub identity read FAILED: \`gh auth token\` ${read.detail} \u2014 this is NOT "no token", so the call is refused rather than sent anonymously (an anonymous 401/404 would read as a permission or missing-object answer). Retry, or set GH_TOKEN/GITHUB_TOKEN for this process.`,
|
|
390
|
+
{ status: 0 }
|
|
391
|
+
);
|
|
392
|
+
}
|
|
393
|
+
return read.state === "ok" ? read.token : void 0;
|
|
394
|
+
}
|
|
395
|
+
function rateLimitResetNote(resetEpochSeconds, now = Date.now()) {
|
|
396
|
+
if (!resetEpochSeconds) return "rate limit exhausted; reset time unknown";
|
|
397
|
+
const resetMs = resetEpochSeconds * 1e3;
|
|
398
|
+
const minutes = Math.max(0, Math.ceil((resetMs - now) / 6e4));
|
|
399
|
+
return `rate limit exhausted; resets at ${new Date(resetMs).toISOString()} (~${minutes}m)`;
|
|
400
|
+
}
|
|
401
|
+
function rateLimitFromResponse(res, detail) {
|
|
402
|
+
const remaining = res.headers.get("x-ratelimit-remaining");
|
|
403
|
+
const resetHeader = res.headers.get("x-ratelimit-reset");
|
|
404
|
+
const reset = resetHeader && /^\d+$/.test(resetHeader) ? Number(resetHeader) : void 0;
|
|
405
|
+
const rateLimited = (res.status === 403 || res.status === 429) && remaining === "0" || /rate limit|secondary rate|abuse detection/i.test(detail);
|
|
406
|
+
return { rateLimited, ...rateLimited && reset !== void 0 ? { rateLimitReset: reset } : {} };
|
|
407
|
+
}
|
|
408
|
+
function joinUrl(base, path2) {
|
|
409
|
+
if (path2.startsWith("http://") || path2.startsWith("https://")) return path2;
|
|
410
|
+
return `${base.replace(/\/+$/, "")}/${path2.replace(/^\/+/, "")}`;
|
|
411
|
+
}
|
|
412
|
+
function withPerPage(url) {
|
|
413
|
+
if (/[?&]per_page=/.test(url)) return url;
|
|
414
|
+
return url.includes("?") ? `${url}&per_page=100` : `${url}?per_page=100`;
|
|
415
|
+
}
|
|
416
|
+
function apiOrigin(baseUrl) {
|
|
417
|
+
return new URL(baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`).origin;
|
|
418
|
+
}
|
|
419
|
+
function nextLink(linkHeader) {
|
|
420
|
+
if (!linkHeader) return void 0;
|
|
421
|
+
for (const part of linkHeader.split(",")) {
|
|
422
|
+
const match = part.match(/<([^>]+)>\s*;\s*rel="next"/);
|
|
423
|
+
if (match) return match[1];
|
|
424
|
+
}
|
|
425
|
+
return void 0;
|
|
426
|
+
}
|
|
427
|
+
function safeNextLink(linkHeader, allowedOrigin) {
|
|
428
|
+
const next = nextLink(linkHeader);
|
|
429
|
+
if (!next) return void 0;
|
|
430
|
+
let origin;
|
|
431
|
+
try {
|
|
432
|
+
origin = new URL(next).origin;
|
|
433
|
+
} catch {
|
|
434
|
+
throw new GitHubApiError(`pagination link rejected: invalid URL (${next})`, { status: 0 });
|
|
435
|
+
}
|
|
436
|
+
if (origin !== allowedOrigin) {
|
|
437
|
+
throw new GitHubApiError(`pagination link rejected: cross-origin ${origin} (expected ${allowedOrigin})`, { status: 0 });
|
|
438
|
+
}
|
|
439
|
+
return next;
|
|
440
|
+
}
|
|
441
|
+
async function errorFromResponse(res) {
|
|
442
|
+
let detail = "";
|
|
443
|
+
try {
|
|
444
|
+
const text = await res.text();
|
|
445
|
+
try {
|
|
446
|
+
const parsed = JSON.parse(text);
|
|
447
|
+
detail = parsed.message ?? text;
|
|
448
|
+
} catch {
|
|
449
|
+
detail = text;
|
|
450
|
+
}
|
|
451
|
+
} catch {
|
|
452
|
+
detail = "";
|
|
453
|
+
}
|
|
454
|
+
const suffix = detail ? `: ${detail.trim()}` : "";
|
|
455
|
+
const limit = rateLimitFromResponse(res, detail);
|
|
456
|
+
const budgetNote = limit.rateLimited ? ` \u2014 ${rateLimitResetNote(limit.rateLimitReset)}` : "";
|
|
457
|
+
return new GitHubApiError(`HTTP ${res.status}${suffix}${budgetNote} (${res.url})`, {
|
|
458
|
+
status: res.status,
|
|
459
|
+
...limit.rateLimited ? { rateLimited: true, rateLimitReset: limit.rateLimitReset } : {}
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
function createGitHubClient(options = {}) {
|
|
463
|
+
const baseUrl = options.baseUrl ?? process.env.GITHUB_API_URL ?? "https://api.github.com";
|
|
464
|
+
const allowedOrigin = apiOrigin(baseUrl);
|
|
465
|
+
const token = options.token ?? githubToken;
|
|
466
|
+
const defaultTimeoutMs = options.defaultTimeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
467
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
468
|
+
const externalSignal = options.signal;
|
|
469
|
+
async function request(method, url, init = {}) {
|
|
470
|
+
const t = await token();
|
|
471
|
+
const headers = {
|
|
472
|
+
Accept: "application/vnd.github+json",
|
|
473
|
+
"X-GitHub-Api-Version": "2022-11-28",
|
|
474
|
+
"User-Agent": "mmi-cli",
|
|
475
|
+
...t ? { Authorization: `Bearer ${t}` } : {},
|
|
476
|
+
...init.body !== void 0 ? { "Content-Type": "application/json" } : {},
|
|
477
|
+
...init.headers
|
|
478
|
+
};
|
|
479
|
+
const timeoutSignal = AbortSignal.timeout(init.timeoutMs ?? defaultTimeoutMs);
|
|
480
|
+
const res = await fetchImpl(url, {
|
|
481
|
+
method,
|
|
482
|
+
headers,
|
|
483
|
+
body: init.body !== void 0 ? JSON.stringify(init.body) : void 0,
|
|
484
|
+
signal: externalSignal ? AbortSignal.any([externalSignal, timeoutSignal]) : timeoutSignal
|
|
485
|
+
});
|
|
486
|
+
if (!res.ok) throw await errorFromResponse(res);
|
|
487
|
+
return res;
|
|
488
|
+
}
|
|
489
|
+
async function parseJson2(res) {
|
|
490
|
+
if (res.status === 204) return void 0;
|
|
491
|
+
const text = await res.text();
|
|
492
|
+
if (!text) return void 0;
|
|
493
|
+
return JSON.parse(text);
|
|
494
|
+
}
|
|
495
|
+
return {
|
|
496
|
+
async rest(method, path2, init) {
|
|
497
|
+
const res = await request(method, joinUrl(baseUrl, path2), init);
|
|
498
|
+
return parseJson2(res);
|
|
499
|
+
},
|
|
500
|
+
async restPaginate(path2, init) {
|
|
501
|
+
const items = [];
|
|
502
|
+
let url = withPerPage(joinUrl(baseUrl, path2));
|
|
503
|
+
while (url) {
|
|
504
|
+
const res = await request("GET", url, init);
|
|
505
|
+
const page = await parseJson2(res);
|
|
506
|
+
if (!Array.isArray(page)) {
|
|
507
|
+
throw new GitHubApiError(
|
|
508
|
+
`pagination page was not a JSON array (got ${page === void 0 ? "an empty body" : typeof page}) \u2014 the list read is PARTIAL and must not be treated as complete: ${url}. Retry the call.`,
|
|
509
|
+
{ status: res.status }
|
|
510
|
+
);
|
|
511
|
+
}
|
|
512
|
+
items.push(...page);
|
|
513
|
+
url = safeNextLink(res.headers.get("link"), allowedOrigin);
|
|
514
|
+
}
|
|
515
|
+
return items;
|
|
516
|
+
},
|
|
517
|
+
async graphql(query, variables, init) {
|
|
518
|
+
const res = await request("POST", joinUrl(baseUrl, "graphql"), {
|
|
519
|
+
...init,
|
|
520
|
+
body: { query, ...variables ? { variables } : {} }
|
|
521
|
+
});
|
|
522
|
+
const parsed = await parseJson2(res);
|
|
523
|
+
if (parsed?.errors?.length) {
|
|
524
|
+
const message2 = parsed.errors.map((e) => e.message ?? e.type ?? "unknown GraphQL error").join("; ");
|
|
525
|
+
const rateLimited = parsed.errors.some((e) => e.type === "RATE_LIMITED" || /rate limit/i.test(e.message ?? ""));
|
|
526
|
+
if (rateLimited) {
|
|
527
|
+
const resetHeader = res.headers.get("x-ratelimit-reset");
|
|
528
|
+
const reset = resetHeader && /^\d+$/.test(resetHeader) ? Number(resetHeader) : void 0;
|
|
529
|
+
throw new GitHubApiError(`GraphQL: ${message2} \u2014 GraphQL ${rateLimitResetNote(reset)}; REST may still have headroom`, {
|
|
530
|
+
status: 200,
|
|
531
|
+
graphqlErrors: parsed.errors,
|
|
532
|
+
rateLimited: true,
|
|
533
|
+
rateLimitReset: reset
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
throw new GitHubApiError(`GraphQL: ${message2}`, { status: 200, graphqlErrors: parsed.errors });
|
|
537
|
+
}
|
|
538
|
+
if (!parsed || parsed.data === void 0 || parsed.data === null) {
|
|
539
|
+
throw new GitHubApiError("GraphQL response did not include data", { status: 200 });
|
|
540
|
+
}
|
|
541
|
+
return parsed.data;
|
|
542
|
+
}
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
function defaultGitHubClient() {
|
|
546
|
+
cachedDefaultClient ??= createGitHubClient();
|
|
547
|
+
return cachedDefaultClient;
|
|
548
|
+
}
|
|
549
|
+
var cachedGhCliTokenRead, GitHubApiError, DEFAULT_TIMEOUT_MS, cachedDefaultClient;
|
|
550
|
+
var init_github_client = __esm({
|
|
551
|
+
"src/github-client.ts"() {
|
|
552
|
+
"use strict";
|
|
553
|
+
init_cli_shared();
|
|
554
|
+
GitHubApiError = class extends Error {
|
|
555
|
+
status;
|
|
556
|
+
stderr;
|
|
557
|
+
graphqlErrors;
|
|
558
|
+
/** #4588: true when GitHub refused THIS call for budget (primary or secondary rate limit),
|
|
559
|
+
* read from the refusing response itself — never the rate_limit endpoint. */
|
|
560
|
+
rateLimited;
|
|
561
|
+
/** Epoch seconds when the exhausted pool resets (`X-Ratelimit-Reset` of the refusing response). */
|
|
562
|
+
rateLimitReset;
|
|
563
|
+
constructor(message2, opts = {}) {
|
|
564
|
+
super(message2);
|
|
565
|
+
this.name = "GitHubApiError";
|
|
566
|
+
this.status = opts.status ?? 0;
|
|
567
|
+
this.stderr = message2;
|
|
568
|
+
this.graphqlErrors = opts.graphqlErrors;
|
|
569
|
+
this.rateLimited = opts.rateLimited;
|
|
570
|
+
this.rateLimitReset = opts.rateLimitReset;
|
|
571
|
+
}
|
|
572
|
+
};
|
|
573
|
+
DEFAULT_TIMEOUT_MS = 2e4;
|
|
574
|
+
}
|
|
575
|
+
});
|
|
576
|
+
|
|
577
|
+
// src/fetch-retry.ts
|
|
578
|
+
async function fetchWithRetry(fetchImpl, url, init, opts = {}) {
|
|
579
|
+
const attempts = opts.attempts ?? 3;
|
|
580
|
+
const baseDelayMs = opts.baseDelayMs ?? 250;
|
|
581
|
+
const retryOn = opts.retryOn ?? ((res) => res.status >= 500);
|
|
582
|
+
const sleep2 = opts.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
|
|
583
|
+
let lastErr;
|
|
584
|
+
for (let i = 0; i < attempts; i++) {
|
|
585
|
+
const isLast = i === attempts - 1;
|
|
586
|
+
const attemptInit = opts.timeoutMs ? { ...init, signal: AbortSignal.timeout(opts.timeoutMs) } : init;
|
|
587
|
+
try {
|
|
588
|
+
const res = await fetchImpl(url, attemptInit);
|
|
589
|
+
if (!isLast && retryOn(res)) {
|
|
590
|
+
await sleep2(baseDelayMs * 2 ** i);
|
|
591
|
+
continue;
|
|
592
|
+
}
|
|
593
|
+
return res;
|
|
594
|
+
} catch (e) {
|
|
595
|
+
lastErr = e;
|
|
596
|
+
if (isLast) throw e;
|
|
597
|
+
await sleep2(baseDelayMs * 2 ** i);
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
throw lastErr;
|
|
601
|
+
}
|
|
602
|
+
var init_fetch_retry = __esm({
|
|
603
|
+
"src/fetch-retry.ts"() {
|
|
604
|
+
"use strict";
|
|
605
|
+
}
|
|
606
|
+
});
|
|
607
|
+
|
|
608
|
+
// src/hub-auth.ts
|
|
609
|
+
function normalizeBaseUrl(baseUrl) {
|
|
610
|
+
return baseUrl.replace(/\/$/, "");
|
|
611
|
+
}
|
|
612
|
+
function tokenFingerprint(token) {
|
|
613
|
+
return (0, import_node_crypto.createHash)("sha256").update(token).digest("hex");
|
|
614
|
+
}
|
|
615
|
+
function defaultHubSessionCachePath(env = process.env) {
|
|
616
|
+
if (env.MMI_HUB_SESSION_CACHE) return env.MMI_HUB_SESSION_CACHE;
|
|
617
|
+
if (process.platform === "win32") {
|
|
618
|
+
const base2 = env.LOCALAPPDATA || (0, import_node_path3.join)((0, import_node_os.homedir)(), "AppData", "Local");
|
|
619
|
+
return (0, import_node_path3.join)(base2, "MMI Future", "mmi-cli", "hub-session.json");
|
|
620
|
+
}
|
|
621
|
+
const base = env.XDG_STATE_HOME || (0, import_node_path3.join)((0, import_node_os.homedir)(), ".local", "state");
|
|
622
|
+
return (0, import_node_path3.join)(base, "mmi-cli", "hub-session.json");
|
|
623
|
+
}
|
|
624
|
+
function roleFromToken(token) {
|
|
625
|
+
const part = token?.split(".")[1];
|
|
626
|
+
if (!part) return void 0;
|
|
627
|
+
try {
|
|
628
|
+
const claims = JSON.parse(Buffer.from(part, "base64url").toString("utf8"));
|
|
629
|
+
return claims.role === "owner" ? "owner" : void 0;
|
|
630
|
+
} catch {
|
|
631
|
+
return void 0;
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
function readCache(path2, apiUrl, now, githubTokenFingerprint) {
|
|
635
|
+
try {
|
|
636
|
+
const session = JSON.parse((0, import_node_fs3.readFileSync)(path2, "utf8"));
|
|
637
|
+
if (!session.token || !session.expiresAt || session.apiUrl !== apiUrl) return null;
|
|
638
|
+
if (session.githubTokenFingerprint !== githubTokenFingerprint) return null;
|
|
639
|
+
if (new Date(session.expiresAt).getTime() <= now.getTime() + REFRESH_WINDOW_MS) return null;
|
|
640
|
+
return { ...session, role: roleFromToken(session.token) };
|
|
641
|
+
} catch {
|
|
642
|
+
return null;
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
function writeCache(path2, session) {
|
|
646
|
+
(0, import_node_fs3.mkdirSync)((0, import_node_path3.dirname)(path2), { recursive: true });
|
|
647
|
+
const tmp = `${path2}.${process.pid}.${Date.now()}.tmp`;
|
|
648
|
+
(0, import_node_fs3.writeFileSync)(tmp, JSON.stringify(session, null, 2) + "\n", { encoding: "utf8", mode: 384 });
|
|
649
|
+
try {
|
|
650
|
+
(0, import_node_fs3.chmodSync)(tmp, 384);
|
|
651
|
+
} catch {
|
|
652
|
+
}
|
|
653
|
+
(0, import_node_fs3.renameSync)(tmp, path2);
|
|
654
|
+
try {
|
|
655
|
+
(0, import_node_fs3.chmodSync)(path2, 384);
|
|
656
|
+
} catch {
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
async function hubAuthSession(deps) {
|
|
660
|
+
if (!deps.baseUrl) return void 0;
|
|
661
|
+
const apiUrl = normalizeBaseUrl(deps.baseUrl);
|
|
662
|
+
const envToken = process.env.MMI_HUB_TOKEN;
|
|
663
|
+
if (envToken) {
|
|
664
|
+
return { ...{ token: envToken }, expiresAt: new Date(Date.now() + 30 * 60 * 1e3).toISOString(), apiUrl, githubTokenFingerprint: "env-override" };
|
|
665
|
+
}
|
|
666
|
+
const now = deps.now?.() ?? /* @__PURE__ */ new Date();
|
|
667
|
+
const cachePath = deps.cachePath ?? defaultHubSessionCachePath();
|
|
668
|
+
const ghToken = await deps.githubToken();
|
|
669
|
+
if (!ghToken) return void 0;
|
|
670
|
+
const githubTokenFingerprint = tokenFingerprint(ghToken);
|
|
671
|
+
const cached = readCache(cachePath, apiUrl, now, githubTokenFingerprint);
|
|
672
|
+
if (cached) return cached;
|
|
673
|
+
try {
|
|
674
|
+
const res = await fetchWithRetry(
|
|
675
|
+
deps.fetch ?? fetch,
|
|
676
|
+
`${apiUrl}/auth/session`,
|
|
677
|
+
{ method: "POST", headers: { ...clientVersionHeaders(), Authorization: `Bearer ${ghToken}` } },
|
|
678
|
+
{ attempts: EXCHANGE_ATTEMPTS, timeoutMs: EXCHANGE_TIMEOUT_MS }
|
|
679
|
+
);
|
|
680
|
+
if (!res.ok) return void 0;
|
|
681
|
+
const body = await res.json();
|
|
682
|
+
if (!body.token || !body.expiresAt) return void 0;
|
|
683
|
+
const session = {
|
|
684
|
+
token: body.token,
|
|
685
|
+
expiresAt: body.expiresAt,
|
|
686
|
+
login: typeof body.login === "string" ? body.login : void 0,
|
|
687
|
+
// #3513: from the SIGNED token, not the response body — one rule at every hop, so the cache
|
|
688
|
+
// read and the network read cannot disagree about what counts as an assertion.
|
|
689
|
+
role: roleFromToken(body.token),
|
|
690
|
+
apiUrl,
|
|
691
|
+
githubTokenFingerprint
|
|
692
|
+
};
|
|
693
|
+
try {
|
|
694
|
+
writeCache(cachePath, session);
|
|
695
|
+
} catch {
|
|
696
|
+
}
|
|
697
|
+
return session;
|
|
698
|
+
} catch {
|
|
699
|
+
return void 0;
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
async function hubAuthToken(deps) {
|
|
703
|
+
return (await hubAuthSession(deps))?.token;
|
|
704
|
+
}
|
|
705
|
+
var import_node_crypto, import_node_fs3, import_node_path3, import_node_os, REFRESH_WINDOW_MS, EXCHANGE_TIMEOUT_MS, EXCHANGE_ATTEMPTS;
|
|
706
|
+
var init_hub_auth = __esm({
|
|
707
|
+
"src/hub-auth.ts"() {
|
|
708
|
+
"use strict";
|
|
709
|
+
import_node_crypto = require("node:crypto");
|
|
710
|
+
import_node_fs3 = require("node:fs");
|
|
711
|
+
import_node_path3 = require("node:path");
|
|
712
|
+
import_node_os = require("node:os");
|
|
713
|
+
init_fetch_retry();
|
|
714
|
+
init_client_version();
|
|
715
|
+
REFRESH_WINDOW_MS = 10 * 60 * 1e3;
|
|
716
|
+
EXCHANGE_TIMEOUT_MS = 8e3;
|
|
717
|
+
EXCHANGE_ATTEMPTS = 2;
|
|
718
|
+
}
|
|
719
|
+
});
|
|
720
|
+
|
|
721
|
+
// src/house-map.ts
|
|
722
|
+
function isHouseRoot(token) {
|
|
723
|
+
return HOUSE_ROOTS.includes(token);
|
|
724
|
+
}
|
|
725
|
+
function isDeclaredHouseAlias(houseToken, lookupPath) {
|
|
726
|
+
const segments = lookupPath.split(" ");
|
|
727
|
+
for (let end = segments.length; end > 0; end -= 1) {
|
|
728
|
+
const key = segments.slice(0, end).join(" ");
|
|
729
|
+
const aliases = HOUSE_ALIASES[key];
|
|
730
|
+
if (aliases) return aliases.includes(houseToken);
|
|
731
|
+
}
|
|
732
|
+
return false;
|
|
733
|
+
}
|
|
734
|
+
function houseForPath(path2) {
|
|
735
|
+
if (path2 === "") return "core";
|
|
736
|
+
const segments = path2.split(" ");
|
|
737
|
+
for (let end = segments.length; end > 0; end -= 1) {
|
|
738
|
+
const key = segments.slice(0, end).join(" ");
|
|
739
|
+
const house = HOUSE_MAP[key];
|
|
740
|
+
if (house) return house;
|
|
741
|
+
}
|
|
742
|
+
return void 0;
|
|
743
|
+
}
|
|
744
|
+
function canonicalPathFor(path2) {
|
|
745
|
+
const house = houseForPath(path2);
|
|
746
|
+
if (!house) return void 0;
|
|
747
|
+
return house === "core" ? path2 : `${house} ${path2}`;
|
|
748
|
+
}
|
|
749
|
+
function canonicalArgvFor(args) {
|
|
750
|
+
const lookup = args.filter((tok) => !tok.startsWith("-")).slice(0, 2).join(" ");
|
|
751
|
+
const house = houseForPath(lookup);
|
|
752
|
+
return house && house !== "core" ? [house, ...args] : args;
|
|
753
|
+
}
|
|
754
|
+
var HOUSE_ROOTS, COMPAT_SHIM_DEATH_WAVE, FLAT_ALIAS_CUT_NOTE, HOUSE_QUESTIONS, HOUSE_MAP, HOUSE_ALIASES;
|
|
755
|
+
var init_house_map = __esm({
|
|
756
|
+
"src/house-map.ts"() {
|
|
757
|
+
"use strict";
|
|
758
|
+
HOUSE_ROOTS = ["oracle", "harbour", "devops", "vault", "learning"];
|
|
759
|
+
COMPAT_SHIM_DEATH_WAVE = "Wave 3";
|
|
760
|
+
FLAT_ALIAS_CUT_NOTE = `flat Wave 0 alias \u2014 removed in ${COMPAT_SHIM_DEATH_WAVE} (#4316, #4438); only the canonical house-prefixed path parses`;
|
|
761
|
+
HOUSE_QUESTIONS = {
|
|
762
|
+
oracle: "Is it live?",
|
|
763
|
+
harbour: "Is it bounded?",
|
|
764
|
+
devops: "Is it legal?",
|
|
765
|
+
vault: "Is it guarded?",
|
|
766
|
+
learning: "Did it learn?",
|
|
767
|
+
core: "Is it one door?"
|
|
768
|
+
};
|
|
769
|
+
HOUSE_MAP = {
|
|
770
|
+
// --- oracle — live truth ------------------------------------------------------------------------
|
|
771
|
+
board: "oracle",
|
|
772
|
+
// board management (read + the guarded mutations that keep it live)
|
|
773
|
+
issue: "oracle",
|
|
774
|
+
// issues are live org truth
|
|
775
|
+
wave: "oracle",
|
|
776
|
+
// read-side multi-worktree board visibility (`wave status`)
|
|
777
|
+
next: "oracle",
|
|
778
|
+
// read-side board: the next actionable item
|
|
779
|
+
docs: "oracle",
|
|
780
|
+
// generated docs surfaces — the live org knowledge routing index
|
|
781
|
+
org: "oracle",
|
|
782
|
+
// org projects/registry/access reads (subgroup overrides below)
|
|
783
|
+
"org project": "oracle",
|
|
784
|
+
// registry projections (declared + projected live truth)
|
|
785
|
+
"org access": "oracle",
|
|
786
|
+
// org access role/audit reads
|
|
787
|
+
"org config": "oracle",
|
|
788
|
+
// live org configuration read
|
|
789
|
+
// --- harbour — declared lanes -------------------------------------------------------------------
|
|
790
|
+
"org schedules": "harbour",
|
|
791
|
+
// register/run/park schedule rows under the one lane contract
|
|
792
|
+
// --- devops — shipping --------------------------------------------------------------------------
|
|
793
|
+
pr: "devops",
|
|
794
|
+
ci: "devops",
|
|
795
|
+
// the CI/gate audit
|
|
796
|
+
rcand: "devops",
|
|
797
|
+
release: "devops",
|
|
798
|
+
hotfix: "devops",
|
|
799
|
+
train: "devops",
|
|
800
|
+
"wave land": "devops",
|
|
801
|
+
// the write-side serial merge train is shipping, not board observation
|
|
802
|
+
bootstrap: "devops",
|
|
803
|
+
// repo provisioning + propagate
|
|
804
|
+
runtime: "devops",
|
|
805
|
+
// tenant/deploy/box/edge — shipping and central deploy
|
|
806
|
+
"org rules": "devops",
|
|
807
|
+
// org-managed repository rule delivery (.gitignore)
|
|
808
|
+
// --- vault — secrets ----------------------------------------------------------------------------
|
|
809
|
+
secrets: "vault",
|
|
810
|
+
"org oauth": "vault",
|
|
811
|
+
// OAuth credential planning/set/verify
|
|
812
|
+
// --- learning — self-improvement ----------------------------------------------------------------
|
|
813
|
+
report: "learning",
|
|
814
|
+
// friction reports
|
|
815
|
+
"skill-lesson": "learning",
|
|
816
|
+
"closure-rate": "learning",
|
|
817
|
+
// closure rate per loop kind, computed at read (#4440)
|
|
818
|
+
pickup: "learning",
|
|
819
|
+
// cloud-agent adoption gate (#5708)
|
|
820
|
+
// --- core — the front door itself ---------------------------------------------------------------
|
|
821
|
+
commands: "core",
|
|
822
|
+
whoami: "core",
|
|
823
|
+
spawn: "core",
|
|
824
|
+
// this repo's process-spawn contract
|
|
825
|
+
tests: "core",
|
|
826
|
+
// this repo's test-policy contract
|
|
827
|
+
dist: "core",
|
|
828
|
+
// this repo's committed dist/BOM drift receipt (#5576)
|
|
829
|
+
doctor: "core",
|
|
830
|
+
stage: "core",
|
|
831
|
+
plugin: "core",
|
|
832
|
+
// plugin lifecycle + guards (CLI house owns plugins)
|
|
833
|
+
explain: "core",
|
|
834
|
+
// command-surface help
|
|
835
|
+
status: "core",
|
|
836
|
+
// repo-orientation snapshot (front door — torn toward oracle, kept core)
|
|
837
|
+
onboard: "core"
|
|
838
|
+
// repo-readiness orientation (front door — torn toward oracle, kept core)
|
|
839
|
+
};
|
|
840
|
+
HOUSE_ALIASES = {
|
|
841
|
+
issue: ["devops"],
|
|
842
|
+
// filing/managing issues is oracle, but reads as shipping work
|
|
843
|
+
"issue create": ["devops"]
|
|
844
|
+
};
|
|
845
|
+
}
|
|
846
|
+
});
|
|
847
|
+
|
|
848
|
+
// src/stdin-inject.ts
|
|
849
|
+
function stdinHasPipedInput(statFd = () => (0, import_node_fs4.fstatSync)(0), getIsTTY = () => process.stdin.isTTY) {
|
|
850
|
+
try {
|
|
851
|
+
const stat4 = statFd();
|
|
852
|
+
if (stat4.isFIFO() || stat4.isFile()) return true;
|
|
853
|
+
if (stat4.isCharacterDevice()) return false;
|
|
854
|
+
if (stat4.isSocket()) return false;
|
|
855
|
+
if (getIsTTY() === true) return false;
|
|
856
|
+
return true;
|
|
857
|
+
} catch {
|
|
858
|
+
return false;
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
async function readStdin(opts = {}) {
|
|
862
|
+
if (injectedStdin !== void 0) return injectedStdin;
|
|
863
|
+
if (!stdinHasPipedInput()) return "";
|
|
864
|
+
const maxBytes = opts.maxBytes ?? STDIN_MAX_BYTES;
|
|
865
|
+
const timeoutMs = opts.timeoutMs ?? STDIN_DRAIN_TIMEOUT_MS;
|
|
866
|
+
const chunks = [];
|
|
867
|
+
let total = 0;
|
|
868
|
+
const drain = (async () => {
|
|
869
|
+
for await (const chunk of process.stdin) {
|
|
870
|
+
const buf = chunk;
|
|
871
|
+
const room = maxBytes - total;
|
|
872
|
+
if (buf.length >= room) {
|
|
873
|
+
chunks.push(buf.subarray(0, room));
|
|
874
|
+
total = maxBytes;
|
|
875
|
+
break;
|
|
876
|
+
}
|
|
877
|
+
chunks.push(buf);
|
|
878
|
+
total += buf.length;
|
|
879
|
+
}
|
|
880
|
+
})().catch(() => {
|
|
881
|
+
});
|
|
882
|
+
let timer;
|
|
883
|
+
const timeout = new Promise((resolve7) => {
|
|
884
|
+
timer = setTimeout(resolve7, timeoutMs);
|
|
885
|
+
});
|
|
886
|
+
try {
|
|
887
|
+
await Promise.race([drain, timeout]);
|
|
888
|
+
} finally {
|
|
889
|
+
if (timer) clearTimeout(timer);
|
|
890
|
+
try {
|
|
891
|
+
process.stdin.unref();
|
|
892
|
+
} catch {
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
896
|
+
}
|
|
897
|
+
var import_node_fs4, injectedStdin, STDIN_MAX_BYTES, STDIN_DRAIN_TIMEOUT_MS;
|
|
898
|
+
var init_stdin_inject = __esm({
|
|
899
|
+
"src/stdin-inject.ts"() {
|
|
900
|
+
"use strict";
|
|
901
|
+
import_node_fs4 = require("node:fs");
|
|
902
|
+
STDIN_MAX_BYTES = 8 * 1024 * 1024;
|
|
903
|
+
STDIN_DRAIN_TIMEOUT_MS = 5e3;
|
|
904
|
+
}
|
|
905
|
+
});
|
|
906
|
+
|
|
907
|
+
// src/cli-shared.ts
|
|
908
|
+
function killProcessTree(pid) {
|
|
909
|
+
try {
|
|
910
|
+
if (process.platform === "win32") {
|
|
911
|
+
(0, import_node_child_process2.execFileSync)("taskkill", ["/PID", String(pid), "/T", "/F"], { stdio: "ignore", windowsHide: true });
|
|
912
|
+
} else {
|
|
913
|
+
process.kill(pid, "SIGKILL");
|
|
914
|
+
}
|
|
915
|
+
return true;
|
|
916
|
+
} catch {
|
|
917
|
+
return false;
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
function execFileHard(file, args, options) {
|
|
921
|
+
const { timeout, step, ...rest } = options;
|
|
922
|
+
const started = Date.now();
|
|
923
|
+
return new Promise((resolve7, reject) => {
|
|
924
|
+
const child2 = (0, import_node_child_process2.execFile)(file, args, { encoding: "utf8", windowsHide: true, ...rest, timeout: 0 }, (error, stdout, stderr) => {
|
|
925
|
+
clearTimeout(timer);
|
|
926
|
+
if (expired) return;
|
|
927
|
+
if (error) reject(error);
|
|
928
|
+
else resolve7({ stdout: String(stdout), stderr: String(stderr) });
|
|
929
|
+
});
|
|
930
|
+
let expired = false;
|
|
931
|
+
const timer = setTimeout(() => {
|
|
932
|
+
expired = true;
|
|
933
|
+
const killed = child2.pid ? killProcessTree(child2.pid) : false;
|
|
934
|
+
child2.stdout?.destroy();
|
|
935
|
+
child2.stderr?.destroy();
|
|
936
|
+
child2.unref();
|
|
937
|
+
reject(new ExecDeadlineError(step, timeout, Date.now() - started, killed));
|
|
938
|
+
}, timeout);
|
|
939
|
+
timer.unref?.();
|
|
940
|
+
});
|
|
941
|
+
}
|
|
942
|
+
async function githubLogin() {
|
|
943
|
+
cachedGithubLogin ??= execFileP("gh", ["api", "user", "--jq", ".login"]).then(({ stdout }) => stdout.trim() || void 0).catch(() => void 0);
|
|
944
|
+
return cachedGithubLogin;
|
|
945
|
+
}
|
|
946
|
+
async function hubHeaders(extra = {}) {
|
|
947
|
+
const cfg = await loadConfig();
|
|
948
|
+
const t = await hubAuthToken({ baseUrl: cfg.sagaApiUrl ?? defaultHubUrl(), githubToken });
|
|
949
|
+
const base = { ...clientVersionHeaders(), ...extra };
|
|
950
|
+
return t ? { ...base, Authorization: `Bearer ${t}` } : base;
|
|
951
|
+
}
|
|
952
|
+
async function loadConfig() {
|
|
953
|
+
return { sagaApiUrl: defaultHubUrl() };
|
|
954
|
+
}
|
|
955
|
+
async function originRemoteUrl() {
|
|
956
|
+
return gitOut(["config", "--get", "remote.origin.url"]);
|
|
957
|
+
}
|
|
958
|
+
async function isOrgRepoRoot(readOrigin = originRemoteUrl) {
|
|
959
|
+
return /[:/]mutmutco\//i.test(await readOrigin());
|
|
960
|
+
}
|
|
961
|
+
async function repoProject(cfg) {
|
|
962
|
+
const remote = await gitOut(["remote", "get-url", "origin"]);
|
|
963
|
+
const repo = remote.replace(/\.git$/, "").split("/").pop() || "-";
|
|
964
|
+
return cfg.project || repo;
|
|
965
|
+
}
|
|
966
|
+
function argvWantsJson() {
|
|
967
|
+
return process.argv.some((a) => a === "--json" || a.startsWith("--json="));
|
|
968
|
+
}
|
|
969
|
+
function argvWantsMachineFailure() {
|
|
970
|
+
return argvWantsJson() || process.argv.some((a) => a === "--validate-only" || a === "--dry-run");
|
|
971
|
+
}
|
|
972
|
+
function commandFromFailMessage(msg) {
|
|
973
|
+
const head = msg.split(":", 1)[0].trim();
|
|
974
|
+
if (!head || head.startsWith("-")) return "mmi-cli";
|
|
975
|
+
if (!/^[a-z][a-z0-9-]*(?: [a-z][a-z0-9-]*){0,5}$/.test(head)) return "mmi-cli";
|
|
976
|
+
return canonicalPathFor(head) ?? head;
|
|
977
|
+
}
|
|
978
|
+
function canonicalFailMessage(msg) {
|
|
979
|
+
const colon = msg.indexOf(":");
|
|
980
|
+
if (colon < 0) return msg;
|
|
981
|
+
const command = commandFromFailMessage(msg);
|
|
982
|
+
return command === "mmi-cli" ? msg : `${command}${msg.slice(colon)}`;
|
|
983
|
+
}
|
|
984
|
+
function fail(msg, payload) {
|
|
985
|
+
const json = argvWantsMachineFailure();
|
|
986
|
+
const canonicalMsg = canonicalFailMessage(msg);
|
|
987
|
+
if (payload && json) {
|
|
988
|
+
console.error(formatErrorEnvelope(canonicalMsg, payload));
|
|
989
|
+
} else {
|
|
990
|
+
if (!json) console.error(`run: mmi-cli explain ${commandFromFailMessage(msg)}`);
|
|
991
|
+
console.error(`mmi-cli ${canonicalMsg}`);
|
|
992
|
+
}
|
|
993
|
+
hardExit(1);
|
|
994
|
+
}
|
|
995
|
+
async function failGracefulEnvelope(msg, payload) {
|
|
996
|
+
if (payload && argvWantsMachineFailure()) {
|
|
997
|
+
console.error(formatErrorEnvelope(msg, payload));
|
|
998
|
+
return cleanExit(1);
|
|
999
|
+
}
|
|
1000
|
+
return failGraceful(msg);
|
|
1001
|
+
}
|
|
1002
|
+
async function planMutation(opts, args, commandName, planFn) {
|
|
1003
|
+
const validateOnly = opts.validateOnly === true;
|
|
1004
|
+
const dryRun = opts.dryRun === true;
|
|
1005
|
+
if (!validateOnly && !dryRun) return null;
|
|
1006
|
+
const planned = planFn ? await planFn(opts, args) : { command: commandName, args };
|
|
1007
|
+
return validateOnly ? { ok: true, planned } : { dry_run: true, planned };
|
|
1008
|
+
}
|
|
1009
|
+
function commandPath(cmd) {
|
|
1010
|
+
const parts = [];
|
|
1011
|
+
let node = cmd;
|
|
1012
|
+
while (node && node.parent) {
|
|
1013
|
+
parts.unshift(node.name());
|
|
1014
|
+
node = node.parent;
|
|
1015
|
+
}
|
|
1016
|
+
return parts.join(" ") || cmd.name();
|
|
1017
|
+
}
|
|
1018
|
+
function jsonParity(cmd) {
|
|
1019
|
+
if (!cmd.options.some((o) => o.long === "--json")) {
|
|
1020
|
+
cmd.option("--json", "machine-readable output (default; accepted for parity)");
|
|
1021
|
+
}
|
|
1022
|
+
return cmd;
|
|
1023
|
+
}
|
|
1024
|
+
function mutating(cmd, planFn) {
|
|
1025
|
+
const marker = cmd;
|
|
1026
|
+
if (marker.__mmiMutating) return cmd;
|
|
1027
|
+
marker.__mmiMutating = true;
|
|
1028
|
+
if (!cmd.options.some((o) => o.long === "--json")) cmd.option("--json", "machine-readable output");
|
|
1029
|
+
cmd.option("--dry-run", "resolve + validate, print the planned action as JSON, and exit without writing");
|
|
1030
|
+
cmd.option("--validate-only", "validate flags/enums/refs, print {ok,planned} or the C2 error envelope, and exit without writing");
|
|
1031
|
+
const registerAction = cmd.action.bind(cmd);
|
|
1032
|
+
cmd.action = ((handler) => registerAction(async (...actionArgs) => {
|
|
1033
|
+
const command = actionArgs[actionArgs.length - 1];
|
|
1034
|
+
const opts = command.opts();
|
|
1035
|
+
const positionals = actionArgs.slice(0, -2);
|
|
1036
|
+
const out = await planMutation(opts, positionals, commandPath(command), planFn);
|
|
1037
|
+
if (out) {
|
|
1038
|
+
console.log(JSON.stringify(out));
|
|
1039
|
+
return;
|
|
1040
|
+
}
|
|
1041
|
+
return handler(...actionArgs);
|
|
1042
|
+
}));
|
|
1043
|
+
return cmd;
|
|
1044
|
+
}
|
|
1045
|
+
function installProcessBackstop() {
|
|
1046
|
+
process.on("unhandledRejection", (reason) => void failGraceful(reason instanceof Error ? reason.message : String(reason)));
|
|
1047
|
+
process.on("uncaughtException", (err) => void failGraceful(err instanceof Error ? err.message : String(err)));
|
|
1048
|
+
}
|
|
1049
|
+
function rawFlag(flag) {
|
|
1050
|
+
return process.argv.some((arg) => arg === flag || arg.startsWith(`${flag}=`));
|
|
1051
|
+
}
|
|
1052
|
+
function rawValue(flag, fallback) {
|
|
1053
|
+
const index = process.argv.indexOf(flag);
|
|
1054
|
+
if (index >= 0 && process.argv[index + 1]) return process.argv[index + 1];
|
|
1055
|
+
const inline = process.argv.find((arg) => arg.startsWith(`${flag}=`));
|
|
1056
|
+
return inline ? inline.slice(flag.length + 1) : fallback;
|
|
1057
|
+
}
|
|
1058
|
+
function printLine(value) {
|
|
1059
|
+
(0, import_node_fs5.writeSync)(1, `${value}
|
|
1060
|
+
`);
|
|
1061
|
+
}
|
|
1062
|
+
var import_node_child_process2, import_node_fs5, import_node_util3, rawExecFileP, DEFAULT_EXEC_TIMEOUT_MS, execFileP, GIT_TIMEOUT_MS, ExecDeadlineError, cachedGithubLogin, gitOut, consoleIo;
|
|
1063
|
+
var init_cli_shared = __esm({
|
|
1064
|
+
"src/cli-shared.ts"() {
|
|
1065
|
+
"use strict";
|
|
1066
|
+
import_node_child_process2 = require("node:child_process");
|
|
1067
|
+
import_node_fs5 = require("node:fs");
|
|
1068
|
+
import_node_util3 = require("node:util");
|
|
1069
|
+
init_hub_url();
|
|
1070
|
+
init_client_version();
|
|
1071
|
+
init_clean_exit();
|
|
1072
|
+
init_error_codes();
|
|
1073
|
+
init_github_client();
|
|
1074
|
+
init_hub_auth();
|
|
1075
|
+
init_house_map();
|
|
1076
|
+
init_stdin_inject();
|
|
1077
|
+
rawExecFileP = (0, import_node_util3.promisify)(import_node_child_process2.execFile);
|
|
1078
|
+
DEFAULT_EXEC_TIMEOUT_MS = 1e4;
|
|
1079
|
+
execFileP = (file, args, options = {}) => (
|
|
1080
|
+
// encoding 'utf8' guarantees string stdout/stderr at runtime; the cast pins the type because
|
|
1081
|
+
// promisify(execFile)'s overloads widen to string|Buffer when options is spread in.
|
|
1082
|
+
rawExecFileP(file, args, { encoding: "utf8", windowsHide: true, timeout: DEFAULT_EXEC_TIMEOUT_MS, killSignal: "SIGTERM", ...options })
|
|
1083
|
+
);
|
|
1084
|
+
GIT_TIMEOUT_MS = DEFAULT_EXEC_TIMEOUT_MS;
|
|
1085
|
+
ExecDeadlineError = class extends Error {
|
|
1086
|
+
constructor(step, timeoutMs, elapsedMs, killed) {
|
|
1087
|
+
super(
|
|
1088
|
+
`\`${step}\` did not finish within ${Math.round(timeoutMs / 1e3)}s (gave up after ${Math.round(elapsedMs / 1e3)}s). It stopped responding and did not exit when asked to, so the timeout alone could not end it; ${killed ? "its process tree was force-terminated" : "its process tree could NOT be terminated and may still be running"}.`
|
|
1089
|
+
);
|
|
1090
|
+
this.step = step;
|
|
1091
|
+
this.timeoutMs = timeoutMs;
|
|
1092
|
+
this.elapsedMs = elapsedMs;
|
|
1093
|
+
this.killed = killed;
|
|
1094
|
+
this.name = "ExecDeadlineError";
|
|
1095
|
+
}
|
|
1096
|
+
step;
|
|
1097
|
+
timeoutMs;
|
|
1098
|
+
elapsedMs;
|
|
1099
|
+
killed;
|
|
1100
|
+
};
|
|
1101
|
+
gitOut = async (args) => {
|
|
1102
|
+
try {
|
|
1103
|
+
return (await execFileP("git", [...args])).stdout.trim();
|
|
1104
|
+
} catch {
|
|
1105
|
+
return "";
|
|
1106
|
+
}
|
|
1107
|
+
};
|
|
1108
|
+
consoleIo = { log: (m) => console.log(m), err: (m) => console.error(m) };
|
|
1109
|
+
}
|
|
1110
|
+
});
|
|
1111
|
+
|
|
1112
|
+
// src/board-write.ts
|
|
1113
|
+
var board_write_exports = {};
|
|
1114
|
+
__export(board_write_exports, {
|
|
1115
|
+
writeHubBoardField: () => writeHubBoardField
|
|
1116
|
+
});
|
|
1117
|
+
async function writeHubBoardField(request) {
|
|
1118
|
+
const config = await loadConfig();
|
|
1119
|
+
const res = await fetch(`${config.sagaApiUrl?.replace(/\/$/, "")}/board/field`, {
|
|
1120
|
+
method: "POST",
|
|
1121
|
+
headers: await hubHeaders({ "content-type": "application/json" }),
|
|
1122
|
+
body: JSON.stringify(request),
|
|
1123
|
+
signal: AbortSignal.timeout(25e3)
|
|
1124
|
+
});
|
|
1125
|
+
const body = await res.json().catch(() => null);
|
|
1126
|
+
if (!res.ok || body?.updated !== true) throw new Error(`board field write HTTP ${res.status}: ${body?.error ?? "unconfirmed result"}`);
|
|
1127
|
+
}
|
|
1128
|
+
var init_board_write = __esm({
|
|
1129
|
+
"src/board-write.ts"() {
|
|
1130
|
+
"use strict";
|
|
1131
|
+
init_cli_shared();
|
|
1132
|
+
}
|
|
1133
|
+
});
|
|
1134
|
+
|
|
1135
|
+
// src/index.ts
|
|
1136
|
+
var index_exports = {};
|
|
1137
|
+
__export(index_exports, {
|
|
1138
|
+
DEFAULT_PRIORITY: () => DEFAULT_PRIORITY,
|
|
1139
|
+
argvWantsJson: () => argvWantsJson3,
|
|
1140
|
+
awsCallerArn: () => awsCallerArn,
|
|
1141
|
+
ciAuditDeps: () => ciAuditDeps2,
|
|
1142
|
+
classifyParseError: () => classifyParseError,
|
|
1143
|
+
commandOwnLongFlags: () => commandOwnLongFlags,
|
|
1144
|
+
envHealLockPath: () => envHealLockPath,
|
|
1145
|
+
isOrgRegisteredRepo: () => isOrgRegisteredRepo,
|
|
1146
|
+
parseInvalidChoiceError: () => parseInvalidChoiceError,
|
|
1147
|
+
positionalTargetForm: () => positionalTargetForm,
|
|
1148
|
+
registryClientDeps: () => registryClientDeps,
|
|
1149
|
+
repoSlug: () => repoSlug,
|
|
1150
|
+
suggestCommandPath: () => suggestCommandPath,
|
|
1151
|
+
unknownCommandCandidates: () => unknownCommandCandidates
|
|
1152
|
+
});
|
|
1153
|
+
module.exports = __toCommonJS(index_exports);
|
|
1154
|
+
|
|
1155
|
+
// node_modules/commander/lib/error.js
|
|
1156
|
+
var CommanderError = class extends Error {
|
|
1157
|
+
/**
|
|
1158
|
+
* Constructs the CommanderError class
|
|
1159
|
+
* @param {number} exitCode suggested exit code which could be used with process.exit
|
|
1160
|
+
* @param {string} code an id string representing the error
|
|
1161
|
+
* @param {string} message human-readable description of the error
|
|
1162
|
+
*/
|
|
1163
|
+
constructor(exitCode, code, message2) {
|
|
1164
|
+
super(message2);
|
|
1165
|
+
Error.captureStackTrace(this, this.constructor);
|
|
1166
|
+
this.name = this.constructor.name;
|
|
1167
|
+
this.code = code;
|
|
1168
|
+
this.exitCode = exitCode;
|
|
1169
|
+
this.nestedError = void 0;
|
|
1170
|
+
}
|
|
1171
|
+
};
|
|
1172
|
+
var InvalidArgumentError = class extends CommanderError {
|
|
1173
|
+
/**
|
|
1174
|
+
* Constructs the InvalidArgumentError class
|
|
1175
|
+
* @param {string} [message] explanation of why argument is invalid
|
|
1176
|
+
*/
|
|
1177
|
+
constructor(message2) {
|
|
1178
|
+
super(1, "commander.invalidArgument", message2);
|
|
1179
|
+
Error.captureStackTrace(this, this.constructor);
|
|
1180
|
+
this.name = this.constructor.name;
|
|
1181
|
+
}
|
|
1182
|
+
};
|
|
1183
|
+
|
|
1184
|
+
// node_modules/commander/lib/argument.js
|
|
1185
|
+
var Argument = class {
|
|
1186
|
+
/**
|
|
1187
|
+
* Initialize a new command argument with the given name and description.
|
|
1188
|
+
* The default is that the argument is required, and you can explicitly
|
|
1189
|
+
* indicate this with <> around the name. Put [] around the name for an optional argument.
|
|
1190
|
+
*
|
|
1191
|
+
* @param {string} name
|
|
1192
|
+
* @param {string} [description]
|
|
1193
|
+
*/
|
|
1194
|
+
constructor(name, description) {
|
|
1195
|
+
this.description = description || "";
|
|
1196
|
+
this.variadic = false;
|
|
1197
|
+
this.parseArg = void 0;
|
|
1198
|
+
this.defaultValue = void 0;
|
|
1199
|
+
this.defaultValueDescription = void 0;
|
|
1200
|
+
this.argChoices = void 0;
|
|
1201
|
+
switch (name[0]) {
|
|
1202
|
+
case "<":
|
|
1203
|
+
this.required = true;
|
|
1204
|
+
this._name = name.slice(1, -1);
|
|
1205
|
+
break;
|
|
1206
|
+
case "[":
|
|
1207
|
+
this.required = false;
|
|
1208
|
+
this._name = name.slice(1, -1);
|
|
1209
|
+
break;
|
|
1210
|
+
default:
|
|
1211
|
+
this.required = true;
|
|
1212
|
+
this._name = name;
|
|
1213
|
+
break;
|
|
1214
|
+
}
|
|
1215
|
+
if (this._name.endsWith("...")) {
|
|
1216
|
+
this.variadic = true;
|
|
1217
|
+
this._name = this._name.slice(0, -3);
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
/**
|
|
1221
|
+
* Return argument name.
|
|
1222
|
+
*
|
|
1223
|
+
* @return {string}
|
|
1224
|
+
*/
|
|
1225
|
+
name() {
|
|
1226
|
+
return this._name;
|
|
1227
|
+
}
|
|
1228
|
+
/**
|
|
1229
|
+
* @package
|
|
1230
|
+
*/
|
|
1231
|
+
_collectValue(value, previous) {
|
|
1232
|
+
if (previous === this.defaultValue || !Array.isArray(previous)) {
|
|
1233
|
+
return [value];
|
|
1234
|
+
}
|
|
1235
|
+
previous.push(value);
|
|
1236
|
+
return previous;
|
|
1237
|
+
}
|
|
1238
|
+
/**
|
|
1239
|
+
* Set the default value, and optionally supply the description to be displayed in the help.
|
|
1240
|
+
*
|
|
1241
|
+
* @param {*} value
|
|
1242
|
+
* @param {string} [description]
|
|
1243
|
+
* @return {Argument}
|
|
1244
|
+
*/
|
|
1245
|
+
default(value, description) {
|
|
1246
|
+
this.defaultValue = value;
|
|
1247
|
+
this.defaultValueDescription = description;
|
|
1248
|
+
return this;
|
|
1249
|
+
}
|
|
1250
|
+
/**
|
|
1251
|
+
* Set the custom handler for processing CLI command arguments into argument values.
|
|
1252
|
+
*
|
|
1253
|
+
* @param {Function} [fn]
|
|
1254
|
+
* @return {Argument}
|
|
1255
|
+
*/
|
|
1256
|
+
argParser(fn) {
|
|
1257
|
+
this.parseArg = fn;
|
|
1258
|
+
return this;
|
|
1259
|
+
}
|
|
1260
|
+
/**
|
|
1261
|
+
* Only allow argument value to be one of choices.
|
|
1262
|
+
*
|
|
1263
|
+
* @param {string[]} values
|
|
1264
|
+
* @return {Argument}
|
|
1265
|
+
*/
|
|
1266
|
+
choices(values) {
|
|
1267
|
+
this.argChoices = values.slice();
|
|
1268
|
+
this.parseArg = (arg, previous) => {
|
|
1269
|
+
if (!this.argChoices.includes(arg)) {
|
|
1270
|
+
throw new InvalidArgumentError(
|
|
1271
|
+
`Allowed choices are ${this.argChoices.join(", ")}.`
|
|
1272
|
+
);
|
|
1273
|
+
}
|
|
1274
|
+
if (this.variadic) {
|
|
1275
|
+
return this._collectValue(arg, previous);
|
|
1276
|
+
}
|
|
1277
|
+
return arg;
|
|
1278
|
+
};
|
|
1279
|
+
return this;
|
|
1280
|
+
}
|
|
1281
|
+
/**
|
|
1282
|
+
* Make argument required.
|
|
1283
|
+
*
|
|
1284
|
+
* @returns {Argument}
|
|
1285
|
+
*/
|
|
1286
|
+
argRequired() {
|
|
1287
|
+
this.required = true;
|
|
1288
|
+
return this;
|
|
1289
|
+
}
|
|
1290
|
+
/**
|
|
1291
|
+
* Make argument optional.
|
|
1292
|
+
*
|
|
1293
|
+
* @returns {Argument}
|
|
1294
|
+
*/
|
|
1295
|
+
argOptional() {
|
|
1296
|
+
this.required = false;
|
|
1297
|
+
return this;
|
|
1298
|
+
}
|
|
1299
|
+
};
|
|
1300
|
+
function humanReadableArgName(arg) {
|
|
1301
|
+
const nameOutput = arg.name() + (arg.variadic === true ? "..." : "");
|
|
1302
|
+
return arg.required ? "<" + nameOutput + ">" : "[" + nameOutput + "]";
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
// node_modules/commander/lib/command.js
|
|
1306
|
+
var import_node_events = require("node:events");
|
|
1307
|
+
var import_node_child_process = __toESM(require("node:child_process"), 1);
|
|
1308
|
+
var import_node_path = __toESM(require("node:path"), 1);
|
|
1309
|
+
var import_node_fs = __toESM(require("node:fs"), 1);
|
|
1310
|
+
var import_node_process = __toESM(require("node:process"), 1);
|
|
1311
|
+
var import_node_util2 = require("node:util");
|
|
1312
|
+
|
|
1313
|
+
// node_modules/commander/lib/help.js
|
|
1314
|
+
var import_node_util = require("node:util");
|
|
1315
|
+
var Help = class {
|
|
1316
|
+
constructor() {
|
|
1317
|
+
this.helpWidth = void 0;
|
|
1318
|
+
this.minWidthToWrap = 40;
|
|
1319
|
+
this.sortSubcommands = false;
|
|
1320
|
+
this.sortOptions = false;
|
|
1321
|
+
this.showGlobalOptions = false;
|
|
1322
|
+
}
|
|
1323
|
+
/**
|
|
1324
|
+
* prepareContext is called by Commander after applying overrides from `Command.configureHelp()`
|
|
1325
|
+
* and just before calling `formatHelp()`.
|
|
1326
|
+
*
|
|
1327
|
+
* Commander just uses the helpWidth and the rest is provided for optional use by more complex subclasses.
|
|
1328
|
+
*
|
|
1329
|
+
* @param {{ error?: boolean, helpWidth?: number, outputHasColors?: boolean }} contextOptions
|
|
1330
|
+
*/
|
|
1331
|
+
prepareContext(contextOptions) {
|
|
1332
|
+
this.helpWidth = this.helpWidth ?? contextOptions.helpWidth ?? 80;
|
|
1333
|
+
}
|
|
1334
|
+
/**
|
|
1335
|
+
* Get an array of the visible subcommands. Includes a placeholder for the implicit help command, if there is one.
|
|
1336
|
+
*
|
|
1337
|
+
* @param {Command} cmd
|
|
1338
|
+
* @returns {Command[]}
|
|
1339
|
+
*/
|
|
1340
|
+
visibleCommands(cmd) {
|
|
1341
|
+
const visibleCommands = cmd.commands.filter((cmd2) => !cmd2._hidden);
|
|
1342
|
+
const helpCommand = cmd._getHelpCommand();
|
|
1343
|
+
if (helpCommand && !helpCommand._hidden) {
|
|
1344
|
+
visibleCommands.push(helpCommand);
|
|
1345
|
+
}
|
|
1346
|
+
if (this.sortSubcommands) {
|
|
1347
|
+
visibleCommands.sort((a, b) => {
|
|
1348
|
+
return a.name().localeCompare(b.name());
|
|
1349
|
+
});
|
|
1350
|
+
}
|
|
1351
|
+
return visibleCommands;
|
|
1352
|
+
}
|
|
1353
|
+
/**
|
|
1354
|
+
* Compare options for sort.
|
|
1355
|
+
*
|
|
1356
|
+
* @param {Option} a
|
|
1357
|
+
* @param {Option} b
|
|
1358
|
+
* @returns {number}
|
|
1359
|
+
*/
|
|
1360
|
+
compareOptions(a, b) {
|
|
1361
|
+
const getSortKey = (option) => {
|
|
1362
|
+
return option.short ? option.short.replace(/^-/, "") : option.long.replace(/^--/, "");
|
|
1363
|
+
};
|
|
1364
|
+
return getSortKey(a).localeCompare(getSortKey(b));
|
|
1365
|
+
}
|
|
1366
|
+
/**
|
|
1367
|
+
* Get an array of the visible options. Includes a placeholder for the implicit help option, if there is one.
|
|
1368
|
+
*
|
|
1369
|
+
* @param {Command} cmd
|
|
1370
|
+
* @returns {Option[]}
|
|
1371
|
+
*/
|
|
1372
|
+
visibleOptions(cmd) {
|
|
1373
|
+
const visibleOptions = cmd.options.filter((option) => !option.hidden);
|
|
1374
|
+
const helpOption = cmd._getHelpOption();
|
|
1375
|
+
if (helpOption && !helpOption.hidden) {
|
|
1376
|
+
const removeShort = helpOption.short && cmd._findOption(helpOption.short);
|
|
1377
|
+
const removeLong = helpOption.long && cmd._findOption(helpOption.long);
|
|
1378
|
+
if (!removeShort && !removeLong) {
|
|
1379
|
+
visibleOptions.push(helpOption);
|
|
1380
|
+
} else if (helpOption.long && !removeLong) {
|
|
1381
|
+
visibleOptions.push(
|
|
1382
|
+
cmd.createOption(helpOption.long, helpOption.description)
|
|
1383
|
+
);
|
|
1384
|
+
} else if (helpOption.short && !removeShort) {
|
|
1385
|
+
visibleOptions.push(
|
|
1386
|
+
cmd.createOption(helpOption.short, helpOption.description)
|
|
1387
|
+
);
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
if (this.sortOptions) {
|
|
1391
|
+
visibleOptions.sort(this.compareOptions);
|
|
1392
|
+
}
|
|
1393
|
+
return visibleOptions;
|
|
1394
|
+
}
|
|
1395
|
+
/**
|
|
1396
|
+
* Get an array of the visible global options. (Not including help.)
|
|
1397
|
+
*
|
|
1398
|
+
* @param {Command} cmd
|
|
1399
|
+
* @returns {Option[]}
|
|
1400
|
+
*/
|
|
1401
|
+
visibleGlobalOptions(cmd) {
|
|
1402
|
+
if (!this.showGlobalOptions) return [];
|
|
1403
|
+
const globalOptions = [];
|
|
1404
|
+
for (let ancestorCmd = cmd.parent; ancestorCmd; ancestorCmd = ancestorCmd.parent) {
|
|
1405
|
+
const visibleOptions = ancestorCmd.options.filter(
|
|
1406
|
+
(option) => !option.hidden
|
|
1407
|
+
);
|
|
1408
|
+
globalOptions.push(...visibleOptions);
|
|
1409
|
+
}
|
|
1410
|
+
if (this.sortOptions) {
|
|
1411
|
+
globalOptions.sort(this.compareOptions);
|
|
1412
|
+
}
|
|
1413
|
+
return globalOptions;
|
|
1414
|
+
}
|
|
1415
|
+
/**
|
|
1416
|
+
* Get an array of the arguments if any have a description.
|
|
1417
|
+
*
|
|
1418
|
+
* @param {Command} cmd
|
|
1419
|
+
* @returns {Argument[]}
|
|
1420
|
+
*/
|
|
1421
|
+
visibleArguments(cmd) {
|
|
1422
|
+
if (cmd._argsDescription) {
|
|
1423
|
+
cmd.registeredArguments.forEach((argument) => {
|
|
1424
|
+
argument.description = argument.description || cmd._argsDescription[argument.name()] || "";
|
|
1425
|
+
});
|
|
1426
|
+
}
|
|
1427
|
+
if (cmd.registeredArguments.find((argument) => argument.description)) {
|
|
1428
|
+
return cmd.registeredArguments;
|
|
1429
|
+
}
|
|
1430
|
+
return [];
|
|
1431
|
+
}
|
|
1432
|
+
/**
|
|
1433
|
+
* Get the command term to show in the list of subcommands.
|
|
1434
|
+
*
|
|
330
1435
|
* @param {Command} cmd
|
|
331
1436
|
* @returns {string}
|
|
332
1437
|
*/
|
|
@@ -2772,1661 +3877,654 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2772
3877
|
}
|
|
2773
3878
|
const config = errorOptions || {};
|
|
2774
3879
|
const exitCode = config.exitCode || 1;
|
|
2775
|
-
const code = config.code || "commander.error";
|
|
2776
|
-
this._exit(exitCode, code, message2);
|
|
2777
|
-
}
|
|
2778
|
-
/**
|
|
2779
|
-
* Apply any option related environment variables, if option does
|
|
2780
|
-
* not have a value from cli or client code.
|
|
2781
|
-
*
|
|
2782
|
-
* @private
|
|
2783
|
-
*/
|
|
2784
|
-
_parseOptionsEnv() {
|
|
2785
|
-
this.options.forEach((option) => {
|
|
2786
|
-
if (option.envVar && option.envVar in import_node_process.default.env) {
|
|
2787
|
-
const optionKey = option.attributeName();
|
|
2788
|
-
if (this.getOptionValue(optionKey) === void 0 || ["default", "config", "env"].includes(
|
|
2789
|
-
this.getOptionValueSource(optionKey)
|
|
2790
|
-
)) {
|
|
2791
|
-
if (option.required || option.optional) {
|
|
2792
|
-
this.emit(`optionEnv:${option.name()}`, import_node_process.default.env[option.envVar]);
|
|
2793
|
-
} else {
|
|
2794
|
-
this.emit(`optionEnv:${option.name()}`);
|
|
2795
|
-
}
|
|
2796
|
-
}
|
|
2797
|
-
}
|
|
2798
|
-
});
|
|
2799
|
-
}
|
|
2800
|
-
/**
|
|
2801
|
-
* Apply any implied option values, if option is undefined or default value.
|
|
2802
|
-
*
|
|
2803
|
-
* @private
|
|
2804
|
-
*/
|
|
2805
|
-
_parseOptionsImplied() {
|
|
2806
|
-
const dualHelper = new DualOptions(this.options);
|
|
2807
|
-
const hasCustomOptionValue = (optionKey) => {
|
|
2808
|
-
return this.getOptionValue(optionKey) !== void 0 && !["default", "implied"].includes(this.getOptionValueSource(optionKey));
|
|
2809
|
-
};
|
|
2810
|
-
this.options.filter(
|
|
2811
|
-
(option) => option.implied !== void 0 && hasCustomOptionValue(option.attributeName()) && dualHelper.valueFromOption(
|
|
2812
|
-
this.getOptionValue(option.attributeName()),
|
|
2813
|
-
option
|
|
2814
|
-
)
|
|
2815
|
-
).forEach((option) => {
|
|
2816
|
-
Object.keys(option.implied).filter((impliedKey) => !hasCustomOptionValue(impliedKey)).forEach((impliedKey) => {
|
|
2817
|
-
this.setOptionValueWithSource(
|
|
2818
|
-
impliedKey,
|
|
2819
|
-
option.implied[impliedKey],
|
|
2820
|
-
"implied"
|
|
2821
|
-
);
|
|
2822
|
-
});
|
|
2823
|
-
});
|
|
2824
|
-
}
|
|
2825
|
-
/**
|
|
2826
|
-
* Argument `name` is missing.
|
|
2827
|
-
*
|
|
2828
|
-
* @param {string} name
|
|
2829
|
-
* @private
|
|
2830
|
-
*/
|
|
2831
|
-
missingArgument(name) {
|
|
2832
|
-
const message2 = `error: missing required argument '${name}'`;
|
|
2833
|
-
this.error(message2, { code: "commander.missingArgument" });
|
|
2834
|
-
}
|
|
2835
|
-
/**
|
|
2836
|
-
* `Option` is missing an argument.
|
|
2837
|
-
*
|
|
2838
|
-
* @param {Option} option
|
|
2839
|
-
* @private
|
|
2840
|
-
*/
|
|
2841
|
-
optionMissingArgument(option) {
|
|
2842
|
-
const message2 = `error: option '${option.flags}' argument missing`;
|
|
2843
|
-
this.error(message2, { code: "commander.optionMissingArgument" });
|
|
2844
|
-
}
|
|
2845
|
-
/**
|
|
2846
|
-
* `Option` does not have a value, and is a mandatory option.
|
|
2847
|
-
*
|
|
2848
|
-
* @param {Option} option
|
|
2849
|
-
* @private
|
|
2850
|
-
*/
|
|
2851
|
-
missingMandatoryOptionValue(option) {
|
|
2852
|
-
const message2 = `error: required option '${option.flags}' not specified`;
|
|
2853
|
-
this.error(message2, { code: "commander.missingMandatoryOptionValue" });
|
|
2854
|
-
}
|
|
2855
|
-
/**
|
|
2856
|
-
* `Option` conflicts with another option.
|
|
2857
|
-
*
|
|
2858
|
-
* @param {Option} option
|
|
2859
|
-
* @param {Option} conflictingOption
|
|
2860
|
-
* @private
|
|
2861
|
-
*/
|
|
2862
|
-
_conflictingOption(option, conflictingOption) {
|
|
2863
|
-
const findBestOptionFromValue = (option2) => {
|
|
2864
|
-
const optionKey = option2.attributeName();
|
|
2865
|
-
const optionValue = this.getOptionValue(optionKey);
|
|
2866
|
-
const negativeOption = this.options.find(
|
|
2867
|
-
(target) => target.negate && optionKey === target.attributeName()
|
|
2868
|
-
);
|
|
2869
|
-
const positiveOption = this.options.find(
|
|
2870
|
-
(target) => !target.negate && optionKey === target.attributeName()
|
|
2871
|
-
);
|
|
2872
|
-
if (negativeOption && (negativeOption.presetArg === void 0 && optionValue === false || negativeOption.presetArg !== void 0 && optionValue === negativeOption.presetArg)) {
|
|
2873
|
-
return negativeOption;
|
|
2874
|
-
}
|
|
2875
|
-
return positiveOption || option2;
|
|
2876
|
-
};
|
|
2877
|
-
const getErrorMessage = (option2) => {
|
|
2878
|
-
const bestOption = findBestOptionFromValue(option2);
|
|
2879
|
-
const optionKey = bestOption.attributeName();
|
|
2880
|
-
const source = this.getOptionValueSource(optionKey);
|
|
2881
|
-
if (source === "env") {
|
|
2882
|
-
return `environment variable '${bestOption.envVar}'`;
|
|
2883
|
-
}
|
|
2884
|
-
return `option '${bestOption.flags}'`;
|
|
2885
|
-
};
|
|
2886
|
-
const message2 = `error: ${getErrorMessage(option)} cannot be used with ${getErrorMessage(conflictingOption)}`;
|
|
2887
|
-
this.error(message2, { code: "commander.conflictingOption" });
|
|
2888
|
-
}
|
|
2889
|
-
/**
|
|
2890
|
-
* Unknown option `flag`.
|
|
2891
|
-
*
|
|
2892
|
-
* @param {string} flag
|
|
2893
|
-
* @private
|
|
2894
|
-
*/
|
|
2895
|
-
unknownOption(flag) {
|
|
2896
|
-
if (this._allowUnknownOption) return;
|
|
2897
|
-
let suggestion = "";
|
|
2898
|
-
if (flag.startsWith("--") && this._showSuggestionAfterError) {
|
|
2899
|
-
let candidateFlags = [];
|
|
2900
|
-
let command = this;
|
|
2901
|
-
do {
|
|
2902
|
-
const moreFlags = command.createHelp().visibleOptions(command).filter((option) => option.long).map((option) => option.long);
|
|
2903
|
-
candidateFlags = candidateFlags.concat(moreFlags);
|
|
2904
|
-
command = command.parent;
|
|
2905
|
-
} while (command && !command._enablePositionalOptions);
|
|
2906
|
-
suggestion = suggestSimilar(flag, candidateFlags);
|
|
2907
|
-
}
|
|
2908
|
-
const message2 = `error: unknown option '${flag}'${suggestion}`;
|
|
2909
|
-
this.error(message2, { code: "commander.unknownOption" });
|
|
2910
|
-
}
|
|
2911
|
-
/**
|
|
2912
|
-
* Excess arguments, more than expected.
|
|
2913
|
-
*
|
|
2914
|
-
* @param {string[]} receivedArgs
|
|
2915
|
-
* @private
|
|
2916
|
-
*/
|
|
2917
|
-
_excessArguments(receivedArgs) {
|
|
2918
|
-
if (this._allowExcessArguments) return;
|
|
2919
|
-
const expected = this.registeredArguments.length;
|
|
2920
|
-
const s = expected === 1 ? "" : "s";
|
|
2921
|
-
const received = receivedArgs.length;
|
|
2922
|
-
const forSubcommand = this.parent ? ` for '${this.name()}'` : "";
|
|
2923
|
-
const details = receivedArgs.join(", ");
|
|
2924
|
-
const message2 = `error: too many arguments${forSubcommand}. Expected ${expected} argument${s} but got ${received}: ${details}.`;
|
|
2925
|
-
this.error(message2, { code: "commander.excessArguments" });
|
|
2926
|
-
}
|
|
2927
|
-
/**
|
|
2928
|
-
* Unknown command.
|
|
2929
|
-
*
|
|
2930
|
-
* @private
|
|
2931
|
-
*/
|
|
2932
|
-
unknownCommand() {
|
|
2933
|
-
const unknownName = this.args[0];
|
|
2934
|
-
let suggestion = "";
|
|
2935
|
-
if (this._showSuggestionAfterError) {
|
|
2936
|
-
const candidateNames = [];
|
|
2937
|
-
this.createHelp().visibleCommands(this).forEach((command) => {
|
|
2938
|
-
candidateNames.push(command.name());
|
|
2939
|
-
if (command.alias()) candidateNames.push(command.alias());
|
|
2940
|
-
});
|
|
2941
|
-
suggestion = suggestSimilar(unknownName, candidateNames);
|
|
2942
|
-
}
|
|
2943
|
-
const message2 = `error: unknown command '${unknownName}'${suggestion}`;
|
|
2944
|
-
this.error(message2, { code: "commander.unknownCommand" });
|
|
2945
|
-
}
|
|
2946
|
-
/**
|
|
2947
|
-
* Get or set the program version.
|
|
2948
|
-
*
|
|
2949
|
-
* This method auto-registers the "-V, --version" option which will print the version number.
|
|
2950
|
-
*
|
|
2951
|
-
* You can optionally supply the flags and description to override the defaults.
|
|
2952
|
-
*
|
|
2953
|
-
* @param {string} [str]
|
|
2954
|
-
* @param {string} [flags]
|
|
2955
|
-
* @param {string} [description]
|
|
2956
|
-
* @return {(this | string | undefined)} `this` command for chaining, or version string if no arguments
|
|
2957
|
-
*/
|
|
2958
|
-
version(str, flags, description) {
|
|
2959
|
-
if (str === void 0) return this._version;
|
|
2960
|
-
this._version = str;
|
|
2961
|
-
flags = flags || "-V, --version";
|
|
2962
|
-
description = description || "output the version number";
|
|
2963
|
-
const versionOption = this.createOption(flags, description);
|
|
2964
|
-
this._versionOptionName = versionOption.attributeName();
|
|
2965
|
-
this._registerOption(versionOption);
|
|
2966
|
-
this.on("option:" + versionOption.name(), () => {
|
|
2967
|
-
this._outputConfiguration.writeOut(`${str}
|
|
2968
|
-
`);
|
|
2969
|
-
this._exit(0, "commander.version", str);
|
|
2970
|
-
});
|
|
2971
|
-
return this;
|
|
2972
|
-
}
|
|
2973
|
-
/**
|
|
2974
|
-
* Set the description.
|
|
2975
|
-
*
|
|
2976
|
-
* @param {string} [str]
|
|
2977
|
-
* @param {object} [argsDescription]
|
|
2978
|
-
* @return {(string|Command)}
|
|
2979
|
-
*/
|
|
2980
|
-
description(str, argsDescription) {
|
|
2981
|
-
if (str === void 0 && argsDescription === void 0)
|
|
2982
|
-
return this._description;
|
|
2983
|
-
this._description = str;
|
|
2984
|
-
if (argsDescription) {
|
|
2985
|
-
this._argsDescription = argsDescription;
|
|
2986
|
-
}
|
|
2987
|
-
return this;
|
|
2988
|
-
}
|
|
2989
|
-
/**
|
|
2990
|
-
* Set the summary. Used when listed as subcommand of parent.
|
|
2991
|
-
*
|
|
2992
|
-
* @param {string} [str]
|
|
2993
|
-
* @return {(string|Command)}
|
|
2994
|
-
*/
|
|
2995
|
-
summary(str) {
|
|
2996
|
-
if (str === void 0) return this._summary;
|
|
2997
|
-
this._summary = str;
|
|
2998
|
-
return this;
|
|
2999
|
-
}
|
|
3000
|
-
/**
|
|
3001
|
-
* Set an alias for the command.
|
|
3002
|
-
*
|
|
3003
|
-
* You may call more than once to add multiple aliases. Only the first alias is shown in the auto-generated help.
|
|
3004
|
-
*
|
|
3005
|
-
* @param {string} [alias]
|
|
3006
|
-
* @return {(string|Command)}
|
|
3007
|
-
*/
|
|
3008
|
-
alias(alias) {
|
|
3009
|
-
if (alias === void 0) return this._aliases[0];
|
|
3010
|
-
let command = this;
|
|
3011
|
-
if (this.commands.length !== 0 && this.commands[this.commands.length - 1]._executableHandler) {
|
|
3012
|
-
command = this.commands[this.commands.length - 1];
|
|
3013
|
-
}
|
|
3014
|
-
if (alias === command._name)
|
|
3015
|
-
throw new Error("Command alias can't be the same as its name");
|
|
3016
|
-
const matchingCommand = this.parent?._findCommand(alias);
|
|
3017
|
-
if (matchingCommand) {
|
|
3018
|
-
const existingCmd = [matchingCommand.name()].concat(matchingCommand.aliases()).join("|");
|
|
3019
|
-
throw new Error(
|
|
3020
|
-
`cannot add alias '${alias}' to command '${this.name()}' as already have command '${existingCmd}'`
|
|
3021
|
-
);
|
|
3022
|
-
}
|
|
3023
|
-
command._aliases.push(alias);
|
|
3024
|
-
return this;
|
|
3025
|
-
}
|
|
3026
|
-
/**
|
|
3027
|
-
* Set aliases for the command.
|
|
3028
|
-
*
|
|
3029
|
-
* Only the first alias is shown in the auto-generated help.
|
|
3030
|
-
*
|
|
3031
|
-
* @param {string[]} [aliases]
|
|
3032
|
-
* @return {(string[]|Command)}
|
|
3033
|
-
*/
|
|
3034
|
-
aliases(aliases) {
|
|
3035
|
-
if (aliases === void 0) return this._aliases;
|
|
3036
|
-
aliases.forEach((alias) => this.alias(alias));
|
|
3037
|
-
return this;
|
|
3038
|
-
}
|
|
3039
|
-
/**
|
|
3040
|
-
* Set / get the command usage `str`.
|
|
3041
|
-
*
|
|
3042
|
-
* @param {string} [str]
|
|
3043
|
-
* @return {(string|Command)}
|
|
3044
|
-
*/
|
|
3045
|
-
usage(str) {
|
|
3046
|
-
if (str === void 0) {
|
|
3047
|
-
if (this._usage) return this._usage;
|
|
3048
|
-
const args = this.registeredArguments.map((arg) => {
|
|
3049
|
-
return humanReadableArgName(arg);
|
|
3050
|
-
});
|
|
3051
|
-
return [].concat(
|
|
3052
|
-
this.options.length || this._helpOption !== null ? "[options]" : [],
|
|
3053
|
-
this.commands.length ? "[command]" : [],
|
|
3054
|
-
this.registeredArguments.length ? args : []
|
|
3055
|
-
).join(" ");
|
|
3056
|
-
}
|
|
3057
|
-
this._usage = str;
|
|
3058
|
-
return this;
|
|
3059
|
-
}
|
|
3060
|
-
/**
|
|
3061
|
-
* Get or set the name of the command.
|
|
3062
|
-
*
|
|
3063
|
-
* @param {string} [str]
|
|
3064
|
-
* @return {(string|Command)}
|
|
3065
|
-
*/
|
|
3066
|
-
name(str) {
|
|
3067
|
-
if (str === void 0) return this._name;
|
|
3068
|
-
this._name = str;
|
|
3069
|
-
return this;
|
|
3070
|
-
}
|
|
3071
|
-
/**
|
|
3072
|
-
* Set/get the help group heading for this subcommand in parent command's help.
|
|
3073
|
-
*
|
|
3074
|
-
* @param {string} [heading]
|
|
3075
|
-
* @return {Command | string}
|
|
3076
|
-
*/
|
|
3077
|
-
helpGroup(heading) {
|
|
3078
|
-
if (heading === void 0) return this._helpGroupHeading ?? "";
|
|
3079
|
-
this._helpGroupHeading = heading;
|
|
3080
|
-
return this;
|
|
3081
|
-
}
|
|
3082
|
-
/**
|
|
3083
|
-
* Set/get the default help group heading for subcommands added to this command.
|
|
3084
|
-
* (This does not override a group set directly on the subcommand using .helpGroup().)
|
|
3085
|
-
*
|
|
3086
|
-
* @example
|
|
3087
|
-
* program.commandsGroup('Development Commands:);
|
|
3088
|
-
* program.command('watch')...
|
|
3089
|
-
* program.command('lint')...
|
|
3090
|
-
* ...
|
|
3091
|
-
*
|
|
3092
|
-
* @param {string} [heading]
|
|
3093
|
-
* @returns {Command | string}
|
|
3094
|
-
*/
|
|
3095
|
-
commandsGroup(heading) {
|
|
3096
|
-
if (heading === void 0) return this._defaultCommandGroup ?? "";
|
|
3097
|
-
this._defaultCommandGroup = heading;
|
|
3098
|
-
return this;
|
|
3099
|
-
}
|
|
3100
|
-
/**
|
|
3101
|
-
* Set/get the default help group heading for options added to this command.
|
|
3102
|
-
* (This does not override a group set directly on the option using .helpGroup().)
|
|
3103
|
-
*
|
|
3104
|
-
* @example
|
|
3105
|
-
* program
|
|
3106
|
-
* .optionsGroup('Development Options:')
|
|
3107
|
-
* .option('-d, --debug', 'output extra debugging')
|
|
3108
|
-
* .option('-p, --profile', 'output profiling information')
|
|
3109
|
-
*
|
|
3110
|
-
* @param {string} [heading]
|
|
3111
|
-
* @returns {Command | string}
|
|
3112
|
-
*/
|
|
3113
|
-
optionsGroup(heading) {
|
|
3114
|
-
if (heading === void 0) return this._defaultOptionGroup ?? "";
|
|
3115
|
-
this._defaultOptionGroup = heading;
|
|
3116
|
-
return this;
|
|
3117
|
-
}
|
|
3118
|
-
/**
|
|
3119
|
-
* @param {Option} option
|
|
3120
|
-
* @private
|
|
3121
|
-
*/
|
|
3122
|
-
_initOptionGroup(option) {
|
|
3123
|
-
if (this._defaultOptionGroup && !option.helpGroupHeading)
|
|
3124
|
-
option.helpGroup(this._defaultOptionGroup);
|
|
3125
|
-
}
|
|
3126
|
-
/**
|
|
3127
|
-
* @param {Command} cmd
|
|
3128
|
-
* @private
|
|
3129
|
-
*/
|
|
3130
|
-
_initCommandGroup(cmd) {
|
|
3131
|
-
if (this._defaultCommandGroup && !cmd.helpGroup())
|
|
3132
|
-
cmd.helpGroup(this._defaultCommandGroup);
|
|
3133
|
-
}
|
|
3134
|
-
/**
|
|
3135
|
-
* Set the name of the command from script filename, such as process.argv[1],
|
|
3136
|
-
* or import.meta.filename.
|
|
3137
|
-
*
|
|
3138
|
-
* (Used internally and public although not documented in README.)
|
|
3139
|
-
*
|
|
3140
|
-
* @example
|
|
3141
|
-
* program.nameFromFilename(import.meta.filename);
|
|
3142
|
-
*
|
|
3143
|
-
* @param {string} filename
|
|
3144
|
-
* @return {Command}
|
|
3145
|
-
*/
|
|
3146
|
-
nameFromFilename(filename) {
|
|
3147
|
-
this._name = import_node_path.default.basename(filename, import_node_path.default.extname(filename));
|
|
3148
|
-
return this;
|
|
3149
|
-
}
|
|
3150
|
-
/**
|
|
3151
|
-
* Get or set the directory for searching for executable subcommands of this command.
|
|
3152
|
-
*
|
|
3153
|
-
* @example
|
|
3154
|
-
* program.executableDir(import.meta.dirname);
|
|
3155
|
-
* // or
|
|
3156
|
-
* program.executableDir('subcommands');
|
|
3157
|
-
*
|
|
3158
|
-
* @param {string} [path]
|
|
3159
|
-
* @return {(string|null|Command)}
|
|
3160
|
-
*/
|
|
3161
|
-
executableDir(path2) {
|
|
3162
|
-
if (path2 === void 0) return this._executableDir;
|
|
3163
|
-
this._executableDir = path2;
|
|
3164
|
-
return this;
|
|
3165
|
-
}
|
|
3166
|
-
/**
|
|
3167
|
-
* Return program help documentation.
|
|
3168
|
-
*
|
|
3169
|
-
* @param {{ error: boolean }} [contextOptions] - pass {error:true} to wrap for stderr instead of stdout
|
|
3170
|
-
* @return {string}
|
|
3171
|
-
*/
|
|
3172
|
-
helpInformation(contextOptions) {
|
|
3173
|
-
const helper = this.createHelp();
|
|
3174
|
-
const context = this._getOutputContext(contextOptions);
|
|
3175
|
-
helper.prepareContext({
|
|
3176
|
-
error: context.error,
|
|
3177
|
-
helpWidth: context.helpWidth,
|
|
3178
|
-
outputHasColors: context.hasColors
|
|
3179
|
-
});
|
|
3180
|
-
const text = helper.formatHelp(this, helper);
|
|
3181
|
-
if (context.hasColors) return text;
|
|
3182
|
-
return this._outputConfiguration.stripColor(text);
|
|
3183
|
-
}
|
|
3184
|
-
/**
|
|
3185
|
-
* @typedef HelpContext
|
|
3186
|
-
* @type {object}
|
|
3187
|
-
* @property {boolean} error
|
|
3188
|
-
* @property {number} helpWidth
|
|
3189
|
-
* @property {boolean} hasColors
|
|
3190
|
-
* @property {function} write - includes stripColor if needed
|
|
3191
|
-
*
|
|
3192
|
-
* @returns {HelpContext}
|
|
3193
|
-
* @private
|
|
3194
|
-
*/
|
|
3195
|
-
_getOutputContext(contextOptions) {
|
|
3196
|
-
contextOptions = contextOptions || {};
|
|
3197
|
-
const error = !!contextOptions.error;
|
|
3198
|
-
let baseWrite;
|
|
3199
|
-
let hasColors;
|
|
3200
|
-
let helpWidth;
|
|
3201
|
-
if (error) {
|
|
3202
|
-
baseWrite = (str) => this._outputConfiguration.writeErr(str);
|
|
3203
|
-
hasColors = this._outputConfiguration.getErrHasColors();
|
|
3204
|
-
helpWidth = this._outputConfiguration.getErrHelpWidth();
|
|
3205
|
-
} else {
|
|
3206
|
-
baseWrite = (str) => this._outputConfiguration.writeOut(str);
|
|
3207
|
-
hasColors = this._outputConfiguration.getOutHasColors();
|
|
3208
|
-
helpWidth = this._outputConfiguration.getOutHelpWidth();
|
|
3209
|
-
}
|
|
3210
|
-
const write = (str) => {
|
|
3211
|
-
if (!hasColors) str = this._outputConfiguration.stripColor(str);
|
|
3212
|
-
return baseWrite(str);
|
|
3213
|
-
};
|
|
3214
|
-
return { error, write, hasColors, helpWidth };
|
|
3215
|
-
}
|
|
3216
|
-
/**
|
|
3217
|
-
* Output help information for this command.
|
|
3218
|
-
*
|
|
3219
|
-
* Outputs built-in help, and custom text added using `.addHelpText()`.
|
|
3220
|
-
*
|
|
3221
|
-
* @param {{ error: boolean } | Function} [contextOptions] - pass {error:true} to write to stderr instead of stdout
|
|
3222
|
-
*/
|
|
3223
|
-
outputHelp(contextOptions) {
|
|
3224
|
-
let deprecatedCallback;
|
|
3225
|
-
if (typeof contextOptions === "function") {
|
|
3226
|
-
deprecatedCallback = contextOptions;
|
|
3227
|
-
contextOptions = void 0;
|
|
3228
|
-
}
|
|
3229
|
-
const outputContext = this._getOutputContext(contextOptions);
|
|
3230
|
-
const eventContext = {
|
|
3231
|
-
error: outputContext.error,
|
|
3232
|
-
write: outputContext.write,
|
|
3233
|
-
command: this
|
|
3234
|
-
};
|
|
3235
|
-
this._getCommandAndAncestors().reverse().forEach((command) => command.emit("beforeAllHelp", eventContext));
|
|
3236
|
-
this.emit("beforeHelp", eventContext);
|
|
3237
|
-
let helpInformation = this.helpInformation({ error: outputContext.error });
|
|
3238
|
-
if (deprecatedCallback) {
|
|
3239
|
-
helpInformation = deprecatedCallback(helpInformation);
|
|
3240
|
-
if (typeof helpInformation !== "string" && !Buffer.isBuffer(helpInformation)) {
|
|
3241
|
-
throw new Error("outputHelp callback must return a string or a Buffer");
|
|
3242
|
-
}
|
|
3243
|
-
}
|
|
3244
|
-
outputContext.write(helpInformation);
|
|
3245
|
-
if (this._getHelpOption()?.long) {
|
|
3246
|
-
this.emit(this._getHelpOption().long);
|
|
3247
|
-
}
|
|
3248
|
-
this.emit("afterHelp", eventContext);
|
|
3249
|
-
this._getCommandAndAncestors().forEach(
|
|
3250
|
-
(command) => command.emit("afterAllHelp", eventContext)
|
|
3251
|
-
);
|
|
3880
|
+
const code = config.code || "commander.error";
|
|
3881
|
+
this._exit(exitCode, code, message2);
|
|
3252
3882
|
}
|
|
3253
3883
|
/**
|
|
3254
|
-
*
|
|
3255
|
-
*
|
|
3256
|
-
*
|
|
3257
|
-
* @example
|
|
3258
|
-
* program.helpOption('-?, --help' 'show help'); // customise
|
|
3259
|
-
* program.helpOption(false); // disable
|
|
3884
|
+
* Apply any option related environment variables, if option does
|
|
3885
|
+
* not have a value from cli or client code.
|
|
3260
3886
|
*
|
|
3261
|
-
* @
|
|
3262
|
-
* @param {string} [description]
|
|
3263
|
-
* @return {Command} `this` command for chaining
|
|
3887
|
+
* @private
|
|
3264
3888
|
*/
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
if (
|
|
3268
|
-
|
|
3269
|
-
if (this.
|
|
3270
|
-
this.
|
|
3889
|
+
_parseOptionsEnv() {
|
|
3890
|
+
this.options.forEach((option) => {
|
|
3891
|
+
if (option.envVar && option.envVar in import_node_process.default.env) {
|
|
3892
|
+
const optionKey = option.attributeName();
|
|
3893
|
+
if (this.getOptionValue(optionKey) === void 0 || ["default", "config", "env"].includes(
|
|
3894
|
+
this.getOptionValueSource(optionKey)
|
|
3895
|
+
)) {
|
|
3896
|
+
if (option.required || option.optional) {
|
|
3897
|
+
this.emit(`optionEnv:${option.name()}`, import_node_process.default.env[option.envVar]);
|
|
3898
|
+
} else {
|
|
3899
|
+
this.emit(`optionEnv:${option.name()}`);
|
|
3900
|
+
}
|
|
3271
3901
|
}
|
|
3272
|
-
} else {
|
|
3273
|
-
this._helpOption = null;
|
|
3274
3902
|
}
|
|
3275
|
-
|
|
3276
|
-
}
|
|
3277
|
-
this._helpOption = this.createOption(
|
|
3278
|
-
flags ?? "-h, --help",
|
|
3279
|
-
description ?? "display help for command"
|
|
3280
|
-
);
|
|
3281
|
-
if (flags || description) this._initOptionGroup(this._helpOption);
|
|
3282
|
-
return this;
|
|
3903
|
+
});
|
|
3283
3904
|
}
|
|
3284
3905
|
/**
|
|
3285
|
-
*
|
|
3286
|
-
* Returns null if has been disabled with .helpOption(false).
|
|
3906
|
+
* Apply any implied option values, if option is undefined or default value.
|
|
3287
3907
|
*
|
|
3288
|
-
* @
|
|
3289
|
-
* @package
|
|
3908
|
+
* @private
|
|
3290
3909
|
*/
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
|
|
3910
|
+
_parseOptionsImplied() {
|
|
3911
|
+
const dualHelper = new DualOptions(this.options);
|
|
3912
|
+
const hasCustomOptionValue = (optionKey) => {
|
|
3913
|
+
return this.getOptionValue(optionKey) !== void 0 && !["default", "implied"].includes(this.getOptionValueSource(optionKey));
|
|
3914
|
+
};
|
|
3915
|
+
this.options.filter(
|
|
3916
|
+
(option) => option.implied !== void 0 && hasCustomOptionValue(option.attributeName()) && dualHelper.valueFromOption(
|
|
3917
|
+
this.getOptionValue(option.attributeName()),
|
|
3918
|
+
option
|
|
3919
|
+
)
|
|
3920
|
+
).forEach((option) => {
|
|
3921
|
+
Object.keys(option.implied).filter((impliedKey) => !hasCustomOptionValue(impliedKey)).forEach((impliedKey) => {
|
|
3922
|
+
this.setOptionValueWithSource(
|
|
3923
|
+
impliedKey,
|
|
3924
|
+
option.implied[impliedKey],
|
|
3925
|
+
"implied"
|
|
3926
|
+
);
|
|
3927
|
+
});
|
|
3928
|
+
});
|
|
3296
3929
|
}
|
|
3297
3930
|
/**
|
|
3298
|
-
*
|
|
3299
|
-
* This is an alternative to using helpOption() to customise the flags and description etc.
|
|
3931
|
+
* Argument `name` is missing.
|
|
3300
3932
|
*
|
|
3301
|
-
* @param {
|
|
3302
|
-
* @
|
|
3933
|
+
* @param {string} name
|
|
3934
|
+
* @private
|
|
3303
3935
|
*/
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
this.
|
|
3307
|
-
return this;
|
|
3936
|
+
missingArgument(name) {
|
|
3937
|
+
const message2 = `error: missing required argument '${name}'`;
|
|
3938
|
+
this.error(message2, { code: "commander.missingArgument" });
|
|
3308
3939
|
}
|
|
3309
3940
|
/**
|
|
3310
|
-
*
|
|
3311
|
-
*
|
|
3312
|
-
* Outputs built-in help, and custom text added using `.addHelpText()`.
|
|
3941
|
+
* `Option` is missing an argument.
|
|
3313
3942
|
*
|
|
3314
|
-
* @param {
|
|
3943
|
+
* @param {Option} option
|
|
3944
|
+
* @private
|
|
3315
3945
|
*/
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
if (exitCode === 0 && contextOptions && typeof contextOptions !== "function" && contextOptions.error) {
|
|
3320
|
-
exitCode = 1;
|
|
3321
|
-
}
|
|
3322
|
-
this._exit(exitCode, "commander.help", "(outputHelp)");
|
|
3946
|
+
optionMissingArgument(option) {
|
|
3947
|
+
const message2 = `error: option '${option.flags}' argument missing`;
|
|
3948
|
+
this.error(message2, { code: "commander.optionMissingArgument" });
|
|
3323
3949
|
}
|
|
3324
3950
|
/**
|
|
3325
|
-
*
|
|
3326
|
-
* @typedef HelpTextEventContext
|
|
3327
|
-
* @type {object}
|
|
3328
|
-
* @property {boolean} error
|
|
3329
|
-
* @property {Command} command
|
|
3330
|
-
* @property {function} write
|
|
3331
|
-
*/
|
|
3332
|
-
/**
|
|
3333
|
-
* Add additional text to be displayed with the built-in help.
|
|
3334
|
-
*
|
|
3335
|
-
* Position is 'before' or 'after' to affect just this command,
|
|
3336
|
-
* and 'beforeAll' or 'afterAll' to affect this command and all its subcommands.
|
|
3951
|
+
* `Option` does not have a value, and is a mandatory option.
|
|
3337
3952
|
*
|
|
3338
|
-
* @param {
|
|
3339
|
-
* @
|
|
3340
|
-
* @return {Command} `this` command for chaining
|
|
3953
|
+
* @param {Option} option
|
|
3954
|
+
* @private
|
|
3341
3955
|
*/
|
|
3342
|
-
|
|
3343
|
-
const
|
|
3344
|
-
|
|
3345
|
-
throw new Error(`Unexpected value for position to addHelpText.
|
|
3346
|
-
Expecting one of '${allowedValues.join("', '")}'`);
|
|
3347
|
-
}
|
|
3348
|
-
const helpEvent = `${position}Help`;
|
|
3349
|
-
this.on(helpEvent, (context) => {
|
|
3350
|
-
let helpStr;
|
|
3351
|
-
if (typeof text === "function") {
|
|
3352
|
-
helpStr = text({ error: context.error, command: context.command });
|
|
3353
|
-
} else {
|
|
3354
|
-
helpStr = text;
|
|
3355
|
-
}
|
|
3356
|
-
if (helpStr) {
|
|
3357
|
-
context.write(`${helpStr}
|
|
3358
|
-
`);
|
|
3359
|
-
}
|
|
3360
|
-
});
|
|
3361
|
-
return this;
|
|
3956
|
+
missingMandatoryOptionValue(option) {
|
|
3957
|
+
const message2 = `error: required option '${option.flags}' not specified`;
|
|
3958
|
+
this.error(message2, { code: "commander.missingMandatoryOptionValue" });
|
|
3362
3959
|
}
|
|
3363
3960
|
/**
|
|
3364
|
-
*
|
|
3961
|
+
* `Option` conflicts with another option.
|
|
3365
3962
|
*
|
|
3366
|
-
* @param {
|
|
3963
|
+
* @param {Option} option
|
|
3964
|
+
* @param {Option} conflictingOption
|
|
3367
3965
|
* @private
|
|
3368
3966
|
*/
|
|
3369
|
-
|
|
3370
|
-
const
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
this.
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
return arg;
|
|
3382
|
-
}
|
|
3383
|
-
let debugOption;
|
|
3384
|
-
let debugHost = "127.0.0.1";
|
|
3385
|
-
let debugPort = "9229";
|
|
3386
|
-
let match;
|
|
3387
|
-
if ((match = arg.match(/^(--inspect(-brk)?)$/)) !== null) {
|
|
3388
|
-
debugOption = match[1];
|
|
3389
|
-
} else if ((match = arg.match(/^(--inspect(-brk|-port)?)=([^:]+)$/)) !== null) {
|
|
3390
|
-
debugOption = match[1];
|
|
3391
|
-
if (/^\d+$/.test(match[3])) {
|
|
3392
|
-
debugPort = match[3];
|
|
3393
|
-
} else {
|
|
3394
|
-
debugHost = match[3];
|
|
3967
|
+
_conflictingOption(option, conflictingOption) {
|
|
3968
|
+
const findBestOptionFromValue = (option2) => {
|
|
3969
|
+
const optionKey = option2.attributeName();
|
|
3970
|
+
const optionValue = this.getOptionValue(optionKey);
|
|
3971
|
+
const negativeOption = this.options.find(
|
|
3972
|
+
(target) => target.negate && optionKey === target.attributeName()
|
|
3973
|
+
);
|
|
3974
|
+
const positiveOption = this.options.find(
|
|
3975
|
+
(target) => !target.negate && optionKey === target.attributeName()
|
|
3976
|
+
);
|
|
3977
|
+
if (negativeOption && (negativeOption.presetArg === void 0 && optionValue === false || negativeOption.presetArg !== void 0 && optionValue === negativeOption.presetArg)) {
|
|
3978
|
+
return negativeOption;
|
|
3395
3979
|
}
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
return arg;
|
|
3405
|
-
});
|
|
3406
|
-
}
|
|
3407
|
-
function useColor() {
|
|
3408
|
-
if (import_node_process.default.env.NO_COLOR || import_node_process.default.env.FORCE_COLOR === "0" || import_node_process.default.env.FORCE_COLOR === "false")
|
|
3409
|
-
return false;
|
|
3410
|
-
if (import_node_process.default.env.FORCE_COLOR || import_node_process.default.env.CLICOLOR_FORCE !== void 0)
|
|
3411
|
-
return true;
|
|
3412
|
-
return void 0;
|
|
3413
|
-
}
|
|
3414
|
-
|
|
3415
|
-
// node_modules/commander/index.js
|
|
3416
|
-
var program = new Command();
|
|
3417
|
-
|
|
3418
|
-
// src/command-composition.ts
|
|
3419
|
-
var import_node_fs48 = require("node:fs");
|
|
3420
|
-
|
|
3421
|
-
// src/clean-exit.ts
|
|
3422
|
-
var UNDICI_GLOBAL_DISPATCHER_SYMBOL = Object.getOwnPropertySymbols(globalThis).find(
|
|
3423
|
-
(s) => s.description === "undici.globalDispatcher.1" || s.description?.startsWith("undici.globalDispatcher.")
|
|
3424
|
-
) ?? /* @__PURE__ */ Symbol.for("undici.globalDispatcher.1");
|
|
3425
|
-
function globalDispatcher() {
|
|
3426
|
-
return globalThis[UNDICI_GLOBAL_DISPATCHER_SYMBOL];
|
|
3427
|
-
}
|
|
3428
|
-
function destroyHttpPool() {
|
|
3429
|
-
try {
|
|
3430
|
-
const dispatcher = globalDispatcher();
|
|
3431
|
-
if (dispatcher?.destroy) {
|
|
3432
|
-
void dispatcher.destroy();
|
|
3433
|
-
return true;
|
|
3434
|
-
}
|
|
3435
|
-
} catch {
|
|
3436
|
-
}
|
|
3437
|
-
return false;
|
|
3438
|
-
}
|
|
3439
|
-
var closingDispatcher;
|
|
3440
|
-
var closingDispatcherPromise;
|
|
3441
|
-
async function closeHttpPool() {
|
|
3442
|
-
const dispatcher = globalDispatcher();
|
|
3443
|
-
if (!dispatcher) return;
|
|
3444
|
-
if (dispatcher === closingDispatcher && closingDispatcherPromise) {
|
|
3445
|
-
await closingDispatcherPromise;
|
|
3446
|
-
return;
|
|
3447
|
-
}
|
|
3448
|
-
closingDispatcher = dispatcher;
|
|
3449
|
-
closingDispatcherPromise = (async () => {
|
|
3450
|
-
try {
|
|
3451
|
-
if (dispatcher.close) await dispatcher.close();
|
|
3452
|
-
else if (dispatcher.destroy) await dispatcher.destroy();
|
|
3453
|
-
} catch {
|
|
3454
|
-
try {
|
|
3455
|
-
if (dispatcher.destroy) await dispatcher.destroy();
|
|
3456
|
-
} catch {
|
|
3980
|
+
return positiveOption || option2;
|
|
3981
|
+
};
|
|
3982
|
+
const getErrorMessage = (option2) => {
|
|
3983
|
+
const bestOption = findBestOptionFromValue(option2);
|
|
3984
|
+
const optionKey = bestOption.attributeName();
|
|
3985
|
+
const source = this.getOptionValueSource(optionKey);
|
|
3986
|
+
if (source === "env") {
|
|
3987
|
+
return `environment variable '${bestOption.envVar}'`;
|
|
3457
3988
|
}
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
}
|
|
3462
|
-
function hardExit(code) {
|
|
3463
|
-
destroyHttpPool();
|
|
3464
|
-
process.exit(code);
|
|
3465
|
-
}
|
|
3466
|
-
var STDIO_FLUSH_TIMEOUT_MS = 2e3;
|
|
3467
|
-
function flushStream(stream) {
|
|
3468
|
-
return new Promise((resolve7) => {
|
|
3469
|
-
try {
|
|
3470
|
-
stream.write("", () => resolve7());
|
|
3471
|
-
} catch {
|
|
3472
|
-
resolve7();
|
|
3473
|
-
}
|
|
3474
|
-
});
|
|
3475
|
-
}
|
|
3476
|
-
async function flushStdio(timeoutMs = STDIO_FLUSH_TIMEOUT_MS) {
|
|
3477
|
-
await Promise.race([
|
|
3478
|
-
Promise.all([flushStream(process.stdout), flushStream(process.stderr)]),
|
|
3479
|
-
new Promise((resolve7) => {
|
|
3480
|
-
setTimeout(resolve7, timeoutMs).unref?.();
|
|
3481
|
-
})
|
|
3482
|
-
]);
|
|
3483
|
-
}
|
|
3484
|
-
async function cleanExit(code) {
|
|
3485
|
-
process.exitCode = code;
|
|
3486
|
-
await closeHttpPool();
|
|
3487
|
-
await flushStdio();
|
|
3488
|
-
await new Promise((resolve7) => setImmediate(resolve7));
|
|
3489
|
-
return void 0;
|
|
3490
|
-
}
|
|
3491
|
-
var CLI_EXIT_WATCHDOG_MS = (() => {
|
|
3492
|
-
const testOverride = Number(process.env.MMI_CLI_TEST_EXIT_WATCHDOG_MS);
|
|
3493
|
-
return process.env.NODE_ENV === "test" && Number.isFinite(testOverride) && testOverride >= 25 ? testOverride : 1e4;
|
|
3494
|
-
})();
|
|
3495
|
-
async function finishCliRun(watchdogMs = CLI_EXIT_WATCHDOG_MS) {
|
|
3496
|
-
const timer = setTimeout(() => {
|
|
3497
|
-
console.error(
|
|
3498
|
-
`mmi-cli: command finished but the process did not exit within ${watchdogMs}ms \u2014 a handle leaked (${describeActiveHandles()}); forcing exit (#2904). Please report this.`
|
|
3499
|
-
);
|
|
3500
|
-
void flushStdio().finally(() => process.exit(typeof process.exitCode === "number" ? process.exitCode : 0));
|
|
3501
|
-
}, watchdogMs);
|
|
3502
|
-
timer.unref?.();
|
|
3503
|
-
await closeHttpPool();
|
|
3504
|
-
}
|
|
3505
|
-
function describeActiveHandles() {
|
|
3506
|
-
let summary;
|
|
3507
|
-
try {
|
|
3508
|
-
const counts = /* @__PURE__ */ new Map();
|
|
3509
|
-
for (const type of process.getActiveResourcesInfo()) counts.set(type, (counts.get(type) ?? 0) + 1);
|
|
3510
|
-
summary = [...counts.entries()].sort().map(([type, n]) => n > 1 ? `${type}\xD7${n}` : type).join(", ") || "none reported";
|
|
3511
|
-
} catch {
|
|
3512
|
-
summary = "unavailable";
|
|
3513
|
-
}
|
|
3514
|
-
try {
|
|
3515
|
-
const children = (process._getActiveHandles?.() ?? []).filter((h) => h?.constructor?.name === "ChildProcess").map((h) => `${h.spawnfile ?? "?"}(pid=${h.pid ?? "?"})`);
|
|
3516
|
-
if (children.length) summary += `; live children: ${children.join(", ")}`;
|
|
3517
|
-
} catch {
|
|
3518
|
-
}
|
|
3519
|
-
return summary;
|
|
3520
|
-
}
|
|
3521
|
-
async function failGraceful(msg) {
|
|
3522
|
-
console.error(`mmi-cli ${msg}`);
|
|
3523
|
-
return cleanExit(1);
|
|
3524
|
-
}
|
|
3525
|
-
|
|
3526
|
-
// src/cli-shared.ts
|
|
3527
|
-
var import_node_child_process2 = require("node:child_process");
|
|
3528
|
-
var import_node_fs5 = require("node:fs");
|
|
3529
|
-
var import_node_util3 = require("node:util");
|
|
3530
|
-
|
|
3531
|
-
// src/hub-url.ts
|
|
3532
|
-
var DEFAULT_HUB_URL = "https://tqxxwzftic.execute-api.eu-central-1.amazonaws.com";
|
|
3533
|
-
function defaultHubUrl() {
|
|
3534
|
-
return process.env.MMI_HUB_URL || DEFAULT_HUB_URL;
|
|
3535
|
-
}
|
|
3536
|
-
|
|
3537
|
-
// src/client-version.ts
|
|
3538
|
-
var import_node_fs2 = require("node:fs");
|
|
3539
|
-
var import_node_path2 = require("node:path");
|
|
3540
|
-
|
|
3541
|
-
// ../infra/compat.mjs
|
|
3542
|
-
var CLIENT_VERSION_HEADER = "x-client-version";
|
|
3543
|
-
function parseSemver(s) {
|
|
3544
|
-
if (typeof s !== "string") return null;
|
|
3545
|
-
const m = /^(\d+)\.(\d+)\.(\d+)(?:[-+]|$)/.exec(s.trim());
|
|
3546
|
-
if (!m) return null;
|
|
3547
|
-
return { major: Number(m[1]), minor: Number(m[2]), patch: Number(m[3]) };
|
|
3548
|
-
}
|
|
3549
|
-
function versionAtLeast(v, min) {
|
|
3550
|
-
const a = parseSemver(v);
|
|
3551
|
-
const b = parseSemver(min);
|
|
3552
|
-
if (!a || !b) return false;
|
|
3553
|
-
if (a.major !== b.major) return a.major > b.major;
|
|
3554
|
-
if (a.minor !== b.minor) return a.minor > b.minor;
|
|
3555
|
-
return a.patch >= b.patch;
|
|
3556
|
-
}
|
|
3557
|
-
|
|
3558
|
-
// src/client-version.ts
|
|
3559
|
-
function resolveClientVersionManifestCandidates(distDir = __dirname) {
|
|
3560
|
-
return [
|
|
3561
|
-
(0, import_node_path2.join)(distDir, "..", "..", ".claude-plugin", "plugin.json"),
|
|
3562
|
-
(0, import_node_path2.join)(distDir, "..", "package.json")
|
|
3563
|
-
];
|
|
3564
|
-
}
|
|
3565
|
-
function readVersionFromManifest(path2) {
|
|
3566
|
-
try {
|
|
3567
|
-
const version = JSON.parse((0, import_node_fs2.readFileSync)(path2, "utf8")).version;
|
|
3568
|
-
return typeof version === "string" && version.trim() ? version.trim() : null;
|
|
3569
|
-
} catch {
|
|
3570
|
-
return null;
|
|
3571
|
-
}
|
|
3572
|
-
}
|
|
3573
|
-
function resolveClientVersion() {
|
|
3574
|
-
for (const manifest of resolveClientVersionManifestCandidates()) {
|
|
3575
|
-
const version = readVersionFromManifest(manifest);
|
|
3576
|
-
if (version) return version;
|
|
3577
|
-
}
|
|
3578
|
-
return "0.0.0";
|
|
3579
|
-
}
|
|
3580
|
-
function clientVersionHeaders() {
|
|
3581
|
-
return { [CLIENT_VERSION_HEADER]: resolveClientVersion() };
|
|
3582
|
-
}
|
|
3583
|
-
function upgradeRequiredError(res, body) {
|
|
3584
|
-
const minVersion = body && typeof body === "object" && typeof body.minVersion === "string" ? body.minVersion : "a newer version";
|
|
3585
|
-
return `Hub requires mmi-cli >= ${minVersion} \u2014 run mmi-cli doctor (installed ${resolveClientVersion()})`;
|
|
3586
|
-
}
|
|
3587
|
-
|
|
3588
|
-
// src/error-codes.ts
|
|
3589
|
-
var ERROR_CODES = {
|
|
3590
|
-
/** A required flag was not supplied (e.g. `issue create` without `--priority`). */
|
|
3591
|
-
ERR_MISSING_FLAG: "ERR_MISSING_FLAG",
|
|
3592
|
-
/** Two mutually-exclusive flags were both supplied (e.g. `--title` with `--title-file`). */
|
|
3593
|
-
ERR_CONFLICTING_FLAGS: "ERR_CONFLICTING_FLAGS",
|
|
3594
|
-
/** A flag was supplied but its resolved value is empty (e.g. an empty `--title-file` or empty stdin). */
|
|
3595
|
-
ERR_EMPTY_INPUT: "ERR_EMPTY_INPUT",
|
|
3596
|
-
/** A supplied value has the right source but an invalid shape (e.g. a title with line breaks). */
|
|
3597
|
-
ERR_INVALID_INPUT: "ERR_INVALID_INPUT",
|
|
3598
|
-
/** A flag's value is outside its allowed set (e.g. `--priority nope`). */
|
|
3599
|
-
ERR_BAD_ENUM: "ERR_BAD_ENUM",
|
|
3600
|
-
/** An unknown flag or subcommand — usually a typo; carries a `did_you_mean`. */
|
|
3601
|
-
ERR_UNKNOWN_FLAG: "ERR_UNKNOWN_FLAG",
|
|
3602
|
-
/** A positional argument was passed to a command that does not take it (e.g. `oracle board read 496`,
|
|
3603
|
-
* a whole-board read given an issue number). Carries a `corrected_command` when exactly one sibling
|
|
3604
|
-
* answers the same verb positionally (#6354). */
|
|
3605
|
-
ERR_EXCESS_ARGUMENT: "ERR_EXCESS_ARGUMENT",
|
|
3606
|
-
/** A referenced resource (issue, repo, board item) does not exist. */
|
|
3607
|
-
ERR_NOT_FOUND: "ERR_NOT_FOUND",
|
|
3608
|
-
/** Missing / rejected credentials on a path that needs auth. */
|
|
3609
|
-
ERR_NO_AUTH: "ERR_NO_AUTH",
|
|
3610
|
-
/** The operation partially succeeded (some units done, some failed). */
|
|
3611
|
-
ERR_PARTIAL: "ERR_PARTIAL",
|
|
3612
|
-
/** The request was well-formed and every referent resolved, but the target's CURRENT STATE forbids the
|
|
3613
|
-
* mutation (HTTP 409 semantics) — e.g. reparenting an issue that already has a parent. Deliberately not
|
|
3614
|
-
* one code per API constraint: retry is futile until the named state is changed, and that is the fact a
|
|
3615
|
-
* caller has to act on, whichever rule produced it. */
|
|
3616
|
-
ERR_STATE_CONFLICT: "ERR_STATE_CONFLICT"
|
|
3617
|
-
};
|
|
3618
|
-
var ERROR_CODE_REFERENCE = [
|
|
3619
|
-
{
|
|
3620
|
-
code: ERROR_CODES.ERR_MISSING_FLAG,
|
|
3621
|
-
meaning: "A required flag was not supplied.",
|
|
3622
|
-
typical_fix: "Run `mmi-cli explain <command>` and retry with the required flag."
|
|
3623
|
-
},
|
|
3624
|
-
{
|
|
3625
|
-
code: ERROR_CODES.ERR_CONFLICTING_FLAGS,
|
|
3626
|
-
meaning: "Two mutually-exclusive flags were supplied together.",
|
|
3627
|
-
typical_fix: "Pass only one of the conflicting flags (see `offending_flag`) and retry."
|
|
3628
|
-
},
|
|
3629
|
-
{
|
|
3630
|
-
code: ERROR_CODES.ERR_EMPTY_INPUT,
|
|
3631
|
-
meaning: "A flag was supplied but resolved to an empty value (e.g. an empty file or empty stdin).",
|
|
3632
|
-
typical_fix: "Provide non-empty content for the flag in `offending_flag` (a file with text, or a real pipe/heredoc for stdin)."
|
|
3633
|
-
},
|
|
3634
|
-
{
|
|
3635
|
-
code: ERROR_CODES.ERR_INVALID_INPUT,
|
|
3636
|
-
meaning: "A supplied value has an invalid shape for the flag.",
|
|
3637
|
-
typical_fix: "Correct the value named by `offending_flag` and retry."
|
|
3638
|
-
},
|
|
3639
|
-
{
|
|
3640
|
-
code: ERROR_CODES.ERR_BAD_ENUM,
|
|
3641
|
-
meaning: "A flag value is outside the allowed enum.",
|
|
3642
|
-
typical_fix: "Use one of the values in `expected`; casing and separators are often normalized by the CLI when supported."
|
|
3643
|
-
},
|
|
3644
|
-
{
|
|
3645
|
-
code: ERROR_CODES.ERR_UNKNOWN_FLAG,
|
|
3646
|
-
meaning: "A flag or subcommand is not known to this CLI version.",
|
|
3647
|
-
typical_fix: "Check `did_you_mean`, route with `mmi-cli commands --json`, then inspect exact detail with `mmi-cli explain <command> --json`; update the CLI if it should exist."
|
|
3648
|
-
},
|
|
3649
|
-
{
|
|
3650
|
-
code: ERROR_CODES.ERR_EXCESS_ARGUMENT,
|
|
3651
|
-
meaning: "A positional argument was supplied to a command that takes none (or fewer).",
|
|
3652
|
-
typical_fix: "Run the command named by `corrected_command`; otherwise drop the extra argument and select the target with the flags in `mmi-cli explain <command> --json`."
|
|
3653
|
-
},
|
|
3654
|
-
{
|
|
3655
|
-
code: ERROR_CODES.ERR_NOT_FOUND,
|
|
3656
|
-
meaning: "The referenced issue, PR, repo, board item, or other resource was not found.",
|
|
3657
|
-
typical_fix: "Verify the identifier and repo, then rerun with an explicit `--repo <owner/repo>` when local repo detection is ambiguous."
|
|
3658
|
-
},
|
|
3659
|
-
{
|
|
3660
|
-
code: ERROR_CODES.ERR_NO_AUTH,
|
|
3661
|
-
meaning: "The command needs credentials that are missing, expired, or rejected.",
|
|
3662
|
-
typical_fix: "Run `mmi-cli doctor --self` or refresh the relevant GitHub/Hub session before retrying."
|
|
3663
|
-
},
|
|
3664
|
-
{
|
|
3665
|
-
code: ERROR_CODES.ERR_PARTIAL,
|
|
3666
|
-
meaning: "A batch operation completed some units and failed others.",
|
|
3667
|
-
typical_fix: "Read the per-unit results, fix the failed inputs, and rerun only the failed units."
|
|
3668
|
-
},
|
|
3669
|
-
{
|
|
3670
|
-
code: ERROR_CODES.ERR_STATE_CONFLICT,
|
|
3671
|
-
meaning: "The request was valid and every referent resolved, but the target resource's current state forbids it.",
|
|
3672
|
-
typical_fix: "A plain retry fails identically. Read the state field the envelope names (e.g. `current_parent`), change that state deliberately with the command that owns it, then retry."
|
|
3673
|
-
}
|
|
3674
|
-
];
|
|
3675
|
-
function buildErrorEnvelope(message2, payload) {
|
|
3676
|
-
const env = { error_code: payload.code, message: message2 };
|
|
3677
|
-
if (payload.offending_flag !== void 0) env.offending_flag = payload.offending_flag;
|
|
3678
|
-
if (payload.expected !== void 0) env.expected = payload.expected;
|
|
3679
|
-
if (payload.did_you_mean !== void 0) env.did_you_mean = payload.did_you_mean;
|
|
3680
|
-
if (payload.corrected_command !== void 0) env.corrected_command = payload.corrected_command;
|
|
3681
|
-
if (payload.current_parent !== void 0) env.current_parent = payload.current_parent;
|
|
3682
|
-
if (payload.issue_ref !== void 0) env.issue_ref = payload.issue_ref;
|
|
3683
|
-
if (payload.board_status !== void 0) env.board_status = payload.board_status;
|
|
3684
|
-
return env;
|
|
3685
|
-
}
|
|
3686
|
-
function formatErrorEnvelope(message2, payload) {
|
|
3687
|
-
return JSON.stringify(buildErrorEnvelope(message2, payload));
|
|
3688
|
-
}
|
|
3689
|
-
function levenshtein(a, b) {
|
|
3690
|
-
if (a === b) return 0;
|
|
3691
|
-
if (a.length === 0) return b.length;
|
|
3692
|
-
if (b.length === 0) return a.length;
|
|
3693
|
-
let prev = Array.from({ length: b.length + 1 }, (_, i) => i);
|
|
3694
|
-
let curr = new Array(b.length + 1);
|
|
3695
|
-
for (let i = 1; i <= a.length; i++) {
|
|
3696
|
-
curr[0] = i;
|
|
3697
|
-
for (let j = 1; j <= b.length; j++) {
|
|
3698
|
-
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
3699
|
-
curr[j] = Math.min(curr[j - 1] + 1, prev[j] + 1, prev[j - 1] + cost);
|
|
3700
|
-
}
|
|
3701
|
-
[prev, curr] = [curr, prev];
|
|
3702
|
-
}
|
|
3703
|
-
return prev[b.length];
|
|
3704
|
-
}
|
|
3705
|
-
function didYouMean(input, candidates) {
|
|
3706
|
-
const strip = (s) => s.replace(/^-+/, "");
|
|
3707
|
-
const target = strip(input);
|
|
3708
|
-
if (!target) return void 0;
|
|
3709
|
-
let best;
|
|
3710
|
-
for (const candidate of candidates) {
|
|
3711
|
-
const cand = strip(candidate);
|
|
3712
|
-
if (!cand) continue;
|
|
3713
|
-
if (cand === target) continue;
|
|
3714
|
-
if (cand === `${target}-file` || target === `${cand}-file`) continue;
|
|
3715
|
-
const distance = levenshtein(target, cand);
|
|
3716
|
-
const prefix = cand.startsWith(target) || target.startsWith(cand);
|
|
3717
|
-
const threshold = Math.max(2, Math.ceil(cand.length * 0.4));
|
|
3718
|
-
if (!prefix && distance > threshold) continue;
|
|
3719
|
-
const better = !best || distance < best.distance || distance === best.distance && prefix && !best.prefix;
|
|
3720
|
-
if (better) best = { flag: candidate, distance, prefix };
|
|
3721
|
-
}
|
|
3722
|
-
return best?.flag;
|
|
3723
|
-
}
|
|
3724
|
-
|
|
3725
|
-
// src/github-client.ts
|
|
3726
|
-
function classifyGhTokenExecFailure(e) {
|
|
3727
|
-
const err = e;
|
|
3728
|
-
const stderr = typeof err?.stderr === "string" ? err.stderr.trim() : "";
|
|
3729
|
-
const detail = (stderr || err?.message || String(e)).replace(/\s+/g, " ").slice(0, 200);
|
|
3730
|
-
if (err?.code === "ENOENT") return { state: "absent", detail: "gh is not installed on PATH" };
|
|
3731
|
-
if (err?.killed === true || (err?.signal ?? null) !== null) return { state: "failed", detail: `gh auth token did not complete (${detail})` };
|
|
3732
|
-
if (/not logged (in|into)|no oauth token|authentication token not found|gh auth login/i.test(`${stderr} ${err?.message ?? ""}`)) {
|
|
3733
|
-
return { state: "absent", detail: "gh is installed but not logged in" };
|
|
3734
|
-
}
|
|
3735
|
-
return { state: "failed", detail };
|
|
3736
|
-
}
|
|
3737
|
-
var cachedGhCliTokenRead;
|
|
3738
|
-
async function githubTokenRead() {
|
|
3739
|
-
if (process.env.GH_TOKEN) return { state: "ok", token: process.env.GH_TOKEN };
|
|
3740
|
-
if (process.env.GITHUB_TOKEN) return { state: "ok", token: process.env.GITHUB_TOKEN };
|
|
3741
|
-
cachedGhCliTokenRead ??= execFileP("gh", ["auth", "token"]).then(({ stdout }) => {
|
|
3742
|
-
const token = stdout.trim();
|
|
3743
|
-
return token ? { state: "ok", token } : { state: "absent", detail: "`gh auth token` exited 0 without printing a token" };
|
|
3744
|
-
}).catch((e) => classifyGhTokenExecFailure(e));
|
|
3745
|
-
return cachedGhCliTokenRead;
|
|
3746
|
-
}
|
|
3747
|
-
async function githubToken() {
|
|
3748
|
-
const read = await githubTokenRead();
|
|
3749
|
-
if (read.state === "failed") {
|
|
3750
|
-
throw new GitHubApiError(
|
|
3751
|
-
`GitHub identity read FAILED: \`gh auth token\` ${read.detail} \u2014 this is NOT "no token", so the call is refused rather than sent anonymously (an anonymous 401/404 would read as a permission or missing-object answer). Retry, or set GH_TOKEN/GITHUB_TOKEN for this process.`,
|
|
3752
|
-
{ status: 0 }
|
|
3753
|
-
);
|
|
3754
|
-
}
|
|
3755
|
-
return read.state === "ok" ? read.token : void 0;
|
|
3756
|
-
}
|
|
3757
|
-
var GitHubApiError = class extends Error {
|
|
3758
|
-
status;
|
|
3759
|
-
stderr;
|
|
3760
|
-
graphqlErrors;
|
|
3761
|
-
/** #4588: true when GitHub refused THIS call for budget (primary or secondary rate limit),
|
|
3762
|
-
* read from the refusing response itself — never the rate_limit endpoint. */
|
|
3763
|
-
rateLimited;
|
|
3764
|
-
/** Epoch seconds when the exhausted pool resets (`X-Ratelimit-Reset` of the refusing response). */
|
|
3765
|
-
rateLimitReset;
|
|
3766
|
-
constructor(message2, opts = {}) {
|
|
3767
|
-
super(message2);
|
|
3768
|
-
this.name = "GitHubApiError";
|
|
3769
|
-
this.status = opts.status ?? 0;
|
|
3770
|
-
this.stderr = message2;
|
|
3771
|
-
this.graphqlErrors = opts.graphqlErrors;
|
|
3772
|
-
this.rateLimited = opts.rateLimited;
|
|
3773
|
-
this.rateLimitReset = opts.rateLimitReset;
|
|
3774
|
-
}
|
|
3775
|
-
};
|
|
3776
|
-
function rateLimitResetNote(resetEpochSeconds, now = Date.now()) {
|
|
3777
|
-
if (!resetEpochSeconds) return "rate limit exhausted; reset time unknown";
|
|
3778
|
-
const resetMs = resetEpochSeconds * 1e3;
|
|
3779
|
-
const minutes = Math.max(0, Math.ceil((resetMs - now) / 6e4));
|
|
3780
|
-
return `rate limit exhausted; resets at ${new Date(resetMs).toISOString()} (~${minutes}m)`;
|
|
3781
|
-
}
|
|
3782
|
-
function rateLimitFromResponse(res, detail) {
|
|
3783
|
-
const remaining = res.headers.get("x-ratelimit-remaining");
|
|
3784
|
-
const resetHeader = res.headers.get("x-ratelimit-reset");
|
|
3785
|
-
const reset = resetHeader && /^\d+$/.test(resetHeader) ? Number(resetHeader) : void 0;
|
|
3786
|
-
const rateLimited = (res.status === 403 || res.status === 429) && remaining === "0" || /rate limit|secondary rate|abuse detection/i.test(detail);
|
|
3787
|
-
return { rateLimited, ...rateLimited && reset !== void 0 ? { rateLimitReset: reset } : {} };
|
|
3788
|
-
}
|
|
3789
|
-
var DEFAULT_TIMEOUT_MS = 2e4;
|
|
3790
|
-
function joinUrl(base, path2) {
|
|
3791
|
-
if (path2.startsWith("http://") || path2.startsWith("https://")) return path2;
|
|
3792
|
-
return `${base.replace(/\/+$/, "")}/${path2.replace(/^\/+/, "")}`;
|
|
3793
|
-
}
|
|
3794
|
-
function withPerPage(url) {
|
|
3795
|
-
if (/[?&]per_page=/.test(url)) return url;
|
|
3796
|
-
return url.includes("?") ? `${url}&per_page=100` : `${url}?per_page=100`;
|
|
3797
|
-
}
|
|
3798
|
-
function apiOrigin(baseUrl) {
|
|
3799
|
-
return new URL(baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`).origin;
|
|
3800
|
-
}
|
|
3801
|
-
function nextLink(linkHeader) {
|
|
3802
|
-
if (!linkHeader) return void 0;
|
|
3803
|
-
for (const part of linkHeader.split(",")) {
|
|
3804
|
-
const match = part.match(/<([^>]+)>\s*;\s*rel="next"/);
|
|
3805
|
-
if (match) return match[1];
|
|
3989
|
+
return `option '${bestOption.flags}'`;
|
|
3990
|
+
};
|
|
3991
|
+
const message2 = `error: ${getErrorMessage(option)} cannot be used with ${getErrorMessage(conflictingOption)}`;
|
|
3992
|
+
this.error(message2, { code: "commander.conflictingOption" });
|
|
3806
3993
|
}
|
|
3807
|
-
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
|
|
3994
|
+
/**
|
|
3995
|
+
* Unknown option `flag`.
|
|
3996
|
+
*
|
|
3997
|
+
* @param {string} flag
|
|
3998
|
+
* @private
|
|
3999
|
+
*/
|
|
4000
|
+
unknownOption(flag) {
|
|
4001
|
+
if (this._allowUnknownOption) return;
|
|
4002
|
+
let suggestion = "";
|
|
4003
|
+
if (flag.startsWith("--") && this._showSuggestionAfterError) {
|
|
4004
|
+
let candidateFlags = [];
|
|
4005
|
+
let command = this;
|
|
4006
|
+
do {
|
|
4007
|
+
const moreFlags = command.createHelp().visibleOptions(command).filter((option) => option.long).map((option) => option.long);
|
|
4008
|
+
candidateFlags = candidateFlags.concat(moreFlags);
|
|
4009
|
+
command = command.parent;
|
|
4010
|
+
} while (command && !command._enablePositionalOptions);
|
|
4011
|
+
suggestion = suggestSimilar(flag, candidateFlags);
|
|
4012
|
+
}
|
|
4013
|
+
const message2 = `error: unknown option '${flag}'${suggestion}`;
|
|
4014
|
+
this.error(message2, { code: "commander.unknownOption" });
|
|
3817
4015
|
}
|
|
3818
|
-
|
|
3819
|
-
|
|
4016
|
+
/**
|
|
4017
|
+
* Excess arguments, more than expected.
|
|
4018
|
+
*
|
|
4019
|
+
* @param {string[]} receivedArgs
|
|
4020
|
+
* @private
|
|
4021
|
+
*/
|
|
4022
|
+
_excessArguments(receivedArgs) {
|
|
4023
|
+
if (this._allowExcessArguments) return;
|
|
4024
|
+
const expected = this.registeredArguments.length;
|
|
4025
|
+
const s = expected === 1 ? "" : "s";
|
|
4026
|
+
const received = receivedArgs.length;
|
|
4027
|
+
const forSubcommand = this.parent ? ` for '${this.name()}'` : "";
|
|
4028
|
+
const details = receivedArgs.join(", ");
|
|
4029
|
+
const message2 = `error: too many arguments${forSubcommand}. Expected ${expected} argument${s} but got ${received}: ${details}.`;
|
|
4030
|
+
this.error(message2, { code: "commander.excessArguments" });
|
|
3820
4031
|
}
|
|
3821
|
-
|
|
3822
|
-
|
|
3823
|
-
|
|
3824
|
-
|
|
3825
|
-
|
|
3826
|
-
|
|
3827
|
-
|
|
3828
|
-
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
|
|
4032
|
+
/**
|
|
4033
|
+
* Unknown command.
|
|
4034
|
+
*
|
|
4035
|
+
* @private
|
|
4036
|
+
*/
|
|
4037
|
+
unknownCommand() {
|
|
4038
|
+
const unknownName = this.args[0];
|
|
4039
|
+
let suggestion = "";
|
|
4040
|
+
if (this._showSuggestionAfterError) {
|
|
4041
|
+
const candidateNames = [];
|
|
4042
|
+
this.createHelp().visibleCommands(this).forEach((command) => {
|
|
4043
|
+
candidateNames.push(command.name());
|
|
4044
|
+
if (command.alias()) candidateNames.push(command.alias());
|
|
4045
|
+
});
|
|
4046
|
+
suggestion = suggestSimilar(unknownName, candidateNames);
|
|
3832
4047
|
}
|
|
3833
|
-
|
|
3834
|
-
|
|
4048
|
+
const message2 = `error: unknown command '${unknownName}'${suggestion}`;
|
|
4049
|
+
this.error(message2, { code: "commander.unknownCommand" });
|
|
3835
4050
|
}
|
|
3836
|
-
|
|
3837
|
-
|
|
3838
|
-
|
|
3839
|
-
|
|
3840
|
-
|
|
3841
|
-
|
|
3842
|
-
|
|
3843
|
-
}
|
|
3844
|
-
|
|
3845
|
-
|
|
3846
|
-
|
|
3847
|
-
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
const
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
|
|
3857
|
-
|
|
3858
|
-
|
|
3859
|
-
|
|
3860
|
-
};
|
|
3861
|
-
const timeoutSignal = AbortSignal.timeout(init.timeoutMs ?? defaultTimeoutMs);
|
|
3862
|
-
const res = await fetchImpl(url, {
|
|
3863
|
-
method,
|
|
3864
|
-
headers,
|
|
3865
|
-
body: init.body !== void 0 ? JSON.stringify(init.body) : void 0,
|
|
3866
|
-
signal: externalSignal ? AbortSignal.any([externalSignal, timeoutSignal]) : timeoutSignal
|
|
4051
|
+
/**
|
|
4052
|
+
* Get or set the program version.
|
|
4053
|
+
*
|
|
4054
|
+
* This method auto-registers the "-V, --version" option which will print the version number.
|
|
4055
|
+
*
|
|
4056
|
+
* You can optionally supply the flags and description to override the defaults.
|
|
4057
|
+
*
|
|
4058
|
+
* @param {string} [str]
|
|
4059
|
+
* @param {string} [flags]
|
|
4060
|
+
* @param {string} [description]
|
|
4061
|
+
* @return {(this | string | undefined)} `this` command for chaining, or version string if no arguments
|
|
4062
|
+
*/
|
|
4063
|
+
version(str, flags, description) {
|
|
4064
|
+
if (str === void 0) return this._version;
|
|
4065
|
+
this._version = str;
|
|
4066
|
+
flags = flags || "-V, --version";
|
|
4067
|
+
description = description || "output the version number";
|
|
4068
|
+
const versionOption = this.createOption(flags, description);
|
|
4069
|
+
this._versionOptionName = versionOption.attributeName();
|
|
4070
|
+
this._registerOption(versionOption);
|
|
4071
|
+
this.on("option:" + versionOption.name(), () => {
|
|
4072
|
+
this._outputConfiguration.writeOut(`${str}
|
|
4073
|
+
`);
|
|
4074
|
+
this._exit(0, "commander.version", str);
|
|
3867
4075
|
});
|
|
3868
|
-
|
|
3869
|
-
return res;
|
|
4076
|
+
return this;
|
|
3870
4077
|
}
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
|
|
4078
|
+
/**
|
|
4079
|
+
* Set the description.
|
|
4080
|
+
*
|
|
4081
|
+
* @param {string} [str]
|
|
4082
|
+
* @param {object} [argsDescription]
|
|
4083
|
+
* @return {(string|Command)}
|
|
4084
|
+
*/
|
|
4085
|
+
description(str, argsDescription) {
|
|
4086
|
+
if (str === void 0 && argsDescription === void 0)
|
|
4087
|
+
return this._description;
|
|
4088
|
+
this._description = str;
|
|
4089
|
+
if (argsDescription) {
|
|
4090
|
+
this._argsDescription = argsDescription;
|
|
4091
|
+
}
|
|
4092
|
+
return this;
|
|
3876
4093
|
}
|
|
3877
|
-
|
|
3878
|
-
|
|
3879
|
-
|
|
3880
|
-
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
|
|
3884
|
-
|
|
3885
|
-
|
|
3886
|
-
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
|
|
3890
|
-
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
...init,
|
|
3902
|
-
body: { query, ...variables ? { variables } : {} }
|
|
3903
|
-
});
|
|
3904
|
-
const parsed = await parseJson2(res);
|
|
3905
|
-
if (parsed?.errors?.length) {
|
|
3906
|
-
const message2 = parsed.errors.map((e) => e.message ?? e.type ?? "unknown GraphQL error").join("; ");
|
|
3907
|
-
const rateLimited = parsed.errors.some((e) => e.type === "RATE_LIMITED" || /rate limit/i.test(e.message ?? ""));
|
|
3908
|
-
if (rateLimited) {
|
|
3909
|
-
const resetHeader = res.headers.get("x-ratelimit-reset");
|
|
3910
|
-
const reset = resetHeader && /^\d+$/.test(resetHeader) ? Number(resetHeader) : void 0;
|
|
3911
|
-
throw new GitHubApiError(`GraphQL: ${message2} \u2014 GraphQL ${rateLimitResetNote(reset)}; REST may still have headroom`, {
|
|
3912
|
-
status: 200,
|
|
3913
|
-
graphqlErrors: parsed.errors,
|
|
3914
|
-
rateLimited: true,
|
|
3915
|
-
rateLimitReset: reset
|
|
3916
|
-
});
|
|
3917
|
-
}
|
|
3918
|
-
throw new GitHubApiError(`GraphQL: ${message2}`, { status: 200, graphqlErrors: parsed.errors });
|
|
3919
|
-
}
|
|
3920
|
-
if (!parsed || parsed.data === void 0 || parsed.data === null) {
|
|
3921
|
-
throw new GitHubApiError("GraphQL response did not include data", { status: 200 });
|
|
3922
|
-
}
|
|
3923
|
-
return parsed.data;
|
|
4094
|
+
/**
|
|
4095
|
+
* Set the summary. Used when listed as subcommand of parent.
|
|
4096
|
+
*
|
|
4097
|
+
* @param {string} [str]
|
|
4098
|
+
* @return {(string|Command)}
|
|
4099
|
+
*/
|
|
4100
|
+
summary(str) {
|
|
4101
|
+
if (str === void 0) return this._summary;
|
|
4102
|
+
this._summary = str;
|
|
4103
|
+
return this;
|
|
4104
|
+
}
|
|
4105
|
+
/**
|
|
4106
|
+
* Set an alias for the command.
|
|
4107
|
+
*
|
|
4108
|
+
* You may call more than once to add multiple aliases. Only the first alias is shown in the auto-generated help.
|
|
4109
|
+
*
|
|
4110
|
+
* @param {string} [alias]
|
|
4111
|
+
* @return {(string|Command)}
|
|
4112
|
+
*/
|
|
4113
|
+
alias(alias) {
|
|
4114
|
+
if (alias === void 0) return this._aliases[0];
|
|
4115
|
+
let command = this;
|
|
4116
|
+
if (this.commands.length !== 0 && this.commands[this.commands.length - 1]._executableHandler) {
|
|
4117
|
+
command = this.commands[this.commands.length - 1];
|
|
3924
4118
|
}
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
3931
|
-
}
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
3940
|
-
|
|
3941
|
-
|
|
3942
|
-
|
|
3943
|
-
|
|
3944
|
-
|
|
3945
|
-
|
|
3946
|
-
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
|
|
3950
|
-
|
|
3951
|
-
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
|
|
3955
|
-
|
|
3956
|
-
|
|
3957
|
-
|
|
3958
|
-
if (
|
|
3959
|
-
|
|
4119
|
+
if (alias === command._name)
|
|
4120
|
+
throw new Error("Command alias can't be the same as its name");
|
|
4121
|
+
const matchingCommand = this.parent?._findCommand(alias);
|
|
4122
|
+
if (matchingCommand) {
|
|
4123
|
+
const existingCmd = [matchingCommand.name()].concat(matchingCommand.aliases()).join("|");
|
|
4124
|
+
throw new Error(
|
|
4125
|
+
`cannot add alias '${alias}' to command '${this.name()}' as already have command '${existingCmd}'`
|
|
4126
|
+
);
|
|
4127
|
+
}
|
|
4128
|
+
command._aliases.push(alias);
|
|
4129
|
+
return this;
|
|
4130
|
+
}
|
|
4131
|
+
/**
|
|
4132
|
+
* Set aliases for the command.
|
|
4133
|
+
*
|
|
4134
|
+
* Only the first alias is shown in the auto-generated help.
|
|
4135
|
+
*
|
|
4136
|
+
* @param {string[]} [aliases]
|
|
4137
|
+
* @return {(string[]|Command)}
|
|
4138
|
+
*/
|
|
4139
|
+
aliases(aliases) {
|
|
4140
|
+
if (aliases === void 0) return this._aliases;
|
|
4141
|
+
aliases.forEach((alias) => this.alias(alias));
|
|
4142
|
+
return this;
|
|
4143
|
+
}
|
|
4144
|
+
/**
|
|
4145
|
+
* Set / get the command usage `str`.
|
|
4146
|
+
*
|
|
4147
|
+
* @param {string} [str]
|
|
4148
|
+
* @return {(string|Command)}
|
|
4149
|
+
*/
|
|
4150
|
+
usage(str) {
|
|
4151
|
+
if (str === void 0) {
|
|
4152
|
+
if (this._usage) return this._usage;
|
|
4153
|
+
const args = this.registeredArguments.map((arg) => {
|
|
4154
|
+
return humanReadableArgName(arg);
|
|
4155
|
+
});
|
|
4156
|
+
return [].concat(
|
|
4157
|
+
this.options.length || this._helpOption !== null ? "[options]" : [],
|
|
4158
|
+
this.commands.length ? "[command]" : [],
|
|
4159
|
+
this.registeredArguments.length ? args : []
|
|
4160
|
+
).join(" ");
|
|
3960
4161
|
}
|
|
4162
|
+
this._usage = str;
|
|
4163
|
+
return this;
|
|
3961
4164
|
}
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
|
|
3970
|
-
|
|
3971
|
-
|
|
3972
|
-
function tokenFingerprint(token) {
|
|
3973
|
-
return (0, import_node_crypto.createHash)("sha256").update(token).digest("hex");
|
|
3974
|
-
}
|
|
3975
|
-
function defaultHubSessionCachePath(env = process.env) {
|
|
3976
|
-
if (env.MMI_HUB_SESSION_CACHE) return env.MMI_HUB_SESSION_CACHE;
|
|
3977
|
-
if (process.platform === "win32") {
|
|
3978
|
-
const base2 = env.LOCALAPPDATA || (0, import_node_path3.join)((0, import_node_os.homedir)(), "AppData", "Local");
|
|
3979
|
-
return (0, import_node_path3.join)(base2, "MMI Future", "mmi-cli", "hub-session.json");
|
|
4165
|
+
/**
|
|
4166
|
+
* Get or set the name of the command.
|
|
4167
|
+
*
|
|
4168
|
+
* @param {string} [str]
|
|
4169
|
+
* @return {(string|Command)}
|
|
4170
|
+
*/
|
|
4171
|
+
name(str) {
|
|
4172
|
+
if (str === void 0) return this._name;
|
|
4173
|
+
this._name = str;
|
|
4174
|
+
return this;
|
|
3980
4175
|
}
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
return void 0;
|
|
4176
|
+
/**
|
|
4177
|
+
* Set/get the help group heading for this subcommand in parent command's help.
|
|
4178
|
+
*
|
|
4179
|
+
* @param {string} [heading]
|
|
4180
|
+
* @return {Command | string}
|
|
4181
|
+
*/
|
|
4182
|
+
helpGroup(heading) {
|
|
4183
|
+
if (heading === void 0) return this._helpGroupHeading ?? "";
|
|
4184
|
+
this._helpGroupHeading = heading;
|
|
4185
|
+
return this;
|
|
3992
4186
|
}
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
|
|
4002
|
-
|
|
4187
|
+
/**
|
|
4188
|
+
* Set/get the default help group heading for subcommands added to this command.
|
|
4189
|
+
* (This does not override a group set directly on the subcommand using .helpGroup().)
|
|
4190
|
+
*
|
|
4191
|
+
* @example
|
|
4192
|
+
* program.commandsGroup('Development Commands:);
|
|
4193
|
+
* program.command('watch')...
|
|
4194
|
+
* program.command('lint')...
|
|
4195
|
+
* ...
|
|
4196
|
+
*
|
|
4197
|
+
* @param {string} [heading]
|
|
4198
|
+
* @returns {Command | string}
|
|
4199
|
+
*/
|
|
4200
|
+
commandsGroup(heading) {
|
|
4201
|
+
if (heading === void 0) return this._defaultCommandGroup ?? "";
|
|
4202
|
+
this._defaultCommandGroup = heading;
|
|
4203
|
+
return this;
|
|
4003
4204
|
}
|
|
4004
|
-
|
|
4005
|
-
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
|
|
4205
|
+
/**
|
|
4206
|
+
* Set/get the default help group heading for options added to this command.
|
|
4207
|
+
* (This does not override a group set directly on the option using .helpGroup().)
|
|
4208
|
+
*
|
|
4209
|
+
* @example
|
|
4210
|
+
* program
|
|
4211
|
+
* .optionsGroup('Development Options:')
|
|
4212
|
+
* .option('-d, --debug', 'output extra debugging')
|
|
4213
|
+
* .option('-p, --profile', 'output profiling information')
|
|
4214
|
+
*
|
|
4215
|
+
* @param {string} [heading]
|
|
4216
|
+
* @returns {Command | string}
|
|
4217
|
+
*/
|
|
4218
|
+
optionsGroup(heading) {
|
|
4219
|
+
if (heading === void 0) return this._defaultOptionGroup ?? "";
|
|
4220
|
+
this._defaultOptionGroup = heading;
|
|
4221
|
+
return this;
|
|
4012
4222
|
}
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
|
|
4016
|
-
|
|
4223
|
+
/**
|
|
4224
|
+
* @param {Option} option
|
|
4225
|
+
* @private
|
|
4226
|
+
*/
|
|
4227
|
+
_initOptionGroup(option) {
|
|
4228
|
+
if (this._defaultOptionGroup && !option.helpGroupHeading)
|
|
4229
|
+
option.helpGroup(this._defaultOptionGroup);
|
|
4017
4230
|
}
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
-
|
|
4021
|
-
|
|
4022
|
-
|
|
4023
|
-
|
|
4024
|
-
|
|
4231
|
+
/**
|
|
4232
|
+
* @param {Command} cmd
|
|
4233
|
+
* @private
|
|
4234
|
+
*/
|
|
4235
|
+
_initCommandGroup(cmd) {
|
|
4236
|
+
if (this._defaultCommandGroup && !cmd.helpGroup())
|
|
4237
|
+
cmd.helpGroup(this._defaultCommandGroup);
|
|
4025
4238
|
}
|
|
4026
|
-
|
|
4027
|
-
|
|
4028
|
-
|
|
4029
|
-
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
|
|
4036
|
-
|
|
4037
|
-
|
|
4038
|
-
|
|
4039
|
-
);
|
|
4040
|
-
|
|
4041
|
-
const body = await res.json();
|
|
4042
|
-
if (!body.token || !body.expiresAt) return void 0;
|
|
4043
|
-
const session = {
|
|
4044
|
-
token: body.token,
|
|
4045
|
-
expiresAt: body.expiresAt,
|
|
4046
|
-
login: typeof body.login === "string" ? body.login : void 0,
|
|
4047
|
-
// #3513: from the SIGNED token, not the response body — one rule at every hop, so the cache
|
|
4048
|
-
// read and the network read cannot disagree about what counts as an assertion.
|
|
4049
|
-
role: roleFromToken(body.token),
|
|
4050
|
-
apiUrl,
|
|
4051
|
-
githubTokenFingerprint
|
|
4052
|
-
};
|
|
4053
|
-
try {
|
|
4054
|
-
writeCache(cachePath, session);
|
|
4055
|
-
} catch {
|
|
4056
|
-
}
|
|
4057
|
-
return session;
|
|
4058
|
-
} catch {
|
|
4059
|
-
return void 0;
|
|
4239
|
+
/**
|
|
4240
|
+
* Set the name of the command from script filename, such as process.argv[1],
|
|
4241
|
+
* or import.meta.filename.
|
|
4242
|
+
*
|
|
4243
|
+
* (Used internally and public although not documented in README.)
|
|
4244
|
+
*
|
|
4245
|
+
* @example
|
|
4246
|
+
* program.nameFromFilename(import.meta.filename);
|
|
4247
|
+
*
|
|
4248
|
+
* @param {string} filename
|
|
4249
|
+
* @return {Command}
|
|
4250
|
+
*/
|
|
4251
|
+
nameFromFilename(filename) {
|
|
4252
|
+
this._name = import_node_path.default.basename(filename, import_node_path.default.extname(filename));
|
|
4253
|
+
return this;
|
|
4060
4254
|
}
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
|
|
4064
|
-
|
|
4065
|
-
|
|
4066
|
-
//
|
|
4067
|
-
|
|
4068
|
-
|
|
4069
|
-
|
|
4070
|
-
}
|
|
4071
|
-
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
devops: "Is it legal?",
|
|
4077
|
-
vault: "Is it guarded?",
|
|
4078
|
-
learning: "Did it learn?",
|
|
4079
|
-
core: "Is it one door?"
|
|
4080
|
-
};
|
|
4081
|
-
var HOUSE_MAP = {
|
|
4082
|
-
// --- oracle — live truth ------------------------------------------------------------------------
|
|
4083
|
-
board: "oracle",
|
|
4084
|
-
// board management (read + the guarded mutations that keep it live)
|
|
4085
|
-
issue: "oracle",
|
|
4086
|
-
// issues are live org truth
|
|
4087
|
-
wave: "oracle",
|
|
4088
|
-
// read-side multi-worktree board visibility (`wave status`)
|
|
4089
|
-
next: "oracle",
|
|
4090
|
-
// read-side board: the next actionable item
|
|
4091
|
-
docs: "oracle",
|
|
4092
|
-
// generated docs surfaces — the live org knowledge routing index
|
|
4093
|
-
org: "oracle",
|
|
4094
|
-
// org projects/registry/access reads (subgroup overrides below)
|
|
4095
|
-
"org project": "oracle",
|
|
4096
|
-
// registry projections (declared + projected live truth)
|
|
4097
|
-
"org access": "oracle",
|
|
4098
|
-
// org access role/audit reads
|
|
4099
|
-
"org config": "oracle",
|
|
4100
|
-
// live org configuration read
|
|
4101
|
-
// --- harbour — declared lanes -------------------------------------------------------------------
|
|
4102
|
-
"org schedules": "harbour",
|
|
4103
|
-
// register/run/park schedule rows under the one lane contract
|
|
4104
|
-
// --- devops — shipping --------------------------------------------------------------------------
|
|
4105
|
-
pr: "devops",
|
|
4106
|
-
ci: "devops",
|
|
4107
|
-
// the CI/gate audit
|
|
4108
|
-
rcand: "devops",
|
|
4109
|
-
release: "devops",
|
|
4110
|
-
hotfix: "devops",
|
|
4111
|
-
train: "devops",
|
|
4112
|
-
"wave land": "devops",
|
|
4113
|
-
// the write-side serial merge train is shipping, not board observation
|
|
4114
|
-
bootstrap: "devops",
|
|
4115
|
-
// repo provisioning + propagate
|
|
4116
|
-
runtime: "devops",
|
|
4117
|
-
// tenant/deploy/box/edge — shipping and central deploy
|
|
4118
|
-
"org rules": "devops",
|
|
4119
|
-
// org-managed repository rule delivery (.gitignore)
|
|
4120
|
-
// --- vault — secrets ----------------------------------------------------------------------------
|
|
4121
|
-
secrets: "vault",
|
|
4122
|
-
"org oauth": "vault",
|
|
4123
|
-
// OAuth credential planning/set/verify
|
|
4124
|
-
// --- learning — self-improvement ----------------------------------------------------------------
|
|
4125
|
-
report: "learning",
|
|
4126
|
-
// friction reports
|
|
4127
|
-
"skill-lesson": "learning",
|
|
4128
|
-
"closure-rate": "learning",
|
|
4129
|
-
// closure rate per loop kind, computed at read (#4440)
|
|
4130
|
-
pickup: "learning",
|
|
4131
|
-
// cloud-agent adoption gate (#5708)
|
|
4132
|
-
// --- core — the front door itself ---------------------------------------------------------------
|
|
4133
|
-
commands: "core",
|
|
4134
|
-
whoami: "core",
|
|
4135
|
-
spawn: "core",
|
|
4136
|
-
// this repo's process-spawn contract
|
|
4137
|
-
tests: "core",
|
|
4138
|
-
// this repo's test-policy contract
|
|
4139
|
-
dist: "core",
|
|
4140
|
-
// this repo's committed dist/BOM drift receipt (#5576)
|
|
4141
|
-
doctor: "core",
|
|
4142
|
-
stage: "core",
|
|
4143
|
-
plugin: "core",
|
|
4144
|
-
// plugin lifecycle + guards (CLI house owns plugins)
|
|
4145
|
-
explain: "core",
|
|
4146
|
-
// command-surface help
|
|
4147
|
-
status: "core",
|
|
4148
|
-
// repo-orientation snapshot (front door — torn toward oracle, kept core)
|
|
4149
|
-
onboard: "core"
|
|
4150
|
-
// repo-readiness orientation (front door — torn toward oracle, kept core)
|
|
4151
|
-
};
|
|
4152
|
-
var HOUSE_ALIASES = {
|
|
4153
|
-
issue: ["devops"],
|
|
4154
|
-
// filing/managing issues is oracle, but reads as shipping work
|
|
4155
|
-
"issue create": ["devops"]
|
|
4156
|
-
};
|
|
4157
|
-
function isDeclaredHouseAlias(houseToken, lookupPath) {
|
|
4158
|
-
const segments = lookupPath.split(" ");
|
|
4159
|
-
for (let end = segments.length; end > 0; end -= 1) {
|
|
4160
|
-
const key = segments.slice(0, end).join(" ");
|
|
4161
|
-
const aliases = HOUSE_ALIASES[key];
|
|
4162
|
-
if (aliases) return aliases.includes(houseToken);
|
|
4255
|
+
/**
|
|
4256
|
+
* Get or set the directory for searching for executable subcommands of this command.
|
|
4257
|
+
*
|
|
4258
|
+
* @example
|
|
4259
|
+
* program.executableDir(import.meta.dirname);
|
|
4260
|
+
* // or
|
|
4261
|
+
* program.executableDir('subcommands');
|
|
4262
|
+
*
|
|
4263
|
+
* @param {string} [path]
|
|
4264
|
+
* @return {(string|null|Command)}
|
|
4265
|
+
*/
|
|
4266
|
+
executableDir(path2) {
|
|
4267
|
+
if (path2 === void 0) return this._executableDir;
|
|
4268
|
+
this._executableDir = path2;
|
|
4269
|
+
return this;
|
|
4163
4270
|
}
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
const
|
|
4172
|
-
|
|
4271
|
+
/**
|
|
4272
|
+
* Return program help documentation.
|
|
4273
|
+
*
|
|
4274
|
+
* @param {{ error: boolean }} [contextOptions] - pass {error:true} to wrap for stderr instead of stdout
|
|
4275
|
+
* @return {string}
|
|
4276
|
+
*/
|
|
4277
|
+
helpInformation(contextOptions) {
|
|
4278
|
+
const helper = this.createHelp();
|
|
4279
|
+
const context = this._getOutputContext(contextOptions);
|
|
4280
|
+
helper.prepareContext({
|
|
4281
|
+
error: context.error,
|
|
4282
|
+
helpWidth: context.helpWidth,
|
|
4283
|
+
outputHasColors: context.hasColors
|
|
4284
|
+
});
|
|
4285
|
+
const text = helper.formatHelp(this, helper);
|
|
4286
|
+
if (context.hasColors) return text;
|
|
4287
|
+
return this._outputConfiguration.stripColor(text);
|
|
4173
4288
|
}
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
|
|
4177
|
-
|
|
4178
|
-
|
|
4179
|
-
|
|
4180
|
-
}
|
|
4181
|
-
|
|
4182
|
-
|
|
4183
|
-
|
|
4184
|
-
|
|
4185
|
-
|
|
4186
|
-
|
|
4187
|
-
|
|
4188
|
-
|
|
4189
|
-
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
|
|
4289
|
+
/**
|
|
4290
|
+
* @typedef HelpContext
|
|
4291
|
+
* @type {object}
|
|
4292
|
+
* @property {boolean} error
|
|
4293
|
+
* @property {number} helpWidth
|
|
4294
|
+
* @property {boolean} hasColors
|
|
4295
|
+
* @property {function} write - includes stripColor if needed
|
|
4296
|
+
*
|
|
4297
|
+
* @returns {HelpContext}
|
|
4298
|
+
* @private
|
|
4299
|
+
*/
|
|
4300
|
+
_getOutputContext(contextOptions) {
|
|
4301
|
+
contextOptions = contextOptions || {};
|
|
4302
|
+
const error = !!contextOptions.error;
|
|
4303
|
+
let baseWrite;
|
|
4304
|
+
let hasColors;
|
|
4305
|
+
let helpWidth;
|
|
4306
|
+
if (error) {
|
|
4307
|
+
baseWrite = (str) => this._outputConfiguration.writeErr(str);
|
|
4308
|
+
hasColors = this._outputConfiguration.getErrHasColors();
|
|
4309
|
+
helpWidth = this._outputConfiguration.getErrHelpWidth();
|
|
4310
|
+
} else {
|
|
4311
|
+
baseWrite = (str) => this._outputConfiguration.writeOut(str);
|
|
4312
|
+
hasColors = this._outputConfiguration.getOutHasColors();
|
|
4313
|
+
helpWidth = this._outputConfiguration.getOutHelpWidth();
|
|
4314
|
+
}
|
|
4315
|
+
const write = (str) => {
|
|
4316
|
+
if (!hasColors) str = this._outputConfiguration.stripColor(str);
|
|
4317
|
+
return baseWrite(str);
|
|
4318
|
+
};
|
|
4319
|
+
return { error, write, hasColors, helpWidth };
|
|
4200
4320
|
}
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
|
|
4208
|
-
|
|
4209
|
-
|
|
4210
|
-
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4321
|
+
/**
|
|
4322
|
+
* Output help information for this command.
|
|
4323
|
+
*
|
|
4324
|
+
* Outputs built-in help, and custom text added using `.addHelpText()`.
|
|
4325
|
+
*
|
|
4326
|
+
* @param {{ error: boolean } | Function} [contextOptions] - pass {error:true} to write to stderr instead of stdout
|
|
4327
|
+
*/
|
|
4328
|
+
outputHelp(contextOptions) {
|
|
4329
|
+
let deprecatedCallback;
|
|
4330
|
+
if (typeof contextOptions === "function") {
|
|
4331
|
+
deprecatedCallback = contextOptions;
|
|
4332
|
+
contextOptions = void 0;
|
|
4333
|
+
}
|
|
4334
|
+
const outputContext = this._getOutputContext(contextOptions);
|
|
4335
|
+
const eventContext = {
|
|
4336
|
+
error: outputContext.error,
|
|
4337
|
+
write: outputContext.write,
|
|
4338
|
+
command: this
|
|
4339
|
+
};
|
|
4340
|
+
this._getCommandAndAncestors().reverse().forEach((command) => command.emit("beforeAllHelp", eventContext));
|
|
4341
|
+
this.emit("beforeHelp", eventContext);
|
|
4342
|
+
let helpInformation = this.helpInformation({ error: outputContext.error });
|
|
4343
|
+
if (deprecatedCallback) {
|
|
4344
|
+
helpInformation = deprecatedCallback(helpInformation);
|
|
4345
|
+
if (typeof helpInformation !== "string" && !Buffer.isBuffer(helpInformation)) {
|
|
4346
|
+
throw new Error("outputHelp callback must return a string or a Buffer");
|
|
4219
4347
|
}
|
|
4220
|
-
chunks.push(buf);
|
|
4221
|
-
total += buf.length;
|
|
4222
4348
|
}
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
|
|
4226
|
-
const timeout = new Promise((resolve7) => {
|
|
4227
|
-
timer = setTimeout(resolve7, timeoutMs);
|
|
4228
|
-
});
|
|
4229
|
-
try {
|
|
4230
|
-
await Promise.race([drain, timeout]);
|
|
4231
|
-
} finally {
|
|
4232
|
-
if (timer) clearTimeout(timer);
|
|
4233
|
-
try {
|
|
4234
|
-
process.stdin.unref();
|
|
4235
|
-
} catch {
|
|
4349
|
+
outputContext.write(helpInformation);
|
|
4350
|
+
if (this._getHelpOption()?.long) {
|
|
4351
|
+
this.emit(this._getHelpOption().long);
|
|
4236
4352
|
}
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
// src/cli-shared.ts
|
|
4242
|
-
var rawExecFileP = (0, import_node_util3.promisify)(import_node_child_process2.execFile);
|
|
4243
|
-
var DEFAULT_EXEC_TIMEOUT_MS = 1e4;
|
|
4244
|
-
var execFileP = (file, args, options = {}) => (
|
|
4245
|
-
// encoding 'utf8' guarantees string stdout/stderr at runtime; the cast pins the type because
|
|
4246
|
-
// promisify(execFile)'s overloads widen to string|Buffer when options is spread in.
|
|
4247
|
-
rawExecFileP(file, args, { encoding: "utf8", windowsHide: true, timeout: DEFAULT_EXEC_TIMEOUT_MS, killSignal: "SIGTERM", ...options })
|
|
4248
|
-
);
|
|
4249
|
-
var GIT_TIMEOUT_MS = DEFAULT_EXEC_TIMEOUT_MS;
|
|
4250
|
-
var ExecDeadlineError = class extends Error {
|
|
4251
|
-
constructor(step, timeoutMs, elapsedMs, killed) {
|
|
4252
|
-
super(
|
|
4253
|
-
`\`${step}\` did not finish within ${Math.round(timeoutMs / 1e3)}s (gave up after ${Math.round(elapsedMs / 1e3)}s). It stopped responding and did not exit when asked to, so the timeout alone could not end it; ${killed ? "its process tree was force-terminated" : "its process tree could NOT be terminated and may still be running"}.`
|
|
4353
|
+
this.emit("afterHelp", eventContext);
|
|
4354
|
+
this._getCommandAndAncestors().forEach(
|
|
4355
|
+
(command) => command.emit("afterAllHelp", eventContext)
|
|
4254
4356
|
);
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
}
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
|
|
4271
|
-
|
|
4357
|
+
}
|
|
4358
|
+
/**
|
|
4359
|
+
* You can pass in flags and a description to customise the built-in help option.
|
|
4360
|
+
* Pass in false to disable the built-in help option.
|
|
4361
|
+
*
|
|
4362
|
+
* @example
|
|
4363
|
+
* program.helpOption('-?, --help' 'show help'); // customise
|
|
4364
|
+
* program.helpOption(false); // disable
|
|
4365
|
+
*
|
|
4366
|
+
* @param {(string | boolean)} flags
|
|
4367
|
+
* @param {string} [description]
|
|
4368
|
+
* @return {Command} `this` command for chaining
|
|
4369
|
+
*/
|
|
4370
|
+
helpOption(flags, description) {
|
|
4371
|
+
if (typeof flags === "boolean") {
|
|
4372
|
+
if (flags) {
|
|
4373
|
+
if (this._helpOption === null) this._helpOption = void 0;
|
|
4374
|
+
if (this._defaultOptionGroup) {
|
|
4375
|
+
this._initOptionGroup(this._getHelpOption());
|
|
4376
|
+
}
|
|
4377
|
+
} else {
|
|
4378
|
+
this._helpOption = null;
|
|
4379
|
+
}
|
|
4380
|
+
return this;
|
|
4272
4381
|
}
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4382
|
+
this._helpOption = this.createOption(
|
|
4383
|
+
flags ?? "-h, --help",
|
|
4384
|
+
description ?? "display help for command"
|
|
4385
|
+
);
|
|
4386
|
+
if (flags || description) this._initOptionGroup(this._helpOption);
|
|
4387
|
+
return this;
|
|
4276
4388
|
}
|
|
4277
|
-
|
|
4278
|
-
|
|
4279
|
-
|
|
4280
|
-
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
|
|
4284
|
-
|
|
4285
|
-
|
|
4286
|
-
|
|
4287
|
-
}
|
|
4288
|
-
|
|
4289
|
-
const timer = setTimeout(() => {
|
|
4290
|
-
expired = true;
|
|
4291
|
-
const killed = child2.pid ? killProcessTree(child2.pid) : false;
|
|
4292
|
-
child2.stdout?.destroy();
|
|
4293
|
-
child2.stderr?.destroy();
|
|
4294
|
-
child2.unref();
|
|
4295
|
-
reject(new ExecDeadlineError(step, timeout, Date.now() - started, killed));
|
|
4296
|
-
}, timeout);
|
|
4297
|
-
timer.unref?.();
|
|
4298
|
-
});
|
|
4299
|
-
}
|
|
4300
|
-
var cachedGithubLogin;
|
|
4301
|
-
async function githubLogin() {
|
|
4302
|
-
cachedGithubLogin ??= execFileP("gh", ["api", "user", "--jq", ".login"]).then(({ stdout }) => stdout.trim() || void 0).catch(() => void 0);
|
|
4303
|
-
return cachedGithubLogin;
|
|
4304
|
-
}
|
|
4305
|
-
async function hubHeaders(extra = {}) {
|
|
4306
|
-
const cfg = await loadConfig();
|
|
4307
|
-
const t = await hubAuthToken({ baseUrl: cfg.sagaApiUrl ?? defaultHubUrl(), githubToken });
|
|
4308
|
-
const base = { ...clientVersionHeaders(), ...extra };
|
|
4309
|
-
return t ? { ...base, Authorization: `Bearer ${t}` } : base;
|
|
4310
|
-
}
|
|
4311
|
-
async function loadConfig() {
|
|
4312
|
-
return { sagaApiUrl: defaultHubUrl() };
|
|
4313
|
-
}
|
|
4314
|
-
async function originRemoteUrl() {
|
|
4315
|
-
return gitOut(["config", "--get", "remote.origin.url"]);
|
|
4316
|
-
}
|
|
4317
|
-
async function isOrgRepoRoot(readOrigin = originRemoteUrl) {
|
|
4318
|
-
return /[:/]mutmutco\//i.test(await readOrigin());
|
|
4319
|
-
}
|
|
4320
|
-
var gitOut = async (args) => {
|
|
4321
|
-
try {
|
|
4322
|
-
return (await execFileP("git", [...args])).stdout.trim();
|
|
4323
|
-
} catch {
|
|
4324
|
-
return "";
|
|
4389
|
+
/**
|
|
4390
|
+
* Lazy create help option.
|
|
4391
|
+
* Returns null if has been disabled with .helpOption(false).
|
|
4392
|
+
*
|
|
4393
|
+
* @returns {(Option | null)} the help option
|
|
4394
|
+
* @package
|
|
4395
|
+
*/
|
|
4396
|
+
_getHelpOption() {
|
|
4397
|
+
if (this._helpOption === void 0) {
|
|
4398
|
+
this.helpOption(void 0, void 0);
|
|
4399
|
+
}
|
|
4400
|
+
return this._helpOption;
|
|
4325
4401
|
}
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
}
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
return argvWantsJson() || process.argv.some((a) => a === "--validate-only" || a === "--dry-run");
|
|
4338
|
-
}
|
|
4339
|
-
function commandFromFailMessage(msg) {
|
|
4340
|
-
const head = msg.split(":", 1)[0].trim();
|
|
4341
|
-
if (!head || head.startsWith("-")) return "mmi-cli";
|
|
4342
|
-
if (!/^[a-z][a-z0-9-]*(?: [a-z][a-z0-9-]*){0,5}$/.test(head)) return "mmi-cli";
|
|
4343
|
-
return canonicalPathFor(head) ?? head;
|
|
4344
|
-
}
|
|
4345
|
-
function canonicalFailMessage(msg) {
|
|
4346
|
-
const colon = msg.indexOf(":");
|
|
4347
|
-
if (colon < 0) return msg;
|
|
4348
|
-
const command = commandFromFailMessage(msg);
|
|
4349
|
-
return command === "mmi-cli" ? msg : `${command}${msg.slice(colon)}`;
|
|
4350
|
-
}
|
|
4351
|
-
function fail(msg, payload) {
|
|
4352
|
-
const json = argvWantsMachineFailure();
|
|
4353
|
-
const canonicalMsg = canonicalFailMessage(msg);
|
|
4354
|
-
if (payload && json) {
|
|
4355
|
-
console.error(formatErrorEnvelope(canonicalMsg, payload));
|
|
4356
|
-
} else {
|
|
4357
|
-
if (!json) console.error(`run: mmi-cli explain ${commandFromFailMessage(msg)}`);
|
|
4358
|
-
console.error(`mmi-cli ${canonicalMsg}`);
|
|
4402
|
+
/**
|
|
4403
|
+
* Supply your own option to use for the built-in help option.
|
|
4404
|
+
* This is an alternative to using helpOption() to customise the flags and description etc.
|
|
4405
|
+
*
|
|
4406
|
+
* @param {Option} option
|
|
4407
|
+
* @return {Command} `this` command for chaining
|
|
4408
|
+
*/
|
|
4409
|
+
addHelpOption(option) {
|
|
4410
|
+
this._helpOption = option;
|
|
4411
|
+
this._initOptionGroup(option);
|
|
4412
|
+
return this;
|
|
4359
4413
|
}
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
|
|
4414
|
+
/**
|
|
4415
|
+
* Output help information and exit.
|
|
4416
|
+
*
|
|
4417
|
+
* Outputs built-in help, and custom text added using `.addHelpText()`.
|
|
4418
|
+
*
|
|
4419
|
+
* @param {{ error: boolean }} [contextOptions] - pass {error:true} to write to stderr instead of stdout
|
|
4420
|
+
*/
|
|
4421
|
+
help(contextOptions) {
|
|
4422
|
+
this.outputHelp(contextOptions);
|
|
4423
|
+
let exitCode = Number(import_node_process.default.exitCode ?? 0);
|
|
4424
|
+
if (exitCode === 0 && contextOptions && typeof contextOptions !== "function" && contextOptions.error) {
|
|
4425
|
+
exitCode = 1;
|
|
4426
|
+
}
|
|
4427
|
+
this._exit(exitCode, "commander.help", "(outputHelp)");
|
|
4366
4428
|
}
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
|
|
4429
|
+
/**
|
|
4430
|
+
* // Do a little typing to coordinate emit and listener for the help text events.
|
|
4431
|
+
* @typedef HelpTextEventContext
|
|
4432
|
+
* @type {object}
|
|
4433
|
+
* @property {boolean} error
|
|
4434
|
+
* @property {Command} command
|
|
4435
|
+
* @property {function} write
|
|
4436
|
+
*/
|
|
4437
|
+
/**
|
|
4438
|
+
* Add additional text to be displayed with the built-in help.
|
|
4439
|
+
*
|
|
4440
|
+
* Position is 'before' or 'after' to affect just this command,
|
|
4441
|
+
* and 'beforeAll' or 'afterAll' to affect this command and all its subcommands.
|
|
4442
|
+
*
|
|
4443
|
+
* @param {string} position - before or after built-in help
|
|
4444
|
+
* @param {(string | Function)} text - string to add, or a function returning a string
|
|
4445
|
+
* @return {Command} `this` command for chaining
|
|
4446
|
+
*/
|
|
4447
|
+
addHelpText(position, text) {
|
|
4448
|
+
const allowedValues = ["beforeAll", "before", "after", "afterAll"];
|
|
4449
|
+
if (!allowedValues.includes(position)) {
|
|
4450
|
+
throw new Error(`Unexpected value for position to addHelpText.
|
|
4451
|
+
Expecting one of '${allowedValues.join("', '")}'`);
|
|
4452
|
+
}
|
|
4453
|
+
const helpEvent = `${position}Help`;
|
|
4454
|
+
this.on(helpEvent, (context) => {
|
|
4455
|
+
let helpStr;
|
|
4456
|
+
if (typeof text === "function") {
|
|
4457
|
+
helpStr = text({ error: context.error, command: context.command });
|
|
4458
|
+
} else {
|
|
4459
|
+
helpStr = text;
|
|
4460
|
+
}
|
|
4461
|
+
if (helpStr) {
|
|
4462
|
+
context.write(`${helpStr}
|
|
4463
|
+
`);
|
|
4464
|
+
}
|
|
4465
|
+
});
|
|
4466
|
+
return this;
|
|
4382
4467
|
}
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4468
|
+
/**
|
|
4469
|
+
* Output help information if help flags specified
|
|
4470
|
+
*
|
|
4471
|
+
* @param {Array} args - array of options to search for help flags
|
|
4472
|
+
* @private
|
|
4473
|
+
*/
|
|
4474
|
+
_outputHelpIfRequested(args) {
|
|
4475
|
+
const helpOption = this._getHelpOption();
|
|
4476
|
+
const helpRequested = helpOption && args.find((arg) => helpOption.is(arg));
|
|
4477
|
+
if (helpRequested) {
|
|
4478
|
+
this.outputHelp();
|
|
4479
|
+
this._exit(0, "commander.helpDisplayed", "(outputHelp)");
|
|
4480
|
+
}
|
|
4388
4481
|
}
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
marker.__mmiMutating = true;
|
|
4395
|
-
if (!cmd.options.some((o) => o.long === "--json")) cmd.option("--json", "machine-readable output");
|
|
4396
|
-
cmd.option("--dry-run", "resolve + validate, print the planned action as JSON, and exit without writing");
|
|
4397
|
-
cmd.option("--validate-only", "validate flags/enums/refs, print {ok,planned} or the C2 error envelope, and exit without writing");
|
|
4398
|
-
const registerAction = cmd.action.bind(cmd);
|
|
4399
|
-
cmd.action = ((handler) => registerAction(async (...actionArgs) => {
|
|
4400
|
-
const command = actionArgs[actionArgs.length - 1];
|
|
4401
|
-
const opts = command.opts();
|
|
4402
|
-
const positionals = actionArgs.slice(0, -2);
|
|
4403
|
-
const out = await planMutation(opts, positionals, commandPath(command), planFn);
|
|
4404
|
-
if (out) {
|
|
4405
|
-
console.log(JSON.stringify(out));
|
|
4406
|
-
return;
|
|
4482
|
+
};
|
|
4483
|
+
function incrementNodeInspectorPort(args) {
|
|
4484
|
+
return args.map((arg) => {
|
|
4485
|
+
if (!arg.startsWith("--inspect")) {
|
|
4486
|
+
return arg;
|
|
4407
4487
|
}
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
}
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
|
|
4422
|
-
|
|
4423
|
-
|
|
4488
|
+
let debugOption;
|
|
4489
|
+
let debugHost = "127.0.0.1";
|
|
4490
|
+
let debugPort = "9229";
|
|
4491
|
+
let match;
|
|
4492
|
+
if ((match = arg.match(/^(--inspect(-brk)?)$/)) !== null) {
|
|
4493
|
+
debugOption = match[1];
|
|
4494
|
+
} else if ((match = arg.match(/^(--inspect(-brk|-port)?)=([^:]+)$/)) !== null) {
|
|
4495
|
+
debugOption = match[1];
|
|
4496
|
+
if (/^\d+$/.test(match[3])) {
|
|
4497
|
+
debugPort = match[3];
|
|
4498
|
+
} else {
|
|
4499
|
+
debugHost = match[3];
|
|
4500
|
+
}
|
|
4501
|
+
} else if ((match = arg.match(/^(--inspect(-brk|-port)?)=([^:]+):(\d+)$/)) !== null) {
|
|
4502
|
+
debugOption = match[1];
|
|
4503
|
+
debugHost = match[3];
|
|
4504
|
+
debugPort = match[4];
|
|
4505
|
+
}
|
|
4506
|
+
if (debugOption && debugPort !== "0") {
|
|
4507
|
+
return `${debugOption}=${debugHost}:${parseInt(debugPort) + 1}`;
|
|
4508
|
+
}
|
|
4509
|
+
return arg;
|
|
4510
|
+
});
|
|
4424
4511
|
}
|
|
4425
|
-
function
|
|
4426
|
-
(0
|
|
4427
|
-
|
|
4512
|
+
function useColor() {
|
|
4513
|
+
if (import_node_process.default.env.NO_COLOR || import_node_process.default.env.FORCE_COLOR === "0" || import_node_process.default.env.FORCE_COLOR === "false")
|
|
4514
|
+
return false;
|
|
4515
|
+
if (import_node_process.default.env.FORCE_COLOR || import_node_process.default.env.CLICOLOR_FORCE !== void 0)
|
|
4516
|
+
return true;
|
|
4517
|
+
return void 0;
|
|
4428
4518
|
}
|
|
4429
4519
|
|
|
4520
|
+
// node_modules/commander/index.js
|
|
4521
|
+
var program = new Command();
|
|
4522
|
+
|
|
4523
|
+
// src/command-composition.ts
|
|
4524
|
+
var import_node_fs48 = require("node:fs");
|
|
4525
|
+
init_clean_exit();
|
|
4526
|
+
init_cli_shared();
|
|
4527
|
+
|
|
4430
4528
|
// src/doctor-fleet-drift.ts
|
|
4431
4529
|
var import_node_fs6 = require("node:fs");
|
|
4432
4530
|
var import_node_os2 = require("node:os");
|
|
@@ -4599,6 +4697,9 @@ function readFleetDrift(env, activeSurfaces) {
|
|
|
4599
4697
|
}
|
|
4600
4698
|
}
|
|
4601
4699
|
|
|
4700
|
+
// src/command-composition.ts
|
|
4701
|
+
init_error_codes();
|
|
4702
|
+
|
|
4602
4703
|
// src/git-clean-tree.ts
|
|
4603
4704
|
function isAgentScratchPath(path2) {
|
|
4604
4705
|
const normalized = path2.replace(/\\/g, "/").trim();
|
|
@@ -4804,6 +4905,7 @@ function excessArgumentMessage(extra, corrected) {
|
|
|
4804
4905
|
// src/released-version-cache.ts
|
|
4805
4906
|
var import_node_fs7 = require("node:fs");
|
|
4806
4907
|
var import_node_path5 = require("node:path");
|
|
4908
|
+
init_client_version();
|
|
4807
4909
|
var RELEASED_VERSION_CACHE_MS = 24 * 36e5;
|
|
4808
4910
|
function releasedVersionCachePath(runtimeRoot) {
|
|
4809
4911
|
return (0, import_node_path5.join)(runtimeRoot, "head-ts", ".released-version");
|
|
@@ -5309,8 +5411,12 @@ var import_node_path46 = require("node:path");
|
|
|
5309
5411
|
var import_node_fs13 = require("node:fs");
|
|
5310
5412
|
var import_node_os9 = require("node:os");
|
|
5311
5413
|
var import_node_path11 = require("node:path");
|
|
5414
|
+
init_cli_shared();
|
|
5415
|
+
init_github_client();
|
|
5312
5416
|
|
|
5313
5417
|
// src/board-snapshot.ts
|
|
5418
|
+
init_fetch_retry();
|
|
5419
|
+
init_client_version();
|
|
5314
5420
|
var BOARD_SNAPSHOT_TIMEOUT_MS = 25e3;
|
|
5315
5421
|
function isSnapshotShape(body) {
|
|
5316
5422
|
const b = body;
|
|
@@ -5358,6 +5464,7 @@ async function fetchHubBoardSnapshot(request, deps) {
|
|
|
5358
5464
|
}
|
|
5359
5465
|
|
|
5360
5466
|
// src/github-quota.ts
|
|
5467
|
+
init_github_client();
|
|
5361
5468
|
var RATE_LIMIT_WAIT_CAP_MS = 12e4;
|
|
5362
5469
|
var RateLimitedError = class extends Error {
|
|
5363
5470
|
receipt;
|
|
@@ -5899,6 +6006,9 @@ async function withAlreadyClosedCommitTargets(input, fetchIssueState) {
|
|
|
5899
6006
|
return alreadyClosed.length ? { ...input, alreadyClosed: [.../* @__PURE__ */ new Set([...input.alreadyClosed ?? [], ...alreadyClosed])] } : input;
|
|
5900
6007
|
}
|
|
5901
6008
|
|
|
6009
|
+
// src/repo-resolve.ts
|
|
6010
|
+
init_cli_shared();
|
|
6011
|
+
|
|
5902
6012
|
// src/registry-degrade.ts
|
|
5903
6013
|
function registryDegradeError(error) {
|
|
5904
6014
|
return new Error(
|
|
@@ -5913,6 +6023,10 @@ var ORG_CONFIG_PATH = "/org/config";
|
|
|
5913
6023
|
var PROJECTS_ENVELOPE_KEY = "projects";
|
|
5914
6024
|
var REGISTRY_FETCH_TIMEOUT_MS = 8e3;
|
|
5915
6025
|
|
|
6026
|
+
// src/registry-client.ts
|
|
6027
|
+
init_fetch_retry();
|
|
6028
|
+
init_client_version();
|
|
6029
|
+
|
|
5916
6030
|
// src/workflow-context.ts
|
|
5917
6031
|
function parseWorkflowJobs(yaml) {
|
|
5918
6032
|
const lines2 = yaml.split(/\r?\n/);
|
|
@@ -6969,6 +7083,11 @@ function boardConfigFromProject(meta, floor = {}) {
|
|
|
6969
7083
|
};
|
|
6970
7084
|
}
|
|
6971
7085
|
|
|
7086
|
+
// src/cli-doctor-shared.ts
|
|
7087
|
+
init_cli_shared();
|
|
7088
|
+
init_hub_auth();
|
|
7089
|
+
init_github_client();
|
|
7090
|
+
|
|
6972
7091
|
// src/project-model.ts
|
|
6973
7092
|
var PROJECT_TYPES = ["web-app", "hub-service", "content", "desktop-app", "desktop-game", "mobile-app", "non-deployable", "cli-tool", "worker"];
|
|
6974
7093
|
var DEPLOY_MODELS = ["hub-serverless", "serverless", "tenant-container", "solo-container", "static-cdn", "registry-publish", "content", "none"];
|
|
@@ -7204,6 +7323,8 @@ ${lines2.join("\n")}`;
|
|
|
7204
7323
|
}
|
|
7205
7324
|
|
|
7206
7325
|
// src/issue-surface.ts
|
|
7326
|
+
init_cli_shared();
|
|
7327
|
+
init_error_codes();
|
|
7207
7328
|
var SURFACE_PREFIX = "surface:";
|
|
7208
7329
|
var SURFACE_READ_TIMEOUT_MS = 1e4;
|
|
7209
7330
|
function labelsCarrySurface(labels) {
|
|
@@ -7342,6 +7463,7 @@ function shouldWithdrawSurfaceFlag(result) {
|
|
|
7342
7463
|
}
|
|
7343
7464
|
|
|
7344
7465
|
// src/secrets-transport.ts
|
|
7466
|
+
init_client_version();
|
|
7345
7467
|
var OWNER = "mutmutco";
|
|
7346
7468
|
var SSM_ROOT = "/mmi-future";
|
|
7347
7469
|
var PROJECT_TIER_SEGMENT = "dev";
|
|
@@ -7959,6 +8081,7 @@ async function secretsPreflight(deps, opts) {
|
|
|
7959
8081
|
// src/secrets-execution.ts
|
|
7960
8082
|
var import_node_child_process4 = require("node:child_process");
|
|
7961
8083
|
var import_node_os5 = require("node:os");
|
|
8084
|
+
init_clean_exit();
|
|
7962
8085
|
|
|
7963
8086
|
// src/gh-create.ts
|
|
7964
8087
|
var import_promises = require("node:fs/promises");
|
|
@@ -7994,6 +8117,8 @@ function isPriorityFieldConfigured(cfg) {
|
|
|
7994
8117
|
}
|
|
7995
8118
|
|
|
7996
8119
|
// src/gh-create.ts
|
|
8120
|
+
init_cli_shared();
|
|
8121
|
+
init_github_client();
|
|
7997
8122
|
var ISSUE_TYPES = ["bug", "feature", "task"];
|
|
7998
8123
|
var GH_MUTATION_TIMEOUT_MS = 12e4;
|
|
7999
8124
|
function timeoutKillNote(err, timeoutMs) {
|
|
@@ -9790,6 +9915,9 @@ function readSettingsAutoUpdate(raw, name) {
|
|
|
9790
9915
|
var CATALOG_CONTENT_REF = "main";
|
|
9791
9916
|
var CATALOG_REF_PIN_STEPS = `add \`"ref": "${CATALOG_CONTENT_REF}"\` to this marketplace's \`source\` in ~/.claude/plugins/known_marketplaces.json, then restart Claude`;
|
|
9792
9917
|
|
|
9918
|
+
// src/plugin-guard-io.ts
|
|
9919
|
+
init_cli_shared();
|
|
9920
|
+
|
|
9793
9921
|
// src/plugin-guard.ts
|
|
9794
9922
|
function buildPluginGuardDecision(i) {
|
|
9795
9923
|
if (!i.isOrgRepo) return { state: "not-org" };
|
|
@@ -10663,6 +10791,9 @@ function describeSessionIdentity(env = process.env) {
|
|
|
10663
10791
|
};
|
|
10664
10792
|
}
|
|
10665
10793
|
|
|
10794
|
+
// src/board-doctor-config.ts
|
|
10795
|
+
init_github_client();
|
|
10796
|
+
|
|
10666
10797
|
// ../infra/board-vocab.mjs
|
|
10667
10798
|
var BOARD_STATUSES = ["Todo", "In Progress", "In Review", "Done"];
|
|
10668
10799
|
|
|
@@ -10993,7 +11124,14 @@ mutation($projectId: ID!, $itemId: ID!) {
|
|
|
10993
11124
|
}
|
|
10994
11125
|
}`;
|
|
10995
11126
|
async function updateItemSingleSelect(client, projectId, itemId, fieldId, optionId) {
|
|
10996
|
-
|
|
11127
|
+
try {
|
|
11128
|
+
await client.graphql(UPDATE_ITEM_FIELD_MUTATION, { projectId, itemId, fieldId, optionId });
|
|
11129
|
+
} catch (error) {
|
|
11130
|
+
const errors = error.graphqlErrors;
|
|
11131
|
+
if (!errors?.length || !errors.every((entry) => entry.type === "INSUFFICIENT_SCOPES")) throw error;
|
|
11132
|
+
const { writeHubBoardField: writeHubBoardField2 } = await Promise.resolve().then(() => (init_board_write(), board_write_exports));
|
|
11133
|
+
await writeHubBoardField2({ projectId, itemId, fieldId, optionId });
|
|
11134
|
+
}
|
|
10997
11135
|
}
|
|
10998
11136
|
function parseIssueSelector(selector, defaultRepo, expectedRepo) {
|
|
10999
11137
|
const parsed = parseIssueRef(selector, expectedRepo);
|
|
@@ -12014,7 +12152,11 @@ function ghError(e) {
|
|
|
12014
12152
|
return (err.stderr || err.message || String(e)).trim();
|
|
12015
12153
|
}
|
|
12016
12154
|
|
|
12155
|
+
// src/board-claim-move.ts
|
|
12156
|
+
init_github_client();
|
|
12157
|
+
|
|
12017
12158
|
// src/sub-issue.ts
|
|
12159
|
+
init_error_codes();
|
|
12018
12160
|
function buildResolveIdArgs(ref) {
|
|
12019
12161
|
const args = ["issue", "view", String(ref.number), "--json", "id", "--jq", ".id"];
|
|
12020
12162
|
if (ref.repo) args.push("--repo", ref.repo);
|
|
@@ -12651,6 +12793,7 @@ async function postClaimMarkerComment(client, item, actor = describeSessionIdent
|
|
|
12651
12793
|
}
|
|
12652
12794
|
|
|
12653
12795
|
// src/board-cleanup.ts
|
|
12796
|
+
init_github_client();
|
|
12654
12797
|
async function removeRepoBoardItems(options, deps = {}) {
|
|
12655
12798
|
const cfg = resolveBoardConfig(options.config);
|
|
12656
12799
|
const client = deps.client ?? defaultGitHubClient();
|
|
@@ -13041,6 +13184,7 @@ async function waitForPrChecks(deps) {
|
|
|
13041
13184
|
}
|
|
13042
13185
|
|
|
13043
13186
|
// src/bootstrap-ruleset.ts
|
|
13187
|
+
init_github_client();
|
|
13044
13188
|
var PRODUCT_RULESET_NAME = "mmi-product-required-checks";
|
|
13045
13189
|
var PRODUCT_GATE_CONTEXT = "gate";
|
|
13046
13190
|
var PRODUCT_RULESET_PATH = ".github/rulesets/mmi-product-required-checks.json";
|
|
@@ -14951,6 +15095,9 @@ function isJervHubRepo(repo) {
|
|
|
14951
15095
|
var import_node_fs18 = require("node:fs");
|
|
14952
15096
|
var import_node_path16 = require("node:path");
|
|
14953
15097
|
|
|
15098
|
+
// src/fleet-lockstep-enforce.ts
|
|
15099
|
+
init_github_client();
|
|
15100
|
+
|
|
14954
15101
|
// src/bootstrap-org-ruleset.ts
|
|
14955
15102
|
var ORG_NO_AGENT_FILES_RULESET_NAME = "mmi-no-agent-files-org";
|
|
14956
15103
|
var ORG_LOGIN = "mutmutco";
|
|
@@ -15106,32 +15253,33 @@ function collaboratorRole(c) {
|
|
|
15106
15253
|
async function auditRepoCollaborators(repo, owners, deps, projectAdmins = /* @__PURE__ */ new Set(), sanctionedAdmins = /* @__PURE__ */ new Set()) {
|
|
15107
15254
|
const collabs = await restPagedJson(deps, `repos/${repo}/collaborators?affiliation=direct`, []);
|
|
15108
15255
|
const findings = [];
|
|
15109
|
-
const
|
|
15256
|
+
const adminLogins = /* @__PURE__ */ new Set();
|
|
15257
|
+
const listed = (logins, login) => [...logins].some((entry) => entry.toLowerCase() === login.toLowerCase());
|
|
15110
15258
|
for (const c of collabs) {
|
|
15111
|
-
if (owners
|
|
15259
|
+
if (listed(owners, c.login)) continue;
|
|
15112
15260
|
const role = collaboratorRole(c);
|
|
15113
|
-
|
|
15114
|
-
if (OVERGRANT_ROLES.has(role) &&
|
|
15261
|
+
if (role === "admin") adminLogins.add(c.login.toLowerCase());
|
|
15262
|
+
if (OVERGRANT_ROLES.has(role) && (listed(projectAdmins, c.login) || listed(sanctionedAdmins, c.login))) continue;
|
|
15115
15263
|
if (OVERGRANT_ROLES.has(role)) {
|
|
15116
15264
|
findings.push({
|
|
15117
15265
|
repo,
|
|
15118
15266
|
kind: "collaborator-overgrant",
|
|
15119
15267
|
severity: "high",
|
|
15120
15268
|
actor: c.login,
|
|
15121
|
-
detail: `direct collaborator @${c.login} holds role '${role}'
|
|
15269
|
+
detail: `direct collaborator @${c.login} holds role '${role}' without a project-admin registration or owner sanction`,
|
|
15122
15270
|
remediation: `gh api -X PUT repos/${repo}/collaborators/${c.login} -f permission=push`
|
|
15123
15271
|
});
|
|
15124
15272
|
}
|
|
15125
15273
|
}
|
|
15126
15274
|
for (const login of projectAdmins) {
|
|
15127
|
-
if (owners
|
|
15275
|
+
if (listed(owners, login) || adminLogins.has(login.toLowerCase())) continue;
|
|
15128
15276
|
findings.push({
|
|
15129
15277
|
repo,
|
|
15130
15278
|
kind: "collaborator-undergrant",
|
|
15131
15279
|
severity: "medium",
|
|
15132
15280
|
actor: login,
|
|
15133
|
-
detail: `@${login} is a declared project-admin of ${repo}
|
|
15134
|
-
remediation: `gh api -X PUT repos/${repo}/collaborators/${login} -f permission=
|
|
15281
|
+
detail: `@${login} is a declared project-admin of ${repo} but lacks the required repository admin role`,
|
|
15282
|
+
remediation: `gh api -X PUT repos/${repo}/collaborators/${login} -f permission=admin`
|
|
15135
15283
|
});
|
|
15136
15284
|
}
|
|
15137
15285
|
return findings;
|
|
@@ -15414,6 +15562,13 @@ function renderAccessReport(report) {
|
|
|
15414
15562
|
return lines2.join("\n");
|
|
15415
15563
|
}
|
|
15416
15564
|
|
|
15565
|
+
// src/fleet-lockstep-enforce.ts
|
|
15566
|
+
init_clean_exit();
|
|
15567
|
+
init_cli_shared();
|
|
15568
|
+
|
|
15569
|
+
// ../infra/src/version-gate.ts
|
|
15570
|
+
init_compat();
|
|
15571
|
+
|
|
15417
15572
|
// ../infra/src/infra-constants.ts
|
|
15418
15573
|
var HUB_REPO3 = "mutmutco/MMI-Hub";
|
|
15419
15574
|
var STAGES = ["dev", "rc", "main"];
|
|
@@ -15703,10 +15858,10 @@ var rollout_plan_default = {
|
|
|
15703
15858
|
note: "The v4.0.0 stamp happens at cut time (D6e #4463); until then the candidate is the origin/development head artifacts (built cli/dist + npm pack), identity proven by dist content hash (D6a)."
|
|
15704
15859
|
},
|
|
15705
15860
|
baseline: {
|
|
15706
|
-
version: "4.3.
|
|
15707
|
-
tag: "v4.3.
|
|
15708
|
-
commit: "
|
|
15709
|
-
npm: "@mutmutco/cli@4.3.
|
|
15861
|
+
version: "4.3.47",
|
|
15862
|
+
tag: "v4.3.47",
|
|
15863
|
+
commit: "9c81f5030532",
|
|
15864
|
+
npm: "@mutmutco/cli@4.3.47"
|
|
15710
15865
|
},
|
|
15711
15866
|
exitCriterion: "fleet-n-of-n",
|
|
15712
15867
|
hubOnlyShortcut: "forbidden",
|
|
@@ -15723,14 +15878,14 @@ var rollout_plan_default = {
|
|
|
15723
15878
|
repo: "mutmutco/mmi-hub",
|
|
15724
15879
|
role: "canary",
|
|
15725
15880
|
schedule: "train",
|
|
15726
|
-
v3Target: "v4.3.
|
|
15881
|
+
v3Target: "v4.3.47"
|
|
15727
15882
|
}
|
|
15728
15883
|
],
|
|
15729
15884
|
rollbackTrigger: "Any red inside the post-contract soak window: `devops train gate` FAIL attributable to the v4 doors, Hub endpoint health probe failure, a pre-v4 client admitted instead of receiving actionable HTTP 426, or npm consumer install/doctor failure on the v4-only dist.",
|
|
15730
15885
|
rollback: {
|
|
15731
15886
|
independent: true,
|
|
15732
|
-
mechanism: "npm dist-tag latest -> 4.3.
|
|
15733
|
-
v3Target: "v4.3.
|
|
15887
|
+
mechanism: "npm dist-tag latest -> 4.3.47 and redeploy the Hub Lambda from tag v4.3.47 (9c81f5030532); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
|
|
15888
|
+
v3Target: "v4.3.47 (@mutmutco/cli@4.3.47, tag commit 9c81f5030532 \u2014 last known-good release carrying the repo-index v4-only contract)"
|
|
15734
15889
|
}
|
|
15735
15890
|
},
|
|
15736
15891
|
{
|
|
@@ -15888,6 +16043,13 @@ var rollout_plan_default = {
|
|
|
15888
16043
|
]
|
|
15889
16044
|
};
|
|
15890
16045
|
|
|
16046
|
+
// src/fleet-lockstep-gate.ts
|
|
16047
|
+
init_clean_exit();
|
|
16048
|
+
|
|
16049
|
+
// src/fleet-track-inventory.ts
|
|
16050
|
+
init_cli_shared();
|
|
16051
|
+
init_clean_exit();
|
|
16052
|
+
|
|
15891
16053
|
// src/train-status.ts
|
|
15892
16054
|
function buildTrainStatusReport(input) {
|
|
15893
16055
|
const bumpIntent = input.bumpIntent ?? process.env.MMI_BUMP_INTENT;
|
|
@@ -16036,6 +16198,10 @@ function formatOrgVersions(report) {
|
|
|
16036
16198
|
return lines2.join("\n");
|
|
16037
16199
|
}
|
|
16038
16200
|
|
|
16201
|
+
// src/query-commands.ts
|
|
16202
|
+
init_cli_shared();
|
|
16203
|
+
init_error_codes();
|
|
16204
|
+
|
|
16039
16205
|
// src/issue-view-json.ts
|
|
16040
16206
|
var DEFAULT_ISSUE_VIEW_FIELDS = "number,title,state,url,labels,author,assignees,milestone,body";
|
|
16041
16207
|
function normalizeIssueViewJsonFields(tokens2) {
|
|
@@ -19592,6 +19758,7 @@ var import_node_path19 = require("node:path");
|
|
|
19592
19758
|
// src/jerv-cli-spawn.ts
|
|
19593
19759
|
var import_node_os11 = require("node:os");
|
|
19594
19760
|
var import_node_path18 = require("node:path");
|
|
19761
|
+
init_cli_shared();
|
|
19595
19762
|
var JERV_CLI_ENTRY = (0, import_node_path18.join)("node_modules", "@jervaise", "jerv-cli", "dist", "index.cjs");
|
|
19596
19763
|
function pathEnvEntries(pathEnv, platform2 = process.platform) {
|
|
19597
19764
|
if (platform2 !== "win32") {
|
|
@@ -21335,8 +21502,12 @@ async function beginReleaseLedger(deps, cwd, targetTag) {
|
|
|
21335
21502
|
});
|
|
21336
21503
|
}
|
|
21337
21504
|
|
|
21505
|
+
// src/train-doctor.ts
|
|
21506
|
+
init_client_version();
|
|
21507
|
+
|
|
21338
21508
|
// src/train-self-converge.ts
|
|
21339
21509
|
var import_node_child_process8 = require("node:child_process");
|
|
21510
|
+
init_cli_shared();
|
|
21340
21511
|
var SELF_CONVERGE_INSTALL_TIMEOUT_MS = 12e4;
|
|
21341
21512
|
var SELF_CONVERGE_VERSION_TIMEOUT_MS = 3e4;
|
|
21342
21513
|
var isWin2 = process.platform === "win32";
|
|
@@ -21698,7 +21869,7 @@ async function runTrainDoctor(input) {
|
|
|
21698
21869
|
const tip = await git3(["rev-parse", "--verify", "--quiet", `refs/remotes/origin/${startBranch}`]);
|
|
21699
21870
|
const checkRuns = JSON.parse(await train.run("gh", ["api", `repos/${repo}/commits/${tip}/check-runs`, "--jq", TRAIN_CHECK_RUNS_JQ]));
|
|
21700
21871
|
const statuses = JSON.parse(await train.run("gh", ["api", `repos/${repo}/commits/${tip}/status`, "--jq", TRAIN_COMMIT_STATUS_JQ]));
|
|
21701
|
-
const observed = required.filter((c) => checkRuns.some((r) => r.name === c) || statuses.some((s) => s.context === c));
|
|
21872
|
+
const observed = required.filter((c) => checkRuns.some((r) => r.name === c && !(r.status === "completed" && (r.conclusion === "skipped" || r.conclusion === "neutral"))) || statuses.some((s) => s.context === c));
|
|
21702
21873
|
const red = observed.filter((c) => resolveContextState(c, checkRuns, statuses) === "failed");
|
|
21703
21874
|
const inFlight = observed.filter((c) => resolveContextState(c, checkRuns, statuses) === "pending");
|
|
21704
21875
|
const at = `${startBranch}@${tip.slice(0, 12)}`;
|
|
@@ -24804,6 +24975,9 @@ async function applyCiReconcileRepo(repo, deps) {
|
|
|
24804
24975
|
return finalizeCiReconcile(repo, deps, result, report);
|
|
24805
24976
|
}
|
|
24806
24977
|
|
|
24978
|
+
// src/command-composition.ts
|
|
24979
|
+
init_client_version();
|
|
24980
|
+
|
|
24807
24981
|
// src/command-consolidation.ts
|
|
24808
24982
|
function child(parent, name) {
|
|
24809
24983
|
const found = parent.commands.find((command) => command.name() === name);
|
|
@@ -24860,7 +25034,12 @@ function consolidateCommandNamespaces(program3) {
|
|
|
24860
25034
|
move(program3, stage, "port-range");
|
|
24861
25035
|
}
|
|
24862
25036
|
|
|
25037
|
+
// src/command-manifest.ts
|
|
25038
|
+
init_error_codes();
|
|
25039
|
+
init_house_map();
|
|
25040
|
+
|
|
24863
25041
|
// src/command-taxonomy.ts
|
|
25042
|
+
init_house_map();
|
|
24864
25043
|
var COMMAND_METADATA = /* @__PURE__ */ Symbol.for("mmi.commandTaxonomy.metadata");
|
|
24865
25044
|
var PRIMARY_GROUPS = [
|
|
24866
25045
|
["Orient", ["onboard", "status", "next", "doctor", "whoami", "commands", "explain"]],
|
|
@@ -25401,6 +25580,9 @@ function formatManifestHuman(manifest, options = {}) {
|
|
|
25401
25580
|
return lines2.join("\n");
|
|
25402
25581
|
}
|
|
25403
25582
|
|
|
25583
|
+
// src/command-composition.ts
|
|
25584
|
+
init_house_map();
|
|
25585
|
+
|
|
25404
25586
|
// src/plugin-cache-prune.ts
|
|
25405
25587
|
var PLUGIN_CACHE_KEEP = 2;
|
|
25406
25588
|
var VERSION_DIR = /^\d+\.\d+\.\d+(?:[-+].*)?$/;
|
|
@@ -25761,7 +25943,13 @@ async function activateAppActor(commandPath3, env, mint) {
|
|
|
25761
25943
|
return "app";
|
|
25762
25944
|
}
|
|
25763
25945
|
|
|
25946
|
+
// src/board-commands.ts
|
|
25947
|
+
init_cli_shared();
|
|
25948
|
+
init_clean_exit();
|
|
25949
|
+
init_error_codes();
|
|
25950
|
+
|
|
25764
25951
|
// src/config-load.ts
|
|
25952
|
+
init_cli_shared();
|
|
25765
25953
|
var discoveredConfig = null;
|
|
25766
25954
|
var lastDiscoverMiss = null;
|
|
25767
25955
|
function lastBoardDiscoverMiss() {
|
|
@@ -26105,6 +26293,8 @@ function registerBoardCommands(program3) {
|
|
|
26105
26293
|
var import_node_fs25 = require("node:fs");
|
|
26106
26294
|
var import_node_os14 = require("node:os");
|
|
26107
26295
|
var import_node_path25 = require("node:path");
|
|
26296
|
+
init_cli_shared();
|
|
26297
|
+
init_clean_exit();
|
|
26108
26298
|
|
|
26109
26299
|
// src/command-plans.ts
|
|
26110
26300
|
function parseTrainTag(tag) {
|
|
@@ -26268,6 +26458,13 @@ function renderSteps(title, steps) {
|
|
|
26268
26458
|
].join("\n");
|
|
26269
26459
|
}
|
|
26270
26460
|
|
|
26461
|
+
// src/bootstrap-commands.ts
|
|
26462
|
+
init_house_map();
|
|
26463
|
+
init_github_client();
|
|
26464
|
+
|
|
26465
|
+
// src/port-range-assign.ts
|
|
26466
|
+
init_cli_shared();
|
|
26467
|
+
|
|
26271
26468
|
// src/port-registry.ts
|
|
26272
26469
|
var import_node_fs24 = require("node:fs");
|
|
26273
26470
|
var import_node_path24 = require("node:path");
|
|
@@ -27350,10 +27547,10 @@ async function verifyBootstrap(repo, repoClass, deps, releaseTrack) {
|
|
|
27350
27547
|
try {
|
|
27351
27548
|
const owners = new Set(await resolveOwners(deps));
|
|
27352
27549
|
const sanctioned = new Set(deps.sanctionedAdmins ?? []);
|
|
27353
|
-
const overgrants = (await auditRepoCollaborators(repo, owners, deps,
|
|
27550
|
+
const overgrants = (await auditRepoCollaborators(repo, owners, deps, new Set(deps.projectAdmins ?? []), sanctioned)).filter((f) => f.kind === "collaborator-overgrant");
|
|
27354
27551
|
checks.push({
|
|
27355
27552
|
ok: overgrants.length === 0,
|
|
27356
|
-
label: "
|
|
27553
|
+
label: "repository admin roles match project admins and owner sanctions",
|
|
27357
27554
|
detail: overgrants.length ? `over-granted: ${overgrants.map((f) => f.actor).join(", ")}` : sanctioned.size ? `sanctioned admin: ${[...sanctioned].join(", ")} (access-matrix.json, an owner decision)` : void 0
|
|
27358
27555
|
});
|
|
27359
27556
|
} catch {
|
|
@@ -27671,6 +27868,7 @@ function renderBootstrapVerifyReport(report) {
|
|
|
27671
27868
|
|
|
27672
27869
|
// src/bootstrap-seed-delivery.ts
|
|
27673
27870
|
var import_node_crypto9 = require("node:crypto");
|
|
27871
|
+
init_github_client();
|
|
27674
27872
|
var SHA = /^[a-f0-9]{40}$/;
|
|
27675
27873
|
async function readSeedFile(repo, target, ref, client) {
|
|
27676
27874
|
try {
|
|
@@ -27802,6 +28000,7 @@ function registerBootstrapCommands(program3) {
|
|
|
27802
28000
|
let report = await verifyBootstrap(repo, o.class, {
|
|
27803
28001
|
client: defaultGitHubClient(),
|
|
27804
28002
|
projectMeta: meta,
|
|
28003
|
+
projectAdmins: meta?.projectAdmins,
|
|
27805
28004
|
deployModel: typeof meta?.deployModel === "string" ? meta.deployModel : void 0,
|
|
27806
28005
|
deployFacts,
|
|
27807
28006
|
deployFactsRead: deployFacts !== null,
|
|
@@ -28926,6 +29125,8 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
|
|
|
28926
29125
|
}
|
|
28927
29126
|
|
|
28928
29127
|
// src/call-telemetry.ts
|
|
29128
|
+
init_client_version();
|
|
29129
|
+
init_hub_url();
|
|
28929
29130
|
var TELEMETRY_TIMEOUT_MS = 2e3;
|
|
28930
29131
|
var CI_MARKERS = [
|
|
28931
29132
|
"CI",
|
|
@@ -28966,6 +29167,10 @@ function emitCliCallTelemetry(command) {
|
|
|
28966
29167
|
}
|
|
28967
29168
|
}
|
|
28968
29169
|
|
|
29170
|
+
// src/deploy-commands.ts
|
|
29171
|
+
init_cli_shared();
|
|
29172
|
+
init_clean_exit();
|
|
29173
|
+
|
|
28969
29174
|
// src/deploy-status.ts
|
|
28970
29175
|
function buildDeployStatusReport(input) {
|
|
28971
29176
|
const deploy = input.deployFacts?.stages[input.stage] ?? null;
|
|
@@ -29065,6 +29270,9 @@ function registerDeployCommands(program3) {
|
|
|
29065
29270
|
});
|
|
29066
29271
|
}
|
|
29067
29272
|
|
|
29273
|
+
// src/deploy-guards.ts
|
|
29274
|
+
init_cli_shared();
|
|
29275
|
+
|
|
29068
29276
|
// src/project-set.ts
|
|
29069
29277
|
var UNSET_KEYS = ["oauth", "requiredRuntimeSecrets", "requiredBuildSecrets", "tenantTasks", "secrets", "edgeDomains", "requiredGcpApis", "publishRequired", "publishDir", "releaseChannel", "releaseLanguage", "dsManifestPath", "fofuEnabled", "consumesDesignSystem", "ci", "requiredChecks", "requiredCheckBranches", "ciExemptReason", "gate", "seedCanary"];
|
|
29070
29278
|
var UNSET_KEY_SET = new Set(UNSET_KEYS);
|
|
@@ -29844,6 +30052,10 @@ Rollback only after independent verification: set-deploy --no-env-file false; pr
|
|
|
29844
30052
|
return { ok: true };
|
|
29845
30053
|
}
|
|
29846
30054
|
|
|
30055
|
+
// src/deploy-port-doctor.ts
|
|
30056
|
+
init_fetch_retry();
|
|
30057
|
+
init_client_version();
|
|
30058
|
+
|
|
29847
30059
|
// ../infra/src/deploy-port-collision.ts
|
|
29848
30060
|
function formatDeployPortCollisionReportLine(collision) {
|
|
29849
30061
|
const owners = collision.owners.map((o) => `${o.slug}/${o.stage}`).join(", ");
|
|
@@ -29914,6 +30126,9 @@ function renderDeployPortDoctor(report) {
|
|
|
29914
30126
|
return lines2;
|
|
29915
30127
|
}
|
|
29916
30128
|
|
|
30129
|
+
// src/discovery-commands.ts
|
|
30130
|
+
init_cli_shared();
|
|
30131
|
+
|
|
29917
30132
|
// src/wave-status.ts
|
|
29918
30133
|
var import_node_fs28 = require("node:fs");
|
|
29919
30134
|
|
|
@@ -30790,6 +31005,8 @@ async function collectWaveStatus(deps) {
|
|
|
30790
31005
|
}
|
|
30791
31006
|
|
|
30792
31007
|
// src/discovery-commands.ts
|
|
31008
|
+
init_github_client();
|
|
31009
|
+
init_cli_shared();
|
|
30793
31010
|
var import_node_fs29 = require("node:fs");
|
|
30794
31011
|
var import_node_os15 = require("node:os");
|
|
30795
31012
|
var import_node_path28 = require("node:path");
|
|
@@ -32620,6 +32837,9 @@ async function runDoctorClean(opts, io, deps) {
|
|
|
32620
32837
|
}
|
|
32621
32838
|
|
|
32622
32839
|
// src/explain-command.ts
|
|
32840
|
+
init_cli_shared();
|
|
32841
|
+
init_error_codes();
|
|
32842
|
+
init_house_map();
|
|
32623
32843
|
var LOOP_PLAYBOOKS = {
|
|
32624
32844
|
agent: {
|
|
32625
32845
|
title: "Agent",
|
|
@@ -32935,12 +33155,20 @@ function parseOriginRepo(remoteUrl) {
|
|
|
32935
33155
|
return `${match[1]}/${match[2]}`;
|
|
32936
33156
|
}
|
|
32937
33157
|
|
|
33158
|
+
// src/command-composition.ts
|
|
33159
|
+
init_github_client();
|
|
33160
|
+
|
|
32938
33161
|
// src/issue-commands.ts
|
|
32939
33162
|
var import_node_fs30 = require("node:fs");
|
|
32940
33163
|
var import_node_crypto10 = require("node:crypto");
|
|
33164
|
+
init_cli_shared();
|
|
33165
|
+
init_clean_exit();
|
|
33166
|
+
init_error_codes();
|
|
33167
|
+
init_github_client();
|
|
32941
33168
|
|
|
32942
33169
|
// src/issue-body.ts
|
|
32943
33170
|
var import_node_os16 = require("node:os");
|
|
33171
|
+
init_error_codes();
|
|
32944
33172
|
var TextArgError = class extends Error {
|
|
32945
33173
|
constructor(message2, code, offendingFlag) {
|
|
32946
33174
|
super(message2);
|
|
@@ -33003,6 +33231,8 @@ async function resolveIssueTitle(input, deps) {
|
|
|
33003
33231
|
}
|
|
33004
33232
|
|
|
33005
33233
|
// src/learning-closure-rate.ts
|
|
33234
|
+
init_cli_shared();
|
|
33235
|
+
init_error_codes();
|
|
33006
33236
|
var CLOSURE_RATE_TIMEOUT_MS = 2e4;
|
|
33007
33237
|
var LOOP_ITEM_CAP = 100;
|
|
33008
33238
|
var EVIDENCE_CONCURRENCY = 4;
|
|
@@ -33919,6 +34149,8 @@ ${lines2}`, {
|
|
|
33919
34149
|
}
|
|
33920
34150
|
|
|
33921
34151
|
// src/learning-pickup.ts
|
|
34152
|
+
init_cli_shared();
|
|
34153
|
+
init_github_client();
|
|
33922
34154
|
var LEARNING_PICKUP_CMD = ["mmi-cli", "learning", "pickup"].join(" ");
|
|
33923
34155
|
var LEARNING_CLAIM_MARKER_LIVE_MS = 24 * 60 * 6e4;
|
|
33924
34156
|
function isLearningChannelItem(labels) {
|
|
@@ -34179,6 +34411,7 @@ function registerOrgHealthQuery(program3, deps = defaultOrgHealthQueryDeps()) {
|
|
|
34179
34411
|
}
|
|
34180
34412
|
|
|
34181
34413
|
// src/pr-checks-rest.ts
|
|
34414
|
+
init_cli_shared();
|
|
34182
34415
|
var REST_GH_TIMEOUT_MS = 2e4;
|
|
34183
34416
|
var pollTokenProvider;
|
|
34184
34417
|
var pollTokenOnce;
|
|
@@ -34609,6 +34842,8 @@ async function fetchRestCorePool(gh = defaultGhApi) {
|
|
|
34609
34842
|
|
|
34610
34843
|
// src/pr-commands.ts
|
|
34611
34844
|
var import_promises4 = require("node:fs/promises");
|
|
34845
|
+
init_cli_shared();
|
|
34846
|
+
init_error_codes();
|
|
34612
34847
|
var GC_GH_TIMEOUT_MS2 = 2e4;
|
|
34613
34848
|
var CHECKS_WATCH_POLL_MS = 15e3;
|
|
34614
34849
|
var CHECKS_WATCH_TIMEOUT_MS = 10 * 6e4;
|
|
@@ -35179,6 +35414,9 @@ function writeError(res) {
|
|
|
35179
35414
|
var import_promises5 = require("node:fs/promises");
|
|
35180
35415
|
var import_node_child_process11 = require("node:child_process");
|
|
35181
35416
|
var import_node_util6 = require("node:util");
|
|
35417
|
+
init_clean_exit();
|
|
35418
|
+
init_github_client();
|
|
35419
|
+
init_cli_shared();
|
|
35182
35420
|
var execFileP4 = (0, import_node_util6.promisify)(import_node_child_process11.execFile);
|
|
35183
35421
|
var AWS_REGION = "eu-central-1";
|
|
35184
35422
|
var AWS_TIMEOUT_MS = 3e4;
|
|
@@ -35497,6 +35735,9 @@ function registerSchedulesCommands(program3) {
|
|
|
35497
35735
|
var import_node_fs32 = require("node:fs");
|
|
35498
35736
|
var import_node_path30 = require("node:path");
|
|
35499
35737
|
var import_node_os17 = require("node:os");
|
|
35738
|
+
init_cli_shared();
|
|
35739
|
+
init_hub_auth();
|
|
35740
|
+
init_github_client();
|
|
35500
35741
|
|
|
35501
35742
|
// src/secrets-diff.ts
|
|
35502
35743
|
var TIMEOUT_MS2 = 8e3;
|
|
@@ -35876,6 +36117,7 @@ function registerSecretsCommands(program3) {
|
|
|
35876
36117
|
}
|
|
35877
36118
|
|
|
35878
36119
|
// src/session-report.ts
|
|
36120
|
+
init_cli_shared();
|
|
35879
36121
|
var GC_GH_TIMEOUT_MS3 = 2e4;
|
|
35880
36122
|
function shapeSessionIssues(report) {
|
|
35881
36123
|
if (!report) return [];
|
|
@@ -35995,6 +36237,8 @@ function registerSessionReport(program3) {
|
|
|
35995
36237
|
// src/stage-commands.ts
|
|
35996
36238
|
var import_node_fs33 = require("node:fs");
|
|
35997
36239
|
var import_node_path31 = require("node:path");
|
|
36240
|
+
init_cli_shared();
|
|
36241
|
+
init_clean_exit();
|
|
35998
36242
|
|
|
35999
36243
|
// src/stage-default.ts
|
|
36000
36244
|
function shellFor() {
|
|
@@ -36063,39 +36307,7 @@ function decideStage(inputs) {
|
|
|
36063
36307
|
}
|
|
36064
36308
|
|
|
36065
36309
|
// src/stage-live.ts
|
|
36066
|
-
var import_node_net2 = require("node:net");
|
|
36067
36310
|
var STAGE_LIVE_HUB_REPO = "mutmutco/MMI-Hub";
|
|
36068
|
-
var IP_ECHO_URL = "https://api.ipify.org";
|
|
36069
|
-
var IP6_ECHO_URL = "https://api6.ipify.org";
|
|
36070
|
-
var IP_DETECT_TIMEOUT_MS = 1e4;
|
|
36071
|
-
function validStageLiveIp(ip) {
|
|
36072
|
-
return (0, import_node_net2.isIP)(ip.trim()) !== 0;
|
|
36073
|
-
}
|
|
36074
|
-
async function detectPublicIp(fetchImpl = fetch) {
|
|
36075
|
-
return detectPublicIpFrom(IP_ECHO_URL, fetchImpl);
|
|
36076
|
-
}
|
|
36077
|
-
async function detectCallerIps(fetchImpl = fetch) {
|
|
36078
|
-
const [v4, v6] = await Promise.allSettled([
|
|
36079
|
-
detectPublicIp(fetchImpl),
|
|
36080
|
-
detectPublicIpFrom(IP6_ECHO_URL, fetchImpl)
|
|
36081
|
-
]);
|
|
36082
|
-
if (v4.status === "rejected") throw v4.reason;
|
|
36083
|
-
const ip = v4.value;
|
|
36084
|
-
const candidate = v6.status === "fulfilled" ? v6.value : void 0;
|
|
36085
|
-
return { ip, ip6: candidate && (0, import_node_net2.isIP)(candidate) === 6 ? candidate : void 0 };
|
|
36086
|
-
}
|
|
36087
|
-
async function detectPublicIpFrom(url, fetchImpl) {
|
|
36088
|
-
let res;
|
|
36089
|
-
try {
|
|
36090
|
-
res = await fetchImpl(url, { signal: AbortSignal.timeout(IP_DETECT_TIMEOUT_MS) });
|
|
36091
|
-
} catch (e) {
|
|
36092
|
-
throw new Error(`public IP detection failed (${url}): ${e.message}`);
|
|
36093
|
-
}
|
|
36094
|
-
if (!res.ok) throw new Error(`public IP detection failed: HTTP ${res.status} from ${url}`);
|
|
36095
|
-
const ip = (await res.text()).trim();
|
|
36096
|
-
if (!validStageLiveIp(ip)) throw new Error(`public IP detection returned a non-IP body from ${url}: "${ip.slice(0, 80)}"`);
|
|
36097
|
-
return ip;
|
|
36098
|
-
}
|
|
36099
36311
|
function isStageLiveDeployModel(deployModel, projectType) {
|
|
36100
36312
|
if (deployModel) return deployModel === "tenant-container";
|
|
36101
36313
|
return projectType === "web-app";
|
|
@@ -36107,16 +36319,14 @@ function stageLiveUnsupportedReason(deployModel, projectType) {
|
|
|
36107
36319
|
}
|
|
36108
36320
|
function stageLiveUpSteps(t) {
|
|
36109
36321
|
return [
|
|
36110
|
-
{ label: `
|
|
36322
|
+
{ label: `clear legacy IP gates for ${t.host} via the Hub backend (tenant-control cf-gate-clear; no new rules)` },
|
|
36111
36323
|
{ label: `deploy ${t.ref ?? "<current branch>"} to the ${t.slug} dev stage via the Hub backend (tenant-deploy)` },
|
|
36112
|
-
{ label: `gate ${t.host} to your IPv4 and your IPv6 /64 at the Cloudflare edge via the Hub backend (tenant-control cf-gate-allow)` },
|
|
36113
36324
|
{ label: "tear down when done", command: "mmi-cli stage --live --down --apply" }
|
|
36114
36325
|
];
|
|
36115
36326
|
}
|
|
36116
36327
|
function stageLiveDownSteps(t) {
|
|
36117
36328
|
return [
|
|
36118
|
-
{ label: `stop the ${t.slug} dev runtime via the Hub backend (tenant-control stop)` }
|
|
36119
|
-
{ label: `remove the Cloudflare edge gate for ${t.host} via the Hub backend (tenant-control cf-gate-clear)` }
|
|
36329
|
+
{ label: `stop the ${t.slug} dev runtime via the Hub backend (tenant-control stop)` }
|
|
36120
36330
|
];
|
|
36121
36331
|
}
|
|
36122
36332
|
function stageLiveDownNoop(t, reason) {
|
|
@@ -36131,39 +36341,28 @@ function stageLiveDownNoop(t, reason) {
|
|
|
36131
36341
|
}
|
|
36132
36342
|
async function runStageLiveUp(deps, t) {
|
|
36133
36343
|
if (!t.ref?.trim()) throw new Error("stage --live: cannot resolve the current branch to deploy");
|
|
36134
|
-
const detected = await deps.detectIp();
|
|
36135
|
-
const ip = detected.ip.trim();
|
|
36136
|
-
if (!validStageLiveIp(ip)) throw new Error(`stage --live: detected public IP is not a literal IPv4/IPv6 address: "${ip.slice(0, 80)}"`);
|
|
36137
|
-
const ip6 = detected.ip6?.trim() || void 0;
|
|
36138
36344
|
if (!t.host?.trim()) throw new Error("stage --live: cannot resolve the dev edge host (registry edgeDomains.dev)");
|
|
36345
|
+
await deps.control({ repo: t.repo, action: "cf-gate-clear", host: t.host });
|
|
36139
36346
|
await deps.deployDev({ repo: t.repo, ref: t.ref });
|
|
36140
|
-
await deps.control({ repo: t.repo, action: "cf-gate-allow", host: t.host, ip, ip6 });
|
|
36141
|
-
const allowed = ip6 ? `${ip} and your IPv6 /64 prefix (from ${ip6})` : `${ip} (IPv4 only \u2014 no public IPv6 detected)`;
|
|
36142
36347
|
return {
|
|
36143
36348
|
command: "stage --live",
|
|
36144
36349
|
mode: "up",
|
|
36145
36350
|
slug: t.slug,
|
|
36146
36351
|
repo: t.repo,
|
|
36147
36352
|
ref: t.ref,
|
|
36148
|
-
|
|
36149
|
-
|
|
36150
|
-
dispatched: ["tenant-deploy.yml", "tenant-control.yml"],
|
|
36151
|
-
// #2656: the gate now writes a skip+block pair and self-verifies from the runner (a non-allowed vantage),
|
|
36152
|
-
// so a gate that failed to close fails the run RED. The stage is private only once that gate run is green.
|
|
36153
|
-
message: `dispatched the dev deploy of ${t.ref} and the Cloudflare edge gate for ${t.host} \u2192 ${allowed}; watch the runs in ${STAGE_LIVE_HUB_REPO} Actions and treat the stage as private ONLY once the cf-gate-allow run is green (it self-verifies the host is blocked) \u2014 tear down with: mmi-cli stage --live --down --apply`
|
|
36353
|
+
dispatched: ["tenant-control.yml", "tenant-deploy.yml"],
|
|
36354
|
+
message: `dispatched legacy gate cleanup and the dev deploy of ${t.ref}; ${t.host} has no stage IP restriction once both runs succeed in ${STAGE_LIVE_HUB_REPO} Actions. The app's own sign-in still applies. Tear down with: mmi-cli stage --live --down --apply`
|
|
36154
36355
|
};
|
|
36155
36356
|
}
|
|
36156
36357
|
async function runStageLiveDown(deps, t) {
|
|
36157
|
-
if (!t.host?.trim()) throw new Error("stage --live: cannot resolve the dev edge host (registry edgeDomains.dev)");
|
|
36158
36358
|
await deps.control({ repo: t.repo, action: "stop" });
|
|
36159
|
-
await deps.control({ repo: t.repo, action: "cf-gate-clear", host: t.host });
|
|
36160
36359
|
return {
|
|
36161
36360
|
command: "stage --live",
|
|
36162
36361
|
mode: "down",
|
|
36163
36362
|
slug: t.slug,
|
|
36164
36363
|
repo: t.repo,
|
|
36165
|
-
dispatched: ["tenant-control.yml"
|
|
36166
|
-
message:
|
|
36364
|
+
dispatched: ["tenant-control.yml"],
|
|
36365
|
+
message: "dispatched the dev stop; verify the workflow succeeds before treating the stage as stopped"
|
|
36167
36366
|
};
|
|
36168
36367
|
}
|
|
36169
36368
|
|
|
@@ -36405,13 +36604,12 @@ function registerStageCommands(program3) {
|
|
|
36405
36604
|
}
|
|
36406
36605
|
const rcDeps = registryClientDeps(await loadConfig());
|
|
36407
36606
|
const deps = {
|
|
36408
|
-
detectIp: () => detectCallerIps(),
|
|
36409
36607
|
deployDev: async ({ repo, ref }) => {
|
|
36410
36608
|
const res = await tenantDeploy({ repo, stage: "dev", ref }, rcDeps);
|
|
36411
36609
|
if (!res.ok) throw new Error(`dev deploy dispatch failed: ${res.body?.error ?? res.error ?? `HTTP ${res.status}`}`);
|
|
36412
36610
|
},
|
|
36413
|
-
control: async ({ repo, action, host
|
|
36414
|
-
const res = await tenantControl({ repo, stage: "dev", action, host
|
|
36611
|
+
control: async ({ repo, action, host }) => {
|
|
36612
|
+
const res = await tenantControl({ repo, stage: "dev", action, host }, rcDeps);
|
|
36415
36613
|
if (!res.ok) throw new Error(`runtime tenant control ${action} dispatch failed: ${res.body?.error ?? res.error ?? `HTTP ${res.status}`}`);
|
|
36416
36614
|
}
|
|
36417
36615
|
};
|
|
@@ -36422,7 +36620,7 @@ function registerStageCommands(program3) {
|
|
|
36422
36620
|
return failGraceful(`stage --live: ${e.message}`);
|
|
36423
36621
|
}
|
|
36424
36622
|
}
|
|
36425
|
-
const stage = program3.command("stage").description("plan or run the repo local stage environment; --live =
|
|
36623
|
+
const stage = program3.command("stage").description("plan or run the repo local stage environment; --live = on-demand cloud dev stage; remote rc/live move only via the gated rcand/release/hotfix train").option("--json", "machine-readable output").option("--apply", "run the full local stage: stop previous in this worktree, build, start, health-check").option("--port <port>", "loopback port for this worktree stage (1024..65535; default picks a free port in the registry range)").option("--live", "personal cloud dev stage: deploy the current branch to the dev runtime, without a stage IP restriction").option("--down", "with --live: stop the dev runtime").option("--timeout-ms <ms>", "bounded build/health timeout", "60000").action(async (o) => {
|
|
36426
36624
|
if (o.down && !o.live) return fail("stage: --down applies to --live only (local teardown is `mmi-cli stage stop --apply`)");
|
|
36427
36625
|
if (o.live) return runStageLiveCommand(o);
|
|
36428
36626
|
const { resolution: res, project: project2, cfg: stageCfg } = await resolveStage();
|
|
@@ -36712,8 +36910,12 @@ function renderVerifySecrets(body) {
|
|
|
36712
36910
|
var import_node_child_process16 = require("node:child_process");
|
|
36713
36911
|
var import_node_fs41 = require("node:fs");
|
|
36714
36912
|
var import_promises7 = require("node:fs/promises");
|
|
36913
|
+
init_clean_exit();
|
|
36914
|
+
init_cli_shared();
|
|
36915
|
+
init_error_codes();
|
|
36715
36916
|
|
|
36716
36917
|
// src/session-runtime.ts
|
|
36918
|
+
init_house_map();
|
|
36717
36919
|
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));";
|
|
36718
36920
|
function spawnDetachedSelf(args, deps, opts = {}) {
|
|
36719
36921
|
try {
|
|
@@ -36768,6 +36970,9 @@ async function resolveAutoAddBoardAttach(client, cfg, selector, priority, warn =
|
|
|
36768
36970
|
return { projectItemId };
|
|
36769
36971
|
}
|
|
36770
36972
|
|
|
36973
|
+
// src/command-register-collaboration.ts
|
|
36974
|
+
init_house_map();
|
|
36975
|
+
|
|
36771
36976
|
// src/issue-check.ts
|
|
36772
36977
|
var CHECKLIST_RE = /^([ \t]*[-*+] \[)([ xX])(\] )(.*)$/gm;
|
|
36773
36978
|
function findChecklistItems(body) {
|
|
@@ -36975,10 +37180,15 @@ async function runPrLand(prNumber, options, deps) {
|
|
|
36975
37180
|
};
|
|
36976
37181
|
}
|
|
36977
37182
|
|
|
37183
|
+
// src/command-register-collaboration.ts
|
|
37184
|
+
init_github_client();
|
|
37185
|
+
|
|
36978
37186
|
// src/merge-cleanup.ts
|
|
36979
37187
|
var import_node_fs36 = require("node:fs");
|
|
36980
37188
|
var import_node_path34 = require("node:path");
|
|
36981
37189
|
var import_node_os18 = require("node:os");
|
|
37190
|
+
init_cli_shared();
|
|
37191
|
+
init_github_client();
|
|
36982
37192
|
|
|
36983
37193
|
// src/board-advance.ts
|
|
36984
37194
|
function repoOf2(ref) {
|
|
@@ -38263,6 +38473,7 @@ var import_node_fs37 = require("node:fs");
|
|
|
38263
38473
|
var import_node_path35 = require("node:path");
|
|
38264
38474
|
|
|
38265
38475
|
// src/cross-repo-filing-issue.ts
|
|
38476
|
+
init_github_client();
|
|
38266
38477
|
function crossRepoFilingRetryCommand(prRepo, prNumber) {
|
|
38267
38478
|
return `mmi-cli devops pr merge ${prNumber} --repo ${prRepo}`;
|
|
38268
38479
|
}
|
|
@@ -38470,6 +38681,7 @@ var import_node_child_process14 = require("node:child_process");
|
|
|
38470
38681
|
var import_node_fs38 = require("node:fs");
|
|
38471
38682
|
var import_node_os19 = require("node:os");
|
|
38472
38683
|
var import_node_path36 = require("node:path");
|
|
38684
|
+
init_cli_shared();
|
|
38473
38685
|
var REVIEW_VERDICT_MARKER = "<!-- zeroci-review v1 -->";
|
|
38474
38686
|
var REVIEW_VERDICTS = ["PROCEED", "CORRECT", "ESCALATE"];
|
|
38475
38687
|
function isReviewVerdict(value) {
|
|
@@ -38649,6 +38861,7 @@ async function postPrCommentFromFile(number, repo, body) {
|
|
|
38649
38861
|
|
|
38650
38862
|
// src/pr-create-docs-check.ts
|
|
38651
38863
|
var import_node_child_process15 = require("node:child_process");
|
|
38864
|
+
init_cli_shared();
|
|
38652
38865
|
var GIT_TIMEOUT_MS2 = 15e3;
|
|
38653
38866
|
function catFileBatch(root, ref, paths) {
|
|
38654
38867
|
if (paths.length === 0) return Promise.resolve([]);
|
|
@@ -38769,6 +38982,7 @@ async function checkDocsIndexAtHead(opts, deps) {
|
|
|
38769
38982
|
}
|
|
38770
38983
|
|
|
38771
38984
|
// src/pr-create-claim-guard.ts
|
|
38985
|
+
init_github_client();
|
|
38772
38986
|
var CLAIM_GUARD_RATE_LIMIT_WAIT_CAP_MS = 3e4;
|
|
38773
38987
|
function withRateLimitRetry(client, seams = {}) {
|
|
38774
38988
|
const throttledPaths = /* @__PURE__ */ new Set();
|
|
@@ -38827,6 +39041,7 @@ async function prCreateClaimRefusal(body, repoOption, deps = {}) {
|
|
|
38827
39041
|
// src/worktree-merge-cleanup.ts
|
|
38828
39042
|
var import_node_fs40 = require("node:fs");
|
|
38829
39043
|
var import_node_path38 = require("node:path");
|
|
39044
|
+
init_cli_shared();
|
|
38830
39045
|
|
|
38831
39046
|
// src/worktree-evidence-archive.ts
|
|
38832
39047
|
var import_node_fs39 = require("node:fs");
|
|
@@ -41208,6 +41423,9 @@ ${list}`);
|
|
|
41208
41423
|
|
|
41209
41424
|
// src/command-register-developer.ts
|
|
41210
41425
|
var import_node_fs46 = require("node:fs");
|
|
41426
|
+
init_clean_exit();
|
|
41427
|
+
init_cli_shared();
|
|
41428
|
+
init_error_codes();
|
|
41211
41429
|
|
|
41212
41430
|
// src/whoami.ts
|
|
41213
41431
|
async function resolveWhoami(deps) {
|
|
@@ -41238,6 +41456,8 @@ async function resolveWhoami(deps) {
|
|
|
41238
41456
|
|
|
41239
41457
|
// src/command-register-developer.ts
|
|
41240
41458
|
var import_node_path44 = require("node:path");
|
|
41459
|
+
init_house_map();
|
|
41460
|
+
init_hub_url();
|
|
41241
41461
|
|
|
41242
41462
|
// src/wave-land.ts
|
|
41243
41463
|
function planWaveLand(prs) {
|
|
@@ -41269,6 +41489,7 @@ async function executeWaveLand(plan, deps) {
|
|
|
41269
41489
|
|
|
41270
41490
|
// src/box-commands.ts
|
|
41271
41491
|
var import_node_fs42 = require("node:fs");
|
|
41492
|
+
init_clean_exit();
|
|
41272
41493
|
|
|
41273
41494
|
// src/box.ts
|
|
41274
41495
|
var BOX_KEYS = {
|
|
@@ -41676,6 +41897,9 @@ function runDistStatus(root) {
|
|
|
41676
41897
|
}
|
|
41677
41898
|
}
|
|
41678
41899
|
|
|
41900
|
+
// src/edge-commands.ts
|
|
41901
|
+
init_cli_shared();
|
|
41902
|
+
|
|
41679
41903
|
// src/edge-tunnel.ts
|
|
41680
41904
|
var HOSTNAME_RE = /^(?=.{1,253}$)([a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)(\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+$/;
|
|
41681
41905
|
var UPSTREAM_RE = /^https?:\/\/[^/\s]+(?::\d+)?(?:\/.*)?$/;
|
|
@@ -41742,9 +41966,15 @@ function registerEdgeCommands(program3) {
|
|
|
41742
41966
|
});
|
|
41743
41967
|
}
|
|
41744
41968
|
|
|
41969
|
+
// src/command-register-developer.ts
|
|
41970
|
+
init_github_client();
|
|
41971
|
+
init_hub_auth();
|
|
41972
|
+
|
|
41745
41973
|
// src/schedules-lift-command.ts
|
|
41746
41974
|
var import_promises8 = require("node:fs/promises");
|
|
41747
41975
|
var import_node_path42 = require("node:path");
|
|
41976
|
+
init_clean_exit();
|
|
41977
|
+
init_cli_shared();
|
|
41748
41978
|
var DEFAULT_WORKFLOWS_DIR = ".github/workflows";
|
|
41749
41979
|
var SCHEDULE_REPO_RE = /^[A-Za-z0-9_.-]+$/;
|
|
41750
41980
|
var SchedulesLiftUsageError = class extends Error {
|
|
@@ -42222,6 +42452,10 @@ function registerDeveloperCommands(program3) {
|
|
|
42222
42452
|
|
|
42223
42453
|
// src/command-register-train-operations.ts
|
|
42224
42454
|
var import_promises10 = require("node:fs/promises");
|
|
42455
|
+
init_clean_exit();
|
|
42456
|
+
init_cli_shared();
|
|
42457
|
+
init_client_version();
|
|
42458
|
+
init_house_map();
|
|
42225
42459
|
|
|
42226
42460
|
// src/hotfix-apply.ts
|
|
42227
42461
|
var import_promises9 = require("node:fs/promises");
|
|
@@ -43633,6 +43867,9 @@ function checkHotfixCarries(options) {
|
|
|
43633
43867
|
// src/train-commands.ts
|
|
43634
43868
|
var import_node_fs47 = require("node:fs");
|
|
43635
43869
|
var import_node_path45 = require("node:path");
|
|
43870
|
+
init_cli_shared();
|
|
43871
|
+
init_clean_exit();
|
|
43872
|
+
init_client_version();
|
|
43636
43873
|
var INVOKED_ARGV = process.argv.slice(2);
|
|
43637
43874
|
var RELEASE_BUMP_INTENTS = ["major", "minor", "patch"];
|
|
43638
43875
|
function resolveReleaseBumpIntent(raw) {
|