@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 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 };