@mutmutco/cli 2.61.1 → 2.63.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -56,7 +56,6 @@ mmi-cli doctor --json
56
56
  - `mmi-cli rcand`, `release`, and `hotfix` render guarded train plans; product trains trigger the Hub's central tenant deployer, while MMI-Hub releases directly from `development` to `main`.
57
57
  - `mmi-cli bootstrap`, `bootstrap verify`, and `bootstrap apply` plan, audit, and seed repo onboarding.
58
58
  - `mmi-cli access audit` checks collaborator roles and train-branch allowlists.
59
- - `mmi-cli throttle report` reads `.mmi/throttle/trace.jsonl` and prints gate denial stats from the org Scrooge v2 Read/Shell gates (Claude Code + Cursor IDE) — files ≥50 KB require an explicit positive Read `limit`; output separates `denied (block)` vs `would-block (observe)`.
60
59
  - `mmi-cli doctor` checks GitHub auth, repo config, CLI availability, plugin install/config/version state, and stale MMI plugin cache dirs, auto-repairing the safe gaps.
61
60
 
62
61
  Hub API calls do not send the raw GitHub token on every request. The CLI exchanges it at `/auth/session`
package/dist/index.cjs CHANGED
@@ -1,28 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __esm = (fn, res, err) => function __init() {
6
- if (err) throw err[0];
7
- try {
8
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
9
- } catch (e) {
10
- throw err = [e], e;
11
- }
12
- };
13
- var __export = (target, all) => {
14
- for (var name in all)
15
- __defProp(target, name, { get: all[name], enumerable: true });
16
- };
17
-
18
- // ../infra/compat.mjs
19
- var init_compat = __esm({
20
- "../infra/compat.mjs"() {
21
- "use strict";
22
- }
23
- });
24
3
 
25
4
  // src/client-version.ts
