bantamkit-mcp 0.26.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.
Files changed (148) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +398 -0
  3. package/assets/contracts/default.yaml +90 -0
  4. package/assets/evals/devteam/manifest.yaml +351 -0
  5. package/assets/evals/devteam/repo/HISTORY.md +18 -0
  6. package/assets/evals/devteam/repo/README.md +12 -0
  7. package/assets/evals/devteam/repo/docs/architecture.md +17 -0
  8. package/assets/evals/devteam/repo/docs/runbook.md +10 -0
  9. package/assets/evals/devteam/repo/issues/142-settlement-timeout.md +23 -0
  10. package/assets/evals/devteam/repo/patches/0009-retry-budget.patch +38 -0
  11. package/assets/evals/devteam/repo/src/ledger/__init__.py +3 -0
  12. package/assets/evals/devteam/repo/src/ledger/config.py +35 -0
  13. package/assets/evals/devteam/repo/src/ledger/errors.py +13 -0
  14. package/assets/evals/devteam/repo/src/ledger/posting.py +12 -0
  15. package/assets/evals/devteam/repo/src/ledger/registry.py +7 -0
  16. package/assets/evals/devteam/repo/src/ledger/report.py +9 -0
  17. package/assets/evals/devteam/repo/src/ledger/retry.py +17 -0
  18. package/assets/evals/devteam/repo/src/ledger/settle.py +16 -0
  19. package/assets/evals/devteam/repo/src/ledger/validate.py +14 -0
  20. package/assets/evals/devteam/repo/tests/test_posting.py +13 -0
  21. package/assets/evals/devteam/repo/tests/test_settle.py +9 -0
  22. package/assets/evals/devteam/tasks/dt-error-contract.yaml +186 -0
  23. package/assets/evals/devteam/tasks/dt-handler-map.yaml +183 -0
  24. package/assets/evals/devteam/tasks/dt-patch-before-after.yaml +182 -0
  25. package/assets/evals/devteam/tasks/dt-retry-attempts.yaml +181 -0
  26. package/assets/evals/devteam/tasks/dt-settlement-config.yaml +185 -0
  27. package/assets/evals/devteam/tasks/dt-symbol-home.yaml +181 -0
  28. package/assets/evals/devteam/tasks/dt-trace-blame.yaml +182 -0
  29. package/assets/evals/devteam/tasks/dt-unread-key.yaml +180 -0
  30. package/assets/evals/document/tasks/doc-large-in-137.yaml +38 -0
  31. package/assets/evals/document/tasks/doc-large-in-359.yaml +44 -0
  32. package/assets/evals/document/tasks/doc-large-in-372.yaml +38 -0
  33. package/assets/evals/document/tasks/doc-large-out-11764.yaml +37 -0
  34. package/assets/evals/document/tasks/doc-large-out-4137.yaml +37 -0
  35. package/assets/evals/document/tasks/doc-large-out-8022.yaml +37 -0
  36. package/assets/evals/document/tasks/doc-small-137.yaml +37 -0
  37. package/assets/evals/document/tasks/doc-small-261.yaml +37 -0
  38. package/assets/evals/document/tasks/doc-small-388.yaml +37 -0
  39. package/assets/evals/fixtures/.gitkeep +0 -0
  40. package/assets/evals/fixtures/catalog.json +6 -0
  41. package/assets/evals/perturbations/task-completion.yaml +576 -0
  42. package/assets/evals/tasks/.gitkeep +0 -0
  43. package/assets/evals/tasks/extract-contact.yaml +14 -0
  44. package/assets/evals/tasks/extract-invoice.yaml +14 -0
  45. package/assets/evals/tasks/extract-order.yaml +15 -0
  46. package/assets/evals/tasks/extract-schedule.yaml +14 -0
  47. package/assets/evals/tasks/extract-versions.yaml +17 -0
  48. package/assets/evals/tasks/nav-prod-port.yaml +84 -0
  49. package/assets/evals/tasks/nav-release-bundle.yaml +87 -0
  50. package/assets/evals/tasks/recall-audit-retention.yaml +17 -0
  51. package/assets/evals/tasks/recall-cache-ttl.yaml +13 -0
  52. package/assets/evals/tasks/recall-db-port.yaml +17 -0
  53. package/assets/evals/tasks/recall-deploy.yaml +13 -0
  54. package/assets/evals/tasks/recall-env-endpoint.yaml +18 -0
  55. package/assets/evals/tasks/recall-oncall-rotation.yaml +21 -0
  56. package/assets/evals/tasks/recall-oncall.yaml +13 -0
  57. package/assets/evals/tasks/recall-org-quota.yaml +18 -0
  58. package/assets/evals/tasks/recall-owner.yaml +13 -0
  59. package/assets/evals/tasks/shop-basket-total.yaml +10 -0
  60. package/assets/evals/tasks/shop-cheapest.yaml +9 -0
  61. package/assets/evals/tasks/shop-compare.yaml +9 -0
  62. package/assets/evals/tasks/shop-gadget-value.yaml +9 -0
  63. package/assets/evals/tasks/shop-stock-total.yaml +9 -0
  64. package/assets/evals/tasks/shop-total.yaml +9 -0
  65. package/assets/profiles/default.yaml +31 -0
  66. package/assets/profiles/patient.yaml +31 -0
  67. package/assets/rubrics/.gitkeep +0 -0
  68. package/assets/rubrics/code-quality.yaml +20 -0
  69. package/assets/rubrics/grounded-completion.yaml +37 -0
  70. package/assets/rubrics/task-completion.yaml +28 -0
  71. package/assets/schemas/shiftwork-checkpoint.json +188 -0
  72. package/assets/skills/.gitkeep +0 -0
  73. package/assets/skills/file-graph.md +7 -0
  74. package/assets/skills/memory.md +35 -0
  75. package/assets/tools/.gitkeep +0 -0
  76. package/assets/tools/bantamkit_read.json +48 -0
  77. package/assets/tools/bantamkit_status.json +25 -0
  78. package/assets/tools/build_identity.json +17 -0
  79. package/assets/tools/document_list.json +12 -0
  80. package/assets/tools/document_read.json +31 -0
  81. package/assets/tools/file_graph.json +12 -0
  82. package/assets/tools/memory_compact.json +31 -0
  83. package/assets/tools/memory_recall.json +38 -0
  84. package/assets/tools/memory_save.json +61 -0
  85. package/assets/tools/shiftwork_clock_in.json +25 -0
  86. package/assets/tools/shiftwork_clock_out.json +60 -0
  87. package/assets/tools/shiftwork_status.json +25 -0
  88. package/assets/tools/skill_audit.json +70 -0
  89. package/assets/tools/validate_json.json +31 -0
  90. package/dist/assets.d.ts +48 -0
  91. package/dist/assets.js +109 -0
  92. package/dist/charsets.d.ts +17 -0
  93. package/dist/charsets.js +580 -0
  94. package/dist/cli.d.ts +12 -0
  95. package/dist/cli.js +280 -0
  96. package/dist/contract.d.ts +145 -0
  97. package/dist/contract.js +608 -0
  98. package/dist/docread.d.ts +357 -0
  99. package/dist/docread.js +3315 -0
  100. package/dist/errors.d.ts +11 -0
  101. package/dist/errors.js +14 -0
  102. package/dist/eventlog.d.ts +137 -0
  103. package/dist/eventlog.js +294 -0
  104. package/dist/htmlentities.d.ts +2 -0
  105. package/dist/htmlentities.js +16 -0
  106. package/dist/index.d.ts +23 -0
  107. package/dist/index.js +13 -0
  108. package/dist/mcp/identity.d.ts +25 -0
  109. package/dist/mcp/identity.js +275 -0
  110. package/dist/mcp/pyargs.d.ts +80 -0
  111. package/dist/mcp/pyargs.js +362 -0
  112. package/dist/mcp/sdkjson.d.ts +56 -0
  113. package/dist/mcp/sdkjson.js +91 -0
  114. package/dist/mcp/server.d.ts +45 -0
  115. package/dist/mcp/server.js +740 -0
  116. package/dist/mcp/status.d.ts +210 -0
  117. package/dist/mcp/status.js +357 -0
  118. package/dist/mcp/transport.d.ts +68 -0
  119. package/dist/mcp/transport.js +111 -0
  120. package/dist/mcpreport.d.ts +214 -0
  121. package/dist/mcpreport.js +758 -0
  122. package/dist/memory/cli.d.ts +2 -0
  123. package/dist/memory/cli.js +396 -0
  124. package/dist/memory/component.d.ts +256 -0
  125. package/dist/memory/component.js +497 -0
  126. package/dist/memory/factfile.d.ts +120 -0
  127. package/dist/memory/factfile.js +406 -0
  128. package/dist/memory/layers.d.ts +92 -0
  129. package/dist/memory/layers.js +410 -0
  130. package/dist/memory/pyfs.d.ts +521 -0
  131. package/dist/memory/pyfs.js +1608 -0
  132. package/dist/memory/pyyaml.d.ts +155 -0
  133. package/dist/memory/pyyaml.js +868 -0
  134. package/dist/memory/store.d.ts +478 -0
  135. package/dist/memory/store.js +1034 -0
  136. package/dist/pyargparse.d.ts +141 -0
  137. package/dist/pyargparse.js +813 -0
  138. package/dist/pyjson.d.ts +110 -0
  139. package/dist/pyjson.js +524 -0
  140. package/dist/pyjsonschema.d.ts +50 -0
  141. package/dist/pyjsonschema.js +951 -0
  142. package/dist/shiftwork.d.ts +60 -0
  143. package/dist/shiftwork.js +324 -0
  144. package/dist/skillaudit.d.ts +172 -0
  145. package/dist/skillaudit.js +914 -0
  146. package/dist/statusline.d.ts +106 -0
  147. package/dist/statusline.js +281 -0
  148. package/package.json +45 -0
