@videlic/connect 0.1.1 → 0.1.7
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 +4 -0
- package/evidence.d.mts +172 -0
- package/evidence.mjs +3005 -0
- package/hook.mjs +1468 -42
- package/install.mjs +38 -4
- package/package.json +9 -1
package/README.md
CHANGED
|
@@ -23,6 +23,10 @@ Code already ships with, so macOS, Windows, and Linux use the identical command.
|
|
|
23
23
|
## Notes
|
|
24
24
|
|
|
25
25
|
- The hook only runs when a session **ends** — nothing in the background.
|
|
26
|
+
- On each stop it asks [`gh`](https://cli.github.com) which pull request the
|
|
27
|
+
current branch is on (`gh pr view`, read-only). No `gh`, no login, or no pull
|
|
28
|
+
request yet — the session is still sent, and the hook says so in one line in
|
|
29
|
+
your terminal.
|
|
26
30
|
- Sessions that started **before** install are skipped (consent guard).
|
|
27
31
|
- Remove it by deleting the `Stop` entry in `~/.claude/settings.json`.
|
|
28
32
|
- `VIDELIC_API_URL` overrides the API endpoint (defaults to production).
|
package/evidence.d.mts
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for `evidence.mjs`.
|
|
3
|
+
*
|
|
4
|
+
* The collector is plain JavaScript because it is copied to `~/.claude` and run
|
|
5
|
+
* by `node` with nothing around it — no build, no loader, no `node_modules`.
|
|
6
|
+
* This file exists so the ONE place that reads it inside the monorepo, the
|
|
7
|
+
* cross-producer parity test, is type-checked like everything else rather than
|
|
8
|
+
* silently `any`: the test's whole job is to prove two implementations agree,
|
|
9
|
+
* and a test that could pass the wrong shape to one of them would be the last
|
|
10
|
+
* place to want an untyped call.
|
|
11
|
+
*
|
|
12
|
+
* Shapes are imported from `@ao/types`, never re-declared. A hand-written copy
|
|
13
|
+
* of `EvidenceBundle` here would be a third definition of the thing whose
|
|
14
|
+
* second definition this package already is, and the type is precisely what
|
|
15
|
+
* both producers are supposed to share. The import is compile-time only and
|
|
16
|
+
* reaches nothing at runtime — `evidence.mjs` still imports `node:` and
|
|
17
|
+
* nothing else, which `hook.test.mjs` holds it to.
|
|
18
|
+
*/
|
|
19
|
+
import type {
|
|
20
|
+
EvidenceBundle,
|
|
21
|
+
EvidenceEdgeKind,
|
|
22
|
+
EvidenceListTests,
|
|
23
|
+
EvidenceManifest,
|
|
24
|
+
EvidenceSection,
|
|
25
|
+
EvidenceSent,
|
|
26
|
+
} from "@ao/types/src/report/evidence";
|
|
27
|
+
|
|
28
|
+
export const EVIDENCE_V: 1;
|
|
29
|
+
export const EVIDENCE_GRAPH_FORMAT: 2;
|
|
30
|
+
export const COLLECT_BUDGET_MS: number;
|
|
31
|
+
export const LIST_TESTS_BUDGET_MS: number;
|
|
32
|
+
export const TREE_CAP: number;
|
|
33
|
+
export const BODY_CAP_BYTES: number;
|
|
34
|
+
|
|
35
|
+
/** The edge kinds the graph carries — the bundle's own vocabulary, not a copy of it. */
|
|
36
|
+
export interface ModuleEdge {
|
|
37
|
+
specifier: string;
|
|
38
|
+
kind: EvidenceEdgeKind;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface ModuleEdgeOptions {
|
|
42
|
+
declaration?: boolean;
|
|
43
|
+
jsx?: boolean;
|
|
44
|
+
typescript?: boolean;
|
|
45
|
+
script?: boolean;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function isDeclarationFile(path: string): boolean;
|
|
49
|
+
export function moduleEdgeOptions(path: string): ModuleEdgeOptions;
|
|
50
|
+
export function maskModuleSource(src: string, opts?: ModuleEdgeOptions): string;
|
|
51
|
+
export function moduleDoubt(content: string, opts?: ModuleEdgeOptions): number;
|
|
52
|
+
export function extractModuleEdges(content: string, opts?: ModuleEdgeOptions, report?: { doubtAt: number }): ModuleEdge[];
|
|
53
|
+
export const MANIFEST_FIELD_MAX_DEPTH: number;
|
|
54
|
+
export const MANIFEST_FIELD_MAX_BYTES: number;
|
|
55
|
+
export function manifestFieldFits(v: unknown): boolean;
|
|
56
|
+
export function manifestName(body: string | null | undefined): string | null;
|
|
57
|
+
export function readManifest(path: string, body: string | null | undefined): EvidenceManifest;
|
|
58
|
+
export function isTestPath(path: string): boolean;
|
|
59
|
+
export function expectedTestPaths(sourcePath: string): string[];
|
|
60
|
+
export function isGraphSource(path: string): boolean;
|
|
61
|
+
|
|
62
|
+
export interface EvidenceSelection {
|
|
63
|
+
manifests: string[];
|
|
64
|
+
sources: string[];
|
|
65
|
+
changed: string[];
|
|
66
|
+
pairedTests: string[];
|
|
67
|
+
}
|
|
68
|
+
export function selectEvidence(treePaths: ReadonlySet<string>, changedPaths: readonly string[]): EvidenceSelection;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Which sections to BUILD — the budget's decision, made by the caller.
|
|
72
|
+
*
|
|
73
|
+
* `listTests` is absent from every rebuild literal on purpose and therefore
|
|
74
|
+
* optional here: a selection a runner has already given costs nothing to carry
|
|
75
|
+
* and has no relationship to the clock that cut the file read, so it survives a
|
|
76
|
+
* rebuild by construction rather than by every literal remembering to name it.
|
|
77
|
+
*/
|
|
78
|
+
export interface EvidenceWant {
|
|
79
|
+
tree?: boolean;
|
|
80
|
+
graph: boolean;
|
|
81
|
+
packageMap: boolean;
|
|
82
|
+
contents: boolean;
|
|
83
|
+
listTests?: boolean;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** One Bash command line the session ran, with the directory it ran in. */
|
|
87
|
+
export interface TranscriptCommand {
|
|
88
|
+
command: string;
|
|
89
|
+
cwd: string | null;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** A runner question: which runner, in which repo-relative directory, with which arguments. */
|
|
93
|
+
export interface ListTestsPlanItem {
|
|
94
|
+
runner: "jest" | "vitest";
|
|
95
|
+
dir: string;
|
|
96
|
+
args: string[];
|
|
97
|
+
command: string;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function runnerInvocations(
|
|
101
|
+
commandLine: string,
|
|
102
|
+
from?: string,
|
|
103
|
+
root?: string | null,
|
|
104
|
+
): { runner: "jest" | "vitest"; dir: string; args: string[] }[];
|
|
105
|
+
export function commandsFromTranscript(sessionData: string): TranscriptCommand[];
|
|
106
|
+
export function listTestsPlan(entries: readonly (TranscriptCommand | string)[], root: string): ListTestsPlanItem[];
|
|
107
|
+
export function runnerBinary(root: string, dir: string, runner: "jest" | "vitest"): string | null;
|
|
108
|
+
export function askRunner(input: {
|
|
109
|
+
root: string;
|
|
110
|
+
plan: ListTestsPlanItem;
|
|
111
|
+
timeoutMs: number;
|
|
112
|
+
now: () => number;
|
|
113
|
+
}): { ok: true; entry: EvidenceListTests } | { ok: false; reason: "tool-missing" | "off-repo" };
|
|
114
|
+
export function collectListTests(input: {
|
|
115
|
+
root: string;
|
|
116
|
+
plan: readonly ListTestsPlanItem[];
|
|
117
|
+
budgetMs: number;
|
|
118
|
+
now: () => number;
|
|
119
|
+
headOf: () => string;
|
|
120
|
+
}): { entries: EvidenceListTests[]; absence: EvidenceAbsences[EvidenceSection] | null };
|
|
121
|
+
export function normaliseListTests(
|
|
122
|
+
entries: readonly EvidenceListTests[] | undefined,
|
|
123
|
+
): EvidenceListTests[] | undefined;
|
|
124
|
+
|
|
125
|
+
/** Why a section that was not built is missing. `sent` is derived from this and from what was built. */
|
|
126
|
+
export type EvidenceAbsences = Partial<Record<EvidenceSection, Exclude<EvidenceSent[EvidenceSection], true>>>;
|
|
127
|
+
|
|
128
|
+
export function buildEvidence(input: {
|
|
129
|
+
head: string;
|
|
130
|
+
defaultBranch?: string | null;
|
|
131
|
+
porcelainClean: boolean;
|
|
132
|
+
collectedAt: string;
|
|
133
|
+
clientVersion?: string;
|
|
134
|
+
tree: { paths: ReadonlySet<string>; truncated: boolean };
|
|
135
|
+
read: (paths: readonly string[]) => Map<string, string | null>;
|
|
136
|
+
changedPaths: readonly string[];
|
|
137
|
+
listTests?: readonly EvidenceListTests[];
|
|
138
|
+
want?: EvidenceWant;
|
|
139
|
+
absences?: EvidenceAbsences;
|
|
140
|
+
partial: EvidenceBundle["partial"];
|
|
141
|
+
}): EvidenceBundle;
|
|
142
|
+
|
|
143
|
+
export function defaultBranchOf(root: string, timeoutMs: number): string | null;
|
|
144
|
+
export function changedPathsOf(root: string, defaultBranch: string | null, timeoutMs: number): string[];
|
|
145
|
+
|
|
146
|
+
/** `bundle: null` with a `reason` is a repository we could not read — not an empty one. */
|
|
147
|
+
export interface CollectResult {
|
|
148
|
+
bundle: EvidenceBundle | null;
|
|
149
|
+
reason: string | null;
|
|
150
|
+
spentMs: number;
|
|
151
|
+
defaultBranch?: string | null;
|
|
152
|
+
bytes?: number;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export function collectEvidence(opts: {
|
|
156
|
+
root: string;
|
|
157
|
+
clientVersion?: string;
|
|
158
|
+
budgetMs?: number;
|
|
159
|
+
/** Injectable clock — the budget tests need one, and `Date.now` is not a fact a test may wait for. */
|
|
160
|
+
now?: () => number;
|
|
161
|
+
defaultBranch?: string | null;
|
|
162
|
+
changedPaths?: readonly string[];
|
|
163
|
+
/**
|
|
164
|
+
* The session's own Bash command lines, newest first, each with the directory
|
|
165
|
+
* it ran in. `undefined` means the caller did not ask for a selection at all
|
|
166
|
+
* — `sent.listTests` then says `not-collected`, which is a different fact
|
|
167
|
+
* from a repository that runs no tests and must not be spelled the same way.
|
|
168
|
+
*/
|
|
169
|
+
testCommands?: readonly (TranscriptCommand | string)[];
|
|
170
|
+
}): CollectResult;
|
|
171
|
+
|
|
172
|
+
export type { EvidenceBundle, EvidenceSection, EvidenceSent };
|