@thehammer/danx-session-telemetry 0.1.42 → 0.1.43
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 +2 -3
- package/dist/.source-hash +1 -1
- package/dist/claim-tracker.d.ts +1 -1
- package/dist/claim-tracker.js +2 -2
- package/dist/dispatch-usage.d.ts +3 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/dist/internal-logger.js +4 -4
- package/dist/pricing.d.ts +2 -15
- package/dist/pricing.js +16 -26
- package/dist/session-log-watcher.d.ts +2 -2
- package/dist/session-log-watcher.js +2 -2
- package/dist/stats-wire.d.ts +1 -1
- package/dist/subagent-live.js +3 -3
- package/dist/usage-ledger.d.ts +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
DX-2962 — the shared Claude Code transcript collector, extracted from
|
|
4
4
|
danxbot root's `src/agent/session-log-watcher.ts` so the danxbot worker and
|
|
5
|
-
the `danx-dashboard-mcp`
|
|
5
|
+
the `danx-dashboard-mcp` MCP server's plan event relay (DX-2954) run **identical** collector
|
|
6
6
|
code, instead of the worker's copy silently diverging from a re-implementation
|
|
7
7
|
inside the MCP package.
|
|
8
8
|
|
|
@@ -44,7 +44,7 @@ own header comments for the per-file reasoning.
|
|
|
44
44
|
| Consumer | Mechanism | Why |
|
|
45
45
|
|---|---|---|
|
|
46
46
|
| **danxbot worker** (root repo, `tsx src/index.ts`) | npm **workspace** link (`"workspaces": ["packages/*"]` in root `package.json`, `"@thehammer/danx-session-telemetry"` in root `dependencies`) | The worker and this package always ship from the SAME repo commit — a workspace link means the worker runs whatever source the current commit carries, with zero drift risk and no dependency on registry propagation timing. The Docker image builds `dist/` for it in a dedicated builder stage (alongside `frontend-builder` in `Dockerfile`) since the final image's `npm ci --omit=dev` never installs this package's own `devDependencies` (`typescript`). |
|
|
47
|
-
| **`danx-dashboard-mcp`
|
|
47
|
+
| **`danx-dashboard-mcp` MCP server** (separate npm-published package, DX-2954) | Ordinary npm dependency, **pinned to the exact published version** the worker's commit ships | The MCP server is a genuinely separate installable artifact (`npx -y @thehammer/danx-dashboard-mcp`), so it cannot workspace-link into danxbot's own checkout — it needs the real published bytes. Pinning exact (not `^`/`~`) is what makes "worker and MCP run identical collector code for any given release" true: MCP's own version bump is the only thing that ever changes what collector code it runs. |
|
|
48
48
|
| **Dashboard server** (`src/dashboard/*`) | Same npm dependency shape as the worker (the dashboard server's `src/` is root-repo code, so it resolves through the SAME root workspace link as the worker) | An npm dependency resolves through ordinary node_modules lookup, so no `@backend`-style alias is needed. |
|
|
49
49
|
|
|
50
50
|
## Release order (DX-2962 AC3)
|
|
@@ -52,7 +52,6 @@ own header comments for the per-file reasoning.
|
|
|
52
52
|
1. Publish this package (`make publish-danx-session-telemetry`).
|
|
53
53
|
2. Publish `danx-dashboard-mcp` (only once it depends on this package — DX-2954).
|
|
54
54
|
3. Deploy the danxbot backend.
|
|
55
|
-
4. Move the plugin's bridge-version pin.
|
|
56
55
|
|
|
57
56
|
Publishing comes before deploying because the publish-drift gate
|
|
58
57
|
(`src/dispatch/publish-drift-gate.ts`) refuses a finalize whose bumped
|
package/dist/.source-hash
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
1f7f247f7e5d5039a351835d2525a04c03edbb7a4ddac07cf83d4d599fe7ef07
|
package/dist/claim-tracker.d.ts
CHANGED
|
@@ -31,7 +31,7 @@ export interface ClaimState {
|
|
|
31
31
|
export declare function emptyClaimState(): ClaimState;
|
|
32
32
|
/**
|
|
33
33
|
* The per-process claim tracker: one state per sub-agent source. Fed every
|
|
34
|
-
* transcript line by `DispatchUsage` (operator-bridge mode only — the worker never
|
|
34
|
+
* transcript line by `DispatchUsage` (`operator-bridge` mode only — the worker never
|
|
35
35
|
* constructs one), seeded from the stored cursor at attach, and snapshotted per
|
|
36
36
|
* source for the stats write.
|
|
37
37
|
*/
|
package/dist/claim-tracker.js
CHANGED
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
*
|
|
38
38
|
* The state is the held set PLUS the transitions whose `tool_use` has been read
|
|
39
39
|
* and whose `tool_result` has not (`pending`). Both are persisted beside the
|
|
40
|
-
* source's read cursor (`dispatch_source_cursors.claims`): a
|
|
40
|
+
* source's read cursor (`dispatch_source_cursors.claims`): a relay that restarts
|
|
41
41
|
* resumes at its stored `acked` offset, and a pickup that sits before it is never
|
|
42
42
|
* re-read, so without the state every later reply would go unattributed. The
|
|
43
43
|
* pending half closes the narrow window where the restart lands between a pickup's
|
|
@@ -133,7 +133,7 @@ function transitionOf(block) {
|
|
|
133
133
|
}
|
|
134
134
|
/**
|
|
135
135
|
* The per-process claim tracker: one state per sub-agent source. Fed every
|
|
136
|
-
* transcript line by `DispatchUsage` (operator-bridge mode only — the worker never
|
|
136
|
+
* transcript line by `DispatchUsage` (`operator-bridge` mode only — the worker never
|
|
137
137
|
* constructs one), seeded from the stored cursor at attach, and snapshotted per
|
|
138
138
|
* source for the stats write.
|
|
139
139
|
*/
|
package/dist/dispatch-usage.d.ts
CHANGED
|
@@ -37,8 +37,9 @@ export type FlushOutcome = "ok" | "failed" | "refused";
|
|
|
37
37
|
* dispatch by refusing the WHOLE batch, which would stall the worker's stats,
|
|
38
38
|
* token ceiling and spend alert on every resend - so a worker is structurally
|
|
39
39
|
* unable to send one.
|
|
40
|
-
* - `"operator-bridge"` - the
|
|
41
|
-
* (`danx-dashboard-mcp`'s `session-stats.ts`), the only path that attributes.
|
|
40
|
+
* - `"operator-bridge"` - the plan event relay of an operator session
|
|
41
|
+
* (`danx-dashboard-mcp`'s `session-stats.ts`), the only path that attributes. The value keeps its old name on purpose: it is
|
|
42
|
+
* this package's published API (the MCP package passes it), so renaming it is a new telemetry release, not a text fix.
|
|
42
43
|
*/
|
|
43
44
|
export type DispatchUsageMode = "worker" | "operator-bridge";
|
|
44
45
|
export declare class DispatchUsage {
|
package/dist/index.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* (small per-reply bookkeeping only, kept in memory for the life of the
|
|
7
7
|
* process — see `session-log-watcher.ts`'s header). Consumed by the
|
|
8
8
|
* danxbot worker (Node, workspace-linked — see the README) and, from
|
|
9
|
-
* DX-2954, the `danx-dashboard-mcp`
|
|
9
|
+
* DX-2954, the `danx-dashboard-mcp` MCP server's plan event relay (Node, npm-installed at
|
|
10
10
|
* a pinned exact version).
|
|
11
11
|
*
|
|
12
12
|
* A browser-safe subset with NO `node:` imports lives at the `./browser`
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* (small per-reply bookkeeping only, kept in memory for the life of the
|
|
7
7
|
* process — see `session-log-watcher.ts`'s header). Consumed by the
|
|
8
8
|
* danxbot worker (Node, workspace-linked — see the README) and, from
|
|
9
|
-
* DX-2954, the `danx-dashboard-mcp`
|
|
9
|
+
* DX-2954, the `danx-dashboard-mcp` MCP server's plan event relay (Node, npm-installed at
|
|
10
10
|
* a pinned exact version).
|
|
11
11
|
*
|
|
12
12
|
* A browser-safe subset with NO `node:` imports lives at the `./browser`
|
|
@@ -28,7 +28,7 @@ export * from "./ledger-timing.js";
|
|
|
28
28
|
export * from "./transcript-timing.js";
|
|
29
29
|
export * from "./pricing.js";
|
|
30
30
|
// DX-2954 — the ONE stats collector and its wire, shared by the danxbot worker
|
|
31
|
-
// and the
|
|
31
|
+
// and the MCP server's relay (operator sessions) so both report the same stats the
|
|
32
32
|
// same way (epic DX-2958): the stats payload/response schema and its strict
|
|
33
33
|
// parser, the collector that ships ledger entries + transcript cursors +
|
|
34
34
|
// running-set changes, the transcript-side running-set producer, and the FIFO
|
package/dist/internal-logger.js
CHANGED
|
@@ -12,10 +12,10 @@ function emit(level, component, message, error) {
|
|
|
12
12
|
else if (error !== undefined) {
|
|
13
13
|
entry.error = String(error);
|
|
14
14
|
}
|
|
15
|
-
// DX-2954 — every level goes to STDERR. The
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
15
|
+
// DX-2954 — every level goes to STDERR. The MCP server's
|
|
16
|
+
// relay and the one-shot subcommands run this collector; the subcommands' STDOUT is a protocol
|
|
17
|
+
// channel the plugin parses (and the MCP server's is JSON-RPC), so a log line there
|
|
18
|
+
// would corrupt it. The worker captures both streams.
|
|
19
19
|
console.error(JSON.stringify(entry));
|
|
20
20
|
}
|
|
21
21
|
export function createLogger(component) {
|
package/dist/pricing.d.ts
CHANGED
|
@@ -114,28 +114,15 @@ export type PriceResult = {
|
|
|
114
114
|
* cleanly, whatever its id looks like.
|
|
115
115
|
*/
|
|
116
116
|
export declare function priceUsage(model: string, speed: string, tokens: PricedTokens): PriceResult;
|
|
117
|
-
/**
|
|
118
|
-
* The list price `priceUsage` charges for a model at a speed (a fast request on a model that bills fast at the standard rate reads the
|
|
119
|
-
* standard table), or `null` when the tables have none. The default `PriceLookup` of {@link priceLedgerCredit}.
|
|
120
|
-
*/
|
|
121
|
-
export declare function listedPrice(model: string, speed: string): ModelPrice | null;
|
|
122
|
-
/**
|
|
123
|
-
* DX-4595 - dollars for `tokens` at `price` (USD per million tokens): each bucket with its own price. The ONE copy of the formula: `priceUsage`
|
|
124
|
-
* charges the list price with it, and spend pacing charges an account's own (editable) prices with it.
|
|
125
|
-
*/
|
|
126
|
-
export declare function costOfTokens(tokens: PricedTokens, price: ModelPrice): number;
|
|
127
117
|
/** True when `model` has a standard-speed price (used by tests + guards). */
|
|
128
118
|
export declare function isPricedModel(model: string): boolean;
|
|
129
|
-
/** What a model costs at a speed, per million tokens; `null` when there is no price. */
|
|
130
|
-
export type PriceLookup = (model: string, speed: string) => ModelPrice | null;
|
|
131
119
|
/**
|
|
132
120
|
* DX-4508 — one ledger credit's cost, exactly as the server's usage-ledger writer stores it (moved here from
|
|
133
121
|
* `src/dashboard/usage-ledger.ts` so the live sub-agent view, `subagent-live.ts`, prices a reply with the SAME rule
|
|
134
122
|
* instead of a copy): a `<synthetic>` reply costs nothing and is never unpriced; a reply with no model is unpriced only
|
|
135
|
-
* when it carries tokens; any other model
|
|
136
|
-
* one costing 0 and naming itself. DX-4595: spend pacing passes an account's own prices as `priceOf` and so gets the same rule.
|
|
123
|
+
* when it carries tokens; any other model goes through {@link priceUsage}, an unpriced one costing 0 and naming itself.
|
|
137
124
|
*/
|
|
138
|
-
export declare function priceLedgerCredit(model: string | null, speed: string, tokens: PricedTokens
|
|
125
|
+
export declare function priceLedgerCredit(model: string | null, speed: string, tokens: PricedTokens): {
|
|
139
126
|
costUsd: number;
|
|
140
127
|
unpriced: {
|
|
141
128
|
model: string;
|
package/dist/pricing.js
CHANGED
|
@@ -163,29 +163,20 @@ export function listListPrices() {
|
|
|
163
163
|
* cleanly, whatever its id looks like.
|
|
164
164
|
*/
|
|
165
165
|
export function priceUsage(model, speed, tokens) {
|
|
166
|
-
const price = listedPrice(model, speed);
|
|
167
|
-
return price === null ? { kind: "unpriced", model, speed } : { kind: "priced", costUsd: costOfTokens(tokens, price) };
|
|
168
|
-
}
|
|
169
|
-
/**
|
|
170
|
-
* The list price `priceUsage` charges for a model at a speed (a fast request on a model that bills fast at the standard rate reads the
|
|
171
|
-
* standard table), or `null` when the tables have none. The default `PriceLookup` of {@link priceLedgerCredit}.
|
|
172
|
-
*/
|
|
173
|
-
export function listedPrice(model, speed) {
|
|
174
166
|
const useFastTable = speed === FAST_SPEED && !FAST_BILLS_AT_STANDARD_RATE.has(model);
|
|
175
167
|
const table = useFastTable ? FAST_PRICING : PRICING;
|
|
176
|
-
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
1_000_000);
|
|
168
|
+
if (!Object.hasOwn(table, model))
|
|
169
|
+
return { kind: "unpriced", model, speed };
|
|
170
|
+
const p = table[model];
|
|
171
|
+
return {
|
|
172
|
+
kind: "priced",
|
|
173
|
+
costUsd: (tokens.input * p.input +
|
|
174
|
+
tokens.output * p.output +
|
|
175
|
+
tokens.cacheRead * p.cacheRead +
|
|
176
|
+
tokens.cacheWrite5m * p.cacheWrite5m +
|
|
177
|
+
tokens.cacheWrite1h * p.cacheWrite1h) /
|
|
178
|
+
1_000_000,
|
|
179
|
+
};
|
|
189
180
|
}
|
|
190
181
|
/** True when `model` has a standard-speed price (used by tests + guards). */
|
|
191
182
|
export function isPricedModel(model) {
|
|
@@ -197,16 +188,15 @@ export function isPricedModel(model) {
|
|
|
197
188
|
* DX-4508 — one ledger credit's cost, exactly as the server's usage-ledger writer stores it (moved here from
|
|
198
189
|
* `src/dashboard/usage-ledger.ts` so the live sub-agent view, `subagent-live.ts`, prices a reply with the SAME rule
|
|
199
190
|
* instead of a copy): a `<synthetic>` reply costs nothing and is never unpriced; a reply with no model is unpriced only
|
|
200
|
-
* when it carries tokens; any other model
|
|
201
|
-
* one costing 0 and naming itself. DX-4595: spend pacing passes an account's own prices as `priceOf` and so gets the same rule.
|
|
191
|
+
* when it carries tokens; any other model goes through {@link priceUsage}, an unpriced one costing 0 and naming itself.
|
|
202
192
|
*/
|
|
203
|
-
export function priceLedgerCredit(model, speed, tokens
|
|
193
|
+
export function priceLedgerCredit(model, speed, tokens) {
|
|
204
194
|
if (model === SYNTHETIC_MODEL)
|
|
205
195
|
return { costUsd: 0, unpriced: null };
|
|
206
196
|
if (model === null) {
|
|
207
197
|
const zero = tokens.input === 0 && tokens.output === 0 && tokens.cacheRead === 0 && tokens.cacheWrite5m === 0 && tokens.cacheWrite1h === 0;
|
|
208
198
|
return zero ? { costUsd: 0, unpriced: null } : { costUsd: 0, unpriced: { model: "(none)", speed } };
|
|
209
199
|
}
|
|
210
|
-
const
|
|
211
|
-
return
|
|
200
|
+
const r = priceUsage(model, speed, tokens);
|
|
201
|
+
return r.kind === "priced" ? { costUsd: r.costUsd, unpriced: null } : { costUsd: 0, unpriced: { model: r.model, speed: r.speed } };
|
|
212
202
|
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* DX-2962: moved unchanged from danxbot root `src/agent/session-log-watcher.ts`
|
|
5
5
|
* into this shared published package, so the danxbot worker and the
|
|
6
|
-
* `danx-dashboard-mcp`
|
|
6
|
+
* `danx-dashboard-mcp` MCP server's relay (DX-2954) run identical collector
|
|
7
7
|
* code. Only the imports changed — `../logger.js` -> `./internal-logger.js`
|
|
8
8
|
* (this package's own tiny logging shim, since root's `logger.ts` has ~300
|
|
9
9
|
* unrelated consumers and does not move), `../types.js` -> `./types.js`
|
|
@@ -408,7 +408,7 @@ export declare class SessionLogWatcher {
|
|
|
408
408
|
/**
|
|
409
409
|
* DX-3964 - register a usage-feed consumer: it receives the parsed raw line of every assistant, user,
|
|
410
410
|
* attachment and system line, in file order, with the same `EntryMeta` as `onEntry`. The ONLY subscribers are
|
|
411
|
-
* the collector's two consumers at each of its two sites (the worker and the operator
|
|
411
|
+
* the collector's two consumers at each of its two sites (the worker and the operator session's relay): `DispatchUsage`
|
|
412
412
|
* and, DX-4498, the activity observer, which reads the sub-agent's brief and Claude Code's task notifications,
|
|
413
413
|
* neither of which is an entry. `convertJsonlEntry` and every
|
|
414
414
|
* `onEntry` subscriber keep seeing exactly what they saw before, because human prompts, attachments (tens of
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* DX-2962: moved unchanged from danxbot root `src/agent/session-log-watcher.ts`
|
|
5
5
|
* into this shared published package, so the danxbot worker and the
|
|
6
|
-
* `danx-dashboard-mcp`
|
|
6
|
+
* `danx-dashboard-mcp` MCP server's relay (DX-2954) run identical collector
|
|
7
7
|
* code. Only the imports changed — `../logger.js` -> `./internal-logger.js`
|
|
8
8
|
* (this package's own tiny logging shim, since root's `logger.ts` has ~300
|
|
9
9
|
* unrelated consumers and does not move), `../types.js` -> `./types.js`
|
|
@@ -624,7 +624,7 @@ export class SessionLogWatcher {
|
|
|
624
624
|
/**
|
|
625
625
|
* DX-3964 - register a usage-feed consumer: it receives the parsed raw line of every assistant, user,
|
|
626
626
|
* attachment and system line, in file order, with the same `EntryMeta` as `onEntry`. The ONLY subscribers are
|
|
627
|
-
* the collector's two consumers at each of its two sites (the worker and the operator
|
|
627
|
+
* the collector's two consumers at each of its two sites (the worker and the operator session's relay): `DispatchUsage`
|
|
628
628
|
* and, DX-4498, the activity observer, which reads the sub-agent's brief and Claude Code's task notifications,
|
|
629
629
|
* neither of which is an entry. `convertJsonlEntry` and every
|
|
630
630
|
* `onEntry` subscriber keep seeing exactly what they saw before, because human prompts, attachments (tens of
|
package/dist/stats-wire.d.ts
CHANGED
|
@@ -121,7 +121,7 @@ export interface ActivityChange {
|
|
|
121
121
|
/**
|
|
122
122
|
* DX-4508 — the card its spawning `Agent` call names: the first card id in its (redacted) `description`, else the
|
|
123
123
|
* first anywhere in its brief; null when neither names one. The name stays `briefIssueId` (and the column
|
|
124
|
-
* `brief_issue_id`): renaming a required wire field would make every
|
|
124
|
+
* `brief_issue_id`): renaming a required wire field would make every relay already published fail the strict parser.
|
|
125
125
|
*/
|
|
126
126
|
briefIssueId: string | null;
|
|
127
127
|
}
|
package/dist/subagent-live.js
CHANGED
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
* DX-4508 — a LOCAL live view of a session's sub-agents, for the plugin's plan pane.
|
|
3
3
|
*
|
|
4
4
|
* The pane shows one card per sub-agent: what it is, what it is doing, and what it has spent. Its dashboard path
|
|
5
|
-
* (`GET /api/plan-sessions/:id/subagents`) lags about 80s behind the transcript (the
|
|
5
|
+
* (`GET /api/plan-sessions/:id/subagents`) lags about 80s behind the transcript (the relay's 5s poll, its 15s
|
|
6
6
|
* heartbeat flush, the pane's 60s read), so the same facts are also computed here, on the operator's own machine, from
|
|
7
7
|
* the transcript files themselves, and streamed by `danx-dashboard-mcp subagents-live` within a poll of being written.
|
|
8
8
|
*
|
|
9
9
|
* ## One place computes each number
|
|
10
10
|
*
|
|
11
|
-
* Nothing here counts or prices on its own. It consumes the SAME two watcher feeds the
|
|
11
|
+
* Nothing here counts or prices on its own. It consumes the SAME two watcher feeds the relay wires
|
|
12
12
|
* (`onSourceDiscovered`, `onUsageLine`) into the SAME producers:
|
|
13
13
|
*
|
|
14
14
|
* | Snapshot field | Computed by | As the dashboard read derives it from |
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
* ## Where the live view differs from the observer's own stamps
|
|
26
26
|
*
|
|
27
27
|
* `startedAt` and `lastActivityAt` come from the sub-agent's own transcript lines (its first and newest `assistant` /
|
|
28
|
-
* `user` line). The observer stamps a start at the moment its watcher DISCOVERED the file, which is right for the
|
|
28
|
+
* `user` line). The observer stamps a start at the moment its watcher DISCOVERED the file, which is right for the relay
|
|
29
29
|
* (its first discovery is the real start, and the server keeps the earliest), but this view reads every file from byte
|
|
30
30
|
* 0 each time it starts, so a discovery stamp would show every finished sub-agent as having started, and been active,
|
|
31
31
|
* just now. The discovery stamp is used only for a sub-agent that has written no line yet.
|
package/dist/usage-ledger.d.ts
CHANGED
|
@@ -45,7 +45,7 @@ export interface LedgerEntry {
|
|
|
45
45
|
toolUseIds: string[];
|
|
46
46
|
/**
|
|
47
47
|
* DX-3962 - the card this reply is credited to, or `null`. Fixed by the
|
|
48
|
-
* reply's FIRST line and never changed by a later one. Only an operator-
|
|
48
|
+
* reply's FIRST line and never changed by a later one. Only an operator-session
|
|
49
49
|
* collector (`DispatchUsage`, `"operator-bridge"` mode) ever sets it; every
|
|
50
50
|
* other producer of an entry carries `null`.
|
|
51
51
|
*/
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thehammer/danx-session-telemetry",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Shared Claude Code transcript collector (DX-2962) — incremental JSONL tailing for the danxbot worker and the danx-dashboard-mcp
|
|
3
|
+
"version": "0.1.43",
|
|
4
|
+
"description": "Shared Claude Code transcript collector (DX-2962) — incremental JSONL tailing for the danxbot worker and the danx-dashboard-mcp MCP server's relay, so both run identical collector code.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "dist/index.js",
|