@muggleai/works 5.11.1 → 5.12.0-staging.74
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/config/runtime-targets.json +33 -0
- package/dist/{chunk-MSPMXBO5.js → chunk-DJ6W5PZA.js} +486 -351
- package/dist/{chunk-WUMAJOBT.js → chunk-VTSS6TGQ.js} +158 -56
- package/dist/cli.js +2 -2
- package/dist/index.js +2 -2
- package/dist/plugin/hooks/README.md +6 -1
- package/dist/plugin/hooks/hooks.json +24 -0
- package/dist/plugin/scripts/guardrail-capability-claim.sh +38 -0
- package/dist/plugin/scripts/guardrail-comment-reply-gate.sh +42 -0
- package/dist/plugin/scripts/guardrail-debug-path-gate.sh +1 -1
- package/dist/plugin/scripts/guardrail-e2e-gate.sh +1 -1
- package/dist/plugin/scripts/guardrail-record-comment-replies.sh +28 -0
- package/dist/plugin/scripts/guardrail-resolve-gate.sh +22 -0
- package/dist/plugin/scripts/guardrail-stage-gate.sh +1 -1
- package/dist/plugin/scripts/guardrail-terminal-gate.sh +1 -1
- package/dist/plugin/scripts/guardrail-walkthrough-gate.sh +1 -1
- package/dist/plugin/scripts/guardrail-watch-gate.sh +1 -1
- package/dist/plugin/scripts/guardrails.mjs +542 -34
- package/dist/plugin/scripts/pr-watch-loop.sh +9 -24
- package/dist/plugin/scripts/pr-watch-state.jq +52 -0
- package/dist/plugin/skills/_shared/identity-and-inbox.md +39 -0
- package/dist/plugin/skills/_shared/sync-branch-with-base.md +29 -0
- package/dist/plugin/skills/_shared/telemetry-events/muggle-do-escalation.md +3 -2
- package/dist/plugin/skills/_shared/vcs/github/unresolved-threads.md +2 -0
- package/dist/plugin/skills/_shared/vcs/gitlab/unresolved-discussions.md +3 -1
- package/dist/plugin/skills/_shared/vcs/gitlab.md +0 -1
- package/dist/plugin/skills/do/address-reviews.md +5 -2
- package/dist/plugin/skills/do/build.md +9 -0
- package/dist/plugin/skills/do/e2e-acceptance.md +2 -0
- package/dist/plugin/skills/do/e2e-repair.md +98 -0
- package/dist/plugin/skills/do/open-prs/forward.md +17 -9
- package/dist/plugin/skills/do/open-prs/update.md +9 -2
- package/dist/plugin/skills/do/per-comment-replies.md +13 -1
- package/dist/plugin/skills/do/pre-flight.md +2 -2
- package/dist/plugin/skills/do/resolve-conflicts.md +59 -59
- package/dist/plugin/skills/muggle-browser-task/SKILL.md +1 -1
- package/dist/plugin/skills/muggle-do/SKILL.md +6 -5
- package/dist/plugin/skills/muggle-pr-followup/arm-watcher.md +1 -1
- package/dist/plugin/skills/muggle-preferences/preference-gates/autoRebase.md +5 -5
- package/dist/plugin/skills/muggle-status/SKILL.md +15 -6
- package/dist/plugin/skills/muggle-test/SKILL.md +1 -0
- package/dist/plugin/skills/muggle-test-feature-local/SKILL.md +5 -3
- package/dist/plugin/skills/muggle-test-prepare/steps/rebase-check.md +1 -1
- package/dist/release-manifest.json +3 -3
- package/dist/src-FRYBTZ6J.js +1 -0
- package/package.json +22 -9
- package/plugin/hooks/README.md +6 -1
- package/plugin/hooks/hooks.json +24 -0
- package/plugin/scripts/guardrail-capability-claim.sh +38 -0
- package/plugin/scripts/guardrail-comment-reply-gate.sh +42 -0
- package/plugin/scripts/guardrail-debug-path-gate.sh +1 -1
- package/plugin/scripts/guardrail-e2e-gate.sh +1 -1
- package/plugin/scripts/guardrail-record-comment-replies.sh +28 -0
- package/plugin/scripts/guardrail-resolve-gate.sh +22 -0
- package/plugin/scripts/guardrail-stage-gate.sh +1 -1
- package/plugin/scripts/guardrail-terminal-gate.sh +1 -1
- package/plugin/scripts/guardrail-walkthrough-gate.sh +1 -1
- package/plugin/scripts/guardrail-watch-gate.sh +1 -1
- package/plugin/scripts/guardrails.mjs +542 -34
- package/plugin/scripts/pr-watch-loop.sh +9 -24
- package/plugin/scripts/pr-watch-state.jq +52 -0
- package/plugin/skills/_shared/identity-and-inbox.md +39 -0
- package/plugin/skills/_shared/sync-branch-with-base.md +29 -0
- package/plugin/skills/_shared/telemetry-events/muggle-do-escalation.md +3 -2
- package/plugin/skills/_shared/vcs/github/unresolved-threads.md +2 -0
- package/plugin/skills/_shared/vcs/gitlab/unresolved-discussions.md +3 -1
- package/plugin/skills/_shared/vcs/gitlab.md +0 -1
- package/plugin/skills/do/address-reviews.md +5 -2
- package/plugin/skills/do/build.md +9 -0
- package/plugin/skills/do/e2e-acceptance.md +2 -0
- package/plugin/skills/do/e2e-repair.md +98 -0
- package/plugin/skills/do/open-prs/forward.md +17 -9
- package/plugin/skills/do/open-prs/update.md +9 -2
- package/plugin/skills/do/per-comment-replies.md +13 -1
- package/plugin/skills/do/pre-flight.md +2 -2
- package/plugin/skills/do/resolve-conflicts.md +59 -59
- package/plugin/skills/muggle-browser-task/SKILL.md +1 -1
- package/plugin/skills/muggle-do/SKILL.md +6 -5
- package/plugin/skills/muggle-pr-followup/arm-watcher.md +1 -1
- package/plugin/skills/muggle-preferences/preference-gates/autoRebase.md +5 -5
- package/plugin/skills/muggle-status/SKILL.md +15 -6
- package/plugin/skills/muggle-test/SKILL.md +1 -0
- package/plugin/skills/muggle-test-feature-local/SKILL.md +5 -3
- package/plugin/skills/muggle-test-prepare/steps/rebase-check.md +1 -1
- package/scripts/postinstall.mjs +94 -6
- package/scripts/release-integrity/compareVersions.mjs +24 -0
- package/scripts/release-integrity/constants.mjs +8 -0
- package/scripts/release-integrity/index.d.mts +21 -0
- package/scripts/release-integrity/index.mjs +4 -0
- package/scripts/release-integrity/resolveIntegrityPolicy.mjs +37 -0
- package/scripts/release-integrity/verifyReleaseSignature.mjs +51 -0
- package/dist/plugin/skills/_shared/rebase-before-e2e.md +0 -21
- package/dist/plugin/skills/_shared/vcs/gitlab/resolve-discussion.md +0 -10
- package/dist/src-B5OTAZKM.js +0 -1
- package/plugin/skills/_shared/rebase-before-e2e.md +0 -21
- package/plugin/skills/_shared/vcs/gitlab/resolve-discussion.md +0 -10
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import * as
|
|
2
|
-
import { randomUUID } from 'crypto';
|
|
3
|
-
import * as fs5 from 'fs';
|
|
1
|
+
import * as fs6 from 'fs';
|
|
4
2
|
import { readFileSync, existsSync, mkdirSync, writeFileSync } from 'fs';
|
|
5
|
-
import * as
|
|
3
|
+
import * as path11 from 'path';
|
|
6
4
|
import { join, dirname } from 'path';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
import * as crypto from 'crypto';
|
|
7
|
+
import { randomUUID } from 'crypto';
|
|
7
8
|
import * as os4 from 'os';
|
|
8
9
|
import { platform } from 'os';
|
|
9
10
|
import winston from 'winston';
|
|
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 fs10 from 'fs/promises';
|
|
14
14
|
import AppInsights from 'applicationinsights';
|
|
15
15
|
import { z } from 'zod';
|
|
16
16
|
|
|
@@ -30,6 +30,7 @@ var __export = (target, all) => {
|
|
|
30
30
|
var src_exports = {};
|
|
31
31
|
__export(src_exports, {
|
|
32
32
|
DEFAULT_PREFERENCES: () => DEFAULT_PREFERENCES,
|
|
33
|
+
ElectronAppReleaseStream: () => ElectronAppReleaseStream,
|
|
33
34
|
PREFERENCES_FILE_NAME: () => PREFERENCES_FILE_NAME,
|
|
34
35
|
PREFERENCES_PROJECT_DIR_NAME: () => PREFERENCES_PROJECT_DIR_NAME,
|
|
35
36
|
PREFERENCES_SCHEMA: () => PREFERENCES_SCHEMA,
|
|
@@ -38,8 +39,10 @@ __export(src_exports, {
|
|
|
38
39
|
PreferenceKey: () => PreferenceKey,
|
|
39
40
|
PreferenceValue: () => PreferenceValue,
|
|
40
41
|
ProjectPreferencesReconcileOutcome: () => ProjectPreferencesReconcileOutcome,
|
|
42
|
+
RuntimeTarget: () => RuntimeTarget,
|
|
41
43
|
WATCHER_LIFETIME_SECONDS: () => WATCHER_LIFETIME_SECONDS,
|
|
42
44
|
WATCHER_LIFETIME_UNBOUNDED_SECONDS: () => WATCHER_LIFETIME_UNBOUNDED_SECONDS,
|
|
45
|
+
assertDeviceCodeClientProvisioned: () => assertDeviceCodeClientProvisioned,
|
|
43
46
|
buildElectronAppChecksumsUrl: () => buildElectronAppChecksumsUrl,
|
|
44
47
|
buildElectronAppReleaseAssetUrl: () => buildElectronAppReleaseAssetUrl,
|
|
45
48
|
buildElectronAppReleaseTag: () => buildElectronAppReleaseTag,
|
|
@@ -50,6 +53,8 @@ __export(src_exports, {
|
|
|
50
53
|
deleteCredentials: () => deleteCredentials,
|
|
51
54
|
e2e: () => e2e_exports2,
|
|
52
55
|
formatPreferencesOneLiner: () => formatPreferencesOneLiner,
|
|
56
|
+
getActiveElectronAppReleaseStream: () => getActiveElectronAppReleaseStream,
|
|
57
|
+
getActiveRuntimeTarget: () => getActiveRuntimeTarget,
|
|
53
58
|
getApiKey: () => getApiKey,
|
|
54
59
|
getApiKeyFilePath: () => getApiKeyFilePath,
|
|
55
60
|
getAuthService: () => getAuthService,
|
|
@@ -63,12 +68,15 @@ __export(src_exports, {
|
|
|
63
68
|
getDownloadBaseUrl: () => getDownloadBaseUrl,
|
|
64
69
|
getElectronAppChecksums: () => getElectronAppChecksums,
|
|
65
70
|
getElectronAppDir: () => getElectronAppDir,
|
|
71
|
+
getElectronAppReleaseTagPrefix: () => getElectronAppReleaseTagPrefix,
|
|
72
|
+
getElectronAppSignedFromVersion: () => getElectronAppSignedFromVersion,
|
|
66
73
|
getElectronAppVersion: () => getElectronAppVersion,
|
|
67
74
|
getElectronAppVersionSource: () => getElectronAppVersionSource,
|
|
68
75
|
getLocalQaTools: () => getLocalQaTools,
|
|
69
76
|
getLogger: () => getLogger,
|
|
70
77
|
getPlatformKey: () => getPlatformKey,
|
|
71
78
|
getQaTools: () => getQaTools,
|
|
79
|
+
getReleaseSignerIdentityUri: () => getReleaseSignerIdentityUri,
|
|
72
80
|
getValidApiKeyData: () => getValidApiKeyData,
|
|
73
81
|
getValidCredentials: () => getValidCredentials,
|
|
74
82
|
hasApiKey: () => hasApiKey,
|
|
@@ -87,8 +95,12 @@ __export(src_exports, {
|
|
|
87
95
|
resetConfig: () => resetConfig,
|
|
88
96
|
resetLogger: () => resetLogger,
|
|
89
97
|
resetPreference: () => resetPreference,
|
|
98
|
+
resolveActiveProfile: () => resolveActiveProfile,
|
|
99
|
+
resolveActiveReleaseStream: () => resolveActiveReleaseStream,
|
|
100
|
+
resolveActiveReleaseTagPrefix: () => resolveActiveReleaseTagPrefix,
|
|
90
101
|
resolveElectronAppPathOrNull: () => resolveElectronAppPathOrNull,
|
|
91
102
|
resolvePreferences: () => resolvePreferences,
|
|
103
|
+
resolveRuntimeTarget: () => resolveRuntimeTarget,
|
|
92
104
|
saveApiKey: () => saveApiKey,
|
|
93
105
|
saveApiKeyData: () => saveApiKeyData,
|
|
94
106
|
saveCredentials: () => saveCredentials,
|
|
@@ -98,9 +110,121 @@ __export(src_exports, {
|
|
|
98
110
|
verifyFileChecksum: () => verifyFileChecksum,
|
|
99
111
|
writePreferences: () => writePreferences2
|
|
100
112
|
});
|
|
113
|
+
|
|
114
|
+
// packages/mcps/src/shared/runtime-target-types.ts
|
|
115
|
+
var RuntimeTarget = /* @__PURE__ */ ((RuntimeTarget2) => {
|
|
116
|
+
RuntimeTarget2["Production"] = "production";
|
|
117
|
+
RuntimeTarget2["Staging"] = "staging";
|
|
118
|
+
RuntimeTarget2["Dev"] = "dev";
|
|
119
|
+
return RuntimeTarget2;
|
|
120
|
+
})(RuntimeTarget || {});
|
|
121
|
+
var ElectronAppReleaseStream = /* @__PURE__ */ ((ElectronAppReleaseStream3) => {
|
|
122
|
+
ElectronAppReleaseStream3["Production"] = "production";
|
|
123
|
+
ElectronAppReleaseStream3["Staging"] = "staging";
|
|
124
|
+
return ElectronAppReleaseStream3;
|
|
125
|
+
})(ElectronAppReleaseStream || {});
|
|
126
|
+
var DEFAULT_AUTH0_SCOPE = "openid profile email offline_access";
|
|
127
|
+
var DEFAULT_WEB_SERVICE_URL = "http://localhost:3001";
|
|
128
|
+
var RUNTIME_TARGET_ENV_VAR = "MUGGLE_MCP_PROMPT_SERVICE_TARGET";
|
|
129
|
+
var RUNTIME_TARGETS_FILE = path11.join("config", "runtime-targets.json");
|
|
130
|
+
function getPackageRoot() {
|
|
131
|
+
const currentDir = path11.dirname(fileURLToPath(import.meta.url));
|
|
132
|
+
if (currentDir.includes(path11.join("dist", "shared"))) {
|
|
133
|
+
return path11.resolve(currentDir, "..", "..");
|
|
134
|
+
}
|
|
135
|
+
if (currentDir.endsWith("dist")) {
|
|
136
|
+
return path11.resolve(currentDir, "..");
|
|
137
|
+
}
|
|
138
|
+
if (currentDir.includes(path11.join("src", "shared"))) {
|
|
139
|
+
return path11.resolve(currentDir, "..", "..", "..", "..");
|
|
140
|
+
}
|
|
141
|
+
return path11.dirname(currentDir);
|
|
142
|
+
}
|
|
143
|
+
var runtimeTargetDataCache = null;
|
|
144
|
+
function getRuntimeTargetData() {
|
|
145
|
+
if (runtimeTargetDataCache) {
|
|
146
|
+
return runtimeTargetDataCache;
|
|
147
|
+
}
|
|
148
|
+
const profilesPath = path11.join(getPackageRoot(), RUNTIME_TARGETS_FILE);
|
|
149
|
+
let parsedData;
|
|
150
|
+
try {
|
|
151
|
+
parsedData = JSON.parse(fs6.readFileSync(profilesPath, "utf-8"));
|
|
152
|
+
} catch (error) {
|
|
153
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
154
|
+
throw new Error(
|
|
155
|
+
`Failed to read runtime target profiles.
|
|
156
|
+
Path: ${profilesPath}
|
|
157
|
+
Error: ${errorMessage}
|
|
158
|
+
This is a bug - please report it.`,
|
|
159
|
+
{ cause: error }
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
for (const target of Object.values(RuntimeTarget)) {
|
|
163
|
+
if (!parsedData.targets?.[target]) {
|
|
164
|
+
throw new Error(
|
|
165
|
+
`Missing runtime target '${target}' in profile data.
|
|
166
|
+
Path: ${profilesPath}
|
|
167
|
+
This is a bug - please report it.`
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
for (const stream of Object.values(ElectronAppReleaseStream)) {
|
|
172
|
+
if (!parsedData.streams?.[stream]) {
|
|
173
|
+
throw new Error(
|
|
174
|
+
`Missing electron-app release stream '${stream}' in profile data.
|
|
175
|
+
Path: ${profilesPath}
|
|
176
|
+
This is a bug - please report it.`
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
runtimeTargetDataCache = parsedData;
|
|
181
|
+
return runtimeTargetDataCache;
|
|
182
|
+
}
|
|
183
|
+
function getRuntimeTargetProfiles() {
|
|
184
|
+
return getRuntimeTargetData().targets;
|
|
185
|
+
}
|
|
186
|
+
function getElectronAppReleaseStreams() {
|
|
187
|
+
return getRuntimeTargetData().streams;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// packages/mcps/src/shared/runtime-target.ts
|
|
191
|
+
var KNOWN_RUNTIME_TARGETS = [
|
|
192
|
+
"production" /* Production */,
|
|
193
|
+
"staging" /* Staging */,
|
|
194
|
+
"dev" /* Dev */
|
|
195
|
+
];
|
|
196
|
+
function resolveRuntimeTarget(bakedDefault) {
|
|
197
|
+
const overrideValue = process.env[RUNTIME_TARGET_ENV_VAR];
|
|
198
|
+
if (overrideValue) {
|
|
199
|
+
const matchedTarget = KNOWN_RUNTIME_TARGETS.find((target) => target === overrideValue);
|
|
200
|
+
if (!matchedTarget) {
|
|
201
|
+
throw new Error(
|
|
202
|
+
`Invalid ${RUNTIME_TARGET_ENV_VAR} value: '${overrideValue}'. Expected one of: ${KNOWN_RUNTIME_TARGETS.join(", ")}.`
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
return matchedTarget;
|
|
206
|
+
}
|
|
207
|
+
return bakedDefault ?? "dev" /* Dev */;
|
|
208
|
+
}
|
|
209
|
+
function resolveActiveProfile(bakedDefault) {
|
|
210
|
+
return getRuntimeTargetProfiles()[resolveRuntimeTarget(bakedDefault)];
|
|
211
|
+
}
|
|
212
|
+
function resolveActiveReleaseStream(bakedDefault) {
|
|
213
|
+
return resolveActiveProfile(bakedDefault).electronAppReleaseStream;
|
|
214
|
+
}
|
|
215
|
+
function resolveActiveReleaseTagPrefix(bakedDefault) {
|
|
216
|
+
return getElectronAppReleaseStreams()[resolveActiveReleaseStream(bakedDefault)].electronAppReleaseTagPrefix;
|
|
217
|
+
}
|
|
218
|
+
function assertDeviceCodeClientProvisioned(target) {
|
|
219
|
+
if (getRuntimeTargetProfiles()[target].auth0ClientId === "") {
|
|
220
|
+
throw new Error(
|
|
221
|
+
`Runtime target '${target}' has no Auth0 device code client provisioned. Provision a native application with the device code grant in that tenant, then record its client ID in RUNTIME_TARGET_PROFILES.`
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
101
225
|
var DATA_DIR_NAME = ".muggle-ai";
|
|
102
226
|
function getDataDir() {
|
|
103
|
-
return
|
|
227
|
+
return path11.join(os4.homedir(), DATA_DIR_NAME);
|
|
104
228
|
}
|
|
105
229
|
var DEV_MANIFEST = {
|
|
106
230
|
release: "dev",
|
|
@@ -147,44 +271,34 @@ function readReleaseManifest() {
|
|
|
147
271
|
}
|
|
148
272
|
|
|
149
273
|
// packages/mcps/src/shared/config.ts
|
|
150
|
-
var DEFAULT_PROMPT_SERVICE_PRODUCTION_URL = "https://promptservice.muggle-ai.com";
|
|
151
|
-
var DEFAULT_PROMPT_SERVICE_DEV_URL = "http://localhost:5050";
|
|
152
|
-
var DEFAULT_WEB_SERVICE_URL = "http://localhost:3001";
|
|
153
274
|
var ELECTRON_APP_DIR = "electron-app";
|
|
154
|
-
var ELECTRON_APP_RELEASE_TAG_PREFIX = "electron-app-v";
|
|
155
275
|
var API_KEY_FILE = "api-key.json";
|
|
156
|
-
var
|
|
157
|
-
var DEFAULT_AUTH0_PRODUCTION_CLIENT_ID = "UgG5UjoyLksxMciWWKqVpwfWrJ4rFvtT";
|
|
158
|
-
var DEFAULT_AUTH0_PRODUCTION_AUDIENCE = "https://muggleai.us.auth0.com/api/v2/";
|
|
159
|
-
var DEFAULT_AUTH0_DEV_DOMAIN = "dev-po4mxmz0rd8a0w8w.us.auth0.com";
|
|
160
|
-
var DEFAULT_AUTH0_DEV_CLIENT_ID = "GBvkMdTbCI80XJXnJ90MmbEvXwcWGUtw";
|
|
161
|
-
var DEFAULT_AUTH0_DEV_AUDIENCE = "https://dev-po4mxmz0rd8a0w8w.us.auth0.com/api/v2/";
|
|
162
|
-
var DEFAULT_AUTH0_SCOPE = "openid profile email offline_access";
|
|
276
|
+
var OAUTH_SESSION_FILE = "oauth-session.json";
|
|
163
277
|
var configInstance = null;
|
|
164
278
|
var muggleConfigCache = null;
|
|
165
|
-
function
|
|
279
|
+
function getPackageRoot2() {
|
|
166
280
|
const currentFilePath = fileURLToPath(import.meta.url);
|
|
167
|
-
const currentDir =
|
|
168
|
-
if (currentDir.includes(
|
|
169
|
-
return
|
|
281
|
+
const currentDir = path11.dirname(currentFilePath);
|
|
282
|
+
if (currentDir.includes(path11.join("dist", "shared"))) {
|
|
283
|
+
return path11.resolve(currentDir, "..", "..");
|
|
170
284
|
}
|
|
171
285
|
if (currentDir.endsWith("dist")) {
|
|
172
|
-
return
|
|
286
|
+
return path11.resolve(currentDir, "..");
|
|
173
287
|
}
|
|
174
|
-
if (currentDir.includes(
|
|
175
|
-
return
|
|
288
|
+
if (currentDir.includes(path11.join("src", "shared"))) {
|
|
289
|
+
return path11.resolve(currentDir, "..", "..", "..", "..");
|
|
176
290
|
}
|
|
177
|
-
return
|
|
291
|
+
return path11.dirname(currentDir);
|
|
178
292
|
}
|
|
179
293
|
function getMuggleConfig() {
|
|
180
294
|
if (muggleConfigCache) {
|
|
181
295
|
return muggleConfigCache;
|
|
182
296
|
}
|
|
183
|
-
const packageRoot =
|
|
184
|
-
const packageJsonPath =
|
|
297
|
+
const packageRoot = getPackageRoot2();
|
|
298
|
+
const packageJsonPath = path11.join(packageRoot, "package.json");
|
|
185
299
|
let packageJson;
|
|
186
300
|
try {
|
|
187
|
-
const content =
|
|
301
|
+
const content = fs6.readFileSync(packageJsonPath, "utf-8");
|
|
188
302
|
packageJson = JSON.parse(content);
|
|
189
303
|
} catch (error) {
|
|
190
304
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -221,45 +335,65 @@ function getMuggleConfig() {
|
|
|
221
335
|
This is a bug - please report it.`
|
|
222
336
|
);
|
|
223
337
|
}
|
|
224
|
-
|
|
338
|
+
const runtimeTargetDefault = config.runtimeTargetDefault;
|
|
339
|
+
if (runtimeTargetDefault !== void 0 && !Object.values(RuntimeTarget).includes(runtimeTargetDefault)) {
|
|
225
340
|
throw new Error(
|
|
226
341
|
`Invalid muggleConfig.runtimeTargetDefault in package.json.
|
|
227
342
|
Path: ${packageJsonPath}
|
|
228
343
|
Value: ${JSON.stringify(config.runtimeTargetDefault)}
|
|
229
|
-
Expected: "
|
|
344
|
+
Expected one of: ${Object.values(RuntimeTarget).join(", ")}
|
|
230
345
|
This is a bug - please report it.`
|
|
231
346
|
);
|
|
232
347
|
}
|
|
233
348
|
muggleConfigCache = {
|
|
234
349
|
electronAppVersion: config.electronAppVersion,
|
|
235
350
|
downloadBaseUrl: config.downloadBaseUrl,
|
|
236
|
-
|
|
237
|
-
runtimeTargetDefault
|
|
351
|
+
checksumsByStream: config.checksumsByStream || {},
|
|
352
|
+
runtimeTargetDefault
|
|
238
353
|
};
|
|
239
354
|
return muggleConfigCache;
|
|
240
355
|
}
|
|
241
356
|
function getDataDir2() {
|
|
242
357
|
return getDataDir();
|
|
243
358
|
}
|
|
359
|
+
function buildElectronAppDirName(params) {
|
|
360
|
+
if (params.releaseStream === "production" /* Production */) {
|
|
361
|
+
return params.version;
|
|
362
|
+
}
|
|
363
|
+
return `${params.version}-${params.releaseStream}`;
|
|
364
|
+
}
|
|
365
|
+
function buildOAuthSessionFileName(params) {
|
|
366
|
+
if (params.runtimeTarget === "production" /* Production */) {
|
|
367
|
+
return OAUTH_SESSION_FILE;
|
|
368
|
+
}
|
|
369
|
+
return `oauth-session-${params.runtimeTarget}.json`;
|
|
370
|
+
}
|
|
244
371
|
function getDownloadedElectronAppPath() {
|
|
245
372
|
const platformName = os4.platform();
|
|
246
373
|
const version = getElectronAppVersion();
|
|
247
|
-
const baseDir =
|
|
374
|
+
const baseDir = path11.join(
|
|
375
|
+
getDataDir2(),
|
|
376
|
+
ELECTRON_APP_DIR,
|
|
377
|
+
buildElectronAppDirName({
|
|
378
|
+
version,
|
|
379
|
+
releaseStream: getActiveElectronAppReleaseStream()
|
|
380
|
+
})
|
|
381
|
+
);
|
|
248
382
|
let binaryPath;
|
|
249
383
|
switch (platformName) {
|
|
250
384
|
case "darwin":
|
|
251
|
-
binaryPath =
|
|
385
|
+
binaryPath = path11.join(baseDir, "MuggleAI.app", "Contents", "MacOS", "MuggleAI");
|
|
252
386
|
break;
|
|
253
387
|
case "win32":
|
|
254
|
-
binaryPath =
|
|
388
|
+
binaryPath = path11.join(baseDir, "MuggleAI.exe");
|
|
255
389
|
break;
|
|
256
390
|
case "linux":
|
|
257
|
-
binaryPath =
|
|
391
|
+
binaryPath = path11.join(baseDir, "MuggleAI");
|
|
258
392
|
break;
|
|
259
393
|
default:
|
|
260
394
|
return null;
|
|
261
395
|
}
|
|
262
|
-
if (
|
|
396
|
+
if (fs6.existsSync(binaryPath)) {
|
|
263
397
|
return binaryPath;
|
|
264
398
|
}
|
|
265
399
|
return null;
|
|
@@ -270,25 +404,25 @@ function getSystemElectronAppPath() {
|
|
|
270
404
|
let binaryPath;
|
|
271
405
|
switch (platformName) {
|
|
272
406
|
case "darwin":
|
|
273
|
-
binaryPath =
|
|
407
|
+
binaryPath = path11.join(homeDir, "Applications", "MuggleAI.app", "Contents", "MacOS", "MuggleAI");
|
|
274
408
|
break;
|
|
275
409
|
case "win32":
|
|
276
|
-
binaryPath =
|
|
410
|
+
binaryPath = path11.join(homeDir, "AppData", "Local", "Programs", "MuggleAI", "MuggleAI.exe");
|
|
277
411
|
break;
|
|
278
412
|
case "linux":
|
|
279
|
-
binaryPath =
|
|
413
|
+
binaryPath = path11.join(homeDir, ".local", "share", "muggle-ai", "MuggleAI");
|
|
280
414
|
break;
|
|
281
415
|
default:
|
|
282
416
|
return null;
|
|
283
417
|
}
|
|
284
|
-
if (
|
|
418
|
+
if (fs6.existsSync(binaryPath)) {
|
|
285
419
|
return binaryPath;
|
|
286
420
|
}
|
|
287
421
|
return null;
|
|
288
422
|
}
|
|
289
423
|
function resolveElectronAppPathOrNull() {
|
|
290
424
|
const customPath = process.env.ELECTRON_APP_PATH;
|
|
291
|
-
if (customPath &&
|
|
425
|
+
if (customPath && fs6.existsSync(customPath)) {
|
|
292
426
|
return customPath;
|
|
293
427
|
}
|
|
294
428
|
const downloadedPath = getDownloadedElectronAppPath();
|
|
@@ -303,12 +437,12 @@ function resolveElectronAppPathOrNull() {
|
|
|
303
437
|
}
|
|
304
438
|
function resolveWebServicePath() {
|
|
305
439
|
const customPath = process.env.WEB_SERVICE_PATH;
|
|
306
|
-
if (customPath &&
|
|
440
|
+
if (customPath && fs6.existsSync(customPath)) {
|
|
307
441
|
return customPath;
|
|
308
442
|
}
|
|
309
|
-
const packageRoot =
|
|
310
|
-
const siblingPath =
|
|
311
|
-
if (
|
|
443
|
+
const packageRoot = getPackageRoot2();
|
|
444
|
+
const siblingPath = path11.resolve(packageRoot, "..", "web-service", "dist", "src", "index.js");
|
|
445
|
+
if (fs6.existsSync(siblingPath)) {
|
|
312
446
|
return siblingPath;
|
|
313
447
|
}
|
|
314
448
|
return null;
|
|
@@ -320,65 +454,24 @@ function parseInteger(value, defaultValue) {
|
|
|
320
454
|
const parsed = parseInt(value, 10);
|
|
321
455
|
return isNaN(parsed) ? defaultValue : parsed;
|
|
322
456
|
}
|
|
323
|
-
function
|
|
324
|
-
|
|
325
|
-
if (runtimeTargetFromEnv) {
|
|
326
|
-
if (runtimeTargetFromEnv === "production" || runtimeTargetFromEnv === "dev") {
|
|
327
|
-
return runtimeTargetFromEnv;
|
|
328
|
-
}
|
|
329
|
-
throw new Error(
|
|
330
|
-
`Invalid MUGGLE_MCP_PROMPT_SERVICE_TARGET value: '${runtimeTargetFromEnv}'. Expected 'production' or 'dev'.`
|
|
331
|
-
);
|
|
332
|
-
}
|
|
333
|
-
const muggleConfig = getMuggleConfig();
|
|
334
|
-
if (muggleConfig.runtimeTargetDefault) {
|
|
335
|
-
return muggleConfig.runtimeTargetDefault;
|
|
336
|
-
}
|
|
337
|
-
return "dev";
|
|
338
|
-
}
|
|
339
|
-
function getDefaultPromptServiceUrl() {
|
|
340
|
-
const runtimeTarget = getPromptServiceRuntimeTarget();
|
|
341
|
-
if (runtimeTarget === "dev") {
|
|
342
|
-
return DEFAULT_PROMPT_SERVICE_DEV_URL;
|
|
343
|
-
}
|
|
344
|
-
return DEFAULT_PROMPT_SERVICE_PRODUCTION_URL;
|
|
457
|
+
function getActiveRuntimeTarget() {
|
|
458
|
+
return resolveRuntimeTarget(getMuggleConfig().runtimeTargetDefault);
|
|
345
459
|
}
|
|
346
|
-
function
|
|
347
|
-
|
|
348
|
-
if (runtimeTarget === "dev") {
|
|
349
|
-
return DEFAULT_AUTH0_DEV_DOMAIN;
|
|
350
|
-
}
|
|
351
|
-
return DEFAULT_AUTH0_PRODUCTION_DOMAIN;
|
|
352
|
-
}
|
|
353
|
-
function getDefaultAuth0ClientId() {
|
|
354
|
-
const runtimeTarget = getPromptServiceRuntimeTarget();
|
|
355
|
-
if (runtimeTarget === "production") {
|
|
356
|
-
return DEFAULT_AUTH0_PRODUCTION_CLIENT_ID;
|
|
357
|
-
}
|
|
358
|
-
return DEFAULT_AUTH0_DEV_CLIENT_ID;
|
|
359
|
-
}
|
|
360
|
-
function getDefaultAuth0Audience() {
|
|
361
|
-
const runtimeTarget = getPromptServiceRuntimeTarget();
|
|
362
|
-
if (runtimeTarget === "dev") {
|
|
363
|
-
return DEFAULT_AUTH0_DEV_AUDIENCE;
|
|
364
|
-
}
|
|
365
|
-
return DEFAULT_AUTH0_PRODUCTION_AUDIENCE;
|
|
460
|
+
function getActiveProfile() {
|
|
461
|
+
return resolveActiveProfile(getMuggleConfig().runtimeTargetDefault);
|
|
366
462
|
}
|
|
367
463
|
function buildAuth0Config() {
|
|
368
|
-
const
|
|
369
|
-
const defaultAuth0ClientId = getDefaultAuth0ClientId();
|
|
370
|
-
const defaultAuth0Audience = getDefaultAuth0Audience();
|
|
464
|
+
const activeProfile = getActiveProfile();
|
|
371
465
|
return {
|
|
372
|
-
domain: process.env.AUTH0_DOMAIN ??
|
|
373
|
-
clientId: process.env.AUTH0_CLIENT_ID ??
|
|
374
|
-
audience: process.env.AUTH0_AUDIENCE ??
|
|
466
|
+
domain: process.env.AUTH0_DOMAIN ?? activeProfile.auth0Domain,
|
|
467
|
+
clientId: process.env.AUTH0_CLIENT_ID ?? activeProfile.auth0ClientId,
|
|
468
|
+
audience: process.env.AUTH0_AUDIENCE ?? activeProfile.auth0Audience,
|
|
375
469
|
scope: process.env.AUTH0_SCOPE ?? DEFAULT_AUTH0_SCOPE
|
|
376
470
|
};
|
|
377
471
|
}
|
|
378
472
|
function buildE2eConfig() {
|
|
379
|
-
const defaultPromptServiceUrl = getDefaultPromptServiceUrl();
|
|
380
473
|
return {
|
|
381
|
-
promptServiceBaseUrl: process.env.PROMPT_SERVICE_BASE_URL ??
|
|
474
|
+
promptServiceBaseUrl: process.env.PROMPT_SERVICE_BASE_URL ?? getActiveProfile().promptServiceBaseUrl,
|
|
382
475
|
requestTimeoutMs: parseInteger(process.env.REQUEST_TIMEOUT_MS, 3e4),
|
|
383
476
|
workflowTimeoutMs: parseInteger(process.env.WORKFLOW_TIMEOUT_MS, 12e4)
|
|
384
477
|
};
|
|
@@ -386,25 +479,25 @@ function buildE2eConfig() {
|
|
|
386
479
|
function buildLocalQaConfig() {
|
|
387
480
|
const dataDir = getDataDir2();
|
|
388
481
|
const auth0Scopes = (process.env.AUTH0_SCOPE ?? DEFAULT_AUTH0_SCOPE).split(" ");
|
|
389
|
-
const
|
|
390
|
-
const defaultAuth0Domain = getDefaultAuth0Domain();
|
|
391
|
-
const defaultAuth0ClientId = getDefaultAuth0ClientId();
|
|
392
|
-
const defaultAuth0Audience = getDefaultAuth0Audience();
|
|
482
|
+
const activeProfile = getActiveProfile();
|
|
393
483
|
return {
|
|
394
484
|
webServiceUrl: process.env.WEB_SERVICE_URL ?? DEFAULT_WEB_SERVICE_URL,
|
|
395
|
-
promptServiceUrl: process.env.PROMPT_SERVICE_BASE_URL ??
|
|
485
|
+
promptServiceUrl: process.env.PROMPT_SERVICE_BASE_URL ?? activeProfile.promptServiceBaseUrl,
|
|
396
486
|
dataDir,
|
|
397
|
-
sessionsDir:
|
|
398
|
-
projectsDir:
|
|
399
|
-
tempDir:
|
|
400
|
-
apiKeyFilePath:
|
|
401
|
-
oauthSessionFilePath:
|
|
487
|
+
sessionsDir: path11.join(dataDir, "sessions"),
|
|
488
|
+
projectsDir: path11.join(dataDir, "projects"),
|
|
489
|
+
tempDir: path11.join(dataDir, "temp"),
|
|
490
|
+
apiKeyFilePath: path11.join(dataDir, API_KEY_FILE),
|
|
491
|
+
oauthSessionFilePath: path11.join(
|
|
492
|
+
dataDir,
|
|
493
|
+
buildOAuthSessionFileName({ runtimeTarget: getActiveRuntimeTarget() })
|
|
494
|
+
),
|
|
402
495
|
webServicePath: resolveWebServicePath(),
|
|
403
|
-
webServicePidFile:
|
|
496
|
+
webServicePidFile: path11.join(dataDir, "web-service.pid"),
|
|
404
497
|
auth0: {
|
|
405
|
-
domain: process.env.AUTH0_DOMAIN ??
|
|
406
|
-
clientId: process.env.AUTH0_CLIENT_ID ??
|
|
407
|
-
audience: process.env.AUTH0_AUDIENCE ??
|
|
498
|
+
domain: process.env.AUTH0_DOMAIN ?? activeProfile.auth0Domain,
|
|
499
|
+
clientId: process.env.AUTH0_CLIENT_ID ?? activeProfile.auth0ClientId,
|
|
500
|
+
audience: process.env.AUTH0_AUDIENCE ?? activeProfile.auth0Audience,
|
|
408
501
|
scopes: auth0Scopes
|
|
409
502
|
}
|
|
410
503
|
};
|
|
@@ -435,10 +528,10 @@ function getElectronAppVersion() {
|
|
|
435
528
|
if (envVersion && /^\d+\.\d+\.\d+$/.test(envVersion)) {
|
|
436
529
|
return envVersion;
|
|
437
530
|
}
|
|
438
|
-
const overridePath =
|
|
439
|
-
if (
|
|
531
|
+
const overridePath = path11.join(getDataDir2(), VERSION_OVERRIDE_FILE);
|
|
532
|
+
if (fs6.existsSync(overridePath)) {
|
|
440
533
|
try {
|
|
441
|
-
const content = JSON.parse(
|
|
534
|
+
const content = JSON.parse(fs6.readFileSync(overridePath, "utf-8"));
|
|
442
535
|
if (content.version && typeof content.version === "string") {
|
|
443
536
|
return content.version;
|
|
444
537
|
}
|
|
@@ -452,10 +545,10 @@ function getElectronAppVersionSource() {
|
|
|
452
545
|
if (envVersion && /^\d+\.\d+\.\d+$/.test(envVersion)) {
|
|
453
546
|
return "env";
|
|
454
547
|
}
|
|
455
|
-
const overridePath =
|
|
456
|
-
if (
|
|
548
|
+
const overridePath = path11.join(getDataDir2(), VERSION_OVERRIDE_FILE);
|
|
549
|
+
if (fs6.existsSync(overridePath)) {
|
|
457
550
|
try {
|
|
458
|
-
const content = JSON.parse(
|
|
551
|
+
const content = JSON.parse(fs6.readFileSync(overridePath, "utf-8"));
|
|
459
552
|
if (content.version && typeof content.version === "string") {
|
|
460
553
|
return "override";
|
|
461
554
|
}
|
|
@@ -470,8 +563,14 @@ function getBundledElectronAppVersion() {
|
|
|
470
563
|
function getDownloadBaseUrl() {
|
|
471
564
|
return getMuggleConfig().downloadBaseUrl;
|
|
472
565
|
}
|
|
566
|
+
function getActiveElectronAppReleaseStream() {
|
|
567
|
+
return resolveActiveReleaseStream(getMuggleConfig().runtimeTargetDefault);
|
|
568
|
+
}
|
|
569
|
+
function getElectronAppReleaseTagPrefix() {
|
|
570
|
+
return resolveActiveReleaseTagPrefix(getMuggleConfig().runtimeTargetDefault);
|
|
571
|
+
}
|
|
473
572
|
function buildElectronAppReleaseTag(version) {
|
|
474
|
-
return `${
|
|
573
|
+
return `${getElectronAppReleaseTagPrefix()}${version}`;
|
|
475
574
|
}
|
|
476
575
|
function buildElectronAppReleaseAssetUrl(params) {
|
|
477
576
|
return `${getDownloadBaseUrl()}/${buildElectronAppReleaseTag(params.version)}/${params.assetFileName}`;
|
|
@@ -480,14 +579,27 @@ function buildElectronAppChecksumsUrl(version) {
|
|
|
480
579
|
return `${getDownloadBaseUrl()}/${buildElectronAppReleaseTag(version)}/checksums.txt`;
|
|
481
580
|
}
|
|
482
581
|
function getElectronAppChecksums() {
|
|
483
|
-
return getMuggleConfig().
|
|
582
|
+
return getMuggleConfig().checksumsByStream?.[getActiveElectronAppReleaseStream()];
|
|
583
|
+
}
|
|
584
|
+
function getElectronAppSignedFromVersion() {
|
|
585
|
+
return getMuggleConfig().electronAppSignedFromVersion ?? "";
|
|
586
|
+
}
|
|
587
|
+
function getReleaseSignerIdentityUri() {
|
|
588
|
+
return getMuggleConfig().signerIdentityUri ?? "";
|
|
484
589
|
}
|
|
485
590
|
function isElectronAppInstalled() {
|
|
486
591
|
return getDownloadedElectronAppPath() !== null;
|
|
487
592
|
}
|
|
488
593
|
function getElectronAppDir(version) {
|
|
489
594
|
const resolvedVersion = version ?? getElectronAppVersion();
|
|
490
|
-
return
|
|
595
|
+
return path11.join(
|
|
596
|
+
getDataDir2(),
|
|
597
|
+
ELECTRON_APP_DIR,
|
|
598
|
+
buildElectronAppDirName({
|
|
599
|
+
version: resolvedVersion,
|
|
600
|
+
releaseStream: getActiveElectronAppReleaseStream()
|
|
601
|
+
})
|
|
602
|
+
);
|
|
491
603
|
}
|
|
492
604
|
|
|
493
605
|
// packages/mcps/src/shared/logger.ts
|
|
@@ -544,14 +656,14 @@ function getPlatformKey() {
|
|
|
544
656
|
}
|
|
545
657
|
}
|
|
546
658
|
async function calculateFileChecksum(filePath) {
|
|
547
|
-
return new Promise((
|
|
659
|
+
return new Promise((resolve6, reject) => {
|
|
548
660
|
const hash = crypto.createHash("sha256");
|
|
549
|
-
const stream =
|
|
661
|
+
const stream = fs6.createReadStream(filePath);
|
|
550
662
|
stream.on("data", (data) => {
|
|
551
663
|
hash.update(data);
|
|
552
664
|
});
|
|
553
665
|
stream.on("end", () => {
|
|
554
|
-
|
|
666
|
+
resolve6(hash.digest("hex"));
|
|
555
667
|
});
|
|
556
668
|
stream.on("error", (error) => {
|
|
557
669
|
reject(error);
|
|
@@ -561,7 +673,7 @@ async function calculateFileChecksum(filePath) {
|
|
|
561
673
|
async function verifyFileChecksum(filePath, expectedChecksum) {
|
|
562
674
|
if (!expectedChecksum || expectedChecksum.trim() === "") {
|
|
563
675
|
logger.warn("Checksum verification skipped - no checksum provided", {
|
|
564
|
-
file:
|
|
676
|
+
file: path11.basename(filePath)
|
|
565
677
|
});
|
|
566
678
|
return {
|
|
567
679
|
valid: true,
|
|
@@ -577,13 +689,13 @@ async function verifyFileChecksum(filePath, expectedChecksum) {
|
|
|
577
689
|
const valid = normalizedExpected === normalizedActual;
|
|
578
690
|
if (!valid) {
|
|
579
691
|
logger.error("Checksum verification failed", {
|
|
580
|
-
file:
|
|
692
|
+
file: path11.basename(filePath),
|
|
581
693
|
expected: normalizedExpected,
|
|
582
694
|
actual: normalizedActual
|
|
583
695
|
});
|
|
584
696
|
} else {
|
|
585
697
|
logger.info("Checksum verified successfully", {
|
|
586
|
-
file:
|
|
698
|
+
file: path11.basename(filePath),
|
|
587
699
|
checksum: normalizedActual
|
|
588
700
|
});
|
|
589
701
|
}
|
|
@@ -596,7 +708,7 @@ async function verifyFileChecksum(filePath, expectedChecksum) {
|
|
|
596
708
|
} catch (error) {
|
|
597
709
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
598
710
|
logger.error("Checksum calculation failed", {
|
|
599
|
-
file:
|
|
711
|
+
file: path11.basename(filePath),
|
|
600
712
|
error: errorMessage
|
|
601
713
|
});
|
|
602
714
|
return {
|
|
@@ -629,7 +741,7 @@ function getOpenCommand(url) {
|
|
|
629
741
|
}
|
|
630
742
|
}
|
|
631
743
|
async function openBrowserUrl(options) {
|
|
632
|
-
return new Promise((
|
|
744
|
+
return new Promise((resolve6) => {
|
|
633
745
|
try {
|
|
634
746
|
const command = getOpenCommand(options.url);
|
|
635
747
|
logger2.debug("[Browser] Opening URL", { url: options.url, command });
|
|
@@ -639,13 +751,13 @@ async function openBrowserUrl(options) {
|
|
|
639
751
|
url: options.url,
|
|
640
752
|
error: error.message
|
|
641
753
|
});
|
|
642
|
-
|
|
754
|
+
resolve6({
|
|
643
755
|
opened: false,
|
|
644
756
|
error: error.message
|
|
645
757
|
});
|
|
646
758
|
} else {
|
|
647
759
|
logger2.info("[Browser] URL opened successfully", { url: options.url });
|
|
648
|
-
|
|
760
|
+
resolve6({ opened: true });
|
|
649
761
|
}
|
|
650
762
|
});
|
|
651
763
|
} catch (error) {
|
|
@@ -654,7 +766,7 @@ async function openBrowserUrl(options) {
|
|
|
654
766
|
url: options.url,
|
|
655
767
|
error: errorMessage
|
|
656
768
|
});
|
|
657
|
-
|
|
769
|
+
resolve6({
|
|
658
770
|
opened: false,
|
|
659
771
|
error: errorMessage
|
|
660
772
|
});
|
|
@@ -663,23 +775,23 @@ async function openBrowserUrl(options) {
|
|
|
663
775
|
}
|
|
664
776
|
var API_KEY_FILE2 = "api-key.json";
|
|
665
777
|
function getApiKeyFilePath() {
|
|
666
|
-
return
|
|
778
|
+
return path11.join(getDataDir(), API_KEY_FILE2);
|
|
667
779
|
}
|
|
668
780
|
function ensureDataDir() {
|
|
669
781
|
const dataDir = getDataDir();
|
|
670
|
-
if (!
|
|
671
|
-
|
|
782
|
+
if (!fs6.existsSync(dataDir)) {
|
|
783
|
+
fs6.mkdirSync(dataDir, { recursive: true });
|
|
672
784
|
}
|
|
673
785
|
}
|
|
674
786
|
function loadApiKeyData() {
|
|
675
787
|
const logger6 = getLogger();
|
|
676
788
|
const apiKeyPath = getApiKeyFilePath();
|
|
677
789
|
try {
|
|
678
|
-
if (!
|
|
790
|
+
if (!fs6.existsSync(apiKeyPath)) {
|
|
679
791
|
logger6.debug("No API key file found", { path: apiKeyPath });
|
|
680
792
|
return null;
|
|
681
793
|
}
|
|
682
|
-
const content =
|
|
794
|
+
const content = fs6.readFileSync(apiKeyPath, "utf-8");
|
|
683
795
|
const data = JSON.parse(content);
|
|
684
796
|
return data;
|
|
685
797
|
} catch (error) {
|
|
@@ -695,7 +807,7 @@ function saveApiKeyData(data) {
|
|
|
695
807
|
try {
|
|
696
808
|
ensureDataDir();
|
|
697
809
|
const content = JSON.stringify(data, null, 2);
|
|
698
|
-
|
|
810
|
+
fs6.writeFileSync(apiKeyPath, content, { mode: 384 });
|
|
699
811
|
logger6.info("API key saved", { path: apiKeyPath });
|
|
700
812
|
} catch (error) {
|
|
701
813
|
logger6.error("Failed to save API key", {
|
|
@@ -708,8 +820,8 @@ function deleteApiKeyData() {
|
|
|
708
820
|
const logger6 = getLogger();
|
|
709
821
|
const apiKeyPath = getApiKeyFilePath();
|
|
710
822
|
try {
|
|
711
|
-
if (
|
|
712
|
-
|
|
823
|
+
if (fs6.existsSync(apiKeyPath)) {
|
|
824
|
+
fs6.unlinkSync(apiKeyPath);
|
|
713
825
|
logger6.info("API key deleted", { path: apiKeyPath });
|
|
714
826
|
}
|
|
715
827
|
} catch (error) {
|
|
@@ -748,7 +860,7 @@ function saveApiKey(params) {
|
|
|
748
860
|
apiKeyId: params.apiKeyId
|
|
749
861
|
};
|
|
750
862
|
const content = JSON.stringify(data, null, 2);
|
|
751
|
-
|
|
863
|
+
fs6.writeFileSync(apiKeyPath, content, { mode: 384 });
|
|
752
864
|
logger6.info("API key saved", { path: apiKeyPath });
|
|
753
865
|
} catch (error) {
|
|
754
866
|
logger6.error("Failed to save API key", {
|
|
@@ -839,6 +951,14 @@ var TestResultStatus = /* @__PURE__ */ ((TestResultStatus2) => {
|
|
|
839
951
|
return TestResultStatus2;
|
|
840
952
|
})(TestResultStatus || {});
|
|
841
953
|
|
|
954
|
+
// packages/mcps/src/mcp/local/services/stored-auth-target.ts
|
|
955
|
+
function isStoredAuthForRuntimeTarget(params) {
|
|
956
|
+
if (!params.storedRuntimeTarget) {
|
|
957
|
+
return params.activeRuntimeTarget === "production" /* Production */;
|
|
958
|
+
}
|
|
959
|
+
return params.storedRuntimeTarget === params.activeRuntimeTarget;
|
|
960
|
+
}
|
|
961
|
+
|
|
842
962
|
// packages/mcps/src/mcp/local/services/auth-service.ts
|
|
843
963
|
var DEFAULT_LOGIN_WAIT_TIMEOUT_MS = 12e4;
|
|
844
964
|
var AuthService = class {
|
|
@@ -852,8 +972,8 @@ var AuthService = class {
|
|
|
852
972
|
constructor() {
|
|
853
973
|
const config = getConfig();
|
|
854
974
|
this.oauthSessionFilePath = config.localQa.oauthSessionFilePath;
|
|
855
|
-
this.pendingDeviceCodePath =
|
|
856
|
-
|
|
975
|
+
this.pendingDeviceCodePath = path11.join(
|
|
976
|
+
path11.dirname(config.localQa.oauthSessionFilePath),
|
|
857
977
|
"pending-device-code.json"
|
|
858
978
|
);
|
|
859
979
|
}
|
|
@@ -962,11 +1082,11 @@ var AuthService = class {
|
|
|
962
1082
|
*/
|
|
963
1083
|
storePendingDeviceCode(params) {
|
|
964
1084
|
const logger6 = getLogger();
|
|
965
|
-
const dir =
|
|
966
|
-
if (!
|
|
967
|
-
|
|
1085
|
+
const dir = path11.dirname(this.pendingDeviceCodePath);
|
|
1086
|
+
if (!fs6.existsSync(dir)) {
|
|
1087
|
+
fs6.mkdirSync(dir, { recursive: true });
|
|
968
1088
|
}
|
|
969
|
-
|
|
1089
|
+
fs6.writeFileSync(this.pendingDeviceCodePath, JSON.stringify(params, null, 2), {
|
|
970
1090
|
encoding: "utf-8",
|
|
971
1091
|
mode: 384
|
|
972
1092
|
});
|
|
@@ -977,12 +1097,12 @@ var AuthService = class {
|
|
|
977
1097
|
*/
|
|
978
1098
|
getPendingDeviceCode() {
|
|
979
1099
|
const logger6 = getLogger();
|
|
980
|
-
if (!
|
|
1100
|
+
if (!fs6.existsSync(this.pendingDeviceCodePath)) {
|
|
981
1101
|
logger6.debug("No pending device code found");
|
|
982
1102
|
return null;
|
|
983
1103
|
}
|
|
984
1104
|
try {
|
|
985
|
-
const content =
|
|
1105
|
+
const content = fs6.readFileSync(this.pendingDeviceCodePath, "utf-8");
|
|
986
1106
|
const data = JSON.parse(content);
|
|
987
1107
|
const now = /* @__PURE__ */ new Date();
|
|
988
1108
|
const expiresAt = new Date(data.expiresAt);
|
|
@@ -1004,9 +1124,9 @@ var AuthService = class {
|
|
|
1004
1124
|
*/
|
|
1005
1125
|
clearPendingDeviceCode() {
|
|
1006
1126
|
const logger6 = getLogger();
|
|
1007
|
-
if (
|
|
1127
|
+
if (fs6.existsSync(this.pendingDeviceCodePath)) {
|
|
1008
1128
|
try {
|
|
1009
|
-
|
|
1129
|
+
fs6.unlinkSync(this.pendingDeviceCodePath);
|
|
1010
1130
|
logger6.debug("Pending device code cleared");
|
|
1011
1131
|
} catch (error) {
|
|
1012
1132
|
logger6.warn("Failed to clear pending device code", {
|
|
@@ -1173,29 +1293,43 @@ var AuthService = class {
|
|
|
1173
1293
|
refreshToken: tokenResponse.refreshToken,
|
|
1174
1294
|
expiresAt,
|
|
1175
1295
|
email,
|
|
1176
|
-
userId
|
|
1296
|
+
userId,
|
|
1297
|
+
runtimeTarget: getActiveRuntimeTarget()
|
|
1177
1298
|
};
|
|
1178
|
-
const dir =
|
|
1179
|
-
if (!
|
|
1180
|
-
|
|
1299
|
+
const dir = path11.dirname(this.oauthSessionFilePath);
|
|
1300
|
+
if (!fs6.existsSync(dir)) {
|
|
1301
|
+
fs6.mkdirSync(dir, { recursive: true });
|
|
1181
1302
|
}
|
|
1182
|
-
|
|
1303
|
+
fs6.writeFileSync(this.oauthSessionFilePath, JSON.stringify(storedAuth, null, 2), {
|
|
1183
1304
|
encoding: "utf-8",
|
|
1184
1305
|
mode: 384
|
|
1185
1306
|
});
|
|
1186
1307
|
logger6.info("Auth stored successfully", { email, expiresAt });
|
|
1187
1308
|
}
|
|
1188
1309
|
/**
|
|
1189
|
-
* Load stored authentication.
|
|
1310
|
+
* Load stored authentication for the active runtime target.
|
|
1311
|
+
* @returns Stored auth, or null when it is absent, unreadable, or was issued for another target.
|
|
1190
1312
|
*/
|
|
1191
1313
|
loadStoredAuth() {
|
|
1192
1314
|
const logger6 = getLogger();
|
|
1193
|
-
if (!
|
|
1315
|
+
if (!fs6.existsSync(this.oauthSessionFilePath)) {
|
|
1194
1316
|
return null;
|
|
1195
1317
|
}
|
|
1196
1318
|
try {
|
|
1197
|
-
const content =
|
|
1198
|
-
|
|
1319
|
+
const content = fs6.readFileSync(this.oauthSessionFilePath, "utf-8");
|
|
1320
|
+
const storedAuth = JSON.parse(content);
|
|
1321
|
+
const activeRuntimeTarget = getActiveRuntimeTarget();
|
|
1322
|
+
if (!isStoredAuthForRuntimeTarget({
|
|
1323
|
+
storedRuntimeTarget: storedAuth.runtimeTarget,
|
|
1324
|
+
activeRuntimeTarget
|
|
1325
|
+
})) {
|
|
1326
|
+
logger6.warn("Ignoring stored auth issued for a different runtime target", {
|
|
1327
|
+
storedRuntimeTarget: storedAuth.runtimeTarget ?? "unrecorded",
|
|
1328
|
+
activeRuntimeTarget
|
|
1329
|
+
});
|
|
1330
|
+
return null;
|
|
1331
|
+
}
|
|
1332
|
+
return storedAuth;
|
|
1199
1333
|
} catch (error) {
|
|
1200
1334
|
logger6.error("Failed to load stored auth", {
|
|
1201
1335
|
error: error instanceof Error ? error.message : String(error)
|
|
@@ -1276,13 +1410,14 @@ var AuthService = class {
|
|
|
1276
1410
|
refreshToken: tokenData.refresh_token ?? storedAuth.refreshToken,
|
|
1277
1411
|
expiresAt: newExpiresAt,
|
|
1278
1412
|
email: storedAuth.email,
|
|
1279
|
-
userId: storedAuth.userId
|
|
1413
|
+
userId: storedAuth.userId,
|
|
1414
|
+
runtimeTarget: storedAuth.runtimeTarget ?? getActiveRuntimeTarget()
|
|
1280
1415
|
};
|
|
1281
|
-
const dir =
|
|
1282
|
-
if (!
|
|
1283
|
-
|
|
1416
|
+
const dir = path11.dirname(this.oauthSessionFilePath);
|
|
1417
|
+
if (!fs6.existsSync(dir)) {
|
|
1418
|
+
fs6.mkdirSync(dir, { recursive: true });
|
|
1284
1419
|
}
|
|
1285
|
-
|
|
1420
|
+
fs6.writeFileSync(this.oauthSessionFilePath, JSON.stringify(updatedAuth, null, 2), {
|
|
1286
1421
|
encoding: "utf-8",
|
|
1287
1422
|
mode: 384
|
|
1288
1423
|
});
|
|
@@ -1334,12 +1469,12 @@ var AuthService = class {
|
|
|
1334
1469
|
*/
|
|
1335
1470
|
logout() {
|
|
1336
1471
|
const logger6 = getLogger();
|
|
1337
|
-
if (!
|
|
1472
|
+
if (!fs6.existsSync(this.oauthSessionFilePath)) {
|
|
1338
1473
|
logger6.debug("No auth to clear");
|
|
1339
1474
|
return false;
|
|
1340
1475
|
}
|
|
1341
1476
|
try {
|
|
1342
|
-
|
|
1477
|
+
fs6.unlinkSync(this.oauthSessionFilePath);
|
|
1343
1478
|
logger6.info("Auth cleared successfully");
|
|
1344
1479
|
return true;
|
|
1345
1480
|
} catch (error) {
|
|
@@ -1359,9 +1494,9 @@ function resetAuthService() {
|
|
|
1359
1494
|
serviceInstance = null;
|
|
1360
1495
|
}
|
|
1361
1496
|
function sleep(params) {
|
|
1362
|
-
return new Promise((
|
|
1497
|
+
return new Promise((resolve6) => {
|
|
1363
1498
|
setTimeout(() => {
|
|
1364
|
-
|
|
1499
|
+
resolve6();
|
|
1365
1500
|
}, params.durationMs);
|
|
1366
1501
|
});
|
|
1367
1502
|
}
|
|
@@ -1384,12 +1519,12 @@ var StorageService = class {
|
|
|
1384
1519
|
*/
|
|
1385
1520
|
ensureDirectories() {
|
|
1386
1521
|
const logger6 = getLogger();
|
|
1387
|
-
if (!
|
|
1388
|
-
|
|
1522
|
+
if (!fs6.existsSync(this.dataDir)) {
|
|
1523
|
+
fs6.mkdirSync(this.dataDir, { recursive: true });
|
|
1389
1524
|
logger6.info("Created data directory", { path: this.dataDir });
|
|
1390
1525
|
}
|
|
1391
|
-
if (!
|
|
1392
|
-
|
|
1526
|
+
if (!fs6.existsSync(this.sessionsDir)) {
|
|
1527
|
+
fs6.mkdirSync(this.sessionsDir, { recursive: true });
|
|
1393
1528
|
logger6.info("Created sessions directory", { path: this.sessionsDir });
|
|
1394
1529
|
}
|
|
1395
1530
|
}
|
|
@@ -1401,11 +1536,11 @@ var StorageService = class {
|
|
|
1401
1536
|
createSessionDirectory(sessionId) {
|
|
1402
1537
|
const logger6 = getLogger();
|
|
1403
1538
|
this.ensureDirectories();
|
|
1404
|
-
const sessionDir =
|
|
1405
|
-
if (!
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1539
|
+
const sessionDir = path11.join(this.sessionsDir, sessionId);
|
|
1540
|
+
if (!fs6.existsSync(sessionDir)) {
|
|
1541
|
+
fs6.mkdirSync(sessionDir, { recursive: true });
|
|
1542
|
+
fs6.mkdirSync(path11.join(sessionDir, "screenshots"), { recursive: true });
|
|
1543
|
+
fs6.mkdirSync(path11.join(sessionDir, "logs"), { recursive: true });
|
|
1409
1544
|
logger6.info("Created session directory", { sessionId, path: sessionDir });
|
|
1410
1545
|
}
|
|
1411
1546
|
return sessionDir;
|
|
@@ -1417,8 +1552,8 @@ var StorageService = class {
|
|
|
1417
1552
|
saveSessionMetadata(metadata) {
|
|
1418
1553
|
const logger6 = getLogger();
|
|
1419
1554
|
const sessionDir = this.createSessionDirectory(metadata.sessionId);
|
|
1420
|
-
const metadataPath =
|
|
1421
|
-
|
|
1555
|
+
const metadataPath = path11.join(sessionDir, "metadata.json");
|
|
1556
|
+
fs6.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2), "utf-8");
|
|
1422
1557
|
logger6.debug("Saved session metadata", { sessionId: metadata.sessionId });
|
|
1423
1558
|
}
|
|
1424
1559
|
/**
|
|
@@ -1428,12 +1563,12 @@ var StorageService = class {
|
|
|
1428
1563
|
*/
|
|
1429
1564
|
loadSessionMetadata(sessionId) {
|
|
1430
1565
|
const logger6 = getLogger();
|
|
1431
|
-
const metadataPath =
|
|
1432
|
-
if (!
|
|
1566
|
+
const metadataPath = path11.join(this.sessionsDir, sessionId, "metadata.json");
|
|
1567
|
+
if (!fs6.existsSync(metadataPath)) {
|
|
1433
1568
|
return null;
|
|
1434
1569
|
}
|
|
1435
1570
|
try {
|
|
1436
|
-
const content =
|
|
1571
|
+
const content = fs6.readFileSync(metadataPath, "utf-8");
|
|
1437
1572
|
return JSON.parse(content);
|
|
1438
1573
|
} catch (error) {
|
|
1439
1574
|
logger6.error("Failed to load session metadata", {
|
|
@@ -1448,12 +1583,12 @@ var StorageService = class {
|
|
|
1448
1583
|
* @returns Array of session IDs.
|
|
1449
1584
|
*/
|
|
1450
1585
|
listSessions() {
|
|
1451
|
-
if (!
|
|
1586
|
+
if (!fs6.existsSync(this.sessionsDir)) {
|
|
1452
1587
|
return [];
|
|
1453
1588
|
}
|
|
1454
|
-
return
|
|
1455
|
-
const entryPath =
|
|
1456
|
-
return
|
|
1589
|
+
return fs6.readdirSync(this.sessionsDir).filter((entry) => {
|
|
1590
|
+
const entryPath = path11.join(this.sessionsDir, entry);
|
|
1591
|
+
return fs6.statSync(entryPath).isDirectory();
|
|
1457
1592
|
});
|
|
1458
1593
|
}
|
|
1459
1594
|
/**
|
|
@@ -1461,13 +1596,13 @@ var StorageService = class {
|
|
|
1461
1596
|
* @returns Current session ID, or null.
|
|
1462
1597
|
*/
|
|
1463
1598
|
getCurrentSessionId() {
|
|
1464
|
-
const currentPath =
|
|
1465
|
-
if (!
|
|
1599
|
+
const currentPath = path11.join(this.sessionsDir, "current");
|
|
1600
|
+
if (!fs6.existsSync(currentPath)) {
|
|
1466
1601
|
return null;
|
|
1467
1602
|
}
|
|
1468
1603
|
try {
|
|
1469
|
-
const target =
|
|
1470
|
-
return
|
|
1604
|
+
const target = fs6.readlinkSync(currentPath);
|
|
1605
|
+
return path11.basename(target);
|
|
1471
1606
|
} catch {
|
|
1472
1607
|
return null;
|
|
1473
1608
|
}
|
|
@@ -1478,12 +1613,12 @@ var StorageService = class {
|
|
|
1478
1613
|
*/
|
|
1479
1614
|
setCurrentSession(sessionId) {
|
|
1480
1615
|
const logger6 = getLogger();
|
|
1481
|
-
const currentPath =
|
|
1482
|
-
const targetPath =
|
|
1483
|
-
if (
|
|
1484
|
-
|
|
1616
|
+
const currentPath = path11.join(this.sessionsDir, "current");
|
|
1617
|
+
const targetPath = path11.join(this.sessionsDir, sessionId);
|
|
1618
|
+
if (fs6.existsSync(currentPath)) {
|
|
1619
|
+
fs6.unlinkSync(currentPath);
|
|
1485
1620
|
}
|
|
1486
|
-
|
|
1621
|
+
fs6.symlinkSync(targetPath, currentPath);
|
|
1487
1622
|
logger6.info("Set current session", { sessionId });
|
|
1488
1623
|
}
|
|
1489
1624
|
/**
|
|
@@ -1494,8 +1629,8 @@ var StorageService = class {
|
|
|
1494
1629
|
const { sessionId, filename, data } = params;
|
|
1495
1630
|
const logger6 = getLogger();
|
|
1496
1631
|
const sessionDir = this.createSessionDirectory(sessionId);
|
|
1497
|
-
const screenshotPath =
|
|
1498
|
-
|
|
1632
|
+
const screenshotPath = path11.join(sessionDir, "screenshots", filename);
|
|
1633
|
+
fs6.writeFileSync(screenshotPath, data);
|
|
1499
1634
|
logger6.debug("Saved screenshot", { sessionId, filename });
|
|
1500
1635
|
return screenshotPath;
|
|
1501
1636
|
}
|
|
@@ -1507,8 +1642,8 @@ var StorageService = class {
|
|
|
1507
1642
|
const { sessionId, content } = params;
|
|
1508
1643
|
const logger6 = getLogger();
|
|
1509
1644
|
const sessionDir = this.createSessionDirectory(sessionId);
|
|
1510
|
-
const resultsPath =
|
|
1511
|
-
|
|
1645
|
+
const resultsPath = path11.join(sessionDir, "results.md");
|
|
1646
|
+
fs6.appendFileSync(resultsPath, content + "\n", "utf-8");
|
|
1512
1647
|
logger6.debug("Appended to results", { sessionId });
|
|
1513
1648
|
}
|
|
1514
1649
|
/**
|
|
@@ -1517,11 +1652,11 @@ var StorageService = class {
|
|
|
1517
1652
|
* @returns Results content, or null if not found.
|
|
1518
1653
|
*/
|
|
1519
1654
|
getResults(sessionId) {
|
|
1520
|
-
const resultsPath =
|
|
1521
|
-
if (!
|
|
1655
|
+
const resultsPath = path11.join(this.sessionsDir, sessionId, "results.md");
|
|
1656
|
+
if (!fs6.existsSync(resultsPath)) {
|
|
1522
1657
|
return null;
|
|
1523
1658
|
}
|
|
1524
|
-
return
|
|
1659
|
+
return fs6.readFileSync(resultsPath, "utf-8");
|
|
1525
1660
|
}
|
|
1526
1661
|
/**
|
|
1527
1662
|
* Get the data directory path.
|
|
@@ -1586,7 +1721,7 @@ var StorageService = class {
|
|
|
1586
1721
|
const { sessionId, targetUrl, testInstructions } = params;
|
|
1587
1722
|
const logger6 = getLogger();
|
|
1588
1723
|
const sessionDir = this.createSessionDirectory(sessionId);
|
|
1589
|
-
const resultsPath =
|
|
1724
|
+
const resultsPath = path11.join(sessionDir, "results.md");
|
|
1590
1725
|
const header = [
|
|
1591
1726
|
`# Test Results: ${sessionId}`,
|
|
1592
1727
|
"",
|
|
@@ -1599,7 +1734,7 @@ var StorageService = class {
|
|
|
1599
1734
|
"## Test Steps",
|
|
1600
1735
|
""
|
|
1601
1736
|
].join("\n");
|
|
1602
|
-
|
|
1737
|
+
fs6.writeFileSync(resultsPath, header, "utf-8");
|
|
1603
1738
|
logger6.debug("Initialized results.md", { sessionId });
|
|
1604
1739
|
}
|
|
1605
1740
|
/**
|
|
@@ -1610,7 +1745,7 @@ var StorageService = class {
|
|
|
1610
1745
|
const { sessionId, step } = params;
|
|
1611
1746
|
const logger6 = getLogger();
|
|
1612
1747
|
const sessionDir = this.createSessionDirectory(sessionId);
|
|
1613
|
-
const resultsPath =
|
|
1748
|
+
const resultsPath = path11.join(sessionDir, "results.md");
|
|
1614
1749
|
const statusIcon = step.success ? "\u2713" : "\u2717";
|
|
1615
1750
|
const stepContent = [
|
|
1616
1751
|
`### Step ${step.stepNumber}: ${step.action}`,
|
|
@@ -1620,7 +1755,7 @@ var StorageService = class {
|
|
|
1620
1755
|
step.screenshotPath ? `- **Screenshot:** [step-${String(step.stepNumber).padStart(3, "0")}.png](screenshots/step-${String(step.stepNumber).padStart(3, "0")}.png)` : "",
|
|
1621
1756
|
""
|
|
1622
1757
|
].filter(Boolean).join("\n");
|
|
1623
|
-
|
|
1758
|
+
fs6.appendFileSync(resultsPath, stepContent + "\n", "utf-8");
|
|
1624
1759
|
logger6.debug("Appended step to results", { sessionId, stepNumber: step.stepNumber });
|
|
1625
1760
|
const metadata = this.loadSessionMetadata(sessionId);
|
|
1626
1761
|
if (metadata) {
|
|
@@ -1635,9 +1770,9 @@ var StorageService = class {
|
|
|
1635
1770
|
finalizeResults(params) {
|
|
1636
1771
|
const { sessionId, status, summary } = params;
|
|
1637
1772
|
const logger6 = getLogger();
|
|
1638
|
-
const sessionDir =
|
|
1639
|
-
const resultsPath =
|
|
1640
|
-
if (!
|
|
1773
|
+
const sessionDir = path11.join(this.sessionsDir, sessionId);
|
|
1774
|
+
const resultsPath = path11.join(sessionDir, "results.md");
|
|
1775
|
+
if (!fs6.existsSync(resultsPath)) {
|
|
1641
1776
|
logger6.warn("Results file not found for finalization", { sessionId });
|
|
1642
1777
|
return;
|
|
1643
1778
|
}
|
|
@@ -1660,7 +1795,7 @@ var StorageService = class {
|
|
|
1660
1795
|
"",
|
|
1661
1796
|
summary ? summary : ""
|
|
1662
1797
|
].join("\n");
|
|
1663
|
-
|
|
1798
|
+
fs6.appendFileSync(resultsPath, footer, "utf-8");
|
|
1664
1799
|
logger6.debug("Finalized results.md", { sessionId, status });
|
|
1665
1800
|
if (metadata) {
|
|
1666
1801
|
metadata.durationMs = durationMs;
|
|
@@ -1718,9 +1853,9 @@ var StorageService = class {
|
|
|
1718
1853
|
}
|
|
1719
1854
|
const sessionDate = new Date(metadata.startTime);
|
|
1720
1855
|
if (sessionDate < cutoffDate) {
|
|
1721
|
-
const sessionDir =
|
|
1856
|
+
const sessionDir = path11.join(this.sessionsDir, sessionId);
|
|
1722
1857
|
try {
|
|
1723
|
-
|
|
1858
|
+
fs6.rmSync(sessionDir, { recursive: true, force: true });
|
|
1724
1859
|
deletedCount++;
|
|
1725
1860
|
logger6.info("Deleted old session", {
|
|
1726
1861
|
sessionId,
|
|
@@ -1748,7 +1883,7 @@ var StorageService = class {
|
|
|
1748
1883
|
* @returns Session directory path.
|
|
1749
1884
|
*/
|
|
1750
1885
|
getSessionPath(sessionId) {
|
|
1751
|
-
return
|
|
1886
|
+
return path11.join(this.sessionsDir, sessionId);
|
|
1752
1887
|
}
|
|
1753
1888
|
/**
|
|
1754
1889
|
* Delete a specific session.
|
|
@@ -1757,20 +1892,20 @@ var StorageService = class {
|
|
|
1757
1892
|
*/
|
|
1758
1893
|
deleteSession(sessionId) {
|
|
1759
1894
|
const logger6 = getLogger();
|
|
1760
|
-
const sessionDir =
|
|
1761
|
-
if (!
|
|
1895
|
+
const sessionDir = path11.join(this.sessionsDir, sessionId);
|
|
1896
|
+
if (!fs6.existsSync(sessionDir)) {
|
|
1762
1897
|
logger6.warn("Session not found for deletion", { sessionId });
|
|
1763
1898
|
return false;
|
|
1764
1899
|
}
|
|
1765
1900
|
try {
|
|
1766
1901
|
const currentId = this.getCurrentSessionId();
|
|
1767
1902
|
if (currentId === sessionId) {
|
|
1768
|
-
const currentPath =
|
|
1769
|
-
if (
|
|
1770
|
-
|
|
1903
|
+
const currentPath = path11.join(this.sessionsDir, "current");
|
|
1904
|
+
if (fs6.existsSync(currentPath)) {
|
|
1905
|
+
fs6.unlinkSync(currentPath);
|
|
1771
1906
|
}
|
|
1772
1907
|
}
|
|
1773
|
-
|
|
1908
|
+
fs6.rmSync(sessionDir, { recursive: true, force: true });
|
|
1774
1909
|
logger6.info("Deleted session", { sessionId });
|
|
1775
1910
|
return true;
|
|
1776
1911
|
} catch (error) {
|
|
@@ -1799,19 +1934,19 @@ var RunResultStorageService = class {
|
|
|
1799
1934
|
constructor() {
|
|
1800
1935
|
const storageService = getStorageService();
|
|
1801
1936
|
const dataDir = storageService.getDataDir();
|
|
1802
|
-
this.runResultsDir =
|
|
1803
|
-
this.testScriptsDir =
|
|
1937
|
+
this.runResultsDir = path11.join(dataDir, "run-results");
|
|
1938
|
+
this.testScriptsDir = path11.join(dataDir, "test-scripts");
|
|
1804
1939
|
this.ensureDirectories();
|
|
1805
1940
|
}
|
|
1806
1941
|
/**
|
|
1807
1942
|
* Ensure storage directories exist.
|
|
1808
1943
|
*/
|
|
1809
1944
|
ensureDirectories() {
|
|
1810
|
-
if (!
|
|
1811
|
-
|
|
1945
|
+
if (!fs6.existsSync(this.runResultsDir)) {
|
|
1946
|
+
fs6.mkdirSync(this.runResultsDir, { recursive: true });
|
|
1812
1947
|
}
|
|
1813
|
-
if (!
|
|
1814
|
-
|
|
1948
|
+
if (!fs6.existsSync(this.testScriptsDir)) {
|
|
1949
|
+
fs6.mkdirSync(this.testScriptsDir, { recursive: true });
|
|
1815
1950
|
}
|
|
1816
1951
|
}
|
|
1817
1952
|
// ========================================
|
|
@@ -1822,11 +1957,11 @@ var RunResultStorageService = class {
|
|
|
1822
1957
|
*/
|
|
1823
1958
|
listRunResults() {
|
|
1824
1959
|
try {
|
|
1825
|
-
const files =
|
|
1960
|
+
const files = fs6.readdirSync(this.runResultsDir).filter((f) => f.endsWith(".json"));
|
|
1826
1961
|
const results = [];
|
|
1827
1962
|
for (const file of files) {
|
|
1828
1963
|
try {
|
|
1829
|
-
const content =
|
|
1964
|
+
const content = fs6.readFileSync(path11.join(this.runResultsDir, file), "utf-8");
|
|
1830
1965
|
results.push(JSON.parse(content));
|
|
1831
1966
|
} catch {
|
|
1832
1967
|
logger3.warn("Failed to read run result file", { file });
|
|
@@ -1841,12 +1976,12 @@ var RunResultStorageService = class {
|
|
|
1841
1976
|
* Get a run result by ID.
|
|
1842
1977
|
*/
|
|
1843
1978
|
getRunResult(runId) {
|
|
1844
|
-
const filePath =
|
|
1845
|
-
if (!
|
|
1979
|
+
const filePath = path11.join(this.runResultsDir, `${runId}.json`);
|
|
1980
|
+
if (!fs6.existsSync(filePath)) {
|
|
1846
1981
|
return void 0;
|
|
1847
1982
|
}
|
|
1848
1983
|
try {
|
|
1849
|
-
const content =
|
|
1984
|
+
const content = fs6.readFileSync(filePath, "utf-8");
|
|
1850
1985
|
return JSON.parse(content);
|
|
1851
1986
|
} catch {
|
|
1852
1987
|
return void 0;
|
|
@@ -1856,8 +1991,8 @@ var RunResultStorageService = class {
|
|
|
1856
1991
|
* Save a run result.
|
|
1857
1992
|
*/
|
|
1858
1993
|
saveRunResult(result) {
|
|
1859
|
-
const filePath =
|
|
1860
|
-
|
|
1994
|
+
const filePath = path11.join(this.runResultsDir, `${result.id}.json`);
|
|
1995
|
+
fs6.writeFileSync(filePath, JSON.stringify(result, null, 2));
|
|
1861
1996
|
}
|
|
1862
1997
|
/**
|
|
1863
1998
|
* Create a new run result.
|
|
@@ -1905,11 +2040,11 @@ var RunResultStorageService = class {
|
|
|
1905
2040
|
*/
|
|
1906
2041
|
listTestScripts() {
|
|
1907
2042
|
try {
|
|
1908
|
-
const files =
|
|
2043
|
+
const files = fs6.readdirSync(this.testScriptsDir).filter((f) => f.endsWith(".json"));
|
|
1909
2044
|
const scripts = [];
|
|
1910
2045
|
for (const file of files) {
|
|
1911
2046
|
try {
|
|
1912
|
-
const content =
|
|
2047
|
+
const content = fs6.readFileSync(path11.join(this.testScriptsDir, file), "utf-8");
|
|
1913
2048
|
scripts.push(JSON.parse(content));
|
|
1914
2049
|
} catch {
|
|
1915
2050
|
logger3.warn("Failed to read test script file", { file });
|
|
@@ -1924,12 +2059,12 @@ var RunResultStorageService = class {
|
|
|
1924
2059
|
* Get a test script by ID.
|
|
1925
2060
|
*/
|
|
1926
2061
|
getTestScript(testScriptId) {
|
|
1927
|
-
const filePath =
|
|
1928
|
-
if (!
|
|
2062
|
+
const filePath = path11.join(this.testScriptsDir, `${testScriptId}.json`);
|
|
2063
|
+
if (!fs6.existsSync(filePath)) {
|
|
1929
2064
|
return void 0;
|
|
1930
2065
|
}
|
|
1931
2066
|
try {
|
|
1932
|
-
const content =
|
|
2067
|
+
const content = fs6.readFileSync(filePath, "utf-8");
|
|
1933
2068
|
return JSON.parse(content);
|
|
1934
2069
|
} catch {
|
|
1935
2070
|
return void 0;
|
|
@@ -1939,8 +2074,8 @@ var RunResultStorageService = class {
|
|
|
1939
2074
|
* Save a test script.
|
|
1940
2075
|
*/
|
|
1941
2076
|
saveTestScript(script) {
|
|
1942
|
-
const filePath =
|
|
1943
|
-
|
|
2077
|
+
const filePath = path11.join(this.testScriptsDir, `${script.id}.json`);
|
|
2078
|
+
fs6.writeFileSync(filePath, JSON.stringify(script, null, 2));
|
|
1944
2079
|
}
|
|
1945
2080
|
/**
|
|
1946
2081
|
* Create a new test script.
|
|
@@ -2190,13 +2325,13 @@ var PREFERENCES_SCHEMA = {
|
|
|
2190
2325
|
|
|
2191
2326
|
// packages/mcps/src/shared/llm-env-service.ts
|
|
2192
2327
|
function resolveLlmEnvOverrides(dataDirOverride2) {
|
|
2193
|
-
const filePath =
|
|
2328
|
+
const filePath = path11.join(getDataDir(), PREFERENCES_FILE_NAME);
|
|
2194
2329
|
let block;
|
|
2195
2330
|
try {
|
|
2196
|
-
if (!
|
|
2331
|
+
if (!fs6.existsSync(filePath)) {
|
|
2197
2332
|
return {};
|
|
2198
2333
|
}
|
|
2199
|
-
const raw = JSON.parse(
|
|
2334
|
+
const raw = JSON.parse(fs6.readFileSync(filePath, "utf-8"));
|
|
2200
2335
|
block = raw[LLM_ENV_PREFERENCE_KEY];
|
|
2201
2336
|
} catch {
|
|
2202
2337
|
return {};
|
|
@@ -2404,13 +2539,13 @@ var MODIFY_LOCK_STALE_MS = 5e3;
|
|
|
2404
2539
|
|
|
2405
2540
|
// packages/mcps/src/mcp/local/services/local-execution-lock.ts
|
|
2406
2541
|
function lockFilePath() {
|
|
2407
|
-
return
|
|
2542
|
+
return path11.join(getDataDir(), LOCK_FILE_NAME);
|
|
2408
2543
|
}
|
|
2409
2544
|
function modifyLockPath() {
|
|
2410
2545
|
return lockFilePath() + MODIFY_LOCK_SUFFIX;
|
|
2411
2546
|
}
|
|
2412
2547
|
function normalizeCwd(cwd) {
|
|
2413
|
-
const resolved =
|
|
2548
|
+
const resolved = path11.resolve(cwd);
|
|
2414
2549
|
return os4.platform() === "win32" ? resolved.toLowerCase() : resolved;
|
|
2415
2550
|
}
|
|
2416
2551
|
function pidIsAlive(pid) {
|
|
@@ -2426,7 +2561,7 @@ function pidIsAlive(pid) {
|
|
|
2426
2561
|
}
|
|
2427
2562
|
async function readState() {
|
|
2428
2563
|
try {
|
|
2429
|
-
const raw = await
|
|
2564
|
+
const raw = await fs10.readFile(lockFilePath(), "utf-8");
|
|
2430
2565
|
return JSON.parse(raw);
|
|
2431
2566
|
} catch (error) {
|
|
2432
2567
|
if (error.code === "ENOENT") return null;
|
|
@@ -2434,28 +2569,28 @@ async function readState() {
|
|
|
2434
2569
|
}
|
|
2435
2570
|
}
|
|
2436
2571
|
async function writeState(state2) {
|
|
2437
|
-
await
|
|
2572
|
+
await fs10.writeFile(lockFilePath(), JSON.stringify(state2, null, 2), "utf-8");
|
|
2438
2573
|
}
|
|
2439
2574
|
async function deleteStateFile() {
|
|
2440
2575
|
try {
|
|
2441
|
-
await
|
|
2576
|
+
await fs10.unlink(lockFilePath());
|
|
2442
2577
|
} catch (error) {
|
|
2443
2578
|
if (error.code !== "ENOENT") throw error;
|
|
2444
2579
|
}
|
|
2445
2580
|
}
|
|
2446
2581
|
async function withModifyLock(fn) {
|
|
2447
|
-
await
|
|
2582
|
+
await fs10.mkdir(path11.dirname(modifyLockPath()), { recursive: true });
|
|
2448
2583
|
const modifyPath = modifyLockPath();
|
|
2449
2584
|
let fileHandle = null;
|
|
2450
2585
|
while (fileHandle === null) {
|
|
2451
2586
|
try {
|
|
2452
|
-
fileHandle = await
|
|
2587
|
+
fileHandle = await fs10.open(modifyPath, "wx");
|
|
2453
2588
|
} catch (error) {
|
|
2454
2589
|
if (error.code !== "EEXIST") throw error;
|
|
2455
2590
|
try {
|
|
2456
|
-
const stat3 = await
|
|
2591
|
+
const stat3 = await fs10.stat(modifyPath);
|
|
2457
2592
|
if (Date.now() - stat3.mtimeMs > MODIFY_LOCK_STALE_MS) {
|
|
2458
|
-
await
|
|
2593
|
+
await fs10.unlink(modifyPath).catch(() => void 0);
|
|
2459
2594
|
continue;
|
|
2460
2595
|
}
|
|
2461
2596
|
} catch {
|
|
@@ -2468,7 +2603,7 @@ async function withModifyLock(fn) {
|
|
|
2468
2603
|
return await fn();
|
|
2469
2604
|
} finally {
|
|
2470
2605
|
await fileHandle.close().catch(() => void 0);
|
|
2471
|
-
await
|
|
2606
|
+
await fs10.unlink(modifyPath).catch(() => void 0);
|
|
2472
2607
|
}
|
|
2473
2608
|
}
|
|
2474
2609
|
async function tryAcquireOnce(params) {
|
|
@@ -2607,12 +2742,12 @@ function extractStudioCloudRefs(studioReturnedResult) {
|
|
|
2607
2742
|
return refs;
|
|
2608
2743
|
}
|
|
2609
2744
|
async function readCloudRefsFile(inputFilePath) {
|
|
2610
|
-
const cloudRefsPath =
|
|
2611
|
-
|
|
2612
|
-
`cloudrefs_${
|
|
2745
|
+
const cloudRefsPath = path11.join(
|
|
2746
|
+
path11.dirname(inputFilePath),
|
|
2747
|
+
`cloudrefs_${path11.basename(inputFilePath)}`
|
|
2613
2748
|
);
|
|
2614
2749
|
try {
|
|
2615
|
-
return JSON.parse(await
|
|
2750
|
+
return JSON.parse(await fs10.readFile(cloudRefsPath, "utf-8"));
|
|
2616
2751
|
} catch {
|
|
2617
2752
|
return void 0;
|
|
2618
2753
|
}
|
|
@@ -2631,15 +2766,15 @@ function getAuthenticatedUserId() {
|
|
|
2631
2766
|
}
|
|
2632
2767
|
async function findPackageJsonAsync() {
|
|
2633
2768
|
const currentFileUrl = import.meta.url;
|
|
2634
|
-
const currentDir =
|
|
2769
|
+
const currentDir = path11.dirname(fileURLToPath(currentFileUrl));
|
|
2635
2770
|
const candidatePaths = [
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2771
|
+
path11.resolve(currentDir, "../../../package.json"),
|
|
2772
|
+
path11.resolve(currentDir, "../package.json"),
|
|
2773
|
+
path11.resolve(currentDir, "../../package.json")
|
|
2639
2774
|
];
|
|
2640
2775
|
for (const candidatePath of candidatePaths) {
|
|
2641
2776
|
try {
|
|
2642
|
-
const packageJsonRaw = await
|
|
2777
|
+
const packageJsonRaw = await fs10.readFile(candidatePath, "utf-8");
|
|
2643
2778
|
const packageJson = JSON.parse(packageJsonRaw);
|
|
2644
2779
|
if (packageJson.name === "@muggleai/works" && packageJson.version && packageJson.muggleConfig?.electronAppVersion) {
|
|
2645
2780
|
return {
|
|
@@ -2685,20 +2820,20 @@ function buildStudioAuthContent() {
|
|
|
2685
2820
|
}
|
|
2686
2821
|
async function ensureTempDir() {
|
|
2687
2822
|
const config = getConfig();
|
|
2688
|
-
const tempDir =
|
|
2689
|
-
await
|
|
2823
|
+
const tempDir = path11.join(config.localQa.dataDir, "temp");
|
|
2824
|
+
await fs10.mkdir(tempDir, { recursive: true });
|
|
2690
2825
|
return tempDir;
|
|
2691
2826
|
}
|
|
2692
2827
|
async function writeTempFile(params) {
|
|
2693
2828
|
const tempDir = await ensureTempDir();
|
|
2694
|
-
const filePath =
|
|
2695
|
-
await
|
|
2829
|
+
const filePath = path11.join(tempDir, params.filename);
|
|
2830
|
+
await fs10.writeFile(filePath, JSON.stringify(params.data, null, 2));
|
|
2696
2831
|
return filePath;
|
|
2697
2832
|
}
|
|
2698
2833
|
async function cleanupTempFiles(params) {
|
|
2699
2834
|
for (const filePath of params.filePaths) {
|
|
2700
2835
|
try {
|
|
2701
|
-
await
|
|
2836
|
+
await fs10.unlink(filePath);
|
|
2702
2837
|
} catch {
|
|
2703
2838
|
}
|
|
2704
2839
|
}
|
|
@@ -2706,12 +2841,12 @@ async function cleanupTempFiles(params) {
|
|
|
2706
2841
|
async function moveResultsToArtifacts(params) {
|
|
2707
2842
|
const storageService = getStorageService();
|
|
2708
2843
|
const sessionsDir = storageService.getSessionsDir();
|
|
2709
|
-
const artifactsDir =
|
|
2710
|
-
const actionScriptPath =
|
|
2711
|
-
await
|
|
2712
|
-
await
|
|
2844
|
+
const artifactsDir = path11.join(sessionsDir, params.runId);
|
|
2845
|
+
const actionScriptPath = path11.join(artifactsDir, "action-script.json");
|
|
2846
|
+
await fs10.mkdir(artifactsDir, { recursive: true });
|
|
2847
|
+
await fs10.copyFile(params.generatedScriptPath, actionScriptPath);
|
|
2713
2848
|
try {
|
|
2714
|
-
await
|
|
2849
|
+
await fs10.unlink(params.generatedScriptPath);
|
|
2715
2850
|
} catch {
|
|
2716
2851
|
}
|
|
2717
2852
|
return artifactsDir;
|
|
@@ -2719,13 +2854,13 @@ async function moveResultsToArtifacts(params) {
|
|
|
2719
2854
|
async function writeExecutionLogs(params) {
|
|
2720
2855
|
const storageService = getStorageService();
|
|
2721
2856
|
const sessionsDir = storageService.getSessionsDir();
|
|
2722
|
-
const artifactsDir =
|
|
2723
|
-
await
|
|
2724
|
-
const stdoutPath =
|
|
2725
|
-
const stderrPath =
|
|
2857
|
+
const artifactsDir = path11.join(sessionsDir, params.runId);
|
|
2858
|
+
await fs10.mkdir(artifactsDir, { recursive: true });
|
|
2859
|
+
const stdoutPath = path11.join(artifactsDir, "stdout.log");
|
|
2860
|
+
const stderrPath = path11.join(artifactsDir, "stderr.log");
|
|
2726
2861
|
await Promise.all([
|
|
2727
|
-
|
|
2728
|
-
|
|
2862
|
+
fs10.writeFile(stdoutPath, params.stdout, "utf-8"),
|
|
2863
|
+
fs10.writeFile(stderrPath, params.stderr, "utf-8")
|
|
2729
2864
|
]);
|
|
2730
2865
|
logger4.info("Wrote execution logs to artifacts directory", {
|
|
2731
2866
|
runId: params.runId,
|
|
@@ -2735,10 +2870,10 @@ async function writeExecutionLogs(params) {
|
|
|
2735
2870
|
async function preserveElectronRuntimeArtifacts(params) {
|
|
2736
2871
|
try {
|
|
2737
2872
|
const tempDir = await ensureTempDir();
|
|
2738
|
-
const markerPath =
|
|
2873
|
+
const markerPath = path11.join(tempDir, `${params.runId}_runtime_dir.txt`);
|
|
2739
2874
|
let runtimeDir = null;
|
|
2740
2875
|
try {
|
|
2741
|
-
const marker = await
|
|
2876
|
+
const marker = await fs10.readFile(markerPath, "utf-8");
|
|
2742
2877
|
const trimmed = marker.trim();
|
|
2743
2878
|
if (trimmed.length > 0) runtimeDir = trimmed;
|
|
2744
2879
|
} catch (markerReadError) {
|
|
@@ -2760,25 +2895,25 @@ async function preserveElectronRuntimeArtifacts(params) {
|
|
|
2760
2895
|
return;
|
|
2761
2896
|
}
|
|
2762
2897
|
try {
|
|
2763
|
-
await
|
|
2898
|
+
await fs10.access(runtimeDir);
|
|
2764
2899
|
} catch {
|
|
2765
2900
|
logger4.warn("Electron runtime dir referenced but missing on disk", {
|
|
2766
2901
|
runId: params.runId,
|
|
2767
2902
|
runtimeDir
|
|
2768
2903
|
});
|
|
2769
|
-
await
|
|
2904
|
+
await fs10.unlink(markerPath).catch(() => void 0);
|
|
2770
2905
|
return;
|
|
2771
2906
|
}
|
|
2772
2907
|
const storage = getStorageService();
|
|
2773
|
-
const destDir =
|
|
2774
|
-
await
|
|
2775
|
-
await
|
|
2908
|
+
const destDir = path11.join(storage.getSessionsDir(), params.runId, "electron-runtime");
|
|
2909
|
+
await fs10.mkdir(destDir, { recursive: true });
|
|
2910
|
+
await fs10.cp(runtimeDir, destDir, { recursive: true });
|
|
2776
2911
|
logger4.info("Preserved Electron runtime artifacts", {
|
|
2777
2912
|
runId: params.runId,
|
|
2778
2913
|
sourceDir: runtimeDir,
|
|
2779
2914
|
destDir
|
|
2780
2915
|
});
|
|
2781
|
-
await
|
|
2916
|
+
await fs10.unlink(markerPath).catch(() => void 0);
|
|
2782
2917
|
} catch (preserveError) {
|
|
2783
2918
|
logger4.warn("Failed to preserve Electron runtime artifacts", {
|
|
2784
2919
|
runId: params.runId,
|
|
@@ -2787,14 +2922,14 @@ async function preserveElectronRuntimeArtifacts(params) {
|
|
|
2787
2922
|
}
|
|
2788
2923
|
}
|
|
2789
2924
|
async function scanForRuntimeDirByMtime(params) {
|
|
2790
|
-
const runtimeRoot =
|
|
2925
|
+
const runtimeRoot = path11.join(params.electronCwd, "user_data", "runtime");
|
|
2791
2926
|
try {
|
|
2792
|
-
const entries = await
|
|
2927
|
+
const entries = await fs10.readdir(runtimeRoot, { withFileTypes: true });
|
|
2793
2928
|
let bestCandidate = null;
|
|
2794
2929
|
for (const entry of entries) {
|
|
2795
2930
|
if (!entry.isDirectory()) continue;
|
|
2796
|
-
const fullPath =
|
|
2797
|
-
const stat3 = await
|
|
2931
|
+
const fullPath = path11.join(runtimeRoot, entry.name);
|
|
2932
|
+
const stat3 = await fs10.stat(fullPath);
|
|
2798
2933
|
if (stat3.mtimeMs < params.spawnAtMs) continue;
|
|
2799
2934
|
if (bestCandidate === null || stat3.mtimeMs > bestCandidate.mtimeMs) {
|
|
2800
2935
|
bestCandidate = { path: fullPath, mtimeMs: stat3.mtimeMs };
|
|
@@ -2850,7 +2985,7 @@ async function executeElectronAppAsync(params) {
|
|
|
2850
2985
|
spawnArgs,
|
|
2851
2986
|
llmEnvOverrideNames
|
|
2852
2987
|
});
|
|
2853
|
-
const electronCwd =
|
|
2988
|
+
const electronCwd = path11.dirname(electronAppPath);
|
|
2854
2989
|
const child = spawn(electronAppPath, spawnArgs, {
|
|
2855
2990
|
stdio: ["ignore", "pipe", "pipe"],
|
|
2856
2991
|
env: electronEnv,
|
|
@@ -2865,7 +3000,7 @@ async function executeElectronAppAsync(params) {
|
|
|
2865
3000
|
capturedStderr: ""
|
|
2866
3001
|
};
|
|
2867
3002
|
activeProcesses.set(params.runId, processInfo);
|
|
2868
|
-
return await new Promise((
|
|
3003
|
+
return await new Promise((resolve6, reject) => {
|
|
2869
3004
|
let settled = false;
|
|
2870
3005
|
const finalize = (result) => {
|
|
2871
3006
|
if (settled) {
|
|
@@ -2877,7 +3012,7 @@ async function executeElectronAppAsync(params) {
|
|
|
2877
3012
|
}
|
|
2878
3013
|
activeProcesses.delete(params.runId);
|
|
2879
3014
|
if (result.ok) {
|
|
2880
|
-
|
|
3015
|
+
resolve6(result.payload);
|
|
2881
3016
|
} else {
|
|
2882
3017
|
reject(result.payload);
|
|
2883
3018
|
}
|
|
@@ -3032,17 +3167,17 @@ ${executionResult.stdout}
|
|
|
3032
3167
|
STDERR:
|
|
3033
3168
|
${executionResult.stderr}`;
|
|
3034
3169
|
const sessionsDir = getStorageService().getSessionsDir();
|
|
3035
|
-
const artifactsDir2 =
|
|
3036
|
-
const generatedScriptPath2 =
|
|
3037
|
-
|
|
3038
|
-
`gen_${
|
|
3170
|
+
const artifactsDir2 = path11.join(sessionsDir, runId);
|
|
3171
|
+
const generatedScriptPath2 = path11.join(
|
|
3172
|
+
path11.dirname(inputFilePath),
|
|
3173
|
+
`gen_${path11.basename(inputFilePath)}`
|
|
3039
3174
|
);
|
|
3040
3175
|
let failedStudioResult;
|
|
3041
3176
|
try {
|
|
3042
|
-
const failedScriptRaw = await
|
|
3177
|
+
const failedScriptRaw = await fs10.readFile(generatedScriptPath2, "utf-8");
|
|
3043
3178
|
failedStudioResult = JSON.parse(failedScriptRaw);
|
|
3044
|
-
await
|
|
3045
|
-
await
|
|
3179
|
+
await fs10.copyFile(generatedScriptPath2, path11.join(artifactsDir2, "action-script.json"));
|
|
3180
|
+
await fs10.unlink(generatedScriptPath2).catch(() => {
|
|
3046
3181
|
});
|
|
3047
3182
|
} catch {
|
|
3048
3183
|
}
|
|
@@ -3071,11 +3206,11 @@ ${executionResult.stderr}`;
|
|
|
3071
3206
|
errorMessage: failureMessage
|
|
3072
3207
|
};
|
|
3073
3208
|
}
|
|
3074
|
-
const generatedScriptPath =
|
|
3075
|
-
|
|
3076
|
-
`gen_${
|
|
3209
|
+
const generatedScriptPath = path11.join(
|
|
3210
|
+
path11.dirname(inputFilePath),
|
|
3211
|
+
`gen_${path11.basename(inputFilePath)}`
|
|
3077
3212
|
);
|
|
3078
|
-
const generatedScriptRaw = await
|
|
3213
|
+
const generatedScriptRaw = await fs10.readFile(generatedScriptPath, "utf-8");
|
|
3079
3214
|
const generatedScript = JSON.parse(generatedScriptRaw);
|
|
3080
3215
|
const generatedSteps = generatedScript.steps;
|
|
3081
3216
|
if (!Array.isArray(generatedSteps)) {
|
|
@@ -3218,7 +3353,7 @@ STDOUT:
|
|
|
3218
3353
|
${executionResult.stdout}
|
|
3219
3354
|
STDERR:
|
|
3220
3355
|
${executionResult.stderr}`;
|
|
3221
|
-
const artifactsDir2 =
|
|
3356
|
+
const artifactsDir2 = path11.join(getStorageService().getSessionsDir(), runId);
|
|
3222
3357
|
storage.updateRunResult(runId, {
|
|
3223
3358
|
status: "failed",
|
|
3224
3359
|
executionTimeMs,
|
|
@@ -3236,7 +3371,7 @@ ${executionResult.stderr}`;
|
|
|
3236
3371
|
errorMessage: failureMessage
|
|
3237
3372
|
};
|
|
3238
3373
|
}
|
|
3239
|
-
const artifactsDir =
|
|
3374
|
+
const artifactsDir = path11.join(getStorageService().getSessionsDir(), runId);
|
|
3240
3375
|
const replayStudioResult = await readCloudRefsFile(inputFilePath);
|
|
3241
3376
|
const replayStudioCloudRefs = extractStudioCloudRefs(replayStudioResult);
|
|
3242
3377
|
storage.updateRunResult(runId, {
|
|
@@ -3673,7 +3808,7 @@ var PREFS_FILENAME = "preferences.json";
|
|
|
3673
3808
|
var OAUTH_SESSION_FILENAME = "oauth-session.json";
|
|
3674
3809
|
var RELEASE_MANIFEST_FILENAME = "release-manifest.json";
|
|
3675
3810
|
function getDataDir3() {
|
|
3676
|
-
return
|
|
3811
|
+
return path11.join(os4.homedir(), DATA_DIR_NAME2);
|
|
3677
3812
|
}
|
|
3678
3813
|
|
|
3679
3814
|
var cachedInstallId;
|
|
@@ -3738,9 +3873,9 @@ function isValid2(value) {
|
|
|
3738
3873
|
function readReleaseManifest2() {
|
|
3739
3874
|
if (cachedManifest2 !== void 0)
|
|
3740
3875
|
return cachedManifest2;
|
|
3741
|
-
const
|
|
3876
|
+
const path17 = MANIFEST_PATH2;
|
|
3742
3877
|
try {
|
|
3743
|
-
const raw = readFileSync(
|
|
3878
|
+
const raw = readFileSync(path17, "utf8");
|
|
3744
3879
|
const parsed = JSON.parse(raw);
|
|
3745
3880
|
cachedManifest2 = isValid2(parsed) ? parsed : DEV_MANIFEST2;
|
|
3746
3881
|
return cachedManifest2;
|
|
@@ -4519,17 +4654,17 @@ var PromptServiceClient = class {
|
|
|
4519
4654
|
* @param path - Path to validate.
|
|
4520
4655
|
* @throws GatewayError if path is not allowed.
|
|
4521
4656
|
*/
|
|
4522
|
-
validatePath(
|
|
4523
|
-
const isAllowed = ALLOWED_UPSTREAM_PREFIXES.some((prefix) =>
|
|
4657
|
+
validatePath(path17) {
|
|
4658
|
+
const isAllowed = ALLOWED_UPSTREAM_PREFIXES.some((prefix) => path17.startsWith(prefix));
|
|
4524
4659
|
if (!isAllowed) {
|
|
4525
4660
|
const logger6 = getLogger();
|
|
4526
4661
|
logger6.error("Path not in allowlist", {
|
|
4527
|
-
path:
|
|
4662
|
+
path: path17,
|
|
4528
4663
|
allowedPrefixes: ALLOWED_UPSTREAM_PREFIXES
|
|
4529
4664
|
});
|
|
4530
4665
|
throw new GatewayError({
|
|
4531
4666
|
code: "FORBIDDEN" /* FORBIDDEN */,
|
|
4532
|
-
message: `Path '${
|
|
4667
|
+
message: `Path '${path17}' is not allowed`
|
|
4533
4668
|
});
|
|
4534
4669
|
}
|
|
4535
4670
|
}
|
|
@@ -6582,11 +6717,11 @@ var TELEMETRY_DIR_NAME = "telemetry";
|
|
|
6582
6717
|
var FAILURE_EVENTS_FILE_NAME = "failure-events.jsonl";
|
|
6583
6718
|
function appendFailureEvent(record) {
|
|
6584
6719
|
try {
|
|
6585
|
-
const dir =
|
|
6586
|
-
|
|
6587
|
-
const filePath =
|
|
6720
|
+
const dir = path11.join(getDataDir(), TELEMETRY_DIR_NAME);
|
|
6721
|
+
fs6.mkdirSync(dir, { recursive: true });
|
|
6722
|
+
const filePath = path11.join(dir, FAILURE_EVENTS_FILE_NAME);
|
|
6588
6723
|
const full = { ts: (/* @__PURE__ */ new Date()).toISOString(), ...record };
|
|
6589
|
-
|
|
6724
|
+
fs6.appendFileSync(filePath, `${JSON.stringify(full)}
|
|
6590
6725
|
`, "utf-8");
|
|
6591
6726
|
} catch (error) {
|
|
6592
6727
|
getLogger().warn("Failed to append failure event", {
|
|
@@ -6605,17 +6740,17 @@ var ProjectPreferencesReconcileOutcome = /* @__PURE__ */ ((ProjectPreferencesRec
|
|
|
6605
6740
|
|
|
6606
6741
|
// packages/mcps/src/shared/preferences-service.ts
|
|
6607
6742
|
function getGlobalPreferencesFilePath(dataDirOverride2) {
|
|
6608
|
-
return
|
|
6743
|
+
return path11.join(dataDirOverride2 ?? getDataDir(), PREFERENCES_FILE_NAME);
|
|
6609
6744
|
}
|
|
6610
6745
|
function isFirstRun(dataDirOverride2) {
|
|
6611
|
-
return !
|
|
6746
|
+
return !fs6.existsSync(getGlobalPreferencesFilePath(dataDirOverride2));
|
|
6612
6747
|
}
|
|
6613
6748
|
function readPreferencesFile(filePath) {
|
|
6614
6749
|
try {
|
|
6615
|
-
if (!
|
|
6750
|
+
if (!fs6.existsSync(filePath)) {
|
|
6616
6751
|
return {};
|
|
6617
6752
|
}
|
|
6618
|
-
const raw = JSON.parse(
|
|
6753
|
+
const raw = JSON.parse(fs6.readFileSync(filePath, "utf-8"));
|
|
6619
6754
|
return raw.preferences ?? {};
|
|
6620
6755
|
} catch (error) {
|
|
6621
6756
|
getLogger().warn("Failed to read preferences file", {
|
|
@@ -6631,15 +6766,15 @@ function writePreferencesFile(filePath, prefs) {
|
|
|
6631
6766
|
version: PREFERENCES_VERSION,
|
|
6632
6767
|
preferences: prefs
|
|
6633
6768
|
};
|
|
6634
|
-
|
|
6769
|
+
fs6.writeFileSync(filePath, `${JSON.stringify(file, null, 2)}
|
|
6635
6770
|
`, "utf-8");
|
|
6636
6771
|
}
|
|
6637
6772
|
function readRawPreferencesFile(filePath) {
|
|
6638
6773
|
try {
|
|
6639
|
-
if (!
|
|
6774
|
+
if (!fs6.existsSync(filePath)) {
|
|
6640
6775
|
return {};
|
|
6641
6776
|
}
|
|
6642
|
-
return JSON.parse(
|
|
6777
|
+
return JSON.parse(fs6.readFileSync(filePath, "utf-8"));
|
|
6643
6778
|
} catch {
|
|
6644
6779
|
return {};
|
|
6645
6780
|
}
|
|
@@ -6650,14 +6785,14 @@ function resolvePreferences(dataDirOverride2) {
|
|
|
6650
6785
|
}
|
|
6651
6786
|
function writePreferences2(prefs, dataDirOverride2) {
|
|
6652
6787
|
const dir = dataDirOverride2 ?? getDataDir();
|
|
6653
|
-
|
|
6654
|
-
const filePath =
|
|
6788
|
+
fs6.mkdirSync(dir, { recursive: true });
|
|
6789
|
+
const filePath = path11.join(dir, PREFERENCES_FILE_NAME);
|
|
6655
6790
|
const existing = readPreferencesFile(filePath);
|
|
6656
6791
|
writePreferencesFile(filePath, { ...existing, ...prefs });
|
|
6657
6792
|
}
|
|
6658
6793
|
function resetPreference(key, dataDirOverride2) {
|
|
6659
6794
|
const filePath = getGlobalPreferencesFilePath(dataDirOverride2);
|
|
6660
|
-
if (!
|
|
6795
|
+
if (!fs6.existsSync(filePath)) {
|
|
6661
6796
|
return;
|
|
6662
6797
|
}
|
|
6663
6798
|
if (!key) {
|
|
@@ -6669,7 +6804,7 @@ function resetPreference(key, dataDirOverride2) {
|
|
|
6669
6804
|
writePreferencesFile(filePath, existing);
|
|
6670
6805
|
}
|
|
6671
6806
|
function reconcileProjectPreferences(cwd, dataDirOverride2) {
|
|
6672
|
-
const projectFilePath =
|
|
6807
|
+
const projectFilePath = path11.join(cwd, PREFERENCES_PROJECT_DIR_NAME, PREFERENCES_FILE_NAME);
|
|
6673
6808
|
const projectPreferences = readPreferencesFile(projectFilePath);
|
|
6674
6809
|
const projectKeys = Object.keys(projectPreferences);
|
|
6675
6810
|
if (projectKeys.length === 0) {
|
|
@@ -6714,17 +6849,17 @@ var MUGGLE_HOME_DISPLAY_DIR = "~/.muggle-ai";
|
|
|
6714
6849
|
|
|
6715
6850
|
// packages/mcps/src/shared/cwd-keyed-cache.ts
|
|
6716
6851
|
function resolveHomeFilePath(cache) {
|
|
6717
|
-
return
|
|
6852
|
+
return path11.join(getDataDir(), cache.fileName);
|
|
6718
6853
|
}
|
|
6719
6854
|
function resolveLegacyFilePath(cache, cwd) {
|
|
6720
|
-
return
|
|
6855
|
+
return path11.join(cwd, LEGACY_CACHE_DIR_NAME, cache.fileName);
|
|
6721
6856
|
}
|
|
6722
6857
|
function parseJsonFile(filePath) {
|
|
6723
6858
|
try {
|
|
6724
|
-
if (!
|
|
6859
|
+
if (!fs6.existsSync(filePath)) {
|
|
6725
6860
|
return null;
|
|
6726
6861
|
}
|
|
6727
|
-
return JSON.parse(
|
|
6862
|
+
return JSON.parse(fs6.readFileSync(filePath, "utf-8"));
|
|
6728
6863
|
} catch (error) {
|
|
6729
6864
|
getLogger().warn("Failed to read cache file", {
|
|
6730
6865
|
path: filePath,
|
|
@@ -6738,12 +6873,12 @@ function readHomeEntries(cache) {
|
|
|
6738
6873
|
return parsed?.entries ?? {};
|
|
6739
6874
|
}
|
|
6740
6875
|
function writeHomeEntries(cache, entries) {
|
|
6741
|
-
|
|
6876
|
+
fs6.mkdirSync(getDataDir(), { recursive: true });
|
|
6742
6877
|
const file = {
|
|
6743
6878
|
version: CWD_KEYED_CACHE_VERSION,
|
|
6744
6879
|
entries
|
|
6745
6880
|
};
|
|
6746
|
-
|
|
6881
|
+
fs6.writeFileSync(
|
|
6747
6882
|
resolveHomeFilePath(cache),
|
|
6748
6883
|
`${JSON.stringify(file, null, 2)}
|
|
6749
6884
|
`,
|
|
@@ -6757,7 +6892,7 @@ function readLegacyEntry(cache, cwd) {
|
|
|
6757
6892
|
return parsed?.[cache.legacyEntryKey] ?? null;
|
|
6758
6893
|
}
|
|
6759
6894
|
function readCwdEntry(cache, cwd) {
|
|
6760
|
-
const cwdKey =
|
|
6895
|
+
const cwdKey = path11.resolve(cwd);
|
|
6761
6896
|
const entries = readHomeEntries(cache);
|
|
6762
6897
|
const homeEntry = entries[cwdKey];
|
|
6763
6898
|
if (homeEntry) {
|
|
@@ -6779,18 +6914,18 @@ function readCwdEntry(cache, cwd) {
|
|
|
6779
6914
|
}
|
|
6780
6915
|
function writeCwdEntry(cache, cwd, entry) {
|
|
6781
6916
|
const entries = readHomeEntries(cache);
|
|
6782
|
-
writeHomeEntries(cache, { ...entries, [
|
|
6917
|
+
writeHomeEntries(cache, { ...entries, [path11.resolve(cwd)]: entry });
|
|
6783
6918
|
}
|
|
6784
6919
|
function clearCwdEntry(cache, cwd) {
|
|
6785
6920
|
const entries = readHomeEntries(cache);
|
|
6786
|
-
const cwdKey =
|
|
6921
|
+
const cwdKey = path11.resolve(cwd);
|
|
6787
6922
|
if (cwdKey in entries) {
|
|
6788
6923
|
delete entries[cwdKey];
|
|
6789
6924
|
writeHomeEntries(cache, entries);
|
|
6790
6925
|
}
|
|
6791
6926
|
const legacyFilePath = resolveLegacyFilePath(cache, cwd);
|
|
6792
|
-
if (
|
|
6793
|
-
|
|
6927
|
+
if (fs6.existsSync(legacyFilePath)) {
|
|
6928
|
+
fs6.unlinkSync(legacyFilePath);
|
|
6794
6929
|
}
|
|
6795
6930
|
}
|
|
6796
6931
|
|
|
@@ -6955,7 +7090,7 @@ var runResultGetTool = {
|
|
|
6955
7090
|
const testScript = storage.getTestScript(storedRunResult.testScriptId);
|
|
6956
7091
|
testScriptSteps = testScript?.actionScript?.length;
|
|
6957
7092
|
}
|
|
6958
|
-
if (storedRunResult.artifactsDir &&
|
|
7093
|
+
if (storedRunResult.artifactsDir && fs6.existsSync(storedRunResult.artifactsDir)) {
|
|
6959
7094
|
contentParts.push(
|
|
6960
7095
|
"",
|
|
6961
7096
|
"### Artifacts (view action script + screenshots)",
|
|
@@ -6963,26 +7098,26 @@ var runResultGetTool = {
|
|
|
6963
7098
|
`**Location:** \`${storedRunResult.artifactsDir}\``,
|
|
6964
7099
|
""
|
|
6965
7100
|
);
|
|
6966
|
-
const actionScriptPath =
|
|
6967
|
-
const resultsMdPath =
|
|
6968
|
-
const screenshotsDir =
|
|
6969
|
-
const stdoutLogPath =
|
|
6970
|
-
const stderrLogPath =
|
|
7101
|
+
const actionScriptPath = path11.join(storedRunResult.artifactsDir, "action-script.json");
|
|
7102
|
+
const resultsMdPath = path11.join(storedRunResult.artifactsDir, "results.md");
|
|
7103
|
+
const screenshotsDir = path11.join(storedRunResult.artifactsDir, "screenshots");
|
|
7104
|
+
const stdoutLogPath = path11.join(storedRunResult.artifactsDir, "stdout.log");
|
|
7105
|
+
const stderrLogPath = path11.join(storedRunResult.artifactsDir, "stderr.log");
|
|
6971
7106
|
const artifactItems = [];
|
|
6972
|
-
if (
|
|
7107
|
+
if (fs6.existsSync(actionScriptPath)) {
|
|
6973
7108
|
artifactItems.push("- `action-script.json` \u2014 generated test steps");
|
|
6974
7109
|
}
|
|
6975
|
-
if (
|
|
7110
|
+
if (fs6.existsSync(resultsMdPath)) {
|
|
6976
7111
|
artifactItems.push("- `results.md` \u2014 step-by-step report with screenshot links");
|
|
6977
7112
|
}
|
|
6978
|
-
if (
|
|
6979
|
-
const screenshots =
|
|
7113
|
+
if (fs6.existsSync(screenshotsDir)) {
|
|
7114
|
+
const screenshots = fs6.readdirSync(screenshotsDir).filter((f) => /\.(png|jpg|jpeg|webp)$/i.test(f));
|
|
6980
7115
|
artifactItems.push(`- \`screenshots/\` \u2014 ${screenshots.length} image(s)`);
|
|
6981
7116
|
}
|
|
6982
|
-
if (
|
|
7117
|
+
if (fs6.existsSync(stdoutLogPath)) {
|
|
6983
7118
|
artifactItems.push("- `stdout.log` \u2014 electron-app stdout output");
|
|
6984
7119
|
}
|
|
6985
|
-
if (
|
|
7120
|
+
if (fs6.existsSync(stderrLogPath)) {
|
|
6986
7121
|
artifactItems.push("- `stderr.log` \u2014 electron-app stderr output");
|
|
6987
7122
|
}
|
|
6988
7123
|
if (artifactItems.length > 0) {
|
|
@@ -7633,4 +7768,4 @@ var WATCHER_LIFETIME_SECONDS = {
|
|
|
7633
7768
|
["never" /* Never */]: WATCHER_LIFETIME_UNBOUNDED_SECONDS
|
|
7634
7769
|
};
|
|
7635
7770
|
|
|
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 };
|
|
7771
|
+
export { DEFAULT_PREFERENCES, ElectronAppReleaseStream, EventName, PREFERENCES_FILE_NAME, PREFERENCES_PROJECT_DIR_NAME, PREFERENCES_SCHEMA, PREFERENCES_VERSION, PREFERENCE_ALLOWED_VALUES, PreferenceKey, PreferenceValue, ProjectPreferencesReconcileOutcome, RuntimeTarget, ServiceName, Surface, WATCHER_LIFETIME_SECONDS, WATCHER_LIFETIME_UNBOUNDED_SECONDS, __export, __require, assertDeviceCodeClientProvisioned, buildElectronAppChecksumsUrl, buildElectronAppReleaseAssetUrl, buildElectronAppReleaseTag, calculateFileChecksum, createApiKeyWithToken, createChildLogger, deleteApiKeyData, deleteCredentials, e2e_exports2 as e2e_exports, formatPreferencesOneLiner, getActiveElectronAppReleaseStream, getActiveRuntimeTarget, getApiKey, getApiKeyFilePath, getAuthService, getBundledElectronAppVersion, getCallerCredentials, getCallerCredentialsAsync, getChecksumForPlatform, getConfig, getCredentialsFilePath, getDataDir2 as getDataDir, getDisclosureCopy, getDownloadBaseUrl, getElectronAppChecksums, getElectronAppDir, getElectronAppReleaseTagPrefix, getElectronAppSignedFromVersion, getElectronAppVersion, getElectronAppVersionSource, getLocalQaTools, getLogger, getPlatformKey, getQaTools, getReleaseSignerIdentityUri, 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, resolveActiveProfile, resolveActiveReleaseStream, resolveActiveReleaseTagPrefix, resolveElectronAppPathOrNull, resolvePreferences, resolveRuntimeTarget, saveApiKey, saveApiKeyData, saveCredentials, src_exports, startDeviceCodeFlow, toolRequiresAuth, track, validatePreference, verifyFileChecksum, writePreferences2 as writePreferences };
|