@agentuity/cli 1.0.1 → 1.0.3
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/AGENTS.md +40 -24
- package/bin/cli.ts +47 -22
- package/dist/agent-detection.d.ts +23 -38
- package/dist/agent-detection.d.ts.map +1 -1
- package/dist/agent-detection.js +412 -153
- package/dist/agent-detection.js.map +1 -1
- package/dist/ai-help.d.ts +23 -0
- package/dist/ai-help.d.ts.map +1 -0
- package/dist/ai-help.js +328 -0
- package/dist/ai-help.js.map +1 -0
- package/dist/api.js +1 -1
- package/dist/api.js.map +1 -1
- package/dist/auth.d.ts +10 -1
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +176 -16
- package/dist/auth.js.map +1 -1
- package/dist/banner.d.ts.map +1 -1
- package/dist/banner.js +5 -0
- package/dist/banner.js.map +1 -1
- package/dist/cache/agent-intro.d.ts +13 -0
- package/dist/cache/agent-intro.d.ts.map +1 -0
- package/dist/cache/agent-intro.js +54 -0
- package/dist/cache/agent-intro.js.map +1 -0
- package/dist/cache/index.d.ts +1 -0
- package/dist/cache/index.d.ts.map +1 -1
- package/dist/cache/index.js +1 -0
- package/dist/cache/index.js.map +1 -1
- package/dist/cache/resource-region.d.ts +3 -2
- package/dist/cache/resource-region.d.ts.map +1 -1
- package/dist/cache/resource-region.js +13 -4
- package/dist/cache/resource-region.js.map +1 -1
- package/dist/catalyst.d.ts +7 -0
- package/dist/catalyst.d.ts.map +1 -0
- package/dist/catalyst.js +15 -0
- package/dist/catalyst.js.map +1 -0
- package/dist/cli.d.ts +12 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +290 -67
- package/dist/cli.js.map +1 -1
- package/dist/cmd/ai/detect.d.ts +3 -0
- package/dist/cmd/ai/detect.d.ts.map +1 -0
- package/dist/cmd/ai/detect.js +49 -0
- package/dist/cmd/ai/detect.js.map +1 -0
- package/dist/cmd/ai/index.d.ts.map +1 -1
- package/dist/cmd/ai/index.js +18 -1
- package/dist/cmd/ai/index.js.map +1 -1
- package/dist/cmd/ai/intro.d.ts +7 -0
- package/dist/cmd/ai/intro.d.ts.map +1 -0
- package/dist/cmd/ai/intro.js +141 -0
- package/dist/cmd/ai/intro.js.map +1 -0
- package/dist/cmd/ai/opencode/run.d.ts.map +1 -1
- package/dist/cmd/ai/opencode/run.js +5 -0
- package/dist/cmd/ai/opencode/run.js.map +1 -1
- package/dist/cmd/build/ast.d.ts.map +1 -1
- package/dist/cmd/build/ast.js +79 -0
- package/dist/cmd/build/ast.js.map +1 -1
- package/dist/cmd/build/vite/bun-dev-server.d.ts.map +1 -1
- package/dist/cmd/build/vite/bun-dev-server.js +2 -0
- package/dist/cmd/build/vite/bun-dev-server.js.map +1 -1
- package/dist/cmd/build/vite/docs-generator.d.ts.map +1 -1
- package/dist/cmd/build/vite/docs-generator.js +15 -1
- package/dist/cmd/build/vite/docs-generator.js.map +1 -1
- package/dist/cmd/build/vite/env-types-generator.d.ts +26 -0
- package/dist/cmd/build/vite/env-types-generator.d.ts.map +1 -0
- package/dist/cmd/build/vite/env-types-generator.js +110 -0
- package/dist/cmd/build/vite/env-types-generator.js.map +1 -0
- package/dist/cmd/build/vite/index.d.ts +2 -0
- package/dist/cmd/build/vite/index.d.ts.map +1 -1
- package/dist/cmd/build/vite/index.js +12 -1
- package/dist/cmd/build/vite/index.js.map +1 -1
- package/dist/cmd/build/vite/public-asset-path-plugin.d.ts.map +1 -1
- package/dist/cmd/build/vite/public-asset-path-plugin.js.map +1 -1
- package/dist/cmd/build/vite/vite-builder.d.ts +2 -0
- package/dist/cmd/build/vite/vite-builder.d.ts.map +1 -1
- package/dist/cmd/build/vite/vite-builder.js +10 -1
- package/dist/cmd/build/vite/vite-builder.js.map +1 -1
- package/dist/cmd/cloud/db/create.js.map +1 -1
- package/dist/cmd/cloud/db/delete.js.map +1 -1
- package/dist/cmd/cloud/db/get.d.ts.map +1 -1
- package/dist/cmd/cloud/db/get.js +27 -12
- package/dist/cmd/cloud/db/get.js.map +1 -1
- package/dist/cmd/cloud/deploy-fork.d.ts.map +1 -1
- package/dist/cmd/cloud/deploy-fork.js +2 -0
- package/dist/cmd/cloud/deploy-fork.js.map +1 -1
- package/dist/cmd/cloud/deploy.d.ts.map +1 -1
- package/dist/cmd/cloud/deploy.js +17 -0
- package/dist/cmd/cloud/deploy.js.map +1 -1
- package/dist/cmd/cloud/env/import.js.map +1 -1
- package/dist/cmd/cloud/env/list.js.map +1 -1
- package/dist/cmd/cloud/env/push.js.map +1 -1
- package/dist/cmd/cloud/keyvalue/util.d.ts.map +1 -1
- package/dist/cmd/cloud/keyvalue/util.js +3 -3
- package/dist/cmd/cloud/keyvalue/util.js.map +1 -1
- package/dist/cmd/cloud/machine/list.js +3 -3
- package/dist/cmd/cloud/machine/list.js.map +1 -1
- package/dist/cmd/cloud/region/index.js.map +1 -1
- package/dist/cmd/cloud/region-lookup.d.ts +7 -4
- package/dist/cmd/cloud/region-lookup.d.ts.map +1 -1
- package/dist/cmd/cloud/region-lookup.js +59 -14
- package/dist/cmd/cloud/region-lookup.js.map +1 -1
- package/dist/cmd/cloud/sandbox/cp.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/cp.js +7 -5
- package/dist/cmd/cloud/sandbox/cp.js.map +1 -1
- package/dist/cmd/cloud/sandbox/create.js +2 -2
- package/dist/cmd/cloud/sandbox/create.js.map +1 -1
- package/dist/cmd/cloud/sandbox/delete.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/delete.js +8 -7
- package/dist/cmd/cloud/sandbox/delete.js.map +1 -1
- package/dist/cmd/cloud/sandbox/download.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/download.js +7 -5
- package/dist/cmd/cloud/sandbox/download.js.map +1 -1
- package/dist/cmd/cloud/sandbox/env.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/env.js +7 -5
- package/dist/cmd/cloud/sandbox/env.js.map +1 -1
- package/dist/cmd/cloud/sandbox/exec.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/exec.js +7 -5
- package/dist/cmd/cloud/sandbox/exec.js.map +1 -1
- package/dist/cmd/cloud/sandbox/get.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/get.js +12 -7
- package/dist/cmd/cloud/sandbox/get.js.map +1 -1
- package/dist/cmd/cloud/sandbox/list.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/list.js +40 -63
- package/dist/cmd/cloud/sandbox/list.js.map +1 -1
- package/dist/cmd/cloud/sandbox/ls.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/ls.js +7 -5
- package/dist/cmd/cloud/sandbox/ls.js.map +1 -1
- package/dist/cmd/cloud/sandbox/mkdir.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/mkdir.js +7 -5
- package/dist/cmd/cloud/sandbox/mkdir.js.map +1 -1
- package/dist/cmd/cloud/sandbox/rm.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/rm.js +7 -5
- package/dist/cmd/cloud/sandbox/rm.js.map +1 -1
- package/dist/cmd/cloud/sandbox/rmdir.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/rmdir.js +7 -5
- package/dist/cmd/cloud/sandbox/rmdir.js.map +1 -1
- package/dist/cmd/cloud/sandbox/run.js +1 -1
- package/dist/cmd/cloud/sandbox/run.js.map +1 -1
- package/dist/cmd/cloud/sandbox/snapshot/build.js.map +1 -1
- package/dist/cmd/cloud/sandbox/snapshot/get.js.map +1 -1
- package/dist/cmd/cloud/sandbox/upload.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/upload.js +7 -5
- package/dist/cmd/cloud/sandbox/upload.js.map +1 -1
- package/dist/cmd/cloud/sandbox/util.d.ts +2 -2
- package/dist/cmd/cloud/sandbox/util.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/util.js +14 -13
- package/dist/cmd/cloud/sandbox/util.js.map +1 -1
- package/dist/cmd/cloud/ssh.d.ts.map +1 -1
- package/dist/cmd/cloud/ssh.js +3 -3
- package/dist/cmd/cloud/ssh.js.map +1 -1
- package/dist/cmd/cloud/storage/create.js.map +1 -1
- package/dist/cmd/cloud/storage/delete.js.map +1 -1
- package/dist/cmd/cloud/storage/get.d.ts.map +1 -1
- package/dist/cmd/cloud/storage/get.js +5 -11
- package/dist/cmd/cloud/storage/get.js.map +1 -1
- package/dist/cmd/cloud/storage/list.d.ts.map +1 -1
- package/dist/cmd/cloud/storage/list.js +6 -6
- package/dist/cmd/cloud/storage/list.js.map +1 -1
- package/dist/cmd/cloud/stream/create.d.ts.map +1 -1
- package/dist/cmd/cloud/stream/create.js +7 -4
- package/dist/cmd/cloud/stream/create.js.map +1 -1
- package/dist/cmd/cloud/stream/delete.d.ts.map +1 -1
- package/dist/cmd/cloud/stream/delete.js +25 -4
- package/dist/cmd/cloud/stream/delete.js.map +1 -1
- package/dist/cmd/cloud/stream/get.d.ts.map +1 -1
- package/dist/cmd/cloud/stream/get.js +91 -62
- package/dist/cmd/cloud/stream/get.js.map +1 -1
- package/dist/cmd/cloud/stream/list.d.ts.map +1 -1
- package/dist/cmd/cloud/stream/list.js +66 -38
- package/dist/cmd/cloud/stream/list.js.map +1 -1
- package/dist/cmd/cloud/stream/util.d.ts +20 -0
- package/dist/cmd/cloud/stream/util.d.ts.map +1 -1
- package/dist/cmd/cloud/stream/util.js +27 -3
- package/dist/cmd/cloud/stream/util.js.map +1 -1
- package/dist/cmd/cloud/vector/util.d.ts.map +1 -1
- package/dist/cmd/cloud/vector/util.js +3 -3
- package/dist/cmd/cloud/vector/util.js.map +1 -1
- package/dist/cmd/dev/index.js.map +1 -1
- package/dist/cmd/git/account/add.js.map +1 -1
- package/dist/cmd/git/list.js.map +1 -1
- package/dist/cmd/project/add/database.d.ts +2 -0
- package/dist/cmd/project/add/database.d.ts.map +1 -0
- package/dist/cmd/project/add/database.js +123 -0
- package/dist/cmd/project/add/database.js.map +1 -0
- package/dist/cmd/project/add/domain.d.ts +2 -0
- package/dist/cmd/project/add/domain.d.ts.map +1 -0
- package/dist/cmd/project/add/domain.js +152 -0
- package/dist/cmd/project/add/domain.js.map +1 -0
- package/dist/cmd/project/add/index.d.ts +2 -0
- package/dist/cmd/project/add/index.d.ts.map +1 -0
- package/dist/cmd/project/add/index.js +35 -0
- package/dist/cmd/project/add/index.js.map +1 -0
- package/dist/cmd/project/add/storage.d.ts +2 -0
- package/dist/cmd/project/add/storage.d.ts.map +1 -0
- package/dist/cmd/project/add/storage.js +123 -0
- package/dist/cmd/project/add/storage.js.map +1 -0
- package/dist/cmd/project/auth/init.js.map +1 -1
- package/dist/cmd/project/index.d.ts.map +1 -1
- package/dist/cmd/project/index.js +7 -0
- package/dist/cmd/project/index.js.map +1 -1
- package/dist/cmd/project/reconcile.d.ts.map +1 -1
- package/dist/cmd/project/reconcile.js +32 -0
- package/dist/cmd/project/reconcile.js.map +1 -1
- package/dist/cmd/support/report.js.map +1 -1
- package/dist/cmd/support/system.js +2 -2
- package/dist/cmd/support/system.js.map +1 -1
- package/dist/config.d.ts +6 -3
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +31 -7
- package/dist/config.js.map +1 -1
- package/dist/errors.d.ts +2 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +5 -0
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/repl.js +2 -1
- package/dist/repl.js.map +1 -1
- package/dist/tui/box.d.ts +3 -1
- package/dist/tui/box.d.ts.map +1 -1
- package/dist/tui/box.js +22 -7
- package/dist/tui/box.js.map +1 -1
- package/dist/tui/colors.d.ts +0 -3
- package/dist/tui/colors.d.ts.map +1 -1
- package/dist/tui/colors.js +76 -23
- package/dist/tui/colors.js.map +1 -1
- package/dist/tui/prompt.d.ts +2 -0
- package/dist/tui/prompt.d.ts.map +1 -1
- package/dist/tui/prompt.js +44 -3
- package/dist/tui/prompt.js.map +1 -1
- package/dist/tui/symbols.d.ts +0 -4
- package/dist/tui/symbols.d.ts.map +1 -1
- package/dist/tui/symbols.js +5 -0
- package/dist/tui/symbols.js.map +1 -1
- package/dist/tui.d.ts +8 -0
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +54 -9
- package/dist/tui.js.map +1 -1
- package/dist/types.d.ts +37 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -1
- package/dist/version-check.d.ts.map +1 -1
- package/dist/version-check.js +5 -0
- package/dist/version-check.js.map +1 -1
- package/package.json +6 -6
- package/src/agent-detection.ts +457 -160
- package/src/ai-help.ts +393 -0
- package/src/api.ts +1 -1
- package/src/auth.ts +226 -17
- package/src/banner.ts +5 -0
- package/src/cache/agent-intro.ts +62 -0
- package/src/cache/index.ts +2 -0
- package/src/cache/resource-region.ts +28 -7
- package/src/catalyst.ts +16 -0
- package/src/cli.ts +375 -93
- package/src/cmd/ai/detect.ts +54 -0
- package/src/cmd/ai/index.ts +18 -1
- package/src/cmd/ai/intro.ts +154 -0
- package/src/cmd/ai/opencode/run.ts +5 -0
- package/src/cmd/build/ast.ts +97 -0
- package/src/cmd/build/vite/bun-dev-server.ts +2 -0
- package/src/cmd/build/vite/docs-generator.ts +15 -1
- package/src/cmd/build/vite/env-types-generator.ts +145 -0
- package/src/cmd/build/vite/index.ts +15 -0
- package/src/cmd/build/vite/public-asset-path-plugin.ts +8 -2
- package/src/cmd/build/vite/vite-builder.ts +31 -11
- package/src/cmd/cloud/db/create.ts +16 -16
- package/src/cmd/cloud/db/delete.ts +19 -19
- package/src/cmd/cloud/db/get.ts +32 -17
- package/src/cmd/cloud/deploy-fork.ts +2 -0
- package/src/cmd/cloud/deploy.ts +17 -0
- package/src/cmd/cloud/env/import.ts +6 -6
- package/src/cmd/cloud/env/list.ts +11 -11
- package/src/cmd/cloud/env/push.ts +6 -6
- package/src/cmd/cloud/keyvalue/util.ts +3 -3
- package/src/cmd/cloud/machine/list.ts +3 -3
- package/src/cmd/cloud/region/index.ts +3 -3
- package/src/cmd/cloud/region-lookup.ts +82 -22
- package/src/cmd/cloud/sandbox/cp.ts +9 -4
- package/src/cmd/cloud/sandbox/create.ts +2 -2
- package/src/cmd/cloud/sandbox/delete.ts +10 -7
- package/src/cmd/cloud/sandbox/download.ts +8 -5
- package/src/cmd/cloud/sandbox/env.ts +8 -5
- package/src/cmd/cloud/sandbox/exec.ts +10 -5
- package/src/cmd/cloud/sandbox/get.ts +13 -7
- package/src/cmd/cloud/sandbox/list.ts +47 -73
- package/src/cmd/cloud/sandbox/ls.ts +9 -5
- package/src/cmd/cloud/sandbox/mkdir.ts +9 -5
- package/src/cmd/cloud/sandbox/rm.ts +9 -5
- package/src/cmd/cloud/sandbox/rmdir.ts +9 -5
- package/src/cmd/cloud/sandbox/run.ts +1 -1
- package/src/cmd/cloud/sandbox/snapshot/build.ts +31 -31
- package/src/cmd/cloud/sandbox/snapshot/get.ts +17 -17
- package/src/cmd/cloud/sandbox/upload.ts +8 -5
- package/src/cmd/cloud/sandbox/util.ts +15 -14
- package/src/cmd/cloud/ssh.ts +2 -4
- package/src/cmd/cloud/storage/create.ts +16 -16
- package/src/cmd/cloud/storage/delete.ts +19 -19
- package/src/cmd/cloud/storage/get.ts +5 -16
- package/src/cmd/cloud/storage/list.ts +12 -6
- package/src/cmd/cloud/stream/create.ts +8 -4
- package/src/cmd/cloud/stream/delete.ts +28 -4
- package/src/cmd/cloud/stream/get.ts +102 -64
- package/src/cmd/cloud/stream/list.ts +76 -44
- package/src/cmd/cloud/stream/util.ts +39 -3
- package/src/cmd/cloud/vector/util.ts +3 -3
- package/src/cmd/dev/index.ts +4 -4
- package/src/cmd/git/account/add.ts +5 -5
- package/src/cmd/git/list.ts +7 -7
- package/src/cmd/project/add/database.ts +145 -0
- package/src/cmd/project/add/domain.ts +181 -0
- package/src/cmd/project/add/index.ts +35 -0
- package/src/cmd/project/add/storage.ts +147 -0
- package/src/cmd/project/auth/init.ts +6 -6
- package/src/cmd/project/index.ts +7 -0
- package/src/cmd/project/reconcile.ts +40 -0
- package/src/cmd/support/report.ts +5 -5
- package/src/cmd/support/system.ts +2 -2
- package/src/config.ts +40 -12
- package/src/errors.ts +7 -0
- package/src/index.ts +11 -0
- package/src/repl.ts +4 -1
- package/src/tui/box.ts +24 -9
- package/src/tui/colors.ts +83 -26
- package/src/tui/prompt.ts +55 -3
- package/src/tui/symbols.ts +6 -0
- package/src/tui.ts +55 -9
- package/src/types.ts +46 -2
- package/src/version-check.ts +6 -0
package/src/agent-detection.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { dlopen, FFIType, ptr } from 'bun:ffi';
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Map of process names to internal agent short names.
|
|
5
|
-
* The key is the process name (or substring) that appears in the parent process command line.
|
|
6
|
+
* The key is the process name (or substring) that appears in the parent process path or command line.
|
|
6
7
|
* The value is the internal short name used to identify the agent.
|
|
7
8
|
*
|
|
8
9
|
* Process names verified via `agentuity cloud sandbox run --runtime <agent>:latest`:
|
|
@@ -30,6 +31,7 @@ export const KNOWN_AGENTS: [string, string][] = [
|
|
|
30
31
|
['windsurf', 'windsurf'],
|
|
31
32
|
['zed', 'zed'],
|
|
32
33
|
['amp', 'amp'],
|
|
34
|
+
['warp', 'warp'],
|
|
33
35
|
// TODO: VSCode Agent Mode detection - need to find a reliable way to detect
|
|
34
36
|
// when VSCode's built-in agent (Copilot Chat) is running commands vs just
|
|
35
37
|
// running in VSCode's integrated terminal. May need env var detection.
|
|
@@ -38,234 +40,529 @@ export const KNOWN_AGENTS: [string, string][] = [
|
|
|
38
40
|
export type KnownAgent = (typeof KNOWN_AGENTS)[number][1];
|
|
39
41
|
|
|
40
42
|
/**
|
|
41
|
-
*
|
|
43
|
+
* Display names for known agents (human-friendly names)
|
|
42
44
|
*/
|
|
43
|
-
|
|
45
|
+
export const AGENT_DISPLAY_NAMES: Record<string, string> = {
|
|
46
|
+
opencode: 'Open Code',
|
|
47
|
+
codex: 'OpenAI Codex',
|
|
48
|
+
cursor: 'Cursor',
|
|
49
|
+
'claude-code': 'Claude Code',
|
|
50
|
+
copilot: 'GitHub Copilot',
|
|
51
|
+
gemini: 'Gemini',
|
|
52
|
+
cline: 'Cline',
|
|
53
|
+
roo: 'Roo Code',
|
|
54
|
+
windsurf: 'Windsurf',
|
|
55
|
+
zed: 'Zed',
|
|
56
|
+
amp: 'Amp',
|
|
57
|
+
warp: 'Warp',
|
|
58
|
+
};
|
|
44
59
|
|
|
45
60
|
/**
|
|
46
|
-
*
|
|
61
|
+
* Get the display name for an agent ID
|
|
47
62
|
*/
|
|
48
|
-
|
|
63
|
+
export function getAgentDisplayName(agentId: string): string {
|
|
64
|
+
return AGENT_DISPLAY_NAMES[agentId] || agentId;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// ============================================================================
|
|
68
|
+
// FFI-based Fast Process Path Resolution
|
|
69
|
+
// ============================================================================
|
|
70
|
+
|
|
71
|
+
const PATH_MAX = 4096; // Linux PATH_MAX, also sufficient for macOS
|
|
72
|
+
const ARG_MAX = 65536; // Maximum command line length
|
|
49
73
|
|
|
50
74
|
/**
|
|
51
|
-
*
|
|
75
|
+
* Type for the FFI function that gets a process path
|
|
52
76
|
*/
|
|
53
|
-
|
|
77
|
+
type GetProcessPath = (pid: number) => string | null;
|
|
54
78
|
|
|
55
79
|
/**
|
|
56
|
-
*
|
|
80
|
+
* Type for the FFI function that gets a parent PID
|
|
57
81
|
*/
|
|
58
|
-
|
|
59
|
-
return new Promise((resolve) => {
|
|
60
|
-
const ps = spawn('ps', ['-p', String(pid), '-o', 'ppid=,command='], {
|
|
61
|
-
stdio: ['ignore', 'pipe', 'ignore'],
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
let output = '';
|
|
65
|
-
|
|
66
|
-
ps.stdout.on('data', (data: Buffer) => {
|
|
67
|
-
output += data.toString();
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
ps.on('close', () => {
|
|
71
|
-
const trimmed = output.trim();
|
|
72
|
-
if (!trimmed) {
|
|
73
|
-
resolve(undefined);
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// Output format: " PPID COMMAND" (ppid is right-aligned, then space, then command)
|
|
78
|
-
const match = trimmed.match(/^\s*(\d+)\s+(.+)$/);
|
|
79
|
-
if (!match) {
|
|
80
|
-
resolve(undefined);
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const ppidStr = match[1];
|
|
85
|
-
const commandStr = match[2];
|
|
86
|
-
if (!ppidStr || !commandStr) {
|
|
87
|
-
resolve(undefined);
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const ppid = parseInt(ppidStr, 10);
|
|
92
|
-
const command = commandStr.toLowerCase();
|
|
93
|
-
|
|
94
|
-
if (isNaN(ppid) || ppid <= 1 || !command) {
|
|
95
|
-
resolve(undefined);
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
82
|
+
type GetParentPid = (pid: number) => number | null;
|
|
98
83
|
|
|
99
|
-
|
|
100
|
-
|
|
84
|
+
/**
|
|
85
|
+
* Type for the FFI function that gets command line arguments
|
|
86
|
+
*/
|
|
87
|
+
type GetProcessCmdline = (pid: number) => string | null;
|
|
101
88
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
89
|
+
interface FFIFunctions {
|
|
90
|
+
getProcessPath: GetProcessPath;
|
|
91
|
+
getParentPid: GetParentPid;
|
|
92
|
+
getProcessCmdline: GetProcessCmdline;
|
|
106
93
|
}
|
|
107
94
|
|
|
108
95
|
/**
|
|
109
|
-
*
|
|
96
|
+
* Stub FFI functions for unsupported platforms or when FFI fails to load.
|
|
110
97
|
*/
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
98
|
+
const unsupportedFFI: FFIFunctions = {
|
|
99
|
+
getProcessPath: () => null,
|
|
100
|
+
getParentPid: () => null,
|
|
101
|
+
getProcessCmdline: () => null,
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Initialize FFI functions for the current platform.
|
|
106
|
+
* Returns null functions for unsupported platforms or if FFI initialization fails.
|
|
107
|
+
*/
|
|
108
|
+
function initFFI(): FFIFunctions {
|
|
109
|
+
try {
|
|
110
|
+
if (process.platform === 'darwin') {
|
|
111
|
+
return initDarwinFFI();
|
|
112
|
+
} else if (process.platform === 'linux') {
|
|
113
|
+
return initLinuxFFI();
|
|
115
114
|
}
|
|
115
|
+
} catch (err) {
|
|
116
|
+
// FFI initialization failed (e.g., missing libc on musl/Alpine, dlopen error)
|
|
117
|
+
// Fall back to unsupported stub - agent detection will be skipped
|
|
118
|
+
if (process.env.AGENTUITY_DEBUG_AGENT_DETECTION === '1') {
|
|
119
|
+
console.error(
|
|
120
|
+
'[agent-detection] FFI initialization failed:',
|
|
121
|
+
err instanceof Error ? err.message : err
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
return unsupportedFFI;
|
|
116
125
|
}
|
|
117
|
-
|
|
126
|
+
// Unsupported platform (Windows, etc.)
|
|
127
|
+
return unsupportedFFI;
|
|
118
128
|
}
|
|
119
129
|
|
|
120
130
|
/**
|
|
121
|
-
*
|
|
122
|
-
*
|
|
131
|
+
* Initialize macOS FFI functions using libSystem.dylib
|
|
132
|
+
*
|
|
133
|
+
* NOTE: Shared mutable buffers (pathBuf, argBuf, kinfoBuffer) are safe only in
|
|
134
|
+
* single-threaded use. Detection is synchronous and single-threaded, but any
|
|
135
|
+
* future concurrent usage would corrupt these buffers.
|
|
123
136
|
*/
|
|
124
|
-
function
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
137
|
+
function initDarwinFFI(): FFIFunctions {
|
|
138
|
+
// Shared buffers - reused across calls (single-threaded assumption)
|
|
139
|
+
const pathBuf = new Uint8Array(PATH_MAX);
|
|
140
|
+
const argBuf = new Uint8Array(ARG_MAX);
|
|
141
|
+
|
|
142
|
+
// Size of kinfo_proc struct on macOS (arm64 and x86_64)
|
|
143
|
+
const KINFO_PROC_SIZE = 648;
|
|
144
|
+
const kinfoBuffer = new Uint8Array(KINFO_PROC_SIZE);
|
|
145
|
+
|
|
146
|
+
// Load libSystem for proc_pidpath and sysctl
|
|
147
|
+
const lib = dlopen('libSystem.dylib', {
|
|
148
|
+
proc_pidpath: {
|
|
149
|
+
args: [FFIType.i32, FFIType.ptr, FFIType.u32],
|
|
150
|
+
returns: FFIType.i32,
|
|
151
|
+
},
|
|
152
|
+
sysctl: {
|
|
153
|
+
args: [FFIType.ptr, FFIType.u32, FFIType.ptr, FFIType.ptr, FFIType.ptr, FFIType.u64],
|
|
154
|
+
returns: FFIType.i32,
|
|
155
|
+
},
|
|
156
|
+
});
|
|
131
157
|
|
|
132
|
-
|
|
158
|
+
const getProcessPath: GetProcessPath = (pid: number) => {
|
|
159
|
+
if (pid <= 0) return null;
|
|
160
|
+
try {
|
|
161
|
+
const len = lib.symbols.proc_pidpath(pid, ptr(pathBuf), PATH_MAX);
|
|
162
|
+
if (len > 0) {
|
|
163
|
+
return new TextDecoder().decode(pathBuf.subarray(0, len)).replace(/\0.*/, '');
|
|
164
|
+
}
|
|
165
|
+
} catch {
|
|
166
|
+
// Ignore errors (process may have died, permission denied, etc.)
|
|
167
|
+
}
|
|
168
|
+
return null;
|
|
169
|
+
};
|
|
133
170
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
171
|
+
// Get parent PID using sysctl KERN_PROC_PID
|
|
172
|
+
// CTL_KERN = 1, KERN_PROC = 14, KERN_PROC_PID = 1
|
|
173
|
+
const getParentPid: GetParentPid = (pid: number) => {
|
|
174
|
+
if (pid <= 1) return null;
|
|
175
|
+
try {
|
|
176
|
+
const mib = new Int32Array([1, 14, 1, pid]);
|
|
177
|
+
const sizePtr = new BigUint64Array([BigInt(KINFO_PROC_SIZE)]);
|
|
178
|
+
|
|
179
|
+
const result = lib.symbols.sysctl(ptr(mib), 4, ptr(kinfoBuffer), ptr(sizePtr), null, 0);
|
|
180
|
+
if (result === 0) {
|
|
181
|
+
// e_ppid offset in kinfo_proc on macOS arm64/x86_64:
|
|
182
|
+
// kp_eproc starts at 296, e_ppid is at offset 264 within kp_eproc
|
|
183
|
+
// Total offset: 560
|
|
184
|
+
const view = new DataView(kinfoBuffer.buffer);
|
|
185
|
+
const ppid = view.getInt32(560, true); // little-endian
|
|
186
|
+
return ppid > 1 ? ppid : null;
|
|
137
187
|
}
|
|
188
|
+
} catch {
|
|
189
|
+
// Ignore errors
|
|
190
|
+
}
|
|
191
|
+
return null;
|
|
192
|
+
};
|
|
138
193
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
194
|
+
// Get command line using sysctl KERN_PROCARGS2
|
|
195
|
+
// CTL_KERN = 1, KERN_PROCARGS2 = 49
|
|
196
|
+
const getProcessCmdline: GetProcessCmdline = (pid: number) => {
|
|
197
|
+
if (pid <= 0) return null;
|
|
198
|
+
try {
|
|
199
|
+
// MIB for KERN_PROCARGS2: [CTL_KERN, KERN_PROCARGS2, pid]
|
|
200
|
+
const mib = new Int32Array([1, 49, pid]);
|
|
201
|
+
const sizePtr = new BigUint64Array([BigInt(ARG_MAX)]);
|
|
202
|
+
|
|
203
|
+
const result = lib.symbols.sysctl(ptr(mib), 3, ptr(argBuf), ptr(sizePtr), null, 0);
|
|
204
|
+
|
|
205
|
+
if (result === 0) {
|
|
206
|
+
const size = Number(sizePtr[0]);
|
|
207
|
+
if (size > 0) {
|
|
208
|
+
// KERN_PROCARGS2 format:
|
|
209
|
+
// - 4 bytes: argc (number of arguments)
|
|
210
|
+
// - exec_path\0
|
|
211
|
+
// - padding (zeros until aligned)
|
|
212
|
+
// - arg0\0arg1\0arg2\0...
|
|
213
|
+
// We want to extract exactly argc args (not env vars that follow)
|
|
214
|
+
const data = argBuf.subarray(0, size);
|
|
215
|
+
|
|
216
|
+
// Read argc (first 4 bytes, little-endian)
|
|
217
|
+
const argc = new DataView(data.buffer, data.byteOffset).getInt32(0, true);
|
|
218
|
+
let offset = 4;
|
|
219
|
+
|
|
220
|
+
// Skip exec_path (find first null)
|
|
221
|
+
while (offset < size && data[offset] !== 0) offset++;
|
|
222
|
+
offset++; // Skip the null
|
|
223
|
+
|
|
224
|
+
// Skip padding (multiple nulls)
|
|
225
|
+
while (offset < size && data[offset] === 0) offset++;
|
|
226
|
+
|
|
227
|
+
// Now we're at the arguments - collect exactly argc args
|
|
228
|
+
const args: string[] = [];
|
|
229
|
+
let start = offset;
|
|
230
|
+
for (let i = offset; i < size; i++) {
|
|
231
|
+
if (data[i] === 0) {
|
|
232
|
+
if (i > start) {
|
|
233
|
+
args.push(new TextDecoder().decode(data.subarray(start, i)));
|
|
234
|
+
}
|
|
235
|
+
start = i + 1;
|
|
236
|
+
// Stop after collecting argc args
|
|
237
|
+
if (args.length >= argc) break;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return args.join(' ');
|
|
242
|
+
}
|
|
143
243
|
}
|
|
244
|
+
} catch {
|
|
245
|
+
// Ignore errors
|
|
246
|
+
}
|
|
247
|
+
return null;
|
|
248
|
+
};
|
|
144
249
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
250
|
+
return { getProcessPath, getParentPid, getProcessCmdline };
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Initialize Linux FFI functions using libc.so.6
|
|
255
|
+
*/
|
|
256
|
+
function initLinuxFFI(): FFIFunctions {
|
|
257
|
+
const pathBuf = new Uint8Array(PATH_MAX);
|
|
258
|
+
|
|
259
|
+
const lib = dlopen('libc.so.6', {
|
|
260
|
+
readlink: {
|
|
261
|
+
args: [FFIType.cstring, FFIType.ptr, FFIType.u64],
|
|
262
|
+
returns: FFIType.i64,
|
|
263
|
+
},
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
const getProcessPath: GetProcessPath = (pid: number) => {
|
|
267
|
+
if (pid <= 0) return null;
|
|
268
|
+
try {
|
|
269
|
+
const procPath = Buffer.from(`/proc/${pid}/exe\0`);
|
|
270
|
+
const len = Number(lib.symbols.readlink(ptr(procPath), ptr(pathBuf), PATH_MAX));
|
|
271
|
+
if (len > 0) {
|
|
272
|
+
return new TextDecoder().decode(pathBuf.subarray(0, len));
|
|
149
273
|
}
|
|
274
|
+
} catch {
|
|
275
|
+
// Ignore errors (process may have died, permission denied, etc.)
|
|
276
|
+
}
|
|
277
|
+
return null;
|
|
278
|
+
};
|
|
150
279
|
|
|
151
|
-
|
|
152
|
-
|
|
280
|
+
const getParentPid: GetParentPid = (pid: number) => {
|
|
281
|
+
if (pid <= 1) return null;
|
|
282
|
+
try {
|
|
283
|
+
// Read /proc/{pid}/stat to get parent PID (4th field)
|
|
284
|
+
const statPath = `/proc/${pid}/stat`;
|
|
285
|
+
const content = readFileSync(statPath, 'utf-8');
|
|
286
|
+
// Format: pid (comm) state ppid ...
|
|
287
|
+
// Need to handle comm with spaces/parens: find last ')' then parse
|
|
288
|
+
const lastParen = content.lastIndexOf(')');
|
|
289
|
+
if (lastParen === -1) return null;
|
|
290
|
+
const rest = content.slice(lastParen + 2); // Skip ') '
|
|
291
|
+
const fields = rest.split(' ');
|
|
292
|
+
const ppidField = fields[1]; // ppid is 2nd field after state
|
|
293
|
+
if (!ppidField) return null;
|
|
294
|
+
const ppid = parseInt(ppidField, 10);
|
|
295
|
+
return isNaN(ppid) || ppid <= 1 ? null : ppid;
|
|
296
|
+
} catch {
|
|
297
|
+
// Ignore errors
|
|
153
298
|
}
|
|
299
|
+
return null;
|
|
300
|
+
};
|
|
154
301
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
302
|
+
// Read command line from /proc/{pid}/cmdline (null-separated args)
|
|
303
|
+
const getProcessCmdline: GetProcessCmdline = (pid: number) => {
|
|
304
|
+
if (pid <= 0) return null;
|
|
305
|
+
try {
|
|
306
|
+
const cmdlinePath = `/proc/${pid}/cmdline`;
|
|
307
|
+
const content = readFileSync(cmdlinePath);
|
|
308
|
+
if (content.length > 0) {
|
|
309
|
+
// Replace null bytes with spaces to get full command line
|
|
310
|
+
return new TextDecoder().decode(content).replace(/\0/g, ' ').trim();
|
|
311
|
+
}
|
|
312
|
+
} catch {
|
|
313
|
+
// Ignore errors
|
|
159
314
|
}
|
|
315
|
+
return null;
|
|
316
|
+
};
|
|
160
317
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
318
|
+
return { getProcessPath, getParentPid, getProcessCmdline };
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Initialize FFI functions lazily
|
|
322
|
+
let ffi: FFIFunctions | null = null;
|
|
323
|
+
|
|
324
|
+
function getFFI(): FFIFunctions {
|
|
325
|
+
if (!ffi) {
|
|
326
|
+
ffi = initFFI();
|
|
327
|
+
}
|
|
328
|
+
return ffi;
|
|
165
329
|
}
|
|
166
330
|
|
|
331
|
+
// ============================================================================
|
|
332
|
+
// Agent Detection Logic
|
|
333
|
+
// ============================================================================
|
|
334
|
+
|
|
167
335
|
/**
|
|
168
|
-
*
|
|
169
|
-
* Call this early in CLI startup to begin detection in the background.
|
|
336
|
+
* Cached detection result (null = not yet run, undefined = no agent detected)
|
|
170
337
|
*/
|
|
171
|
-
|
|
172
|
-
if (detectionPromise !== null) {
|
|
173
|
-
// Already started
|
|
174
|
-
return;
|
|
175
|
-
}
|
|
338
|
+
let cachedResult: string | undefined | null = null;
|
|
176
339
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
340
|
+
/**
|
|
341
|
+
* Check if a path's basename matches any known agent
|
|
342
|
+
*/
|
|
343
|
+
function matchAgentPath(path: string): string | undefined {
|
|
344
|
+
// Extract basename from path
|
|
345
|
+
const basename = path.split('/').pop()?.toLowerCase() ?? '';
|
|
346
|
+
for (const [processName, agentName] of KNOWN_AGENTS) {
|
|
347
|
+
if (basename.includes(processName)) {
|
|
348
|
+
return agentName;
|
|
186
349
|
}
|
|
187
|
-
|
|
188
|
-
|
|
350
|
+
}
|
|
351
|
+
return undefined;
|
|
189
352
|
}
|
|
190
353
|
|
|
191
354
|
/**
|
|
192
|
-
*
|
|
193
|
-
*
|
|
194
|
-
*
|
|
195
|
-
*
|
|
196
|
-
* @example
|
|
197
|
-
* ```typescript
|
|
198
|
-
* onAgentDetected((agent) => {
|
|
199
|
-
* if (agent) {
|
|
200
|
-
* console.log(`Detected agent: ${agent}`);
|
|
201
|
-
* }
|
|
202
|
-
* });
|
|
203
|
-
* ```
|
|
355
|
+
* Check if a cmdline matches any known agent.
|
|
356
|
+
* Only checks argv[0] and arguments that look like executable paths,
|
|
357
|
+
* NOT environment variables or arbitrary path strings.
|
|
204
358
|
*/
|
|
205
|
-
|
|
206
|
-
//
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
359
|
+
function matchAgentCmdline(cmdline: string): string | undefined {
|
|
360
|
+
// Split cmdline into arguments (null-separated on macOS/Linux, but we get space-separated here)
|
|
361
|
+
// The cmdline format from our FFI is: "cmd arg1 arg2 ENV1=val1 ENV2=val2..."
|
|
362
|
+
// We only want to check the command and args that look like executables
|
|
363
|
+
const parts = cmdline.split(/\s+/);
|
|
364
|
+
|
|
365
|
+
for (const part of parts) {
|
|
366
|
+
// Skip environment variables (contain =)
|
|
367
|
+
if (part.includes('=')) {
|
|
368
|
+
continue;
|
|
212
369
|
}
|
|
213
|
-
return;
|
|
214
|
-
}
|
|
215
370
|
|
|
216
|
-
|
|
217
|
-
|
|
371
|
+
// Check if this looks like an executable path or command
|
|
372
|
+
// - Starts with / (absolute path)
|
|
373
|
+
// - Is a simple command name (no path separators, no special chars)
|
|
374
|
+
const isPath = part.startsWith('/');
|
|
375
|
+
const isSimpleCommand = !part.includes('/') && !part.includes('=') && part.length < 50;
|
|
376
|
+
|
|
377
|
+
if (isPath || isSimpleCommand) {
|
|
378
|
+
const basename = part.split('/').pop()?.toLowerCase() ?? '';
|
|
379
|
+
for (const [processName, agentName] of KNOWN_AGENTS) {
|
|
380
|
+
if (basename.includes(processName)) {
|
|
381
|
+
return agentName;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
return undefined;
|
|
218
387
|
}
|
|
219
388
|
|
|
220
389
|
/**
|
|
221
|
-
*
|
|
222
|
-
*
|
|
223
|
-
*
|
|
224
|
-
*
|
|
225
|
-
* Use this for synchronous access when you don't want to wait for detection.
|
|
390
|
+
* Check if stdin is connected to a TTY (interactive terminal).
|
|
391
|
+
* When humans type commands, stdin is usually a TTY.
|
|
392
|
+
* When agents run commands programmatically, stdin is usually piped/closed.
|
|
226
393
|
*/
|
|
227
|
-
|
|
228
|
-
return
|
|
394
|
+
function isInteractiveSession(): boolean {
|
|
395
|
+
return process.stdin.isTTY === true;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// Enable debug output with AGENTUITY_DEBUG_AGENT_DETECTION=1
|
|
399
|
+
const DEBUG = process.env.AGENTUITY_DEBUG_AGENT_DETECTION === '1';
|
|
400
|
+
|
|
401
|
+
function debugLog(...args: unknown[]): void {
|
|
402
|
+
if (DEBUG) {
|
|
403
|
+
console.error('[agent-detection]', ...args);
|
|
404
|
+
}
|
|
229
405
|
}
|
|
230
406
|
|
|
231
407
|
/**
|
|
232
|
-
*
|
|
233
|
-
*
|
|
408
|
+
* Synchronously detect the parent agent by walking up the process tree.
|
|
409
|
+
* Uses FFI for fast process path and command line resolution.
|
|
234
410
|
*
|
|
235
|
-
*
|
|
411
|
+
* Detection strategy:
|
|
412
|
+
* - If stdin is a TTY (interactive session), don't report as agent
|
|
413
|
+
* (human is typing commands, even if inside an agent's terminal)
|
|
414
|
+
* - If stdin is NOT a TTY, check the process tree for known agents
|
|
236
415
|
*/
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
416
|
+
function detectParentAgent(): string | undefined {
|
|
417
|
+
debugLog('Starting detection, PID:', process.pid, 'PPID:', process.ppid);
|
|
418
|
+
debugLog('stdin.isTTY:', process.stdin.isTTY);
|
|
419
|
+
|
|
420
|
+
// Dump relevant env vars for debugging agent detection
|
|
421
|
+
if (DEBUG) {
|
|
422
|
+
const relevantEnvVars = Object.entries(process.env)
|
|
423
|
+
.filter(
|
|
424
|
+
([key]) =>
|
|
425
|
+
key.startsWith('WARP') ||
|
|
426
|
+
key.startsWith('TERM') ||
|
|
427
|
+
key.startsWith('AGENTUITY') ||
|
|
428
|
+
key === 'SHELL' ||
|
|
429
|
+
key === 'LC_TERMINAL' ||
|
|
430
|
+
key === 'ITERM_SESSION_ID' ||
|
|
431
|
+
key === 'VSCODE_INJECTION' ||
|
|
432
|
+
key === 'CURSOR_TRACE_ID'
|
|
433
|
+
)
|
|
434
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
435
|
+
.join(', ');
|
|
436
|
+
debugLog('Relevant env vars:', relevantEnvVars || '(none)');
|
|
437
|
+
debugLog('WARP_AGENT_MODE:', process.env.WARP_AGENT_MODE ?? '(not set)');
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// Short-circuit: if AGENTUITY_AGENT_MODE is set, use it directly
|
|
441
|
+
// Use "false", "0", or "none" to explicitly disable detection
|
|
442
|
+
const agentMode = process.env.AGENTUITY_AGENT_MODE;
|
|
443
|
+
if (agentMode) {
|
|
444
|
+
if (agentMode === 'false' || agentMode === '0' || agentMode === 'none') {
|
|
445
|
+
debugLog('AGENTUITY_AGENT_MODE explicitly disabled:', agentMode);
|
|
446
|
+
return undefined;
|
|
447
|
+
}
|
|
448
|
+
debugLog('Using AGENTUITY_AGENT_MODE:', agentMode);
|
|
449
|
+
return agentMode;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// Warp terminal: detect via WARP_AGENT_MODE env var (set by Warp AI)
|
|
453
|
+
// Note: Warp doesn't currently set this, but will in the future
|
|
454
|
+
if (process.env.WARP_AGENT_MODE === 'true') {
|
|
455
|
+
debugLog('Detected Warp AI via WARP_AGENT_MODE=true');
|
|
456
|
+
return 'warp';
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// If this is an interactive session (TTY), assume human is running the command
|
|
460
|
+
// Note: Warp AI also runs with TTY=true, so Warp users should set
|
|
461
|
+
// AGENTUITY_AGENT_MODE=warp until Warp sets WARP_AGENT_MODE=true
|
|
462
|
+
if (isInteractiveSession()) {
|
|
463
|
+
debugLog('Interactive session (TTY), skipping detection');
|
|
464
|
+
return undefined;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// Unsupported on Windows (for now)
|
|
468
|
+
if (process.platform === 'win32') {
|
|
469
|
+
debugLog('Windows not supported');
|
|
470
|
+
return undefined;
|
|
240
471
|
}
|
|
472
|
+
|
|
473
|
+
const { getProcessPath, getParentPid, getProcessCmdline } = getFFI();
|
|
474
|
+
|
|
475
|
+
// Guard for no parent process (e.g., PID 1 in containers)
|
|
476
|
+
const ppid = process.ppid;
|
|
477
|
+
if (!ppid || ppid <= 1) {
|
|
478
|
+
debugLog('No parent process (ppid:', ppid, ')');
|
|
479
|
+
return undefined;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// Walk up the process tree looking for known agents
|
|
483
|
+
const maxDepth = 10;
|
|
484
|
+
let currentPid = ppid;
|
|
485
|
+
|
|
486
|
+
for (let depth = 0; depth < maxDepth && currentPid > 1; depth++) {
|
|
487
|
+
// Check the executable path for agent match
|
|
488
|
+
const path = getProcessPath(currentPid);
|
|
489
|
+
debugLog(`[${depth}] PID ${currentPid} path:`, path);
|
|
490
|
+
|
|
491
|
+
if (path) {
|
|
492
|
+
const agent = matchAgentPath(path);
|
|
493
|
+
if (agent) {
|
|
494
|
+
debugLog(`[${depth}] Matched agent from path:`, agent);
|
|
495
|
+
return agent;
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
// Check the command line (for agents running as node/bun scripts)
|
|
500
|
+
const cmdline = getProcessCmdline(currentPid);
|
|
501
|
+
debugLog(
|
|
502
|
+
`[${depth}] PID ${currentPid} cmdline:`,
|
|
503
|
+
cmdline?.substring(0, 200) + (cmdline && cmdline.length > 200 ? '...' : '')
|
|
504
|
+
);
|
|
505
|
+
|
|
506
|
+
if (cmdline) {
|
|
507
|
+
const agent = matchAgentCmdline(cmdline);
|
|
508
|
+
if (agent) {
|
|
509
|
+
debugLog(`[${depth}] Matched agent from cmdline:`, agent);
|
|
510
|
+
return agent;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
// Move up
|
|
515
|
+
const parentPid = getParentPid(currentPid);
|
|
516
|
+
debugLog(`[${depth}] Parent of ${currentPid}:`, parentPid);
|
|
517
|
+
if (!parentPid) break;
|
|
518
|
+
currentPid = parentPid;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
debugLog('No agent found');
|
|
522
|
+
return undefined;
|
|
241
523
|
}
|
|
242
524
|
|
|
243
525
|
/**
|
|
244
|
-
*
|
|
245
|
-
* Returns the agent
|
|
526
|
+
* Get the executing agent if the CLI is being run from a known coding agent.
|
|
527
|
+
* Returns the agent ID if detected, undefined otherwise.
|
|
246
528
|
*
|
|
247
|
-
* This function
|
|
248
|
-
*
|
|
529
|
+
* This function runs synchronously using FFI for fast process path resolution.
|
|
530
|
+
* Results are cached after the first call.
|
|
249
531
|
*
|
|
250
532
|
* @example
|
|
251
533
|
* ```typescript
|
|
252
|
-
* const agent =
|
|
534
|
+
* const agent = getExecutingAgent();
|
|
253
535
|
* if (agent) {
|
|
254
536
|
* logger.debug(`Running from agent: ${agent}`);
|
|
255
537
|
* }
|
|
256
538
|
* ```
|
|
257
539
|
*/
|
|
258
|
-
export
|
|
259
|
-
// Return cached result if
|
|
540
|
+
export function getExecutingAgent(): string | undefined {
|
|
541
|
+
// Return cached result if already detected
|
|
260
542
|
if (cachedResult !== null) {
|
|
261
|
-
return cachedResult;
|
|
543
|
+
return cachedResult ?? undefined;
|
|
262
544
|
}
|
|
263
545
|
|
|
264
|
-
//
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
546
|
+
// Run detection and cache
|
|
547
|
+
cachedResult = detectParentAgent();
|
|
548
|
+
return cachedResult;
|
|
549
|
+
}
|
|
268
550
|
|
|
269
|
-
|
|
270
|
-
|
|
551
|
+
/**
|
|
552
|
+
* Get environment variables to pass to subprocesses for agent detection.
|
|
553
|
+
* This allows child processes to skip re-detection by using the cached result.
|
|
554
|
+
*
|
|
555
|
+
* @example
|
|
556
|
+
* ```typescript
|
|
557
|
+
* const proc = Bun.spawn(['bun', 'run', 'dev'], {
|
|
558
|
+
* env: { ...process.env, ...getAgentEnv() },
|
|
559
|
+
* });
|
|
560
|
+
* ```
|
|
561
|
+
*/
|
|
562
|
+
export function getAgentEnv(): Record<string, string> {
|
|
563
|
+
const agent = getExecutingAgent();
|
|
564
|
+
if (agent) {
|
|
565
|
+
return { AGENTUITY_AGENT_MODE: agent };
|
|
566
|
+
}
|
|
567
|
+
return {};
|
|
271
568
|
}
|