@muggleai/works 4.6.1 → 4.8.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 +1 -6
- package/dist/{chunk-2FVSZ5LQ.js → chunk-2ZDLQAO4.js} +80 -22
- package/dist/{chunk-HDEZDEM6.js → chunk-OUI734ME.js} +4 -1
- package/dist/cli.js +2 -2
- package/dist/index.js +2 -2
- package/dist/plugin/.claude-plugin/plugin.json +1 -1
- package/dist/plugin/.cursor-plugin/plugin.json +1 -1
- package/dist/plugin/skills/muggle-works-npm-release/SKILL.md +198 -0
- package/dist/release-manifest.json +4 -4
- package/dist/{src-TX2KXI26.js → src-2IDMKEJ5.js} +1 -1
- package/package.json +6 -6
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/.cursor-plugin/plugin.json +1 -1
- package/plugin/skills/muggle-works-npm-release/SKILL.md +198 -0
package/README.md
CHANGED
|
@@ -554,12 +554,7 @@ CI/CD and publishing
|
|
|
554
554
|
| `verify-end-user-upgrade.yml` | Weekly + manual | Existing-user upgrade validation (cleanup + re-download + health checks) |
|
|
555
555
|
| `publish-works-to-npm.yml` | Tag `v*` or manual | Verify (including release checksums), audit, smoke-install, publish to npm |
|
|
556
556
|
|
|
557
|
-
|
|
558
|
-
```bash
|
|
559
|
-
git tag v<version> && git push --tags
|
|
560
|
-
# publish-works-to-npm.yml handles the rest
|
|
561
|
-
```
|
|
562
|
-
|
|
557
|
+
**Publishing `@muggleai/works`:** use the repo-level skill **`plugin/skills/muggle-works-npm-release/SKILL.md`** (bump + `pnpm run sync:versions`, local verify, `chore(release)` PR, merge, then `workflow_dispatch` with an explicit `version`). Do not rely on tagging alone while `package.json` / marketplace manifests on `master` are still old — CI can publish a version that does not match the checked-in manifests. Tag `v*` push remains a valid workflow trigger when it matches the merged release commit.
|
|
563
558
|
|
|
564
559
|
Release tag strategy
|
|
565
560
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { __export, getLogger, getConfig, createChildLogger, buildElectronAppReleaseAssetUrl, getAuthService, hasApiKey, getElectronAppVersion, getElectronAppDir, getPlatformKey, isElectronAppInstalled, getElectronAppChecksums, getChecksumForPlatform, verifyFileChecksum, calculateFileChecksum, getQaTools, getLocalQaTools, performLogout, performLogin, toolRequiresAuth, getCallerCredentials, getDataDir, getBundledElectronAppVersion, getElectronAppVersionSource, getCredentialsFilePath, buildElectronAppChecksumsUrl, __require } from './chunk-
|
|
1
|
+
import { __export, getLogger, getConfig, createChildLogger, buildElectronAppReleaseAssetUrl, getAuthService, hasApiKey, getElectronAppVersion, getElectronAppDir, getPlatformKey, isElectronAppInstalled, getElectronAppChecksums, getChecksumForPlatform, verifyFileChecksum, calculateFileChecksum, getQaTools, getLocalQaTools, performLogout, performLogin, toolRequiresAuth, getCallerCredentials, getDataDir, getBundledElectronAppVersion, getElectronAppVersionSource, getCredentialsFilePath, buildElectronAppChecksumsUrl, __require } from './chunk-OUI734ME.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';
|
|
@@ -356,12 +356,41 @@ function endingScreenshot(test) {
|
|
|
356
356
|
}
|
|
357
357
|
return test.steps[test.steps.length - 1];
|
|
358
358
|
}
|
|
359
|
+
function defaultEndingCaption(test) {
|
|
360
|
+
if (test.status === "failed") {
|
|
361
|
+
return `Failure at step ${test.failureStepIndex}`;
|
|
362
|
+
}
|
|
363
|
+
return "Final page after the test completed";
|
|
364
|
+
}
|
|
365
|
+
function endingFrame(test) {
|
|
366
|
+
if (test.endingScreenshotUrl) {
|
|
367
|
+
return {
|
|
368
|
+
url: test.endingScreenshotUrl,
|
|
369
|
+
caption: test.endingScreenshotCaption ?? defaultEndingCaption(test)
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
const step = endingScreenshot(test);
|
|
373
|
+
if (!step) {
|
|
374
|
+
return null;
|
|
375
|
+
}
|
|
376
|
+
return {
|
|
377
|
+
url: step.screenshotUrl,
|
|
378
|
+
caption: test.endingScreenshotCaption ?? defaultEndingCaption(test)
|
|
379
|
+
};
|
|
380
|
+
}
|
|
359
381
|
function fullSizeImage(url, alt) {
|
|
360
382
|
return `<a href="${url}"><img src="${url}" width="${DETAIL_IMAGE_WIDTH}" alt="${alt}"></a>`;
|
|
361
383
|
}
|
|
362
384
|
function safeInlineCode(s) {
|
|
363
385
|
return s.replace(/`/g, "\u2018");
|
|
364
386
|
}
|
|
387
|
+
function buildTestNumbering(report) {
|
|
388
|
+
const map = /* @__PURE__ */ new Map();
|
|
389
|
+
report.tests.forEach((t, i) => {
|
|
390
|
+
map.set(t.testCaseId, i + 1);
|
|
391
|
+
});
|
|
392
|
+
return map;
|
|
393
|
+
}
|
|
365
394
|
function renderOverview(report) {
|
|
366
395
|
const { total, passed, failed } = countTests(report);
|
|
367
396
|
const lines = [
|
|
@@ -374,10 +403,11 @@ function renderOverview(report) {
|
|
|
374
403
|
return lines.join("\n");
|
|
375
404
|
}
|
|
376
405
|
lines.push("", "**Tests run:**");
|
|
406
|
+
const numbering = buildTestNumbering(report);
|
|
377
407
|
const anyGrouped = report.tests.some((t) => Boolean(t.useCaseName));
|
|
378
408
|
if (!anyGrouped) {
|
|
379
409
|
for (const t of report.tests) {
|
|
380
|
-
lines.push(`- ${statusEmoji(t)} ${t.name}`);
|
|
410
|
+
lines.push(`- **${numbering.get(t.testCaseId)}.** ${statusEmoji(t)} ${t.name}`);
|
|
381
411
|
}
|
|
382
412
|
return lines.join("\n");
|
|
383
413
|
}
|
|
@@ -402,23 +432,23 @@ function renderOverview(report) {
|
|
|
402
432
|
}
|
|
403
433
|
for (const entry of flat) {
|
|
404
434
|
if (entry.type === "test") {
|
|
405
|
-
lines.push(`- ${statusEmoji(entry.test)} ${entry.test.name}`);
|
|
435
|
+
lines.push(`- **${numbering.get(entry.test.testCaseId)}.** ${statusEmoji(entry.test)} ${entry.test.name}`);
|
|
406
436
|
} else {
|
|
407
437
|
lines.push(`- **${entry.key}**`);
|
|
408
438
|
for (const t of groups.get(entry.key)) {
|
|
409
|
-
lines.push(` - ${statusEmoji(t)} ${t.name}`);
|
|
439
|
+
lines.push(` - **${numbering.get(t.testCaseId)}.** ${statusEmoji(t)} ${t.name}`);
|
|
410
440
|
}
|
|
411
441
|
}
|
|
412
442
|
}
|
|
413
443
|
return lines.join("\n");
|
|
414
444
|
}
|
|
415
|
-
function renderTestDetails(test, projectId) {
|
|
416
|
-
const summary = renderSummaryLine(test);
|
|
417
|
-
const
|
|
445
|
+
function renderTestDetails(test, projectId, testNumber) {
|
|
446
|
+
const summary = renderSummaryLine(test, testNumber);
|
|
447
|
+
const frameBlock = renderEndingFrame(test);
|
|
418
448
|
const resultLines = renderResultSummary(test, projectId);
|
|
419
449
|
const body = ["", "<br>", ""];
|
|
420
|
-
if (
|
|
421
|
-
body.push(
|
|
450
|
+
if (frameBlock) {
|
|
451
|
+
body.push(...frameBlock, "");
|
|
422
452
|
}
|
|
423
453
|
body.push(...resultLines);
|
|
424
454
|
return `<details>
|
|
@@ -427,20 +457,24 @@ ${body.join("\n")}
|
|
|
427
457
|
|
|
428
458
|
</details>`;
|
|
429
459
|
}
|
|
430
|
-
function renderSummaryLine(test) {
|
|
431
|
-
const base =
|
|
460
|
+
function renderSummaryLine(test, testNumber) {
|
|
461
|
+
const base = `<b>${testNumber}. ${test.name}</b> ${statusEmoji(test)}`;
|
|
432
462
|
const tail = " <i>\u25B6 click to expand</i>";
|
|
433
463
|
if (test.description) {
|
|
434
464
|
return `${base} \u2014 ${test.description}${tail}`;
|
|
435
465
|
}
|
|
436
466
|
return `${base}${tail}`;
|
|
437
467
|
}
|
|
438
|
-
function
|
|
439
|
-
const
|
|
440
|
-
if (!
|
|
468
|
+
function renderEndingFrame(test) {
|
|
469
|
+
const frame = endingFrame(test);
|
|
470
|
+
if (!frame) {
|
|
441
471
|
return null;
|
|
442
472
|
}
|
|
443
|
-
return
|
|
473
|
+
return [
|
|
474
|
+
`**\u{1F4F8} Ending screen \u2014 ${frame.caption}**`,
|
|
475
|
+
"",
|
|
476
|
+
fullSizeImage(frame.url, test.name)
|
|
477
|
+
];
|
|
444
478
|
}
|
|
445
479
|
function renderResultSummary(test, projectId) {
|
|
446
480
|
const dashboardUrl = `${DASHBOARD_URL_BASE}/${projectId}/scripts?modal=script-details&testCaseId=${encodeURIComponent(test.testCaseId)}`;
|
|
@@ -469,7 +503,7 @@ function renderBody(report, opts) {
|
|
|
469
503
|
"_Full per-test details in the comment below \u2014 the PR description was too large to inline them._"
|
|
470
504
|
].join("\n");
|
|
471
505
|
}
|
|
472
|
-
const detailBlocks = report.tests.map((t) => renderTestDetails(t, report.projectId));
|
|
506
|
+
const detailBlocks = report.tests.map((t, i) => renderTestDetails(t, report.projectId, i + 1));
|
|
473
507
|
return [
|
|
474
508
|
overview,
|
|
475
509
|
"",
|
|
@@ -482,7 +516,7 @@ function renderComment(report) {
|
|
|
482
516
|
if (report.tests.length === 0) {
|
|
483
517
|
return "";
|
|
484
518
|
}
|
|
485
|
-
const detailBlocks = report.tests.map((t) => renderTestDetails(t, report.projectId));
|
|
519
|
+
const detailBlocks = report.tests.map((t, i) => renderTestDetails(t, report.projectId, i + 1));
|
|
486
520
|
return [
|
|
487
521
|
"## E2E acceptance evidence (overflow)",
|
|
488
522
|
"",
|
|
@@ -523,7 +557,9 @@ var PassedTestSchema = z.object({
|
|
|
523
557
|
status: z.literal("passed"),
|
|
524
558
|
steps: z.array(StepSchema),
|
|
525
559
|
useCaseName: z.string().min(1).optional(),
|
|
526
|
-
description: z.string().min(1).optional()
|
|
560
|
+
description: z.string().min(1).optional(),
|
|
561
|
+
endingScreenshotUrl: z.string().url().optional(),
|
|
562
|
+
endingScreenshotCaption: z.string().min(1).optional()
|
|
527
563
|
});
|
|
528
564
|
var FailedTestSchema = z.object({
|
|
529
565
|
name: z.string().min(1),
|
|
@@ -537,7 +573,9 @@ var FailedTestSchema = z.object({
|
|
|
537
573
|
error: z.string().min(1),
|
|
538
574
|
artifactsDir: z.string().min(1).optional(),
|
|
539
575
|
useCaseName: z.string().min(1).optional(),
|
|
540
|
-
description: z.string().min(1).optional()
|
|
576
|
+
description: z.string().min(1).optional(),
|
|
577
|
+
endingScreenshotUrl: z.string().url().optional(),
|
|
578
|
+
endingScreenshotCaption: z.string().min(1).optional()
|
|
541
579
|
});
|
|
542
580
|
var TestResultSchema = z.discriminatedUnion("status", [
|
|
543
581
|
PassedTestSchema,
|
|
@@ -558,6 +596,7 @@ var GS_SCHEME = "gs://";
|
|
|
558
596
|
var PUBLIC_URL_PATH = "/v1/protected/storage/publicUrl";
|
|
559
597
|
var RESOLVE_TIMEOUT_MS = 1e4;
|
|
560
598
|
var LOG_PREFIX = "build-pr-section";
|
|
599
|
+
var IMAGE_PROXY_PREFIX = "https://images.weserv.nl/?url=";
|
|
561
600
|
|
|
562
601
|
// src/cli/pr-section/resolve-urls.ts
|
|
563
602
|
function errMsg(e) {
|
|
@@ -566,6 +605,12 @@ function errMsg(e) {
|
|
|
566
605
|
function isGsUrl(url) {
|
|
567
606
|
return url.startsWith(GS_SCHEME);
|
|
568
607
|
}
|
|
608
|
+
function wrapInImageProxy(url) {
|
|
609
|
+
if (url.startsWith(IMAGE_PROXY_PREFIX)) {
|
|
610
|
+
return url;
|
|
611
|
+
}
|
|
612
|
+
return `${IMAGE_PROXY_PREFIX}${encodeURIComponent(url)}`;
|
|
613
|
+
}
|
|
569
614
|
function buildAuthHeaders(credentials) {
|
|
570
615
|
const headers = {};
|
|
571
616
|
if (credentials.bearerToken) {
|
|
@@ -584,6 +629,9 @@ function collectGsUrls(report) {
|
|
|
584
629
|
seen.add(step.screenshotUrl);
|
|
585
630
|
}
|
|
586
631
|
}
|
|
632
|
+
if (test.endingScreenshotUrl && isGsUrl(test.endingScreenshotUrl)) {
|
|
633
|
+
seen.add(test.endingScreenshotUrl);
|
|
634
|
+
}
|
|
587
635
|
}
|
|
588
636
|
return Array.from(seen);
|
|
589
637
|
}
|
|
@@ -619,7 +667,17 @@ function remapStep(step, urlMap) {
|
|
|
619
667
|
return { ...step, screenshotUrl: resolved };
|
|
620
668
|
}
|
|
621
669
|
function remapTest(test, urlMap) {
|
|
622
|
-
|
|
670
|
+
const remapped = {
|
|
671
|
+
...test,
|
|
672
|
+
steps: test.steps.map((s) => remapStep(s, urlMap))
|
|
673
|
+
};
|
|
674
|
+
if (test.endingScreenshotUrl) {
|
|
675
|
+
const resolved = urlMap.get(test.endingScreenshotUrl);
|
|
676
|
+
if (resolved) {
|
|
677
|
+
remapped.endingScreenshotUrl = resolved;
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
return remapped;
|
|
623
681
|
}
|
|
624
682
|
async function resolveGsScreenshotUrls(report, opts) {
|
|
625
683
|
const { stderrWrite } = opts;
|
|
@@ -628,7 +686,7 @@ async function resolveGsScreenshotUrls(report, opts) {
|
|
|
628
686
|
if (gsUrls.length === 0) {
|
|
629
687
|
return report;
|
|
630
688
|
}
|
|
631
|
-
const mcps = await import('./src-
|
|
689
|
+
const mcps = await import('./src-2IDMKEJ5.js');
|
|
632
690
|
const credentials = await mcps.getCallerCredentialsAsync();
|
|
633
691
|
if (!credentials.bearerToken && !credentials.apiKey) {
|
|
634
692
|
stderrWrite(
|
|
@@ -647,7 +705,7 @@ async function resolveGsScreenshotUrls(report, opts) {
|
|
|
647
705
|
for (let i = 0; i < gsUrls.length; i++) {
|
|
648
706
|
const https = resolved[i];
|
|
649
707
|
if (https) {
|
|
650
|
-
urlMap.set(gsUrls[i], https);
|
|
708
|
+
urlMap.set(gsUrls[i], wrapInImageProxy(https));
|
|
651
709
|
} else {
|
|
652
710
|
failureCount++;
|
|
653
711
|
}
|
|
@@ -2407,9 +2407,11 @@ ${executionResult.stderr}`;
|
|
|
2407
2407
|
`Generated script does not contain a valid 'steps' array. File: ${generatedScriptPath}`
|
|
2408
2408
|
);
|
|
2409
2409
|
}
|
|
2410
|
+
const generatedSummaryStep = generatedScript.summaryStep;
|
|
2410
2411
|
storage.updateTestScript(localTestScript.id, {
|
|
2411
2412
|
status: "generated",
|
|
2412
|
-
actionScript: generatedSteps
|
|
2413
|
+
actionScript: generatedSteps,
|
|
2414
|
+
summaryStep: generatedSummaryStep
|
|
2413
2415
|
});
|
|
2414
2416
|
const artifactsDir = await moveResultsToArtifacts({
|
|
2415
2417
|
runId,
|
|
@@ -5629,6 +5631,7 @@ var publishTestScriptTool = {
|
|
|
5629
5631
|
uploadedAt
|
|
5630
5632
|
},
|
|
5631
5633
|
actionScript: testScript.actionScript,
|
|
5634
|
+
summaryStep: testScript.summaryStep,
|
|
5632
5635
|
status: runResult.status === "passed" ? "passed" : "failed",
|
|
5633
5636
|
executionTimeMs: runResult.executionTimeMs,
|
|
5634
5637
|
errorMessage: runResult.errorMessage
|
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-2ZDLQAO4.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-OUI734ME.js';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "muggle",
|
|
3
3
|
"description": "Run real-browser end-to-end (E2E) acceptance tests on your web app from any AI coding agent. Generate test scripts from plain English, replay them on localhost, capture screenshots, and validate user flows like signup, checkout, and dashboards. Works across Claude Code, Cursor, Codex, and Windsurf.",
|
|
4
|
-
"version": "4.
|
|
4
|
+
"version": "4.8.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Muggle AI",
|
|
7
7
|
"email": "support@muggle-ai.com"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "muggle",
|
|
3
3
|
"displayName": "Muggle AI",
|
|
4
4
|
"description": "Ship quality products with AI-powered end-to-end (E2E) acceptance testing that validates your web app like a real user — from Claude Code and Cursor to PR.",
|
|
5
|
-
"version": "4.
|
|
5
|
+
"version": "4.8.0",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Muggle AI",
|
|
8
8
|
"email": "support@muggle-ai.com"
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: muggle-works-npm-release
|
|
3
|
+
description: >-
|
|
4
|
+
Cut @muggleai/works release: AskQuestion (major/minor/patch), sync master, stop if
|
|
5
|
+
nothing ships, semver baseline + Electron from GitHub, confirm plan, bump
|
|
6
|
+
package.json + sync:versions, full local verify, chore(release) PR, merge via gh,
|
|
7
|
+
dispatch publish-works-to-npm.yml—no local npm publish.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Muggle Works — npm release (single playbook)
|
|
11
|
+
|
|
12
|
+
Repo: **`multiplex-ai/muggle-ai-works`**. Workflow: **`.github/workflows/publish-works-to-npm.yml`** (“Publish Works to npm”). **Never** run local **`npm publish`** (OIDC trusted publishing in CI).
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Phase 1 — Ask bump type (do this first)
|
|
17
|
+
|
|
18
|
+
**Stop until the user answers.**
|
|
19
|
+
|
|
20
|
+
**Prefer `AskQuestion`** with exactly these three options: **major**, **minor**, **patch** (fix). If the environment has no structured question tool, ask the same in plain text:
|
|
21
|
+
|
|
22
|
+
> Is this release a **major**, **minor**, or **patch** (fix)?
|
|
23
|
+
|
|
24
|
+
You may **recommend** a bump from commit subjects (e.g. `feat!` / breaking → major, `feat` → minor, `fix` / `chore` → patch) but **do not** choose for them. **Do not** edit files yet.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Phase 2 — Sync, surface state, empty-release gate
|
|
29
|
+
|
|
30
|
+
Run from **`muggle-ai-works`**:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
git checkout master && git pull --ff-only && git fetch --tags
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Show what is shipping:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
node -e 'console.log("master package.json:", require("./package.json").version)'
|
|
40
|
+
npm view @muggleai/works version 2>&1 | sed 's/^/npm latest: /'
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**Commits since the last release commit** (stop if there is nothing to ship):
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
LAST_RELEASE_SHA=$(git log --grep='chore(release)' --format='%H' -1)
|
|
47
|
+
git log --oneline "$LAST_RELEASE_SHA..HEAD"
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
- If the log is **empty**, tell the user there is **nothing to ship** and **stop** (no branch, no bump, no PR).
|
|
51
|
+
- If non-empty, present commits as a short table (subject; PR number from title/body if present).
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Phase 3 — Version baseline, Electron, print summary, confirm
|
|
56
|
+
|
|
57
|
+
### npm version (`nextNpmVersion`)
|
|
58
|
+
|
|
59
|
+
1. **`npm view @muggleai/works version`** — last published on npm.
|
|
60
|
+
2. Root **`package.json` → `version`** on current **`master`** checkout.
|
|
61
|
+
3. **Baseline** = **semver-higher** of those two (never target below repo or npm).
|
|
62
|
+
4. Apply the user’s **major / minor / patch** to that baseline → **`nextNpmVersion`** (semver-correct).
|
|
63
|
+
|
|
64
|
+
### Electron (`muggleConfig`)
|
|
65
|
+
|
|
66
|
+
1. Read **`package.json` → `muggleConfig.electronAppVersion`**.
|
|
67
|
+
2. **Latest desktop on GitHub:**
|
|
68
|
+
`https://api.github.com/repos/multiplex-ai/muggle-ai-works/releases?per_page=30`
|
|
69
|
+
→ newest **`tag_name`** matching **`electron-app-v*`** → strip prefix → **`latestElectronVersion`** (semver only).
|
|
70
|
+
|
|
71
|
+
### Print (always)
|
|
72
|
+
|
|
73
|
+
| Item | Value |
|
|
74
|
+
| :--- | :---- |
|
|
75
|
+
| Last **@muggleai/works** on npm | … |
|
|
76
|
+
| **Baseline** for bump | … |
|
|
77
|
+
| **`nextNpmVersion`** (to publish) | … |
|
|
78
|
+
| Current **`electronAppVersion`** | … |
|
|
79
|
+
| Latest **`electron-app-v…`** on GitHub | … |
|
|
80
|
+
|
|
81
|
+
### Electron bump decision
|
|
82
|
+
|
|
83
|
+
If **`latestElectronVersion`** ≠ current **`electronAppVersion`**, ask: **bump** Electron + all four **`muggleConfig.checksums`** to **`latestElectronVersion`**, or **keep** current.
|
|
84
|
+
|
|
85
|
+
If bumping, checksums from:
|
|
86
|
+
|
|
87
|
+
`https://github.com/multiplex-ai/muggle-ai-works/releases/download/electron-app-vVERSION/checksums.txt`
|
|
88
|
+
|
|
89
|
+
Map zip artifacts → **`darwin-arm64`**, **`darwin-x64`**, **`win32-x64`**, **`linux-x64`** (same mapping rules as today).
|
|
90
|
+
|
|
91
|
+
**Stop again:** user must **confirm** the full plan (**`nextNpmVersion`** + Electron choice). If they cancel, **do not** branch, merge, or dispatch CI.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Phase 4 — After explicit confirmation only
|
|
96
|
+
|
|
97
|
+
### 1. Branch and bump
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
git checkout -b "chore/release-<VERSION>"
|
|
101
|
+
npm version "<VERSION>" --no-git-tag-version
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Replace **`<VERSION>`** with **`nextNpmVersion`** (dots in the branch name are fine, e.g. `chore/release-4.8.0`).
|
|
105
|
+
|
|
106
|
+
- If Electron bump agreed: set **`muggleConfig.electronAppVersion`** and all four **`muggleConfig.checksums`** in **`package.json`**.
|
|
107
|
+
|
|
108
|
+
### 2. Propagate versions (do not hand-edit manifests)
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
pnpm run sync:versions
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Never hand-edit **`.claude-plugin/marketplace.json`**, **`.cursor-plugin/marketplace.json`**, **`plugin/.claude-plugin/plugin.json`**, **`plugin/.cursor-plugin/plugin.json`**, or **`server.json`** — **`sync-versions`** (and **`build`**) owns them.
|
|
115
|
+
|
|
116
|
+
If you changed Electron after the first sync, run **`pnpm run sync:versions`** again.
|
|
117
|
+
|
|
118
|
+
### 3. Full local verify (before push)
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
pnpm run lint:check && pnpm run typecheck && pnpm test && pnpm run build && pnpm run verify:plugin && pnpm run verify:contracts && pnpm run verify:electron-release-checksums
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
- **`pnpm run build`** is required before **`verify:plugin`** — the verifier reads the **built** plugin under **`dist/plugin/`**, not source under **`plugin/`**.
|
|
125
|
+
- If **anything** fails, **stop** and surface the error; **do not** push a broken release.
|
|
126
|
+
|
|
127
|
+
### 4. Commit (**`chore(release)`**)
|
|
128
|
+
|
|
129
|
+
Stage version-touched files (at minimum **`package.json`** plus whatever **`sync:versions`** changed — typically the marketplace/plugin **`server.json`** paths above).
|
|
130
|
+
|
|
131
|
+
**Subject:** `chore(release): @muggleai/works <VERSION>`
|
|
132
|
+
|
|
133
|
+
**Body:** one bullet per shipping PR / theme, note **Electron** bump or unchanged, and any coordinated follow-ups in sibling repos (e.g. teaching-service, UI). Use a **heredoc** for `git commit` so newlines are preserved.
|
|
134
|
+
|
|
135
|
+
### 5. PR, merge, update local **`master`**
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
git push -u origin HEAD
|
|
139
|
+
gh pr create --repo multiplex-ai/muggle-ai-works --base master --head <branch> \
|
|
140
|
+
--title "chore(release): @muggleai/works <VERSION>" \
|
|
141
|
+
--body "<PR body: version delta, bump rationale, shipping list, Electron status, manifests touched by sync:versions, short test plan checklist>"
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
**Merge:** when the human has approved the release in this session, run **`gh pr merge`** (squash is fine unless the repo prefers merge commits), then:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
git checkout master && git pull --ff-only
|
|
148
|
+
node -e 'console.log("master now:", require("./package.json").version)'
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Confirm **`package.json`** on **`master`** matches **`nextNpmVersion`** before publishing.
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Phase 5 — Trigger publish (CI only)
|
|
156
|
+
|
|
157
|
+
Prefer **explicit version** (not “auto bump”):
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
gh workflow run publish-works-to-npm.yml --repo multiplex-ai/muggle-ai-works --ref master \
|
|
161
|
+
--field "version=<VERSION>" --field "bump=patch"
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
The `bump=patch` field is a harmless placeholder when `version` is set; the workflow prefers the explicit `version` input.
|
|
165
|
+
|
|
166
|
+
**Or** **`git tag "v<VERSION>"`** && **`git push origin "v<VERSION>"`** only if that tag **does not** already exist on the remote; if the tag exists, use **`workflow_dispatch`** with **`version`**.
|
|
167
|
+
|
|
168
|
+
Watch the run and confirm jobs succeed:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
gh run list --repo multiplex-ai/muggle-ai-works --workflow=publish-works-to-npm.yml --limit 1
|
|
172
|
+
gh run watch <RUN_ID> --repo multiplex-ai/muggle-ai-works --exit-status
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Verify the registry:
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
npm view @muggleai/works version
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Give the user the **Actions run URL**. If npm lags, wait ~60s and retry.
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## Rules
|
|
186
|
+
|
|
187
|
+
- **No local `npm publish`.**
|
|
188
|
+
- **Phase 1:** use **`AskQuestion`** for major / minor / patch when available (see Phase 1).
|
|
189
|
+
- Phases 1–3: keep chat concise; Phase 4–5 can be terse status lines.
|
|
190
|
+
- If the user cancels after Phase 3, **do not** merge or dispatch CI.
|
|
191
|
+
- **Tag vs npm:** **`v*`** tags are for the **npm** package; **`electron-app-v*`** is separate — **`electronAppVersion`** can move independently of **`version`**.
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## Notes (troubleshooting)
|
|
196
|
+
|
|
197
|
+
- Workflow **`name:`** / filename is tied to npm **Trusted Publishing** — see the comment block at the top of **`publish-works-to-npm.yml`** if auth fails.
|
|
198
|
+
- If commits land on **`master`** between opening the PR and merging, re-check **`git log`** vs the last **`chore(release)`** before merging; rebasing the release branch may be needed so **`master`** still matches what you intend to ship.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"release": "4.
|
|
3
|
-
"buildId": "run-
|
|
4
|
-
"commitSha": "
|
|
5
|
-
"buildTime": "2026-04-
|
|
2
|
+
"release": "4.8.0",
|
|
3
|
+
"buildId": "run-19-1",
|
|
4
|
+
"commitSha": "970c730d39e45df17c9f9498ddcad410beafb8fb",
|
|
5
|
+
"buildTime": "2026-04-12T05:58:39Z",
|
|
6
6
|
"serviceName": "muggle-ai-works-mcp"
|
|
7
7
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { buildElectronAppChecksumsUrl, buildElectronAppReleaseAssetUrl, buildElectronAppReleaseTag, calculateFileChecksum, createApiKeyWithToken, createChildLogger, deleteApiKeyData, deleteCredentials, e2e_exports as e2e, getApiKey, getApiKeyFilePath, getAuthService, getBundledElectronAppVersion, getCallerCredentials, getCallerCredentialsAsync, getChecksumForPlatform, getConfig, getCredentialsFilePath, getDataDir, getDownloadBaseUrl, getElectronAppChecksums, getElectronAppDir, getElectronAppVersion, getElectronAppVersionSource, getLocalQaTools, getLogger, getPlatformKey, getQaTools, getValidApiKeyData, getValidCredentials, hasApiKey, isElectronAppInstalled, loadApiKeyData, loadCredentials, local_exports as localQa, mcp_exports as mcp, openBrowserUrl, performLogin, performLogout, pollDeviceCode, e2e_exports as qa, resetConfig, resetLogger, saveApiKey, saveApiKeyData, saveCredentials, startDeviceCodeFlow, toolRequiresAuth, verifyFileChecksum } from './chunk-
|
|
1
|
+
export { buildElectronAppChecksumsUrl, buildElectronAppReleaseAssetUrl, buildElectronAppReleaseTag, calculateFileChecksum, createApiKeyWithToken, createChildLogger, deleteApiKeyData, deleteCredentials, e2e_exports as e2e, getApiKey, getApiKeyFilePath, getAuthService, getBundledElectronAppVersion, getCallerCredentials, getCallerCredentialsAsync, getChecksumForPlatform, getConfig, getCredentialsFilePath, getDataDir, getDownloadBaseUrl, getElectronAppChecksums, getElectronAppDir, getElectronAppVersion, getElectronAppVersionSource, getLocalQaTools, getLogger, getPlatformKey, getQaTools, getValidApiKeyData, getValidCredentials, hasApiKey, isElectronAppInstalled, loadApiKeyData, loadCredentials, local_exports as localQa, mcp_exports as mcp, openBrowserUrl, performLogin, performLogout, pollDeviceCode, e2e_exports as qa, resetConfig, resetLogger, saveApiKey, saveApiKeyData, saveCredentials, startDeviceCodeFlow, toolRequiresAuth, verifyFileChecksum } from './chunk-OUI734ME.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": "4.
|
|
4
|
+
"version": "4.8.0",
|
|
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",
|
|
@@ -41,14 +41,14 @@
|
|
|
41
41
|
"test:watch": "vitest"
|
|
42
42
|
},
|
|
43
43
|
"muggleConfig": {
|
|
44
|
-
"electronAppVersion": "1.0.
|
|
44
|
+
"electronAppVersion": "1.0.55",
|
|
45
45
|
"downloadBaseUrl": "https://github.com/multiplex-ai/muggle-ai-works/releases/download",
|
|
46
46
|
"runtimeTargetDefault": "production",
|
|
47
47
|
"checksums": {
|
|
48
|
-
"darwin-arm64": "
|
|
49
|
-
"darwin-x64": "
|
|
50
|
-
"win32-x64": "
|
|
51
|
-
"linux-x64": "
|
|
48
|
+
"darwin-arm64": "b489ecb3273d8c15727ab80430468099a41e58417ef0f853de435f13aff0d903",
|
|
49
|
+
"darwin-x64": "38a34f45a23a9b53e3383c1f016363a294a28c3abdc454da35a34f1b03ddc191",
|
|
50
|
+
"win32-x64": "795495f9ddaab676e60f0140651c04f8d375adbadd3258a387bc7c82581c6d76",
|
|
51
|
+
"linux-x64": "2005101c8b23bce055c2d059e0a123f2b795779fd88df3658fdd1b74f4684599"
|
|
52
52
|
}
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "muggle",
|
|
3
3
|
"description": "Run real-browser end-to-end (E2E) acceptance tests on your web app from any AI coding agent. Generate test scripts from plain English, replay them on localhost, capture screenshots, and validate user flows like signup, checkout, and dashboards. Works across Claude Code, Cursor, Codex, and Windsurf.",
|
|
4
|
-
"version": "4.
|
|
4
|
+
"version": "4.8.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Muggle AI",
|
|
7
7
|
"email": "support@muggle-ai.com"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "muggle",
|
|
3
3
|
"displayName": "Muggle AI",
|
|
4
4
|
"description": "Ship quality products with AI-powered end-to-end (E2E) acceptance testing that validates your web app like a real user — from Claude Code and Cursor to PR.",
|
|
5
|
-
"version": "4.
|
|
5
|
+
"version": "4.8.0",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Muggle AI",
|
|
8
8
|
"email": "support@muggle-ai.com"
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: muggle-works-npm-release
|
|
3
|
+
description: >-
|
|
4
|
+
Cut @muggleai/works release: AskQuestion (major/minor/patch), sync master, stop if
|
|
5
|
+
nothing ships, semver baseline + Electron from GitHub, confirm plan, bump
|
|
6
|
+
package.json + sync:versions, full local verify, chore(release) PR, merge via gh,
|
|
7
|
+
dispatch publish-works-to-npm.yml—no local npm publish.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Muggle Works — npm release (single playbook)
|
|
11
|
+
|
|
12
|
+
Repo: **`multiplex-ai/muggle-ai-works`**. Workflow: **`.github/workflows/publish-works-to-npm.yml`** (“Publish Works to npm”). **Never** run local **`npm publish`** (OIDC trusted publishing in CI).
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Phase 1 — Ask bump type (do this first)
|
|
17
|
+
|
|
18
|
+
**Stop until the user answers.**
|
|
19
|
+
|
|
20
|
+
**Prefer `AskQuestion`** with exactly these three options: **major**, **minor**, **patch** (fix). If the environment has no structured question tool, ask the same in plain text:
|
|
21
|
+
|
|
22
|
+
> Is this release a **major**, **minor**, or **patch** (fix)?
|
|
23
|
+
|
|
24
|
+
You may **recommend** a bump from commit subjects (e.g. `feat!` / breaking → major, `feat` → minor, `fix` / `chore` → patch) but **do not** choose for them. **Do not** edit files yet.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Phase 2 — Sync, surface state, empty-release gate
|
|
29
|
+
|
|
30
|
+
Run from **`muggle-ai-works`**:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
git checkout master && git pull --ff-only && git fetch --tags
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Show what is shipping:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
node -e 'console.log("master package.json:", require("./package.json").version)'
|
|
40
|
+
npm view @muggleai/works version 2>&1 | sed 's/^/npm latest: /'
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**Commits since the last release commit** (stop if there is nothing to ship):
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
LAST_RELEASE_SHA=$(git log --grep='chore(release)' --format='%H' -1)
|
|
47
|
+
git log --oneline "$LAST_RELEASE_SHA..HEAD"
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
- If the log is **empty**, tell the user there is **nothing to ship** and **stop** (no branch, no bump, no PR).
|
|
51
|
+
- If non-empty, present commits as a short table (subject; PR number from title/body if present).
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Phase 3 — Version baseline, Electron, print summary, confirm
|
|
56
|
+
|
|
57
|
+
### npm version (`nextNpmVersion`)
|
|
58
|
+
|
|
59
|
+
1. **`npm view @muggleai/works version`** — last published on npm.
|
|
60
|
+
2. Root **`package.json` → `version`** on current **`master`** checkout.
|
|
61
|
+
3. **Baseline** = **semver-higher** of those two (never target below repo or npm).
|
|
62
|
+
4. Apply the user’s **major / minor / patch** to that baseline → **`nextNpmVersion`** (semver-correct).
|
|
63
|
+
|
|
64
|
+
### Electron (`muggleConfig`)
|
|
65
|
+
|
|
66
|
+
1. Read **`package.json` → `muggleConfig.electronAppVersion`**.
|
|
67
|
+
2. **Latest desktop on GitHub:**
|
|
68
|
+
`https://api.github.com/repos/multiplex-ai/muggle-ai-works/releases?per_page=30`
|
|
69
|
+
→ newest **`tag_name`** matching **`electron-app-v*`** → strip prefix → **`latestElectronVersion`** (semver only).
|
|
70
|
+
|
|
71
|
+
### Print (always)
|
|
72
|
+
|
|
73
|
+
| Item | Value |
|
|
74
|
+
| :--- | :---- |
|
|
75
|
+
| Last **@muggleai/works** on npm | … |
|
|
76
|
+
| **Baseline** for bump | … |
|
|
77
|
+
| **`nextNpmVersion`** (to publish) | … |
|
|
78
|
+
| Current **`electronAppVersion`** | … |
|
|
79
|
+
| Latest **`electron-app-v…`** on GitHub | … |
|
|
80
|
+
|
|
81
|
+
### Electron bump decision
|
|
82
|
+
|
|
83
|
+
If **`latestElectronVersion`** ≠ current **`electronAppVersion`**, ask: **bump** Electron + all four **`muggleConfig.checksums`** to **`latestElectronVersion`**, or **keep** current.
|
|
84
|
+
|
|
85
|
+
If bumping, checksums from:
|
|
86
|
+
|
|
87
|
+
`https://github.com/multiplex-ai/muggle-ai-works/releases/download/electron-app-vVERSION/checksums.txt`
|
|
88
|
+
|
|
89
|
+
Map zip artifacts → **`darwin-arm64`**, **`darwin-x64`**, **`win32-x64`**, **`linux-x64`** (same mapping rules as today).
|
|
90
|
+
|
|
91
|
+
**Stop again:** user must **confirm** the full plan (**`nextNpmVersion`** + Electron choice). If they cancel, **do not** branch, merge, or dispatch CI.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Phase 4 — After explicit confirmation only
|
|
96
|
+
|
|
97
|
+
### 1. Branch and bump
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
git checkout -b "chore/release-<VERSION>"
|
|
101
|
+
npm version "<VERSION>" --no-git-tag-version
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Replace **`<VERSION>`** with **`nextNpmVersion`** (dots in the branch name are fine, e.g. `chore/release-4.8.0`).
|
|
105
|
+
|
|
106
|
+
- If Electron bump agreed: set **`muggleConfig.electronAppVersion`** and all four **`muggleConfig.checksums`** in **`package.json`**.
|
|
107
|
+
|
|
108
|
+
### 2. Propagate versions (do not hand-edit manifests)
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
pnpm run sync:versions
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Never hand-edit **`.claude-plugin/marketplace.json`**, **`.cursor-plugin/marketplace.json`**, **`plugin/.claude-plugin/plugin.json`**, **`plugin/.cursor-plugin/plugin.json`**, or **`server.json`** — **`sync-versions`** (and **`build`**) owns them.
|
|
115
|
+
|
|
116
|
+
If you changed Electron after the first sync, run **`pnpm run sync:versions`** again.
|
|
117
|
+
|
|
118
|
+
### 3. Full local verify (before push)
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
pnpm run lint:check && pnpm run typecheck && pnpm test && pnpm run build && pnpm run verify:plugin && pnpm run verify:contracts && pnpm run verify:electron-release-checksums
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
- **`pnpm run build`** is required before **`verify:plugin`** — the verifier reads the **built** plugin under **`dist/plugin/`**, not source under **`plugin/`**.
|
|
125
|
+
- If **anything** fails, **stop** and surface the error; **do not** push a broken release.
|
|
126
|
+
|
|
127
|
+
### 4. Commit (**`chore(release)`**)
|
|
128
|
+
|
|
129
|
+
Stage version-touched files (at minimum **`package.json`** plus whatever **`sync:versions`** changed — typically the marketplace/plugin **`server.json`** paths above).
|
|
130
|
+
|
|
131
|
+
**Subject:** `chore(release): @muggleai/works <VERSION>`
|
|
132
|
+
|
|
133
|
+
**Body:** one bullet per shipping PR / theme, note **Electron** bump or unchanged, and any coordinated follow-ups in sibling repos (e.g. teaching-service, UI). Use a **heredoc** for `git commit` so newlines are preserved.
|
|
134
|
+
|
|
135
|
+
### 5. PR, merge, update local **`master`**
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
git push -u origin HEAD
|
|
139
|
+
gh pr create --repo multiplex-ai/muggle-ai-works --base master --head <branch> \
|
|
140
|
+
--title "chore(release): @muggleai/works <VERSION>" \
|
|
141
|
+
--body "<PR body: version delta, bump rationale, shipping list, Electron status, manifests touched by sync:versions, short test plan checklist>"
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
**Merge:** when the human has approved the release in this session, run **`gh pr merge`** (squash is fine unless the repo prefers merge commits), then:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
git checkout master && git pull --ff-only
|
|
148
|
+
node -e 'console.log("master now:", require("./package.json").version)'
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Confirm **`package.json`** on **`master`** matches **`nextNpmVersion`** before publishing.
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Phase 5 — Trigger publish (CI only)
|
|
156
|
+
|
|
157
|
+
Prefer **explicit version** (not “auto bump”):
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
gh workflow run publish-works-to-npm.yml --repo multiplex-ai/muggle-ai-works --ref master \
|
|
161
|
+
--field "version=<VERSION>" --field "bump=patch"
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
The `bump=patch` field is a harmless placeholder when `version` is set; the workflow prefers the explicit `version` input.
|
|
165
|
+
|
|
166
|
+
**Or** **`git tag "v<VERSION>"`** && **`git push origin "v<VERSION>"`** only if that tag **does not** already exist on the remote; if the tag exists, use **`workflow_dispatch`** with **`version`**.
|
|
167
|
+
|
|
168
|
+
Watch the run and confirm jobs succeed:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
gh run list --repo multiplex-ai/muggle-ai-works --workflow=publish-works-to-npm.yml --limit 1
|
|
172
|
+
gh run watch <RUN_ID> --repo multiplex-ai/muggle-ai-works --exit-status
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Verify the registry:
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
npm view @muggleai/works version
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Give the user the **Actions run URL**. If npm lags, wait ~60s and retry.
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## Rules
|
|
186
|
+
|
|
187
|
+
- **No local `npm publish`.**
|
|
188
|
+
- **Phase 1:** use **`AskQuestion`** for major / minor / patch when available (see Phase 1).
|
|
189
|
+
- Phases 1–3: keep chat concise; Phase 4–5 can be terse status lines.
|
|
190
|
+
- If the user cancels after Phase 3, **do not** merge or dispatch CI.
|
|
191
|
+
- **Tag vs npm:** **`v*`** tags are for the **npm** package; **`electron-app-v*`** is separate — **`electronAppVersion`** can move independently of **`version`**.
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## Notes (troubleshooting)
|
|
196
|
+
|
|
197
|
+
- Workflow **`name:`** / filename is tied to npm **Trusted Publishing** — see the comment block at the top of **`publish-works-to-npm.yml`** if auth fails.
|
|
198
|
+
- If commits land on **`master`** between opening the PR and merging, re-check **`git log`** vs the last **`chore(release)`** before merging; rebasing the release branch may be needed so **`master`** still matches what you intend to ship.
|