vouchington-tooling 0.0.21 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -0
- package/dist/browser-session-runner/attempt.d.mts +2 -0
- package/dist/browser-session-runner/attempt.mjs +195 -0
- package/dist/browser-session-runner/index.d.mts +4 -0
- package/dist/browser-session-runner/index.mjs +64 -0
- package/dist/browser-session-runner/process-group.d.mts +5 -0
- package/dist/browser-session-runner/process-group.mjs +23 -0
- package/dist/browser-session-runner/result.d.mts +2 -0
- package/dist/browser-session-runner/result.mjs +11 -0
- package/dist/browser-session-runner/tail-queue.d.mts +8 -0
- package/dist/browser-session-runner/tail-queue.mjs +30 -0
- package/dist/browser-session-runner/tail.d.mts +1 -0
- package/dist/browser-session-runner/tail.mjs +12 -0
- package/dist/browser-session-runner/types.d.mts +53 -0
- package/dist/browser-session-runner/types.mjs +1 -0
- package/dist/cli/commands/retrospective-transcript.d.mts +1 -0
- package/dist/cli/commands/retrospective-transcript.mjs +31 -0
- package/dist/cli/index.mjs +3 -0
- package/dist/cli/parse.d.mts +3 -0
- package/dist/cli/parse.mjs +2 -0
- package/dist/cli/usage.d.mts +1 -1
- package/dist/cli/usage.mjs +2 -0
- package/dist/coverage-transport/outcome.mjs +3 -1
- package/dist/index.d.mts +6 -0
- package/dist/index.mjs +3 -0
- package/dist/retrospective-transcript/claude.d.mts +2 -0
- package/dist/retrospective-transcript/claude.mjs +67 -0
- package/dist/retrospective-transcript/codex.d.mts +11 -0
- package/dist/retrospective-transcript/codex.mjs +174 -0
- package/dist/retrospective-transcript/format.d.mts +4 -0
- package/dist/retrospective-transcript/format.mjs +22 -0
- package/dist/retrospective-transcript/index.d.mts +22 -0
- package/dist/retrospective-transcript/index.mjs +151 -0
- package/dist/retrospective-transcript/javascript-command.d.mts +1 -0
- package/dist/retrospective-transcript/javascript-command.mjs +25 -0
- package/dist/retrospective-transcript/shared.d.mts +31 -0
- package/dist/retrospective-transcript/shared.mjs +213 -0
- package/dist/vitest-diagnostics/directory.d.mts +12 -0
- package/dist/vitest-diagnostics/directory.mjs +44 -0
- package/dist/vitest-diagnostics/index.d.mts +22 -0
- package/dist/vitest-diagnostics/index.mjs +123 -0
- package/dist/vitest-diagnostics/read-file.d.mts +2 -0
- package/dist/vitest-diagnostics/read-file.mjs +37 -0
- package/package.json +16 -1
package/README.md
CHANGED
|
@@ -37,6 +37,7 @@ vouchington run-with-timeout 120 10 docker push example
|
|
|
37
37
|
vouchington lint-links --offline
|
|
38
38
|
vouchington materialize-pr-context
|
|
39
39
|
vouchington wait-for-apt-locks
|
|
40
|
+
vouchington retrospective-transcript --jsonl /path/to/transcript.jsonl
|
|
40
41
|
vouchington install-playwright-chromium-arm64
|
|
41
42
|
vouchington ghcr-package-retention example%2Fapi
|
|
42
43
|
vouchington nuget-central-version trusted.props candidate.props metadata.json out.props
|
|
@@ -45,6 +46,12 @@ vouchington post-review
|
|
|
45
46
|
vouchington stage-review-payload optional|required <source> <destination>
|
|
46
47
|
```
|
|
47
48
|
|
|
49
|
+
`retrospective-transcript` discovers Codex and Claude transcripts by default. It also reads a
|
|
50
|
+
Claude-compatible transcript when `CURSOR_SESSION_ID` is set, and Grok's `updates.jsonl` session
|
|
51
|
+
layout when `GROK_SESSION_ID` is set. Use `--grok-sessions-dir` to point discovery at a nondefault
|
|
52
|
+
Grok session root. Without `--session-id`, it reads those session identities from the host
|
|
53
|
+
environment.
|
|
54
|
+
|
|
48
55
|
Host-lock environment:
|
|
49
56
|
|
|
50
57
|
| Variable | Default | Meaning |
|
|
@@ -83,6 +90,7 @@ import {
|
|
|
83
90
|
import { createArtifactClassifier, runCleanup } from 'vouchington-tooling/gha-artifacts-cleanup'
|
|
84
91
|
import { validateOptionalHttpOrigin } from 'vouchington-tooling/http-origin'
|
|
85
92
|
import { boundPendingLine, splitCompleteLines } from 'vouchington-tooling/process-line-buffer'
|
|
93
|
+
import { runBrowserSession } from 'vouchington-tooling/browser-session-runner'
|
|
86
94
|
import {
|
|
87
95
|
generateSchemaSnapshot,
|
|
88
96
|
renderSchemaMarkdown,
|
|
@@ -111,8 +119,28 @@ import { validateNugetUpdate } from 'vouchington-tooling/nuget-central-version'
|
|
|
111
119
|
import { normalizeSwiftSource } from 'vouchington-tooling/swift-semantic-equal'
|
|
112
120
|
import { parseUniqueSwiftBinaryTargetChecksum } from 'vouchington-tooling/swift-source-offset'
|
|
113
121
|
import { validateResolvedPinDelta } from 'vouchington-tooling/swift-resolved-pin-delta'
|
|
122
|
+
import {
|
|
123
|
+
formatDiagnosticReportSummaries,
|
|
124
|
+
readDiagnosticReportSummaries,
|
|
125
|
+
} from 'vouchington-tooling/vitest-diagnostics'
|
|
126
|
+
import { runRetrospectiveTranscript } from 'vouchington-tooling/retrospective-transcript'
|
|
114
127
|
```
|
|
115
128
|
|
|
116
129
|
The artifact, review-payload, HTTP body, and pagination APIs validate untrusted inputs at their
|
|
117
130
|
boundaries. Review posting lives in `gha-post-review` and talks to GitHub only through caller-supplied
|
|
118
131
|
credentials (job token or a minted Claude GitHub App token).
|
|
132
|
+
|
|
133
|
+
`vitest-diagnostics` reads Node diagnostic report JSON from a caller-selected directory. It sorts
|
|
134
|
+
filenames, tolerates partial files, returns only a bounded field allowlist, and never emits raw
|
|
135
|
+
native frame symbols. Both structured reads and text rendering have hard report-count limits.
|
|
136
|
+
|
|
137
|
+
`browser-session-runner` supervises caller-created browser-test processes. Callers supply command
|
|
138
|
+
construction, line classification, retry/outcome policy, and budgets; the library owns process-group
|
|
139
|
+
termination, output line buffering, shared deadlines, progress watchdogs, diagnostics, and parent signals.
|
|
140
|
+
The returned process must identify a dedicated process group, such as a child spawned with
|
|
141
|
+
`detached: true`; its `processGroupId` is signalled without assuming the child PID is a group ID.
|
|
142
|
+
Stall exits use the caller's `classifyExit` policy, while parent signals and shared-deadline expiration
|
|
143
|
+
are terminal. Output is decoded independently per stream; unfinished lines are classified at close and
|
|
144
|
+
`diagnosticTailBytes` retains a UTF-8-safe tail no larger than its byte budget.
|
|
145
|
+
The runner uses monotonic elapsed time, rejects timer budgets above Node's maximum delay, and waits for
|
|
146
|
+
the dedicated process group to exit after the direct child closes so descendants cannot overlap a retry.
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { StringDecoder } from 'node:string_decoder';
|
|
2
|
+
import { boundPendingLine, splitCompleteLines } from '../process-line-buffer/index.mjs';
|
|
3
|
+
import { tailText } from './tail.mjs';
|
|
4
|
+
import { TailQueue } from './tail-queue.mjs';
|
|
5
|
+
export function runAttempt(options, deps, deadline, attempt) {
|
|
6
|
+
return new Promise((resolve, reject) => {
|
|
7
|
+
const startedAt = deps.now(), process = options.start(attempt);
|
|
8
|
+
if (!Number.isSafeInteger(process.processGroupId) ||
|
|
9
|
+
process.processGroupId <= 0 ||
|
|
10
|
+
process.processGroupId > 2_147_483_647) {
|
|
11
|
+
try {
|
|
12
|
+
process.kill('SIGKILL');
|
|
13
|
+
}
|
|
14
|
+
catch { }
|
|
15
|
+
throw new RangeError('processGroupId must be positive');
|
|
16
|
+
}
|
|
17
|
+
const maxTail = options.diagnosticTailBytes ?? 4096;
|
|
18
|
+
const drainTimeoutMs = options.graceMs + (options.processGroupDrainMs ?? options.graceMs);
|
|
19
|
+
const tail = new TailQueue(maxTail);
|
|
20
|
+
let startupProgress = false, semanticProgress = false;
|
|
21
|
+
let failure, hasFailure = false, childExited = false, closeExit, draining = false, drainDone = false, reason = 'exit', complete = false, terminating = false;
|
|
22
|
+
let killTimer, stallTimer;
|
|
23
|
+
const listeners = [];
|
|
24
|
+
const finish = (exit) => {
|
|
25
|
+
if (complete)
|
|
26
|
+
return;
|
|
27
|
+
complete = true;
|
|
28
|
+
deps.clearTimeout(deadlineTimer);
|
|
29
|
+
if (killTimer)
|
|
30
|
+
deps.clearTimeout(killTimer);
|
|
31
|
+
deps.clearTimeout(stallTimer);
|
|
32
|
+
for (const remove of listeners)
|
|
33
|
+
remove();
|
|
34
|
+
const result = {
|
|
35
|
+
attempts: 0,
|
|
36
|
+
deadlineExceeded: reason === 'deadline',
|
|
37
|
+
diagnosticTail: tailText(tail.toBuffer(), maxTail),
|
|
38
|
+
exit,
|
|
39
|
+
reason,
|
|
40
|
+
semanticProgress,
|
|
41
|
+
startupProgress,
|
|
42
|
+
};
|
|
43
|
+
if (hasFailure)
|
|
44
|
+
reject(failure);
|
|
45
|
+
else
|
|
46
|
+
resolve(result);
|
|
47
|
+
};
|
|
48
|
+
const signal = (value) => {
|
|
49
|
+
try {
|
|
50
|
+
deps.killProcessGroup(process.processGroupId, value);
|
|
51
|
+
}
|
|
52
|
+
catch { }
|
|
53
|
+
try {
|
|
54
|
+
process.kill(value);
|
|
55
|
+
}
|
|
56
|
+
catch { }
|
|
57
|
+
};
|
|
58
|
+
const terminate = (nextReason) => {
|
|
59
|
+
if (nextReason === 'deadline' && childExited && reason === 'exit')
|
|
60
|
+
return;
|
|
61
|
+
if (nextReason === 'parent-signal' || nextReason === 'deadline') {
|
|
62
|
+
if (reason === 'exit' || reason === 'startup-stall' || reason === 'semantic-stall')
|
|
63
|
+
reason = nextReason;
|
|
64
|
+
else if (reason !== nextReason)
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
else if (reason !== 'exit')
|
|
68
|
+
return;
|
|
69
|
+
else if (nextReason !== 'exit')
|
|
70
|
+
reason = nextReason;
|
|
71
|
+
if (terminating)
|
|
72
|
+
return;
|
|
73
|
+
terminating = true;
|
|
74
|
+
killTimer = deps.setTimeout(() => {
|
|
75
|
+
if (deps.isProcessGroupAlive(process.processGroupId))
|
|
76
|
+
signal('SIGKILL');
|
|
77
|
+
}, options.graceMs);
|
|
78
|
+
signal('SIGTERM');
|
|
79
|
+
};
|
|
80
|
+
const fail = (error) => {
|
|
81
|
+
if (hasFailure)
|
|
82
|
+
return;
|
|
83
|
+
failure = error;
|
|
84
|
+
hasFailure = true;
|
|
85
|
+
terminate('exit');
|
|
86
|
+
};
|
|
87
|
+
const drain = () => {
|
|
88
|
+
if (draining)
|
|
89
|
+
return;
|
|
90
|
+
draining = true;
|
|
91
|
+
void deps.waitForProcessGroupExit(process.processGroupId, drainTimeoutMs).then(() => {
|
|
92
|
+
drainDone = true;
|
|
93
|
+
if (closeExit)
|
|
94
|
+
finish(closeExit);
|
|
95
|
+
}, (error) => {
|
|
96
|
+
fail(error);
|
|
97
|
+
finish(closeExit ?? { code: null, signal: null });
|
|
98
|
+
});
|
|
99
|
+
};
|
|
100
|
+
const armStall = (ms, nextReason) => {
|
|
101
|
+
if (stallTimer)
|
|
102
|
+
deps.clearTimeout(stallTimer);
|
|
103
|
+
stallTimer = deps.setTimeout(() => terminate(nextReason), ms);
|
|
104
|
+
};
|
|
105
|
+
const consume = () => {
|
|
106
|
+
const decoder = new StringDecoder('utf8');
|
|
107
|
+
let pending = '';
|
|
108
|
+
const line = (value) => {
|
|
109
|
+
const event = options.onLine(value);
|
|
110
|
+
if (event === 'startup' && !startupProgress) {
|
|
111
|
+
startupProgress = true;
|
|
112
|
+
if (!childExited)
|
|
113
|
+
armStall(options.semanticStallMs, 'semantic-stall');
|
|
114
|
+
}
|
|
115
|
+
if (event === 'semantic') {
|
|
116
|
+
semanticProgress = true;
|
|
117
|
+
if (startupProgress && !childExited)
|
|
118
|
+
armStall(options.semanticStallMs, 'semantic-stall');
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
const appendLines = (text) => {
|
|
122
|
+
tail.append(text);
|
|
123
|
+
const split = splitCompleteLines(pending + text);
|
|
124
|
+
pending = boundPendingLine(split.pending);
|
|
125
|
+
for (const value of split.complete)
|
|
126
|
+
line(value);
|
|
127
|
+
};
|
|
128
|
+
return {
|
|
129
|
+
flush: () => {
|
|
130
|
+
appendLines(decoder.end());
|
|
131
|
+
if (pending)
|
|
132
|
+
line(pending);
|
|
133
|
+
},
|
|
134
|
+
write: (chunk) => appendLines(decoder.write(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk))),
|
|
135
|
+
};
|
|
136
|
+
};
|
|
137
|
+
const streams = [process.stdout, process.stderr].map((stream) => stream ? consume() : undefined);
|
|
138
|
+
for (const [index, stream] of [process.stdout, process.stderr].entries())
|
|
139
|
+
stream?.on('data', (chunk) => {
|
|
140
|
+
try {
|
|
141
|
+
streams[index].write(chunk);
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
fail(error);
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
for (const stream of [process.stdout, process.stderr])
|
|
148
|
+
stream?.on('error', fail);
|
|
149
|
+
const remainingDeadlineMs = deadline - deps.now();
|
|
150
|
+
const deadlineTimer = deps.setTimeout(() => terminate('deadline'), Math.max(1, remainingDeadlineMs));
|
|
151
|
+
const remainingStartupMs = options.startupStallMs - (deps.now() - startedAt);
|
|
152
|
+
armStall(Math.max(1, remainingStartupMs), 'startup-stall');
|
|
153
|
+
if (remainingStartupMs <= 0)
|
|
154
|
+
terminate('startup-stall');
|
|
155
|
+
if (remainingDeadlineMs <= 0)
|
|
156
|
+
terminate('deadline');
|
|
157
|
+
for (const value of ['SIGINT', 'SIGTERM']) {
|
|
158
|
+
const listener = () => terminate('parent-signal');
|
|
159
|
+
deps.onParentSignal(value, listener);
|
|
160
|
+
listeners.push(() => deps.offParentSignal(value, listener));
|
|
161
|
+
}
|
|
162
|
+
process.on('error', () => terminate('exit'));
|
|
163
|
+
process.on('exit', () => {
|
|
164
|
+
if (reason === 'exit' && deps.now() >= deadline)
|
|
165
|
+
reason = 'deadline';
|
|
166
|
+
childExited = true;
|
|
167
|
+
deps.clearTimeout(stallTimer);
|
|
168
|
+
if (!deps.isProcessGroupAlive(process.processGroupId))
|
|
169
|
+
return;
|
|
170
|
+
terminate(reason);
|
|
171
|
+
drain();
|
|
172
|
+
});
|
|
173
|
+
process.on('close', (code, value) => {
|
|
174
|
+
for (const stream of streams)
|
|
175
|
+
try {
|
|
176
|
+
stream?.flush();
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
fail(error);
|
|
180
|
+
}
|
|
181
|
+
if (!childExited &&
|
|
182
|
+
deps.now() >= deadline &&
|
|
183
|
+
reason !== 'parent-signal' &&
|
|
184
|
+
reason !== 'deadline')
|
|
185
|
+
reason = 'deadline';
|
|
186
|
+
closeExit = { code, signal: value };
|
|
187
|
+
if (!deps.isProcessGroupAlive(process.processGroupId))
|
|
188
|
+
return finish(closeExit);
|
|
189
|
+
terminate(reason);
|
|
190
|
+
drain();
|
|
191
|
+
if (drainDone || hasFailure)
|
|
192
|
+
finish(closeExit);
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { BrowserSessionDeps, BrowserSessionOptions, BrowserSessionResult } from './types.mts';
|
|
2
|
+
export type { BrowserSessionDeps, BrowserSessionEvent, BrowserSessionExit, BrowserSessionOptions, BrowserSessionProcess, BrowserSessionResult, } from './types.mts';
|
|
3
|
+
export { ProcessGroupDrainTimeoutError } from './process-group.mts';
|
|
4
|
+
export declare function runBrowserSession(options: BrowserSessionOptions, deps?: BrowserSessionDeps): Promise<BrowserSessionResult>;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { runAttempt } from './attempt.mjs';
|
|
2
|
+
import { expiredResult } from './result.mjs';
|
|
3
|
+
import { isProcessGroupAlive, waitForProcessGroupExit } from './process-group.mjs';
|
|
4
|
+
export { ProcessGroupDrainTimeoutError } from './process-group.mjs';
|
|
5
|
+
const defaultDeps = {
|
|
6
|
+
clearInterval,
|
|
7
|
+
clearTimeout,
|
|
8
|
+
isProcessGroupAlive,
|
|
9
|
+
killProcessGroup: (processGroupId, signal) => {
|
|
10
|
+
try {
|
|
11
|
+
process.kill(-processGroupId, signal);
|
|
12
|
+
}
|
|
13
|
+
catch (error) {
|
|
14
|
+
if (error.code !== 'ESRCH')
|
|
15
|
+
throw error;
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
now: () => performance.now(),
|
|
19
|
+
offParentSignal: (signal, listener) => process.off(signal, listener),
|
|
20
|
+
onParentSignal: (signal, listener) => process.on(signal, listener),
|
|
21
|
+
setInterval,
|
|
22
|
+
setTimeout,
|
|
23
|
+
waitForProcessGroupExit,
|
|
24
|
+
};
|
|
25
|
+
export async function runBrowserSession(options, deps = defaultDeps) {
|
|
26
|
+
validateOptions(options);
|
|
27
|
+
if (deps === defaultDeps && process.platform === 'win32')
|
|
28
|
+
throw new Error('browser-session-runner default process-group control is unsupported on Windows');
|
|
29
|
+
const deadline = deps.now() + options.deadlineMs;
|
|
30
|
+
let last;
|
|
31
|
+
let attempts = 0;
|
|
32
|
+
for (let attempt = 1; attempt <= options.attempts && deps.now() < deadline; attempt += 1) {
|
|
33
|
+
attempts = attempt;
|
|
34
|
+
last = await runAttempt(options, deps, deadline, attempt);
|
|
35
|
+
if (last.reason === 'parent-signal' ||
|
|
36
|
+
last.reason === 'deadline' ||
|
|
37
|
+
options.classifyExit(last.exit, omitAttempts(last)) !== 'retry')
|
|
38
|
+
return { ...last, attempts };
|
|
39
|
+
}
|
|
40
|
+
if (attempts === options.attempts)
|
|
41
|
+
return { ...last, attempts };
|
|
42
|
+
return { ...(last ?? expiredResult()), attempts, deadlineExceeded: true, reason: 'deadline' };
|
|
43
|
+
}
|
|
44
|
+
function validateOptions(options) {
|
|
45
|
+
const maxTimerDelay = 2_147_483_647;
|
|
46
|
+
for (const [name, value] of [
|
|
47
|
+
['attempts', options.attempts],
|
|
48
|
+
['deadlineMs', options.deadlineMs],
|
|
49
|
+
['graceMs', options.graceMs],
|
|
50
|
+
['processGroupDrainMs', options.processGroupDrainMs ?? options.graceMs],
|
|
51
|
+
['semanticStallMs', options.semanticStallMs],
|
|
52
|
+
['startupStallMs', options.startupStallMs],
|
|
53
|
+
['watchdogIntervalMs', options.watchdogIntervalMs ?? 1000],
|
|
54
|
+
]) {
|
|
55
|
+
if (!Number.isSafeInteger(value) || value <= 0 || value > maxTimerDelay)
|
|
56
|
+
throw new RangeError(`${name} must be a positive Node timer delay`);
|
|
57
|
+
}
|
|
58
|
+
const tailBytes = options.diagnosticTailBytes ?? 4096;
|
|
59
|
+
if (!Number.isSafeInteger(tailBytes) || tailBytes <= 0)
|
|
60
|
+
throw new RangeError('diagnosticTailBytes must be positive');
|
|
61
|
+
}
|
|
62
|
+
function omitAttempts({ attempts: _attempts, ...result }) {
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare class ProcessGroupDrainTimeoutError extends Error {
|
|
2
|
+
constructor(processGroupId: number, timeoutMs: number);
|
|
3
|
+
}
|
|
4
|
+
export declare function isProcessGroupAlive(processGroupId: number): boolean;
|
|
5
|
+
export declare function waitForProcessGroupExit(processGroupId: number, timeoutMs: number): Promise<void>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export class ProcessGroupDrainTimeoutError extends Error {
|
|
2
|
+
constructor(processGroupId, timeoutMs) {
|
|
3
|
+
super(`Process group ${processGroupId} did not exit within ${timeoutMs}ms after SIGKILL`);
|
|
4
|
+
this.name = 'ProcessGroupDrainTimeoutError';
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
export function isProcessGroupAlive(processGroupId) {
|
|
8
|
+
try {
|
|
9
|
+
process.kill(-processGroupId, 0);
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
return error.code !== 'ESRCH';
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export async function waitForProcessGroupExit(processGroupId, timeoutMs) {
|
|
17
|
+
const deadline = performance.now() + timeoutMs;
|
|
18
|
+
while (isProcessGroupAlive(processGroupId)) {
|
|
19
|
+
if (performance.now() >= deadline)
|
|
20
|
+
throw new ProcessGroupDrainTimeoutError(processGroupId, timeoutMs);
|
|
21
|
+
await new Promise((resolve) => setTimeout(resolve, Math.min(10, deadline - performance.now())));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export class TailQueue {
|
|
2
|
+
maxBytes;
|
|
3
|
+
chunks = [];
|
|
4
|
+
bytes = 0;
|
|
5
|
+
constructor(maxBytes) {
|
|
6
|
+
this.maxBytes = maxBytes;
|
|
7
|
+
}
|
|
8
|
+
append(text) {
|
|
9
|
+
const chunk = Buffer.from(text);
|
|
10
|
+
if (chunk.length >= this.maxBytes) {
|
|
11
|
+
this.chunks.splice(0, this.chunks.length, chunk.subarray(-this.maxBytes));
|
|
12
|
+
this.bytes = this.maxBytes;
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
this.chunks.push(chunk);
|
|
16
|
+
this.bytes += chunk.length;
|
|
17
|
+
while (this.bytes > this.maxBytes) {
|
|
18
|
+
const first = this.chunks[0];
|
|
19
|
+
const overflow = this.bytes - this.maxBytes;
|
|
20
|
+
if (first.length <= overflow)
|
|
21
|
+
this.chunks.shift();
|
|
22
|
+
else
|
|
23
|
+
this.chunks[0] = first.subarray(overflow);
|
|
24
|
+
this.bytes -= Math.min(first.length, overflow);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
toBuffer() {
|
|
28
|
+
return Buffer.concat(this.chunks, this.bytes);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function tailText(tail: Buffer, maxBytes: number): string;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export function tailText(tail, maxBytes) {
|
|
2
|
+
const bounded = tail.subarray(Math.max(0, tail.length - maxBytes));
|
|
3
|
+
for (let start = 0; start < Math.min(4, bounded.length); start += 1) {
|
|
4
|
+
for (let end = 0; end < Math.min(4, bounded.length - start); end += 1) {
|
|
5
|
+
try {
|
|
6
|
+
return new TextDecoder('utf-8', { fatal: true }).decode(bounded.subarray(start, bounded.length - end));
|
|
7
|
+
}
|
|
8
|
+
catch { }
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
return '';
|
|
12
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { ChildProcess } from 'node:child_process';
|
|
2
|
+
export type BrowserSessionEvent = 'startup' | 'semantic';
|
|
3
|
+
export type BrowserSessionExit = {
|
|
4
|
+
code: number | null;
|
|
5
|
+
signal: NodeJS.Signals | null;
|
|
6
|
+
};
|
|
7
|
+
type BrowserSessionStream = {
|
|
8
|
+
on(event: 'data', listener: (chunk: string | Buffer) => void): unknown;
|
|
9
|
+
on(event: 'error', listener: (error: Error) => void): unknown;
|
|
10
|
+
};
|
|
11
|
+
export type BrowserSessionResult = {
|
|
12
|
+
attempts: number;
|
|
13
|
+
deadlineExceeded: boolean;
|
|
14
|
+
diagnosticTail: string;
|
|
15
|
+
exit: BrowserSessionExit;
|
|
16
|
+
reason: 'exit' | 'parent-signal' | 'semantic-stall' | 'startup-stall' | 'deadline';
|
|
17
|
+
startupProgress: boolean;
|
|
18
|
+
semanticProgress: boolean;
|
|
19
|
+
};
|
|
20
|
+
export type BrowserSessionProcess = Pick<ChildProcess, 'kill'> & {
|
|
21
|
+
processGroupId: number;
|
|
22
|
+
on(event: 'close', listener: (code: number | null, signal: NodeJS.Signals | null) => void): unknown;
|
|
23
|
+
on(event: 'error', listener: (error: Error) => void): unknown;
|
|
24
|
+
on(event: 'exit', listener: (code: number | null, signal: NodeJS.Signals | null) => void): unknown;
|
|
25
|
+
stderr?: BrowserSessionStream | null;
|
|
26
|
+
stdout?: BrowserSessionStream | null;
|
|
27
|
+
};
|
|
28
|
+
export type BrowserSessionDeps = {
|
|
29
|
+
clearInterval(handle: unknown): void;
|
|
30
|
+
clearTimeout(handle: unknown): void;
|
|
31
|
+
isProcessGroupAlive(processGroupId: number): boolean;
|
|
32
|
+
killProcessGroup(processGroupId: number, signal: NodeJS.Signals): void;
|
|
33
|
+
now(): number;
|
|
34
|
+
offParentSignal(signal: NodeJS.Signals, listener: () => void): void;
|
|
35
|
+
onParentSignal(signal: NodeJS.Signals, listener: () => void): void;
|
|
36
|
+
setInterval(callback: () => void, ms: number): unknown;
|
|
37
|
+
setTimeout(callback: () => void, ms: number): unknown;
|
|
38
|
+
waitForProcessGroupExit(processGroupId: number, timeoutMs: number): Promise<void>;
|
|
39
|
+
};
|
|
40
|
+
export type BrowserSessionOptions = {
|
|
41
|
+
attempts: number;
|
|
42
|
+
classifyExit(exit: BrowserSessionExit, result: Omit<BrowserSessionResult, 'attempts'>): 'retry' | 'return';
|
|
43
|
+
deadlineMs: number;
|
|
44
|
+
diagnosticTailBytes?: number;
|
|
45
|
+
graceMs: number;
|
|
46
|
+
onLine(line: string): BrowserSessionEvent | undefined;
|
|
47
|
+
processGroupDrainMs?: number;
|
|
48
|
+
semanticStallMs: number;
|
|
49
|
+
start(attempt: number): BrowserSessionProcess;
|
|
50
|
+
startupStallMs: number;
|
|
51
|
+
watchdogIntervalMs?: number;
|
|
52
|
+
};
|
|
53
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runRetrospectiveTranscriptCommand(args: string[]): Promise<number>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { parseArgs } from 'node:util';
|
|
2
|
+
import { runRetrospectiveTranscript, } from '../../retrospective-transcript/index.mjs';
|
|
3
|
+
export async function runRetrospectiveTranscriptCommand(args) {
|
|
4
|
+
try {
|
|
5
|
+
const { values } = parseArgs({
|
|
6
|
+
args,
|
|
7
|
+
strict: true,
|
|
8
|
+
options: {
|
|
9
|
+
'session-id': { type: 'string' },
|
|
10
|
+
jsonl: { type: 'string' },
|
|
11
|
+
'projects-dir': { type: 'string' },
|
|
12
|
+
'codex-sessions-dir': { type: 'string' },
|
|
13
|
+
'grok-sessions-dir': { type: 'string' },
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
const options = {
|
|
17
|
+
...(values['session-id'] ? { sessionId: values['session-id'] } : {}),
|
|
18
|
+
...(values.jsonl ? { jsonlPath: values.jsonl } : {}),
|
|
19
|
+
...(values['projects-dir'] ? { projectsDir: values['projects-dir'] } : {}),
|
|
20
|
+
...(values['codex-sessions-dir'] ? { codexSessionsDir: values['codex-sessions-dir'] } : {}),
|
|
21
|
+
...(values['grok-sessions-dir'] ? { grokSessionsDir: values['grok-sessions-dir'] } : {}),
|
|
22
|
+
env: process.env,
|
|
23
|
+
};
|
|
24
|
+
process.stdout.write(await runRetrospectiveTranscript(options));
|
|
25
|
+
return 0;
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
29
|
+
return 2;
|
|
30
|
+
}
|
|
31
|
+
}
|
package/dist/cli/index.mjs
CHANGED
|
@@ -14,6 +14,7 @@ import { runPostReviewCommand } from './commands/post-review.mjs';
|
|
|
14
14
|
import { runStageReviewPayloadCommand } from './commands/stage-review-payload.mjs';
|
|
15
15
|
import { runSwiftSemanticEqualCommand } from './commands/swift-semantic-equal.mjs';
|
|
16
16
|
import { runVitestBlobManifestCommand } from './commands/vitest-blob-manifest.mjs';
|
|
17
|
+
import { runRetrospectiveTranscriptCommand } from './commands/retrospective-transcript.mjs';
|
|
17
18
|
import { runWithHostLock } from './commands/with-host-lock.mjs';
|
|
18
19
|
import { parseCli } from './parse.mjs';
|
|
19
20
|
import { packageScriptPath } from './script-path.mjs';
|
|
@@ -92,6 +93,8 @@ export function runCli(argv = process.argv) {
|
|
|
92
93
|
return runHttpOrigin(parsed.field, parsed.value);
|
|
93
94
|
case 'gha-artifacts-cleanup':
|
|
94
95
|
return runGhaArtifactsCleanup(parsed);
|
|
96
|
+
case 'retrospective-transcript':
|
|
97
|
+
return runRetrospectiveTranscriptCommand(parsed.args);
|
|
95
98
|
}
|
|
96
99
|
}
|
|
97
100
|
function readInstalledVersion() {
|
package/dist/cli/parse.d.mts
CHANGED
|
@@ -40,6 +40,9 @@ export type ParsedCli = {
|
|
|
40
40
|
kind: 'http-origin';
|
|
41
41
|
field: string;
|
|
42
42
|
value: string;
|
|
43
|
+
} | {
|
|
44
|
+
kind: 'retrospective-transcript';
|
|
45
|
+
args: string[];
|
|
43
46
|
} | ParsedGhaRuntimeAudit | ParsedGhaArtifactsCleanup;
|
|
44
47
|
export type ScriptCommand = 'gha-output' | 'gha-needs-results' | 'download-with-diagnostics' | 'host-pressure-diagnostics' | 'allocate-browser-safe-ports' | 'diagnose-port-collision' | 'prepare-trivy-db' | 'check-cache-size' | 'make-shard-matrix' | 'load-runner-env' | 'clean-workspace' | 'install-github-release' | 'run-with-timeout' | 'lint-links' | 'materialize-pr-context' | 'wait-for-apt-locks' | 'install-playwright-chromium-arm64' | 'ghcr-package-retention';
|
|
45
48
|
export declare function parseCli(argv: readonly string[]): ParsedCli;
|
package/dist/cli/parse.mjs
CHANGED
|
@@ -47,6 +47,8 @@ export function parseCli(argv) {
|
|
|
47
47
|
return { kind: 'stage-review-payload', args: rest };
|
|
48
48
|
if (command === 'http-origin')
|
|
49
49
|
return parseHttpOrigin(rest);
|
|
50
|
+
if (command === 'retrospective-transcript')
|
|
51
|
+
return { kind: 'retrospective-transcript', args: rest };
|
|
50
52
|
if (command === 'gha-artifacts-cleanup')
|
|
51
53
|
return parseGhaArtifactsCleanup(rest);
|
|
52
54
|
if (command !== undefined && SCRIPT_COMMANDS.has(command)) {
|
package/dist/cli/usage.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const USAGE = "Usage: vouchington <command> [options]\n\nCommands:\n runner-port-policy Print or validate a runner port policy\n with-host-lock Run a command under a host-wide lock\n gha-runtime-audit Audit successful GitHub Actions job runtimes\n gha-output Write a collision-safe multiline GITHUB_OUTPUT record\n gha-needs-results Fail if required GitHub Actions job results failed\n download-with-diagnostics Download a URL and report HTTP status on failure\n host-pressure-diagnostics Print a bounded host memory/OOM/PSI snapshot\n allocate-browser-safe-ports Allocate Fetch-safe localhost ports\n diagnose-port-collision Capture bounded localhost port diagnostics\n prepare-trivy-db Download the Trivy vulnerability database\n gha-artifacts-cleanup Delete classified GitHub Actions artifacts\n http-origin Validate an optional HTTP(S) origin\n vitest-blob-manifest Stamp a vitest-blob-manifest:v1 identity file\n pnpm-install Install a pnpm workspace with retry and release-age fail-fast\n check-cache-size Measure a path and decide whether to save a GHA cache\n make-shard-matrix Emit a [1..N] GitHub Actions shard matrix\n load-runner-env Overlay a runner env file onto GITHUB_ENV with injection guards\n clean-workspace Reset a persistent-runner workspace with a fork-PR trust gate\n install-github-release Download a checksum-verified GitHub Release binary\n run-with-timeout Run a command with GNU timeout or a Perl fallback\n lint-links Two-pass lychee: internal links fail, external warn\n materialize-pr-context Dump PR title/body/files/diff/comments and #N crawl\n wait-for-apt-locks Wait until apt/dpkg lock files are free\n install-playwright-chromium-arm64 Install Playwright Chromium from browsers.json\n ghcr-package-retention Delete old GHCR package versions past KEEP_MIN\n nuget-central-version Validate a Directory.Packages.props PackageVersion delta\n swift-semantic-equal Compare Swift sources ignoring comments and whitespace\n post-review Post one COMMENT review from a staged payload file\n stage-review-payload Validate a review payload file into a staging directory\n\nOptions:\n -h, --help Show this help\n -v, --version Print the package version\n\nrunner-port-policy\n (no args) Print the shipped policy as JSON\n --file <path> Validate and print a policy file\n --reserved <port> Print true if the port is reserved\n\nwith-host-lock\n --name <family>\n [--slots <n>]\n --timeout-seconds <n>\n [--command-timeout-seconds <n>]\n [--failure-diagnostics <absolute-script>]\n [--on-acquire-timeout fail|run-unlocked]\n -- <command> [args...]\n\ngha-runtime-audit\n [--repository owner/name] Default GITHUB_REPOSITORY\n [--branch main]\n --pr-workflow <name|/regex/> Repeatable\n --push-workflow <name|/regex/> Repeatable\n\ngha-output <name>\ngha-needs-results [label]\ndownload-with-diagnostics <url> <destination> [-- curl-args...]\nhost-pressure-diagnostics\nallocate-browser-safe-ports [count] [--policy path] [--forbidden-ports path]\ndiagnose-port-collision [--ports \"2200 2216\"] [--output-dir PATH]\nprepare-trivy-db\ngha-artifacts-cleanup run --run-id <id> [--keep-pattern glob] [--delete-pattern glob] [--patterns-file json]\ngha-artifacts-cleanup sweep --older-than-hours <n> [--keep-pattern glob] [--delete-pattern glob] [--patterns-file json]\nhttp-origin [--field NAME] [value]\nvitest-blob-manifest <suite> [reports-directory]\npnpm-install --runner-lifecycle persistent|ephemeral|ephemeral-full --install-scripts true|false\ncheck-cache-size <path> <max-bytes> <label>\nmake-shard-matrix <total>\nload-runner-env\nclean-workspace\ninstall-github-release --repo owner/name --version X --asset 'name-{platform}.tar.gz' --bin name [--tag-prefix PREFIX] [--no-checksum] [--checksums-asset NAME] [--version-flag FLAG] [--bin-dir DIR]\nrun-with-timeout <timeout-seconds> <kill-after-seconds> <command...>\nlint-links [--offline] [--config PATH] [--glob PATTERN] [files...]\nmaterialize-pr-context\nwait-for-apt-locks\ninstall-playwright-chromium-arm64 [name:archive...]\nghcr-package-retention <url-encoded-package>...\nnuget-central-version <trusted-props> <candidate-props> <metadata-json> <output-props>\nswift-semantic-equal <base> <head> <file.swift>\npost-review\nstage-review-payload optional|required <source> <destination>\n";
|
|
1
|
+
export declare const USAGE = "Usage: vouchington <command> [options]\n\nCommands:\n runner-port-policy Print or validate a runner port policy\n with-host-lock Run a command under a host-wide lock\n gha-runtime-audit Audit successful GitHub Actions job runtimes\n gha-output Write a collision-safe multiline GITHUB_OUTPUT record\n gha-needs-results Fail if required GitHub Actions job results failed\n download-with-diagnostics Download a URL and report HTTP status on failure\n host-pressure-diagnostics Print a bounded host memory/OOM/PSI snapshot\n allocate-browser-safe-ports Allocate Fetch-safe localhost ports\n diagnose-port-collision Capture bounded localhost port diagnostics\n prepare-trivy-db Download the Trivy vulnerability database\n gha-artifacts-cleanup Delete classified GitHub Actions artifacts\n http-origin Validate an optional HTTP(S) origin\n vitest-blob-manifest Stamp a vitest-blob-manifest:v1 identity file\n pnpm-install Install a pnpm workspace with retry and release-age fail-fast\n check-cache-size Measure a path and decide whether to save a GHA cache\n make-shard-matrix Emit a [1..N] GitHub Actions shard matrix\n load-runner-env Overlay a runner env file onto GITHUB_ENV with injection guards\n clean-workspace Reset a persistent-runner workspace with a fork-PR trust gate\n install-github-release Download a checksum-verified GitHub Release binary\n run-with-timeout Run a command with GNU timeout or a Perl fallback\n lint-links Two-pass lychee: internal links fail, external warn\n materialize-pr-context Dump PR title/body/files/diff/comments and #N crawl\n wait-for-apt-locks Wait until apt/dpkg lock files are free\n install-playwright-chromium-arm64 Install Playwright Chromium from browsers.json\n ghcr-package-retention Delete old GHCR package versions past KEEP_MIN\n nuget-central-version Validate a Directory.Packages.props PackageVersion delta\n swift-semantic-equal Compare Swift sources ignoring comments and whitespace\n post-review Post one COMMENT review from a staged payload file\n stage-review-payload Validate a review payload file into a staging directory\n retrospective-transcript Format facts from Claude-compatible, Codex, or Grok transcripts\n\nOptions:\n -h, --help Show this help\n -v, --version Print the package version\n\nrunner-port-policy\n (no args) Print the shipped policy as JSON\n --file <path> Validate and print a policy file\n --reserved <port> Print true if the port is reserved\n\nwith-host-lock\n --name <family>\n [--slots <n>]\n --timeout-seconds <n>\n [--command-timeout-seconds <n>]\n [--failure-diagnostics <absolute-script>]\n [--on-acquire-timeout fail|run-unlocked]\n -- <command> [args...]\n\ngha-runtime-audit\n [--repository owner/name] Default GITHUB_REPOSITORY\n [--branch main]\n --pr-workflow <name|/regex/> Repeatable\n --push-workflow <name|/regex/> Repeatable\n\ngha-output <name>\ngha-needs-results [label]\ndownload-with-diagnostics <url> <destination> [-- curl-args...]\nhost-pressure-diagnostics\nallocate-browser-safe-ports [count] [--policy path] [--forbidden-ports path]\ndiagnose-port-collision [--ports \"2200 2216\"] [--output-dir PATH]\nprepare-trivy-db\ngha-artifacts-cleanup run --run-id <id> [--keep-pattern glob] [--delete-pattern glob] [--patterns-file json]\ngha-artifacts-cleanup sweep --older-than-hours <n> [--keep-pattern glob] [--delete-pattern glob] [--patterns-file json]\nhttp-origin [--field NAME] [value]\nvitest-blob-manifest <suite> [reports-directory]\npnpm-install --runner-lifecycle persistent|ephemeral|ephemeral-full --install-scripts true|false\ncheck-cache-size <path> <max-bytes> <label>\nmake-shard-matrix <total>\nload-runner-env\nclean-workspace\ninstall-github-release --repo owner/name --version X --asset 'name-{platform}.tar.gz' --bin name [--tag-prefix PREFIX] [--no-checksum] [--checksums-asset NAME] [--version-flag FLAG] [--bin-dir DIR]\nrun-with-timeout <timeout-seconds> <kill-after-seconds> <command...>\nlint-links [--offline] [--config PATH] [--glob PATTERN] [files...]\nmaterialize-pr-context\nwait-for-apt-locks\ninstall-playwright-chromium-arm64 [name:archive...]\nghcr-package-retention <url-encoded-package>...\nnuget-central-version <trusted-props> <candidate-props> <metadata-json> <output-props>\nswift-semantic-equal <base> <head> <file.swift>\npost-review\nstage-review-payload optional|required <source> <destination>\nretrospective-transcript [--session-id ID] [--jsonl PATH] [--projects-dir PATH] [--codex-sessions-dir PATH] [--grok-sessions-dir PATH]\n";
|
|
2
2
|
export declare function printUsage(stream?: NodeJS.WritableStream): void;
|
package/dist/cli/usage.mjs
CHANGED
|
@@ -30,6 +30,7 @@ Commands:
|
|
|
30
30
|
swift-semantic-equal Compare Swift sources ignoring comments and whitespace
|
|
31
31
|
post-review Post one COMMENT review from a staged payload file
|
|
32
32
|
stage-review-payload Validate a review payload file into a staging directory
|
|
33
|
+
retrospective-transcript Format facts from Claude-compatible, Codex, or Grok transcripts
|
|
33
34
|
|
|
34
35
|
Options:
|
|
35
36
|
-h, --help Show this help
|
|
@@ -82,6 +83,7 @@ nuget-central-version <trusted-props> <candidate-props> <metadata-json> <output-
|
|
|
82
83
|
swift-semantic-equal <base> <head> <file.swift>
|
|
83
84
|
post-review
|
|
84
85
|
stage-review-payload optional|required <source> <destination>
|
|
86
|
+
retrospective-transcript [--session-id ID] [--jsonl PATH] [--projects-dir PATH] [--codex-sessions-dir PATH] [--grok-sessions-dir PATH]
|
|
85
87
|
`;
|
|
86
88
|
export function printUsage(stream = process.stdout) {
|
|
87
89
|
stream.write(USAGE);
|
|
@@ -23,7 +23,9 @@ export function assertCoverageTransportOutcome(suite, primary, artifactAttempt1,
|
|
|
23
23
|
return true;
|
|
24
24
|
}
|
|
25
25
|
if (artifactSucceeded) {
|
|
26
|
-
|
|
26
|
+
if (primary !== 'skipped') {
|
|
27
|
+
emit(`::warning::Coverage persisted only to GitHub artifacts for suite=${suite}; S3 primary is degraded.`);
|
|
28
|
+
}
|
|
27
29
|
return true;
|
|
28
30
|
}
|
|
29
31
|
emit(`::error::COVERAGE_TRANSPORT_EXHAUSTED suite=${suite} Neither S3 nor GitHub artifacts persisted the coverage pair.`);
|
package/dist/index.d.mts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export { codexChildren, codexIdentity, computeTranscriptFacts, formatTranscriptFacts, formatUnavailable, resolveTranscriptFile, runRetrospectiveTranscript, } from './retrospective-transcript/index.mts';
|
|
2
|
+
export type { ResolveOptions, TokenTotals, TranscriptFacts, } from './retrospective-transcript/index.mts';
|
|
1
3
|
export { EphemeralListenerAttemptsExhaustedError, isRunnerReservedPort, listenOnRunnerUnreservedEphemeralPort, loadRunnerPortPolicy, runnerPortPolicy, validateRunnerPortPolicy, } from './runner-port-policy/index.mts';
|
|
2
4
|
export type { EphemeralListenerOptions, RunnerPortPolicy } from './runner-port-policy/index.mts';
|
|
3
5
|
export { extractAlterTableAddColumnLocations, extractCreateIndexMetadata, extractCreateTableMetadata, extractDefaultFunction, extractDropIndexMetadata, extractFuncCallArgColumnNames, extractMigrationConstraintMetadata, initSqlAst, lineOfUtf8ByteOffset, MissingSqlAstParserError, parseSql, } from './sql-ast/index.mts';
|
|
@@ -20,6 +22,8 @@ export { createArtifactClassifier, parseArtifactPatternsJson, planRunDeletions,
|
|
|
20
22
|
export type { ArtifactClassification, ArtifactClassifier, ArtifactPatterns, CleanupRequest, DeletionSummary, } from './gha-artifacts-cleanup/index.mts';
|
|
21
23
|
export { validateOptionalHttpOrigin } from './http-origin/index.mts';
|
|
22
24
|
export { boundPendingLine, DEFAULT_MAX_PENDING_LINE_LENGTH, DEFAULT_TRUNCATED_LINE_MARKER, splitCompleteLines, } from './process-line-buffer/index.mts';
|
|
25
|
+
export { ProcessGroupDrainTimeoutError, runBrowserSession, } from './browser-session-runner/index.mts';
|
|
26
|
+
export type { BrowserSessionDeps, BrowserSessionEvent, BrowserSessionExit, BrowserSessionOptions, BrowserSessionProcess, BrowserSessionResult, } from './browser-session-runner/index.mts';
|
|
23
27
|
export { buildSchemaSnapshot, detectRenamedIndexes, generateSchemaSnapshot, indexShapeKey, readSchemaCatalog, renderSchemaMarkdown, stableStringify, writeSchemaSnapshot, } from './pg-schema-snapshot/index.mts';
|
|
24
28
|
export type { CatalogQuery, PartitionPolicy, SchemaCatalog, SchemaGrowthMaps, SchemaSnapshot, SchemaTableSnapshot, } from './pg-schema-snapshot/index.mts';
|
|
25
29
|
export { buildOpenApiDocument, hashContractSchema, nodeToOpenApi, writeOpenApi, } from './openapi-document/index.mts';
|
|
@@ -56,3 +60,5 @@ export { normalizeSwiftSource } from './swift-semantic-equal/index.mts';
|
|
|
56
60
|
export { isSwiftCodeOffset, parseUniqueSwiftBinaryTargetChecksum, } from './swift-source-offset/index.mts';
|
|
57
61
|
export { validateResolvedPinDelta } from './swift-resolved-pin-delta/index.mts';
|
|
58
62
|
export type { ResolvedDocument, ResolvedPin, ValidateResolvedPinDeltaOptions, } from './swift-resolved-pin-delta/index.mts';
|
|
63
|
+
export { DEFAULT_MAX_DIAGNOSTIC_REPORTS, DEFAULT_MAX_FORMATTED_DIAGNOSTIC_REPORTS, formatDiagnosticReportSummaries, HARD_MAX_DIAGNOSTIC_REPORTS, readDiagnosticReportSummaries, summarizeDiagnosticReport, } from './vitest-diagnostics/index.mts';
|
|
64
|
+
export type { DiagnosticReportLimitOptions, DiagnosticReportSummary, } from './vitest-diagnostics/index.mts';
|