@muggleai/works 5.9.0 → 5.11.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 +8 -0
- package/dist/{chunk-LVUJ4E62.js → chunk-MSPMXBO5.js} +638 -468
- package/dist/{chunk-5PYK7DWB.js → chunk-WUMAJOBT.js} +17 -6
- 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/README.md +19 -13
- package/dist/plugin/agents/test-prepare-runner.md +4 -1
- package/dist/plugin/agents/visual-walkthrough-builder.md +12 -5
- package/dist/plugin/commands/mtest.md +1 -1
- package/dist/plugin/hooks/README.md +15 -3
- package/dist/plugin/hooks/hooks.json +79 -0
- package/dist/plugin/scripts/ensure-electron-app.sh +62 -47
- package/dist/plugin/scripts/guardrail-classify-gate.sh +23 -0
- package/dist/plugin/scripts/guardrail-debug-path-gate.sh +41 -0
- package/dist/plugin/scripts/guardrail-pr-terminal.sh +6 -2
- package/dist/plugin/scripts/guardrail-record-stage-read.sh +21 -0
- package/dist/plugin/scripts/guardrail-record-stage-signals.sh +23 -0
- package/dist/plugin/scripts/guardrail-record-tests.sh +11 -4
- package/dist/plugin/scripts/guardrail-report-format.sh +9 -5
- package/dist/plugin/scripts/guardrail-skill-stages.sh +35 -0
- package/dist/plugin/scripts/guardrail-stage-gate.sh +43 -0
- package/dist/plugin/scripts/guardrail-walkthrough-gate.sh +41 -0
- package/dist/plugin/scripts/guardrails.mjs +474 -80
- package/dist/plugin/scripts/pr-watch-events.sh +116 -0
- package/dist/plugin/scripts/pr-watch-guards.sh +8 -2
- package/dist/plugin/scripts/pr-watch-loop.sh +254 -0
- package/dist/plugin/scripts/reconcile-stale-watchers.sh +66 -18
- package/dist/plugin/scripts/sign-body.sh +88 -0
- package/dist/plugin/skills/CLAUDE.md +16 -0
- package/dist/plugin/skills/_shared/post-merge-cleanup.md +83 -3
- package/dist/plugin/skills/_shared/pr-followup-helpers/loop-signature.md +6 -8
- package/dist/plugin/skills/_shared/pr-followup-helpers/reply-routing.md +10 -18
- package/dist/plugin/skills/_shared/resolve-e2e-validation-context.md +1 -0
- package/dist/plugin/skills/_shared/vcs/CLAUDE.md +1 -0
- package/dist/plugin/skills/_shared/vcs/github/pr-edit.md +3 -2
- package/dist/plugin/skills/_shared/vcs/github/reply-line-comment.md +3 -2
- package/dist/plugin/skills/_shared/vcs/github/top-level-comment.md +3 -2
- package/dist/plugin/skills/_shared/vcs/gitlab/mr-create.md +4 -1
- package/dist/plugin/skills/_shared/vcs/gitlab/mr-edit.md +4 -1
- package/dist/plugin/skills/_shared/vcs/gitlab/mr-note.md +4 -1
- package/dist/plugin/skills/_shared/vcs/gitlab/reply-discussion.md +4 -1
- package/dist/plugin/skills/_shared/vcs/post-signature.md +23 -12
- package/dist/plugin/skills/do/open-prs/forward.md +2 -2
- package/dist/plugin/skills/do/per-comment-replies.md +2 -15
- package/dist/plugin/skills/muggle/SKILL.md +1 -1
- package/dist/plugin/skills/muggle-browser-task/SKILL.md +1 -1
- package/dist/plugin/skills/muggle-pr-followup/CLAUDE.md +2 -1
- package/dist/plugin/skills/muggle-pr-followup/SKILL.md +6 -3
- package/dist/plugin/skills/muggle-pr-followup/adopt.md +60 -0
- package/dist/plugin/skills/muggle-pr-followup/arm-watcher.md +10 -14
- package/dist/plugin/skills/muggle-pr-followup/auto-track.md +2 -0
- package/dist/plugin/skills/muggle-pr-followup/evals/evals.json +63 -1
- package/dist/plugin/skills/muggle-pr-followup/output-templates/help.md +11 -1
- package/dist/plugin/skills/muggle-pr-followup/output-templates/inline-reply.md +1 -7
- package/dist/plugin/skills/muggle-pr-followup/output-templates/resolve-reminder.md +1 -4
- package/dist/plugin/skills/muggle-pr-followup/reconcile.md +32 -6
- package/dist/plugin/skills/muggle-pr-followup/state-schemas.md +18 -0
- package/dist/plugin/skills/muggle-preferences/SKILL.md +1 -1
- package/dist/plugin/skills/muggle-preferences/evals/evals.json +45 -0
- package/dist/plugin/skills/muggle-preferences/ops/change-one.md +1 -1
- package/dist/plugin/skills/muggle-preferences/ops/configure.md +4 -5
- package/dist/plugin/skills/muggle-preferences/ops/list.md +1 -1
- package/dist/plugin/skills/muggle-preferences/ops/set.md +3 -4
- package/dist/plugin/skills/muggle-preferences/preference-gates/README.md +3 -3
- package/dist/plugin/skills/muggle-preferences/preference-gates/autoSelectLocalHost.md +2 -2
- package/dist/plugin/skills/muggle-preferences/preference-gates/autoSelectProject.md +1 -1
- package/dist/plugin/skills/muggle-preferences/preference-gates/watcherLifetime.md +23 -0
- package/dist/plugin/skills/muggle-test/SKILL.md +23 -3
- package/dist/plugin/skills/muggle-test/execute-local.md +2 -0
- package/dist/plugin/skills/muggle-test-feature-local/SKILL.md +6 -1
- package/dist/plugin/skills/muggle-test-import/SKILL.md +1 -1
- package/dist/plugin/skills/muggle-test-prepare/SKILL.md +28 -15
- package/dist/plugin/skills/muggle-test-prepare/steps/check-running.md +1 -1
- package/dist/plugin/skills/muggle-test-prepare/steps/confirm-recipe.md +56 -0
- package/dist/plugin/skills/muggle-test-prepare/steps/derive-service-graph.md +51 -0
- package/dist/plugin/skills/muggle-test-prepare/steps/e2e-instructions.md +111 -0
- package/dist/plugin/skills/muggle-test-prepare/steps/identify-services.md +4 -2
- package/dist/plugin/skills/muggle-test-prepare/steps/readiness-report.md +12 -5
- package/dist/plugin/skills/muggle-test-prepare/steps/record-resolution.md +32 -0
- package/dist/plugin/skills/muggle-test-prepare/steps/replay-or-learn.md +20 -0
- package/dist/plugin/skills/muggle-test-prepare/steps/reuse-plan.md +9 -6
- package/dist/plugin/skills/muggle-test-prepare/steps/smoke-test.md +5 -1
- package/dist/plugin/skills/muggle-test-prepare/steps/start-services.md +3 -1
- package/dist/plugin/skills/muggle-test-regenerate-missing/SKILL.md +1 -1
- package/dist/release-manifest.json +4 -4
- package/dist/src-B5OTAZKM.js +1 -0
- package/package.json +7 -6
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/.cursor-plugin/plugin.json +1 -1
- package/plugin/README.md +19 -13
- package/plugin/agents/test-prepare-runner.md +4 -1
- package/plugin/agents/visual-walkthrough-builder.md +12 -5
- package/plugin/commands/mtest.md +1 -1
- package/plugin/hooks/README.md +15 -3
- package/plugin/hooks/hooks.json +79 -0
- package/plugin/scripts/ensure-electron-app.sh +62 -47
- package/plugin/scripts/guardrail-classify-gate.sh +23 -0
- package/plugin/scripts/guardrail-debug-path-gate.sh +41 -0
- package/plugin/scripts/guardrail-pr-terminal.sh +6 -2
- package/plugin/scripts/guardrail-record-stage-read.sh +21 -0
- package/plugin/scripts/guardrail-record-stage-signals.sh +23 -0
- package/plugin/scripts/guardrail-record-tests.sh +11 -4
- package/plugin/scripts/guardrail-report-format.sh +9 -5
- package/plugin/scripts/guardrail-skill-stages.sh +35 -0
- package/plugin/scripts/guardrail-stage-gate.sh +43 -0
- package/plugin/scripts/guardrail-walkthrough-gate.sh +41 -0
- package/plugin/scripts/guardrails.mjs +474 -80
- package/plugin/scripts/pr-watch-events.sh +116 -0
- package/plugin/scripts/pr-watch-guards.sh +8 -2
- package/plugin/scripts/pr-watch-loop.sh +254 -0
- package/plugin/scripts/reconcile-stale-watchers.sh +66 -18
- package/plugin/scripts/sign-body.sh +88 -0
- package/plugin/skills/CLAUDE.md +16 -0
- package/plugin/skills/_shared/post-merge-cleanup.md +83 -3
- package/plugin/skills/_shared/pr-followup-helpers/loop-signature.md +6 -8
- package/plugin/skills/_shared/pr-followup-helpers/reply-routing.md +10 -18
- package/plugin/skills/_shared/resolve-e2e-validation-context.md +1 -0
- package/plugin/skills/_shared/vcs/CLAUDE.md +1 -0
- package/plugin/skills/_shared/vcs/github/pr-edit.md +3 -2
- package/plugin/skills/_shared/vcs/github/reply-line-comment.md +3 -2
- package/plugin/skills/_shared/vcs/github/top-level-comment.md +3 -2
- package/plugin/skills/_shared/vcs/gitlab/mr-create.md +4 -1
- package/plugin/skills/_shared/vcs/gitlab/mr-edit.md +4 -1
- package/plugin/skills/_shared/vcs/gitlab/mr-note.md +4 -1
- package/plugin/skills/_shared/vcs/gitlab/reply-discussion.md +4 -1
- package/plugin/skills/_shared/vcs/post-signature.md +23 -12
- package/plugin/skills/do/open-prs/forward.md +2 -2
- package/plugin/skills/do/per-comment-replies.md +2 -15
- package/plugin/skills/muggle/SKILL.md +1 -1
- package/plugin/skills/muggle-browser-task/SKILL.md +1 -1
- package/plugin/skills/muggle-pr-followup/CLAUDE.md +2 -1
- package/plugin/skills/muggle-pr-followup/SKILL.md +6 -3
- package/plugin/skills/muggle-pr-followup/adopt.md +60 -0
- package/plugin/skills/muggle-pr-followup/arm-watcher.md +10 -14
- package/plugin/skills/muggle-pr-followup/auto-track.md +2 -0
- package/plugin/skills/muggle-pr-followup/evals/evals.json +63 -1
- package/plugin/skills/muggle-pr-followup/output-templates/help.md +11 -1
- package/plugin/skills/muggle-pr-followup/output-templates/inline-reply.md +1 -7
- package/plugin/skills/muggle-pr-followup/output-templates/resolve-reminder.md +1 -4
- package/plugin/skills/muggle-pr-followup/reconcile.md +32 -6
- package/plugin/skills/muggle-pr-followup/state-schemas.md +18 -0
- package/plugin/skills/muggle-preferences/SKILL.md +1 -1
- package/plugin/skills/muggle-preferences/evals/evals.json +45 -0
- package/plugin/skills/muggle-preferences/ops/change-one.md +1 -1
- package/plugin/skills/muggle-preferences/ops/configure.md +4 -5
- package/plugin/skills/muggle-preferences/ops/list.md +1 -1
- package/plugin/skills/muggle-preferences/ops/set.md +3 -4
- package/plugin/skills/muggle-preferences/preference-gates/README.md +3 -3
- package/plugin/skills/muggle-preferences/preference-gates/autoSelectLocalHost.md +2 -2
- package/plugin/skills/muggle-preferences/preference-gates/autoSelectProject.md +1 -1
- package/plugin/skills/muggle-preferences/preference-gates/watcherLifetime.md +23 -0
- package/plugin/skills/muggle-test/SKILL.md +23 -3
- package/plugin/skills/muggle-test/execute-local.md +2 -0
- package/plugin/skills/muggle-test-feature-local/SKILL.md +6 -1
- package/plugin/skills/muggle-test-import/SKILL.md +1 -1
- package/plugin/skills/muggle-test-prepare/SKILL.md +28 -15
- package/plugin/skills/muggle-test-prepare/steps/check-running.md +1 -1
- package/plugin/skills/muggle-test-prepare/steps/confirm-recipe.md +56 -0
- package/plugin/skills/muggle-test-prepare/steps/derive-service-graph.md +51 -0
- package/plugin/skills/muggle-test-prepare/steps/e2e-instructions.md +111 -0
- package/plugin/skills/muggle-test-prepare/steps/identify-services.md +4 -2
- package/plugin/skills/muggle-test-prepare/steps/readiness-report.md +12 -5
- package/plugin/skills/muggle-test-prepare/steps/record-resolution.md +32 -0
- package/plugin/skills/muggle-test-prepare/steps/replay-or-learn.md +20 -0
- package/plugin/skills/muggle-test-prepare/steps/reuse-plan.md +9 -6
- package/plugin/skills/muggle-test-prepare/steps/smoke-test.md +5 -1
- package/plugin/skills/muggle-test-prepare/steps/start-services.md +3 -1
- package/plugin/skills/muggle-test-regenerate-missing/SKILL.md +1 -1
- package/dist/src-FDK2KQSZ.js +0 -1
|
@@ -2,7 +2,7 @@ import * as crypto from 'crypto';
|
|
|
2
2
|
import { randomUUID } from 'crypto';
|
|
3
3
|
import * as fs5 from 'fs';
|
|
4
4
|
import { readFileSync, existsSync, mkdirSync, writeFileSync } from 'fs';
|
|
5
|
-
import * as
|
|
5
|
+
import * as path10 from 'path';
|
|
6
6
|
import { join, dirname } from 'path';
|
|
7
7
|
import * as os4 from 'os';
|
|
8
8
|
import { platform } from 'os';
|
|
@@ -10,7 +10,7 @@ import winston from 'winston';
|
|
|
10
10
|
import { fileURLToPath } from 'url';
|
|
11
11
|
import { exec, spawn } from 'child_process';
|
|
12
12
|
import axios, { AxiosError } from 'axios';
|
|
13
|
-
import * as
|
|
13
|
+
import * as fs9 from 'fs/promises';
|
|
14
14
|
import AppInsights from 'applicationinsights';
|
|
15
15
|
import { z } from 'zod';
|
|
16
16
|
|
|
@@ -37,6 +37,9 @@ __export(src_exports, {
|
|
|
37
37
|
PREFERENCE_ALLOWED_VALUES: () => PREFERENCE_ALLOWED_VALUES,
|
|
38
38
|
PreferenceKey: () => PreferenceKey,
|
|
39
39
|
PreferenceValue: () => PreferenceValue,
|
|
40
|
+
ProjectPreferencesReconcileOutcome: () => ProjectPreferencesReconcileOutcome,
|
|
41
|
+
WATCHER_LIFETIME_SECONDS: () => WATCHER_LIFETIME_SECONDS,
|
|
42
|
+
WATCHER_LIFETIME_UNBOUNDED_SECONDS: () => WATCHER_LIFETIME_UNBOUNDED_SECONDS,
|
|
40
43
|
buildElectronAppChecksumsUrl: () => buildElectronAppChecksumsUrl,
|
|
41
44
|
buildElectronAppReleaseAssetUrl: () => buildElectronAppReleaseAssetUrl,
|
|
42
45
|
buildElectronAppReleaseTag: () => buildElectronAppReleaseTag,
|
|
@@ -80,8 +83,7 @@ __export(src_exports, {
|
|
|
80
83
|
performLogout: () => performLogout,
|
|
81
84
|
pollDeviceCode: () => pollDeviceCode,
|
|
82
85
|
qa: () => e2e_exports2,
|
|
83
|
-
|
|
84
|
-
readProjectPreferences: () => readProjectPreferences,
|
|
86
|
+
reconcileProjectPreferences: () => reconcileProjectPreferences,
|
|
85
87
|
resetConfig: () => resetConfig,
|
|
86
88
|
resetLogger: () => resetLogger,
|
|
87
89
|
resetPreference: () => resetPreference,
|
|
@@ -98,7 +100,7 @@ __export(src_exports, {
|
|
|
98
100
|
});
|
|
99
101
|
var DATA_DIR_NAME = ".muggle-ai";
|
|
100
102
|
function getDataDir() {
|
|
101
|
-
return
|
|
103
|
+
return path10.join(os4.homedir(), DATA_DIR_NAME);
|
|
102
104
|
}
|
|
103
105
|
var DEV_MANIFEST = {
|
|
104
106
|
release: "dev",
|
|
@@ -162,24 +164,24 @@ var configInstance = null;
|
|
|
162
164
|
var muggleConfigCache = null;
|
|
163
165
|
function getPackageRoot() {
|
|
164
166
|
const currentFilePath = fileURLToPath(import.meta.url);
|
|
165
|
-
const currentDir =
|
|
166
|
-
if (currentDir.includes(
|
|
167
|
-
return
|
|
167
|
+
const currentDir = path10.dirname(currentFilePath);
|
|
168
|
+
if (currentDir.includes(path10.join("dist", "shared"))) {
|
|
169
|
+
return path10.resolve(currentDir, "..", "..");
|
|
168
170
|
}
|
|
169
171
|
if (currentDir.endsWith("dist")) {
|
|
170
|
-
return
|
|
172
|
+
return path10.resolve(currentDir, "..");
|
|
171
173
|
}
|
|
172
|
-
if (currentDir.includes(
|
|
173
|
-
return
|
|
174
|
+
if (currentDir.includes(path10.join("src", "shared"))) {
|
|
175
|
+
return path10.resolve(currentDir, "..", "..");
|
|
174
176
|
}
|
|
175
|
-
return
|
|
177
|
+
return path10.dirname(currentDir);
|
|
176
178
|
}
|
|
177
179
|
function getMuggleConfig() {
|
|
178
180
|
if (muggleConfigCache) {
|
|
179
181
|
return muggleConfigCache;
|
|
180
182
|
}
|
|
181
183
|
const packageRoot = getPackageRoot();
|
|
182
|
-
const packageJsonPath =
|
|
184
|
+
const packageJsonPath = path10.join(packageRoot, "package.json");
|
|
183
185
|
let packageJson;
|
|
184
186
|
try {
|
|
185
187
|
const content = fs5.readFileSync(packageJsonPath, "utf-8");
|
|
@@ -242,17 +244,17 @@ function getDataDir2() {
|
|
|
242
244
|
function getDownloadedElectronAppPath() {
|
|
243
245
|
const platformName = os4.platform();
|
|
244
246
|
const version = getElectronAppVersion();
|
|
245
|
-
const baseDir =
|
|
247
|
+
const baseDir = path10.join(getDataDir2(), ELECTRON_APP_DIR, version);
|
|
246
248
|
let binaryPath;
|
|
247
249
|
switch (platformName) {
|
|
248
250
|
case "darwin":
|
|
249
|
-
binaryPath =
|
|
251
|
+
binaryPath = path10.join(baseDir, "MuggleAI.app", "Contents", "MacOS", "MuggleAI");
|
|
250
252
|
break;
|
|
251
253
|
case "win32":
|
|
252
|
-
binaryPath =
|
|
254
|
+
binaryPath = path10.join(baseDir, "MuggleAI.exe");
|
|
253
255
|
break;
|
|
254
256
|
case "linux":
|
|
255
|
-
binaryPath =
|
|
257
|
+
binaryPath = path10.join(baseDir, "MuggleAI");
|
|
256
258
|
break;
|
|
257
259
|
default:
|
|
258
260
|
return null;
|
|
@@ -268,13 +270,13 @@ function getSystemElectronAppPath() {
|
|
|
268
270
|
let binaryPath;
|
|
269
271
|
switch (platformName) {
|
|
270
272
|
case "darwin":
|
|
271
|
-
binaryPath =
|
|
273
|
+
binaryPath = path10.join(homeDir, "Applications", "MuggleAI.app", "Contents", "MacOS", "MuggleAI");
|
|
272
274
|
break;
|
|
273
275
|
case "win32":
|
|
274
|
-
binaryPath =
|
|
276
|
+
binaryPath = path10.join(homeDir, "AppData", "Local", "Programs", "MuggleAI", "MuggleAI.exe");
|
|
275
277
|
break;
|
|
276
278
|
case "linux":
|
|
277
|
-
binaryPath =
|
|
279
|
+
binaryPath = path10.join(homeDir, ".local", "share", "muggle-ai", "MuggleAI");
|
|
278
280
|
break;
|
|
279
281
|
default:
|
|
280
282
|
return null;
|
|
@@ -305,7 +307,7 @@ function resolveWebServicePath() {
|
|
|
305
307
|
return customPath;
|
|
306
308
|
}
|
|
307
309
|
const packageRoot = getPackageRoot();
|
|
308
|
-
const siblingPath =
|
|
310
|
+
const siblingPath = path10.resolve(packageRoot, "..", "web-service", "dist", "src", "index.js");
|
|
309
311
|
if (fs5.existsSync(siblingPath)) {
|
|
310
312
|
return siblingPath;
|
|
311
313
|
}
|
|
@@ -392,13 +394,13 @@ function buildLocalQaConfig() {
|
|
|
392
394
|
webServiceUrl: process.env.WEB_SERVICE_URL ?? DEFAULT_WEB_SERVICE_URL,
|
|
393
395
|
promptServiceUrl: process.env.PROMPT_SERVICE_BASE_URL ?? defaultPromptServiceUrl,
|
|
394
396
|
dataDir,
|
|
395
|
-
sessionsDir:
|
|
396
|
-
projectsDir:
|
|
397
|
-
tempDir:
|
|
398
|
-
apiKeyFilePath:
|
|
399
|
-
oauthSessionFilePath:
|
|
397
|
+
sessionsDir: path10.join(dataDir, "sessions"),
|
|
398
|
+
projectsDir: path10.join(dataDir, "projects"),
|
|
399
|
+
tempDir: path10.join(dataDir, "temp"),
|
|
400
|
+
apiKeyFilePath: path10.join(dataDir, API_KEY_FILE),
|
|
401
|
+
oauthSessionFilePath: path10.join(dataDir, "oauth-session.json"),
|
|
400
402
|
webServicePath: resolveWebServicePath(),
|
|
401
|
-
webServicePidFile:
|
|
403
|
+
webServicePidFile: path10.join(dataDir, "web-service.pid"),
|
|
402
404
|
auth0: {
|
|
403
405
|
domain: process.env.AUTH0_DOMAIN ?? defaultAuth0Domain,
|
|
404
406
|
clientId: process.env.AUTH0_CLIENT_ID ?? defaultAuth0ClientId,
|
|
@@ -433,7 +435,7 @@ function getElectronAppVersion() {
|
|
|
433
435
|
if (envVersion && /^\d+\.\d+\.\d+$/.test(envVersion)) {
|
|
434
436
|
return envVersion;
|
|
435
437
|
}
|
|
436
|
-
const overridePath =
|
|
438
|
+
const overridePath = path10.join(getDataDir2(), VERSION_OVERRIDE_FILE);
|
|
437
439
|
if (fs5.existsSync(overridePath)) {
|
|
438
440
|
try {
|
|
439
441
|
const content = JSON.parse(fs5.readFileSync(overridePath, "utf-8"));
|
|
@@ -450,7 +452,7 @@ function getElectronAppVersionSource() {
|
|
|
450
452
|
if (envVersion && /^\d+\.\d+\.\d+$/.test(envVersion)) {
|
|
451
453
|
return "env";
|
|
452
454
|
}
|
|
453
|
-
const overridePath =
|
|
455
|
+
const overridePath = path10.join(getDataDir2(), VERSION_OVERRIDE_FILE);
|
|
454
456
|
if (fs5.existsSync(overridePath)) {
|
|
455
457
|
try {
|
|
456
458
|
const content = JSON.parse(fs5.readFileSync(overridePath, "utf-8"));
|
|
@@ -485,7 +487,7 @@ function isElectronAppInstalled() {
|
|
|
485
487
|
}
|
|
486
488
|
function getElectronAppDir(version) {
|
|
487
489
|
const resolvedVersion = version ?? getElectronAppVersion();
|
|
488
|
-
return
|
|
490
|
+
return path10.join(getDataDir2(), ELECTRON_APP_DIR, resolvedVersion);
|
|
489
491
|
}
|
|
490
492
|
|
|
491
493
|
// packages/mcps/src/shared/logger.ts
|
|
@@ -542,14 +544,14 @@ function getPlatformKey() {
|
|
|
542
544
|
}
|
|
543
545
|
}
|
|
544
546
|
async function calculateFileChecksum(filePath) {
|
|
545
|
-
return new Promise((
|
|
547
|
+
return new Promise((resolve5, reject) => {
|
|
546
548
|
const hash = crypto.createHash("sha256");
|
|
547
549
|
const stream = fs5.createReadStream(filePath);
|
|
548
550
|
stream.on("data", (data) => {
|
|
549
551
|
hash.update(data);
|
|
550
552
|
});
|
|
551
553
|
stream.on("end", () => {
|
|
552
|
-
|
|
554
|
+
resolve5(hash.digest("hex"));
|
|
553
555
|
});
|
|
554
556
|
stream.on("error", (error) => {
|
|
555
557
|
reject(error);
|
|
@@ -559,7 +561,7 @@ async function calculateFileChecksum(filePath) {
|
|
|
559
561
|
async function verifyFileChecksum(filePath, expectedChecksum) {
|
|
560
562
|
if (!expectedChecksum || expectedChecksum.trim() === "") {
|
|
561
563
|
logger.warn("Checksum verification skipped - no checksum provided", {
|
|
562
|
-
file:
|
|
564
|
+
file: path10.basename(filePath)
|
|
563
565
|
});
|
|
564
566
|
return {
|
|
565
567
|
valid: true,
|
|
@@ -575,13 +577,13 @@ async function verifyFileChecksum(filePath, expectedChecksum) {
|
|
|
575
577
|
const valid = normalizedExpected === normalizedActual;
|
|
576
578
|
if (!valid) {
|
|
577
579
|
logger.error("Checksum verification failed", {
|
|
578
|
-
file:
|
|
580
|
+
file: path10.basename(filePath),
|
|
579
581
|
expected: normalizedExpected,
|
|
580
582
|
actual: normalizedActual
|
|
581
583
|
});
|
|
582
584
|
} else {
|
|
583
585
|
logger.info("Checksum verified successfully", {
|
|
584
|
-
file:
|
|
586
|
+
file: path10.basename(filePath),
|
|
585
587
|
checksum: normalizedActual
|
|
586
588
|
});
|
|
587
589
|
}
|
|
@@ -594,7 +596,7 @@ async function verifyFileChecksum(filePath, expectedChecksum) {
|
|
|
594
596
|
} catch (error) {
|
|
595
597
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
596
598
|
logger.error("Checksum calculation failed", {
|
|
597
|
-
file:
|
|
599
|
+
file: path10.basename(filePath),
|
|
598
600
|
error: errorMessage
|
|
599
601
|
});
|
|
600
602
|
return {
|
|
@@ -627,7 +629,7 @@ function getOpenCommand(url) {
|
|
|
627
629
|
}
|
|
628
630
|
}
|
|
629
631
|
async function openBrowserUrl(options) {
|
|
630
|
-
return new Promise((
|
|
632
|
+
return new Promise((resolve5) => {
|
|
631
633
|
try {
|
|
632
634
|
const command = getOpenCommand(options.url);
|
|
633
635
|
logger2.debug("[Browser] Opening URL", { url: options.url, command });
|
|
@@ -637,13 +639,13 @@ async function openBrowserUrl(options) {
|
|
|
637
639
|
url: options.url,
|
|
638
640
|
error: error.message
|
|
639
641
|
});
|
|
640
|
-
|
|
642
|
+
resolve5({
|
|
641
643
|
opened: false,
|
|
642
644
|
error: error.message
|
|
643
645
|
});
|
|
644
646
|
} else {
|
|
645
647
|
logger2.info("[Browser] URL opened successfully", { url: options.url });
|
|
646
|
-
|
|
648
|
+
resolve5({ opened: true });
|
|
647
649
|
}
|
|
648
650
|
});
|
|
649
651
|
} catch (error) {
|
|
@@ -652,7 +654,7 @@ async function openBrowserUrl(options) {
|
|
|
652
654
|
url: options.url,
|
|
653
655
|
error: errorMessage
|
|
654
656
|
});
|
|
655
|
-
|
|
657
|
+
resolve5({
|
|
656
658
|
opened: false,
|
|
657
659
|
error: errorMessage
|
|
658
660
|
});
|
|
@@ -661,7 +663,7 @@ async function openBrowserUrl(options) {
|
|
|
661
663
|
}
|
|
662
664
|
var API_KEY_FILE2 = "api-key.json";
|
|
663
665
|
function getApiKeyFilePath() {
|
|
664
|
-
return
|
|
666
|
+
return path10.join(getDataDir(), API_KEY_FILE2);
|
|
665
667
|
}
|
|
666
668
|
function ensureDataDir() {
|
|
667
669
|
const dataDir = getDataDir();
|
|
@@ -850,8 +852,8 @@ var AuthService = class {
|
|
|
850
852
|
constructor() {
|
|
851
853
|
const config = getConfig();
|
|
852
854
|
this.oauthSessionFilePath = config.localQa.oauthSessionFilePath;
|
|
853
|
-
this.pendingDeviceCodePath =
|
|
854
|
-
|
|
855
|
+
this.pendingDeviceCodePath = path10.join(
|
|
856
|
+
path10.dirname(config.localQa.oauthSessionFilePath),
|
|
855
857
|
"pending-device-code.json"
|
|
856
858
|
);
|
|
857
859
|
}
|
|
@@ -960,7 +962,7 @@ var AuthService = class {
|
|
|
960
962
|
*/
|
|
961
963
|
storePendingDeviceCode(params) {
|
|
962
964
|
const logger6 = getLogger();
|
|
963
|
-
const dir =
|
|
965
|
+
const dir = path10.dirname(this.pendingDeviceCodePath);
|
|
964
966
|
if (!fs5.existsSync(dir)) {
|
|
965
967
|
fs5.mkdirSync(dir, { recursive: true });
|
|
966
968
|
}
|
|
@@ -1173,7 +1175,7 @@ var AuthService = class {
|
|
|
1173
1175
|
email,
|
|
1174
1176
|
userId
|
|
1175
1177
|
};
|
|
1176
|
-
const dir =
|
|
1178
|
+
const dir = path10.dirname(this.oauthSessionFilePath);
|
|
1177
1179
|
if (!fs5.existsSync(dir)) {
|
|
1178
1180
|
fs5.mkdirSync(dir, { recursive: true });
|
|
1179
1181
|
}
|
|
@@ -1276,7 +1278,7 @@ var AuthService = class {
|
|
|
1276
1278
|
email: storedAuth.email,
|
|
1277
1279
|
userId: storedAuth.userId
|
|
1278
1280
|
};
|
|
1279
|
-
const dir =
|
|
1281
|
+
const dir = path10.dirname(this.oauthSessionFilePath);
|
|
1280
1282
|
if (!fs5.existsSync(dir)) {
|
|
1281
1283
|
fs5.mkdirSync(dir, { recursive: true });
|
|
1282
1284
|
}
|
|
@@ -1357,9 +1359,9 @@ function resetAuthService() {
|
|
|
1357
1359
|
serviceInstance = null;
|
|
1358
1360
|
}
|
|
1359
1361
|
function sleep(params) {
|
|
1360
|
-
return new Promise((
|
|
1362
|
+
return new Promise((resolve5) => {
|
|
1361
1363
|
setTimeout(() => {
|
|
1362
|
-
|
|
1364
|
+
resolve5();
|
|
1363
1365
|
}, params.durationMs);
|
|
1364
1366
|
});
|
|
1365
1367
|
}
|
|
@@ -1399,11 +1401,11 @@ var StorageService = class {
|
|
|
1399
1401
|
createSessionDirectory(sessionId) {
|
|
1400
1402
|
const logger6 = getLogger();
|
|
1401
1403
|
this.ensureDirectories();
|
|
1402
|
-
const sessionDir =
|
|
1404
|
+
const sessionDir = path10.join(this.sessionsDir, sessionId);
|
|
1403
1405
|
if (!fs5.existsSync(sessionDir)) {
|
|
1404
1406
|
fs5.mkdirSync(sessionDir, { recursive: true });
|
|
1405
|
-
fs5.mkdirSync(
|
|
1406
|
-
fs5.mkdirSync(
|
|
1407
|
+
fs5.mkdirSync(path10.join(sessionDir, "screenshots"), { recursive: true });
|
|
1408
|
+
fs5.mkdirSync(path10.join(sessionDir, "logs"), { recursive: true });
|
|
1407
1409
|
logger6.info("Created session directory", { sessionId, path: sessionDir });
|
|
1408
1410
|
}
|
|
1409
1411
|
return sessionDir;
|
|
@@ -1415,7 +1417,7 @@ var StorageService = class {
|
|
|
1415
1417
|
saveSessionMetadata(metadata) {
|
|
1416
1418
|
const logger6 = getLogger();
|
|
1417
1419
|
const sessionDir = this.createSessionDirectory(metadata.sessionId);
|
|
1418
|
-
const metadataPath =
|
|
1420
|
+
const metadataPath = path10.join(sessionDir, "metadata.json");
|
|
1419
1421
|
fs5.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2), "utf-8");
|
|
1420
1422
|
logger6.debug("Saved session metadata", { sessionId: metadata.sessionId });
|
|
1421
1423
|
}
|
|
@@ -1426,7 +1428,7 @@ var StorageService = class {
|
|
|
1426
1428
|
*/
|
|
1427
1429
|
loadSessionMetadata(sessionId) {
|
|
1428
1430
|
const logger6 = getLogger();
|
|
1429
|
-
const metadataPath =
|
|
1431
|
+
const metadataPath = path10.join(this.sessionsDir, sessionId, "metadata.json");
|
|
1430
1432
|
if (!fs5.existsSync(metadataPath)) {
|
|
1431
1433
|
return null;
|
|
1432
1434
|
}
|
|
@@ -1450,7 +1452,7 @@ var StorageService = class {
|
|
|
1450
1452
|
return [];
|
|
1451
1453
|
}
|
|
1452
1454
|
return fs5.readdirSync(this.sessionsDir).filter((entry) => {
|
|
1453
|
-
const entryPath =
|
|
1455
|
+
const entryPath = path10.join(this.sessionsDir, entry);
|
|
1454
1456
|
return fs5.statSync(entryPath).isDirectory();
|
|
1455
1457
|
});
|
|
1456
1458
|
}
|
|
@@ -1459,13 +1461,13 @@ var StorageService = class {
|
|
|
1459
1461
|
* @returns Current session ID, or null.
|
|
1460
1462
|
*/
|
|
1461
1463
|
getCurrentSessionId() {
|
|
1462
|
-
const currentPath =
|
|
1464
|
+
const currentPath = path10.join(this.sessionsDir, "current");
|
|
1463
1465
|
if (!fs5.existsSync(currentPath)) {
|
|
1464
1466
|
return null;
|
|
1465
1467
|
}
|
|
1466
1468
|
try {
|
|
1467
1469
|
const target = fs5.readlinkSync(currentPath);
|
|
1468
|
-
return
|
|
1470
|
+
return path10.basename(target);
|
|
1469
1471
|
} catch {
|
|
1470
1472
|
return null;
|
|
1471
1473
|
}
|
|
@@ -1476,8 +1478,8 @@ var StorageService = class {
|
|
|
1476
1478
|
*/
|
|
1477
1479
|
setCurrentSession(sessionId) {
|
|
1478
1480
|
const logger6 = getLogger();
|
|
1479
|
-
const currentPath =
|
|
1480
|
-
const targetPath =
|
|
1481
|
+
const currentPath = path10.join(this.sessionsDir, "current");
|
|
1482
|
+
const targetPath = path10.join(this.sessionsDir, sessionId);
|
|
1481
1483
|
if (fs5.existsSync(currentPath)) {
|
|
1482
1484
|
fs5.unlinkSync(currentPath);
|
|
1483
1485
|
}
|
|
@@ -1492,7 +1494,7 @@ var StorageService = class {
|
|
|
1492
1494
|
const { sessionId, filename, data } = params;
|
|
1493
1495
|
const logger6 = getLogger();
|
|
1494
1496
|
const sessionDir = this.createSessionDirectory(sessionId);
|
|
1495
|
-
const screenshotPath =
|
|
1497
|
+
const screenshotPath = path10.join(sessionDir, "screenshots", filename);
|
|
1496
1498
|
fs5.writeFileSync(screenshotPath, data);
|
|
1497
1499
|
logger6.debug("Saved screenshot", { sessionId, filename });
|
|
1498
1500
|
return screenshotPath;
|
|
@@ -1505,7 +1507,7 @@ var StorageService = class {
|
|
|
1505
1507
|
const { sessionId, content } = params;
|
|
1506
1508
|
const logger6 = getLogger();
|
|
1507
1509
|
const sessionDir = this.createSessionDirectory(sessionId);
|
|
1508
|
-
const resultsPath =
|
|
1510
|
+
const resultsPath = path10.join(sessionDir, "results.md");
|
|
1509
1511
|
fs5.appendFileSync(resultsPath, content + "\n", "utf-8");
|
|
1510
1512
|
logger6.debug("Appended to results", { sessionId });
|
|
1511
1513
|
}
|
|
@@ -1515,7 +1517,7 @@ var StorageService = class {
|
|
|
1515
1517
|
* @returns Results content, or null if not found.
|
|
1516
1518
|
*/
|
|
1517
1519
|
getResults(sessionId) {
|
|
1518
|
-
const resultsPath =
|
|
1520
|
+
const resultsPath = path10.join(this.sessionsDir, sessionId, "results.md");
|
|
1519
1521
|
if (!fs5.existsSync(resultsPath)) {
|
|
1520
1522
|
return null;
|
|
1521
1523
|
}
|
|
@@ -1584,7 +1586,7 @@ var StorageService = class {
|
|
|
1584
1586
|
const { sessionId, targetUrl, testInstructions } = params;
|
|
1585
1587
|
const logger6 = getLogger();
|
|
1586
1588
|
const sessionDir = this.createSessionDirectory(sessionId);
|
|
1587
|
-
const resultsPath =
|
|
1589
|
+
const resultsPath = path10.join(sessionDir, "results.md");
|
|
1588
1590
|
const header = [
|
|
1589
1591
|
`# Test Results: ${sessionId}`,
|
|
1590
1592
|
"",
|
|
@@ -1608,7 +1610,7 @@ var StorageService = class {
|
|
|
1608
1610
|
const { sessionId, step } = params;
|
|
1609
1611
|
const logger6 = getLogger();
|
|
1610
1612
|
const sessionDir = this.createSessionDirectory(sessionId);
|
|
1611
|
-
const resultsPath =
|
|
1613
|
+
const resultsPath = path10.join(sessionDir, "results.md");
|
|
1612
1614
|
const statusIcon = step.success ? "\u2713" : "\u2717";
|
|
1613
1615
|
const stepContent = [
|
|
1614
1616
|
`### Step ${step.stepNumber}: ${step.action}`,
|
|
@@ -1633,8 +1635,8 @@ var StorageService = class {
|
|
|
1633
1635
|
finalizeResults(params) {
|
|
1634
1636
|
const { sessionId, status, summary } = params;
|
|
1635
1637
|
const logger6 = getLogger();
|
|
1636
|
-
const sessionDir =
|
|
1637
|
-
const resultsPath =
|
|
1638
|
+
const sessionDir = path10.join(this.sessionsDir, sessionId);
|
|
1639
|
+
const resultsPath = path10.join(sessionDir, "results.md");
|
|
1638
1640
|
if (!fs5.existsSync(resultsPath)) {
|
|
1639
1641
|
logger6.warn("Results file not found for finalization", { sessionId });
|
|
1640
1642
|
return;
|
|
@@ -1716,7 +1718,7 @@ var StorageService = class {
|
|
|
1716
1718
|
}
|
|
1717
1719
|
const sessionDate = new Date(metadata.startTime);
|
|
1718
1720
|
if (sessionDate < cutoffDate) {
|
|
1719
|
-
const sessionDir =
|
|
1721
|
+
const sessionDir = path10.join(this.sessionsDir, sessionId);
|
|
1720
1722
|
try {
|
|
1721
1723
|
fs5.rmSync(sessionDir, { recursive: true, force: true });
|
|
1722
1724
|
deletedCount++;
|
|
@@ -1746,7 +1748,7 @@ var StorageService = class {
|
|
|
1746
1748
|
* @returns Session directory path.
|
|
1747
1749
|
*/
|
|
1748
1750
|
getSessionPath(sessionId) {
|
|
1749
|
-
return
|
|
1751
|
+
return path10.join(this.sessionsDir, sessionId);
|
|
1750
1752
|
}
|
|
1751
1753
|
/**
|
|
1752
1754
|
* Delete a specific session.
|
|
@@ -1755,7 +1757,7 @@ var StorageService = class {
|
|
|
1755
1757
|
*/
|
|
1756
1758
|
deleteSession(sessionId) {
|
|
1757
1759
|
const logger6 = getLogger();
|
|
1758
|
-
const sessionDir =
|
|
1760
|
+
const sessionDir = path10.join(this.sessionsDir, sessionId);
|
|
1759
1761
|
if (!fs5.existsSync(sessionDir)) {
|
|
1760
1762
|
logger6.warn("Session not found for deletion", { sessionId });
|
|
1761
1763
|
return false;
|
|
@@ -1763,7 +1765,7 @@ var StorageService = class {
|
|
|
1763
1765
|
try {
|
|
1764
1766
|
const currentId = this.getCurrentSessionId();
|
|
1765
1767
|
if (currentId === sessionId) {
|
|
1766
|
-
const currentPath =
|
|
1768
|
+
const currentPath = path10.join(this.sessionsDir, "current");
|
|
1767
1769
|
if (fs5.existsSync(currentPath)) {
|
|
1768
1770
|
fs5.unlinkSync(currentPath);
|
|
1769
1771
|
}
|
|
@@ -1797,8 +1799,8 @@ var RunResultStorageService = class {
|
|
|
1797
1799
|
constructor() {
|
|
1798
1800
|
const storageService = getStorageService();
|
|
1799
1801
|
const dataDir = storageService.getDataDir();
|
|
1800
|
-
this.runResultsDir =
|
|
1801
|
-
this.testScriptsDir =
|
|
1802
|
+
this.runResultsDir = path10.join(dataDir, "run-results");
|
|
1803
|
+
this.testScriptsDir = path10.join(dataDir, "test-scripts");
|
|
1802
1804
|
this.ensureDirectories();
|
|
1803
1805
|
}
|
|
1804
1806
|
/**
|
|
@@ -1824,7 +1826,7 @@ var RunResultStorageService = class {
|
|
|
1824
1826
|
const results = [];
|
|
1825
1827
|
for (const file of files) {
|
|
1826
1828
|
try {
|
|
1827
|
-
const content = fs5.readFileSync(
|
|
1829
|
+
const content = fs5.readFileSync(path10.join(this.runResultsDir, file), "utf-8");
|
|
1828
1830
|
results.push(JSON.parse(content));
|
|
1829
1831
|
} catch {
|
|
1830
1832
|
logger3.warn("Failed to read run result file", { file });
|
|
@@ -1839,7 +1841,7 @@ var RunResultStorageService = class {
|
|
|
1839
1841
|
* Get a run result by ID.
|
|
1840
1842
|
*/
|
|
1841
1843
|
getRunResult(runId) {
|
|
1842
|
-
const filePath =
|
|
1844
|
+
const filePath = path10.join(this.runResultsDir, `${runId}.json`);
|
|
1843
1845
|
if (!fs5.existsSync(filePath)) {
|
|
1844
1846
|
return void 0;
|
|
1845
1847
|
}
|
|
@@ -1854,7 +1856,7 @@ var RunResultStorageService = class {
|
|
|
1854
1856
|
* Save a run result.
|
|
1855
1857
|
*/
|
|
1856
1858
|
saveRunResult(result) {
|
|
1857
|
-
const filePath =
|
|
1859
|
+
const filePath = path10.join(this.runResultsDir, `${result.id}.json`);
|
|
1858
1860
|
fs5.writeFileSync(filePath, JSON.stringify(result, null, 2));
|
|
1859
1861
|
}
|
|
1860
1862
|
/**
|
|
@@ -1907,7 +1909,7 @@ var RunResultStorageService = class {
|
|
|
1907
1909
|
const scripts = [];
|
|
1908
1910
|
for (const file of files) {
|
|
1909
1911
|
try {
|
|
1910
|
-
const content = fs5.readFileSync(
|
|
1912
|
+
const content = fs5.readFileSync(path10.join(this.testScriptsDir, file), "utf-8");
|
|
1911
1913
|
scripts.push(JSON.parse(content));
|
|
1912
1914
|
} catch {
|
|
1913
1915
|
logger3.warn("Failed to read test script file", { file });
|
|
@@ -1922,7 +1924,7 @@ var RunResultStorageService = class {
|
|
|
1922
1924
|
* Get a test script by ID.
|
|
1923
1925
|
*/
|
|
1924
1926
|
getTestScript(testScriptId) {
|
|
1925
|
-
const filePath =
|
|
1927
|
+
const filePath = path10.join(this.testScriptsDir, `${testScriptId}.json`);
|
|
1926
1928
|
if (!fs5.existsSync(filePath)) {
|
|
1927
1929
|
return void 0;
|
|
1928
1930
|
}
|
|
@@ -1937,7 +1939,7 @@ var RunResultStorageService = class {
|
|
|
1937
1939
|
* Save a test script.
|
|
1938
1940
|
*/
|
|
1939
1941
|
saveTestScript(script) {
|
|
1940
|
-
const filePath =
|
|
1942
|
+
const filePath = path10.join(this.testScriptsDir, `${script.id}.json`);
|
|
1941
1943
|
fs5.writeFileSync(filePath, JSON.stringify(script, null, 2));
|
|
1942
1944
|
}
|
|
1943
1945
|
/**
|
|
@@ -1987,6 +1989,246 @@ function resetRunResultStorageService() {
|
|
|
1987
1989
|
instance = null;
|
|
1988
1990
|
}
|
|
1989
1991
|
|
|
1992
|
+
// packages/mcps/src/shared/llm-env-constants.ts
|
|
1993
|
+
var LLM_ENV_PREFERENCE_KEY = "llmEnv";
|
|
1994
|
+
var FORWARDABLE_LLM_ENV_NAMES = [
|
|
1995
|
+
"MUGGLE_LLM_PROVIDER",
|
|
1996
|
+
"MUGGLE_LLM_BASE_URL",
|
|
1997
|
+
"MUGGLE_LLM_API_KEY",
|
|
1998
|
+
"MUGGLE_LLM_MODEL",
|
|
1999
|
+
"MUGGLE_LLM_MODEL_PREDICTION",
|
|
2000
|
+
"MUGGLE_LLM_MODEL_SUMMARIZER",
|
|
2001
|
+
"MUGGLE_LLM_MODEL_EVAL",
|
|
2002
|
+
"MUGGLE_LLM_MAX_TOKENS",
|
|
2003
|
+
"MUGGLE_LLM_TEMPERATURE",
|
|
2004
|
+
"MUGGLE_LLM_TOP_P",
|
|
2005
|
+
"MUGGLE_LLM_TIMEOUT_MS"
|
|
2006
|
+
];
|
|
2007
|
+
|
|
2008
|
+
// packages/mcps/src/shared/preferences-types.ts
|
|
2009
|
+
var PreferenceKey = /* @__PURE__ */ ((PreferenceKey2) => {
|
|
2010
|
+
PreferenceKey2["AutoLogin"] = "autoLogin";
|
|
2011
|
+
PreferenceKey2["AutoSelectProject"] = "autoSelectProject";
|
|
2012
|
+
PreferenceKey2["AutoSelectLocalHost"] = "autoSelectLocalHost";
|
|
2013
|
+
PreferenceKey2["ShowElectronBrowser"] = "showElectronBrowser";
|
|
2014
|
+
PreferenceKey2["OpenTestResultsAfterRun"] = "openTestResultsAfterRun";
|
|
2015
|
+
PreferenceKey2["DefaultExecutionMode"] = "defaultExecutionMode";
|
|
2016
|
+
PreferenceKey2["SuggestRelatedUseCases"] = "suggestRelatedUseCases";
|
|
2017
|
+
PreferenceKey2["SuggestRelatedTestCases"] = "suggestRelatedTestCases";
|
|
2018
|
+
PreferenceKey2["AutoDetectChanges"] = "autoDetectChanges";
|
|
2019
|
+
PreferenceKey2["PostPRVisualWalkthrough"] = "postPRVisualWalkthrough";
|
|
2020
|
+
PreferenceKey2["AutoCreatePR"] = "autoCreatePR";
|
|
2021
|
+
PreferenceKey2["CheckForUpdates"] = "checkForUpdates";
|
|
2022
|
+
PreferenceKey2["VerboseOutput"] = "verboseOutput";
|
|
2023
|
+
PreferenceKey2["AutoUseWorktree"] = "autoUseWorktree";
|
|
2024
|
+
PreferenceKey2["AutoRebase"] = "autoRebase";
|
|
2025
|
+
PreferenceKey2["AutoCleanup"] = "autoCleanup";
|
|
2026
|
+
PreferenceKey2["AutoE2ETest"] = "autoE2ETest";
|
|
2027
|
+
PreferenceKey2["AutoResolveConflicts"] = "autoResolveConflicts";
|
|
2028
|
+
PreferenceKey2["AutoReuseValidationContext"] = "autoReuseValidationContext";
|
|
2029
|
+
PreferenceKey2["AutoRouteBuildToMuggleDo"] = "autoRouteBuildToMuggleDo";
|
|
2030
|
+
PreferenceKey2["AutoWatchPR"] = "autoWatchPR";
|
|
2031
|
+
PreferenceKey2["WatcherLifetime"] = "watcherLifetime";
|
|
2032
|
+
PreferenceKey2["ReusePreparePlan"] = "reusePreparePlan";
|
|
2033
|
+
return PreferenceKey2;
|
|
2034
|
+
})(PreferenceKey || {});
|
|
2035
|
+
var PreferenceValue = /* @__PURE__ */ ((PreferenceValue2) => {
|
|
2036
|
+
PreferenceValue2["Always"] = "always";
|
|
2037
|
+
PreferenceValue2["Ask"] = "ask";
|
|
2038
|
+
PreferenceValue2["Never"] = "never";
|
|
2039
|
+
PreferenceValue2["Local"] = "local";
|
|
2040
|
+
PreferenceValue2["Remote"] = "remote";
|
|
2041
|
+
PreferenceValue2["OneDay"] = "1d";
|
|
2042
|
+
PreferenceValue2["SevenDays"] = "7d";
|
|
2043
|
+
return PreferenceValue2;
|
|
2044
|
+
})(PreferenceValue || {});
|
|
2045
|
+
|
|
2046
|
+
// packages/mcps/src/shared/preferences-constants.ts
|
|
2047
|
+
var PREFERENCES_FILE_NAME = "preferences.json";
|
|
2048
|
+
var PREFERENCES_PROJECT_DIR_NAME = ".muggle-ai";
|
|
2049
|
+
var PREFERENCES_VERSION = 1;
|
|
2050
|
+
var DEFAULT_PREFERENCES = {
|
|
2051
|
+
["autoLogin" /* AutoLogin */]: "always" /* Always */,
|
|
2052
|
+
["autoSelectProject" /* AutoSelectProject */]: "always" /* Always */,
|
|
2053
|
+
["autoSelectLocalHost" /* AutoSelectLocalHost */]: "always" /* Always */,
|
|
2054
|
+
["showElectronBrowser" /* ShowElectronBrowser */]: "always" /* Always */,
|
|
2055
|
+
["openTestResultsAfterRun" /* OpenTestResultsAfterRun */]: "always" /* Always */,
|
|
2056
|
+
["defaultExecutionMode" /* DefaultExecutionMode */]: "local" /* Local */,
|
|
2057
|
+
["suggestRelatedUseCases" /* SuggestRelatedUseCases */]: "always" /* Always */,
|
|
2058
|
+
["suggestRelatedTestCases" /* SuggestRelatedTestCases */]: "always" /* Always */,
|
|
2059
|
+
["autoDetectChanges" /* AutoDetectChanges */]: "always" /* Always */,
|
|
2060
|
+
["postPRVisualWalkthrough" /* PostPRVisualWalkthrough */]: "always" /* Always */,
|
|
2061
|
+
["autoCreatePR" /* AutoCreatePR */]: "always" /* Always */,
|
|
2062
|
+
["checkForUpdates" /* CheckForUpdates */]: "always" /* Always */,
|
|
2063
|
+
["verboseOutput" /* VerboseOutput */]: "never" /* Never */,
|
|
2064
|
+
["autoUseWorktree" /* AutoUseWorktree */]: "always" /* Always */,
|
|
2065
|
+
["autoRebase" /* AutoRebase */]: "always" /* Always */,
|
|
2066
|
+
["autoCleanup" /* AutoCleanup */]: "always" /* Always */,
|
|
2067
|
+
["autoE2ETest" /* AutoE2ETest */]: "always" /* Always */,
|
|
2068
|
+
["autoResolveConflicts" /* AutoResolveConflicts */]: "always" /* Always */,
|
|
2069
|
+
["autoReuseValidationContext" /* AutoReuseValidationContext */]: "always" /* Always */,
|
|
2070
|
+
["autoRouteBuildToMuggleDo" /* AutoRouteBuildToMuggleDo */]: "always" /* Always */,
|
|
2071
|
+
["autoWatchPR" /* AutoWatchPR */]: "always" /* Always */,
|
|
2072
|
+
["reusePreparePlan" /* ReusePreparePlan */]: "always" /* Always */,
|
|
2073
|
+
["watcherLifetime" /* WatcherLifetime */]: "7d" /* SevenDays */
|
|
2074
|
+
};
|
|
2075
|
+
var ALWAYS_ASK_NEVER = [
|
|
2076
|
+
"always" /* Always */,
|
|
2077
|
+
"ask" /* Ask */,
|
|
2078
|
+
"never" /* Never */
|
|
2079
|
+
];
|
|
2080
|
+
var ALWAYS_ASK = [
|
|
2081
|
+
"always" /* Always */,
|
|
2082
|
+
"ask" /* Ask */
|
|
2083
|
+
];
|
|
2084
|
+
var LOCAL_REMOTE_ASK = [
|
|
2085
|
+
"local" /* Local */,
|
|
2086
|
+
"remote" /* Remote */,
|
|
2087
|
+
"ask" /* Ask */
|
|
2088
|
+
];
|
|
2089
|
+
var WATCHER_LIFETIMES = [
|
|
2090
|
+
"1d" /* OneDay */,
|
|
2091
|
+
"7d" /* SevenDays */,
|
|
2092
|
+
"never" /* Never */
|
|
2093
|
+
];
|
|
2094
|
+
var PREFERENCE_ALLOWED_VALUES = {
|
|
2095
|
+
["autoLogin" /* AutoLogin */]: ALWAYS_ASK_NEVER,
|
|
2096
|
+
["autoSelectProject" /* AutoSelectProject */]: ALWAYS_ASK_NEVER,
|
|
2097
|
+
["autoSelectLocalHost" /* AutoSelectLocalHost */]: ALWAYS_ASK_NEVER,
|
|
2098
|
+
["showElectronBrowser" /* ShowElectronBrowser */]: ALWAYS_ASK_NEVER,
|
|
2099
|
+
["openTestResultsAfterRun" /* OpenTestResultsAfterRun */]: ALWAYS_ASK_NEVER,
|
|
2100
|
+
["defaultExecutionMode" /* DefaultExecutionMode */]: LOCAL_REMOTE_ASK,
|
|
2101
|
+
["suggestRelatedUseCases" /* SuggestRelatedUseCases */]: ALWAYS_ASK_NEVER,
|
|
2102
|
+
["suggestRelatedTestCases" /* SuggestRelatedTestCases */]: ALWAYS_ASK_NEVER,
|
|
2103
|
+
["autoDetectChanges" /* AutoDetectChanges */]: ALWAYS_ASK_NEVER,
|
|
2104
|
+
["postPRVisualWalkthrough" /* PostPRVisualWalkthrough */]: ALWAYS_ASK_NEVER,
|
|
2105
|
+
["autoCreatePR" /* AutoCreatePR */]: ALWAYS_ASK_NEVER,
|
|
2106
|
+
["checkForUpdates" /* CheckForUpdates */]: ALWAYS_ASK_NEVER,
|
|
2107
|
+
["verboseOutput" /* VerboseOutput */]: ALWAYS_ASK_NEVER,
|
|
2108
|
+
["autoUseWorktree" /* AutoUseWorktree */]: ALWAYS_ASK_NEVER,
|
|
2109
|
+
["autoRebase" /* AutoRebase */]: ALWAYS_ASK_NEVER,
|
|
2110
|
+
["autoCleanup" /* AutoCleanup */]: ALWAYS_ASK_NEVER,
|
|
2111
|
+
["autoE2ETest" /* AutoE2ETest */]: ALWAYS_ASK,
|
|
2112
|
+
["autoResolveConflicts" /* AutoResolveConflicts */]: ALWAYS_ASK_NEVER,
|
|
2113
|
+
["autoReuseValidationContext" /* AutoReuseValidationContext */]: ALWAYS_ASK_NEVER,
|
|
2114
|
+
["autoRouteBuildToMuggleDo" /* AutoRouteBuildToMuggleDo */]: ALWAYS_ASK_NEVER,
|
|
2115
|
+
["autoWatchPR" /* AutoWatchPR */]: ALWAYS_ASK_NEVER,
|
|
2116
|
+
["reusePreparePlan" /* ReusePreparePlan */]: ALWAYS_ASK_NEVER,
|
|
2117
|
+
["watcherLifetime" /* WatcherLifetime */]: WATCHER_LIFETIMES
|
|
2118
|
+
};
|
|
2119
|
+
var PREFERENCES_SCHEMA = {
|
|
2120
|
+
["autoLogin" /* AutoLogin */]: {
|
|
2121
|
+
description: "When a tool requires auth and saved credentials exist, reuse them without prompting"
|
|
2122
|
+
},
|
|
2123
|
+
["autoSelectProject" /* AutoSelectProject */]: {
|
|
2124
|
+
description: "When a skill needs a Muggle Test project and one was used previously in this repo, reuse it without prompting"
|
|
2125
|
+
},
|
|
2126
|
+
["autoSelectLocalHost" /* AutoSelectLocalHost */]: {
|
|
2127
|
+
description: "When running local tests, reuse the dev server URL from the previous run in this repo without prompting"
|
|
2128
|
+
},
|
|
2129
|
+
["showElectronBrowser" /* ShowElectronBrowser */]: {
|
|
2130
|
+
description: "When running local E2E tests, show the Electron browser window"
|
|
2131
|
+
},
|
|
2132
|
+
["openTestResultsAfterRun" /* OpenTestResultsAfterRun */]: {
|
|
2133
|
+
description: "After a local E2E test run completes, open the per-run results page on Muggle Test dashboard"
|
|
2134
|
+
},
|
|
2135
|
+
["defaultExecutionMode" /* DefaultExecutionMode */]: {
|
|
2136
|
+
description: "When a skill supports both local and remote test execution, which to default to"
|
|
2137
|
+
},
|
|
2138
|
+
["suggestRelatedUseCases" /* SuggestRelatedUseCases */]: {
|
|
2139
|
+
description: "After creating or running a use case, suggest related use cases to add"
|
|
2140
|
+
},
|
|
2141
|
+
["suggestRelatedTestCases" /* SuggestRelatedTestCases */]: {
|
|
2142
|
+
description: "After creating or running a test case, suggest related test cases to add"
|
|
2143
|
+
},
|
|
2144
|
+
["autoDetectChanges" /* AutoDetectChanges */]: {
|
|
2145
|
+
description: "When running muggle-test, scan local git changes and map to affected test cases"
|
|
2146
|
+
},
|
|
2147
|
+
["postPRVisualWalkthrough" /* PostPRVisualWalkthrough */]: {
|
|
2148
|
+
description: "After test results are available, post visual walkthrough comment with screenshots to the PR"
|
|
2149
|
+
},
|
|
2150
|
+
["autoCreatePR" /* AutoCreatePR */]: {
|
|
2151
|
+
description: "At the end of the muggle-do dev cycle (or when a test needs an open PR to post results to), push the branch and open a PR without prompting"
|
|
2152
|
+
},
|
|
2153
|
+
["checkForUpdates" /* CheckForUpdates */]: {
|
|
2154
|
+
description: "At session start, check if a newer Muggle Test version is available and notify"
|
|
2155
|
+
},
|
|
2156
|
+
["verboseOutput" /* VerboseOutput */]: {
|
|
2157
|
+
description: "Show detailed progress logs during skill and tool execution"
|
|
2158
|
+
},
|
|
2159
|
+
["autoUseWorktree" /* AutoUseWorktree */]: {
|
|
2160
|
+
description: "When starting non-trivial development work, create a git worktree to isolate the change from the current checkout"
|
|
2161
|
+
},
|
|
2162
|
+
["autoRebase" /* AutoRebase */]: {
|
|
2163
|
+
description: "Before running dev servers or E2E tests on a branch behind origin, rebase onto the default branch first"
|
|
2164
|
+
},
|
|
2165
|
+
["autoCleanup" /* AutoCleanup */]: {
|
|
2166
|
+
description: "After a PR is merged, automatically run the cleanup sequence: remove worktree, delete branches, clear local artifacts, prune [gone] branches"
|
|
2167
|
+
},
|
|
2168
|
+
["autoE2ETest" /* AutoE2ETest */]: {
|
|
2169
|
+
description: "Run Stage 6 (E2E acceptance) at the end of every /muggle-do cycle (default always \u2014 running E2E is the point of muggle-do; never is not an option)"
|
|
2170
|
+
},
|
|
2171
|
+
["autoResolveConflicts" /* AutoResolveConflicts */]: {
|
|
2172
|
+
description: "When a rebase onto the default branch hits conflicts, resolve them autonomously behind a verify-or-rollback gate instead of aborting and escalating"
|
|
2173
|
+
},
|
|
2174
|
+
["autoReuseValidationContext" /* AutoReuseValidationContext */]: {
|
|
2175
|
+
description: "When a prior session left an E2E validation context for this working tree, reuse it instead of re-asking the validation questions"
|
|
2176
|
+
},
|
|
2177
|
+
["autoRouteBuildToMuggleDo" /* AutoRouteBuildToMuggleDo */]: {
|
|
2178
|
+
description: "When a prompt looks like a build/implement/fix request, route it through the /muggle-do pipeline (requirements \u2192 build \u2192 impact \u2192 tests \u2192 E2E \u2192 PR \u2192 watcher)"
|
|
2179
|
+
},
|
|
2180
|
+
["autoWatchPR" /* AutoWatchPR */]: {
|
|
2181
|
+
description: "After a test run opens a PR, start a muggle-pr-followup watcher that polls for new reviews and hands them to /muggle-do"
|
|
2182
|
+
},
|
|
2183
|
+
["reusePreparePlan" /* ReusePreparePlan */]: {
|
|
2184
|
+
description: "Reuse the saved prepare plan for this stack (skip discovery, jump to check-running + smoke-test) instead of rediscovering from scratch"
|
|
2185
|
+
},
|
|
2186
|
+
["watcherLifetime" /* WatcherLifetime */]: {
|
|
2187
|
+
description: "How long a muggle-pr-followup watch loop polls before retiring itself \u2014 1d, 7d, or never (unbounded, which leaves no time-based reaper for an orphaned loop)"
|
|
2188
|
+
}
|
|
2189
|
+
};
|
|
2190
|
+
|
|
2191
|
+
// packages/mcps/src/shared/llm-env-service.ts
|
|
2192
|
+
function resolveLlmEnvOverrides(dataDirOverride2) {
|
|
2193
|
+
const filePath = path10.join(getDataDir(), PREFERENCES_FILE_NAME);
|
|
2194
|
+
let block;
|
|
2195
|
+
try {
|
|
2196
|
+
if (!fs5.existsSync(filePath)) {
|
|
2197
|
+
return {};
|
|
2198
|
+
}
|
|
2199
|
+
const raw = JSON.parse(fs5.readFileSync(filePath, "utf-8"));
|
|
2200
|
+
block = raw[LLM_ENV_PREFERENCE_KEY];
|
|
2201
|
+
} catch {
|
|
2202
|
+
return {};
|
|
2203
|
+
}
|
|
2204
|
+
if (!block || typeof block !== "object" || Array.isArray(block)) {
|
|
2205
|
+
return {};
|
|
2206
|
+
}
|
|
2207
|
+
const overrides = {};
|
|
2208
|
+
for (const [name, value] of Object.entries(block)) {
|
|
2209
|
+
if (!FORWARDABLE_LLM_ENV_NAMES.includes(name)) {
|
|
2210
|
+
continue;
|
|
2211
|
+
}
|
|
2212
|
+
if (value === null || value === void 0 || value === "") {
|
|
2213
|
+
continue;
|
|
2214
|
+
}
|
|
2215
|
+
overrides[name] = String(value);
|
|
2216
|
+
}
|
|
2217
|
+
return overrides;
|
|
2218
|
+
}
|
|
2219
|
+
function applyLlmEnvOverrides(baseEnv, dataDirOverride2) {
|
|
2220
|
+
const overrides = resolveLlmEnvOverrides();
|
|
2221
|
+
const appliedNames = [];
|
|
2222
|
+
for (const [name, value] of Object.entries(overrides)) {
|
|
2223
|
+
if (baseEnv[name] !== void 0 && baseEnv[name] !== "") {
|
|
2224
|
+
continue;
|
|
2225
|
+
}
|
|
2226
|
+
baseEnv[name] = value;
|
|
2227
|
+
appliedNames.push(name);
|
|
2228
|
+
}
|
|
2229
|
+
return { env: baseEnv, appliedNames };
|
|
2230
|
+
}
|
|
2231
|
+
|
|
1990
2232
|
// packages/mcps/src/mcp/local/services/replay-url-rewrite.ts
|
|
1991
2233
|
function rewriteActionScriptUrls(params) {
|
|
1992
2234
|
const { actionScript, originalUrl, localUrl } = params;
|
|
@@ -2162,13 +2404,13 @@ var MODIFY_LOCK_STALE_MS = 5e3;
|
|
|
2162
2404
|
|
|
2163
2405
|
// packages/mcps/src/mcp/local/services/local-execution-lock.ts
|
|
2164
2406
|
function lockFilePath() {
|
|
2165
|
-
return
|
|
2407
|
+
return path10.join(getDataDir(), LOCK_FILE_NAME);
|
|
2166
2408
|
}
|
|
2167
2409
|
function modifyLockPath() {
|
|
2168
2410
|
return lockFilePath() + MODIFY_LOCK_SUFFIX;
|
|
2169
2411
|
}
|
|
2170
2412
|
function normalizeCwd(cwd) {
|
|
2171
|
-
const resolved =
|
|
2413
|
+
const resolved = path10.resolve(cwd);
|
|
2172
2414
|
return os4.platform() === "win32" ? resolved.toLowerCase() : resolved;
|
|
2173
2415
|
}
|
|
2174
2416
|
function pidIsAlive(pid) {
|
|
@@ -2184,7 +2426,7 @@ function pidIsAlive(pid) {
|
|
|
2184
2426
|
}
|
|
2185
2427
|
async function readState() {
|
|
2186
2428
|
try {
|
|
2187
|
-
const raw = await
|
|
2429
|
+
const raw = await fs9.readFile(lockFilePath(), "utf-8");
|
|
2188
2430
|
return JSON.parse(raw);
|
|
2189
2431
|
} catch (error) {
|
|
2190
2432
|
if (error.code === "ENOENT") return null;
|
|
@@ -2192,28 +2434,28 @@ async function readState() {
|
|
|
2192
2434
|
}
|
|
2193
2435
|
}
|
|
2194
2436
|
async function writeState(state2) {
|
|
2195
|
-
await
|
|
2437
|
+
await fs9.writeFile(lockFilePath(), JSON.stringify(state2, null, 2), "utf-8");
|
|
2196
2438
|
}
|
|
2197
2439
|
async function deleteStateFile() {
|
|
2198
2440
|
try {
|
|
2199
|
-
await
|
|
2441
|
+
await fs9.unlink(lockFilePath());
|
|
2200
2442
|
} catch (error) {
|
|
2201
2443
|
if (error.code !== "ENOENT") throw error;
|
|
2202
2444
|
}
|
|
2203
2445
|
}
|
|
2204
2446
|
async function withModifyLock(fn) {
|
|
2205
|
-
await
|
|
2447
|
+
await fs9.mkdir(path10.dirname(modifyLockPath()), { recursive: true });
|
|
2206
2448
|
const modifyPath = modifyLockPath();
|
|
2207
2449
|
let fileHandle = null;
|
|
2208
2450
|
while (fileHandle === null) {
|
|
2209
2451
|
try {
|
|
2210
|
-
fileHandle = await
|
|
2452
|
+
fileHandle = await fs9.open(modifyPath, "wx");
|
|
2211
2453
|
} catch (error) {
|
|
2212
2454
|
if (error.code !== "EEXIST") throw error;
|
|
2213
2455
|
try {
|
|
2214
|
-
const stat3 = await
|
|
2456
|
+
const stat3 = await fs9.stat(modifyPath);
|
|
2215
2457
|
if (Date.now() - stat3.mtimeMs > MODIFY_LOCK_STALE_MS) {
|
|
2216
|
-
await
|
|
2458
|
+
await fs9.unlink(modifyPath).catch(() => void 0);
|
|
2217
2459
|
continue;
|
|
2218
2460
|
}
|
|
2219
2461
|
} catch {
|
|
@@ -2226,7 +2468,7 @@ async function withModifyLock(fn) {
|
|
|
2226
2468
|
return await fn();
|
|
2227
2469
|
} finally {
|
|
2228
2470
|
await fileHandle.close().catch(() => void 0);
|
|
2229
|
-
await
|
|
2471
|
+
await fs9.unlink(modifyPath).catch(() => void 0);
|
|
2230
2472
|
}
|
|
2231
2473
|
}
|
|
2232
2474
|
async function tryAcquireOnce(params) {
|
|
@@ -2365,12 +2607,12 @@ function extractStudioCloudRefs(studioReturnedResult) {
|
|
|
2365
2607
|
return refs;
|
|
2366
2608
|
}
|
|
2367
2609
|
async function readCloudRefsFile(inputFilePath) {
|
|
2368
|
-
const cloudRefsPath =
|
|
2369
|
-
|
|
2370
|
-
`cloudrefs_${
|
|
2610
|
+
const cloudRefsPath = path10.join(
|
|
2611
|
+
path10.dirname(inputFilePath),
|
|
2612
|
+
`cloudrefs_${path10.basename(inputFilePath)}`
|
|
2371
2613
|
);
|
|
2372
2614
|
try {
|
|
2373
|
-
return JSON.parse(await
|
|
2615
|
+
return JSON.parse(await fs9.readFile(cloudRefsPath, "utf-8"));
|
|
2374
2616
|
} catch {
|
|
2375
2617
|
return void 0;
|
|
2376
2618
|
}
|
|
@@ -2389,15 +2631,15 @@ function getAuthenticatedUserId() {
|
|
|
2389
2631
|
}
|
|
2390
2632
|
async function findPackageJsonAsync() {
|
|
2391
2633
|
const currentFileUrl = import.meta.url;
|
|
2392
|
-
const currentDir =
|
|
2634
|
+
const currentDir = path10.dirname(fileURLToPath(currentFileUrl));
|
|
2393
2635
|
const candidatePaths = [
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2636
|
+
path10.resolve(currentDir, "../../../package.json"),
|
|
2637
|
+
path10.resolve(currentDir, "../package.json"),
|
|
2638
|
+
path10.resolve(currentDir, "../../package.json")
|
|
2397
2639
|
];
|
|
2398
2640
|
for (const candidatePath of candidatePaths) {
|
|
2399
2641
|
try {
|
|
2400
|
-
const packageJsonRaw = await
|
|
2642
|
+
const packageJsonRaw = await fs9.readFile(candidatePath, "utf-8");
|
|
2401
2643
|
const packageJson = JSON.parse(packageJsonRaw);
|
|
2402
2644
|
if (packageJson.name === "@muggleai/works" && packageJson.version && packageJson.muggleConfig?.electronAppVersion) {
|
|
2403
2645
|
return {
|
|
@@ -2443,20 +2685,20 @@ function buildStudioAuthContent() {
|
|
|
2443
2685
|
}
|
|
2444
2686
|
async function ensureTempDir() {
|
|
2445
2687
|
const config = getConfig();
|
|
2446
|
-
const tempDir =
|
|
2447
|
-
await
|
|
2688
|
+
const tempDir = path10.join(config.localQa.dataDir, "temp");
|
|
2689
|
+
await fs9.mkdir(tempDir, { recursive: true });
|
|
2448
2690
|
return tempDir;
|
|
2449
2691
|
}
|
|
2450
2692
|
async function writeTempFile(params) {
|
|
2451
2693
|
const tempDir = await ensureTempDir();
|
|
2452
|
-
const filePath =
|
|
2453
|
-
await
|
|
2694
|
+
const filePath = path10.join(tempDir, params.filename);
|
|
2695
|
+
await fs9.writeFile(filePath, JSON.stringify(params.data, null, 2));
|
|
2454
2696
|
return filePath;
|
|
2455
2697
|
}
|
|
2456
2698
|
async function cleanupTempFiles(params) {
|
|
2457
2699
|
for (const filePath of params.filePaths) {
|
|
2458
2700
|
try {
|
|
2459
|
-
await
|
|
2701
|
+
await fs9.unlink(filePath);
|
|
2460
2702
|
} catch {
|
|
2461
2703
|
}
|
|
2462
2704
|
}
|
|
@@ -2464,12 +2706,12 @@ async function cleanupTempFiles(params) {
|
|
|
2464
2706
|
async function moveResultsToArtifacts(params) {
|
|
2465
2707
|
const storageService = getStorageService();
|
|
2466
2708
|
const sessionsDir = storageService.getSessionsDir();
|
|
2467
|
-
const artifactsDir =
|
|
2468
|
-
const actionScriptPath =
|
|
2469
|
-
await
|
|
2470
|
-
await
|
|
2709
|
+
const artifactsDir = path10.join(sessionsDir, params.runId);
|
|
2710
|
+
const actionScriptPath = path10.join(artifactsDir, "action-script.json");
|
|
2711
|
+
await fs9.mkdir(artifactsDir, { recursive: true });
|
|
2712
|
+
await fs9.copyFile(params.generatedScriptPath, actionScriptPath);
|
|
2471
2713
|
try {
|
|
2472
|
-
await
|
|
2714
|
+
await fs9.unlink(params.generatedScriptPath);
|
|
2473
2715
|
} catch {
|
|
2474
2716
|
}
|
|
2475
2717
|
return artifactsDir;
|
|
@@ -2477,13 +2719,13 @@ async function moveResultsToArtifacts(params) {
|
|
|
2477
2719
|
async function writeExecutionLogs(params) {
|
|
2478
2720
|
const storageService = getStorageService();
|
|
2479
2721
|
const sessionsDir = storageService.getSessionsDir();
|
|
2480
|
-
const artifactsDir =
|
|
2481
|
-
await
|
|
2482
|
-
const stdoutPath =
|
|
2483
|
-
const stderrPath =
|
|
2722
|
+
const artifactsDir = path10.join(sessionsDir, params.runId);
|
|
2723
|
+
await fs9.mkdir(artifactsDir, { recursive: true });
|
|
2724
|
+
const stdoutPath = path10.join(artifactsDir, "stdout.log");
|
|
2725
|
+
const stderrPath = path10.join(artifactsDir, "stderr.log");
|
|
2484
2726
|
await Promise.all([
|
|
2485
|
-
|
|
2486
|
-
|
|
2727
|
+
fs9.writeFile(stdoutPath, params.stdout, "utf-8"),
|
|
2728
|
+
fs9.writeFile(stderrPath, params.stderr, "utf-8")
|
|
2487
2729
|
]);
|
|
2488
2730
|
logger4.info("Wrote execution logs to artifacts directory", {
|
|
2489
2731
|
runId: params.runId,
|
|
@@ -2493,10 +2735,10 @@ async function writeExecutionLogs(params) {
|
|
|
2493
2735
|
async function preserveElectronRuntimeArtifacts(params) {
|
|
2494
2736
|
try {
|
|
2495
2737
|
const tempDir = await ensureTempDir();
|
|
2496
|
-
const markerPath =
|
|
2738
|
+
const markerPath = path10.join(tempDir, `${params.runId}_runtime_dir.txt`);
|
|
2497
2739
|
let runtimeDir = null;
|
|
2498
2740
|
try {
|
|
2499
|
-
const marker = await
|
|
2741
|
+
const marker = await fs9.readFile(markerPath, "utf-8");
|
|
2500
2742
|
const trimmed = marker.trim();
|
|
2501
2743
|
if (trimmed.length > 0) runtimeDir = trimmed;
|
|
2502
2744
|
} catch (markerReadError) {
|
|
@@ -2518,25 +2760,25 @@ async function preserveElectronRuntimeArtifacts(params) {
|
|
|
2518
2760
|
return;
|
|
2519
2761
|
}
|
|
2520
2762
|
try {
|
|
2521
|
-
await
|
|
2763
|
+
await fs9.access(runtimeDir);
|
|
2522
2764
|
} catch {
|
|
2523
2765
|
logger4.warn("Electron runtime dir referenced but missing on disk", {
|
|
2524
2766
|
runId: params.runId,
|
|
2525
2767
|
runtimeDir
|
|
2526
2768
|
});
|
|
2527
|
-
await
|
|
2769
|
+
await fs9.unlink(markerPath).catch(() => void 0);
|
|
2528
2770
|
return;
|
|
2529
2771
|
}
|
|
2530
2772
|
const storage = getStorageService();
|
|
2531
|
-
const destDir =
|
|
2532
|
-
await
|
|
2533
|
-
await
|
|
2773
|
+
const destDir = path10.join(storage.getSessionsDir(), params.runId, "electron-runtime");
|
|
2774
|
+
await fs9.mkdir(destDir, { recursive: true });
|
|
2775
|
+
await fs9.cp(runtimeDir, destDir, { recursive: true });
|
|
2534
2776
|
logger4.info("Preserved Electron runtime artifacts", {
|
|
2535
2777
|
runId: params.runId,
|
|
2536
2778
|
sourceDir: runtimeDir,
|
|
2537
2779
|
destDir
|
|
2538
2780
|
});
|
|
2539
|
-
await
|
|
2781
|
+
await fs9.unlink(markerPath).catch(() => void 0);
|
|
2540
2782
|
} catch (preserveError) {
|
|
2541
2783
|
logger4.warn("Failed to preserve Electron runtime artifacts", {
|
|
2542
2784
|
runId: params.runId,
|
|
@@ -2545,14 +2787,14 @@ async function preserveElectronRuntimeArtifacts(params) {
|
|
|
2545
2787
|
}
|
|
2546
2788
|
}
|
|
2547
2789
|
async function scanForRuntimeDirByMtime(params) {
|
|
2548
|
-
const runtimeRoot =
|
|
2790
|
+
const runtimeRoot = path10.join(params.electronCwd, "user_data", "runtime");
|
|
2549
2791
|
try {
|
|
2550
|
-
const entries = await
|
|
2792
|
+
const entries = await fs9.readdir(runtimeRoot, { withFileTypes: true });
|
|
2551
2793
|
let bestCandidate = null;
|
|
2552
2794
|
for (const entry of entries) {
|
|
2553
2795
|
if (!entry.isDirectory()) continue;
|
|
2554
|
-
const fullPath =
|
|
2555
|
-
const stat3 = await
|
|
2796
|
+
const fullPath = path10.join(runtimeRoot, entry.name);
|
|
2797
|
+
const stat3 = await fs9.stat(fullPath);
|
|
2556
2798
|
if (stat3.mtimeMs < params.spawnAtMs) continue;
|
|
2557
2799
|
if (bestCandidate === null || stat3.mtimeMs > bestCandidate.mtimeMs) {
|
|
2558
2800
|
bestCandidate = { path: fullPath, mtimeMs: stat3.mtimeMs };
|
|
@@ -2597,15 +2839,18 @@ async function executeElectronAppAsync(params) {
|
|
|
2597
2839
|
if (params.freshSession) {
|
|
2598
2840
|
spawnArgs.push("--fresh-session");
|
|
2599
2841
|
}
|
|
2842
|
+
const { env: electronEnv, appliedNames: llmEnvOverrideNames } = applyLlmEnvOverrides({
|
|
2843
|
+
...process.env
|
|
2844
|
+
});
|
|
2845
|
+
delete electronEnv.ELECTRON_RUN_AS_NODE;
|
|
2600
2846
|
logger4.info("Spawning electron-app for local execution", {
|
|
2601
2847
|
runId: params.runId,
|
|
2602
2848
|
mode,
|
|
2603
2849
|
electronAppPath,
|
|
2604
|
-
spawnArgs
|
|
2850
|
+
spawnArgs,
|
|
2851
|
+
llmEnvOverrideNames
|
|
2605
2852
|
});
|
|
2606
|
-
const
|
|
2607
|
-
delete electronEnv.ELECTRON_RUN_AS_NODE;
|
|
2608
|
-
const electronCwd = path9.dirname(electronAppPath);
|
|
2853
|
+
const electronCwd = path10.dirname(electronAppPath);
|
|
2609
2854
|
const child = spawn(electronAppPath, spawnArgs, {
|
|
2610
2855
|
stdio: ["ignore", "pipe", "pipe"],
|
|
2611
2856
|
env: electronEnv,
|
|
@@ -2620,7 +2865,7 @@ async function executeElectronAppAsync(params) {
|
|
|
2620
2865
|
capturedStderr: ""
|
|
2621
2866
|
};
|
|
2622
2867
|
activeProcesses.set(params.runId, processInfo);
|
|
2623
|
-
return await new Promise((
|
|
2868
|
+
return await new Promise((resolve5, reject) => {
|
|
2624
2869
|
let settled = false;
|
|
2625
2870
|
const finalize = (result) => {
|
|
2626
2871
|
if (settled) {
|
|
@@ -2632,7 +2877,7 @@ async function executeElectronAppAsync(params) {
|
|
|
2632
2877
|
}
|
|
2633
2878
|
activeProcesses.delete(params.runId);
|
|
2634
2879
|
if (result.ok) {
|
|
2635
|
-
|
|
2880
|
+
resolve5(result.payload);
|
|
2636
2881
|
} else {
|
|
2637
2882
|
reject(result.payload);
|
|
2638
2883
|
}
|
|
@@ -2787,17 +3032,17 @@ ${executionResult.stdout}
|
|
|
2787
3032
|
STDERR:
|
|
2788
3033
|
${executionResult.stderr}`;
|
|
2789
3034
|
const sessionsDir = getStorageService().getSessionsDir();
|
|
2790
|
-
const artifactsDir2 =
|
|
2791
|
-
const generatedScriptPath2 =
|
|
2792
|
-
|
|
2793
|
-
`gen_${
|
|
3035
|
+
const artifactsDir2 = path10.join(sessionsDir, runId);
|
|
3036
|
+
const generatedScriptPath2 = path10.join(
|
|
3037
|
+
path10.dirname(inputFilePath),
|
|
3038
|
+
`gen_${path10.basename(inputFilePath)}`
|
|
2794
3039
|
);
|
|
2795
3040
|
let failedStudioResult;
|
|
2796
3041
|
try {
|
|
2797
|
-
const failedScriptRaw = await
|
|
3042
|
+
const failedScriptRaw = await fs9.readFile(generatedScriptPath2, "utf-8");
|
|
2798
3043
|
failedStudioResult = JSON.parse(failedScriptRaw);
|
|
2799
|
-
await
|
|
2800
|
-
await
|
|
3044
|
+
await fs9.copyFile(generatedScriptPath2, path10.join(artifactsDir2, "action-script.json"));
|
|
3045
|
+
await fs9.unlink(generatedScriptPath2).catch(() => {
|
|
2801
3046
|
});
|
|
2802
3047
|
} catch {
|
|
2803
3048
|
}
|
|
@@ -2826,11 +3071,11 @@ ${executionResult.stderr}`;
|
|
|
2826
3071
|
errorMessage: failureMessage
|
|
2827
3072
|
};
|
|
2828
3073
|
}
|
|
2829
|
-
const generatedScriptPath =
|
|
2830
|
-
|
|
2831
|
-
`gen_${
|
|
3074
|
+
const generatedScriptPath = path10.join(
|
|
3075
|
+
path10.dirname(inputFilePath),
|
|
3076
|
+
`gen_${path10.basename(inputFilePath)}`
|
|
2832
3077
|
);
|
|
2833
|
-
const generatedScriptRaw = await
|
|
3078
|
+
const generatedScriptRaw = await fs9.readFile(generatedScriptPath, "utf-8");
|
|
2834
3079
|
const generatedScript = JSON.parse(generatedScriptRaw);
|
|
2835
3080
|
const generatedSteps = generatedScript.steps;
|
|
2836
3081
|
if (!Array.isArray(generatedSteps)) {
|
|
@@ -2973,7 +3218,7 @@ STDOUT:
|
|
|
2973
3218
|
${executionResult.stdout}
|
|
2974
3219
|
STDERR:
|
|
2975
3220
|
${executionResult.stderr}`;
|
|
2976
|
-
const artifactsDir2 =
|
|
3221
|
+
const artifactsDir2 = path10.join(getStorageService().getSessionsDir(), runId);
|
|
2977
3222
|
storage.updateRunResult(runId, {
|
|
2978
3223
|
status: "failed",
|
|
2979
3224
|
executionTimeMs,
|
|
@@ -2991,7 +3236,7 @@ ${executionResult.stderr}`;
|
|
|
2991
3236
|
errorMessage: failureMessage
|
|
2992
3237
|
};
|
|
2993
3238
|
}
|
|
2994
|
-
const artifactsDir =
|
|
3239
|
+
const artifactsDir = path10.join(getStorageService().getSessionsDir(), runId);
|
|
2995
3240
|
const replayStudioResult = await readCloudRefsFile(inputFilePath);
|
|
2996
3241
|
const replayStudioCloudRefs = extractStudioCloudRefs(replayStudioResult);
|
|
2997
3242
|
storage.updateRunResult(runId, {
|
|
@@ -3428,7 +3673,7 @@ var PREFS_FILENAME = "preferences.json";
|
|
|
3428
3673
|
var OAUTH_SESSION_FILENAME = "oauth-session.json";
|
|
3429
3674
|
var RELEASE_MANIFEST_FILENAME = "release-manifest.json";
|
|
3430
3675
|
function getDataDir3() {
|
|
3431
|
-
return
|
|
3676
|
+
return path10.join(os4.homedir(), DATA_DIR_NAME2);
|
|
3432
3677
|
}
|
|
3433
3678
|
|
|
3434
3679
|
var cachedInstallId;
|
|
@@ -6257,186 +6502,17 @@ var CleanupSessionsInputSchema = z.object({
|
|
|
6257
6502
|
max_age_days: z.number().int().min(0).optional().describe("Maximum age of sessions to keep (in days). Sessions older than this will be deleted. Defaults to 30.")
|
|
6258
6503
|
});
|
|
6259
6504
|
var EmptyInputSchema2 = z.object({});
|
|
6260
|
-
|
|
6261
|
-
// packages/mcps/src/shared/preferences-types.ts
|
|
6262
|
-
var PreferenceKey = /* @__PURE__ */ ((PreferenceKey2) => {
|
|
6263
|
-
PreferenceKey2["AutoLogin"] = "autoLogin";
|
|
6264
|
-
PreferenceKey2["AutoSelectProject"] = "autoSelectProject";
|
|
6265
|
-
PreferenceKey2["AutoSelectLocalHost"] = "autoSelectLocalHost";
|
|
6266
|
-
PreferenceKey2["ShowElectronBrowser"] = "showElectronBrowser";
|
|
6267
|
-
PreferenceKey2["OpenTestResultsAfterRun"] = "openTestResultsAfterRun";
|
|
6268
|
-
PreferenceKey2["DefaultExecutionMode"] = "defaultExecutionMode";
|
|
6269
|
-
PreferenceKey2["SuggestRelatedUseCases"] = "suggestRelatedUseCases";
|
|
6270
|
-
PreferenceKey2["SuggestRelatedTestCases"] = "suggestRelatedTestCases";
|
|
6271
|
-
PreferenceKey2["AutoDetectChanges"] = "autoDetectChanges";
|
|
6272
|
-
PreferenceKey2["PostPRVisualWalkthrough"] = "postPRVisualWalkthrough";
|
|
6273
|
-
PreferenceKey2["AutoCreatePR"] = "autoCreatePR";
|
|
6274
|
-
PreferenceKey2["CheckForUpdates"] = "checkForUpdates";
|
|
6275
|
-
PreferenceKey2["VerboseOutput"] = "verboseOutput";
|
|
6276
|
-
PreferenceKey2["AutoUseWorktree"] = "autoUseWorktree";
|
|
6277
|
-
PreferenceKey2["AutoRebase"] = "autoRebase";
|
|
6278
|
-
PreferenceKey2["AutoCleanup"] = "autoCleanup";
|
|
6279
|
-
PreferenceKey2["AutoE2ETest"] = "autoE2ETest";
|
|
6280
|
-
PreferenceKey2["AutoResolveConflicts"] = "autoResolveConflicts";
|
|
6281
|
-
PreferenceKey2["AutoReuseValidationContext"] = "autoReuseValidationContext";
|
|
6282
|
-
PreferenceKey2["AutoRouteBuildToMuggleDo"] = "autoRouteBuildToMuggleDo";
|
|
6283
|
-
PreferenceKey2["AutoWatchPR"] = "autoWatchPR";
|
|
6284
|
-
PreferenceKey2["ReusePreparePlan"] = "reusePreparePlan";
|
|
6285
|
-
return PreferenceKey2;
|
|
6286
|
-
})(PreferenceKey || {});
|
|
6287
|
-
var PreferenceValue = /* @__PURE__ */ ((PreferenceValue2) => {
|
|
6288
|
-
PreferenceValue2["Always"] = "always";
|
|
6289
|
-
PreferenceValue2["Ask"] = "ask";
|
|
6290
|
-
PreferenceValue2["Never"] = "never";
|
|
6291
|
-
PreferenceValue2["Local"] = "local";
|
|
6292
|
-
PreferenceValue2["Remote"] = "remote";
|
|
6293
|
-
return PreferenceValue2;
|
|
6294
|
-
})(PreferenceValue || {});
|
|
6295
|
-
|
|
6296
|
-
// packages/mcps/src/shared/preferences-constants.ts
|
|
6297
|
-
var PREFERENCES_FILE_NAME = "preferences.json";
|
|
6298
|
-
var PREFERENCES_PROJECT_DIR_NAME = ".muggle-ai";
|
|
6299
|
-
var PREFERENCES_VERSION = 1;
|
|
6300
|
-
var DEFAULT_PREFERENCES = {
|
|
6301
|
-
["autoLogin" /* AutoLogin */]: "always" /* Always */,
|
|
6302
|
-
["autoSelectProject" /* AutoSelectProject */]: "always" /* Always */,
|
|
6303
|
-
["autoSelectLocalHost" /* AutoSelectLocalHost */]: "always" /* Always */,
|
|
6304
|
-
["showElectronBrowser" /* ShowElectronBrowser */]: "always" /* Always */,
|
|
6305
|
-
["openTestResultsAfterRun" /* OpenTestResultsAfterRun */]: "always" /* Always */,
|
|
6306
|
-
["defaultExecutionMode" /* DefaultExecutionMode */]: "local" /* Local */,
|
|
6307
|
-
["suggestRelatedUseCases" /* SuggestRelatedUseCases */]: "always" /* Always */,
|
|
6308
|
-
["suggestRelatedTestCases" /* SuggestRelatedTestCases */]: "always" /* Always */,
|
|
6309
|
-
["autoDetectChanges" /* AutoDetectChanges */]: "always" /* Always */,
|
|
6310
|
-
["postPRVisualWalkthrough" /* PostPRVisualWalkthrough */]: "always" /* Always */,
|
|
6311
|
-
["autoCreatePR" /* AutoCreatePR */]: "always" /* Always */,
|
|
6312
|
-
["checkForUpdates" /* CheckForUpdates */]: "always" /* Always */,
|
|
6313
|
-
["verboseOutput" /* VerboseOutput */]: "never" /* Never */,
|
|
6314
|
-
["autoUseWorktree" /* AutoUseWorktree */]: "always" /* Always */,
|
|
6315
|
-
["autoRebase" /* AutoRebase */]: "always" /* Always */,
|
|
6316
|
-
["autoCleanup" /* AutoCleanup */]: "always" /* Always */,
|
|
6317
|
-
["autoE2ETest" /* AutoE2ETest */]: "always" /* Always */,
|
|
6318
|
-
["autoResolveConflicts" /* AutoResolveConflicts */]: "always" /* Always */,
|
|
6319
|
-
["autoReuseValidationContext" /* AutoReuseValidationContext */]: "always" /* Always */,
|
|
6320
|
-
["autoRouteBuildToMuggleDo" /* AutoRouteBuildToMuggleDo */]: "always" /* Always */,
|
|
6321
|
-
["autoWatchPR" /* AutoWatchPR */]: "always" /* Always */,
|
|
6322
|
-
["reusePreparePlan" /* ReusePreparePlan */]: "always" /* Always */
|
|
6323
|
-
};
|
|
6324
|
-
var ALWAYS_ASK_NEVER = [
|
|
6325
|
-
"always" /* Always */,
|
|
6326
|
-
"ask" /* Ask */,
|
|
6327
|
-
"never" /* Never */
|
|
6328
|
-
];
|
|
6329
|
-
var ALWAYS_ASK = [
|
|
6330
|
-
"always" /* Always */,
|
|
6331
|
-
"ask" /* Ask */
|
|
6332
|
-
];
|
|
6333
|
-
var LOCAL_REMOTE_ASK = [
|
|
6334
|
-
"local" /* Local */,
|
|
6335
|
-
"remote" /* Remote */,
|
|
6336
|
-
"ask" /* Ask */
|
|
6337
|
-
];
|
|
6338
|
-
var PREFERENCE_ALLOWED_VALUES = {
|
|
6339
|
-
["autoLogin" /* AutoLogin */]: ALWAYS_ASK_NEVER,
|
|
6340
|
-
["autoSelectProject" /* AutoSelectProject */]: ALWAYS_ASK_NEVER,
|
|
6341
|
-
["autoSelectLocalHost" /* AutoSelectLocalHost */]: ALWAYS_ASK_NEVER,
|
|
6342
|
-
["showElectronBrowser" /* ShowElectronBrowser */]: ALWAYS_ASK_NEVER,
|
|
6343
|
-
["openTestResultsAfterRun" /* OpenTestResultsAfterRun */]: ALWAYS_ASK_NEVER,
|
|
6344
|
-
["defaultExecutionMode" /* DefaultExecutionMode */]: LOCAL_REMOTE_ASK,
|
|
6345
|
-
["suggestRelatedUseCases" /* SuggestRelatedUseCases */]: ALWAYS_ASK_NEVER,
|
|
6346
|
-
["suggestRelatedTestCases" /* SuggestRelatedTestCases */]: ALWAYS_ASK_NEVER,
|
|
6347
|
-
["autoDetectChanges" /* AutoDetectChanges */]: ALWAYS_ASK_NEVER,
|
|
6348
|
-
["postPRVisualWalkthrough" /* PostPRVisualWalkthrough */]: ALWAYS_ASK_NEVER,
|
|
6349
|
-
["autoCreatePR" /* AutoCreatePR */]: ALWAYS_ASK_NEVER,
|
|
6350
|
-
["checkForUpdates" /* CheckForUpdates */]: ALWAYS_ASK_NEVER,
|
|
6351
|
-
["verboseOutput" /* VerboseOutput */]: ALWAYS_ASK_NEVER,
|
|
6352
|
-
["autoUseWorktree" /* AutoUseWorktree */]: ALWAYS_ASK_NEVER,
|
|
6353
|
-
["autoRebase" /* AutoRebase */]: ALWAYS_ASK_NEVER,
|
|
6354
|
-
["autoCleanup" /* AutoCleanup */]: ALWAYS_ASK_NEVER,
|
|
6355
|
-
["autoE2ETest" /* AutoE2ETest */]: ALWAYS_ASK,
|
|
6356
|
-
["autoResolveConflicts" /* AutoResolveConflicts */]: ALWAYS_ASK_NEVER,
|
|
6357
|
-
["autoReuseValidationContext" /* AutoReuseValidationContext */]: ALWAYS_ASK_NEVER,
|
|
6358
|
-
["autoRouteBuildToMuggleDo" /* AutoRouteBuildToMuggleDo */]: ALWAYS_ASK_NEVER,
|
|
6359
|
-
["autoWatchPR" /* AutoWatchPR */]: ALWAYS_ASK_NEVER,
|
|
6360
|
-
["reusePreparePlan" /* ReusePreparePlan */]: ALWAYS_ASK_NEVER
|
|
6361
|
-
};
|
|
6362
|
-
var PREFERENCES_SCHEMA = {
|
|
6363
|
-
["autoLogin" /* AutoLogin */]: {
|
|
6364
|
-
description: "When a tool requires auth and saved credentials exist, reuse them without prompting"
|
|
6365
|
-
},
|
|
6366
|
-
["autoSelectProject" /* AutoSelectProject */]: {
|
|
6367
|
-
description: "When a skill needs a Muggle Test project and one was used previously in this repo, reuse it without prompting"
|
|
6368
|
-
},
|
|
6369
|
-
["autoSelectLocalHost" /* AutoSelectLocalHost */]: {
|
|
6370
|
-
description: "When running local tests, reuse the dev server URL from the previous run in this repo without prompting"
|
|
6371
|
-
},
|
|
6372
|
-
["showElectronBrowser" /* ShowElectronBrowser */]: {
|
|
6373
|
-
description: "When running local E2E tests, show the Electron browser window"
|
|
6374
|
-
},
|
|
6375
|
-
["openTestResultsAfterRun" /* OpenTestResultsAfterRun */]: {
|
|
6376
|
-
description: "After a local E2E test run completes, open the per-run results page on Muggle Test dashboard"
|
|
6377
|
-
},
|
|
6378
|
-
["defaultExecutionMode" /* DefaultExecutionMode */]: {
|
|
6379
|
-
description: "When a skill supports both local and remote test execution, which to default to"
|
|
6380
|
-
},
|
|
6381
|
-
["suggestRelatedUseCases" /* SuggestRelatedUseCases */]: {
|
|
6382
|
-
description: "After creating or running a use case, suggest related use cases to add"
|
|
6383
|
-
},
|
|
6384
|
-
["suggestRelatedTestCases" /* SuggestRelatedTestCases */]: {
|
|
6385
|
-
description: "After creating or running a test case, suggest related test cases to add"
|
|
6386
|
-
},
|
|
6387
|
-
["autoDetectChanges" /* AutoDetectChanges */]: {
|
|
6388
|
-
description: "When running muggle-test, scan local git changes and map to affected test cases"
|
|
6389
|
-
},
|
|
6390
|
-
["postPRVisualWalkthrough" /* PostPRVisualWalkthrough */]: {
|
|
6391
|
-
description: "After test results are available, post visual walkthrough comment with screenshots to the PR"
|
|
6392
|
-
},
|
|
6393
|
-
["autoCreatePR" /* AutoCreatePR */]: {
|
|
6394
|
-
description: "At the end of the muggle-do dev cycle (or when a test needs an open PR to post results to), push the branch and open a PR without prompting"
|
|
6395
|
-
},
|
|
6396
|
-
["checkForUpdates" /* CheckForUpdates */]: {
|
|
6397
|
-
description: "At session start, check if a newer Muggle Test version is available and notify"
|
|
6398
|
-
},
|
|
6399
|
-
["verboseOutput" /* VerboseOutput */]: {
|
|
6400
|
-
description: "Show detailed progress logs during skill and tool execution"
|
|
6401
|
-
},
|
|
6402
|
-
["autoUseWorktree" /* AutoUseWorktree */]: {
|
|
6403
|
-
description: "When starting non-trivial development work, create a git worktree to isolate the change from the current checkout"
|
|
6404
|
-
},
|
|
6405
|
-
["autoRebase" /* AutoRebase */]: {
|
|
6406
|
-
description: "Before running dev servers or E2E tests on a branch behind origin, rebase onto the default branch first"
|
|
6407
|
-
},
|
|
6408
|
-
["autoCleanup" /* AutoCleanup */]: {
|
|
6409
|
-
description: "After a PR is merged, automatically run the cleanup sequence: remove worktree, delete branches, clear local artifacts, prune [gone] branches"
|
|
6410
|
-
},
|
|
6411
|
-
["autoE2ETest" /* AutoE2ETest */]: {
|
|
6412
|
-
description: "Run Stage 6 (E2E acceptance) at the end of every /muggle-do cycle (default always \u2014 running E2E is the point of muggle-do; never is not an option)"
|
|
6413
|
-
},
|
|
6414
|
-
["autoResolveConflicts" /* AutoResolveConflicts */]: {
|
|
6415
|
-
description: "When a rebase onto the default branch hits conflicts, resolve them autonomously behind a verify-or-rollback gate instead of aborting and escalating"
|
|
6416
|
-
},
|
|
6417
|
-
["autoReuseValidationContext" /* AutoReuseValidationContext */]: {
|
|
6418
|
-
description: "When a prior session left an E2E validation context for this working tree, reuse it instead of re-asking the validation questions"
|
|
6419
|
-
},
|
|
6420
|
-
["autoRouteBuildToMuggleDo" /* AutoRouteBuildToMuggleDo */]: {
|
|
6421
|
-
description: "When a prompt looks like a build/implement/fix request, route it through the /muggle-do pipeline (requirements \u2192 build \u2192 impact \u2192 tests \u2192 E2E \u2192 PR \u2192 watcher)"
|
|
6422
|
-
},
|
|
6423
|
-
["autoWatchPR" /* AutoWatchPR */]: {
|
|
6424
|
-
description: "After a test run opens a PR, start a muggle-pr-followup watcher that polls for new reviews and hands them to /muggle-do"
|
|
6425
|
-
},
|
|
6426
|
-
["reusePreparePlan" /* ReusePreparePlan */]: {
|
|
6427
|
-
description: "Reuse the saved prepare plan for this stack (skip discovery, jump to check-running + smoke-test) instead of rediscovering from scratch"
|
|
6428
|
-
}
|
|
6429
|
-
};
|
|
6430
|
-
|
|
6431
|
-
// packages/mcps/src/mcp/local/contracts/preferences-schemas.ts
|
|
6432
6505
|
var preferenceKeyValues = Object.values(PreferenceKey);
|
|
6433
6506
|
var preferenceValueValues = Object.values(PreferenceValue);
|
|
6434
|
-
var PreferencesSetInputSchema = z.object(
|
|
6435
|
-
|
|
6436
|
-
|
|
6437
|
-
|
|
6438
|
-
|
|
6439
|
-
|
|
6507
|
+
var PreferencesSetInputSchema = z.object(
|
|
6508
|
+
{
|
|
6509
|
+
key: z.enum(preferenceKeyValues).describe("The preference key to set."),
|
|
6510
|
+
value: z.enum(preferenceValueValues).describe("The value. Most keys accept always/ask/never; defaultExecutionMode accepts local/remote/ask.")
|
|
6511
|
+
},
|
|
6512
|
+
{
|
|
6513
|
+
error: "Expected only { key, value }: per-project preferences were removed, so scope and cwd are no longer accepted."
|
|
6514
|
+
}
|
|
6515
|
+
).strict().superRefine((data, ctx) => {
|
|
6440
6516
|
const allowed = PREFERENCE_ALLOWED_VALUES[data.key];
|
|
6441
6517
|
if (!allowed.includes(data.value)) {
|
|
6442
6518
|
ctx.addIssue({
|
|
@@ -6506,9 +6582,9 @@ var TELEMETRY_DIR_NAME = "telemetry";
|
|
|
6506
6582
|
var FAILURE_EVENTS_FILE_NAME = "failure-events.jsonl";
|
|
6507
6583
|
function appendFailureEvent(record) {
|
|
6508
6584
|
try {
|
|
6509
|
-
const dir =
|
|
6585
|
+
const dir = path10.join(getDataDir(), TELEMETRY_DIR_NAME);
|
|
6510
6586
|
fs5.mkdirSync(dir, { recursive: true });
|
|
6511
|
-
const filePath =
|
|
6587
|
+
const filePath = path10.join(dir, FAILURE_EVENTS_FILE_NAME);
|
|
6512
6588
|
const full = { ts: (/* @__PURE__ */ new Date()).toISOString(), ...record };
|
|
6513
6589
|
fs5.appendFileSync(filePath, `${JSON.stringify(full)}
|
|
6514
6590
|
`, "utf-8");
|
|
@@ -6518,9 +6594,21 @@ function appendFailureEvent(record) {
|
|
|
6518
6594
|
});
|
|
6519
6595
|
}
|
|
6520
6596
|
}
|
|
6597
|
+
|
|
6598
|
+
// packages/mcps/src/shared/project-preferences-reconcile-types.ts
|
|
6599
|
+
var ProjectPreferencesReconcileOutcome = /* @__PURE__ */ ((ProjectPreferencesReconcileOutcome2) => {
|
|
6600
|
+
ProjectPreferencesReconcileOutcome2["NoAction"] = "noAction";
|
|
6601
|
+
ProjectPreferencesReconcileOutcome2["CopiedToGlobal"] = "copiedToGlobal";
|
|
6602
|
+
ProjectPreferencesReconcileOutcome2["KeysShadowed"] = "keysShadowed";
|
|
6603
|
+
return ProjectPreferencesReconcileOutcome2;
|
|
6604
|
+
})(ProjectPreferencesReconcileOutcome || {});
|
|
6605
|
+
|
|
6606
|
+
// packages/mcps/src/shared/preferences-service.ts
|
|
6607
|
+
function getGlobalPreferencesFilePath(dataDirOverride2) {
|
|
6608
|
+
return path10.join(dataDirOverride2 ?? getDataDir(), PREFERENCES_FILE_NAME);
|
|
6609
|
+
}
|
|
6521
6610
|
function isFirstRun(dataDirOverride2) {
|
|
6522
|
-
|
|
6523
|
-
return !fs5.existsSync(filePath);
|
|
6611
|
+
return !fs5.existsSync(getGlobalPreferencesFilePath(dataDirOverride2));
|
|
6524
6612
|
}
|
|
6525
6613
|
function readPreferencesFile(filePath) {
|
|
6526
6614
|
try {
|
|
@@ -6537,53 +6625,75 @@ function readPreferencesFile(filePath) {
|
|
|
6537
6625
|
return {};
|
|
6538
6626
|
}
|
|
6539
6627
|
}
|
|
6540
|
-
function
|
|
6541
|
-
const filePath = path9.join(dataDirOverride2 ?? getDataDir(), PREFERENCES_FILE_NAME);
|
|
6542
|
-
const partial = readPreferencesFile(filePath);
|
|
6543
|
-
return { ...DEFAULT_PREFERENCES, ...partial };
|
|
6544
|
-
}
|
|
6545
|
-
function readProjectPreferences(cwd) {
|
|
6546
|
-
const filePath = path9.join(cwd, PREFERENCES_PROJECT_DIR_NAME, PREFERENCES_FILE_NAME);
|
|
6547
|
-
return readPreferencesFile(filePath);
|
|
6548
|
-
}
|
|
6549
|
-
function resolvePreferences(dataDirOverride2, cwd) {
|
|
6550
|
-
const global = readGlobalPreferences(dataDirOverride2);
|
|
6551
|
-
if (!cwd) {
|
|
6552
|
-
return global;
|
|
6553
|
-
}
|
|
6554
|
-
const project = readProjectPreferences(cwd);
|
|
6555
|
-
return { ...global, ...project };
|
|
6556
|
-
}
|
|
6557
|
-
function writePreferences2(prefs, scope, dataDirOverride2, cwd) {
|
|
6558
|
-
const dir = scope === "project" && cwd ? path9.join(cwd, PREFERENCES_PROJECT_DIR_NAME) : dataDirOverride2 ?? getDataDir();
|
|
6559
|
-
fs5.mkdirSync(dir, { recursive: true });
|
|
6560
|
-
const filePath = path9.join(dir, PREFERENCES_FILE_NAME);
|
|
6561
|
-
const existing = readPreferencesFile(filePath);
|
|
6562
|
-
const merged = { ...existing, ...prefs };
|
|
6628
|
+
function writePreferencesFile(filePath, prefs) {
|
|
6563
6629
|
const file = {
|
|
6630
|
+
...readRawPreferencesFile(filePath),
|
|
6564
6631
|
version: PREFERENCES_VERSION,
|
|
6565
|
-
preferences:
|
|
6632
|
+
preferences: prefs
|
|
6566
6633
|
};
|
|
6567
6634
|
fs5.writeFileSync(filePath, `${JSON.stringify(file, null, 2)}
|
|
6568
6635
|
`, "utf-8");
|
|
6569
6636
|
}
|
|
6570
|
-
function
|
|
6571
|
-
|
|
6572
|
-
|
|
6637
|
+
function readRawPreferencesFile(filePath) {
|
|
6638
|
+
try {
|
|
6639
|
+
if (!fs5.existsSync(filePath)) {
|
|
6640
|
+
return {};
|
|
6641
|
+
}
|
|
6642
|
+
return JSON.parse(fs5.readFileSync(filePath, "utf-8"));
|
|
6643
|
+
} catch {
|
|
6644
|
+
return {};
|
|
6645
|
+
}
|
|
6646
|
+
}
|
|
6647
|
+
function resolvePreferences(dataDirOverride2) {
|
|
6648
|
+
const saved = readPreferencesFile(getGlobalPreferencesFilePath(dataDirOverride2));
|
|
6649
|
+
return { ...DEFAULT_PREFERENCES, ...saved };
|
|
6650
|
+
}
|
|
6651
|
+
function writePreferences2(prefs, dataDirOverride2) {
|
|
6652
|
+
const dir = dataDirOverride2 ?? getDataDir();
|
|
6653
|
+
fs5.mkdirSync(dir, { recursive: true });
|
|
6654
|
+
const filePath = path10.join(dir, PREFERENCES_FILE_NAME);
|
|
6655
|
+
const existing = readPreferencesFile(filePath);
|
|
6656
|
+
writePreferencesFile(filePath, { ...existing, ...prefs });
|
|
6657
|
+
}
|
|
6658
|
+
function resetPreference(key, dataDirOverride2) {
|
|
6659
|
+
const filePath = getGlobalPreferencesFilePath(dataDirOverride2);
|
|
6573
6660
|
if (!fs5.existsSync(filePath)) {
|
|
6574
6661
|
return;
|
|
6575
6662
|
}
|
|
6576
6663
|
if (!key) {
|
|
6577
|
-
|
|
6578
|
-
fs5.writeFileSync(filePath, `${JSON.stringify(file2, null, 2)}
|
|
6579
|
-
`, "utf-8");
|
|
6664
|
+
writePreferencesFile(filePath, {});
|
|
6580
6665
|
return;
|
|
6581
6666
|
}
|
|
6582
6667
|
const existing = readPreferencesFile(filePath);
|
|
6583
6668
|
delete existing[key];
|
|
6584
|
-
|
|
6585
|
-
|
|
6586
|
-
|
|
6669
|
+
writePreferencesFile(filePath, existing);
|
|
6670
|
+
}
|
|
6671
|
+
function reconcileProjectPreferences(cwd, dataDirOverride2) {
|
|
6672
|
+
const projectFilePath = path10.join(cwd, PREFERENCES_PROJECT_DIR_NAME, PREFERENCES_FILE_NAME);
|
|
6673
|
+
const projectPreferences = readPreferencesFile(projectFilePath);
|
|
6674
|
+
const projectKeys = Object.keys(projectPreferences);
|
|
6675
|
+
if (projectKeys.length === 0) {
|
|
6676
|
+
return {
|
|
6677
|
+
outcome: "noAction" /* NoAction */,
|
|
6678
|
+
projectFilePath,
|
|
6679
|
+
shadowedKeys: []
|
|
6680
|
+
};
|
|
6681
|
+
}
|
|
6682
|
+
if (isFirstRun(dataDirOverride2)) {
|
|
6683
|
+
writePreferences2(projectPreferences, dataDirOverride2);
|
|
6684
|
+
return {
|
|
6685
|
+
outcome: "copiedToGlobal" /* CopiedToGlobal */,
|
|
6686
|
+
projectFilePath,
|
|
6687
|
+
shadowedKeys: []
|
|
6688
|
+
};
|
|
6689
|
+
}
|
|
6690
|
+
const resolved = resolvePreferences(dataDirOverride2);
|
|
6691
|
+
const shadowedKeys = projectKeys.filter((key) => projectPreferences[key] !== resolved[key]);
|
|
6692
|
+
return {
|
|
6693
|
+
outcome: shadowedKeys.length > 0 ? "keysShadowed" /* KeysShadowed */ : "noAction" /* NoAction */,
|
|
6694
|
+
projectFilePath,
|
|
6695
|
+
shadowedKeys
|
|
6696
|
+
};
|
|
6587
6697
|
}
|
|
6588
6698
|
function validatePreference(key, value) {
|
|
6589
6699
|
const validKeys = Object.values(PreferenceKey);
|
|
@@ -6596,77 +6706,134 @@ function validatePreference(key, value) {
|
|
|
6596
6706
|
function formatPreferencesOneLiner(prefs) {
|
|
6597
6707
|
return Object.entries(prefs).map(([key, value]) => `${key}=${value}`).join(" ");
|
|
6598
6708
|
}
|
|
6599
|
-
|
|
6600
|
-
|
|
6601
|
-
var
|
|
6602
|
-
|
|
6603
|
-
|
|
6709
|
+
|
|
6710
|
+
// packages/mcps/src/shared/cwd-keyed-cache-constants.ts
|
|
6711
|
+
var CWD_KEYED_CACHE_VERSION = 1;
|
|
6712
|
+
var LEGACY_CACHE_DIR_NAME = ".muggle-ai";
|
|
6713
|
+
var MUGGLE_HOME_DISPLAY_DIR = "~/.muggle-ai";
|
|
6714
|
+
|
|
6715
|
+
// packages/mcps/src/shared/cwd-keyed-cache.ts
|
|
6716
|
+
function resolveHomeFilePath(cache) {
|
|
6717
|
+
return path10.join(getDataDir(), cache.fileName);
|
|
6718
|
+
}
|
|
6719
|
+
function resolveLegacyFilePath(cache, cwd) {
|
|
6720
|
+
return path10.join(cwd, LEGACY_CACHE_DIR_NAME, cache.fileName);
|
|
6721
|
+
}
|
|
6722
|
+
function parseJsonFile(filePath) {
|
|
6604
6723
|
try {
|
|
6605
6724
|
if (!fs5.existsSync(filePath)) {
|
|
6606
6725
|
return null;
|
|
6607
6726
|
}
|
|
6608
|
-
|
|
6609
|
-
return raw.lastProject ?? null;
|
|
6727
|
+
return JSON.parse(fs5.readFileSync(filePath, "utf-8"));
|
|
6610
6728
|
} catch (error) {
|
|
6611
|
-
getLogger().warn("Failed to read
|
|
6729
|
+
getLogger().warn("Failed to read cache file", {
|
|
6612
6730
|
path: filePath,
|
|
6613
6731
|
error: error instanceof Error ? error.message : String(error)
|
|
6614
6732
|
});
|
|
6615
6733
|
return null;
|
|
6616
6734
|
}
|
|
6617
6735
|
}
|
|
6618
|
-
function
|
|
6619
|
-
const
|
|
6620
|
-
|
|
6621
|
-
|
|
6736
|
+
function readHomeEntries(cache) {
|
|
6737
|
+
const parsed = parseJsonFile(resolveHomeFilePath(cache));
|
|
6738
|
+
return parsed?.entries ?? {};
|
|
6739
|
+
}
|
|
6740
|
+
function writeHomeEntries(cache, entries) {
|
|
6741
|
+
fs5.mkdirSync(getDataDir(), { recursive: true });
|
|
6622
6742
|
const file = {
|
|
6623
|
-
version:
|
|
6624
|
-
|
|
6743
|
+
version: CWD_KEYED_CACHE_VERSION,
|
|
6744
|
+
entries
|
|
6625
6745
|
};
|
|
6626
|
-
fs5.writeFileSync(
|
|
6627
|
-
|
|
6746
|
+
fs5.writeFileSync(
|
|
6747
|
+
resolveHomeFilePath(cache),
|
|
6748
|
+
`${JSON.stringify(file, null, 2)}
|
|
6749
|
+
`,
|
|
6750
|
+
"utf-8"
|
|
6751
|
+
);
|
|
6628
6752
|
}
|
|
6629
|
-
function
|
|
6630
|
-
const
|
|
6631
|
-
|
|
6632
|
-
|
|
6633
|
-
|
|
6753
|
+
function readLegacyEntry(cache, cwd) {
|
|
6754
|
+
const parsed = parseJsonFile(
|
|
6755
|
+
resolveLegacyFilePath(cache, cwd)
|
|
6756
|
+
);
|
|
6757
|
+
return parsed?.[cache.legacyEntryKey] ?? null;
|
|
6634
6758
|
}
|
|
6635
|
-
|
|
6636
|
-
|
|
6637
|
-
|
|
6638
|
-
|
|
6639
|
-
|
|
6759
|
+
function readCwdEntry(cache, cwd) {
|
|
6760
|
+
const cwdKey = path10.resolve(cwd);
|
|
6761
|
+
const entries = readHomeEntries(cache);
|
|
6762
|
+
const homeEntry = entries[cwdKey];
|
|
6763
|
+
if (homeEntry) {
|
|
6764
|
+
return homeEntry;
|
|
6765
|
+
}
|
|
6766
|
+
const legacyEntry = readLegacyEntry(cache, cwd);
|
|
6767
|
+
if (!legacyEntry) {
|
|
6768
|
+
return null;
|
|
6769
|
+
}
|
|
6640
6770
|
try {
|
|
6641
|
-
|
|
6642
|
-
return null;
|
|
6643
|
-
}
|
|
6644
|
-
const raw = JSON.parse(fs5.readFileSync(filePath, "utf-8"));
|
|
6645
|
-
return raw.lastHost ?? null;
|
|
6771
|
+
writeHomeEntries(cache, { ...entries, [cwdKey]: legacyEntry });
|
|
6646
6772
|
} catch (error) {
|
|
6647
|
-
getLogger().warn("Failed to
|
|
6648
|
-
path:
|
|
6773
|
+
getLogger().warn("Failed to migrate cache entry to the home directory", {
|
|
6774
|
+
path: resolveHomeFilePath(cache),
|
|
6649
6775
|
error: error instanceof Error ? error.message : String(error)
|
|
6650
6776
|
});
|
|
6651
|
-
return null;
|
|
6652
6777
|
}
|
|
6778
|
+
return legacyEntry;
|
|
6779
|
+
}
|
|
6780
|
+
function writeCwdEntry(cache, cwd, entry) {
|
|
6781
|
+
const entries = readHomeEntries(cache);
|
|
6782
|
+
writeHomeEntries(cache, { ...entries, [path10.resolve(cwd)]: entry });
|
|
6783
|
+
}
|
|
6784
|
+
function clearCwdEntry(cache, cwd) {
|
|
6785
|
+
const entries = readHomeEntries(cache);
|
|
6786
|
+
const cwdKey = path10.resolve(cwd);
|
|
6787
|
+
if (cwdKey in entries) {
|
|
6788
|
+
delete entries[cwdKey];
|
|
6789
|
+
writeHomeEntries(cache, entries);
|
|
6790
|
+
}
|
|
6791
|
+
const legacyFilePath = resolveLegacyFilePath(cache, cwd);
|
|
6792
|
+
if (fs5.existsSync(legacyFilePath)) {
|
|
6793
|
+
fs5.unlinkSync(legacyFilePath);
|
|
6794
|
+
}
|
|
6795
|
+
}
|
|
6796
|
+
|
|
6797
|
+
// packages/mcps/src/shared/last-project-constants.ts
|
|
6798
|
+
var LAST_PROJECT_FILE_NAME = "last-project.json";
|
|
6799
|
+
var LAST_PROJECT_CACHE = {
|
|
6800
|
+
fileName: LAST_PROJECT_FILE_NAME,
|
|
6801
|
+
legacyEntryKey: "lastProject"
|
|
6802
|
+
};
|
|
6803
|
+
|
|
6804
|
+
// packages/mcps/src/shared/last-project.ts
|
|
6805
|
+
function readLastProject(cwd) {
|
|
6806
|
+
return readCwdEntry(LAST_PROJECT_CACHE, cwd);
|
|
6807
|
+
}
|
|
6808
|
+
function writeLastProject(cwd, lastProject) {
|
|
6809
|
+
writeCwdEntry(LAST_PROJECT_CACHE, cwd, {
|
|
6810
|
+
...lastProject,
|
|
6811
|
+
savedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
6812
|
+
});
|
|
6813
|
+
}
|
|
6814
|
+
function clearLastProject(cwd) {
|
|
6815
|
+
clearCwdEntry(LAST_PROJECT_CACHE, cwd);
|
|
6816
|
+
}
|
|
6817
|
+
|
|
6818
|
+
// packages/mcps/src/shared/last-host-constants.ts
|
|
6819
|
+
var LAST_HOST_FILE_NAME = "last-host.json";
|
|
6820
|
+
var LAST_HOST_CACHE = {
|
|
6821
|
+
fileName: LAST_HOST_FILE_NAME,
|
|
6822
|
+
legacyEntryKey: "lastHost"
|
|
6823
|
+
};
|
|
6824
|
+
|
|
6825
|
+
// packages/mcps/src/shared/last-host.ts
|
|
6826
|
+
function readLastHost(cwd) {
|
|
6827
|
+
return readCwdEntry(LAST_HOST_CACHE, cwd);
|
|
6653
6828
|
}
|
|
6654
6829
|
function writeLastHost(cwd, host) {
|
|
6655
|
-
|
|
6656
|
-
|
|
6657
|
-
|
|
6658
|
-
|
|
6659
|
-
version: LAST_HOST_VERSION,
|
|
6660
|
-
lastHost: { host, savedAt: (/* @__PURE__ */ new Date()).toISOString() }
|
|
6661
|
-
};
|
|
6662
|
-
fs5.writeFileSync(filePath, `${JSON.stringify(file, null, 2)}
|
|
6663
|
-
`, "utf-8");
|
|
6830
|
+
writeCwdEntry(LAST_HOST_CACHE, cwd, {
|
|
6831
|
+
host,
|
|
6832
|
+
savedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
6833
|
+
});
|
|
6664
6834
|
}
|
|
6665
6835
|
function clearLastHost(cwd) {
|
|
6666
|
-
|
|
6667
|
-
if (fs5.existsSync(filePath)) {
|
|
6668
|
-
fs5.unlinkSync(filePath);
|
|
6669
|
-
}
|
|
6836
|
+
clearCwdEntry(LAST_HOST_CACHE, cwd);
|
|
6670
6837
|
}
|
|
6671
6838
|
|
|
6672
6839
|
// packages/mcps/src/mcp/tools/local/tool-registry.ts
|
|
@@ -6765,42 +6932,42 @@ var runResultGetTool = {
|
|
|
6765
6932
|
logger6.info("Executing muggle-local-run-result-get");
|
|
6766
6933
|
const input = RunResultGetInputSchema.parse(ctx.input);
|
|
6767
6934
|
const storage = getRunResultStorageService();
|
|
6768
|
-
const
|
|
6769
|
-
if (!
|
|
6935
|
+
const storedRunResult = storage.getRunResult(input.runId);
|
|
6936
|
+
if (!storedRunResult) {
|
|
6770
6937
|
return { content: `Run result not found: ${input.runId}`, isError: true };
|
|
6771
6938
|
}
|
|
6772
6939
|
const contentParts = [
|
|
6773
6940
|
"## Run Result Details",
|
|
6774
6941
|
"",
|
|
6775
|
-
`**ID:** ${
|
|
6776
|
-
`**Type:** ${
|
|
6777
|
-
`**Status:** ${
|
|
6778
|
-
`**Cloud Test Case:** ${
|
|
6779
|
-
`**Duration:** ${
|
|
6780
|
-
|
|
6942
|
+
`**ID:** ${storedRunResult.id}`,
|
|
6943
|
+
`**Type:** ${storedRunResult.runType}`,
|
|
6944
|
+
`**Status:** ${storedRunResult.status}`,
|
|
6945
|
+
`**Cloud Test Case:** ${storedRunResult.cloudTestCaseId}`,
|
|
6946
|
+
`**Duration:** ${storedRunResult.executionTimeMs ?? 0}ms`,
|
|
6947
|
+
storedRunResult.errorMessage ? `**Error:** ${storedRunResult.errorMessage}` : "",
|
|
6781
6948
|
// The studio publishes the run during execution; these are its returned cloud refs.
|
|
6782
|
-
|
|
6783
|
-
|
|
6784
|
-
|
|
6949
|
+
storedRunResult.viewUrl ? `**View URL:** ${storedRunResult.viewUrl}` : "",
|
|
6950
|
+
storedRunResult.cloudTestScriptId ? `**Cloud Test Script ID:** ${storedRunResult.cloudTestScriptId}` : "",
|
|
6951
|
+
storedRunResult.cloudActionScriptId ? `**Cloud Action Script ID:** ${storedRunResult.cloudActionScriptId}` : ""
|
|
6785
6952
|
];
|
|
6786
6953
|
let testScriptSteps;
|
|
6787
|
-
if (
|
|
6788
|
-
const testScript = storage.getTestScript(
|
|
6954
|
+
if (storedRunResult.testScriptId) {
|
|
6955
|
+
const testScript = storage.getTestScript(storedRunResult.testScriptId);
|
|
6789
6956
|
testScriptSteps = testScript?.actionScript?.length;
|
|
6790
6957
|
}
|
|
6791
|
-
if (
|
|
6958
|
+
if (storedRunResult.artifactsDir && fs5.existsSync(storedRunResult.artifactsDir)) {
|
|
6792
6959
|
contentParts.push(
|
|
6793
6960
|
"",
|
|
6794
6961
|
"### Artifacts (view action script + screenshots)",
|
|
6795
6962
|
"",
|
|
6796
|
-
`**Location:** \`${
|
|
6963
|
+
`**Location:** \`${storedRunResult.artifactsDir}\``,
|
|
6797
6964
|
""
|
|
6798
6965
|
);
|
|
6799
|
-
const actionScriptPath =
|
|
6800
|
-
const resultsMdPath =
|
|
6801
|
-
const screenshotsDir =
|
|
6802
|
-
const stdoutLogPath =
|
|
6803
|
-
const stderrLogPath =
|
|
6966
|
+
const actionScriptPath = path10.join(storedRunResult.artifactsDir, "action-script.json");
|
|
6967
|
+
const resultsMdPath = path10.join(storedRunResult.artifactsDir, "results.md");
|
|
6968
|
+
const screenshotsDir = path10.join(storedRunResult.artifactsDir, "screenshots");
|
|
6969
|
+
const stdoutLogPath = path10.join(storedRunResult.artifactsDir, "stdout.log");
|
|
6970
|
+
const stderrLogPath = path10.join(storedRunResult.artifactsDir, "stderr.log");
|
|
6804
6971
|
const artifactItems = [];
|
|
6805
6972
|
if (fs5.existsSync(actionScriptPath)) {
|
|
6806
6973
|
artifactItems.push("- `action-script.json` \u2014 generated test steps");
|
|
@@ -6826,13 +6993,13 @@ var runResultGetTool = {
|
|
|
6826
6993
|
"",
|
|
6827
6994
|
"### Ending state",
|
|
6828
6995
|
"",
|
|
6829
|
-
`- **Status:** ${
|
|
6830
|
-
`- **Duration:** ${
|
|
6996
|
+
`- **Status:** ${storedRunResult.status}`,
|
|
6997
|
+
`- **Duration:** ${storedRunResult.executionTimeMs ?? 0}ms`,
|
|
6831
6998
|
testScriptSteps !== void 0 ? `- **Steps generated:** ${testScriptSteps}` : "",
|
|
6832
|
-
|
|
6999
|
+
storedRunResult.artifactsDir ? `- **Artifacts path:** \`${storedRunResult.artifactsDir}\`` : ""
|
|
6833
7000
|
);
|
|
6834
7001
|
const content = contentParts.filter(Boolean).join("\n");
|
|
6835
|
-
return { content, isError: false, data:
|
|
7002
|
+
return { content, isError: false, data: storedRunResult };
|
|
6836
7003
|
}
|
|
6837
7004
|
};
|
|
6838
7005
|
var testScriptListTool = {
|
|
@@ -6892,7 +7059,7 @@ var executeTestGenerationTool = {
|
|
|
6892
7059
|
const input = ExecuteTestGenerationInputSchema.parse(ctx.input);
|
|
6893
7060
|
const showUi = input.showUi !== false;
|
|
6894
7061
|
try {
|
|
6895
|
-
const
|
|
7062
|
+
const generationRun = await executeTestGeneration({
|
|
6896
7063
|
testCase: input.testCase,
|
|
6897
7064
|
localUrl: input.localUrl,
|
|
6898
7065
|
cwd: input.cwd,
|
|
@@ -6902,19 +7069,19 @@ var executeTestGenerationTool = {
|
|
|
6902
7069
|
freshSession: input.freshSession
|
|
6903
7070
|
});
|
|
6904
7071
|
const content = [
|
|
6905
|
-
"## Test Generation " + (
|
|
7072
|
+
"## Test Generation " + (generationRun.status === "passed" ? "Successful" : "Failed"),
|
|
6906
7073
|
"",
|
|
6907
|
-
`**Run ID:** ${
|
|
6908
|
-
`**Test Script ID:** ${
|
|
6909
|
-
`**Status:** ${
|
|
6910
|
-
`**Duration:** ${
|
|
7074
|
+
`**Run ID:** ${generationRun.id}`,
|
|
7075
|
+
`**Test Script ID:** ${generationRun.testScriptId}`,
|
|
7076
|
+
`**Status:** ${generationRun.status}`,
|
|
7077
|
+
`**Duration:** ${generationRun.executionTimeMs}ms`,
|
|
6911
7078
|
`**UI:** ${showUi ? "visible GUI" : "headless"}`,
|
|
6912
|
-
|
|
7079
|
+
generationRun.errorMessage ? `**Error:** ${generationRun.errorMessage}` : ""
|
|
6913
7080
|
].filter(Boolean).join("\n");
|
|
6914
7081
|
return {
|
|
6915
7082
|
content,
|
|
6916
|
-
isError:
|
|
6917
|
-
data:
|
|
7083
|
+
isError: generationRun.status !== "passed",
|
|
7084
|
+
data: generationRun
|
|
6918
7085
|
};
|
|
6919
7086
|
} catch (error) {
|
|
6920
7087
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -6933,7 +7100,7 @@ var executeReplayTool = {
|
|
|
6933
7100
|
const input = ExecuteReplayInputSchema.parse(ctx.input);
|
|
6934
7101
|
const showUi = input.showUi !== false;
|
|
6935
7102
|
try {
|
|
6936
|
-
const
|
|
7103
|
+
const replayRun = await executeReplay({
|
|
6937
7104
|
testScript: input.testScript,
|
|
6938
7105
|
actionScript: input.actionScript,
|
|
6939
7106
|
localUrl: input.localUrl,
|
|
@@ -6944,19 +7111,19 @@ var executeReplayTool = {
|
|
|
6944
7111
|
freshSession: input.freshSession
|
|
6945
7112
|
});
|
|
6946
7113
|
const content = [
|
|
6947
|
-
"## Test Replay " + (
|
|
7114
|
+
"## Test Replay " + (replayRun.status === "passed" ? "Successful" : "Failed"),
|
|
6948
7115
|
"",
|
|
6949
|
-
`**Run ID:** ${
|
|
6950
|
-
`**Test Script ID:** ${
|
|
6951
|
-
`**Status:** ${
|
|
6952
|
-
`**Duration:** ${
|
|
7116
|
+
`**Run ID:** ${replayRun.id}`,
|
|
7117
|
+
`**Test Script ID:** ${replayRun.testScriptId}`,
|
|
7118
|
+
`**Status:** ${replayRun.status}`,
|
|
7119
|
+
`**Duration:** ${replayRun.executionTimeMs}ms`,
|
|
6953
7120
|
`**UI:** ${showUi ? "visible GUI" : "headless"}`,
|
|
6954
|
-
|
|
7121
|
+
replayRun.errorMessage ? `**Error:** ${replayRun.errorMessage}` : ""
|
|
6955
7122
|
].filter(Boolean).join("\n");
|
|
6956
7123
|
return {
|
|
6957
7124
|
content,
|
|
6958
|
-
isError:
|
|
6959
|
-
data:
|
|
7125
|
+
isError: replayRun.status !== "passed",
|
|
7126
|
+
data: replayRun
|
|
6960
7127
|
};
|
|
6961
7128
|
} catch (error) {
|
|
6962
7129
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -6982,27 +7149,22 @@ var cancelExecutionTool = {
|
|
|
6982
7149
|
};
|
|
6983
7150
|
var preferencesSetTool = {
|
|
6984
7151
|
name: "muggle-local-preferences-set",
|
|
6985
|
-
description: "Set a Muggle AI user preference. Preferences control automation behavior (auto-login, show browser, suggest test cases, etc.). Values: 'always' (proceed without asking), 'ask' (prompt each time), 'never' (skip without asking).
|
|
7152
|
+
description: "Set a Muggle AI user preference. Preferences control automation behavior (auto-login, show browser, suggest test cases, etc.). Values: 'always' (proceed without asking), 'ask' (prompt each time), 'never' (skip without asking). Preferences are user-level: they always write to ~/.muggle-ai/preferences.json and apply to every repo.",
|
|
6986
7153
|
inputSchema: PreferencesSetInputSchema,
|
|
6987
7154
|
execute: async (ctx) => {
|
|
6988
7155
|
const logger6 = createChildLogger2(ctx.correlationId);
|
|
6989
7156
|
logger6.info("Executing muggle-local-preferences-set");
|
|
6990
7157
|
const input = PreferencesSetInputSchema.parse(ctx.input);
|
|
6991
|
-
writePreferences2(
|
|
6992
|
-
{ [input.key]: input.value },
|
|
6993
|
-
input.scope,
|
|
6994
|
-
void 0,
|
|
6995
|
-
input.cwd
|
|
6996
|
-
);
|
|
7158
|
+
writePreferences2({ [input.key]: input.value });
|
|
6997
7159
|
return {
|
|
6998
|
-
content: `**${input.key}** set to **${input.value}
|
|
7160
|
+
content: `**${input.key}** set to **${input.value}**.`,
|
|
6999
7161
|
isError: false
|
|
7000
7162
|
};
|
|
7001
7163
|
}
|
|
7002
7164
|
};
|
|
7003
7165
|
var lastProjectGetTool = {
|
|
7004
7166
|
name: "muggle-local-last-project-get",
|
|
7005
|
-
description:
|
|
7167
|
+
description: `Get the cached last-used Muggle Test project for a repo (read from the entry keyed on <cwd> in ${MUGGLE_HOME_DISPLAY_DIR}/${LAST_PROJECT_FILE_NAME}). Returns the project ID, URL, name, and saved-at timestamp, or null if no cache exists. Skills consult this when 'autoSelectProject = always' to silently reuse the project the user picked previously, instead of presenting the project picker every time.`,
|
|
7006
7168
|
inputSchema: LastProjectGetInputSchema,
|
|
7007
7169
|
execute: async (ctx) => {
|
|
7008
7170
|
const logger6 = createChildLogger2(ctx.correlationId);
|
|
@@ -7013,7 +7175,7 @@ var lastProjectGetTool = {
|
|
|
7013
7175
|
const content2 = [
|
|
7014
7176
|
"No cached last-used project for this repo.",
|
|
7015
7177
|
"",
|
|
7016
|
-
`Looked at: \`${
|
|
7178
|
+
`Looked at: \`${MUGGLE_HOME_DISPLAY_DIR}/${LAST_PROJECT_FILE_NAME}\` (entry for \`${input.cwd}\`)`,
|
|
7017
7179
|
"",
|
|
7018
7180
|
"The cache is populated when a user picks an existing project AND chooses 'Yes, save it' on the memory picker (the autoSelectProject preference)."
|
|
7019
7181
|
].join("\n");
|
|
@@ -7032,7 +7194,7 @@ var lastProjectGetTool = {
|
|
|
7032
7194
|
};
|
|
7033
7195
|
var lastProjectSetTool = {
|
|
7034
7196
|
name: "muggle-local-last-project-set",
|
|
7035
|
-
description:
|
|
7197
|
+
description: `Save the user's selected Muggle Test project as the cached last-used project for this repo. Writes the entry keyed on <cwd> in ${MUGGLE_HOME_DISPLAY_DIR}/${LAST_PROJECT_FILE_NAME}. Subsequent skill invocations honor 'autoSelectProject = always' by silently reusing this entry \u2014 no project picker shown. Always pair this call with 'muggle-local-preferences-set autoSelectProject=always' when the user chose 'Yes, save it'.`,
|
|
7036
7198
|
inputSchema: LastProjectSetInputSchema,
|
|
7037
7199
|
execute: async (ctx) => {
|
|
7038
7200
|
const logger6 = createChildLogger2(ctx.correlationId);
|
|
@@ -7046,7 +7208,7 @@ var lastProjectSetTool = {
|
|
|
7046
7208
|
const content = [
|
|
7047
7209
|
`Cached **${input.projectName}** as the last-used project for this repo.`,
|
|
7048
7210
|
"",
|
|
7049
|
-
`Written to: \`${
|
|
7211
|
+
`Written to: \`${MUGGLE_HOME_DISPLAY_DIR}/${LAST_PROJECT_FILE_NAME}\` (entry for \`${input.cwd}\`)`,
|
|
7050
7212
|
"",
|
|
7051
7213
|
"Skills will silently reuse this project on future runs when `autoSelectProject = always`."
|
|
7052
7214
|
].join("\n");
|
|
@@ -7065,14 +7227,14 @@ var lastProjectClearTool = {
|
|
|
7065
7227
|
const content = [
|
|
7066
7228
|
"Cleared the cached last-used project for this repo.",
|
|
7067
7229
|
"",
|
|
7068
|
-
`Path: \`${
|
|
7230
|
+
`Path: \`${MUGGLE_HOME_DISPLAY_DIR}/${LAST_PROJECT_FILE_NAME}\` (entry for \`${input.cwd}\`)`
|
|
7069
7231
|
].join("\n");
|
|
7070
7232
|
return { content, isError: false };
|
|
7071
7233
|
}
|
|
7072
7234
|
};
|
|
7073
7235
|
var lastHostGetTool = {
|
|
7074
7236
|
name: "muggle-local-last-host-get",
|
|
7075
|
-
description:
|
|
7237
|
+
description: `Get the cached last-used local dev server URL for a repo (read from the entry keyed on <cwd> in ${MUGGLE_HOME_DISPLAY_DIR}/${LAST_HOST_FILE_NAME}). Returns the URL and saved-at timestamp, or null if no cache exists. Skills consult this when 'autoSelectLocalHost = always' to silently reuse the URL the user used previously.`,
|
|
7076
7238
|
inputSchema: LastHostGetInputSchema,
|
|
7077
7239
|
execute: async (ctx) => {
|
|
7078
7240
|
const logger6 = createChildLogger2(ctx.correlationId);
|
|
@@ -7083,7 +7245,7 @@ var lastHostGetTool = {
|
|
|
7083
7245
|
const content2 = [
|
|
7084
7246
|
"No cached last-used host for this repo.",
|
|
7085
7247
|
"",
|
|
7086
|
-
`Looked at: \`${
|
|
7248
|
+
`Looked at: \`${MUGGLE_HOME_DISPLAY_DIR}/${LAST_HOST_FILE_NAME}\` (entry for \`${input.cwd}\`)`
|
|
7087
7249
|
].join("\n");
|
|
7088
7250
|
return { content: content2, isError: false };
|
|
7089
7251
|
}
|
|
@@ -7098,7 +7260,7 @@ var lastHostGetTool = {
|
|
|
7098
7260
|
};
|
|
7099
7261
|
var lastHostSetTool = {
|
|
7100
7262
|
name: "muggle-local-last-host-set",
|
|
7101
|
-
description:
|
|
7263
|
+
description: `Save the user's chosen local dev server URL as the cached last-used host for this repo. Writes the entry keyed on <cwd> in ${MUGGLE_HOME_DISPLAY_DIR}/${LAST_HOST_FILE_NAME}. Call this on every host pick (independent of 'Remember this URL?' Picker 2) so future runs can offer 'Use {lastHost}' regardless of whether the user opted to set autoSelectLocalHost=always.`,
|
|
7102
7264
|
inputSchema: LastHostSetInputSchema,
|
|
7103
7265
|
execute: async (ctx) => {
|
|
7104
7266
|
const logger6 = createChildLogger2(ctx.correlationId);
|
|
@@ -7208,7 +7370,7 @@ async function executeTool(name, input, correlationId) {
|
|
|
7208
7370
|
props: { toolName: name, toolSurface: ToolSurface.Local, correlationId }
|
|
7209
7371
|
});
|
|
7210
7372
|
try {
|
|
7211
|
-
const
|
|
7373
|
+
const toolResult = await tool.execute({ input, correlationId });
|
|
7212
7374
|
safeTrack2({
|
|
7213
7375
|
name: EventName.McpToolCompleted,
|
|
7214
7376
|
props: {
|
|
@@ -7216,10 +7378,10 @@ async function executeTool(name, input, correlationId) {
|
|
|
7216
7378
|
toolSurface: ToolSurface.Local,
|
|
7217
7379
|
correlationId,
|
|
7218
7380
|
durationMs: Date.now() - startTime,
|
|
7219
|
-
outcome:
|
|
7381
|
+
outcome: toolResult.isError ? Outcome.Error : Outcome.Success
|
|
7220
7382
|
}
|
|
7221
7383
|
});
|
|
7222
|
-
return
|
|
7384
|
+
return toolResult;
|
|
7223
7385
|
} catch (err) {
|
|
7224
7386
|
safeTrack2({
|
|
7225
7387
|
name: EventName.McpToolCompleted,
|
|
@@ -7463,4 +7625,12 @@ var plugins_exports = {};
|
|
|
7463
7625
|
// packages/mcps/src/mcp/agents/index.ts
|
|
7464
7626
|
var agents_exports = {};
|
|
7465
7627
|
|
|
7466
|
-
|
|
7628
|
+
// packages/mcps/src/shared/watcher-lifetime-constants.ts
|
|
7629
|
+
var WATCHER_LIFETIME_UNBOUNDED_SECONDS = 0;
|
|
7630
|
+
var WATCHER_LIFETIME_SECONDS = {
|
|
7631
|
+
["1d" /* OneDay */]: 86400,
|
|
7632
|
+
["7d" /* SevenDays */]: 604800,
|
|
7633
|
+
["never" /* Never */]: WATCHER_LIFETIME_UNBOUNDED_SECONDS
|
|
7634
|
+
};
|
|
7635
|
+
|
|
7636
|
+
export { DEFAULT_PREFERENCES, EventName, PREFERENCES_FILE_NAME, PREFERENCES_PROJECT_DIR_NAME, PREFERENCES_SCHEMA, PREFERENCES_VERSION, PREFERENCE_ALLOWED_VALUES, PreferenceKey, PreferenceValue, ProjectPreferencesReconcileOutcome, ServiceName, Surface, WATCHER_LIFETIME_SECONDS, WATCHER_LIFETIME_UNBOUNDED_SECONDS, __export, __require, buildElectronAppChecksumsUrl, buildElectronAppReleaseAssetUrl, buildElectronAppReleaseTag, calculateFileChecksum, createApiKeyWithToken, createChildLogger, deleteApiKeyData, deleteCredentials, e2e_exports2 as e2e_exports, formatPreferencesOneLiner, getApiKey, getApiKeyFilePath, getAuthService, getBundledElectronAppVersion, getCallerCredentials, getCallerCredentialsAsync, getChecksumForPlatform, getConfig, getCredentialsFilePath, getDataDir2 as getDataDir, getDisclosureCopy, getDownloadBaseUrl, getElectronAppChecksums, getElectronAppDir, getElectronAppVersion, getElectronAppVersionSource, getLocalQaTools, getLogger, getPlatformKey, getQaTools, getValidApiKeyData, getValidCredentials, hasApiKey, hasShownDisclosure, initTelemetry, isElectronAppInstalled, isFirstRun, loadApiKeyData, loadCredentials, local_exports2 as local_exports, markDisclosureShown, mcp_exports, openBrowserUrl, performLogin, performLogout, pollDeviceCode, reconcileProjectPreferences, resetConfig, resetLogger, resetPreference, resolveElectronAppPathOrNull, resolvePreferences, saveApiKey, saveApiKeyData, saveCredentials, src_exports, startDeviceCodeFlow, toolRequiresAuth, track, validatePreference, verifyFileChecksum, writePreferences2 as writePreferences };
|