@@ -0,0 +1,111 @@
1
+ import { JSONRPCMessageSchema } from '@modelcontextprotocol/sdk/types.js';
2
+ import { PY_LINESEP } from '../memory/pyfs.js';
3
+ /** A JSON-RPC id is a string or a number; the map key is its JSON text, which is total. */
4
+ const idKey = (id) => JSON.stringify(id ?? null);
5
+ export class RawStdioTransport {
6
+ input;
7
+ output;
8
+ onclose;
9
+ onerror;
10
+ onmessage;
11
+ sessionId;
12
+ buffer = Buffer.alloc(0);
13
+ started = false;
14
+ rawLines = new Map();
15
+ exactResults = new Map();
16
+ ondata = (chunk) => this.consume(chunk);
17
+ onstreamerror = (error) => this.onerror?.(error);
18
+ constructor(input = process.stdin, output = process.stdout) {
19
+ this.input = input;
20
+ this.output = output;
21
+ }
22
+ /** The verbatim request line that carried this id, or `undefined` if it is gone. */
23
+ rawLineFor(id) {
24
+ return this.rawLines.get(idKey(id));
25
+ }
26
+ /** Register the exact JSON text to send as this request's `result`. */
27
+ setExactResult(id, json) {
28
+ this.exactResults.set(idKey(id), json);
29
+ }
30
+ async start() {
31
+ if (this.started)
32
+ throw new Error('RawStdioTransport already started');
33
+ this.started = true;
34
+ this.input.on('data', this.ondata);
35
+ this.input.on('error', this.onstreamerror);
36
+ }
37
+ async close() {
38
+ this.input.off('data', this.ondata);
39
+ this.input.off('error', this.onstreamerror);
40
+ if (this.input.listenerCount('data') === 0)
41
+ this.input.pause();
42
+ this.buffer = Buffer.alloc(0);
43
+ this.rawLines.clear();
44
+ this.exactResults.clear();
45
+ this.onclose?.();
46
+ }
47
+ send(message) {
48
+ return new Promise((resolve) => {
49
+ const text = this.frame(message);
50
+ // `os.linesep`, because the reference's stdout is a TEXT stream. The Python SDK writes
51
+ // its frames through `TextIOWrapper(sys.stdout.buffer)` with the default
52
+ // `newline=None`, so on Windows every frame CPython emits ends `\r\n`. MEASURED, run
53
+ // 32646521489: all nine `wire/*: raw frame bytes` cases differed by exactly one byte
54
+ // per frame and by nothing else. A client is free to strip it; a port that claims to
55
+ // be byte-compatible on the wire does not get to decide it is decoration.
56
+ if (this.output.write(`${text}${PY_LINESEP}`))
57
+ resolve();
58
+ else
59
+ this.output.once('drain', () => resolve());
60
+ });
61
+ }
62
+ /**
63
+ * One frame, in the reference's key order, with an exact `result` when one was registered.
64
+ *
65
+ * The raw line and the exact text are both dropped here rather than in the handler: the
66
+ * handler cannot know whether the protocol will actually send its answer (a cancelled
67
+ * request never reaches `send`), and a map that only ever grows is a leak in a process
68
+ * that is meant to run for a session.
69
+ */
70
+ frame(message) {
71
+ const framed = message;
72
+ if (framed.id === undefined)
73
+ return JSON.stringify(message);
74
+ const key = idKey(framed.id);
75
+ this.rawLines.delete(key);
76
+ const id = JSON.stringify(framed.id);
77
+ if ('result' in framed) {
78
+ const exact = this.exactResults.get(key);
79
+ this.exactResults.delete(key);
80
+ return `{"jsonrpc":"2.0","id":${id},"result":${exact ?? JSON.stringify(framed.result)}}`;
81
+ }
82
+ this.exactResults.delete(key);
83
+ if ('error' in framed)
84
+ return `{"jsonrpc":"2.0","id":${id},"error":${JSON.stringify(framed.error)}}`;
85
+ return JSON.stringify(message);
86
+ }
87
+ consume(chunk) {
88
+ this.buffer = Buffer.concat([this.buffer, chunk]);
89
+ for (;;) {
90
+ const at = this.buffer.indexOf(0x0a);
91
+ if (at === -1)
92
+ return;
93
+ const line = this.buffer.toString('utf8', 0, at).replace(/\r$/, '');
94
+ this.buffer = this.buffer.subarray(at + 1);
95
+ if (line.trim() === '')
96
+ continue;
97
+ let message;
98
+ try {
99
+ message = JSONRPCMessageSchema.parse(JSON.parse(line));
100
+ }
101
+ catch (error) {
102
+ this.onerror?.(error);
103
+ continue;
104
+ }
105
+ const id = message.id;
106
+ if (id !== undefined)
107
+ this.rawLines.set(idKey(id), line);
108
+ this.onmessage?.(message);
109
+ }
110
+ }
111
+ }
@@ -0,0 +1,214 @@
1
+ import { formatTimestamp } from './eventlog.js';
2
+ /**
3
+ * Overrides the platform default for the host-log root. The default is only KNOWN on macOS
4
+ * (see `defaultHostLogRoot`), so this is what makes the analyst usable at all on Linux and
5
+ * Windows — and what lets a test run against a fixture tree.
6
+ */
7
+ export declare const HOST_LOG_ROOT_ENV = "BANTAMKIT_HOST_LOG_ROOT";
8
+ /**
9
+ * The ONLY directory name read under a slug directory. `mcp-logs-clickup` and sixteen
10
+ * others sit beside it; globbing `mcp-logs-*` would read another program's log.
11
+ */
12
+ export declare const HOST_LOG_DIRNAME = "mcp-logs-bantamkit";
13
+ /**
14
+ * How far outside the host's `[dispatch, completion]` interval an event's `ts` may fall and
15
+ * still be a CANDIDATE. Not a tolerance for clock skew — both stamps come from one machine
16
+ * clock — but for the lag between the component deciding and the host stamping the reply it
17
+ * eventually read. Widening it produces MORE ambiguity, not more matches.
18
+ */
19
+ export declare const DEFAULT_WINDOW_MS = 250;
20
+ /** Report format version. Bump when a section, a field or an order changes; both runtimes move together. */
21
+ export declare const REPORT_VERSION = 1;
22
+ /**
23
+ * Outcomes worth asking "and then what?" about. An `escalate` that ended a session and an
24
+ * `escalate` followed by nine more calls are different facts about the same word.
25
+ */
26
+ export declare const FOLLOW_UP_OUTCOMES: readonly string[];
27
+ /**
28
+ * `2026-08-23T17:38:47.243Z` -> integer epoch milliseconds, or `null`.
29
+ *
30
+ * Hand-rolled rather than `Date.parse` for the reason the reference is hand-rolled rather
31
+ * than `datetime.fromisoformat`: each stdlib accepts a DIFFERENT wider set (`+00:00`, no
32
+ * `Z`, six fractional digits, `2026-08-23` alone), and this is a compared field. A parser
33
+ * that accepted more would put records on the timeline the host never put there. One regex
34
+ * that admits exactly the host's spelling is the same function on both sides.
35
+ *
36
+ * The arithmetic is done in integers here: no `Date` object is constructed on the way IN,
37
+ * so no local time zone can reach the answer. `formatTimestamp` is the event log's, which
38
+ * is `toISOString()` and is UTC by definition — the two are inverses over the range that
39
+ * matters.
40
+ */
41
+ export declare function parseTimestamp(text: string): number | null;
42
+ /** The inverse, reusing the event log's formatter so one spelling exists in the repo. */
43
+ export { formatTimestamp };
44
+ /**
45
+ * One classified host line. THERE IS NO FIELD HERE THAT CAN HOLD HOST TEXT.
46
+ *
47
+ * `kind` is a token from this module's vocabulary, `tool` passed `[a-z0-9_]{1,64}`,
48
+ * `session` passed `[A-Za-z0-9-]{1,64}`, and the rest are integers. That is the whole leak
49
+ * guard: not a filter applied on the way out, but an absence of anywhere to put it.
50
+ */
51
+ export interface HostRecord {
52
+ readonly tsMs: number;
53
+ readonly session: string;
54
+ readonly kind: 'call-start' | 'call-ok' | 'call-fail' | 'error' | 'other';
55
+ readonly tool: string | null;
56
+ readonly durationMs: number | null;
57
+ }
58
+ /**
59
+ * One JSONL line -> a `HostRecord`, or `null` for anything unparseable.
60
+ *
61
+ * `null` covers a blank line, a truncated tail (the host is appending while this reads), a
62
+ * record with no usable timestamp, and a record with no `debug` and no `error` string. All
63
+ * of them are counted as `unclassified` by the caller and nothing else.
64
+ */
65
+ export declare function parseHostLine(line: string): HostRecord | null;
66
+ /** A dispatch paired with its completion. Either end may be missing; say which. */
67
+ export interface HostCall {
68
+ readonly tool: string;
69
+ readonly session: string;
70
+ readonly startMs: number | null;
71
+ readonly endMs: number | null;
72
+ readonly ok: boolean | null;
73
+ readonly durationMs: number | null;
74
+ }
75
+ /** The one timestamp the join hangs on when only one end was logged. */
76
+ export declare function anchorMs(call: HostCall): number;
77
+ export interface PairedCalls {
78
+ readonly calls: HostCall[];
79
+ readonly incomplete: number;
80
+ readonly orphanCompletions: number;
81
+ }
82
+ /**
83
+ * Dispatches to completions, FIFO within one `(session, tool)`.
84
+ *
85
+ * FIFO and not nearest-time, because within one session and one tool the host's own file
86
+ * order IS the dispatch order — it is one writer appending. Across sessions or across tools
87
+ * no order is assumed, which is why the queue key carries both.
88
+ *
89
+ * Returns the calls plus two honesty counters: dispatches that never completed (the process
90
+ * was killed, or the file was rotated mid-call) and completions with no dispatch in view
91
+ * (the dispatch is in an earlier file that was rotated away).
92
+ */
93
+ export declare function pairCalls(records: readonly HostRecord[]): PairedCalls;
94
+ /** What source A yielded, including the reason it yielded nothing. */
95
+ export interface HostScan {
96
+ readonly root: string | null;
97
+ readonly missing: null | 'not-found' | 'unknown-platform';
98
+ readonly platform: string;
99
+ readonly dirs: number;
100
+ readonly files: number;
101
+ readonly records: number;
102
+ readonly lifecycle: number;
103
+ readonly unclassified: number;
104
+ readonly errors: number;
105
+ readonly errorsWithTool: number;
106
+ readonly calls: HostCall[];
107
+ readonly incomplete: number;
108
+ readonly orphanCompletions: number;
109
+ }
110
+ /**
111
+ * `~/Library/Caches/claude-cli-nodejs` — ON macOS, AND NOWHERE ELSE.
112
+ *
113
+ * Where Claude Code writes this on Linux and on Windows has NOT been measured, and a guess
114
+ * dressed as a default would produce an empty report that reads like "nothing happened". So
115
+ * off darwin this returns `null`, the report says which platform it is on and names
116
+ * `BANTAMKIT_HOST_LOG_ROOT`, and source B is reported alone. `CLAUDE.md`'s parity rule is
117
+ * satisfied by the analyst RUNNING on Windows and saying what it cannot see, not by
118
+ * pretending it looked. Lifting the limitation is a MEASUREMENT, not a code change.
119
+ */
120
+ export declare function defaultHostLogRoot(platform: string, home: string): string | null;
121
+ export declare function resolveHostLogRoot(env: Readonly<Record<string, string | undefined>>, platform?: string, home?: string): string | null;
122
+ /**
123
+ * Every `<root>/*​/mcp-logs-bantamkit/*.jsonl`, sorted, and NOTHING else.
124
+ *
125
+ * The slug directories are listed and each is asked for `mcp-logs-bantamkit` BY NAME. No
126
+ * `mcp-logs-*` pattern is ever built, so a sibling server's directory cannot be reached by
127
+ * this function even by accident — `mcp-logs-clickup` is right there.
128
+ */
129
+ export declare function hostLogFiles(root: string): string[];
130
+ /**
131
+ * `platform` is carried into the scan, not read at render time, so an injected platform
132
+ * reaches the "unknown on this platform" line and a test can see it.
133
+ */
134
+ export declare function scanHostLog(root: string | null, platform?: string): HostScan;
135
+ export interface Event {
136
+ readonly tsMs: number;
137
+ readonly tool: string;
138
+ readonly outcome: string;
139
+ }
140
+ export interface EventScan {
141
+ readonly path: string | null;
142
+ readonly missing: null | 'not-found' | 'off';
143
+ readonly records: number;
144
+ readonly unreadable: number;
145
+ readonly events: Event[];
146
+ }
147
+ /** One `docs/eventlog.md` record. Wrong shape or wrong `ts` -> `null`. */
148
+ export declare function parseEventLine(line: string): Event | null;
149
+ /**
150
+ * Reads the live file AND the one rotated generation, because the rotation rule keeps
151
+ * `<path>.1` and a report that ignored it would lose the older half of a session.
152
+ */
153
+ export declare function scanEventLog(path: string | null): EventScan;
154
+ /**
155
+ * The whole result of the join, uncertainty first.
156
+ *
157
+ * `matched` holds only MUTUALLY UNIQUE pairs. `ambiguousGroups` holds the size of every
158
+ * component that was not one-to-one, as `[events, calls]`. Nothing is dropped: every event
159
+ * lands in exactly one of matched / ambiguous / unmatched, and so does every call.
160
+ */
161
+ export interface Join {
162
+ readonly windowMs: number;
163
+ readonly matched: [Event, HostCall][];
164
+ readonly ambiguousGroups: [number, number][];
165
+ readonly ambiguousEvents: number;
166
+ readonly ambiguousCalls: number;
167
+ readonly unmatchedEvents: Event[];
168
+ readonly unmatchedCalls: HostCall[];
169
+ }
170
+ /**
171
+ * Mutual uniqueness or nothing.
172
+ *
173
+ * A greedy nearest-time pass would produce a bigger `matched` number and a report that lies
174
+ * about which session an outcome belongs to. The component rule cannot: an event whose
175
+ * candidate call is also some other event's candidate is not paired with it, and both land
176
+ * in one ambiguous group whose sizes are printed. The traversal is ITERATIVE — a busy day
177
+ * is thousands of calls and a recursive flood fill would blow the stack on the one input
178
+ * that matters.
179
+ */
180
+ export declare function join(events: readonly Event[], calls: readonly HostCall[], windowMs: number): Join;
181
+ /**
182
+ * The LOWER median: an element of the input, never a mean.
183
+ *
184
+ * A mean of two integers is a float, a float has to be formatted, and two runtimes format
185
+ * floats differently at the edges. `Array.prototype.sort` is LEXICOGRAPHIC by default, so
186
+ * the numeric comparator is not decoration: `[9, 51]` sorts to `[51, 9]` without it.
187
+ */
188
+ export declare function p50(values: readonly number[]): number;
189
+ /** The report, as the bytes `docs/mcpreport.md` specifies. No clock is read here. */
190
+ export declare function render(host: HostScan, events: EventScan, joined: Join): string;
191
+ export interface ReportOptions {
192
+ readonly windowMs?: number;
193
+ readonly platform?: string;
194
+ readonly home?: string;
195
+ }
196
+ export declare function buildReport(env: Readonly<Record<string, string | undefined>>, eventLogPath: string | null, options?: ReportOptions): string;
197
+ /**
198
+ * Where source B would be for THIS invocation, resolved exactly as the server resolves it.
199
+ *
200
+ * ONE VOCABULARY FOR `BANTAMKIT_EVENT_LOG`, NOT TWO: `eventlog.resolvePath` decides
201
+ * off / default / literal, and this only supplies the store root it needs. The root comes
202
+ * from `--store` when given and otherwise from `discoverProjectStore`, which walks up and
203
+ * DESIGNATES without creating anything — so asking for a report never brings a store into
204
+ * existence.
205
+ *
206
+ * A pinned `BANTAMKIT_MEMORY_DIR` that does not exist makes the walk throw. That is a real
207
+ * answer, not a crash to hide: the report then names the path the walk would have
208
+ * designated, and the `not found at` line says the rest.
209
+ *
210
+ * `pyJoin` on the way out because the reference returns a `Path` and prints `str(Path)`,
211
+ * which collapses `//` and `./` in a literal the operator typed. The file identity does not
212
+ * move; the printed line does, and the line is compared byte for byte.
213
+ */
214
+ export declare function resolveEventLogPath(env: Readonly<Record<string, string | undefined>>, store?: string | null, start?: string | null): string | null;