ai-agent-detect 0.0.1 → 0.1.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/README.md +48 -12
- package/agents/claude-code/index.js +24 -0
- package/agents/grok/index.js +17 -0
- package/agents/index.js +5 -0
- package/fixtures/claude-code.json +41 -0
- package/fixtures/grok.json +51 -0
- package/index.d.ts +37 -0
- package/index.js +139 -5
- package/package.json +28 -3
package/README.md
CHANGED
|
@@ -1,22 +1,58 @@
|
|
|
1
1
|
# ai-agent-detect
|
|
2
2
|
|
|
3
|
-
Detect which AI agent is running your code — structured identity
|
|
3
|
+
Detect which AI agent is running your code — structured identity, not just a boolean.
|
|
4
4
|
|
|
5
|
-
**Status:
|
|
5
|
+
**Status: working prototype.** The code runs (19 tests, 2 live-probed agents); the API may still shift before `0.1.0`.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
```js
|
|
8
|
+
import { detect, isAgent } from 'ai-agent-detect';
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
isAgent(); // boolean — the new isatty()
|
|
11
|
+
isAgent('claude-code'); // assert style: am I running under this one?
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
-
|
|
14
|
-
|
|
13
|
+
detect();
|
|
14
|
+
// {
|
|
15
|
+
// name: 'claude-code', vendor: 'anthropic',
|
|
16
|
+
// version: '2.1.205', mode: 'agent',
|
|
17
|
+
// source: 'env:AI_AGENT', confidence: 'high', corroborated: true,
|
|
18
|
+
// raw: { AI_AGENT: 'claude-code_2-1-205_agent', CLAUDECODE: '1', ... },
|
|
19
|
+
// claims: [ ... ] // every claim the env carries — see below
|
|
20
|
+
// }
|
|
21
|
+
```
|
|
15
22
|
|
|
16
|
-
##
|
|
23
|
+
## Why claims, not a single winner
|
|
17
24
|
|
|
18
|
-
|
|
25
|
+
Agents run agents. A grok session spawned inside a Claude Code session passes the inherited `AI_AGENT` through to its children (live-probed) — environment variables cannot tell you which *layer* set them. So `detect()` reports **every claim** the env carries and never silently picks between conflicting ones. The env cannot order nesting layers, so `claims[]` doesn't pretend to; genuine stack ordering (via process-tree walk) is `detectDeep()`'s job — planned, `ai-agent-detect/node` subpath.
|
|
19
26
|
|
|
20
|
-
|
|
27
|
+
Every claim carries its evidence: `source` (which signal matched), `raw` (the matched variables), `confidence`. Apply your own trust policy instead of inheriting ours.
|
|
28
|
+
|
|
29
|
+
## What it reads
|
|
30
|
+
|
|
31
|
+
1. **`AI_AGENT`** — both value dialects in the wild: `name@version` (Vercel's spec: `devin@1`) and `name_version_mode` (Anthropic ships `claude-code_2-1-205_agent`).
|
|
32
|
+
2. **`AGENT`** — the older convention, value-split: `AGENT=goose` names the agent; `AGENT=1` (opencode) proves agenthood without naming it — `isAgent()` true, every assert form false.
|
|
33
|
+
3. **Vendor tells** — per-agent detector functions. Code, not a condition engine: the claude-code detector recovers the version from `CLAUDE_CODE_EXECPATH` when `AI_AGENT` is stripped; no declarative rule format can express that.
|
|
34
|
+
|
|
35
|
+
## Supported agents
|
|
36
|
+
|
|
37
|
+
| agent | signals | evidence |
|
|
38
|
+
|---|---|---|
|
|
39
|
+
| claude-code | `AI_AGENT` triple, `CLAUDECODE=1`, version via `CLAUDE_CODE_EXECPATH` | live-probed 2026-07-12 |
|
|
40
|
+
| grok | **none** — sets no identity variable (and passes inherited `AI_AGENT` through) | live-probed 2026-07-12 |
|
|
41
|
+
|
|
42
|
+
grok's entry is deliberate: an agent that cannot be detected from env is recorded as such — honesty over reach. Any agent that sets `AI_AGENT` or a name-valued `AGENT` is detected without a registry entry.
|
|
43
|
+
|
|
44
|
+
## Design
|
|
45
|
+
|
|
46
|
+
- **Zero runtime dependencies**, ESM, Node ≥ 18.
|
|
47
|
+
- **Edge-safe core**: no `node:` imports; env access is guarded (`globalThis.process?.env`), so Workers/Deno/Bun run it and env-less runtimes return `null`. Anything runtime-specific will live behind subpath exports.
|
|
48
|
+
- **Sync and cheap**: no spawn, no disk, no network. `process.env` is copied once per process (it's a proxy — see `bench.js`); `detect()` ≈ 0.5µs, `isAgent(name)` short-circuits at ≈ 0.15µs.
|
|
49
|
+
- **Fixtures are the ground truth**: every registry entry ships a recorded env snapshot with probe date and method (`fixtures/`). The test matrix runs every fixture against every detector — no false positives is as tested as no false negatives.
|
|
50
|
+
|
|
51
|
+
## Contributing an agent
|
|
52
|
+
|
|
53
|
+
One folder, one fixture, one PR:
|
|
54
|
+
|
|
55
|
+
1. `agents/<name>/index.js` — `{ name, vendor, procNames, pidEnvVar, detect(env) }`, registered in `agents/index.js` (alphabetical).
|
|
56
|
+
2. `fixtures/<name>.json` — a recorded env snapshot from a live session (probe date + method required; the matrix test fails any entry without one).
|
|
57
|
+
3. `npm test`.
|
|
21
58
|
|
|
22
|
-
`agent-detect` is held as an alias of this package.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// claude-code (Anthropic) — probed 2026-07-12 (see .kanbento/harnesses/claude-code.md).
|
|
2
|
+
// Sets the full AI_AGENT triple (handled by core rung 1); this detector owns
|
|
3
|
+
// the vendor tells, which also work when AI_AGENT is stripped or inherited-over.
|
|
4
|
+
export default {
|
|
5
|
+
name: 'claude-code',
|
|
6
|
+
vendor: 'anthropic',
|
|
7
|
+
procNames: ['claude'],
|
|
8
|
+
pidEnvVar: null,
|
|
9
|
+
detect(env) {
|
|
10
|
+
if (env.CLAUDECODE !== '1') return null;
|
|
11
|
+
const raw = {};
|
|
12
|
+
for (const key of [
|
|
13
|
+
'CLAUDECODE',
|
|
14
|
+
'CLAUDE_CODE_ENTRYPOINT',
|
|
15
|
+
'CLAUDE_CODE_EXECPATH',
|
|
16
|
+
'CLAUDE_CODE_CHILD_SESSION',
|
|
17
|
+
]) {
|
|
18
|
+
if (env[key] !== undefined) raw[key] = env[key];
|
|
19
|
+
}
|
|
20
|
+
// richer than a condition engine: the exec path carries the version
|
|
21
|
+
const version = env.CLAUDE_CODE_EXECPATH?.match(/\/versions\/(\d[\d.]*)/)?.[1] ?? null;
|
|
22
|
+
return { confidence: 'high', version, raw };
|
|
23
|
+
},
|
|
24
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// grok (xAI) — probed 2026-07-12 (see .kanbento/harnesses/grok.md).
|
|
2
|
+
// Sets NO identity variable (grok 0.2.45, scrubbed-env probe). Its children
|
|
3
|
+
// carry only a non-interactive hygiene bundle (CI=true, pagers off, progress
|
|
4
|
+
// off) — too weak to name an agent; weak-signal use is parked (note:design).
|
|
5
|
+
// It also passes inherited AI_AGENT through — the live proof of nested-harness
|
|
6
|
+
// contamination. Env-undetectable, honestly: this detector never fires.
|
|
7
|
+
export default {
|
|
8
|
+
name: 'grok',
|
|
9
|
+
vendor: 'xai',
|
|
10
|
+
// binary is literally `agent` (~/.grok/bin/agent) — generic name; the ppid
|
|
11
|
+
// rung must corroborate via the executable path, not the name alone
|
|
12
|
+
procNames: ['agent'],
|
|
13
|
+
pidEnvVar: null,
|
|
14
|
+
detect() {
|
|
15
|
+
return null;
|
|
16
|
+
},
|
|
17
|
+
};
|
package/agents/index.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"agent": "claude-code",
|
|
3
|
+
"probes": [
|
|
4
|
+
{
|
|
5
|
+
"date": "2026-07-12",
|
|
6
|
+
"method": "live: env inside a Claude Code background session (v2.1.205, macOS)",
|
|
7
|
+
"tier": "probed",
|
|
8
|
+
"env": {
|
|
9
|
+
"AI_AGENT": "claude-code_2-1-205_agent",
|
|
10
|
+
"CLAUDECODE": "1",
|
|
11
|
+
"CLAUDE_CODE_ENTRYPOINT": "cli",
|
|
12
|
+
"CLAUDE_CODE_EXECPATH": "/Users/user/.local/share/claude/versions/2.1.205",
|
|
13
|
+
"CLAUDE_CODE_CHILD_SESSION": "1"
|
|
14
|
+
},
|
|
15
|
+
"expect": {
|
|
16
|
+
"isAgent": true,
|
|
17
|
+
"primary": "claude-code",
|
|
18
|
+
"version": "2.1.205",
|
|
19
|
+
"mode": "agent",
|
|
20
|
+
"claimNames": ["claude-code"]
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"date": "2026-07-12",
|
|
25
|
+
"method": "synthetic: AI_AGENT stripped — vendor tells only; version recovered from CLAUDE_CODE_EXECPATH",
|
|
26
|
+
"tier": "synthetic",
|
|
27
|
+
"env": {
|
|
28
|
+
"CLAUDECODE": "1",
|
|
29
|
+
"CLAUDE_CODE_ENTRYPOINT": "cli",
|
|
30
|
+
"CLAUDE_CODE_EXECPATH": "/Users/user/.local/share/claude/versions/2.1.205"
|
|
31
|
+
},
|
|
32
|
+
"expect": {
|
|
33
|
+
"isAgent": true,
|
|
34
|
+
"primary": "claude-code",
|
|
35
|
+
"version": "2.1.205",
|
|
36
|
+
"mode": null,
|
|
37
|
+
"claimNames": ["claude-code"]
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"agent": "grok",
|
|
3
|
+
"probes": [
|
|
4
|
+
{
|
|
5
|
+
"date": "2026-07-12",
|
|
6
|
+
"method": "live: agent -p child env (grok 0.2.45, macOS), inherited identity vars scrubbed — grok sets no identity var, only a non-interactive hygiene bundle",
|
|
7
|
+
"tier": "probed",
|
|
8
|
+
"env": {
|
|
9
|
+
"CI": "true",
|
|
10
|
+
"CLICOLOR": "1",
|
|
11
|
+
"CLICOLOR_FORCE": "1",
|
|
12
|
+
"PAGER": "cat",
|
|
13
|
+
"GIT_PAGER": "cat",
|
|
14
|
+
"GH_PAGER": "cat",
|
|
15
|
+
"MANPAGER": "cat",
|
|
16
|
+
"SYSTEMD_PAGER": "cat",
|
|
17
|
+
"AWS_PAGER": "",
|
|
18
|
+
"GIT_TERMINAL_PROMPT": "0",
|
|
19
|
+
"GIT_SEQUENCE_EDITOR": "true",
|
|
20
|
+
"NPM_CONFIG_PROGRESS": "true",
|
|
21
|
+
"PIP_PROGRESS_BAR": "on",
|
|
22
|
+
"CARGO_TERM_PROGRESS_WHEN": "always",
|
|
23
|
+
"CARGO_TERM_PROGRESS_WIDTH": "80"
|
|
24
|
+
},
|
|
25
|
+
"expect": {
|
|
26
|
+
"isAgent": false,
|
|
27
|
+
"primary": null,
|
|
28
|
+
"claimNames": []
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"date": "2026-07-12",
|
|
33
|
+
"method": "live: agent -p spawned INSIDE a Claude Code session, unscrubbed — grok passes inherited AI_AGENT through (nested-harness contamination; env-only detection reports the outer layer by design — detectDeep resolves the stack)",
|
|
34
|
+
"tier": "probed",
|
|
35
|
+
"env": {
|
|
36
|
+
"AI_AGENT": "claude-code_2-1-205_agent",
|
|
37
|
+
"CI": "true",
|
|
38
|
+
"CLICOLOR": "1",
|
|
39
|
+
"PAGER": "cat",
|
|
40
|
+
"GIT_PAGER": "cat",
|
|
41
|
+
"GIT_TERMINAL_PROMPT": "0"
|
|
42
|
+
},
|
|
43
|
+
"expect": {
|
|
44
|
+
"isAgent": true,
|
|
45
|
+
"primary": "claude-code",
|
|
46
|
+
"claimNames": ["claude-code"],
|
|
47
|
+
"note": "honest limitation, not a bug: the inner harness (grok) is env-invisible"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
}
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// Hand-written declarations — no build step for a zero-dep package.
|
|
2
|
+
|
|
3
|
+
export interface AgentClaim {
|
|
4
|
+
/** Canonical agent slug, or null when agenthood is proven but unnamed (e.g. AGENT=1). */
|
|
5
|
+
name: string | null;
|
|
6
|
+
vendor: string | null;
|
|
7
|
+
version: string | null;
|
|
8
|
+
mode: string | null;
|
|
9
|
+
/** Which rung produced this claim. */
|
|
10
|
+
source: 'env:AI_AGENT' | 'env:AGENT' | 'env:vendor';
|
|
11
|
+
confidence: 'high' | 'medium' | 'low';
|
|
12
|
+
/** The matched evidence — the env vars this claim rests on. */
|
|
13
|
+
raw: Record<string, string>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface AgentInfo extends AgentClaim {
|
|
17
|
+
/** Set when an independent signal confirmed the primary claim. */
|
|
18
|
+
corroborated?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Every claim the environment carries, deliberately unordered — env cannot
|
|
21
|
+
* order nesting layers (an outer harness's vars pass through inner ones).
|
|
22
|
+
*/
|
|
23
|
+
claims: AgentClaim[];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface DetectOptions {
|
|
27
|
+
/** Inject an env (tests, snapshots). Defaults to process.env, copied once per process. */
|
|
28
|
+
env?: Record<string, string | undefined>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Structured detection: primary claim + all claims, or null when nothing matches. */
|
|
32
|
+
export function detect(opts?: DetectOptions): AgentInfo | null;
|
|
33
|
+
|
|
34
|
+
/** Am I running under any agent? */
|
|
35
|
+
export function isAgent(opts?: DetectOptions): boolean;
|
|
36
|
+
/** Assert style: am I running under this specific agent? */
|
|
37
|
+
export function isAgent(name: string, opts?: DetectOptions): boolean;
|
package/index.js
CHANGED
|
@@ -1,6 +1,140 @@
|
|
|
1
|
-
// ai-agent-detect
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
// ai-agent-detect — edge-safe core: env-only, sync, zero deps.
|
|
2
|
+
// Detection logic is code; the registry holds facts (see agents/).
|
|
3
|
+
import { agents } from './agents/index.js';
|
|
4
|
+
|
|
5
|
+
const TRUTHY = new Set(['1', 'true', 'yes', 'on']);
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Detect the agent(s) running this process from environment signals.
|
|
9
|
+
* Returns the primary claim plus `claims[]` — every claim the env carries,
|
|
10
|
+
* deliberately unordered: env cannot order nesting layers, so it doesn't
|
|
11
|
+
* pretend to. Genuine stack ordering is detectDeep()'s job (./node).
|
|
12
|
+
*/
|
|
13
|
+
export function detect(opts = {}) {
|
|
14
|
+
const env = snapshot(opts.env);
|
|
15
|
+
const claims = [];
|
|
16
|
+
|
|
17
|
+
// rung 1 — the AI_AGENT standard (two dialects in the wild)
|
|
18
|
+
if (env.AI_AGENT) claims.push(parseAiAgent(env.AI_AGENT));
|
|
19
|
+
|
|
20
|
+
// rung 2 — the AGENT convention (value-split: name-valued vs boolean)
|
|
21
|
+
if (env.AGENT) claims.push(parseAgentVar(env.AGENT));
|
|
22
|
+
|
|
23
|
+
// rung 3 — per-agent vendor tells (code, richer than any condition engine)
|
|
24
|
+
for (const agent of agents) {
|
|
25
|
+
const hit = agent.detect(env);
|
|
26
|
+
if (hit) {
|
|
27
|
+
claims.push({
|
|
28
|
+
name: agent.name,
|
|
29
|
+
vendor: agent.vendor ?? null,
|
|
30
|
+
version: null,
|
|
31
|
+
mode: null,
|
|
32
|
+
source: 'env:vendor',
|
|
33
|
+
confidence: 'high',
|
|
34
|
+
...hit,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (claims.length === 0) return null;
|
|
40
|
+
return { ...merge(claims), claims };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* isAgent() — am I running under any agent?
|
|
45
|
+
* isAgent('claude-code') — am I running under this one? (assert style)
|
|
46
|
+
* An anonymous claim (AGENT=1) proves agenthood without naming the agent:
|
|
47
|
+
* isAgent() is true, every assert form is false.
|
|
48
|
+
*/
|
|
49
|
+
export function isAgent(name, opts) {
|
|
50
|
+
if (name !== undefined && typeof name === 'object') {
|
|
51
|
+
opts = name;
|
|
52
|
+
name = undefined;
|
|
53
|
+
}
|
|
54
|
+
const env = snapshot(opts?.env);
|
|
55
|
+
|
|
56
|
+
// Booleans can't get better with more evidence — short-circuit per rung.
|
|
57
|
+
if (env.AI_AGENT) {
|
|
58
|
+
if (name === undefined) return true;
|
|
59
|
+
if (parseAiAgent(env.AI_AGENT).name === name) return true;
|
|
60
|
+
}
|
|
61
|
+
if (env.AGENT) {
|
|
62
|
+
if (name === undefined) return true;
|
|
63
|
+
if (parseAgentVar(env.AGENT).name === name) return true;
|
|
64
|
+
}
|
|
65
|
+
for (const agent of agents) {
|
|
66
|
+
if (name !== undefined && agent.name !== name) continue;
|
|
67
|
+
if (agent.detect(env)) return true;
|
|
68
|
+
}
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// process.env is a proxy into libuv — every property read crosses it (~12µs
|
|
73
|
+
// per detect() measured vs ~2µs on a plain object). Copying it per call is
|
|
74
|
+
// worse (~26µs: every var crosses the proxy). So: copy ONCE per process —
|
|
75
|
+
// the agent's env verdict is fixed at spawn time anyway. An injected env
|
|
76
|
+
// (tests, custom sources) bypasses the cache.
|
|
77
|
+
let cached;
|
|
78
|
+
function snapshot(env) {
|
|
79
|
+
if (env !== undefined) return env;
|
|
80
|
+
if (cached === undefined) {
|
|
81
|
+
const source = globalThis.process?.env;
|
|
82
|
+
cached = source ? { ...source } : {};
|
|
83
|
+
}
|
|
84
|
+
return cached;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// AI_AGENT value dialects observed in the wild (2026-07-12):
|
|
88
|
+
// Anthropic: name_version_mode claude-code_2-1-205_agent (dashes = dots)
|
|
89
|
+
// Vercel: name[@version] devin@1, custom-agent@2.0, v0
|
|
90
|
+
function parseAiAgent(value) {
|
|
91
|
+
const base = {
|
|
92
|
+
vendor: null,
|
|
93
|
+
version: null,
|
|
94
|
+
mode: null,
|
|
95
|
+
source: 'env:AI_AGENT',
|
|
96
|
+
confidence: 'high',
|
|
97
|
+
raw: { AI_AGENT: value },
|
|
98
|
+
};
|
|
99
|
+
if (value.includes('_')) {
|
|
100
|
+
const [name, version, mode] = value.split('_');
|
|
101
|
+
return {
|
|
102
|
+
...base,
|
|
103
|
+
name: name || null,
|
|
104
|
+
version: version ? version.replaceAll('-', '.') : null,
|
|
105
|
+
mode: mode ?? null,
|
|
106
|
+
confidence: name ? 'high' : 'low',
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
if (value.includes('@')) {
|
|
110
|
+
const at = value.lastIndexOf('@');
|
|
111
|
+
return { ...base, name: value.slice(0, at) || null, version: value.slice(at + 1) || null };
|
|
112
|
+
}
|
|
113
|
+
return { ...base, name: value };
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function parseAgentVar(value) {
|
|
117
|
+
const base = { vendor: null, version: null, mode: null, source: 'env:AGENT', raw: { AGENT: value } };
|
|
118
|
+
if (TRUTHY.has(value.toLowerCase())) {
|
|
119
|
+
// boolean-valued (opencode style): agenthood proven, identity unknown
|
|
120
|
+
return { ...base, name: null, confidence: 'medium' };
|
|
121
|
+
}
|
|
122
|
+
return { ...base, name: value, confidence: 'high' }; // name-valued (goose style)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Primary = first named claim in rung order, enriched by corroborating
|
|
126
|
+
// same-name claims. Anonymous claims never displace a named one.
|
|
127
|
+
function merge(claims) {
|
|
128
|
+
const named = claims.filter((c) => c.name);
|
|
129
|
+
if (named.length === 0) return { ...claims[0] };
|
|
130
|
+
const primary = { ...named[0] };
|
|
131
|
+
for (const claim of named.slice(1)) {
|
|
132
|
+
if (claim.name !== primary.name) continue;
|
|
133
|
+
primary.version ??= claim.version;
|
|
134
|
+
primary.mode ??= claim.mode;
|
|
135
|
+
primary.vendor ??= claim.vendor;
|
|
136
|
+
primary.raw = { ...primary.raw, ...claim.raw };
|
|
137
|
+
primary.corroborated = true;
|
|
138
|
+
}
|
|
139
|
+
return primary;
|
|
6
140
|
}
|
package/package.json
CHANGED
|
@@ -1,22 +1,47 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-agent-detect",
|
|
3
|
-
"version": "0.0
|
|
4
|
-
"description": "Detect which AI agent is running your code — structured identity (name, version, mode)
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Detect which AI agent is running your code — structured identity (name, version, mode) with evidence, not just a boolean. Reads the AI_AGENT standard (both dialects) and the signals it misses.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "George Mihailov",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"main": "index.js",
|
|
9
|
+
"types": "index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./index.d.ts",
|
|
13
|
+
"default": "./index.js"
|
|
14
|
+
},
|
|
15
|
+
"./package.json": "./package.json"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"index.js",
|
|
19
|
+
"index.d.ts",
|
|
20
|
+
"agents/",
|
|
21
|
+
"fixtures/"
|
|
22
|
+
],
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=18"
|
|
25
|
+
},
|
|
26
|
+
"scripts": {
|
|
27
|
+
"test": "node --test",
|
|
28
|
+
"bench": "node bench.js",
|
|
29
|
+
"prepublishOnly": "npm test"
|
|
30
|
+
},
|
|
9
31
|
"keywords": [
|
|
10
32
|
"ai-agent",
|
|
11
33
|
"AI_AGENT",
|
|
12
34
|
"agent-detection",
|
|
13
35
|
"detection",
|
|
36
|
+
"isagent",
|
|
14
37
|
"claude-code",
|
|
38
|
+
"grok",
|
|
15
39
|
"codex",
|
|
16
40
|
"cursor",
|
|
17
41
|
"gemini-cli",
|
|
18
42
|
"amp",
|
|
19
|
-
"
|
|
43
|
+
"goose",
|
|
44
|
+
"opencode",
|
|
20
45
|
"agentic"
|
|
21
46
|
]
|
|
22
47
|
}
|