claude-live 0.4.8 → 1.1.1

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 (53) hide show
  1. package/bin/claude-live.js +36 -20
  2. package/package.json +13 -26
  3. package/.claude-plugin/hooks/hooks.json +0 -126
  4. package/.claude-plugin/marketplace.json +0 -27
  5. package/.claude-plugin/plugin.json +0 -14
  6. package/README.md +0 -60
  7. package/bin/check-and-restart.js +0 -63
  8. package/bin/send-hook.sh +0 -34
  9. package/bin/start-server.sh +0 -33
  10. package/client/dist/assets/index-B1BUdq7a.js +0 -47
  11. package/client/dist/assets/index-DjcKbX6b.css +0 -1
  12. package/client/dist/chords/chord_01.wav +0 -0
  13. package/client/dist/chords/chord_02.wav +0 -0
  14. package/client/dist/chords/chord_03.wav +0 -0
  15. package/client/dist/chords/chord_04.wav +0 -0
  16. package/client/dist/chords/chord_05.wav +0 -0
  17. package/client/dist/chords/chord_06.wav +0 -0
  18. package/client/dist/chords/chord_07.wav +0 -0
  19. package/client/dist/chords/chord_08.wav +0 -0
  20. package/client/dist/chords/chord_09.wav +0 -0
  21. package/client/dist/chords/chord_10.wav +0 -0
  22. package/client/dist/chords/chord_11.wav +0 -0
  23. package/client/dist/chords/chord_12.wav +0 -0
  24. package/client/dist/chords/chord_13.wav +0 -0
  25. package/client/dist/chords/chord_14.wav +0 -0
  26. package/client/dist/chords/chord_15.wav +0 -0
  27. package/client/dist/chords/chord_16.wav +0 -0
  28. package/client/dist/index.html +0 -18
  29. package/client/public/chords/chord_01.wav +0 -0
  30. package/client/public/chords/chord_02.wav +0 -0
  31. package/client/public/chords/chord_03.wav +0 -0
  32. package/client/public/chords/chord_04.wav +0 -0
  33. package/client/public/chords/chord_05.wav +0 -0
  34. package/client/public/chords/chord_06.wav +0 -0
  35. package/client/public/chords/chord_07.wav +0 -0
  36. package/client/public/chords/chord_08.wav +0 -0
  37. package/client/public/chords/chord_09.wav +0 -0
  38. package/client/public/chords/chord_10.wav +0 -0
  39. package/client/public/chords/chord_11.wav +0 -0
  40. package/client/public/chords/chord_12.wav +0 -0
  41. package/client/public/chords/chord_13.wav +0 -0
  42. package/client/public/chords/chord_14.wav +0 -0
  43. package/client/public/chords/chord_15.wav +0 -0
  44. package/client/public/chords/chord_16.wav +0 -0
  45. package/commands/claude-live.md +0 -145
  46. package/hooks/hooks.json +0 -166
  47. package/server/index.js +0 -288
  48. package/test-agent-animations-long.js +0 -144
  49. package/test-agent-animations.js +0 -126
  50. package/test-agents.js +0 -61
  51. package/tests/server.test.js +0 -48
  52. package/tests/store.test.ts +0 -141
  53. package/vitest.config.ts +0 -10
