@muggleai/works 5.27.0-staging.242 → 5.27.0-staging.244
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-EK5DJBSY.js → chunk-EPIM27JX.js} +12 -4
- 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/plugin/hooks/README.md +2 -2
- package/dist/plugin/scripts/guardrail-record-stage-read.sh +2 -0
- package/dist/plugin/scripts/guardrails.mjs +213 -174
- package/dist/plugin/skills/CLAUDE.md +2 -0
- package/dist/plugin/skills/do/address-reviews.md +6 -0
- package/dist/plugin/skills/do/fix-ci.md +7 -0
- package/dist/plugin/skills/do/pre-flight.md +11 -0
- package/dist/plugin/skills/do/resolve-conflicts.md +7 -0
- package/dist/plugin/skills/muggle-do/SKILL.md +4 -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
- package/plugin/hooks/README.md +2 -2
- package/plugin/scripts/guardrail-record-stage-read.sh +2 -0
- package/plugin/scripts/guardrails.mjs +213 -174
- package/plugin/skills/CLAUDE.md +2 -0
- package/plugin/skills/do/address-reviews.md +6 -0
- package/plugin/skills/do/fix-ci.md +7 -0
- package/plugin/skills/do/pre-flight.md +11 -0
- package/plugin/skills/do/resolve-conflicts.md +7 -0
- package/plugin/skills/muggle-do/SKILL.md +4 -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.27.0-staging.
|
|
12
|
+
"version": "5.27.0-staging.244"
|
|
13
13
|
}
|
|
14
14
|
]
|
|
15
15
|
}
|
|
@@ -4719,6 +4719,7 @@ mcpToolNamePattern(
|
|
|
4719
4719
|
mcpToolNamePattern("muggle-local-telemetry-event-emit");
|
|
4720
4720
|
mcpToolNamePattern("muggle-remote-user-feedback-create");
|
|
4721
4721
|
var LOCK_POLL_INTERVAL_MS = 10;
|
|
4722
|
+
var UNRECORDED_LOCK_HOLDER_GRACE_MS = 1e4;
|
|
4722
4723
|
|
|
4723
4724
|
// src/guardrails/types.ts
|
|
4724
4725
|
var ProviderPrState = /* @__PURE__ */ ((ProviderPrState2) => {
|
|
@@ -5104,10 +5105,17 @@ function recordedHolder(lockPath) {
|
|
|
5104
5105
|
return void 0;
|
|
5105
5106
|
}
|
|
5106
5107
|
}
|
|
5107
|
-
function
|
|
5108
|
+
function isUnrecordedLockPastGrace(lockPath) {
|
|
5109
|
+
try {
|
|
5110
|
+
return Date.now() - statSync(lockPath).mtimeMs > UNRECORDED_LOCK_HOLDER_GRACE_MS;
|
|
5111
|
+
} catch {
|
|
5112
|
+
return false;
|
|
5113
|
+
}
|
|
5114
|
+
}
|
|
5115
|
+
function breakAbandonedLock(lockPath) {
|
|
5108
5116
|
const holder = recordedHolder(lockPath);
|
|
5109
|
-
|
|
5110
|
-
if (
|
|
5117
|
+
const isAbandoned = holder ? holder.host === hostname() && !isProcessAlive(holder.pid) : isUnrecordedLockPastGrace(lockPath);
|
|
5118
|
+
if (!isAbandoned) return;
|
|
5111
5119
|
try {
|
|
5112
5120
|
unlinkSync(lockPath);
|
|
5113
5121
|
} catch {
|
|
@@ -5132,7 +5140,7 @@ function withFileLock(lockPath, waitMs, run) {
|
|
|
5132
5140
|
})
|
|
5133
5141
|
);
|
|
5134
5142
|
} catch {
|
|
5135
|
-
|
|
5143
|
+
breakAbandonedLock(lockPath);
|
|
5136
5144
|
if (Date.now() >= deadline) return void 0;
|
|
5137
5145
|
pauseBetweenAttempts();
|
|
5138
5146
|
continue;
|
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-EPIM27JX.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-FI6VHHZN.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.27.0-staging.
|
|
4
|
+
"version": "5.27.0-staging.244",
|
|
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.27.0-staging.
|
|
3
|
+
"version": "5.27.0-staging.244",
|
|
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.27.0-staging.
|
|
5
|
+
"version": "5.27.0-staging.244",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Muggle AI",
|
|
8
8
|
"email": "support@muggle-ai.com"
|
package/dist/plugin/.mcp.json
CHANGED
|
@@ -26,7 +26,7 @@ Enforcement is reserved for the handoffs that were being skipped: the E2E accept
|
|
|
26
26
|
|
|
27
27
|
A recorder that *clears* an obligation — a walkthrough posted, a failure diagnosed, a test case classified — records only when the call did not visibly fail (`callOutcome.ts`). Recording from the request alone let a rejected `gh pr comment` mark the walkthrough posted, so the gate went quiet on a PR that never received it.
|
|
28
28
|
|
|
29
|
-
Each guardrail is a bash gate script in `../scripts/` holding a `guardrail_wants` pre-filter and the `guardrails.mjs` subcommand it feeds; the bundled `../scripts/guardrails.mjs` holds the decision logic (built from `src/guardrails/`, vitest-covered). The busy events — a shell command before and after it runs, and every turn end — register one `guardrail-dispatch.sh` command listing their gates, which reads the payload once, asks every gate's pre-filter in that one process, and starts Node once (`guardrails.mjs run <gates...>`) for just the gates that could fire, merging their responses. Rarer events call a gate script directly. Per-session state in `~/.muggle-ai/guardrails/<session_id>.json` tracks what fired. Any *failure* degrades to `{}` (allow) — a gate blocks only by an explicit, tested decision, never by accident; `guardrail-lib.sh` is the one place that falls back, and `run` isolates gates from each other.
|
|
29
|
+
Each guardrail is a bash gate script in `../scripts/` holding a `guardrail_wants` pre-filter and the `guardrails.mjs` subcommand it feeds; the bundled `../scripts/guardrails.mjs` holds the decision logic (built from `src/guardrails/`, vitest-covered). The busy events — a shell command before and after it runs, and every turn end — register one `guardrail-dispatch.sh` command listing their gates, which reads the payload once, asks every gate's pre-filter in that one process, and starts Node once (`guardrails.mjs run <gates...>`) for just the gates that could fire, merging their responses. Rarer events call a gate script directly. Per-session state in `~/.muggle-ai/guardrails/<session_id>.json` tracks what fired. Every hook commits to it under the session's lock, re-reading inside it, because of two hooks that read, change and write it unlocked the later erases the earlier; a hook that cannot take the lock within its wait saves its change beside the state file for a detached job to commit, and one with nothing new to record takes no lock. A lock is broken when its recorded holder is dead, or, when it names none (a hook killed between creating it and recording itself), once it is 10 seconds old. Any *failure* degrades to `{}` (allow) — a gate blocks only by an explicit, tested decision, never by accident; `guardrail-lib.sh` is the one place that falls back, and `run` isolates gates from each other.
|
|
30
30
|
|
|
31
31
|
Every `hooks.json` command enters through `../scripts/hook-entry.sh`, with the hook's script and arguments set as positional parameters first: `set -- guardrail-dispatch.sh guardrail-e2e-gate.sh …; . "${CLAUDE_PLUGIN_ROOT}/scripts/hook-entry.sh"`. Claude Code runs a hook command through Git Bash on Windows and through `/bin/sh` elsewhere. Inside Git Bash the entry sources the script into that same shell, so a hook costs the one Git Bash start Claude Code makes rather than a second `bash` with its own MSYS runtime init — measured at 0.3–1.2 s per firing on a loaded box. Anywhere else `/bin/sh` may be dash, so the entry is POSIX sh and hands the script to a bash of its own, as `bash "<script>"` did. A gate script tells it is the hook's own script — not one `guardrail-dispatch.sh` sourced for its pre-filter — through `guardrail_is_hook_script`, which reads the script path the entry records, or `$0` when bash ran the script.
|
|
32
32
|
|
|
@@ -42,7 +42,7 @@ Pre-filters are bash builtins only (`guardrail-lib.sh`), so an irrelevant event
|
|
|
42
42
|
| `PostToolUse` (AskUserQuestion) | `guardrail-offer-ran.sh` | record | a next-options offer ran while a terminal PR was pending | — | clear `terminalPending` — the only exit for the post-merge Stop gate |
|
|
43
43
|
| `PostToolUse` (Agent, Task) | `guardrail-record-delegation.sh` | record | a `muggle:acceptance-tester` was launched into the background — its response carries no finished report yet | — | append to `e2eDelegations` with the PR URLs its brief names; for a bounded window the E2E and debug-path gates hold off, and the walkthrough gate sets those PRs aside, so the session is never steered into a second browser run alongside the agent's. Shares the AskUserQuestion group's dispatch |
|
|
44
44
|
| `PostToolUse` (Skill + muggle telemetry-skill-emit) | `guardrail-skill-stages.sh` | advise | a skill this plugin ships was invoked; its `SKILL.md` frontmatter may declare `mandatoryStages`. Registered on the skill's own MCP announcement too, so the declaration still lands if the Skill payload ever stops carrying a name. A muggle-test announcement is also an E2E run (the clean SKIP verdict), recorded here alone, so the skill, its stages and the run land in one commit; a write that cannot take the session's lock in time is saved beside the state file and committed by a detached job once the lock frees | — | record `lastInvokedSkillName` + `mandatoryStages` (and `e2eRun` for a muggle-test announcement), and name the declared files as required reading at the moment of use |
|
|
45
|
-
| `PostToolUse` (Read) | `guardrail-record-stage-read.sh` | record | a markdown file under a `skills/` directory was opened | — | append to `stagesRead` — how the stage gate tells a stage that was read from one that was skipped |
|
|
45
|
+
| `PostToolUse` (Read) | `guardrail-record-stage-read.sh` | record | a markdown file under a `skills/` directory was opened | — | append to `stagesRead` — how the stage gate tells a stage that was read from one that was skipped; a route entry file in the plugin's skills tree, opened while a skill runs, also adds the `mandatoryStages` its frontmatter declares |
|
|
46
46
|
| `PostToolUse` (Bash + muggle telemetry-event-emit / user-feedback-create) | `guardrail-record-stage-signals.sh` | record | a Step 6f `pre-execution-classification` emit, debug-path evidence for a failed run (a `*-failure-classified\|resolved` emit or feedback naming it), or a `MUGGLE_STAGE_SKIP` / `MUGGLE_CLASSIFY_SKIP` / `MUGGLE_DEBUG_SKIP` marker | — | set `classifiedTestCaseIds` / `debuggedRuns` / the matching skip flag |
|
|
47
47
|
| `PostToolUse` (Bash) | `guardrail-record-comment-replies.sh` | record | an unresolved-thread fetch named review threads still awaiting an answer (classified by the `<!-- muggle-do:bot -->` marker, never the author login), a threaded reply the provider **confirmed** answered comments in one, or a `MUGGLE_REPLY_SKIP` marker deferred them | — | claim each thread and cover the comments answered, in the per-PR ledger beside the muggle-do slot |
|
|
48
48
|
| `PreToolUse` (Bash, `if` a command names `gh`/`glab`) | `guardrail-report-format.sh` | **enforce** | a `gh pr comment\|create\|edit` body — or a `gh api … issues/comments/<id>` PATCH editing one — reads like an E2E report but lacks the `build-pr-section` sentinel | — | **deny** — render via `muggle build-pr-section` instead |
|
|
@@ -4,6 +4,8 @@ set -uo pipefail
|
|
|
4
4
|
# stage-read observer (PostToolUse/Read, and PostToolUse/Bash through the
|
|
5
5
|
# dispatcher). Records that a file in the skills tree was opened, which is how
|
|
6
6
|
# the Stop gate tells a mandatory stage that was read from one that was skipped.
|
|
7
|
+
# A route's entry file that declares `mandatoryStages` adds that route's stages
|
|
8
|
+
# when it is opened during a skill's run.
|
|
7
9
|
# A host with no Read tool (Codex) opens stage files through the shell — `cat`,
|
|
8
10
|
# `sed -n` — so a shell command that prints one counts as a read too. Emits no
|
|
9
11
|
# directive.
|