@muggleai/works 5.18.0 → 5.19.0-staging.124
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-63RAPKGG.js → chunk-ECZAVRVK.js} +3 -3
- package/dist/{chunk-EKSYEVM2.js → chunk-KBOWKNKR.js} +62 -9
- package/dist/cli.js +2 -2
- package/dist/index.js +2 -2
- package/dist/plugin/skills/_shared/post-merge-cleanup.md +24 -5
- package/dist/plugin/skills/_shared/use-worktrees.md +2 -0
- package/dist/plugin/skills/do/cleanup.md +2 -0
- package/dist/release-manifest.json +3 -3
- package/dist/{src-52J7RTUV.js → src-3E7EWTIT.js} +1 -1
- package/package.json +2 -2
- package/plugin/skills/_shared/post-merge-cleanup.md +24 -5
- package/plugin/skills/_shared/use-worktrees.md +2 -0
- package/plugin/skills/do/cleanup.md +2 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { __export, getLogger, getConfig, createChildLogger, buildElectronAppReleaseAssetUrl, getActiveRuntimeTarget, getAuthService, hasApiKey, getElectronAppVersion, getElectronAppDir, getPlatformKey, reconcileProjectPreferences, getDataDir, PREFERENCES_FILE_NAME, isFirstRun, writePreferences, DEFAULT_PREFERENCES, isElectronAppInstalled, getElectronAppChecksums, getChecksumForPlatform, getElectronAppSignedFromVersion, getReleaseSignerIdentityUri, verifyFileChecksum, calculateFileChecksum, initTelemetry, Surface, ServiceName, track, EventName, getQaTools, getLocalQaTools, performLogout, assertDeviceCodeClientProvisioned, performLogin, toolRequiresAuth, getCallerCredentials, hasShownDisclosure, markDisclosureShown, getBundledElectronAppVersion, getElectronAppVersionSource, getCredentialsFilePath, buildElectronAppChecksumsUrl, __require, getDisclosureCopy, buildOnboardingPlan, applyOnboardingAnswers, needsOnboarding, OnboardingBlanketChoice, PreferenceKey } from './chunk-
|
|
1
|
+
import { __export, getLogger, getConfig, createChildLogger, buildElectronAppReleaseAssetUrl, getActiveRuntimeTarget, getAuthService, hasApiKey, getElectronAppVersion, getElectronAppDir, getPlatformKey, reconcileProjectPreferences, getDataDir, PREFERENCES_FILE_NAME, isFirstRun, writePreferences, DEFAULT_PREFERENCES, isElectronAppInstalled, getElectronAppChecksums, getChecksumForPlatform, getElectronAppSignedFromVersion, getReleaseSignerIdentityUri, verifyFileChecksum, calculateFileChecksum, initTelemetry, Surface, ServiceName, track, EventName, getQaTools, getLocalQaTools, performLogout, assertDeviceCodeClientProvisioned, performLogin, toolRequiresAuth, getCallerCredentials, hasShownDisclosure, markDisclosureShown, getBundledElectronAppVersion, getElectronAppVersionSource, getCredentialsFilePath, buildElectronAppChecksumsUrl, __require, getDisclosureCopy, buildOnboardingPlan, applyOnboardingAnswers, needsOnboarding, OnboardingBlanketChoice, PreferenceKey } from './chunk-KBOWKNKR.js';
|
|
2
2
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
3
3
|
import { ListToolsRequestSchema, CallToolRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
4
4
|
import { v4 } from 'uuid';
|
|
@@ -754,7 +754,7 @@ async function resolveGsScreenshotUrls(report, opts) {
|
|
|
754
754
|
if (gsUrls.length === 0) {
|
|
755
755
|
return report;
|
|
756
756
|
}
|
|
757
|
-
const mcps = await import('./src-
|
|
757
|
+
const mcps = await import('./src-3E7EWTIT.js');
|
|
758
758
|
const credentials = await mcps.getCallerCredentialsAsync();
|
|
759
759
|
if (!credentials.bearerToken && !credentials.apiKey) {
|
|
760
760
|
stderrWrite(
|
|
@@ -807,7 +807,7 @@ var withSentinel = (s) => s ? `${REPORT_SECTION_SENTINEL}
|
|
|
807
807
|
${s}` : s;
|
|
808
808
|
async function resolveDashboardBaseUrl(stderrWrite) {
|
|
809
809
|
try {
|
|
810
|
-
const mcps = await import('./src-
|
|
810
|
+
const mcps = await import('./src-3E7EWTIT.js');
|
|
811
811
|
return mcps.resolveActiveProfile().dashboardBaseUrl;
|
|
812
812
|
} catch (err) {
|
|
813
813
|
stderrWrite(
|
|
@@ -972,6 +972,13 @@ var TestResultStatus = /* @__PURE__ */ ((TestResultStatus2) => {
|
|
|
972
972
|
TestResultStatus2["Skipped"] = "skipped";
|
|
973
973
|
return TestResultStatus2;
|
|
974
974
|
})(TestResultStatus || {});
|
|
975
|
+
var DisplayResolution = /* @__PURE__ */ ((DisplayResolution2) => {
|
|
976
|
+
DisplayResolution2["R_0800x0600"] = "R_0800x0600";
|
|
977
|
+
DisplayResolution2["R_1024x0768"] = "R_1024x0768";
|
|
978
|
+
DisplayResolution2["R_0390x0844"] = "R_0390x0844";
|
|
979
|
+
DisplayResolution2["R_1920x1080"] = "R_1920x1080";
|
|
980
|
+
return DisplayResolution2;
|
|
981
|
+
})(DisplayResolution || {});
|
|
975
982
|
|
|
976
983
|
// packages/mcps/src/mcp/local/services/stored-auth-target.ts
|
|
977
984
|
function decodeJwtPayload(token) {
|
|
@@ -2423,6 +2430,22 @@ function applyLlmEnvOverrides(baseEnv, dataDirOverride2) {
|
|
|
2423
2430
|
return { env: baseEnv, appliedNames };
|
|
2424
2431
|
}
|
|
2425
2432
|
|
|
2433
|
+
// packages/mcps/src/mcp/local/services/display-resolution-constants.ts
|
|
2434
|
+
var DISPLAY_PARAMS_BY_RESOLUTION = {
|
|
2435
|
+
["R_0800x0600" /* R_0800x0600 */]: { browserWindowWidth: 800, browserWindowHeight: 600 },
|
|
2436
|
+
["R_1024x0768" /* R_1024x0768 */]: { browserWindowWidth: 1024, browserWindowHeight: 768 },
|
|
2437
|
+
["R_0390x0844" /* R_0390x0844 */]: { browserWindowWidth: 390, browserWindowHeight: 844 },
|
|
2438
|
+
["R_1920x1080" /* R_1920x1080 */]: { browserWindowWidth: 1920, browserWindowHeight: 1080 }
|
|
2439
|
+
};
|
|
2440
|
+
var DEFAULT_DISPLAY_RESOLUTION = "R_1920x1080" /* R_1920x1080 */;
|
|
2441
|
+
|
|
2442
|
+
// packages/mcps/src/mcp/local/services/display-resolution.ts
|
|
2443
|
+
function resolveDisplayParams(params) {
|
|
2444
|
+
const storedResolution = params.storedDisplayOptions?.[0];
|
|
2445
|
+
const effectiveResolution = params.requestedResolution ?? storedResolution ?? DEFAULT_DISPLAY_RESOLUTION;
|
|
2446
|
+
return DISPLAY_PARAMS_BY_RESOLUTION[effectiveResolution] ?? DISPLAY_PARAMS_BY_RESOLUTION[DEFAULT_DISPLAY_RESOLUTION];
|
|
2447
|
+
}
|
|
2448
|
+
|
|
2426
2449
|
// packages/mcps/src/mcp/local/services/replay-url-rewrite.ts
|
|
2427
2450
|
function rewriteActionScriptUrls(params) {
|
|
2428
2451
|
const { actionScript, originalUrl, localUrl } = params;
|
|
@@ -2515,7 +2538,13 @@ function buildGenerationActionScript(params) {
|
|
|
2515
2538
|
// projectId but NOT equal to it). The MCP has no client-side source for
|
|
2516
2539
|
// it, so leave it empty here; STM-on-local needs a backend resolver.
|
|
2517
2540
|
sharedTestMemoryId: "",
|
|
2518
|
-
runEnvironmentType: "local"
|
|
2541
|
+
runEnvironmentType: "local",
|
|
2542
|
+
// Sizes the studio's webview. Absent, the electron-app falls back to its
|
|
2543
|
+
// own hardcoded 1920x1080, which is why a phone-viewport run needs this.
|
|
2544
|
+
displayParams: resolveDisplayParams({
|
|
2545
|
+
requestedResolution: params.displayResolution,
|
|
2546
|
+
storedDisplayOptions: params.testCase.displayOptions
|
|
2547
|
+
})
|
|
2519
2548
|
},
|
|
2520
2549
|
goal: params.testCase.goal,
|
|
2521
2550
|
url: params.localUrl,
|
|
@@ -2573,7 +2602,12 @@ function buildReplayActionScript(params) {
|
|
|
2573
2602
|
// projectId but NOT equal to it). The MCP has no client-side source for
|
|
2574
2603
|
// it, so leave it empty here; STM-on-local needs a backend resolver.
|
|
2575
2604
|
sharedTestMemoryId: "",
|
|
2576
|
-
runEnvironmentType: "local"
|
|
2605
|
+
runEnvironmentType: "local",
|
|
2606
|
+
// Sizes the studio's webview. Absent, the electron-app falls back to its
|
|
2607
|
+
// own hardcoded 1920x1080, which is why a phone-viewport run needs this.
|
|
2608
|
+
displayParams: resolveDisplayParams({
|
|
2609
|
+
requestedResolution: params.displayResolution
|
|
2610
|
+
})
|
|
2577
2611
|
},
|
|
2578
2612
|
goal: params.testScript.name,
|
|
2579
2613
|
url: params.localUrl,
|
|
@@ -3182,7 +3216,8 @@ async function runTestGenerationLocked(params) {
|
|
|
3182
3216
|
localUrl,
|
|
3183
3217
|
runId,
|
|
3184
3218
|
localTestScriptId: localTestScript.id,
|
|
3185
|
-
ownerUserId: authContent.userId
|
|
3219
|
+
ownerUserId: authContent.userId,
|
|
3220
|
+
displayResolution: params.displayResolution
|
|
3186
3221
|
});
|
|
3187
3222
|
const inputFilePath = await writeTempFile({
|
|
3188
3223
|
filename: `${runId}_input.json`,
|
|
@@ -3369,7 +3404,8 @@ async function runReplayLocked(params) {
|
|
|
3369
3404
|
actionScript,
|
|
3370
3405
|
localUrl,
|
|
3371
3406
|
runId,
|
|
3372
|
-
ownerUserId: authContent.userId
|
|
3407
|
+
ownerUserId: authContent.userId,
|
|
3408
|
+
displayResolution: params.displayResolution
|
|
3373
3409
|
});
|
|
3374
3410
|
const inputFilePath = await writeTempFile({
|
|
3375
3411
|
filename: `${runId}_input.json`,
|
|
@@ -6714,6 +6750,7 @@ __export(local_exports, {
|
|
|
6714
6750
|
executeTool: () => executeTool,
|
|
6715
6751
|
getTool: () => getTool
|
|
6716
6752
|
});
|
|
6753
|
+
var DisplayResolutionSchema = z.nativeEnum(DisplayResolution);
|
|
6717
6754
|
var TestCaseDetailsSchema = z.object({
|
|
6718
6755
|
/** Cloud test case ID. */
|
|
6719
6756
|
id: MuggleEntityIdSchema.describe("Cloud test case ID (UUID)"),
|
|
@@ -6732,7 +6769,11 @@ var TestCaseDetailsSchema = z.object({
|
|
|
6732
6769
|
/** Cloud project ID (required for electron workflow context). */
|
|
6733
6770
|
projectId: MuggleEntityIdSchema.describe("Cloud project ID (UUID)"),
|
|
6734
6771
|
/** Cloud use case ID (required for electron workflow context). */
|
|
6735
|
-
useCaseId: MuggleEntityIdSchema.describe("Cloud use case ID (UUID)")
|
|
6772
|
+
useCaseId: MuggleEntityIdSchema.describe("Cloud use case ID (UUID)"),
|
|
6773
|
+
/** Resolutions stored on the cloud test case; the first entry sizes the run unless the caller names one. */
|
|
6774
|
+
displayOptions: z.array(DisplayResolutionSchema).optional().describe(
|
|
6775
|
+
"Resolutions stored on the cloud test case (from muggle-remote-test-case-get). The first entry sizes the browser unless displayResolution overrides it."
|
|
6776
|
+
)
|
|
6736
6777
|
});
|
|
6737
6778
|
var TestScriptDetailsSchema = z.object({
|
|
6738
6779
|
/** Cloud test script ID. */
|
|
@@ -6766,7 +6807,11 @@ var ExecuteTestGenerationInputSchema = z.object({
|
|
|
6766
6807
|
/** Clear all session storage (cookies, localStorage, etc.) before execution. Use for test cases that require a clean browser state, such as registration, login, or cookie consent flows. */
|
|
6767
6808
|
freshSession: z.boolean().optional().describe("Clear all session storage (cookies, localStorage, etc.) before execution. Use for test cases that require a clean browser state \u2014 e.g. registration, login, or cookie consent flows. Default: false."),
|
|
6768
6809
|
/** Mutation parameters providing variable context for this generation run — a string[] where each element is a plain-English instruction or a local file path for uploads (e.g. "Attach the image at C:\\Users\\user\\photo.jpg"). Matches the electron-app's string[] mutation file format. */
|
|
6769
|
-
mutations: z.array(z.string()).optional().describe(`Mutation parameters: string[] where each element is a plain-English instruction or a local file path (e.g. ["The post content should be 'Hello'", "Attach the image at C:\\\\Users\\\\user\\\\photo.jpg"]).`)
|
|
6810
|
+
mutations: z.array(z.string()).optional().describe(`Mutation parameters: string[] where each element is a plain-English instruction or a local file path (e.g. ["The post content should be 'Hello'", "Attach the image at C:\\\\Users\\\\user\\\\photo.jpg"]).`),
|
|
6811
|
+
/** Resolution for this run. Overrides `testCase.displayOptions`; both absent means 1920x1080. */
|
|
6812
|
+
displayResolution: DisplayResolutionSchema.optional().describe(
|
|
6813
|
+
"Browser resolution for this run, e.g. R_0390x0844 for a 390x844 phone viewport. Overrides testCase.displayOptions; defaults to R_1920x1080 when neither is given."
|
|
6814
|
+
)
|
|
6770
6815
|
});
|
|
6771
6816
|
var ExecuteReplayInputSchema = z.object({
|
|
6772
6817
|
/** Test script metadata from muggle-remote-test-script-get. */
|
|
@@ -6784,7 +6829,11 @@ var ExecuteReplayInputSchema = z.object({
|
|
|
6784
6829
|
/** Clear all session storage (cookies, localStorage, etc.) before execution. Use for test cases that require a clean browser state, such as registration, login, or cookie consent flows. */
|
|
6785
6830
|
freshSession: z.boolean().optional().describe("Clear all session storage (cookies, localStorage, etc.) before execution. Use for test cases that require a clean browser state \u2014 e.g. registration, login, or cookie consent flows. Default: false."),
|
|
6786
6831
|
/** Mutation parameters passed to the LLM step predictor — a string[] where each element is an instruction describing what varies this run. Supports plain-English instructions (e.g. "The post content should be 'Hello world'") and local file paths for uploads (e.g. "Attach the image at C:\\Users\\user\\photo.jpg"). Matches the electron-app's string[] mutation file format. When provided, the electron app uses LLM-driven step prediction instead of deterministic replay. */
|
|
6787
|
-
mutations: z.array(z.string()).optional().describe(`Mutation parameters: string[] where each element is a plain-English instruction or a local file path (e.g. ["The post content should be 'Hello'", "Attach the image at C:\\\\Users\\\\user\\\\photo.jpg"]).`)
|
|
6832
|
+
mutations: z.array(z.string()).optional().describe(`Mutation parameters: string[] where each element is a plain-English instruction or a local file path (e.g. ["The post content should be 'Hello'", "Attach the image at C:\\\\Users\\\\user\\\\photo.jpg"]).`),
|
|
6833
|
+
/** Resolution for this run. A test script carries no stored resolution, so this is replay's only sizing input. */
|
|
6834
|
+
displayResolution: DisplayResolutionSchema.optional().describe(
|
|
6835
|
+
"Browser resolution for this run, e.g. R_0390x0844 for a 390x844 phone viewport. Defaults to R_1920x1080."
|
|
6836
|
+
)
|
|
6788
6837
|
});
|
|
6789
6838
|
var CancelExecutionInputSchema = z.object({
|
|
6790
6839
|
runId: MuggleEntityIdSchema.describe("Run ID (UUID) to cancel")
|
|
@@ -7394,7 +7443,8 @@ var executeTestGenerationTool = {
|
|
|
7394
7443
|
mutations: input.mutations,
|
|
7395
7444
|
timeoutMs: input.timeoutMs,
|
|
7396
7445
|
showUi,
|
|
7397
|
-
freshSession: input.freshSession
|
|
7446
|
+
freshSession: input.freshSession,
|
|
7447
|
+
displayResolution: input.displayResolution
|
|
7398
7448
|
});
|
|
7399
7449
|
const content = [
|
|
7400
7450
|
"## Test Generation " + (generationRun.status === "passed" ? "Successful" : "Failed"),
|
|
@@ -7436,7 +7486,8 @@ var executeReplayTool = {
|
|
|
7436
7486
|
mutations: input.mutations,
|
|
7437
7487
|
timeoutMs: input.timeoutMs,
|
|
7438
7488
|
showUi,
|
|
7439
|
-
freshSession: input.freshSession
|
|
7489
|
+
freshSession: input.freshSession,
|
|
7490
|
+
displayResolution: input.displayResolution
|
|
7440
7491
|
});
|
|
7441
7492
|
const content = [
|
|
7442
7493
|
"## Test Replay " + (replayRun.status === "passed" ? "Successful" : "Failed"),
|
|
@@ -7864,6 +7915,8 @@ __export(local_exports2, {
|
|
|
7864
7915
|
CleanupSessionsInputSchema: () => CleanupSessionsInputSchema,
|
|
7865
7916
|
CloudMappingEntityType: () => CloudMappingEntityType,
|
|
7866
7917
|
DeviceCodePollStatus: () => DeviceCodePollStatus,
|
|
7918
|
+
DisplayResolution: () => DisplayResolution,
|
|
7919
|
+
DisplayResolutionSchema: () => DisplayResolutionSchema,
|
|
7867
7920
|
EmptyInputSchema: () => EmptyInputSchema2,
|
|
7868
7921
|
EventTelemetryEmitInputSchema: () => EventTelemetryEmitInputSchema,
|
|
7869
7922
|
ExecuteReplayInputSchema: () => ExecuteReplayInputSchema,
|
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-
|
|
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-
|
|
1
|
+
export { src_exports as commands, createUnifiedMcpServer, server_exports as server } from './chunk-ECZAVRVK.js';
|
|
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-KBOWKNKR.js';
|
|
@@ -6,11 +6,29 @@ On `always`, the steps below run as one pre-authorized sequence (no per-step pro
|
|
|
6
6
|
|
|
7
7
|
**Verify every step, assume none.** Each step states what proves it succeeded. A step whose side effect *usually* happens is not a step that ran — that assumption is how a branch survives a cleanup that reported success. The [report](#report) states verified state, never intent.
|
|
8
8
|
|
|
9
|
+
**A blocked step is reported, never handed back.** On `always` the gate already authorized this whole sequence, so nobody is sitting on the prompt: stopping to describe an obstacle and wait turns cleanup into a run that hangs until the user next looks at the terminal. Every step ends exactly one of three ways — done, `—` nothing to do, or `❌` with its reason in the [report](#report) and the sequence stopped. Waiting for the user is not a fourth ending. An obstacle you can clear yourself (standing in the directory you are about to remove) you clear and continue; one you cannot (a lock held by another process, a permission you lack) you record and stop. Print the report either way — the report is what tells the user cleanup is over.
|
|
10
|
+
|
|
9
11
|
## Preconditions
|
|
10
12
|
|
|
11
13
|
Confirm the PR is `MERGED` from provider state. A closed-unmerged PR keeps its branch and worktree: the work never landed, so deleting it destroys it.
|
|
12
14
|
|
|
13
|
-
## 1.
|
|
15
|
+
## 1. Leave the worktree
|
|
16
|
+
|
|
17
|
+
Only if a worktree was used. This runs **before** anything is deleted — the working directory is the precondition the rest of the sequence stands on.
|
|
18
|
+
|
|
19
|
+
`git worktree remove` refuses to remove the worktree the command is standing in, and a shell whose directory is deleted out from under it fails everything afterwards with `getcwd`/`No such file or directory`. Both surface as "cleanup can't proceed", and the reflex — announcing that you are inside the directory and waiting for the user — is the stall this step exists to prevent. Moving is yours to do; it needs no one's permission, and the gate already gave it.
|
|
20
|
+
|
|
21
|
+
1. **Resolve the anchor** — the repo's main working tree, which removing a worktree never touches:
|
|
22
|
+
```bash
|
|
23
|
+
git -C {worktreePath} worktree list --porcelain # the first `worktree ` line is the main tree
|
|
24
|
+
```
|
|
25
|
+
2. **Compare resolved paths, not strings.** Resolve the current directory and `{worktreePath}` through symlinks before asking whether one contains the other; `/var/…` against `/private/var/…` reads as "already outside" and the removal then fails anyway. Match on path segments, so a sibling like `<name>-old` is not mistaken for being inside `<name>`.
|
|
26
|
+
3. If the cwd is at or under `{worktreePath}`, move to the anchor now.
|
|
27
|
+
4. Run every remaining command against an explicit repo — `git -C <anchor> …` — so no later step walks back into the tree it is deleting.
|
|
28
|
+
|
|
29
|
+
**Verify:** the resolved cwd is outside `{worktreePath}` **and** still exists (a directory that resolves, not just a string). A cwd that was deleted rather than left is the same stall arriving one step later.
|
|
30
|
+
|
|
31
|
+
## 2. Remove the worktree — link-safe
|
|
14
32
|
|
|
15
33
|
Only if a worktree was used.
|
|
16
34
|
|
|
@@ -26,7 +44,7 @@ A worktree's dependency dir (`node_modules`, and nested workspace copies) is oft
|
|
|
26
44
|
|
|
27
45
|
**Verify:** the path is gone, it no longer appears in `git worktree list`, **and** the shared dependency tree the links pointed at still exists. That last check is the one that catches a link-follow.
|
|
28
46
|
|
|
29
|
-
##
|
|
47
|
+
## 3. Delete the local branch
|
|
30
48
|
|
|
31
49
|
**Skip entirely when no worktree was used** — the branch is then the user's live checkout, and a checked-out branch must never be deleted.
|
|
32
50
|
|
|
@@ -39,7 +57,7 @@ Do not reach for `-D` on faith. Replace the ancestry check with a content check:
|
|
|
39
57
|
|
|
40
58
|
**Verify:** the branch is absent from `git branch --list`.
|
|
41
59
|
|
|
42
|
-
##
|
|
60
|
+
## 4. Delete the remote branch
|
|
43
61
|
|
|
44
62
|
**A provider that auto-deletes the head branch on merge is a setting, not a guarantee.** It can be off for the repo, off for a fork, or simply not fire. Treat auto-delete as something to detect, never as this step having run.
|
|
45
63
|
|
|
@@ -48,7 +66,7 @@ Do not reach for `-D` on faith. Replace the ancestry check with a content check:
|
|
|
48
66
|
|
|
49
67
|
**Verify:** querying the ref returns not-found.
|
|
50
68
|
|
|
51
|
-
##
|
|
69
|
+
## 5. Clear the session slot
|
|
52
70
|
|
|
53
71
|
The slot is `~/.muggle-ai/muggle-do/sessions/<slug>/` — the home directory, not the project.
|
|
54
72
|
|
|
@@ -56,7 +74,7 @@ Clear it only when `prs.json` records a terminal state. A slot for a still-open
|
|
|
56
74
|
|
|
57
75
|
**Verify:** the slot directory is gone, and no non-terminal slot was touched.
|
|
58
76
|
|
|
59
|
-
##
|
|
77
|
+
## 6. Clear this run's prepare artifacts
|
|
60
78
|
|
|
61
79
|
The PID tracker and per-service logs written during environment prep — `/tmp/muggle-test-prepare.json` and `/tmp/muggle-prepare-*.log`.
|
|
62
80
|
|
|
@@ -75,6 +93,7 @@ Cleanup — <slug> (PR #<n>, merged)
|
|
|
75
93
|
|
|
76
94
|
| Step | Result |
|
|
77
95
|
|:----------------------|:------------------------------------------------|
|
|
96
|
+
| Left the worktree | ✅ moved to <repo root> (cwd was inside) |
|
|
78
97
|
| Worktree removed | ✅ .claude/worktrees/<name> (shared deps intact) |
|
|
79
98
|
| Local branch deleted | ✅ users/<user>/<branch> |
|
|
80
99
|
| Remote branch deleted | ✅ (already gone — provider auto-delete) |
|
|
@@ -51,3 +51,5 @@ Use this for feature development, local validation, and PR iteration.
|
|
|
51
51
|
|
|
52
52
|
After merge, remove the worktree.
|
|
53
53
|
See [`post-merge-cleanup.md`](post-merge-cleanup.md).
|
|
54
|
+
|
|
55
|
+
**Never remove a worktree you are standing in.** Step back to the repo's main working tree first — `git worktree remove` refuses from inside, and a deleted working directory breaks every command that follows. Relocating is part of teardown, not a reason to stop and ask.
|
|
@@ -13,3 +13,5 @@ Invoked by `/muggle-do` when the watcher forwards a PR's terminal state. On `mer
|
|
|
13
13
|
3. **Teardown (`merged` only).** When the PR is `merged`, run [`../_shared/post-merge-cleanup.md`](../_shared/post-merge-cleanup.md) with `{worktreePath}` and `{branch}`. That file owns the teardown sequence **and its safety rules** — including skipping worktree-remove and local branch deletion when no worktree was used. This stage adds no teardown logic of its own. On `closed`, skip teardown — the branch and any worktree stay intact.
|
|
14
14
|
4. Append a cleanup line to the session's `followup.log`, recording whether teardown ran.
|
|
15
15
|
5. Suggest the next step per [`next-step.md`](next-step.md), passing whether teardown ran. This is the stage's last action.
|
|
16
|
+
|
|
17
|
+
**Teardown never returns a question.** It finishes with its report — every step done, skipped, or blocked-with-a-reason — so steps 4 and 5 always run. A teardown that appears to be waiting on the user has stalled mid-sequence; the stage is not complete until the report and the next-step suggestion are both printed.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"release": "5.18.0",
|
|
3
|
-
"buildId": "run-
|
|
4
|
-
"commitSha": "
|
|
5
|
-
"buildTime": "2026-09-19T08:
|
|
3
|
+
"buildId": "run-124-1",
|
|
4
|
+
"commitSha": "fd774f165bbdddcd5d9b6707295e6efb6c63fbd5",
|
|
5
|
+
"buildTime": "2026-09-19T08:45:18Z",
|
|
6
6
|
"serviceName": "muggle-ai-works-mcp"
|
|
7
7
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { DEFAULT_PREFERENCES, ElectronAppReleaseStream, ONBOARDING_BLANKET_OPTIONS, ONBOARDING_CHOICE_GROUPS, ONBOARDING_MAX_OFFERS, ONBOARDING_PRIMER_BULLETS, ONBOARDING_PRIMER_HEADLINE, ONBOARDING_TOGGLE_GROUPS, ONBOARDING_TOGGLE_PROMPT, ONBOARDING_UNSELECTED_TOGGLE_VALUE, OnboardingBlanketChoice, OnboardingGroupKind, PREFERENCES_FILE_NAME, PREFERENCES_PROJECT_DIR_NAME, PREFERENCES_SCHEMA, PREFERENCES_VERSION, PREFERENCE_ALLOWED_VALUES, PreferenceKey, PreferenceValue, ProjectPreferencesReconcileOutcome, RuntimeTarget, WATCHER_LIFETIME_SECONDS, WATCHER_LIFETIME_UNBOUNDED_SECONDS, applyOnboardingAnswers, assertDeviceCodeClientProvisioned, buildElectronAppChecksumsUrl, buildElectronAppReleaseAssetUrl, buildElectronAppReleaseTag, buildOnboardingPlan, calculateFileChecksum, completeOnboarding, createApiKeyWithToken, createChildLogger, deleteApiKeyData, deleteCredentials, e2e_exports as e2e, formatPreferencesOneLiner, getActiveElectronAppReleaseStream, getActiveRuntimeTarget, getApiKey, getApiKeyFilePath, getAuthService, getBundledElectronAppVersion, getCallerCredentials, getCallerCredentialsAsync, getChecksumForPlatform, getConfig, getCredentialsFilePath, getDataDir, getDownloadBaseUrl, getElectronAppChecksums, getElectronAppDir, getElectronAppReleaseTagPrefix, getElectronAppSignedFromVersion, getElectronAppVersion, getElectronAppVersionSource, getLocalQaTools, getLogger, getOnboardingToggleKeys, getPlatformKey, getQaTools, getReleaseSignerIdentityUri, getValidApiKeyData, getValidCredentials, hasApiKey, isElectronAppInstalled, isFirstRun, loadApiKeyData, loadCredentials, local_exports as localQa, markOnboardingCompleted, mcp_exports as mcp, needsOnboarding, openBrowserUrl, performLogin, performLogout, pollDeviceCode, e2e_exports as qa, readPreferencesMetadata, reconcileProjectPreferences, recordOnboardingSkip, resetConfig, resetLogger, resetPreference, resolveActiveProfile, resolveActiveReleaseStream, resolveActiveReleaseTagPrefix, resolveBlanketPreferences, resolveElectronAppPathOrNull, resolveOnboardingAnswers, resolvePreferences, resolveRuntimeTarget, resolveTogglePreferences, saveApiKey, saveApiKeyData, saveCredentials, startDeviceCodeFlow, toolRequiresAuth, validatePreference, verifyFileChecksum, writePreferences, writePreferencesWithMetadata } from './chunk-
|
|
1
|
+
export { DEFAULT_PREFERENCES, ElectronAppReleaseStream, ONBOARDING_BLANKET_OPTIONS, ONBOARDING_CHOICE_GROUPS, ONBOARDING_MAX_OFFERS, ONBOARDING_PRIMER_BULLETS, ONBOARDING_PRIMER_HEADLINE, ONBOARDING_TOGGLE_GROUPS, ONBOARDING_TOGGLE_PROMPT, ONBOARDING_UNSELECTED_TOGGLE_VALUE, OnboardingBlanketChoice, OnboardingGroupKind, PREFERENCES_FILE_NAME, PREFERENCES_PROJECT_DIR_NAME, PREFERENCES_SCHEMA, PREFERENCES_VERSION, PREFERENCE_ALLOWED_VALUES, PreferenceKey, PreferenceValue, ProjectPreferencesReconcileOutcome, RuntimeTarget, WATCHER_LIFETIME_SECONDS, WATCHER_LIFETIME_UNBOUNDED_SECONDS, applyOnboardingAnswers, assertDeviceCodeClientProvisioned, buildElectronAppChecksumsUrl, buildElectronAppReleaseAssetUrl, buildElectronAppReleaseTag, buildOnboardingPlan, calculateFileChecksum, completeOnboarding, createApiKeyWithToken, createChildLogger, deleteApiKeyData, deleteCredentials, e2e_exports as e2e, formatPreferencesOneLiner, getActiveElectronAppReleaseStream, getActiveRuntimeTarget, getApiKey, getApiKeyFilePath, getAuthService, getBundledElectronAppVersion, getCallerCredentials, getCallerCredentialsAsync, getChecksumForPlatform, getConfig, getCredentialsFilePath, getDataDir, getDownloadBaseUrl, getElectronAppChecksums, getElectronAppDir, getElectronAppReleaseTagPrefix, getElectronAppSignedFromVersion, getElectronAppVersion, getElectronAppVersionSource, getLocalQaTools, getLogger, getOnboardingToggleKeys, getPlatformKey, getQaTools, getReleaseSignerIdentityUri, getValidApiKeyData, getValidCredentials, hasApiKey, isElectronAppInstalled, isFirstRun, loadApiKeyData, loadCredentials, local_exports as localQa, markOnboardingCompleted, mcp_exports as mcp, needsOnboarding, openBrowserUrl, performLogin, performLogout, pollDeviceCode, e2e_exports as qa, readPreferencesMetadata, reconcileProjectPreferences, recordOnboardingSkip, resetConfig, resetLogger, resetPreference, resolveActiveProfile, resolveActiveReleaseStream, resolveActiveReleaseTagPrefix, resolveBlanketPreferences, resolveElectronAppPathOrNull, resolveOnboardingAnswers, resolvePreferences, resolveRuntimeTarget, resolveTogglePreferences, saveApiKey, saveApiKeyData, saveCredentials, startDeviceCodeFlow, toolRequiresAuth, validatePreference, verifyFileChecksum, writePreferences, writePreferencesWithMetadata } from './chunk-KBOWKNKR.js';
|
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.
|
|
4
|
+
"version": "5.19.0-staging.124",
|
|
5
5
|
"description": "Ship quality products with AI-powered E2E acceptance testing that validates your web app like a real user — from Claude Code and Cursor to PR.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "dist/index.js",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"muggleConfig": {
|
|
55
55
|
"electronAppVersion": "1.10.6",
|
|
56
56
|
"downloadBaseUrl": "https://github.com/multiplex-ai/muggle-ai-works/releases/download",
|
|
57
|
-
"runtimeTargetDefault": "
|
|
57
|
+
"runtimeTargetDefault": "staging",
|
|
58
58
|
"checksumsByStream": {
|
|
59
59
|
"production": {
|
|
60
60
|
"win32-x64": "c20acdc2fd7a05039c62f9e5b079e3068d1b3a23a1b3b37b75e2a650b5401de6",
|
|
@@ -6,11 +6,29 @@ On `always`, the steps below run as one pre-authorized sequence (no per-step pro
|
|
|
6
6
|
|
|
7
7
|
**Verify every step, assume none.** Each step states what proves it succeeded. A step whose side effect *usually* happens is not a step that ran — that assumption is how a branch survives a cleanup that reported success. The [report](#report) states verified state, never intent.
|
|
8
8
|
|
|
9
|
+
**A blocked step is reported, never handed back.** On `always` the gate already authorized this whole sequence, so nobody is sitting on the prompt: stopping to describe an obstacle and wait turns cleanup into a run that hangs until the user next looks at the terminal. Every step ends exactly one of three ways — done, `—` nothing to do, or `❌` with its reason in the [report](#report) and the sequence stopped. Waiting for the user is not a fourth ending. An obstacle you can clear yourself (standing in the directory you are about to remove) you clear and continue; one you cannot (a lock held by another process, a permission you lack) you record and stop. Print the report either way — the report is what tells the user cleanup is over.
|
|
10
|
+
|
|
9
11
|
## Preconditions
|
|
10
12
|
|
|
11
13
|
Confirm the PR is `MERGED` from provider state. A closed-unmerged PR keeps its branch and worktree: the work never landed, so deleting it destroys it.
|
|
12
14
|
|
|
13
|
-
## 1.
|
|
15
|
+
## 1. Leave the worktree
|
|
16
|
+
|
|
17
|
+
Only if a worktree was used. This runs **before** anything is deleted — the working directory is the precondition the rest of the sequence stands on.
|
|
18
|
+
|
|
19
|
+
`git worktree remove` refuses to remove the worktree the command is standing in, and a shell whose directory is deleted out from under it fails everything afterwards with `getcwd`/`No such file or directory`. Both surface as "cleanup can't proceed", and the reflex — announcing that you are inside the directory and waiting for the user — is the stall this step exists to prevent. Moving is yours to do; it needs no one's permission, and the gate already gave it.
|
|
20
|
+
|
|
21
|
+
1. **Resolve the anchor** — the repo's main working tree, which removing a worktree never touches:
|
|
22
|
+
```bash
|
|
23
|
+
git -C {worktreePath} worktree list --porcelain # the first `worktree ` line is the main tree
|
|
24
|
+
```
|
|
25
|
+
2. **Compare resolved paths, not strings.** Resolve the current directory and `{worktreePath}` through symlinks before asking whether one contains the other; `/var/…` against `/private/var/…` reads as "already outside" and the removal then fails anyway. Match on path segments, so a sibling like `<name>-old` is not mistaken for being inside `<name>`.
|
|
26
|
+
3. If the cwd is at or under `{worktreePath}`, move to the anchor now.
|
|
27
|
+
4. Run every remaining command against an explicit repo — `git -C <anchor> …` — so no later step walks back into the tree it is deleting.
|
|
28
|
+
|
|
29
|
+
**Verify:** the resolved cwd is outside `{worktreePath}` **and** still exists (a directory that resolves, not just a string). A cwd that was deleted rather than left is the same stall arriving one step later.
|
|
30
|
+
|
|
31
|
+
## 2. Remove the worktree — link-safe
|
|
14
32
|
|
|
15
33
|
Only if a worktree was used.
|
|
16
34
|
|
|
@@ -26,7 +44,7 @@ A worktree's dependency dir (`node_modules`, and nested workspace copies) is oft
|
|
|
26
44
|
|
|
27
45
|
**Verify:** the path is gone, it no longer appears in `git worktree list`, **and** the shared dependency tree the links pointed at still exists. That last check is the one that catches a link-follow.
|
|
28
46
|
|
|
29
|
-
##
|
|
47
|
+
## 3. Delete the local branch
|
|
30
48
|
|
|
31
49
|
**Skip entirely when no worktree was used** — the branch is then the user's live checkout, and a checked-out branch must never be deleted.
|
|
32
50
|
|
|
@@ -39,7 +57,7 @@ Do not reach for `-D` on faith. Replace the ancestry check with a content check:
|
|
|
39
57
|
|
|
40
58
|
**Verify:** the branch is absent from `git branch --list`.
|
|
41
59
|
|
|
42
|
-
##
|
|
60
|
+
## 4. Delete the remote branch
|
|
43
61
|
|
|
44
62
|
**A provider that auto-deletes the head branch on merge is a setting, not a guarantee.** It can be off for the repo, off for a fork, or simply not fire. Treat auto-delete as something to detect, never as this step having run.
|
|
45
63
|
|
|
@@ -48,7 +66,7 @@ Do not reach for `-D` on faith. Replace the ancestry check with a content check:
|
|
|
48
66
|
|
|
49
67
|
**Verify:** querying the ref returns not-found.
|
|
50
68
|
|
|
51
|
-
##
|
|
69
|
+
## 5. Clear the session slot
|
|
52
70
|
|
|
53
71
|
The slot is `~/.muggle-ai/muggle-do/sessions/<slug>/` — the home directory, not the project.
|
|
54
72
|
|
|
@@ -56,7 +74,7 @@ Clear it only when `prs.json` records a terminal state. A slot for a still-open
|
|
|
56
74
|
|
|
57
75
|
**Verify:** the slot directory is gone, and no non-terminal slot was touched.
|
|
58
76
|
|
|
59
|
-
##
|
|
77
|
+
## 6. Clear this run's prepare artifacts
|
|
60
78
|
|
|
61
79
|
The PID tracker and per-service logs written during environment prep — `/tmp/muggle-test-prepare.json` and `/tmp/muggle-prepare-*.log`.
|
|
62
80
|
|
|
@@ -75,6 +93,7 @@ Cleanup — <slug> (PR #<n>, merged)
|
|
|
75
93
|
|
|
76
94
|
| Step | Result |
|
|
77
95
|
|:----------------------|:------------------------------------------------|
|
|
96
|
+
| Left the worktree | ✅ moved to <repo root> (cwd was inside) |
|
|
78
97
|
| Worktree removed | ✅ .claude/worktrees/<name> (shared deps intact) |
|
|
79
98
|
| Local branch deleted | ✅ users/<user>/<branch> |
|
|
80
99
|
| Remote branch deleted | ✅ (already gone — provider auto-delete) |
|
|
@@ -51,3 +51,5 @@ Use this for feature development, local validation, and PR iteration.
|
|
|
51
51
|
|
|
52
52
|
After merge, remove the worktree.
|
|
53
53
|
See [`post-merge-cleanup.md`](post-merge-cleanup.md).
|
|
54
|
+
|
|
55
|
+
**Never remove a worktree you are standing in.** Step back to the repo's main working tree first — `git worktree remove` refuses from inside, and a deleted working directory breaks every command that follows. Relocating is part of teardown, not a reason to stop and ask.
|
|
@@ -13,3 +13,5 @@ Invoked by `/muggle-do` when the watcher forwards a PR's terminal state. On `mer
|
|
|
13
13
|
3. **Teardown (`merged` only).** When the PR is `merged`, run [`../_shared/post-merge-cleanup.md`](../_shared/post-merge-cleanup.md) with `{worktreePath}` and `{branch}`. That file owns the teardown sequence **and its safety rules** — including skipping worktree-remove and local branch deletion when no worktree was used. This stage adds no teardown logic of its own. On `closed`, skip teardown — the branch and any worktree stay intact.
|
|
14
14
|
4. Append a cleanup line to the session's `followup.log`, recording whether teardown ran.
|
|
15
15
|
5. Suggest the next step per [`next-step.md`](next-step.md), passing whether teardown ran. This is the stage's last action.
|
|
16
|
+
|
|
17
|
+
**Teardown never returns a question.** It finishes with its report — every step done, skipped, or blocked-with-a-reason — so steps 4 and 5 always run. A teardown that appears to be waiting on the user has stalled mid-sequence; the stage is not complete until the report and the next-step suggestion are both printed.
|