react-doctor 0.9.12 → 0.9.13-dev.fa72869

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.
Files changed (52) hide show
  1. package/README.md +34 -1
  2. package/bin/react-doctor.js +1 -9
  3. package/dist/active-run-trace-dlIZeEvb.js +18 -0
  4. package/dist/active-scan-abort-registry-DwG6tSPy.js +28 -0
  5. package/dist/{build-section-divider-BsQvH-7I.js → build-section-divider-DPs8DOje.js} +10 -25
  6. package/dist/{ci-B4x4RjKD.js → ci-DJX0d-zr.js} +13 -12
  7. package/dist/cli.js +121 -41
  8. package/dist/{design-A48PNCf_.js → design-16noMOyv.js} +4 -4
  9. package/dist/{devtools-DPRVRu3S.js → devtools-CC2PAZ85.js} +4 -4
  10. package/dist/{exit-gracefully-Bk531kS-.js → exit-gracefully-CmnLSIyy.js} +15 -9
  11. package/dist/get-east-asian-width-Bv2TD3Xj.js +444 -0
  12. package/dist/{report-error-Pb2uO8EG.js → handle-error-BoWVnsAX.js} +18 -68
  13. package/dist/index.d.ts +53 -42
  14. package/dist/index.js +55119 -54689
  15. package/dist/{inspect-CwH84aSA.js → inspect-CQjmfc6o.js} +44 -33
  16. package/dist/{install-sFN_w425.js → install-BI45HWXE.js} +9 -8
  17. package/dist/{install-doctor-script-DLayXS7q.js → install-doctor-script-Czibd55T.js} +7 -449
  18. package/dist/{install-github-workflow-Goz-KFqb.js → install-github-workflow-DAW5HCoZ.js} +10 -6
  19. package/dist/{install-react-doctor-Bq7dfEBI.js → install-react-doctor-0EPCiZSM.js} +47 -45
  20. package/dist/{run-scan-app-DXBMW54J.js → jsx-runtime-CpHGdrl2.js} +281 -2759
  21. package/dist/path-format-DnHpmJwG.js +9 -0
  22. package/dist/{print-branded-header-D_J8Qdsj.js → print-branded-header-D99_D1jG.js} +4 -4
  23. package/dist/project-analysis-worker.d.ts +1 -0
  24. package/dist/project-analysis-worker.js +51905 -0
  25. package/dist/prompt-runtime-scan-url-BXbCor1e.js +240 -0
  26. package/dist/{read-object-file-Hk79zI91.js → read-object-file-B74hRgMl.js} +4 -4
  27. package/dist/{record-metric-CsQXJewH.js → record-metric-BcJN2xOB.js} +3257 -6019
  28. package/dist/report-error-OirqwZb5.js +64 -0
  29. package/dist/{report-workflow-result-6n_wSqzA.js → report-workflow-result-C4EMosul.js} +5 -5
  30. package/dist/{resolve-scope-DP6rYlNO.js → resolve-scope-CKnF1u7B.js} +8 -10
  31. package/dist/{rules-BnIZ4Fq_.js → rules-D-04wsFx.js} +6 -6
  32. package/dist/run-scan-app-hjGd9Nt9.js +2511 -0
  33. package/dist/runtime-scan/browser-probe.iife.js +855 -0
  34. package/dist/runtime-scan-5ucpiIRF.js +770 -0
  35. package/dist/sanitize-runtime-url-KJQEVCa5.js +76 -0
  36. package/dist/scan-Busv3qJ_.js +47 -0
  37. package/dist/semver-DFtnEmN-.js +3219 -0
  38. package/dist/{should-fail-scan-gate-DzZuTxim.js → should-fail-scan-gate-D1mS86Ff.js} +160 -184
  39. package/dist/{should-skip-prompts-D1GWG2qN.js → should-skip-prompts-DkasjzpQ.js} +4 -4
  40. package/dist/should-use-tui-B5bj9qhm.js +25 -0
  41. package/dist/skills/improve-threejs/SKILL.md +102 -0
  42. package/dist/skills/performance/SKILL.md +113 -0
  43. package/dist/skills/react-doctor/SKILL.md +6 -0
  44. package/dist/{unref-stdin-0a_0uwC6.js → telemetry-runtime-DFNjke5Y.js} +57 -33
  45. package/dist/unref-stdin-SK3WfwxS.js +12 -0
  46. package/dist/{version-Bo5QDp7F.js → version-DKEaWdQZ.js} +4 -4
  47. package/dist/{why-BFYbtnm8.js → why-BP622crq.js} +4 -4
  48. package/dist/with-run-span-B9bjgvks.js +110 -0
  49. package/package.json +9 -10
  50. package/dist/chunk-q7NCDQ7-.js +0 -28
  51. package/dist/lsp.js +0 -81145
  52. package/dist/scan-CnnXz78m.js +0 -53
