repo-contract 0.3.0 → 0.3.2
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/CHANGELOG.md +23 -0
- package/README.md +46 -0
- package/dist/.dts/config/define-repo-contract.d.ts +36 -0
- package/dist/.dts/config/define-repo-contract.d.ts.map +1 -0
- package/dist/.dts/config/tokenize-command.d.ts +33 -0
- package/dist/.dts/config/tokenize-command.d.ts.map +1 -0
- package/dist/.dts/config/validate-config.d.ts +32 -0
- package/dist/.dts/config/validate-config.d.ts.map +1 -0
- package/dist/.dts/errors.d.ts +172 -0
- package/dist/.dts/errors.d.ts.map +1 -0
- package/dist/.dts/evidence/build-evidence.d.ts +26 -0
- package/dist/.dts/evidence/build-evidence.d.ts.map +1 -0
- package/dist/.dts/execution/abort-signals.d.ts +29 -0
- package/dist/.dts/execution/abort-signals.d.ts.map +1 -0
- package/dist/.dts/execution/concurrency-pool.d.ts +14 -0
- package/dist/.dts/execution/concurrency-pool.d.ts.map +1 -0
- package/dist/.dts/execution/dependency-scheduler.d.ts +30 -0
- package/dist/.dts/execution/dependency-scheduler.d.ts.map +1 -0
- package/dist/.dts/execution/process-tree.d.ts +59 -0
- package/dist/.dts/execution/process-tree.d.ts.map +1 -0
- package/dist/.dts/execution/run-checks.d.ts +31 -0
- package/dist/.dts/execution/run-checks.d.ts.map +1 -0
- package/dist/.dts/execution/spawn-check.d.ts +49 -0
- package/dist/.dts/execution/spawn-check.d.ts.map +1 -0
- package/dist/.dts/index.d.ts +14 -0
- package/dist/.dts/index.d.ts.map +1 -0
- package/dist/.dts/parsing/format-schema-issues.d.ts +11 -0
- package/dist/.dts/parsing/format-schema-issues.d.ts.map +1 -0
- package/dist/.dts/parsing/parse-json.d.ts +8 -0
- package/dist/.dts/parsing/parse-json.d.ts.map +1 -0
- package/dist/.dts/parsing/parse-output.d.ts +25 -0
- package/dist/.dts/parsing/parse-output.d.ts.map +1 -0
- package/dist/.dts/parsing/parse-text.d.ts +8 -0
- package/dist/.dts/parsing/parse-text.d.ts.map +1 -0
- package/dist/.dts/parsing/parse-yaml.d.ts +21 -0
- package/dist/.dts/parsing/parse-yaml.d.ts.map +1 -0
- package/dist/.dts/policy/run-policies.d.ts +38 -0
- package/dist/.dts/policy/run-policies.d.ts.map +1 -0
- package/dist/.dts/presets/arethetypeswrong.d.ts +39 -0
- package/dist/.dts/presets/arethetypeswrong.d.ts.map +1 -0
- package/dist/.dts/presets/broken-links.d.ts +16 -0
- package/dist/.dts/presets/broken-links.d.ts.map +1 -0
- package/dist/.dts/presets/commitlint.d.ts +22 -0
- package/dist/.dts/presets/commitlint.d.ts.map +1 -0
- package/dist/.dts/presets/dead-code.d.ts +23 -0
- package/dist/.dts/presets/dead-code.d.ts.map +1 -0
- package/dist/.dts/presets/duplication.d.ts +14 -0
- package/dist/.dts/presets/duplication.d.ts.map +1 -0
- package/dist/.dts/presets/e2e.d.ts +4 -0
- package/dist/.dts/presets/e2e.d.ts.map +1 -0
- package/dist/.dts/presets/format.d.ts +4 -0
- package/dist/.dts/presets/format.d.ts.map +1 -0
- package/dist/.dts/presets/index.d.ts +31 -0
- package/dist/.dts/presets/index.d.ts.map +1 -0
- package/dist/.dts/presets/license.d.ts +4 -0
- package/dist/.dts/presets/license.d.ts.map +1 -0
- package/dist/.dts/presets/lint.d.ts +20 -0
- package/dist/.dts/presets/lint.d.ts.map +1 -0
- package/dist/.dts/presets/markdownlint.d.ts +23 -0
- package/dist/.dts/presets/markdownlint.d.ts.map +1 -0
- package/dist/.dts/presets/publint.d.ts +13 -0
- package/dist/.dts/presets/publint.d.ts.map +1 -0
- package/dist/.dts/presets/security-deps.d.ts +4 -0
- package/dist/.dts/presets/security-deps.d.ts.map +1 -0
- package/dist/.dts/presets/security-secrets.d.ts +4 -0
- package/dist/.dts/presets/security-secrets.d.ts.map +1 -0
- package/dist/.dts/presets/shared/error-warning-pass-policy.d.ts +13 -0
- package/dist/.dts/presets/shared/error-warning-pass-policy.d.ts.map +1 -0
- package/dist/.dts/presets/shared/exit-code-fail-rationale.d.ts +23 -0
- package/dist/.dts/presets/shared/exit-code-fail-rationale.d.ts.map +1 -0
- package/dist/.dts/presets/shared/missing-dependency.d.ts +19 -0
- package/dist/.dts/presets/shared/missing-dependency.d.ts.map +1 -0
- package/dist/.dts/presets/shared/read-json-report.d.ts +33 -0
- package/dist/.dts/presets/shared/read-json-report.d.ts.map +1 -0
- package/dist/.dts/presets/shared/terminal-status.d.ts +25 -0
- package/dist/.dts/presets/shared/terminal-status.d.ts.map +1 -0
- package/dist/.dts/presets/shared/vitest-json-policy.d.ts +20 -0
- package/dist/.dts/presets/shared/vitest-json-policy.d.ts.map +1 -0
- package/dist/.dts/presets/stylelint.d.ts +17 -0
- package/dist/.dts/presets/stylelint.d.ts.map +1 -0
- package/dist/.dts/presets/test.d.ts +4 -0
- package/dist/.dts/presets/test.d.ts.map +1 -0
- package/dist/.dts/presets/typecheck.d.ts +4 -0
- package/dist/.dts/presets/typecheck.d.ts.map +1 -0
- package/dist/.dts/run-repo-contract.d.ts +38 -0
- package/dist/.dts/run-repo-contract.d.ts.map +1 -0
- package/dist/.dts/standard-schema/types.d.ts +76 -0
- package/dist/.dts/standard-schema/types.d.ts.map +1 -0
- package/dist/.dts/types.d.ts +424 -0
- package/dist/.dts/types.d.ts.map +1 -0
- package/dist/index.cjs +99 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +99 -5
- package/dist/index.js.map +1 -1
- package/dist/presets.d.cts +1 -0
- package/dist/presets.d.ts +1 -0
- package/package.json +1 -1
- package/schemas/evidence.schema.json +2 -2
- package/src/config/validate-config.ts +55 -1
- package/src/errors.ts +26 -0
- package/src/evidence/build-evidence.ts +6 -1
- package/src/index.ts +3 -0
- package/src/parsing/format-schema-issues.ts +56 -0
- package/src/parsing/parse-output.ts +50 -3
- package/src/standard-schema/types.ts +93 -0
- package/src/types.ts +48 -12
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.3.2](https://github.com/MaverickCER/repo-contract/compare/repo-contract-v0.3.1...repo-contract-v0.3.2) (2026-09-04)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* validate and transform check output with a Standard Schema ([d53cb17](https://github.com/MaverickCER/repo-contract/commit/d53cb17a9e3a3f939cd403226ab5256be0de79ac))
|
|
9
|
+
* validate and transform check output with a Standard Schema ([fbb7925](https://github.com/MaverickCER/repo-contract/commit/fbb79259f4a6cede1da64a0abd7e1f1541e1d505))
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
### Bug Fixes
|
|
13
|
+
|
|
14
|
+
* address CodeRabbit findings and close mutation-testing gaps in Standard Schema support ([53baf87](https://github.com/MaverickCER/repo-contract/commit/53baf877d367fd17dbe1ec2f312ab9ed790e6ae6))
|
|
15
|
+
* **api-contract:** don't classify a required property on a brand-new container as breaking ([27ad5d5](https://github.com/MaverickCER/repo-contract/commit/27ad5d5c57811d90393b00f48ae8a8bbd413407b))
|
|
16
|
+
* **test:** harden isRuntimeAvailable against spawnSync throwing under load ([60c76b6](https://github.com/MaverickCER/repo-contract/commit/60c76b642dfd6187888f02d31639e68468e77b17))
|
|
17
|
+
|
|
18
|
+
## [0.3.1](https://github.com/MaverickCER/repo-contract/compare/repo-contract-v0.3.0...repo-contract-v0.3.1) (2026-09-03)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
### Bug Fixes
|
|
22
|
+
|
|
23
|
+
* correct the release runbook that shipped types-less tarballs ([f56ea34](https://github.com/MaverickCER/repo-contract/commit/f56ea342606cfc92a09943ea5eb787936e7b7ba9))
|
|
24
|
+
* published tarball missing types; simplify CI matrix ([7ec8fd9](https://github.com/MaverickCER/repo-contract/commit/7ec8fd946bd584098255c5d2ab3f07b98b55ba1f))
|
|
25
|
+
|
|
3
26
|
## [0.3.0](https://github.com/MaverickCER/repo-contract/compare/repo-contract-v0.2.1...repo-contract-v0.3.0) (2026-09-03)
|
|
4
27
|
|
|
5
28
|
|
package/README.md
CHANGED
|
@@ -529,6 +529,50 @@ Provides trimmed text passthrough and always succeeds.
|
|
|
529
529
|
|
|
530
530
|
The sibling mistake -- reading `result.output.value` when the format _was_ requested but the parse itself failed (`result.output.success === false`, so `result.output` has `error`, not `value`) -- similarly rejects with [`PolicyReadFailedParseValueError`](docs/api-report/repo-contract.api.md) instead of a generic `PolicyThrewError`. Check `result.output.success` before reading `.value` to handle a parse failure explicitly rather than hitting either error.
|
|
531
531
|
|
|
532
|
+
#### Validating parsed output with a schema
|
|
533
|
+
|
|
534
|
+
`output.schema` accepts any object implementing [Standard Schema](https://standardschema.dev) --
|
|
535
|
+
Zod, Valibot, ArkType, and others already do. repo-contract does not install or depend on any of
|
|
536
|
+
them; it hand-vendors the (pure-type, zero-runtime-code) `StandardSchemaV1` interface itself (see
|
|
537
|
+
[ADR 0012](specs/decisions/0012-hand-vendored-standard-schema-support-for-optional-output-validation.md)). Bring whichever schema
|
|
538
|
+
library your own repo already uses -- `npm install zod` (or `valibot`, or `arktype`) is your call,
|
|
539
|
+
not repo-contract's. The smallest possible example, using a hand-written object satisfying the
|
|
540
|
+
interface directly rather than any particular library:
|
|
541
|
+
|
|
542
|
+
```ts
|
|
543
|
+
output: {
|
|
544
|
+
format: "json",
|
|
545
|
+
schema: {
|
|
546
|
+
"~standard": {
|
|
547
|
+
version: 1,
|
|
548
|
+
vendor: "example",
|
|
549
|
+
validate: (value) => {
|
|
550
|
+
const errorCount =
|
|
551
|
+
value !== null && typeof value === "object"
|
|
552
|
+
? (value as { errorCount?: unknown }).errorCount
|
|
553
|
+
: undefined
|
|
554
|
+
return typeof errorCount === "number"
|
|
555
|
+
? { value: { errorCount } }
|
|
556
|
+
: { issues: [{ message: "errorCount must be a number", path: ["errorCount"] }] }
|
|
557
|
+
},
|
|
558
|
+
},
|
|
559
|
+
},
|
|
560
|
+
}
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
A successful validation _replaces_ `result.output.value` with the schema's own (possibly
|
|
564
|
+
transformed or coerced) output -- one of the most useful aspects of Standard Schema, not just a
|
|
565
|
+
boolean check: a schema can normalize, default, or reshape its input, and the policy receives that
|
|
566
|
+
result, not the raw parsed value. A failing validation becomes a normal `ParsedOutputFailure` --
|
|
567
|
+
indistinguishable in shape from a malformed-JSON parse failure, joining every issue's own path and
|
|
568
|
+
message into `result.output.error` (e.g. `Schema validation failed: errorCount: errorCount must be
|
|
569
|
+
a number`). `result.output.value`'s declared TypeScript type stays `unknown` regardless -- narrow
|
|
570
|
+
or cast it yourself, same as without a schema.
|
|
571
|
+
|
|
572
|
+
`schema["~standard"].validate()` itself throwing or rejecting (rather than returning a `Result`) is
|
|
573
|
+
different from a failed validation -- it means the schema is broken, not the check's output, so it
|
|
574
|
+
rejects `runRepoContract()` with `StandardSchemaValidateThrewError` instead of becoming evidence.
|
|
575
|
+
|
|
532
576
|
### `dependsOn`
|
|
533
577
|
|
|
534
578
|
By default, every check runs independently and in parallel.
|
|
@@ -1001,6 +1045,8 @@ A **policy throwing** is different. A synchronous throw or rejected promise from
|
|
|
1001
1045
|
|
|
1002
1046
|
Two specific mistakes get their own error instead of a plain `PolicyThrewError`, both naming the check: reading `result.output.value` (or `.success`/`.error`/`.format`) on a check that never configured `output` throws `PolicyReadUnrequestedOutputError`, telling you to add `output: { format: "json" }` (or `"yaml"`/`"text"`); reading `result.output.value` on a check whose requested parse actually failed throws `PolicyReadFailedParseValueError`, telling you to check `result.output.success` first -- see [`output`](#output).
|
|
1003
1047
|
|
|
1048
|
+
A **schema throwing** (`output.schema["~standard"].validate()` itself throwing or rejecting, rather than returning a `Result` -- see [Validating parsed output with a schema](#validating-parsed-output-with-a-schema)) is treated the same as a throwing policy: `StandardSchemaValidateThrewError`, or an `AggregateError` when multiple checks' schemas throw in the same run. A schema _returning_ failure `issues`, by contrast, is not an error at all -- it becomes an ordinary parser-error-shaped `result.output`, exactly like the **Parser errors** case above.
|
|
1049
|
+
|
|
1004
1050
|
## Status and versioning
|
|
1005
1051
|
|
|
1006
1052
|
repo-contract is pre-1.0.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { CheckSchema, RepoContractConfig, ValidatedCheckSchema } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Identity function whose only job is type inference: authoring a config
|
|
4
|
+
* through `defineRepoContract` lets each check's `output` (present or
|
|
5
|
+
* absent, and which format) flow into that same check's `policy` parameter
|
|
6
|
+
* type, without the consumer writing any type annotations themselves. It
|
|
7
|
+
* also statically validates every check's `dependsOn` against its sibling
|
|
8
|
+
* check ids (see `ValidatedCheckSchema`) -- a typo'd or self-referencing id
|
|
9
|
+
* fails to compile here rather than only failing at runtime. Performs no
|
|
10
|
+
* other validation and no cloning -- `runRepoContract` validates whatever
|
|
11
|
+
* config it is ultimately given, whether or not it passed through this
|
|
12
|
+
* function first.
|
|
13
|
+
*
|
|
14
|
+
* `const TChecks` (TypeScript 5.0's `const` type parameter modifier) keeps
|
|
15
|
+
* each check's own configuration -- notably whether `output` is present at
|
|
16
|
+
* all -- from being widened during inference; without it, TypeScript's
|
|
17
|
+
* inference for a `Record` of heterogeneous generic entries does not
|
|
18
|
+
* reliably preserve that per-check shape once a callback property
|
|
19
|
+
* (`policy`) is also present. See `InferParsedValue` in types.ts for the
|
|
20
|
+
* related limitation this does not fully solve.
|
|
21
|
+
*
|
|
22
|
+
* `TChecks` is inferred from the plain, unwrapped `RepoContractConfig<TChecks>`
|
|
23
|
+
* position -- the `ValidatedCheckSchema<TChecks>` constraint on `checks` is
|
|
24
|
+
* intersected in afterward, computed from that already-inferred `TChecks`,
|
|
25
|
+
* rather than substituted in its place. Inferring `TChecks` directly from a
|
|
26
|
+
* mapped/conditional type over itself (as `ValidatedCheckSchema` is) loses
|
|
27
|
+
* the contextual typing every check's `policy` callback otherwise gets --
|
|
28
|
+
* another real, confirmed TypeScript inference limitation, distinct from
|
|
29
|
+
* the `output`-to-`policy` one above.
|
|
30
|
+
* @param config - the config to type-check and return unchanged.
|
|
31
|
+
* @returns the same `config` object, untouched and uncloned.
|
|
32
|
+
*/
|
|
33
|
+
export declare function defineRepoContract<const TChecks extends CheckSchema>(config: RepoContractConfig<TChecks> & {
|
|
34
|
+
readonly checks: ValidatedCheckSchema<TChecks>;
|
|
35
|
+
}): RepoContractConfig<TChecks>;
|
|
36
|
+
//# sourceMappingURL=define-repo-contract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define-repo-contract.d.ts","sourceRoot":"","sources":["../../../src/config/define-repo-contract.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAExF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,CAAC,OAAO,SAAS,WAAW,EAClE,MAAM,EAAE,kBAAkB,CAAC,OAAO,CAAC,GAAG;IAAE,QAAQ,CAAC,MAAM,EAAE,oBAAoB,CAAC,OAAO,CAAC,CAAA;CAAE,GACvF,kBAAkB,CAAC,OAAO,CAAC,CAE7B"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Splits a `run` string into argv (executable + arguments) without invoking
|
|
3
|
+
* a shell -- no shell operator is ever executed, no glob is ever expanded by
|
|
4
|
+
* this package, no environment variable is ever substituted. The result is
|
|
5
|
+
* deterministic: the same input string always produces the same argv array.
|
|
6
|
+
*
|
|
7
|
+
* Quoting: `'...'` and `"..."` group whitespace into a single argument and
|
|
8
|
+
* are themselves stripped from the resulting token. `\` escapes the next
|
|
9
|
+
* character (and is itself stripped) when unquoted or inside a double-quoted
|
|
10
|
+
* span; inside single quotes it is a literal character, exactly as in every
|
|
11
|
+
* POSIX shell -- so a Windows path in single quotes survives intact.
|
|
12
|
+
* Unquoted whitespace (space, tab) separates tokens.
|
|
13
|
+
*
|
|
14
|
+
* Rejected outright (throws `InvalidCheckConfigError`, checkId identifies
|
|
15
|
+
* which check's `run` was invalid): any *unquoted* occurrence of a true
|
|
16
|
+
* shell/multi-command operator -- `;`, `&`, `|`, a backtick, `$(`, `<`, `>`,
|
|
17
|
+
* or a literal newline. A string containing one of these almost always
|
|
18
|
+
* reflects a mistaken assumption that shell interpretation is happening;
|
|
19
|
+
* the fix is either `run: [...]` (array form, bypasses tokenization
|
|
20
|
+
* entirely) or explicit `shell: true`.
|
|
21
|
+
*
|
|
22
|
+
* Deliberately NOT rejected: glob characters (`*`, `?`, `~`, `[`, `]`, `{`,
|
|
23
|
+
* `}`) and a bare `$`. These are common, legitimate literal argv content --
|
|
24
|
+
* many CLI tools (eslint, prettier, tsc) accept and internally expand glob
|
|
25
|
+
* patterns themselves, e.g. `eslint "src/**\/*.ts"` -- and since no shell is
|
|
26
|
+
* ever invoked here, they carry zero shell-injection risk regardless of
|
|
27
|
+
* where they appear in the string.
|
|
28
|
+
* @param run - the command string to tokenize.
|
|
29
|
+
* @param checkId - identifies which check's `run` was invalid, used in the thrown error message.
|
|
30
|
+
* @returns the tokenized argv (executable followed by its arguments).
|
|
31
|
+
*/
|
|
32
|
+
export declare function tokenizeRunString(run: string, checkId: string): readonly string[];
|
|
33
|
+
//# sourceMappingURL=tokenize-command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokenize-command.d.ts","sourceRoot":"","sources":["../../../src/config/tokenize-command.ts"],"names":[],"mappings":"AA8DA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAwHjF"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { RepoContractConfig } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Validates a `RepoContractConfig` structurally and throws before any
|
|
4
|
+
* process spawns. A config with zero checks is valid (an empty `checks`
|
|
5
|
+
* object vacuously satisfies "every check passed"); everything else here is
|
|
6
|
+
* a genuine structural problem. Runtime checks are deliberately defensive
|
|
7
|
+
* about field types rather than trusting the compile-time type, since a
|
|
8
|
+
* config can arrive from plain JavaScript or a widened/cast value.
|
|
9
|
+
* @param config - the config to validate; throws if structurally invalid.
|
|
10
|
+
*/
|
|
11
|
+
export declare function validateRepoContractConfig(config: RepoContractConfig): void;
|
|
12
|
+
/**
|
|
13
|
+
* Whole-graph properties that can't be checked per-check in isolation --
|
|
14
|
+
* run once, after every check's own `dependsOn` shape has already been
|
|
15
|
+
* validated by `validateDependsOn` above, so this can walk every
|
|
16
|
+
* `dependsOn` array without re-checking its shape.
|
|
17
|
+
*
|
|
18
|
+
* Declaration order in the `checks` object doubles as the required topological order (see
|
|
19
|
+
* `CheckDefinition.dependsOn`'s own doc comment): every `dependsOn` id must name a check declared
|
|
20
|
+
* earlier* than the check declaring it. This single backward-reference check subsumes what used
|
|
21
|
+
* to be two separate passes (an unknown-id check, then a DFS cycle detector) -- a cycle is no
|
|
22
|
+
* longer expressible at all once every edge is required to point backward, so there is nothing
|
|
23
|
+
* left for a separate cycle detector to catch. `isolated` needs no validation-time edge computation
|
|
24
|
+
* here: its own implied positional edges (see `run-checks.ts`'s `dependencyIndexesFor`) always
|
|
25
|
+
* point backward (to earlier-declared checks) or are pointed at by later-declared checks, by
|
|
26
|
+
* construction, so they can never introduce a cycle either.
|
|
27
|
+
* @param checks - the full check map, keyed by check id, in declaration order.
|
|
28
|
+
*/
|
|
29
|
+
export declare function validateDependencyGraph(checks: Record<string, {
|
|
30
|
+
dependsOn?: readonly string[];
|
|
31
|
+
}>): void;
|
|
32
|
+
//# sourceMappingURL=validate-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate-config.d.ts","sourceRoot":"","sources":["../../../src/config/validate-config.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAgB,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAKnE;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,kBAAkB,GAAG,IAAI,CAuE3E;AA2VD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC,GACxD,IAAI,CAoBN"}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error hierarchy for repo-contract. Every concrete error carries a stable
|
|
3
|
+
* `code` string for programmatic handling, and never embeds raw
|
|
4
|
+
* stdout/stderr/env values in its message -- only check ids and field names
|
|
5
|
+
* (see SECURITY.md).
|
|
6
|
+
*
|
|
7
|
+
* Three distinct failure classes are kept deliberately separate (see
|
|
8
|
+
* specs/architecture.md):
|
|
9
|
+
* - Structural config problems throw synchronously, before any process
|
|
10
|
+
* spawns (`InvalidRepoContractConfigError`, `InvalidCheckConfigError`).
|
|
11
|
+
* - Anything only discoverable by attempting execution becomes evidence,
|
|
12
|
+
* never a throw (a bad `cwd`, a missing binary -- recorded as
|
|
13
|
+
* `status: "spawn_error"` on that check's `CheckEvidence`).
|
|
14
|
+
* - A policy function throwing or rejecting is a bug in consumer code, not
|
|
15
|
+
* a check failing its contract -- it propagates as a rejected
|
|
16
|
+
* `runRepoContract()` promise (`PolicyThrewError`), never silently
|
|
17
|
+
* turned into a failed verdict entry.
|
|
18
|
+
*/
|
|
19
|
+
export declare abstract class RepoContractError extends Error {
|
|
20
|
+
/** Stable, machine-readable identifier for this error's specific failure mode. */
|
|
21
|
+
abstract readonly code: string;
|
|
22
|
+
}
|
|
23
|
+
/** The top-level `RepoContractConfig` itself is structurally invalid -- e.g. `checks` is not an object, or `concurrency` is not a positive integer. (A `checks` object with zero entries is deliberately valid: the run produces an empty, passing `Verdict`.) Thrown synchronously by `runRepoContract`, before anything spawns -- not by `defineRepoContract`, which performs no runtime validation of its own (see its own doc comment). */
|
|
24
|
+
export declare class InvalidRepoContractConfigError extends RepoContractError {
|
|
25
|
+
/** Always `"REPO_CONTRACT_INVALID_CONFIG"`. */
|
|
26
|
+
readonly code = "REPO_CONTRACT_INVALID_CONFIG";
|
|
27
|
+
constructor(reason: string);
|
|
28
|
+
}
|
|
29
|
+
/** One check's `CheckDefinition` is structurally invalid -- e.g. an empty `run`, a `run` string containing an unquoted shell operator without `shell: true`, or a missing `policy`. Thrown synchronously, before that check (or any other) spawns. */
|
|
30
|
+
export declare class InvalidCheckConfigError extends RepoContractError {
|
|
31
|
+
/** Always `"REPO_CONTRACT_INVALID_CHECK_CONFIG"`. */
|
|
32
|
+
readonly code = "REPO_CONTRACT_INVALID_CHECK_CONFIG";
|
|
33
|
+
/** The id of the check whose configuration was invalid. */
|
|
34
|
+
readonly checkId: string;
|
|
35
|
+
constructor(checkId: string, reason: string);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* `RunRepoContractOptions.checks` (a partial-run request) names a check id that doesn't exist in
|
|
39
|
+
* the configured `checks`. Unlike a `dependsOn` id (already validated to exist by
|
|
40
|
+
* `validateRepoContractConfig` before any run starts), `options.checks` is only ever checked once
|
|
41
|
+
* `runChecks` actually resolves it -- there is no earlier structural-validation pass for it.
|
|
42
|
+
*/
|
|
43
|
+
export declare class UnknownCheckIdError extends RepoContractError {
|
|
44
|
+
/** Always `"REPO_CONTRACT_UNKNOWN_CHECK_ID"`. */
|
|
45
|
+
readonly code = "REPO_CONTRACT_UNKNOWN_CHECK_ID";
|
|
46
|
+
/** The unrecognized check id named in `options.checks`. */
|
|
47
|
+
readonly checkId: string;
|
|
48
|
+
constructor(checkId: string);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* A check's `dependsOn` names a check declared *later* in the same `checks` object.
|
|
52
|
+
* `dependsOn` may only reference a check declared earlier -- see `CheckDefinition.dependsOn`'s own
|
|
53
|
+
* doc comment. Declaration order doubles as the required topological order, so this is the only
|
|
54
|
+
* way an invalid dependency graph can arise; a real cycle is structurally impossible once every
|
|
55
|
+
* edge points backward. Thrown synchronously, before any check spawns.
|
|
56
|
+
*/
|
|
57
|
+
export declare class DependencyDeclaredLaterError extends RepoContractError {
|
|
58
|
+
/** Always `"REPO_CONTRACT_DEPENDENCY_DECLARED_LATER"`. */
|
|
59
|
+
readonly code = "REPO_CONTRACT_DEPENDENCY_DECLARED_LATER";
|
|
60
|
+
/** The id of the check whose `dependsOn` names a later-declared check. */
|
|
61
|
+
readonly checkId: string;
|
|
62
|
+
/** The later-declared check id named in `checkId`'s `dependsOn`. */
|
|
63
|
+
readonly dependencyId: string;
|
|
64
|
+
constructor(checkId: string, dependencyId: string);
|
|
65
|
+
}
|
|
66
|
+
/** A check requested `output: { format: "yaml" }` but the optional `yaml` peer dependency is not installed. Thrown when that check's output is parsed, not at config-validation time (parsing only happens after the process has already run). */
|
|
67
|
+
export declare class ParserDependencyMissingError extends RepoContractError {
|
|
68
|
+
/** Always `"REPO_CONTRACT_PARSER_DEPENDENCY_MISSING"`. */
|
|
69
|
+
readonly code = "REPO_CONTRACT_PARSER_DEPENDENCY_MISSING";
|
|
70
|
+
/** The id of the check whose output could not be parsed. */
|
|
71
|
+
readonly checkId: string;
|
|
72
|
+
/** The output format that was requested but whose optional peer dependency is missing. */
|
|
73
|
+
readonly format: OutputFormatForError;
|
|
74
|
+
constructor(checkId: string, format: OutputFormatForError, cause: unknown);
|
|
75
|
+
}
|
|
76
|
+
type OutputFormatForError = "yaml";
|
|
77
|
+
/**
|
|
78
|
+
* A check's `output.schema["~standard"].validate()` threw synchronously, or returned a `Promise`
|
|
79
|
+
* that rejected, instead of returning a `Result`. This is a bug in the consumer-supplied schema
|
|
80
|
+
* object, not malformed check output -- the same distinction `PolicyThrewError` below draws for a
|
|
81
|
+
* throwing policy: a schema *returning* failure `issues` becomes an ordinary
|
|
82
|
+
* `ParsedOutputFailure` (reported as data, exactly like a malformed-JSON/YAML parse failure), but
|
|
83
|
+
* a schema *throwing* means the validator itself is broken, so it propagates as a rejected
|
|
84
|
+
* `runRepoContract()` promise instead. The original thrown/rejected value is preserved verbatim
|
|
85
|
+
* via the native `Error` `cause` chain.
|
|
86
|
+
*/
|
|
87
|
+
export declare class StandardSchemaValidateThrewError extends RepoContractError {
|
|
88
|
+
/** Always `"REPO_CONTRACT_STANDARD_SCHEMA_VALIDATE_THREW"`. */
|
|
89
|
+
readonly code = "REPO_CONTRACT_STANDARD_SCHEMA_VALIDATE_THREW";
|
|
90
|
+
/** The id of the check whose `output.schema` threw during validation. */
|
|
91
|
+
readonly checkId: string;
|
|
92
|
+
constructor(checkId: string, cause: unknown);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* A check's `policy` function threw synchronously, or returned a `Promise`
|
|
96
|
+
* that later rejected. Both failure modes are wrapped identically. The
|
|
97
|
+
* original thrown/rejected value is preserved verbatim via the native
|
|
98
|
+
* `Error` `cause` chain -- never stringified, summarized, or discarded --
|
|
99
|
+
* so a consumer catching this can still inspect exactly what their own
|
|
100
|
+
* policy code did wrong.
|
|
101
|
+
*
|
|
102
|
+
* A policy throwing never stops any other check's policy from running --
|
|
103
|
+
* every configured check's policy is invoked exactly once regardless of
|
|
104
|
+
* what any other policy does. If more than one policy fails this way in the
|
|
105
|
+
* same run, `runRepoContract()` rejects with a native `AggregateError` whose
|
|
106
|
+
* `errors` array holds one error per failing check -- `PolicyThrewError`,
|
|
107
|
+
* or one of its two narrower siblings below (`PolicyReadUnrequestedOutputError`,
|
|
108
|
+
* `PolicyReadFailedParseValueError`) when the failure matches one of their
|
|
109
|
+
* more specific shapes -- rather than surfacing only the first one found.
|
|
110
|
+
*/
|
|
111
|
+
export declare class PolicyThrewError extends RepoContractError {
|
|
112
|
+
/** Always `"REPO_CONTRACT_POLICY_THREW"`. */
|
|
113
|
+
readonly code = "REPO_CONTRACT_POLICY_THREW";
|
|
114
|
+
/** The id of the check whose policy threw or rejected. */
|
|
115
|
+
readonly checkId: string;
|
|
116
|
+
constructor(checkId: string, cause: unknown);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* A narrower `runPolicies` throws instead of `PolicyThrewError` when the
|
|
120
|
+
* thrown `TypeError`'s own message shows it came from reading a
|
|
121
|
+
* `result.output` property (`.success`, `.value`, `.error`, or `.format`),
|
|
122
|
+
* and this check's `CheckEvidence.output` really is `undefined` -- which
|
|
123
|
+
* happens only when its config never requested `output: { format: ... }` in
|
|
124
|
+
* the first place (see `CheckEvidence.output` in types.ts). Detected from
|
|
125
|
+
* the `TypeError`'s exact V8-produced message ("Cannot read properties of
|
|
126
|
+
* undefined (reading '...')") cross-checked against that `undefined` fact,
|
|
127
|
+
* so it is thrown only for a policy that plausibly hit this exact mistake --
|
|
128
|
+
* any other `TypeError`, or a check that did request a format, still becomes
|
|
129
|
+
* a plain `PolicyThrewError`. This is best-effort inference from the
|
|
130
|
+
* `TypeError`'s message text, not a verified trace back to `result.output`
|
|
131
|
+
* itself -- V8's message carries only the property name, so an unrelated
|
|
132
|
+
* bug that happens to read the same property name off some other
|
|
133
|
+
* `undefined` value can still be misclassified this way (see
|
|
134
|
+
* `unrequestedOutputProperty` in run-policies.ts). `cause` still holds the
|
|
135
|
+
* original `TypeError` verbatim, exactly as `PolicyThrewError` guarantees
|
|
136
|
+
* for every other policy failure, so the true cause remains recoverable
|
|
137
|
+
* either way.
|
|
138
|
+
*/
|
|
139
|
+
export declare class PolicyReadUnrequestedOutputError extends RepoContractError {
|
|
140
|
+
/** Always `"REPO_CONTRACT_POLICY_READ_UNREQUESTED_OUTPUT"`. */
|
|
141
|
+
readonly code = "REPO_CONTRACT_POLICY_READ_UNREQUESTED_OUTPUT";
|
|
142
|
+
/** The id of the check whose policy read `result.output` without requesting a format. */
|
|
143
|
+
readonly checkId: string;
|
|
144
|
+
constructor(checkId: string, property: string, cause: unknown);
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* `PolicyThrewError`'s other special case, alongside
|
|
148
|
+
* `PolicyReadUnrequestedOutputError`: this check *did* request
|
|
149
|
+
* `output: { format: ... }`, but that parse itself failed
|
|
150
|
+
* (`result.output.success === false` -- see `ParsedOutputFailure` in types.ts, which
|
|
151
|
+
* has no `value` field, only `error`), and the policy read a property off
|
|
152
|
+
* `result.output.value` anyway without checking `.success` first. Detected the same
|
|
153
|
+
* way `runPolicies` detects the sibling case -- a thrown `TypeError` whose own
|
|
154
|
+
* message shows a property read off `undefined` -- cross-checked against this
|
|
155
|
+
* check's own evidence having `output.success === false`, so a genuinely unrelated
|
|
156
|
+
* `TypeError`, or a check whose parse actually succeeded, still becomes a plain
|
|
157
|
+
* `PolicyThrewError`. Unlike `PolicyReadUnrequestedOutputError`, the read property
|
|
158
|
+
* isn't restricted to a known list here -- `result.output.value`'s shape is whatever
|
|
159
|
+
* the external tool printed, entirely unknown to repo-contract -- so this match is
|
|
160
|
+
* necessarily a little broader. `cause` still holds the original `TypeError`
|
|
161
|
+
* verbatim; the message never repeats `result.output.error`'s own text, which may
|
|
162
|
+
* contain raw stdout content (see SECURITY.md).
|
|
163
|
+
*/
|
|
164
|
+
export declare class PolicyReadFailedParseValueError extends RepoContractError {
|
|
165
|
+
/** Always `"REPO_CONTRACT_POLICY_READ_FAILED_PARSE_VALUE"`. */
|
|
166
|
+
readonly code = "REPO_CONTRACT_POLICY_READ_FAILED_PARSE_VALUE";
|
|
167
|
+
/** The id of the check whose policy read `result.output.value` after a failed parse. */
|
|
168
|
+
readonly checkId: string;
|
|
169
|
+
constructor(checkId: string, property: string, cause: unknown);
|
|
170
|
+
}
|
|
171
|
+
export {};
|
|
172
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,8BAAsB,iBAAkB,SAAQ,KAAK;IACnD,kFAAkF;IAClF,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAC/B;AAED,+aAA+a;AAC/a,qBAAa,8BAA+B,SAAQ,iBAAiB;IACnE,+CAA+C;IAC/C,QAAQ,CAAC,IAAI,kCAAiC;gBAElC,MAAM,EAAE,MAAM;CAI3B;AAED,sPAAsP;AACtP,qBAAa,uBAAwB,SAAQ,iBAAiB;IAC5D,qDAAqD;IACrD,QAAQ,CAAC,IAAI,wCAAuC;IACpD,2DAA2D;IAC3D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;gBAEZ,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAK5C;AAED;;;;;GAKG;AACH,qBAAa,mBAAoB,SAAQ,iBAAiB;IACxD,iDAAiD;IACjD,QAAQ,CAAC,IAAI,oCAAmC;IAChD,2DAA2D;IAC3D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;gBAEZ,OAAO,EAAE,MAAM;CAO5B;AAED;;;;;;GAMG;AACH,qBAAa,4BAA6B,SAAQ,iBAAiB;IACjE,0DAA0D;IAC1D,QAAQ,CAAC,IAAI,6CAA4C;IACzD,0EAA0E;IAC1E,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,oEAAoE;IACpE,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;gBAEjB,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM;CAUlD;AAED,kPAAkP;AAClP,qBAAa,4BAA6B,SAAQ,iBAAiB;IACjE,0DAA0D;IAC1D,QAAQ,CAAC,IAAI,6CAA4C;IACzD,4DAA4D;IAC5D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,0FAA0F;IAC1F,QAAQ,CAAC,MAAM,EAAE,oBAAoB,CAAA;gBAEzB,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,oBAAoB,EAAE,KAAK,EAAE,OAAO;CAU1E;AAMD,KAAK,oBAAoB,GAAG,MAAM,CAAA;AAElC;;;;;;;;;GASG;AACH,qBAAa,gCAAiC,SAAQ,iBAAiB;IACrE,+DAA+D;IAC/D,QAAQ,CAAC,IAAI,kDAAiD;IAC9D,yEAAyE;IACzE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;gBAEZ,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO;CAQ5C;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,gBAAiB,SAAQ,iBAAiB;IACrD,6CAA6C;IAC7C,QAAQ,CAAC,IAAI,gCAA+B;IAC5C,0DAA0D;IAC1D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;gBAEZ,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO;CAK5C;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,gCAAiC,SAAQ,iBAAiB;IACrE,+DAA+D;IAC/D,QAAQ,CAAC,IAAI,kDAAiD;IAC9D,yFAAyF;IACzF,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;gBAEZ,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO;CAY9D;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,+BAAgC,SAAQ,iBAAiB;IACpE,+DAA+D;IAC/D,QAAQ,CAAC,IAAI,kDAAiD;IAC9D,wFAAwF;IACxF,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;gBAEZ,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO;CAU9D"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { CheckExecutionEntry } from "../execution/run-checks.js";
|
|
2
|
+
import type { CheckDefinition, CheckEvidence, Evidence } from "../types.js";
|
|
3
|
+
/** One check's id, its original definition, and its final evidence (parsed output attached, if requested) -- the parsed-output counterpart to `CheckExecutionEntry`, consumed directly by the policy phase so it never needs to look a check up by id either. */
|
|
4
|
+
export type ParsedCheckEntry = readonly [string, CheckDefinition, CheckEvidence];
|
|
5
|
+
interface BuiltEvidence {
|
|
6
|
+
readonly evidence: Evidence;
|
|
7
|
+
readonly entries: readonly ParsedCheckEntry[];
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Attaches parsed output (if requested) to every check's raw execution
|
|
11
|
+
* evidence and assembles the versioned, immutable `Evidence` object for the
|
|
12
|
+
* run as a whole. Also returns the same information as a flat entries array
|
|
13
|
+
* (see `ParsedCheckEntry`) for the policy phase to consume directly -- by
|
|
14
|
+
* the time this function returns, every check's evidence -- including every
|
|
15
|
+
* sibling check's -- is fully assembled; nothing here is generated lazily
|
|
16
|
+
* or streamed, which is what makes it safe for a policy to read the full
|
|
17
|
+
* `evidence` object, not just its own check's `result` (see
|
|
18
|
+
* specs/architecture.md).
|
|
19
|
+
* @param results - each check's id, definition, and raw execution evidence from the run phase
|
|
20
|
+
* @param startedAt - when the overall run began, recorded on the assembled `Evidence`
|
|
21
|
+
* @param completedAt - when the overall run finished, used with `startedAt` to compute the assembled `Evidence`'s `durationMs`
|
|
22
|
+
* @returns the assembled `Evidence` for the whole run, plus the same checks as a flat `ParsedCheckEntry` array for the policy phase
|
|
23
|
+
*/
|
|
24
|
+
export declare function buildEvidence(results: readonly CheckExecutionEntry[], startedAt: Date, completedAt: Date): Promise<BuiltEvidence>;
|
|
25
|
+
export {};
|
|
26
|
+
//# sourceMappingURL=build-evidence.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-evidence.d.ts","sourceRoot":"","sources":["../../../src/evidence/build-evidence.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAA;AAGrE,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAE3E,iQAAiQ;AACjQ,MAAM,MAAM,gBAAgB,GAAG,SAAS,CAAC,MAAM,EAAE,eAAe,EAAE,aAAa,CAAC,CAAA;AAIhF,UAAU,aAAa;IACrB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;IAC3B,QAAQ,CAAC,OAAO,EAAE,SAAS,gBAAgB,EAAE,CAAA;CAC9C;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,SAAS,mBAAmB,EAAE,EACvC,SAAS,EAAE,IAAI,EACf,WAAW,EAAE,IAAI,GAChB,OAAO,CAAC,aAAa,CAAC,CAgExB"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** The composed signal, and a `dispose` to release any resources this composition holds once it's no longer needed. */
|
|
2
|
+
interface ComposedSignal {
|
|
3
|
+
readonly signal: AbortSignal;
|
|
4
|
+
readonly dispose: () => void;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Combines multiple signals into one that aborts as soon as any input does.
|
|
8
|
+
* Prefers the native `AbortSignal.any()` where available; falls back to a
|
|
9
|
+
* manual composition for engines without it. `AbortSignal.any` landed in
|
|
10
|
+
* Node 20.3.0 -- genuinely newer than this package's `engines.node >=20.0.0`
|
|
11
|
+
* floor, so the fallback is live code for a real gap (a 20.0-20.2 patch
|
|
12
|
+
* release), not dead code kept out of caution.
|
|
13
|
+
*
|
|
14
|
+
* The native path's `dispose` is a no-op -- `AbortSignal.any` manages its own
|
|
15
|
+
* source-signal listeners internally and doesn't leak them. The manual
|
|
16
|
+
* fallback's `dispose` removes the "abort" listeners it added to each input
|
|
17
|
+
* `signal`; without calling it, a long-lived input (like a whole run's shared
|
|
18
|
+
* `AbortSignal`, composed fresh for every check the run spawns) would
|
|
19
|
+
* accumulate one permanent, never-removed listener per composed signal for
|
|
20
|
+
* the rest of its own lifetime, regardless of whether that particular
|
|
21
|
+
* composition ever actually needed to abort. Callers should call `dispose()`
|
|
22
|
+
* once the composed signal is no longer needed, whether or not it ever
|
|
23
|
+
* aborted.
|
|
24
|
+
* @param signals - the signals to combine; the composed signal aborts as soon as any one of them does
|
|
25
|
+
* @returns the composed signal (aborting with that input's abort reason as soon as any signal in `signals` aborts), and a `dispose` to release this composition's own resources
|
|
26
|
+
*/
|
|
27
|
+
export declare function composeSignals(signals: readonly AbortSignal[]): ComposedSignal;
|
|
28
|
+
export {};
|
|
29
|
+
//# sourceMappingURL=abort-signals.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"abort-signals.d.ts","sourceRoot":"","sources":["../../../src/execution/abort-signals.ts"],"names":[],"mappings":"AAAA,uHAAuH;AACvH,UAAU,cAAc;IACtB,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAA;CAC7B;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,GAAG,cAAc,CA4B9E"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runs `worker` over `items` with at most `concurrency` invocations in
|
|
3
|
+
* flight at once, preserving each result at its original index regardless
|
|
4
|
+
* of completion order. Has no knowledge of aborting, killing, or check
|
|
5
|
+
* evidence -- a pure, reusable bounded-parallelism primitive; abort-
|
|
6
|
+
* awareness lives entirely in the caller's `worker` function (see
|
|
7
|
+
* spawn-check.ts).
|
|
8
|
+
* @param items - the items to process, each passed to `worker` along with its index
|
|
9
|
+
* @param concurrency - the maximum number of `worker` calls allowed in flight at once
|
|
10
|
+
* @param worker - the async function run per item; its resolved value becomes that item's result
|
|
11
|
+
* @returns the results, one per item, in the same order as `items` regardless of completion order
|
|
12
|
+
*/
|
|
13
|
+
export declare function runWithConcurrency<T, R>(items: readonly T[], concurrency: number, worker: (item: T, index: number) => Promise<R>): Promise<R[]>;
|
|
14
|
+
//# sourceMappingURL=concurrency-pool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"concurrency-pool.d.ts","sourceRoot":"","sources":["../../../src/execution/concurrency-pool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,wBAAsB,kBAAkB,CAAC,CAAC,EAAE,CAAC,EAC3C,KAAK,EAAE,SAAS,CAAC,EAAE,EACnB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,GAC7C,OAAO,CAAC,CAAC,EAAE,CAAC,CA+Cd"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runs `worker` over `items` with at most `concurrency` invocations in
|
|
3
|
+
* flight at once, like `concurrency-pool.ts`'s `runWithConcurrency`, but
|
|
4
|
+
* additionally respecting a dependency graph: an item whose
|
|
5
|
+
* `dependencyIndexes` are non-empty is not started until every one of
|
|
6
|
+
* those indexes has settled. Has no knowledge of checks, evidence, or
|
|
7
|
+
* abort semantics -- a pure, reusable bounded-parallelism-plus-ordering
|
|
8
|
+
* primitive, kept in its own file rather than folded into
|
|
9
|
+
* `concurrency-pool.ts` so that file's simpler, more heavily-used flat
|
|
10
|
+
* primitive stays untouched.
|
|
11
|
+
*
|
|
12
|
+
* A reactive, event-driven scheduler (conceptually Kahn's algorithm run
|
|
13
|
+
* incrementally): a completing item immediately re-evaluates and unblocks
|
|
14
|
+
* its own dependents, with no artificial "wave" boundary -- a wave/layer
|
|
15
|
+
* design was considered and rejected because it would stall a dependent
|
|
16
|
+
* whose single dependency finished early behind an unrelated slow item
|
|
17
|
+
* sharing its layer, a real regression for a diamond or fan-out shape.
|
|
18
|
+
*
|
|
19
|
+
* The caller is responsible for ensuring `dependencyIndexes` describes an
|
|
20
|
+
* acyclic graph (see `validate-config.ts`'s cycle detection) -- this
|
|
21
|
+
* function's own stall guard below exists only as defense in depth against
|
|
22
|
+
* that invariant being violated, not as the primary means of catching it.
|
|
23
|
+
* @param items - the items to process, each passed to `worker` and `dependencyIndexes` along with its index
|
|
24
|
+
* @param concurrency - the maximum number of `worker` calls allowed in flight at once
|
|
25
|
+
* @param dependencyIndexes - given an item and its index, returns the indexes into `items` that must settle first
|
|
26
|
+
* @param worker - the async function run per item once its dependencies have settled; its resolved value becomes that item's result
|
|
27
|
+
* @returns the results, one per item, in the same order as `items` regardless of completion order
|
|
28
|
+
*/
|
|
29
|
+
export declare function runWithConcurrencyGraph<T, R>(items: readonly T[], concurrency: number, dependencyIndexes: (item: T, index: number) => readonly number[], worker: (item: T, index: number) => Promise<R>): Promise<R[]>;
|
|
30
|
+
//# sourceMappingURL=dependency-scheduler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dependency-scheduler.d.ts","sourceRoot":"","sources":["../../../src/execution/dependency-scheduler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAsB,uBAAuB,CAAC,CAAC,EAAE,CAAC,EAChD,KAAK,EAAE,SAAS,CAAC,EAAE,EACnB,WAAW,EAAE,MAAM,EACnB,iBAAiB,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,SAAS,MAAM,EAAE,EAChE,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,GAC7C,OAAO,CAAC,CAAC,EAAE,CAAC,CAsLd"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { SyncSpawner } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Whether a check's process should be spawned with `detached: true`. On
|
|
4
|
+
* POSIX this makes the spawned process the leader of a new process group
|
|
5
|
+
* (sharing its own pid as the group id), which is what lets `killTree`
|
|
6
|
+
* target the whole group rather than just the immediate child. On Windows,
|
|
7
|
+
* process groups work differently and `detached: true` would instead launch
|
|
8
|
+
* the process in its own console window -- not what's wanted here, since
|
|
9
|
+
* Windows cleanup goes through `taskkill /t` instead (see `killTree`).
|
|
10
|
+
* @returns true on POSIX (spawn as its own process group leader, killable via `killTree`); false on Windows
|
|
11
|
+
*/
|
|
12
|
+
export declare function shouldSpawnDetached(): boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Best-effort termination of an entire process tree rooted at `pid`, not
|
|
15
|
+
* just the immediate process -- necessary because a check's command is
|
|
16
|
+
* often itself a wrapper (`npm run test` spawns `npm`, which spawns the
|
|
17
|
+
* actual test runner), and killing only the wrapper would orphan its
|
|
18
|
+
* descendants. `spawn`'s own `timeout`/`signal` options only ever affect the
|
|
19
|
+
* directly spawned process, never its descendants, which is why this exists
|
|
20
|
+
* as a separate utility rather than relying on those.
|
|
21
|
+
*
|
|
22
|
+
* On POSIX, sends `signal` to the whole process group via the negative-pid
|
|
23
|
+
* convention (requires the process to have been spawned with
|
|
24
|
+
* `detached: true`, see `shouldSpawnDetached`) -- no process spawning
|
|
25
|
+
* required, a single syscall via `process.kill`. On Windows, process groups
|
|
26
|
+
* don't work the same way, so this shells out to `taskkill /pid <pid> /t
|
|
27
|
+
* /f` -- the same technique the `tree-kill` package uses internally -- which
|
|
28
|
+
* walks the system process table for descendants of `pid` regardless of how
|
|
29
|
+
* it was spawned; that requires a synchronous spawn, which -- like every
|
|
30
|
+
* other process-spawning capability in this package -- is a trusted
|
|
31
|
+
* capability the caller supplies (`killProcessTree`, threaded from
|
|
32
|
+
* `RepoContractConfig.killProcessTree`), never imported internally (see
|
|
33
|
+
* specs/decisions/0011-process-spawning-and-ambient-environment-access-are-consumer-supplied-capabilities-not-package-owned.md).
|
|
34
|
+
* When `killProcessTree` is omitted on Windows, this function is a
|
|
35
|
+
* documented no-op -- the caller (`spawn-check.ts`) falls back to
|
|
36
|
+
* terminating just the tracked child process handle directly, which needs
|
|
37
|
+
* no spawn at all.
|
|
38
|
+
*
|
|
39
|
+
* Swallows the expected best-effort-cleanup failures, but not every failure: a
|
|
40
|
+
* process that has already exited (POSIX `ESRCH`, or `taskkill`'s "not found"
|
|
41
|
+
* case) is a no-op, and a POSIX `EPERM` permission error is swallowed the same
|
|
42
|
+
* way -- by the time cleanup runs the process may well have exited on its own,
|
|
43
|
+
* and a failed cleanup should not crash the run. Any *other* failure is
|
|
44
|
+
* rethrown: an unexpected POSIX errno, or (on Windows) a JS-level spawn failure
|
|
45
|
+
* of `taskkill` itself (`result.error`, e.g. the tool missing from PATH), which
|
|
46
|
+
* would otherwise silently leave an orphaned process tree behind.
|
|
47
|
+
*
|
|
48
|
+
* On Windows this always runs `taskkill` with `/f` regardless of which `signal` was requested --
|
|
49
|
+
* not a partial implementation of POSIX's cooperative-SIGTERM-then-SIGKILL escalation, but a
|
|
50
|
+
* reflection of a real platform difference: Windows has no signal-delivery mechanism for an
|
|
51
|
+
* arbitrary process tree by pid at all (this is also why Node's own `ChildProcess.kill()` treats
|
|
52
|
+
* every signal identically on Windows, per Node's own child_process documentation), so there is no
|
|
53
|
+
* more-cooperative alternative to fall back to here the way there is on POSIX.
|
|
54
|
+
* @param pid - the pid of the tree's root process (the process group id on POSIX, since it was spawned detached)
|
|
55
|
+
* @param signal - the POSIX signal to send (on Windows, ignored -- see doc comment above)
|
|
56
|
+
* @param killProcessTree - the consumer-supplied synchronous spawner used only on Windows; a no-op there when omitted (see doc comment above)
|
|
57
|
+
*/
|
|
58
|
+
export declare function killTree(pid: number, signal: NodeJS.Signals, killProcessTree?: SyncSpawner): void;
|
|
59
|
+
//# sourceMappingURL=process-tree.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process-tree.d.ts","sourceRoot":"","sources":["../../../src/execution/process-tree.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAE9C;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,IAAI,OAAO,CAE7C;AAWD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,EAAE,eAAe,CAAC,EAAE,WAAW,GAAG,IAAI,CAoDjG"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { CheckDefinition, CheckEvidence, CheckSchema, RunRepoContractOptions } from "../types.js";
|
|
2
|
+
import type { ExecutionCapability } from "./spawn-check.js";
|
|
3
|
+
/**
|
|
4
|
+
* One check's id, its original definition, and its raw execution evidence,
|
|
5
|
+
* threaded together as a triple rather than three separately-keyed maps --
|
|
6
|
+
* every later stage (parsing, policy evaluation) consumes this directly
|
|
7
|
+
* instead of re-looking a check up by id, which under `noUncheckedIndexedAccess`
|
|
8
|
+
* would otherwise force handling an "undefined" case that can't actually
|
|
9
|
+
* happen (every checkId here comes from the same `Object.entries(checks)`
|
|
10
|
+
* that produced it).
|
|
11
|
+
*/
|
|
12
|
+
export type CheckExecutionEntry = readonly [string, CheckDefinition, CheckEvidence];
|
|
13
|
+
export declare const SELF_TERMINATE_DELAY_MS: number;
|
|
14
|
+
/**
|
|
15
|
+
* Executes every resolved check with at most `concurrency` running at once,
|
|
16
|
+
* returning each check's raw evidence keyed by check id. For a full run
|
|
17
|
+
* (`options.checks` omitted), every configured check id is resolved and
|
|
18
|
+
* therefore appears in the result exactly once, regardless of whether it
|
|
19
|
+
* ever actually spawned (see spawnCheck's documentation for the pre-aborted
|
|
20
|
+
* case). When `options.checks` restricts execution to a subset, only the
|
|
21
|
+
* requested ids and their transitive `dependsOn` are resolved (see
|
|
22
|
+
* `resolveCheckDependencies` above) -- every other configured check id is
|
|
23
|
+
* simply absent from the result, not present with some placeholder value.
|
|
24
|
+
* @param checks - the full set of configured checks, keyed by id
|
|
25
|
+
* @param concurrency - the maximum number of checks to run in parallel at once
|
|
26
|
+
* @param execution - the run's trusted execution capabilities (`spawn`, `env`, resolved global `shell` default), forwarded to every `spawnCheck` call
|
|
27
|
+
* @param options - run options; `options.checks` restricts execution to those ids (plus their dependencies), `options.signal` cancels the whole run
|
|
28
|
+
* @returns each executed check's id, definition, and raw evidence, one entry per resolved check regardless of whether it actually spawned
|
|
29
|
+
*/
|
|
30
|
+
export declare function runChecks(checks: CheckSchema, concurrency: number, execution: ExecutionCapability, options?: RunRepoContractOptions): Promise<readonly CheckExecutionEntry[]>;
|
|
31
|
+
//# sourceMappingURL=run-checks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-checks.d.ts","sourceRoot":"","sources":["../../../src/execution/run-checks.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,eAAe,EACf,aAAa,EACb,WAAW,EACX,sBAAsB,EACvB,MAAM,aAAa,CAAA;AAIpB,OAAO,KAAK,EAAqB,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AAG9E;;;;;;;;GAQG;AACH,MAAM,MAAM,mBAAmB,GAAG,SAAS,CAAC,MAAM,EAAE,eAAe,EAAE,aAAa,CAAC,CAAA;AAYnF,eAAO,MAAM,uBAAuB,QAAgC,CAAA;AAoJpE;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,SAAS,CAC7B,MAAM,EAAE,WAAW,EACnB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,mBAAmB,EAC9B,OAAO,CAAC,EAAE,sBAAsB,GAC/B,OAAO,CAAC,SAAS,mBAAmB,EAAE,CAAC,CAkJzC"}
|