am-i-vibing 0.1.1 → 0.3.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 +36 -3
- package/dist/cli.mjs +22 -13
- package/dist/cli.mjs.map +1 -1
- package/dist/{detector-CddkGnEB.mjs → detector-BrdjJAFA.mjs} +87 -37
- package/dist/detector-BrdjJAFA.mjs.map +1 -0
- package/dist/index.d.mts +60 -6
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +3 -4
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -6
- package/dist/detector-CddkGnEB.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -27,16 +27,18 @@ console.log(`Detected: ${result.name} (${result.type})`);
|
|
|
27
27
|
- **Aider**
|
|
28
28
|
- **Bolt**
|
|
29
29
|
- **Claude Code**
|
|
30
|
+
- **Codex CLI**
|
|
31
|
+
- **Crush**
|
|
30
32
|
- **Cursor**
|
|
31
33
|
- **Gemini CLI**
|
|
32
34
|
- **GitHub Copilot Agent**
|
|
33
35
|
- **Jules**
|
|
34
|
-
- **
|
|
36
|
+
- **Octofriend** (process detection only — requires `checkProcesses`)
|
|
37
|
+
- **opencode**
|
|
35
38
|
- **Replit**
|
|
36
39
|
- **Warp**
|
|
37
40
|
- **Windsurf**
|
|
38
41
|
- **Zed**
|
|
39
|
-
- **opencode**
|
|
40
42
|
|
|
41
43
|
## Example use case
|
|
42
44
|
|
|
@@ -104,6 +106,36 @@ if (isHybrid()) {
|
|
|
104
106
|
// Note: Hybrid environments return true for both isAgent() and isInteractive()
|
|
105
107
|
```
|
|
106
108
|
|
|
109
|
+
### Process-tree detection (opt-in)
|
|
110
|
+
|
|
111
|
+
Most providers expose an environment variable that uniquely identifies them, and
|
|
112
|
+
that's the only signal `am-i-vibing` consults by default. A small number (e.g.
|
|
113
|
+
Octofriend) can only be detected by inspecting the parent process chain. Reading
|
|
114
|
+
the process tree spawns a subprocess and is meaningfully slow on Windows, so it
|
|
115
|
+
is **off by default**.
|
|
116
|
+
|
|
117
|
+
To opt in:
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
import { detectAgenticEnvironment } from "am-i-vibing";
|
|
121
|
+
|
|
122
|
+
const result = detectAgenticEnvironment({ checkProcesses: true });
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
You can also pre-supply an ancestry (e.g. if you are already collecting one):
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
import { detectAgenticEnvironment } from "am-i-vibing";
|
|
129
|
+
import { getProcessAncestry } from "process-ancestry";
|
|
130
|
+
|
|
131
|
+
const result = detectAgenticEnvironment({
|
|
132
|
+
processAncestry: getProcessAncestry(),
|
|
133
|
+
});
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Supplying `processAncestry` implies `checkProcesses: true` unless you set it to
|
|
137
|
+
`false` explicitly.
|
|
138
|
+
|
|
107
139
|
## Detection Result
|
|
108
140
|
|
|
109
141
|
The library returns a `DetectionResult` object with the following structure:
|
|
@@ -151,7 +183,8 @@ npx am-i-vibing --debug
|
|
|
151
183
|
- `-f, --format <json|text>` - Output format (default: text)
|
|
152
184
|
- `-c, --check <agent|interactive|hybrid>` - Check for specific environment type
|
|
153
185
|
- `-q, --quiet` - Only output result, no labels
|
|
154
|
-
- `-
|
|
186
|
+
- `-p, --check-processes` - Also walk the process tree for detection (slower, off by default)
|
|
187
|
+
- `-d, --debug` - Debug output with environment and process info (implies `--check-processes`)
|
|
155
188
|
- `-h, --help` - Show help message
|
|
156
189
|
|
|
157
190
|
### Exit Codes
|
package/dist/cli.mjs
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { i as isInteractive, n as isAgent, r as isHybrid, t as detectAgenticEnvironment } from "./detector-
|
|
2
|
+
import { i as isInteractive, n as isAgent, r as isHybrid, t as detectAgenticEnvironment } from "./detector-BrdjJAFA.mjs";
|
|
3
3
|
import { getProcessAncestry } from "process-ancestry";
|
|
4
4
|
import { parseArgs } from "node:util";
|
|
5
|
-
|
|
6
5
|
//#region src/cli.ts
|
|
7
6
|
function parseCliArgs() {
|
|
8
7
|
const { values } = parseArgs({
|
|
@@ -31,6 +30,11 @@ function parseCliArgs() {
|
|
|
31
30
|
type: "boolean",
|
|
32
31
|
short: "d",
|
|
33
32
|
default: false
|
|
33
|
+
},
|
|
34
|
+
"check-processes": {
|
|
35
|
+
type: "boolean",
|
|
36
|
+
short: "p",
|
|
37
|
+
default: false
|
|
34
38
|
}
|
|
35
39
|
},
|
|
36
40
|
allowPositionals: false
|
|
@@ -52,7 +56,8 @@ function parseCliArgs() {
|
|
|
52
56
|
check: values.check,
|
|
53
57
|
quiet: values.quiet,
|
|
54
58
|
help: values.help,
|
|
55
|
-
debug: values.debug
|
|
59
|
+
debug: values.debug,
|
|
60
|
+
checkProcesses: values["check-processes"]
|
|
56
61
|
};
|
|
57
62
|
}
|
|
58
63
|
function showHelp() {
|
|
@@ -66,6 +71,8 @@ OPTIONS:
|
|
|
66
71
|
-f, --format <json|text> Output format (default: text)
|
|
67
72
|
-c, --check <agent|interactive|hybrid> Check for specific environment type
|
|
68
73
|
-q, --quiet Only output result, no labels
|
|
74
|
+
-p, --check-processes Also walk the process tree for detection
|
|
75
|
+
(slower, off by default)
|
|
69
76
|
-d, --debug Debug output with environment and process info
|
|
70
77
|
-h, --help Show this help message
|
|
71
78
|
|
|
@@ -75,6 +82,7 @@ EXAMPLES:
|
|
|
75
82
|
npx am-i-vibing --check agent # Check if running under agent
|
|
76
83
|
npx am-i-vibing --check hybrid # Check if running under hybrid
|
|
77
84
|
npx am-i-vibing --quiet # Minimal output
|
|
85
|
+
npx am-i-vibing --check-processes # Include process-tree detection
|
|
78
86
|
npx am-i-vibing --debug # Debug with full environment info
|
|
79
87
|
|
|
80
88
|
EXIT CODES:
|
|
@@ -82,11 +90,11 @@ EXIT CODES:
|
|
|
82
90
|
1 No agentic environment detected (or specific check failed)
|
|
83
91
|
`);
|
|
84
92
|
}
|
|
85
|
-
function checkEnvironmentType(checkType) {
|
|
93
|
+
function checkEnvironmentType(checkType, options) {
|
|
86
94
|
switch (checkType) {
|
|
87
|
-
case "agent": return isAgent();
|
|
88
|
-
case "interactive": return isInteractive();
|
|
89
|
-
case "hybrid": return isHybrid();
|
|
95
|
+
case "agent": return isAgent({ checkProcesses: options.checkProcesses });
|
|
96
|
+
case "interactive": return isInteractive({ checkProcesses: options.checkProcesses });
|
|
97
|
+
case "hybrid": return isHybrid({ checkProcesses: options.checkProcesses });
|
|
90
98
|
default: return false;
|
|
91
99
|
}
|
|
92
100
|
}
|
|
@@ -107,10 +115,10 @@ function formatOutput(result, options) {
|
|
|
107
115
|
}
|
|
108
116
|
if (options.format === "json") return JSON.stringify(result, null, 2);
|
|
109
117
|
if (options.quiet) {
|
|
110
|
-
if (options.check) return checkEnvironmentType(options.check) ? "true" : "false";
|
|
118
|
+
if (options.check) return checkEnvironmentType(options.check, options) ? "true" : "false";
|
|
111
119
|
return result.isAgentic ? `${result.name}` : "none";
|
|
112
120
|
}
|
|
113
|
-
if (options.check) return checkEnvironmentType(options.check) ? `✓ Running in ${options.check} environment: ${result.name}` : `✗ Not running in ${options.check} environment`;
|
|
121
|
+
if (options.check) return checkEnvironmentType(options.check, options) ? `✓ Running in ${options.check} environment: ${result.name}` : `✗ Not running in ${options.check} environment`;
|
|
114
122
|
if (!result.isAgentic) return "✗ No agentic environment detected";
|
|
115
123
|
return `✓ Detected: [${result.id}] ${result.name} (${result.type})`;
|
|
116
124
|
}
|
|
@@ -120,16 +128,17 @@ function main() {
|
|
|
120
128
|
showHelp();
|
|
121
129
|
process.exit(0);
|
|
122
130
|
}
|
|
123
|
-
const
|
|
131
|
+
const checkProcesses = options.checkProcesses || options.debug;
|
|
132
|
+
const result = detectAgenticEnvironment({ checkProcesses });
|
|
124
133
|
let exitCode = 1;
|
|
125
|
-
if (options.check) exitCode = checkEnvironmentType(options.check) ? 0 : 1;
|
|
134
|
+
if (options.check) exitCode = checkEnvironmentType(options.check, { checkProcesses }) ? 0 : 1;
|
|
126
135
|
else exitCode = result.isAgentic ? 0 : 1;
|
|
127
136
|
const output = formatOutput(result, options);
|
|
128
137
|
console.log(output);
|
|
129
138
|
process.exit(exitCode);
|
|
130
139
|
}
|
|
131
140
|
main();
|
|
132
|
-
|
|
133
141
|
//#endregion
|
|
134
|
-
export {
|
|
142
|
+
export {};
|
|
143
|
+
|
|
135
144
|
//# sourceMappingURL=cli.mjs.map
|
package/dist/cli.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.mjs","names":[],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { parseArgs } from \"node:util\";\nimport { getProcessAncestry } from \"process-ancestry\";\nimport {\n detectAgenticEnvironment,\n isAgent,\n isInteractive,\n isHybrid,\n} from \"./detector.js\";\n\ninterface CliOptions {\n format?: \"json\" | \"text\";\n check?: \"agent\" | \"interactive\" | \"hybrid\";\n quiet?: boolean;\n help?: boolean;\n debug?: boolean;\n}\n\nfunction parseCliArgs(): CliOptions {\n const { values } = parseArgs({\n args: process.argv.slice(2),\n options: {\n format: {\n type: \"string\",\n short: \"f\",\n default: \"text\",\n },\n check: {\n type: \"string\",\n short: \"c\",\n },\n quiet: {\n type: \"boolean\",\n short: \"q\",\n default: false,\n },\n help: {\n type: \"boolean\",\n short: \"h\",\n default: false,\n },\n debug: {\n type: \"boolean\",\n short: \"d\",\n default: false,\n },\n },\n allowPositionals: false,\n });\n\n // Validate format option\n if (values.format && ![\"json\", \"text\"].includes(values.format)) {\n console.error(\n `Error: Invalid format '${values.format}'. Must be 'json' or 'text'.`,\n );\n process.exit(1);\n }\n\n // Validate check option\n if (values.check
|
|
1
|
+
{"version":3,"file":"cli.mjs","names":[],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { parseArgs } from \"node:util\";\nimport { getProcessAncestry } from \"process-ancestry\";\nimport {\n detectAgenticEnvironment,\n isAgent,\n isInteractive,\n isHybrid,\n} from \"./detector.js\";\n\ninterface CliOptions {\n format?: \"json\" | \"text\";\n check?: \"agent\" | \"interactive\" | \"hybrid\";\n quiet?: boolean;\n help?: boolean;\n debug?: boolean;\n checkProcesses?: boolean;\n}\n\nfunction parseCliArgs(): CliOptions {\n const { values } = parseArgs({\n args: process.argv.slice(2),\n options: {\n format: {\n type: \"string\",\n short: \"f\",\n default: \"text\",\n },\n check: {\n type: \"string\",\n short: \"c\",\n },\n quiet: {\n type: \"boolean\",\n short: \"q\",\n default: false,\n },\n help: {\n type: \"boolean\",\n short: \"h\",\n default: false,\n },\n debug: {\n type: \"boolean\",\n short: \"d\",\n default: false,\n },\n \"check-processes\": {\n type: \"boolean\",\n short: \"p\",\n default: false,\n },\n },\n allowPositionals: false,\n });\n\n // Validate format option\n if (values.format && ![\"json\", \"text\"].includes(values.format)) {\n console.error(\n `Error: Invalid format '${values.format}'. Must be 'json' or 'text'.`,\n );\n process.exit(1);\n }\n\n // Validate check option\n if (\n values.check &&\n ![\"agent\", \"interactive\", \"hybrid\"].includes(values.check)\n ) {\n console.error(\n `Error: Invalid check type '${values.check}'. Must be 'agent', 'interactive', or 'hybrid'.`,\n );\n process.exit(1);\n }\n\n return {\n format: values.format as \"json\" | \"text\",\n check: values.check as \"agent\" | \"interactive\" | \"hybrid\",\n quiet: values.quiet,\n help: values.help,\n debug: values.debug,\n checkProcesses: values[\"check-processes\"],\n };\n}\n\nfunction showHelp(): void {\n console.log(`\nam-i-vibing - Detect agentic coding environments\n\nUSAGE:\n npx am-i-vibing [OPTIONS]\n\nOPTIONS:\n -f, --format <json|text> Output format (default: text)\n -c, --check <agent|interactive|hybrid> Check for specific environment type\n -q, --quiet Only output result, no labels\n -p, --check-processes Also walk the process tree for detection\n (slower, off by default)\n -d, --debug Debug output with environment and process info\n -h, --help Show this help message\n\nEXAMPLES:\n npx am-i-vibing # Detect current environment\n npx am-i-vibing --format json # JSON output\n npx am-i-vibing --check agent # Check if running under agent\n npx am-i-vibing --check hybrid # Check if running under hybrid\n npx am-i-vibing --quiet # Minimal output\n npx am-i-vibing --check-processes # Include process-tree detection\n npx am-i-vibing --debug # Debug with full environment info\n\nEXIT CODES:\n 0 Agentic environment detected (or specific check passed)\n 1 No agentic environment detected (or specific check failed)\n`);\n}\n\nfunction checkEnvironmentType(\n checkType: string,\n options: { checkProcesses?: boolean },\n): boolean {\n switch (checkType) {\n case \"agent\":\n return isAgent({ checkProcesses: options.checkProcesses });\n case \"interactive\":\n return isInteractive({ checkProcesses: options.checkProcesses });\n case \"hybrid\":\n return isHybrid({ checkProcesses: options.checkProcesses });\n default:\n return false;\n }\n}\n\nfunction formatOutput(\n result: ReturnType<typeof detectAgenticEnvironment>,\n options: CliOptions,\n): string {\n if (options.debug) {\n let processAncestry: any[] = [];\n try {\n processAncestry = getProcessAncestry();\n } catch (error) {\n processAncestry = [{ error: \"Failed to get process ancestry\" }];\n }\n\n const debugOutput = {\n detection: result,\n environment: process.env,\n processAncestry,\n };\n return JSON.stringify(debugOutput, null, 2);\n }\n\n if (options.format === \"json\") {\n return JSON.stringify(result, null, 2);\n }\n\n if (options.quiet) {\n if (options.check) {\n return checkEnvironmentType(options.check, options) ? \"true\" : \"false\";\n }\n return result.isAgentic ? `${result.name}` : \"none\";\n }\n\n if (options.check) {\n const matches = checkEnvironmentType(options.check, options);\n return matches\n ? `✓ Running in ${options.check} environment: ${result.name}`\n : `✗ Not running in ${options.check} environment`;\n }\n\n if (!result.isAgentic) {\n return \"✗ No agentic environment detected\";\n }\n\n return `✓ Detected: [${result.id}] ${result.name} (${result.type})`;\n}\n\nfunction main(): void {\n const options = parseCliArgs();\n\n if (options.help) {\n showHelp();\n process.exit(0);\n }\n\n // --debug always reveals the full picture, including process detection\n const checkProcesses = options.checkProcesses || options.debug;\n const result = detectAgenticEnvironment({ checkProcesses });\n let exitCode = 1;\n\n if (options.check) {\n exitCode = checkEnvironmentType(options.check, { checkProcesses }) ? 0 : 1;\n } else {\n exitCode = result.isAgentic ? 0 : 1;\n }\n\n const output = formatOutput(result, options);\n console.log(output);\n\n process.exit(exitCode);\n}\n\nmain();\n"],"mappings":";;;;;AAoBA,SAAS,eAA2B;CAClC,MAAM,EAAE,WAAW,UAAU;EAC3B,MAAM,QAAQ,KAAK,MAAM,EAAE;EAC3B,SAAS;GACP,QAAQ;IACN,MAAM;IACN,OAAO;IACP,SAAS;IACV;GACD,OAAO;IACL,MAAM;IACN,OAAO;IACR;GACD,OAAO;IACL,MAAM;IACN,OAAO;IACP,SAAS;IACV;GACD,MAAM;IACJ,MAAM;IACN,OAAO;IACP,SAAS;IACV;GACD,OAAO;IACL,MAAM;IACN,OAAO;IACP,SAAS;IACV;GACD,mBAAmB;IACjB,MAAM;IACN,OAAO;IACP,SAAS;IACV;GACF;EACD,kBAAkB;EACnB,CAAC;AAGF,KAAI,OAAO,UAAU,CAAC,CAAC,QAAQ,OAAO,CAAC,SAAS,OAAO,OAAO,EAAE;AAC9D,UAAQ,MACN,0BAA0B,OAAO,OAAO,8BACzC;AACD,UAAQ,KAAK,EAAE;;AAIjB,KACE,OAAO,SACP,CAAC;EAAC;EAAS;EAAe;EAAS,CAAC,SAAS,OAAO,MAAM,EAC1D;AACA,UAAQ,MACN,8BAA8B,OAAO,MAAM,iDAC5C;AACD,UAAQ,KAAK,EAAE;;AAGjB,QAAO;EACL,QAAQ,OAAO;EACf,OAAO,OAAO;EACd,OAAO,OAAO;EACd,MAAM,OAAO;EACb,OAAO,OAAO;EACd,gBAAgB,OAAO;EACxB;;AAGH,SAAS,WAAiB;AACxB,SAAQ,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2BZ;;AAGF,SAAS,qBACP,WACA,SACS;AACT,SAAQ,WAAR;EACE,KAAK,QACH,QAAO,QAAQ,EAAE,gBAAgB,QAAQ,gBAAgB,CAAC;EAC5D,KAAK,cACH,QAAO,cAAc,EAAE,gBAAgB,QAAQ,gBAAgB,CAAC;EAClE,KAAK,SACH,QAAO,SAAS,EAAE,gBAAgB,QAAQ,gBAAgB,CAAC;EAC7D,QACE,QAAO;;;AAIb,SAAS,aACP,QACA,SACQ;AACR,KAAI,QAAQ,OAAO;EACjB,IAAI,kBAAyB,EAAE;AAC/B,MAAI;AACF,qBAAkB,oBAAoB;WAC/B,OAAO;AACd,qBAAkB,CAAC,EAAE,OAAO,kCAAkC,CAAC;;EAGjE,MAAM,cAAc;GAClB,WAAW;GACX,aAAa,QAAQ;GACrB;GACD;AACD,SAAO,KAAK,UAAU,aAAa,MAAM,EAAE;;AAG7C,KAAI,QAAQ,WAAW,OACrB,QAAO,KAAK,UAAU,QAAQ,MAAM,EAAE;AAGxC,KAAI,QAAQ,OAAO;AACjB,MAAI,QAAQ,MACV,QAAO,qBAAqB,QAAQ,OAAO,QAAQ,GAAG,SAAS;AAEjE,SAAO,OAAO,YAAY,GAAG,OAAO,SAAS;;AAG/C,KAAI,QAAQ,MAEV,QADgB,qBAAqB,QAAQ,OAAO,QACtC,GACV,gBAAgB,QAAQ,MAAM,gBAAgB,OAAO,SACrD,oBAAoB,QAAQ,MAAM;AAGxC,KAAI,CAAC,OAAO,UACV,QAAO;AAGT,QAAO,gBAAgB,OAAO,GAAG,IAAI,OAAO,KAAK,IAAI,OAAO,KAAK;;AAGnE,SAAS,OAAa;CACpB,MAAM,UAAU,cAAc;AAE9B,KAAI,QAAQ,MAAM;AAChB,YAAU;AACV,UAAQ,KAAK,EAAE;;CAIjB,MAAM,iBAAiB,QAAQ,kBAAkB,QAAQ;CACzD,MAAM,SAAS,yBAAyB,EAAE,gBAAgB,CAAC;CAC3D,IAAI,WAAW;AAEf,KAAI,QAAQ,MACV,YAAW,qBAAqB,QAAQ,OAAO,EAAE,gBAAgB,CAAC,GAAG,IAAI;KAEzE,YAAW,OAAO,YAAY,IAAI;CAGpC,MAAM,SAAS,aAAa,QAAQ,QAAQ;AAC5C,SAAQ,IAAI,OAAO;AAEnB,SAAQ,KAAK,SAAS;;AAGxB,MAAM"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { getProcessAncestry } from "process-ancestry";
|
|
2
|
-
|
|
3
2
|
//#region src/providers.ts
|
|
4
3
|
/**
|
|
5
4
|
* Provider configurations for major AI coding tools
|
|
@@ -43,14 +42,16 @@ const providers = [
|
|
|
43
42
|
},
|
|
44
43
|
{
|
|
45
44
|
id: "gemini-agent",
|
|
46
|
-
name: "Gemini
|
|
45
|
+
name: "Gemini CLI",
|
|
47
46
|
type: "agent",
|
|
47
|
+
envVars: [["GEMINI_CLI", "1"]],
|
|
48
48
|
processChecks: ["gemini"]
|
|
49
49
|
},
|
|
50
50
|
{
|
|
51
51
|
id: "codex",
|
|
52
52
|
name: "OpenAI Codex",
|
|
53
53
|
type: "agent",
|
|
54
|
+
envVars: ["CODEX_THREAD_ID"],
|
|
54
55
|
processChecks: ["codex"]
|
|
55
56
|
},
|
|
56
57
|
{
|
|
@@ -121,8 +122,31 @@ const providers = [
|
|
|
121
122
|
id: "crush",
|
|
122
123
|
name: "Crush",
|
|
123
124
|
type: "agent",
|
|
125
|
+
envVars: [{ any: [
|
|
126
|
+
["CRUSH", "1"],
|
|
127
|
+
["AGENT", "crush"],
|
|
128
|
+
["AI_AGENT", "crush"]
|
|
129
|
+
] }],
|
|
124
130
|
processChecks: ["crush"]
|
|
125
131
|
},
|
|
132
|
+
{
|
|
133
|
+
id: "amp",
|
|
134
|
+
name: "Amp",
|
|
135
|
+
type: "agent",
|
|
136
|
+
envVars: [{ any: ["AMP_CURRENT_THREAD_ID", ["AGENT", "amp"]] }]
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
id: "auggie",
|
|
140
|
+
name: "Auggie",
|
|
141
|
+
type: "agent",
|
|
142
|
+
envVars: [["AUGMENT_AGENT", "1"]]
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
id: "qwen-code",
|
|
146
|
+
name: "Qwen Code",
|
|
147
|
+
type: "agent",
|
|
148
|
+
envVars: [["QWEN_CODE", "1"]]
|
|
149
|
+
},
|
|
126
150
|
{
|
|
127
151
|
id: "vscode-copilot-agent",
|
|
128
152
|
name: "GitHub Copilot in VS Code",
|
|
@@ -140,6 +164,18 @@ const providers = [
|
|
|
140
164
|
name: "Octofriend",
|
|
141
165
|
type: "agent",
|
|
142
166
|
processChecks: ["octofriend"]
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
id: "devin",
|
|
170
|
+
name: "Devin",
|
|
171
|
+
type: "agent",
|
|
172
|
+
processChecks: ["devin"]
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
id: "droid",
|
|
176
|
+
name: "Factory Droid",
|
|
177
|
+
type: "agent",
|
|
178
|
+
processChecks: ["droid"]
|
|
143
179
|
}
|
|
144
180
|
];
|
|
145
181
|
/**
|
|
@@ -154,7 +190,6 @@ function getProvider(name) {
|
|
|
154
190
|
function getProvidersByType(type) {
|
|
155
191
|
return providers.filter((p) => p.type === type);
|
|
156
192
|
}
|
|
157
|
-
|
|
158
193
|
//#endregion
|
|
159
194
|
//#region src/detector.ts
|
|
160
195
|
/**
|
|
@@ -169,10 +204,7 @@ function checkEnvVar(envVarDef, env = process.env) {
|
|
|
169
204
|
* Check if a process is running in the process tree
|
|
170
205
|
*/
|
|
171
206
|
function checkProcess(processName, processAncestry) {
|
|
172
|
-
|
|
173
|
-
const ancestry = processAncestry ?? getProcessAncestry();
|
|
174
|
-
for (const ancestorProcess of ancestry) if (ancestorProcess.command?.includes(processName)) return true;
|
|
175
|
-
} catch (error) {}
|
|
207
|
+
for (const ancestorProcess of processAncestry) if (ancestorProcess.command?.includes(processName)) return true;
|
|
176
208
|
return false;
|
|
177
209
|
}
|
|
178
210
|
/**
|
|
@@ -210,21 +242,45 @@ function createDetectedResult(provider) {
|
|
|
210
242
|
};
|
|
211
243
|
}
|
|
212
244
|
/**
|
|
213
|
-
*
|
|
245
|
+
* Normalize the various supported argument shapes into a DetectOptions object.
|
|
246
|
+
*
|
|
247
|
+
* Supported shapes:
|
|
248
|
+
* - detectAgenticEnvironment()
|
|
249
|
+
* - detectAgenticEnvironment(options)
|
|
250
|
+
* - detectAgenticEnvironment(env) // legacy
|
|
251
|
+
* - detectAgenticEnvironment(env, processAncestry) // legacy
|
|
214
252
|
*/
|
|
215
|
-
function
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
253
|
+
function normalizeOptions(envOrOptions, legacyAncestry) {
|
|
254
|
+
if (envOrOptions != null && typeof envOrOptions === "object" && ("env" in envOrOptions || "processAncestry" in envOrOptions || "checkProcesses" in envOrOptions)) {
|
|
255
|
+
const opts = envOrOptions;
|
|
256
|
+
return {
|
|
257
|
+
env: opts.env ?? process.env,
|
|
258
|
+
processAncestry: opts.processAncestry,
|
|
259
|
+
checkProcesses: opts.checkProcesses ?? opts.processAncestry !== void 0
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
return {
|
|
263
|
+
env: envOrOptions ?? process.env,
|
|
264
|
+
processAncestry: legacyAncestry,
|
|
265
|
+
checkProcesses: legacyAncestry !== void 0
|
|
225
266
|
};
|
|
226
|
-
|
|
267
|
+
}
|
|
268
|
+
function detectAgenticEnvironment(envOrOptions, legacyAncestry) {
|
|
269
|
+
const { env, processAncestry, checkProcesses } = normalizeOptions(envOrOptions, legacyAncestry);
|
|
270
|
+
for (const provider of providers) if (provider.envVars?.some((group) => checkEnvVars(group, env))) return createDetectedResult(provider);
|
|
227
271
|
for (const provider of providers) if (runCustomDetectors(provider)) return createDetectedResult(provider);
|
|
272
|
+
if (checkProcesses) {
|
|
273
|
+
let cachedAncestry = processAncestry;
|
|
274
|
+
const getAncestry = () => {
|
|
275
|
+
if (cachedAncestry === void 0) try {
|
|
276
|
+
cachedAncestry = getProcessAncestry();
|
|
277
|
+
} catch {
|
|
278
|
+
cachedAncestry = [];
|
|
279
|
+
}
|
|
280
|
+
return cachedAncestry;
|
|
281
|
+
};
|
|
282
|
+
for (const provider of providers) if (provider.processChecks?.some((processName) => checkProcess(processName, getAncestry()))) return createDetectedResult(provider);
|
|
283
|
+
}
|
|
228
284
|
return {
|
|
229
285
|
isAgentic: false,
|
|
230
286
|
id: null,
|
|
@@ -232,27 +288,21 @@ function detectAgenticEnvironment(env = process.env, processAncestry) {
|
|
|
232
288
|
type: null
|
|
233
289
|
};
|
|
234
290
|
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
function isAgent(
|
|
239
|
-
const result = detectAgenticEnvironment(
|
|
291
|
+
function isProvider(providerName, envOrOptions, legacyAncestry) {
|
|
292
|
+
return detectAgenticEnvironment(envOrOptions, legacyAncestry).name === providerName;
|
|
293
|
+
}
|
|
294
|
+
function isAgent(envOrOptions, legacyAncestry) {
|
|
295
|
+
const result = detectAgenticEnvironment(envOrOptions, legacyAncestry);
|
|
240
296
|
return result.type === "agent" || result.type === "hybrid";
|
|
241
297
|
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
*/
|
|
245
|
-
function isInteractive(env = process.env, processAncestry) {
|
|
246
|
-
const result = detectAgenticEnvironment(env, processAncestry);
|
|
298
|
+
function isInteractive(envOrOptions, legacyAncestry) {
|
|
299
|
+
const result = detectAgenticEnvironment(envOrOptions, legacyAncestry);
|
|
247
300
|
return result.type === "interactive" || result.type === "hybrid";
|
|
248
301
|
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
*/
|
|
252
|
-
function isHybrid(env = process.env, processAncestry) {
|
|
253
|
-
return detectAgenticEnvironment(env, processAncestry).type === "hybrid";
|
|
302
|
+
function isHybrid(envOrOptions, legacyAncestry) {
|
|
303
|
+
return detectAgenticEnvironment(envOrOptions, legacyAncestry).type === "hybrid";
|
|
254
304
|
}
|
|
255
|
-
|
|
256
305
|
//#endregion
|
|
257
|
-
export {
|
|
258
|
-
|
|
306
|
+
export { isProvider as a, providers as c, isInteractive as i, isAgent as n, getProvider as o, isHybrid as r, getProvidersByType as s, detectAgenticEnvironment as t };
|
|
307
|
+
|
|
308
|
+
//# sourceMappingURL=detector-BrdjJAFA.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detector-BrdjJAFA.mjs","names":[],"sources":["../src/providers.ts","../src/detector.ts"],"sourcesContent":["import type { ProviderConfig } from \"./types.js\";\n\n/**\n * Provider configurations for major AI coding tools\n */\nexport const providers: ProviderConfig[] = [\n {\n id: \"opencode\",\n name: \"OpenCode\",\n type: \"agent\",\n envVars: [\n {\n any: [\n \"OPENCODE\",\n \"OPENCODE_BIN_PATH\",\n \"OPENCODE_SERVER\",\n \"OPENCODE_APP_INFO\",\n \"OPENCODE_MODES\",\n ],\n },\n ],\n },\n {\n id: \"jules\",\n name: \"Jules\",\n type: \"agent\",\n envVars: [\n {\n all: [\n [\"HOME\", \"/home/jules\"],\n [\"USER\", \"swebot\"],\n ],\n },\n ],\n },\n {\n id: \"claude-code\",\n name: \"Claude Code\",\n type: \"agent\",\n envVars: [\"CLAUDECODE\"],\n },\n {\n id: \"cursor-agent\",\n name: \"Cursor Agent\",\n type: \"agent\",\n envVars: [\n {\n all: [\"CURSOR_TRACE_ID\", [\"PAGER\", \"head -n 10000 | cat\"]],\n },\n ],\n },\n {\n id: \"cursor\",\n name: \"Cursor\",\n type: \"interactive\",\n envVars: [\"CURSOR_TRACE_ID\"],\n },\n {\n id: \"gemini-agent\",\n name: \"Gemini CLI\",\n type: \"agent\",\n // Gemini CLI sets GEMINI_CLI=1 on every shell command and MCP server it spawns.\n // See: https://github.com/google-gemini/gemini-cli/blob/main/packages/core/src/services/shellExecutionService.ts\n envVars: [[\"GEMINI_CLI\", \"1\"]],\n processChecks: [\"gemini\"],\n },\n {\n id: \"codex\",\n name: \"OpenAI Codex\",\n type: \"agent\",\n // Codex injects CODEX_THREAD_ID (the session conversation id) into every shell command it runs.\n // See: https://github.com/openai/codex/blob/main/codex-rs/protocol/src/shell_environment.rs\n envVars: [\"CODEX_THREAD_ID\"],\n processChecks: [\"codex\"],\n },\n {\n id: \"replit\",\n name: \"Replit\",\n type: \"agent\",\n envVars: [\"REPL_ID\"],\n },\n {\n id: \"aider\",\n name: \"Aider\",\n type: \"agent\",\n envVars: [\"AIDER_API_KEY\"],\n processChecks: [\"aider\"],\n },\n {\n id: \"bolt-agent\",\n name: \"Bolt.new Agent\",\n type: \"agent\",\n envVars: [\n {\n all: [[\"SHELL\", \"/bin/jsh\"], \"npm_config_yes\"],\n },\n ],\n },\n {\n id: \"bolt\",\n name: \"Bolt.new\",\n type: \"interactive\",\n envVars: [\n {\n all: [[\"SHELL\", \"/bin/jsh\"]],\n none: [\"npm_config_yes\"],\n },\n ],\n },\n {\n id: \"zed-agent\",\n name: \"Zed Agent\",\n type: \"agent\",\n envVars: [\n {\n all: [\n [\"TERM_PROGRAM\", \"zed\"],\n [\"PAGER\", \"cat\"],\n ],\n },\n ],\n },\n {\n id: \"zed\",\n name: \"Zed\",\n type: \"interactive\",\n envVars: [\n {\n all: [[\"TERM_PROGRAM\", \"zed\"]],\n none: [[\"PAGER\", \"cat\"]],\n },\n ],\n },\n {\n id: \"replit-assistant\",\n name: \"Replit Assistant\",\n type: \"agent\",\n envVars: [\n {\n all: [\"REPL_ID\", [\"REPLIT_MODE\", \"assistant\"]],\n },\n ],\n },\n {\n id: \"replit\",\n name: \"Replit\",\n type: \"interactive\",\n envVars: [\n {\n all: [\"REPL_ID\"],\n none: [[\"REPLIT_MODE\", \"assistant\"]],\n },\n ],\n },\n {\n id: \"windsurf\",\n name: \"Windsurf\",\n type: \"agent\",\n envVars: [\"CODEIUM_EDITOR_APP_ROOT\"],\n },\n {\n id: \"crush\",\n name: \"Crush\",\n type: \"agent\",\n // Crush sets CRUSH=1 (and AGENT=crush, AI_AGENT=crush) on every shell exec.\n // See: https://github.com/charmbracelet/crush/blob/main/internal/shell/shell.go\n envVars: [\n {\n any: [\n [\"CRUSH\", \"1\"],\n [\"AGENT\", \"crush\"],\n [\"AI_AGENT\", \"crush\"],\n ],\n },\n ],\n processChecks: [\"crush\"],\n },\n {\n id: \"amp\",\n name: \"Amp\",\n type: \"agent\",\n // Sourcegraph Amp injects AGENT=amp, AGENT_THREAD_ID, and AMP_CURRENT_THREAD_ID\n // into every shell tool execution.\n // See: https://www.npmjs.com/package/@sourcegraph/amp\n envVars: [\n {\n any: [\"AMP_CURRENT_THREAD_ID\", [\"AGENT\", \"amp\"]],\n },\n ],\n },\n {\n id: \"auggie\",\n name: \"Auggie\",\n type: \"agent\",\n // Augment Code's Auggie CLI sets AUGMENT_AGENT=1 in the shell tool's env on\n // every command execution.\n // See: https://www.npmjs.com/package/@augmentcode/auggie\n envVars: [[\"AUGMENT_AGENT\", \"1\"]],\n },\n {\n id: \"qwen-code\",\n name: \"Qwen Code\",\n type: \"agent\",\n // Qwen Code (Alibaba's gemini-cli fork) sets QWEN_CODE=1 on every shell exec.\n // See: https://www.npmjs.com/package/@qwen-code/qwen-code\n envVars: [[\"QWEN_CODE\", \"1\"]],\n },\n {\n id: \"vscode-copilot-agent\",\n name: \"GitHub Copilot in VS Code\",\n type: \"agent\",\n envVars: [\n {\n all: [\n [\"TERM_PROGRAM\", \"vscode\"],\n [\"GIT_PAGER\", \"cat\"],\n ],\n },\n ],\n },\n {\n id: \"warp\",\n name: \"Warp Terminal\",\n type: \"hybrid\",\n envVars: [\n {\n all: [[\"TERM_PROGRAM\", \"WarpTerminal\"]],\n },\n ],\n },\n {\n id: \"octofriend\",\n name: \"Octofriend\",\n type: \"agent\",\n // Octofriend does not currently expose an environment variable signal, so it\n // can only be detected via process ancestry (opt-in).\n processChecks: [\"octofriend\"],\n },\n {\n id: \"devin\",\n name: \"Devin\",\n type: \"agent\",\n // Devin for Terminal does not inject any DEVIN_* env var into shell tool\n // executions (DEVIN_PROJECT_DIR is only set inside hook commands, and\n // DEVIN_SESSION_ID/DEVIN_WRAPPER_ACTIVE only exist in the opt-in `devin shell`\n // integration where the user runs commands themselves). Process ancestry is\n // the only available signal, so detection is opt-in via processAncestry.\n processChecks: [\"devin\"],\n },\n {\n id: \"droid\",\n name: \"Factory Droid\",\n type: \"agent\",\n // Factory's Droid CLI sets DROID_PROJECT_DIR / FACTORY_PROJECT_DIR only inside\n // hook command invocations, not on regular shell tool exec. Process ancestry\n // is the only reliable signal, so detection is opt-in via processAncestry.\n processChecks: [\"droid\"],\n },\n];\n\n/**\n * Get provider configuration by name\n */\nexport function getProvider(name: string): ProviderConfig | undefined {\n return providers.find((p) => p.name === name);\n}\n\n/**\n * Get all providers of a specific type\n */\nexport function getProvidersByType(\n type: \"agent\" | \"interactive\" | \"hybrid\",\n): ProviderConfig[] {\n return providers.filter((p) => p.type === type);\n}\n","import type {\n DetectionResult,\n DetectOptions,\n ProviderConfig,\n EnvVarDefinition,\n EnvVarGroup,\n} from \"./types.js\";\nimport { providers } from \"./providers.js\";\nimport { getProcessAncestry } from \"process-ancestry\";\n\n/**\n * Check if a specific environment variable exists (handles both strings and tuples)\n */\nfunction checkEnvVar(\n envVarDef: EnvVarDefinition,\n env: Record<string, string | undefined> = process.env,\n): boolean {\n const [envVar, expectedValue] =\n typeof envVarDef === \"string\" ? [envVarDef, undefined] : envVarDef;\n\n const actualValue = env[envVar];\n return Boolean(\n actualValue && (!expectedValue || actualValue === expectedValue),\n );\n}\n\n/**\n * Check if a process is running in the process tree\n */\nfunction checkProcess(\n processName: string,\n processAncestry: Array<{ command?: string }>,\n): boolean {\n for (const ancestorProcess of processAncestry) {\n if (ancestorProcess.command?.includes(processName)) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Check if an environment variable group matches based on its properties\n */\nfunction checkEnvVars(\n definition: EnvVarGroup | EnvVarDefinition,\n env: Record<string, string | undefined> = process.env,\n): boolean {\n if (typeof definition === \"string\" || Array.isArray(definition)) {\n return checkEnvVar(definition, env);\n }\n\n const { any, all, none } = definition;\n\n // Check ANY conditions (OR logic) - at least one must pass\n const anyResult =\n !any?.length || any.some((envVar) => checkEnvVar(envVar, env));\n\n // Check ALL conditions (AND logic) - all must pass\n const allResult =\n !all?.length || all.every((envVar) => checkEnvVar(envVar, env));\n\n // Check NONE conditions (NOT logic) - none should pass\n const noneResult =\n !none?.length || !none.some((envVar) => checkEnvVar(envVar, env));\n\n return anyResult && allResult && noneResult;\n}\n\n/**\n * Run custom detectors for a provider\n */\nfunction runCustomDetectors(provider: ProviderConfig): boolean {\n return (\n provider.customDetectors?.some((detector) => {\n try {\n return detector();\n } catch {\n return false;\n }\n }) ?? false\n );\n}\n\n/**\n * Create a positive detection result\n */\nfunction createDetectedResult(provider: ProviderConfig): DetectionResult {\n return {\n isAgentic: true,\n id: provider.id,\n name: provider.name,\n type: provider.type,\n };\n}\n\n/**\n * Normalize the various supported argument shapes into a DetectOptions object.\n *\n * Supported shapes:\n * - detectAgenticEnvironment()\n * - detectAgenticEnvironment(options)\n * - detectAgenticEnvironment(env) // legacy\n * - detectAgenticEnvironment(env, processAncestry) // legacy\n */\nfunction normalizeOptions(\n envOrOptions?: Record<string, string | undefined> | DetectOptions,\n legacyAncestry?: Array<{ command?: string }>,\n): Required<Pick<DetectOptions, \"env\" | \"checkProcesses\">> & {\n processAncestry?: Array<{ command?: string }>;\n} {\n // Distinguish a DetectOptions object from a raw env record. DetectOptions\n // has at least one of the known keys; an env record is a flat string map.\n const looksLikeOptions =\n envOrOptions != null &&\n typeof envOrOptions === \"object\" &&\n (\"env\" in envOrOptions ||\n \"processAncestry\" in envOrOptions ||\n \"checkProcesses\" in envOrOptions);\n\n if (looksLikeOptions) {\n const opts = envOrOptions as DetectOptions;\n return {\n env: opts.env ?? process.env,\n processAncestry: opts.processAncestry,\n // If the caller pre-supplied an ancestry, default checkProcesses to true\n // unless they explicitly opted out.\n checkProcesses:\n opts.checkProcesses ?? opts.processAncestry !== undefined,\n };\n }\n\n return {\n env:\n (envOrOptions as Record<string, string | undefined> | undefined) ??\n process.env,\n processAncestry: legacyAncestry,\n // Legacy callers that explicitly passed an ancestry are presumed to want\n // process checks; otherwise default off.\n checkProcesses: legacyAncestry !== undefined,\n };\n}\n\n/**\n * Detect agentic coding environment\n */\nexport function detectAgenticEnvironment(\n options?: DetectOptions,\n): DetectionResult;\n/**\n * @deprecated Pass an options object instead. This signature is retained for\n * backwards compatibility and will be removed in a future major release.\n */\nexport function detectAgenticEnvironment(\n env: Record<string, string | undefined>,\n processAncestry?: Array<{ command?: string }>,\n): DetectionResult;\nexport function detectAgenticEnvironment(\n envOrOptions?: Record<string, string | undefined> | DetectOptions,\n legacyAncestry?: Array<{ command?: string }>,\n): DetectionResult {\n const { env, processAncestry, checkProcesses } = normalizeOptions(\n envOrOptions,\n legacyAncestry,\n );\n\n // Fast path: check all environment variables first\n for (const provider of providers) {\n if (provider.envVars?.some((group) => checkEnvVars(group, env))) {\n return createDetectedResult(provider);\n }\n }\n\n // Custom detectors next (cheap, in-process)\n for (const provider of providers) {\n if (runCustomDetectors(provider)) {\n return createDetectedResult(provider);\n }\n }\n\n // Slow path: process ancestry checks. Opt-in only because reading the process\n // tree spawns a subprocess (notably slow on Windows).\n if (checkProcesses) {\n let cachedAncestry = processAncestry;\n const getAncestry = () => {\n if (cachedAncestry === undefined) {\n try {\n cachedAncestry = getProcessAncestry();\n } catch {\n cachedAncestry = [];\n }\n }\n return cachedAncestry;\n };\n\n for (const provider of providers) {\n if (\n provider.processChecks?.some((processName) =>\n checkProcess(processName, getAncestry()),\n )\n ) {\n return createDetectedResult(provider);\n }\n }\n }\n\n // No provider detected\n return {\n isAgentic: false,\n id: null,\n name: null,\n type: null,\n };\n}\n\n/**\n * Check if currently running in a specific provider\n */\nexport function isProvider(\n providerName: string,\n options?: DetectOptions,\n): boolean;\n/**\n * @deprecated Pass an options object instead.\n */\nexport function isProvider(\n providerName: string,\n env: Record<string, string | undefined>,\n processAncestry?: Array<{ command?: string }>,\n): boolean;\nexport function isProvider(\n providerName: string,\n envOrOptions?: Record<string, string | undefined> | DetectOptions,\n legacyAncestry?: Array<{ command?: string }>,\n): boolean {\n const result = detectAgenticEnvironment(\n envOrOptions as DetectOptions,\n legacyAncestry as Array<{ command?: string }> | undefined,\n );\n return result.name === providerName;\n}\n\n/**\n * Check if currently running in any agent environment\n */\nexport function isAgent(options?: DetectOptions): boolean;\n/**\n * @deprecated Pass an options object instead.\n */\nexport function isAgent(\n env: Record<string, string | undefined>,\n processAncestry?: Array<{ command?: string }>,\n): boolean;\nexport function isAgent(\n envOrOptions?: Record<string, string | undefined> | DetectOptions,\n legacyAncestry?: Array<{ command?: string }>,\n): boolean {\n const result = detectAgenticEnvironment(\n envOrOptions as DetectOptions,\n legacyAncestry as Array<{ command?: string }> | undefined,\n );\n return result.type === \"agent\" || result.type === \"hybrid\";\n}\n\n/**\n * Check if currently running in any interactive AI environment\n */\nexport function isInteractive(options?: DetectOptions): boolean;\n/**\n * @deprecated Pass an options object instead.\n */\nexport function isInteractive(\n env: Record<string, string | undefined>,\n processAncestry?: Array<{ command?: string }>,\n): boolean;\nexport function isInteractive(\n envOrOptions?: Record<string, string | undefined> | DetectOptions,\n legacyAncestry?: Array<{ command?: string }>,\n): boolean {\n const result = detectAgenticEnvironment(\n envOrOptions as DetectOptions,\n legacyAncestry as Array<{ command?: string }> | undefined,\n );\n return result.type === \"interactive\" || result.type === \"hybrid\";\n}\n\n/**\n * Check if currently running in any hybrid AI environment\n */\nexport function isHybrid(options?: DetectOptions): boolean;\n/**\n * @deprecated Pass an options object instead.\n */\nexport function isHybrid(\n env: Record<string, string | undefined>,\n processAncestry?: Array<{ command?: string }>,\n): boolean;\nexport function isHybrid(\n envOrOptions?: Record<string, string | undefined> | DetectOptions,\n legacyAncestry?: Array<{ command?: string }>,\n): boolean {\n const result = detectAgenticEnvironment(\n envOrOptions as DetectOptions,\n legacyAncestry as Array<{ command?: string }> | undefined,\n );\n return result.type === \"hybrid\";\n}\n"],"mappings":"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"}
|
package/dist/index.d.mts
CHANGED
|
@@ -30,7 +30,7 @@ interface ProviderConfig {
|
|
|
30
30
|
type: AgenticType;
|
|
31
31
|
/** Environment variables */
|
|
32
32
|
envVars?: Array<EnvVarGroup | EnvVarDefinition>;
|
|
33
|
-
/** Process names to check for in the process tree */
|
|
33
|
+
/** Process names to check for in the process tree (only used when checkProcesses is enabled) */
|
|
34
34
|
processChecks?: string[];
|
|
35
35
|
/** Custom detection functions for complex logic */
|
|
36
36
|
customDetectors?: (() => boolean)[];
|
|
@@ -48,6 +48,33 @@ interface DetectionResult {
|
|
|
48
48
|
/** Type of agentic environment, if detected */
|
|
49
49
|
type: AgenticType | null;
|
|
50
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* Options for `detectAgenticEnvironment` and related helpers.
|
|
53
|
+
*/
|
|
54
|
+
interface DetectOptions {
|
|
55
|
+
/**
|
|
56
|
+
* Environment variables to inspect. Defaults to `process.env`.
|
|
57
|
+
*/
|
|
58
|
+
env?: Record<string, string | undefined>;
|
|
59
|
+
/**
|
|
60
|
+
* Pre-computed process ancestry (from `process-ancestry` or compatible). When
|
|
61
|
+
* provided, this is used in place of fetching ancestry at detection time.
|
|
62
|
+
* Implies `checkProcesses: true` unless explicitly set to `false`.
|
|
63
|
+
*/
|
|
64
|
+
processAncestry?: Array<{
|
|
65
|
+
command?: string;
|
|
66
|
+
}>;
|
|
67
|
+
/**
|
|
68
|
+
* Whether to fall back to process-ancestry checks when no environment-variable
|
|
69
|
+
* match is found. Defaults to `false` because fetching the process tree is
|
|
70
|
+
* expensive on some platforms (notably Windows).
|
|
71
|
+
*
|
|
72
|
+
* Set to `true` to enable detection of providers that only expose a
|
|
73
|
+
* processChecks signal (e.g. Octofriend), at the cost of spawning a
|
|
74
|
+
* subprocess to read the process tree.
|
|
75
|
+
*/
|
|
76
|
+
checkProcesses?: boolean;
|
|
77
|
+
}
|
|
51
78
|
//#endregion
|
|
52
79
|
//#region src/providers.d.ts
|
|
53
80
|
/**
|
|
@@ -67,27 +94,54 @@ declare function getProvidersByType(type: "agent" | "interactive" | "hybrid"): P
|
|
|
67
94
|
/**
|
|
68
95
|
* Detect agentic coding environment
|
|
69
96
|
*/
|
|
70
|
-
declare function detectAgenticEnvironment(
|
|
97
|
+
declare function detectAgenticEnvironment(options?: DetectOptions): DetectionResult;
|
|
98
|
+
/**
|
|
99
|
+
* @deprecated Pass an options object instead. This signature is retained for
|
|
100
|
+
* backwards compatibility and will be removed in a future major release.
|
|
101
|
+
*/
|
|
102
|
+
declare function detectAgenticEnvironment(env: Record<string, string | undefined>, processAncestry?: Array<{
|
|
71
103
|
command?: string;
|
|
72
104
|
}>): DetectionResult;
|
|
105
|
+
/**
|
|
106
|
+
* Check if currently running in a specific provider
|
|
107
|
+
*/
|
|
108
|
+
declare function isProvider(providerName: string, options?: DetectOptions): boolean;
|
|
109
|
+
/**
|
|
110
|
+
* @deprecated Pass an options object instead.
|
|
111
|
+
*/
|
|
112
|
+
declare function isProvider(providerName: string, env: Record<string, string | undefined>, processAncestry?: Array<{
|
|
113
|
+
command?: string;
|
|
114
|
+
}>): boolean;
|
|
73
115
|
/**
|
|
74
116
|
* Check if currently running in any agent environment
|
|
75
117
|
*/
|
|
76
|
-
declare function isAgent(
|
|
118
|
+
declare function isAgent(options?: DetectOptions): boolean;
|
|
119
|
+
/**
|
|
120
|
+
* @deprecated Pass an options object instead.
|
|
121
|
+
*/
|
|
122
|
+
declare function isAgent(env: Record<string, string | undefined>, processAncestry?: Array<{
|
|
77
123
|
command?: string;
|
|
78
124
|
}>): boolean;
|
|
79
125
|
/**
|
|
80
126
|
* Check if currently running in any interactive AI environment
|
|
81
127
|
*/
|
|
82
|
-
declare function isInteractive(
|
|
128
|
+
declare function isInteractive(options?: DetectOptions): boolean;
|
|
129
|
+
/**
|
|
130
|
+
* @deprecated Pass an options object instead.
|
|
131
|
+
*/
|
|
132
|
+
declare function isInteractive(env: Record<string, string | undefined>, processAncestry?: Array<{
|
|
83
133
|
command?: string;
|
|
84
134
|
}>): boolean;
|
|
85
135
|
/**
|
|
86
136
|
* Check if currently running in any hybrid AI environment
|
|
87
137
|
*/
|
|
88
|
-
declare function isHybrid(
|
|
138
|
+
declare function isHybrid(options?: DetectOptions): boolean;
|
|
139
|
+
/**
|
|
140
|
+
* @deprecated Pass an options object instead.
|
|
141
|
+
*/
|
|
142
|
+
declare function isHybrid(env: Record<string, string | undefined>, processAncestry?: Array<{
|
|
89
143
|
command?: string;
|
|
90
144
|
}>): boolean;
|
|
91
145
|
//#endregion
|
|
92
|
-
export { type AgenticType, type DetectionResult, type ProviderConfig, detectAgenticEnvironment as default, detectAgenticEnvironment, getProvider, getProvidersByType, isAgent, isHybrid, isInteractive, providers };
|
|
146
|
+
export { type AgenticType, type DetectOptions, type DetectionResult, type EnvVarDefinition, type EnvVarGroup, type ProviderConfig, detectAgenticEnvironment as default, detectAgenticEnvironment, getProvider, getProvidersByType, isAgent, isHybrid, isInteractive, isProvider, providers };
|
|
93
147
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/providers.ts","../src/detector.ts"],"mappings":";;AAGA;;KAAY,WAAA;;;AAKZ;KAAY,gBAAA;;;;UAKK,WAAA;EAAW;EAE1B,GAAA,GAAM,gBAAA;EAAA;EAGN,GAAA,GAAM,gBAAA;EAGC;EAAP,IAAA,GAAO,gBAAA;AAAA;;;;UAMQ,cAAA;EANf;EAQA,EAAA;EARuB;EAWvB,IAAA;EALe;EAQf,IAAA,EAAM,WAAA;;EAGN,OAAA,GAAU,KAAA,CAAM,WAAA,GAAc,gBAAA;EAAd;EAGhB,aAAA;EAHU;EAMV,eAAA;AAAA;;;;UAMe,eAAA;EAZf;EAcA,SAAA;EAdgB;EAiBhB,EAAA;EAdA;EAiBA,IAAA;EAde;EAiBf,IAAA,EAAM,WAAA;AAAA;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/providers.ts","../src/detector.ts"],"mappings":";;AAGA;;KAAY,WAAA;;;AAKZ;KAAY,gBAAA;;;;UAKK,WAAA;EAAW;EAE1B,GAAA,GAAM,gBAAA;EAAA;EAGN,GAAA,GAAM,gBAAA;EAGC;EAAP,IAAA,GAAO,gBAAA;AAAA;;;;UAMQ,cAAA;EANf;EAQA,EAAA;EARuB;EAWvB,IAAA;EALe;EAQf,IAAA,EAAM,WAAA;;EAGN,OAAA,GAAU,KAAA,CAAM,WAAA,GAAc,gBAAA;EAAd;EAGhB,aAAA;EAHU;EAMV,eAAA;AAAA;;;;UAMe,eAAA;EAZf;EAcA,SAAA;EAdgB;EAiBhB,EAAA;EAdA;EAiBA,IAAA;EAde;EAiBf,IAAA,EAAM,WAAA;AAAA;;;;UAMS,aAAA;EAZf;;;EAgBA,GAAA,GAAM,MAAA;EAVW;;AAMnB;;;EAWE,eAAA,GAAkB,KAAA;IAAQ,OAAA;EAAA;EAA1B;;;;;;;;;EAWA,cAAA;AAAA;;;AAtFF;;;AAAA,cCEa,SAAA,EAAW,cAAA;;ADGxB;;iBC+PgB,WAAA,CAAY,IAAA,WAAe,cAAA;;;AD1P3C;iBCiQgB,kBAAA,CACd,IAAA,uCACC,cAAA;;;AD7QH;;;AAAA,iBE+IgB,wBAAA,CACd,OAAA,GAAU,aAAA,GACT,eAAA;;AF5IH;;;iBEiJgB,wBAAA,CACd,GAAA,EAAK,MAAA,8BACL,eAAA,GAAkB,KAAA;EAAQ,OAAA;AAAA,KACzB,eAAA;;;;iBA8Da,UAAA,CACd,YAAA,UACA,OAAA,GAAU,aAAA;;;;iBAKI,UAAA,CACd,YAAA,UACA,GAAA,EAAK,MAAA,8BACL,eAAA,GAAkB,KAAA;EAAQ,OAAA;AAAA;;;;iBAiBZ,OAAA,CAAQ,OAAA,GAAU,aAAA;;AF1NlC;;iBE8NgB,OAAA,CACd,GAAA,EAAK,MAAA,8BACL,eAAA,GAAkB,KAAA;EAAQ,OAAA;AAAA;;;;iBAgBZ,aAAA,CAAc,OAAA,GAAU,aAAA;;;;iBAIxB,aAAA,CACd,GAAA,EAAK,MAAA,8BACL,eAAA,GAAkB,KAAA;EAAQ,OAAA;AAAA;;;;iBAgBZ,QAAA,CAAS,OAAA,GAAU,aAAA;;;AF/OnC;iBEmPgB,QAAA,CACd,GAAA,EAAK,MAAA,8BACL,eAAA,GAAkB,KAAA;EAAQ,OAAA;AAAA"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
|
|
1
|
+
import { a as isProvider, c as providers, i as isInteractive, n as isAgent, o as getProvider, r as isHybrid, s as getProvidersByType, t as detectAgenticEnvironment } from "./detector-BrdjJAFA.mjs";
|
|
3
2
|
//#region src/index.ts
|
|
4
3
|
var src_default = detectAgenticEnvironment;
|
|
5
|
-
|
|
6
4
|
//#endregion
|
|
7
|
-
export { src_default as default, detectAgenticEnvironment, getProvider, getProvidersByType, isAgent, isHybrid, isInteractive, providers };
|
|
5
|
+
export { src_default as default, detectAgenticEnvironment, getProvider, getProvidersByType, isAgent, isHybrid, isInteractive, isProvider, providers };
|
|
6
|
+
|
|
8
7
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * am-i-vibing - Detect agentic coding environments and AI assistant tools\n */\n\n// Export types\nexport type {
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * am-i-vibing - Detect agentic coding environments and AI assistant tools\n */\n\n// Export types\nexport type {\n AgenticType,\n ProviderConfig,\n DetectionResult,\n DetectOptions,\n EnvVarDefinition,\n EnvVarGroup,\n} from \"./types.js\";\n\n// Export providers\nexport { providers, getProvider, getProvidersByType } from \"./providers.js\";\n\n// Export detection functions\nexport {\n detectAgenticEnvironment,\n isProvider,\n isAgent,\n isInteractive,\n isHybrid,\n} from \"./detector.js\";\n\n// Import for default export\nimport { detectAgenticEnvironment } from \"./detector.js\";\n\n// Convenience export for the main function\nexport default detectAgenticEnvironment;\n"],"mappings":";;AA8BA,IAAA,cAAe"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "am-i-vibing",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Detect agentic coding environments and AI assistant tools",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.mjs",
|
|
@@ -15,11 +15,11 @@
|
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
17
17
|
"@arethetypeswrong/cli": "^0.18.2",
|
|
18
|
-
"@types/node": "^24.
|
|
19
|
-
"publint": "^0.3.
|
|
20
|
-
"tsdown": "^0.
|
|
21
|
-
"typescript": "^
|
|
22
|
-
"vitest": "^4.
|
|
18
|
+
"@types/node": "^24.12.2",
|
|
19
|
+
"publint": "^0.3.18",
|
|
20
|
+
"tsdown": "^0.21.10",
|
|
21
|
+
"typescript": "^6.0.3",
|
|
22
|
+
"vitest": "^4.1.5"
|
|
23
23
|
},
|
|
24
24
|
"repository": {
|
|
25
25
|
"type": "git",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"detector-CddkGnEB.mjs","names":[],"sources":["../src/providers.ts","../src/detector.ts"],"sourcesContent":["import type { ProviderConfig } from \"./types.js\";\n\n/**\n * Provider configurations for major AI coding tools\n */\nexport const providers: ProviderConfig[] = [\n {\n id: \"opencode\",\n name: \"OpenCode\",\n type: \"agent\",\n envVars: [\n {\n any: [\n \"OPENCODE\",\n \"OPENCODE_BIN_PATH\",\n \"OPENCODE_SERVER\",\n \"OPENCODE_APP_INFO\",\n \"OPENCODE_MODES\",\n ],\n },\n ],\n },\n {\n id: \"jules\",\n name: \"Jules\",\n type: \"agent\",\n envVars: [\n {\n all: [\n [\"HOME\", \"/home/jules\"],\n [\"USER\", \"swebot\"],\n ],\n },\n ],\n },\n {\n id: \"claude-code\",\n name: \"Claude Code\",\n type: \"agent\",\n envVars: [\"CLAUDECODE\"],\n },\n {\n id: \"cursor-agent\",\n name: \"Cursor Agent\",\n type: \"agent\",\n envVars: [\n {\n all: [\"CURSOR_TRACE_ID\", [\"PAGER\", \"head -n 10000 | cat\"]],\n },\n ],\n },\n {\n id: \"cursor\",\n name: \"Cursor\",\n type: \"interactive\",\n envVars: [\"CURSOR_TRACE_ID\"],\n },\n {\n id: \"gemini-agent\",\n name: \"Gemini Agent\",\n type: \"agent\",\n processChecks: [\"gemini\"],\n },\n {\n id: \"codex\",\n name: \"OpenAI Codex\",\n type: \"agent\",\n processChecks: [\"codex\"],\n },\n {\n id: \"replit\",\n name: \"Replit\",\n type: \"agent\",\n envVars: [\"REPL_ID\"],\n },\n {\n id: \"aider\",\n name: \"Aider\",\n type: \"agent\",\n envVars: [\"AIDER_API_KEY\"],\n processChecks: [\"aider\"],\n },\n {\n id: \"bolt-agent\",\n name: \"Bolt.new Agent\",\n type: \"agent\",\n envVars: [\n {\n all: [[\"SHELL\", \"/bin/jsh\"], \"npm_config_yes\"],\n },\n ],\n },\n {\n id: \"bolt\",\n name: \"Bolt.new\",\n type: \"interactive\",\n envVars: [\n {\n all: [[\"SHELL\", \"/bin/jsh\"]],\n none: [\"npm_config_yes\"],\n },\n ],\n },\n {\n id: \"zed-agent\",\n name: \"Zed Agent\",\n type: \"agent\",\n envVars: [\n {\n all: [\n [\"TERM_PROGRAM\", \"zed\"],\n [\"PAGER\", \"cat\"],\n ],\n },\n ],\n },\n {\n id: \"zed\",\n name: \"Zed\",\n type: \"interactive\",\n envVars: [\n {\n all: [[\"TERM_PROGRAM\", \"zed\"]],\n none: [[\"PAGER\", \"cat\"]],\n },\n ],\n },\n {\n id: \"replit-assistant\",\n name: \"Replit Assistant\",\n type: \"agent\",\n envVars: [\n {\n all: [\"REPL_ID\", [\"REPLIT_MODE\", \"assistant\"]],\n },\n ],\n },\n {\n id: \"replit\",\n name: \"Replit\",\n type: \"interactive\",\n envVars: [\n {\n all: [\"REPL_ID\"],\n none: [[\"REPLIT_MODE\", \"assistant\"]],\n },\n ],\n },\n {\n id: \"windsurf\",\n name: \"Windsurf\",\n type: \"agent\",\n envVars: [\"CODEIUM_EDITOR_APP_ROOT\"],\n },\n {\n id: \"crush\",\n name: \"Crush\",\n type: \"agent\",\n processChecks: [\"crush\"],\n },\n {\n id: \"vscode-copilot-agent\",\n name: \"GitHub Copilot in VS Code\",\n type: \"agent\",\n envVars: [\n {\n all: [\n [\"TERM_PROGRAM\", \"vscode\"],\n [\"GIT_PAGER\", \"cat\"],\n ],\n },\n ],\n },\n {\n id: \"warp\",\n name: \"Warp Terminal\",\n type: \"hybrid\",\n envVars: [\n {\n all: [[\"TERM_PROGRAM\", \"WarpTerminal\"]],\n },\n ],\n },\n {\n id: \"octofriend\",\n name: \"Octofriend\",\n type: \"agent\",\n processChecks: [\"octofriend\"],\n },\n];\n\n/**\n * Get provider configuration by name\n */\nexport function getProvider(name: string): ProviderConfig | undefined {\n return providers.find((p) => p.name === name);\n}\n\n/**\n * Get all providers of a specific type\n */\nexport function getProvidersByType(\n type: \"agent\" | \"interactive\" | \"hybrid\",\n): ProviderConfig[] {\n return providers.filter((p) => p.type === type);\n}\n","import type {\n DetectionResult,\n ProviderConfig,\n EnvVarDefinition,\n EnvVarGroup,\n} from \"./types.js\";\nimport { providers } from \"./providers.js\";\nimport { getProcessAncestry } from \"process-ancestry\";\n\n/**\n * Check if a specific environment variable exists (handles both strings and tuples)\n */\nfunction checkEnvVar(\n envVarDef: EnvVarDefinition,\n env: Record<string, string | undefined> = process.env,\n): boolean {\n const [envVar, expectedValue] =\n typeof envVarDef === \"string\" ? [envVarDef, undefined] : envVarDef;\n\n const actualValue = env[envVar];\n return Boolean(\n actualValue && (!expectedValue || actualValue === expectedValue),\n );\n}\n\n/**\n * Check if a process is running in the process tree\n */\nfunction checkProcess(\n processName: string,\n processAncestry?: Array<{ command?: string }>,\n): boolean {\n try {\n const ancestry = processAncestry ?? getProcessAncestry();\n for (const ancestorProcess of ancestry) {\n if (ancestorProcess.command?.includes(processName)) {\n return true;\n }\n }\n } catch (error) {\n // Ignore process check errors\n }\n return false;\n}\n\n/**\n * Check if an environment variable group matches based on its properties\n */\nfunction checkEnvVars(\n definition: EnvVarGroup | EnvVarDefinition,\n env: Record<string, string | undefined> = process.env,\n): boolean {\n if (typeof definition === \"string\" || Array.isArray(definition)) {\n return checkEnvVar(definition, env);\n }\n\n const { any, all, none } = definition;\n\n // Check ANY conditions (OR logic) - at least one must pass\n const anyResult =\n !any?.length || any.some((envVar) => checkEnvVar(envVar, env));\n\n // Check ALL conditions (AND logic) - all must pass\n const allResult =\n !all?.length || all.every((envVar) => checkEnvVar(envVar, env));\n\n // Check NONE conditions (NOT logic) - none should pass\n const noneResult =\n !none?.length || !none.some((envVar) => checkEnvVar(envVar, env));\n\n return anyResult && allResult && noneResult;\n}\n\n/**\n * Run custom detectors for a provider\n */\nfunction runCustomDetectors(provider: ProviderConfig): boolean {\n return (\n provider.customDetectors?.some((detector) => {\n try {\n return detector();\n } catch {\n return false;\n }\n }) ?? false\n );\n}\n\n/**\n * Create a positive detection result\n */\nfunction createDetectedResult(provider: ProviderConfig): DetectionResult {\n return {\n isAgentic: true,\n id: provider.id,\n name: provider.name,\n type: provider.type,\n };\n}\n\n/**\n * Detect agentic coding environment\n */\nexport function detectAgenticEnvironment(\n env: Record<string, string | undefined> = process.env,\n processAncestry?: Array<{ command?: string }>,\n): DetectionResult {\n // Fast path: check all environment variables first\n for (const provider of providers) {\n if (provider.envVars?.some((group) => checkEnvVars(group, env))) {\n return createDetectedResult(provider);\n }\n }\n\n // Slow path: check processes only if no env var match found\n // Lazy evaluation: compute process ancestry only once when needed\n let cachedAncestry = processAncestry;\n const getAncestry = () => {\n if (cachedAncestry === undefined) {\n try {\n cachedAncestry = getProcessAncestry();\n } catch {\n cachedAncestry = []; // Fallback to empty on error\n }\n }\n return cachedAncestry;\n };\n\n for (const provider of providers) {\n if (provider.processChecks?.some((processName) => checkProcess(processName, getAncestry()))) {\n return createDetectedResult(provider);\n }\n }\n\n // Custom detectors last\n for (const provider of providers) {\n if (runCustomDetectors(provider)) {\n return createDetectedResult(provider);\n }\n }\n\n // No provider detected\n return {\n isAgentic: false,\n id: null,\n name: null,\n type: null,\n };\n}\n\n/**\n * Check if currently running in a specific provider\n */\nexport function isProvider(\n providerName: string,\n env: Record<string, string | undefined> = process.env,\n processAncestry?: Array<{ command?: string }>,\n): boolean {\n const result = detectAgenticEnvironment(env, processAncestry);\n return result.name === providerName;\n}\n\n/**\n * Check if currently running in any agent environment\n */\nexport function isAgent(\n env: Record<string, string | undefined> = process.env,\n processAncestry?: Array<{ command?: string }>,\n): boolean {\n const result = detectAgenticEnvironment(env, processAncestry);\n return result.type === \"agent\" || result.type === \"hybrid\";\n}\n\n/**\n * Check if currently running in any interactive AI environment\n */\nexport function isInteractive(\n env: Record<string, string | undefined> = process.env,\n processAncestry?: Array<{ command?: string }>,\n): boolean {\n const result = detectAgenticEnvironment(env, processAncestry);\n return result.type === \"interactive\" || result.type === \"hybrid\";\n}\n\n/**\n * Check if currently running in any hybrid AI environment\n */\nexport function isHybrid(\n env: Record<string, string | undefined> = process.env,\n processAncestry?: Array<{ command?: string }>,\n): boolean {\n const result = detectAgenticEnvironment(env, processAncestry);\n return result.type === \"hybrid\";\n}\n"],"mappings":";;;;;;AAKA,MAAa,YAA8B;CACzC;EACE,IAAI;EACJ,MAAM;EACN,MAAM;EACN,SAAS,CACP,EACE,KAAK;GACH;GACA;GACA;GACA;GACA;GACD,EACF,CACF;EACF;CACD;EACE,IAAI;EACJ,MAAM;EACN,MAAM;EACN,SAAS,CACP,EACE,KAAK,CACH,CAAC,QAAQ,cAAc,EACvB,CAAC,QAAQ,SAAS,CACnB,EACF,CACF;EACF;CACD;EACE,IAAI;EACJ,MAAM;EACN,MAAM;EACN,SAAS,CAAC,aAAa;EACxB;CACD;EACE,IAAI;EACJ,MAAM;EACN,MAAM;EACN,SAAS,CACP,EACE,KAAK,CAAC,mBAAmB,CAAC,SAAS,sBAAsB,CAAC,EAC3D,CACF;EACF;CACD;EACE,IAAI;EACJ,MAAM;EACN,MAAM;EACN,SAAS,CAAC,kBAAkB;EAC7B;CACD;EACE,IAAI;EACJ,MAAM;EACN,MAAM;EACN,eAAe,CAAC,SAAS;EAC1B;CACD;EACE,IAAI;EACJ,MAAM;EACN,MAAM;EACN,eAAe,CAAC,QAAQ;EACzB;CACD;EACE,IAAI;EACJ,MAAM;EACN,MAAM;EACN,SAAS,CAAC,UAAU;EACrB;CACD;EACE,IAAI;EACJ,MAAM;EACN,MAAM;EACN,SAAS,CAAC,gBAAgB;EAC1B,eAAe,CAAC,QAAQ;EACzB;CACD;EACE,IAAI;EACJ,MAAM;EACN,MAAM;EACN,SAAS,CACP,EACE,KAAK,CAAC,CAAC,SAAS,WAAW,EAAE,iBAAiB,EAC/C,CACF;EACF;CACD;EACE,IAAI;EACJ,MAAM;EACN,MAAM;EACN,SAAS,CACP;GACE,KAAK,CAAC,CAAC,SAAS,WAAW,CAAC;GAC5B,MAAM,CAAC,iBAAiB;GACzB,CACF;EACF;CACD;EACE,IAAI;EACJ,MAAM;EACN,MAAM;EACN,SAAS,CACP,EACE,KAAK,CACH,CAAC,gBAAgB,MAAM,EACvB,CAAC,SAAS,MAAM,CACjB,EACF,CACF;EACF;CACD;EACE,IAAI;EACJ,MAAM;EACN,MAAM;EACN,SAAS,CACP;GACE,KAAK,CAAC,CAAC,gBAAgB,MAAM,CAAC;GAC9B,MAAM,CAAC,CAAC,SAAS,MAAM,CAAC;GACzB,CACF;EACF;CACD;EACE,IAAI;EACJ,MAAM;EACN,MAAM;EACN,SAAS,CACP,EACE,KAAK,CAAC,WAAW,CAAC,eAAe,YAAY,CAAC,EAC/C,CACF;EACF;CACD;EACE,IAAI;EACJ,MAAM;EACN,MAAM;EACN,SAAS,CACP;GACE,KAAK,CAAC,UAAU;GAChB,MAAM,CAAC,CAAC,eAAe,YAAY,CAAC;GACrC,CACF;EACF;CACD;EACE,IAAI;EACJ,MAAM;EACN,MAAM;EACN,SAAS,CAAC,0BAA0B;EACrC;CACD;EACE,IAAI;EACJ,MAAM;EACN,MAAM;EACN,eAAe,CAAC,QAAQ;EACzB;CACD;EACE,IAAI;EACJ,MAAM;EACN,MAAM;EACN,SAAS,CACP,EACE,KAAK,CACH,CAAC,gBAAgB,SAAS,EAC1B,CAAC,aAAa,MAAM,CACrB,EACF,CACF;EACF;CACD;EACE,IAAI;EACJ,MAAM;EACN,MAAM;EACN,SAAS,CACP,EACE,KAAK,CAAC,CAAC,gBAAgB,eAAe,CAAC,EACxC,CACF;EACF;CACD;EACE,IAAI;EACJ,MAAM;EACN,MAAM;EACN,eAAe,CAAC,aAAa;EAC9B;CACF;;;;AAKD,SAAgB,YAAY,MAA0C;AACpE,QAAO,UAAU,MAAM,MAAM,EAAE,SAAS,KAAK;;;;;AAM/C,SAAgB,mBACd,MACkB;AAClB,QAAO,UAAU,QAAQ,MAAM,EAAE,SAAS,KAAK;;;;;;;;AChMjD,SAAS,YACP,WACA,MAA0C,QAAQ,KACzC;CACT,MAAM,CAAC,QAAQ,iBACb,OAAO,cAAc,WAAW,CAAC,WAAW,OAAU,GAAG;CAE3D,MAAM,cAAc,IAAI;AACxB,QAAO,QACL,gBAAgB,CAAC,iBAAiB,gBAAgB,eACnD;;;;;AAMH,SAAS,aACP,aACA,iBACS;AACT,KAAI;EACF,MAAM,WAAW,mBAAmB,oBAAoB;AACxD,OAAK,MAAM,mBAAmB,SAC5B,KAAI,gBAAgB,SAAS,SAAS,YAAY,CAChD,QAAO;UAGJ,OAAO;AAGhB,QAAO;;;;;AAMT,SAAS,aACP,YACA,MAA0C,QAAQ,KACzC;AACT,KAAI,OAAO,eAAe,YAAY,MAAM,QAAQ,WAAW,CAC7D,QAAO,YAAY,YAAY,IAAI;CAGrC,MAAM,EAAE,KAAK,KAAK,SAAS;CAG3B,MAAM,YACJ,CAAC,KAAK,UAAU,IAAI,MAAM,WAAW,YAAY,QAAQ,IAAI,CAAC;CAGhE,MAAM,YACJ,CAAC,KAAK,UAAU,IAAI,OAAO,WAAW,YAAY,QAAQ,IAAI,CAAC;CAGjE,MAAM,aACJ,CAAC,MAAM,UAAU,CAAC,KAAK,MAAM,WAAW,YAAY,QAAQ,IAAI,CAAC;AAEnE,QAAO,aAAa,aAAa;;;;;AAMnC,SAAS,mBAAmB,UAAmC;AAC7D,QACE,SAAS,iBAAiB,MAAM,aAAa;AAC3C,MAAI;AACF,UAAO,UAAU;UACX;AACN,UAAO;;GAET,IAAI;;;;;AAOV,SAAS,qBAAqB,UAA2C;AACvE,QAAO;EACL,WAAW;EACX,IAAI,SAAS;EACb,MAAM,SAAS;EACf,MAAM,SAAS;EAChB;;;;;AAMH,SAAgB,yBACd,MAA0C,QAAQ,KAClD,iBACiB;AAEjB,MAAK,MAAM,YAAY,UACrB,KAAI,SAAS,SAAS,MAAM,UAAU,aAAa,OAAO,IAAI,CAAC,CAC7D,QAAO,qBAAqB,SAAS;CAMzC,IAAI,iBAAiB;CACrB,MAAM,oBAAoB;AACxB,MAAI,mBAAmB,OACrB,KAAI;AACF,oBAAiB,oBAAoB;UAC/B;AACN,oBAAiB,EAAE;;AAGvB,SAAO;;AAGT,MAAK,MAAM,YAAY,UACrB,KAAI,SAAS,eAAe,MAAM,gBAAgB,aAAa,aAAa,aAAa,CAAC,CAAC,CACzF,QAAO,qBAAqB,SAAS;AAKzC,MAAK,MAAM,YAAY,UACrB,KAAI,mBAAmB,SAAS,CAC9B,QAAO,qBAAqB,SAAS;AAKzC,QAAO;EACL,WAAW;EACX,IAAI;EACJ,MAAM;EACN,MAAM;EACP;;;;;AAkBH,SAAgB,QACd,MAA0C,QAAQ,KAClD,iBACS;CACT,MAAM,SAAS,yBAAyB,KAAK,gBAAgB;AAC7D,QAAO,OAAO,SAAS,WAAW,OAAO,SAAS;;;;;AAMpD,SAAgB,cACd,MAA0C,QAAQ,KAClD,iBACS;CACT,MAAM,SAAS,yBAAyB,KAAK,gBAAgB;AAC7D,QAAO,OAAO,SAAS,iBAAiB,OAAO,SAAS;;;;;AAM1D,SAAgB,SACd,MAA0C,QAAQ,KAClD,iBACS;AAET,QADe,yBAAyB,KAAK,gBAAgB,CAC/C,SAAS"}
|