@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
|
@@ -0,0 +1,288 @@
|
|
|
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
|
+
import {
|
|
3
|
+
planFooter
|
|
4
|
+
} from "./chunk-4INLEQE2.js";
|
|
5
|
+
import {
|
|
6
|
+
planAgentSkill
|
|
7
|
+
} from "./chunk-SB3AYQWG.js";
|
|
8
|
+
import {
|
|
9
|
+
detectInstallation,
|
|
10
|
+
initializationPath,
|
|
11
|
+
planIntegration
|
|
12
|
+
} from "./chunk-LEJFE4U5.js";
|
|
13
|
+
import {
|
|
14
|
+
compatibleProductionVersion,
|
|
15
|
+
inspectProject,
|
|
16
|
+
installCli,
|
|
17
|
+
installSdk,
|
|
18
|
+
installedVersion,
|
|
19
|
+
integrationSource
|
|
20
|
+
} from "./chunk-TOID3NYP.js";
|
|
21
|
+
import {
|
|
22
|
+
planPackageRegistry
|
|
23
|
+
} from "./chunk-NMHTFC5Q.js";
|
|
24
|
+
import {
|
|
25
|
+
SetupError,
|
|
26
|
+
apiUrl,
|
|
27
|
+
connectBrowserSetup,
|
|
28
|
+
detectSetupTerminal,
|
|
29
|
+
packageProfile,
|
|
30
|
+
readSetupFile,
|
|
31
|
+
resumeBrowserSetup,
|
|
32
|
+
runBrowserSetup,
|
|
33
|
+
runSetupExecutor,
|
|
34
|
+
setupDigest,
|
|
35
|
+
setupHash,
|
|
36
|
+
verifySetupFiles,
|
|
37
|
+
writeSetupFile
|
|
38
|
+
} from "./chunk-7AAH6C4L.js";
|
|
39
|
+
|
|
40
|
+
// src/setup.ts
|
|
41
|
+
import { basename } from "node:path";
|
|
42
|
+
|
|
43
|
+
// src/setup-plan.ts
|
|
44
|
+
import { randomUUID } from "node:crypto";
|
|
45
|
+
import { lstat, readdir, readFile } from "node:fs/promises";
|
|
46
|
+
import { join, relative } from "node:path";
|
|
47
|
+
var relativeName = (project, path) => relative(project.directory, path).replaceAll("\\", "/");
|
|
48
|
+
var metadata = (files) => files.map((file2) => ({ path: file2.path, before_hash: file2.before === null ? null : setupHash(file2.before), after_hash: setupHash(file2.after) }));
|
|
49
|
+
var exactVersion = (value) => {
|
|
50
|
+
const version = value.replace(/^[~^]/, "");
|
|
51
|
+
if (!/^\d+\.\d+\.\d+(?:-[A-Za-z0-9.-]+)?(?:\+[A-Za-z0-9.-]+)?$/.test(version)) throw new SetupError("setup_package_version", "The package profile must resolve to an exact version before review.");
|
|
52
|
+
return version;
|
|
53
|
+
};
|
|
54
|
+
async function alreadyCompatible(project, name, profile) {
|
|
55
|
+
try {
|
|
56
|
+
const manifest = JSON.parse(await readSetupFile(project.directory, "package.json"));
|
|
57
|
+
const declaration = (name === "@userreason/js" ? manifest.dependencies : manifest.devDependencies)?.[name];
|
|
58
|
+
if (!declaration) return false;
|
|
59
|
+
const installed = JSON.parse(await readSetupFile(project.directory, `node_modules/${name}/package.json`)).version;
|
|
60
|
+
if (typeof installed !== "string") return false;
|
|
61
|
+
return profile.kind === "local-development" ? installed === (name === "@userreason/js" ? profile.sdkVersion : profile.cliVersion) : compatibleProductionVersion(installed, name === "@userreason/js" ? profile.sdkVersion : profile.cliVersion);
|
|
62
|
+
} catch {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
async function file(project, path, after) {
|
|
67
|
+
const name = relativeName(project, path);
|
|
68
|
+
return { path: name, before: await readSetupFile(project.directory, name), after };
|
|
69
|
+
}
|
|
70
|
+
async function installationFiles(project, config) {
|
|
71
|
+
const plan = await planIntegration(project, config);
|
|
72
|
+
if (plan.status === "manual") return null;
|
|
73
|
+
if (plan.status === "integrated") {
|
|
74
|
+
const found = await detectInstallation(project), path = await initializationPath(project);
|
|
75
|
+
if (!found || !path || found.siteId !== config.siteId || found.apiBaseUrl !== config.apiBaseUrl) return null;
|
|
76
|
+
const before = await readSetupFile(project.directory, relativeName(project, path));
|
|
77
|
+
return before === null ? null : [{ path: relativeName(project, path), before, after: before }];
|
|
78
|
+
}
|
|
79
|
+
if (plan.status !== "ready") return null;
|
|
80
|
+
const result = [await file(project, plan.path, plan.after)];
|
|
81
|
+
if (plan.legacyNext) {
|
|
82
|
+
const helper = integrationSource(project.framework, config, project.typescript, true);
|
|
83
|
+
const planned = await file(project, join(project.sourceDirectory, helper.filename), helper.content);
|
|
84
|
+
if (planned.before !== null && planned.before !== planned.after) return null;
|
|
85
|
+
result.unshift(planned);
|
|
86
|
+
}
|
|
87
|
+
return result;
|
|
88
|
+
}
|
|
89
|
+
async function prepareSetupPlan(project, session, apiOrigin, selectedProfile = packageProfile()) {
|
|
90
|
+
const profile = { ...selectedProfile, sdkVersion: exactVersion(selectedProfile.sdkVersion), cliVersion: exactVersion(selectedProfile.cliVersion) };
|
|
91
|
+
const operations = [], manual = [];
|
|
92
|
+
const config = session.site_id ? { siteId: session.site_id, apiBaseUrl: apiUrl(apiOrigin) } : null;
|
|
93
|
+
return prepare(project, session, profile, config, operations, manual);
|
|
94
|
+
}
|
|
95
|
+
async function prepare(project, session, profile, config, operations = [], manual = []) {
|
|
96
|
+
const add = (kind, files, extra = {}) => {
|
|
97
|
+
const effect = { effect_id: randomUUID(), kind, files: metadata(files), ...extra };
|
|
98
|
+
operations.push({ effect, files });
|
|
99
|
+
};
|
|
100
|
+
let initialized = false;
|
|
101
|
+
let initialization = null;
|
|
102
|
+
if (session.choices.install_sdk) {
|
|
103
|
+
initialization = config ? await installationFiles(project, config) : null;
|
|
104
|
+
initialized = initialization !== null;
|
|
105
|
+
if (!initialization) manual.push({ kind: "initialize_sdk", code: "review_required" });
|
|
106
|
+
} else if (config) {
|
|
107
|
+
const installed = await detectInstallation(project);
|
|
108
|
+
initialized = installed?.siteId === config.siteId && installed?.apiBaseUrl === config.apiBaseUrl;
|
|
109
|
+
}
|
|
110
|
+
const packages = [];
|
|
111
|
+
if (session.choices.install_sdk && !await alreadyCompatible(project, "@userreason/js", profile)) packages.push({ name: "@userreason/js", version: exactVersion(profile.sdkVersion) });
|
|
112
|
+
if (session.choices.install_skill && initialized && !await alreadyCompatible(project, "@userreason/cli", profile)) packages.push({ name: "@userreason/cli", version: exactVersion(profile.cliVersion) });
|
|
113
|
+
if (packages.length) {
|
|
114
|
+
const before = await readSetupFile(project.directory, "package.json");
|
|
115
|
+
if (!before) throw new SetupError("setup_manifest_invalid", "The project needs an ordinary package.json.");
|
|
116
|
+
const manifest = JSON.parse(before);
|
|
117
|
+
for (const item of packages) {
|
|
118
|
+
const section = item.name === "@userreason/js" ? "dependencies" : "devDependencies";
|
|
119
|
+
if (manifest[section] && (typeof manifest[section] !== "object" || Array.isArray(manifest[section]))) throw new SetupError("setup_manifest_invalid", "The dependency manifest needs review.");
|
|
120
|
+
manifest[section] = { ...manifest[section], [item.name]: item.version };
|
|
121
|
+
const other = section === "dependencies" ? "devDependencies" : "dependencies";
|
|
122
|
+
if (manifest[other]?.[item.name] !== void 0) {
|
|
123
|
+
delete manifest[other][item.name];
|
|
124
|
+
if (!Object.keys(manifest[other]).length) delete manifest[other];
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
const indent = /\n([ \t]+)"/.exec(before)?.[1] ?? " ";
|
|
128
|
+
const after = JSON.stringify(manifest, null, indent) + (before.endsWith("\n") ? "\n" : "");
|
|
129
|
+
const files = [{ path: "package.json", before, after }];
|
|
130
|
+
const registry = await planPackageRegistry(project, profile);
|
|
131
|
+
if (registry) files.push({ ...registry, path: relativeName(project, registry.path) });
|
|
132
|
+
const guards = [];
|
|
133
|
+
for (const path of [".npmrc", ".yarnrc", ".yarnrc.yml"]) {
|
|
134
|
+
const content = await readSetupFile(project.directory, path);
|
|
135
|
+
if (!files.some((file2) => file2.path === path) && content !== null) files.push({ path, before: content, after: content });
|
|
136
|
+
guards.push({ path, before_hash: content === null ? null : setupHash(content) });
|
|
137
|
+
}
|
|
138
|
+
const paths = project.packageManager === "npm" ? ["package-lock.json"] : project.packageManager === "pnpm" ? ["pnpm-lock.yaml"] : ["yarn.lock", ".pnp.cjs", ".pnp.loader.mjs"];
|
|
139
|
+
const managed_outputs = await Promise.all(paths.map(async (path) => {
|
|
140
|
+
const content = await readSetupFile(project.directory, path);
|
|
141
|
+
return { path, before_hash: content === null ? null : setupHash(content) };
|
|
142
|
+
}));
|
|
143
|
+
add("install_packages", files, { package_manager: project.packageManager, packages, managed_outputs });
|
|
144
|
+
operations.at(-1).guards = guards;
|
|
145
|
+
}
|
|
146
|
+
if (initialization) add("initialize_sdk", initialization, { site_id: config.siteId });
|
|
147
|
+
if (session.choices.install_skill) {
|
|
148
|
+
if (!initialized) manual.push({ kind: "install_skill", code: "dependency_failed" });
|
|
149
|
+
else {
|
|
150
|
+
const skill = await planAgentSkill(project);
|
|
151
|
+
if ("files" in skill && (!skill.update || Object.keys(skill.update.snapshot).every((path) => skill.files.some((file2) => file2.path === path)))) {
|
|
152
|
+
const files = await Promise.all(skill.files.map((item) => file(project, join(skill.path, item.path), item.content)));
|
|
153
|
+
add("install_skill", files);
|
|
154
|
+
} else if (!("files" in skill) && skill.reason === "up_to_date" && skill.path) {
|
|
155
|
+
const files = await Promise.all(["references/management.md", "SKILL.md"].map(async (path) => {
|
|
156
|
+
const name = `${skill.path}/${path}`;
|
|
157
|
+
const before = await readSetupFile(project.directory, name);
|
|
158
|
+
if (before === null) throw new Error("Missing installed skill");
|
|
159
|
+
return { path: name, before, after: before };
|
|
160
|
+
}));
|
|
161
|
+
add("install_skill", files);
|
|
162
|
+
} else manual.push({ kind: "install_skill", code: "review_required" });
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
if (session.choices.footer_badge) {
|
|
166
|
+
const overlay = new Map(operations.flatMap((operation) => operation.files.map((file2) => [join(project.directory, file2.path), file2.after])));
|
|
167
|
+
const footer = await planFooter(project, overlay);
|
|
168
|
+
if (footer.status === "manual") manual.push({ kind: "insert_footer", code: footer.code === "missing_footer" ? "unsupported" : "review_required" });
|
|
169
|
+
else add("insert_footer", [{ path: relativeName(project, footer.path), before: footer.before, after: footer.after }], { placement: { path: relativeName(project, footer.path), anchor_hash: footer.anchorHash } });
|
|
170
|
+
}
|
|
171
|
+
return { wire: { project_fingerprint: session.project_fingerprint, choices_digest: setupDigest(session.choices), effects: operations.map((item) => item.effect), ...manual.length ? { manual_steps: manual } : {} }, operations };
|
|
172
|
+
}
|
|
173
|
+
async function snapshot(project) {
|
|
174
|
+
const result = {}, stack = [""];
|
|
175
|
+
let entries = 0, bytes = 0;
|
|
176
|
+
while (stack.length) {
|
|
177
|
+
const folder = stack.pop();
|
|
178
|
+
for (const entry of await readdir(join(project.directory, folder), { withFileTypes: true })) {
|
|
179
|
+
if (++entries > 2e4) throw new SetupError("setup_files_changed", "Project scanning exceeds the bounded review budget.");
|
|
180
|
+
const path = folder ? `${folder}/${entry.name}` : entry.name;
|
|
181
|
+
if (path === "node_modules" || path === ".git" || /^\.userreason-npm-/.test(path) || /^\.yarn\/(cache|unplugged)(\/|$)/.test(path) || path === ".yarn/install-state.gz") continue;
|
|
182
|
+
const info = await lstat(join(project.directory, path));
|
|
183
|
+
if (info.isSymbolicLink()) {
|
|
184
|
+
result[path] = "link";
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
if (info.isDirectory()) stack.push(path);
|
|
188
|
+
else if (info.isFile()) {
|
|
189
|
+
bytes += info.size;
|
|
190
|
+
if (info.size > 2e7 || bytes > 64e6) throw new SetupError("setup_files_changed", "Project scanning exceeds the bounded byte budget.");
|
|
191
|
+
result[path] = setupHash(await readFile(join(project.directory, path)));
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return result;
|
|
196
|
+
}
|
|
197
|
+
function setupRuntime(project, apiOrigin, selectedProfile = packageProfile()) {
|
|
198
|
+
apiOrigin = apiUrl(apiOrigin);
|
|
199
|
+
const profile = { ...selectedProfile, sdkVersion: exactVersion(selectedProfile.sdkVersion), cliVersion: exactVersion(selectedProfile.cliVersion) };
|
|
200
|
+
return {
|
|
201
|
+
prepare: (session) => prepare(project, session, profile, session.site_id ? { siteId: session.site_id, apiBaseUrl: apiOrigin } : null),
|
|
202
|
+
async apply(operation, signal) {
|
|
203
|
+
const current = await inspectProject(project.directory, project.framework);
|
|
204
|
+
if (current.packageManager !== project.packageManager) throw new SetupError("setup_files_changed", "The package manager changed after review.");
|
|
205
|
+
if (operation.effect.kind !== "install_packages") {
|
|
206
|
+
if (operation.effect.kind === "insert_footer") {
|
|
207
|
+
const footer = await planFooter(current);
|
|
208
|
+
if (footer.status === "manual" || relativeName(project, footer.path) !== operation.effect.placement.path || footer.anchorHash !== operation.effect.placement.anchor_hash || footer.after !== operation.files[0]?.after)
|
|
209
|
+
throw new SetupError("setup_files_changed", "The reviewed footer placement changed.");
|
|
210
|
+
}
|
|
211
|
+
if (operation.effect.kind === "install_skill") {
|
|
212
|
+
const skill = await planAgentSkill(current);
|
|
213
|
+
if ("files" in skill) {
|
|
214
|
+
if (skill.files.length !== operation.files.length || skill.files.some((item) => !operation.files.some((file2) => file2.path === relativeName(project, join(skill.path, item.path)) && file2.after === item.content)))
|
|
215
|
+
throw new SetupError("setup_files_changed", "The reviewed skill changed.");
|
|
216
|
+
} else if (skill.reason !== "up_to_date" || !operation.files.every((file2) => file2.before === file2.after)) throw new SetupError("setup_files_changed", "An existing skill needs review.");
|
|
217
|
+
}
|
|
218
|
+
const already = operation.files.every((file2) => file2.before === file2.after);
|
|
219
|
+
for (const file2 of operation.files) {
|
|
220
|
+
signal.throwIfAborted();
|
|
221
|
+
await writeSetupFile(project.directory, file2);
|
|
222
|
+
}
|
|
223
|
+
return already ? "already_present" : "verified";
|
|
224
|
+
}
|
|
225
|
+
if (operation.effect.package_manager !== current.packageManager) throw new SetupError("setup_command_mismatch", "The package manager differs from the reviewed command.");
|
|
226
|
+
for (const item of operation.effect.packages) if (item.version !== (item.name === "@userreason/js" ? profile.sdkVersion : profile.cliVersion)) throw new SetupError("setup_package_version", "The approved package version differs from this local package profile.");
|
|
227
|
+
const before = await snapshot(project);
|
|
228
|
+
for (const file2 of operation.files.filter((file3) => file3.path !== "package.json")) await writeSetupFile(project.directory, file2);
|
|
229
|
+
for (const item of operation.effect.packages) {
|
|
230
|
+
signal.throwIfAborted();
|
|
231
|
+
await (item.name === "@userreason/js" ? installSdk : installCli)(current, { profile, exact: true, signal, configureRegistry: false });
|
|
232
|
+
}
|
|
233
|
+
const manifest = operation.files.find((file2) => file2.path === "package.json");
|
|
234
|
+
const actual = await readSetupFile(project.directory, manifest.path);
|
|
235
|
+
if (!actual || setupDigest(JSON.parse(actual)) !== setupDigest(JSON.parse(manifest.after))) throw new Error("The package manager made unexpected manifest changes");
|
|
236
|
+
await writeSetupFile(project.directory, { ...manifest, before: actual });
|
|
237
|
+
const after = await snapshot(project), allowed = /* @__PURE__ */ new Set([...operation.files.map((file2) => file2.path), ...(operation.effect.managed_outputs ?? []).map((file2) => file2.path)]);
|
|
238
|
+
for (const path of /* @__PURE__ */ new Set([...Object.keys(before), ...Object.keys(after)])) if (!allowed.has(path) && before[path] !== after[path]) throw new Error("The package manager changed an unreviewed project file");
|
|
239
|
+
return "verified";
|
|
240
|
+
},
|
|
241
|
+
async verify(operation) {
|
|
242
|
+
if (!await verifySetupFiles(project.directory, operation.files, "after")) return false;
|
|
243
|
+
if (operation.effect.kind !== "install_packages") return true;
|
|
244
|
+
for (const item of operation.effect.packages) if (await installedVersion(project, item.name).catch(() => "") !== item.version) return false;
|
|
245
|
+
return true;
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// src/setup.ts
|
|
251
|
+
function connectSetup(apiOrigin, project, onBrowser, options = {}) {
|
|
252
|
+
return connectBrowserSetup(apiOrigin, {
|
|
253
|
+
directory: project.directory,
|
|
254
|
+
browserOrigin: options.browserOrigin,
|
|
255
|
+
capabilities: {
|
|
256
|
+
framework: project.framework,
|
|
257
|
+
package_manager: project.packageManager,
|
|
258
|
+
install_packages: true,
|
|
259
|
+
initialize_sdk: true,
|
|
260
|
+
install_skill: true,
|
|
261
|
+
insert_footer: true,
|
|
262
|
+
source_review: true,
|
|
263
|
+
sample_read: true,
|
|
264
|
+
...options.automaticSetup ? { onboarding_v2: true } : {},
|
|
265
|
+
...options.launcher ? { launcher: options.launcher } : {},
|
|
266
|
+
project_name: basename(project.directory).replace(/[\u0000-\u001f\u007f\/\\]/g, "").trim().slice(0, 120) || "Application",
|
|
267
|
+
terminal: detectSetupTerminal()
|
|
268
|
+
}
|
|
269
|
+
}, onBrowser, options);
|
|
270
|
+
}
|
|
271
|
+
function resumeSetup(apiOrigin, setupId, project, options = {}) {
|
|
272
|
+
return resumeBrowserSetup(apiOrigin, setupId, project.directory, options);
|
|
273
|
+
}
|
|
274
|
+
function executeSetup(client, project, options = {}) {
|
|
275
|
+
return runSetupExecutor(client, project.directory, setupRuntime(project, client.identity.api_url), options);
|
|
276
|
+
}
|
|
277
|
+
function runSetup(client, project, options = {}) {
|
|
278
|
+
return runBrowserSetup(client, project.directory, setupRuntime(project, client.identity.api_url), options);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
export {
|
|
282
|
+
prepareSetupPlan,
|
|
283
|
+
setupRuntime,
|
|
284
|
+
connectSetup,
|
|
285
|
+
resumeSetup,
|
|
286
|
+
executeSetup,
|
|
287
|
+
runSetup
|
|
288
|
+
};
|
|
@@ -1,13 +1,13 @@
|
|
|
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
|
-
import {
|
|
3
|
-
Cancelled
|
|
4
|
-
} from "./chunk-SJVLAYGG.js";
|
|
5
2
|
import {
|
|
6
3
|
cliCommand
|
|
7
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-TOID3NYP.js";
|
|
8
5
|
import {
|
|
9
6
|
require_dist
|
|
10
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-NMHTFC5Q.js";
|
|
8
|
+
import {
|
|
9
|
+
Cancelled
|
|
10
|
+
} from "./chunk-EVNEX5N5.js";
|
|
11
11
|
import {
|
|
12
12
|
__toESM
|
|
13
13
|
} from "./chunk-WL3NOIM6.js";
|
|
@@ -245,7 +245,7 @@ Agents can propose feedback investigations, read the current documentation and u
|
|
|
245
245
|
terminal.success("Feedback skill installed in .agents/skills/userreason");
|
|
246
246
|
return { status: "added", path: ".agents/skills/userreason" };
|
|
247
247
|
} catch (error) {
|
|
248
|
-
if (error instanceof Cancelled) return { status: "declined" };
|
|
248
|
+
if (error instanceof Cancelled) return { status: "declined", reason: "user_cancelled" };
|
|
249
249
|
terminal.warn("Installation is complete. The optional agent skill could not be installed; the skill directory needs review.");
|
|
250
250
|
return { status: "failed", reason: "skill_directory_needs_review" };
|
|
251
251
|
}
|
|
@@ -1,10 +1,13 @@
|
|
|
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
|
+
import {
|
|
3
|
+
installFailureDetails
|
|
4
|
+
} from "./chunk-PJQOSDYS.js";
|
|
2
5
|
import {
|
|
3
6
|
configurePackageRegistry
|
|
4
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-NMHTFC5Q.js";
|
|
5
8
|
import {
|
|
6
9
|
packageProfile
|
|
7
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-7AAH6C4L.js";
|
|
8
11
|
|
|
9
12
|
// src/project.ts
|
|
10
13
|
import { lstat, readFile, writeFile, access, mkdtemp, realpath, rm } from "node:fs/promises";
|
|
@@ -140,7 +143,7 @@ async function hasCompatibleSdk(project, profile = packageProfile()) {
|
|
|
140
143
|
try {
|
|
141
144
|
const manifest = JSON.parse(await readFile(join(project.directory, "package.json"), "utf8"));
|
|
142
145
|
const version = await installedVersion(project, "@userreason/js");
|
|
143
|
-
return Boolean(manifest.dependencies?.["@userreason/js"] && (profile.kind === "local-development" ? version === profile.sdkVersion :
|
|
146
|
+
return Boolean(manifest.dependencies?.["@userreason/js"] && (profile.kind === "local-development" ? version === profile.sdkVersion : compatibleProductionVersion(version, profile.sdkVersion)));
|
|
144
147
|
} catch {
|
|
145
148
|
return false;
|
|
146
149
|
}
|
|
@@ -157,8 +160,13 @@ async function hasCompatibleCli(project, profile = packageProfile()) {
|
|
|
157
160
|
return false;
|
|
158
161
|
}
|
|
159
162
|
}
|
|
163
|
+
function compatibleProductionVersion(version, requested) {
|
|
164
|
+
const installed = /^(\d+)\.(\d+)\.(\d+)$/.exec(version);
|
|
165
|
+
const target = /^(\d+)\.(\d+)\.(\d+)$/.exec(requested.replace(/^[~^]/, ""));
|
|
166
|
+
return Boolean(installed && target && installed[1] === target[1] && installed[2] === target[2] && Number(installed[3]) >= Number(target[3]));
|
|
167
|
+
}
|
|
160
168
|
function compatibleCliVersion(version, profile) {
|
|
161
|
-
return profile.kind === "local-development" ? version === profile.cliVersion :
|
|
169
|
+
return profile.kind === "local-development" ? version === profile.cliVersion : compatibleProductionVersion(version, profile.cliVersion);
|
|
162
170
|
}
|
|
163
171
|
function cliInstallCommand(project, profile = packageProfile()) {
|
|
164
172
|
return sdkInstallCommand(project, profile).replace("@userreason/js@" + profile.sdkVersion, "--save-dev @userreason/cli@" + profile.cliVersion).replace("yarn add --mode=skip-build --save-dev", "yarn add --mode=skip-build --dev").replace("yarn add --ignore-scripts --save-dev", "yarn add --ignore-scripts --dev");
|
|
@@ -177,10 +185,12 @@ async function installDependency(project, dependency, options) {
|
|
|
177
185
|
const spec = dependency === "sdk" ? `@userreason/js@${profile.sdkVersion}` : `@userreason/cli@${profile.cliVersion}`;
|
|
178
186
|
const args = project.packageManager === "npm" ? ["install", "--ignore-scripts", spec] : project.packageManager === "pnpm" ? ["add", "--ignore-scripts", spec] : (project.yarnMajor ?? 1) >= 2 ? ["add", "--mode=skip-build", spec] : ["add", "--ignore-scripts", spec];
|
|
179
187
|
if (dependency === "cli") args.push(project.packageManager === "yarn" ? "--dev" : "--save-dev");
|
|
180
|
-
if (profile.kind === "local-development") args.push(project.packageManager === "yarn" ? "--exact" : "--save-exact");
|
|
188
|
+
if (profile.kind === "local-development" || options.exact) args.push(project.packageManager === "yarn" ? "--exact" : "--save-exact");
|
|
181
189
|
let cache;
|
|
190
|
+
let logs = "";
|
|
182
191
|
try {
|
|
183
|
-
|
|
192
|
+
options.signal?.throwIfAborted();
|
|
193
|
+
if (options.configureRegistry !== false) await configurePackageRegistry(project, profile);
|
|
184
194
|
if (project.packageManager === "npm") {
|
|
185
195
|
cache = await mkdtemp(join(await realpath(project.directory), ".userreason-npm-"));
|
|
186
196
|
args.push("--cache", cache);
|
|
@@ -197,16 +207,28 @@ async function installDependency(project, dependency, options) {
|
|
|
197
207
|
...cache ? { npm_config_cache: cache, NPM_CONFIG_CACHE: cache } : {}
|
|
198
208
|
}
|
|
199
209
|
});
|
|
200
|
-
let
|
|
210
|
+
let killTimer;
|
|
211
|
+
const abort = () => {
|
|
212
|
+
child.kill("SIGTERM");
|
|
213
|
+
killTimer = setTimeout(() => child.kill("SIGKILL"), 2e3);
|
|
214
|
+
killTimer.unref();
|
|
215
|
+
};
|
|
216
|
+
options.signal?.addEventListener("abort", abort, { once: true });
|
|
217
|
+
if (options.signal?.aborted) abort();
|
|
201
218
|
const capture = (chunk) => {
|
|
202
219
|
const text = chunk.toString();
|
|
203
220
|
logs = (logs + text).slice(-64e3);
|
|
204
|
-
if (options.verbose) process.stderr.write(text);
|
|
205
221
|
};
|
|
206
222
|
child.stdout?.on("data", capture);
|
|
207
223
|
child.stderr?.on("data", capture);
|
|
208
224
|
child.on("error", () => reject(new SdkInstallError(`Unable to start ${project.packageManager}.`)));
|
|
209
225
|
child.on("close", (code) => {
|
|
226
|
+
options.signal?.removeEventListener("abort", abort);
|
|
227
|
+
if (killTimer) clearTimeout(killTimer);
|
|
228
|
+
if (options.signal?.aborted) {
|
|
229
|
+
reject(options.signal.reason);
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
210
232
|
if (code === 0) {
|
|
211
233
|
if (/\b[1-9]\d*\s+vulnerabilit(?:y|ies)\b|\bWARN\b|\bwarning\b/i.test(logs))
|
|
212
234
|
options.onWarning?.(
|
|
@@ -217,19 +239,24 @@ async function installDependency(project, dependency, options) {
|
|
|
217
239
|
const restricted = /ERR_ACCESS_DENIED|Access to this API has been restricted/.test(logs);
|
|
218
240
|
reject(
|
|
219
241
|
new SdkInstallError(
|
|
220
|
-
restricted ? `Your Node or package-manager permission policy blocked ${label} installation. Run the manual install command in your normal terminal.` : `${label} installation failed (${project.packageManager} exit ${code}).
|
|
242
|
+
restricted ? `Your Node or package-manager permission policy blocked ${label} installation. Run the manual install command in your normal terminal.` : `${label} installation failed (${project.packageManager} exit ${code}). Package-manager details follow.`
|
|
221
243
|
)
|
|
222
244
|
);
|
|
223
245
|
}
|
|
224
246
|
});
|
|
225
247
|
});
|
|
226
248
|
} catch (error) {
|
|
227
|
-
if (error instanceof SdkInstallError)
|
|
249
|
+
if (error instanceof SdkInstallError) {
|
|
250
|
+
const details = await installFailureDetails(project.directory, cache, logs);
|
|
251
|
+
if (details) error.message += "\n" + details;
|
|
252
|
+
throw error;
|
|
253
|
+
}
|
|
228
254
|
throw new SdkInstallError(
|
|
229
|
-
"Unable to prepare
|
|
255
|
+
"Unable to prepare or run package installation. " + await installFailureDetails(project.directory, cache, error instanceof Error ? error.message : "Unknown local error."),
|
|
230
256
|
{ cause: error }
|
|
231
257
|
);
|
|
232
258
|
} finally {
|
|
259
|
+
if (options.verbose && logs) process.stderr.write(await installFailureDetails(project.directory, cache, logs) + "\n");
|
|
233
260
|
if (cache) {
|
|
234
261
|
try {
|
|
235
262
|
await rm(cache, { recursive: true, force: true });
|
|
@@ -266,10 +293,12 @@ export {
|
|
|
266
293
|
initializationSource,
|
|
267
294
|
integrationSource,
|
|
268
295
|
writeIntegration,
|
|
296
|
+
installedVersion,
|
|
269
297
|
cliCommand,
|
|
270
298
|
hasCompatibleSdk,
|
|
271
299
|
sdkInstallCommand,
|
|
272
300
|
hasCompatibleCli,
|
|
301
|
+
compatibleProductionVersion,
|
|
273
302
|
compatibleCliVersion,
|
|
274
303
|
cliInstallCommand,
|
|
275
304
|
SdkInstallError,
|
|
@@ -1,14 +1,14 @@
|
|
|
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
|
-
import {
|
|
3
|
-
Cancelled
|
|
4
|
-
} from "./chunk-SJVLAYGG.js";
|
|
5
2
|
import {
|
|
6
3
|
cliCommand,
|
|
7
4
|
compatibleCliVersion
|
|
8
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-TOID3NYP.js";
|
|
6
|
+
import {
|
|
7
|
+
Cancelled
|
|
8
|
+
} from "./chunk-EVNEX5N5.js";
|
|
9
9
|
import {
|
|
10
10
|
packageProfile
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-7AAH6C4L.js";
|
|
12
12
|
|
|
13
13
|
// src/global-cli.ts
|
|
14
14
|
import { execFile } from "node:child_process";
|
|
@@ -102,7 +102,7 @@ This installs development CLI ${profile.cliVersion} from ${profile.registry}, re
|
|
|
102
102
|
if (!available) terminal.warn(`Global CLI ${installed.version} is installed, but this terminal does not resolve userreason to it. Check npm's global bin directory in PATH and restart your terminal or agent. Use ${cliCommand(project)} in this project meanwhile.`);
|
|
103
103
|
return { status: reuse ? "already_present" : "installed", version: installed.version, command_available: available };
|
|
104
104
|
} catch (error) {
|
|
105
|
-
if (error instanceof Cancelled) return { status: "declined" };
|
|
105
|
+
if (error instanceof Cancelled) return { status: "declined", reason: "user_cancelled" };
|
|
106
106
|
terminal.warn(`The optional global CLI could not be set up. ${error instanceof Error ? error.message : ""}`);
|
|
107
107
|
terminal.note(`${command}
|
|
108
108
|
|
|
@@ -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-LEJFE4U5.js";
|
|
5
5
|
import {
|
|
6
6
|
DEFAULT_API
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-TOID3NYP.js";
|
|
8
8
|
import {
|
|
9
9
|
apiUrl,
|
|
10
10
|
configDirectory,
|
|
11
11
|
uuid
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-7AAH6C4L.js";
|
|
13
13
|
|
|
14
14
|
// src/state.ts
|
|
15
15
|
import { mkdir, readFile, writeFile, rename, rm, realpath, lstat } from "node:fs/promises";
|
|
@@ -2,14 +2,14 @@ import { createRequire as createWizardRequire } from 'node:module'; import { fil
|
|
|
2
2
|
import {
|
|
3
3
|
Cancelled,
|
|
4
4
|
openBrowser
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-EVNEX5N5.js";
|
|
6
6
|
import {
|
|
7
7
|
authorizeCli,
|
|
8
8
|
grantSummary,
|
|
9
9
|
printable,
|
|
10
10
|
resolveCredentials,
|
|
11
11
|
saveConfig
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-7AAH6C4L.js";
|
|
13
13
|
|
|
14
14
|
// src/cli-access.ts
|
|
15
15
|
async function offerCliAccess(config, terminal, options) {
|
|
@@ -39,7 +39,7 @@ async function offerCliAccess(config, terminal, options) {
|
|
|
39
39
|
return { status: "approved", grant };
|
|
40
40
|
} catch (error) {
|
|
41
41
|
waiting?.stop();
|
|
42
|
-
if (error instanceof Cancelled) return { status: "declined" };
|
|
42
|
+
if (error instanceof Cancelled) return { status: "declined", reason: "user_cancelled" };
|
|
43
43
|
if (error instanceof Error) terminal.warn(printable(error.message));
|
|
44
44
|
terminal.warn("The application is installed, but ongoing CLI access was not connected. Run the project CLI with login --open to finish.");
|
|
45
45
|
return { status: "failed" };
|
|
@@ -0,0 +1,31 @@
|
|
|
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
|
+
import {
|
|
3
|
+
firstSurvey,
|
|
4
|
+
firstSurveyHandoff
|
|
5
|
+
} from "./chunk-7AAH6C4L.js";
|
|
6
|
+
|
|
7
|
+
// src/first-survey.ts
|
|
8
|
+
var surveySuggestionsEnabled = false;
|
|
9
|
+
function beginFirstSurveyPreparation(_root, _mode, _prepare) {
|
|
10
|
+
return void 0;
|
|
11
|
+
}
|
|
12
|
+
async function offerFirstSurvey(client, root, workspace, site, ui, mode) {
|
|
13
|
+
if (!surveySuggestionsEnabled || mode.development || !mode.interactive || mode.preview) return { state: "skipped" };
|
|
14
|
+
const choice = await ui.choose(
|
|
15
|
+
"Find your first useful survey? Nothing changes or publishes automatically.",
|
|
16
|
+
[
|
|
17
|
+
{ value: "guided", label: "Review suggestions" },
|
|
18
|
+
{ value: "agent", label: "Continue with my coding agent" },
|
|
19
|
+
{ value: "finish", label: "Finish setup" }
|
|
20
|
+
],
|
|
21
|
+
"finish"
|
|
22
|
+
);
|
|
23
|
+
if (choice === "agent") ui.show(firstSurveyHandoff(root, client.config.apiUrl, workspace, site));
|
|
24
|
+
if (choice === "guided") return firstSurvey(client, root, workspace, site, ui);
|
|
25
|
+
return { state: "skipped" };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export {
|
|
29
|
+
beginFirstSurveyPreparation,
|
|
30
|
+
offerFirstSurvey
|
|
31
|
+
};
|
package/dist/cli-access.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
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
|
offerCliAccess
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
6
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-XPFKXLIZ.js";
|
|
5
|
+
import "./chunk-EVNEX5N5.js";
|
|
6
|
+
import "./chunk-7AAH6C4L.js";
|
|
7
7
|
import "./chunk-WL3NOIM6.js";
|
|
8
8
|
export {
|
|
9
9
|
offerCliAccess
|
package/dist/connection.js
CHANGED
|
@@ -4,10 +4,10 @@ import {
|
|
|
4
4
|
compatibilityCredentials,
|
|
5
5
|
connectInstallation,
|
|
6
6
|
memoryCredentials
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-DMXUXEQI.js";
|
|
8
8
|
import {
|
|
9
9
|
CredentialStoreError
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-7AAH6C4L.js";
|
|
11
11
|
import "./chunk-WL3NOIM6.js";
|
|
12
12
|
export {
|
|
13
13
|
BrowserConnectionUnavailable,
|
|
@@ -0,0 +1,11 @@
|
|
|
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
|
+
import {
|
|
3
|
+
beginFirstSurveyPreparation,
|
|
4
|
+
offerFirstSurvey
|
|
5
|
+
} from "./chunk-ZHJV247H.js";
|
|
6
|
+
import "./chunk-7AAH6C4L.js";
|
|
7
|
+
import "./chunk-WL3NOIM6.js";
|
|
8
|
+
export {
|
|
9
|
+
beginFirstSurveyPreparation,
|
|
10
|
+
offerFirstSurvey
|
|
11
|
+
};
|
package/dist/footer.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
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
|
+
import {
|
|
3
|
+
FOOTER_LINK,
|
|
4
|
+
applyFooter,
|
|
5
|
+
planFooter
|
|
6
|
+
} from "./chunk-4INLEQE2.js";
|
|
7
|
+
import "./chunk-LEJFE4U5.js";
|
|
8
|
+
import "./chunk-TOID3NYP.js";
|
|
9
|
+
import "./chunk-PJQOSDYS.js";
|
|
10
|
+
import "./chunk-NMHTFC5Q.js";
|
|
11
|
+
import "./chunk-7AAH6C4L.js";
|
|
12
|
+
import "./chunk-WL3NOIM6.js";
|
|
13
|
+
export {
|
|
14
|
+
FOOTER_LINK,
|
|
15
|
+
applyFooter,
|
|
16
|
+
planFooter
|
|
17
|
+
};
|
package/dist/global-cli.js
CHANGED
|
@@ -2,11 +2,12 @@ import { createRequire as createWizardRequire } from 'node:module'; import { fil
|
|
|
2
2
|
import {
|
|
3
3
|
globalCliInstallCommand,
|
|
4
4
|
offerGlobalCli
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
7
|
-
import "./chunk-
|
|
8
|
-
import "./chunk-
|
|
9
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-TRBSH5G7.js";
|
|
6
|
+
import "./chunk-TOID3NYP.js";
|
|
7
|
+
import "./chunk-PJQOSDYS.js";
|
|
8
|
+
import "./chunk-NMHTFC5Q.js";
|
|
9
|
+
import "./chunk-EVNEX5N5.js";
|
|
10
|
+
import "./chunk-7AAH6C4L.js";
|
|
10
11
|
import "./chunk-WL3NOIM6.js";
|
|
11
12
|
export {
|
|
12
13
|
globalCliInstallCommand,
|
|
@@ -0,0 +1,9 @@
|
|
|
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
|
+
import {
|
|
3
|
+
installFailureDetails
|
|
4
|
+
} from "./chunk-PJQOSDYS.js";
|
|
5
|
+
import "./chunk-7AAH6C4L.js";
|
|
6
|
+
import "./chunk-WL3NOIM6.js";
|
|
7
|
+
export {
|
|
8
|
+
installFailureDetails
|
|
9
|
+
};
|