@@ -1,10 +1,10 @@
1
1
 
2
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="d678e544-bf9c-5a23-bf1c-c11caae57e45")}catch(e){}}();
3
- import { R as CliInputError, S as CI_TRUST_COMPANIES, cn as highlighter, ot as GITHUB_ACTIONS_SETUP_URL, t as recordCount, un as isErrnoException, w as METRIC, wt as SKILL_NAME } from "./record-metric-CsQXJewH.js";
4
- import { A as packageHasNestedRecordKey, D as getPackageJsonPath, E as ensureTrailingNewline, I as writeJsonFile, L as cliLogger, M as readPackageJson, N as resolveGitPath, O as isRecord, P as runGit, S as REACT_DOCTOR_COMMAND, T as VITE_PLUS_HOOKS_PATH, _ as LEFTHOOK_CONFIG_FILES, a as installReactDoctorScriptStep, b as OVERCOMMIT_CONFIG_FILE, c as spinner, g as HUSKY_HOOKS_PATH, h as HOOK_RELATIVE_PATH, j as packageHasRecordKey, k as packageHasDependency, m as HOOK_FILE_NAME, n as findNearestPackageDirectory, r as hasDoctorDependency, t as DOCTOR_PACKAGE_NAME, v as LEGACY_HOOK_RUNNER_RELATIVE_PATH, x as PRE_COMMIT_CONFIG_FILE, y as NON_BLOCKING_REACT_DOCTOR_COMMAND } from "./install-doctor-script-DLayXS7q.js";
5
- import { a as readReactDoctorWorkflow, c as workflowUsesV1Action, d as detectDefaultBranch, l as prompts, n as getReactDoctorWorkflowPath, o as upgradeReactDoctorWorkflowInPlace, r as installReactDoctorWorkflow } from "./install-github-workflow-Goz-KFqb.js";
6
- import { t as shouldSkipPrompts } from "./should-skip-prompts-D1GWG2qN.js";
7
- import { a as recordGate, c as ACTION_UPGRADE_EVENT, d as INSTALL_AGENTS_PREFERENCE_ID, h as detectAvailableAgents, i as readPreference, l as CI_PITCH_EVENT, m as computeDefaultSelectedAgents, n as openUrl, r as isGatePending, s as writePreference, t as reportWorkflowResult } from "./report-workflow-result-6n_wSqzA.js";
2
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="d43042c4-c766-54b9-a30f-944a55426467")}catch(e){}}();
3
+ import { C as CI_TRUST_COMPANIES, Kt as highlighter, T as METRIC, br as isErrnoException, cr as GITHUB_ACTIONS_SETUP_URL, gr as SKILL_NAME, t as recordCount, z as CliInputError } from "./record-metric-BcJN2xOB.js";
4
+ import { C as isRecord, D as readPackageJson, E as packageHasRecordKey, M as cliLogger, O as resolveGitPath, S as getPackageJsonPath, T as packageHasNestedRecordKey, _ as REACT_DOCTOR_COMMAND, a as installReactDoctorScriptStep, b as VITE_PLUS_HOOKS_PATH, c as spinner, d as HUSKY_HOOKS_PATH, f as LEFTHOOK_CONFIG_FILES, g as PRE_COMMIT_CONFIG_FILE, h as OVERCOMMIT_CONFIG_FILE, j as writeJsonFile, k as runGit, l as HOOK_FILE_NAME, m as NON_BLOCKING_REACT_DOCTOR_COMMAND, n as findNearestPackageDirectory, p as LEGACY_HOOK_RUNNER_RELATIVE_PATH, r as hasDoctorDependency, t as DOCTOR_PACKAGE_NAME, u as HOOK_RELATIVE_PATH, w as packageHasDependency, x as ensureTrailingNewline } from "./install-doctor-script-Czibd55T.js";
5
+ import { a as readReactDoctorWorkflow, c as workflowUsesV1Action, d as detectDefaultBranch, l as prompts, n as getReactDoctorWorkflowPath, o as upgradeReactDoctorWorkflowInPlace, r as installReactDoctorWorkflow } from "./install-github-workflow-DAW5HCoZ.js";
6
+ import { t as shouldSkipPrompts } from "./should-skip-prompts-DkasjzpQ.js";
7
+ import { a as recordGate, c as ACTION_UPGRADE_EVENT, d as INSTALL_AGENTS_PREFERENCE_ID, h as detectAvailableAgents, i as readPreference, l as CI_PITCH_EVENT, m as computeDefaultSelectedAgents, n as openUrl, r as isGatePending, s as writePreference, t as reportWorkflowResult } from "./report-workflow-result-C4EMosul.js";
8
8
  import { execFile } from "node:child_process";
