react-doctor 0.9.7 → 0.9.8-dev.7f028ea
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/dist/build-section-divider-DKzi1sn2.js +312 -0
- package/dist/ci-BKAwxTDf.js +7501 -0
- package/dist/cli.js +96 -10780
- package/dist/design-ROS4n3k3.js +14 -0
- package/dist/{devtools-BQATi33M.js → devtools-DPRVRu3S.js} +3 -3
- package/dist/exit-gracefully-De1Nzy3z.js +47 -0
- package/dist/index.d.ts +4703 -4081
- package/dist/index.js +6070 -4387
- package/dist/inspect-Z_e5RkQs.js +1443 -0
- package/dist/install-BDS2ISd_.js +32 -0
- package/dist/install-doctor-script-J-zvzVqR.js +3251 -0
- package/dist/install-github-workflow-CAo3dNh1.js +267 -0
- package/dist/install-react-doctor-C_5DWtTC.js +1154 -0
- package/dist/lsp.js +6183 -4512
- package/dist/print-branded-header-UfYgFqhb.js +22 -0
- package/dist/read-object-file-BDLV3R4X.js +24 -0
- package/dist/{exit-gracefully-BJRsqdaK.js → record-metric-BGxpNcR0.js} +6252 -11955
- package/dist/report-error-Wat6_MDs.js +158 -0
- package/dist/report-workflow-result-CULZXneJ.js +279 -0
- package/dist/resolve-scope-BbndLz4E.js +339 -0
- package/dist/rules-BSF6erEQ.js +581 -0
- package/dist/{run-scan-app-DawD5rhU.js → run-scan-app-D1yyCXe2.js} +36 -29
- package/dist/scan-BTYPKfS9.js +53 -0
- package/dist/should-fail-scan-gate-CgCFA8pU.js +3075 -0
- package/dist/should-skip-prompts-CZbr6sjQ.js +10 -0
- package/dist/unref-stdin-noiOzC5n.js +120 -0
- package/dist/version-BAsYYPLc.js +21 -0
- package/dist/why-DZ9AgG5O.js +21 -0
- package/package.json +6 -7
|
@@ -0,0 +1,158 @@
|
|
|
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]="98355477-37ef-5b82-8b69-b28370c58639")}catch(e){}}();
|
|
3
|
+
import { D as SENTRY_FLUSH_TIMEOUT_MS, H as CANONICAL_DISCORD_URL, Hn as gen, Ht as formatErrorChain, In as error, U as CANONICAL_GITHUB_URL, Ut as formatReactDoctorError, Yn as runSync, cn as isReactDoctorError, en as highlighter, i as buildSentryScope, m as VERSION, nn as isErrnoException, t as recordCount, y as METRIC } from "./record-metric-BGxpNcR0.js";
|
|
4
|
+
import { c as isEnvironmentError, i as recordRunTraceId, n as getActiveRunTrace, o as isExpectedUserError, s as formatEnvironmentError } from "./unref-stdin-noiOzC5n.js";
|
|
5
|
+
import * as Sentry from "@sentry/node";
|
|
6
|
+
//#region src/cli/utils/handle-error.ts
|
|
7
|
+
const OTLP_ENDPOINT_ENVIRONMENT_VARIABLE = "REACT_DOCTOR_OTLP_ENDPOINT";
|
|
8
|
+
const OTLP_AUTH_HEADER_ENVIRONMENT_VARIABLE = "REACT_DOCTOR_OTLP_AUTH_HEADER";
|
|
9
|
+
const formatErrorForReport = (error) => isReactDoctorError(error) ? formatReactDoctorError(error) : formatErrorChain(error);
|
|
10
|
+
const formatSingleLine = (text) => text.replaceAll(/\s+/g, " ").trim();
|
|
11
|
+
const getErrorReportContext = () => ({
|
|
12
|
+
cwd: process.cwd(),
|
|
13
|
+
command: process.argv.join(" "),
|
|
14
|
+
nodeVersion: process.version,
|
|
15
|
+
platform: process.platform,
|
|
16
|
+
architecture: process.arch,
|
|
17
|
+
isOtlpEndpointConfigured: Boolean(process.env[OTLP_ENDPOINT_ENVIRONMENT_VARIABLE]),
|
|
18
|
+
isOtlpAuthHeaderConfigured: Boolean(process.env[OTLP_AUTH_HEADER_ENVIRONMENT_VARIABLE])
|
|
19
|
+
});
|
|
20
|
+
const formatConfiguredState = (isConfigured) => isConfigured ? "yes" : "no";
|
|
21
|
+
const buildErrorIssueBody = (error, context, sentryEventId) => {
|
|
22
|
+
const formattedError = formatErrorForReport(error) || "(empty error)";
|
|
23
|
+
const isOtlpExporterEnabled = context.isOtlpEndpointConfigured && context.isOtlpAuthHeaderConfigured;
|
|
24
|
+
return [
|
|
25
|
+
"## Error",
|
|
26
|
+
"",
|
|
27
|
+
"```text",
|
|
28
|
+
formattedError,
|
|
29
|
+
"```",
|
|
30
|
+
"",
|
|
31
|
+
"## Runtime",
|
|
32
|
+
"",
|
|
33
|
+
`- react-doctor version: ${VERSION}`,
|
|
34
|
+
`- node: ${context.nodeVersion}`,
|
|
35
|
+
`- platform: ${context.platform} ${context.architecture}`,
|
|
36
|
+
`- cwd: ${context.cwd}`,
|
|
37
|
+
`- command: ${context.command}`,
|
|
38
|
+
...sentryEventId ? [`- Sentry reference: ${sentryEventId}`] : [],
|
|
39
|
+
"",
|
|
40
|
+
"## OpenTelemetry",
|
|
41
|
+
"",
|
|
42
|
+
`- ${OTLP_ENDPOINT_ENVIRONMENT_VARIABLE} configured: ${formatConfiguredState(context.isOtlpEndpointConfigured)}`,
|
|
43
|
+
`- ${OTLP_AUTH_HEADER_ENVIRONMENT_VARIABLE} configured: ${formatConfiguredState(context.isOtlpAuthHeaderConfigured)} (value redacted)`,
|
|
44
|
+
`- OTLP exporter enabled: ${formatConfiguredState(isOtlpExporterEnabled)}`,
|
|
45
|
+
"- trace/span link, if exported: ",
|
|
46
|
+
"",
|
|
47
|
+
"## Notes",
|
|
48
|
+
"",
|
|
49
|
+
"Please add reproduction steps and any relevant repository details."
|
|
50
|
+
].join("\n");
|
|
51
|
+
};
|
|
52
|
+
const buildErrorIssueUrl = (error, sentryEventId) => {
|
|
53
|
+
const formattedError = formatSingleLine(formatErrorForReport(error));
|
|
54
|
+
const issueUrl = new URL(`${CANONICAL_GITHUB_URL}/issues/new`);
|
|
55
|
+
issueUrl.searchParams.set("title", formattedError ? `CLI error: ${formattedError}` : "CLI error");
|
|
56
|
+
issueUrl.searchParams.set("labels", "bug");
|
|
57
|
+
issueUrl.searchParams.set("body", buildErrorIssueBody(error, getErrorReportContext(), sentryEventId));
|
|
58
|
+
return issueUrl.toString();
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Effect-typed renderer: every message routes through `Console.error`
|
|
62
|
+
* so test runs can swap `Console` to a capture sink and the output
|
|
63
|
+
* appears in the right stream (stderr) in production. Lines stay
|
|
64
|
+
* red-highlighted (matches the historical `consoleLogger.error`
|
|
65
|
+
* contract) so the user sees a clearly distinguished error block.
|
|
66
|
+
*/
|
|
67
|
+
const handleErrorEffect = (error$2, sentryEventId) => gen(function* () {
|
|
68
|
+
yield* error("");
|
|
69
|
+
yield* error(highlighter.error("Something went wrong. Please check the error below for more details."));
|
|
70
|
+
yield* error(highlighter.error(`If the problem persists, please open this prefilled issue: ${buildErrorIssueUrl(error$2, sentryEventId)}`));
|
|
71
|
+
yield* error(highlighter.error(`You can also ask for help in Discord: ${CANONICAL_DISCORD_URL}`));
|
|
72
|
+
if (sentryEventId) yield* error(highlighter.error(`Reference (mention this when reporting): ${sentryEventId}`));
|
|
73
|
+
yield* error("");
|
|
74
|
+
yield* error(highlighter.error(formatErrorForReport(error$2)));
|
|
75
|
+
yield* error("");
|
|
76
|
+
});
|
|
77
|
+
/**
|
|
78
|
+
* Sync façade for legacy callers (top-level CLI command bodies that
|
|
79
|
+
* aren't yet Effect-typed). Bridges via `Effect.runSync` so the
|
|
80
|
+
* underlying Console writes happen exactly like the Effect path.
|
|
81
|
+
*/
|
|
82
|
+
const handleError = (error, options = {}) => {
|
|
83
|
+
runSync(handleErrorEffect(error, options.sentryEventId));
|
|
84
|
+
if (options.shouldExit !== false) process.exit(1);
|
|
85
|
+
process.exitCode = 1;
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* Renderer for expected, user-actionable failures — a bad `--diff` value,
|
|
89
|
+
* a base branch that isn't fetched, or environment errors like disk-full or
|
|
90
|
+
* permission-denied. Prints just the (already human-readable) message — no
|
|
91
|
+
* "Something went wrong", prefilled issue, Discord link, or Sentry reference
|
|
92
|
+
* — because there is no bug to report.
|
|
93
|
+
*/
|
|
94
|
+
const handleUserError = (error$1, options = {}) => {
|
|
95
|
+
const isEnvError = isEnvironmentError(error$1);
|
|
96
|
+
if (isEnvError) recordCount(METRIC.cliEnvironmentError, 1, { code: (isErrnoException(error$1) ? error$1.code : void 0) ?? "unknown" });
|
|
97
|
+
const message = isEnvError ? formatEnvironmentError(error$1) : formatErrorForReport(error$1);
|
|
98
|
+
runSync(gen(function* () {
|
|
99
|
+
yield* error("");
|
|
100
|
+
yield* error(highlighter.error(message));
|
|
101
|
+
yield* error("");
|
|
102
|
+
}));
|
|
103
|
+
if (options.shouldExit !== false) process.exit(1);
|
|
104
|
+
process.exitCode = 1;
|
|
105
|
+
};
|
|
106
|
+
//#endregion
|
|
107
|
+
//#region src/cli/utils/report-error.ts
|
|
108
|
+
/**
|
|
109
|
+
* Sends an error to Sentry — enriched with a fresh snapshot of the current run
|
|
110
|
+
* (version, platform, CI/agent, invocation, scanned project) and, when a run
|
|
111
|
+
* transaction is in flight, linked to its trace via the scope's propagation
|
|
112
|
+
* context so the crash and its transaction share a `trace_id` — then waits for
|
|
113
|
+
* delivery before the caller exits. The CLI tears down synchronously after
|
|
114
|
+
* rendering an error, so the awaited `flush` is what actually gets the event
|
|
115
|
+
* (and any in-flight transaction) off the machine.
|
|
116
|
+
*
|
|
117
|
+
* Returns the Sentry event id so the caller can surface it as a reference the
|
|
118
|
+
* user can quote when reporting the bug; returns `undefined` when Sentry was
|
|
119
|
+
* never initialized (`--no-score`, tests, or a missing DSN) or delivery failed.
|
|
120
|
+
* Swallows any transport failure so telemetry can never mask the user's
|
|
121
|
+
* original error.
|
|
122
|
+
*/
|
|
123
|
+
const reportErrorToSentry = async (error) => {
|
|
124
|
+
if (!Sentry.isInitialized()) return void 0;
|
|
125
|
+
if (isExpectedUserError(error)) return void 0;
|
|
126
|
+
try {
|
|
127
|
+
const { tags, contexts } = buildSentryScope();
|
|
128
|
+
let reason = "unknown";
|
|
129
|
+
if (isReactDoctorError(error)) reason = error.reason._tag;
|
|
130
|
+
else if (error instanceof Error) reason = error.name;
|
|
131
|
+
recordCount(METRIC.cliError, 1, {
|
|
132
|
+
command: typeof tags.command === "string" ? tags.command : void 0,
|
|
133
|
+
reason
|
|
134
|
+
});
|
|
135
|
+
const runTrace = getActiveRunTrace();
|
|
136
|
+
const eventId = Sentry.withScope((scope) => {
|
|
137
|
+
for (const [name, context] of Object.entries(contexts)) scope.setContext(name, context);
|
|
138
|
+
scope.setTags(tags);
|
|
139
|
+
if (runTrace) scope.setPropagationContext({
|
|
140
|
+
traceId: runTrace.traceId,
|
|
141
|
+
parentSpanId: runTrace.spanId,
|
|
142
|
+
sampled: runTrace.sampled,
|
|
143
|
+
sampleRand: Math.random()
|
|
144
|
+
});
|
|
145
|
+
recordRunTraceId(scope.getPropagationContext().traceId);
|
|
146
|
+
return Sentry.captureException(error);
|
|
147
|
+
});
|
|
148
|
+
await Sentry.flush(SENTRY_FLUSH_TIMEOUT_MS);
|
|
149
|
+
return eventId;
|
|
150
|
+
} catch {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
//#endregion
|
|
155
|
+
export { handleError as n, handleUserError as r, reportErrorToSentry as t };
|
|
156
|
+
|
|
157
|
+
//# sourceMappingURL=report-error-Wat6_MDs.js.map
|
|
158
|
+
//# debugId=98355477-37ef-5b82-8b69-b28370c58639
|
|
@@ -0,0 +1,279 @@
|
|
|
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]="2c4a070e-23f8-5a31-a4af-18688e5c19c0")}catch(e){}}();
|
|
3
|
+
import { S as REACT_DOCTOR_CONFIG_PROJECT_NAME, t as recordCount, y as METRIC } from "./record-metric-BGxpNcR0.js";
|
|
4
|
+
import { u as isCommandAvailable } from "./install-github-workflow-CAo3dNh1.js";
|
|
5
|
+
import { spawn } from "node:child_process";
|
|
6
|
+
import * as path$1 from "node:path";
|
|
7
|
+
import process$1 from "node:process";
|
|
8
|
+
import { createHash } from "node:crypto";
|
|
9
|
+
import { detectInstalledSkillAgents, getSkillAgentTypes } from "agent-install";
|
|
10
|
+
import Conf from "conf";
|
|
11
|
+
//#region src/cli/utils/detect-agents.ts
|
|
12
|
+
const PATH_BINARIES = {
|
|
13
|
+
"claude-code": ["claude"],
|
|
14
|
+
codex: ["codex"],
|
|
15
|
+
cursor: ["cursor", "agent"],
|
|
16
|
+
droid: ["droid"],
|
|
17
|
+
"gemini-cli": ["gemini"],
|
|
18
|
+
"github-copilot": ["copilot"],
|
|
19
|
+
opencode: ["opencode"],
|
|
20
|
+
pi: ["pi", "omegon"]
|
|
21
|
+
};
|
|
22
|
+
const detectPathAvailableAgents = () => {
|
|
23
|
+
const detected = [];
|
|
24
|
+
for (const [agent, binaries] of Object.entries(PATH_BINARIES)) if (binaries.some(isCommandAvailable)) detected.push(agent);
|
|
25
|
+
return detected;
|
|
26
|
+
};
|
|
27
|
+
const detectAvailableAgents = async () => {
|
|
28
|
+
const detected = new Set([...detectPathAvailableAgents(), ...await detectInstalledSkillAgents()]);
|
|
29
|
+
return getSkillAgentTypes().filter((agent) => agent !== "universal" && detected.has(agent));
|
|
30
|
+
};
|
|
31
|
+
const DEFAULT_INSTALL_AGENTS = [
|
|
32
|
+
"claude-code",
|
|
33
|
+
"cursor",
|
|
34
|
+
"codex",
|
|
35
|
+
"opencode"
|
|
36
|
+
];
|
|
37
|
+
const computeDefaultSelectedAgents = (detectedAgents, rememberedAgents) => {
|
|
38
|
+
const detected = new Set(detectedAgents);
|
|
39
|
+
const remembered = rememberedAgents.filter((agent) => detected.has(agent));
|
|
40
|
+
if (remembered.length > 0) return remembered;
|
|
41
|
+
const defaults = DEFAULT_INSTALL_AGENTS.filter((agent) => detected.has(agent));
|
|
42
|
+
if (defaults.length > 0) return defaults;
|
|
43
|
+
return detectedAgents.length === 1 ? [...detectedAgents] : [];
|
|
44
|
+
};
|
|
45
|
+
//#endregion
|
|
46
|
+
//#region src/cli/utils/now-iso.ts
|
|
47
|
+
const nowIso = () => (/* @__PURE__ */ new Date()).toISOString();
|
|
48
|
+
const ONBOARDING_EVENT = "onboarding";
|
|
49
|
+
const CI_PITCH_EVENT = "ci-pitch";
|
|
50
|
+
const ACTION_UPGRADE_EVENT = "action-upgrade-v2";
|
|
51
|
+
const SETUP_HINT_EVENT = "setup-hint";
|
|
52
|
+
const HANDOFF_TARGET_PREFERENCE_ID = "handoff-target";
|
|
53
|
+
const INSTALL_AGENTS_PREFERENCE_ID = "install-agents";
|
|
54
|
+
const foldLegacyDecisions = (projects, legacy, eventId) => {
|
|
55
|
+
for (const [hash, record] of Object.entries(legacy ?? {})) {
|
|
56
|
+
const existing = projects[hash] ?? { rootDirectory: record.rootDirectory ?? "" };
|
|
57
|
+
projects[hash] = {
|
|
58
|
+
...existing,
|
|
59
|
+
events: {
|
|
60
|
+
...existing.events,
|
|
61
|
+
[eventId]: {
|
|
62
|
+
firedAt: record.at ?? nowIso(),
|
|
63
|
+
version: 1,
|
|
64
|
+
...record.outcome ? { outcome: record.outcome } : {}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
const migrateCliState = (state) => {
|
|
71
|
+
if (typeof state.schemaVersion === "number" && state.schemaVersion >= 2) return state;
|
|
72
|
+
const projects = {};
|
|
73
|
+
for (const [hash, record] of Object.entries(state.projects ?? {})) {
|
|
74
|
+
const carried = {
|
|
75
|
+
rootDirectory: record.rootDirectory,
|
|
76
|
+
...record.events ? { events: record.events } : {},
|
|
77
|
+
...record.migrations ? { migrations: record.migrations } : {}
|
|
78
|
+
};
|
|
79
|
+
projects[hash] = record.setupPrompt === false ? {
|
|
80
|
+
...carried,
|
|
81
|
+
events: {
|
|
82
|
+
...carried.events,
|
|
83
|
+
[SETUP_HINT_EVENT]: {
|
|
84
|
+
firedAt: nowIso(),
|
|
85
|
+
version: 1,
|
|
86
|
+
outcome: "declined"
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
} : carried;
|
|
90
|
+
}
|
|
91
|
+
foldLegacyDecisions(projects, state.ciPrompts, CI_PITCH_EVENT);
|
|
92
|
+
foldLegacyDecisions(projects, state.actionUpgrades, ACTION_UPGRADE_EVENT);
|
|
93
|
+
return {
|
|
94
|
+
schemaVersion: 2,
|
|
95
|
+
global: typeof state.onboardedAt === "string" ? { events: { [ONBOARDING_EVENT]: {
|
|
96
|
+
firedAt: state.onboardedAt,
|
|
97
|
+
version: 1
|
|
98
|
+
} } } : {},
|
|
99
|
+
projects
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
const resolveConfigDir = (options) => options.cwd ?? (process.env["REACT_DOCTOR_CONFIG_DIR"] || void 0);
|
|
103
|
+
const openStore = (options = {}) => new Conf({
|
|
104
|
+
projectName: REACT_DOCTOR_CONFIG_PROJECT_NAME,
|
|
105
|
+
cwd: resolveConfigDir(options)
|
|
106
|
+
});
|
|
107
|
+
const openMigratedStore = (options) => {
|
|
108
|
+
const store = openStore(options);
|
|
109
|
+
const state = store.store;
|
|
110
|
+
const migrated = migrateCliState(state);
|
|
111
|
+
if (migrated !== state) store.store = migrated;
|
|
112
|
+
return store;
|
|
113
|
+
};
|
|
114
|
+
const readCliState = (select, fallback, options = {}) => {
|
|
115
|
+
try {
|
|
116
|
+
return select(openMigratedStore(options).store);
|
|
117
|
+
} catch {
|
|
118
|
+
return fallback;
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
const updateCliState = (update, options = {}) => {
|
|
122
|
+
try {
|
|
123
|
+
const store = openMigratedStore(options);
|
|
124
|
+
store.store = update(store.store);
|
|
125
|
+
return true;
|
|
126
|
+
} catch {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
//#endregion
|
|
131
|
+
//#region src/cli/utils/hash-project-root.ts
|
|
132
|
+
const hashProjectRoot = (projectRoot) => createHash("sha256").update(path$1.resolve(projectRoot)).digest("hex");
|
|
133
|
+
//#endregion
|
|
134
|
+
//#region src/cli/utils/cli-lifecycle.ts
|
|
135
|
+
const versionOf = (item) => item.version ?? 1;
|
|
136
|
+
const selectScope = (state, scoped, projectRoot) => scoped.scope === "global" ? state.global : projectRoot === void 0 ? void 0 : state.projects?.[hashProjectRoot(projectRoot)];
|
|
137
|
+
const updateScope = (state, scoped, projectRoot, updateScopeState) => {
|
|
138
|
+
if (scoped.scope === "global") return {
|
|
139
|
+
...state,
|
|
140
|
+
global: updateScopeState(state.global ?? {})
|
|
141
|
+
};
|
|
142
|
+
if (projectRoot === void 0) return state;
|
|
143
|
+
const projectKey = hashProjectRoot(projectRoot);
|
|
144
|
+
const base = state.projects?.[projectKey] ?? { rootDirectory: path$1.resolve(projectRoot) };
|
|
145
|
+
return {
|
|
146
|
+
...state,
|
|
147
|
+
projects: {
|
|
148
|
+
...state.projects,
|
|
149
|
+
[projectKey]: {
|
|
150
|
+
...base,
|
|
151
|
+
...updateScopeState(base)
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
};
|
|
156
|
+
const isGatePending = (gate, target = {}, options = {}) => {
|
|
157
|
+
if (gate.scope === "project" && target.projectRoot === void 0) return false;
|
|
158
|
+
return readCliState((state) => {
|
|
159
|
+
const record = selectScope(state, gate, target.projectRoot)?.events?.[gate.id];
|
|
160
|
+
return !record || record.version < versionOf(gate);
|
|
161
|
+
}, gate.fireWhenUnknown ?? false, options);
|
|
162
|
+
};
|
|
163
|
+
const recordGate = (gate, target = {}, options = {}) => updateCliState((state) => updateScope(state, gate, target.projectRoot, (scope) => ({
|
|
164
|
+
...scope,
|
|
165
|
+
events: {
|
|
166
|
+
...scope.events,
|
|
167
|
+
[gate.id]: {
|
|
168
|
+
firedAt: nowIso(),
|
|
169
|
+
version: versionOf(gate),
|
|
170
|
+
...target.outcome ? { outcome: target.outcome } : {}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
})), options);
|
|
174
|
+
const readPreference = (preference, target = {}, options = {}) => readCliState((state) => selectScope(state, preference, target.projectRoot)?.preferences?.[preference.id] ?? null, null, options);
|
|
175
|
+
const writePreference = (preference, value, target = {}, options = {}) => updateCliState((state) => updateScope(state, preference, target.projectRoot, (scope) => ({
|
|
176
|
+
...scope,
|
|
177
|
+
preferences: {
|
|
178
|
+
...scope.preferences,
|
|
179
|
+
[preference.id]: value
|
|
180
|
+
}
|
|
181
|
+
})), options);
|
|
182
|
+
const isMigrationPending = (migration, target = {}, options = {}) => {
|
|
183
|
+
if (migration.scope === "project" && target.projectRoot === void 0) return false;
|
|
184
|
+
return readCliState((state) => {
|
|
185
|
+
const record = selectScope(state, migration, target.projectRoot)?.migrations?.[migration.id];
|
|
186
|
+
return !record || record.version < versionOf(migration);
|
|
187
|
+
}, false, options);
|
|
188
|
+
};
|
|
189
|
+
const recordMigration = (migration, projectRoot, record, options) => updateCliState((state) => updateScope(state, migration, projectRoot, (scope) => ({
|
|
190
|
+
...scope,
|
|
191
|
+
migrations: {
|
|
192
|
+
...scope.migrations,
|
|
193
|
+
[migration.id]: record
|
|
194
|
+
}
|
|
195
|
+
})), options);
|
|
196
|
+
const runMigrations = async (migrations, target = {}, options = {}) => {
|
|
197
|
+
const results = [];
|
|
198
|
+
for (const migration of migrations) {
|
|
199
|
+
if (!isMigrationPending(migration, target, options)) {
|
|
200
|
+
results.push({
|
|
201
|
+
id: migration.id,
|
|
202
|
+
ran: false,
|
|
203
|
+
applied: true
|
|
204
|
+
});
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
let applied = false;
|
|
208
|
+
try {
|
|
209
|
+
applied = await migration.run({ projectRoot: target.projectRoot });
|
|
210
|
+
} catch {
|
|
211
|
+
applied = false;
|
|
212
|
+
}
|
|
213
|
+
if (applied) recordMigration(migration, target.projectRoot, {
|
|
214
|
+
ranAt: nowIso(),
|
|
215
|
+
version: versionOf(migration)
|
|
216
|
+
}, options);
|
|
217
|
+
results.push({
|
|
218
|
+
id: migration.id,
|
|
219
|
+
ran: true,
|
|
220
|
+
applied
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
return results;
|
|
224
|
+
};
|
|
225
|
+
//#endregion
|
|
226
|
+
//#region src/cli/utils/open-url.ts
|
|
227
|
+
const resolveOpenCommand = (url) => {
|
|
228
|
+
if (process$1.platform === "darwin") return {
|
|
229
|
+
command: "open",
|
|
230
|
+
args: [url]
|
|
231
|
+
};
|
|
232
|
+
if (process$1.platform === "win32") return {
|
|
233
|
+
command: "cmd",
|
|
234
|
+
args: [
|
|
235
|
+
"/c",
|
|
236
|
+
"start",
|
|
237
|
+
"",
|
|
238
|
+
url
|
|
239
|
+
]
|
|
240
|
+
};
|
|
241
|
+
return {
|
|
242
|
+
command: "xdg-open",
|
|
243
|
+
args: [url]
|
|
244
|
+
};
|
|
245
|
+
};
|
|
246
|
+
const openUrl = (url) => new Promise((resolve) => {
|
|
247
|
+
try {
|
|
248
|
+
const { command, args } = resolveOpenCommand(url);
|
|
249
|
+
const child = spawn(command, args, {
|
|
250
|
+
detached: true,
|
|
251
|
+
stdio: "ignore"
|
|
252
|
+
});
|
|
253
|
+
child.once("spawn", () => resolve(true));
|
|
254
|
+
child.once("error", () => resolve(false));
|
|
255
|
+
child.unref();
|
|
256
|
+
} catch {
|
|
257
|
+
resolve(false);
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
//#endregion
|
|
261
|
+
//#region src/cli/utils/report-workflow-result.ts
|
|
262
|
+
const reportWorkflowResult = (workflowSpinner, result, projectRoot) => {
|
|
263
|
+
if (result.status === "failed") {
|
|
264
|
+
workflowSpinner.fail("Couldn't write the GitHub Actions workflow.");
|
|
265
|
+
return false;
|
|
266
|
+
}
|
|
267
|
+
if (result.status === "exists") {
|
|
268
|
+
workflowSpinner.succeed("GitHub Actions workflow already configured.");
|
|
269
|
+
return false;
|
|
270
|
+
}
|
|
271
|
+
workflowSpinner.succeed(`GitHub Actions workflow added at ${path$1.relative(projectRoot, result.workflowPath)}.`);
|
|
272
|
+
recordCount(METRIC.installWorkflow, 1);
|
|
273
|
+
return true;
|
|
274
|
+
};
|
|
275
|
+
//#endregion
|
|
276
|
+
export { recordGate as a, ACTION_UPGRADE_EVENT as c, INSTALL_AGENTS_PREFERENCE_ID as d, ONBOARDING_EVENT as f, detectAvailableAgents as h, readPreference as i, CI_PITCH_EVENT as l, computeDefaultSelectedAgents as m, openUrl as n, runMigrations as o, SETUP_HINT_EVENT as p, isGatePending as r, writePreference as s, reportWorkflowResult as t, HANDOFF_TARGET_PREFERENCE_ID as u };
|
|
277
|
+
|
|
278
|
+
//# sourceMappingURL=report-workflow-result-CULZXneJ.js.map
|
|
279
|
+
//# debugId=2c4a070e-23f8-5a31-a4af-18688e5c19c0
|