@haystackeditor/cli 0.25.0 → 0.25.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/dist/capture/adapters/django.js +7 -0
- package/dist/capture/adapters/index.js +10 -0
- package/dist/capture/adapters/next-build.js +113 -0
- package/dist/capture/adapters/next.js +272 -105
- package/dist/capture/adapters/nuxt.js +7 -0
- package/dist/capture/adapters/rails.js +7 -0
- package/dist/capture/adapters/react-router.js +7 -0
- package/dist/capture/adapters/sveltekit.js +7 -0
- package/dist/capture/adapters/vite.js +14 -0
- package/dist/capture/app-config.js +2 -1
- package/dist/capture/csp.js +7 -6
- package/dist/capture/url-rewrites.js +232 -0
- package/dist/capture-step.js +3 -0
- package/dist/commands/capture-manifest.js +25 -17
- package/dist/commands/init-capture.js +44 -27
- package/dist/commands/init-telemetry.js +24 -7
- package/dist/commands/init.js +12 -2
- package/dist/commands/verify-onboarding.js +16 -0
- package/dist/commands/verify.js +2 -2
- package/dist/index.js +2 -0
- package/package.json +1 -1
- package/schemas/init.v1.json +1 -1
package/dist/commands/init.js
CHANGED
|
@@ -359,18 +359,26 @@ export async function initCommand(options) {
|
|
|
359
359
|
const plan = planInit(gitRoot);
|
|
360
360
|
// Telemetry is part of onboarding (CAPTURE-V1 rule 8): planned on every run; a missing answer stops only it.
|
|
361
361
|
const telemetryModule = await import('./init-telemetry.js');
|
|
362
|
-
const telemetryOptions = { app: options.app, origins: options.origin ?? [], consent: options.consent };
|
|
362
|
+
const telemetryOptions = { app: options.app, origins: options.origin ?? [], consent: options.consent, urlRewrites: options.urlRewrites };
|
|
363
363
|
let telemetryPlan = await telemetryModule.planTelemetry(gitRoot, repository, telemetryOptions);
|
|
364
364
|
const telemetryFrom = plan.changes.length;
|
|
365
365
|
plan.changes.push(...telemetryPlan.changes);
|
|
366
366
|
plan.notices.push(...telemetryPlan.notices);
|
|
367
367
|
let notesWritten = null;
|
|
368
368
|
let telemetry = null;
|
|
369
|
+
// Before the apply (a preview, or no login), the report is the preview: what telemetry will do, `received` unchecked (null).
|
|
370
|
+
const report = () => telemetry ?? telemetryModule.previewTelemetry(telemetryPlan, repository, notes);
|
|
371
|
+
const showPreview = () => {
|
|
372
|
+
const preview = telemetryModule.previewTelemetry(telemetryPlan, repository, notes);
|
|
373
|
+
for (const line of telemetryModule.formatTelemetry(preview.telemetry, preview.steps))
|
|
374
|
+
say(line);
|
|
375
|
+
say('');
|
|
376
|
+
};
|
|
369
377
|
const finish = (status, onboarding, exitCode) => {
|
|
370
378
|
if (options.json) {
|
|
371
379
|
const changes = plan.changes.map(({ path, action, reason, diff }) => ({ path, action, reason, diff }));
|
|
372
380
|
process.stdout.write(`${JSON.stringify(withSchema('init', { status, repository, changes, notices: plan.notices, notes: notesWritten,
|
|
373
|
-
onboarding, telemetry: telemetry
|
|
381
|
+
onboarding, telemetry: report().telemetry, telemetrySteps: report().steps }), null, 2)}\n`);
|
|
374
382
|
}
|
|
375
383
|
process.exitCode = exitCode;
|
|
376
384
|
};
|
|
@@ -397,6 +405,7 @@ export async function initCommand(options) {
|
|
|
397
405
|
catch (error) {
|
|
398
406
|
if (!(error instanceof NotLoggedInError))
|
|
399
407
|
throw error;
|
|
408
|
+
showPreview();
|
|
400
409
|
say(chalk.yellow('Not logged in, so nothing was changed. Run `haystack login`, then `haystack init` again.'));
|
|
401
410
|
finish('login-required', null, EXIT_CODES['login-required']);
|
|
402
411
|
return;
|
|
@@ -404,6 +413,7 @@ export async function initCommand(options) {
|
|
|
404
413
|
if (plan.changes.length > 0 && !options.yes) {
|
|
405
414
|
const interactive = !options.json && process.stdin.isTTY === true && process.stdout.isTTY === true;
|
|
406
415
|
if (!interactive || !await confirmed()) {
|
|
416
|
+
showPreview();
|
|
407
417
|
say('Nothing was changed. Run `haystack init --yes` to make these changes.');
|
|
408
418
|
finish('planned', null, EXIT_CODES.planned);
|
|
409
419
|
return;
|
|
@@ -103,6 +103,12 @@ export function parseOnboardingStatus(value, expected) {
|
|
|
103
103
|
if (!Array.isArray(value.services) || !value.services.every(service => isRecord(service) && typeof service.id === 'string'
|
|
104
104
|
&& SERVICE_ENGINES.includes(service.engine)))
|
|
105
105
|
invalid('its services');
|
|
106
|
+
const review = value.review;
|
|
107
|
+
if (!(review === null || (isRecord(review) && (review.verdict === 'accept'
|
|
108
|
+
|| (review.verdict === 'skipped' && typeof review.reason === 'string' && review.reason.length > 0)))))
|
|
109
|
+
invalid('its review');
|
|
110
|
+
if (value.state !== 'ready' && review !== null)
|
|
111
|
+
invalid('its review');
|
|
106
112
|
if (value.block !== null)
|
|
107
113
|
parseOnboardingBlock(value.block);
|
|
108
114
|
const checkpoint = value.checkpoint;
|
|
@@ -311,8 +317,18 @@ export function formatOnboarding(status) {
|
|
|
311
317
|
const outside = [...status.standIns, ...status.unsetProviders, ...standInGapNotes(status.standInGaps)];
|
|
312
318
|
if (outside.length)
|
|
313
319
|
lines.push('', ...outside.map(note => chalk.yellow(`Note: ${safe(note)}`)));
|
|
320
|
+
const unreviewed = reviewNotes(status.review);
|
|
321
|
+
if (unreviewed.length)
|
|
322
|
+
lines.push('', ...unreviewed.map(note => chalk.yellow(`Note: ${safe(note)}`)));
|
|
314
323
|
return lines.join('\n');
|
|
315
324
|
}
|
|
325
|
+
/** Rule 17 (amendment 32): an onboarding the independent review skipped, as the sentence every result shows; none otherwise. */
|
|
326
|
+
export function reviewNotes(review) {
|
|
327
|
+
if (review?.verdict !== 'skipped')
|
|
328
|
+
return [];
|
|
329
|
+
return [`This onboarding was NOT reviewed: the independent review that checks the setup did not cheat is turned off for this `
|
|
330
|
+
+ `team (${review.reason}).`];
|
|
331
|
+
}
|
|
316
332
|
/** Rule 15(g), amendment 3: a stand-in gap as the sentence every result shows. */
|
|
317
333
|
export function standInGapNotes(gaps) {
|
|
318
334
|
return gaps.map(gap => `A stand-in could not serve ${gap} while onboarding signed in and did the workflow; the crawl may meet it too.`);
|
package/dist/commands/verify.js
CHANGED
|
@@ -31,7 +31,7 @@ import { classifyHttpError, readWithRetries, SERVICE_SILENCE_LIMIT_MS, ServiceSi
|
|
|
31
31
|
import { GATEWAY_TIMEOUT_MS, gatewayFetch } from './case-batch.js';
|
|
32
32
|
import { CRAWL_BRIEF_MAX_FUNCTIONS, CRAWL_BRIEF_MAX_GROUPS, CRAWL_BRIEF_MAX_PRODUCTION_ROWS, CRAWL_BUDGET_MAX_MS, CRAWL_BUDGET_MIN_MS, CRAWL_MAX_FINDINGS, CRAWL_MAX_FINDING_STEPS, CRAWL_MAX_IDEAS, CRAWL_MAX_STAND_IN_LINES, CRAWL_MAX_STAND_IN_ROWS, CRAWL_MAX_TEXT_CHARS, CRAWL_WAIT_MAX_MS, CRAWL_POOLS, } from './crawl-contract.js';
|
|
33
33
|
import { captureCheckout, crawlUnavailableText, EXPLICIT_WALL_MS, normalModeFailure, postPrecomputeCapture, } from './verify-precompute.js';
|
|
34
|
-
import { formatOnboarding, onboardingExitCode, readOnboardingStatus, reportOnboardingState, standInGapNotes, waitForOnboarding } from './verify-onboarding.js';
|
|
34
|
+
import { formatOnboarding, onboardingExitCode, readOnboardingStatus, reportOnboardingState, reviewNotes, standInGapNotes, waitForOnboarding, } from './verify-onboarding.js';
|
|
35
35
|
import { formatCapture, readPreVerifyCapture } from './capture-brief.js';
|
|
36
36
|
const CRAWLS_PATH = '/api/agent/cloud-verifier/crawls';
|
|
37
37
|
/** A held read (waitAfter): the service's hold, then the time any read gets. */
|
|
@@ -1094,7 +1094,7 @@ export async function verifyCommand(options) {
|
|
|
1094
1094
|
else {
|
|
1095
1095
|
console.log(formatCrawl(view));
|
|
1096
1096
|
const notes = [...(onboarding?.dataAbsences ?? []), ...(onboarding?.versionChoices ?? []), ...(onboarding?.standIns ?? []),
|
|
1097
|
-
...(onboarding?.unsetProviders ?? []), ...standInGapNotes(onboarding?.standInGaps ?? [])];
|
|
1097
|
+
...(onboarding?.unsetProviders ?? []), ...standInGapNotes(onboarding?.standInGaps ?? []), ...reviewNotes(onboarding?.review ?? null)];
|
|
1098
1098
|
if (notes.length)
|
|
1099
1099
|
console.log(['', ...notes.map(note => `Note: ${safe(note)}`)].join('\n'));
|
|
1100
1100
|
}
|
package/dist/index.js
CHANGED
|
@@ -154,6 +154,7 @@ program
|
|
|
154
154
|
.option('--app <dir>', 'The app whose telemetry init sets up, when the repository has several; see below')
|
|
155
155
|
.option('--origin <url>', 'A production origin of the app (repeat for several): browser capture accepts events only from these', (value, previous = []) => [...previous, value])
|
|
156
156
|
.option('--consent <choice>', 'How the site asks visitors for consent: its consent platform, or not-required when your user decided so')
|
|
157
|
+
.option('--url-rewrites <answer>', 'When init asks: none, or hidden-segment:<name> when the app\'s middleware adds a leading [<name>] segment to page paths')
|
|
157
158
|
.option('--json', 'The result as one JSON document on stdout (see `haystack schema init`)')
|
|
158
159
|
.addHelpText('after', `
|
|
159
160
|
There is no setup file: Haystack works out how to run the app from what the
|
|
@@ -1045,6 +1046,7 @@ program.command('capture').description('Real users\' journeys and devices: the t
|
|
|
1045
1046
|
.description('Publish the app\'s route manifest into its static output (the build step `haystack init` adds)')
|
|
1046
1047
|
.option('--app <dir>', 'The app directory (default: the current directory)')
|
|
1047
1048
|
.option('--rails-routes <file>', 'Rails: the routes file the rake task wrote')
|
|
1049
|
+
.option('--adapter <id>', 'The framework adapter to use instead of the one init recorded in .haystack/capture.json')
|
|
1048
1050
|
.option('--json', 'The release, counts and files written as JSON')
|
|
1049
1051
|
.action((options) => runPublicCommand(() => captureManifestCommand(options), options.json));
|
|
1050
1052
|
// ─── db ──────────────────────────────────────────────────────────────────────
|
package/package.json
CHANGED
package/schemas/init.v1.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "https://docs.haystackeditor.com/cli/schemas/init.v1.json",
|
|
4
4
|
"title": "Haystack init: this repository's setup for `haystack verify`",
|
|
5
|
-
"description": "Machine-readable output of `haystack init --json`. `changes` are the project-local changes init planned (made when status is done); `onboarding` is the base's OnboardingStatusV1 (onboarding_contracts.ts, APP-ONBOARDING-V1) as POST /api/agent/cloud-verifier/onboarding returns it, null unless status is done. `notes` says what became of `--notes`: \"written\" (the repository's onboarding notes are now these), \"unchanged\" (they already were), null without `--notes` or when init stopped before writing them. Exit codes: 0 done (onboarding running or ready), 1 failed (the error envelope), 2 planned (nothing written; run with --yes), 3 done but onboarding blocked, 4 login-required, 5 app-required (install the Haystack GitHub App), 6 done but onboarding stopped before finishing (run init again). `telemetry` (CAPTURE-V1 rule 8e, InitTelemetryReport in capture_contracts.ts) is
|
|
5
|
+
"description": "Machine-readable output of `haystack init --json`. `changes` are the project-local changes init planned (made when status is done); `onboarding` is the base's OnboardingStatusV1 (onboarding_contracts.ts, APP-ONBOARDING-V1) as POST /api/agent/cloud-verifier/onboarding returns it, null unless status is done. `notes` says what became of `--notes`: \"written\" (the repository's onboarding notes are now these), \"unchanged\" (they already were), null without `--notes` or when init stopped before writing them. Exit codes: 0 done (onboarding running or ready), 1 failed (the error envelope), 2 planned (nothing written; run with --yes), 3 done but onboarding blocked, 4 login-required, 5 app-required (install the Haystack GitHub App), 6 done but onboarding stopped before finishing (run init again). `telemetry` (CAPTURE-V1 rule 8e, InitTelemetryReport in capture_contracts.ts) is what telemetry does (status done) or will do (planned, login-required: the same report before anything is written, every `received` null because nothing was checked): per part (`capture`, the browser tag; `server`, server telemetry) `installed`, `manual` with the exact `steps`, or `unsupported` with `why`, and `received`, the newest telemetry Haystack holds for this application (null when none; `stale` past 24 hours), plus `dbProfileCommand`, the `haystack db profile` command for the user to run with production read access (null when the app's database is not one it profiles). `telemetrySteps` is what the person does next for telemetry to arrive, in order, including the off switches; [] without telemetry.",
|
|
6
6
|
"type": "object",
|
|
7
7
|
"additionalProperties": false,
|
|
8
8
|
"required": ["schema_version", "status", "repository", "changes", "notices", "notes", "onboarding", "telemetry", "telemetrySteps"],
|