9
9
  import * as path$1 from "node:path";
10
10
  import * as fs$1 from "node:fs";
@@ -124,10 +124,10 @@ const CLAUDE_HOOK_COMMAND = "node \"$CLAUDE_PROJECT_DIR/.claude/hooks/react-doct
124
124
  const CURSOR_HOOKS_RELATIVE_PATH = ".cursor/hooks.json";
125
125
  const CURSOR_HOOK_RELATIVE_PATH = ".cursor/hooks/react-doctor.mjs";
126
126
  const CURSOR_HOOK_COMMAND = "node .cursor/hooks/react-doctor.mjs";
127
- const CURSOR_HOOK_MATCHER = "Write|Edit|MultiEdit|ApplyPatch";
128
127
  const CURSOR_HOOKS_SCHEMA_VERSION = 1;
129
128
  const LEGACY_HOOK_SCRIPT_PATHS = [".claude/hooks/react-doctor.sh", ".cursor/hooks/react-doctor.sh"];
130
129
  const isLegacyHookCommand = (command) => typeof command === "string" && LEGACY_HOOK_SCRIPT_PATHS.some((legacyPath) => command.includes(legacyPath));
130
+ const isManagedHookCommand = (command, installedCommand) => command === installedCommand || isLegacyHookCommand(command);
131
131
  const isSupportedAgent = (agent) => agent === CLAUDE_AGENT || agent === CURSOR_AGENT;
132
132
  const readJsonFile = (filePath, fallback) => {
133
133
  if (!fs$1.existsSync(filePath)) return fallback;
@@ -147,10 +147,12 @@ const readJsonFileSafely = (filePath, fallback) => {
147
147
  return fallback;
148
148
  }
149
149
  };
