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.
Files changed (87) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +194 -0
  3. package/dist/capture-prompt.d.ts +14 -0
  4. package/dist/capture-prompt.d.ts.map +1 -0
  5. package/dist/capture-prompt.js +173 -0
  6. package/dist/capture-prompt.js.map +1 -0
  7. package/dist/index.d.ts +9 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +165 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/lib/endpoint-config.d.ts +2 -0
  12. package/dist/lib/endpoint-config.d.ts.map +1 -0
  13. package/dist/lib/endpoint-config.js +2 -0
  14. package/dist/lib/endpoint-config.js.map +1 -0
  15. package/dist/lib/hardware-uuid.d.ts +7 -0
  16. package/dist/lib/hardware-uuid.d.ts.map +1 -0
  17. package/dist/lib/hardware-uuid.js +52 -0
  18. package/dist/lib/hardware-uuid.js.map +1 -0
  19. package/dist/lib/machine-auth.d.ts +11 -0
  20. package/dist/lib/machine-auth.d.ts.map +1 -0
  21. package/dist/lib/machine-auth.js +46 -0
  22. package/dist/lib/machine-auth.js.map +1 -0
  23. package/dist/lib/startup-sync.d.ts +13 -0
  24. package/dist/lib/startup-sync.d.ts.map +1 -0
  25. package/dist/lib/startup-sync.js +147 -0
  26. package/dist/lib/startup-sync.js.map +1 -0
  27. package/dist/lib/streaming.d.ts +18 -0
  28. package/dist/lib/streaming.d.ts.map +1 -0
  29. package/dist/lib/streaming.js +243 -0
  30. package/dist/lib/streaming.js.map +1 -0
  31. package/dist/lib/telemetry/build-event.d.ts +10 -0
  32. package/dist/lib/telemetry/build-event.d.ts.map +1 -0
  33. package/dist/lib/telemetry/build-event.js +32 -0
  34. package/dist/lib/telemetry/build-event.js.map +1 -0
  35. package/dist/lib/telemetry/canonical.d.ts +26 -0
  36. package/dist/lib/telemetry/canonical.d.ts.map +1 -0
  37. package/dist/lib/telemetry/canonical.js +153 -0
  38. package/dist/lib/telemetry/canonical.js.map +1 -0
  39. package/dist/lib/telemetry/index.d.ts +9 -0
  40. package/dist/lib/telemetry/index.d.ts.map +1 -0
  41. package/dist/lib/telemetry/index.js +9 -0
  42. package/dist/lib/telemetry/index.js.map +1 -0
  43. package/dist/lib/telemetry/serialize.d.ts +3 -0
  44. package/dist/lib/telemetry/serialize.d.ts.map +1 -0
  45. package/dist/lib/telemetry/serialize.js +15 -0
  46. package/dist/lib/telemetry/serialize.js.map +1 -0
  47. package/dist/lib/telemetry/types.d.ts +34 -0
  48. package/dist/lib/telemetry/types.d.ts.map +1 -0
  49. package/dist/lib/telemetry/types.js +14 -0
  50. package/dist/lib/telemetry/types.js.map +1 -0
  51. package/dist/lib/telemetry/wire-metadata.d.ts +10 -0
  52. package/dist/lib/telemetry/wire-metadata.d.ts.map +1 -0
  53. package/dist/lib/telemetry/wire-metadata.js +28 -0
  54. package/dist/lib/telemetry/wire-metadata.js.map +1 -0
  55. package/dist/lib/telemetry.d.ts +2 -0
  56. package/dist/lib/telemetry.d.ts.map +1 -0
  57. package/dist/lib/telemetry.js +2 -0
  58. package/dist/lib/telemetry.js.map +1 -0
  59. package/dist/lib/user-profile.d.ts +16 -0
  60. package/dist/lib/user-profile.d.ts.map +1 -0
  61. package/dist/lib/user-profile.js +175 -0
  62. package/dist/lib/user-profile.js.map +1 -0
  63. package/dist/test/canonical.test.d.ts +2 -0
  64. package/dist/test/canonical.test.d.ts.map +1 -0
  65. package/dist/test/canonical.test.js +117 -0
  66. package/dist/test/canonical.test.js.map +1 -0
  67. package/dist/test/endpoint-config.test.d.ts +2 -0
  68. package/dist/test/endpoint-config.test.d.ts.map +1 -0
  69. package/dist/test/endpoint-config.test.js +43 -0
  70. package/dist/test/endpoint-config.test.js.map +1 -0
  71. package/dist/test/index.test.d.ts +2 -0
  72. package/dist/test/index.test.d.ts.map +1 -0
  73. package/dist/test/index.test.js +376 -0
  74. package/dist/test/index.test.js.map +1 -0
  75. package/dist/test/integration-canonical.test.d.ts +2 -0
  76. package/dist/test/integration-canonical.test.d.ts.map +1 -0
  77. package/dist/test/integration-canonical.test.js +157 -0
  78. package/dist/test/integration-canonical.test.js.map +1 -0
  79. package/dist/test/streaming.test.d.ts +2 -0
  80. package/dist/test/streaming.test.d.ts.map +1 -0
  81. package/dist/test/streaming.test.js +223 -0
  82. package/dist/test/streaming.test.js.map +1 -0
  83. package/dist/test/telemetry.test.d.ts +2 -0
  84. package/dist/test/telemetry.test.d.ts.map +1 -0
  85. package/dist/test/telemetry.test.js +201 -0
  86. package/dist/test/telemetry.test.js.map +1 -0
  87. package/package.json +50 -0
