@muggleai/works 5.28.0-staging.249 → 5.28.0-staging.250
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/.claude-plugin/marketplace.json +1 -1
- package/dist/{chunk-USALT4LJ.js → chunk-KGNRBL52.js} +25 -46
- package/dist/cli.js +1 -1
- package/dist/index.js +1 -1
- package/dist/plugin/.claude-plugin/plugin.json +1 -1
- package/dist/plugin/.codex-mcp.json +1 -1
- package/dist/plugin/.codex-plugin/plugin.json +1 -1
- package/dist/plugin/.cursor-plugin/plugin.json +1 -1
- package/dist/plugin/.mcp.json +1 -1
- package/dist/release-manifest.json +3 -3
- package/package.json +1 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/.codex-mcp.json +1 -1
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/plugin/.cursor-plugin/plugin.json +1 -1
- package/plugin/.mcp.json +1 -1
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"name": "muggleai",
|
|
10
10
|
"source": "./plugin",
|
|
11
11
|
"description": "Real-browser E2E acceptance for your coding agent: test the flows you changed and open the PR with screenshots. Built for flows other tools can't reach: managed test identities with live inboxes (magic links, email OTP and 2FA, verification mail, password resets), an encrypted secret store for login and test credentials, and a test graph that runs prerequisite flows first. Plain-English tests become replayable scripts on localhost or preview URLs.",
|
|
12
|
-
"version": "5.28.0-staging.
|
|
12
|
+
"version": "5.28.0-staging.250"
|
|
13
13
|
}
|
|
14
14
|
]
|
|
15
15
|
}
|
|
@@ -5,7 +5,7 @@ import { v4 } from 'uuid';
|
|
|
5
5
|
import { z, ZodError } from 'zod';
|
|
6
6
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
7
7
|
import * as fs from 'fs';
|
|
8
|
-
import { readFileSync, existsSync, rmSync, mkdirSync, readdirSync, createWriteStream, writeFileSync, statSync, readlinkSync, realpathSync, openSync, writeSync, closeSync, unlinkSync, copyFileSync, renameSync, appendFileSync, readSync
|
|
8
|
+
import { readFileSync, existsSync, rmSync, mkdirSync, readdirSync, createWriteStream, writeFileSync, statSync, readlinkSync, realpathSync, openSync, writeSync, closeSync, unlinkSync, copyFileSync, renameSync, appendFileSync, readSync } from 'fs';
|
|
9
9
|
import * as path from 'path';
|
|
10
10
|
import { dirname, resolve, join, basename } from 'path';
|
|
11
11
|
import { fileURLToPath, pathToFileURL } from 'url';
|
|
@@ -2400,8 +2400,6 @@ var TERMINAL_PR_RECHECK_MS = 6 * 60 * 6e4;
|
|
|
2400
2400
|
var WATCH_COMMAND_TIMEOUT_MS = 3e4;
|
|
2401
2401
|
var WATCH_COMMAND_MAX_BUFFER_BYTES = 64 * 1024 * 1024;
|
|
2402
2402
|
var SESSION_FILE_HEAD_BYTES = 64 * 1024;
|
|
2403
|
-
var SESSION_FILE_TAIL_BYTES = 64 * 1024;
|
|
2404
|
-
var USAGE_LIMIT_NOTICE_PATTERN = /\bhit your (?:session|usage|weekly|daily) limit\b|\busage limit reached\b/i;
|
|
2405
2403
|
var WATCH_LOCK_FILE = "watch.lock";
|
|
2406
2404
|
var WATCH_LOCK_WAIT_MS = 6e4;
|
|
2407
2405
|
var PR_WATCH_SLOTS_RELATIVE_PATH = ["muggle-do", "sessions"];
|
|
@@ -2434,6 +2432,8 @@ var PR_WATCH_LOOP_PATTERN = /pr-watch-loop\.sh\b.*?--slot\s+(?:"([^"]+)"|(\S+))/
|
|
|
2434
2432
|
var CLAUDE_SESSION_REGISTRY_DIR_NAME = "sessions";
|
|
2435
2433
|
var CLAUDE_PROJECTS_DIR_NAME = "projects";
|
|
2436
2434
|
var CLAUDE_INSTALLED_PLUGINS_RELATIVE_PATH = ["plugins", "installed_plugins.json"];
|
|
2435
|
+
var CLAUDE_GLOBAL_CONFIG_FILE_NAME = ".claude.json";
|
|
2436
|
+
var USAGE_WINDOW_EXHAUSTED_PERCENT = 100;
|
|
2437
2437
|
var RELOAD_PLUGIN_SCOPE = "user";
|
|
2438
2438
|
var MUGGLE_PLUGIN_ID = "muggleai@muggle-works";
|
|
2439
2439
|
var CODEX_ROLLOUT_PREFIX = "rollout-";
|
|
@@ -2487,6 +2487,7 @@ function resolveWatchPaths(env = process.env) {
|
|
|
2487
2487
|
claudeSessionRegistryDir: join(claudeConfigDir, CLAUDE_SESSION_REGISTRY_DIR_NAME),
|
|
2488
2488
|
claudeProjectsDir: join(claudeConfigDir, CLAUDE_PROJECTS_DIR_NAME),
|
|
2489
2489
|
claudeInstalledPluginsFile: join(claudeConfigDir, ...CLAUDE_INSTALLED_PLUGINS_RELATIVE_PATH),
|
|
2490
|
+
claudeGlobalConfigFile: join(env.CLAUDE_CONFIG_DIR || homedir(), CLAUDE_GLOBAL_CONFIG_FILE_NAME),
|
|
2490
2491
|
codexSessionsDir: join(codexHome, "sessions"),
|
|
2491
2492
|
muggleInstallLogFile: join(muggleDataDir, MUGGLE_INSTALL_LOG_FILE)
|
|
2492
2493
|
};
|
|
@@ -4638,21 +4639,6 @@ function readFileHead(filePath) {
|
|
|
4638
4639
|
if (fileDescriptor !== void 0) closeSync(fileDescriptor);
|
|
4639
4640
|
}
|
|
4640
4641
|
}
|
|
4641
|
-
function readFileTail(filePath) {
|
|
4642
|
-
let fileDescriptor;
|
|
4643
|
-
try {
|
|
4644
|
-
fileDescriptor = openSync(filePath, "r");
|
|
4645
|
-
const fileSize = fstatSync(fileDescriptor).size;
|
|
4646
|
-
const length = Math.min(fileSize, SESSION_FILE_TAIL_BYTES);
|
|
4647
|
-
const buffer = Buffer.alloc(length);
|
|
4648
|
-
const bytesRead = readSync(fileDescriptor, buffer, 0, length, fileSize - length);
|
|
4649
|
-
return buffer.subarray(0, bytesRead).toString("utf-8");
|
|
4650
|
-
} catch {
|
|
4651
|
-
return void 0;
|
|
4652
|
-
} finally {
|
|
4653
|
-
if (fileDescriptor !== void 0) closeSync(fileDescriptor);
|
|
4654
|
-
}
|
|
4655
|
-
}
|
|
4656
4642
|
function cwdFromSessionHead(head) {
|
|
4657
4643
|
const parts = head.match(/"cwd"\s*:\s*("(?:[^"\\]|\\.)*")/);
|
|
4658
4644
|
if (!parts) return void 0;
|
|
@@ -4747,36 +4733,12 @@ function findTranscriptPath(projectsDir, sessionId) {
|
|
|
4747
4733
|
}
|
|
4748
4734
|
return void 0;
|
|
4749
4735
|
}
|
|
4750
|
-
function assistantText(entry) {
|
|
4751
|
-
if (entry.type !== "assistant") return void 0;
|
|
4752
|
-
const content = entry.message?.content;
|
|
4753
|
-
if (typeof content === "string") return content;
|
|
4754
|
-
if (!Array.isArray(content)) return "";
|
|
4755
|
-
return content.map((part) => typeof part?.text === "string" ? part.text : "").join(" ");
|
|
4756
|
-
}
|
|
4757
4736
|
function findClaudeSessionCwd(projectsDir, sessionId) {
|
|
4758
4737
|
const transcriptPath = findTranscriptPath(projectsDir, sessionId);
|
|
4759
4738
|
if (transcriptPath === void 0) return void 0;
|
|
4760
4739
|
const head = readFileHead(transcriptPath);
|
|
4761
4740
|
return head === void 0 ? void 0 : cwdFromSessionHead(head);
|
|
4762
4741
|
}
|
|
4763
|
-
function isStoppedAtUsageLimit(projectsDir, sessionId) {
|
|
4764
|
-
const transcriptPath = findTranscriptPath(projectsDir, sessionId);
|
|
4765
|
-
const tail = transcriptPath === void 0 ? void 0 : readFileTail(transcriptPath);
|
|
4766
|
-
if (tail === void 0) return false;
|
|
4767
|
-
const lines = tail.split("\n");
|
|
4768
|
-
for (let index = lines.length - 1; index >= 0; index--) {
|
|
4769
|
-
let entry;
|
|
4770
|
-
try {
|
|
4771
|
-
entry = JSON.parse(lines[index]);
|
|
4772
|
-
} catch {
|
|
4773
|
-
continue;
|
|
4774
|
-
}
|
|
4775
|
-
const text = assistantText(entry);
|
|
4776
|
-
if (text !== void 0) return USAGE_LIMIT_NOTICE_PATTERN.test(text);
|
|
4777
|
-
}
|
|
4778
|
-
return false;
|
|
4779
|
-
}
|
|
4780
4742
|
var ROLLOUT_SESSION_ID = /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.jsonl$/i;
|
|
4781
4743
|
function sortedChildDirsDescending(dir) {
|
|
4782
4744
|
try {
|
|
@@ -5516,7 +5478,7 @@ function findRunningOwner(sessionsById, ownerSessionId) {
|
|
|
5516
5478
|
const ownerShortId = shortSessionId(ownerSessionId);
|
|
5517
5479
|
return sessionsById.get(ownerSessionId) ?? [...sessionsById.values()].find((session) => session.shortId === ownerShortId);
|
|
5518
5480
|
}
|
|
5519
|
-
function planWatcherRecoveries(assessments, attemptsByOwner, nowMs, isPollingDisabled, sessionsById = /* @__PURE__ */ new Map(),
|
|
5481
|
+
function planWatcherRecoveries(assessments, attemptsByOwner, nowMs, isPollingDisabled, sessionsById = /* @__PURE__ */ new Map(), isUsageLimitInForce = false) {
|
|
5520
5482
|
if (isPollingDisabled) return [];
|
|
5521
5483
|
const slugsByOwner = /* @__PURE__ */ new Map();
|
|
5522
5484
|
for (const assessment of assessments) {
|
|
@@ -5533,9 +5495,8 @@ function planWatcherRecoveries(assessments, attemptsByOwner, nowMs, isPollingDis
|
|
|
5533
5495
|
const recentAttemptsMs = (attemptsByOwner[ownerSessionId] ?? []).map((attemptedAt) => Date.parse(attemptedAt)).filter((attemptedAtMs) => !Number.isNaN(attemptedAtMs) && nowMs - attemptedAtMs < RECOVERY_ATTEMPT_WINDOW_MS);
|
|
5534
5496
|
const lastAttemptMs = Math.max(-Infinity, ...recentAttemptsMs);
|
|
5535
5497
|
const runningOwner = findRunningOwner(sessionsById, ownerSessionId);
|
|
5536
|
-
const isRunningAtUsageLimit = runningOwner !== void 0 && [ownerSessionId, runningOwner.sessionId].some((sessionId) => isStoppedAtUsageLimit2(sessionId));
|
|
5537
5498
|
let outcome = "resume-due" /* ResumeDue */;
|
|
5538
|
-
if (
|
|
5499
|
+
if (isUsageLimitInForce) outcome = "awaiting-usage-limit-reset" /* AwaitingUsageLimitReset */;
|
|
5539
5500
|
else if (recentAttemptsMs.length >= RECOVERY_MAX_ATTEMPTS) outcome = "attempts-exhausted" /* AttemptsExhausted */;
|
|
5540
5501
|
else if (nowMs - lastAttemptMs < RECOVERY_COOLDOWN_MS) outcome = "cooling-down" /* CoolingDown */;
|
|
5541
5502
|
else if (resumesPlanned >= MAX_RESUMES_PER_TICK) outcome = "deferred-by-tick-cap" /* DeferredByTickCap */;
|
|
@@ -5795,6 +5756,24 @@ function classifyTrackedProcesses(table, platform4) {
|
|
|
5795
5756
|
}
|
|
5796
5757
|
return tracked;
|
|
5797
5758
|
}
|
|
5759
|
+
function isUsageWindowExhausted(window, nowMs) {
|
|
5760
|
+
if (typeof window !== "object" || window === null) return false;
|
|
5761
|
+
const { utilization, resets_at: resetsAt, locked_reason: lockedReason } = window;
|
|
5762
|
+
const resetsAtMs = typeof resetsAt === "string" ? Date.parse(resetsAt) : Number.NaN;
|
|
5763
|
+
if (Number.isNaN(resetsAtMs) || resetsAtMs <= nowMs) return false;
|
|
5764
|
+
const isUtilizationExhausted = typeof utilization === "number" && utilization >= USAGE_WINDOW_EXHAUSTED_PERCENT;
|
|
5765
|
+
return isUtilizationExhausted || lockedReason !== null && lockedReason !== void 0;
|
|
5766
|
+
}
|
|
5767
|
+
function isClaudeUsageLimitInForce(claudeGlobalConfigFile, nowMs) {
|
|
5768
|
+
let usageWindows;
|
|
5769
|
+
try {
|
|
5770
|
+
const config = JSON.parse(readFileSync(claudeGlobalConfigFile, "utf-8"));
|
|
5771
|
+
usageWindows = config.cachedUsageUtilization?.utilization ?? {};
|
|
5772
|
+
} catch {
|
|
5773
|
+
return false;
|
|
5774
|
+
}
|
|
5775
|
+
return Object.values(usageWindows).some((usageWindow) => isUsageWindowExhausted(usageWindow, nowMs));
|
|
5776
|
+
}
|
|
5798
5777
|
function readJsonFile(filePath) {
|
|
5799
5778
|
try {
|
|
5800
5779
|
return JSON.parse(readFileSync(filePath, "utf-8"));
|
|
@@ -6055,7 +6034,7 @@ function runTickUnlocked(deps) {
|
|
|
6055
6034
|
deps.nowMs,
|
|
6056
6035
|
isPollingDisabled,
|
|
6057
6036
|
new Map(runningSessions.map((session) => [session.sessionId, session])),
|
|
6058
|
-
(
|
|
6037
|
+
isClaudeUsageLimitInForce(deps.paths.claudeGlobalConfigFile, deps.nowMs)
|
|
6059
6038
|
);
|
|
6060
6039
|
const executed = executeWatcherRecoveries(planned, recoveryAttemptsByOwner, {
|
|
6061
6040
|
runCommand: deps.runCommand,
|
package/dist/cli.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { src_exports as commands, createUnifiedMcpServer, server_exports as server } from './chunk-
|
|
1
|
+
export { src_exports as commands, createUnifiedMcpServer, server_exports as server } from './chunk-KGNRBL52.js';
|
|
2
2
|
export { createChildLogger, e2e_exports as e2e, getConfig, getLocalQaTools, getLogger, getQaTools, local_exports as localQa, mcp_exports as mcp, e2e_exports as qa, src_exports as shared } from './chunk-HBCASFGN.js';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "muggle",
|
|
3
3
|
"description": "Real-browser E2E acceptance for your coding agent: test the flows you changed and open the PR with screenshots. Built for flows other tools can't reach: managed test identities with live inboxes (magic links, email OTP and 2FA, verification mail, password resets), an encrypted secret store for login and test credentials, and a test graph that runs prerequisite flows first. Plain-English tests become replayable scripts on localhost or preview URLs.",
|
|
4
|
-
"version": "5.28.0-staging.
|
|
4
|
+
"version": "5.28.0-staging.250",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Muggle AI",
|
|
7
7
|
"email": "support@muggle-ai.com"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "muggle",
|
|
3
|
-
"version": "5.28.0-staging.
|
|
3
|
+
"version": "5.28.0-staging.250",
|
|
4
4
|
"description": "Real-browser E2E acceptance for your coding agent: test the flows you changed and open the PR with screenshots. Built for flows other tools can't reach: managed test identities with live inboxes (magic links, email OTP and 2FA, verification mail, password resets), an encrypted secret store for login and test credentials, and a test graph that runs prerequisite flows first. Plain-English tests become replayable scripts on localhost or preview URLs.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Muggle AI",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "muggle",
|
|
3
3
|
"displayName": "Muggle AI",
|
|
4
4
|
"description": "Real-browser E2E acceptance for your coding agent: test the flows you changed and open the PR with screenshots. Built for flows other tools can't reach: managed test identities with live inboxes (magic links, email OTP and 2FA, verification mail, password resets), an encrypted secret store for login and test credentials, and a test graph that runs prerequisite flows first. Plain-English tests become replayable scripts on localhost or preview URLs.",
|
|
5
|
-
"version": "5.28.0-staging.
|
|
5
|
+
"version": "5.28.0-staging.250",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Muggle AI",
|
|
8
8
|
"email": "support@muggle-ai.com"
|
package/dist/plugin/.mcp.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"release": "5.26.0",
|
|
3
|
-
"buildId": "run-
|
|
4
|
-
"commitSha": "
|
|
5
|
-
"buildTime": "2026-10-29T23:
|
|
3
|
+
"buildId": "run-250-1",
|
|
4
|
+
"commitSha": "ba9d56238c918b107aabc3037ceab011d08e3e85",
|
|
5
|
+
"buildTime": "2026-10-29T23:38:01Z",
|
|
6
6
|
"serviceName": "muggle-ai-works-mcp"
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@muggleai/works",
|
|
3
3
|
"mcpName": "io.github.multiplex-ai/muggle",
|
|
4
|
-
"version": "5.28.0-staging.
|
|
4
|
+
"version": "5.28.0-staging.250",
|
|
5
5
|
"description": "13 years of Microsoft hyperscale engineering, packaged as a harness for your AI coding agent.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "dist/index.js",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "muggle",
|
|
3
3
|
"description": "Real-browser E2E acceptance for your coding agent: test the flows you changed and open the PR with screenshots. Built for flows other tools can't reach: managed test identities with live inboxes (magic links, email OTP and 2FA, verification mail, password resets), an encrypted secret store for login and test credentials, and a test graph that runs prerequisite flows first. Plain-English tests become replayable scripts on localhost or preview URLs.",
|
|
4
|
-
"version": "5.28.0-staging.
|
|
4
|
+
"version": "5.28.0-staging.250",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Muggle AI",
|
|
7
7
|
"email": "support@muggle-ai.com"
|
package/plugin/.codex-mcp.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "muggle",
|
|
3
|
-
"version": "5.28.0-staging.
|
|
3
|
+
"version": "5.28.0-staging.250",
|
|
4
4
|
"description": "Real-browser E2E acceptance for your coding agent: test the flows you changed and open the PR with screenshots. Built for flows other tools can't reach: managed test identities with live inboxes (magic links, email OTP and 2FA, verification mail, password resets), an encrypted secret store for login and test credentials, and a test graph that runs prerequisite flows first. Plain-English tests become replayable scripts on localhost or preview URLs.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Muggle AI",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "muggle",
|
|
3
3
|
"displayName": "Muggle AI",
|
|
4
4
|
"description": "Real-browser E2E acceptance for your coding agent: test the flows you changed and open the PR with screenshots. Built for flows other tools can't reach: managed test identities with live inboxes (magic links, email OTP and 2FA, verification mail, password resets), an encrypted secret store for login and test credentials, and a test graph that runs prerequisite flows first. Plain-English tests become replayable scripts on localhost or preview URLs.",
|
|
5
|
-
"version": "5.28.0-staging.
|
|
5
|
+
"version": "5.28.0-staging.250",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Muggle AI",
|
|
8
8
|
"email": "support@muggle-ai.com"
|