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 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
- - **Codex CLI**
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
- - `-d, --debug` - Debug output with environment and process info
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-CddkGnEB.mjs";
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 result = detectAgenticEnvironment();
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 && ![\"agent\", \"interactive\", \"hybrid\"].includes(values.check)) {\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 };\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 -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 --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(checkType: string): boolean {\n switch (checkType) {\n case \"agent\":\n return isAgent();\n case \"interactive\":\n return isInteractive();\n case \"hybrid\":\n return isHybrid();\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) ? \"true\" : \"false\";\n }\n return result.isAgentic ? `${result.name}` : \"none\";\n }\n\n if (options.check) {\n const matches = checkEnvironmentType(options.check);\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 const result = detectAgenticEnvironment();\n let exitCode = 1;\n\n if (options.check) {\n exitCode = checkEnvironmentType(options.check) ? 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":";;;;;;AAmBA,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;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,KAAI,OAAO,SAAS,CAAC;EAAC;EAAS;EAAe;EAAS,CAAC,SAAS,OAAO,MAAM,EAAE;AAC9E,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;EACf;;AAGH,SAAS,WAAiB;AACxB,SAAQ,IAAI;;;;;;;;;;;;;;;;;;;;;;;;EAwBZ;;AAGF,SAAS,qBAAqB,WAA4B;AACxD,SAAQ,WAAR;EACE,KAAK,QACH,QAAO,SAAS;EAClB,KAAK,cACH,QAAO,eAAe;EACxB,KAAK,SACH,QAAO,UAAU;EACnB,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,MAAM,GAAG,SAAS;AAExD,SAAO,OAAO,YAAY,GAAG,OAAO,SAAS;;AAG/C,KAAI,QAAQ,MAEV,QADgB,qBAAqB,QAAQ,MAAM,GAE/C,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;;CAGjB,MAAM,SAAS,0BAA0B;CACzC,IAAI,WAAW;AAEf,KAAI,QAAQ,MACV,YAAW,qBAAqB,QAAQ,MAAM,GAAG,IAAI;KAErD,YAAW,OAAO,YAAY,IAAI;CAGpC,MAAM,SAAS,aAAa,QAAQ,QAAQ;AAC5C,SAAQ,IAAI,OAAO;AAEnB,SAAQ,KAAK,SAAS;;AAGxB,MAAM"}
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":"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"}
@@ -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 Agent",
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
- try {
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
- * Detect agentic coding environment
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 detectAgenticEnvironment(env = process.env, processAncestry) {
216
- for (const provider of providers) if (provider.envVars?.some((group) => checkEnvVars(group, env))) return createDetectedResult(provider);
217
- let cachedAncestry = processAncestry;
218
- const getAncestry = () => {
219
- if (cachedAncestry === void 0) try {
220
- cachedAncestry = getProcessAncestry();
221
- } catch {
222
- cachedAncestry = [];
223
- }
224
- return cachedAncestry;
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
- for (const provider of providers) if (provider.processChecks?.some((processName) => checkProcess(processName, getAncestry()))) return createDetectedResult(provider);
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
- * Check if currently running in any agent environment
237
- */
238
- function isAgent(env = process.env, processAncestry) {
239
- const result = detectAgenticEnvironment(env, processAncestry);
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
- * Check if currently running in any interactive AI environment
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
- * Check if currently running in any hybrid AI environment
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 { getProvider as a, isInteractive as i, isAgent as n, getProvidersByType as o, isHybrid as r, providers as s, detectAgenticEnvironment as t };
258
- //# sourceMappingURL=detector-CddkGnEB.mjs.map
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(env?: Record<string, string | undefined>, processAncestry?: Array<{
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(env?: Record<string, string | undefined>, processAncestry?: Array<{
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(env?: Record<string, string | undefined>, processAncestry?: Array<{
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(env?: Record<string, string | undefined>, processAncestry?: Array<{
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
@@ -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;;;AA1DR;;;AAAA,cCEa,SAAA,EAAW,cAAA;;ADGxB;;iBC0LgB,WAAA,CAAY,IAAA,WAAe,cAAA;;;ADrL3C;iBC4LgB,kBAAA,CACd,IAAA,uCACC,cAAA;;;ADxMH;;;AAAA,iBEoGgB,wBAAA,CACd,GAAA,GAAK,MAAA,8BACL,eAAA,GAAkB,KAAA;EAAQ,OAAA;AAAA,KACzB,eAAA;;;;iBA2Da,OAAA,CACd,GAAA,GAAK,MAAA,8BACL,eAAA,GAAkB,KAAA;EAAQ,OAAA;AAAA;;;;iBASZ,aAAA,CACd,GAAA,GAAK,MAAA,8BACL,eAAA,GAAkB,KAAA;EAAQ,OAAA;AAAA;;;AFvJ5B;iBEgKgB,QAAA,CACd,GAAA,GAAK,MAAA,8BACL,eAAA,GAAkB,KAAA;EAAQ,OAAA;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 getProvider, i as isInteractive, n as isAgent, o as getProvidersByType, r as isHybrid, s as providers, t as detectAgenticEnvironment } from "./detector-CddkGnEB.mjs";
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
@@ -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 { AgenticType, ProviderConfig, DetectionResult } from \"./types.js\";\n\n// Export providers\nexport { providers, getProvider, getProvidersByType } from \"./providers.js\";\n\n// Export detection functions\nexport {\n detectAgenticEnvironment,\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":";;;AAsBA,kBAAe"}
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.1.1",
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.10.15",
19
- "publint": "^0.3.17",
20
- "tsdown": "^0.20.3",
21
- "typescript": "^5.9.3",
22
- "vitest": "^4.0.18"
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":"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"}