150
- const findAgentsWithLegacyShellHooks = (projectRoot) => {
150
+ const findAgentsWithOutdatedReactDoctorHooks = (projectRoot) => {
151
151
  const agents = [];
152
- if ((readJsonFileSafely(path$1.join(projectRoot, CLAUDE_SETTINGS_RELATIVE_PATH), {}).hooks?.PostToolBatch ?? []).some((group) => (group.hooks ?? []).some((hook) => isLegacyHookCommand(hook.command)))) agents.push(CLAUDE_AGENT);
153
- if ((readJsonFileSafely(path$1.join(projectRoot, CURSOR_HOOKS_RELATIVE_PATH), {}).hooks?.postToolUse ?? []).some((handler) => isLegacyHookCommand(handler.command))) agents.push(CURSOR_AGENT);
152
+ const settings = readJsonFileSafely(path$1.join(projectRoot, CLAUDE_SETTINGS_RELATIVE_PATH), {});
153
+ if ([...settings.hooks?.PostToolBatch ?? [], ...settings.hooks?.Stop ?? []].some((group) => (group.hooks ?? []).some((hook) => isLegacyHookCommand(hook.command))) || (settings.hooks?.PostToolBatch ?? []).some((group) => (group.hooks ?? []).some((hook) => hook.command === CLAUDE_HOOK_COMMAND))) agents.push(CLAUDE_AGENT);
154
+ const config = readJsonFileSafely(path$1.join(projectRoot, CURSOR_HOOKS_RELATIVE_PATH), {});
155
+ if ([...config.hooks?.postToolUse ?? [], ...config.hooks?.stop ?? []].some((handler) => isLegacyHookCommand(handler.command)) || (config.hooks?.postToolUse ?? []).some((handler) => handler.command === CURSOR_HOOK_COMMAND)) agents.push(CURSOR_AGENT);
154
156
  return agents;
155
157
  };
156
158
  const ensureDirectoryExists = (directoryPath) => {
@@ -167,62 +169,62 @@ const writeJsonFileWithDirectoryCheck = (filePath, value) => {
167
169
  ensureDirectoryExists(path$1.dirname(filePath));
168
170
  writeJsonFile(filePath, value);
169
171
  };
170
- const writeHookScript = (filePath) => {
172
+ const writeHookScript = (filePath, hookEventName) => {
171
173
  ensureDirectoryExists(path$1.dirname(filePath));
172
- fs$1.writeFileSync(filePath, buildAgentHookScript());
174
+ fs$1.writeFileSync(filePath, buildAgentHookScript(hookEventName));
173
175
  try {
174
176
  fs$1.rmSync(filePath.replace(/\.mjs$/, ".sh"), { force: true });
175
177
  } catch {}
176
178
  };
177
- const hasClaudeHookCommand = (groups) => groups.some((group) => (group.hooks ?? []).some((hook) => hook.command === CLAUDE_HOOK_COMMAND));
178
179
  const installClaudeHook = (projectRoot) => {
179
180
  const settingsPath = path$1.join(projectRoot, CLAUDE_SETTINGS_RELATIVE_PATH);
180
181
  const hookPath = path$1.join(projectRoot, CLAUDE_HOOK_RELATIVE_PATH);
181
182
  const settings = readJsonFile(settingsPath, {});
182
183
  const hooks = { ...settings.hooks ?? {} };
183
- const postToolBatchHooks = (hooks.PostToolBatch ?? []).flatMap((group) => {
184
+ const stripManagedHooks = (groups) => groups.flatMap((group) => {
184
185
  const groupHooks = group.hooks ?? [];
185
- const keptHooks = groupHooks.filter((hook) => !isLegacyHookCommand(hook.command));
186
+ const keptHooks = groupHooks.filter((hook) => !isManagedHookCommand(hook.command, CLAUDE_HOOK_COMMAND));
186
187
  if (keptHooks.length === groupHooks.length) return [group];
187
188
  return keptHooks.length > 0 ? [{
188
189
  ...group,
189
190
  hooks: keptHooks
190
191
  }] : [];
191
192
  });
192
- if (!hasClaudeHookCommand(postToolBatchHooks)) postToolBatchHooks.push({ hooks: [{
193
+ const stopHooks = stripManagedHooks(hooks.Stop ?? []);
194
+ stopHooks.push({ hooks: [{
193
195
  type: "command",
194
196
  command: CLAUDE_HOOK_COMMAND
195
197
  }] });
196
- hooks.PostToolBatch = postToolBatchHooks;
198
+ hooks.PostToolBatch = stripManagedHooks(hooks.PostToolBatch ?? []);
199
+ hooks.Stop = stopHooks;
197
200
  writeJsonFileWithDirectoryCheck(settingsPath, {
198
201
  ...settings,
199
202
  hooks
200
203
  });
201
- writeHookScript(hookPath);
204
+ writeHookScript(hookPath, "Stop");
202
205
  return [settingsPath, hookPath];
203
206
  };
204
- const hasCursorHookCommand = (handlers) => handlers.some((handler) => handler.command === CURSOR_HOOK_COMMAND);
205
207
  const installCursorHook = (projectRoot) => {
206
208
  const configPath = path$1.join(projectRoot, CURSOR_HOOKS_RELATIVE_PATH);
207
209
  const hookPath = path$1.join(projectRoot, CURSOR_HOOK_RELATIVE_PATH);
208
210
  const config = readJsonFile(configPath, {});
209
211
  const hooks = { ...config.hooks ?? {} };
210
- const postToolUseHooks = (hooks.postToolUse ?? []).filter((handler) => !isLegacyHookCommand(handler.command));
211
- if (!hasCursorHookCommand(postToolUseHooks)) postToolUseHooks.push({
212
+ const stopHooks = (hooks.stop ?? []).filter((handler) => !isManagedHookCommand(handler.command, CURSOR_HOOK_COMMAND));
213
+ stopHooks.push({
212
214
  command: CURSOR_HOOK_COMMAND,
213
- matcher: CURSOR_HOOK_MATCHER,
214
215
  timeout: 120
215
216
  });
216
- hooks.postToolUse = postToolUseHooks;
217
+ hooks.postToolUse = (hooks.postToolUse ?? []).filter((handler) => !isManagedHookCommand(handler.command, CURSOR_HOOK_COMMAND));
218
+ hooks.stop = stopHooks;
217
219
  writeJsonFileWithDirectoryCheck(configPath, {
218
220
  ...config,
219
221
  version: config.version ?? CURSOR_HOOKS_SCHEMA_VERSION,
220
222
  hooks
221
223
  });
222
- writeHookScript(hookPath);
224
+ writeHookScript(hookPath, "stop");
223
225
  return [configPath, hookPath];
224
226
  };
225
- const buildAgentHookScript = () => [
227
+ const buildAgentHookScript = (hookEventName) => [
226
228
  "import { existsSync, readFileSync, writeFileSync, unlinkSync } from 'node:fs';",
227
229
  "import { tmpdir } from 'node:os';",
228
230
  "import { join, dirname } from 'node:path';",
@@ -231,12 +233,12 @@ const buildAgentHookScript = () => [
231
233
  "",
232
234
  "const __filename = fileURLToPath(import.meta.url);",
233
235
  "const __dirname = dirname(__filename);",
236
+ `const HOOK_EVENT_NAME = ${JSON.stringify(hookEventName)};`,
237
+ `const MAX_CONTINUATIONS = 1;`,
234
238
  "",
235
239
  "// --verbose scans on large diffs can exceed spawnSync's 1 MiB default.",
236
240
  "const SPAWN_MAX_BUFFER_BYTES = 16 * 1024 * 1024;",
237
241
  "",
238
- "const EDIT_TOOL_NAMES = new Set(['Edit', 'Write', 'MultiEdit', 'NotebookEdit', 'ApplyPatch']);",
239
- "",
240
242
  "const readFileOrEmpty = (source) => {",
241
243
  " try {",
242
244
  " return readFileSync(source, 'utf8');",
@@ -246,13 +248,10 @@ const buildAgentHookScript = () => [
246
248
  "};",
247
249
  "",
248
250
  "const shouldScan = (input) => {",
249
- " const eventName = input.hook_event_name || input.eventName || input.event_name;",
250
- " if (eventName === 'PostToolBatch') {",
251
- " const toolCalls = Array.isArray(input.tool_calls) ? input.tool_calls : [];",
252
- " return toolCalls.some((toolCall) => EDIT_TOOL_NAMES.has(toolCall.tool_name));",
253
- " }",
254
- " const toolName = input.tool_name || input.toolName || input.tool;",
255
- " return !toolName || EDIT_TOOL_NAMES.has(toolName);",
251
+ " if (HOOK_EVENT_NAME === 'Stop') return !input.stop_hook_active;",
252
+ " if (input.status && input.status !== 'completed') return false;",
253
+ " const loopCount = Number(input.loop_count);",
254
+ " return !Number.isFinite(loopCount) || loopCount < MAX_CONTINUATIONS;",
256
255
  "};",
257
256
  "",
258
257
  "const runReactDoctor = (outputPath) => {",
@@ -268,11 +267,11 @@ const buildAgentHookScript = () => [
268
267
  " : './node_modules/.bin/react-doctor';",
269
268
  " const commands = [",
270
269
  " ...(existsSync(localBin)",
271
- " ? [localBin + ' --verbose --scope changed --blocking warning --no-score']",
270
+ " ? [localBin + ' --verbose --scope changed --include-untracked --blocking warning --no-score']",
272
271
  " : []),",
273
- " 'react-doctor --verbose --scope changed --blocking warning --no-score',",
274
- " 'pnpm dlx react-doctor@latest --verbose --scope changed --blocking warning --no-score',",
275
- " 'npx --yes react-doctor@latest --verbose --scope changed --blocking warning --no-score',",
272
+ " 'react-doctor --verbose --scope changed --include-untracked --blocking warning --no-score',",
273
+ " 'pnpm dlx react-doctor@latest --verbose --scope changed --include-untracked --blocking warning --no-score',",
274
+ " 'npx --yes react-doctor@latest --verbose --scope changed --include-untracked --blocking warning --no-score',",
276
275
  " ];",
277
276
  "",
278
277
  " for (const command of commands) {",
@@ -331,10 +330,10 @@ const buildAgentHookScript = () => [
331
330
  "",
332
331
  " const message = `React Doctor found issues in the changed files. Review this output and fix the regressions before finishing. For confirmed issues that cannot be fixed now, create GitHub issues with the rule, file/line, confidence, impact, and proposed fix.\\n\\n${scanOutput}`;",
333
332
  "",
334
- " if (input.hook_event_name === 'PostToolBatch') {",
335
- " console.log(JSON.stringify({ hookSpecificOutput: { hookEventName: 'PostToolBatch', additionalContext: message } }));",
333
+ " if (HOOK_EVENT_NAME === 'Stop') {",
334
+ " console.log(JSON.stringify({ decision: 'block', reason: message }));",
336
335
  " } else {",
337
- " console.log(JSON.stringify({ additional_context: message }));",
336
+ " console.log(JSON.stringify({ followup_message: message }));",
338
337
  " }",
339
338
  "};",
340
339
  "",
@@ -1005,7 +1004,10 @@ const installReactDoctorAgentHooksStep = (projectRoot, selectedAgents) => {
1005
1004
  if (hookResult.installedAgents.length === 0) hookSpinner.succeed("No supported native agent hook targets selected.");
1006
1005
  else {
1007
1006
  hookSpinner.succeed(`React Doctor agent hooks installed for ${hookResult.installedAgents.map((agent) => getSkillAgentConfig(agent).displayName).join(", ")}.`);
1008
- recordCount(METRIC.installAgentHooks, 1, { agentsCount: hookResult.installedAgents.length });
1007
+ recordCount(METRIC.installAgentHooks, 1, {
1008
+ agentsCount: hookResult.installedAgents.length,
1009
+ hookEvent: "stop"
1010
+ });
1009
1011
  }
1010
1012
  } catch (error) {
1011
1013
  hookSpinner.fail("Failed to install React Doctor agent hooks.");
@@ -1148,7 +1150,7 @@ const runInstallReactDoctor = async (options = {}) => {
1148
1150
  for (const agent of selectedAgents) recordCount(METRIC.installAgent, 1, { agent });
1149
1151
  };
1150
1152
  //#endregion
1151
- export { askUpgradeActionVersion as a, recordCiPromptDecision as c, installReactDoctorAgentHooks as i, hasHandledActionUpgrade as l, runInstallReactDoctor as n, askAddToGitHubActions as o, findAgentsWithLegacyShellHooks as r, hasHandledCiPrompt as s, getSkillSourceDirectory as t, recordActionUpgradeDecision as u };
1153
+ export { askUpgradeActionVersion as a, recordCiPromptDecision as c, installReactDoctorAgentHooks as i, hasHandledActionUpgrade as l, runInstallReactDoctor as n, askAddToGitHubActions as o, findAgentsWithOutdatedReactDoctorHooks as r, hasHandledCiPrompt as s, getSkillSourceDirectory as t, recordActionUpgradeDecision as u };
1152
1154
 
1153
- //# sourceMappingURL=install-react-doctor-Bq7dfEBI.js.map
1154
- //# debugId=d678e544-bf9c-5a23-bf1c-c11caae57e45
1155
+ //# sourceMappingURL=install-react-doctor-0EPCiZSM.js.map
1156
+ //# debugId=d43042c4-c766-54b9-a30f-944a55426467