optimus-tool-call-staging 0.2.4
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/LICENSE +21 -0
- package/README.md +194 -0
- package/dist/capture-prompt.d.ts +14 -0
- package/dist/capture-prompt.d.ts.map +1 -0
- package/dist/capture-prompt.js +173 -0
- package/dist/capture-prompt.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +165 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/endpoint-config.d.ts +2 -0
- package/dist/lib/endpoint-config.d.ts.map +1 -0
- package/dist/lib/endpoint-config.js +2 -0
- package/dist/lib/endpoint-config.js.map +1 -0
- package/dist/lib/hardware-uuid.d.ts +7 -0
- package/dist/lib/hardware-uuid.d.ts.map +1 -0
- package/dist/lib/hardware-uuid.js +52 -0
- package/dist/lib/hardware-uuid.js.map +1 -0
- package/dist/lib/machine-auth.d.ts +11 -0
- package/dist/lib/machine-auth.d.ts.map +1 -0
- package/dist/lib/machine-auth.js +46 -0
- package/dist/lib/machine-auth.js.map +1 -0
- package/dist/lib/startup-sync.d.ts +13 -0
- package/dist/lib/startup-sync.d.ts.map +1 -0
- package/dist/lib/startup-sync.js +147 -0
- package/dist/lib/startup-sync.js.map +1 -0
- package/dist/lib/streaming.d.ts +18 -0
- package/dist/lib/streaming.d.ts.map +1 -0
- package/dist/lib/streaming.js +243 -0
- package/dist/lib/streaming.js.map +1 -0
- package/dist/lib/telemetry/build-event.d.ts +10 -0
- package/dist/lib/telemetry/build-event.d.ts.map +1 -0
- package/dist/lib/telemetry/build-event.js +32 -0
- package/dist/lib/telemetry/build-event.js.map +1 -0
- package/dist/lib/telemetry/canonical.d.ts +26 -0
- package/dist/lib/telemetry/canonical.d.ts.map +1 -0
- package/dist/lib/telemetry/canonical.js +153 -0
- package/dist/lib/telemetry/canonical.js.map +1 -0
- package/dist/lib/telemetry/index.d.ts +9 -0
- package/dist/lib/telemetry/index.d.ts.map +1 -0
- package/dist/lib/telemetry/index.js +9 -0
- package/dist/lib/telemetry/index.js.map +1 -0
- package/dist/lib/telemetry/serialize.d.ts +3 -0
- package/dist/lib/telemetry/serialize.d.ts.map +1 -0
- package/dist/lib/telemetry/serialize.js +15 -0
- package/dist/lib/telemetry/serialize.js.map +1 -0
- package/dist/lib/telemetry/types.d.ts +34 -0
- package/dist/lib/telemetry/types.d.ts.map +1 -0
- package/dist/lib/telemetry/types.js +14 -0
- package/dist/lib/telemetry/types.js.map +1 -0
- package/dist/lib/telemetry/wire-metadata.d.ts +10 -0
- package/dist/lib/telemetry/wire-metadata.d.ts.map +1 -0
- package/dist/lib/telemetry/wire-metadata.js +28 -0
- package/dist/lib/telemetry/wire-metadata.js.map +1 -0
- package/dist/lib/telemetry.d.ts +2 -0
- package/dist/lib/telemetry.d.ts.map +1 -0
- package/dist/lib/telemetry.js +2 -0
- package/dist/lib/telemetry.js.map +1 -0
- package/dist/lib/user-profile.d.ts +16 -0
- package/dist/lib/user-profile.d.ts.map +1 -0
- package/dist/lib/user-profile.js +175 -0
- package/dist/lib/user-profile.js.map +1 -0
- package/dist/test/canonical.test.d.ts +2 -0
- package/dist/test/canonical.test.d.ts.map +1 -0
- package/dist/test/canonical.test.js +117 -0
- package/dist/test/canonical.test.js.map +1 -0
- package/dist/test/endpoint-config.test.d.ts +2 -0
- package/dist/test/endpoint-config.test.d.ts.map +1 -0
- package/dist/test/endpoint-config.test.js +43 -0
- package/dist/test/endpoint-config.test.js.map +1 -0
- package/dist/test/index.test.d.ts +2 -0
- package/dist/test/index.test.d.ts.map +1 -0
- package/dist/test/index.test.js +376 -0
- package/dist/test/index.test.js.map +1 -0
- package/dist/test/integration-canonical.test.d.ts +2 -0
- package/dist/test/integration-canonical.test.d.ts.map +1 -0
- package/dist/test/integration-canonical.test.js +157 -0
- package/dist/test/integration-canonical.test.js.map +1 -0
- package/dist/test/streaming.test.d.ts +2 -0
- package/dist/test/streaming.test.d.ts.map +1 -0
- package/dist/test/streaming.test.js +223 -0
- package/dist/test/streaming.test.js.map +1 -0
- package/dist/test/telemetry.test.d.ts +2 -0
- package/dist/test/telemetry.test.d.ts.map +1 -0
- package/dist/test/telemetry.test.js +201 -0
- package/dist/test/telemetry.test.js.map +1 -0
- package/package.json +50 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Optimus Labs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# optimus-tool-call
|
|
2
|
+
|
|
3
|
+
Passive, non-blocking audit sensor for tool calls from coding agents (Claude Code, Cursor, GitHub Copilot, etc.).
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **50+ command classifiers** - Full nah taxonomy coverage
|
|
8
|
+
- **40+ action types** - Comprehensive security categorization
|
|
9
|
+
- **Real-time telemetry** - Async event streaming to backend
|
|
10
|
+
- **Zero developer friction** - <50ms p99 latency, never blocks execution
|
|
11
|
+
- **Smart parsing** - Handles pipes, redirects, command chains, shell builtins
|
|
12
|
+
- **Flag-based detection** - Context-aware classification (sed -i, curl -X POST, make --dry-run, etc.)
|
|
13
|
+
|
|
14
|
+
## How It Works
|
|
15
|
+
|
|
16
|
+
1. **Hook Integration**: Integrates with Claude Code PreToolUse hooks
|
|
17
|
+
2. **Command Classification**: Parses and classifies each tool call into an action type
|
|
18
|
+
3. **Telemetry Event**: Creates event with classified action, file paths, session info
|
|
19
|
+
4. **Async Streaming**: Non-blocking queue sends events to backend in batches
|
|
20
|
+
5. **Backend Severity**: Django backend assigns severity (critical/high/medium/low/info)
|
|
21
|
+
6. **Frontend Dashboard**: Real-time audit log with 2-second polling
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install @optimus/tool-call
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Usage
|
|
30
|
+
|
|
31
|
+
Via PreToolUse hook (automatic in Claude Code):
|
|
32
|
+
|
|
33
|
+
```json
|
|
34
|
+
{
|
|
35
|
+
"preToolUse": {
|
|
36
|
+
"matcher": "*",
|
|
37
|
+
"command": "node path/to/optimus-tool-call/dist/index.js"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The hook:
|
|
43
|
+
- Classifies the tool call
|
|
44
|
+
- Extracts relevant metadata (files, commands, patterns)
|
|
45
|
+
- Queues telemetry event
|
|
46
|
+
- Returns `{"continue": true, "permission": "allow"}` (never blocks)
|
|
47
|
+
|
|
48
|
+
## Command Coverage
|
|
49
|
+
|
|
50
|
+
See [COMMAND_COVERAGE.md](./COMMAND_COVERAGE.md) for complete list of 50+ supported commands and their classifications.
|
|
51
|
+
|
|
52
|
+
### Quick Examples
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
Filesystem:
|
|
56
|
+
read: cat, grep, ls, find, head, tail, which
|
|
57
|
+
write: echo, touch, mkdir, cp, mv, chmod
|
|
58
|
+
delete: rm
|
|
59
|
+
|
|
60
|
+
Git:
|
|
61
|
+
safe: log, status, diff, branch
|
|
62
|
+
write: add, commit, checkout, pull
|
|
63
|
+
history_rewrite: push --force, reset --hard, rebase
|
|
64
|
+
|
|
65
|
+
Network:
|
|
66
|
+
outbound: curl, wget, ssh
|
|
67
|
+
write: curl --data, scp, rsync
|
|
68
|
+
|
|
69
|
+
Language Execution:
|
|
70
|
+
python, node, ruby, bash, source, gdb
|
|
71
|
+
|
|
72
|
+
Text Processing:
|
|
73
|
+
sed -i → filesystem_write
|
|
74
|
+
awk with system() → lang_exec
|
|
75
|
+
|
|
76
|
+
And 30+ more...
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Action Types
|
|
80
|
+
|
|
81
|
+
| Type | Examples | Severity |
|
|
82
|
+
|------|----------|----------|
|
|
83
|
+
| `filesystem_read` | cat, grep, ls, find, head | low |
|
|
84
|
+
| `filesystem_write` | echo, touch, mkdir, cp, mv | medium |
|
|
85
|
+
| `filesystem_delete` | rm | medium |
|
|
86
|
+
| `git_safe` | git log, git status | low |
|
|
87
|
+
| `git_write` | git add, git commit | medium |
|
|
88
|
+
| `git_remote_write` | git push | medium |
|
|
89
|
+
| `git_discard` | git branch -d | medium |
|
|
90
|
+
| `git_history_rewrite` | git push --force, git rebase | critical |
|
|
91
|
+
| `network_outbound` | curl GET, wget | low |
|
|
92
|
+
| `network_write` | curl POST, scp, rsync | high |
|
|
93
|
+
| `network_diagnostic` | ping, traceroute | low |
|
|
94
|
+
| `package_install` | npm install, pip install | high |
|
|
95
|
+
| `package_run` | npm run | medium |
|
|
96
|
+
| `lang_exec` | python, node, bash, gdb | high |
|
|
97
|
+
| `process_signal` | kill, pkill | high |
|
|
98
|
+
| `container_read` | docker ps, docker logs | low |
|
|
99
|
+
| `container_write` | docker build, docker create | medium |
|
|
100
|
+
| `container_exec` | docker run, docker exec | medium |
|
|
101
|
+
| `container_destructive` | docker rm, docker stop | high |
|
|
102
|
+
| `service_write` | systemctl start, service restart | high |
|
|
103
|
+
| `agent_exec_bypass` | (reserved for future) | critical |
|
|
104
|
+
| `obfuscated` | (reserved for future) | critical |
|
|
105
|
+
|
|
106
|
+
## Configuration
|
|
107
|
+
|
|
108
|
+
Environment variables (optional):
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
OPTIMUS_API_URL=https://your-host/ # Backend base URL (same as log-llm-config; see optimus-tofu)
|
|
112
|
+
OPTIMUS_ENDPOINT=... # Alternative to OPTIMUS_API_URL
|
|
113
|
+
OPTIMUS_HARDWARE_UUID=... # Override when no stable hardware UUID (e.g. Linux CI)
|
|
114
|
+
OPTIMUS_BATCH_SIZE=50 # Batch size before flush (default: 1 for testing, 50 for prod)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Ingestion uses the same machine auth as `log-llm-config`: keys under `~/opt-ai-sec/management/auth_key.txt`, handshake against `/endpoint_security/auth/`, and HMAC signatures on each batch (see backend `batch_create`).
|
|
118
|
+
|
|
119
|
+
## Architecture
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
┌─────────────────────────────────────────────┐
|
|
123
|
+
│ Coding Agent (Claude Code, Cursor, etc.) │
|
|
124
|
+
└────────────────────┬────────────────────────┘
|
|
125
|
+
│ PreToolUse hook
|
|
126
|
+
▼
|
|
127
|
+
┌─────────────────────────────────────────────┐
|
|
128
|
+
│ optimus-tool-call (TypeScript) │
|
|
129
|
+
│ ├─ Classify command into action type │
|
|
130
|
+
│ ├─ Extract file paths, patterns, etc. │
|
|
131
|
+
│ ├─ Create telemetry event │
|
|
132
|
+
│ └─ Queue for async streaming │
|
|
133
|
+
└────────────────────┬────────────────────────┘
|
|
134
|
+
│ Non-blocking async
|
|
135
|
+
▼
|
|
136
|
+
┌─────────────────────────────────────────────┐
|
|
137
|
+
│ Django Backend (optimus_security) │
|
|
138
|
+
│ ├─ Receive batched events │
|
|
139
|
+
│ ├─ Calculate severity │
|
|
140
|
+
│ ├─ Store in SQLite │
|
|
141
|
+
│ └─ Expose via REST API │
|
|
142
|
+
└────────────────────┬────────────────────────┘
|
|
143
|
+
│ /api/tool-calls/events/recent/
|
|
144
|
+
▼
|
|
145
|
+
┌─────────────────────────────────────────────┐
|
|
146
|
+
│ Frontend Dashboard (React) │
|
|
147
|
+
│ ├─ Real-time audit log (2s polling) │
|
|
148
|
+
│ ├─ Color-coded severity/agent │
|
|
149
|
+
│ └─ Expandable command details │
|
|
150
|
+
└─────────────────────────────────────────────┘
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Development
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
npm install
|
|
157
|
+
npm run build
|
|
158
|
+
npm run test
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Testing
|
|
162
|
+
|
|
163
|
+
E2E test with various commands:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
./test-e2e.sh
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
This will:
|
|
170
|
+
1. Clear the audit log
|
|
171
|
+
2. Run 50+ diverse commands (filesystem, git, network, package, etc.)
|
|
172
|
+
3. Verify correct classification for each
|
|
173
|
+
4. Display coverage summary
|
|
174
|
+
|
|
175
|
+
## Performance
|
|
176
|
+
|
|
177
|
+
- **Classification latency**: <1ms per command
|
|
178
|
+
- **Telemetry overhead**: <50ms p99 (async, non-blocking)
|
|
179
|
+
- **Memory**: ~10MB resident (minimal buffering)
|
|
180
|
+
- **CPU**: Negligible (event-driven)
|
|
181
|
+
|
|
182
|
+
## Safety
|
|
183
|
+
|
|
184
|
+
- ✅ Never blocks agent execution
|
|
185
|
+
- ✅ Always returns `permission: "allow"`
|
|
186
|
+
- ✅ Errors logged but never thrown
|
|
187
|
+
- ✅ Graceful degradation if backend unavailable
|
|
188
|
+
- ✅ Batch timeout ensures events flush (5s default)
|
|
189
|
+
|
|
190
|
+
## References
|
|
191
|
+
|
|
192
|
+
- Based on nah taxonomy: https://github.com/manuelschipper/nah
|
|
193
|
+
- Integrated with Optimus Labs security platform
|
|
194
|
+
- Part of agent compliance and audit infrastructure
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* optimus-capture-prompt — Cursor hook to capture and store prompt text
|
|
4
|
+
*
|
|
5
|
+
* Runs on beforeSubmitPrompt hook. Reads the prompt from stdin (if available),
|
|
6
|
+
* stores it in a temp file keyed by session ID, so that the tool-call hook
|
|
7
|
+
* can retrieve it when processing tool invocations.
|
|
8
|
+
*
|
|
9
|
+
* Cursor hook protocol for beforeSubmitPrompt:
|
|
10
|
+
* - stdin: JSON with prompt text (format varies by Cursor version)
|
|
11
|
+
* - stdout: {"continue": true|false} JSON
|
|
12
|
+
*/
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=capture-prompt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capture-prompt.d.ts","sourceRoot":"","sources":["../src/capture-prompt.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;GAUG"}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* optimus-capture-prompt — Cursor hook to capture and store prompt text
|
|
4
|
+
*
|
|
5
|
+
* Runs on beforeSubmitPrompt hook. Reads the prompt from stdin (if available),
|
|
6
|
+
* stores it in a temp file keyed by session ID, so that the tool-call hook
|
|
7
|
+
* can retrieve it when processing tool invocations.
|
|
8
|
+
*
|
|
9
|
+
* Cursor hook protocol for beforeSubmitPrompt:
|
|
10
|
+
* - stdin: JSON with prompt text (format varies by Cursor version)
|
|
11
|
+
* - stdout: {"continue": true|false} JSON
|
|
12
|
+
*/
|
|
13
|
+
import fs from "fs";
|
|
14
|
+
import os from "os";
|
|
15
|
+
import path from "path";
|
|
16
|
+
const dbg = (...args) => { if (process.env.OPTIMUS_DEBUG)
|
|
17
|
+
console.error(...args); };
|
|
18
|
+
async function main() {
|
|
19
|
+
const stdinData = await readStdin();
|
|
20
|
+
dbg("[optimus-capture-prompt] ===== HOOK STARTED =====");
|
|
21
|
+
dbg("[optimus-capture-prompt] stdin length:", stdinData.length);
|
|
22
|
+
dbg("[optimus-capture-prompt] stdin preview:", stdinData.slice(0, 200));
|
|
23
|
+
let promptText = null;
|
|
24
|
+
let payloadSessionId = null;
|
|
25
|
+
try {
|
|
26
|
+
const raw = JSON.parse(stdinData);
|
|
27
|
+
dbg("[optimus-capture-prompt] Parsed JSON successfully");
|
|
28
|
+
dbg("[optimus-capture-prompt] Raw keys:", Object.keys(raw));
|
|
29
|
+
dbg("[optimus-capture-prompt] Raw payload:", JSON.stringify(raw, null, 2).slice(0, 500));
|
|
30
|
+
// Extract session ID for Cursor (from conversation_id or session_id in payload)
|
|
31
|
+
payloadSessionId =
|
|
32
|
+
(typeof raw.conversation_id === "string" && raw.conversation_id) ||
|
|
33
|
+
(typeof raw.session_id === "string" && raw.session_id) ||
|
|
34
|
+
null;
|
|
35
|
+
// Extract prompt from various possible locations in the hook payload
|
|
36
|
+
promptText =
|
|
37
|
+
extractValue(raw, ["prompt"]) ||
|
|
38
|
+
extractValue(raw, ["text"]) ||
|
|
39
|
+
extractValue(raw, ["message"]) ||
|
|
40
|
+
extractValue(raw, ["input"]) ||
|
|
41
|
+
null;
|
|
42
|
+
// Try to extract from nested message structure
|
|
43
|
+
if (!promptText) {
|
|
44
|
+
const msg = raw.message;
|
|
45
|
+
if (msg && typeof msg === "object") {
|
|
46
|
+
promptText =
|
|
47
|
+
extractValue(msg, ["content"]) ||
|
|
48
|
+
extractValue(msg, ["text"]) ||
|
|
49
|
+
extractValue(msg, ["prompt"]) ||
|
|
50
|
+
null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
dbg("[optimus-capture-prompt] Extracted prompt text:", promptText ? `"${promptText.slice(0, 100)}..."` : "null");
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
// Not valid JSON — might not have prompt in this hook payload
|
|
57
|
+
console.error("[optimus-capture-prompt] Failed to parse JSON:", error);
|
|
58
|
+
}
|
|
59
|
+
// If we have a prompt, store it in a temp file keyed by session ID
|
|
60
|
+
if (promptText) {
|
|
61
|
+
dbg("[optimus-capture-prompt] Storing prompt...");
|
|
62
|
+
try {
|
|
63
|
+
const sessionId = payloadSessionId ||
|
|
64
|
+
process.env.CURSOR_SESSION_ID ||
|
|
65
|
+
process.env.CURSOR_CODE_SESSION_ID ||
|
|
66
|
+
process.env.CLAUDE_CODE_SESSION_ID ||
|
|
67
|
+
"unknown";
|
|
68
|
+
const promptCacheDir = path.join(os.tmpdir(), "optimus-prompt-cache");
|
|
69
|
+
dbg("[optimus-capture-prompt] Session ID:", sessionId);
|
|
70
|
+
dbg("[optimus-capture-prompt] Cache dir:", promptCacheDir);
|
|
71
|
+
// Create cache directory if it doesn't exist
|
|
72
|
+
if (!fs.existsSync(promptCacheDir)) {
|
|
73
|
+
dbg("[optimus-capture-prompt] Creating cache directory...");
|
|
74
|
+
fs.mkdirSync(promptCacheDir, { recursive: true });
|
|
75
|
+
}
|
|
76
|
+
// Write prompt to temp file (with short TTL via filename timestamp)
|
|
77
|
+
const timestamp = Date.now();
|
|
78
|
+
const promptFile = path.join(promptCacheDir, `prompt-${sessionId}-${timestamp}.txt`);
|
|
79
|
+
fs.writeFileSync(promptFile, promptText, "utf-8");
|
|
80
|
+
dbg(`[optimus-capture-prompt] Wrote prompt file: ${promptFile}`);
|
|
81
|
+
// Also write a "latest" symlink for easy access
|
|
82
|
+
const latestFile = path.join(promptCacheDir, `prompt-${sessionId}.txt`);
|
|
83
|
+
try {
|
|
84
|
+
fs.unlinkSync(latestFile);
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
// File might not exist
|
|
88
|
+
}
|
|
89
|
+
try {
|
|
90
|
+
fs.symlinkSync(promptFile, latestFile);
|
|
91
|
+
dbg(`[optimus-capture-prompt] Created symlink: ${latestFile}`);
|
|
92
|
+
}
|
|
93
|
+
catch (e) {
|
|
94
|
+
dbg(`[optimus-capture-prompt] Symlink creation failed (non-fatal):`, e);
|
|
95
|
+
}
|
|
96
|
+
dbg(`[optimus-capture-prompt] SUCCESS: Stored prompt at ${promptFile}`);
|
|
97
|
+
// Clean up old prompt files (older than 5 minutes)
|
|
98
|
+
cleanupOldPromptFiles(promptCacheDir, sessionId);
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
// Non-fatal — if we can't cache the prompt, the tool-call hook just won't have it
|
|
102
|
+
console.error("[optimus-capture-prompt] ERROR: Failed to store prompt:", error);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
dbg("[optimus-capture-prompt] No prompt text found in hook payload");
|
|
107
|
+
}
|
|
108
|
+
// Always allow — never block on prompt capture
|
|
109
|
+
const response = { continue: true };
|
|
110
|
+
dbg("[optimus-capture-prompt] Returning response:", JSON.stringify(response));
|
|
111
|
+
console.log(JSON.stringify(response));
|
|
112
|
+
}
|
|
113
|
+
async function readStdin() {
|
|
114
|
+
return new Promise((resolve) => {
|
|
115
|
+
let data = "";
|
|
116
|
+
process.stdin.setEncoding("utf8");
|
|
117
|
+
process.stdin.on("readable", () => {
|
|
118
|
+
let chunk;
|
|
119
|
+
while ((chunk = process.stdin.read()) !== null) {
|
|
120
|
+
data += chunk;
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
process.stdin.on("end", () => {
|
|
124
|
+
resolve(data);
|
|
125
|
+
});
|
|
126
|
+
process.stdin.on("error", () => {
|
|
127
|
+
resolve("");
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
function extractValue(obj, keys) {
|
|
132
|
+
for (const key of keys) {
|
|
133
|
+
const value = obj[key];
|
|
134
|
+
if (value !== undefined && value !== null && typeof value === "string") {
|
|
135
|
+
return value;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
function cleanupOldPromptFiles(dir, sessionId) {
|
|
141
|
+
try {
|
|
142
|
+
const files = fs.readdirSync(dir);
|
|
143
|
+
const now = Date.now();
|
|
144
|
+
const maxAge = 5 * 60 * 1000; // 5 minutes
|
|
145
|
+
for (const file of files) {
|
|
146
|
+
// Only clean up files for this session
|
|
147
|
+
if (!file.startsWith(`prompt-${sessionId}-`))
|
|
148
|
+
continue;
|
|
149
|
+
const filePath = path.join(dir, file);
|
|
150
|
+
try {
|
|
151
|
+
const stat = fs.statSync(filePath);
|
|
152
|
+
if (now - stat.mtimeMs > maxAge) {
|
|
153
|
+
fs.unlinkSync(filePath);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
// Ignore errors during cleanup
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
// Ignore errors during cleanup
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
main().catch((err) => {
|
|
166
|
+
if (process.env.OPTIMUS_DEBUG) {
|
|
167
|
+
console.error("[optimus-capture-prompt] Fatal error:", err);
|
|
168
|
+
}
|
|
169
|
+
const response = { continue: true };
|
|
170
|
+
console.log(JSON.stringify(response));
|
|
171
|
+
process.exit(0);
|
|
172
|
+
});
|
|
173
|
+
//# sourceMappingURL=capture-prompt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capture-prompt.js","sourceRoot":"","sources":["../src/capture-prompt.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* optimus-tool-call — agentic audit sensor entry point
|
|
4
|
+
*
|
|
5
|
+
* Reads hook JSON from stdin, builds a raw telemetry event, streams it to the
|
|
6
|
+
* backend (server classifies), returns allow response.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;GAKG"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* optimus-tool-call — agentic audit sensor entry point
|
|
4
|
+
*
|
|
5
|
+
* Reads hook JSON from stdin, builds a raw telemetry event, streams it to the
|
|
6
|
+
* backend (server classifies), returns allow response.
|
|
7
|
+
*/
|
|
8
|
+
import fs from "fs";
|
|
9
|
+
import { buildTelemetryEvent, eventToDict } from "./lib/telemetry.js";
|
|
10
|
+
import { queueEvent, ensureShutdown } from "./lib/streaming.js";
|
|
11
|
+
import { normalizeToCanonical } from "./lib/telemetry/canonical.js";
|
|
12
|
+
const dbg = (...args) => { if (process.env.OPTIMUS_DEBUG)
|
|
13
|
+
console.error(...args); };
|
|
14
|
+
async function main() {
|
|
15
|
+
dbg("[optimus-tool-call] ===== HOOK STARTED =====");
|
|
16
|
+
dbg("[optimus-tool-call] NODE_ENV:", process.env.NODE_ENV);
|
|
17
|
+
dbg("[optimus-tool-call] CURSOR:", process.env.CURSOR);
|
|
18
|
+
dbg("[optimus-tool-call] CURSOR_SESSION_ID:", process.env.CURSOR_SESSION_ID);
|
|
19
|
+
dbg("[optimus-tool-call] CLAUDE_CODE_SESSION_ID:", process.env.CLAUDE_CODE_SESSION_ID);
|
|
20
|
+
// Setup shutdown handling
|
|
21
|
+
ensureShutdown();
|
|
22
|
+
// Read stdin
|
|
23
|
+
const stdinData = await readStdin();
|
|
24
|
+
dbg("[optimus-tool-call] stdin length:", stdinData.length);
|
|
25
|
+
dbg("[optimus-tool-call] stdin preview:", stdinData.slice(0, 300));
|
|
26
|
+
// Parse and normalize to canonical format
|
|
27
|
+
let canonical;
|
|
28
|
+
try {
|
|
29
|
+
const raw = JSON.parse(stdinData);
|
|
30
|
+
dbg("[optimus-tool-call] Parsed JSON successfully");
|
|
31
|
+
dbg("[optimus-tool-call] Raw keys:", Object.keys(raw));
|
|
32
|
+
// Normalize to canonical format (works for both Claude and Cursor)
|
|
33
|
+
canonical = normalizeToCanonical(raw);
|
|
34
|
+
dbg("[optimus-tool-call] Detected agent:", canonical.agent);
|
|
35
|
+
dbg("[optimus-tool-call] Hook event name:", canonical.hook_event_name);
|
|
36
|
+
dbg("[optimus-tool-call] Tool name:", canonical.tool_name);
|
|
37
|
+
// Try to extract user prompt from transcript file (works for both Claude and Cursor)
|
|
38
|
+
if (!canonical.user_prompt) {
|
|
39
|
+
const transcriptPath = typeof raw.transcript_path === "string" ? raw.transcript_path : null;
|
|
40
|
+
if (transcriptPath) {
|
|
41
|
+
const userPrompt = readLastUserPrompt(transcriptPath);
|
|
42
|
+
if (userPrompt) {
|
|
43
|
+
canonical = { ...canonical, user_prompt: userPrompt };
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
dbg("[optimus-tool-call] Canonical event:", {
|
|
48
|
+
agent: canonical.agent,
|
|
49
|
+
hook_event_name: canonical.hook_event_name,
|
|
50
|
+
tool_name: canonical.tool_name,
|
|
51
|
+
user_prompt_preview: canonical.user_prompt?.slice(0, 100),
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
// Invalid JSON or parse error — allow and return
|
|
56
|
+
console.error("[optimus-tool-call] ERROR: Failed to parse:", error);
|
|
57
|
+
const response = { continue: true, permission: "allow" };
|
|
58
|
+
console.log(JSON.stringify(response));
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
// Convert canonical to ToolInvocation (for backward compatibility with existing code)
|
|
62
|
+
const invocation = {
|
|
63
|
+
tool_name: canonical.tool_name,
|
|
64
|
+
tool_input: canonical.tool_input,
|
|
65
|
+
tool_use_id: canonical.tool_use_id,
|
|
66
|
+
session_id: canonical.session_id,
|
|
67
|
+
cwd: canonical.cwd,
|
|
68
|
+
hook_event_name: canonical.hook_event_name,
|
|
69
|
+
model: canonical.model,
|
|
70
|
+
user_prompt: canonical.user_prompt,
|
|
71
|
+
raw_event: canonical.raw_event,
|
|
72
|
+
};
|
|
73
|
+
// Build telemetry event
|
|
74
|
+
const event = buildTelemetryEvent(invocation, canonical.agent, canonical.session_id);
|
|
75
|
+
if (event) {
|
|
76
|
+
// Server classifies `action_type`; queue raw invocation for all non-null events.
|
|
77
|
+
await queueEvent(event);
|
|
78
|
+
if (process.env.OPTIMUS_DEBUG) {
|
|
79
|
+
const eventDict = eventToDict(event);
|
|
80
|
+
console.error(`[optimus-tool-call] Queued event: ${JSON.stringify(eventDict)}`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// Always return allow (never block)
|
|
84
|
+
const response = { continue: true, permission: "allow" };
|
|
85
|
+
console.log(JSON.stringify(response));
|
|
86
|
+
}
|
|
87
|
+
async function readStdin() {
|
|
88
|
+
/**
|
|
89
|
+
* Read all of stdin until EOF.
|
|
90
|
+
*/
|
|
91
|
+
return new Promise((resolve, reject) => {
|
|
92
|
+
let data = "";
|
|
93
|
+
process.stdin.setEncoding("utf8");
|
|
94
|
+
process.stdin.on("readable", () => {
|
|
95
|
+
let chunk;
|
|
96
|
+
while ((chunk = process.stdin.read()) !== null) {
|
|
97
|
+
data += chunk;
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
process.stdin.on("end", () => {
|
|
101
|
+
resolve(data);
|
|
102
|
+
});
|
|
103
|
+
process.stdin.on("error", (err) => {
|
|
104
|
+
reject(err);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Read the Claude Code session transcript (JSONL) and return the text of the
|
|
110
|
+
* last user-typed message. Each line is a JSON object; user turns look like:
|
|
111
|
+
* {"type":"user","message":{"role":"user","content":"<text>"},...}
|
|
112
|
+
* Failures are non-fatal — returns null if the file is missing or unreadable.
|
|
113
|
+
*/
|
|
114
|
+
function readLastUserPrompt(transcriptPath) {
|
|
115
|
+
try {
|
|
116
|
+
const raw = fs.readFileSync(transcriptPath, "utf-8");
|
|
117
|
+
const lines = raw.split("\n");
|
|
118
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
119
|
+
const line = lines[i].trim();
|
|
120
|
+
if (!line)
|
|
121
|
+
continue;
|
|
122
|
+
try {
|
|
123
|
+
const entry = JSON.parse(line);
|
|
124
|
+
if (entry.type !== "user")
|
|
125
|
+
continue;
|
|
126
|
+
const msg = entry.message;
|
|
127
|
+
if (!msg || msg.role !== "user")
|
|
128
|
+
continue;
|
|
129
|
+
const content = msg.content;
|
|
130
|
+
if (typeof content === "string" && content.trim()) {
|
|
131
|
+
return content.trim();
|
|
132
|
+
}
|
|
133
|
+
if (Array.isArray(content)) {
|
|
134
|
+
const blocks = content;
|
|
135
|
+
// Skip tool_result turns — those are API feedback, not user-typed messages
|
|
136
|
+
if (blocks.some((c) => c.type === "tool_result"))
|
|
137
|
+
continue;
|
|
138
|
+
const text = blocks
|
|
139
|
+
.filter((c) => c.type === "text" && typeof c.text === "string")
|
|
140
|
+
.map((c) => c.text)
|
|
141
|
+
.join("\n")
|
|
142
|
+
.trim();
|
|
143
|
+
if (text)
|
|
144
|
+
return text;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
// skip malformed lines
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
// file missing or unreadable — non-fatal
|
|
154
|
+
}
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
// Run
|
|
158
|
+
main().catch((err) => {
|
|
159
|
+
console.error("[optimus-tool-call] Fatal error:", err);
|
|
160
|
+
// Always return allow on error
|
|
161
|
+
const response = { continue: true, permission: "allow" };
|
|
162
|
+
console.log(JSON.stringify(response));
|
|
163
|
+
process.exit(0); // Never exit non-zero (never block)
|
|
164
|
+
});
|
|
165
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"endpoint-config.d.ts","sourceRoot":"","sources":["../../src/lib/endpoint-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"endpoint-config.js","sourceRoot":"","sources":["../../src/lib/endpoint-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Run a static shell command and return trimmed stdout (same pattern as log-llm-config). */
|
|
2
|
+
export declare function readCommandOutput(command: string): string;
|
|
3
|
+
/** Resolve hardware UUID from environment or macOS system commands (same strategy as log-llm-config). */
|
|
4
|
+
declare function resolveHardwareUuid(): string;
|
|
5
|
+
export declare function tryResolveHardwareUuid(): string | null;
|
|
6
|
+
export { resolveHardwareUuid };
|
|
7
|
+
//# sourceMappingURL=hardware-uuid.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hardware-uuid.d.ts","sourceRoot":"","sources":["../../src/lib/hardware-uuid.ts"],"names":[],"mappings":"AAEA,6FAA6F;AAC7F,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CASzD;AAED,yGAAyG;AACzG,iBAAS,mBAAmB,IAAI,MAAM,CAyBrC;AAED,wBAAgB,sBAAsB,IAAI,MAAM,GAAG,IAAI,CAMtD;AAED,OAAO,EAAE,mBAAmB,EAAE,CAAC"}
|