@@ -1,141 +0,0 @@
1
- // tests/store.test.ts
2
- import { describe, it, expect } from 'vitest'
3
- import { createStore } from '../client/src/store'
4
-
5
- const makeEvent = (overrides = {}) => ({
6
- id: Math.random().toString(),
7
- session_id: 'sess-1',
8
- timestamp: Date.now(),
9
- hook_event_name: 'PreToolUse' as const,
10
- tool_name: 'Read',
11
- tool_input: { file_path: '/src/foo.ts' },
12
- tool_response: null,
13
- ...overrides
14
- })
15
-
16
- describe('store', () => {
17
- it('keeps last 100 events', () => {
18
- const store = createStore()
19
- for (let i = 0; i < 110; i++) store.addEvent(makeEvent({ id: String(i) }))
20
- expect(store.getBuffer()).toHaveLength(100)
21
- expect(store.getBuffer()[0].id).toBe('10') // oldest remaining
22
- })
23
-
24
- it('derives node age as distance from end of buffer', () => {
25
- const store = createStore()
26
- store.addEvent(makeEvent({ id: '1', tool_input: { file_path: '/a.ts' } }))
27
- store.addEvent(makeEvent({ id: '2', tool_input: { file_path: '/b.ts' } }))
28
- store.addEvent(makeEvent({ id: '3', tool_input: { file_path: '/a.ts' } })) // a.ts touched again
29
- const sessions = store.getSessions()
30
- const cluster = sessions.get('sess-1')!
31
- expect(cluster.nodes.get('file:/a.ts')!.age).toBe(0) // most recent
32
- expect(cluster.nodes.get('file:/b.ts')!.age).toBe(1) // second from end
33
- })
34
-
35
- it('removes nodes pushed out of buffer', () => {
36
- const store = createStore()
37
- store.addEvent(makeEvent({ id: '1', tool_input: { file_path: '/old.ts' } }))
38
- for (let i = 2; i <= 102; i++) {
39
- store.addEvent(makeEvent({ id: String(i), tool_input: { file_path: '/new.ts' } }))
40
- }
41
- const cluster = store.getSessions().get('sess-1')!
42
- expect(cluster.nodes.has('file:/old.ts')).toBe(false)
43
- })
44
-
45
- it('creates separate clusters per session_id', () => {
46
- const store = createStore()
47
- store.addEvent(makeEvent({ session_id: 'sess-a' }))
48
- store.addEvent(makeEvent({ session_id: 'sess-b' }))
49
- expect(store.getSessions().size).toBe(2)
50
- })
51
-
52
- it('sets stopping=true on Stop event', () => {
53
- const store = createStore()
54
- store.addEvent(makeEvent())
55
- store.addEvent(makeEvent({ hook_event_name: 'Stop', tool_name: null, tool_input: null }))
56
- const cluster = store.getSessions().get('sess-1')!
57
- expect(cluster.stopping).toBe(true)
58
- })
59
-
60
- it('sets node ages to 80 on Stop event', () => {
61
- const store = createStore()
62
- store.addEvent(makeEvent({ id: '1', tool_input: { file_path: '/foo.ts' } }))
63
- store.addEvent(makeEvent({ hook_event_name: 'Stop', tool_name: null, tool_input: null }))
64
- const cluster = store.getSessions().get('sess-1')!
65
- for (const node of cluster.nodes.values()) {
66
- expect(node.age).toBeGreaterThanOrEqual(80)
67
- }
68
- })
69
-
70
- it('spawns ResponseSnakes on PostToolUse Write with words', () => {
71
- const store = createStore()
72
- store.addEvent(makeEvent({ id: '1', tool_input: { file_path: '/test.ts' }, tool_name: 'Write' }))
73
- // First pass: replay phase (skipAnimations=true)
74
- store.addEvent(makeEvent({
75
- id: '2',
76
- hook_event_name: 'PostToolUse',
77
- tool_name: 'Write',
78
- tool_input: { file_path: '/test.ts', content: 'function hello world test animation' },
79
- tool_response: null
80
- }), true)
81
- let cluster = store.getSessions().get('sess-1')!
82
- expect(cluster.promptSnakes.length).toBe(0) // No snakes during replay
83
-
84
- // Second pass: live phase (skipAnimations=false)
85
- store.addEvent(makeEvent({
86
- id: '3',
87
- hook_event_name: 'PostToolUse',
88
- tool_name: 'Write',
89
- tool_input: { file_path: '/test.ts', content: 'function hello world test animation' },
90
- tool_response: null
91
- }), false)
92
- cluster = store.getSessions().get('sess-1')!
93
- expect(cluster.promptSnakes.length).toBe(1)
94
- expect(cluster.promptSnakes[0].words.length).toBeGreaterThan(0)
95
- expect(cluster.promptSnakes[0].words[0]).toBe('function')
96
- })
97
-
98
- it('spawns ResponseSnakes on PostToolUse Read with file content', () => {
99
- const store = createStore()
100
- store.addEvent(makeEvent({ id: '1', tool_input: { file_path: '/test.ts' } }))
101
- store.addEvent(makeEvent({
102
- id: '2',
103
- hook_event_name: 'PostToolUse',
104
- tool_name: 'Read',
105
- tool_input: { file_path: '/test.ts' },
106
- tool_response: { type: 'text', file: { filePath: '/test.ts', content: 'const x = 42 testing' } }
107
- }), false)
108
- const cluster = store.getSessions().get('sess-1')!
109
- expect(cluster.promptSnakes.length).toBe(1)
110
- expect(cluster.promptSnakes[0].words[0]).toBe('const')
111
- })
112
-
113
- it('spawns ResponseSnakes on PostToolUse Bash with stdout', () => {
114
- const store = createStore()
115
- store.addEvent(makeEvent({ id: '1', tool_input: { file_path: '/test.sh' } }))
116
- store.addEvent(makeEvent({
117
- id: '2',
118
- hook_event_name: 'PostToolUse',
119
- tool_name: 'Bash',
120
- tool_input: { command: 'echo hello world' },
121
- tool_response: { stdout: 'hello world from bash output', stderr: '', interrupted: false }
122
- }), false)
123
- const cluster = store.getSessions().get('sess-1')!
124
- expect(cluster.promptSnakes.length).toBe(1)
125
- expect(cluster.promptSnakes[0].words[0]).toBe('hello')
126
- })
127
-
128
- it('skips ResponseSnakes during replay phase', () => {
129
- const store = createStore()
130
- store.addEvent(makeEvent({ id: '1', tool_input: { file_path: '/test.ts' } }))
131
- store.addEvent(makeEvent({
132
- id: '2',
133
- hook_event_name: 'PostToolUse',
134
- tool_name: 'Write',
135
- tool_input: { content: 'test content words' },
136
- tool_response: null
137
- }), true) // skipAnimations=true
138
- const cluster = store.getSessions().get('sess-1')!
139
- expect(cluster.promptSnakes.length).toBe(0)
140
- })
141
- })
package/vitest.config.ts DELETED
@@ -1,10 +0,0 @@
1
- import { defineConfig } from 'vitest/config'
2
- import react from '@vitejs/plugin-react'
3
-
4
- export default defineConfig({
5
- plugins: [react()],
6
- test: {
7
- globals: true,
8
- environment: 'node',
9
- },
10
- })