5
+ var import_node_fs = require("node:fs");
6
+ var import_node_path = require("node:path");
26
7
  function resolveClientVersionManifestCandidates(distDir = __dirname) {
27
8
  return [
28
9
  (0, import_node_path.join)(distDir, "..", "..", ".claude-plugin", "plugin.json"),
@@ -46,287 +27,8 @@ function resolveClientVersion() {
46
27
  }
47
28
  return "0.0.0";
48
29
  }
49
- var import_node_fs, import_node_path;
50
- var init_client_version = __esm({
51
- "src/client-version.ts"() {
52
- "use strict";
53
- import_node_fs = require("node:fs");
54
- import_node_path = require("node:path");
55
- init_compat();
56
- }
57
- });
58
-
59
- // src/stdin-inject.ts
60
- function setInjectedStdin(payload) {
61
- injectedStdin = payload;
62
- }
63
- function stdinHasPipedInput(statFd = () => (0, import_node_fs2.fstatSync)(0), getIsTTY = () => process.stdin.isTTY) {
64
- try {
65
- const stat = statFd();
66
- if (stat.isFIFO() || stat.isFile()) return true;
67
- if (stat.isCharacterDevice()) return false;
68
- if (stat.isSocket()) return false;
69
- if (getIsTTY() === true) return false;
70
- return true;
71
- } catch {
72
- return false;
73
- }
74
- }
75
- async function readStdin(opts = {}) {
76
- if (injectedStdin !== void 0) return injectedStdin;
77
- if (!stdinHasPipedInput()) return "";
78
- const maxBytes = opts.maxBytes ?? STDIN_MAX_BYTES;
79
- const timeoutMs = opts.timeoutMs ?? STDIN_DRAIN_TIMEOUT_MS;
80
- const chunks = [];
81
- let total = 0;
82
- const drain = (async () => {
83
- for await (const chunk of process.stdin) {
84
- const buf = chunk;
85
- const room = maxBytes - total;
86
- if (buf.length >= room) {
87
- chunks.push(buf.subarray(0, room));
88
- total = maxBytes;
89
- break;
90
- }
91
- chunks.push(buf);
92
- total += buf.length;
93
- }
94
- })().catch(() => {
95
- });
96
- let timer;
97
- const timeout = new Promise((resolve) => {
98
- timer = setTimeout(resolve, timeoutMs);
99
- });
100
- try {
101
- await Promise.race([drain, timeout]);
102
- } finally {
103
- if (timer) clearTimeout(timer);
104
- try {
105
- process.stdin.unref();
106
- } catch {
107
- }
108
- }
109
- return Buffer.concat(chunks).toString("utf8");
110
- }
111
- var import_node_fs2, injectedStdin, STDIN_MAX_BYTES, STDIN_DRAIN_TIMEOUT_MS;
112
- var init_stdin_inject = __esm({
113
- "src/stdin-inject.ts"() {
114
- "use strict";
115
- import_node_fs2 = require("node:fs");
116
- STDIN_MAX_BYTES = 8 * 1024 * 1024;
117
- STDIN_DRAIN_TIMEOUT_MS = 5e3;
118
- }
119
- });
120
-
121
- // src/daemon-protocol.ts
122
- function daemonDir(env = process.env) {
123
- return env.MMI_CLI_DAEMON_DIR || (0, import_node_path2.join)((0, import_node_os.homedir)(), ".mmi");
124
- }
125
- function tokenPath(env = process.env) {
126
- return (0, import_node_path2.join)(daemonDir(env), "daemon-token");
127
- }
128
- function readDaemonToken(env = process.env) {
129
- try {
130
- const t = (0, import_node_fs3.readFileSync)(tokenPath(env), "utf8").trim();
131
- return t.length > 0 ? t : void 0;
132
- } catch {
133
- return void 0;
134
- }
135
- }
136
- function socketPath(env = process.env, platform = process.platform, user) {
137
- if (env.MMI_CLI_DAEMON_SOCKET) return env.MMI_CLI_DAEMON_SOCKET;
138
- let name = user;
139
- if (!name) {
140
- try {
141
- name = (0, import_node_os.userInfo)().username;
142
- } catch {
143
- name = env.USERNAME || env.USER || "default";
144
- }
145
- }
146
- const hash = (0, import_node_crypto.createHash)("sha256").update(name).digest("hex").slice(0, 12);
147
- return platform === "win32" ? `\\\\.\\pipe\\mmi-cli-${hash}` : (0, import_node_path2.join)(daemonDir(env), `mmi-cli-${hash}.sock`);
148
- }
149
- function argvReadsStdin(args) {
150
- for (let i = 0; i < args.length; i++) {
151
- const a = args[i];
152
- if (a.endsWith("-file=-")) return true;
153
- if (a.endsWith("-file") && args[i + 1] === "-") return true;
154
- }
155
- return false;
156
- }
157
- function daemonEligible(args) {
158
- const verb2 = args[1] ?? "";
159
- return args[0] === "saga" && HOT_VERBS.has(verb2) && !CONTINUITY_HOT_VERBS.has(verb2) && !args.includes("--run") && !args.includes("--help") && !args.includes("-h") && !argvReadsStdin(args);
160
- }
161
- function buildStamp(version, bundleMtimeMs) {
162
- return `${version}#${Math.trunc(bundleMtimeMs)}`;
163
- }
164
- function parseLine(line) {
165
- try {
166
- const v = JSON.parse(line);
167
- return v && typeof v === "object" ? v : void 0;
168
- } catch {
169
- return void 0;
170
- }
171
- }
172
- var import_node_crypto, import_node_fs3, import_node_os, import_node_path2, DEFAULT_IDLE_EXIT_MS, DEFAULT_CONNECT_TIMEOUT_MS, DEFAULT_RESPONSE_TIMEOUT_MS, HOT_VERBS, CONTINUITY_HOT_VERBS, STDIN_VERBS, encodeLine, MAX_FRAME_LENGTH, LineBuffer;
173
- var init_daemon_protocol = __esm({
174
- "src/daemon-protocol.ts"() {
175
- "use strict";
176
- import_node_crypto = require("node:crypto");
177
- import_node_fs3 = require("node:fs");
178
- import_node_os = require("node:os");
179
- import_node_path2 = require("node:path");
180
- DEFAULT_IDLE_EXIT_MS = 30 * 6e4;
181
- DEFAULT_CONNECT_TIMEOUT_MS = 200;
182
- DEFAULT_RESPONSE_TIMEOUT_MS = 2e3;
183
- HOT_VERBS = /* @__PURE__ */ new Set(["note", "probe", "capture", "session", "head-update"]);
184
- CONTINUITY_HOT_VERBS = /* @__PURE__ */ new Set(["note", "probe", "capture", "session", "head-update"]);
185
- STDIN_VERBS = /* @__PURE__ */ new Set(["capture", "session"]);
186
- encodeLine = (obj) => `${JSON.stringify(obj)}
187
- `;
188
- MAX_FRAME_LENGTH = 1024 * 1024;
189
- LineBuffer = class {
190
- constructor(maxFrameLength = MAX_FRAME_LENGTH) {
191
- this.maxFrameLength = maxFrameLength;
192
- }
193
- maxFrameLength;
194
- buf = "";
195
- push(chunk) {
196
- this.buf += chunk;
197
- const parts = this.buf.split("\n");
198
- this.buf = parts.pop() ?? "";
199
- if (this.buf.length > this.maxFrameLength || parts.some((p) => p.length > this.maxFrameLength)) {
200
- this.buf = "";
201
- throw new RangeError("daemon frame too long");
202
- }
203
- return parts.filter((p) => p.length > 0);
204
- }
205
- };
206
- }
207
- });
208
-
209
- // src/daemon-client.ts
210
- var daemon_client_exports = {};
211
- __export(daemon_client_exports, {
212
- clientStamp: () => clientStamp,
213
- spawnDaemon: () => spawnDaemon,
214
- tryDaemonRun: () => tryDaemonRun
215
- });
216
- function clientStamp() {
217
- let mtime = 0;
218
- try {
219
- mtime = (0, import_node_fs4.statSync)((0, import_node_path3.join)(__dirname, "index.cjs")).mtimeMs;
220
- } catch {
221
- }
222
- return buildStamp(resolveClientVersion(), mtime);
223
- }
224
- function spawnDaemon() {
225
- try {
226
- (0, import_node_child_process.spawn)(process.execPath, [process.argv[1], "daemon", "--run"], {
227
- detached: true,
228
- stdio: "ignore",
229
- windowsHide: true,
230
- cwd: (0, import_node_os2.tmpdir)()
231
- }).unref();
232
- } catch {
233
- }
234
- }
235
- function requestOnce(req, path, connectTimeoutMs, responseTimeoutMs) {
236
- return new Promise((resolve) => {
237
- let socket;
238
- try {
239
- socket = (0, import_node_net.connect)(path);
240
- } catch {
241
- return resolve(void 0);
242
- }
243
- let done = false;
244
- let responseTimer;
245
- const connectTimer = setTimeout(() => finish(void 0), connectTimeoutMs);
246
- function finish(v) {
247
- if (done) return;
248
- done = true;
249
- clearTimeout(connectTimer);
250
- if (responseTimer) clearTimeout(responseTimer);
251
- try {
252
- socket.destroy();
253
- } catch {
254
- }
255
- resolve(v);
256
- }
257
- const lb = new LineBuffer();
258
- socket.setEncoding("utf8");
259
- socket.on("connect", () => {
260
- clearTimeout(connectTimer);
261
- responseTimer = setTimeout(() => finish(void 0), responseTimeoutMs);
262
- socket.write(encodeLine(req));
263
- });
264
- socket.on("data", (chunk) => {
265
- let lines;
266
- try {
267
- lines = lb.push(chunk);
268
- } catch {
269
- return finish(void 0);
270
- }
271
- if (lines.length) finish(parseLine(lines[0]));
272
- });
273
- socket.on("error", () => finish(void 0));
274
- socket.on("close", () => finish(void 0));
275
- });
276
- }
277
- async function tryDaemonRun(args, deps = {}) {
278
- const env = deps.env ?? process.env;
279
- if (env.MMI_CLI_NO_DAEMON) return { handled: false };
280
- if (!daemonEligible(args)) return { handled: false };
281
- const respawn = deps.spawnDaemon ?? spawnDaemon;
282
- let stdin;
283
- try {
284
- if (STDIN_VERBS.has(args[1] ?? "")) {
285
- stdin = await (deps.readInput ?? readStdin)();
286
- setInjectedStdin(stdin);
287
- }
288
- const req = {
289
- args,
290
- cwd: process.cwd(),
291
- stamp: deps.stamp ?? clientStamp(),
292
- token: deps.token ?? readDaemonToken(env) ?? "",
293
- ...stdin !== void 0 ? { stdin } : {}
294
- };
295
- const resp = await requestOnce(
296
- req,
297
- deps.path ?? socketPath(env),
298
- deps.connectTimeoutMs ?? DEFAULT_CONNECT_TIMEOUT_MS,
299
- deps.responseTimeoutMs ?? DEFAULT_RESPONSE_TIMEOUT_MS
300
- );
301
- if (!resp || resp.restart) {
302
- respawn();
303
- return { handled: false, stdin };
304
- }
305
- if (resp.decline || typeof resp.code !== "number") return { handled: false, stdin };
306
- if (resp.stdout) (deps.out ?? ((s) => process.stdout.write(s)))(resp.stdout);
307
- if (resp.stderr) (deps.errOut ?? ((s) => process.stderr.write(s)))(resp.stderr);
308
- return { handled: true, code: resp.code };
309
- } catch {
310
- return { handled: false, stdin };
311
- }
312
- }
313
- var import_node_net, import_node_child_process, import_node_fs4, import_node_os2, import_node_path3;
314
- var init_daemon_client = __esm({
315
- "src/daemon-client.ts"() {
316
- "use strict";
317
- import_node_net = require("node:net");
318
- import_node_child_process = require("node:child_process");
319
- import_node_fs4 = require("node:fs");
320
- import_node_os2 = require("node:os");
321
- import_node_path3 = require("node:path");
322
- init_client_version();
323
- init_stdin_inject();
324
- init_daemon_protocol();
325
- }
326
- });
327
30
 
328
31
  // src/boot.ts
329
- init_client_version();
330
32
  function requireSibling(name) {
331
33
  try {
332
34
  return require(name);
@@ -340,14 +42,6 @@ function requireSibling(name) {
340
42
  var verb = process.argv[2];
341
43
  if (process.argv.length === 3 && (verb === "--version" || verb === "-V")) {
342
44
  console.log(resolveClientVersion());
343
- } else if (verb === "saga") {
344
- void Promise.resolve().then(() => (init_daemon_client(), daemon_client_exports)).then(async (c) => {
345
- const r = await c.tryDaemonRun(process.argv.slice(2)).catch(() => ({ handled: false }));
346
- if (r.handled) process.exitCode = r.code;
347
- else requireSibling("./saga.cjs")?.runSagaCli("stdin" in r ? r.stdin : void 0);
348
- });
349
- } else if (verb === "daemon" && process.argv[3] === "--run" && process.argv.length === 4) {
350
- requireSibling("./saga.cjs")?.runDaemon();
351
45
  } else {
352
46
  requireSibling("./main.cjs");
353
47
  }