@userreason/wizard 0.2.0 → 0.3.0
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 +103 -0
- package/dist/agent-note.js +6 -6
- package/dist/agent-skill.js +5 -5
- package/dist/analytics.js +9 -0
- package/dist/bin.js +201 -34
- package/dist/{chunk-FC7PZNYW.js → chunk-2UEUVLCB.js} +3 -3
- package/dist/{chunk-6DCCEVPD.js → chunk-5IO5LY22.js} +33 -11
- package/dist/{chunk-GGARVSPT.js → chunk-77SK7TKZ.js} +8894 -5663
- package/dist/{chunk-YMSGDC4B.js → chunk-CADA5WZ3.js} +28 -6
- package/dist/{chunk-HACTNBV3.js → chunk-F4FKAUQN.js} +3 -3
- package/dist/{chunk-SJVLAYGG.js → chunk-GOYBYAUH.js} +8 -1
- package/dist/chunk-HIF6NUNK.js +33 -0
- package/dist/{chunk-6CJ4ANMN.js → chunk-MFGJ2KPT.js} +1 -1
- package/dist/{chunk-OEGNGGZ2.js → chunk-NMHTFC5Q.js} +10 -3
- package/dist/{chunk-5Z5J6PY5.js → chunk-NZ65XDNL.js} +4 -4
- package/dist/{chunk-3RDJORRS.js → chunk-P6DOSGRZ.js} +1 -1
- package/dist/chunk-SFODN2YB.js +196 -0
- package/dist/chunk-UN24JFV2.js +44 -0
- package/dist/chunk-VXWLSQYK.js +130 -0
- package/dist/chunk-YYFC7TM2.js +286 -0
- package/dist/{chunk-KV6GSBTQ.js → chunk-Z6ZY7X2K.js} +5 -5
- package/dist/{chunk-JD5U4U26.js → chunk-ZHHIHHLU.js} +4 -4
- package/dist/cli-access.js +3 -3
- package/dist/connection.js +2 -2
- package/dist/first-survey.js +11 -0
- package/dist/footer.js +16 -0
- package/dist/global-cli.js +5 -5
- package/dist/integrate.js +4 -4
- package/dist/project.js +7 -3
- package/dist/registry.js +5 -3
- package/dist/setup-flow.js +24 -0
- package/dist/setup.js +32 -0
- package/dist/skills/userreason/SKILL.md +43 -0
- package/dist/skills/userreason/references/management.md +6 -0
- package/dist/startup.js +2 -2
- package/dist/state.js +5 -5
- package/dist/ui.js +2 -2
- package/package.json +1 -2
package/dist/bin.js
CHANGED
|
@@ -3,21 +3,33 @@ import { createRequire as createWizardRequire } from 'node:module'; import { fil
|
|
|
3
3
|
import {
|
|
4
4
|
offerAgentNote,
|
|
5
5
|
planAgentNote
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import {
|
|
8
|
-
offerAgentSkill,
|
|
9
|
-
planAgentSkill
|
|
10
|
-
} from "./chunk-5Z5J6PY5.js";
|
|
6
|
+
} from "./chunk-Z6ZY7X2K.js";
|
|
11
7
|
import {
|
|
12
8
|
offerCliAccess
|
|
13
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-F4FKAUQN.js";
|
|
14
10
|
import {
|
|
15
11
|
offerGlobalCli
|
|
16
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-ZHHIHHLU.js";
|
|
13
|
+
import {
|
|
14
|
+
WizardAnalytics
|
|
15
|
+
} from "./chunk-UN24JFV2.js";
|
|
16
|
+
import {
|
|
17
|
+
beginFirstSurveyPreparation,
|
|
18
|
+
offerFirstSurvey
|
|
19
|
+
} from "./chunk-HIF6NUNK.js";
|
|
20
|
+
import {
|
|
21
|
+
runBrowserWizard
|
|
22
|
+
} from "./chunk-VXWLSQYK.js";
|
|
23
|
+
import "./chunk-YYFC7TM2.js";
|
|
24
|
+
import "./chunk-SFODN2YB.js";
|
|
25
|
+
import {
|
|
26
|
+
offerAgentSkill,
|
|
27
|
+
planAgentSkill
|
|
28
|
+
} from "./chunk-NZ65XDNL.js";
|
|
17
29
|
import {
|
|
18
30
|
ensureCurrentWizard,
|
|
19
31
|
wizardVersion
|
|
20
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-MFGJ2KPT.js";
|
|
21
33
|
import {
|
|
22
34
|
Cancelled,
|
|
23
35
|
Terminal,
|
|
@@ -25,26 +37,26 @@ import {
|
|
|
25
37
|
clean,
|
|
26
38
|
normalizeOrigin,
|
|
27
39
|
openBrowser
|
|
28
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-GOYBYAUH.js";
|
|
29
41
|
import {
|
|
30
42
|
BrowserConnectionUnavailable,
|
|
31
43
|
compatibilityCredentials,
|
|
32
44
|
connectInstallation,
|
|
33
45
|
memoryCredentials
|
|
34
|
-
} from "./chunk-
|
|
46
|
+
} from "./chunk-P6DOSGRZ.js";
|
|
35
47
|
import {
|
|
36
48
|
clearInstallation,
|
|
37
49
|
resolveInstallation,
|
|
38
50
|
saveInstallation,
|
|
39
51
|
savedInstallation
|
|
40
|
-
} from "./chunk-
|
|
52
|
+
} from "./chunk-2UEUVLCB.js";
|
|
41
53
|
import {
|
|
42
54
|
applyIntegration,
|
|
43
55
|
detectInstallation,
|
|
44
56
|
integrationAdditions,
|
|
45
57
|
integrationPreview,
|
|
46
58
|
planIntegration
|
|
47
|
-
} from "./chunk-
|
|
59
|
+
} from "./chunk-5IO5LY22.js";
|
|
48
60
|
import {
|
|
49
61
|
SdkInstallError,
|
|
50
62
|
cliCommand,
|
|
@@ -58,8 +70,8 @@ import {
|
|
|
58
70
|
sdkInstallCommand,
|
|
59
71
|
verifyConfiguration,
|
|
60
72
|
writeIntegration
|
|
61
|
-
} from "./chunk-
|
|
62
|
-
import "./chunk-
|
|
73
|
+
} from "./chunk-CADA5WZ3.js";
|
|
74
|
+
import "./chunk-NMHTFC5Q.js";
|
|
63
75
|
import {
|
|
64
76
|
ApiError,
|
|
65
77
|
AuthenticationError,
|
|
@@ -67,13 +79,14 @@ import {
|
|
|
67
79
|
apiUrl,
|
|
68
80
|
credentialStoreKind,
|
|
69
81
|
detectAgentHarness,
|
|
82
|
+
firstSurveyHandoff,
|
|
70
83
|
login,
|
|
71
84
|
packageProfile,
|
|
72
85
|
resolveConfig,
|
|
73
86
|
resolveCredentials,
|
|
74
87
|
saveConfig,
|
|
75
88
|
uuid
|
|
76
|
-
} from "./chunk-
|
|
89
|
+
} from "./chunk-77SK7TKZ.js";
|
|
77
90
|
import "./chunk-WL3NOIM6.js";
|
|
78
91
|
|
|
79
92
|
// src/bin.ts
|
|
@@ -83,6 +96,9 @@ var help = `UserReason installation wizard
|
|
|
83
96
|
|
|
84
97
|
userreason-wizard [--directory PATH] [--origin URL]
|
|
85
98
|
|
|
99
|
+
--browser-setup (explicit browser-guided setup; falls back when unavailable)
|
|
100
|
+
--resume-setup UUID (resume this project's saved browser setup)
|
|
101
|
+
--browser-origin ORIGIN (trusted dashboard origin for a custom API)
|
|
86
102
|
--workspace UUID / --workspace-name NAME
|
|
87
103
|
--site UUID / --site-name NAME
|
|
88
104
|
--environment development|production (customer site environment)
|
|
@@ -101,6 +117,7 @@ userreason-wizard [--directory PATH] [--origin URL]
|
|
|
101
117
|
--diff (show the full patch for the application edit and the proposed guidance text)
|
|
102
118
|
--interactive (ask questions even when an agent harness or CI is detected)
|
|
103
119
|
--no-color (also NO_COLOR)
|
|
120
|
+
--no-telemetry (also UR_TELEMETRY_DISABLED=1)
|
|
104
121
|
--no-open (print the browser link without opening it)
|
|
105
122
|
--session-only (keep compatibility login only in memory; do not persist credentials)
|
|
106
123
|
--force (replace differing generated files)
|
|
@@ -118,6 +135,10 @@ Prompts are off when stdin or stdout is not a terminal, with --yes or --json, in
|
|
|
118
135
|
var nameError = (value) => !value.trim() || value.trim().length > 240 ? "Enter a name between 1 and 240 characters." : void 0;
|
|
119
136
|
var currentStep = "Reading wizard options";
|
|
120
137
|
var activeTerminal;
|
|
138
|
+
var analytics;
|
|
139
|
+
var surveyPreparation;
|
|
140
|
+
var surveyAbort = new AbortController();
|
|
141
|
+
var measured = (step, operation) => analytics ? analytics.measure(step, operation) : operation();
|
|
121
142
|
var frameworkLabel = (framework) => framework === "next" ? "Next.js" : framework;
|
|
122
143
|
var lowerFirst = (value) => value.charAt(0).toLowerCase() + value.slice(1);
|
|
123
144
|
async function main() {
|
|
@@ -127,7 +148,11 @@ async function main() {
|
|
|
127
148
|
help: { type: "boolean", short: "h" },
|
|
128
149
|
version: { type: "boolean", short: "v" },
|
|
129
150
|
dev: { type: "boolean" },
|
|
151
|
+
"browser-setup": { type: "boolean" },
|
|
152
|
+
"resume-setup": { type: "string" },
|
|
153
|
+
"browser-origin": { type: "string" },
|
|
130
154
|
"api-environment": { type: "string" },
|
|
155
|
+
"no-telemetry": { type: "boolean" },
|
|
131
156
|
yes: { type: "boolean" },
|
|
132
157
|
install: { type: "boolean" },
|
|
133
158
|
refresh: { type: "boolean" },
|
|
@@ -173,6 +198,17 @@ async function main() {
|
|
|
173
198
|
process.stdout.write(help);
|
|
174
199
|
return;
|
|
175
200
|
}
|
|
201
|
+
const browserMode = Boolean(values["browser-setup"] || values["resume-setup"]);
|
|
202
|
+
if (values["browser-setup"] && values["resume-setup"]) throw new Error("Choose --browser-setup or --resume-setup");
|
|
203
|
+
if (values["resume-setup"]) uuid(values["resume-setup"], "Setup ID");
|
|
204
|
+
if (values["browser-origin"]) {
|
|
205
|
+
if (!browserMode) throw new Error("--browser-origin requires browser setup");
|
|
206
|
+
apiUrl(values["browser-origin"], "Browser origin");
|
|
207
|
+
}
|
|
208
|
+
if (browserMode) {
|
|
209
|
+
const conflicts = ["refresh", "dry-run", "install", "skip-install", "integrate", "skip-integrate", "agent-note", "skip-agent-note", "agent-skill", "skip-agent-skill", "global-cli", "skip-global-cli", "cli-access", "skip-cli-access", "workspace", "workspace-name", "site", "site-name", "origin", "environment", "force", "diff", "session-only", "client-id", "credential-store"];
|
|
210
|
+
if (conflicts.some((key) => values[key] !== void 0 && values[key] !== false)) throw new Error("Browser setup choices are reviewed in the browser. Omit terminal installation/resource flags; ongoing CLI access is a separate login.");
|
|
211
|
+
}
|
|
176
212
|
if (values["credential-store"] !== void 0) credentialStoreKind(values["credential-store"]);
|
|
177
213
|
if (values["api-environment"] !== void 0 && !["production", "development"].includes(values["api-environment"]))
|
|
178
214
|
throw new Error("API environment must be development or production");
|
|
@@ -218,8 +254,25 @@ async function main() {
|
|
|
218
254
|
const tty = Boolean(process.stdin.isTTY && process.stdout.isTTY && process.env.TERM !== "dumb");
|
|
219
255
|
const explicitlyQuiet = Boolean(values.yes || values.json);
|
|
220
256
|
const interactive = tty && !explicitlyQuiet && (!harness || Boolean(values.interactive));
|
|
221
|
-
const terminal = new Terminal(interactive, Boolean(values.json), { color: !values["no-color"]
|
|
257
|
+
const terminal = new Terminal(interactive, Boolean(values.json), { color: !values["no-color"], onCancel: () => {
|
|
258
|
+
surveyAbort.abort(new Cancelled());
|
|
259
|
+
surveyPreparation?.cancel();
|
|
260
|
+
if (browserMode) {
|
|
261
|
+
process.exitCode = 130;
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
analytics?.finish(true);
|
|
265
|
+
process.exitCode = 130;
|
|
266
|
+
void (analytics?.flush(true) ?? Promise.resolve()).finally(() => process.exit(130));
|
|
267
|
+
} });
|
|
222
268
|
activeTerminal = terminal;
|
|
269
|
+
try {
|
|
270
|
+
analytics = new WizardAnalytics({ surface: "wizard", releaseVersion: version, executionMode: interactive ? "interactive" : process.env.CI ? "ci" : harness ? "agent" : "noninteractive", apiUrl: values["api-url"] ?? (developmentApi ? "https://api-dev.userreason.com" : "https://api.userreason.com"), disabled: values["no-telemetry"] || values["dry-run"] });
|
|
271
|
+
} catch {
|
|
272
|
+
}
|
|
273
|
+
if (!values.refresh) analytics?.configure({ context: { source_site_environment: newSiteEnvironment === "development" ? "development" : "production" } });
|
|
274
|
+
analytics?.begin("run");
|
|
275
|
+
await analytics?.checkpoint();
|
|
223
276
|
const { c, S } = terminal.kit;
|
|
224
277
|
const dot = ` ${S.dot} `;
|
|
225
278
|
const environmentNote = developmentApi ? `development API${newSiteEnvironment !== apiEnvironment ? `, new sites are ${newSiteEnvironment}` : ""}` : newSiteEnvironment !== apiEnvironment ? `new sites are ${newSiteEnvironment}` : void 0;
|
|
@@ -239,8 +292,27 @@ async function main() {
|
|
|
239
292
|
values.directory ?? process.cwd(),
|
|
240
293
|
values.framework
|
|
241
294
|
);
|
|
295
|
+
analytics?.configure({ wizard: { framework: project.framework, package_manager: project.packageManager } });
|
|
242
296
|
terminal.info(`${clean(project.name)} ${c.muted(`(${frameworkLabel(project.framework)}, ${project.packageManager})`)}`);
|
|
297
|
+
if (browserMode) {
|
|
298
|
+
currentStep = values["resume-setup"] ? "Resuming browser setup" : "Connecting browser setup";
|
|
299
|
+
const interrupted = () => surveyAbort.abort(new Cancelled());
|
|
300
|
+
process.once("SIGINT", interrupted);
|
|
301
|
+
process.once("SIGTERM", interrupted);
|
|
302
|
+
terminal.cancelState = "the local runner stopped; browser approvals, applied changes and saved drafts remain available when you resume";
|
|
303
|
+
let handled;
|
|
304
|
+
try {
|
|
305
|
+
handled = await runBrowserWizard({ project, apiOrigin: apiUrl(values["api-url"] ?? (developmentApi ? "https://api-dev.userreason.com" : "https://api.userreason.com")), browserOrigin: values["browser-origin"], resumeId: values["resume-setup"], profile, version, terminal, noOpen: Boolean(values["no-open"]), json: Boolean(values.json), signal: surveyAbort.signal, measurementDisabled: values["no-telemetry"] });
|
|
306
|
+
} finally {
|
|
307
|
+
process.off("SIGINT", interrupted);
|
|
308
|
+
process.off("SIGTERM", interrupted);
|
|
309
|
+
}
|
|
310
|
+
if (handled) return;
|
|
311
|
+
terminal.cancelState = "nothing was written";
|
|
312
|
+
terminal.info("This server has not enabled browser setup. Continuing with the existing terminal wizard.");
|
|
313
|
+
}
|
|
243
314
|
if (values.refresh) {
|
|
315
|
+
analytics?.configure({ wizard: { resumed: true } });
|
|
244
316
|
currentStep = "Refreshing UserReason packages";
|
|
245
317
|
const existing = await detectInstallation(project);
|
|
246
318
|
if (!existing) throw new Error("No UserReason initialization found. Run the wizard without --refresh to set up this application.");
|
|
@@ -253,18 +325,49 @@ async function main() {
|
|
|
253
325
|
const started = Date.now();
|
|
254
326
|
await terminal.task("Updating UserReason packages", async () => {
|
|
255
327
|
if (!await hasCompatibleSdk(project, profile) || values.install) {
|
|
256
|
-
await installSdk(project, options);
|
|
328
|
+
await measured("sdk_install", () => installSdk(project, options));
|
|
257
329
|
updated.push("@userreason/js");
|
|
258
330
|
}
|
|
259
331
|
if (!await hasCompatibleCli(project, profile) || values.install) {
|
|
260
|
-
await installCli(project, options);
|
|
332
|
+
await measured("cli_install", () => installCli(project, options));
|
|
261
333
|
updated.push("@userreason/cli");
|
|
262
334
|
}
|
|
263
335
|
}, () => updated.length ? `Updated ${updated.map((name) => c.code(name)).join(", ")} ${c.muted(`(${project.packageManager}, ${Math.max(1, Math.round((Date.now() - started) / 1e3))}s)`)}` : "UserReason packages are already current");
|
|
264
|
-
const
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
336
|
+
const refreshOption = async (step, requested, skipped, eligible, operation) => {
|
|
337
|
+
if (!requested) {
|
|
338
|
+
analytics?.step(step, "skipped", { selection_source: skipped ? "flag" : "default", reason: skipped ? "explicit_skip" : "not_requested" });
|
|
339
|
+
return operation();
|
|
340
|
+
}
|
|
341
|
+
if (await eligible().catch(() => false)) analytics?.step(step, "eligible");
|
|
342
|
+
analytics?.step(step, "selected", { selection_source: "flag" });
|
|
343
|
+
return measured(step, operation);
|
|
344
|
+
};
|
|
345
|
+
const globalCli2 = await refreshOption(
|
|
346
|
+
"global_cli",
|
|
347
|
+
values["global-cli"],
|
|
348
|
+
values["skip-global-cli"],
|
|
349
|
+
async () => true,
|
|
350
|
+
() => offerGlobalCli(project, terminal, { installed: true, requested: values["global-cli"], skip: !values["global-cli"], force: values.install, verbose: values.debug, profile, preview: Boolean(values.diff) })
|
|
351
|
+
);
|
|
352
|
+
const agentNote2 = await refreshOption(
|
|
353
|
+
"agent_note",
|
|
354
|
+
values["agent-note"],
|
|
355
|
+
values["skip-agent-note"],
|
|
356
|
+
async () => "path" in await planAgentNote(project),
|
|
357
|
+
() => offerAgentNote(project, terminal, { installed: true, requested: values["agent-note"], skip: !values["agent-note"], preview: Boolean(values.diff) })
|
|
358
|
+
);
|
|
359
|
+
const agentSkill2 = await refreshOption(
|
|
360
|
+
"agent_skill",
|
|
361
|
+
values["agent-skill"],
|
|
362
|
+
values["skip-agent-skill"],
|
|
363
|
+
async () => "files" in await planAgentSkill(project),
|
|
364
|
+
() => offerAgentSkill(project, terminal, { installed: true, requested: values["agent-skill"], skip: !values["agent-skill"], preview: Boolean(values.diff) })
|
|
365
|
+
);
|
|
366
|
+
const cliAccess2 = await refreshOption("cli_access", values["cli-access"], values["skip-cli-access"], async () => true, async () => {
|
|
367
|
+
if (!values["cli-access"]) return { status: "skipped" };
|
|
368
|
+
const accessConfig = await resolveConfig({ development: developmentApi, apiUrl: existing.apiBaseUrl, clientId: values["client-id"], credentialStore: values["credential-store"] });
|
|
369
|
+
return offerCliAccess(accessConfig, terminal, { installed: true, requested: true, noOpen: values["no-open"], development: developmentApi, preview: Boolean(values.diff) });
|
|
370
|
+
});
|
|
268
371
|
const untouched = [!values["global-cli"] && ["global command", "--global-cli"], !values["agent-note"] && ["AGENTS.md note", "--agent-note"], !values["agent-skill"] && ["agent skill", "--agent-skill"], !values["cli-access"] && ["CLI access", "--cli-access"]].filter(Boolean);
|
|
269
372
|
terminal.block("Ready", [
|
|
270
373
|
c.muted("Reload or restart your app to load the updated SDK."),
|
|
@@ -334,6 +437,7 @@ async function main() {
|
|
|
334
437
|
clientId: values["client-id"],
|
|
335
438
|
credentialStore: values["credential-store"]
|
|
336
439
|
});
|
|
440
|
+
analytics?.configure({ apiUrl: config.apiUrl });
|
|
337
441
|
let resumeStorageBlocked = false;
|
|
338
442
|
const warnResumeStorage = () => {
|
|
339
443
|
if (resumeStorageBlocked) return;
|
|
@@ -350,12 +454,14 @@ async function main() {
|
|
|
350
454
|
let workspaceChoice = values.workspace ? uuid(values.workspace) : saved?.workspaceId;
|
|
351
455
|
const siteChoice = values.site ? uuid(values.site) : saved?.siteId;
|
|
352
456
|
const resumed = Boolean(saved && !values.workspace && !values.site);
|
|
457
|
+
analytics?.configure({ wizard: { resumed } });
|
|
353
458
|
if (siteChoice && !workspaceChoice) {
|
|
354
459
|
currentStep = "Resolving the existing site";
|
|
355
460
|
const origin = values.origin ? normalizeOrigin(values.origin, newSiteEnvironment === "development" ? "development" : "production") : void 0;
|
|
356
461
|
workspaceChoice = (await resolveInstallation({ siteId: siteChoice, apiBaseUrl: config.apiUrl }, origin)).workspaceId;
|
|
357
462
|
}
|
|
358
|
-
|
|
463
|
+
const rawCredentials = resolveCredentials(config);
|
|
464
|
+
let credentials = analytics?.observeCredentials(rawCredentials) ?? rawCredentials, client = new UserReasonClient(config, credentials), connection;
|
|
359
465
|
const open = async (url) => !values["no-open"] && await openBrowser(url);
|
|
360
466
|
const approvalWait = async (label, url, note) => {
|
|
361
467
|
const opened = await open(url);
|
|
@@ -373,6 +479,8 @@ async function main() {
|
|
|
373
479
|
let waiting;
|
|
374
480
|
let unrestrictedOrigins = false;
|
|
375
481
|
currentStep = "Connecting browser sign-in and approval";
|
|
482
|
+
analytics?.begin("authentication");
|
|
483
|
+
await analytics?.checkpoint();
|
|
376
484
|
try {
|
|
377
485
|
connection = await connectInstallation(
|
|
378
486
|
config,
|
|
@@ -399,7 +507,9 @@ async function main() {
|
|
|
399
507
|
}
|
|
400
508
|
);
|
|
401
509
|
waiting?.stop();
|
|
402
|
-
|
|
510
|
+
const temporaryCredentials = memoryCredentials(connection.session);
|
|
511
|
+
credentials = analytics?.observeCredentials(temporaryCredentials) ?? temporaryCredentials;
|
|
512
|
+
analytics?.setSession(connection.session);
|
|
403
513
|
client = new UserReasonClient(config, credentials, {
|
|
404
514
|
lock: (operation) => operation()
|
|
405
515
|
});
|
|
@@ -419,7 +529,8 @@ async function main() {
|
|
|
419
529
|
return terminal.confirm("Keep this session in memory only? No credentials will be saved.");
|
|
420
530
|
}
|
|
421
531
|
);
|
|
422
|
-
credentials = compatibility.credentials;
|
|
532
|
+
credentials = analytics?.observeCredentials(compatibility.credentials) ?? compatibility.credentials;
|
|
533
|
+
analytics?.setSession(compatibility.session);
|
|
423
534
|
client = new UserReasonClient(
|
|
424
535
|
config,
|
|
425
536
|
credentials,
|
|
@@ -471,6 +582,11 @@ async function main() {
|
|
|
471
582
|
await deviceSignIn();
|
|
472
583
|
account = await client.account();
|
|
473
584
|
}
|
|
585
|
+
analytics?.end("authentication");
|
|
586
|
+
if (developmentApi && terminal.interactive && !values.yes && !values.json && !values.diff) {
|
|
587
|
+
surveyPreparation = beginFirstSurveyPreparation(project.directory, { development: developmentApi, interactive: terminal.interactive });
|
|
588
|
+
}
|
|
589
|
+
analytics?.begin("target_selection");
|
|
474
590
|
const who = connection ? clean(connection.session.email) : void 0;
|
|
475
591
|
let selectedWorkspace;
|
|
476
592
|
const approvedWorkspace = connection?.workspaceId ?? workspaceChoice;
|
|
@@ -555,6 +671,8 @@ async function main() {
|
|
|
555
671
|
siteId: selectedSite?.id ?? siteIds.siteId,
|
|
556
672
|
apiBaseUrl: config.apiUrl
|
|
557
673
|
};
|
|
674
|
+
analytics?.end("target_selection");
|
|
675
|
+
analytics?.configure({ context: { ...selectedWorkspace ? { workspace_id: selectedWorkspace.id } : {}, ...selectedSite ? { site_id: selectedSite.id } : {}, source_site_environment: selectedSite?.environment ?? environment } });
|
|
558
676
|
currentStep = "Preparing the application integration";
|
|
559
677
|
const reviewed = values["skip-integrate"] ? void 0 : await planIntegration(project, installation);
|
|
560
678
|
const additions = reviewed ? integrationAdditions(reviewed) : void 0;
|
|
@@ -577,18 +695,37 @@ async function main() {
|
|
|
577
695
|
]);
|
|
578
696
|
} else terminal.block("Changes", [reviewed?.status === "integrated" && !packages.length ? c.muted(`nothing to edit${dot}@userreason/js and @userreason/cli are current`) : installRow]);
|
|
579
697
|
const extras = [];
|
|
698
|
+
if (developmentApi && interactive && !values.diff) extras.push({ value: "surveys", label: "Recommend surveys (share selected app code with Cerebras and OpenAI)", hint: "Optional. Suggestions first; drafts only when selected. No publishing or event edits.", initial: true });
|
|
580
699
|
if (reviewed?.status === "ready" && additions) extras.push({ value: "edit", label: `${additions.created ? "Create" : "Edit"} ${additions.path}`, hint: "add UserReason.init", initial: true });
|
|
581
700
|
if (noteProbe && "path" in noteProbe) extras.push({ value: "note", label: `${noteProbe.file} ${noteProbe.replacement ? "note update" : "note"}`, hint: "user-feedback guidance", initial: true });
|
|
582
701
|
if (skillProbe && "files" in skillProbe) extras.push({ value: "skill", label: skillProbe.update ? "Agent skill update" : "Agent skill", hint: ".agents/skills/userreason", initial: true });
|
|
583
702
|
if (!values["skip-cli-access"] && !values["session-only"]) extras.push({ value: "access", label: "Ongoing CLI access", hint: "second approval (90 days)", initial: true });
|
|
584
703
|
if (!values["skip-global-cli"] && !values["skip-install"]) extras.push({ value: "global", label: "Global userreason command", hint: `optional${dot}npm i -g, replaces the current global CLI`, initial: Boolean(values["global-cli"]) });
|
|
704
|
+
for (const item of extras) {
|
|
705
|
+
if (item.value === "surveys") continue;
|
|
706
|
+
const step = { edit: "initialization", note: "agent_note", skill: "agent_skill", access: "cli_access", global: "global_cli" }[item.value];
|
|
707
|
+
analytics?.step(step, "eligible");
|
|
708
|
+
if (interactive) analytics?.step(step, "offered", { selection_source: "prompt" });
|
|
709
|
+
}
|
|
710
|
+
if (interactive && extras.length) analytics?.begin("options");
|
|
711
|
+
await analytics?.checkpoint();
|
|
585
712
|
const picked = interactive ? new Set(extras.length ? await terminal.multiselect(`Set up ${c.muted(`${dot.trim()} recommended steps are selected`)}`, extras, extras.filter((item) => item.initial).map((item) => item.value)) : []) : void 0;
|
|
713
|
+
if (interactive && extras.length) {
|
|
714
|
+
analytics?.end("options");
|
|
715
|
+
for (const item of extras) {
|
|
716
|
+
if (item.value === "surveys") continue;
|
|
717
|
+
const step = { edit: "initialization", note: "agent_note", skill: "agent_skill", access: "cli_access", global: "global_cli" }[item.value];
|
|
718
|
+
analytics?.step(step, picked?.has(item.value) ? "selected" : "declined", { selection_source: "prompt" });
|
|
719
|
+
}
|
|
720
|
+
}
|
|
586
721
|
const integrate = Boolean(reviewed?.status === "ready" && (picked ? picked.has("edit") : values.integrate || values.yes));
|
|
587
722
|
const choice = (key, flag, skipFlag) => picked ? { requested: picked.has(key), skip: !picked.has(key) } : { requested: Boolean(values[flag]), skip: skipFlag };
|
|
723
|
+
if (!interactive) analytics?.step("initialization", integrate ? "selected" : "skipped", { selection_source: values.integrate || values["skip-integrate"] || values.yes ? "flag" : "default", ...!integrate ? { reason: values["skip-integrate"] ? "explicit_skip" : "not_requested" } : {} });
|
|
588
724
|
const noteChoice = choice("note", "agent-note", Boolean(values["skip-agent-note"]));
|
|
589
725
|
const skillChoice = choice("skill", "agent-skill", Boolean(values["skip-agent-skill"]));
|
|
590
726
|
const globalChoice = choice("global", "global-cli", Boolean(values["skip-global-cli"] || values["skip-install"]));
|
|
591
727
|
const accessChoice = choice("access", "cli-access", Boolean(values["skip-cli-access"] || values["session-only"]));
|
|
728
|
+
if (!interactive) for (const [step, decision] of [["agent_note", noteChoice], ["agent_skill", skillChoice], ["global_cli", globalChoice], ["cli_access", accessChoice]]) analytics?.step(step, decision.requested ? "selected" : "skipped", { selection_source: decision.requested || decision.skip ? "flag" : "default", ...!decision.requested ? { reason: decision.skip ? "explicit_skip" : "not_requested" } : {} });
|
|
592
729
|
terminal.cancelState = "some steps are done; rerun the wizard to continue";
|
|
593
730
|
if (!selectedWorkspace) {
|
|
594
731
|
currentStep = "Creating the workspace";
|
|
@@ -625,6 +762,7 @@ async function main() {
|
|
|
625
762
|
);
|
|
626
763
|
terminal.success(`Created site ${c.code(clean(selectedSite.name))}`);
|
|
627
764
|
}
|
|
765
|
+
analytics?.configure({ context: { workspace_id: selectedWorkspace.id, site_id: selectedSite.id, source_site_environment: selectedSite.environment } });
|
|
628
766
|
currentStep = "Saving optional installation resume details";
|
|
629
767
|
if (!await saveInstallation(project.directory, installation)) warnResumeStorage();
|
|
630
768
|
currentStep = "Preparing initialization files";
|
|
@@ -645,9 +783,10 @@ async function main() {
|
|
|
645
783
|
await terminal.task("Installing @userreason/js, @userreason/cli", async () => {
|
|
646
784
|
if (shouldInstall) {
|
|
647
785
|
try {
|
|
648
|
-
|
|
786
|
+
const operation = () => installSdk(project, { profile, verbose: values.debug, onWarning: (message) => {
|
|
649
787
|
warnings.push(message);
|
|
650
788
|
} });
|
|
789
|
+
await measured("sdk_install", operation);
|
|
651
790
|
sdkInstalled = true;
|
|
652
791
|
installed.push("@userreason/js");
|
|
653
792
|
} catch (error) {
|
|
@@ -658,9 +797,10 @@ async function main() {
|
|
|
658
797
|
}
|
|
659
798
|
if (shouldInstallCli) {
|
|
660
799
|
try {
|
|
661
|
-
|
|
800
|
+
const operation = () => installCli(project, { profile, verbose: values.debug, onWarning: (message) => {
|
|
662
801
|
warnings.push(message);
|
|
663
802
|
} });
|
|
803
|
+
await measured("cli_install", operation);
|
|
664
804
|
cliInstalled = true;
|
|
665
805
|
installed.push("@userreason/cli");
|
|
666
806
|
} catch (error) {
|
|
@@ -684,16 +824,17 @@ Then rerun the wizard. Your saved workspace and site will be reused.`, failure.t
|
|
|
684
824
|
const concrete = await planIntegration(project, installation);
|
|
685
825
|
if (reviewed.status !== "ready" || concrete.status !== "ready" || concrete.path !== reviewed.path || concrete.before !== reviewed.before || concrete.after !== reviewed.after)
|
|
686
826
|
throw new Error("The application entry changed after the preview. Rerun to review it again.");
|
|
687
|
-
await applyIntegration(concrete);
|
|
827
|
+
await measured("initialization", () => applyIntegration(concrete));
|
|
688
828
|
if (concrete.before === null) generated.files.push(concrete.path);
|
|
689
829
|
terminal.success(`${concrete.before === null ? "Created" : "Edited"} ${c.code(additions?.path ?? "")}`);
|
|
690
830
|
}
|
|
831
|
+
if (existingPlan?.status === "integrated") analytics?.step("initialization", "already_present");
|
|
691
832
|
const integrated = Boolean(integrate && !installFailed || existingPlan?.status === "integrated");
|
|
692
833
|
if (!integrated && !installFailed) terminal.note(generated.instruction, "Application integration");
|
|
693
834
|
currentStep = "Checking site configuration";
|
|
694
835
|
const verification = await terminal.task(
|
|
695
836
|
"Checking site configuration",
|
|
696
|
-
() => verifyConfiguration(installation, hostOrigin ?? "https://installation.userreason.invalid"),
|
|
837
|
+
() => analytics ? analytics.measure("configuration_check", () => verifyConfiguration(installation, hostOrigin ?? "https://installation.userreason.invalid"), "completed") : verifyConfiguration(installation, hostOrigin ?? "https://installation.userreason.invalid"),
|
|
697
838
|
"Site configuration reachable"
|
|
698
839
|
);
|
|
699
840
|
if (integrated && sdkInstalled && !installFailed) {
|
|
@@ -705,13 +846,30 @@ Then rerun the wizard. Your saved workspace and site will be reused.`, failure.t
|
|
|
705
846
|
if (picked && !completed && !installFailed && (picked.has("note") || picked.has("skill")))
|
|
706
847
|
terminal.warn("The note and skill wait for an initialized SDK. Rerun with the entry edit selected, or apply the initialization yourself first.");
|
|
707
848
|
currentStep = "Offering the optional user feedback note";
|
|
708
|
-
const agentNote = await offerAgentNote(project, terminal, { installed: completed, ...noteChoice, preview: Boolean(values.diff) });
|
|
849
|
+
const agentNote = await measured("agent_note", () => offerAgentNote(project, terminal, { installed: completed, ...noteChoice, preview: Boolean(values.diff) }));
|
|
709
850
|
currentStep = "Offering the optional feedback agent skill";
|
|
710
|
-
const agentSkill = await offerAgentSkill(project, terminal, { installed: completed, ...skillChoice, preview: Boolean(values.diff) });
|
|
851
|
+
const agentSkill = await measured("agent_skill", () => offerAgentSkill(project, terminal, { installed: completed, ...skillChoice, preview: Boolean(values.diff) }));
|
|
711
852
|
currentStep = "Offering the optional global CLI";
|
|
712
|
-
const globalCli = await offerGlobalCli(project, terminal, { installed: cliInstalled && !installFailed, ...globalChoice, force: values.install, verbose: values.debug, profile, preview: Boolean(values.diff) });
|
|
853
|
+
const globalCli = await measured("global_cli", () => offerGlobalCli(project, terminal, { installed: cliInstalled && !installFailed, ...globalChoice, force: values.install, verbose: values.debug, profile, preview: Boolean(values.diff) }));
|
|
713
854
|
currentStep = "Offering ongoing CLI access";
|
|
714
|
-
const cliAccess = await offerCliAccess(config, terminal, { installed: cliInstalled && !installFailed, ...accessChoice, noOpen: values["no-open"], development: developmentApi, preview: Boolean(values.diff) });
|
|
855
|
+
const cliAccess = await measured("cli_access", () => offerCliAccess(config, terminal, { installed: cliInstalled && !installFailed, ...accessChoice, noOpen: values["no-open"], development: developmentApi, preview: Boolean(values.diff) }));
|
|
856
|
+
if (completed && terminal.interactive && !values.yes && !values.json && !values.diff) {
|
|
857
|
+
try {
|
|
858
|
+
currentStep = "Creating the first survey";
|
|
859
|
+
await offerFirstSurvey(new UserReasonClient(config, resolveCredentials(config)), project.directory, selectedWorkspace.id, selectedSite.id, {
|
|
860
|
+
show: (message) => terminal.note(message, developmentApi ? "Recommended surveys" : "First survey"),
|
|
861
|
+
confirm: (message) => terminal.confirm(message, false),
|
|
862
|
+
choose: (message, options, initialValue) => terminal.select(message, options, initialValue),
|
|
863
|
+
answer: (message) => terminal.text(message),
|
|
864
|
+
chooseMany: (message, options, initial) => terminal.multiselect(message, options, initial),
|
|
865
|
+
loading: (message, work) => terminal.task(message, work, () => void 0),
|
|
866
|
+
signal: surveyAbort.signal
|
|
867
|
+
}, { development: developmentApi, interactive: terminal.interactive, product: selectedSite.name, preparation: surveyPreparation, sourceConsent: picked?.has("surveys") });
|
|
868
|
+
} catch (error) {
|
|
869
|
+
terminal.warn("Optional first-survey assistance did not finish. Installation is preserved. Use the ongoing CLI connection with site:read and survey:write; no installation grant is broadened.");
|
|
870
|
+
terminal.note(firstSurveyHandoff(project.directory, config.apiUrl, selectedWorkspace.id, selectedSite.id), "Resume with your agent");
|
|
871
|
+
}
|
|
872
|
+
}
|
|
715
873
|
const nextStep = installFailed ? `Run ${sdkInstalled ? cliInstallCommand(project, profile) : sdkInstallCommand(project, profile)} in your normal terminal, then rerun the wizard to finish setup.` : integrated ? "Start your app and open it in the browser to connect the SDK." : generated.instruction;
|
|
716
874
|
const siteLine = `${clean(selectedWorkspace.name)} ${S.arrow} ${clean(selectedSite.name)} ${c.muted(`(${siteDetail(selectedSite)})`)}`;
|
|
717
875
|
terminal.block(installFailed ? "Saved" : "Ready", [c.muted(installFailed ? "SDK installation is pending. After installing, rerun the wizard; your site is reused." : "SDK not connected yet. Start your app to connect it.")], { suffix: siteLine, kind: installFailed ? "warn" : "done" });
|
|
@@ -749,11 +907,16 @@ var approvalProgress;
|
|
|
749
907
|
main().catch((error) => {
|
|
750
908
|
const detail = error instanceof Error ? error.message : "Installation failed";
|
|
751
909
|
if (error instanceof Cancelled) {
|
|
752
|
-
|
|
910
|
+
analytics?.finish(true);
|
|
911
|
+
if (activeTerminal) {
|
|
912
|
+
activeTerminal.cancelled();
|
|
913
|
+
return;
|
|
914
|
+
}
|
|
753
915
|
process.stderr.write(detail + "\n");
|
|
754
916
|
process.exitCode = 130;
|
|
755
917
|
return;
|
|
756
918
|
}
|
|
919
|
+
analytics?.finish(false, true);
|
|
757
920
|
const message = `${currentStep}: ${detail}`;
|
|
758
921
|
if (process.argv.includes("--json"))
|
|
759
922
|
process.stdout.write(JSON.stringify({ error: "wizard_failed", step: currentStep, message }) + "\n");
|
|
@@ -761,4 +924,8 @@ main().catch((error) => {
|
|
|
761
924
|
activeTerminal.error(clean(detail), [`while ${lowerFirst(currentStep)}`]);
|
|
762
925
|
else process.stderr.write(message + "\n");
|
|
763
926
|
process.exitCode = 1;
|
|
927
|
+
}).finally(async () => {
|
|
928
|
+
surveyPreparation?.cancel();
|
|
929
|
+
analytics?.finish(false, Boolean(process.exitCode));
|
|
930
|
+
await analytics?.flush(true);
|
|
764
931
|
});
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { createRequire as createWizardRequire } from 'node:module'; import { fileURLToPath as wizardFileURLToPath } from 'node:url'; import { dirname as wizardDirname } from 'node:path'; const require = createWizardRequire(import.meta.url); const __filename = wizardFileURLToPath(import.meta.url); const __dirname = wizardDirname(__filename);
|
|
2
2
|
import {
|
|
3
3
|
detectInstallation
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-5IO5LY22.js";
|
|
5
5
|
import {
|
|
6
6
|
DEFAULT_API
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-CADA5WZ3.js";
|
|
8
8
|
import {
|
|
9
9
|
apiUrl,
|
|
10
10
|
configDirectory,
|
|
11
11
|
uuid
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-77SK7TKZ.js";
|
|
13
13
|
|
|
14
14
|
// src/state.ts
|
|
15
15
|
import { mkdir, readFile, writeFile, rename, rm, realpath, lstat } from "node:fs/promises";
|
|
@@ -3,10 +3,10 @@ import {
|
|
|
3
3
|
DEFAULT_API,
|
|
4
4
|
initializationSource,
|
|
5
5
|
integrationSource
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-CADA5WZ3.js";
|
|
7
7
|
import {
|
|
8
8
|
require_typescript
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-77SK7TKZ.js";
|
|
10
10
|
import {
|
|
11
11
|
__toESM
|
|
12
12
|
} from "./chunk-WL3NOIM6.js";
|
|
@@ -673,8 +673,26 @@ function reactRoots(ast) {
|
|
|
673
673
|
if (!creationCount && renders.length > 1) return [];
|
|
674
674
|
return renders.flatMap((node) => node.arguments[0] ? [node.arguments[0]] : []);
|
|
675
675
|
}
|
|
676
|
-
function
|
|
677
|
-
const
|
|
676
|
+
function integrationReferences(ast) {
|
|
677
|
+
const modules = nodes(ast, import_typescript.default.isStringLiteral).filter((literal) => {
|
|
678
|
+
const parent = literal.parent;
|
|
679
|
+
return (import_typescript.default.isImportDeclaration(parent) || import_typescript.default.isExportDeclaration(parent)) && parent.moduleSpecifier === literal || import_typescript.default.isExternalModuleReference(parent) && parent.expression === literal || import_typescript.default.isCallExpression(parent) && parent.arguments[0] === literal && (parent.expression.kind === import_typescript.default.SyntaxKind.ImportKeyword || import_typescript.default.isIdentifier(parent.expression) && parent.expression.text === "require");
|
|
680
|
+
}).map((literal) => literal.text);
|
|
681
|
+
const tags = nodes(ast, (node) => import_typescript.default.isJsxOpeningElement(node) || import_typescript.default.isJsxSelfClosingElement(node)).map((node) => node.tagName.getText(ast));
|
|
682
|
+
const globalAccess = nodes(ast, import_typescript.default.isElementAccessExpression).some((node) => import_typescript.default.isIdentifier(node.expression) && ["window", "globalThis", "self", "global"].includes(node.expression.text) && import_typescript.default.isStringLiteralLike(node.argumentExpression) && node.argumentExpression.text === "UserReason");
|
|
683
|
+
const identifier = nodes(ast, import_typescript.default.isIdentifier).some((node) => {
|
|
684
|
+
if (node.text !== "UserReason") return false;
|
|
685
|
+
const parent = node.parent;
|
|
686
|
+
if ((import_typescript.default.isPropertyAssignment(parent) || import_typescript.default.isPropertyDeclaration(parent) || import_typescript.default.isPropertySignature(parent) || import_typescript.default.isMethodDeclaration(parent) || import_typescript.default.isMethodSignature(parent) || import_typescript.default.isGetAccessorDeclaration(parent) || import_typescript.default.isSetAccessorDeclaration(parent) || import_typescript.default.isJsxAttribute(parent)) && parent.name === node) return false;
|
|
687
|
+
if ((import_typescript.default.isBindingElement(parent) || import_typescript.default.isImportSpecifier(parent)) && parent.propertyName === node) return false;
|
|
688
|
+
if (import_typescript.default.isExportSpecifier(parent) && parent.name === node && parent.propertyName) return false;
|
|
689
|
+
if (import_typescript.default.isLabeledStatement(parent) || import_typescript.default.isBreakStatement(parent) || import_typescript.default.isContinueStatement(parent)) return false;
|
|
690
|
+
return true;
|
|
691
|
+
});
|
|
692
|
+
return { modules, tags, identifier: identifier || globalAccess };
|
|
693
|
+
}
|
|
694
|
+
function existing(text, config = dummy, path = "entry.tsx") {
|
|
695
|
+
const ast = parse(path, text), calls = ast ? sdkCalls(ast) : [];
|
|
678
696
|
if (calls.length) {
|
|
679
697
|
try {
|
|
680
698
|
let first;
|
|
@@ -690,11 +708,13 @@ function existing(text, config = dummy) {
|
|
|
690
708
|
}
|
|
691
709
|
return { status: "integrated", reason: "SDK initialization is already present; its configuration is preserved." };
|
|
692
710
|
}
|
|
693
|
-
if (
|
|
711
|
+
if (!ast) return;
|
|
712
|
+
const references = integrationReferences(ast);
|
|
713
|
+
if (references.modules.some((name) => /userreason\.generated/.test(name)) && references.tags.includes("UserReasonProvider"))
|
|
694
714
|
return { status: "integrated", reason: "Existing generated initialization is already present." };
|
|
695
|
-
if (/userreason\.client/.test(
|
|
715
|
+
if (references.modules.some((name) => /userreason\.client/.test(name)) && references.tags.includes("UserReasonInit"))
|
|
696
716
|
return { status: "integrated", reason: "Browser initialization is already present." };
|
|
697
|
-
if (
|
|
717
|
+
if (references.identifier || references.modules.some((name) => name === "@userreason/js" || /userreason\.(?:generated|client)/.test(name)))
|
|
698
718
|
return { status: "manual", reason: "An existing UserReason integration needs review before editing the entry." };
|
|
699
719
|
}
|
|
700
720
|
async function planIntegration(project, config = dummy) {
|
|
@@ -716,11 +736,13 @@ async function planIntegration(project, config = dummy) {
|
|
|
716
736
|
const found2 = files.filter((value) => value.text !== void 0);
|
|
717
737
|
if (found2.length > 1) return { status: "manual", reason: "Multiple instrumentation-client files need review." };
|
|
718
738
|
for (const root of ["app/layout.tsx", "app/layout.jsx", "app/layout.js", "pages/_app.tsx", "pages/_app.jsx", "pages/_app.js"]) {
|
|
719
|
-
const rootText = await source(project,
|
|
720
|
-
|
|
739
|
+
const rootPath = join(directory, root), rootText = await source(project, rootPath);
|
|
740
|
+
const rootAst = rootText ? parse(rootPath, rootText) : void 0;
|
|
741
|
+
if (rootText && rootAst && integrationReferences(rootAst).modules.some((name2) => /userreason\.(?:generated|client)/.test(name2)))
|
|
742
|
+
return existing(rootText, dummy, rootPath) ?? { status: "manual", reason: "Existing root initialization needs review." };
|
|
721
743
|
}
|
|
722
744
|
const { path: path2, text: text2 } = found2[0] ?? files[project.typescript ? 0 : 1];
|
|
723
|
-
const current2 = text2 ? existing(text2, config) : void 0;
|
|
745
|
+
const current2 = text2 ? existing(text2, config, path2) : void 0;
|
|
724
746
|
if (current2) return current2;
|
|
725
747
|
const ast = parse(path2, text2 ?? "");
|
|
726
748
|
if (!ast) return { status: "manual", reason: "Client instrumentation could not be parsed safely." };
|
|
@@ -776,7 +798,7 @@ ${initializationSource(config)}`),
|
|
|
776
798
|
};
|
|
777
799
|
const { path, text } = found[0];
|
|
778
800
|
const name = project.framework === "next" ? "UserReasonInit" : "UserReason";
|
|
779
|
-
const current = existing(text, config);
|
|
801
|
+
const current = existing(text, config, path);
|
|
780
802
|
if (current) return current;
|
|
781
803
|
let after;
|
|
782
804
|
{
|