@jevitate/cli 0.16.1 → 0.18.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 +55 -5
- package/dist/author-journey-cli.js +11 -8
- package/dist/author-journey-cli.js.map +1 -1
- package/dist/bin.js +3126 -1078
- package/dist/build-info.generated.js +3 -3
- package/dist/catalog-api.d.ts +22 -0
- package/dist/catalog-api.js +49 -0
- package/dist/catalog-api.js.map +1 -1
- package/dist/catalog-cli.js +59 -37
- package/dist/catalog-cli.js.map +1 -1
- package/dist/cli-shared.d.ts +6 -1
- package/dist/cli-shared.js +11 -2
- package/dist/cli-shared.js.map +1 -1
- package/dist/exit-codes.js +9 -0
- package/dist/exit-codes.js.map +1 -1
- package/dist/journey-anchor-cli.js +16 -8
- package/dist/journey-anchor-cli.js.map +1 -1
- package/dist/journey-annotate-cli.js +10 -5
- package/dist/journey-annotate-cli.js.map +1 -1
- package/dist/journey-api.d.ts +10 -0
- package/dist/journey-api.js +23 -2
- package/dist/journey-api.js.map +1 -1
- package/dist/journey-bundle.d.ts +83 -0
- package/dist/journey-bundle.js +252 -0
- package/dist/journey-bundle.js.map +1 -0
- package/dist/journey-chain.d.ts +105 -0
- package/dist/journey-chain.js +331 -0
- package/dist/journey-chain.js.map +1 -0
- package/dist/journey-cli/anchors.js +11 -6
- package/dist/journey-cli/anchors.js.map +1 -1
- package/dist/journey-cli/chain.d.ts +8 -0
- package/dist/journey-cli/chain.js +113 -0
- package/dist/journey-cli/chain.js.map +1 -0
- package/dist/journey-cli/find.js +10 -5
- package/dist/journey-cli/find.js.map +1 -1
- package/dist/journey-cli/lint.js +13 -9
- package/dist/journey-cli/lint.js.map +1 -1
- package/dist/journey-cli/list.js +10 -5
- package/dist/journey-cli/list.js.map +1 -1
- package/dist/journey-cli/migrate.js +13 -6
- package/dist/journey-cli/migrate.js.map +1 -1
- package/dist/journey-cli/promote.js +11 -6
- package/dist/journey-cli/promote.js.map +1 -1
- package/dist/journey-cli/publish.js +12 -6
- package/dist/journey-cli/publish.js.map +1 -1
- package/dist/journey-cli/review.js +14 -8
- package/dist/journey-cli/review.js.map +1 -1
- package/dist/journey-cli/run.js +25 -10
- package/dist/journey-cli/run.js.map +1 -1
- package/dist/journey-cli/shared.d.ts +19 -1
- package/dist/journey-cli/shared.js +28 -0
- package/dist/journey-cli/shared.js.map +1 -1
- package/dist/journey-cli/verify.js +13 -6
- package/dist/journey-cli/verify.js.map +1 -1
- package/dist/journey-cli-bundle.d.ts +4 -0
- package/dist/journey-cli-bundle.js +70 -0
- package/dist/journey-cli-bundle.js.map +1 -0
- package/dist/journey-cli-readiness.d.ts +4 -0
- package/dist/journey-cli-readiness.js +163 -0
- package/dist/journey-cli-readiness.js.map +1 -0
- package/dist/journey-cli.d.ts +1 -1
- package/dist/journey-cli.js +9 -1
- package/dist/journey-cli.js.map +1 -1
- package/dist/journey-demo-cli.js +10 -5
- package/dist/journey-demo-cli.js.map +1 -1
- package/dist/journey-handback.d.ts +62 -0
- package/dist/journey-handback.js +150 -0
- package/dist/journey-handback.js.map +1 -0
- package/dist/journey-link-api.js +1 -1
- package/dist/journey-link-api.js.map +1 -1
- package/dist/journey-link-cli.js +13 -8
- package/dist/journey-link-cli.js.map +1 -1
- package/dist/journey-readiness.d.ts +104 -0
- package/dist/journey-readiness.js +369 -0
- package/dist/journey-readiness.js.map +1 -0
- package/dist/journey-verify.d.ts +2 -0
- package/dist/journey-verify.js +14 -1
- package/dist/journey-verify.js.map +1 -1
- package/dist/mcp-cli-tools.js +79 -20
- package/dist/mcp-cli-tools.js.map +1 -1
- package/dist/program.js +3 -0
- package/dist/program.js.map +1 -1
- package/dist/project-layout.d.ts +57 -0
- package/dist/project-layout.js +144 -0
- package/dist/project-layout.js.map +1 -0
- package/dist/project-where.d.ts +4 -0
- package/dist/project-where.js +48 -0
- package/dist/project-where.js.map +1 -0
- package/package.json +9 -9
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { Journey, JourneyReview } from "@jevitate/journey";
|
|
2
|
+
import { loadCatalog } from "./catalog-api.js";
|
|
3
|
+
import type { Catalog } from "./catalog.js";
|
|
4
|
+
import { reviewJourneyById } from "./journey-review-api.js";
|
|
5
|
+
import { runJourneyReadiness, type ReadinessReceipt, type ReadinessVerdict } from "./journey-readiness.js";
|
|
6
|
+
/**
|
|
7
|
+
* #584 — `jevitate journey bundle <id> [--with <toId>] --out <dir>` and
|
|
8
|
+
* `jevitate journey bundle --check <dir>` (docs/contracts/readiness-and-bundle.md §4). The bundle is
|
|
9
|
+
* local and never uploaded: it writes `<dir>/bundle.md` and `<dir>/manifest.json` from a `report`-mode
|
|
10
|
+
* readiness (a browser never opens). `bundle.md` is what a reviewer reads — the verdict, blockers and
|
|
11
|
+
* any inconclusive/stale proof first, then each Journey's intent, links, contracts, boundary, side
|
|
12
|
+
* effects, hashes, step objectives and readiness checks — and the human-only commands to run next.
|
|
13
|
+
* `manifest.json` records every hash it was built from; `--check` re-derives them and fails closed
|
|
14
|
+
* (`E_BUNDLE_STALE`) when any moved. It only prints commands a person runs: it never approves,
|
|
15
|
+
* promotes or uploads.
|
|
16
|
+
*/
|
|
17
|
+
/** #584: a local bundle build's request. `out` is created (recursively) if missing; nothing outside it is written. */
|
|
18
|
+
export interface JourneyBundleOptions {
|
|
19
|
+
readonly id: string;
|
|
20
|
+
readonly with?: string;
|
|
21
|
+
readonly out: string;
|
|
22
|
+
readonly journeysDir: string;
|
|
23
|
+
readonly catalogDir?: string | null;
|
|
24
|
+
readonly targetsFile?: string;
|
|
25
|
+
/** The project root an upload fixture resolves against, as `journey run` (optional). */
|
|
26
|
+
readonly projectDir?: string;
|
|
27
|
+
}
|
|
28
|
+
export interface JourneyBundleCheckOptions {
|
|
29
|
+
readonly journeysDir: string;
|
|
30
|
+
readonly catalogDir?: string | null;
|
|
31
|
+
readonly targetsFile?: string;
|
|
32
|
+
}
|
|
33
|
+
/** #584: test seams. `readiness`/`review`/`loadCatalog` default to the real modules. */
|
|
34
|
+
export interface JourneyBundleDeps {
|
|
35
|
+
readonly readiness?: typeof runJourneyReadiness;
|
|
36
|
+
readonly review?: typeof reviewJourneyById;
|
|
37
|
+
readonly loadCatalog?: typeof loadCatalog;
|
|
38
|
+
/** Whether a Journey has a pending annotation draft (default: the sidecar file exists). */
|
|
39
|
+
readonly annotationDraft?: (journeysDir: string, id: string) => boolean;
|
|
40
|
+
readonly cwd?: () => string;
|
|
41
|
+
}
|
|
42
|
+
export interface JourneyBundleResult {
|
|
43
|
+
readonly out: string;
|
|
44
|
+
readonly files: readonly string[];
|
|
45
|
+
readonly verdict: ReadinessVerdict;
|
|
46
|
+
}
|
|
47
|
+
export interface JourneyBundleCheckResult {
|
|
48
|
+
readonly stale: false;
|
|
49
|
+
}
|
|
50
|
+
/** One hash the bundle was built from, so `--check` can re-derive it. */
|
|
51
|
+
export interface JourneyBundleManifest {
|
|
52
|
+
readonly bundleVersion: 1;
|
|
53
|
+
readonly journeys: ReadonlyArray<{
|
|
54
|
+
readonly id: string;
|
|
55
|
+
readonly contentHash: string;
|
|
56
|
+
readonly reviewHash: string;
|
|
57
|
+
}>;
|
|
58
|
+
readonly catalog: ReadonlyArray<{
|
|
59
|
+
readonly kind: "persona" | "job";
|
|
60
|
+
readonly id: string;
|
|
61
|
+
readonly hash: string;
|
|
62
|
+
}>;
|
|
63
|
+
readonly verdict: ReadinessVerdict;
|
|
64
|
+
readonly generatedAt: string;
|
|
65
|
+
}
|
|
66
|
+
/** #584: a stale manifest — `--check` re-derived a different hash (exit 1). */
|
|
67
|
+
export declare class BundleStaleError extends Error {
|
|
68
|
+
readonly changed: readonly string[];
|
|
69
|
+
readonly code = "E_BUNDLE_STALE";
|
|
70
|
+
constructor(changed: readonly string[]);
|
|
71
|
+
}
|
|
72
|
+
interface JourneyEntry {
|
|
73
|
+
readonly id: string;
|
|
74
|
+
readonly journey: Journey;
|
|
75
|
+
readonly review: JourneyReview;
|
|
76
|
+
}
|
|
77
|
+
/** §4: the bundle's Markdown. The verdict, blockers and any inconclusive/stale proof come first. */
|
|
78
|
+
export declare function renderJourneyBundle(receipt: ReadinessReceipt, entries: readonly JourneyEntry[], catalog: Catalog, drafts: ReadonlySet<string>): string;
|
|
79
|
+
/** #584: build the local bundle from a `report`-mode readiness and the review sheet of each Journey. */
|
|
80
|
+
export declare function buildJourneyBundle(opts: JourneyBundleOptions, deps?: JourneyBundleDeps): Promise<JourneyBundleResult>;
|
|
81
|
+
/** #584: re-derive every hash the bundle recorded; a moved hash throws `BundleStaleError` (exit 1). */
|
|
82
|
+
export declare function checkJourneyBundle(dir: string, opts: JourneyBundleCheckOptions, deps?: JourneyBundleDeps): Promise<JourneyBundleCheckResult>;
|
|
83
|
+
export {};
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
3
|
+
import { join, resolve } from "node:path";
|
|
4
|
+
import { clock } from "@jevitate/domain";
|
|
5
|
+
import { loadCatalog } from "./catalog-api.js";
|
|
6
|
+
import { annotationDraftPath, journeyContentHash } from "./journey-annotate-api.js";
|
|
7
|
+
import { reviewJourneyById } from "./journey-review-api.js";
|
|
8
|
+
import { runJourneyReadiness } from "./journey-readiness.js";
|
|
9
|
+
/** #584: a stale manifest — `--check` re-derived a different hash (exit 1). */
|
|
10
|
+
export class BundleStaleError extends Error {
|
|
11
|
+
changed;
|
|
12
|
+
code = "E_BUNDLE_STALE";
|
|
13
|
+
constructor(changed) {
|
|
14
|
+
super(`the bundle is stale: ${changed.join("; ")}`);
|
|
15
|
+
this.changed = changed;
|
|
16
|
+
this.name = "BundleStaleError";
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/** The label every approval state carries (§4): technical readiness, draft, prior approval, stale approval, current authorization. */
|
|
20
|
+
function catalogApprovalLabel(status) {
|
|
21
|
+
switch (status) {
|
|
22
|
+
case "approved":
|
|
23
|
+
return "current authorization";
|
|
24
|
+
case "stale":
|
|
25
|
+
return "stale approval";
|
|
26
|
+
case "draft":
|
|
27
|
+
return "draft";
|
|
28
|
+
default:
|
|
29
|
+
return "unknown";
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/** How a Journey's own promotion reads: not promoted is `draft`, an approval that no longer binds is `stale approval`. */
|
|
33
|
+
function journeyApprovalLabel(entry) {
|
|
34
|
+
const approval = entry.journey.metadata.approval;
|
|
35
|
+
const change = entry.review.changeSinceApproval;
|
|
36
|
+
const stale = (change.kind === "diff" || change.kind === "snapshot-missing") && change.changed;
|
|
37
|
+
if (entry.journey.metadata.promoted && approval !== undefined && !stale)
|
|
38
|
+
return "current authorization";
|
|
39
|
+
if (stale)
|
|
40
|
+
return "stale approval";
|
|
41
|
+
if (approval !== undefined)
|
|
42
|
+
return "prior approval";
|
|
43
|
+
return "draft";
|
|
44
|
+
}
|
|
45
|
+
function handoffFieldLines(fields, indent) {
|
|
46
|
+
return Object.entries(fields).map(([name, decl]) => `${indent}${name}: ${decl.type}${decl.required === false ? " (optional)" : ""}`);
|
|
47
|
+
}
|
|
48
|
+
/** §4: the #582 contracts, by field name and type only (never a value). */
|
|
49
|
+
function contractLines(entry) {
|
|
50
|
+
const outputs = entry.journey.metadata.outputs;
|
|
51
|
+
const inputs = entry.journey.metadata.inputs;
|
|
52
|
+
if (outputs === undefined && inputs === undefined)
|
|
53
|
+
return ["contracts: none declared"];
|
|
54
|
+
const lines = ["contracts:"];
|
|
55
|
+
if (outputs !== undefined)
|
|
56
|
+
lines.push(...outputsLines(outputs));
|
|
57
|
+
if (inputs !== undefined)
|
|
58
|
+
lines.push(...inputsLines(inputs));
|
|
59
|
+
return lines;
|
|
60
|
+
}
|
|
61
|
+
function outputsLines(outputs) {
|
|
62
|
+
const lines = [` outputs: ${outputs.contract}`];
|
|
63
|
+
lines.push(...handoffFieldLines(outputs.fields, " "));
|
|
64
|
+
if (outputs.collection !== undefined)
|
|
65
|
+
lines.push(` collection: ${outputs.collection}`);
|
|
66
|
+
return lines;
|
|
67
|
+
}
|
|
68
|
+
function inputsLines(inputs) {
|
|
69
|
+
const lines = [` inputs: accepts ${inputs.accepts}`, ...handoffFieldLines(inputs.request.fields, " request ")];
|
|
70
|
+
for (const [param, binding] of Object.entries(inputs.bindings)) {
|
|
71
|
+
const source = "record" in binding ? `record.${binding.record}` : "request" in binding ? `request.${binding.request}` : "const" in binding ? `const.${binding.const}` : `secret.${binding.secret}`;
|
|
72
|
+
lines.push(` binding ${param} <- ${source}`);
|
|
73
|
+
}
|
|
74
|
+
return lines;
|
|
75
|
+
}
|
|
76
|
+
/** §4: a person runs these, in order (persona approve, job approve, annotations approve, journey promote). */
|
|
77
|
+
function humanCommands(entry, catalog, draft, ready) {
|
|
78
|
+
const commands = [];
|
|
79
|
+
const personaId = entry.review.catalog?.persona?.id;
|
|
80
|
+
const jobId = entry.review.catalog?.job?.id;
|
|
81
|
+
if (personaId !== undefined) {
|
|
82
|
+
const hash = catalog.personas.find((p) => p.id === personaId)?.contentHash;
|
|
83
|
+
commands.push(`jevitate persona approve ${personaId}${hash === undefined ? "" : ` --reviewed-hash ${hash}`}`);
|
|
84
|
+
}
|
|
85
|
+
if (jobId !== undefined) {
|
|
86
|
+
const hash = catalog.jobs.find((j) => j.id === jobId)?.contentHash;
|
|
87
|
+
commands.push(`jevitate job approve ${jobId}${hash === undefined ? "" : ` --reviewed-hash ${hash}`}`);
|
|
88
|
+
}
|
|
89
|
+
if (draft)
|
|
90
|
+
commands.push(`jevitate journey annotate ${entry.id} --approve`);
|
|
91
|
+
// §4: while any technical blocker remains, promote moves under "After the blockers are fixed" without a hash.
|
|
92
|
+
if (ready)
|
|
93
|
+
commands.push(`jevitate journey promote ${entry.id} --reviewed-hash ${entry.review.contentHash}`);
|
|
94
|
+
return commands;
|
|
95
|
+
}
|
|
96
|
+
function journeySection(entry, receipt) {
|
|
97
|
+
const m = entry.journey.metadata;
|
|
98
|
+
const lines = [`## Journey: ${entry.id}`, ""];
|
|
99
|
+
lines.push(`goal: ${m.goal ?? "(none)"}`);
|
|
100
|
+
const links = entry.review.catalog;
|
|
101
|
+
if (links?.persona !== undefined)
|
|
102
|
+
lines.push(`persona: ${links.persona.id} (${catalogApprovalLabel(links.persona.status)})`);
|
|
103
|
+
if (links?.job !== undefined)
|
|
104
|
+
lines.push(`job: ${links.job.id} (${catalogApprovalLabel(links.job.status)})`);
|
|
105
|
+
lines.push(...contractLines(entry));
|
|
106
|
+
const boundary = m.boundary;
|
|
107
|
+
lines.push(boundary === undefined ? "boundary: none declared" : `boundary: ${boundary.kind}; stop before "${boundary.stopBefore.label}"; next step: ${boundary.nextStep}`);
|
|
108
|
+
lines.push("side effects:");
|
|
109
|
+
if (entry.review.sideEffects.writeRequests.length === 0)
|
|
110
|
+
lines.push(" none");
|
|
111
|
+
for (const w of entry.review.sideEffects.writeRequests)
|
|
112
|
+
lines.push(` ${w.method} ${w.endpoint} (${w.source}${w.step === undefined ? "" : `, step ${w.step}`})`);
|
|
113
|
+
lines.push(`content hash: ${journeyContentHash(entry.journey)}`);
|
|
114
|
+
lines.push(`review hash: ${entry.review.contentHash}`);
|
|
115
|
+
lines.push(`approval: ${journeyApprovalLabel(entry)}`);
|
|
116
|
+
lines.push("steps:");
|
|
117
|
+
for (const step of entry.review.steps)
|
|
118
|
+
lines.push(` ${step.number}. ${step.action} — objective: ${step.objective ?? "(pending)"}`);
|
|
119
|
+
if (entry.review.summary.missingIntent.length > 0) {
|
|
120
|
+
lines.push("pending annotations:");
|
|
121
|
+
for (const item of entry.review.summary.missingIntent)
|
|
122
|
+
lines.push(` - ${item}`);
|
|
123
|
+
}
|
|
124
|
+
lines.push("readiness:");
|
|
125
|
+
for (const check of receipt.checks.filter((c) => c.journey === entry.id))
|
|
126
|
+
lines.push(checkLine(check));
|
|
127
|
+
return lines;
|
|
128
|
+
}
|
|
129
|
+
function checkLine(check) {
|
|
130
|
+
return ` ${check.check}: ${check.state} — ${check.detail}${check.evidence === undefined ? "" : ` (evidence: ${check.evidence})`}`;
|
|
131
|
+
}
|
|
132
|
+
/** §4: the bundle's Markdown. The verdict, blockers and any inconclusive/stale proof come first. */
|
|
133
|
+
export function renderJourneyBundle(receipt, entries, catalog, drafts) {
|
|
134
|
+
const lines = [`# Journey readiness bundle`, "", `verdict: ${receipt.verdict}`, ""];
|
|
135
|
+
const blockers = receipt.blockers;
|
|
136
|
+
if (blockers.length > 0) {
|
|
137
|
+
lines.push("## Blockers", "");
|
|
138
|
+
for (const b of blockers)
|
|
139
|
+
lines.push(`- ${b.journey} ${b.check}: ${b.why} — next: ${b.next}`);
|
|
140
|
+
lines.push("");
|
|
141
|
+
}
|
|
142
|
+
const flagged = receipt.checks.filter((c) => c.state === "inconclusive" || c.state === "stale");
|
|
143
|
+
if (flagged.length > 0) {
|
|
144
|
+
lines.push("## Inconclusive or stale evidence", "");
|
|
145
|
+
for (const c of flagged)
|
|
146
|
+
lines.push(`- ${c.journey} ${c.check}: ${c.state} — ${c.detail}`);
|
|
147
|
+
lines.push("");
|
|
148
|
+
}
|
|
149
|
+
for (const entry of entries) {
|
|
150
|
+
lines.push(...journeySection(entry, receipt), "");
|
|
151
|
+
}
|
|
152
|
+
const ready = receipt.verdict === "technically-ready";
|
|
153
|
+
lines.push("## Human-only commands", "");
|
|
154
|
+
for (const entry of entries) {
|
|
155
|
+
for (const command of humanCommands(entry, catalog, drafts.has(entry.id), ready))
|
|
156
|
+
lines.push(`- ${command}`);
|
|
157
|
+
}
|
|
158
|
+
if (!ready) {
|
|
159
|
+
lines.push("");
|
|
160
|
+
lines.push("## After the blockers are fixed", "");
|
|
161
|
+
for (const entry of entries)
|
|
162
|
+
lines.push(`- jevitate journey promote ${entry.id}`);
|
|
163
|
+
}
|
|
164
|
+
lines.push("");
|
|
165
|
+
return `${lines.join("\n")}\n`;
|
|
166
|
+
}
|
|
167
|
+
function catalogEntries(entries, catalog) {
|
|
168
|
+
const wanted = new Map();
|
|
169
|
+
const add = (kind, id, hash) => {
|
|
170
|
+
if (id === undefined || hash === undefined)
|
|
171
|
+
return;
|
|
172
|
+
wanted.set(`${kind}\u0000${id}`, { kind, id, hash });
|
|
173
|
+
};
|
|
174
|
+
for (const entry of entries) {
|
|
175
|
+
const links = entry.review.catalog;
|
|
176
|
+
add("persona", links?.persona?.id, catalog.personas.find((p) => p.id === links?.persona?.id)?.contentHash);
|
|
177
|
+
add("job", links?.job?.id, catalog.jobs.find((j) => j.id === links?.job?.id)?.contentHash);
|
|
178
|
+
}
|
|
179
|
+
return [...wanted.values()].sort((a, b) => (a.kind === b.kind ? a.id.localeCompare(b.id) : a.kind.localeCompare(b.kind)));
|
|
180
|
+
}
|
|
181
|
+
function defaultAnnotationDraft(journeysDir, id) {
|
|
182
|
+
return existsSync(annotationDraftPath(journeysDir, id));
|
|
183
|
+
}
|
|
184
|
+
/** #584: build the local bundle from a `report`-mode readiness and the review sheet of each Journey. */
|
|
185
|
+
export async function buildJourneyBundle(opts, deps = {}) {
|
|
186
|
+
const readiness = deps.readiness ?? runJourneyReadiness;
|
|
187
|
+
const review = deps.review ?? reviewJourneyById;
|
|
188
|
+
const catalogOf = deps.loadCatalog ?? loadCatalog;
|
|
189
|
+
const draftExists = deps.annotationDraft ?? defaultAnnotationDraft;
|
|
190
|
+
const readinessOpts = {
|
|
191
|
+
id: opts.id,
|
|
192
|
+
...(opts.with === undefined ? {} : { with: opts.with }),
|
|
193
|
+
mode: "report",
|
|
194
|
+
journeysDir: opts.journeysDir,
|
|
195
|
+
...(opts.catalogDir === undefined ? {} : { catalogDir: opts.catalogDir }),
|
|
196
|
+
...(opts.targetsFile === undefined ? {} : { targetsFile: opts.targetsFile }),
|
|
197
|
+
...(opts.projectDir === undefined ? {} : { projectDir: opts.projectDir }),
|
|
198
|
+
};
|
|
199
|
+
const receiptDeps = deps.cwd === undefined ? {} : { cwd: deps.cwd };
|
|
200
|
+
const receipt = await readiness(readinessOpts, receiptDeps);
|
|
201
|
+
const ids = [opts.id, ...(opts.with === undefined ? [] : [opts.with])];
|
|
202
|
+
const reviewOpts = { strict: true, ...(opts.catalogDir === undefined ? {} : { catalogDir: opts.catalogDir }), ...(opts.targetsFile === undefined ? {} : { targetsFile: opts.targetsFile }) };
|
|
203
|
+
const entries = [];
|
|
204
|
+
for (const id of ids) {
|
|
205
|
+
const loaded = await review(opts.journeysDir, id, reviewOpts);
|
|
206
|
+
entries.push({ id, journey: loaded.journey, review: loaded.review });
|
|
207
|
+
}
|
|
208
|
+
const catalog = await catalogOf(opts.catalogDir === undefined ? null : opts.catalogDir, opts.journeysDir);
|
|
209
|
+
const drafts = new Set(ids.filter((id) => draftExists(opts.journeysDir, id)));
|
|
210
|
+
const out = resolve(opts.out);
|
|
211
|
+
const bundlePath = join(out, "bundle.md");
|
|
212
|
+
const manifestPath = join(out, "manifest.json");
|
|
213
|
+
const manifest = {
|
|
214
|
+
bundleVersion: 1,
|
|
215
|
+
journeys: entries.map((e) => ({ id: e.id, contentHash: journeyContentHash(e.journey), reviewHash: e.review.contentHash })),
|
|
216
|
+
catalog: catalogEntries(entries, catalog),
|
|
217
|
+
verdict: receipt.verdict,
|
|
218
|
+
generatedAt: clock.nowIso(),
|
|
219
|
+
};
|
|
220
|
+
await mkdir(out, { recursive: true });
|
|
221
|
+
await writeFile(bundlePath, renderJourneyBundle(receipt, entries, catalog, drafts), "utf8");
|
|
222
|
+
await writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, "utf8");
|
|
223
|
+
return { out, files: [bundlePath, manifestPath], verdict: receipt.verdict };
|
|
224
|
+
}
|
|
225
|
+
/** #584: re-derive every hash the bundle recorded; a moved hash throws `BundleStaleError` (exit 1). */
|
|
226
|
+
export async function checkJourneyBundle(dir, opts, deps = {}) {
|
|
227
|
+
const review = deps.review ?? reviewJourneyById;
|
|
228
|
+
const catalogOf = deps.loadCatalog ?? loadCatalog;
|
|
229
|
+
const manifestPath = join(resolve(dir), "manifest.json");
|
|
230
|
+
const manifest = JSON.parse(await readFile(manifestPath, "utf8"));
|
|
231
|
+
const reviewOpts = { strict: true, ...(opts.catalogDir === undefined ? {} : { catalogDir: opts.catalogDir }), ...(opts.targetsFile === undefined ? {} : { targetsFile: opts.targetsFile }) };
|
|
232
|
+
const changed = [];
|
|
233
|
+
for (const recorded of manifest.journeys) {
|
|
234
|
+
const loaded = await review(opts.journeysDir, recorded.id, reviewOpts);
|
|
235
|
+
if (journeyContentHash(loaded.journey) !== recorded.contentHash)
|
|
236
|
+
changed.push(`journey ${recorded.id} contentHash`);
|
|
237
|
+
if (loaded.review.contentHash !== recorded.reviewHash)
|
|
238
|
+
changed.push(`journey ${recorded.id} reviewHash`);
|
|
239
|
+
}
|
|
240
|
+
if (manifest.catalog.length > 0) {
|
|
241
|
+
const catalog = await catalogOf(opts.catalogDir === undefined ? null : opts.catalogDir, opts.journeysDir);
|
|
242
|
+
for (const recorded of manifest.catalog) {
|
|
243
|
+
const current = recorded.kind === "persona" ? catalog.personas.find((p) => p.id === recorded.id)?.contentHash : catalog.jobs.find((j) => j.id === recorded.id)?.contentHash;
|
|
244
|
+
if (current !== recorded.hash)
|
|
245
|
+
changed.push(`${recorded.kind} ${recorded.id} hash`);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
if (changed.length > 0)
|
|
249
|
+
throw new BundleStaleError(changed);
|
|
250
|
+
return { stale: false };
|
|
251
|
+
}
|
|
252
|
+
//# sourceMappingURL=journey-bundle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"journey-bundle.js","sourceRoot":"","sources":["../src/journey-bundle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAEzC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AACpF,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,mBAAmB,EAAmG,MAAM,wBAAwB,CAAC;AA6D9J,+EAA+E;AAC/E,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IAEpB;IADZ,IAAI,GAAG,gBAAgB,CAAC;IACjC,YAAqB,OAA0B;QAC7C,KAAK,CAAC,wBAAwB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QADjC,YAAO,GAAP,OAAO,CAAmB;QAE7C,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;IACjC,CAAC;CACF;AAQD,sIAAsI;AACtI,SAAS,oBAAoB,CAAC,MAAkD;IAC9E,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,UAAU;YACb,OAAO,uBAAuB,CAAC;QACjC,KAAK,OAAO;YACV,OAAO,gBAAgB,CAAC;QAC1B,KAAK,OAAO;YACV,OAAO,OAAO,CAAC;QACjB;YACE,OAAO,SAAS,CAAC;IACrB,CAAC;AACH,CAAC;AAED,0HAA0H;AAC1H,SAAS,oBAAoB,CAAC,KAAmB;IAC/C,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC;IACjD,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,mBAAmB,CAAC;IAChD,MAAM,KAAK,GAAG,CAAC,MAAM,CAAC,IAAI,KAAK,MAAM,IAAI,MAAM,CAAC,IAAI,KAAK,kBAAkB,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC;IAC/F,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,IAAI,QAAQ,KAAK,SAAS,IAAI,CAAC,KAAK;QAAE,OAAO,uBAAuB,CAAC;IACxG,IAAI,KAAK;QAAE,OAAO,gBAAgB,CAAC;IACnC,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,gBAAgB,CAAC;IACpD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,iBAAiB,CAAC,MAAqB,EAAE,MAAc;IAC9D,OAAO,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,GAAG,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,QAAQ,KAAK,KAAK,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACvI,CAAC;AAED,2EAA2E;AAC3E,SAAS,aAAa,CAAC,KAAmB;IACxC,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC;IAC/C,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;IAC7C,IAAI,OAAO,KAAK,SAAS,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,CAAC,0BAA0B,CAAC,CAAC;IACvF,MAAM,KAAK,GAAG,CAAC,YAAY,CAAC,CAAC;IAC7B,IAAI,OAAO,KAAK,SAAS;QAAE,KAAK,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;IAChE,IAAI,MAAM,KAAK,SAAS;QAAE,KAAK,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;IAC7D,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,YAAY,CAAC,OAA2B;IAC/C,MAAM,KAAK,GAAG,CAAC,cAAc,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IACjD,KAAK,CAAC,IAAI,CAAC,GAAG,iBAAiB,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACzD,IAAI,OAAO,CAAC,UAAU,KAAK,SAAS;QAAE,KAAK,CAAC,IAAI,CAAC,mBAAmB,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;IAC1F,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,WAAW,CAAC,MAAyB;IAC5C,MAAM,KAAK,GAAG,CAAC,qBAAqB,MAAM,CAAC,OAAO,EAAE,EAAE,GAAG,iBAAiB,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC;IACnH,KAAK,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC/D,MAAM,MAAM,GAAG,QAAQ,IAAI,OAAO,CAAC,CAAC,CAAC,UAAU,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS,IAAI,OAAO,CAAC,CAAC,CAAC,WAAW,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,SAAS,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,UAAU,OAAO,CAAC,MAAM,EAAE,CAAC;QACnM,KAAK,CAAC,IAAI,CAAC,eAAe,KAAK,OAAO,MAAM,EAAE,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,8GAA8G;AAC9G,SAAS,aAAa,CAAC,KAAmB,EAAE,OAAgB,EAAE,KAAc,EAAE,KAAc;IAC1F,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC;IACpD,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,GAAG,EAAE,EAAE,CAAC;IAC5C,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,SAAS,CAAC,EAAE,WAAW,CAAC;QAC3E,QAAQ,CAAC,IAAI,CAAC,4BAA4B,SAAS,GAAG,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,oBAAoB,IAAI,EAAE,EAAE,CAAC,CAAC;IAChH,CAAC;IACD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,CAAC,EAAE,WAAW,CAAC;QACnE,QAAQ,CAAC,IAAI,CAAC,wBAAwB,KAAK,GAAG,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,oBAAoB,IAAI,EAAE,EAAE,CAAC,CAAC;IACxG,CAAC;IACD,IAAI,KAAK;QAAE,QAAQ,CAAC,IAAI,CAAC,6BAA6B,KAAK,CAAC,EAAE,YAAY,CAAC,CAAC;IAC5E,8GAA8G;IAC9G,IAAI,KAAK;QAAE,QAAQ,CAAC,IAAI,CAAC,4BAA4B,KAAK,CAAC,EAAE,oBAAoB,KAAK,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC;IAC7G,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,cAAc,CAAC,KAAmB,EAAE,OAAyB;IACpE,MAAM,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;IACjC,MAAM,KAAK,GAAa,CAAC,eAAe,KAAK,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;IACxD,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,IAAI,QAAQ,EAAE,CAAC,CAAC;IAC1C,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC;IACnC,IAAI,KAAK,EAAE,OAAO,KAAK,SAAS;QAAE,KAAK,CAAC,IAAI,CAAC,YAAY,KAAK,CAAC,OAAO,CAAC,EAAE,KAAK,oBAAoB,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC7H,IAAI,KAAK,EAAE,GAAG,KAAK,SAAS;QAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,KAAK,CAAC,GAAG,CAAC,EAAE,KAAK,oBAAoB,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC7G,KAAK,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;IACpC,MAAM,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC;IAC5B,KAAK,CAAC,IAAI,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,aAAa,QAAQ,CAAC,IAAI,kBAAkB,QAAQ,CAAC,UAAU,CAAC,KAAK,iBAAiB,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC3K,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IAC5B,IAAI,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,aAAa,CAAC,MAAM,KAAK,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC9E,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,aAAa;QAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACjK,KAAK,CAAC,IAAI,CAAC,iBAAiB,kBAAkB,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACjE,KAAK,CAAC,IAAI,CAAC,gBAAgB,KAAK,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC;IACvD,KAAK,CAAC,IAAI,CAAC,aAAa,oBAAoB,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACvD,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACrB,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK;QAAE,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM,iBAAiB,IAAI,CAAC,SAAS,IAAI,WAAW,EAAE,CAAC,CAAC;IACpI,IAAI,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClD,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;QACnC,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,aAAa;YAAE,KAAK,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;IACnF,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACzB,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,KAAK,CAAC,EAAE,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;IACvG,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,SAAS,CAAC,KAAqB;IACtC,OAAO,KAAK,KAAK,CAAC,KAAK,KAAK,KAAK,CAAC,KAAK,MAAM,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,eAAe,KAAK,CAAC,QAAQ,GAAG,EAAE,CAAC;AACrI,CAAC;AAED,oGAAoG;AACpG,MAAM,UAAU,mBAAmB,CAAC,OAAyB,EAAE,OAAgC,EAAE,OAAgB,EAAE,MAA2B;IAC5I,MAAM,KAAK,GAAa,CAAC,4BAA4B,EAAE,EAAE,EAAE,YAAY,OAAO,CAAC,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;IAC9F,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;IAClC,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,KAAK,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;QAC9B,KAAK,MAAM,CAAC,IAAI,QAAQ;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,GAAG,YAAY,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QAC9F,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;IACD,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,cAAc,IAAI,CAAC,CAAC,KAAK,KAAK,OAAO,CAAC,CAAC;IAChG,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,KAAK,CAAC,IAAI,CAAC,mCAAmC,EAAE,EAAE,CAAC,CAAC;QACpD,KAAK,MAAM,CAAC,IAAI,OAAO;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;QAC3F,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,KAAK,CAAC,IAAI,CAAC,GAAG,cAAc,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC;IACpD,CAAC;IACD,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,KAAK,mBAAmB,CAAC;IACtD,KAAK,CAAC,IAAI,CAAC,wBAAwB,EAAE,EAAE,CAAC,CAAC;IACzC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,KAAK,MAAM,OAAO,IAAI,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,OAAO,EAAE,CAAC,CAAC;IAC/G,CAAC;IACD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,iCAAiC,EAAE,EAAE,CAAC,CAAC;QAClD,KAAK,MAAM,KAAK,IAAI,OAAO;YAAE,KAAK,CAAC,IAAI,CAAC,8BAA8B,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC;IACpF,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;AACjC,CAAC;AAED,SAAS,cAAc,CAAC,OAAgC,EAAE,OAAgB;IACxE,MAAM,MAAM,GAAG,IAAI,GAAG,EAAiE,CAAC;IACxF,MAAM,GAAG,GAAG,CAAC,IAAuB,EAAE,EAAsB,EAAE,IAAwB,EAAQ,EAAE;QAC9F,IAAI,EAAE,KAAK,SAAS,IAAI,IAAI,KAAK,SAAS;YAAE,OAAO;QACnD,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,SAAS,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IACvD,CAAC,CAAC;IACF,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC;QACnC,GAAG,CAAC,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,EAAE,WAAW,CAAC,CAAC;QAC3G,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,EAAE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,EAAE,WAAW,CAAC,CAAC;IAC7F,CAAC;IACD,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC5H,CAAC;AAED,SAAS,sBAAsB,CAAC,WAAmB,EAAE,EAAU;IAC7D,OAAO,UAAU,CAAC,mBAAmB,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,CAAC;AAC1D,CAAC;AAED,wGAAwG;AACxG,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,IAA0B,EAAE,OAA0B,EAAE;IAC/F,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,mBAAmB,CAAC;IACxD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,iBAAiB,CAAC;IAChD,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,IAAI,WAAW,CAAC;IAClD,MAAM,WAAW,GAAG,IAAI,CAAC,eAAe,IAAI,sBAAsB,CAAC;IAEnE,MAAM,aAAa,GAA4B;QAC7C,EAAE,EAAE,IAAI,CAAC,EAAE;QACX,GAAG,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;QACvD,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,GAAG,CAAC,IAAI,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC;QACzE,GAAG,CAAC,IAAI,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC;QAC5E,GAAG,CAAC,IAAI,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC;KAC1E,CAAC;IACF,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC;IACpE,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;IAE5D,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACvE,MAAM,UAAU,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,EAAW,CAAC;IACtM,MAAM,OAAO,GAAmB,EAAE,CAAC;IACnC,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC;QACrB,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,EAAE,UAAU,CAAC,CAAC;QAC9D,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;IACvE,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;IAC1G,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;IAE9E,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC9B,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IAC1C,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC;IAChD,MAAM,QAAQ,GAA0B;QACtC,aAAa,EAAE,CAAC;QAChB,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,WAAW,EAAE,kBAAkB,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC;QAC1H,OAAO,EAAE,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC;QACzC,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,WAAW,EAAE,KAAK,CAAC,MAAM,EAAE;KAC5B,CAAC;IACF,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACtC,MAAM,SAAS,CAAC,UAAU,EAAE,mBAAmB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC;IAC5F,MAAM,SAAS,CAAC,YAAY,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAChF,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,UAAU,EAAE,YAAY,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;AAC9E,CAAC;AAED,uGAAuG;AACvG,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,GAAW,EAAE,IAA+B,EAAE,OAA0B,EAAE;IACjH,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,iBAAiB,CAAC;IAChD,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,IAAI,WAAW,CAAC;IAClD,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,eAAe,CAAC,CAAC;IACzD,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC,CAA0B,CAAC;IAC3F,MAAM,UAAU,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,EAAW,CAAC;IACtM,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,MAAM,QAAQ,IAAI,QAAQ,CAAC,QAAQ,EAAE,CAAC;QACzC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;QACvE,IAAI,kBAAkB,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,WAAW;YAAE,OAAO,CAAC,IAAI,CAAC,WAAW,QAAQ,CAAC,EAAE,cAAc,CAAC,CAAC;QACpH,IAAI,MAAM,CAAC,MAAM,CAAC,WAAW,KAAK,QAAQ,CAAC,UAAU;YAAE,OAAO,CAAC,IAAI,CAAC,WAAW,QAAQ,CAAC,EAAE,aAAa,CAAC,CAAC;IAC3G,CAAC;IACD,IAAI,QAAQ,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChC,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QAC1G,KAAK,MAAM,QAAQ,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;YACxC,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,QAAQ,CAAC,EAAE,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,QAAQ,CAAC,EAAE,CAAC,EAAE,WAAW,CAAC;YAC5K,IAAI,OAAO,KAAK,QAAQ,CAAC,IAAI;gBAAE,OAAO,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,IAAI,IAAI,QAAQ,CAAC,EAAE,OAAO,CAAC,CAAC;QACtF,CAAC;IACH,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,IAAI,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAC5D,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { type HandoffRejection } from "@jevitate/journey";
|
|
2
|
+
import type { JourneyRunResult, SiteGateDeps } from "@jevitate/runtime";
|
|
3
|
+
import type { BrowserPort, EmulationSpec } from "@jevitate/playwright";
|
|
4
|
+
import type { BrowserRunOptions } from "./browser-run-options.js";
|
|
5
|
+
import type { ResolvedJourneyEnvironment } from "./environments.js";
|
|
6
|
+
import { type RunJourneyProgrammaticallyOptions } from "./journey-api.js";
|
|
7
|
+
/**
|
|
8
|
+
* #580 (docs/journey-chain-contract.md §5): `jevitate journey chain` runs a discover Journey once,
|
|
9
|
+
* then a prepare-only reply Journey once per approved request matched to a discovered record. This is
|
|
10
|
+
* the one programmatic surface the CLI and the (separately reviewed) MCP tool share.
|
|
11
|
+
*
|
|
12
|
+
* The result carries names and outcomes only — never a record field's value (e.g. `sourceText`) or a
|
|
13
|
+
* request's `replyText`.
|
|
14
|
+
*
|
|
15
|
+
* #582 (docs/contracts/journey-handoff.md §4-§5): when the reply Journey declares `metadata.inputs`,
|
|
16
|
+
* the discovered records and the requests are validated by the pure `@jevitate/journey` handoff
|
|
17
|
+
* validators and each request is matched on `inputs.request.key` and bound by `bindParams`.
|
|
18
|
+
*/
|
|
19
|
+
/** The runner `journey run` uses; a testing seam so the chain can be driven without a browser. */
|
|
20
|
+
export type JourneyChainRunner = (options: RunJourneyProgrammaticallyOptions) => Promise<JourneyRunResult>;
|
|
21
|
+
/** Injectable wiring for `runJourneyChain` (all optional; the real runner is the default). */
|
|
22
|
+
export interface JourneyChainDeps {
|
|
23
|
+
/** Testing seam — defaults to `runJourneyProgrammatically`. */
|
|
24
|
+
readonly runJourney?: JourneyChainRunner;
|
|
25
|
+
}
|
|
26
|
+
export type JourneyChainErrorCode = "E_CHAIN_FROM_FAILED" | "E_CHAIN_EMPTY" | "E_CHAIN_REQUEST" | "E_CHAIN_NOT_PROMOTED" | "E_HANDOFF_INCOMPATIBLE";
|
|
27
|
+
/** A chain-stopping failure (§5 steps 1, 2 and the §4 request contract). */
|
|
28
|
+
export declare class JourneyChainError extends Error {
|
|
29
|
+
readonly code: JourneyChainErrorCode;
|
|
30
|
+
constructor(code: JourneyChainErrorCode, message: string);
|
|
31
|
+
}
|
|
32
|
+
/** §5 step 4: a matched record is missing a field the reply Journey needs — per request, never a guess. */
|
|
33
|
+
export declare const E_CHAIN_FIELD = "E_CHAIN_FIELD";
|
|
34
|
+
/** One approved, prepare-only request (§4). `commentId` + `account` are the identity; no other key exists. */
|
|
35
|
+
export interface ChainRequest {
|
|
36
|
+
readonly commentId: string;
|
|
37
|
+
readonly account: string;
|
|
38
|
+
readonly replyText: string;
|
|
39
|
+
}
|
|
40
|
+
/** One matched request's run outcome (§5 result `runs[]`). */
|
|
41
|
+
export interface ChainRunResult {
|
|
42
|
+
readonly commentId: string;
|
|
43
|
+
readonly account: string;
|
|
44
|
+
readonly outcome: string;
|
|
45
|
+
readonly reason?: string;
|
|
46
|
+
/** §5 (handoff): the accepted contract (`name@major`). */
|
|
47
|
+
readonly contract?: string;
|
|
48
|
+
/** §5 (handoff): `sha256:` of the record's declared fields. */
|
|
49
|
+
readonly fingerprint?: string;
|
|
50
|
+
/** §5 (handoff): when the producing run finished (ISO 8601 UTC, from the injectable clock). */
|
|
51
|
+
readonly capturedAt?: string;
|
|
52
|
+
}
|
|
53
|
+
/** One request with no discovered record (§5 result `unmatched[]`). */
|
|
54
|
+
export interface ChainUnmatched {
|
|
55
|
+
readonly commentId: string;
|
|
56
|
+
readonly account: string;
|
|
57
|
+
}
|
|
58
|
+
/** The §5 result: the discover run's summary, one entry per matched request, the unmatched requests. */
|
|
59
|
+
export interface JourneyChainResult {
|
|
60
|
+
readonly from: {
|
|
61
|
+
readonly journey: string;
|
|
62
|
+
readonly outcome: string;
|
|
63
|
+
readonly records: number;
|
|
64
|
+
};
|
|
65
|
+
readonly runs: readonly ChainRunResult[];
|
|
66
|
+
readonly unmatched: readonly ChainUnmatched[];
|
|
67
|
+
/** §4/§5 (handoff): records, ambiguous keys and requests a chain refused to run; absent in 0.17.0 mode. */
|
|
68
|
+
readonly rejected?: readonly HandoffRejection[];
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* §4: parse the JSON Lines file of prepare-only requests. `commentId`, `account` and `replyText` are
|
|
72
|
+
* exactly the keys; any other key, a missing key or a non-string value is refused (`E_CHAIN_REQUEST`).
|
|
73
|
+
* Blank lines are skipped; approval metadata stays in Bizops and is not read here.
|
|
74
|
+
*/
|
|
75
|
+
export declare function parseChainRequests(text: string): ChainRequest[];
|
|
76
|
+
/** §5 step 5: the chain succeeded only when every request matched and every run was `ok`. */
|
|
77
|
+
export declare function chainSucceeded(result: JourneyChainResult): boolean;
|
|
78
|
+
/** The flags every run in the chain shares (environment, session, browser, allowlist, site policy). */
|
|
79
|
+
export interface RunJourneyChainOptions {
|
|
80
|
+
readonly from: string;
|
|
81
|
+
readonly to: string;
|
|
82
|
+
/** The approved requests as raw JSON Lines (§4). */
|
|
83
|
+
readonly requests: string;
|
|
84
|
+
/** The journeys directory. */
|
|
85
|
+
readonly dir: string;
|
|
86
|
+
readonly environment?: ResolvedJourneyEnvironment;
|
|
87
|
+
readonly storageState?: string;
|
|
88
|
+
readonly browser?: BrowserRunOptions;
|
|
89
|
+
readonly emulation?: EmulationSpec;
|
|
90
|
+
readonly browserPortFactory?: () => BrowserPort;
|
|
91
|
+
readonly allow?: readonly string[];
|
|
92
|
+
readonly siteGate?: SiteGateDeps;
|
|
93
|
+
/**
|
|
94
|
+
* Refuse a `from` or `to` Journey that is not promoted (`E_CHAIN_NOT_PROMOTED`) before anything
|
|
95
|
+
* runs. The CLI sets it unless `--allow-draft`; MCP can never unset it (promoted-only, as run_journey).
|
|
96
|
+
*/
|
|
97
|
+
readonly requirePromoted?: boolean;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* §5: run `from` once, join each approved request to the record with the same `commentId` and
|
|
101
|
+
* `account`, and run `to` once per match with §3's params. Unmatched requests are listed and never
|
|
102
|
+
* run. A failed `from` stops the chain (`E_CHAIN_FROM_FAILED`); a missing/zero record count stops it
|
|
103
|
+
* (`E_CHAIN_EMPTY`); a malformed request refuses the whole file (`E_CHAIN_REQUEST`).
|
|
104
|
+
*/
|
|
105
|
+
export declare function runJourneyChain(opts: RunJourneyChainOptions, deps?: JourneyChainDeps): Promise<JourneyChainResult>;
|