@avi2dg/checks 0.31.0 → 0.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/README.md +6 -3
- package/dist/readability/index.js +18 -9
- package/docs/configs/commit-messages.md +5 -0
- package/docs/configs/typescript-rules.md +1 -1
- package/docs/design.md +42 -4
- package/docs/gates/checks-commit-identity.md +3 -0
- package/docs/gates/checks-docs.md +9 -3
- package/docs/gates/checks-lint.md +1 -1
- package/docs/gates/checks-mutation.md +2 -1
- package/docs/gates/checks-release-notes.md +10 -1
- package/docs/gates/checks-release-pr.md +185 -0
- package/docs/gates/checks-release-report.md +4 -2
- package/docs/gates/checks-release-tag.md +63 -0
- package/docs/gates/checks-secrets.md +93 -0
- package/docs/gates/checks-vendor.md +3 -3
- package/package.json +23 -6
- package/src/core/gates.ts +1 -0
- package/src/core/git.ts +1 -1
- package/src/core/lint.ts +1 -1
- package/src/delivery/commit-identity.ts +17 -1
- package/src/delivery/github.ts +38 -0
- package/src/delivery/gitleaks.toml +113 -0
- package/src/delivery/gitleaks.ts +111 -0
- package/src/delivery/release-pr.ts +196 -0
- package/src/delivery/release-report.ts +3 -30
- package/src/delivery/release-tag.ts +64 -0
- package/src/delivery/release.ts +79 -0
- package/src/delivery/secrets.ts +86 -0
- package/src/dependencies/osv-scanner.ts +3 -45
- package/src/dependencies/pinned-binary.ts +80 -0
- package/src/docs/doc-agents.ts +22 -20
- package/src/docs/doc-names.ts +1 -1
- package/src/docs/doc-references.ts +14 -7
- package/src/docs/docs.ts +15 -2
- package/src/docs/prose-matchers.ts +1 -1
- package/src/docs/sentence-length.ts +106 -0
- package/src/testing/flake.ts +1 -1
- package/src/testing/mutation.ts +1 -1
- package/src/testing/test.ts +1 -1
package/src/docs/doc-agents.ts
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
|
+
import { Parser, type NodeType } from "commonmark";
|
|
1
2
|
import { commandNames, type Snapshot } from "./doc-references.ts";
|
|
2
3
|
import { AGENT_NAMES, scanMarkdown, type MarkdownLine } from "./prose-matchers.ts";
|
|
3
4
|
|
|
4
5
|
export const AGENT_CEILING = 3000;
|
|
5
6
|
|
|
6
|
-
const LIST_ITEM = /^(?:\s*>)*\s*(?:[-*+]|\d{1,9}[.)])(?:\s|$)/;
|
|
7
|
-
const INDENT = /^[ \t]*/;
|
|
8
|
-
const CODE_INDENT = 4;
|
|
9
7
|
const INLINE_LINK =
|
|
10
8
|
/(?<![!\\])\[(?:[^[\]\\]|\\.|\[[^\]]*\])*\]\(\s*(?:<[^<>\n]+>|[^\s()<>]+(?:\([^\s()]*\)[^\s()<>]*)*)(?:\s+(?:"[^"]*"|'[^']*'))?\s*\)/g;
|
|
11
9
|
const MAINTAINING = /^\s{0,3}#{1,6}\s+Maintaining this file(?:\s+#+)?\s*$/;
|
|
@@ -27,8 +25,24 @@ export function ceilingFinding(text: string): AgentFinding | undefined {
|
|
|
27
25
|
};
|
|
28
26
|
}
|
|
29
27
|
|
|
28
|
+
function blockStarts(lines: readonly MarkdownLine[], type: NodeType): ReadonlySet<number> {
|
|
29
|
+
const read = lines.map(({ kind, raw }) => (kind === "front-matter" ? "" : raw)).join("\n");
|
|
30
|
+
const walker = new Parser().parse(read).walker();
|
|
31
|
+
const starts = new Set<number>();
|
|
32
|
+
for (let step = walker.next(); step !== null; step = walker.next()) {
|
|
33
|
+
if (step.entering && step.node.type === type) starts.add(step.node.sourcepos[0][0]);
|
|
34
|
+
}
|
|
35
|
+
return starts;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function linesOpening(text: string, type: NodeType): readonly MarkdownLine[] {
|
|
39
|
+
const lines = scanMarkdown(text);
|
|
40
|
+
const starts = blockStarts(lines, type);
|
|
41
|
+
return lines.filter(({ line }) => starts.has(line)).flatMap(({ line, raw }) => scanMarkdown(raw).map((alone) => ({ ...alone, line })));
|
|
42
|
+
}
|
|
43
|
+
|
|
30
44
|
export function maintainingFinding(text: string): AgentFinding | undefined {
|
|
31
|
-
const heading =
|
|
45
|
+
const heading = linesOpening(text, "heading").find(({ raw }) => MAINTAINING.test(raw));
|
|
32
46
|
if (heading === undefined) return undefined;
|
|
33
47
|
return {
|
|
34
48
|
line: heading.line,
|
|
@@ -36,27 +50,14 @@ export function maintainingFinding(text: string): AgentFinding | undefined {
|
|
|
36
50
|
};
|
|
37
51
|
}
|
|
38
52
|
|
|
39
|
-
function indentOf(raw: string): number {
|
|
40
|
-
return (INDENT.exec(raw)?.[0] ?? "").replaceAll("\t", " ").length;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
53
|
export function entries(text: string): readonly MarkdownLine[] {
|
|
44
|
-
|
|
45
|
-
let afterBlank = true;
|
|
46
|
-
return scanMarkdown(text).filter((line) => {
|
|
47
|
-
const blank = line.raw.trim() === "";
|
|
48
|
-
const indented = !blank && indentOf(line.raw) >= CODE_INDENT && !line.raw.trimStart().startsWith(">");
|
|
49
|
-
const listItem = line.kind === "prose" && LIST_ITEM.test(line.prose) && (inList || !indented);
|
|
50
|
-
if (listItem) inList = true;
|
|
51
|
-
else if (!blank && !indented && (afterBlank || line.kind !== "prose")) inList = false;
|
|
52
|
-
afterBlank = blank;
|
|
53
|
-
return listItem;
|
|
54
|
-
});
|
|
54
|
+
return linesOpening(text, "item");
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
type Tracked = Pick<Snapshot, "files" | "directories">;
|
|
58
58
|
|
|
59
59
|
const STAYS = new Set(["", "."]);
|
|
60
|
+
const NAMES_A_SEGMENT = /[^/]/;
|
|
60
61
|
|
|
61
62
|
function joined(directory: string, segment: string): string {
|
|
62
63
|
return directory === "" ? segment : `${directory}/${segment}`;
|
|
@@ -76,10 +77,11 @@ function resolvesFrom(directory: string, span: string, tracked: Tracked): boolea
|
|
|
76
77
|
if (walked === undefined) return false;
|
|
77
78
|
if (!STAYS.has(last) && last !== ".." && tracked.files.has(joined(walked, last))) return true;
|
|
78
79
|
const end = enter(walked, last, tracked);
|
|
79
|
-
return end !== undefined && end !== ""
|
|
80
|
+
return end !== undefined && end !== "";
|
|
80
81
|
}
|
|
81
82
|
|
|
82
83
|
function namesTrackedPath(agentFile: string, span: string, tracked: Tracked): boolean {
|
|
84
|
+
if (!NAMES_A_SEGMENT.test(span)) return false;
|
|
83
85
|
const directory = agentFile.includes("/") ? agentFile.slice(0, agentFile.lastIndexOf("/")) : "";
|
|
84
86
|
const fromFile = resolvesFrom(directory, span, tracked);
|
|
85
87
|
return fromFile || (!span.startsWith("./") && !span.startsWith("../") && resolvesFrom("", span, tracked));
|
package/src/docs/doc-names.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Effect, FileSystem, Option, Path, Schema } from "effect";
|
|
2
|
-
import { ChildProcessSpawner } from "effect/
|
|
2
|
+
import { ChildProcessSpawner } from "effect/process";
|
|
3
3
|
import { collect, git, pathsAt } from "../core/git.ts";
|
|
4
4
|
import type { Unresolved } from "./doc-references.ts";
|
|
5
5
|
import { scanMarkdown } from "./prose-matchers.ts";
|
|
@@ -78,20 +78,28 @@ function unresolvedPath(doc: string, line: number, span: string, snapshot: Snaps
|
|
|
78
78
|
const SCHEME = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;
|
|
79
79
|
const ASCII_ESCAPE = /%([0-7][0-9a-f])/gi;
|
|
80
80
|
|
|
81
|
+
function linkPath(doc: string, target: string, hash: number): string | undefined {
|
|
82
|
+
const written = (hash < 0 ? target : target.slice(0, hash)).split("?", 1)[0] ?? "";
|
|
83
|
+
const decoded = written.replace(ASCII_ESCAPE, (_, code: string) => String.fromCharCode(Number.parseInt(code, 16)));
|
|
84
|
+
return decoded === "" ? doc : decoded.startsWith("/") ? normalize(decoded) : within(directoryOf(doc), decoded);
|
|
85
|
+
}
|
|
86
|
+
|
|
81
87
|
function unresolvedLink(doc: string, line: number, target: string, snapshot: Snapshot): Unresolved | undefined {
|
|
82
88
|
if (target === "" || SCHEME.test(target)) return undefined;
|
|
83
89
|
const hash = target.indexOf("#");
|
|
84
|
-
const
|
|
85
|
-
const decoded = written.replace(ASCII_ESCAPE, (_, code: string) => String.fromCharCode(Number.parseInt(code, 16)));
|
|
86
|
-
const path = decoded === "" ? doc : decoded.startsWith("/") ? normalize(decoded) : within(directoryOf(doc), decoded);
|
|
90
|
+
const path = linkPath(doc, target, hash);
|
|
87
91
|
if (path === undefined) return undefined;
|
|
88
92
|
const named = target;
|
|
89
93
|
if (!exists(snapshot, path)) {
|
|
90
94
|
return { kind: "link", line, named, message: `links to \`${named}\`, which is not in the repository`, missing: { type: "file", path } };
|
|
91
95
|
}
|
|
92
96
|
const anchor = hash < 0 ? "" : target.slice(hash + 1);
|
|
97
|
+
if (anchor === "") return undefined;
|
|
93
98
|
const anchors = snapshot.anchors.get(path);
|
|
94
|
-
if (
|
|
99
|
+
if (anchors === undefined) {
|
|
100
|
+
return { kind: "link", line, named, message: `links to \`${named}\`, and \`${path}\` has no headings to check`, missing: { type: "anchor" } };
|
|
101
|
+
}
|
|
102
|
+
if (anchors.has(anchor) || anchors.has(anchor.toLowerCase())) return undefined;
|
|
95
103
|
return { kind: "link", line, named, message: `links to \`${named}\`, and \`${path}\` has no heading with that anchor`, missing: { type: "anchor" } };
|
|
96
104
|
}
|
|
97
105
|
|
|
@@ -152,9 +160,8 @@ export function anchoredTargets(doc: string, text: string): readonly string[] {
|
|
|
152
160
|
links.flatMap((target) => {
|
|
153
161
|
const hash = target.indexOf("#");
|
|
154
162
|
if (hash < 0 || SCHEME.test(target)) return [];
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
return path?.endsWith(".md") === true ? [path] : [];
|
|
163
|
+
const path = linkPath(doc, target, hash);
|
|
164
|
+
return path !== undefined && (path.endsWith(".md") || path.endsWith(".mdx")) ? [path] : [];
|
|
158
165
|
}),
|
|
159
166
|
);
|
|
160
167
|
}
|
package/src/docs/docs.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { readTexts, snapshotAt, stillMissing } from "./doc-snapshot.ts";
|
|
|
8
8
|
import { changedLines, changedPaths, git, pathsAt, rangeEnds, refArgs } from "../core/git.ts";
|
|
9
9
|
import { runMain } from "../core/main.ts";
|
|
10
10
|
import { proseFindings, readerOf } from "./prose-matchers.ts";
|
|
11
|
+
import { longSentences } from "./sentence-length.ts";
|
|
11
12
|
|
|
12
13
|
type Finding = {
|
|
13
14
|
readonly path: string;
|
|
@@ -22,6 +23,7 @@ type Judged = {
|
|
|
22
23
|
readonly agents: number;
|
|
23
24
|
readonly findings: readonly Finding[];
|
|
24
25
|
readonly advisory: ReadonlyMap<string, number>;
|
|
26
|
+
readonly sentenceAdvisory: readonly Finding[];
|
|
25
27
|
readonly brokenBefore: readonly Finding[];
|
|
26
28
|
};
|
|
27
29
|
|
|
@@ -105,6 +107,9 @@ const runDocs = Effect.fn("runDocs")(function* (root: string, base: string, head
|
|
|
105
107
|
const prose = edited.flatMap(({ path, reader }) =>
|
|
106
108
|
proseFindings(text(path), reader, changed.get(path)).map(({ line, message }) => ({ path, line, message })),
|
|
107
109
|
);
|
|
110
|
+
const sentenceAdvisory = edited
|
|
111
|
+
.flatMap(({ path }) => longSentences(text(path), changed.get(path)).map(({ line, message }) => ({ path, line, message })))
|
|
112
|
+
.toSorted(inPathOrder);
|
|
108
113
|
const judging = (path: string): Judging => ({ commands: !speaksToConsumers(text(path)) });
|
|
109
114
|
// A directory the range deletes still belongs to this repository, so a path under it is stale rather than another repository's.
|
|
110
115
|
const roots = rootsOf(yield* pathsAt(base, [], root));
|
|
@@ -133,6 +138,7 @@ const runDocs = Effect.fn("runDocs")(function* (root: string, base: string, head
|
|
|
133
138
|
...entries,
|
|
134
139
|
].toSorted(inPathOrder),
|
|
135
140
|
advisory,
|
|
141
|
+
sentenceAdvisory,
|
|
136
142
|
brokenBefore: references.brokenBefore.toSorted(inPathOrder),
|
|
137
143
|
} satisfies Judged;
|
|
138
144
|
});
|
|
@@ -141,7 +147,7 @@ function describe({ path, line, message }: Finding): string {
|
|
|
141
147
|
return ` ${path}${line === undefined ? "" : `:${line}`}: ${message}`;
|
|
142
148
|
}
|
|
143
149
|
|
|
144
|
-
export function report({ held, edited, named, agents, findings, advisory, brokenBefore }: Judged): string {
|
|
150
|
+
export function report({ held, edited, named, agents, findings, advisory, sentenceAdvisory, brokenBefore }: Judged): string {
|
|
145
151
|
const verdict =
|
|
146
152
|
findings.length === 0
|
|
147
153
|
? [
|
|
@@ -158,6 +164,13 @@ export function report({ held, edited, named, agents, findings, advisory, broken
|
|
|
158
164
|
`${NAME}: advisory, ${advisory.size} doc file(s) the range leaves alone do not hold to their templates yet:`,
|
|
159
165
|
...[...advisory].map(([path, count]) => ` ${path}: ${count} violation(s)`),
|
|
160
166
|
];
|
|
167
|
+
const sentences =
|
|
168
|
+
sentenceAdvisory.length === 0
|
|
169
|
+
? []
|
|
170
|
+
: [
|
|
171
|
+
`${NAME}: advisory, ${sentenceAdvisory.length} sentence(s) over the trial length caps:`,
|
|
172
|
+
...sentenceAdvisory.map(describe),
|
|
173
|
+
];
|
|
161
174
|
const broken =
|
|
162
175
|
brokenBefore.length === 0
|
|
163
176
|
? []
|
|
@@ -165,7 +178,7 @@ export function report({ held, edited, named, agents, findings, advisory, broken
|
|
|
165
178
|
`${NAME}: advisory, ${brokenBefore.length} path(s), link(s) or command(s) the living docs or agent files name were broken before the range:`,
|
|
166
179
|
...brokenBefore.map(describe),
|
|
167
180
|
];
|
|
168
|
-
return [...verdict, ...unconformed, ...broken].join("\n");
|
|
181
|
+
return [...verdict, ...unconformed, ...sentences, ...broken].join("\n");
|
|
169
182
|
}
|
|
170
183
|
|
|
171
184
|
const docs = Effect.gen(function* () {
|
|
@@ -243,7 +243,7 @@ export function scanMarkdown(text: string): readonly MarkdownLine[] {
|
|
|
243
243
|
|
|
244
244
|
const LEADING_MARKERS = /^(?:\s*>)*\s*(?:#{1,6}\s+|(?:[-*+]|\d{1,9}[.)])\s+(?:\[[ xX]\]\s+)?)?/;
|
|
245
245
|
|
|
246
|
-
function bodyOf({ prose }: MarkdownLine): string {
|
|
246
|
+
export function bodyOf({ prose }: MarkdownLine): string {
|
|
247
247
|
const markers = LEADING_MARKERS.exec(prose)?.[0] ?? "";
|
|
248
248
|
return BLANK.repeat(markers.length) + prose.slice(markers.length);
|
|
249
249
|
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { bodyOf, scanMarkdown } from "./prose-matchers.ts";
|
|
2
|
+
|
|
3
|
+
export const PROCEDURAL_WORD_CAP = 20;
|
|
4
|
+
export const DESCRIPTIVE_WORD_CAP = 25;
|
|
5
|
+
|
|
6
|
+
export type SentenceKind = "procedural" | "descriptive";
|
|
7
|
+
|
|
8
|
+
export type SentenceLength = {
|
|
9
|
+
readonly line: number;
|
|
10
|
+
readonly words: number;
|
|
11
|
+
readonly kind: SentenceKind;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export type LongSentence = SentenceLength & {
|
|
15
|
+
readonly message: string;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
function graphemesOf(body: string): readonly string[] {
|
|
19
|
+
return [...new Intl.Segmenter().segment(body)].map(({ segment }) => segment);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function dropPrefix(raw: string): string {
|
|
23
|
+
const chars = graphemesOf(raw);
|
|
24
|
+
for (const [at, char] of chars.entries()) {
|
|
25
|
+
if (char !== " " && char !== "\t" && char !== ">") return chars.slice(at).join("");
|
|
26
|
+
}
|
|
27
|
+
return "";
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function orderedAt(raw: string): boolean {
|
|
31
|
+
const rest = dropPrefix(raw);
|
|
32
|
+
const digits = /^\d+/.exec(rest)?.[0] ?? "";
|
|
33
|
+
if (digits === "") return false;
|
|
34
|
+
const marker = rest.charAt(digits.length);
|
|
35
|
+
if (marker !== "." && marker !== ")") return false;
|
|
36
|
+
const after = rest.charAt(digits.length + 1);
|
|
37
|
+
return after === " " || after === "\t" || after === "";
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function isWordChar(char: string): boolean {
|
|
41
|
+
return (char >= "0" && char <= "9") || (char >= "A" && char <= "Z") || (char >= "a" && char <= "z");
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function wordsIn(sentence: string): number {
|
|
45
|
+
let words = 0;
|
|
46
|
+
let inToken = false;
|
|
47
|
+
let holdsWordChar = false;
|
|
48
|
+
for (const char of sentence) {
|
|
49
|
+
if (char === " " || char === "\t") {
|
|
50
|
+
if (inToken && holdsWordChar) words += 1;
|
|
51
|
+
inToken = false;
|
|
52
|
+
holdsWordChar = false;
|
|
53
|
+
} else {
|
|
54
|
+
inToken = true;
|
|
55
|
+
if (isWordChar(char)) holdsWordChar = true;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return inToken && holdsWordChar ? words + 1 : words;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function isCloser(char: string): boolean {
|
|
62
|
+
return char === '"' || char === "'" || char === ")" || char === "]" || char === "*" || char === "_" || char === "”" || char === "’";
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function sentencesIn(body: string): readonly string[] {
|
|
66
|
+
const chars = graphemesOf(body);
|
|
67
|
+
const sentences: string[] = [];
|
|
68
|
+
let start = 0;
|
|
69
|
+
let cut = -1;
|
|
70
|
+
for (const [at, char] of chars.entries()) {
|
|
71
|
+
if (char === "." || char === "!" || char === "?") cut = at + 1;
|
|
72
|
+
else if (cut === at && isCloser(char)) cut = at + 1;
|
|
73
|
+
else if (cut > start && (char === " " || char === "\t")) {
|
|
74
|
+
sentences.push(chars.slice(start, cut).join(""));
|
|
75
|
+
start = cut;
|
|
76
|
+
cut = -1;
|
|
77
|
+
} else if (cut > start) cut = -1;
|
|
78
|
+
}
|
|
79
|
+
if (cut === chars.length && cut > start) {
|
|
80
|
+
sentences.push(chars.slice(start, cut).join(""));
|
|
81
|
+
start = cut;
|
|
82
|
+
}
|
|
83
|
+
const tail = chars.slice(start).join("");
|
|
84
|
+
if (tail.trim() !== "") sentences.push(tail);
|
|
85
|
+
return sentences;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function sentenceLengths(text: string, within?: ReadonlySet<number>): readonly SentenceLength[] {
|
|
89
|
+
return scanMarkdown(text).flatMap((line) => {
|
|
90
|
+
if (line.kind !== "prose" || (within !== undefined && !within.has(line.line))) return [];
|
|
91
|
+
const kind: SentenceKind = orderedAt(line.raw) ? "procedural" : "descriptive";
|
|
92
|
+
return sentencesIn(bodyOf(line)).map((sentence) => ({ line: line.line, words: wordsIn(sentence), kind }));
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function longSentences(text: string, within?: ReadonlySet<number>): readonly LongSentence[] {
|
|
97
|
+
return sentenceLengths(text, within).flatMap(({ line, words, kind }) => {
|
|
98
|
+
const cap = kind === "procedural" ? PROCEDURAL_WORD_CAP : DESCRIPTIVE_WORD_CAP;
|
|
99
|
+
if (words <= cap) return [];
|
|
100
|
+
const rule =
|
|
101
|
+
kind === "procedural"
|
|
102
|
+
? `procedural means an ordered list item; descriptive caps at ${DESCRIPTIVE_WORD_CAP} words`
|
|
103
|
+
: `procedural means an ordered list item, capped at ${PROCEDURAL_WORD_CAP} words`;
|
|
104
|
+
return [{ line, words, kind, message: `carries a ${words}-word ${kind} sentence, over the ${cap}-word cap (${rule})` }];
|
|
105
|
+
});
|
|
106
|
+
}
|
package/src/testing/flake.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
import { Config, Console, Effect, FileSystem, Option, Path, Random, Schema } from "effect";
|
|
3
|
-
import { ChildProcess, ChildProcessSpawner } from "effect/
|
|
3
|
+
import { ChildProcess, ChildProcessSpawner } from "effect/process";
|
|
4
4
|
import { runMain, Usage } from "../core/main.ts";
|
|
5
5
|
import { NAME_SEPARATOR, parseReport, ReportError, reporterArgs, type TestResult } from "./test-report.ts";
|
|
6
6
|
|
package/src/testing/mutation.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
import { Config, Effect, Schema } from "effect";
|
|
3
|
-
import { ChildProcess, ChildProcessSpawner } from "effect/
|
|
3
|
+
import { ChildProcess, ChildProcessSpawner } from "effect/process";
|
|
4
4
|
import { runMain } from "../core/main.ts";
|
|
5
5
|
import { fullRunRefusal } from "./mutation-scope.js";
|
|
6
6
|
|
package/src/testing/test.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
import { Config, Console, Effect, FileSystem, Path, Schema } from "effect";
|
|
3
|
-
import { ChildProcess, ChildProcessSpawner } from "effect/
|
|
3
|
+
import { ChildProcess, ChildProcessSpawner } from "effect/process";
|
|
4
4
|
import { TEST_ENTRY_POINT } from "../core/gates.ts";
|
|
5
5
|
import { runMain, Usage } from "../core/main.ts";
|
|
6
6
|
import { readSkipDeclarations, type Environment, type SkipDeclaration, type TestTier } from "./test-skips.ts";
|