pactwright 0.0.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/LICENSE +201 -0
- package/README.md +68 -0
- package/dist/adapter/claude-code.d.ts +53 -0
- package/dist/adapter/claude-code.js +241 -0
- package/dist/adapter/commands.d.ts +19 -0
- package/dist/adapter/commands.js +162 -0
- package/dist/atomic.d.ts +6 -0
- package/dist/atomic.js +11 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +561 -0
- package/dist/config/config.d.ts +55 -0
- package/dist/config/config.js +199 -0
- package/dist/config/lifecycle.d.ts +34 -0
- package/dist/config/lifecycle.js +81 -0
- package/dist/config/lock.d.ts +43 -0
- package/dist/config/lock.js +141 -0
- package/dist/context.d.ts +59 -0
- package/dist/context.js +111 -0
- package/dist/errors.d.ts +21 -0
- package/dist/errors.js +25 -0
- package/dist/eval/case.d.ts +123 -0
- package/dist/eval/case.js +17 -0
- package/dist/eval/core-suite.d.ts +3 -0
- package/dist/eval/core-suite.js +431 -0
- package/dist/eval/runner.d.ts +75 -0
- package/dist/eval/runner.js +159 -0
- package/dist/eval/sandbox.d.ts +39 -0
- package/dist/eval/sandbox.js +143 -0
- package/dist/extension/manage.d.ts +65 -0
- package/dist/extension/manage.js +372 -0
- package/dist/extension/manifest.d.ts +36 -0
- package/dist/extension/manifest.js +164 -0
- package/dist/extension/resolve.d.ts +77 -0
- package/dist/extension/resolve.js +271 -0
- package/dist/graph/edge-schema.d.ts +55 -0
- package/dist/graph/edge-schema.js +0 -0
- package/dist/graph/edges.d.ts +22 -0
- package/dist/graph/edges.js +63 -0
- package/dist/graph/ids.d.ts +14 -0
- package/dist/graph/ids.js +38 -0
- package/dist/graph/lineage.d.ts +48 -0
- package/dist/graph/lineage.js +226 -0
- package/dist/graph/mutations.d.ts +108 -0
- package/dist/graph/mutations.js +356 -0
- package/dist/graph/nodes.d.ts +46 -0
- package/dist/graph/nodes.js +137 -0
- package/dist/graph/revision.d.ts +50 -0
- package/dist/graph/revision.js +75 -0
- package/dist/graph/schema.d.ts +54 -0
- package/dist/graph/schema.js +90 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +33 -0
- package/dist/init.d.ts +47 -0
- package/dist/init.js +132 -0
- package/dist/lifecycle/engine.d.ts +75 -0
- package/dist/lifecycle/engine.js +146 -0
- package/dist/lifecycle/record.d.ts +18 -0
- package/dist/lifecycle/record.js +157 -0
- package/dist/lifecycle/run.d.ts +62 -0
- package/dist/lifecycle/run.js +167 -0
- package/dist/loader.d.ts +38 -0
- package/dist/loader.js +64 -0
- package/dist/pack/capabilities.d.ts +22 -0
- package/dist/pack/capabilities.js +31 -0
- package/dist/pack/locate.d.ts +22 -0
- package/dist/pack/locate.js +80 -0
- package/dist/pack/manifest.d.ts +34 -0
- package/dist/pack/manifest.js +168 -0
- package/dist/pack/resolve.d.ts +92 -0
- package/dist/pack/resolve.js +238 -0
- package/dist/project.d.ts +22 -0
- package/dist/project.js +37 -0
- package/dist/sync.d.ts +54 -0
- package/dist/sync.js +98 -0
- package/dist/validate.d.ts +23 -0
- package/dist/validate.js +32 -0
- package/dist/validation.d.ts +24 -0
- package/dist/validation.js +83 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +8 -0
- package/dist/yaml.d.ts +12 -0
- package/dist/yaml.js +32 -0
- package/package.json +65 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { Problem } from "../errors.js";
|
|
2
|
+
import type { ParseResult } from "../config/config.js";
|
|
3
|
+
import { type UnknownRecord } from "../validation.js";
|
|
4
|
+
/**
|
|
5
|
+
* A Project Graph node: Markdown with YAML frontmatter (Delivery Graph §5).
|
|
6
|
+
* Only the common fields are typed here; type-specific fields stay in
|
|
7
|
+
* `frontmatter` for the schema layer to interpret.
|
|
8
|
+
*/
|
|
9
|
+
export interface GraphNode {
|
|
10
|
+
readonly id: string;
|
|
11
|
+
readonly type: string;
|
|
12
|
+
readonly title: string;
|
|
13
|
+
readonly created: string;
|
|
14
|
+
readonly frontmatter: Readonly<UnknownRecord>;
|
|
15
|
+
readonly body: string;
|
|
16
|
+
readonly path: string;
|
|
17
|
+
}
|
|
18
|
+
export declare const REQUIRED_NODE_FIELDS: readonly ["id", "type", "title", "created"];
|
|
19
|
+
/** `<type>-<slug>-<short-hash>`; type and slug are lowercase kebab tokens. */
|
|
20
|
+
export declare const NODE_TYPE_PATTERN: RegExp;
|
|
21
|
+
export declare const NODE_ID_PATTERN: RegExp;
|
|
22
|
+
export declare const CREATED_PATTERN: RegExp;
|
|
23
|
+
/**
|
|
24
|
+
* Checks that `id` has the shape `<type>-<slug>-<short-hash>` and that its
|
|
25
|
+
* type prefix equals `type`. Returns problems (empty when valid).
|
|
26
|
+
*/
|
|
27
|
+
export declare function checkNodeId(id: string, type: string): string | undefined;
|
|
28
|
+
export declare function parseNodeFile(text: string, path: string): ParseResult<GraphNode>;
|
|
29
|
+
/**
|
|
30
|
+
* IDs never change (Delivery Graph §5) and records are superseded, not
|
|
31
|
+
* deleted. Compares a previous graph snapshot with a proposed one and reports
|
|
32
|
+
* `id-removed` for every id that no longer exists — which is exactly how a
|
|
33
|
+
* renamed-and-re-identified node file shows up. An in-place id edit is
|
|
34
|
+
* already rejected by `parseNodeFile` (`filename-mismatch`). New ids are fine.
|
|
35
|
+
*/
|
|
36
|
+
export declare function checkNodeIdImmutability(previous: readonly Pick<GraphNode, "id" | "path">[], proposed: readonly Pick<GraphNode, "id" | "path">[]): readonly Problem[];
|
|
37
|
+
export interface NodesLoadResult {
|
|
38
|
+
/** Successfully parsed nodes, sorted by id. */
|
|
39
|
+
readonly nodes: readonly GraphNode[];
|
|
40
|
+
readonly problems: readonly Problem[];
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Loads every `*.md` file directly inside `dir` as a node. A missing
|
|
44
|
+
* directory is a problem; an existing empty directory yields no nodes.
|
|
45
|
+
*/
|
|
46
|
+
export declare function loadNodes(dir: string): NodesLoadResult;
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
2
|
+
import { basename, join } from "node:path";
|
|
3
|
+
import { Checker, expectRecord, expectString, requireKeys, } from "../validation.js";
|
|
4
|
+
import { parseYaml } from "../yaml.js";
|
|
5
|
+
export const REQUIRED_NODE_FIELDS = ["id", "type", "title", "created"];
|
|
6
|
+
/** `<type>-<slug>-<short-hash>`; type and slug are lowercase kebab tokens. */
|
|
7
|
+
export const NODE_TYPE_PATTERN = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
|
|
8
|
+
export const NODE_ID_PATTERN = /^([a-z][a-z0-9]*(?:-[a-z0-9]+)*)-([a-z0-9]+(?:-[a-z0-9]+)*)-([0-9a-f]{4,})$/;
|
|
9
|
+
export const CREATED_PATTERN = /^\d{4}-\d{2}-\d{2}$/;
|
|
10
|
+
const FRONTMATTER_PATTERN = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)([\s\S]*)$/;
|
|
11
|
+
/**
|
|
12
|
+
* Checks that `id` has the shape `<type>-<slug>-<short-hash>` and that its
|
|
13
|
+
* type prefix equals `type`. Returns problems (empty when valid).
|
|
14
|
+
*/
|
|
15
|
+
export function checkNodeId(id, type) {
|
|
16
|
+
const match = NODE_ID_PATTERN.exec(id);
|
|
17
|
+
if (match === null)
|
|
18
|
+
return `id "${id}" must match <type>-<slug>-<short-hash>`;
|
|
19
|
+
if (!id.startsWith(`${type}-`)) {
|
|
20
|
+
return `id "${id}" must start with the node type "${type}-"`;
|
|
21
|
+
}
|
|
22
|
+
const rest = id.slice(type.length + 1);
|
|
23
|
+
if (!/^[a-z0-9]+(?:-[a-z0-9]+)*-[0-9a-f]{4,}$/.test(rest)) {
|
|
24
|
+
return `id "${id}" must be "${type}-<slug>-<short-hash>"`;
|
|
25
|
+
}
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
export function parseNodeFile(text, path) {
|
|
29
|
+
const c = new Checker(path);
|
|
30
|
+
const match = FRONTMATTER_PATTERN.exec(text);
|
|
31
|
+
if (match === null) {
|
|
32
|
+
c.fail("missing-frontmatter", "node file must start with a YAML frontmatter block delimited by ---");
|
|
33
|
+
return { value: undefined, problems: c.problems };
|
|
34
|
+
}
|
|
35
|
+
const yaml = parseYaml(match[1] ?? "", path);
|
|
36
|
+
if (yaml.problems.length > 0)
|
|
37
|
+
return { value: undefined, problems: yaml.problems };
|
|
38
|
+
const front = expectRecord(c, yaml.value, "frontmatter");
|
|
39
|
+
if (front === undefined)
|
|
40
|
+
return { value: undefined, problems: c.problems };
|
|
41
|
+
requireKeys(c, front, "frontmatter", REQUIRED_NODE_FIELDS);
|
|
42
|
+
const id = expectString(c, front["id"], "frontmatter.id");
|
|
43
|
+
const type = expectString(c, front["type"], "frontmatter.type");
|
|
44
|
+
const title = expectString(c, front["title"], "frontmatter.title");
|
|
45
|
+
const created = expectString(c, front["created"], "frontmatter.created");
|
|
46
|
+
if (type !== undefined && !NODE_TYPE_PATTERN.test(type)) {
|
|
47
|
+
c.fail("invalid-type", `frontmatter.type "${type}" must be a lowercase kebab-case token`);
|
|
48
|
+
}
|
|
49
|
+
if (id !== undefined && type !== undefined && NODE_TYPE_PATTERN.test(type)) {
|
|
50
|
+
const idProblem = checkNodeId(id, type);
|
|
51
|
+
if (idProblem !== undefined)
|
|
52
|
+
c.fail("invalid-id", idProblem);
|
|
53
|
+
}
|
|
54
|
+
if (created !== undefined && !CREATED_PATTERN.test(created)) {
|
|
55
|
+
c.fail("invalid-value", `frontmatter.created "${created}" must be an ISO date (YYYY-MM-DD)`);
|
|
56
|
+
}
|
|
57
|
+
if (id !== undefined && basename(path) !== `${id}.md`) {
|
|
58
|
+
c.fail("filename-mismatch", `node file must be named "${id}.md" to match its id`);
|
|
59
|
+
}
|
|
60
|
+
const body = (match[2] ?? "").trim();
|
|
61
|
+
if (body.length === 0)
|
|
62
|
+
c.fail("missing-body", "node must have a Markdown body after the frontmatter");
|
|
63
|
+
if (!c.ok ||
|
|
64
|
+
id === undefined ||
|
|
65
|
+
type === undefined ||
|
|
66
|
+
title === undefined ||
|
|
67
|
+
created === undefined) {
|
|
68
|
+
return { value: undefined, problems: c.problems };
|
|
69
|
+
}
|
|
70
|
+
return { value: { id, type, title, created, frontmatter: front, body, path }, problems: [] };
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* IDs never change (Delivery Graph §5) and records are superseded, not
|
|
74
|
+
* deleted. Compares a previous graph snapshot with a proposed one and reports
|
|
75
|
+
* `id-removed` for every id that no longer exists — which is exactly how a
|
|
76
|
+
* renamed-and-re-identified node file shows up. An in-place id edit is
|
|
77
|
+
* already rejected by `parseNodeFile` (`filename-mismatch`). New ids are fine.
|
|
78
|
+
*/
|
|
79
|
+
export function checkNodeIdImmutability(previous, proposed) {
|
|
80
|
+
const current = new Set(proposed.map((node) => node.id));
|
|
81
|
+
return previous
|
|
82
|
+
.filter((node) => !current.has(node.id))
|
|
83
|
+
.map((node) => ({
|
|
84
|
+
code: "id-removed",
|
|
85
|
+
message: `node id "${node.id}" is missing from the proposed graph; IDs never change and nodes are superseded, not deleted`,
|
|
86
|
+
path: node.path,
|
|
87
|
+
}));
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Loads every `*.md` file directly inside `dir` as a node. A missing
|
|
91
|
+
* directory is a problem; an existing empty directory yields no nodes.
|
|
92
|
+
*/
|
|
93
|
+
export function loadNodes(dir) {
|
|
94
|
+
if (!existsSync(dir) || !statSync(dir).isDirectory()) {
|
|
95
|
+
return {
|
|
96
|
+
nodes: [],
|
|
97
|
+
problems: [{ code: "missing-directory", message: "nodes directory not found", path: dir }],
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
const problems = [];
|
|
101
|
+
const nodes = [];
|
|
102
|
+
const seen = new Map();
|
|
103
|
+
const files = readdirSync(dir)
|
|
104
|
+
.filter((name) => name.endsWith(".md"))
|
|
105
|
+
.sort();
|
|
106
|
+
for (const name of files) {
|
|
107
|
+
const path = join(dir, name);
|
|
108
|
+
let content;
|
|
109
|
+
try {
|
|
110
|
+
content = readFileSync(path, "utf8");
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
// A directory named *.md, unreadable permissions, a broken symlink:
|
|
114
|
+
// a Problem, never a raw filesystem throw out of the loader.
|
|
115
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
116
|
+
problems.push({ code: "unreadable-file", message: `cannot read file: ${detail}`, path });
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
const parsed = parseNodeFile(content, path);
|
|
120
|
+
problems.push(...parsed.problems);
|
|
121
|
+
if (parsed.value === undefined)
|
|
122
|
+
continue;
|
|
123
|
+
const previous = seen.get(parsed.value.id);
|
|
124
|
+
if (previous !== undefined) {
|
|
125
|
+
problems.push({
|
|
126
|
+
code: "duplicate-id",
|
|
127
|
+
message: `node id "${parsed.value.id}" is already declared in ${previous}`,
|
|
128
|
+
path,
|
|
129
|
+
});
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
seen.set(parsed.value.id, path);
|
|
133
|
+
nodes.push(parsed.value);
|
|
134
|
+
}
|
|
135
|
+
nodes.sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
|
|
136
|
+
return { nodes, problems };
|
|
137
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { Edge } from "./edges.js";
|
|
2
|
+
import type { GraphNode } from "./nodes.js";
|
|
3
|
+
/**
|
|
4
|
+
* An extension-owned canonical graph record (Assets, Publications,
|
|
5
|
+
* Deployments, Observations…). Extensions hand these to `graphRevision`; the
|
|
6
|
+
* core never interprets `record`, it only canonicalises and hashes it.
|
|
7
|
+
*/
|
|
8
|
+
export interface CanonicalRecord {
|
|
9
|
+
/** Extension id that owns the record. */
|
|
10
|
+
readonly owner: string;
|
|
11
|
+
/** Record kind within that extension. */
|
|
12
|
+
readonly kind: string;
|
|
13
|
+
readonly id: string;
|
|
14
|
+
/** JSON-like data: records, arrays, strings, numbers, booleans, null. */
|
|
15
|
+
readonly record: unknown;
|
|
16
|
+
}
|
|
17
|
+
/** Everything that contributes to the Project Graph revision (Delivery Graph §5). */
|
|
18
|
+
export interface RevisionInput {
|
|
19
|
+
readonly nodes: readonly GraphNode[];
|
|
20
|
+
readonly edges: readonly Edge[];
|
|
21
|
+
/** Extension canonical records; absent means none. */
|
|
22
|
+
readonly records?: readonly CanonicalRecord[];
|
|
23
|
+
}
|
|
24
|
+
/** Bump only when the canonical payload shape changes; every revision changes with it. */
|
|
25
|
+
export declare const REVISION_VERSION = 1;
|
|
26
|
+
/** A revision is `sha256:<64 hex>`, the same shape as lock-file hashes. */
|
|
27
|
+
export declare const REVISION_PATTERN: RegExp;
|
|
28
|
+
/**
|
|
29
|
+
* JSON with object keys sorted recursively, `undefined` members dropped and
|
|
30
|
+
* no whitespace, so equal values always serialise to equal bytes.
|
|
31
|
+
*/
|
|
32
|
+
export declare function canonicalJson(value: unknown): string;
|
|
33
|
+
/**
|
|
34
|
+
* The exact bytes hashed by `graphRevision`, exposed for tests and tooling.
|
|
35
|
+
*
|
|
36
|
+
* Canonicalisation (Delivery Graph §5, "canonicalise ordering before hashing"):
|
|
37
|
+
* nodes reduce to `{ id, frontmatter, body }` sorted by id — the file path is
|
|
38
|
+
* where the record sits, not graph state, and the common fields already live
|
|
39
|
+
* in the frontmatter; bodies use LF line endings; edges sort by
|
|
40
|
+
* (source, type, target); extension records sort by (owner, kind, id).
|
|
41
|
+
* Config, lock, lifecycle, lineage, reports, adapter output and any other
|
|
42
|
+
* derived or operational state never enter the payload.
|
|
43
|
+
*/
|
|
44
|
+
export declare function canonicalGraphPayload(input: RevisionInput): string;
|
|
45
|
+
/**
|
|
46
|
+
* The deterministic Project Graph revision: sha256 over the canonical
|
|
47
|
+
* payload. The same canonical graph state always yields the same revision;
|
|
48
|
+
* nothing outside it can move it.
|
|
49
|
+
*/
|
|
50
|
+
export declare function graphRevision(input: RevisionInput): string;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { HASH_PATTERN } from "../config/lock.js";
|
|
3
|
+
import { PactwrightError } from "../errors.js";
|
|
4
|
+
/** Bump only when the canonical payload shape changes; every revision changes with it. */
|
|
5
|
+
export const REVISION_VERSION = 1;
|
|
6
|
+
/** A revision is `sha256:<64 hex>`, the same shape as lock-file hashes. */
|
|
7
|
+
export const REVISION_PATTERN = HASH_PATTERN;
|
|
8
|
+
function compare(a, b) {
|
|
9
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* JSON with object keys sorted recursively, `undefined` members dropped and
|
|
13
|
+
* no whitespace, so equal values always serialise to equal bytes.
|
|
14
|
+
*/
|
|
15
|
+
export function canonicalJson(value) {
|
|
16
|
+
return canonicalise(value, new Set());
|
|
17
|
+
}
|
|
18
|
+
function canonicalise(value, path) {
|
|
19
|
+
if (value === null || typeof value !== "object")
|
|
20
|
+
return JSON.stringify(value) ?? "null";
|
|
21
|
+
if (path.has(value)) {
|
|
22
|
+
throw new PactwrightError("cyclic-value", "cannot canonicalise a value that contains itself");
|
|
23
|
+
}
|
|
24
|
+
path.add(value);
|
|
25
|
+
try {
|
|
26
|
+
if (Array.isArray(value)) {
|
|
27
|
+
return `[${value.map((item) => canonicalise(item, path)).join(",")}]`;
|
|
28
|
+
}
|
|
29
|
+
const record = value;
|
|
30
|
+
const members = Object.keys(record)
|
|
31
|
+
.filter((key) => record[key] !== undefined)
|
|
32
|
+
.sort(compare)
|
|
33
|
+
.map((key) => `${JSON.stringify(key)}:${canonicalise(record[key], path)}`);
|
|
34
|
+
return `{${members.join(",")}}`;
|
|
35
|
+
}
|
|
36
|
+
finally {
|
|
37
|
+
path.delete(value);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The exact bytes hashed by `graphRevision`, exposed for tests and tooling.
|
|
42
|
+
*
|
|
43
|
+
* Canonicalisation (Delivery Graph §5, "canonicalise ordering before hashing"):
|
|
44
|
+
* nodes reduce to `{ id, frontmatter, body }` sorted by id — the file path is
|
|
45
|
+
* where the record sits, not graph state, and the common fields already live
|
|
46
|
+
* in the frontmatter; bodies use LF line endings; edges sort by
|
|
47
|
+
* (source, type, target); extension records sort by (owner, kind, id).
|
|
48
|
+
* Config, lock, lifecycle, lineage, reports, adapter output and any other
|
|
49
|
+
* derived or operational state never enter the payload.
|
|
50
|
+
*/
|
|
51
|
+
export function canonicalGraphPayload(input) {
|
|
52
|
+
const nodes = [...input.nodes]
|
|
53
|
+
.sort((a, b) => compare(a.id, b.id))
|
|
54
|
+
.map((node) => ({
|
|
55
|
+
id: node.id,
|
|
56
|
+
frontmatter: node.frontmatter,
|
|
57
|
+
body: node.body.replace(/\r\n/g, "\n"),
|
|
58
|
+
}));
|
|
59
|
+
const edges = [...input.edges]
|
|
60
|
+
.sort((a, b) => compare(a.source, b.source) || compare(a.type, b.type) || compare(a.target, b.target))
|
|
61
|
+
.map((edge) => ({ source: edge.source, type: edge.type, target: edge.target }));
|
|
62
|
+
const records = [...(input.records ?? [])]
|
|
63
|
+
.sort((a, b) => compare(a.owner, b.owner) || compare(a.kind, b.kind) || compare(a.id, b.id))
|
|
64
|
+
.map((item) => ({ owner: item.owner, kind: item.kind, id: item.id, record: item.record }));
|
|
65
|
+
return canonicalJson({ version: REVISION_VERSION, nodes, edges, records });
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* The deterministic Project Graph revision: sha256 over the canonical
|
|
69
|
+
* payload. The same canonical graph state always yields the same revision;
|
|
70
|
+
* nothing outside it can move it.
|
|
71
|
+
*/
|
|
72
|
+
export function graphRevision(input) {
|
|
73
|
+
const digest = createHash("sha256").update(canonicalGraphPayload(input), "utf8").digest("hex");
|
|
74
|
+
return `sha256:${digest}`;
|
|
75
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { type Problem } from "../errors.js";
|
|
2
|
+
import { Checker } from "../validation.js";
|
|
3
|
+
import type { GraphNode } from "./nodes.js";
|
|
4
|
+
/** The five durable core Delivery node types (Delivery Graph §5). */
|
|
5
|
+
export declare const CORE_NODE_TYPES: readonly ["intent", "decision", "contract", "brief", "evidence"];
|
|
6
|
+
export type CoreNodeType = (typeof CORE_NODE_TYPES)[number];
|
|
7
|
+
/** Allowed Decision outcomes (Delivery Graph §8). */
|
|
8
|
+
export declare const DECISION_OUTCOMES: readonly ["proceed", "reject", "defer"];
|
|
9
|
+
export type DecisionOutcome = (typeof DECISION_OUTCOMES)[number];
|
|
10
|
+
/** `decided_by` records the actual actor as `<kind>:<name>` (Delivery Graph §8). */
|
|
11
|
+
export declare const DECIDED_BY_KINDS: readonly ["human", "agent", "automation"];
|
|
12
|
+
export type DecidedByKind = (typeof DECIDED_BY_KINDS)[number];
|
|
13
|
+
export declare const DECIDED_BY_PATTERN: RegExp;
|
|
14
|
+
export interface DecidedBy {
|
|
15
|
+
readonly kind: DecidedByKind;
|
|
16
|
+
readonly name: string;
|
|
17
|
+
}
|
|
18
|
+
/** Splits `human:samir` into `{ kind: "human", name: "samir" }`; `undefined` when malformed. */
|
|
19
|
+
export declare function parseDecidedBy(value: string): DecidedBy | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* A node type schema: the type-specific frontmatter fields required beyond
|
|
22
|
+
* the common ones, plus an optional deeper check run only when those fields
|
|
23
|
+
* are present.
|
|
24
|
+
*/
|
|
25
|
+
export interface NodeSchema {
|
|
26
|
+
readonly type: string;
|
|
27
|
+
readonly requiredFields: readonly string[];
|
|
28
|
+
readonly validate?: (node: GraphNode, c: Checker) => void;
|
|
29
|
+
}
|
|
30
|
+
/** Node schemas keyed by node type. */
|
|
31
|
+
export type NodeSchemaRegistry = Readonly<Record<string, NodeSchema>>;
|
|
32
|
+
/**
|
|
33
|
+
* Builds a frozen registry. Throws `duplicate-node-type` when two schemas
|
|
34
|
+
* claim the same type; later extensions compose registries with
|
|
35
|
+
* `createNodeSchemaRegistry([...Object.values(CORE_NODE_SCHEMAS), ...own])`.
|
|
36
|
+
*/
|
|
37
|
+
export declare function createNodeSchemaRegistry(schemas: readonly NodeSchema[]): NodeSchemaRegistry;
|
|
38
|
+
/** Registered node types, sorted. */
|
|
39
|
+
export declare function nodeTypes(registry: NodeSchemaRegistry): readonly string[];
|
|
40
|
+
/**
|
|
41
|
+
* The core Delivery schema registry: exactly the five durable node types.
|
|
42
|
+
* Contract alternatives (§7), Delivery execution and Review (§11) are
|
|
43
|
+
* transient and deliberately absent.
|
|
44
|
+
*/
|
|
45
|
+
export declare const CORE_NODE_SCHEMAS: NodeSchemaRegistry;
|
|
46
|
+
/** Validates one parsed node against the registry (Delivery Graph §21, Nodes). */
|
|
47
|
+
export declare function validateNode(node: GraphNode, registry: NodeSchemaRegistry): readonly Problem[];
|
|
48
|
+
export declare function validateNodes(nodes: readonly GraphNode[], registry: NodeSchemaRegistry): readonly Problem[];
|
|
49
|
+
export interface DecisionFields {
|
|
50
|
+
readonly outcome: DecisionOutcome;
|
|
51
|
+
readonly decidedBy: DecidedBy;
|
|
52
|
+
}
|
|
53
|
+
/** Typed view of a valid decision's fields; `undefined` for any other or invalid node. */
|
|
54
|
+
export declare function decisionFields(node: GraphNode): DecisionFields | undefined;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { PactwrightError } from "../errors.js";
|
|
2
|
+
import { Checker, requireKeys } from "../validation.js";
|
|
3
|
+
/** The five durable core Delivery node types (Delivery Graph §5). */
|
|
4
|
+
export const CORE_NODE_TYPES = ["intent", "decision", "contract", "brief", "evidence"];
|
|
5
|
+
/** Allowed Decision outcomes (Delivery Graph §8). */
|
|
6
|
+
export const DECISION_OUTCOMES = ["proceed", "reject", "defer"];
|
|
7
|
+
/** `decided_by` records the actual actor as `<kind>:<name>` (Delivery Graph §8). */
|
|
8
|
+
export const DECIDED_BY_KINDS = ["human", "agent", "automation"];
|
|
9
|
+
export const DECIDED_BY_PATTERN = /^(human|agent|automation):\S+$/;
|
|
10
|
+
/** Splits `human:samir` into `{ kind: "human", name: "samir" }`; `undefined` when malformed. */
|
|
11
|
+
export function parseDecidedBy(value) {
|
|
12
|
+
if (!DECIDED_BY_PATTERN.test(value))
|
|
13
|
+
return undefined;
|
|
14
|
+
const separator = value.indexOf(":");
|
|
15
|
+
return { kind: value.slice(0, separator), name: value.slice(separator + 1) };
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Builds a frozen registry. Throws `duplicate-node-type` when two schemas
|
|
19
|
+
* claim the same type; later extensions compose registries with
|
|
20
|
+
* `createNodeSchemaRegistry([...Object.values(CORE_NODE_SCHEMAS), ...own])`.
|
|
21
|
+
*/
|
|
22
|
+
export function createNodeSchemaRegistry(schemas) {
|
|
23
|
+
// Prototype-less, so a type like "constructor" can never resolve to an
|
|
24
|
+
// Object.prototype member instead of a registered schema.
|
|
25
|
+
const registry = Object.create(null);
|
|
26
|
+
for (const schema of schemas) {
|
|
27
|
+
if (Object.hasOwn(registry, schema.type)) {
|
|
28
|
+
throw new PactwrightError("duplicate-node-type", `node type "${schema.type}" is already registered`);
|
|
29
|
+
}
|
|
30
|
+
registry[schema.type] = schema;
|
|
31
|
+
}
|
|
32
|
+
return Object.freeze(registry);
|
|
33
|
+
}
|
|
34
|
+
/** Registered node types, sorted. */
|
|
35
|
+
export function nodeTypes(registry) {
|
|
36
|
+
return Object.keys(registry).sort();
|
|
37
|
+
}
|
|
38
|
+
function validateDecision(node, c) {
|
|
39
|
+
const outcome = node.frontmatter["outcome"];
|
|
40
|
+
if (outcome !== undefined && !DECISION_OUTCOMES.includes(outcome)) {
|
|
41
|
+
c.fail("invalid-outcome", `frontmatter.outcome must be one of: ${DECISION_OUTCOMES.join(", ")}`);
|
|
42
|
+
}
|
|
43
|
+
const decidedBy = node.frontmatter["decided_by"];
|
|
44
|
+
if (decidedBy !== undefined &&
|
|
45
|
+
(typeof decidedBy !== "string" || !DECIDED_BY_PATTERN.test(decidedBy))) {
|
|
46
|
+
c.fail("invalid-actor", `frontmatter.decided_by must be "<kind>:<name>" with kind one of: ${DECIDED_BY_KINDS.join(", ")}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The core Delivery schema registry: exactly the five durable node types.
|
|
51
|
+
* Contract alternatives (§7), Delivery execution and Review (§11) are
|
|
52
|
+
* transient and deliberately absent.
|
|
53
|
+
*/
|
|
54
|
+
export const CORE_NODE_SCHEMAS = createNodeSchemaRegistry([
|
|
55
|
+
{ type: "intent", requiredFields: [] },
|
|
56
|
+
{ type: "decision", requiredFields: ["decided_by", "outcome"], validate: validateDecision },
|
|
57
|
+
{ type: "contract", requiredFields: [] },
|
|
58
|
+
{ type: "brief", requiredFields: [] },
|
|
59
|
+
{ type: "evidence", requiredFields: [] },
|
|
60
|
+
]);
|
|
61
|
+
/** Validates one parsed node against the registry (Delivery Graph §21, Nodes). */
|
|
62
|
+
export function validateNode(node, registry) {
|
|
63
|
+
const c = new Checker(node.path);
|
|
64
|
+
const schema = registry[node.type];
|
|
65
|
+
if (schema === undefined) {
|
|
66
|
+
c.fail("unknown-node-type", `node type "${node.type}" is not a registered node type (known: ${nodeTypes(registry).join(", ")})`);
|
|
67
|
+
return c.problems;
|
|
68
|
+
}
|
|
69
|
+
requireKeys(c, node.frontmatter, "frontmatter", schema.requiredFields);
|
|
70
|
+
schema.validate?.(node, c);
|
|
71
|
+
return c.problems;
|
|
72
|
+
}
|
|
73
|
+
export function validateNodes(nodes, registry) {
|
|
74
|
+
return nodes.flatMap((node) => validateNode(node, registry));
|
|
75
|
+
}
|
|
76
|
+
/** Typed view of a valid decision's fields; `undefined` for any other or invalid node. */
|
|
77
|
+
export function decisionFields(node) {
|
|
78
|
+
if (node.type !== "decision")
|
|
79
|
+
return undefined;
|
|
80
|
+
const outcome = node.frontmatter["outcome"];
|
|
81
|
+
const rawActor = node.frontmatter["decided_by"];
|
|
82
|
+
if (!DECISION_OUTCOMES.includes(outcome))
|
|
83
|
+
return undefined;
|
|
84
|
+
if (typeof rawActor !== "string")
|
|
85
|
+
return undefined;
|
|
86
|
+
const decidedBy = parseDecidedBy(rawActor);
|
|
87
|
+
if (decidedBy === undefined)
|
|
88
|
+
return undefined;
|
|
89
|
+
return { outcome: outcome, decidedBy };
|
|
90
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export { PactwrightError, formatProblem, type Problem } from "./errors.js";
|
|
2
|
+
export { ADAPTER_TYPES, CONFIG_VERSION, loadConfig, parseConfig, rewriteConfig, serialiseConfig, type ConfigExtension, type PactwrightConfig, type ParseResult, } from "./config/config.js";
|
|
3
|
+
export { ACTORS, CORE_STAGES, DECISION_STAGE, EXECUTION_MODES, LIFECYCLE_VERSION, decisionActor, humanGates, isHumanGate, loadLifecycle, parseLifecycle, type Actor, type ExecutionMode, type LifecycleConfig, type StageConfig, type StageName, } from "./config/lifecycle.js";
|
|
4
|
+
export { EXTENSION_ID_PATTERN, HASH_PATTERN, loadLock, parseLock, type LockExtension, type LockFile, } from "./config/lock.js";
|
|
5
|
+
export { CREATED_PATTERN, NODE_ID_PATTERN, NODE_TYPE_PATTERN, REQUIRED_NODE_FIELDS, checkNodeId, checkNodeIdImmutability, loadNodes, parseNodeFile, type GraphNode, type NodesLoadResult, } from "./graph/nodes.js";
|
|
6
|
+
export { CORE_NODE_SCHEMAS, CORE_NODE_TYPES, DECIDED_BY_KINDS, DECIDED_BY_PATTERN, DECISION_OUTCOMES, createNodeSchemaRegistry, decisionFields, nodeTypes, parseDecidedBy, validateNode, validateNodes, type CoreNodeType, type DecidedBy, type DecidedByKind, type DecisionFields, type DecisionOutcome, type NodeSchema, type NodeSchemaRegistry, } from "./graph/schema.js";
|
|
7
|
+
export { CORE_EDGE_OWNER, CORE_EDGE_SCHEMAS, CORE_EDGE_TYPES, createEdgeSchemaRegistry, edgeTypes, validateEdges, type CoreEdgeType, type EdgeSchema, type EdgeSchemaRegistry, } from "./graph/edge-schema.js";
|
|
8
|
+
export { DELIVERY_STATES, deriveLineage, deriveLineages, isCurrent, validateLineages, type DeliveryState, type Lineage, type LineageResult, } from "./graph/lineage.js";
|
|
9
|
+
export { EDGE_TYPE_PATTERN, edgeKey, loadEdges, parseEdges, type Edge, type EdgesParseResult, } from "./graph/edges.js";
|
|
10
|
+
export { mintNodeId, slugify } from "./graph/ids.js";
|
|
11
|
+
export { createBrief, createEvidence, createIntent, recordDecision, type CreateBriefInput, type CreateEvidenceInput, type CreateIntentInput, type RecordDecisionInput, type RecordedDecision, } from "./graph/mutations.js";
|
|
12
|
+
export { REVISION_PATTERN, REVISION_VERSION, canonicalGraphPayload, canonicalJson, graphRevision, type CanonicalRecord, type RevisionInput, } from "./graph/revision.js";
|
|
13
|
+
export { CONFIG_FILE, EDGES_FILE, LIFECYCLE_FILE, LOCK_FILE, NODES_DIR, findProjectRoot, projectPaths, type ProjectPaths, } from "./project.js";
|
|
14
|
+
export { loadProject, type LoadProjectOptions, type Project } from "./loader.js";
|
|
15
|
+
export { CONFIG_TEMPLATE, INIT_DIRS, LIFECYCLE_TEMPLATE, initProject, initTemplates, type InitEntry, type InitReport, } from "./init.js";
|
|
16
|
+
export { runtimeVersion } from "./version.js";
|
|
17
|
+
export { GRAPH_MARKING_STAGES, TRANSIENT_STAGES, completedStages, isActive, isTransientStage, lifecycleNext, lifecycleStatus, nextActionFor, pendingStages, selectLineages, type LifecycleStatus, type LineageStatus, type NextAction, } from "./lifecycle/engine.js";
|
|
18
|
+
export { noExecutor, runLifecycle, type RunOptions, type RunResult, type RunStop, type StageExecutor, type StageOutcome, type StageRequest, } from "./lifecycle/run.js";
|
|
19
|
+
export { validateProject, type ValidationReport } from "./validate.js";
|
|
20
|
+
export { renderGitHubWorkflows, syncProject, type SyncReport } from "./sync.js";
|
|
21
|
+
export { findIntentOf, loadContext, type ContextContributor, type ContextOptions, type DeliveryContext, type ExtensionContext, type HistoryRecord, } from "./context.js";
|
|
22
|
+
export { CAPABILITY_PATTERN, CORE_CAPABILITIES, missingCapabilities, requiredCapabilities, type CoreCapability, } from "./pack/capabilities.js";
|
|
23
|
+
export { PACK_MANIFEST_FILE, SKILLS_DIR, loadPackManifest, parsePackManifest, skillPath, type PackAgent, type PackManifest, } from "./pack/manifest.js";
|
|
24
|
+
export { agentFor, assertPackComplete, locatePack, lockEntriesFor, resolveAndLock, resolveDesiredState, resolvePack, satisfiesRange, serialiseLock, writeLock, type DesiredState, type ResolvePackOptions, type ResolvedPack, } from "./pack/resolve.js";
|
|
25
|
+
export { isRecordingStage, recordStage, type RecordResult, type RecordingStage, } from "./lifecycle/record.js";
|
|
26
|
+
export { EXTENSION_MANIFEST_FILE, loadExtensionManifest, parseExtensionManifest, type ExtensionManifest, } from "./extension/manifest.js";
|
|
27
|
+
export { RESERVED_NAMESPACES, composedRegistries, enabledManifests, extensionLockEntries, extensionSchemas, resolveExtensions, type ResolveExtensionsOptions, type ResolvedExtension, } from "./extension/resolve.js";
|
|
28
|
+
export { addExtension, removeExtension, upgradeExtension, type ExtensionChange, type ExtensionChangeReport, } from "./extension/manage.js";
|
|
29
|
+
export { GENERATED_MARKER, MANAGED_DIRS, isGenerated, renderClaudeCodeAdapter, writeAdapter, type RenderedFiles, type WriteAdapterResult, } from "./adapter/claude-code.js";
|
|
30
|
+
export { COMMAND_TEMPLATES, templateFor, type CommandTemplate } from "./adapter/commands.js";
|
|
31
|
+
export { type AssertionResult, type CandidateRunner, type CandidateTask, type DeterministicAssertion, type EvalCase, type EvalSuite, type Observation, type ScriptedCandidate, type SemanticDimension, type SemanticJudge, type SemanticJudgement, type ViolationCandidate, } from "./eval/case.js";
|
|
32
|
+
export { evalPassed, runEval, type DeterministicResult, type EvalCaseResult, type EvalOptions, type EvalReport, type SemanticResult, } from "./eval/runner.js";
|
|
33
|
+
export { CORE_DELIVERY_SUITE } from "./eval/core-suite.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export { PactwrightError, formatProblem } from "./errors.js";
|
|
2
|
+
export { ADAPTER_TYPES, CONFIG_VERSION, loadConfig, parseConfig, rewriteConfig, serialiseConfig, } from "./config/config.js";
|
|
3
|
+
export { ACTORS, CORE_STAGES, DECISION_STAGE, EXECUTION_MODES, LIFECYCLE_VERSION, decisionActor, humanGates, isHumanGate, loadLifecycle, parseLifecycle, } from "./config/lifecycle.js";
|
|
4
|
+
export { EXTENSION_ID_PATTERN, HASH_PATTERN, loadLock, parseLock, } from "./config/lock.js";
|
|
5
|
+
export { CREATED_PATTERN, NODE_ID_PATTERN, NODE_TYPE_PATTERN, REQUIRED_NODE_FIELDS, checkNodeId, checkNodeIdImmutability, loadNodes, parseNodeFile, } from "./graph/nodes.js";
|
|
6
|
+
export { CORE_NODE_SCHEMAS, CORE_NODE_TYPES, DECIDED_BY_KINDS, DECIDED_BY_PATTERN, DECISION_OUTCOMES, createNodeSchemaRegistry, decisionFields, nodeTypes, parseDecidedBy, validateNode, validateNodes, } from "./graph/schema.js";
|
|
7
|
+
export { CORE_EDGE_OWNER, CORE_EDGE_SCHEMAS, CORE_EDGE_TYPES, createEdgeSchemaRegistry, edgeTypes, validateEdges, } from "./graph/edge-schema.js";
|
|
8
|
+
export { DELIVERY_STATES, deriveLineage, deriveLineages, isCurrent, validateLineages, } from "./graph/lineage.js";
|
|
9
|
+
export { EDGE_TYPE_PATTERN, edgeKey, loadEdges, parseEdges, } from "./graph/edges.js";
|
|
10
|
+
export { mintNodeId, slugify } from "./graph/ids.js";
|
|
11
|
+
export { createBrief, createEvidence, createIntent, recordDecision, } from "./graph/mutations.js";
|
|
12
|
+
export { REVISION_PATTERN, REVISION_VERSION, canonicalGraphPayload, canonicalJson, graphRevision, } from "./graph/revision.js";
|
|
13
|
+
export { CONFIG_FILE, EDGES_FILE, LIFECYCLE_FILE, LOCK_FILE, NODES_DIR, findProjectRoot, projectPaths, } from "./project.js";
|
|
14
|
+
export { loadProject } from "./loader.js";
|
|
15
|
+
export { CONFIG_TEMPLATE, INIT_DIRS, LIFECYCLE_TEMPLATE, initProject, initTemplates, } from "./init.js";
|
|
16
|
+
export { runtimeVersion } from "./version.js";
|
|
17
|
+
export { GRAPH_MARKING_STAGES, TRANSIENT_STAGES, completedStages, isActive, isTransientStage, lifecycleNext, lifecycleStatus, nextActionFor, pendingStages, selectLineages, } from "./lifecycle/engine.js";
|
|
18
|
+
export { noExecutor, runLifecycle, } from "./lifecycle/run.js";
|
|
19
|
+
export { validateProject } from "./validate.js";
|
|
20
|
+
export { renderGitHubWorkflows, syncProject } from "./sync.js";
|
|
21
|
+
export { findIntentOf, loadContext, } from "./context.js";
|
|
22
|
+
export { CAPABILITY_PATTERN, CORE_CAPABILITIES, missingCapabilities, requiredCapabilities, } from "./pack/capabilities.js";
|
|
23
|
+
export { PACK_MANIFEST_FILE, SKILLS_DIR, loadPackManifest, parsePackManifest, skillPath, } from "./pack/manifest.js";
|
|
24
|
+
export { agentFor, assertPackComplete, locatePack, lockEntriesFor, resolveAndLock, resolveDesiredState, resolvePack, satisfiesRange, serialiseLock, writeLock, } from "./pack/resolve.js";
|
|
25
|
+
export { isRecordingStage, recordStage, } from "./lifecycle/record.js";
|
|
26
|
+
export { EXTENSION_MANIFEST_FILE, loadExtensionManifest, parseExtensionManifest, } from "./extension/manifest.js";
|
|
27
|
+
export { RESERVED_NAMESPACES, composedRegistries, enabledManifests, extensionLockEntries, extensionSchemas, resolveExtensions, } from "./extension/resolve.js";
|
|
28
|
+
export { addExtension, removeExtension, upgradeExtension, } from "./extension/manage.js";
|
|
29
|
+
export { GENERATED_MARKER, MANAGED_DIRS, isGenerated, renderClaudeCodeAdapter, writeAdapter, } from "./adapter/claude-code.js";
|
|
30
|
+
export { COMMAND_TEMPLATES, templateFor } from "./adapter/commands.js";
|
|
31
|
+
export {} from "./eval/case.js";
|
|
32
|
+
export { evalPassed, runEval, } from "./eval/runner.js";
|
|
33
|
+
export { CORE_DELIVERY_SUITE } from "./eval/core-suite.js";
|
package/dist/init.d.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { Problem } from "./errors.js";
|
|
2
|
+
/**
|
|
3
|
+
* Default `.pactwright/config.yml` (Distribution §3): the `@pactwright/standard`
|
|
4
|
+
* pack with Claude Code defaults. `github.enabled` stays `false` until GitHub
|
|
5
|
+
* provisioning exists (Distribution §§9–14); `init` creates no `.github/`
|
|
6
|
+
* content.
|
|
7
|
+
*/
|
|
8
|
+
export declare const CONFIG_TEMPLATE: string;
|
|
9
|
+
/** Default `.pactwright/lifecycle.yml`: the human-gated core Delivery lifecycle (Delivery Graph §17). */
|
|
10
|
+
export declare const LIFECYCLE_TEMPLATE = "version: 1\n\nstages:\n capture-intent:\n execution: manual\n propose-contracts:\n execution: automatic\n approve-contract:\n execution: manual\n actor: human\n write-brief:\n execution: automatic\n deliver-brief:\n execution: automatic\n review:\n execution: automatic\n prepare-evidence:\n execution: automatic\n";
|
|
11
|
+
/**
|
|
12
|
+
* The files `init` owns, in report order: relative path → content. The lock
|
|
13
|
+
* is not a template — it is resolved from the on-disk configuration after
|
|
14
|
+
* these files exist.
|
|
15
|
+
*/
|
|
16
|
+
export declare function initTemplates(): ReadonlyMap<string, string>;
|
|
17
|
+
/**
|
|
18
|
+
* Directories `init` creates empty: the Claude Code adapter surface, filled
|
|
19
|
+
* by `pactwright sync` (Distribution §8) — `init` never copies runtime
|
|
20
|
+
* scripts, agents or commands into the repository (Distribution §2).
|
|
21
|
+
*/
|
|
22
|
+
export declare const INIT_DIRS: readonly string[];
|
|
23
|
+
/** One path `init` considered: what it is and what happened to it. */
|
|
24
|
+
export interface InitEntry {
|
|
25
|
+
/** Repository-relative path, e.g. `.pactwright/config.yml`. */
|
|
26
|
+
readonly path: string;
|
|
27
|
+
readonly kind: "file" | "dir";
|
|
28
|
+
/** `skipped` means the path already existed and was left untouched. */
|
|
29
|
+
readonly action: "created" | "skipped";
|
|
30
|
+
}
|
|
31
|
+
/** `pactwright init` result. */
|
|
32
|
+
export interface InitReport {
|
|
33
|
+
readonly ok: boolean;
|
|
34
|
+
readonly root: string;
|
|
35
|
+
/** Every path considered, in order; empty `problems` when `ok`. */
|
|
36
|
+
readonly entries: readonly InitEntry[];
|
|
37
|
+
readonly problems: readonly Problem[];
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Initialises the Pactwright-owned core structure (Distribution §§2–3) in
|
|
41
|
+
* `root`: configuration, lifecycle, the empty graph, the empty adapter
|
|
42
|
+
* directories, then the resolved `.pactwright/lock.yml`. Existing paths are
|
|
43
|
+
* never read or overwritten — each is reported `skipped` — so re-running in
|
|
44
|
+
* an initialised repository changes nothing. Finishes by validating the
|
|
45
|
+
* resulting project state; never throws for expected failures.
|
|
46
|
+
*/
|
|
47
|
+
export declare function initProject(root?: string): InitReport;
|