@userreason/wizard 0.2.1 → 0.3.1
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 +95 -0
- package/dist/agent-note.js +7 -6
- package/dist/agent-skill.js +6 -5
- package/dist/analytics.js +9 -0
- package/dist/bin.js +222 -51
- package/dist/chunk-4INLEQE2.js +196 -0
- package/dist/{chunk-GGARVSPT.js → chunk-7AAH6C4L.js} +9198 -5670
- package/dist/{chunk-ULHKVBPD.js → chunk-7O7H3PIM.js} +7 -7
- package/dist/chunk-CSZW2ULJ.js +152 -0
- package/dist/{chunk-3RDJORRS.js → chunk-DMXUXEQI.js} +1 -1
- package/dist/{chunk-SJVLAYGG.js → chunk-EVNEX5N5.js} +8 -1
- package/dist/chunk-KF37D5WL.js +44 -0
- package/dist/{chunk-5SC2K42Q.js → chunk-LEJFE4U5.js} +2 -2
- package/dist/{chunk-OEGNGGZ2.js → chunk-NMHTFC5Q.js} +10 -3
- package/dist/{chunk-6CJ4ANMN.js → chunk-NNPYUATH.js} +1 -1
- package/dist/chunk-PJQOSDYS.js +50 -0
- package/dist/chunk-Q5U5UOQN.js +288 -0
- package/dist/{chunk-5Z5J6PY5.js → chunk-SB3AYQWG.js} +6 -6
- package/dist/{chunk-YMSGDC4B.js → chunk-TOID3NYP.js} +40 -11
- package/dist/{chunk-JD5U4U26.js → chunk-TRBSH5G7.js} +6 -6
- package/dist/{chunk-ZGZOBW2B.js → chunk-XASPGFYK.js} +3 -3
- package/dist/{chunk-HACTNBV3.js → chunk-XPFKXLIZ.js} +3 -3
- package/dist/chunk-ZHJV247H.js +31 -0
- package/dist/cli-access.js +3 -3
- package/dist/connection.js +2 -2
- package/dist/first-survey.js +11 -0
- package/dist/footer.js +17 -0
- package/dist/global-cli.js +6 -5
- package/dist/install-diagnostics.js +9 -0
- package/dist/integrate.js +5 -4
- package/dist/project.js +8 -3
- package/dist/registry.js +5 -3
- package/dist/setup-flow.js +25 -0
- package/dist/setup.js +33 -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 +6 -5
- package/dist/ui.js +2 -2
- package/package.json +1 -2
package/dist/bin.js
CHANGED
|
@@ -1,50 +1,48 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
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);
|
|
3
|
+
import {
|
|
4
|
+
runBrowserWizard
|
|
5
|
+
} from "./chunk-CSZW2ULJ.js";
|
|
6
|
+
import {
|
|
7
|
+
clearInstallation,
|
|
8
|
+
resolveInstallation,
|
|
9
|
+
saveInstallation,
|
|
10
|
+
savedInstallation
|
|
11
|
+
} from "./chunk-XASPGFYK.js";
|
|
3
12
|
import {
|
|
4
13
|
offerAgentNote,
|
|
5
14
|
planAgentNote
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import {
|
|
8
|
-
offerAgentSkill,
|
|
9
|
-
planAgentSkill
|
|
10
|
-
} from "./chunk-5Z5J6PY5.js";
|
|
15
|
+
} from "./chunk-7O7H3PIM.js";
|
|
11
16
|
import {
|
|
12
17
|
offerCliAccess
|
|
13
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-XPFKXLIZ.js";
|
|
14
19
|
import {
|
|
15
20
|
offerGlobalCli
|
|
16
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-TRBSH5G7.js";
|
|
17
22
|
import {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
} from "./chunk-6CJ4ANMN.js";
|
|
23
|
+
WizardAnalytics
|
|
24
|
+
} from "./chunk-KF37D5WL.js";
|
|
21
25
|
import {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
openBrowser
|
|
28
|
-
} from "./chunk-SJVLAYGG.js";
|
|
26
|
+
beginFirstSurveyPreparation,
|
|
27
|
+
offerFirstSurvey
|
|
28
|
+
} from "./chunk-ZHJV247H.js";
|
|
29
|
+
import "./chunk-Q5U5UOQN.js";
|
|
30
|
+
import "./chunk-4INLEQE2.js";
|
|
29
31
|
import {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
memoryCredentials
|
|
34
|
-
} from "./chunk-3RDJORRS.js";
|
|
32
|
+
offerAgentSkill,
|
|
33
|
+
planAgentSkill
|
|
34
|
+
} from "./chunk-SB3AYQWG.js";
|
|
35
35
|
import {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
savedInstallation
|
|
40
|
-
} from "./chunk-ZGZOBW2B.js";
|
|
36
|
+
ensureCurrentWizard,
|
|
37
|
+
wizardVersion
|
|
38
|
+
} from "./chunk-NNPYUATH.js";
|
|
41
39
|
import {
|
|
42
40
|
applyIntegration,
|
|
43
41
|
detectInstallation,
|
|
44
42
|
integrationAdditions,
|
|
45
43
|
integrationPreview,
|
|
46
44
|
planIntegration
|
|
47
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-LEJFE4U5.js";
|
|
48
46
|
import {
|
|
49
47
|
SdkInstallError,
|
|
50
48
|
cliCommand,
|
|
@@ -58,8 +56,23 @@ import {
|
|
|
58
56
|
sdkInstallCommand,
|
|
59
57
|
verifyConfiguration,
|
|
60
58
|
writeIntegration
|
|
61
|
-
} from "./chunk-
|
|
62
|
-
import "./chunk-
|
|
59
|
+
} from "./chunk-TOID3NYP.js";
|
|
60
|
+
import "./chunk-PJQOSDYS.js";
|
|
61
|
+
import "./chunk-NMHTFC5Q.js";
|
|
62
|
+
import {
|
|
63
|
+
Cancelled,
|
|
64
|
+
Terminal,
|
|
65
|
+
approvalStatus,
|
|
66
|
+
clean,
|
|
67
|
+
normalizeOrigin,
|
|
68
|
+
openBrowser
|
|
69
|
+
} from "./chunk-EVNEX5N5.js";
|
|
70
|
+
import {
|
|
71
|
+
BrowserConnectionUnavailable,
|
|
72
|
+
compatibilityCredentials,
|
|
73
|
+
connectInstallation,
|
|
74
|
+
memoryCredentials
|
|
75
|
+
} from "./chunk-DMXUXEQI.js";
|
|
63
76
|
import {
|
|
64
77
|
ApiError,
|
|
65
78
|
AuthenticationError,
|
|
@@ -67,13 +80,14 @@ import {
|
|
|
67
80
|
apiUrl,
|
|
68
81
|
credentialStoreKind,
|
|
69
82
|
detectAgentHarness,
|
|
83
|
+
firstSurveyHandoff,
|
|
70
84
|
login,
|
|
71
85
|
packageProfile,
|
|
72
86
|
resolveConfig,
|
|
73
87
|
resolveCredentials,
|
|
74
88
|
saveConfig,
|
|
75
89
|
uuid
|
|
76
|
-
} from "./chunk-
|
|
90
|
+
} from "./chunk-7AAH6C4L.js";
|
|
77
91
|
import "./chunk-WL3NOIM6.js";
|
|
78
92
|
|
|
79
93
|
// src/bin.ts
|
|
@@ -83,6 +97,10 @@ var help = `UserReason installation wizard
|
|
|
83
97
|
|
|
84
98
|
userreason-wizard [--directory PATH] [--origin URL]
|
|
85
99
|
|
|
100
|
+
--browser-setup (browser-guided setup; default for development onboarding)
|
|
101
|
+
--terminal-setup (use terminal onboarding instead)
|
|
102
|
+
--resume-setup UUID (resume this project's saved browser setup)
|
|
103
|
+
--browser-origin ORIGIN (trusted dashboard origin for a custom API)
|
|
86
104
|
--workspace UUID / --workspace-name NAME
|
|
87
105
|
--site UUID / --site-name NAME
|
|
88
106
|
--environment development|production (customer site environment)
|
|
@@ -101,6 +119,7 @@ userreason-wizard [--directory PATH] [--origin URL]
|
|
|
101
119
|
--diff (show the full patch for the application edit and the proposed guidance text)
|
|
102
120
|
--interactive (ask questions even when an agent harness or CI is detected)
|
|
103
121
|
--no-color (also NO_COLOR)
|
|
122
|
+
--no-telemetry (also UR_TELEMETRY_DISABLED=1)
|
|
104
123
|
--no-open (print the browser link without opening it)
|
|
105
124
|
--session-only (keep compatibility login only in memory; do not persist credentials)
|
|
106
125
|
--force (replace differing generated files)
|
|
@@ -118,6 +137,10 @@ Prompts are off when stdin or stdout is not a terminal, with --yes or --json, in
|
|
|
118
137
|
var nameError = (value) => !value.trim() || value.trim().length > 240 ? "Enter a name between 1 and 240 characters." : void 0;
|
|
119
138
|
var currentStep = "Reading wizard options";
|
|
120
139
|
var activeTerminal;
|
|
140
|
+
var analytics;
|
|
141
|
+
var surveyPreparation;
|
|
142
|
+
var surveyAbort = new AbortController();
|
|
143
|
+
var measured = (step, operation) => analytics ? analytics.measure(step, operation) : operation();
|
|
121
144
|
var frameworkLabel = (framework) => framework === "next" ? "Next.js" : framework;
|
|
122
145
|
var lowerFirst = (value) => value.charAt(0).toLowerCase() + value.slice(1);
|
|
123
146
|
async function main() {
|
|
@@ -127,7 +150,12 @@ async function main() {
|
|
|
127
150
|
help: { type: "boolean", short: "h" },
|
|
128
151
|
version: { type: "boolean", short: "v" },
|
|
129
152
|
dev: { type: "boolean" },
|
|
153
|
+
"browser-setup": { type: "boolean" },
|
|
154
|
+
"terminal-setup": { type: "boolean" },
|
|
155
|
+
"resume-setup": { type: "string" },
|
|
156
|
+
"browser-origin": { type: "string" },
|
|
130
157
|
"api-environment": { type: "string" },
|
|
158
|
+
"no-telemetry": { type: "boolean" },
|
|
131
159
|
yes: { type: "boolean" },
|
|
132
160
|
install: { type: "boolean" },
|
|
133
161
|
refresh: { type: "boolean" },
|
|
@@ -173,7 +201,6 @@ async function main() {
|
|
|
173
201
|
process.stdout.write(help);
|
|
174
202
|
return;
|
|
175
203
|
}
|
|
176
|
-
if (values["credential-store"] !== void 0) credentialStoreKind(values["credential-store"]);
|
|
177
204
|
if (values["api-environment"] !== void 0 && !["production", "development"].includes(values["api-environment"]))
|
|
178
205
|
throw new Error("API environment must be development or production");
|
|
179
206
|
if (values.dev && values["api-environment"] === "production")
|
|
@@ -181,6 +208,20 @@ async function main() {
|
|
|
181
208
|
const embeddedProfile = packageProfile();
|
|
182
209
|
const apiEnvironment = values["api-environment"] ?? (values.dev ? "development" : embeddedProfile.apiEnvironment);
|
|
183
210
|
const developmentApi = apiEnvironment === "development";
|
|
211
|
+
const explicitBrowserMode = Boolean(values["browser-setup"] || values["resume-setup"]);
|
|
212
|
+
if (values["browser-setup"] && values["resume-setup"]) throw new Error("Choose --browser-setup or --resume-setup");
|
|
213
|
+
if (values["terminal-setup"] && explicitBrowserMode) throw new Error("Choose --terminal-setup or browser setup");
|
|
214
|
+
if (values["resume-setup"]) uuid(values["resume-setup"], "Setup ID");
|
|
215
|
+
const terminalFlags = ["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"];
|
|
216
|
+
const hasTerminalFlags = terminalFlags.some((key) => values[key] !== void 0 && values[key] !== false);
|
|
217
|
+
const browserMode = explicitBrowserMode || developmentApi && !values["terminal-setup"] && !hasTerminalFlags && !values.yes && !values.json;
|
|
218
|
+
if (values["browser-origin"]) {
|
|
219
|
+
if (!browserMode) throw new Error("--browser-origin requires browser setup");
|
|
220
|
+
apiUrl(values["browser-origin"], "Browser origin");
|
|
221
|
+
}
|
|
222
|
+
if (browserMode && hasTerminalFlags)
|
|
223
|
+
throw new Error("Browser setup choices are reviewed in the browser. Omit terminal installation/resource flags; ongoing CLI access is a separate login.");
|
|
224
|
+
if (values["credential-store"] !== void 0) credentialStoreKind(values["credential-store"]);
|
|
184
225
|
const newSiteEnvironment = values.environment ?? apiEnvironment;
|
|
185
226
|
if (values["global-cli"] && values["skip-global-cli"]) throw new Error("Choose --global-cli or --skip-global-cli");
|
|
186
227
|
if (values["global-cli"] && values["skip-install"]) throw new Error("--global-cli requires project package installation; omit --skip-install");
|
|
@@ -218,8 +259,25 @@ async function main() {
|
|
|
218
259
|
const tty = Boolean(process.stdin.isTTY && process.stdout.isTTY && process.env.TERM !== "dumb");
|
|
219
260
|
const explicitlyQuiet = Boolean(values.yes || values.json);
|
|
220
261
|
const interactive = tty && !explicitlyQuiet && (!harness || Boolean(values.interactive));
|
|
221
|
-
const terminal = new Terminal(interactive, Boolean(values.json), { color: !values["no-color"]
|
|
262
|
+
const terminal = new Terminal(interactive, Boolean(values.json), { color: !values["no-color"], onCancel: () => {
|
|
263
|
+
surveyAbort.abort(new Cancelled());
|
|
264
|
+
surveyPreparation?.cancel();
|
|
265
|
+
if (browserMode) {
|
|
266
|
+
process.exitCode = 130;
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
analytics?.finish(true);
|
|
270
|
+
process.exitCode = 130;
|
|
271
|
+
void (analytics?.flush(true) ?? Promise.resolve()).finally(() => process.exit(130));
|
|
272
|
+
} });
|
|
222
273
|
activeTerminal = terminal;
|
|
274
|
+
try {
|
|
275
|
+
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"] });
|
|
276
|
+
} catch {
|
|
277
|
+
}
|
|
278
|
+
if (!values.refresh) analytics?.configure({ context: { source_site_environment: newSiteEnvironment === "development" ? "development" : "production" } });
|
|
279
|
+
analytics?.begin("run");
|
|
280
|
+
await analytics?.checkpoint();
|
|
223
281
|
const { c, S } = terminal.kit;
|
|
224
282
|
const dot = ` ${S.dot} `;
|
|
225
283
|
const environmentNote = developmentApi ? `development API${newSiteEnvironment !== apiEnvironment ? `, new sites are ${newSiteEnvironment}` : ""}` : newSiteEnvironment !== apiEnvironment ? `new sites are ${newSiteEnvironment}` : void 0;
|
|
@@ -239,8 +297,27 @@ async function main() {
|
|
|
239
297
|
values.directory ?? process.cwd(),
|
|
240
298
|
values.framework
|
|
241
299
|
);
|
|
300
|
+
analytics?.configure({ wizard: { framework: project.framework, package_manager: project.packageManager } });
|
|
242
301
|
terminal.info(`${clean(project.name)} ${c.muted(`(${frameworkLabel(project.framework)}, ${project.packageManager})`)}`);
|
|
302
|
+
if (browserMode) {
|
|
303
|
+
currentStep = values["resume-setup"] ? "Resuming browser setup" : "Connecting browser setup";
|
|
304
|
+
const interrupted = () => surveyAbort.abort(new Cancelled());
|
|
305
|
+
process.once("SIGINT", interrupted);
|
|
306
|
+
process.once("SIGTERM", interrupted);
|
|
307
|
+
terminal.cancelState = "the local runner stopped; browser approvals, applied changes and saved drafts remain available when you resume";
|
|
308
|
+
let handled;
|
|
309
|
+
try {
|
|
310
|
+
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, development: developmentApi, noOpen: Boolean(values["no-open"]), json: Boolean(values.json), signal: surveyAbort.signal, measurementDisabled: values["no-telemetry"] });
|
|
311
|
+
} finally {
|
|
312
|
+
process.off("SIGINT", interrupted);
|
|
313
|
+
process.off("SIGTERM", interrupted);
|
|
314
|
+
}
|
|
315
|
+
if (handled) return;
|
|
316
|
+
terminal.cancelState = "nothing was written";
|
|
317
|
+
terminal.info("This server has not enabled browser setup. Continuing with the existing terminal wizard.");
|
|
318
|
+
}
|
|
243
319
|
if (values.refresh) {
|
|
320
|
+
analytics?.configure({ wizard: { resumed: true } });
|
|
244
321
|
currentStep = "Refreshing UserReason packages";
|
|
245
322
|
const existing = await detectInstallation(project);
|
|
246
323
|
if (!existing) throw new Error("No UserReason initialization found. Run the wizard without --refresh to set up this application.");
|
|
@@ -253,18 +330,49 @@ async function main() {
|
|
|
253
330
|
const started = Date.now();
|
|
254
331
|
await terminal.task("Updating UserReason packages", async () => {
|
|
255
332
|
if (!await hasCompatibleSdk(project, profile) || values.install) {
|
|
256
|
-
await installSdk(project, options);
|
|
333
|
+
await measured("sdk_install", () => installSdk(project, options));
|
|
257
334
|
updated.push("@userreason/js");
|
|
258
335
|
}
|
|
259
336
|
if (!await hasCompatibleCli(project, profile) || values.install) {
|
|
260
|
-
await installCli(project, options);
|
|
337
|
+
await measured("cli_install", () => installCli(project, options));
|
|
261
338
|
updated.push("@userreason/cli");
|
|
262
339
|
}
|
|
263
340
|
}, () => 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
|
-
|
|
341
|
+
const refreshOption = async (step, requested, skipped, eligible, operation) => {
|
|
342
|
+
if (!requested) {
|
|
343
|
+
analytics?.step(step, "skipped", { selection_source: skipped ? "flag" : "default", reason: skipped ? "explicit_skip" : "not_requested" });
|
|
344
|
+
return operation();
|
|
345
|
+
}
|
|
346
|
+
if (await eligible().catch(() => false)) analytics?.step(step, "eligible");
|
|
347
|
+
analytics?.step(step, "selected", { selection_source: "flag" });
|
|
348
|
+
return measured(step, operation);
|
|
349
|
+
};
|
|
350
|
+
const globalCli2 = await refreshOption(
|
|
351
|
+
"global_cli",
|
|
352
|
+
values["global-cli"],
|
|
353
|
+
values["skip-global-cli"],
|
|
354
|
+
async () => true,
|
|
355
|
+
() => offerGlobalCli(project, terminal, { installed: true, requested: values["global-cli"], skip: !values["global-cli"], force: values.install, verbose: values.debug, profile, preview: Boolean(values.diff) })
|
|
356
|
+
);
|
|
357
|
+
const agentNote2 = await refreshOption(
|
|
358
|
+
"agent_note",
|
|
359
|
+
values["agent-note"],
|
|
360
|
+
values["skip-agent-note"],
|
|
361
|
+
async () => "path" in await planAgentNote(project),
|
|
362
|
+
() => offerAgentNote(project, terminal, { installed: true, requested: values["agent-note"], skip: !values["agent-note"], preview: Boolean(values.diff) })
|
|
363
|
+
);
|
|
364
|
+
const agentSkill2 = await refreshOption(
|
|
365
|
+
"agent_skill",
|
|
366
|
+
values["agent-skill"],
|
|
367
|
+
values["skip-agent-skill"],
|
|
368
|
+
async () => "files" in await planAgentSkill(project),
|
|
369
|
+
() => offerAgentSkill(project, terminal, { installed: true, requested: values["agent-skill"], skip: !values["agent-skill"], preview: Boolean(values.diff) })
|
|
370
|
+
);
|
|
371
|
+
const cliAccess2 = await refreshOption("cli_access", values["cli-access"], values["skip-cli-access"], async () => true, async () => {
|
|
372
|
+
if (!values["cli-access"]) return { status: "skipped" };
|
|
373
|
+
const accessConfig = await resolveConfig({ development: developmentApi, apiUrl: existing.apiBaseUrl, clientId: values["client-id"], credentialStore: values["credential-store"] });
|
|
374
|
+
return offerCliAccess(accessConfig, terminal, { installed: true, requested: true, noOpen: values["no-open"], development: developmentApi, preview: Boolean(values.diff) });
|
|
375
|
+
});
|
|
268
376
|
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
377
|
terminal.block("Ready", [
|
|
270
378
|
c.muted("Reload or restart your app to load the updated SDK."),
|
|
@@ -334,6 +442,7 @@ async function main() {
|
|
|
334
442
|
clientId: values["client-id"],
|
|
335
443
|
credentialStore: values["credential-store"]
|
|
336
444
|
});
|
|
445
|
+
analytics?.configure({ apiUrl: config.apiUrl });
|
|
337
446
|
let resumeStorageBlocked = false;
|
|
338
447
|
const warnResumeStorage = () => {
|
|
339
448
|
if (resumeStorageBlocked) return;
|
|
@@ -350,12 +459,14 @@ async function main() {
|
|
|
350
459
|
let workspaceChoice = values.workspace ? uuid(values.workspace) : saved?.workspaceId;
|
|
351
460
|
const siteChoice = values.site ? uuid(values.site) : saved?.siteId;
|
|
352
461
|
const resumed = Boolean(saved && !values.workspace && !values.site);
|
|
462
|
+
analytics?.configure({ wizard: { resumed } });
|
|
353
463
|
if (siteChoice && !workspaceChoice) {
|
|
354
464
|
currentStep = "Resolving the existing site";
|
|
355
465
|
const origin = values.origin ? normalizeOrigin(values.origin, newSiteEnvironment === "development" ? "development" : "production") : void 0;
|
|
356
466
|
workspaceChoice = (await resolveInstallation({ siteId: siteChoice, apiBaseUrl: config.apiUrl }, origin)).workspaceId;
|
|
357
467
|
}
|
|
358
|
-
|
|
468
|
+
const rawCredentials = resolveCredentials(config);
|
|
469
|
+
let credentials = analytics?.observeCredentials(rawCredentials) ?? rawCredentials, client = new UserReasonClient(config, credentials), connection;
|
|
359
470
|
const open = async (url) => !values["no-open"] && await openBrowser(url);
|
|
360
471
|
const approvalWait = async (label, url, note) => {
|
|
361
472
|
const opened = await open(url);
|
|
@@ -373,6 +484,8 @@ async function main() {
|
|
|
373
484
|
let waiting;
|
|
374
485
|
let unrestrictedOrigins = false;
|
|
375
486
|
currentStep = "Connecting browser sign-in and approval";
|
|
487
|
+
analytics?.begin("authentication");
|
|
488
|
+
await analytics?.checkpoint();
|
|
376
489
|
try {
|
|
377
490
|
connection = await connectInstallation(
|
|
378
491
|
config,
|
|
@@ -399,7 +512,9 @@ async function main() {
|
|
|
399
512
|
}
|
|
400
513
|
);
|
|
401
514
|
waiting?.stop();
|
|
402
|
-
|
|
515
|
+
const temporaryCredentials = memoryCredentials(connection.session);
|
|
516
|
+
credentials = analytics?.observeCredentials(temporaryCredentials) ?? temporaryCredentials;
|
|
517
|
+
analytics?.setSession(connection.session);
|
|
403
518
|
client = new UserReasonClient(config, credentials, {
|
|
404
519
|
lock: (operation) => operation()
|
|
405
520
|
});
|
|
@@ -419,7 +534,8 @@ async function main() {
|
|
|
419
534
|
return terminal.confirm("Keep this session in memory only? No credentials will be saved.");
|
|
420
535
|
}
|
|
421
536
|
);
|
|
422
|
-
credentials = compatibility.credentials;
|
|
537
|
+
credentials = analytics?.observeCredentials(compatibility.credentials) ?? compatibility.credentials;
|
|
538
|
+
analytics?.setSession(compatibility.session);
|
|
423
539
|
client = new UserReasonClient(
|
|
424
540
|
config,
|
|
425
541
|
credentials,
|
|
@@ -471,6 +587,11 @@ async function main() {
|
|
|
471
587
|
await deviceSignIn();
|
|
472
588
|
account = await client.account();
|
|
473
589
|
}
|
|
590
|
+
analytics?.end("authentication");
|
|
591
|
+
if (developmentApi && terminal.interactive && !values.yes && !values.json && !values.diff) {
|
|
592
|
+
surveyPreparation = beginFirstSurveyPreparation(project.directory, { development: developmentApi, interactive: terminal.interactive });
|
|
593
|
+
}
|
|
594
|
+
analytics?.begin("target_selection");
|
|
474
595
|
const who = connection ? clean(connection.session.email) : void 0;
|
|
475
596
|
let selectedWorkspace;
|
|
476
597
|
const approvedWorkspace = connection?.workspaceId ?? workspaceChoice;
|
|
@@ -555,6 +676,8 @@ async function main() {
|
|
|
555
676
|
siteId: selectedSite?.id ?? siteIds.siteId,
|
|
556
677
|
apiBaseUrl: config.apiUrl
|
|
557
678
|
};
|
|
679
|
+
analytics?.end("target_selection");
|
|
680
|
+
analytics?.configure({ context: { ...selectedWorkspace ? { workspace_id: selectedWorkspace.id } : {}, ...selectedSite ? { site_id: selectedSite.id } : {}, source_site_environment: selectedSite?.environment ?? environment } });
|
|
558
681
|
currentStep = "Preparing the application integration";
|
|
559
682
|
const reviewed = values["skip-integrate"] ? void 0 : await planIntegration(project, installation);
|
|
560
683
|
const additions = reviewed ? integrationAdditions(reviewed) : void 0;
|
|
@@ -582,13 +705,31 @@ async function main() {
|
|
|
582
705
|
if (skillProbe && "files" in skillProbe) extras.push({ value: "skill", label: skillProbe.update ? "Agent skill update" : "Agent skill", hint: ".agents/skills/userreason", initial: true });
|
|
583
706
|
if (!values["skip-cli-access"] && !values["session-only"]) extras.push({ value: "access", label: "Ongoing CLI access", hint: "second approval (90 days)", initial: true });
|
|
584
707
|
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"]) });
|
|
708
|
+
for (const item of extras) {
|
|
709
|
+
if (item.value === "surveys") continue;
|
|
710
|
+
const step = { edit: "initialization", note: "agent_note", skill: "agent_skill", access: "cli_access", global: "global_cli" }[item.value];
|
|
711
|
+
analytics?.step(step, "eligible");
|
|
712
|
+
if (interactive) analytics?.step(step, "offered", { selection_source: "prompt" });
|
|
713
|
+
}
|
|
714
|
+
if (interactive && extras.length) analytics?.begin("options");
|
|
715
|
+
await analytics?.checkpoint();
|
|
585
716
|
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;
|
|
717
|
+
if (interactive && extras.length) {
|
|
718
|
+
analytics?.end("options");
|
|
719
|
+
for (const item of extras) {
|
|
720
|
+
if (item.value === "surveys") continue;
|
|
721
|
+
const step = { edit: "initialization", note: "agent_note", skill: "agent_skill", access: "cli_access", global: "global_cli" }[item.value];
|
|
722
|
+
analytics?.step(step, picked?.has(item.value) ? "selected" : "declined", { selection_source: "prompt" });
|
|
723
|
+
}
|
|
724
|
+
}
|
|
586
725
|
const integrate = Boolean(reviewed?.status === "ready" && (picked ? picked.has("edit") : values.integrate || values.yes));
|
|
587
726
|
const choice = (key, flag, skipFlag) => picked ? { requested: picked.has(key), skip: !picked.has(key) } : { requested: Boolean(values[flag]), skip: skipFlag };
|
|
727
|
+
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
728
|
const noteChoice = choice("note", "agent-note", Boolean(values["skip-agent-note"]));
|
|
589
729
|
const skillChoice = choice("skill", "agent-skill", Boolean(values["skip-agent-skill"]));
|
|
590
730
|
const globalChoice = choice("global", "global-cli", Boolean(values["skip-global-cli"] || values["skip-install"]));
|
|
591
731
|
const accessChoice = choice("access", "cli-access", Boolean(values["skip-cli-access"] || values["session-only"]));
|
|
732
|
+
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
733
|
terminal.cancelState = "some steps are done; rerun the wizard to continue";
|
|
593
734
|
if (!selectedWorkspace) {
|
|
594
735
|
currentStep = "Creating the workspace";
|
|
@@ -625,6 +766,7 @@ async function main() {
|
|
|
625
766
|
);
|
|
626
767
|
terminal.success(`Created site ${c.code(clean(selectedSite.name))}`);
|
|
627
768
|
}
|
|
769
|
+
analytics?.configure({ context: { workspace_id: selectedWorkspace.id, site_id: selectedSite.id, source_site_environment: selectedSite.environment } });
|
|
628
770
|
currentStep = "Saving optional installation resume details";
|
|
629
771
|
if (!await saveInstallation(project.directory, installation)) warnResumeStorage();
|
|
630
772
|
currentStep = "Preparing initialization files";
|
|
@@ -645,9 +787,10 @@ async function main() {
|
|
|
645
787
|
await terminal.task("Installing @userreason/js, @userreason/cli", async () => {
|
|
646
788
|
if (shouldInstall) {
|
|
647
789
|
try {
|
|
648
|
-
|
|
790
|
+
const operation = () => installSdk(project, { profile, verbose: values.debug, onWarning: (message) => {
|
|
649
791
|
warnings.push(message);
|
|
650
792
|
} });
|
|
793
|
+
await measured("sdk_install", operation);
|
|
651
794
|
sdkInstalled = true;
|
|
652
795
|
installed.push("@userreason/js");
|
|
653
796
|
} catch (error) {
|
|
@@ -658,9 +801,10 @@ async function main() {
|
|
|
658
801
|
}
|
|
659
802
|
if (shouldInstallCli) {
|
|
660
803
|
try {
|
|
661
|
-
|
|
804
|
+
const operation = () => installCli(project, { profile, verbose: values.debug, onWarning: (message) => {
|
|
662
805
|
warnings.push(message);
|
|
663
806
|
} });
|
|
807
|
+
await measured("cli_install", operation);
|
|
664
808
|
cliInstalled = true;
|
|
665
809
|
installed.push("@userreason/cli");
|
|
666
810
|
} catch (error) {
|
|
@@ -684,16 +828,17 @@ Then rerun the wizard. Your saved workspace and site will be reused.`, failure.t
|
|
|
684
828
|
const concrete = await planIntegration(project, installation);
|
|
685
829
|
if (reviewed.status !== "ready" || concrete.status !== "ready" || concrete.path !== reviewed.path || concrete.before !== reviewed.before || concrete.after !== reviewed.after)
|
|
686
830
|
throw new Error("The application entry changed after the preview. Rerun to review it again.");
|
|
687
|
-
await applyIntegration(concrete);
|
|
831
|
+
await measured("initialization", () => applyIntegration(concrete));
|
|
688
832
|
if (concrete.before === null) generated.files.push(concrete.path);
|
|
689
833
|
terminal.success(`${concrete.before === null ? "Created" : "Edited"} ${c.code(additions?.path ?? "")}`);
|
|
690
834
|
}
|
|
835
|
+
if (existingPlan?.status === "integrated") analytics?.step("initialization", "already_present");
|
|
691
836
|
const integrated = Boolean(integrate && !installFailed || existingPlan?.status === "integrated");
|
|
692
837
|
if (!integrated && !installFailed) terminal.note(generated.instruction, "Application integration");
|
|
693
838
|
currentStep = "Checking site configuration";
|
|
694
839
|
const verification = await terminal.task(
|
|
695
840
|
"Checking site configuration",
|
|
696
|
-
() => verifyConfiguration(installation, hostOrigin ?? "https://installation.userreason.invalid"),
|
|
841
|
+
() => analytics ? analytics.measure("configuration_check", () => verifyConfiguration(installation, hostOrigin ?? "https://installation.userreason.invalid"), "completed") : verifyConfiguration(installation, hostOrigin ?? "https://installation.userreason.invalid"),
|
|
697
842
|
"Site configuration reachable"
|
|
698
843
|
);
|
|
699
844
|
if (integrated && sdkInstalled && !installFailed) {
|
|
@@ -705,13 +850,30 @@ Then rerun the wizard. Your saved workspace and site will be reused.`, failure.t
|
|
|
705
850
|
if (picked && !completed && !installFailed && (picked.has("note") || picked.has("skill")))
|
|
706
851
|
terminal.warn("The note and skill wait for an initialized SDK. Rerun with the entry edit selected, or apply the initialization yourself first.");
|
|
707
852
|
currentStep = "Offering the optional user feedback note";
|
|
708
|
-
const agentNote = await offerAgentNote(project, terminal, { installed: completed, ...noteChoice, preview: Boolean(values.diff) });
|
|
853
|
+
const agentNote = await measured("agent_note", () => offerAgentNote(project, terminal, { installed: completed, ...noteChoice, preview: Boolean(values.diff) }));
|
|
709
854
|
currentStep = "Offering the optional feedback agent skill";
|
|
710
|
-
const agentSkill = await offerAgentSkill(project, terminal, { installed: completed, ...skillChoice, preview: Boolean(values.diff) });
|
|
855
|
+
const agentSkill = await measured("agent_skill", () => offerAgentSkill(project, terminal, { installed: completed, ...skillChoice, preview: Boolean(values.diff) }));
|
|
711
856
|
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) });
|
|
857
|
+
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
858
|
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) });
|
|
859
|
+
const cliAccess = await measured("cli_access", () => offerCliAccess(config, terminal, { installed: cliInstalled && !installFailed, ...accessChoice, noOpen: values["no-open"], development: developmentApi, preview: Boolean(values.diff) }));
|
|
860
|
+
if (!developmentApi && completed && terminal.interactive && !values.yes && !values.json && !values.diff) {
|
|
861
|
+
try {
|
|
862
|
+
currentStep = "Creating the first survey";
|
|
863
|
+
await offerFirstSurvey(new UserReasonClient(config, resolveCredentials(config)), project.directory, selectedWorkspace.id, selectedSite.id, {
|
|
864
|
+
show: (message) => terminal.note(message, developmentApi ? "Recommended surveys" : "First survey"),
|
|
865
|
+
confirm: (message) => terminal.confirm(message, false),
|
|
866
|
+
choose: (message, options, initialValue) => terminal.select(message, options, initialValue),
|
|
867
|
+
answer: (message) => terminal.text(message),
|
|
868
|
+
chooseMany: (message, options, initial) => terminal.multiselect(message, options, initial),
|
|
869
|
+
loading: (message, work) => terminal.task(message, work, () => void 0),
|
|
870
|
+
signal: surveyAbort.signal
|
|
871
|
+
}, { development: developmentApi, interactive: terminal.interactive, product: selectedSite.name, preparation: surveyPreparation, sourceConsent: picked?.has("surveys") });
|
|
872
|
+
} catch (error) {
|
|
873
|
+
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.");
|
|
874
|
+
terminal.note(firstSurveyHandoff(project.directory, config.apiUrl, selectedWorkspace.id, selectedSite.id), "Resume with your agent");
|
|
875
|
+
}
|
|
876
|
+
}
|
|
715
877
|
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
878
|
const siteLine = `${clean(selectedWorkspace.name)} ${S.arrow} ${clean(selectedSite.name)} ${c.muted(`(${siteDetail(selectedSite)})`)}`;
|
|
717
879
|
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 +911,16 @@ var approvalProgress;
|
|
|
749
911
|
main().catch((error) => {
|
|
750
912
|
const detail = error instanceof Error ? error.message : "Installation failed";
|
|
751
913
|
if (error instanceof Cancelled) {
|
|
752
|
-
|
|
914
|
+
analytics?.finish(true);
|
|
915
|
+
if (activeTerminal) {
|
|
916
|
+
activeTerminal.cancelled();
|
|
917
|
+
return;
|
|
918
|
+
}
|
|
753
919
|
process.stderr.write(detail + "\n");
|
|
754
920
|
process.exitCode = 130;
|
|
755
921
|
return;
|
|
756
922
|
}
|
|
923
|
+
analytics?.finish(false, true);
|
|
757
924
|
const message = `${currentStep}: ${detail}`;
|
|
758
925
|
if (process.argv.includes("--json"))
|
|
759
926
|
process.stdout.write(JSON.stringify({ error: "wizard_failed", step: currentStep, message }) + "\n");
|
|
@@ -761,4 +928,8 @@ main().catch((error) => {
|
|
|
761
928
|
activeTerminal.error(clean(detail), [`while ${lowerFirst(currentStep)}`]);
|
|
762
929
|
else process.stderr.write(message + "\n");
|
|
763
930
|
process.exitCode = 1;
|
|
931
|
+
}).finally(async () => {
|
|
932
|
+
surveyPreparation?.cancel();
|
|
933
|
+
analytics?.finish(false, Boolean(process.exitCode));
|
|
934
|
+
await analytics?.flush(true);
|
|
764
935
|
});
|