@jevitate/cli 0.1.0 → 0.2.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 +23 -0
- package/dist/ai-cli.js +40 -30
- package/dist/ai-cli.js.map +1 -1
- package/dist/author-journey-cli.d.ts +4 -0
- package/dist/author-journey-cli.js +109 -0
- package/dist/author-journey-cli.js.map +1 -0
- package/dist/bin.js +58077 -22454
- package/dist/bin.js.map +1 -1
- package/dist/browser-run-options.d.ts +58 -0
- package/dist/browser-run-options.js +106 -0
- package/dist/browser-run-options.js.map +1 -0
- package/dist/build-info.generated.d.ts +2 -0
- package/dist/build-info.generated.js +10 -0
- package/dist/build-info.generated.js.map +1 -0
- package/dist/check-api.d.ts +5 -0
- package/dist/check-api.js +233 -0
- package/dist/check-api.js.map +1 -0
- package/dist/check-budget.d.ts +26 -0
- package/dist/check-budget.js +89 -0
- package/dist/check-budget.js.map +1 -0
- package/dist/check-cli.d.ts +31 -0
- package/dist/check-cli.js +109 -0
- package/dist/check-cli.js.map +1 -0
- package/dist/check-execute.d.ts +25 -0
- package/dist/check-execute.js +385 -0
- package/dist/check-execute.js.map +1 -0
- package/dist/check-plan.d.ts +113 -0
- package/dist/check-plan.js +448 -0
- package/dist/check-plan.js.map +1 -0
- package/dist/check-suite.d.ts +171 -0
- package/dist/check-suite.js +515 -0
- package/dist/check-suite.js.map +1 -0
- package/dist/check-types.d.ts +181 -0
- package/dist/check-types.js +35 -0
- package/dist/check-types.js.map +1 -0
- package/dist/cli-args.d.ts +26 -0
- package/dist/cli-args.js +50 -0
- package/dist/cli-args.js.map +1 -0
- package/dist/cli-output.d.ts +102 -0
- package/dist/cli-output.js +516 -0
- package/dist/cli-output.js.map +1 -0
- package/dist/cli-reference.d.ts +3 -0
- package/dist/cli-reference.js +81 -0
- package/dist/cli-reference.js.map +1 -0
- package/dist/cli-refusal.d.ts +12 -0
- package/dist/cli-refusal.js +52 -0
- package/dist/cli-refusal.js.map +1 -0
- package/dist/cli-shared.d.ts +330 -0
- package/dist/cli-shared.js +492 -0
- package/dist/cli-shared.js.map +1 -0
- package/dist/cli-surface.d.ts +33 -0
- package/dist/cli-surface.js +48 -0
- package/dist/cli-surface.js.map +1 -0
- package/dist/conversation-options.d.ts +15 -0
- package/dist/conversation-options.js +10 -0
- package/dist/conversation-options.js.map +1 -0
- package/dist/credentials-file.d.ts +15 -0
- package/dist/credentials-file.js +56 -0
- package/dist/credentials-file.js.map +1 -0
- package/dist/data-dir.d.ts +1 -1
- package/dist/data-dir.js +1 -1
- package/dist/defect-evidence.d.ts +141 -0
- package/dist/defect-evidence.js +502 -0
- package/dist/defect-evidence.js.map +1 -0
- package/dist/demo-aspect-api.d.ts +209 -0
- package/dist/demo-aspect-api.js +397 -0
- package/dist/demo-aspect-api.js.map +1 -0
- package/dist/demo-aspect-cli.d.ts +3 -0
- package/dist/demo-aspect-cli.js +241 -0
- package/dist/demo-aspect-cli.js.map +1 -0
- package/dist/demo-capture.d.ts +108 -0
- package/dist/demo-capture.js +438 -0
- package/dist/demo-capture.js.map +1 -0
- package/dist/engine.d.ts +35 -0
- package/dist/engine.js +25 -0
- package/dist/engine.js.map +1 -0
- package/dist/environments.d.ts +155 -0
- package/dist/environments.js +364 -0
- package/dist/environments.js.map +1 -0
- package/dist/exit-codes.d.ts +46 -0
- package/dist/exit-codes.js +91 -0
- package/dist/exit-codes.js.map +1 -0
- package/dist/explore-adversarial.d.ts +137 -0
- package/dist/explore-adversarial.js +218 -0
- package/dist/explore-adversarial.js.map +1 -0
- package/dist/explore-api.d.ts +7 -187
- package/dist/explore-api.js +7 -301
- package/dist/explore-api.js.map +1 -1
- package/dist/explore-author.d.ts +79 -0
- package/dist/explore-author.js +86 -0
- package/dist/explore-author.js.map +1 -0
- package/dist/explore-cli.d.ts +7 -0
- package/dist/explore-cli.js +963 -0
- package/dist/explore-cli.js.map +1 -0
- package/dist/explore-coverage.d.ts +158 -0
- package/dist/explore-coverage.js +240 -0
- package/dist/explore-coverage.js.map +1 -0
- package/dist/explore-feature.d.ts +127 -0
- package/dist/explore-feature.js +220 -0
- package/dist/explore-feature.js.map +1 -0
- package/dist/explore-goal.d.ts +253 -0
- package/dist/explore-goal.js +374 -0
- package/dist/explore-goal.js.map +1 -0
- package/dist/explore-shared.d.ts +152 -0
- package/dist/explore-shared.js +129 -0
- package/dist/explore-shared.js.map +1 -0
- package/dist/explore-specs.d.ts +53 -0
- package/dist/explore-specs.js +333 -0
- package/dist/explore-specs.js.map +1 -0
- package/dist/findings-filing.d.ts +64 -0
- package/dist/findings-filing.js +108 -0
- package/dist/findings-filing.js.map +1 -0
- package/dist/fixture-auth.d.ts +52 -0
- package/dist/fixture-auth.js +82 -0
- package/dist/fixture-auth.js.map +1 -0
- package/dist/fixture-cli.d.ts +70 -0
- package/dist/fixture-cli.js +178 -0
- package/dist/fixture-cli.js.map +1 -0
- package/dist/github-issue-filer.d.ts +62 -0
- package/dist/github-issue-filer.js +188 -0
- package/dist/github-issue-filer.js.map +1 -0
- package/dist/host-health-run.d.ts +24 -0
- package/dist/host-health-run.js +27 -0
- package/dist/host-health-run.js.map +1 -0
- package/dist/http-5xx-outcome.d.ts +6 -0
- package/dist/http-5xx-outcome.js +39 -0
- package/dist/http-5xx-outcome.js.map +1 -0
- package/dist/inbox-cli.d.ts +7 -0
- package/dist/inbox-cli.js +197 -0
- package/dist/inbox-cli.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/init-cli.d.ts +4 -0
- package/dist/init-cli.js +127 -0
- package/dist/init-cli.js.map +1 -0
- package/dist/init-keys.d.ts +19 -2
- package/dist/init-keys.js +15 -4
- package/dist/init-keys.js.map +1 -1
- package/dist/init-next-steps.d.ts +35 -0
- package/dist/init-next-steps.js +79 -0
- package/dist/init-next-steps.js.map +1 -0
- package/dist/invariants-file.d.ts +34 -0
- package/dist/invariants-file.js +68 -0
- package/dist/invariants-file.js.map +1 -0
- package/dist/invariants-validate.d.ts +30 -0
- package/dist/invariants-validate.js +105 -0
- package/dist/invariants-validate.js.map +1 -0
- package/dist/journey-annotate-api.d.ts +76 -0
- package/dist/journey-annotate-api.js +256 -0
- package/dist/journey-annotate-api.js.map +1 -0
- package/dist/journey-annotate-cli.d.ts +9 -0
- package/dist/journey-annotate-cli.js +179 -0
- package/dist/journey-annotate-cli.js.map +1 -0
- package/dist/journey-api.d.ts +79 -2
- package/dist/journey-api.js +136 -19
- package/dist/journey-api.js.map +1 -1
- package/dist/journey-cli.d.ts +4 -0
- package/dist/journey-cli.js +370 -0
- package/dist/journey-cli.js.map +1 -0
- package/dist/journey-demo-api.d.ts +112 -0
- package/dist/journey-demo-api.js +392 -0
- package/dist/journey-demo-api.js.map +1 -0
- package/dist/journey-demo-cli.d.ts +10 -0
- package/dist/journey-demo-cli.js +155 -0
- package/dist/journey-demo-cli.js.map +1 -0
- package/dist/kill-signal.d.ts +193 -0
- package/dist/kill-signal.js +284 -0
- package/dist/kill-signal.js.map +1 -0
- package/dist/launch-armed.d.ts +37 -0
- package/dist/launch-armed.js +31 -0
- package/dist/launch-armed.js.map +1 -0
- package/dist/ledger-api.d.ts +106 -0
- package/dist/ledger-api.js +237 -0
- package/dist/ledger-api.js.map +1 -0
- package/dist/ledger-cli.d.ts +18 -0
- package/dist/ledger-cli.js +107 -0
- package/dist/ledger-cli.js.map +1 -0
- package/dist/load-api.d.ts +29 -11
- package/dist/load-api.js +23 -15
- package/dist/load-api.js.map +1 -1
- package/dist/load-cli.d.ts +4 -0
- package/dist/load-cli.js +97 -0
- package/dist/load-cli.js.map +1 -0
- package/dist/log-correlation.d.ts +147 -0
- package/dist/log-correlation.js +325 -0
- package/dist/log-correlation.js.map +1 -0
- package/dist/log-lines.d.ts +131 -0
- package/dist/log-lines.js +389 -0
- package/dist/log-lines.js.map +1 -0
- package/dist/log-sources.d.ts +71 -0
- package/dist/log-sources.js +235 -0
- package/dist/log-sources.js.map +1 -0
- package/dist/logs-cli.d.ts +3 -0
- package/dist/logs-cli.js +51 -0
- package/dist/logs-cli.js.map +1 -0
- package/dist/logs-retention.d.ts +28 -0
- package/dist/logs-retention.js +84 -0
- package/dist/logs-retention.js.map +1 -0
- package/dist/mcp-api.d.ts +89 -1
- package/dist/mcp-api.js +472 -18
- package/dist/mcp-api.js.map +1 -1
- package/dist/mcp-args.d.ts +38 -0
- package/dist/mcp-args.js +131 -0
- package/dist/mcp-args.js.map +1 -0
- package/dist/mcp-cli-bridge.d.ts +34 -0
- package/dist/mcp-cli-bridge.js +62 -0
- package/dist/mcp-cli-bridge.js.map +1 -0
- package/dist/mcp-cli-runner.d.ts +29 -0
- package/dist/mcp-cli-runner.js +44 -0
- package/dist/mcp-cli-runner.js.map +1 -0
- package/dist/mcp-cli-tools.d.ts +125 -0
- package/dist/mcp-cli-tools.js +680 -0
- package/dist/mcp-cli-tools.js.map +1 -0
- package/dist/mcp-paths.d.ts +28 -0
- package/dist/mcp-paths.js +76 -0
- package/dist/mcp-paths.js.map +1 -0
- package/dist/mission-actors.d.ts +40 -0
- package/dist/mission-actors.js +72 -0
- package/dist/mission-actors.js.map +1 -0
- package/dist/mission-api.d.ts +35 -0
- package/dist/mission-api.js +58 -2
- package/dist/mission-api.js.map +1 -1
- package/dist/mission-cli.d.ts +4 -0
- package/dist/mission-cli.js +247 -0
- package/dist/mission-cli.js.map +1 -0
- package/dist/mission-exit.d.ts +22 -0
- package/dist/mission-exit.js +26 -0
- package/dist/mission-exit.js.map +1 -0
- package/dist/mission-fixtures.d.ts +225 -0
- package/dist/mission-fixtures.js +828 -0
- package/dist/mission-fixtures.js.map +1 -0
- package/dist/mission-journal.d.ts +60 -0
- package/dist/mission-journal.js +115 -0
- package/dist/mission-journal.js.map +1 -0
- package/dist/mission-queue-cli.d.ts +10 -0
- package/dist/mission-queue-cli.js +198 -0
- package/dist/mission-queue-cli.js.map +1 -0
- package/dist/mission-queue-runner.d.ts +126 -0
- package/dist/mission-queue-runner.js +397 -0
- package/dist/mission-queue-runner.js.map +1 -0
- package/dist/multi-run-cli.d.ts +37 -0
- package/dist/multi-run-cli.js +110 -0
- package/dist/multi-run-cli.js.map +1 -0
- package/dist/multi-run.d.ts +339 -0
- package/dist/multi-run.js +619 -0
- package/dist/multi-run.js.map +1 -0
- package/dist/openrouter-call.d.ts +22 -0
- package/dist/openrouter-call.js +63 -0
- package/dist/openrouter-call.js.map +1 -0
- package/dist/profile-cli.d.ts +4 -0
- package/dist/profile-cli.js +57 -0
- package/dist/profile-cli.js.map +1 -0
- package/dist/program.d.ts +3 -75
- package/dist/program.js +119 -1921
- package/dist/program.js.map +1 -1
- package/dist/project-dir.d.ts +96 -0
- package/dist/project-dir.js +220 -0
- package/dist/project-dir.js.map +1 -0
- package/dist/record-api.d.ts +10 -6
- package/dist/record-api.js +39 -28
- package/dist/record-api.js.map +1 -1
- package/dist/record-cli.d.ts +4 -0
- package/dist/record-cli.js +64 -0
- package/dist/record-cli.js.map +1 -0
- package/dist/recording-cli.d.ts +4 -0
- package/dist/recording-cli.js +248 -0
- package/dist/recording-cli.js.map +1 -0
- package/dist/regression-api.d.ts +101 -0
- package/dist/regression-api.js +384 -5
- package/dist/regression-api.js.map +1 -1
- package/dist/regression-cli.d.ts +4 -0
- package/dist/regression-cli.js +232 -0
- package/dist/regression-cli.js.map +1 -0
- package/dist/report-api.d.ts +146 -0
- package/dist/report-api.js +430 -0
- package/dist/report-api.js.map +1 -0
- package/dist/report-cli.d.ts +12 -0
- package/dist/report-cli.js +147 -0
- package/dist/report-cli.js.map +1 -0
- package/dist/result-schema.d.ts +22 -0
- package/dist/result-schema.js +28 -0
- package/dist/result-schema.js.map +1 -0
- package/dist/run-index.d.ts +29 -0
- package/dist/run-index.js +70 -0
- package/dist/run-index.js.map +1 -0
- package/dist/run-screenshots.d.ts +123 -0
- package/dist/run-screenshots.js +229 -0
- package/dist/run-screenshots.js.map +1 -0
- package/dist/runtime-env.d.ts +8 -0
- package/dist/runtime-env.js +22 -0
- package/dist/runtime-env.js.map +1 -0
- package/dist/secret-args.d.ts +23 -0
- package/dist/secret-args.js +45 -0
- package/dist/secret-args.js.map +1 -0
- package/dist/serve-cli.d.ts +4 -0
- package/dist/serve-cli.js +95 -0
- package/dist/serve-cli.js.map +1 -0
- package/dist/server-log-verify.d.ts +34 -0
- package/dist/server-log-verify.js +115 -0
- package/dist/server-log-verify.js.map +1 -0
- package/dist/session-check.d.ts +14 -0
- package/dist/session-check.js +44 -0
- package/dist/session-check.js.map +1 -0
- package/dist/site-cli.d.ts +4 -0
- package/dist/site-cli.js +127 -0
- package/dist/site-cli.js.map +1 -0
- package/dist/site-gate-cli.d.ts +28 -0
- package/dist/site-gate-cli.js +58 -0
- package/dist/site-gate-cli.js.map +1 -0
- package/dist/source-api.js +18 -3
- package/dist/source-api.js.map +1 -1
- package/dist/source-cli.d.ts +4 -0
- package/dist/source-cli.js +284 -0
- package/dist/source-cli.js.map +1 -0
- package/dist/source-run-api.d.ts +27 -1
- package/dist/source-run-api.js +22 -11
- package/dist/source-run-api.js.map +1 -1
- package/dist/storage-state-snapshot.d.ts +50 -0
- package/dist/storage-state-snapshot.js +87 -0
- package/dist/storage-state-snapshot.js.map +1 -0
- package/dist/suite-explore-options.d.ts +289 -0
- package/dist/suite-explore-options.js +140 -0
- package/dist/suite-explore-options.js.map +1 -0
- package/dist/target-config.d.ts +109 -0
- package/dist/target-config.js +216 -0
- package/dist/target-config.js.map +1 -0
- package/dist/transcript-file.d.ts +12 -0
- package/dist/transcript-file.js +23 -0
- package/dist/transcript-file.js.map +1 -0
- package/dist/ui-api.d.ts +3 -0
- package/dist/ui-api.js +7 -1
- package/dist/ui-api.js.map +1 -1
- package/dist/usability-capture.d.ts +43 -0
- package/dist/usability-capture.js +326 -0
- package/dist/usability-capture.js.map +1 -0
- package/dist/usage-config.d.ts +36 -0
- package/dist/usage-config.js +114 -0
- package/dist/usage-config.js.map +1 -0
- package/dist/ux-api.d.ts +3 -75
- package/dist/ux-api.js +3 -220
- package/dist/ux-api.js.map +1 -1
- package/dist/ux-cli.d.ts +4 -0
- package/dist/ux-cli.js +102 -0
- package/dist/ux-cli.js.map +1 -0
- package/dist/ux-config.d.ts +29 -0
- package/dist/ux-config.js +103 -0
- package/dist/ux-config.js.map +1 -0
- package/dist/ux-evidence.d.ts +54 -0
- package/dist/ux-evidence.js +197 -0
- package/dist/ux-evidence.js.map +1 -0
- package/dist/ux-review.d.ts +112 -0
- package/dist/ux-review.js +151 -0
- package/dist/ux-review.js.map +1 -0
- package/dist/ux-usability.d.ts +238 -0
- package/dist/ux-usability.js +494 -0
- package/dist/ux-usability.js.map +1 -0
- package/dist/verify-fix-api.d.ts +173 -0
- package/dist/verify-fix-api.js +454 -0
- package/dist/verify-fix-api.js.map +1 -0
- package/dist/verify-fix-cli.d.ts +4 -0
- package/dist/verify-fix-cli.js +110 -0
- package/dist/verify-fix-cli.js.map +1 -0
- package/package.json +19 -14
- package/skills/jevitate-ci-check/SKILL.md +77 -0
- package/skills/jevitate-demo/SKILL.md +61 -0
- package/skills/jevitate-explore/SKILL.md +88 -87
- package/skills/jevitate-getting-started/SKILL.md +88 -0
- package/skills/jevitate-load-test/SKILL.md +11 -2
- package/skills/jevitate-mission-scope/SKILL.md +19 -11
- package/skills/jevitate-record/SKILL.md +23 -5
- package/skills/jevitate-run-journey/SKILL.md +61 -17
- package/skills/jevitate-sources/SKILL.md +57 -14
- package/skills/jevitate-ux-review/SKILL.md +106 -16
- package/skills/jevitate-verify-fix/SKILL.md +76 -0
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
import { rm } from "node:fs/promises";
|
|
3
|
+
import { secretForms } from "@jevitate/ai-core";
|
|
4
|
+
import { DEMO_OVERLAY_HIDE_STYLE } from "@jevitate/explore";
|
|
5
|
+
import { descriptorToLocator } from "@jevitate/recorder";
|
|
6
|
+
/** The screenshot options a set of layers produces (the overlay-hiding style always first). */
|
|
7
|
+
export async function captureOptions(page, ctx, layers) {
|
|
8
|
+
const styles = [DEMO_OVERLAY_HIDE_STYLE];
|
|
9
|
+
const mask = [];
|
|
10
|
+
let maskColor;
|
|
11
|
+
for (const layer of layers) {
|
|
12
|
+
const c = await layer.prepare(page, ctx);
|
|
13
|
+
if (c === undefined)
|
|
14
|
+
continue;
|
|
15
|
+
if (c.style !== undefined && c.style !== "")
|
|
16
|
+
styles.push(c.style);
|
|
17
|
+
if (c.mask !== undefined)
|
|
18
|
+
mask.push(...c.mask);
|
|
19
|
+
if (c.maskColor !== undefined)
|
|
20
|
+
maskColor = c.maskColor;
|
|
21
|
+
}
|
|
22
|
+
return { style: styles.join("\n"), mask, ...(maskColor === undefined ? {} : { maskColor }) };
|
|
23
|
+
}
|
|
24
|
+
/** Writes one step's PNG at `path`: the viewport, overlay hidden, every layer applied. Throws on failure. */
|
|
25
|
+
export async function captureStepScreenshot(page, path, ctx, layers = []) {
|
|
26
|
+
const { style, mask, maskColor } = await captureOptions(page, ctx, layers);
|
|
27
|
+
await page.screenshot({
|
|
28
|
+
path,
|
|
29
|
+
type: "png",
|
|
30
|
+
animations: "disabled",
|
|
31
|
+
style,
|
|
32
|
+
...(mask.length === 0 ? {} : { mask }),
|
|
33
|
+
...(maskColor === undefined ? {} : { maskColor }),
|
|
34
|
+
});
|
|
35
|
+
try {
|
|
36
|
+
for (const layer of layers)
|
|
37
|
+
await layer.confirm?.(page, ctx);
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
await rm(path, { force: true });
|
|
41
|
+
throw err;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// ── #250/#251: the pixel mask ────────────────────────────────────────────────────────────────────
|
|
45
|
+
/** The solid colour a secret is painted over with (the usability capture's mask colour, pinned). */
|
|
46
|
+
export const PIXEL_MASK_COLOR = "#FF00FF";
|
|
47
|
+
/** The attribute marking the mask layer's host element (never hidden by the capture style). */
|
|
48
|
+
export const PIXEL_MASK_ATTR = "data-jevitate-mask-layer";
|
|
49
|
+
/** The mask could not be applied or proven: the capture is skipped (fail closed), never written. */
|
|
50
|
+
export class MaskUnavailableError extends Error {
|
|
51
|
+
code = "E_PIXEL_MASK";
|
|
52
|
+
constructor(message) {
|
|
53
|
+
super(message);
|
|
54
|
+
this.name = "MaskUnavailableError";
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* BROWSER CODE (a string: evaluated as-is, never transpiled). `__CFG__` is replaced by the JSON
|
|
59
|
+
* config `{ name, secrets, fill, attr }`. Idempotent per document; installs `window[name]`
|
|
60
|
+
* (non-enumerable, non-writable, non-configurable — a random name per run, so a page cannot
|
|
61
|
+
* pre-empt or fake it). Secret values live only inside this closure.
|
|
62
|
+
*/
|
|
63
|
+
const MASK_RUNTIME = String.raw `((cfg) => {
|
|
64
|
+
if (window[cfg.name]) return true;
|
|
65
|
+
const SECRETS = cfg.secrets.filter((s) => typeof s === "string" && s.trim().length > 0);
|
|
66
|
+
const SKIP = new Set(["SCRIPT", "STYLE", "NOSCRIPT", "TEMPLATE", "HEAD", "TITLE", "META", "LINK"]);
|
|
67
|
+
const PAD = 2;
|
|
68
|
+
const CSS = ":host{all:initial}*{pointer-events:none !important;box-sizing:border-box}[hidden]{display:none !important}" +
|
|
69
|
+
".m{position:fixed;background:" + cfg.fill + ";border-radius:2px}" +
|
|
70
|
+
".h{position:fixed;border:3px solid #f59e0b;border-radius:6px;box-shadow:0 0 0 4px rgba(245,158,11,.35)}";
|
|
71
|
+
let host = null;
|
|
72
|
+
let layer = null;
|
|
73
|
+
let hiBox = null;
|
|
74
|
+
let dirty = true;
|
|
75
|
+
let targets = [];
|
|
76
|
+
const boxes = [];
|
|
77
|
+
let drawn = [];
|
|
78
|
+
let highlightEl = null;
|
|
79
|
+
let lastError = "";
|
|
80
|
+
const holds = (s) => typeof s === "string" && s.length > 0 && SECRETS.some((x) => s.includes(x));
|
|
81
|
+
const ensureHost = () => {
|
|
82
|
+
const root = document.documentElement;
|
|
83
|
+
if (!root) return false;
|
|
84
|
+
if (host === null) {
|
|
85
|
+
host = document.createElement("jevitate-mask");
|
|
86
|
+
host.setAttribute(cfg.attr, "");
|
|
87
|
+
host.setAttribute("aria-hidden", "true");
|
|
88
|
+
host.setAttribute("inert", "");
|
|
89
|
+
const st = { display: "block", visibility: "visible", opacity: "1", position: "fixed", top: "0", left: "0",
|
|
90
|
+
width: "0", height: "0", overflow: "visible", "pointer-events": "none", "z-index": "2147483647",
|
|
91
|
+
transform: "none", filter: "none", "clip-path": "none", margin: "0", padding: "0", border: "0" };
|
|
92
|
+
for (const k of Object.keys(st)) host.style.setProperty(k, st[k], "important");
|
|
93
|
+
const shadow = host.attachShadow({ mode: "closed" });
|
|
94
|
+
try {
|
|
95
|
+
const sheet = new CSSStyleSheet();
|
|
96
|
+
sheet.replaceSync(CSS);
|
|
97
|
+
shadow.adoptedStyleSheets = [sheet];
|
|
98
|
+
} catch (e) {
|
|
99
|
+
const s = document.createElement("style");
|
|
100
|
+
s.textContent = CSS;
|
|
101
|
+
shadow.appendChild(s);
|
|
102
|
+
}
|
|
103
|
+
layer = document.createElement("div");
|
|
104
|
+
hiBox = document.createElement("div");
|
|
105
|
+
hiBox.className = "h";
|
|
106
|
+
hiBox.hidden = true;
|
|
107
|
+
shadow.append(layer, hiBox);
|
|
108
|
+
}
|
|
109
|
+
// The last child of <html>: painted after (above) every same-z-index page layer.
|
|
110
|
+
if (host.parentNode !== root || root.lastElementChild !== host) root.appendChild(host);
|
|
111
|
+
return true;
|
|
112
|
+
};
|
|
113
|
+
const collect = () => {
|
|
114
|
+
const out = [];
|
|
115
|
+
if (SECRETS.length === 0) return out;
|
|
116
|
+
const roots = [document];
|
|
117
|
+
const perSecretRanges = new Map();
|
|
118
|
+
for (let i = 0; i < roots.length; i++) {
|
|
119
|
+
const w = document.createTreeWalker(roots[i], NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT);
|
|
120
|
+
for (let n = w.nextNode(); n !== null; n = w.nextNode()) {
|
|
121
|
+
if (n.nodeType === 3) {
|
|
122
|
+
const p = n.parentElement;
|
|
123
|
+
if (p !== null && SKIP.has(p.tagName)) continue;
|
|
124
|
+
const v = n.nodeValue;
|
|
125
|
+
if (!v) continue;
|
|
126
|
+
for (const s of SECRETS) {
|
|
127
|
+
let at = v.indexOf(s);
|
|
128
|
+
while (at >= 0) {
|
|
129
|
+
out.push({ kind: "range", node: n, start: at, end: at + s.length });
|
|
130
|
+
perSecretRanges.set(s, (perSecretRanges.get(s) || 0) + 1);
|
|
131
|
+
at = v.indexOf(s, at + s.length);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
const el = n;
|
|
137
|
+
if (el === host) continue;
|
|
138
|
+
if (el.shadowRoot) roots.push(el.shadowRoot);
|
|
139
|
+
if (SKIP.has(el.tagName)) continue;
|
|
140
|
+
let hit = false;
|
|
141
|
+
const tag = el.tagName;
|
|
142
|
+
if (tag === "INPUT" || tag === "TEXTAREA") {
|
|
143
|
+
const type = (el.getAttribute("type") || "").toLowerCase();
|
|
144
|
+
if (!(tag === "INPUT" && type === "password") && holds(el.value)) hit = true;
|
|
145
|
+
} else if (tag === "SELECT") {
|
|
146
|
+
const t = Array.from(el.selectedOptions || []).map((o) => o.text).join(" ");
|
|
147
|
+
if (holds(t) || holds(el.value)) hit = true;
|
|
148
|
+
}
|
|
149
|
+
if (!hit) for (const a of Array.from(el.attributes)) if (holds(a.value)) { hit = true; break; }
|
|
150
|
+
if (hit) out.push({ kind: "el", el });
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// A secret split across text nodes (e.g. "sec<b>ret</b>"): mask the deepest element holding it whole.
|
|
154
|
+
const body = document.body;
|
|
155
|
+
if (body) {
|
|
156
|
+
const text = body.textContent || "";
|
|
157
|
+
for (const s of SECRETS) {
|
|
158
|
+
let total = 0;
|
|
159
|
+
for (let at = text.indexOf(s); at >= 0; at = text.indexOf(s, at + s.length)) total++;
|
|
160
|
+
if (total <= (perSecretRanges.get(s) || 0)) continue;
|
|
161
|
+
const walk = (el) => {
|
|
162
|
+
let child = false;
|
|
163
|
+
for (const c of Array.from(el.children)) {
|
|
164
|
+
if (SKIP.has(c.tagName)) continue;
|
|
165
|
+
if ((c.textContent || "").includes(s)) { child = true; walk(c); }
|
|
166
|
+
}
|
|
167
|
+
if (!child && !out.some((t) => t.kind === "range" && el.contains(t.node))) out.push({ kind: "el", el });
|
|
168
|
+
};
|
|
169
|
+
walk(body);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return out;
|
|
173
|
+
};
|
|
174
|
+
const rectsOf = (t) => {
|
|
175
|
+
if (t.kind === "range") {
|
|
176
|
+
if (!t.node.isConnected) return null;
|
|
177
|
+
const r = document.createRange();
|
|
178
|
+
try { r.setStart(t.node, t.start); r.setEnd(t.node, t.end); } catch (e) { return null; }
|
|
179
|
+
return Array.from(r.getClientRects());
|
|
180
|
+
}
|
|
181
|
+
if (!t.el.isConnected) return null;
|
|
182
|
+
return [t.el.getBoundingClientRect()];
|
|
183
|
+
};
|
|
184
|
+
const fieldText = (el) => el.tagName === "SELECT" ? Array.from(el.selectedOptions || []).map((o) => o.text).join(" ") + " " + el.value : el.value;
|
|
185
|
+
const inputsChanged = () => {
|
|
186
|
+
if (SECRETS.length === 0) return false;
|
|
187
|
+
const flagged = new Set(targets.filter((t) => t.kind === "el").map((t) => t.el));
|
|
188
|
+
for (const el of Array.from(document.querySelectorAll("input, textarea, select"))) {
|
|
189
|
+
if (el.tagName === "INPUT" && (el.getAttribute("type") || "").toLowerCase() === "password") continue;
|
|
190
|
+
if (holds(fieldText(el)) && !flagged.has(el)) return true;
|
|
191
|
+
}
|
|
192
|
+
return false;
|
|
193
|
+
};
|
|
194
|
+
const place = (d, r, pad) => {
|
|
195
|
+
d.style.left = (r.left - pad) + "px";
|
|
196
|
+
d.style.top = (r.top - pad) + "px";
|
|
197
|
+
d.style.width = (r.width + 2 * pad) + "px";
|
|
198
|
+
d.style.height = (r.height + 2 * pad) + "px";
|
|
199
|
+
};
|
|
200
|
+
const update = () => {
|
|
201
|
+
if (!ensureHost()) return;
|
|
202
|
+
if (dirty || inputsChanged()) { targets = collect(); dirty = false; }
|
|
203
|
+
const rects = [];
|
|
204
|
+
for (const t of targets) {
|
|
205
|
+
const rs = rectsOf(t);
|
|
206
|
+
if (rs === null) { dirty = true; continue; }
|
|
207
|
+
for (const r of rs) if (r.width > 0 || r.height > 0) rects.push(r);
|
|
208
|
+
}
|
|
209
|
+
while (boxes.length < rects.length) {
|
|
210
|
+
const d = document.createElement("div");
|
|
211
|
+
d.className = "m";
|
|
212
|
+
layer.appendChild(d);
|
|
213
|
+
boxes.push(d);
|
|
214
|
+
}
|
|
215
|
+
for (let i = 0; i < boxes.length; i++) {
|
|
216
|
+
const d = boxes[i];
|
|
217
|
+
if (i < rects.length) { place(d, rects[i], PAD); d.hidden = false; } else d.hidden = true;
|
|
218
|
+
}
|
|
219
|
+
drawn = rects;
|
|
220
|
+
if (highlightEl !== null && highlightEl.isConnected) {
|
|
221
|
+
place(hiBox, highlightEl.getBoundingClientRect(), 5);
|
|
222
|
+
hiBox.hidden = false;
|
|
223
|
+
} else hiBox.hidden = true;
|
|
224
|
+
};
|
|
225
|
+
const tick = () => {
|
|
226
|
+
try { update(); lastError = ""; } catch (e) { lastError = String((e && e.message) || e).slice(0, 200); }
|
|
227
|
+
requestAnimationFrame(tick);
|
|
228
|
+
};
|
|
229
|
+
const mo = new MutationObserver((records) => {
|
|
230
|
+
for (const r of records) {
|
|
231
|
+
if (r.type === "attributes" && (r.attributeName === "style" || r.attributeName === "class")) continue;
|
|
232
|
+
if (r.type === "childList" && r.target === document.documentElement &&
|
|
233
|
+
Array.from(r.addedNodes).concat(Array.from(r.removedNodes)).every((x) => x === host)) continue;
|
|
234
|
+
dirty = true;
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
mo.observe(document, { subtree: true, childList: true, characterData: true, attributes: true });
|
|
239
|
+
const mark = () => { dirty = true; };
|
|
240
|
+
window.addEventListener("input", mark, true);
|
|
241
|
+
window.addEventListener("change", mark, true);
|
|
242
|
+
const covers = (b, r) => b.left <= r.left + 0.5 && b.top <= r.top + 0.5 && b.right >= r.right - 0.5 && b.bottom >= r.bottom - 0.5;
|
|
243
|
+
const api = {
|
|
244
|
+
verify() {
|
|
245
|
+
dirty = true;
|
|
246
|
+
try { update(); } catch (e) {
|
|
247
|
+
return { ok: false, occurrences: 0, masked: 0, reason: "the mask update failed: " + String((e && e.message) || e).slice(0, 200), rects: [] };
|
|
248
|
+
}
|
|
249
|
+
const problems = [];
|
|
250
|
+
if (SECRETS.length > 0) {
|
|
251
|
+
if (host === null || !host.isConnected) problems.push("the mask layer is not attached");
|
|
252
|
+
else {
|
|
253
|
+
const cs = getComputedStyle(host);
|
|
254
|
+
if (cs.display === "none" || cs.visibility !== "visible" || Number(cs.opacity) < 1) problems.push("the mask layer is hidden");
|
|
255
|
+
if (document.documentElement.lastElementChild !== host) problems.push("the mask layer is not the last layer");
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
if (drawn.length > 0 && document.querySelector(":modal, :popover-open, :fullscreen") !== null) {
|
|
259
|
+
problems.push("a top-layer element (modal dialog, popover or fullscreen) could paint over the mask");
|
|
260
|
+
}
|
|
261
|
+
let masked = 0;
|
|
262
|
+
const live = boxes.filter((d) => !d.hidden).map((d) => d.getBoundingClientRect());
|
|
263
|
+
for (const r of drawn) if (live.some((b) => covers(b, r))) masked++;
|
|
264
|
+
if (masked < drawn.length) problems.push((drawn.length - masked) + " occurrence(s) not covered by a mask box");
|
|
265
|
+
if (lastError !== "") problems.push("the mask loop failed: " + lastError);
|
|
266
|
+
const out = { ok: problems.length === 0, occurrences: drawn.length, masked, rects: drawn.map((r) => ({ x: r.left, y: r.top, width: r.width, height: r.height })) };
|
|
267
|
+
if (problems.length > 0) out.reason = problems.join("; ");
|
|
268
|
+
return out;
|
|
269
|
+
},
|
|
270
|
+
highlight(el) { highlightEl = el || null; try { update(); } catch (e) { /* presentation only */ } return highlightEl !== null; },
|
|
271
|
+
clearHighlight() { highlightEl = null; try { update(); } catch (e) { /* presentation only */ } return true; },
|
|
272
|
+
};
|
|
273
|
+
Object.defineProperty(window, cfg.name, { value: Object.freeze(api), enumerable: false, configurable: false, writable: false });
|
|
274
|
+
requestAnimationFrame(tick);
|
|
275
|
+
return true;
|
|
276
|
+
})(__CFG__)`;
|
|
277
|
+
/** Bound on one mask round-trip (ms). */
|
|
278
|
+
const MASK_CALL_MS = 5_000;
|
|
279
|
+
async function within(p, what) {
|
|
280
|
+
let timer;
|
|
281
|
+
try {
|
|
282
|
+
return await Promise.race([
|
|
283
|
+
p,
|
|
284
|
+
new Promise((_, reject) => {
|
|
285
|
+
timer = setTimeout(() => reject(new MaskUnavailableError(`${what} timed out after ${MASK_CALL_MS}ms`)), MASK_CALL_MS);
|
|
286
|
+
}),
|
|
287
|
+
]);
|
|
288
|
+
}
|
|
289
|
+
finally {
|
|
290
|
+
if (timer !== undefined)
|
|
291
|
+
clearTimeout(timer);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
function errText(e) {
|
|
295
|
+
return (e instanceof Error ? e.message : String(e)).split("\n")[0] ?? "unknown error";
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* One run's pixel mask over its registered secrets (raw and URL-encoded forms, as `redactText`).
|
|
299
|
+
* `install` (per browser context, before its first navigation — every later document and frame gets
|
|
300
|
+
* it from an init script) keeps a VIDEO masked; `verify`/`layer()` prove it at each capture and
|
|
301
|
+
* `assertMasked` throws {@link MaskUnavailableError} when it cannot be proven. With no secrets there
|
|
302
|
+
* is nothing to mask: `verify` is trivially ok and nothing is injected for it.
|
|
303
|
+
*/
|
|
304
|
+
export class SecretPixelMask {
|
|
305
|
+
#source;
|
|
306
|
+
#name;
|
|
307
|
+
#contexts = new WeakSet();
|
|
308
|
+
/** True when there is at least one secret to mask. */
|
|
309
|
+
active;
|
|
310
|
+
constructor(secrets) {
|
|
311
|
+
const forms = [...new Set(secrets.filter((s) => typeof s === "string" && s.trim() !== "").flatMap((s) => [...secretForms(s)]))];
|
|
312
|
+
this.active = forms.length > 0;
|
|
313
|
+
this.#name = `__jevitateMask_${randomBytes(8).toString("hex")}`;
|
|
314
|
+
// JSON inside a JS expression (valid JS since ES2019); `<` escaped so no value can close a script context.
|
|
315
|
+
const cfg = JSON.stringify({ name: this.#name, secrets: forms, fill: PIXEL_MASK_COLOR, attr: PIXEL_MASK_ATTR })
|
|
316
|
+
.replace(/</g, "\\u003c");
|
|
317
|
+
this.#source = MASK_RUNTIME.replace("__CFG__", () => cfg);
|
|
318
|
+
}
|
|
319
|
+
/** Installs the live mask in `page`'s context (every future document/frame) and every current frame. Throws when it cannot. */
|
|
320
|
+
async install(page) {
|
|
321
|
+
const ctx = page.context();
|
|
322
|
+
if (!this.#contexts.has(ctx)) {
|
|
323
|
+
try {
|
|
324
|
+
await within(ctx.addInitScript({ content: this.#source }), "installing the pixel mask");
|
|
325
|
+
}
|
|
326
|
+
catch (e) {
|
|
327
|
+
throw new MaskUnavailableError(`could not install the pixel mask: ${errText(e)}`);
|
|
328
|
+
}
|
|
329
|
+
this.#contexts.add(ctx);
|
|
330
|
+
}
|
|
331
|
+
for (const p of ctx.pages())
|
|
332
|
+
for (const f of p.frames())
|
|
333
|
+
await this.#inject(f);
|
|
334
|
+
}
|
|
335
|
+
async #inject(frame) {
|
|
336
|
+
if (frame.isDetached())
|
|
337
|
+
return;
|
|
338
|
+
try {
|
|
339
|
+
await within(frame.evaluate(this.#source), "injecting the pixel mask");
|
|
340
|
+
}
|
|
341
|
+
catch (e) {
|
|
342
|
+
if (frame.isDetached())
|
|
343
|
+
return;
|
|
344
|
+
throw new MaskUnavailableError(`could not apply the pixel mask to a frame: ${errText(e)}`);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
/** Proves the mask covers every visible secret occurrence in every frame of `page`, now. */
|
|
348
|
+
async verify(page) {
|
|
349
|
+
if (!this.active)
|
|
350
|
+
return { ok: true, occurrences: 0, masked: 0, rects: [] };
|
|
351
|
+
let occurrences = 0;
|
|
352
|
+
let masked = 0;
|
|
353
|
+
let rects = [];
|
|
354
|
+
const reasons = [];
|
|
355
|
+
for (const frame of page.frames()) {
|
|
356
|
+
if (frame.isDetached())
|
|
357
|
+
continue;
|
|
358
|
+
try {
|
|
359
|
+
await this.#inject(frame);
|
|
360
|
+
const r = await within(frame.evaluate((name) => window[name]?.verify() ?? null, this.#name), "verifying the pixel mask");
|
|
361
|
+
if (r === null) {
|
|
362
|
+
reasons.push("the mask is not installed in a frame");
|
|
363
|
+
continue;
|
|
364
|
+
}
|
|
365
|
+
occurrences += r.occurrences;
|
|
366
|
+
masked += r.masked;
|
|
367
|
+
if (frame === page.mainFrame())
|
|
368
|
+
rects = r.rects;
|
|
369
|
+
if (!r.ok)
|
|
370
|
+
reasons.push(r.reason ?? "the mask could not be proven");
|
|
371
|
+
}
|
|
372
|
+
catch (e) {
|
|
373
|
+
if (frame.isDetached())
|
|
374
|
+
continue;
|
|
375
|
+
reasons.push(errText(e));
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
return { ok: reasons.length === 0, occurrences, masked, rects, ...(reasons.length === 0 ? {} : { reason: reasons.join("; ") }) };
|
|
379
|
+
}
|
|
380
|
+
/** Throws {@link MaskUnavailableError} unless {@link verify} proves the mask. */
|
|
381
|
+
async assertMasked(page) {
|
|
382
|
+
const r = await this.verify(page);
|
|
383
|
+
if (!r.ok)
|
|
384
|
+
throw new MaskUnavailableError(`secret masking could not be proven: ${r.reason ?? "unknown"}`);
|
|
385
|
+
return r;
|
|
386
|
+
}
|
|
387
|
+
/** The capture layer: proven before the screenshot and again after it (a failure deletes the file). */
|
|
388
|
+
layer() {
|
|
389
|
+
return {
|
|
390
|
+
name: "secret-pixel-mask",
|
|
391
|
+
prepare: async (page) => {
|
|
392
|
+
await this.assertMasked(page);
|
|
393
|
+
},
|
|
394
|
+
confirm: async (page) => {
|
|
395
|
+
await this.assertMasked(page);
|
|
396
|
+
},
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
/** Draws a capture highlight box around `target`'s first match (display-only). True when shown. */
|
|
400
|
+
async highlight(page, target) {
|
|
401
|
+
try {
|
|
402
|
+
await this.#inject(page.mainFrame());
|
|
403
|
+
return await within(descriptorToLocator(page, target)
|
|
404
|
+
.first()
|
|
405
|
+
.evaluate((el, name) => window[name]?.highlight(el) === true, this.#name, { timeout: 2_000 }), "highlighting the failing element");
|
|
406
|
+
}
|
|
407
|
+
catch {
|
|
408
|
+
return false; // a highlight is presentation only
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
/** Removes the capture highlight (best-effort). */
|
|
412
|
+
async clearHighlight(page) {
|
|
413
|
+
await within(page.evaluate((name) => window[name]?.clearHighlight(), this.#name), "clearing the highlight").catch(() => undefined);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* A port whose every session carries the live pixel mask from before its first navigation — so a
|
|
418
|
+
* `recordVideo` session's every frame is masked. A session whose mask cannot be installed is closed
|
|
419
|
+
* and the open throws {@link MaskUnavailableError}: nothing is recorded unmasked.
|
|
420
|
+
*/
|
|
421
|
+
export function maskingPort(port, mask) {
|
|
422
|
+
if (!mask.active)
|
|
423
|
+
return port;
|
|
424
|
+
return {
|
|
425
|
+
open: async (o) => {
|
|
426
|
+
const session = await port.open(o);
|
|
427
|
+
try {
|
|
428
|
+
await mask.install(session.page);
|
|
429
|
+
}
|
|
430
|
+
catch (e) {
|
|
431
|
+
await session.close().catch(() => undefined);
|
|
432
|
+
throw e;
|
|
433
|
+
}
|
|
434
|
+
return session;
|
|
435
|
+
},
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
//# sourceMappingURL=demo-capture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"demo-capture.js","sourceRoot":"","sources":["../src/demo-capture.ts"],"names":[],"mappings":"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"}
|
package/dist/engine.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build identity for every mission result, issue draft, and `--version` (issue #83): "It's hard
|
|
3
|
+
* to attribute results to a build" — the dev workflow (`npm link` to a live working tree) means
|
|
4
|
+
* `jevitate --version`'s package.json number alone doesn't change between rebuilds, so two
|
|
5
|
+
* results from different builds in the same dogfooding session were indistinguishable.
|
|
6
|
+
*
|
|
7
|
+
* `commit`/`builtAt` come from ONE of two places, and both fall back to `"unknown"` — never a
|
|
8
|
+
* fabricated value:
|
|
9
|
+
*
|
|
10
|
+
* - the esbuild bundle (`pnpm --filter @jevitate/cli run bundle`, what npm actually publishes)
|
|
11
|
+
* folds them in as literals via an esbuild `define` (`build.mjs`), computed there from
|
|
12
|
+
* `git rev-parse` at bundle time;
|
|
13
|
+
* - the plain `tsc --build` dist (what a dev `npm link` install runs — no bundler
|
|
14
|
+
* substitution ever touches it) reads the SAME git-rev-parse-or-"unknown" computation from a
|
|
15
|
+
* small generated module written just before `tsc --build` runs
|
|
16
|
+
* (`scripts/generate-build-info.mjs`, hooked into the package's "build" script).
|
|
17
|
+
*
|
|
18
|
+
* Both compute identically; only the injection mechanism differs by build path, so this module
|
|
19
|
+
* simply prefers whichever one actually ran.
|
|
20
|
+
*/
|
|
21
|
+
export interface EngineInfo {
|
|
22
|
+
readonly version: string;
|
|
23
|
+
readonly commit: string;
|
|
24
|
+
readonly builtAt: string;
|
|
25
|
+
}
|
|
26
|
+
/** This build's identity: the published version plus which commit/build produced it. */
|
|
27
|
+
export declare function currentEngineInfo(): EngineInfo;
|
|
28
|
+
/**
|
|
29
|
+
* Stamps a CLI result with the build that produced it (#112) — every envelope a command emits
|
|
30
|
+
* (`journey run`, `load run`, `source run`, `verify-fix`, `regression capture`, `ux`) carries the
|
|
31
|
+
* same `engine` the explore results do, so evidence from any surface can be tied to a build.
|
|
32
|
+
*/
|
|
33
|
+
export declare function withEngine<T extends object>(result: T, engine?: EngineInfo): T & {
|
|
34
|
+
engine: EngineInfo;
|
|
35
|
+
};
|
package/dist/engine.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { GENERATED_BUILT_AT, GENERATED_COMMIT } from "./build-info.generated.js";
|
|
2
|
+
import { readCliVersion } from "./version.js";
|
|
3
|
+
function bundledCommit() {
|
|
4
|
+
return typeof __JEVITATE_BUILD_COMMIT__ !== "undefined" ? __JEVITATE_BUILD_COMMIT__ : undefined;
|
|
5
|
+
}
|
|
6
|
+
function bundledBuiltAt() {
|
|
7
|
+
return typeof __JEVITATE_BUILT_AT__ !== "undefined" ? __JEVITATE_BUILT_AT__ : undefined;
|
|
8
|
+
}
|
|
9
|
+
/** This build's identity: the published version plus which commit/build produced it. */
|
|
10
|
+
export function currentEngineInfo() {
|
|
11
|
+
return {
|
|
12
|
+
version: readCliVersion(),
|
|
13
|
+
commit: bundledCommit() ?? GENERATED_COMMIT,
|
|
14
|
+
builtAt: bundledBuiltAt() ?? GENERATED_BUILT_AT,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Stamps a CLI result with the build that produced it (#112) — every envelope a command emits
|
|
19
|
+
* (`journey run`, `load run`, `source run`, `verify-fix`, `regression capture`, `ux`) carries the
|
|
20
|
+
* same `engine` the explore results do, so evidence from any surface can be tied to a build.
|
|
21
|
+
*/
|
|
22
|
+
export function withEngine(result, engine = currentEngineInfo()) {
|
|
23
|
+
return { ...result, engine };
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACjF,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAkC9C,SAAS,aAAa;IACpB,OAAO,OAAO,yBAAyB,KAAK,WAAW,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,SAAS,CAAC;AAClG,CAAC;AAED,SAAS,cAAc;IACrB,OAAO,OAAO,qBAAqB,KAAK,WAAW,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,SAAS,CAAC;AAC1F,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,iBAAiB;IAC/B,OAAO;QACL,OAAO,EAAE,cAAc,EAAE;QACzB,MAAM,EAAE,aAAa,EAAE,IAAI,gBAAgB;QAC3C,OAAO,EAAE,cAAc,EAAE,IAAI,kBAAkB;KAChD,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAmB,MAAS,EAAE,SAAqB,iBAAiB,EAAE;IAC9F,OAAO,EAAE,GAAG,MAAM,EAAE,MAAM,EAAE,CAAC;AAC/B,CAAC"}
|