@mcp-index/sdk 0.3.2 → 0.5.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/CHANGELOG.md +36 -0
- package/README.md +31 -0
- package/dist/src/actionClass.d.ts +98 -0
- package/dist/src/actionClass.d.ts.map +1 -0
- package/dist/src/actionClass.js +350 -0
- package/dist/src/actionClass.js.map +1 -0
- package/dist/src/driftTelemetry.d.ts +89 -0
- package/dist/src/driftTelemetry.d.ts.map +1 -0
- package/dist/src/driftTelemetry.js +262 -0
- package/dist/src/driftTelemetry.js.map +1 -0
- package/dist/src/gate.d.ts +6 -0
- package/dist/src/gate.d.ts.map +1 -1
- package/dist/src/gate.js +26 -2
- package/dist/src/gate.js.map +1 -1
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +4 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/preflight.d.ts +6 -2
- package/dist/src/preflight.d.ts.map +1 -1
- package/dist/src/preflight.js.map +1 -1
- package/dist/src/scan.d.ts.map +1 -1
- package/dist/src/scan.js +4 -1
- package/dist/src/scan.js.map +1 -1
- package/dist/src/wrap.d.ts.map +1 -1
- package/dist/src/wrap.js +4 -3
- package/dist/src/wrap.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,42 @@
|
|
|
3
3
|
All notable changes to the TypeScript SDK. Versioning is semver (0.x: minor =
|
|
4
4
|
additive feature, patch = fix). Backward-compatible additions only in 0.2.0.
|
|
5
5
|
|
|
6
|
+
## [Unreleased]
|
|
7
|
+
|
|
8
|
+
Staged for the next publish — `npm publish` packs the current `README.md`, so these
|
|
9
|
+
ride out automatically with the next version bump (no ad-hoc republish needed).
|
|
10
|
+
|
|
11
|
+
## 0.5.0 — 2026-06-09
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
- **Drift telemetry (M1, opt-in, OFF by default).** On a tool pin or a contract drift the
|
|
15
|
+
gate can emit one one-way signal — salted (HMAC) fingerprints of the server/tool id, the
|
|
16
|
+
contract hashes, the change type, a safety flag, an hour-rounded time, and a random install
|
|
17
|
+
id. Never a schema, argument, description, URL, or server/tool name. Enable with
|
|
18
|
+
`MCPINDEX_DRIFT_TELEMETRY=detection`; fail-open (never blocks or changes a tool call). The
|
|
19
|
+
consent string is exported as `DRIFT_TELEMETRY_NOTICE`.
|
|
20
|
+
|
|
21
|
+
### Docs
|
|
22
|
+
- README "What it does" now documents the default-on blast-radius grade (Tier-0a action
|
|
23
|
+
classification) shipped in 0.4.0, with the `MCPINDEX_ACTION_CLASSIFICATION_ENABLED=0`
|
|
24
|
+
opt-out. (0.4.0 published before the README caught up.)
|
|
25
|
+
|
|
26
|
+
## 0.4.0 — 2026-06-08
|
|
27
|
+
|
|
28
|
+
### Added
|
|
29
|
+
- **Local Tier-0a action classification (blast radius).** The gate now COMPUTES the
|
|
30
|
+
advisory `actionClassification` block locally from the live tool definition — action
|
|
31
|
+
type, resource, side-effect, reversibility, egress, and a static autonomy ceiling —
|
|
32
|
+
instead of leaving it `null` until a hosted verdict supplied one. So the blast-radius
|
|
33
|
+
grade is on by default in the SDK, at parity with the Python `mcpindex-preflight`
|
|
34
|
+
client. Default-on; opt out with `MCPINDEX_ACTION_CLASSIFICATION_ENABLED=0`. Pure,
|
|
35
|
+
deterministic, total, and a byte-for-byte port of the Python `cse.action_class.classify`
|
|
36
|
+
(12-case cross-language golden parity test). **Advisory only** — it rides alongside the
|
|
37
|
+
decision and never moves `PROCEED`/`HOLD` (AD-1). New exports: `classifyAction`,
|
|
38
|
+
`classifyToolDef`, `actionClassificationEnabled`, and the `ActionType` /
|
|
39
|
+
`SideEffectClass` / `Reversibility` / `Egress` / `ScopeHint` / `PatternShape` /
|
|
40
|
+
`AutonomyCeiling` / `NoteClass` / `Severity` / `EvidenceRefType` enums.
|
|
41
|
+
|
|
6
42
|
## 0.3.2 — 2026-06-08
|
|
7
43
|
|
|
8
44
|
### Fixed
|
package/README.md
CHANGED
|
@@ -36,6 +36,11 @@ const guarded = wrap(session); // pins each tool's contract on first use (TOFU
|
|
|
36
36
|
on a benign change (no false alarm).
|
|
37
37
|
- Postures: `Monitor` (notify + proceed) / `Guard` (default; hold dangerous) /
|
|
38
38
|
`Strict` (hold any drift).
|
|
39
|
+
- Grades each call's **blast radius** (Tier-0a action classification) on the verdict:
|
|
40
|
+
action type (read / write / delete / send / …), reversibility, egress, and a static
|
|
41
|
+
autonomy ceiling, computed locally from the live contract. **Advisory** — it rides
|
|
42
|
+
alongside the decision and never moves HOLD/PROCEED. On by default; opt out with
|
|
43
|
+
`MCPINDEX_ACTION_CLASSIFICATION_ENABLED=0`.
|
|
39
44
|
|
|
40
45
|
## What it is NOT
|
|
41
46
|
|
|
@@ -43,6 +48,32 @@ The verdict is a **contract-diff, not a safety oracle** — it tells you the con
|
|
|
43
48
|
*changed* versus your pin, not that the new contract is safe. It does not "block attacks"
|
|
44
49
|
or "guarantee safe." You decide what a HOLD means for your agent.
|
|
45
50
|
|
|
51
|
+
## Drift telemetry (opt-in, OFF by default)
|
|
52
|
+
|
|
53
|
+
The SDK can report **that** a tool's contract drifted — so mcpindex can track drift on servers
|
|
54
|
+
it can't crawl itself (private / auth-gated). It is **off by default and sends nothing** unless
|
|
55
|
+
you turn it on:
|
|
56
|
+
|
|
57
|
+
```sh
|
|
58
|
+
export MCPINDEX_DRIFT_TELEMETRY=detection # off (default) | detection | contribute
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
When enabled, each tool you pin and each contract drift sends **one one-way signal**:
|
|
62
|
+
|
|
63
|
+
- **What it sends:** salted (HMAC) fingerprints of the server/tool id, the contract hashes, the
|
|
64
|
+
change type (the fixed ChangeKind vocabulary), a safety flag, an **hour-rounded** timestamp,
|
|
65
|
+
and a random install id (a token that links one machine's signals so distinct installs can be
|
|
66
|
+
counted — not derived from you).
|
|
67
|
+
- **What it NEVER sends:** tool schemas, arguments, descriptions, URLs, server/tool **names**, or
|
|
68
|
+
any of your data. The payload has no free-text field by construction, and the ingest rejects
|
|
69
|
+
anything that isn't the closed shape.
|
|
70
|
+
- **Fail-open:** telemetry never blocks, slows, or changes a tool call. Losing a signal is always
|
|
71
|
+
preferred to perturbing the gate.
|
|
72
|
+
|
|
73
|
+
`detection` enables the closed signal above; `contribute` is reserved for a future, separately
|
|
74
|
+
opt-in richer tier (it behaves identically today). The full notice is exported as
|
|
75
|
+
`DRIFT_TELEMETRY_NOTICE`. Unset the variable any time to stop.
|
|
76
|
+
|
|
46
77
|
## License
|
|
47
78
|
|
|
48
79
|
PolyForm Noncommercial 1.0.0 — © Bhartis LLC. Free for noncommercial use; commercial use
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tier 0a — the static action classifier (TS port of `cse.action_class`).
|
|
3
|
+
*
|
|
4
|
+
* Grades the *action* a tool would take (its blast radius), not just whether the
|
|
5
|
+
* tool is trustworthy. Pure, deterministic, model-free, total (never throws on
|
|
6
|
+
* hostile input). Reuses the structural risk leg (`risk.assess`) + the name-token
|
|
7
|
+
* lexicon (`lexicon.nameTokens`) and maps them into the spec's action-classification
|
|
8
|
+
* schema (action_type / resource / side-effect / reversibility / egress + a STATIC,
|
|
9
|
+
* fail-closed autonomy_ceiling).
|
|
10
|
+
*
|
|
11
|
+
* ADVISORY only: it rides ALONGSIDE the gate decision and NEVER moves PROCEED/HOLD.
|
|
12
|
+
* The `autonomy_ceiling` here is the STATIC cold-start default; the calibration-backed
|
|
13
|
+
* ceiling lives in the private moat and is structurally unreachable from the SDK.
|
|
14
|
+
*
|
|
15
|
+
* Cross-language parity: the value tables and derivation ladder mirror
|
|
16
|
+
* `corpus_eval/tooling/cse/action_class.py` byte-for-byte. Keep them in lockstep.
|
|
17
|
+
*/
|
|
18
|
+
import type { ActionClassification, ToolDef } from "./preflight.js";
|
|
19
|
+
export declare enum ActionType {
|
|
20
|
+
READ = "read",
|
|
21
|
+
LIST = "list",
|
|
22
|
+
SEARCH = "search",
|
|
23
|
+
WRITE = "write",
|
|
24
|
+
UPDATE = "update",
|
|
25
|
+
DELETE = "delete",
|
|
26
|
+
SEND = "send",
|
|
27
|
+
EXECUTE = "execute",
|
|
28
|
+
AUTH = "auth",
|
|
29
|
+
ADMIN = "admin",
|
|
30
|
+
UNKNOWN = "unknown"
|
|
31
|
+
}
|
|
32
|
+
export declare enum SideEffectClass {
|
|
33
|
+
NONE = "none",
|
|
34
|
+
LOCAL_WRITE = "local-write",
|
|
35
|
+
OUTBOUND = "outbound",
|
|
36
|
+
DESTRUCTIVE = "destructive"
|
|
37
|
+
}
|
|
38
|
+
export declare enum Reversibility {
|
|
39
|
+
REVERSIBLE = "reversible",
|
|
40
|
+
HARD_TO_REVERSE = "hard-to-reverse",
|
|
41
|
+
IRREVERSIBLE = "irreversible"
|
|
42
|
+
}
|
|
43
|
+
export declare enum Egress {
|
|
44
|
+
NONE = "none",
|
|
45
|
+
INTERNAL = "internal",
|
|
46
|
+
EXTERNAL = "external"
|
|
47
|
+
}
|
|
48
|
+
export declare enum ScopeHint {
|
|
49
|
+
NARROW = "narrow",
|
|
50
|
+
BROAD = "broad",
|
|
51
|
+
UNBOUNDED = "unbounded"
|
|
52
|
+
}
|
|
53
|
+
export declare enum PatternShape {
|
|
54
|
+
LITERAL = "literal",
|
|
55
|
+
SINGLE_ARG = "single-arg",
|
|
56
|
+
GLOB = "glob",
|
|
57
|
+
WILDCARD = "wildcard",
|
|
58
|
+
TEMPLATED = "templated"
|
|
59
|
+
}
|
|
60
|
+
export declare enum AutonomyCeiling {
|
|
61
|
+
DISCOVERY = "discovery",
|
|
62
|
+
REVERSIBLE = "reversible",
|
|
63
|
+
NEEDS_APPROVAL = "needs-approval",
|
|
64
|
+
NEVER_UNATTENDED = "never-unattended"
|
|
65
|
+
}
|
|
66
|
+
export declare enum NoteClass {
|
|
67
|
+
DESTRUCTIVE_NO_UNDO_PATH = "destructive_no_undo_path",
|
|
68
|
+
ANNOTATION_CONTRADICTS_PROBE = "annotation_contradicts_probe",
|
|
69
|
+
KNOWN_CVE = "known_cve",
|
|
70
|
+
OBSERVED_EXFIL = "observed_exfil",
|
|
71
|
+
SCOPE_ESCAPE = "scope_escape"
|
|
72
|
+
}
|
|
73
|
+
export declare enum Severity {
|
|
74
|
+
LOW = "low",
|
|
75
|
+
MEDIUM = "medium",
|
|
76
|
+
HIGH = "high"
|
|
77
|
+
}
|
|
78
|
+
export declare enum EvidenceRefType {
|
|
79
|
+
PROBE = "probe",
|
|
80
|
+
SCHEMA_FLAG = "schema_flag",
|
|
81
|
+
CORPUS_CELL = "corpus_cell",
|
|
82
|
+
CVE = "cve"
|
|
83
|
+
}
|
|
84
|
+
/** Precedence ladder, deterministic legs only (annotations advisory-UP + verb-keyword
|
|
85
|
+
* over name). A self-declared readOnlyHint can NEVER lower a class the verb raises;
|
|
86
|
+
* destructiveHint:true floors the effective type at DELETE. No verb match -> UNKNOWN. */
|
|
87
|
+
export declare function deriveActionTypes(name: string, annotations?: unknown): [ActionType[], ActionType];
|
|
88
|
+
/** Static action classification (Tier 0a). Pure, deterministic, total. The
|
|
89
|
+
* autonomy_ceiling is the STATIC cold-start default (basis="static"). */
|
|
90
|
+
export declare function classify(name: string, description: string, inputSchema: unknown, annotations?: unknown): ActionClassification;
|
|
91
|
+
/** Tier 0a feature flag — default ON; opt out by setting the env var to a falsey
|
|
92
|
+
* string. Read at call time (not import) so a toggle takes effect without reimport. */
|
|
93
|
+
export declare function actionClassificationEnabled(env?: Record<string, string | undefined>): boolean;
|
|
94
|
+
/** Convenience wrapper for the gate: classify a live tool definition. Returns null
|
|
95
|
+
* when the flag is off or the definition is unusable (mirrors Python
|
|
96
|
+
* `build_action_classification`). Never throws. */
|
|
97
|
+
export declare function classifyToolDef(name: string, defn: ToolDef | null, env?: Record<string, string | undefined>): ActionClassification | null;
|
|
98
|
+
//# sourceMappingURL=actionClass.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"actionClass.d.ts","sourceRoot":"","sources":["../../src/actionClass.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,OAAO,KAAK,EAAE,oBAAoB,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAIpE,oBAAY,UAAU;IACpB,IAAI,SAAS;IACb,IAAI,SAAS;IACb,MAAM,WAAW;IACjB,KAAK,UAAU;IACf,MAAM,WAAW;IACjB,MAAM,WAAW;IACjB,IAAI,SAAS;IACb,OAAO,YAAY;IACnB,IAAI,SAAS;IACb,KAAK,UAAU;IACf,OAAO,YAAY;CACpB;AAED,oBAAY,eAAe;IACzB,IAAI,SAAS;IACb,WAAW,gBAAgB;IAC3B,QAAQ,aAAa;IACrB,WAAW,gBAAgB;CAC5B;AAED,oBAAY,aAAa;IACvB,UAAU,eAAe;IACzB,eAAe,oBAAoB;IACnC,YAAY,iBAAiB;CAC9B;AAED,oBAAY,MAAM;IAChB,IAAI,SAAS;IACb,QAAQ,aAAa;IACrB,QAAQ,aAAa;CACtB;AAED,oBAAY,SAAS;IACnB,MAAM,WAAW;IACjB,KAAK,UAAU;IACf,SAAS,cAAc;CACxB;AAED,oBAAY,YAAY;IACtB,OAAO,YAAY;IACnB,UAAU,eAAe;IACzB,IAAI,SAAS;IACb,QAAQ,aAAa;IACrB,SAAS,cAAc;CACxB;AAED,oBAAY,eAAe;IACzB,SAAS,cAAc;IACvB,UAAU,eAAe;IACzB,cAAc,mBAAmB;IACjC,gBAAgB,qBAAqB;CACtC;AAED,oBAAY,SAAS;IACnB,wBAAwB,6BAA6B;IACrD,4BAA4B,iCAAiC;IAC7D,SAAS,cAAc;IACvB,cAAc,mBAAmB;IACjC,YAAY,iBAAiB;CAC9B;AAED,oBAAY,QAAQ;IAClB,GAAG,QAAQ;IACX,MAAM,WAAW;IACjB,IAAI,SAAS;CACd;AAED,oBAAY,eAAe;IACzB,KAAK,UAAU;IACf,WAAW,gBAAgB;IAC3B,WAAW,gBAAgB;IAC3B,GAAG,QAAQ;CACZ;AAkED;;yFAEyF;AACzF,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,EACZ,WAAW,GAAE,OAAc,GAC1B,CAAC,UAAU,EAAE,EAAE,UAAU,CAAC,CAc5B;AA8ID;yEACyE;AACzE,wBAAgB,QAAQ,CACtB,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,OAAO,EACpB,WAAW,GAAE,OAAc,GAC1B,oBAAoB,CAqBtB;AAKD;uFACuF;AACvF,wBAAgB,2BAA2B,CAAC,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,GAAG,OAAO,CAG1G;AAED;;mDAEmD;AACnD,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,OAAO,GAAG,IAAI,EACpB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GACvC,oBAAoB,GAAG,IAAI,CAmB7B"}
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tier 0a — the static action classifier (TS port of `cse.action_class`).
|
|
3
|
+
*
|
|
4
|
+
* Grades the *action* a tool would take (its blast radius), not just whether the
|
|
5
|
+
* tool is trustworthy. Pure, deterministic, model-free, total (never throws on
|
|
6
|
+
* hostile input). Reuses the structural risk leg (`risk.assess`) + the name-token
|
|
7
|
+
* lexicon (`lexicon.nameTokens`) and maps them into the spec's action-classification
|
|
8
|
+
* schema (action_type / resource / side-effect / reversibility / egress + a STATIC,
|
|
9
|
+
* fail-closed autonomy_ceiling).
|
|
10
|
+
*
|
|
11
|
+
* ADVISORY only: it rides ALONGSIDE the gate decision and NEVER moves PROCEED/HOLD.
|
|
12
|
+
* The `autonomy_ceiling` here is the STATIC cold-start default; the calibration-backed
|
|
13
|
+
* ceiling lives in the private moat and is structurally unreachable from the SDK.
|
|
14
|
+
*
|
|
15
|
+
* Cross-language parity: the value tables and derivation ladder mirror
|
|
16
|
+
* `corpus_eval/tooling/cse/action_class.py` byte-for-byte. Keep them in lockstep.
|
|
17
|
+
*/
|
|
18
|
+
import { assess, blastRank, BlastRadius, DomainClass } from "./risk.js";
|
|
19
|
+
import { nameTokens } from "./lexicon.js";
|
|
20
|
+
// ----------------------------------------------------------------------- enums
|
|
21
|
+
export var ActionType;
|
|
22
|
+
(function (ActionType) {
|
|
23
|
+
ActionType["READ"] = "read";
|
|
24
|
+
ActionType["LIST"] = "list";
|
|
25
|
+
ActionType["SEARCH"] = "search";
|
|
26
|
+
ActionType["WRITE"] = "write";
|
|
27
|
+
ActionType["UPDATE"] = "update";
|
|
28
|
+
ActionType["DELETE"] = "delete";
|
|
29
|
+
ActionType["SEND"] = "send";
|
|
30
|
+
ActionType["EXECUTE"] = "execute";
|
|
31
|
+
ActionType["AUTH"] = "auth";
|
|
32
|
+
ActionType["ADMIN"] = "admin";
|
|
33
|
+
ActionType["UNKNOWN"] = "unknown";
|
|
34
|
+
})(ActionType || (ActionType = {}));
|
|
35
|
+
export var SideEffectClass;
|
|
36
|
+
(function (SideEffectClass) {
|
|
37
|
+
SideEffectClass["NONE"] = "none";
|
|
38
|
+
SideEffectClass["LOCAL_WRITE"] = "local-write";
|
|
39
|
+
SideEffectClass["OUTBOUND"] = "outbound";
|
|
40
|
+
SideEffectClass["DESTRUCTIVE"] = "destructive";
|
|
41
|
+
})(SideEffectClass || (SideEffectClass = {}));
|
|
42
|
+
export var Reversibility;
|
|
43
|
+
(function (Reversibility) {
|
|
44
|
+
Reversibility["REVERSIBLE"] = "reversible";
|
|
45
|
+
Reversibility["HARD_TO_REVERSE"] = "hard-to-reverse";
|
|
46
|
+
Reversibility["IRREVERSIBLE"] = "irreversible";
|
|
47
|
+
})(Reversibility || (Reversibility = {}));
|
|
48
|
+
export var Egress;
|
|
49
|
+
(function (Egress) {
|
|
50
|
+
Egress["NONE"] = "none";
|
|
51
|
+
Egress["INTERNAL"] = "internal";
|
|
52
|
+
Egress["EXTERNAL"] = "external";
|
|
53
|
+
})(Egress || (Egress = {}));
|
|
54
|
+
export var ScopeHint;
|
|
55
|
+
(function (ScopeHint) {
|
|
56
|
+
ScopeHint["NARROW"] = "narrow";
|
|
57
|
+
ScopeHint["BROAD"] = "broad";
|
|
58
|
+
ScopeHint["UNBOUNDED"] = "unbounded";
|
|
59
|
+
})(ScopeHint || (ScopeHint = {}));
|
|
60
|
+
export var PatternShape;
|
|
61
|
+
(function (PatternShape) {
|
|
62
|
+
PatternShape["LITERAL"] = "literal";
|
|
63
|
+
PatternShape["SINGLE_ARG"] = "single-arg";
|
|
64
|
+
PatternShape["GLOB"] = "glob";
|
|
65
|
+
PatternShape["WILDCARD"] = "wildcard";
|
|
66
|
+
PatternShape["TEMPLATED"] = "templated";
|
|
67
|
+
})(PatternShape || (PatternShape = {}));
|
|
68
|
+
export var AutonomyCeiling;
|
|
69
|
+
(function (AutonomyCeiling) {
|
|
70
|
+
AutonomyCeiling["DISCOVERY"] = "discovery";
|
|
71
|
+
AutonomyCeiling["REVERSIBLE"] = "reversible";
|
|
72
|
+
AutonomyCeiling["NEEDS_APPROVAL"] = "needs-approval";
|
|
73
|
+
AutonomyCeiling["NEVER_UNATTENDED"] = "never-unattended";
|
|
74
|
+
})(AutonomyCeiling || (AutonomyCeiling = {}));
|
|
75
|
+
export var NoteClass;
|
|
76
|
+
(function (NoteClass) {
|
|
77
|
+
NoteClass["DESTRUCTIVE_NO_UNDO_PATH"] = "destructive_no_undo_path";
|
|
78
|
+
NoteClass["ANNOTATION_CONTRADICTS_PROBE"] = "annotation_contradicts_probe";
|
|
79
|
+
NoteClass["KNOWN_CVE"] = "known_cve";
|
|
80
|
+
NoteClass["OBSERVED_EXFIL"] = "observed_exfil";
|
|
81
|
+
NoteClass["SCOPE_ESCAPE"] = "scope_escape";
|
|
82
|
+
})(NoteClass || (NoteClass = {}));
|
|
83
|
+
export var Severity;
|
|
84
|
+
(function (Severity) {
|
|
85
|
+
Severity["LOW"] = "low";
|
|
86
|
+
Severity["MEDIUM"] = "medium";
|
|
87
|
+
Severity["HIGH"] = "high";
|
|
88
|
+
})(Severity || (Severity = {}));
|
|
89
|
+
export var EvidenceRefType;
|
|
90
|
+
(function (EvidenceRefType) {
|
|
91
|
+
EvidenceRefType["PROBE"] = "probe";
|
|
92
|
+
EvidenceRefType["SCHEMA_FLAG"] = "schema_flag";
|
|
93
|
+
EvidenceRefType["CORPUS_CELL"] = "corpus_cell";
|
|
94
|
+
EvidenceRefType["CVE"] = "cve";
|
|
95
|
+
})(EvidenceRefType || (EvidenceRefType = {}));
|
|
96
|
+
// ------------------------------------------------------- derivation primitives
|
|
97
|
+
// Verb token -> action_type. Most-destructive wins on multi-match (see DESTRUCT_RANK).
|
|
98
|
+
const VERB_TO_TYPE = [
|
|
99
|
+
[ActionType.DELETE, new Set("delete remove drop destroy purge wipe truncate prune".split(" "))],
|
|
100
|
+
[ActionType.EXECUTE, new Set("exec execute run eval".split(" "))],
|
|
101
|
+
[ActionType.ADMIN, new Set("provision deploy terminate reboot scale kill".split(" "))],
|
|
102
|
+
[ActionType.AUTH, new Set("authorize grant revoke issue".split(" "))],
|
|
103
|
+
[ActionType.SEND, new Set("send post publish notify dispatch email broadcast tweet sms message".split(" "))],
|
|
104
|
+
[ActionType.WRITE, new Set("write create insert upload put".split(" "))],
|
|
105
|
+
[ActionType.UPDATE, new Set("update modify patch merge set".split(" "))],
|
|
106
|
+
[ActionType.SEARCH, new Set("search query lookup find".split(" "))],
|
|
107
|
+
[ActionType.LIST, new Set("list".split(" "))],
|
|
108
|
+
[ActionType.READ, new Set("get read fetch describe show view".split(" "))],
|
|
109
|
+
];
|
|
110
|
+
// Descending destructiveness — tiebreak for the "effective" action_type and the
|
|
111
|
+
// fail-closed ordering. UNKNOWN is most severe (we could not classify it).
|
|
112
|
+
const DESTRUCT_ORDER = [
|
|
113
|
+
ActionType.UNKNOWN,
|
|
114
|
+
ActionType.DELETE,
|
|
115
|
+
ActionType.EXECUTE,
|
|
116
|
+
ActionType.ADMIN,
|
|
117
|
+
ActionType.AUTH,
|
|
118
|
+
ActionType.SEND,
|
|
119
|
+
ActionType.WRITE,
|
|
120
|
+
ActionType.UPDATE,
|
|
121
|
+
ActionType.SEARCH,
|
|
122
|
+
ActionType.LIST,
|
|
123
|
+
ActionType.READ,
|
|
124
|
+
];
|
|
125
|
+
const DESTRUCT_RANK = new Map(DESTRUCT_ORDER.map((t, i) => [t, i]));
|
|
126
|
+
const READ_TYPES = new Set([
|
|
127
|
+
ActionType.READ,
|
|
128
|
+
ActionType.LIST,
|
|
129
|
+
ActionType.SEARCH,
|
|
130
|
+
]);
|
|
131
|
+
// Defense-in-depth caps on the attacker-controlled tool name + schema.
|
|
132
|
+
const MAX_NAME = 8192; // chars of name tokenized (mirrors risk MAX_TEXT)
|
|
133
|
+
const MAX_PROPS = 512; // top-level schema property keys scanned before fail-closed
|
|
134
|
+
function isPlainObject(x) {
|
|
135
|
+
return typeof x === "object" && x !== null && !Array.isArray(x);
|
|
136
|
+
}
|
|
137
|
+
function intersects(a, b) {
|
|
138
|
+
for (const x of a)
|
|
139
|
+
if (b.has(x))
|
|
140
|
+
return true;
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
/** Read a boolean MCP annotation hint; total, fail-safe (non-object / missing /
|
|
144
|
+
* non-bool -> false). */
|
|
145
|
+
function annotationBool(annotations, key) {
|
|
146
|
+
if (isPlainObject(annotations)) {
|
|
147
|
+
const v = annotations[key];
|
|
148
|
+
if (typeof v === "boolean")
|
|
149
|
+
return v;
|
|
150
|
+
}
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
/** Precedence ladder, deterministic legs only (annotations advisory-UP + verb-keyword
|
|
154
|
+
* over name). A self-declared readOnlyHint can NEVER lower a class the verb raises;
|
|
155
|
+
* destructiveHint:true floors the effective type at DELETE. No verb match -> UNKNOWN. */
|
|
156
|
+
export function deriveActionTypes(name, annotations = null) {
|
|
157
|
+
const tokens = nameTokens(name.slice(0, MAX_NAME));
|
|
158
|
+
const matched = new Set();
|
|
159
|
+
for (const [t, verbs] of VERB_TO_TYPE) {
|
|
160
|
+
if (intersects(tokens, verbs))
|
|
161
|
+
matched.add(t);
|
|
162
|
+
}
|
|
163
|
+
if (annotationBool(annotations, "destructiveHint"))
|
|
164
|
+
matched.add(ActionType.DELETE);
|
|
165
|
+
if (matched.size === 0)
|
|
166
|
+
return [[ActionType.UNKNOWN], ActionType.UNKNOWN];
|
|
167
|
+
const ordered = [...matched].sort((a, b) => (DESTRUCT_RANK.get(a) ?? 0) - (DESTRUCT_RANK.get(b) ?? 0));
|
|
168
|
+
return [ordered, ordered[0]];
|
|
169
|
+
}
|
|
170
|
+
/** Coarse static scope/pattern shape from the schema's top-level params. Conservative:
|
|
171
|
+
* no arg values, no deep walk. Fail-closed for non-trivial / pathological schemas. */
|
|
172
|
+
function scopePattern(inputSchema) {
|
|
173
|
+
if (!isPlainObject(inputSchema))
|
|
174
|
+
return [ScopeHint.BROAD, PatternShape.TEMPLATED];
|
|
175
|
+
const props = inputSchema["properties"];
|
|
176
|
+
if (!isPlainObject(props) || Object.keys(props).length === 0) {
|
|
177
|
+
return [ScopeHint.NARROW, PatternShape.LITERAL];
|
|
178
|
+
}
|
|
179
|
+
const keys = Object.keys(props);
|
|
180
|
+
if (keys.length > MAX_PROPS)
|
|
181
|
+
return [ScopeHint.UNBOUNDED, PatternShape.WILDCARD];
|
|
182
|
+
const names = new Set(keys.map((k) => k.toLowerCase()));
|
|
183
|
+
const globIsh = new Set(["glob", "pattern", "wildcard", "regex"]);
|
|
184
|
+
const multiIsh = new Set(["ids", "keys", "paths", "targets", "filters", "query"]);
|
|
185
|
+
if (intersects(names, globIsh))
|
|
186
|
+
return [ScopeHint.UNBOUNDED, PatternShape.GLOB];
|
|
187
|
+
for (const nm of names) {
|
|
188
|
+
const spec = props[nm];
|
|
189
|
+
if (isPlainObject(spec) && spec["type"] === "array") {
|
|
190
|
+
return [ScopeHint.UNBOUNDED, PatternShape.WILDCARD];
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
if (intersects(names, multiIsh))
|
|
194
|
+
return [ScopeHint.BROAD, PatternShape.WILDCARD];
|
|
195
|
+
return [ScopeHint.NARROW, PatternShape.SINGLE_ARG];
|
|
196
|
+
}
|
|
197
|
+
function sideEffectClass(eff, ra) {
|
|
198
|
+
if (READ_TYPES.has(eff) && ra.looksReadOnly)
|
|
199
|
+
return SideEffectClass.NONE;
|
|
200
|
+
if (eff === ActionType.DELETE || eff === ActionType.EXECUTE || eff === ActionType.ADMIN) {
|
|
201
|
+
return SideEffectClass.DESTRUCTIVE;
|
|
202
|
+
}
|
|
203
|
+
if (ra.domainClass === DomainClass.PAYMENTS)
|
|
204
|
+
return SideEffectClass.DESTRUCTIVE;
|
|
205
|
+
if (eff === ActionType.SEND || ra.domainClass === DomainClass.COMMS) {
|
|
206
|
+
return SideEffectClass.OUTBOUND;
|
|
207
|
+
}
|
|
208
|
+
if (eff === ActionType.WRITE || eff === ActionType.UPDATE || eff === ActionType.AUTH) {
|
|
209
|
+
return SideEffectClass.LOCAL_WRITE;
|
|
210
|
+
}
|
|
211
|
+
// Fallthrough: a read-NAMED tool the risk leg refused to confirm read-only, or an
|
|
212
|
+
// UNKNOWN type. Fail closed to local-write (UNKNOWN is floored to never-unattended
|
|
213
|
+
// downstream by the ceiling).
|
|
214
|
+
return SideEffectClass.LOCAL_WRITE;
|
|
215
|
+
}
|
|
216
|
+
function reversibility(eff, sec) {
|
|
217
|
+
if (eff === ActionType.DELETE ||
|
|
218
|
+
eff === ActionType.EXECUTE ||
|
|
219
|
+
eff === ActionType.ADMIN ||
|
|
220
|
+
eff === ActionType.AUTH) {
|
|
221
|
+
return Reversibility.IRREVERSIBLE;
|
|
222
|
+
}
|
|
223
|
+
if (sec === SideEffectClass.DESTRUCTIVE)
|
|
224
|
+
return Reversibility.IRREVERSIBLE;
|
|
225
|
+
if (sec === SideEffectClass.OUTBOUND || eff === ActionType.WRITE || eff === ActionType.UPDATE) {
|
|
226
|
+
return Reversibility.HARD_TO_REVERSE;
|
|
227
|
+
}
|
|
228
|
+
return Reversibility.REVERSIBLE;
|
|
229
|
+
}
|
|
230
|
+
function egressOf(eff, sec) {
|
|
231
|
+
if (sec === SideEffectClass.OUTBOUND)
|
|
232
|
+
return Egress.EXTERNAL;
|
|
233
|
+
if (READ_TYPES.has(eff) && sec === SideEffectClass.NONE)
|
|
234
|
+
return Egress.NONE;
|
|
235
|
+
return Egress.INTERNAL;
|
|
236
|
+
}
|
|
237
|
+
/** Cold-start fail-closed lattice. UNKNOWN / HIGH-blast-irreversible / execute ->
|
|
238
|
+
* never-unattended; then by side-effect/reversibility, fail-closed. */
|
|
239
|
+
function staticCeiling(eff, sec, rev, blast) {
|
|
240
|
+
if (eff === ActionType.UNKNOWN)
|
|
241
|
+
return AutonomyCeiling.NEVER_UNATTENDED;
|
|
242
|
+
if (rev === Reversibility.IRREVERSIBLE && blastRank(blast) >= blastRank(BlastRadius.HIGH)) {
|
|
243
|
+
return AutonomyCeiling.NEVER_UNATTENDED;
|
|
244
|
+
}
|
|
245
|
+
if (eff === ActionType.EXECUTE)
|
|
246
|
+
return AutonomyCeiling.NEVER_UNATTENDED;
|
|
247
|
+
if (rev === Reversibility.IRREVERSIBLE || sec === SideEffectClass.OUTBOUND) {
|
|
248
|
+
return AutonomyCeiling.NEEDS_APPROVAL;
|
|
249
|
+
}
|
|
250
|
+
if (sec === SideEffectClass.LOCAL_WRITE || rev === Reversibility.HARD_TO_REVERSE) {
|
|
251
|
+
return AutonomyCeiling.REVERSIBLE;
|
|
252
|
+
}
|
|
253
|
+
return AutonomyCeiling.DISCOVERY;
|
|
254
|
+
}
|
|
255
|
+
function resourceKind(ra) {
|
|
256
|
+
return ra.domainClass !== DomainClass.UNKNOWN ? ra.domainClass : "unknown";
|
|
257
|
+
}
|
|
258
|
+
function evidence(ra, eff) {
|
|
259
|
+
const refs = [];
|
|
260
|
+
if (ra.nameWriteish)
|
|
261
|
+
refs.push({ ref_type: EvidenceRefType.SCHEMA_FLAG, ref_id: "name_writeish" });
|
|
262
|
+
if (ra.hasWritePayloadParam) {
|
|
263
|
+
refs.push({ ref_type: EvidenceRefType.SCHEMA_FLAG, ref_id: "write_payload_param" });
|
|
264
|
+
}
|
|
265
|
+
if (ra.requiresCredential) {
|
|
266
|
+
refs.push({ ref_type: EvidenceRefType.SCHEMA_FLAG, ref_id: "requires_credential" });
|
|
267
|
+
}
|
|
268
|
+
if (ra.domainClass !== DomainClass.UNKNOWN) {
|
|
269
|
+
refs.push({ ref_type: EvidenceRefType.SCHEMA_FLAG, ref_id: `domain.${ra.domainClass}` });
|
|
270
|
+
}
|
|
271
|
+
refs.push({ ref_type: EvidenceRefType.SCHEMA_FLAG, ref_id: `action.${eff}` });
|
|
272
|
+
return refs.slice(0, 16);
|
|
273
|
+
}
|
|
274
|
+
function riskNotes(eff, sec, annotations) {
|
|
275
|
+
const notes = [];
|
|
276
|
+
if (annotationBool(annotations, "readOnlyHint") && sec !== SideEffectClass.NONE) {
|
|
277
|
+
notes.push({
|
|
278
|
+
note_class: NoteClass.ANNOTATION_CONTRADICTS_PROBE,
|
|
279
|
+
severity: Severity.HIGH,
|
|
280
|
+
source: { ref_type: EvidenceRefType.SCHEMA_FLAG, ref_id: "readonly_hint_vs_writeish" },
|
|
281
|
+
provenance: "derived",
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
if (sec === SideEffectClass.DESTRUCTIVE) {
|
|
285
|
+
notes.push({
|
|
286
|
+
note_class: NoteClass.DESTRUCTIVE_NO_UNDO_PATH,
|
|
287
|
+
severity: Severity.MEDIUM,
|
|
288
|
+
source: { ref_type: EvidenceRefType.SCHEMA_FLAG, ref_id: `action.${eff}` },
|
|
289
|
+
provenance: "derived",
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
return notes;
|
|
293
|
+
}
|
|
294
|
+
/** Static action classification (Tier 0a). Pure, deterministic, total. The
|
|
295
|
+
* autonomy_ceiling is the STATIC cold-start default (basis="static"). */
|
|
296
|
+
export function classify(name, description, inputSchema, annotations = null) {
|
|
297
|
+
const ra = assess(name, description, inputSchema);
|
|
298
|
+
const [types, eff] = deriveActionTypes(name, annotations);
|
|
299
|
+
const [scope, pattern] = scopePattern(inputSchema);
|
|
300
|
+
const sec = sideEffectClass(eff, ra);
|
|
301
|
+
const rev = reversibility(eff, sec);
|
|
302
|
+
const egress = egressOf(eff, sec);
|
|
303
|
+
const ceiling = staticCeiling(eff, sec, rev, ra.blastRadius);
|
|
304
|
+
return {
|
|
305
|
+
action_types: types,
|
|
306
|
+
effective_action_type: eff,
|
|
307
|
+
resource: { kind: resourceKind(ra), pattern, scope_hint: scope },
|
|
308
|
+
side_effect_class: sec,
|
|
309
|
+
reversibility: rev,
|
|
310
|
+
egress,
|
|
311
|
+
autonomy_ceiling: ceiling,
|
|
312
|
+
autonomy_ceiling_basis: "static",
|
|
313
|
+
known_risk_notes: riskNotes(eff, sec, annotations),
|
|
314
|
+
evidence: evidence(ra, eff),
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
const ACTION_CLASS_ENV = "MCPINDEX_ACTION_CLASSIFICATION_ENABLED";
|
|
318
|
+
const FALSEY = new Set(["0", "false", "no", "off"]);
|
|
319
|
+
/** Tier 0a feature flag — default ON; opt out by setting the env var to a falsey
|
|
320
|
+
* string. Read at call time (not import) so a toggle takes effect without reimport. */
|
|
321
|
+
export function actionClassificationEnabled(env = process.env) {
|
|
322
|
+
const raw = (env[ACTION_CLASS_ENV] ?? "").trim().toLowerCase();
|
|
323
|
+
return !FALSEY.has(raw);
|
|
324
|
+
}
|
|
325
|
+
/** Convenience wrapper for the gate: classify a live tool definition. Returns null
|
|
326
|
+
* when the flag is off or the definition is unusable (mirrors Python
|
|
327
|
+
* `build_action_classification`). Never throws. */
|
|
328
|
+
export function classifyToolDef(name, defn, env) {
|
|
329
|
+
if (!actionClassificationEnabled(env))
|
|
330
|
+
return null;
|
|
331
|
+
if (defn === null || !name)
|
|
332
|
+
return null;
|
|
333
|
+
try {
|
|
334
|
+
const d = defn;
|
|
335
|
+
const rawDesc = d["description"];
|
|
336
|
+
// Mirror Python `str(defn.get("description", ""))`: identical for the normal string
|
|
337
|
+
// case; a non-string description is malformed/hostile, so stringify its CONTENT (never
|
|
338
|
+
// "[object Object]") so embedded text is still scanned — the grade can't be suppressed by
|
|
339
|
+
// sending a non-string. Security-conservative; never fail-open to a lower blast radius.
|
|
340
|
+
const description = typeof rawDesc === "string" ? rawDesc : rawDesc == null ? "" : JSON.stringify(rawDesc);
|
|
341
|
+
// Mirror Python `schema if isinstance(schema, dict) else {}`: a tool with no (or a
|
|
342
|
+
// non-object) inputSchema grades identically here and on the server.
|
|
343
|
+
const inputSchema = isPlainObject(d["inputSchema"]) ? d["inputSchema"] : {};
|
|
344
|
+
return classify(name, description, inputSchema, d["annotations"]);
|
|
345
|
+
}
|
|
346
|
+
catch {
|
|
347
|
+
return null;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
//# sourceMappingURL=actionClass.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"actionClass.js","sourceRoot":"","sources":["../../src/actionClass.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Drift telemetry — the detection-tier emit (M1 of the usage-log drift flywheel).
|
|
3
|
+
*
|
|
4
|
+
* Opt-in (`MCPINDEX_DRIFT_TELEMETRY` ∈ {off,detection,contribute}, default off),
|
|
5
|
+
* fire-and-forget, fail-OPEN. On a TOFU pin (coverage) or a classified drift (outcome),
|
|
6
|
+
* emit a CLOSED, privacy-by-construction signal: salted fingerprints + change enums +
|
|
7
|
+
* content hashes ONLY — NEVER a schema, an argument, a URL, or a plaintext server/tool
|
|
8
|
+
* name. Mirrors the `outcomes.ts` discipline: the only thing that ever leaves the device
|
|
9
|
+
* is a safe projection built by construction, not a redaction of a richer record.
|
|
10
|
+
*
|
|
11
|
+
* PRIVACY INVARIANT (enforced by construction + the leak test): the DriftSignal has no
|
|
12
|
+
* field that can hold a raw string from the tool's schema/args/description.
|
|
13
|
+
* - server_fp / tool_fp are HMAC-SHA256 fingerprints under a GLOBAL salt. Global salt =>
|
|
14
|
+
* a public server_id is de-anonymizable by anyone who can guess it (ACCEPTED — public
|
|
15
|
+
* servers are public); a private/internal server_id is unreversible (PROTECTED).
|
|
16
|
+
* - prev_hash / new_hash are the gate's own `definition_hash` — already a SHA over the
|
|
17
|
+
* canonical contract, public-by-design (it is what the verdict is keyed on).
|
|
18
|
+
* - change_kinds is the closed `ChangeKind` enum vocabulary; safety_relevant is a bool.
|
|
19
|
+
* - at_hour is coarsened to the hour (no sub-hour timing fingerprint).
|
|
20
|
+
*
|
|
21
|
+
* The emit path NEVER blocks on the network and NEVER throws: it appends to a bounded ring
|
|
22
|
+
* buffer and returns; a single unref'd timer flushes batches in the background. A flush
|
|
23
|
+
* failure DROPS the batch (no retry) — losing telemetry is always preferable to perturbing
|
|
24
|
+
* a tool call. Telemetry is a SINGLETON across every Gate (one buffer, one timer).
|
|
25
|
+
*
|
|
26
|
+
* Byte-identical fingerprints to the Python port `tooling/cse/drift_telemetry.py` — the
|
|
27
|
+
* cross-language parity test pins this.
|
|
28
|
+
*/
|
|
29
|
+
import type { Change } from "./schemaDiff.js";
|
|
30
|
+
export type DriftMode = "off" | "detection" | "contribute";
|
|
31
|
+
/** The canonical human-readable consent notice — the single source of truth for the README
|
|
32
|
+
* and the future first-run prompt (M5). Byte-identical to the Python `DRIFT_TELEMETRY_NOTICE`. */
|
|
33
|
+
export declare const DRIFT_TELEMETRY_NOTICE: string;
|
|
34
|
+
/** The CLOSED wire payload. Every field is a fingerprint, a content hash, a closed enum,
|
|
35
|
+
* a bool, an hour-stamp, or the opaque install id — never a raw tool string. */
|
|
36
|
+
export interface DriftSignal {
|
|
37
|
+
readonly v: 1;
|
|
38
|
+
readonly event: "pin" | "drift";
|
|
39
|
+
readonly server_fp: string;
|
|
40
|
+
readonly tool_fp: string;
|
|
41
|
+
readonly prev_hash: string | null;
|
|
42
|
+
readonly new_hash: string;
|
|
43
|
+
readonly change_kinds: string[] | null;
|
|
44
|
+
readonly safety_relevant: boolean;
|
|
45
|
+
readonly at_hour: string;
|
|
46
|
+
readonly sdk: string;
|
|
47
|
+
readonly install_id: string;
|
|
48
|
+
}
|
|
49
|
+
export type DriftTransport = (batch: DriftSignal[]) => Promise<void>;
|
|
50
|
+
/** HMAC-SHA256(GLOBAL_SALT, msg) hex, truncated to 16 bytes (32 hex chars). Byte-identical
|
|
51
|
+
* to the Python `_fingerprint`. */
|
|
52
|
+
export declare function fingerprint(msg: string): string;
|
|
53
|
+
export declare function serverFp(serverId: string): string;
|
|
54
|
+
export declare function toolFp(serverId: string, toolName: string): string;
|
|
55
|
+
/** Coarsen an ISO-8601 stamp to the hour: "2026-06-09T05:09:46.123Z" → "2026-06-09T05:00:00Z".
|
|
56
|
+
* Returns "" on any unexpected shape (never leaks sub-hour precision; never throws). Mirrors
|
|
57
|
+
* the Python `_at_hour`. */
|
|
58
|
+
export declare function atHour(nowIso: string): string;
|
|
59
|
+
/** Build the coverage (pin) signal. Pure — exported for the leak/parity tests. */
|
|
60
|
+
export declare function buildPinSignal(serverId: string, toolName: string, definitionHash: string, nowIso: string, installId: string): DriftSignal;
|
|
61
|
+
/** Build the outcome (drift) signal. Pure — exported for the leak/parity tests. The change
|
|
62
|
+
* details (path/detail strings, which CAN carry tool text) are DROPPED here by construction;
|
|
63
|
+
* only the closed `kind` enum and the `safetyRelevant` bool survive. */
|
|
64
|
+
export declare function buildDriftSignal(serverId: string, toolName: string, prevHash: string, newHash: string, changes: readonly Change[], nowIso: string, installId: string): DriftSignal;
|
|
65
|
+
/** The singleton emit engine. One per process; every Gate shares it. */
|
|
66
|
+
declare class DriftTelemetry {
|
|
67
|
+
private buffer;
|
|
68
|
+
private timer;
|
|
69
|
+
private flushing;
|
|
70
|
+
private mode;
|
|
71
|
+
private cachedInstallId;
|
|
72
|
+
private transport;
|
|
73
|
+
private resolveMode;
|
|
74
|
+
enabled(): boolean;
|
|
75
|
+
private installId;
|
|
76
|
+
private enqueue;
|
|
77
|
+
/** Drain the buffer and POST it. Best-effort: a transport failure drops the batch with no
|
|
78
|
+
* retry (fail-open). Never throws. */
|
|
79
|
+
flush(): Promise<void>;
|
|
80
|
+
recordPin(serverId: string, toolName: string, definitionHash: string, nowIso: string): void;
|
|
81
|
+
recordDrift(serverId: string, toolName: string, prevHash: string, newHash: string, changes: readonly Change[], nowIso: string): void;
|
|
82
|
+
_setTransport(t: DriftTransport): void;
|
|
83
|
+
_reset(): void;
|
|
84
|
+
_drainForTest(): DriftSignal[];
|
|
85
|
+
}
|
|
86
|
+
/** Process-wide singleton. The Gate calls `driftTelemetry.recordPin/recordDrift`. */
|
|
87
|
+
export declare const driftTelemetry: DriftTelemetry;
|
|
88
|
+
export {};
|
|
89
|
+
//# sourceMappingURL=driftTelemetry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"driftTelemetry.d.ts","sourceRoot":"","sources":["../../src/driftTelemetry.ts"],"names":[],"mappings":"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"}
|