This is an automated email from the ASF dual-hosted git repository.
hsluoyz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/casbin-gateway.git
The following commit(s) were added to refs/heads/master by this push:
new a56a30e fix(agent): see the agent npx runs from its cache
a56a30e is described below
commit a56a30ea70a0315555b3fa4c08276ba42f94352a
Author: Yang Luo <[email protected]>
AuthorDate: Sun Aug 23 21:21:11 2026 +0800
fix(agent): see the agent npx runs from its cache
---
agent/fingerprint_load_test.go | 2 +-
agent/fingerprints/dsh.json | 6 ++++++
agent/scan_unix.go | 3 +++
agent/scan_windows.go | 3 +++
agentprocess/process.go | 32 ++++++++++++++++++++++++++++++--
web/src/components/AgentIcon.tsx | 1 +
6 files changed, 44 insertions(+), 3 deletions(-)
diff --git a/agent/fingerprint_load_test.go b/agent/fingerprint_load_test.go
index 14fca08..aed8072 100644
--- a/agent/fingerprint_load_test.go
+++ b/agent/fingerprint_load_test.go
@@ -23,7 +23,7 @@ import (
func TestFingerprintsLoad(t *testing.T) {
want := []string{
"claude-code", "claude-desktop", "codex-cli", "codex",
"cursor-agent",
- "cursor", "openagent", "openclaw", "windsurf",
+ "cursor", "dsh", "openagent", "openclaw", "windsurf",
}
loaded, err := loadFingerprints(fingerprintFS)
diff --git a/agent/fingerprints/dsh.json b/agent/fingerprints/dsh.json
new file mode 100644
index 0000000..daf8fd4
--- /dev/null
+++ b/agent/fingerprints/dsh.json
@@ -0,0 +1,6 @@
+{
+ "id": "dsh",
+ "displayName": "DeepSeek Harness",
+ "execName": "dsh",
+ "npmPackage": "@deepseek-ai/dsh"
+}
diff --git a/agent/scan_unix.go b/agent/scan_unix.go
index ca8e58c..3e7e780 100644
--- a/agent/scan_unix.go
+++ b/agent/scan_unix.go
@@ -69,6 +69,9 @@ func userNpmPatterns(fingerprint *Fingerprint, home string)
[]string {
filepath.Join(home, ".asdf", "installs", "nodejs", "*", "lib",
"node_modules", pkg, "package.json"),
// pnpm groups its global packages under a store layout version.
filepath.Join(home, ".local", "share", "pnpm", "global", "*",
"node_modules", pkg, "package.json"),
+ // An agent whose documented command is "npx <package>" is never
+ // installed globally; the copy npx keeps in npm's cache is the
install.
+ filepath.Join(home, ".npm", "_npx", "*", "node_modules", pkg,
"package.json"),
}
for _, dir := range fingerprint.ExtraUnixNpmDirs {
patterns = append(patterns, filepath.Join(home,
filepath.FromSlash(dir), "node_modules", pkg, "package.json"))
diff --git a/agent/scan_windows.go b/agent/scan_windows.go
index ae30d36..14db6e0 100644
--- a/agent/scan_windows.go
+++ b/agent/scan_windows.go
@@ -324,6 +324,9 @@ func scanWindowsNpm(ctx context.Context, fingerprint
*Fingerprint, home homeDir)
filepath.Join(local, "Volta", "tools", "image", "packages",
pkg, "lib", "node_modules", pkg, "package.json"),
// pnpm groups its global packages under a store layout version.
filepath.Join(local, "pnpm", "global", "*", "node_modules",
pkg, "package.json"),
+ // An agent whose documented command is "npx <package>" is never
+ // installed globally; the copy npx keeps in npm's cache is the
install.
+ filepath.Join(local, "npm-cache", "_npx", "*", "node_modules",
pkg, "package.json"),
}
for _, dir := range fingerprint.ExtraWindowsNpmDirs {
patterns = append(patterns, filepath.Join(local,
filepath.FromSlash(dir), "node_modules", pkg, "package.json"))
diff --git a/agentprocess/process.go b/agentprocess/process.go
index ed68afc..e4c50a4 100644
--- a/agentprocess/process.go
+++ b/agentprocess/process.go
@@ -235,8 +235,36 @@ func containsPath(command, path string) bool {
return false
}
path = filepath.Clean(path)
+ if textContains(command, path) {
+ return true
+ }
+ // A shim reaches its target through its own directory, so the command
line
+ // spells the file with a relative hop the recorded installation has
not.
+ for _, argument := range commandArguments(command) {
+ if textContains(filepath.Clean(argument), path) {
+ return true
+ }
+ }
+ return false
+}
+
+func textContains(text, path string) bool {
if runtime.GOOS == "windows" {
- return strings.Contains(strings.ToLower(command),
strings.ToLower(path))
+ return strings.Contains(strings.ToLower(text),
strings.ToLower(path))
+ }
+ return strings.Contains(text, path)
+}
+
+// commandArguments splits a command line the way its quoting reads, so an
+// argument holding a path with spaces stays one string.
+func commandArguments(command string) []string {
+ var arguments []string
+ for i, part := range strings.Split(command, `"`) {
+ if i%2 == 1 {
+ arguments = append(arguments, part)
+ continue
+ }
+ arguments = append(arguments, strings.Fields(part)...)
}
- return strings.Contains(command, path)
+ return arguments
}
diff --git a/web/src/components/AgentIcon.tsx b/web/src/components/AgentIcon.tsx
index b810d5c..eb62fd7 100644
--- a/web/src/components/AgentIcon.tsx
+++ b/web/src/components/AgentIcon.tsx
@@ -26,6 +26,7 @@ const agentSites: Record<string, string> = {
"Cursor Agent": "cursor.com",
Windsurf: "windsurf.com",
OpenAgent: "openagentai.org",
+ "DeepSeek Harness": "deepseek.com",
};
const agentKey = (agent: unknown) =>
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]