@@ -0,0 +1,157 @@
1
+ import { test } from "node:test";
2
+ import assert from "node:assert";
3
+ import { buildTelemetryEvent } from "../lib/telemetry.js";
4
+ import { normalizeToCanonical } from "../lib/telemetry/canonical.js";
5
+ /**
6
+ * Integration tests verifying that Claude and Cursor produce identical
7
+ * telemetry events for the same tool invocations.
8
+ */
9
+ test("Integration: Read /etc/passwd from both agents produces same event", () => {
10
+ // Claude hook payload
11
+ const claudeRaw = {
12
+ hook_event_name: "PreToolUse",
13
+ tool_name: "Read",
14
+ tool_input: { file_path: "/etc/passwd" },
15
+ session_id: "session-123",
16
+ cwd: "/home/user",
17
+ };
18
+ // Cursor hook payload (same action, different format)
19
+ const cursorRaw = {
20
+ toolUse: { name: "Read", input: { file_path: "/etc/passwd" } },
21
+ sessionId: "session-123",
22
+ cwd: "/home/user",
23
+ };
24
+ // Normalize both
25
+ const claudeCanonical = normalizeToCanonical(claudeRaw);
26
+ const cursorCanonical = normalizeToCanonical(cursorRaw);
27
+ // Build telemetry events
28
+ const claudeEvent = buildTelemetryEvent({
29
+ tool_name: claudeCanonical.tool_name,
30
+ tool_input: claudeCanonical.tool_input,
31
+ session_id: claudeCanonical.session_id,
32
+ cwd: claudeCanonical.cwd,
33
+ hook_event_name: claudeCanonical.hook_event_name,
34
+ raw_event: claudeCanonical.raw_event,
35
+ }, "claude", claudeCanonical.session_id);
36
+ const cursorEvent = buildTelemetryEvent({
37
+ tool_name: cursorCanonical.tool_name,
38
+ tool_input: cursorCanonical.tool_input,
39
+ session_id: cursorCanonical.session_id,
40
+ cwd: cursorCanonical.cwd,
41
+ hook_event_name: cursorCanonical.hook_event_name,
42
+ raw_event: cursorCanonical.raw_event,
43
+ }, "cursor", cursorCanonical.session_id);
44
+ // Verify critical fields match (except agent_identity which should differ)
45
+ assert(claudeEvent);
46
+ assert(cursorEvent);
47
+ assert.strictEqual(claudeEvent.event_type, cursorEvent.event_type);
48
+ assert.strictEqual(claudeEvent.session_id, cursorEvent.session_id);
49
+ assert.strictEqual(claudeEvent.working_directory, cursorEvent.working_directory);
50
+ assert.strictEqual(claudeEvent.tool_call_metadata.tool_name, cursorEvent.tool_call_metadata.tool_name);
51
+ assert.deepEqual(claudeEvent.tool_call_metadata.tool_input, cursorEvent.tool_call_metadata.tool_input);
52
+ // Agent identity should be different
53
+ assert.strictEqual(claudeEvent.agent_identity, "claude");
54
+ assert.strictEqual(cursorEvent.agent_identity, "cursor");
55
+ });
56
+ test("Integration: Dangerous shell command from both agents", () => {
57
+ // Claude preToolUse with bash command
58
+ const claudeRaw = {
59
+ hook_event_name: "PreToolUse",
60
+ tool_name: "Bash",
61
+ tool_input: { command: "rm -rf /var/log" },
62
+ user_prompt: "clean up logs",
63
+ session_id: "claude-sess",
64
+ };
65
+ // Cursor preToolUse with bash command (different field names)
66
+ const cursorRaw = {
67
+ toolUse: {
68
+ name: "Bash",
69
+ input: { command: "rm -rf /var/log" },
70
+ },
71
+ user_prompt: "clean up logs",
72
+ sessionId: "cursor-sess",
73
+ };
74
+ const claudeCanonical = normalizeToCanonical(claudeRaw);
75
+ const cursorCanonical = normalizeToCanonical(cursorRaw);
76
+ // Tool information should be identical
77
+ assert.strictEqual(claudeCanonical.tool_name, cursorCanonical.tool_name);
78
+ assert.strictEqual(claudeCanonical.tool_name, "Bash");
79
+ assert.deepEqual(claudeCanonical.tool_input.command, cursorCanonical.tool_input.command);
80
+ assert.strictEqual(claudeCanonical.user_prompt, cursorCanonical.user_prompt);
81
+ // But agents should be detected correctly
82
+ assert.strictEqual(claudeCanonical.agent, "claude");
83
+ assert.strictEqual(cursorCanonical.agent, "cursor");
84
+ });
85
+ test("Integration: Web operations from both agents", () => {
86
+ const claudeRaw = {
87
+ hook_event_name: "PreToolUse",
88
+ tool_name: "WebFetch",
89
+ tool_input: { url: "https://api.github.com/user", prompt: "check auth" },
90
+ user_prompt: "verify github access",
91
+ };
92
+ const cursorRaw = {
93
+ toolName: "WebFetch",
94
+ toolInput: { url: "https://api.github.com/user", prompt: "check auth" },
95
+ userPrompt: "verify github access",
96
+ };
97
+ const claudeCanonical = normalizeToCanonical(claudeRaw);
98
+ const cursorCanonical = normalizeToCanonical(cursorRaw);
99
+ assert.strictEqual(claudeCanonical.tool_name, "WebFetch");
100
+ assert.strictEqual(cursorCanonical.tool_name, "WebFetch");
101
+ assert.deepEqual(claudeCanonical.tool_input, cursorCanonical.tool_input);
102
+ });
103
+ test("Integration: MCP tool invocations from both agents", () => {
104
+ const claudeRaw = {
105
+ hook_event_name: "PreToolUse",
106
+ tool_name: "mcp__sequential_thinking__think",
107
+ tool_input: { thought: "this is complex" },
108
+ };
109
+ const cursorRaw = {
110
+ toolName: "mcp__sequential_thinking__think",
111
+ toolInput: { thought: "this is complex" },
112
+ };
113
+ const claudeCanonical = normalizeToCanonical(claudeRaw);
114
+ const cursorCanonical = normalizeToCanonical(cursorRaw);
115
+ assert.strictEqual(claudeCanonical.tool_name, cursorCanonical.tool_name);
116
+ assert.deepEqual(claudeCanonical.tool_input, cursorCanonical.tool_input);
117
+ });
118
+ test("Integration: Cursor beforeShellExecution maps to same canonical as Claude preToolUse Bash", () => {
119
+ // Claude preToolUse with Bash
120
+ const claudeRaw = {
121
+ hook_event_name: "PreToolUse",
122
+ tool_name: "Bash",
123
+ tool_input: { command: "curl -X GET https://api.example.com" },
124
+ };
125
+ // Cursor beforeShellExecution with same command
126
+ const cursorRaw = {
127
+ command: "curl -X GET https://api.example.com",
128
+ };
129
+ const claudeCanonical = normalizeToCanonical(claudeRaw);
130
+ const cursorCanonical = normalizeToCanonical(cursorRaw);
131
+ // Both should identify as shell operations
132
+ assert.strictEqual(claudeCanonical.tool_name, "Bash");
133
+ assert.strictEqual(cursorCanonical.tool_name, "Bash");
134
+ // Tool input should be normalized the same way
135
+ assert.deepEqual(claudeCanonical.tool_input, cursorCanonical.tool_input);
136
+ assert.strictEqual(claudeCanonical.tool_input.command, "curl -X GET https://api.example.com");
137
+ });
138
+ test("Integration: Write operations with sensitivity", () => {
139
+ const claudeRaw = {
140
+ hook_event_name: "PreToolUse",
141
+ tool_name: "Write",
142
+ tool_input: { file_path: "~/.ssh/authorized_keys" },
143
+ user_prompt: "add SSH key",
144
+ };
145
+ const cursorRaw = {
146
+ tool: { name: "Write", input: { file_path: "~/.ssh/authorized_keys" } },
147
+ userPrompt: "add SSH key",
148
+ };
149
+ const claudeCanonical = normalizeToCanonical(claudeRaw);
150
+ const cursorCanonical = normalizeToCanonical(cursorRaw);
151
+ // Sensitive path should be preserved identically
152
+ assert.strictEqual(claudeCanonical.tool_name, "Write");
153
+ assert.strictEqual(cursorCanonical.tool_name, "Write");
154
+ assert.deepEqual(claudeCanonical.tool_input, cursorCanonical.tool_input);
155
+ assert.strictEqual(claudeCanonical.tool_input.file_path, "~/.ssh/authorized_keys");
156
+ });
157
+ //# sourceMappingURL=integration-canonical.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integration-canonical.test.js","sourceRoot":"","sources":["../../src/test/integration-canonical.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=streaming.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"streaming.test.d.ts","sourceRoot":"","sources":["../../src/test/streaming.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,223 @@
1
+ import { test } from "node:test";
2
+ import assert from "node:assert";
3
+ import { queueEvent, flushEvents, ensureShutdown } from "../lib/streaming.js";
4
+ // Note: These tests are basic structure tests. Full integration tests with actual HTTP
5
+ // would require mocking fetch/http, which is done in integration tests.
6
+ // Helper to create a mock event
7
+ function createMockEvent() {
8
+ return {
9
+ timestamp: new Date().toISOString(),
10
+ agent_identity: "test-agent",
11
+ event_type: "tool_call",
12
+ session_id: "test-session",
13
+ tool_use_id: "test-tool-use",
14
+ hook_event_name: "preToolUse",
15
+ working_directory: "/tmp",
16
+ tool_call_metadata: {
17
+ tool_name: "Bash",
18
+ tool_input: { command: "ls -la" },
19
+ },
20
+ };
21
+ }
22
+ test("Event object structure - has required fields", () => {
23
+ const event = createMockEvent();
24
+ assert.strictEqual(typeof event.timestamp, "string");
25
+ assert.strictEqual(event.agent_identity, "test-agent");
26
+ assert.strictEqual(event.event_type, "tool_call");
27
+ assert(event.tool_call_metadata);
28
+ assert.strictEqual(event.tool_call_metadata.tool_name, "Bash");
29
+ assert.strictEqual(event.tool_call_metadata.tool_input?.command, "ls -la");
30
+ });
31
+ test("Event object - metadata structure", () => {
32
+ const event = createMockEvent();
33
+ const meta = event.tool_call_metadata;
34
+ assert.strictEqual(typeof meta.tool_name, "string");
35
+ assert(meta.tool_input);
36
+ });
37
+ test("Event object - optional fields can be null", () => {
38
+ const event = {
39
+ timestamp: new Date().toISOString(),
40
+ agent_identity: "test",
41
+ event_type: "tool_call",
42
+ tool_call_metadata: {
43
+ tool_name: "Read",
44
+ tool_input: { file_path: "/z" },
45
+ },
46
+ };
47
+ assert.strictEqual(event.session_id, undefined);
48
+ assert.strictEqual(event.tool_use_id, undefined);
49
+ });
50
+ test("Event serialization - JSON.stringify works", () => {
51
+ const event = createMockEvent();
52
+ const json = JSON.stringify(event);
53
+ assert(typeof json === "string");
54
+ const parsed = JSON.parse(json);
55
+ assert.strictEqual(parsed.agent_identity, "test-agent");
56
+ });
57
+ test("Event batch structure", () => {
58
+ const events = [createMockEvent(), createMockEvent(), createMockEvent()];
59
+ const batch = { events };
60
+ assert.strictEqual(batch.events.length, 3);
61
+ const json = JSON.stringify(batch);
62
+ const parsed = JSON.parse(json);
63
+ assert.strictEqual(parsed.events.length, 3);
64
+ });
65
+ test("MCP event - tool_name carries server; no client-side mcp split", () => {
66
+ const event = {
67
+ timestamp: new Date().toISOString(),
68
+ agent_identity: "claude",
69
+ event_type: "tool_call",
70
+ tool_call_metadata: {
71
+ tool_name: "mcp__filesystem__read_file",
72
+ tool_input: { path: "/" },
73
+ },
74
+ };
75
+ assert.strictEqual(event.tool_call_metadata.tool_name, "mcp__filesystem__read_file");
76
+ });
77
+ test("Event - excludes undefined nested fields in serialization", () => {
78
+ const event = {
79
+ timestamp: new Date().toISOString(),
80
+ agent_identity: "test",
81
+ event_type: "tool_call",
82
+ tool_call_metadata: {
83
+ tool_name: "Read",
84
+ tool_input: { file_path: "/y" },
85
+ },
86
+ };
87
+ const json = JSON.stringify(event);
88
+ const parsed = JSON.parse(json);
89
+ // undefined fields should not appear in JSON
90
+ assert(!("session_id" in parsed) || parsed.session_id === undefined);
91
+ });
92
+ test("Event with all optional fields", () => {
93
+ const event = {
94
+ timestamp: "2024-01-01T00:00:00Z",
95
+ agent_identity: "claude",
96
+ event_type: "tool_call",
97
+ session_id: "session-123",
98
+ tool_use_id: "tooluse-456",
99
+ hook_event_name: "preToolUse",
100
+ working_directory: "/home/user/project",
101
+ tool_call_metadata: {
102
+ tool_name: "Bash",
103
+ tool_input: { command: "git push --force" },
104
+ },
105
+ };
106
+ assert.strictEqual(event.session_id, "session-123");
107
+ assert.strictEqual(event.working_directory, "/home/user/project");
108
+ assert.strictEqual(event.tool_call_metadata.tool_input?.command, "git push --force");
109
+ });
110
+ test("Event - different agent identities", () => {
111
+ const agents = ["claude", "cursor", "copilot", "unknown"];
112
+ for (const agent of agents) {
113
+ const event = {
114
+ timestamp: new Date().toISOString(),
115
+ agent_identity: agent,
116
+ event_type: "tool_call",
117
+ tool_call_metadata: {
118
+ tool_name: "Read",
119
+ tool_input: { file_path: "/a" },
120
+ },
121
+ };
122
+ assert.strictEqual(event.agent_identity, agent);
123
+ }
124
+ });
125
+ test("Batch payload validation", () => {
126
+ const events = Array.from({ length: 50 }, (_, i) => ({
127
+ ...createMockEvent(),
128
+ tool_use_id: `tool-${i}`,
129
+ }));
130
+ const batch = { events };
131
+ assert.strictEqual(batch.events.length, 50);
132
+ // All should be serializable
133
+ const json = JSON.stringify(batch);
134
+ assert(json.length > 0);
135
+ const parsed = JSON.parse(json);
136
+ assert.strictEqual(parsed.events.length, 50);
137
+ });
138
+ test("Event timestamp format", () => {
139
+ const event = createMockEvent();
140
+ const timestamp = new Date(event.timestamp);
141
+ assert(!isNaN(timestamp.getTime()));
142
+ assert(event.timestamp.includes("T"));
143
+ assert(event.timestamp.includes("Z") || event.timestamp.includes("+"));
144
+ });
145
+ test("Tool input preservation", () => {
146
+ const toolInput = {
147
+ file_path: "/tmp/test.txt",
148
+ custom_field: "custom_value",
149
+ nested: { key: "value" },
150
+ };
151
+ const event = {
152
+ timestamp: new Date().toISOString(),
153
+ agent_identity: "test",
154
+ event_type: "tool_call",
155
+ tool_call_metadata: {
156
+ tool_name: "Read",
157
+ tool_input: toolInput,
158
+ },
159
+ };
160
+ assert.strictEqual(event.tool_call_metadata.tool_input.file_path, "/tmp/test.txt");
161
+ assert.strictEqual(event.tool_call_metadata.tool_input.custom_field, "custom_value");
162
+ assert.deepStrictEqual(event.tool_call_metadata.tool_input.nested, { key: "value" });
163
+ });
164
+ // === Tests for ensureShutdown() graceful shutdown behavior (Devin comment fix) ===
165
+ // Documentation: https://github.com/devin-ai-integration/...
166
+ //
167
+ // The original ensureShutdown() only cleared the batch timer but never flushed
168
+ // queued events, causing silent data loss when BATCH_SIZE > 1 (production config).
169
+ // The fix uses beforeExit to allow async flush and handles SIGTERM/SIGINT signals.
170
+ test("ensureShutdown - function exists and is callable", () => {
171
+ // Basic smoke test to ensure the function is properly exported
172
+ assert.strictEqual(typeof ensureShutdown, "function");
173
+ });
174
+ test("ensureShutdown - should not throw on call", () => {
175
+ // Verify the function can be called without errors
176
+ assert.doesNotThrow(() => {
177
+ // Note: We can only call this once per process safely
178
+ // In real usage, it's called during module initialization
179
+ ensureShutdown();
180
+ });
181
+ });
182
+ test("flushEvents - function exists and is callable", async () => {
183
+ // Verify flushEvents is properly exported for testing
184
+ assert.strictEqual(typeof flushEvents, "function");
185
+ // Should handle empty queue gracefully
186
+ await assert.doesNotReject(async () => {
187
+ await flushEvents();
188
+ });
189
+ });
190
+ test("queueEvent - function exists and is callable", async () => {
191
+ // Verify queueEvent is properly exported
192
+ assert.strictEqual(typeof queueEvent, "function");
193
+ });
194
+ test("streaming - verifies fix addresses Devin comment about data loss", () => {
195
+ // This test documents the fix for Devin's code review:
196
+ //
197
+ // Original issue:
198
+ // - ensureShutdown() only cleared batch timer, never flushed events
199
+ // - process.on('exit') doesn't support async operations
200
+ // - With BATCH_SIZE > 1, events were silently lost
201
+ //
202
+ // Solution:
203
+ // - Changed to process.on('beforeExit') which supports async
204
+ // - Added SIGTERM/SIGINT handlers for graceful shutdown
205
+ // - Actually calls flushEvents() to prevent data loss
206
+ const sourceCode = ensureShutdown.toString();
207
+ // Verify the fix is in place
208
+ assert.match(sourceCode, /beforeExit/, "Should use beforeExit to allow async flush");
209
+ assert.match(sourceCode, /flushEvents/, "Should call flushEvents() not just clear timer");
210
+ assert.match(sourceCode, /SIGTERM|SIGINT/, "Should handle graceful shutdown signals");
211
+ });
212
+ test("queueEvent + flushEvents - can queue and flush events", async () => {
213
+ // Integration test: verify events can be queued without crashing
214
+ // (actual HTTP send would be mocked in integration tests)
215
+ const event = createMockEvent();
216
+ assert.doesNotThrow(() => {
217
+ // Queue should not throw (it's async but we're testing non-throwing behavior)
218
+ queueEvent(event).catch(() => {
219
+ // Ignore network errors in this basic test
220
+ });
221
+ });
222
+ });
223
+ //# sourceMappingURL=streaming.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"streaming.test.js","sourceRoot":"","sources":["../../src/test/streaming.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=telemetry.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telemetry.test.d.ts","sourceRoot":"","sources":["../../src/test/telemetry.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,201 @@
1
+ import { test } from "node:test";
2
+ import assert from "node:assert";
3
+ import { buildTelemetryEvent, eventToDict } from "../lib/telemetry.js";
4
+ test("buildTelemetryEvent - null input returns null", () => {
5
+ assert.strictEqual(buildTelemetryEvent(null), null);
6
+ assert.strictEqual(buildTelemetryEvent(undefined), null);
7
+ });
8
+ test("buildTelemetryEvent - filesystem read sends raw fields (classification is server-side)", () => {
9
+ const inv = {
10
+ tool_name: "Read",
11
+ tool_input: { file_path: "/etc/passwd" },
12
+ };
13
+ const event = buildTelemetryEvent(inv, "test-agent");
14
+ assert(event);
15
+ assert.strictEqual(event.agent_identity, "test-agent");
16
+ assert.strictEqual(event.event_type, "tool_call");
17
+ assert.strictEqual(event.tool_call_metadata.tool_name, "Read");
18
+ assert.strictEqual(event.tool_call_metadata.tool_input?.file_path, "/etc/passwd");
19
+ });
20
+ test("buildTelemetryEvent - filesystem write raw", () => {
21
+ const inv = {
22
+ tool_name: "Write",
23
+ tool_input: { file_path: "/tmp/test.txt" },
24
+ };
25
+ const event = buildTelemetryEvent(inv, "claude");
26
+ assert(event);
27
+ assert.strictEqual(event.tool_call_metadata.tool_name, "Write");
28
+ });
29
+ test("buildTelemetryEvent - filesystem edit raw", () => {
30
+ const inv = {
31
+ tool_name: "Edit",
32
+ tool_input: { file_path: "/tmp/edit.txt" },
33
+ };
34
+ const event = buildTelemetryEvent(inv, "claude");
35
+ assert(event);
36
+ });
37
+ test("buildTelemetryEvent - sensitive path still raw on client", () => {
38
+ const inv = {
39
+ tool_name: "Read",
40
+ tool_input: { file_path: "~/.ssh/id_rsa" },
41
+ };
42
+ const event = buildTelemetryEvent(inv, "claude");
43
+ assert(event);
44
+ });
45
+ test("buildTelemetryEvent - grep credential pattern raw", () => {
46
+ const inv = {
47
+ tool_name: "Grep",
48
+ tool_input: { pattern: "password" },
49
+ };
50
+ const event = buildTelemetryEvent(inv, "claude");
51
+ assert(event);
52
+ assert.strictEqual(event.tool_call_metadata.tool_input?.pattern, "password");
53
+ });
54
+ test("buildTelemetryEvent - webfetch raw", () => {
55
+ const inv = {
56
+ tool_name: "WebFetch",
57
+ tool_input: { url: "https://example.com" },
58
+ };
59
+ const event = buildTelemetryEvent(inv, "claude");
60
+ assert(event);
61
+ });
62
+ test("buildTelemetryEvent - websearch raw", () => {
63
+ const inv = {
64
+ tool_name: "WebSearch",
65
+ tool_input: { query: "security" },
66
+ };
67
+ const event = buildTelemetryEvent(inv, "claude");
68
+ assert(event);
69
+ });
70
+ test("buildTelemetryEvent - shell passes command for server tokenization", () => {
71
+ const inv = {
72
+ tool_name: "Shell",
73
+ tool_input: { command: "git push origin main" },
74
+ };
75
+ const event = buildTelemetryEvent(inv, "claude");
76
+ assert(event);
77
+ assert.strictEqual(event.tool_call_metadata.tool_input?.command, "git push origin main");
78
+ });
79
+ test("buildTelemetryEvent - bash command raw", () => {
80
+ const inv = {
81
+ tool_name: "Bash",
82
+ tool_input: { command: "rm -rf /tmp/test" },
83
+ };
84
+ const event = buildTelemetryEvent(inv, "claude");
85
+ assert(event);
86
+ assert.strictEqual(event.tool_call_metadata.tool_input?.command, "rm -rf /tmp/test");
87
+ });
88
+ test("buildTelemetryEvent - mcp tool name is raw only (no mcp_server / mcp_tool on client)", () => {
89
+ const inv = {
90
+ tool_name: "mcp__filesystem__read_file",
91
+ tool_input: { path: "/etc/hosts" },
92
+ };
93
+ const event = buildTelemetryEvent(inv, "claude");
94
+ assert(event);
95
+ assert.strictEqual(event.tool_call_metadata.tool_name, "mcp__filesystem__read_file");
96
+ assert.strictEqual(event.tool_call_metadata.tool_input?.path, "/etc/hosts");
97
+ });
98
+ test("buildTelemetryEvent - non-filesystem mcp tool raw", () => {
99
+ const inv = {
100
+ tool_name: "mcp__sequential_thinking__think",
101
+ tool_input: { prompt: "reason about this" },
102
+ };
103
+ const event = buildTelemetryEvent(inv, "claude");
104
+ assert(event);
105
+ assert.strictEqual(event.tool_call_metadata.tool_name, "mcp__sequential_thinking__think");
106
+ });
107
+ test("buildTelemetryEvent - preserves session id and tool use id", () => {
108
+ const inv = {
109
+ tool_name: "Read",
110
+ tool_input: { file_path: "/tmp/test" },
111
+ tool_use_id: "tooluse_123",
112
+ cwd: "/home/user",
113
+ hook_event_name: "preToolUse",
114
+ };
115
+ const event = buildTelemetryEvent(inv, "cursor", "session_abc");
116
+ assert(event);
117
+ assert.strictEqual(event.session_id, "session_abc");
118
+ assert.strictEqual(event.tool_use_id, "tooluse_123");
119
+ assert.strictEqual(event.working_directory, "/home/user");
120
+ assert.strictEqual(event.hook_event_name, "preToolUse");
121
+ });
122
+ test("eventToDict - converts event to dictionary", () => {
123
+ const inv = {
124
+ tool_name: "Read",
125
+ tool_input: { file_path: "/etc/hosts" },
126
+ };
127
+ const event = buildTelemetryEvent(inv, "test-agent");
128
+ assert(event);
129
+ const dict = eventToDict(event);
130
+ assert.strictEqual(dict.agent_identity, "test-agent");
131
+ assert.strictEqual(dict.event_type, "tool_call");
132
+ assert.strictEqual(dict.tool_name, "Read");
133
+ assert.deepStrictEqual(dict.tool_input, { file_path: "/etc/hosts" });
134
+ assert.strictEqual("action_type" in dict, false);
135
+ });
136
+ test("buildTelemetryEvent - unknown tool raw", () => {
137
+ const inv = {
138
+ tool_name: "CustomUnknownTool",
139
+ tool_input: {},
140
+ };
141
+ const event = buildTelemetryEvent(inv, "claude");
142
+ assert(event);
143
+ });
144
+ test("buildTelemetryEvent - timestamp is ISO string", () => {
145
+ const inv = {
146
+ tool_name: "Read",
147
+ tool_input: { file_path: "/tmp" },
148
+ };
149
+ const event = buildTelemetryEvent(inv);
150
+ assert(event);
151
+ assert(typeof event.timestamp === "string");
152
+ const parsed = new Date(event.timestamp);
153
+ assert(!isNaN(parsed.getTime()));
154
+ });
155
+ test("buildTelemetryEvent - normalizes tool name casing", () => {
156
+ const inv = {
157
+ tool_name: "read",
158
+ tool_input: { file_path: "/tmp" },
159
+ };
160
+ const event = buildTelemetryEvent(inv, "claude");
161
+ assert(event);
162
+ assert.strictEqual(event.tool_call_metadata.tool_name, "read");
163
+ });
164
+ test("buildTelemetryEvent - passes raw_event for server shell command resolution", () => {
165
+ const inv = {
166
+ tool_name: "Bash",
167
+ tool_input: {},
168
+ raw_event: { command: "ls -la /tmp" },
169
+ };
170
+ const event = buildTelemetryEvent(inv);
171
+ assert(event);
172
+ assert(event.tool_call_metadata.raw_event);
173
+ assert.strictEqual(event.tool_call_metadata.raw_event.command, "ls -la /tmp");
174
+ });
175
+ test("buildTelemetryEvent - handles cmd alias for command", () => {
176
+ const inv = {
177
+ tool_name: "Bash",
178
+ tool_input: { cmd: "npm install" },
179
+ };
180
+ const event = buildTelemetryEvent(inv);
181
+ assert(event);
182
+ assert.strictEqual(event.tool_call_metadata.tool_input?.cmd, "npm install");
183
+ });
184
+ test("buildTelemetryEvent - glob sensitive path raw", () => {
185
+ const inv = {
186
+ tool_name: "Glob",
187
+ tool_input: { path: "/home/user/.ssh/" },
188
+ };
189
+ const event = buildTelemetryEvent(inv);
190
+ assert(event);
191
+ assert.strictEqual(event.tool_call_metadata.tool_input?.path, "/home/user/.ssh/");
192
+ });
193
+ test("buildTelemetryEvent - glob normal path raw", () => {
194
+ const inv = {
195
+ tool_name: "Glob",
196
+ tool_input: { path: "/tmp/files" },
197
+ };
198
+ const event = buildTelemetryEvent(inv);
199
+ assert(event);
200
+ });
201
+ //# sourceMappingURL=telemetry.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telemetry.test.js","sourceRoot":"","sources":["../../src/test/telemetry.test.ts"],"names":[],"mappings":"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"}