@muggleai/works 5.11.0 → 5.12.0-staging.73
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-FCDHJD6I.js} +441 -347
- package/dist/{chunk-WUMAJOBT.js → chunk-O7LFABOC.js} +39 -35
- package/dist/cli.js +2 -2
- package/dist/index.js +2 -2
- package/dist/plugin/hooks/README.md +4 -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 +506 -32
- 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-TFNPZD5X.js +1 -0
- package/package.json +17 -8
- package/plugin/hooks/README.md +4 -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 +506 -32
- 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 +59 -2
- 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,6 +68,7 @@ __export(src_exports, {
|
|
|
63
68
|
getDownloadBaseUrl: () => getDownloadBaseUrl,
|
|
64
69
|
getElectronAppChecksums: () => getElectronAppChecksums,
|
|
65
70
|
getElectronAppDir: () => getElectronAppDir,
|
|
71
|
+
getElectronAppReleaseTagPrefix: () => getElectronAppReleaseTagPrefix,
|
|
66
72
|
getElectronAppVersion: () => getElectronAppVersion,
|
|
67
73
|
getElectronAppVersionSource: () => getElectronAppVersionSource,
|
|
68
74
|
getLocalQaTools: () => getLocalQaTools,
|
|
@@ -87,8 +93,12 @@ __export(src_exports, {
|
|
|
87
93
|
resetConfig: () => resetConfig,
|
|
88
94
|
resetLogger: () => resetLogger,
|
|
89
95
|
resetPreference: () => resetPreference,
|
|
96
|
+
resolveActiveProfile: () => resolveActiveProfile,
|
|
97
|
+
resolveActiveReleaseStream: () => resolveActiveReleaseStream,
|
|
98
|
+
resolveActiveReleaseTagPrefix: () => resolveActiveReleaseTagPrefix,
|
|
90
99
|
resolveElectronAppPathOrNull: () => resolveElectronAppPathOrNull,
|
|
91
100
|
resolvePreferences: () => resolvePreferences,
|
|
101
|
+
resolveRuntimeTarget: () => resolveRuntimeTarget,
|
|
92
102
|
saveApiKey: () => saveApiKey,
|
|
93
103
|
saveApiKeyData: () => saveApiKeyData,
|
|
94
104
|
saveCredentials: () => saveCredentials,
|
|
@@ -98,9 +108,121 @@ __export(src_exports, {
|
|
|
98
108
|
verifyFileChecksum: () => verifyFileChecksum,
|
|
99
109
|
writePreferences: () => writePreferences2
|
|
100
110
|
});
|
|
111
|
+
|
|
112
|
+
// packages/mcps/src/shared/runtime-target-types.ts
|
|
113
|
+
var RuntimeTarget = /* @__PURE__ */ ((RuntimeTarget2) => {
|
|
114
|
+
RuntimeTarget2["Production"] = "production";
|
|
115
|
+
RuntimeTarget2["Staging"] = "staging";
|
|
116
|
+
RuntimeTarget2["Dev"] = "dev";
|
|
117
|
+
return RuntimeTarget2;
|
|
118
|
+
})(RuntimeTarget || {});
|
|
119
|
+
var ElectronAppReleaseStream = /* @__PURE__ */ ((ElectronAppReleaseStream3) => {
|
|
120
|
+
ElectronAppReleaseStream3["Production"] = "production";
|
|
121
|
+
ElectronAppReleaseStream3["Staging"] = "staging";
|
|
122
|
+
return ElectronAppReleaseStream3;
|
|
123
|
+
})(ElectronAppReleaseStream || {});
|
|
124
|
+
var DEFAULT_AUTH0_SCOPE = "openid profile email offline_access";
|
|
125
|
+
var DEFAULT_WEB_SERVICE_URL = "http://localhost:3001";
|
|
126
|
+
var RUNTIME_TARGET_ENV_VAR = "MUGGLE_MCP_PROMPT_SERVICE_TARGET";
|
|
127
|
+
var RUNTIME_TARGETS_FILE = path11.join("config", "runtime-targets.json");
|
|
128
|
+
function getPackageRoot() {
|
|
129
|
+
const currentDir = path11.dirname(fileURLToPath(import.meta.url));
|
|
130
|
+
if (currentDir.includes(path11.join("dist", "shared"))) {
|
|
131
|
+
return path11.resolve(currentDir, "..", "..");
|
|
132
|
+
}
|
|
133
|
+
if (currentDir.endsWith("dist")) {
|
|
134
|
+
return path11.resolve(currentDir, "..");
|
|
135
|
+
}
|
|
136
|
+
if (currentDir.includes(path11.join("src", "shared"))) {
|
|
137
|
+
return path11.resolve(currentDir, "..", "..", "..", "..");
|
|
138
|
+
}
|
|
139
|
+
return path11.dirname(currentDir);
|
|
140
|
+
}
|
|
141
|
+
var runtimeTargetDataCache = null;
|
|
142
|
+
function getRuntimeTargetData() {
|
|
143
|
+
if (runtimeTargetDataCache) {
|
|
144
|
+
return runtimeTargetDataCache;
|
|
145
|
+
}
|
|
146
|
+
const profilesPath = path11.join(getPackageRoot(), RUNTIME_TARGETS_FILE);
|
|
147
|
+
let parsedData;
|
|
148
|
+
try {
|
|
149
|
+
parsedData = JSON.parse(fs6.readFileSync(profilesPath, "utf-8"));
|
|
150
|
+
} catch (error) {
|
|
151
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
152
|
+
throw new Error(
|
|
153
|
+
`Failed to read runtime target profiles.
|
|
154
|
+
Path: ${profilesPath}
|
|
155
|
+
Error: ${errorMessage}
|
|
156
|
+
This is a bug - please report it.`,
|
|
157
|
+
{ cause: error }
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
for (const target of Object.values(RuntimeTarget)) {
|
|
161
|
+
if (!parsedData.targets?.[target]) {
|
|
162
|
+
throw new Error(
|
|
163
|
+
`Missing runtime target '${target}' in profile data.
|
|
164
|
+
Path: ${profilesPath}
|
|
165
|
+
This is a bug - please report it.`
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
for (const stream of Object.values(ElectronAppReleaseStream)) {
|
|
170
|
+
if (!parsedData.streams?.[stream]) {
|
|
171
|
+
throw new Error(
|
|
172
|
+
`Missing electron-app release stream '${stream}' in profile data.
|
|
173
|
+
Path: ${profilesPath}
|
|
174
|
+
This is a bug - please report it.`
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
runtimeTargetDataCache = parsedData;
|
|
179
|
+
return runtimeTargetDataCache;
|
|
180
|
+
}
|
|
181
|
+
function getRuntimeTargetProfiles() {
|
|
182
|
+
return getRuntimeTargetData().targets;
|
|
183
|
+
}
|
|
184
|
+
function getElectronAppReleaseStreams() {
|
|
185
|
+
return getRuntimeTargetData().streams;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// packages/mcps/src/shared/runtime-target.ts
|
|
189
|
+
var KNOWN_RUNTIME_TARGETS = [
|
|
190
|
+
"production" /* Production */,
|
|
191
|
+
"staging" /* Staging */,
|
|
192
|
+
"dev" /* Dev */
|
|
193
|
+
];
|
|
194
|
+
function resolveRuntimeTarget(bakedDefault) {
|
|
195
|
+
const overrideValue = process.env[RUNTIME_TARGET_ENV_VAR];
|
|
196
|
+
if (overrideValue) {
|
|
197
|
+
const matchedTarget = KNOWN_RUNTIME_TARGETS.find((target) => target === overrideValue);
|
|
198
|
+
if (!matchedTarget) {
|
|
199
|
+
throw new Error(
|
|
200
|
+
`Invalid ${RUNTIME_TARGET_ENV_VAR} value: '${overrideValue}'. Expected one of: ${KNOWN_RUNTIME_TARGETS.join(", ")}.`
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
return matchedTarget;
|
|
204
|
+
}
|
|
205
|
+
return bakedDefault ?? "dev" /* Dev */;
|
|
206
|
+
}
|
|
207
|
+
function resolveActiveProfile(bakedDefault) {
|
|
208
|
+
return getRuntimeTargetProfiles()[resolveRuntimeTarget(bakedDefault)];
|
|
209
|
+
}
|
|
210
|
+
function resolveActiveReleaseStream(bakedDefault) {
|
|
211
|
+
return resolveActiveProfile(bakedDefault).electronAppReleaseStream;
|
|
212
|
+
}
|
|
213
|
+
function resolveActiveReleaseTagPrefix(bakedDefault) {
|
|
214
|
+
return getElectronAppReleaseStreams()[resolveActiveReleaseStream(bakedDefault)].electronAppReleaseTagPrefix;
|
|
215
|
+
}
|
|
216
|
+
function assertDeviceCodeClientProvisioned(target) {
|
|
217
|
+
if (getRuntimeTargetProfiles()[target].auth0ClientId === "") {
|
|
218
|
+
throw new Error(
|
|
219
|
+
`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.`
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
101
223
|
var DATA_DIR_NAME = ".muggle-ai";
|
|
102
224
|
function getDataDir() {
|
|
103
|
-
return
|
|
225
|
+
return path11.join(os4.homedir(), DATA_DIR_NAME);
|
|
104
226
|
}
|
|
105
227
|
var DEV_MANIFEST = {
|
|
106
228
|
release: "dev",
|
|
@@ -147,44 +269,33 @@ function readReleaseManifest() {
|
|
|
147
269
|
}
|
|
148
270
|
|
|
149
271
|
// 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
272
|
var ELECTRON_APP_DIR = "electron-app";
|
|
154
|
-
var ELECTRON_APP_RELEASE_TAG_PREFIX = "electron-app-v";
|
|
155
273
|
var API_KEY_FILE = "api-key.json";
|
|
156
|
-
var DEFAULT_AUTH0_PRODUCTION_DOMAIN = "login.muggle-ai.com";
|
|
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";
|
|
163
274
|
var configInstance = null;
|
|
164
275
|
var muggleConfigCache = null;
|
|
165
|
-
function
|
|
276
|
+
function getPackageRoot2() {
|
|
166
277
|
const currentFilePath = fileURLToPath(import.meta.url);
|
|
167
|
-
const currentDir =
|
|
168
|
-
if (currentDir.includes(
|
|
169
|
-
return
|
|
278
|
+
const currentDir = path11.dirname(currentFilePath);
|
|
279
|
+
if (currentDir.includes(path11.join("dist", "shared"))) {
|
|
280
|
+
return path11.resolve(currentDir, "..", "..");
|
|
170
281
|
}
|
|
171
282
|
if (currentDir.endsWith("dist")) {
|
|
172
|
-
return
|
|
283
|
+
return path11.resolve(currentDir, "..");
|
|
173
284
|
}
|
|
174
|
-
if (currentDir.includes(
|
|
175
|
-
return
|
|
285
|
+
if (currentDir.includes(path11.join("src", "shared"))) {
|
|
286
|
+
return path11.resolve(currentDir, "..", "..", "..", "..");
|
|
176
287
|
}
|
|
177
|
-
return
|
|
288
|
+
return path11.dirname(currentDir);
|
|
178
289
|
}
|
|
179
290
|
function getMuggleConfig() {
|
|
180
291
|
if (muggleConfigCache) {
|
|
181
292
|
return muggleConfigCache;
|
|
182
293
|
}
|
|
183
|
-
const packageRoot =
|
|
184
|
-
const packageJsonPath =
|
|
294
|
+
const packageRoot = getPackageRoot2();
|
|
295
|
+
const packageJsonPath = path11.join(packageRoot, "package.json");
|
|
185
296
|
let packageJson;
|
|
186
297
|
try {
|
|
187
|
-
const content =
|
|
298
|
+
const content = fs6.readFileSync(packageJsonPath, "utf-8");
|
|
188
299
|
packageJson = JSON.parse(content);
|
|
189
300
|
} catch (error) {
|
|
190
301
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -221,45 +332,59 @@ function getMuggleConfig() {
|
|
|
221
332
|
This is a bug - please report it.`
|
|
222
333
|
);
|
|
223
334
|
}
|
|
224
|
-
|
|
335
|
+
const runtimeTargetDefault = config.runtimeTargetDefault;
|
|
336
|
+
if (runtimeTargetDefault !== void 0 && !Object.values(RuntimeTarget).includes(runtimeTargetDefault)) {
|
|
225
337
|
throw new Error(
|
|
226
338
|
`Invalid muggleConfig.runtimeTargetDefault in package.json.
|
|
227
339
|
Path: ${packageJsonPath}
|
|
228
340
|
Value: ${JSON.stringify(config.runtimeTargetDefault)}
|
|
229
|
-
Expected: "
|
|
341
|
+
Expected one of: ${Object.values(RuntimeTarget).join(", ")}
|
|
230
342
|
This is a bug - please report it.`
|
|
231
343
|
);
|
|
232
344
|
}
|
|
233
345
|
muggleConfigCache = {
|
|
234
346
|
electronAppVersion: config.electronAppVersion,
|
|
235
347
|
downloadBaseUrl: config.downloadBaseUrl,
|
|
236
|
-
|
|
237
|
-
runtimeTargetDefault
|
|
348
|
+
checksumsByStream: config.checksumsByStream || {},
|
|
349
|
+
runtimeTargetDefault
|
|
238
350
|
};
|
|
239
351
|
return muggleConfigCache;
|
|
240
352
|
}
|
|
241
353
|
function getDataDir2() {
|
|
242
354
|
return getDataDir();
|
|
243
355
|
}
|
|
356
|
+
function buildElectronAppDirName(params) {
|
|
357
|
+
if (params.releaseStream === "production" /* Production */) {
|
|
358
|
+
return params.version;
|
|
359
|
+
}
|
|
360
|
+
return `${params.version}-${params.releaseStream}`;
|
|
361
|
+
}
|
|
244
362
|
function getDownloadedElectronAppPath() {
|
|
245
363
|
const platformName = os4.platform();
|
|
246
364
|
const version = getElectronAppVersion();
|
|
247
|
-
const baseDir =
|
|
365
|
+
const baseDir = path11.join(
|
|
366
|
+
getDataDir2(),
|
|
367
|
+
ELECTRON_APP_DIR,
|
|
368
|
+
buildElectronAppDirName({
|
|
369
|
+
version,
|
|
370
|
+
releaseStream: getActiveElectronAppReleaseStream()
|
|
371
|
+
})
|
|
372
|
+
);
|
|
248
373
|
let binaryPath;
|
|
249
374
|
switch (platformName) {
|
|
250
375
|
case "darwin":
|
|
251
|
-
binaryPath =
|
|
376
|
+
binaryPath = path11.join(baseDir, "MuggleAI.app", "Contents", "MacOS", "MuggleAI");
|
|
252
377
|
break;
|
|
253
378
|
case "win32":
|
|
254
|
-
binaryPath =
|
|
379
|
+
binaryPath = path11.join(baseDir, "MuggleAI.exe");
|
|
255
380
|
break;
|
|
256
381
|
case "linux":
|
|
257
|
-
binaryPath =
|
|
382
|
+
binaryPath = path11.join(baseDir, "MuggleAI");
|
|
258
383
|
break;
|
|
259
384
|
default:
|
|
260
385
|
return null;
|
|
261
386
|
}
|
|
262
|
-
if (
|
|
387
|
+
if (fs6.existsSync(binaryPath)) {
|
|
263
388
|
return binaryPath;
|
|
264
389
|
}
|
|
265
390
|
return null;
|
|
@@ -270,25 +395,25 @@ function getSystemElectronAppPath() {
|
|
|
270
395
|
let binaryPath;
|
|
271
396
|
switch (platformName) {
|
|
272
397
|
case "darwin":
|
|
273
|
-
binaryPath =
|
|
398
|
+
binaryPath = path11.join(homeDir, "Applications", "MuggleAI.app", "Contents", "MacOS", "MuggleAI");
|
|
274
399
|
break;
|
|
275
400
|
case "win32":
|
|
276
|
-
binaryPath =
|
|
401
|
+
binaryPath = path11.join(homeDir, "AppData", "Local", "Programs", "MuggleAI", "MuggleAI.exe");
|
|
277
402
|
break;
|
|
278
403
|
case "linux":
|
|
279
|
-
binaryPath =
|
|
404
|
+
binaryPath = path11.join(homeDir, ".local", "share", "muggle-ai", "MuggleAI");
|
|
280
405
|
break;
|
|
281
406
|
default:
|
|
282
407
|
return null;
|
|
283
408
|
}
|
|
284
|
-
if (
|
|
409
|
+
if (fs6.existsSync(binaryPath)) {
|
|
285
410
|
return binaryPath;
|
|
286
411
|
}
|
|
287
412
|
return null;
|
|
288
413
|
}
|
|
289
414
|
function resolveElectronAppPathOrNull() {
|
|
290
415
|
const customPath = process.env.ELECTRON_APP_PATH;
|
|
291
|
-
if (customPath &&
|
|
416
|
+
if (customPath && fs6.existsSync(customPath)) {
|
|
292
417
|
return customPath;
|
|
293
418
|
}
|
|
294
419
|
const downloadedPath = getDownloadedElectronAppPath();
|
|
@@ -303,12 +428,12 @@ function resolveElectronAppPathOrNull() {
|
|
|
303
428
|
}
|
|
304
429
|
function resolveWebServicePath() {
|
|
305
430
|
const customPath = process.env.WEB_SERVICE_PATH;
|
|
306
|
-
if (customPath &&
|
|
431
|
+
if (customPath && fs6.existsSync(customPath)) {
|
|
307
432
|
return customPath;
|
|
308
433
|
}
|
|
309
|
-
const packageRoot =
|
|
310
|
-
const siblingPath =
|
|
311
|
-
if (
|
|
434
|
+
const packageRoot = getPackageRoot2();
|
|
435
|
+
const siblingPath = path11.resolve(packageRoot, "..", "web-service", "dist", "src", "index.js");
|
|
436
|
+
if (fs6.existsSync(siblingPath)) {
|
|
312
437
|
return siblingPath;
|
|
313
438
|
}
|
|
314
439
|
return null;
|
|
@@ -320,65 +445,24 @@ function parseInteger(value, defaultValue) {
|
|
|
320
445
|
const parsed = parseInt(value, 10);
|
|
321
446
|
return isNaN(parsed) ? defaultValue : parsed;
|
|
322
447
|
}
|
|
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;
|
|
448
|
+
function getActiveRuntimeTarget() {
|
|
449
|
+
return resolveRuntimeTarget(getMuggleConfig().runtimeTargetDefault);
|
|
345
450
|
}
|
|
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;
|
|
451
|
+
function getActiveProfile() {
|
|
452
|
+
return resolveActiveProfile(getMuggleConfig().runtimeTargetDefault);
|
|
366
453
|
}
|
|
367
454
|
function buildAuth0Config() {
|
|
368
|
-
const
|
|
369
|
-
const defaultAuth0ClientId = getDefaultAuth0ClientId();
|
|
370
|
-
const defaultAuth0Audience = getDefaultAuth0Audience();
|
|
455
|
+
const activeProfile = getActiveProfile();
|
|
371
456
|
return {
|
|
372
|
-
domain: process.env.AUTH0_DOMAIN ??
|
|
373
|
-
clientId: process.env.AUTH0_CLIENT_ID ??
|
|
374
|
-
audience: process.env.AUTH0_AUDIENCE ??
|
|
457
|
+
domain: process.env.AUTH0_DOMAIN ?? activeProfile.auth0Domain,
|
|
458
|
+
clientId: process.env.AUTH0_CLIENT_ID ?? activeProfile.auth0ClientId,
|
|
459
|
+
audience: process.env.AUTH0_AUDIENCE ?? activeProfile.auth0Audience,
|
|
375
460
|
scope: process.env.AUTH0_SCOPE ?? DEFAULT_AUTH0_SCOPE
|
|
376
461
|
};
|
|
377
462
|
}
|
|
378
463
|
function buildE2eConfig() {
|
|
379
|
-
const defaultPromptServiceUrl = getDefaultPromptServiceUrl();
|
|
380
464
|
return {
|
|
381
|
-
promptServiceBaseUrl: process.env.PROMPT_SERVICE_BASE_URL ??
|
|
465
|
+
promptServiceBaseUrl: process.env.PROMPT_SERVICE_BASE_URL ?? getActiveProfile().promptServiceBaseUrl,
|
|
382
466
|
requestTimeoutMs: parseInteger(process.env.REQUEST_TIMEOUT_MS, 3e4),
|
|
383
467
|
workflowTimeoutMs: parseInteger(process.env.WORKFLOW_TIMEOUT_MS, 12e4)
|
|
384
468
|
};
|
|
@@ -386,25 +470,22 @@ function buildE2eConfig() {
|
|
|
386
470
|
function buildLocalQaConfig() {
|
|
387
471
|
const dataDir = getDataDir2();
|
|
388
472
|
const auth0Scopes = (process.env.AUTH0_SCOPE ?? DEFAULT_AUTH0_SCOPE).split(" ");
|
|
389
|
-
const
|
|
390
|
-
const defaultAuth0Domain = getDefaultAuth0Domain();
|
|
391
|
-
const defaultAuth0ClientId = getDefaultAuth0ClientId();
|
|
392
|
-
const defaultAuth0Audience = getDefaultAuth0Audience();
|
|
473
|
+
const activeProfile = getActiveProfile();
|
|
393
474
|
return {
|
|
394
475
|
webServiceUrl: process.env.WEB_SERVICE_URL ?? DEFAULT_WEB_SERVICE_URL,
|
|
395
|
-
promptServiceUrl: process.env.PROMPT_SERVICE_BASE_URL ??
|
|
476
|
+
promptServiceUrl: process.env.PROMPT_SERVICE_BASE_URL ?? activeProfile.promptServiceBaseUrl,
|
|
396
477
|
dataDir,
|
|
397
|
-
sessionsDir:
|
|
398
|
-
projectsDir:
|
|
399
|
-
tempDir:
|
|
400
|
-
apiKeyFilePath:
|
|
401
|
-
oauthSessionFilePath:
|
|
478
|
+
sessionsDir: path11.join(dataDir, "sessions"),
|
|
479
|
+
projectsDir: path11.join(dataDir, "projects"),
|
|
480
|
+
tempDir: path11.join(dataDir, "temp"),
|
|
481
|
+
apiKeyFilePath: path11.join(dataDir, API_KEY_FILE),
|
|
482
|
+
oauthSessionFilePath: path11.join(dataDir, "oauth-session.json"),
|
|
402
483
|
webServicePath: resolveWebServicePath(),
|
|
403
|
-
webServicePidFile:
|
|
484
|
+
webServicePidFile: path11.join(dataDir, "web-service.pid"),
|
|
404
485
|
auth0: {
|
|
405
|
-
domain: process.env.AUTH0_DOMAIN ??
|
|
406
|
-
clientId: process.env.AUTH0_CLIENT_ID ??
|
|
407
|
-
audience: process.env.AUTH0_AUDIENCE ??
|
|
486
|
+
domain: process.env.AUTH0_DOMAIN ?? activeProfile.auth0Domain,
|
|
487
|
+
clientId: process.env.AUTH0_CLIENT_ID ?? activeProfile.auth0ClientId,
|
|
488
|
+
audience: process.env.AUTH0_AUDIENCE ?? activeProfile.auth0Audience,
|
|
408
489
|
scopes: auth0Scopes
|
|
409
490
|
}
|
|
410
491
|
};
|
|
@@ -435,10 +516,10 @@ function getElectronAppVersion() {
|
|
|
435
516
|
if (envVersion && /^\d+\.\d+\.\d+$/.test(envVersion)) {
|
|
436
517
|
return envVersion;
|
|
437
518
|
}
|
|
438
|
-
const overridePath =
|
|
439
|
-
if (
|
|
519
|
+
const overridePath = path11.join(getDataDir2(), VERSION_OVERRIDE_FILE);
|
|
520
|
+
if (fs6.existsSync(overridePath)) {
|
|
440
521
|
try {
|
|
441
|
-
const content = JSON.parse(
|
|
522
|
+
const content = JSON.parse(fs6.readFileSync(overridePath, "utf-8"));
|
|
442
523
|
if (content.version && typeof content.version === "string") {
|
|
443
524
|
return content.version;
|
|
444
525
|
}
|
|
@@ -452,10 +533,10 @@ function getElectronAppVersionSource() {
|
|
|
452
533
|
if (envVersion && /^\d+\.\d+\.\d+$/.test(envVersion)) {
|
|
453
534
|
return "env";
|
|
454
535
|
}
|
|
455
|
-
const overridePath =
|
|
456
|
-
if (
|
|
536
|
+
const overridePath = path11.join(getDataDir2(), VERSION_OVERRIDE_FILE);
|
|
537
|
+
if (fs6.existsSync(overridePath)) {
|
|
457
538
|
try {
|
|
458
|
-
const content = JSON.parse(
|
|
539
|
+
const content = JSON.parse(fs6.readFileSync(overridePath, "utf-8"));
|
|
459
540
|
if (content.version && typeof content.version === "string") {
|
|
460
541
|
return "override";
|
|
461
542
|
}
|
|
@@ -470,8 +551,14 @@ function getBundledElectronAppVersion() {
|
|
|
470
551
|
function getDownloadBaseUrl() {
|
|
471
552
|
return getMuggleConfig().downloadBaseUrl;
|
|
472
553
|
}
|
|
554
|
+
function getActiveElectronAppReleaseStream() {
|
|
555
|
+
return resolveActiveReleaseStream(getMuggleConfig().runtimeTargetDefault);
|
|
556
|
+
}
|
|
557
|
+
function getElectronAppReleaseTagPrefix() {
|
|
558
|
+
return resolveActiveReleaseTagPrefix(getMuggleConfig().runtimeTargetDefault);
|
|
559
|
+
}
|
|
473
560
|
function buildElectronAppReleaseTag(version) {
|
|
474
|
-
return `${
|
|
561
|
+
return `${getElectronAppReleaseTagPrefix()}${version}`;
|
|
475
562
|
}
|
|
476
563
|
function buildElectronAppReleaseAssetUrl(params) {
|
|
477
564
|
return `${getDownloadBaseUrl()}/${buildElectronAppReleaseTag(params.version)}/${params.assetFileName}`;
|
|
@@ -480,14 +567,21 @@ function buildElectronAppChecksumsUrl(version) {
|
|
|
480
567
|
return `${getDownloadBaseUrl()}/${buildElectronAppReleaseTag(version)}/checksums.txt`;
|
|
481
568
|
}
|
|
482
569
|
function getElectronAppChecksums() {
|
|
483
|
-
return getMuggleConfig().
|
|
570
|
+
return getMuggleConfig().checksumsByStream?.[getActiveElectronAppReleaseStream()];
|
|
484
571
|
}
|
|
485
572
|
function isElectronAppInstalled() {
|
|
486
573
|
return getDownloadedElectronAppPath() !== null;
|
|
487
574
|
}
|
|
488
575
|
function getElectronAppDir(version) {
|
|
489
576
|
const resolvedVersion = version ?? getElectronAppVersion();
|
|
490
|
-
return
|
|
577
|
+
return path11.join(
|
|
578
|
+
getDataDir2(),
|
|
579
|
+
ELECTRON_APP_DIR,
|
|
580
|
+
buildElectronAppDirName({
|
|
581
|
+
version: resolvedVersion,
|
|
582
|
+
releaseStream: getActiveElectronAppReleaseStream()
|
|
583
|
+
})
|
|
584
|
+
);
|
|
491
585
|
}
|
|
492
586
|
|
|
493
587
|
// packages/mcps/src/shared/logger.ts
|
|
@@ -544,14 +638,14 @@ function getPlatformKey() {
|
|
|
544
638
|
}
|
|
545
639
|
}
|
|
546
640
|
async function calculateFileChecksum(filePath) {
|
|
547
|
-
return new Promise((
|
|
641
|
+
return new Promise((resolve6, reject) => {
|
|
548
642
|
const hash = crypto.createHash("sha256");
|
|
549
|
-
const stream =
|
|
643
|
+
const stream = fs6.createReadStream(filePath);
|
|
550
644
|
stream.on("data", (data) => {
|
|
551
645
|
hash.update(data);
|
|
552
646
|
});
|
|
553
647
|
stream.on("end", () => {
|
|
554
|
-
|
|
648
|
+
resolve6(hash.digest("hex"));
|
|
555
649
|
});
|
|
556
650
|
stream.on("error", (error) => {
|
|
557
651
|
reject(error);
|
|
@@ -561,7 +655,7 @@ async function calculateFileChecksum(filePath) {
|
|
|
561
655
|
async function verifyFileChecksum(filePath, expectedChecksum) {
|
|
562
656
|
if (!expectedChecksum || expectedChecksum.trim() === "") {
|
|
563
657
|
logger.warn("Checksum verification skipped - no checksum provided", {
|
|
564
|
-
file:
|
|
658
|
+
file: path11.basename(filePath)
|
|
565
659
|
});
|
|
566
660
|
return {
|
|
567
661
|
valid: true,
|
|
@@ -577,13 +671,13 @@ async function verifyFileChecksum(filePath, expectedChecksum) {
|
|
|
577
671
|
const valid = normalizedExpected === normalizedActual;
|
|
578
672
|
if (!valid) {
|
|
579
673
|
logger.error("Checksum verification failed", {
|
|
580
|
-
file:
|
|
674
|
+
file: path11.basename(filePath),
|
|
581
675
|
expected: normalizedExpected,
|
|
582
676
|
actual: normalizedActual
|
|
583
677
|
});
|
|
584
678
|
} else {
|
|
585
679
|
logger.info("Checksum verified successfully", {
|
|
586
|
-
file:
|
|
680
|
+
file: path11.basename(filePath),
|
|
587
681
|
checksum: normalizedActual
|
|
588
682
|
});
|
|
589
683
|
}
|
|
@@ -596,7 +690,7 @@ async function verifyFileChecksum(filePath, expectedChecksum) {
|
|
|
596
690
|
} catch (error) {
|
|
597
691
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
598
692
|
logger.error("Checksum calculation failed", {
|
|
599
|
-
file:
|
|
693
|
+
file: path11.basename(filePath),
|
|
600
694
|
error: errorMessage
|
|
601
695
|
});
|
|
602
696
|
return {
|
|
@@ -629,7 +723,7 @@ function getOpenCommand(url) {
|
|
|
629
723
|
}
|
|
630
724
|
}
|
|
631
725
|
async function openBrowserUrl(options) {
|
|
632
|
-
return new Promise((
|
|
726
|
+
return new Promise((resolve6) => {
|
|
633
727
|
try {
|
|
634
728
|
const command = getOpenCommand(options.url);
|
|
635
729
|
logger2.debug("[Browser] Opening URL", { url: options.url, command });
|
|
@@ -639,13 +733,13 @@ async function openBrowserUrl(options) {
|
|
|
639
733
|
url: options.url,
|
|
640
734
|
error: error.message
|
|
641
735
|
});
|
|
642
|
-
|
|
736
|
+
resolve6({
|
|
643
737
|
opened: false,
|
|
644
738
|
error: error.message
|
|
645
739
|
});
|
|
646
740
|
} else {
|
|
647
741
|
logger2.info("[Browser] URL opened successfully", { url: options.url });
|
|
648
|
-
|
|
742
|
+
resolve6({ opened: true });
|
|
649
743
|
}
|
|
650
744
|
});
|
|
651
745
|
} catch (error) {
|
|
@@ -654,7 +748,7 @@ async function openBrowserUrl(options) {
|
|
|
654
748
|
url: options.url,
|
|
655
749
|
error: errorMessage
|
|
656
750
|
});
|
|
657
|
-
|
|
751
|
+
resolve6({
|
|
658
752
|
opened: false,
|
|
659
753
|
error: errorMessage
|
|
660
754
|
});
|
|
@@ -663,23 +757,23 @@ async function openBrowserUrl(options) {
|
|
|
663
757
|
}
|
|
664
758
|
var API_KEY_FILE2 = "api-key.json";
|
|
665
759
|
function getApiKeyFilePath() {
|
|
666
|
-
return
|
|
760
|
+
return path11.join(getDataDir(), API_KEY_FILE2);
|
|
667
761
|
}
|
|
668
762
|
function ensureDataDir() {
|
|
669
763
|
const dataDir = getDataDir();
|
|
670
|
-
if (!
|
|
671
|
-
|
|
764
|
+
if (!fs6.existsSync(dataDir)) {
|
|
765
|
+
fs6.mkdirSync(dataDir, { recursive: true });
|
|
672
766
|
}
|
|
673
767
|
}
|
|
674
768
|
function loadApiKeyData() {
|
|
675
769
|
const logger6 = getLogger();
|
|
676
770
|
const apiKeyPath = getApiKeyFilePath();
|
|
677
771
|
try {
|
|
678
|
-
if (!
|
|
772
|
+
if (!fs6.existsSync(apiKeyPath)) {
|
|
679
773
|
logger6.debug("No API key file found", { path: apiKeyPath });
|
|
680
774
|
return null;
|
|
681
775
|
}
|
|
682
|
-
const content =
|
|
776
|
+
const content = fs6.readFileSync(apiKeyPath, "utf-8");
|
|
683
777
|
const data = JSON.parse(content);
|
|
684
778
|
return data;
|
|
685
779
|
} catch (error) {
|
|
@@ -695,7 +789,7 @@ function saveApiKeyData(data) {
|
|
|
695
789
|
try {
|
|
696
790
|
ensureDataDir();
|
|
697
791
|
const content = JSON.stringify(data, null, 2);
|
|
698
|
-
|
|
792
|
+
fs6.writeFileSync(apiKeyPath, content, { mode: 384 });
|
|
699
793
|
logger6.info("API key saved", { path: apiKeyPath });
|
|
700
794
|
} catch (error) {
|
|
701
795
|
logger6.error("Failed to save API key", {
|
|
@@ -708,8 +802,8 @@ function deleteApiKeyData() {
|
|
|
708
802
|
const logger6 = getLogger();
|
|
709
803
|
const apiKeyPath = getApiKeyFilePath();
|
|
710
804
|
try {
|
|
711
|
-
if (
|
|
712
|
-
|
|
805
|
+
if (fs6.existsSync(apiKeyPath)) {
|
|
806
|
+
fs6.unlinkSync(apiKeyPath);
|
|
713
807
|
logger6.info("API key deleted", { path: apiKeyPath });
|
|
714
808
|
}
|
|
715
809
|
} catch (error) {
|
|
@@ -748,7 +842,7 @@ function saveApiKey(params) {
|
|
|
748
842
|
apiKeyId: params.apiKeyId
|
|
749
843
|
};
|
|
750
844
|
const content = JSON.stringify(data, null, 2);
|
|
751
|
-
|
|
845
|
+
fs6.writeFileSync(apiKeyPath, content, { mode: 384 });
|
|
752
846
|
logger6.info("API key saved", { path: apiKeyPath });
|
|
753
847
|
} catch (error) {
|
|
754
848
|
logger6.error("Failed to save API key", {
|
|
@@ -852,8 +946,8 @@ var AuthService = class {
|
|
|
852
946
|
constructor() {
|
|
853
947
|
const config = getConfig();
|
|
854
948
|
this.oauthSessionFilePath = config.localQa.oauthSessionFilePath;
|
|
855
|
-
this.pendingDeviceCodePath =
|
|
856
|
-
|
|
949
|
+
this.pendingDeviceCodePath = path11.join(
|
|
950
|
+
path11.dirname(config.localQa.oauthSessionFilePath),
|
|
857
951
|
"pending-device-code.json"
|
|
858
952
|
);
|
|
859
953
|
}
|
|
@@ -962,11 +1056,11 @@ var AuthService = class {
|
|
|
962
1056
|
*/
|
|
963
1057
|
storePendingDeviceCode(params) {
|
|
964
1058
|
const logger6 = getLogger();
|
|
965
|
-
const dir =
|
|
966
|
-
if (!
|
|
967
|
-
|
|
1059
|
+
const dir = path11.dirname(this.pendingDeviceCodePath);
|
|
1060
|
+
if (!fs6.existsSync(dir)) {
|
|
1061
|
+
fs6.mkdirSync(dir, { recursive: true });
|
|
968
1062
|
}
|
|
969
|
-
|
|
1063
|
+
fs6.writeFileSync(this.pendingDeviceCodePath, JSON.stringify(params, null, 2), {
|
|
970
1064
|
encoding: "utf-8",
|
|
971
1065
|
mode: 384
|
|
972
1066
|
});
|
|
@@ -977,12 +1071,12 @@ var AuthService = class {
|
|
|
977
1071
|
*/
|
|
978
1072
|
getPendingDeviceCode() {
|
|
979
1073
|
const logger6 = getLogger();
|
|
980
|
-
if (!
|
|
1074
|
+
if (!fs6.existsSync(this.pendingDeviceCodePath)) {
|
|
981
1075
|
logger6.debug("No pending device code found");
|
|
982
1076
|
return null;
|
|
983
1077
|
}
|
|
984
1078
|
try {
|
|
985
|
-
const content =
|
|
1079
|
+
const content = fs6.readFileSync(this.pendingDeviceCodePath, "utf-8");
|
|
986
1080
|
const data = JSON.parse(content);
|
|
987
1081
|
const now = /* @__PURE__ */ new Date();
|
|
988
1082
|
const expiresAt = new Date(data.expiresAt);
|
|
@@ -1004,9 +1098,9 @@ var AuthService = class {
|
|
|
1004
1098
|
*/
|
|
1005
1099
|
clearPendingDeviceCode() {
|
|
1006
1100
|
const logger6 = getLogger();
|
|
1007
|
-
if (
|
|
1101
|
+
if (fs6.existsSync(this.pendingDeviceCodePath)) {
|
|
1008
1102
|
try {
|
|
1009
|
-
|
|
1103
|
+
fs6.unlinkSync(this.pendingDeviceCodePath);
|
|
1010
1104
|
logger6.debug("Pending device code cleared");
|
|
1011
1105
|
} catch (error) {
|
|
1012
1106
|
logger6.warn("Failed to clear pending device code", {
|
|
@@ -1175,11 +1269,11 @@ var AuthService = class {
|
|
|
1175
1269
|
email,
|
|
1176
1270
|
userId
|
|
1177
1271
|
};
|
|
1178
|
-
const dir =
|
|
1179
|
-
if (!
|
|
1180
|
-
|
|
1272
|
+
const dir = path11.dirname(this.oauthSessionFilePath);
|
|
1273
|
+
if (!fs6.existsSync(dir)) {
|
|
1274
|
+
fs6.mkdirSync(dir, { recursive: true });
|
|
1181
1275
|
}
|
|
1182
|
-
|
|
1276
|
+
fs6.writeFileSync(this.oauthSessionFilePath, JSON.stringify(storedAuth, null, 2), {
|
|
1183
1277
|
encoding: "utf-8",
|
|
1184
1278
|
mode: 384
|
|
1185
1279
|
});
|
|
@@ -1190,11 +1284,11 @@ var AuthService = class {
|
|
|
1190
1284
|
*/
|
|
1191
1285
|
loadStoredAuth() {
|
|
1192
1286
|
const logger6 = getLogger();
|
|
1193
|
-
if (!
|
|
1287
|
+
if (!fs6.existsSync(this.oauthSessionFilePath)) {
|
|
1194
1288
|
return null;
|
|
1195
1289
|
}
|
|
1196
1290
|
try {
|
|
1197
|
-
const content =
|
|
1291
|
+
const content = fs6.readFileSync(this.oauthSessionFilePath, "utf-8");
|
|
1198
1292
|
return JSON.parse(content);
|
|
1199
1293
|
} catch (error) {
|
|
1200
1294
|
logger6.error("Failed to load stored auth", {
|
|
@@ -1278,11 +1372,11 @@ var AuthService = class {
|
|
|
1278
1372
|
email: storedAuth.email,
|
|
1279
1373
|
userId: storedAuth.userId
|
|
1280
1374
|
};
|
|
1281
|
-
const dir =
|
|
1282
|
-
if (!
|
|
1283
|
-
|
|
1375
|
+
const dir = path11.dirname(this.oauthSessionFilePath);
|
|
1376
|
+
if (!fs6.existsSync(dir)) {
|
|
1377
|
+
fs6.mkdirSync(dir, { recursive: true });
|
|
1284
1378
|
}
|
|
1285
|
-
|
|
1379
|
+
fs6.writeFileSync(this.oauthSessionFilePath, JSON.stringify(updatedAuth, null, 2), {
|
|
1286
1380
|
encoding: "utf-8",
|
|
1287
1381
|
mode: 384
|
|
1288
1382
|
});
|
|
@@ -1334,12 +1428,12 @@ var AuthService = class {
|
|
|
1334
1428
|
*/
|
|
1335
1429
|
logout() {
|
|
1336
1430
|
const logger6 = getLogger();
|
|
1337
|
-
if (!
|
|
1431
|
+
if (!fs6.existsSync(this.oauthSessionFilePath)) {
|
|
1338
1432
|
logger6.debug("No auth to clear");
|
|
1339
1433
|
return false;
|
|
1340
1434
|
}
|
|
1341
1435
|
try {
|
|
1342
|
-
|
|
1436
|
+
fs6.unlinkSync(this.oauthSessionFilePath);
|
|
1343
1437
|
logger6.info("Auth cleared successfully");
|
|
1344
1438
|
return true;
|
|
1345
1439
|
} catch (error) {
|
|
@@ -1359,9 +1453,9 @@ function resetAuthService() {
|
|
|
1359
1453
|
serviceInstance = null;
|
|
1360
1454
|
}
|
|
1361
1455
|
function sleep(params) {
|
|
1362
|
-
return new Promise((
|
|
1456
|
+
return new Promise((resolve6) => {
|
|
1363
1457
|
setTimeout(() => {
|
|
1364
|
-
|
|
1458
|
+
resolve6();
|
|
1365
1459
|
}, params.durationMs);
|
|
1366
1460
|
});
|
|
1367
1461
|
}
|
|
@@ -1384,12 +1478,12 @@ var StorageService = class {
|
|
|
1384
1478
|
*/
|
|
1385
1479
|
ensureDirectories() {
|
|
1386
1480
|
const logger6 = getLogger();
|
|
1387
|
-
if (!
|
|
1388
|
-
|
|
1481
|
+
if (!fs6.existsSync(this.dataDir)) {
|
|
1482
|
+
fs6.mkdirSync(this.dataDir, { recursive: true });
|
|
1389
1483
|
logger6.info("Created data directory", { path: this.dataDir });
|
|
1390
1484
|
}
|
|
1391
|
-
if (!
|
|
1392
|
-
|
|
1485
|
+
if (!fs6.existsSync(this.sessionsDir)) {
|
|
1486
|
+
fs6.mkdirSync(this.sessionsDir, { recursive: true });
|
|
1393
1487
|
logger6.info("Created sessions directory", { path: this.sessionsDir });
|
|
1394
1488
|
}
|
|
1395
1489
|
}
|
|
@@ -1401,11 +1495,11 @@ var StorageService = class {
|
|
|
1401
1495
|
createSessionDirectory(sessionId) {
|
|
1402
1496
|
const logger6 = getLogger();
|
|
1403
1497
|
this.ensureDirectories();
|
|
1404
|
-
const sessionDir =
|
|
1405
|
-
if (!
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1498
|
+
const sessionDir = path11.join(this.sessionsDir, sessionId);
|
|
1499
|
+
if (!fs6.existsSync(sessionDir)) {
|
|
1500
|
+
fs6.mkdirSync(sessionDir, { recursive: true });
|
|
1501
|
+
fs6.mkdirSync(path11.join(sessionDir, "screenshots"), { recursive: true });
|
|
1502
|
+
fs6.mkdirSync(path11.join(sessionDir, "logs"), { recursive: true });
|
|
1409
1503
|
logger6.info("Created session directory", { sessionId, path: sessionDir });
|
|
1410
1504
|
}
|
|
1411
1505
|
return sessionDir;
|
|
@@ -1417,8 +1511,8 @@ var StorageService = class {
|
|
|
1417
1511
|
saveSessionMetadata(metadata) {
|
|
1418
1512
|
const logger6 = getLogger();
|
|
1419
1513
|
const sessionDir = this.createSessionDirectory(metadata.sessionId);
|
|
1420
|
-
const metadataPath =
|
|
1421
|
-
|
|
1514
|
+
const metadataPath = path11.join(sessionDir, "metadata.json");
|
|
1515
|
+
fs6.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2), "utf-8");
|
|
1422
1516
|
logger6.debug("Saved session metadata", { sessionId: metadata.sessionId });
|
|
1423
1517
|
}
|
|
1424
1518
|
/**
|
|
@@ -1428,12 +1522,12 @@ var StorageService = class {
|
|
|
1428
1522
|
*/
|
|
1429
1523
|
loadSessionMetadata(sessionId) {
|
|
1430
1524
|
const logger6 = getLogger();
|
|
1431
|
-
const metadataPath =
|
|
1432
|
-
if (!
|
|
1525
|
+
const metadataPath = path11.join(this.sessionsDir, sessionId, "metadata.json");
|
|
1526
|
+
if (!fs6.existsSync(metadataPath)) {
|
|
1433
1527
|
return null;
|
|
1434
1528
|
}
|
|
1435
1529
|
try {
|
|
1436
|
-
const content =
|
|
1530
|
+
const content = fs6.readFileSync(metadataPath, "utf-8");
|
|
1437
1531
|
return JSON.parse(content);
|
|
1438
1532
|
} catch (error) {
|
|
1439
1533
|
logger6.error("Failed to load session metadata", {
|
|
@@ -1448,12 +1542,12 @@ var StorageService = class {
|
|
|
1448
1542
|
* @returns Array of session IDs.
|
|
1449
1543
|
*/
|
|
1450
1544
|
listSessions() {
|
|
1451
|
-
if (!
|
|
1545
|
+
if (!fs6.existsSync(this.sessionsDir)) {
|
|
1452
1546
|
return [];
|
|
1453
1547
|
}
|
|
1454
|
-
return
|
|
1455
|
-
const entryPath =
|
|
1456
|
-
return
|
|
1548
|
+
return fs6.readdirSync(this.sessionsDir).filter((entry) => {
|
|
1549
|
+
const entryPath = path11.join(this.sessionsDir, entry);
|
|
1550
|
+
return fs6.statSync(entryPath).isDirectory();
|
|
1457
1551
|
});
|
|
1458
1552
|
}
|
|
1459
1553
|
/**
|
|
@@ -1461,13 +1555,13 @@ var StorageService = class {
|
|
|
1461
1555
|
* @returns Current session ID, or null.
|
|
1462
1556
|
*/
|
|
1463
1557
|
getCurrentSessionId() {
|
|
1464
|
-
const currentPath =
|
|
1465
|
-
if (!
|
|
1558
|
+
const currentPath = path11.join(this.sessionsDir, "current");
|
|
1559
|
+
if (!fs6.existsSync(currentPath)) {
|
|
1466
1560
|
return null;
|
|
1467
1561
|
}
|
|
1468
1562
|
try {
|
|
1469
|
-
const target =
|
|
1470
|
-
return
|
|
1563
|
+
const target = fs6.readlinkSync(currentPath);
|
|
1564
|
+
return path11.basename(target);
|
|
1471
1565
|
} catch {
|
|
1472
1566
|
return null;
|
|
1473
1567
|
}
|
|
@@ -1478,12 +1572,12 @@ var StorageService = class {
|
|
|
1478
1572
|
*/
|
|
1479
1573
|
setCurrentSession(sessionId) {
|
|
1480
1574
|
const logger6 = getLogger();
|
|
1481
|
-
const currentPath =
|
|
1482
|
-
const targetPath =
|
|
1483
|
-
if (
|
|
1484
|
-
|
|
1575
|
+
const currentPath = path11.join(this.sessionsDir, "current");
|
|
1576
|
+
const targetPath = path11.join(this.sessionsDir, sessionId);
|
|
1577
|
+
if (fs6.existsSync(currentPath)) {
|
|
1578
|
+
fs6.unlinkSync(currentPath);
|
|
1485
1579
|
}
|
|
1486
|
-
|
|
1580
|
+
fs6.symlinkSync(targetPath, currentPath);
|
|
1487
1581
|
logger6.info("Set current session", { sessionId });
|
|
1488
1582
|
}
|
|
1489
1583
|
/**
|
|
@@ -1494,8 +1588,8 @@ var StorageService = class {
|
|
|
1494
1588
|
const { sessionId, filename, data } = params;
|
|
1495
1589
|
const logger6 = getLogger();
|
|
1496
1590
|
const sessionDir = this.createSessionDirectory(sessionId);
|
|
1497
|
-
const screenshotPath =
|
|
1498
|
-
|
|
1591
|
+
const screenshotPath = path11.join(sessionDir, "screenshots", filename);
|
|
1592
|
+
fs6.writeFileSync(screenshotPath, data);
|
|
1499
1593
|
logger6.debug("Saved screenshot", { sessionId, filename });
|
|
1500
1594
|
return screenshotPath;
|
|
1501
1595
|
}
|
|
@@ -1507,8 +1601,8 @@ var StorageService = class {
|
|
|
1507
1601
|
const { sessionId, content } = params;
|
|
1508
1602
|
const logger6 = getLogger();
|
|
1509
1603
|
const sessionDir = this.createSessionDirectory(sessionId);
|
|
1510
|
-
const resultsPath =
|
|
1511
|
-
|
|
1604
|
+
const resultsPath = path11.join(sessionDir, "results.md");
|
|
1605
|
+
fs6.appendFileSync(resultsPath, content + "\n", "utf-8");
|
|
1512
1606
|
logger6.debug("Appended to results", { sessionId });
|
|
1513
1607
|
}
|
|
1514
1608
|
/**
|
|
@@ -1517,11 +1611,11 @@ var StorageService = class {
|
|
|
1517
1611
|
* @returns Results content, or null if not found.
|
|
1518
1612
|
*/
|
|
1519
1613
|
getResults(sessionId) {
|
|
1520
|
-
const resultsPath =
|
|
1521
|
-
if (!
|
|
1614
|
+
const resultsPath = path11.join(this.sessionsDir, sessionId, "results.md");
|
|
1615
|
+
if (!fs6.existsSync(resultsPath)) {
|
|
1522
1616
|
return null;
|
|
1523
1617
|
}
|
|
1524
|
-
return
|
|
1618
|
+
return fs6.readFileSync(resultsPath, "utf-8");
|
|
1525
1619
|
}
|
|
1526
1620
|
/**
|
|
1527
1621
|
* Get the data directory path.
|
|
@@ -1586,7 +1680,7 @@ var StorageService = class {
|
|
|
1586
1680
|
const { sessionId, targetUrl, testInstructions } = params;
|
|
1587
1681
|
const logger6 = getLogger();
|
|
1588
1682
|
const sessionDir = this.createSessionDirectory(sessionId);
|
|
1589
|
-
const resultsPath =
|
|
1683
|
+
const resultsPath = path11.join(sessionDir, "results.md");
|
|
1590
1684
|
const header = [
|
|
1591
1685
|
`# Test Results: ${sessionId}`,
|
|
1592
1686
|
"",
|
|
@@ -1599,7 +1693,7 @@ var StorageService = class {
|
|
|
1599
1693
|
"## Test Steps",
|
|
1600
1694
|
""
|
|
1601
1695
|
].join("\n");
|
|
1602
|
-
|
|
1696
|
+
fs6.writeFileSync(resultsPath, header, "utf-8");
|
|
1603
1697
|
logger6.debug("Initialized results.md", { sessionId });
|
|
1604
1698
|
}
|
|
1605
1699
|
/**
|
|
@@ -1610,7 +1704,7 @@ var StorageService = class {
|
|
|
1610
1704
|
const { sessionId, step } = params;
|
|
1611
1705
|
const logger6 = getLogger();
|
|
1612
1706
|
const sessionDir = this.createSessionDirectory(sessionId);
|
|
1613
|
-
const resultsPath =
|
|
1707
|
+
const resultsPath = path11.join(sessionDir, "results.md");
|
|
1614
1708
|
const statusIcon = step.success ? "\u2713" : "\u2717";
|
|
1615
1709
|
const stepContent = [
|
|
1616
1710
|
`### Step ${step.stepNumber}: ${step.action}`,
|
|
@@ -1620,7 +1714,7 @@ var StorageService = class {
|
|
|
1620
1714
|
step.screenshotPath ? `- **Screenshot:** [step-${String(step.stepNumber).padStart(3, "0")}.png](screenshots/step-${String(step.stepNumber).padStart(3, "0")}.png)` : "",
|
|
1621
1715
|
""
|
|
1622
1716
|
].filter(Boolean).join("\n");
|
|
1623
|
-
|
|
1717
|
+
fs6.appendFileSync(resultsPath, stepContent + "\n", "utf-8");
|
|
1624
1718
|
logger6.debug("Appended step to results", { sessionId, stepNumber: step.stepNumber });
|
|
1625
1719
|
const metadata = this.loadSessionMetadata(sessionId);
|
|
1626
1720
|
if (metadata) {
|
|
@@ -1635,9 +1729,9 @@ var StorageService = class {
|
|
|
1635
1729
|
finalizeResults(params) {
|
|
1636
1730
|
const { sessionId, status, summary } = params;
|
|
1637
1731
|
const logger6 = getLogger();
|
|
1638
|
-
const sessionDir =
|
|
1639
|
-
const resultsPath =
|
|
1640
|
-
if (!
|
|
1732
|
+
const sessionDir = path11.join(this.sessionsDir, sessionId);
|
|
1733
|
+
const resultsPath = path11.join(sessionDir, "results.md");
|
|
1734
|
+
if (!fs6.existsSync(resultsPath)) {
|
|
1641
1735
|
logger6.warn("Results file not found for finalization", { sessionId });
|
|
1642
1736
|
return;
|
|
1643
1737
|
}
|
|
@@ -1660,7 +1754,7 @@ var StorageService = class {
|
|
|
1660
1754
|
"",
|
|
1661
1755
|
summary ? summary : ""
|
|
1662
1756
|
].join("\n");
|
|
1663
|
-
|
|
1757
|
+
fs6.appendFileSync(resultsPath, footer, "utf-8");
|
|
1664
1758
|
logger6.debug("Finalized results.md", { sessionId, status });
|
|
1665
1759
|
if (metadata) {
|
|
1666
1760
|
metadata.durationMs = durationMs;
|
|
@@ -1718,9 +1812,9 @@ var StorageService = class {
|
|
|
1718
1812
|
}
|
|
1719
1813
|
const sessionDate = new Date(metadata.startTime);
|
|
1720
1814
|
if (sessionDate < cutoffDate) {
|
|
1721
|
-
const sessionDir =
|
|
1815
|
+
const sessionDir = path11.join(this.sessionsDir, sessionId);
|
|
1722
1816
|
try {
|
|
1723
|
-
|
|
1817
|
+
fs6.rmSync(sessionDir, { recursive: true, force: true });
|
|
1724
1818
|
deletedCount++;
|
|
1725
1819
|
logger6.info("Deleted old session", {
|
|
1726
1820
|
sessionId,
|
|
@@ -1748,7 +1842,7 @@ var StorageService = class {
|
|
|
1748
1842
|
* @returns Session directory path.
|
|
1749
1843
|
*/
|
|
1750
1844
|
getSessionPath(sessionId) {
|
|
1751
|
-
return
|
|
1845
|
+
return path11.join(this.sessionsDir, sessionId);
|
|
1752
1846
|
}
|
|
1753
1847
|
/**
|
|
1754
1848
|
* Delete a specific session.
|
|
@@ -1757,20 +1851,20 @@ var StorageService = class {
|
|
|
1757
1851
|
*/
|
|
1758
1852
|
deleteSession(sessionId) {
|
|
1759
1853
|
const logger6 = getLogger();
|
|
1760
|
-
const sessionDir =
|
|
1761
|
-
if (!
|
|
1854
|
+
const sessionDir = path11.join(this.sessionsDir, sessionId);
|
|
1855
|
+
if (!fs6.existsSync(sessionDir)) {
|
|
1762
1856
|
logger6.warn("Session not found for deletion", { sessionId });
|
|
1763
1857
|
return false;
|
|
1764
1858
|
}
|
|
1765
1859
|
try {
|
|
1766
1860
|
const currentId = this.getCurrentSessionId();
|
|
1767
1861
|
if (currentId === sessionId) {
|
|
1768
|
-
const currentPath =
|
|
1769
|
-
if (
|
|
1770
|
-
|
|
1862
|
+
const currentPath = path11.join(this.sessionsDir, "current");
|
|
1863
|
+
if (fs6.existsSync(currentPath)) {
|
|
1864
|
+
fs6.unlinkSync(currentPath);
|
|
1771
1865
|
}
|
|
1772
1866
|
}
|
|
1773
|
-
|
|
1867
|
+
fs6.rmSync(sessionDir, { recursive: true, force: true });
|
|
1774
1868
|
logger6.info("Deleted session", { sessionId });
|
|
1775
1869
|
return true;
|
|
1776
1870
|
} catch (error) {
|
|
@@ -1799,19 +1893,19 @@ var RunResultStorageService = class {
|
|
|
1799
1893
|
constructor() {
|
|
1800
1894
|
const storageService = getStorageService();
|
|
1801
1895
|
const dataDir = storageService.getDataDir();
|
|
1802
|
-
this.runResultsDir =
|
|
1803
|
-
this.testScriptsDir =
|
|
1896
|
+
this.runResultsDir = path11.join(dataDir, "run-results");
|
|
1897
|
+
this.testScriptsDir = path11.join(dataDir, "test-scripts");
|
|
1804
1898
|
this.ensureDirectories();
|
|
1805
1899
|
}
|
|
1806
1900
|
/**
|
|
1807
1901
|
* Ensure storage directories exist.
|
|
1808
1902
|
*/
|
|
1809
1903
|
ensureDirectories() {
|
|
1810
|
-
if (!
|
|
1811
|
-
|
|
1904
|
+
if (!fs6.existsSync(this.runResultsDir)) {
|
|
1905
|
+
fs6.mkdirSync(this.runResultsDir, { recursive: true });
|
|
1812
1906
|
}
|
|
1813
|
-
if (!
|
|
1814
|
-
|
|
1907
|
+
if (!fs6.existsSync(this.testScriptsDir)) {
|
|
1908
|
+
fs6.mkdirSync(this.testScriptsDir, { recursive: true });
|
|
1815
1909
|
}
|
|
1816
1910
|
}
|
|
1817
1911
|
// ========================================
|
|
@@ -1822,11 +1916,11 @@ var RunResultStorageService = class {
|
|
|
1822
1916
|
*/
|
|
1823
1917
|
listRunResults() {
|
|
1824
1918
|
try {
|
|
1825
|
-
const files =
|
|
1919
|
+
const files = fs6.readdirSync(this.runResultsDir).filter((f) => f.endsWith(".json"));
|
|
1826
1920
|
const results = [];
|
|
1827
1921
|
for (const file of files) {
|
|
1828
1922
|
try {
|
|
1829
|
-
const content =
|
|
1923
|
+
const content = fs6.readFileSync(path11.join(this.runResultsDir, file), "utf-8");
|
|
1830
1924
|
results.push(JSON.parse(content));
|
|
1831
1925
|
} catch {
|
|
1832
1926
|
logger3.warn("Failed to read run result file", { file });
|
|
@@ -1841,12 +1935,12 @@ var RunResultStorageService = class {
|
|
|
1841
1935
|
* Get a run result by ID.
|
|
1842
1936
|
*/
|
|
1843
1937
|
getRunResult(runId) {
|
|
1844
|
-
const filePath =
|
|
1845
|
-
if (!
|
|
1938
|
+
const filePath = path11.join(this.runResultsDir, `${runId}.json`);
|
|
1939
|
+
if (!fs6.existsSync(filePath)) {
|
|
1846
1940
|
return void 0;
|
|
1847
1941
|
}
|
|
1848
1942
|
try {
|
|
1849
|
-
const content =
|
|
1943
|
+
const content = fs6.readFileSync(filePath, "utf-8");
|
|
1850
1944
|
return JSON.parse(content);
|
|
1851
1945
|
} catch {
|
|
1852
1946
|
return void 0;
|
|
@@ -1856,8 +1950,8 @@ var RunResultStorageService = class {
|
|
|
1856
1950
|
* Save a run result.
|
|
1857
1951
|
*/
|
|
1858
1952
|
saveRunResult(result) {
|
|
1859
|
-
const filePath =
|
|
1860
|
-
|
|
1953
|
+
const filePath = path11.join(this.runResultsDir, `${result.id}.json`);
|
|
1954
|
+
fs6.writeFileSync(filePath, JSON.stringify(result, null, 2));
|
|
1861
1955
|
}
|
|
1862
1956
|
/**
|
|
1863
1957
|
* Create a new run result.
|
|
@@ -1905,11 +1999,11 @@ var RunResultStorageService = class {
|
|
|
1905
1999
|
*/
|
|
1906
2000
|
listTestScripts() {
|
|
1907
2001
|
try {
|
|
1908
|
-
const files =
|
|
2002
|
+
const files = fs6.readdirSync(this.testScriptsDir).filter((f) => f.endsWith(".json"));
|
|
1909
2003
|
const scripts = [];
|
|
1910
2004
|
for (const file of files) {
|
|
1911
2005
|
try {
|
|
1912
|
-
const content =
|
|
2006
|
+
const content = fs6.readFileSync(path11.join(this.testScriptsDir, file), "utf-8");
|
|
1913
2007
|
scripts.push(JSON.parse(content));
|
|
1914
2008
|
} catch {
|
|
1915
2009
|
logger3.warn("Failed to read test script file", { file });
|
|
@@ -1924,12 +2018,12 @@ var RunResultStorageService = class {
|
|
|
1924
2018
|
* Get a test script by ID.
|
|
1925
2019
|
*/
|
|
1926
2020
|
getTestScript(testScriptId) {
|
|
1927
|
-
const filePath =
|
|
1928
|
-
if (!
|
|
2021
|
+
const filePath = path11.join(this.testScriptsDir, `${testScriptId}.json`);
|
|
2022
|
+
if (!fs6.existsSync(filePath)) {
|
|
1929
2023
|
return void 0;
|
|
1930
2024
|
}
|
|
1931
2025
|
try {
|
|
1932
|
-
const content =
|
|
2026
|
+
const content = fs6.readFileSync(filePath, "utf-8");
|
|
1933
2027
|
return JSON.parse(content);
|
|
1934
2028
|
} catch {
|
|
1935
2029
|
return void 0;
|
|
@@ -1939,8 +2033,8 @@ var RunResultStorageService = class {
|
|
|
1939
2033
|
* Save a test script.
|
|
1940
2034
|
*/
|
|
1941
2035
|
saveTestScript(script) {
|
|
1942
|
-
const filePath =
|
|
1943
|
-
|
|
2036
|
+
const filePath = path11.join(this.testScriptsDir, `${script.id}.json`);
|
|
2037
|
+
fs6.writeFileSync(filePath, JSON.stringify(script, null, 2));
|
|
1944
2038
|
}
|
|
1945
2039
|
/**
|
|
1946
2040
|
* Create a new test script.
|
|
@@ -2190,13 +2284,13 @@ var PREFERENCES_SCHEMA = {
|
|
|
2190
2284
|
|
|
2191
2285
|
// packages/mcps/src/shared/llm-env-service.ts
|
|
2192
2286
|
function resolveLlmEnvOverrides(dataDirOverride2) {
|
|
2193
|
-
const filePath =
|
|
2287
|
+
const filePath = path11.join(getDataDir(), PREFERENCES_FILE_NAME);
|
|
2194
2288
|
let block;
|
|
2195
2289
|
try {
|
|
2196
|
-
if (!
|
|
2290
|
+
if (!fs6.existsSync(filePath)) {
|
|
2197
2291
|
return {};
|
|
2198
2292
|
}
|
|
2199
|
-
const raw = JSON.parse(
|
|
2293
|
+
const raw = JSON.parse(fs6.readFileSync(filePath, "utf-8"));
|
|
2200
2294
|
block = raw[LLM_ENV_PREFERENCE_KEY];
|
|
2201
2295
|
} catch {
|
|
2202
2296
|
return {};
|
|
@@ -2404,13 +2498,13 @@ var MODIFY_LOCK_STALE_MS = 5e3;
|
|
|
2404
2498
|
|
|
2405
2499
|
// packages/mcps/src/mcp/local/services/local-execution-lock.ts
|
|
2406
2500
|
function lockFilePath() {
|
|
2407
|
-
return
|
|
2501
|
+
return path11.join(getDataDir(), LOCK_FILE_NAME);
|
|
2408
2502
|
}
|
|
2409
2503
|
function modifyLockPath() {
|
|
2410
2504
|
return lockFilePath() + MODIFY_LOCK_SUFFIX;
|
|
2411
2505
|
}
|
|
2412
2506
|
function normalizeCwd(cwd) {
|
|
2413
|
-
const resolved =
|
|
2507
|
+
const resolved = path11.resolve(cwd);
|
|
2414
2508
|
return os4.platform() === "win32" ? resolved.toLowerCase() : resolved;
|
|
2415
2509
|
}
|
|
2416
2510
|
function pidIsAlive(pid) {
|
|
@@ -2426,7 +2520,7 @@ function pidIsAlive(pid) {
|
|
|
2426
2520
|
}
|
|
2427
2521
|
async function readState() {
|
|
2428
2522
|
try {
|
|
2429
|
-
const raw = await
|
|
2523
|
+
const raw = await fs10.readFile(lockFilePath(), "utf-8");
|
|
2430
2524
|
return JSON.parse(raw);
|
|
2431
2525
|
} catch (error) {
|
|
2432
2526
|
if (error.code === "ENOENT") return null;
|
|
@@ -2434,28 +2528,28 @@ async function readState() {
|
|
|
2434
2528
|
}
|
|
2435
2529
|
}
|
|
2436
2530
|
async function writeState(state2) {
|
|
2437
|
-
await
|
|
2531
|
+
await fs10.writeFile(lockFilePath(), JSON.stringify(state2, null, 2), "utf-8");
|
|
2438
2532
|
}
|
|
2439
2533
|
async function deleteStateFile() {
|
|
2440
2534
|
try {
|
|
2441
|
-
await
|
|
2535
|
+
await fs10.unlink(lockFilePath());
|
|
2442
2536
|
} catch (error) {
|
|
2443
2537
|
if (error.code !== "ENOENT") throw error;
|
|
2444
2538
|
}
|
|
2445
2539
|
}
|
|
2446
2540
|
async function withModifyLock(fn) {
|
|
2447
|
-
await
|
|
2541
|
+
await fs10.mkdir(path11.dirname(modifyLockPath()), { recursive: true });
|
|
2448
2542
|
const modifyPath = modifyLockPath();
|
|
2449
2543
|
let fileHandle = null;
|
|
2450
2544
|
while (fileHandle === null) {
|
|
2451
2545
|
try {
|
|
2452
|
-
fileHandle = await
|
|
2546
|
+
fileHandle = await fs10.open(modifyPath, "wx");
|
|
2453
2547
|
} catch (error) {
|
|
2454
2548
|
if (error.code !== "EEXIST") throw error;
|
|
2455
2549
|
try {
|
|
2456
|
-
const stat3 = await
|
|
2550
|
+
const stat3 = await fs10.stat(modifyPath);
|
|
2457
2551
|
if (Date.now() - stat3.mtimeMs > MODIFY_LOCK_STALE_MS) {
|
|
2458
|
-
await
|
|
2552
|
+
await fs10.unlink(modifyPath).catch(() => void 0);
|
|
2459
2553
|
continue;
|
|
2460
2554
|
}
|
|
2461
2555
|
} catch {
|
|
@@ -2468,7 +2562,7 @@ async function withModifyLock(fn) {
|
|
|
2468
2562
|
return await fn();
|
|
2469
2563
|
} finally {
|
|
2470
2564
|
await fileHandle.close().catch(() => void 0);
|
|
2471
|
-
await
|
|
2565
|
+
await fs10.unlink(modifyPath).catch(() => void 0);
|
|
2472
2566
|
}
|
|
2473
2567
|
}
|
|
2474
2568
|
async function tryAcquireOnce(params) {
|
|
@@ -2607,12 +2701,12 @@ function extractStudioCloudRefs(studioReturnedResult) {
|
|
|
2607
2701
|
return refs;
|
|
2608
2702
|
}
|
|
2609
2703
|
async function readCloudRefsFile(inputFilePath) {
|
|
2610
|
-
const cloudRefsPath =
|
|
2611
|
-
|
|
2612
|
-
`cloudrefs_${
|
|
2704
|
+
const cloudRefsPath = path11.join(
|
|
2705
|
+
path11.dirname(inputFilePath),
|
|
2706
|
+
`cloudrefs_${path11.basename(inputFilePath)}`
|
|
2613
2707
|
);
|
|
2614
2708
|
try {
|
|
2615
|
-
return JSON.parse(await
|
|
2709
|
+
return JSON.parse(await fs10.readFile(cloudRefsPath, "utf-8"));
|
|
2616
2710
|
} catch {
|
|
2617
2711
|
return void 0;
|
|
2618
2712
|
}
|
|
@@ -2631,15 +2725,15 @@ function getAuthenticatedUserId() {
|
|
|
2631
2725
|
}
|
|
2632
2726
|
async function findPackageJsonAsync() {
|
|
2633
2727
|
const currentFileUrl = import.meta.url;
|
|
2634
|
-
const currentDir =
|
|
2728
|
+
const currentDir = path11.dirname(fileURLToPath(currentFileUrl));
|
|
2635
2729
|
const candidatePaths = [
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2730
|
+
path11.resolve(currentDir, "../../../package.json"),
|
|
2731
|
+
path11.resolve(currentDir, "../package.json"),
|
|
2732
|
+
path11.resolve(currentDir, "../../package.json")
|
|
2639
2733
|
];
|
|
2640
2734
|
for (const candidatePath of candidatePaths) {
|
|
2641
2735
|
try {
|
|
2642
|
-
const packageJsonRaw = await
|
|
2736
|
+
const packageJsonRaw = await fs10.readFile(candidatePath, "utf-8");
|
|
2643
2737
|
const packageJson = JSON.parse(packageJsonRaw);
|
|
2644
2738
|
if (packageJson.name === "@muggleai/works" && packageJson.version && packageJson.muggleConfig?.electronAppVersion) {
|
|
2645
2739
|
return {
|
|
@@ -2685,20 +2779,20 @@ function buildStudioAuthContent() {
|
|
|
2685
2779
|
}
|
|
2686
2780
|
async function ensureTempDir() {
|
|
2687
2781
|
const config = getConfig();
|
|
2688
|
-
const tempDir =
|
|
2689
|
-
await
|
|
2782
|
+
const tempDir = path11.join(config.localQa.dataDir, "temp");
|
|
2783
|
+
await fs10.mkdir(tempDir, { recursive: true });
|
|
2690
2784
|
return tempDir;
|
|
2691
2785
|
}
|
|
2692
2786
|
async function writeTempFile(params) {
|
|
2693
2787
|
const tempDir = await ensureTempDir();
|
|
2694
|
-
const filePath =
|
|
2695
|
-
await
|
|
2788
|
+
const filePath = path11.join(tempDir, params.filename);
|
|
2789
|
+
await fs10.writeFile(filePath, JSON.stringify(params.data, null, 2));
|
|
2696
2790
|
return filePath;
|
|
2697
2791
|
}
|
|
2698
2792
|
async function cleanupTempFiles(params) {
|
|
2699
2793
|
for (const filePath of params.filePaths) {
|
|
2700
2794
|
try {
|
|
2701
|
-
await
|
|
2795
|
+
await fs10.unlink(filePath);
|
|
2702
2796
|
} catch {
|
|
2703
2797
|
}
|
|
2704
2798
|
}
|
|
@@ -2706,12 +2800,12 @@ async function cleanupTempFiles(params) {
|
|
|
2706
2800
|
async function moveResultsToArtifacts(params) {
|
|
2707
2801
|
const storageService = getStorageService();
|
|
2708
2802
|
const sessionsDir = storageService.getSessionsDir();
|
|
2709
|
-
const artifactsDir =
|
|
2710
|
-
const actionScriptPath =
|
|
2711
|
-
await
|
|
2712
|
-
await
|
|
2803
|
+
const artifactsDir = path11.join(sessionsDir, params.runId);
|
|
2804
|
+
const actionScriptPath = path11.join(artifactsDir, "action-script.json");
|
|
2805
|
+
await fs10.mkdir(artifactsDir, { recursive: true });
|
|
2806
|
+
await fs10.copyFile(params.generatedScriptPath, actionScriptPath);
|
|
2713
2807
|
try {
|
|
2714
|
-
await
|
|
2808
|
+
await fs10.unlink(params.generatedScriptPath);
|
|
2715
2809
|
} catch {
|
|
2716
2810
|
}
|
|
2717
2811
|
return artifactsDir;
|
|
@@ -2719,13 +2813,13 @@ async function moveResultsToArtifacts(params) {
|
|
|
2719
2813
|
async function writeExecutionLogs(params) {
|
|
2720
2814
|
const storageService = getStorageService();
|
|
2721
2815
|
const sessionsDir = storageService.getSessionsDir();
|
|
2722
|
-
const artifactsDir =
|
|
2723
|
-
await
|
|
2724
|
-
const stdoutPath =
|
|
2725
|
-
const stderrPath =
|
|
2816
|
+
const artifactsDir = path11.join(sessionsDir, params.runId);
|
|
2817
|
+
await fs10.mkdir(artifactsDir, { recursive: true });
|
|
2818
|
+
const stdoutPath = path11.join(artifactsDir, "stdout.log");
|
|
2819
|
+
const stderrPath = path11.join(artifactsDir, "stderr.log");
|
|
2726
2820
|
await Promise.all([
|
|
2727
|
-
|
|
2728
|
-
|
|
2821
|
+
fs10.writeFile(stdoutPath, params.stdout, "utf-8"),
|
|
2822
|
+
fs10.writeFile(stderrPath, params.stderr, "utf-8")
|
|
2729
2823
|
]);
|
|
2730
2824
|
logger4.info("Wrote execution logs to artifacts directory", {
|
|
2731
2825
|
runId: params.runId,
|
|
@@ -2735,10 +2829,10 @@ async function writeExecutionLogs(params) {
|
|
|
2735
2829
|
async function preserveElectronRuntimeArtifacts(params) {
|
|
2736
2830
|
try {
|
|
2737
2831
|
const tempDir = await ensureTempDir();
|
|
2738
|
-
const markerPath =
|
|
2832
|
+
const markerPath = path11.join(tempDir, `${params.runId}_runtime_dir.txt`);
|
|
2739
2833
|
let runtimeDir = null;
|
|
2740
2834
|
try {
|
|
2741
|
-
const marker = await
|
|
2835
|
+
const marker = await fs10.readFile(markerPath, "utf-8");
|
|
2742
2836
|
const trimmed = marker.trim();
|
|
2743
2837
|
if (trimmed.length > 0) runtimeDir = trimmed;
|
|
2744
2838
|
} catch (markerReadError) {
|
|
@@ -2760,25 +2854,25 @@ async function preserveElectronRuntimeArtifacts(params) {
|
|
|
2760
2854
|
return;
|
|
2761
2855
|
}
|
|
2762
2856
|
try {
|
|
2763
|
-
await
|
|
2857
|
+
await fs10.access(runtimeDir);
|
|
2764
2858
|
} catch {
|
|
2765
2859
|
logger4.warn("Electron runtime dir referenced but missing on disk", {
|
|
2766
2860
|
runId: params.runId,
|
|
2767
2861
|
runtimeDir
|
|
2768
2862
|
});
|
|
2769
|
-
await
|
|
2863
|
+
await fs10.unlink(markerPath).catch(() => void 0);
|
|
2770
2864
|
return;
|
|
2771
2865
|
}
|
|
2772
2866
|
const storage = getStorageService();
|
|
2773
|
-
const destDir =
|
|
2774
|
-
await
|
|
2775
|
-
await
|
|
2867
|
+
const destDir = path11.join(storage.getSessionsDir(), params.runId, "electron-runtime");
|
|
2868
|
+
await fs10.mkdir(destDir, { recursive: true });
|
|
2869
|
+
await fs10.cp(runtimeDir, destDir, { recursive: true });
|
|
2776
2870
|
logger4.info("Preserved Electron runtime artifacts", {
|
|
2777
2871
|
runId: params.runId,
|
|
2778
2872
|
sourceDir: runtimeDir,
|
|
2779
2873
|
destDir
|
|
2780
2874
|
});
|
|
2781
|
-
await
|
|
2875
|
+
await fs10.unlink(markerPath).catch(() => void 0);
|
|
2782
2876
|
} catch (preserveError) {
|
|
2783
2877
|
logger4.warn("Failed to preserve Electron runtime artifacts", {
|
|
2784
2878
|
runId: params.runId,
|
|
@@ -2787,14 +2881,14 @@ async function preserveElectronRuntimeArtifacts(params) {
|
|
|
2787
2881
|
}
|
|
2788
2882
|
}
|
|
2789
2883
|
async function scanForRuntimeDirByMtime(params) {
|
|
2790
|
-
const runtimeRoot =
|
|
2884
|
+
const runtimeRoot = path11.join(params.electronCwd, "user_data", "runtime");
|
|
2791
2885
|
try {
|
|
2792
|
-
const entries = await
|
|
2886
|
+
const entries = await fs10.readdir(runtimeRoot, { withFileTypes: true });
|
|
2793
2887
|
let bestCandidate = null;
|
|
2794
2888
|
for (const entry of entries) {
|
|
2795
2889
|
if (!entry.isDirectory()) continue;
|
|
2796
|
-
const fullPath =
|
|
2797
|
-
const stat3 = await
|
|
2890
|
+
const fullPath = path11.join(runtimeRoot, entry.name);
|
|
2891
|
+
const stat3 = await fs10.stat(fullPath);
|
|
2798
2892
|
if (stat3.mtimeMs < params.spawnAtMs) continue;
|
|
2799
2893
|
if (bestCandidate === null || stat3.mtimeMs > bestCandidate.mtimeMs) {
|
|
2800
2894
|
bestCandidate = { path: fullPath, mtimeMs: stat3.mtimeMs };
|
|
@@ -2850,7 +2944,7 @@ async function executeElectronAppAsync(params) {
|
|
|
2850
2944
|
spawnArgs,
|
|
2851
2945
|
llmEnvOverrideNames
|
|
2852
2946
|
});
|
|
2853
|
-
const electronCwd =
|
|
2947
|
+
const electronCwd = path11.dirname(electronAppPath);
|
|
2854
2948
|
const child = spawn(electronAppPath, spawnArgs, {
|
|
2855
2949
|
stdio: ["ignore", "pipe", "pipe"],
|
|
2856
2950
|
env: electronEnv,
|
|
@@ -2865,7 +2959,7 @@ async function executeElectronAppAsync(params) {
|
|
|
2865
2959
|
capturedStderr: ""
|
|
2866
2960
|
};
|
|
2867
2961
|
activeProcesses.set(params.runId, processInfo);
|
|
2868
|
-
return await new Promise((
|
|
2962
|
+
return await new Promise((resolve6, reject) => {
|
|
2869
2963
|
let settled = false;
|
|
2870
2964
|
const finalize = (result) => {
|
|
2871
2965
|
if (settled) {
|
|
@@ -2877,7 +2971,7 @@ async function executeElectronAppAsync(params) {
|
|
|
2877
2971
|
}
|
|
2878
2972
|
activeProcesses.delete(params.runId);
|
|
2879
2973
|
if (result.ok) {
|
|
2880
|
-
|
|
2974
|
+
resolve6(result.payload);
|
|
2881
2975
|
} else {
|
|
2882
2976
|
reject(result.payload);
|
|
2883
2977
|
}
|
|
@@ -3032,17 +3126,17 @@ ${executionResult.stdout}
|
|
|
3032
3126
|
STDERR:
|
|
3033
3127
|
${executionResult.stderr}`;
|
|
3034
3128
|
const sessionsDir = getStorageService().getSessionsDir();
|
|
3035
|
-
const artifactsDir2 =
|
|
3036
|
-
const generatedScriptPath2 =
|
|
3037
|
-
|
|
3038
|
-
`gen_${
|
|
3129
|
+
const artifactsDir2 = path11.join(sessionsDir, runId);
|
|
3130
|
+
const generatedScriptPath2 = path11.join(
|
|
3131
|
+
path11.dirname(inputFilePath),
|
|
3132
|
+
`gen_${path11.basename(inputFilePath)}`
|
|
3039
3133
|
);
|
|
3040
3134
|
let failedStudioResult;
|
|
3041
3135
|
try {
|
|
3042
|
-
const failedScriptRaw = await
|
|
3136
|
+
const failedScriptRaw = await fs10.readFile(generatedScriptPath2, "utf-8");
|
|
3043
3137
|
failedStudioResult = JSON.parse(failedScriptRaw);
|
|
3044
|
-
await
|
|
3045
|
-
await
|
|
3138
|
+
await fs10.copyFile(generatedScriptPath2, path11.join(artifactsDir2, "action-script.json"));
|
|
3139
|
+
await fs10.unlink(generatedScriptPath2).catch(() => {
|
|
3046
3140
|
});
|
|
3047
3141
|
} catch {
|
|
3048
3142
|
}
|
|
@@ -3071,11 +3165,11 @@ ${executionResult.stderr}`;
|
|
|
3071
3165
|
errorMessage: failureMessage
|
|
3072
3166
|
};
|
|
3073
3167
|
}
|
|
3074
|
-
const generatedScriptPath =
|
|
3075
|
-
|
|
3076
|
-
`gen_${
|
|
3168
|
+
const generatedScriptPath = path11.join(
|
|
3169
|
+
path11.dirname(inputFilePath),
|
|
3170
|
+
`gen_${path11.basename(inputFilePath)}`
|
|
3077
3171
|
);
|
|
3078
|
-
const generatedScriptRaw = await
|
|
3172
|
+
const generatedScriptRaw = await fs10.readFile(generatedScriptPath, "utf-8");
|
|
3079
3173
|
const generatedScript = JSON.parse(generatedScriptRaw);
|
|
3080
3174
|
const generatedSteps = generatedScript.steps;
|
|
3081
3175
|
if (!Array.isArray(generatedSteps)) {
|
|
@@ -3218,7 +3312,7 @@ STDOUT:
|
|
|
3218
3312
|
${executionResult.stdout}
|
|
3219
3313
|
STDERR:
|
|
3220
3314
|
${executionResult.stderr}`;
|
|
3221
|
-
const artifactsDir2 =
|
|
3315
|
+
const artifactsDir2 = path11.join(getStorageService().getSessionsDir(), runId);
|
|
3222
3316
|
storage.updateRunResult(runId, {
|
|
3223
3317
|
status: "failed",
|
|
3224
3318
|
executionTimeMs,
|
|
@@ -3236,7 +3330,7 @@ ${executionResult.stderr}`;
|
|
|
3236
3330
|
errorMessage: failureMessage
|
|
3237
3331
|
};
|
|
3238
3332
|
}
|
|
3239
|
-
const artifactsDir =
|
|
3333
|
+
const artifactsDir = path11.join(getStorageService().getSessionsDir(), runId);
|
|
3240
3334
|
const replayStudioResult = await readCloudRefsFile(inputFilePath);
|
|
3241
3335
|
const replayStudioCloudRefs = extractStudioCloudRefs(replayStudioResult);
|
|
3242
3336
|
storage.updateRunResult(runId, {
|
|
@@ -3673,7 +3767,7 @@ var PREFS_FILENAME = "preferences.json";
|
|
|
3673
3767
|
var OAUTH_SESSION_FILENAME = "oauth-session.json";
|
|
3674
3768
|
var RELEASE_MANIFEST_FILENAME = "release-manifest.json";
|
|
3675
3769
|
function getDataDir3() {
|
|
3676
|
-
return
|
|
3770
|
+
return path11.join(os4.homedir(), DATA_DIR_NAME2);
|
|
3677
3771
|
}
|
|
3678
3772
|
|
|
3679
3773
|
var cachedInstallId;
|
|
@@ -3738,9 +3832,9 @@ function isValid2(value) {
|
|
|
3738
3832
|
function readReleaseManifest2() {
|
|
3739
3833
|
if (cachedManifest2 !== void 0)
|
|
3740
3834
|
return cachedManifest2;
|
|
3741
|
-
const
|
|
3835
|
+
const path17 = MANIFEST_PATH2;
|
|
3742
3836
|
try {
|
|
3743
|
-
const raw = readFileSync(
|
|
3837
|
+
const raw = readFileSync(path17, "utf8");
|
|
3744
3838
|
const parsed = JSON.parse(raw);
|
|
3745
3839
|
cachedManifest2 = isValid2(parsed) ? parsed : DEV_MANIFEST2;
|
|
3746
3840
|
return cachedManifest2;
|
|
@@ -4519,17 +4613,17 @@ var PromptServiceClient = class {
|
|
|
4519
4613
|
* @param path - Path to validate.
|
|
4520
4614
|
* @throws GatewayError if path is not allowed.
|
|
4521
4615
|
*/
|
|
4522
|
-
validatePath(
|
|
4523
|
-
const isAllowed = ALLOWED_UPSTREAM_PREFIXES.some((prefix) =>
|
|
4616
|
+
validatePath(path17) {
|
|
4617
|
+
const isAllowed = ALLOWED_UPSTREAM_PREFIXES.some((prefix) => path17.startsWith(prefix));
|
|
4524
4618
|
if (!isAllowed) {
|
|
4525
4619
|
const logger6 = getLogger();
|
|
4526
4620
|
logger6.error("Path not in allowlist", {
|
|
4527
|
-
path:
|
|
4621
|
+
path: path17,
|
|
4528
4622
|
allowedPrefixes: ALLOWED_UPSTREAM_PREFIXES
|
|
4529
4623
|
});
|
|
4530
4624
|
throw new GatewayError({
|
|
4531
4625
|
code: "FORBIDDEN" /* FORBIDDEN */,
|
|
4532
|
-
message: `Path '${
|
|
4626
|
+
message: `Path '${path17}' is not allowed`
|
|
4533
4627
|
});
|
|
4534
4628
|
}
|
|
4535
4629
|
}
|
|
@@ -6582,11 +6676,11 @@ var TELEMETRY_DIR_NAME = "telemetry";
|
|
|
6582
6676
|
var FAILURE_EVENTS_FILE_NAME = "failure-events.jsonl";
|
|
6583
6677
|
function appendFailureEvent(record) {
|
|
6584
6678
|
try {
|
|
6585
|
-
const dir =
|
|
6586
|
-
|
|
6587
|
-
const filePath =
|
|
6679
|
+
const dir = path11.join(getDataDir(), TELEMETRY_DIR_NAME);
|
|
6680
|
+
fs6.mkdirSync(dir, { recursive: true });
|
|
6681
|
+
const filePath = path11.join(dir, FAILURE_EVENTS_FILE_NAME);
|
|
6588
6682
|
const full = { ts: (/* @__PURE__ */ new Date()).toISOString(), ...record };
|
|
6589
|
-
|
|
6683
|
+
fs6.appendFileSync(filePath, `${JSON.stringify(full)}
|
|
6590
6684
|
`, "utf-8");
|
|
6591
6685
|
} catch (error) {
|
|
6592
6686
|
getLogger().warn("Failed to append failure event", {
|
|
@@ -6605,17 +6699,17 @@ var ProjectPreferencesReconcileOutcome = /* @__PURE__ */ ((ProjectPreferencesRec
|
|
|
6605
6699
|
|
|
6606
6700
|
// packages/mcps/src/shared/preferences-service.ts
|
|
6607
6701
|
function getGlobalPreferencesFilePath(dataDirOverride2) {
|
|
6608
|
-
return
|
|
6702
|
+
return path11.join(dataDirOverride2 ?? getDataDir(), PREFERENCES_FILE_NAME);
|
|
6609
6703
|
}
|
|
6610
6704
|
function isFirstRun(dataDirOverride2) {
|
|
6611
|
-
return !
|
|
6705
|
+
return !fs6.existsSync(getGlobalPreferencesFilePath(dataDirOverride2));
|
|
6612
6706
|
}
|
|
6613
6707
|
function readPreferencesFile(filePath) {
|
|
6614
6708
|
try {
|
|
6615
|
-
if (!
|
|
6709
|
+
if (!fs6.existsSync(filePath)) {
|
|
6616
6710
|
return {};
|
|
6617
6711
|
}
|
|
6618
|
-
const raw = JSON.parse(
|
|
6712
|
+
const raw = JSON.parse(fs6.readFileSync(filePath, "utf-8"));
|
|
6619
6713
|
return raw.preferences ?? {};
|
|
6620
6714
|
} catch (error) {
|
|
6621
6715
|
getLogger().warn("Failed to read preferences file", {
|
|
@@ -6631,15 +6725,15 @@ function writePreferencesFile(filePath, prefs) {
|
|
|
6631
6725
|
version: PREFERENCES_VERSION,
|
|
6632
6726
|
preferences: prefs
|
|
6633
6727
|
};
|
|
6634
|
-
|
|
6728
|
+
fs6.writeFileSync(filePath, `${JSON.stringify(file, null, 2)}
|
|
6635
6729
|
`, "utf-8");
|
|
6636
6730
|
}
|
|
6637
6731
|
function readRawPreferencesFile(filePath) {
|
|
6638
6732
|
try {
|
|
6639
|
-
if (!
|
|
6733
|
+
if (!fs6.existsSync(filePath)) {
|
|
6640
6734
|
return {};
|
|
6641
6735
|
}
|
|
6642
|
-
return JSON.parse(
|
|
6736
|
+
return JSON.parse(fs6.readFileSync(filePath, "utf-8"));
|
|
6643
6737
|
} catch {
|
|
6644
6738
|
return {};
|
|
6645
6739
|
}
|
|
@@ -6650,14 +6744,14 @@ function resolvePreferences(dataDirOverride2) {
|
|
|
6650
6744
|
}
|
|
6651
6745
|
function writePreferences2(prefs, dataDirOverride2) {
|
|
6652
6746
|
const dir = dataDirOverride2 ?? getDataDir();
|
|
6653
|
-
|
|
6654
|
-
const filePath =
|
|
6747
|
+
fs6.mkdirSync(dir, { recursive: true });
|
|
6748
|
+
const filePath = path11.join(dir, PREFERENCES_FILE_NAME);
|
|
6655
6749
|
const existing = readPreferencesFile(filePath);
|
|
6656
6750
|
writePreferencesFile(filePath, { ...existing, ...prefs });
|
|
6657
6751
|
}
|
|
6658
6752
|
function resetPreference(key, dataDirOverride2) {
|
|
6659
6753
|
const filePath = getGlobalPreferencesFilePath(dataDirOverride2);
|
|
6660
|
-
if (!
|
|
6754
|
+
if (!fs6.existsSync(filePath)) {
|
|
6661
6755
|
return;
|
|
6662
6756
|
}
|
|
6663
6757
|
if (!key) {
|
|
@@ -6669,7 +6763,7 @@ function resetPreference(key, dataDirOverride2) {
|
|
|
6669
6763
|
writePreferencesFile(filePath, existing);
|
|
6670
6764
|
}
|
|
6671
6765
|
function reconcileProjectPreferences(cwd, dataDirOverride2) {
|
|
6672
|
-
const projectFilePath =
|
|
6766
|
+
const projectFilePath = path11.join(cwd, PREFERENCES_PROJECT_DIR_NAME, PREFERENCES_FILE_NAME);
|
|
6673
6767
|
const projectPreferences = readPreferencesFile(projectFilePath);
|
|
6674
6768
|
const projectKeys = Object.keys(projectPreferences);
|
|
6675
6769
|
if (projectKeys.length === 0) {
|
|
@@ -6714,17 +6808,17 @@ var MUGGLE_HOME_DISPLAY_DIR = "~/.muggle-ai";
|
|
|
6714
6808
|
|
|
6715
6809
|
// packages/mcps/src/shared/cwd-keyed-cache.ts
|
|
6716
6810
|
function resolveHomeFilePath(cache) {
|
|
6717
|
-
return
|
|
6811
|
+
return path11.join(getDataDir(), cache.fileName);
|
|
6718
6812
|
}
|
|
6719
6813
|
function resolveLegacyFilePath(cache, cwd) {
|
|
6720
|
-
return
|
|
6814
|
+
return path11.join(cwd, LEGACY_CACHE_DIR_NAME, cache.fileName);
|
|
6721
6815
|
}
|
|
6722
6816
|
function parseJsonFile(filePath) {
|
|
6723
6817
|
try {
|
|
6724
|
-
if (!
|
|
6818
|
+
if (!fs6.existsSync(filePath)) {
|
|
6725
6819
|
return null;
|
|
6726
6820
|
}
|
|
6727
|
-
return JSON.parse(
|
|
6821
|
+
return JSON.parse(fs6.readFileSync(filePath, "utf-8"));
|
|
6728
6822
|
} catch (error) {
|
|
6729
6823
|
getLogger().warn("Failed to read cache file", {
|
|
6730
6824
|
path: filePath,
|
|
@@ -6738,12 +6832,12 @@ function readHomeEntries(cache) {
|
|
|
6738
6832
|
return parsed?.entries ?? {};
|
|
6739
6833
|
}
|
|
6740
6834
|
function writeHomeEntries(cache, entries) {
|
|
6741
|
-
|
|
6835
|
+
fs6.mkdirSync(getDataDir(), { recursive: true });
|
|
6742
6836
|
const file = {
|
|
6743
6837
|
version: CWD_KEYED_CACHE_VERSION,
|
|
6744
6838
|
entries
|
|
6745
6839
|
};
|
|
6746
|
-
|
|
6840
|
+
fs6.writeFileSync(
|
|
6747
6841
|
resolveHomeFilePath(cache),
|
|
6748
6842
|
`${JSON.stringify(file, null, 2)}
|
|
6749
6843
|
`,
|
|
@@ -6757,7 +6851,7 @@ function readLegacyEntry(cache, cwd) {
|
|
|
6757
6851
|
return parsed?.[cache.legacyEntryKey] ?? null;
|
|
6758
6852
|
}
|
|
6759
6853
|
function readCwdEntry(cache, cwd) {
|
|
6760
|
-
const cwdKey =
|
|
6854
|
+
const cwdKey = path11.resolve(cwd);
|
|
6761
6855
|
const entries = readHomeEntries(cache);
|
|
6762
6856
|
const homeEntry = entries[cwdKey];
|
|
6763
6857
|
if (homeEntry) {
|
|
@@ -6779,18 +6873,18 @@ function readCwdEntry(cache, cwd) {
|
|
|
6779
6873
|
}
|
|
6780
6874
|
function writeCwdEntry(cache, cwd, entry) {
|
|
6781
6875
|
const entries = readHomeEntries(cache);
|
|
6782
|
-
writeHomeEntries(cache, { ...entries, [
|
|
6876
|
+
writeHomeEntries(cache, { ...entries, [path11.resolve(cwd)]: entry });
|
|
6783
6877
|
}
|
|
6784
6878
|
function clearCwdEntry(cache, cwd) {
|
|
6785
6879
|
const entries = readHomeEntries(cache);
|
|
6786
|
-
const cwdKey =
|
|
6880
|
+
const cwdKey = path11.resolve(cwd);
|
|
6787
6881
|
if (cwdKey in entries) {
|
|
6788
6882
|
delete entries[cwdKey];
|
|
6789
6883
|
writeHomeEntries(cache, entries);
|
|
6790
6884
|
}
|
|
6791
6885
|
const legacyFilePath = resolveLegacyFilePath(cache, cwd);
|
|
6792
|
-
if (
|
|
6793
|
-
|
|
6886
|
+
if (fs6.existsSync(legacyFilePath)) {
|
|
6887
|
+
fs6.unlinkSync(legacyFilePath);
|
|
6794
6888
|
}
|
|
6795
6889
|
}
|
|
6796
6890
|
|
|
@@ -6955,7 +7049,7 @@ var runResultGetTool = {
|
|
|
6955
7049
|
const testScript = storage.getTestScript(storedRunResult.testScriptId);
|
|
6956
7050
|
testScriptSteps = testScript?.actionScript?.length;
|
|
6957
7051
|
}
|
|
6958
|
-
if (storedRunResult.artifactsDir &&
|
|
7052
|
+
if (storedRunResult.artifactsDir && fs6.existsSync(storedRunResult.artifactsDir)) {
|
|
6959
7053
|
contentParts.push(
|
|
6960
7054
|
"",
|
|
6961
7055
|
"### Artifacts (view action script + screenshots)",
|
|
@@ -6963,26 +7057,26 @@ var runResultGetTool = {
|
|
|
6963
7057
|
`**Location:** \`${storedRunResult.artifactsDir}\``,
|
|
6964
7058
|
""
|
|
6965
7059
|
);
|
|
6966
|
-
const actionScriptPath =
|
|
6967
|
-
const resultsMdPath =
|
|
6968
|
-
const screenshotsDir =
|
|
6969
|
-
const stdoutLogPath =
|
|
6970
|
-
const stderrLogPath =
|
|
7060
|
+
const actionScriptPath = path11.join(storedRunResult.artifactsDir, "action-script.json");
|
|
7061
|
+
const resultsMdPath = path11.join(storedRunResult.artifactsDir, "results.md");
|
|
7062
|
+
const screenshotsDir = path11.join(storedRunResult.artifactsDir, "screenshots");
|
|
7063
|
+
const stdoutLogPath = path11.join(storedRunResult.artifactsDir, "stdout.log");
|
|
7064
|
+
const stderrLogPath = path11.join(storedRunResult.artifactsDir, "stderr.log");
|
|
6971
7065
|
const artifactItems = [];
|
|
6972
|
-
if (
|
|
7066
|
+
if (fs6.existsSync(actionScriptPath)) {
|
|
6973
7067
|
artifactItems.push("- `action-script.json` \u2014 generated test steps");
|
|
6974
7068
|
}
|
|
6975
|
-
if (
|
|
7069
|
+
if (fs6.existsSync(resultsMdPath)) {
|
|
6976
7070
|
artifactItems.push("- `results.md` \u2014 step-by-step report with screenshot links");
|
|
6977
7071
|
}
|
|
6978
|
-
if (
|
|
6979
|
-
const screenshots =
|
|
7072
|
+
if (fs6.existsSync(screenshotsDir)) {
|
|
7073
|
+
const screenshots = fs6.readdirSync(screenshotsDir).filter((f) => /\.(png|jpg|jpeg|webp)$/i.test(f));
|
|
6980
7074
|
artifactItems.push(`- \`screenshots/\` \u2014 ${screenshots.length} image(s)`);
|
|
6981
7075
|
}
|
|
6982
|
-
if (
|
|
7076
|
+
if (fs6.existsSync(stdoutLogPath)) {
|
|
6983
7077
|
artifactItems.push("- `stdout.log` \u2014 electron-app stdout output");
|
|
6984
7078
|
}
|
|
6985
|
-
if (
|
|
7079
|
+
if (fs6.existsSync(stderrLogPath)) {
|
|
6986
7080
|
artifactItems.push("- `stderr.log` \u2014 electron-app stderr output");
|
|
6987
7081
|
}
|
|
6988
7082
|
if (artifactItems.length > 0) {
|
|
@@ -7633,4 +7727,4 @@ var WATCHER_LIFETIME_SECONDS = {
|
|
|
7633
7727
|
["never" /* Never */]: WATCHER_LIFETIME_UNBOUNDED_SECONDS
|
|
7634
7728
|
};
|
|
7635
7729
|
|
|
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 };
|
|
7730
|
+
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, 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, resolveActiveProfile, resolveActiveReleaseStream, resolveActiveReleaseTagPrefix, resolveElectronAppPathOrNull, resolvePreferences, resolveRuntimeTarget, saveApiKey, saveApiKeyData, saveCredentials, src_exports, startDeviceCodeFlow, toolRequiresAuth, track, validatePreference, verifyFileChecksum, writePreferences2 as writePreferences };
|