react-doctor 0.9.12 → 0.9.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -1
- package/bin/react-doctor.js +1 -9
- package/dist/active-run-trace-dlIZeEvb.js +18 -0
- package/dist/active-scan-abort-registry-DwG6tSPy.js +28 -0
- package/dist/{build-section-divider-BsQvH-7I.js → build-section-divider-DELfSn3p.js} +10 -25
- package/dist/{ci-B4x4RjKD.js → ci-DqnZCnrL.js} +13 -12
- package/dist/cli.js +121 -41
- package/dist/{design-A48PNCf_.js → design-DqUidb1f.js} +4 -4
- package/dist/{devtools-DPRVRu3S.js → devtools-CC2PAZ85.js} +4 -4
- package/dist/{exit-gracefully-Bk531kS-.js → exit-gracefully-CrpeIbra.js} +15 -9
- package/dist/get-east-asian-width-Bv2TD3Xj.js +444 -0
- package/dist/{report-error-Pb2uO8EG.js → handle-error-BEYYtsCl.js} +18 -68
- package/dist/index.d.ts +53 -42
- package/dist/index.js +55119 -54689
- package/dist/{inspect-CwH84aSA.js → inspect-BjMaC5WV.js} +44 -33
- package/dist/{install-sFN_w425.js → install-DxLmASQ5.js} +9 -8
- package/dist/{install-doctor-script-DLayXS7q.js → install-doctor-script-4EWviJL8.js} +7 -449
- package/dist/{install-github-workflow-Goz-KFqb.js → install-github-workflow-BPznUbbo.js} +10 -6
- package/dist/{install-react-doctor-Bq7dfEBI.js → install-react-doctor-Baq9hjoF.js} +47 -45
- package/dist/{run-scan-app-DXBMW54J.js → jsx-runtime-DvynQ_wu.js} +281 -2759
- package/dist/path-format-DnHpmJwG.js +9 -0
- package/dist/{print-branded-header-D_J8Qdsj.js → print-branded-header-DSB6i3kk.js} +4 -4
- package/dist/project-analysis-worker.d.ts +1 -0
- package/dist/project-analysis-worker.js +51901 -0
- package/dist/prompt-runtime-scan-url-BibDt9O1.js +240 -0
- package/dist/{read-object-file-Hk79zI91.js → read-object-file-DfWpkle4.js} +4 -4
- package/dist/{record-metric-CsQXJewH.js → record-metric-Cckscwg_.js} +3257 -6019
- package/dist/report-error-C1YnoRNl.js +64 -0
- package/dist/{report-workflow-result-6n_wSqzA.js → report-workflow-result-IdGRoBFN.js} +5 -5
- package/dist/{resolve-scope-DP6rYlNO.js → resolve-scope-Bb6fljxd.js} +8 -10
- package/dist/{rules-BnIZ4Fq_.js → rules-BcFekwN4.js} +6 -6
- package/dist/run-scan-app-CKHynQx8.js +2511 -0
- package/dist/runtime-scan/browser-probe.iife.js +855 -0
- package/dist/runtime-scan-7Y_mbqEa.js +770 -0
- package/dist/sanitize-runtime-url-DzyBLbi3.js +76 -0
- package/dist/scan-DQCwBx6p.js +47 -0
- package/dist/semver-DFtnEmN-.js +3219 -0
- package/dist/{should-fail-scan-gate-DzZuTxim.js → should-fail-scan-gate-BYPsKIde.js} +160 -184
- package/dist/{should-skip-prompts-D1GWG2qN.js → should-skip-prompts-CKkbB3rC.js} +4 -4
- package/dist/should-use-tui-Crfoao-l.js +25 -0
- package/dist/skills/improve-threejs/SKILL.md +102 -0
- package/dist/skills/performance/SKILL.md +113 -0
- package/dist/skills/react-doctor/SKILL.md +6 -0
- package/dist/{unref-stdin-0a_0uwC6.js → telemetry-runtime-DKJyjz9o.js} +57 -33
- package/dist/unref-stdin-SK3WfwxS.js +12 -0
- package/dist/{version-Bo5QDp7F.js → version-CMkUAGmw.js} +4 -4
- package/dist/{why-BFYbtnm8.js → why-By3I6_Ex.js} +4 -4
- package/dist/with-run-span-DxFGyW7k.js +110 -0
- package/package.json +9 -10
- package/dist/chunk-q7NCDQ7-.js +0 -28
- package/dist/lsp.js +0 -81145
- 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]="
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
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-
|
|
6
|
-
import { t as shouldSkipPrompts } from "./should-skip-prompts-
|
|
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-
|
|
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]="cd38449c-31aa-551e-9372-f62b08fbcd13")}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-Cckscwg_.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-4EWviJL8.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-BPznUbbo.js";
|
|
6
|
+
import { t as shouldSkipPrompts } from "./should-skip-prompts-CKkbB3rC.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-IdGRoBFN.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
|
|
150
|
+
const findAgentsWithOutdatedReactDoctorHooks = (projectRoot) => {
|
|
151
151
|
const agents = [];
|
|
152
|
-
|
|
153
|
-
if ((
|
|
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
|
|
184
|
+
const stripManagedHooks = (groups) => groups.flatMap((group) => {
|
|
184
185
|
const groupHooks = group.hooks ?? [];
|
|
185
|
-
const keptHooks = groupHooks.filter((hook) => !
|
|
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
|
-
|
|
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 =
|
|
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
|
|
211
|
-
|
|
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 =
|
|
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
|
-
"
|
|
250
|
-
" if (
|
|
251
|
-
"
|
|
252
|
-
"
|
|
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 (
|
|
335
|
-
" console.log(JSON.stringify({
|
|
333
|
+
" if (HOOK_EVENT_NAME === 'Stop') {",
|
|
334
|
+
" console.log(JSON.stringify({ decision: 'block', reason: message }));",
|
|
336
335
|
" } else {",
|
|
337
|
-
" console.log(JSON.stringify({
|
|
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, {
|
|
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,
|
|
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-
|
|
1154
|
-
//# debugId=
|
|
1155
|
+
//# sourceMappingURL=install-react-doctor-Baq9hjoF.js.map
|
|
1156
|
+
//# debugId=cd38449c-31aa-551e-9372-f62b08fbcd13
|