@raidou/pi-notify 0.4.0 → 0.5.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.
- package/README.md +15 -1
- package/package.json +3 -1
- package/src/config.ts +0 -3
- package/src/dashboard/command.ts +3 -8
- package/src/dashboard/consts.ts +6 -0
- package/src/dashboard/session-store.test.ts +156 -8
- package/src/dashboard/session-store.ts +16 -12
- package/src/dashboard/state-store.test.ts +89 -17
- package/src/dashboard/state-store.ts +88 -32
- package/src/dashboard/ui/columns.ts +102 -0
- package/src/dashboard/ui/dashboard.test.ts +118 -0
- package/src/dashboard/ui/dashboard.ts +122 -0
- package/src/index.ts +2 -11
- package/src/state-tracker.test.ts +227 -12
- package/src/state-tracker.ts +53 -6
- package/src/dashboard/ui.ts +0 -193
- package/src/events.test.ts +0 -115
- package/src/events.ts +0 -31
- package/src/idle.ts +0 -37
- package/src/tool.ts +0 -21
package/src/events.test.ts
DELETED
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
import type { ExtensionAPI } from '@earendil-works/pi-coding-agent'
|
|
2
|
-
import { describe, expect, it } from 'vitest'
|
|
3
|
-
|
|
4
|
-
import type { ResolvedNotifyConfig } from './config.js'
|
|
5
|
-
import { EventsNotifier } from './events.js'
|
|
6
|
-
|
|
7
|
-
type EventsListener = (payload: unknown) => void
|
|
8
|
-
|
|
9
|
-
interface FakePi {
|
|
10
|
-
eventListeners: Map<string, Set<EventsListener>>
|
|
11
|
-
listeners: Map<string, Set<(...args: unknown[]) => void>>
|
|
12
|
-
events: { on(event: string, listener: EventsListener): () => void }
|
|
13
|
-
on(event: string, listener: (...args: unknown[]) => void): void
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function makeFakePi(): FakePi {
|
|
17
|
-
const eventListeners = new Map<string, Set<EventsListener>>()
|
|
18
|
-
const listeners = new Map<string, Set<(...args: unknown[]) => void>>()
|
|
19
|
-
return {
|
|
20
|
-
eventListeners,
|
|
21
|
-
listeners,
|
|
22
|
-
events: {
|
|
23
|
-
on(event, listener) {
|
|
24
|
-
let set = eventListeners.get(event)
|
|
25
|
-
if (!set) {
|
|
26
|
-
set = new Set()
|
|
27
|
-
eventListeners.set(event, set)
|
|
28
|
-
}
|
|
29
|
-
set.add(listener)
|
|
30
|
-
return () => {
|
|
31
|
-
set.delete(listener)
|
|
32
|
-
}
|
|
33
|
-
},
|
|
34
|
-
},
|
|
35
|
-
on(event, listener) {
|
|
36
|
-
let set = listeners.get(event)
|
|
37
|
-
if (!set) {
|
|
38
|
-
set = new Set()
|
|
39
|
-
listeners.set(event, set)
|
|
40
|
-
}
|
|
41
|
-
set.add(listener)
|
|
42
|
-
},
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function makeConfig(
|
|
47
|
-
events: ResolvedNotifyConfig['events'],
|
|
48
|
-
): ResolvedNotifyConfig {
|
|
49
|
-
return {
|
|
50
|
-
enabled: true,
|
|
51
|
-
notifyTools: new Set<string>(),
|
|
52
|
-
events,
|
|
53
|
-
finished: true,
|
|
54
|
-
finishedThrottleMs: 0,
|
|
55
|
-
onlyNotifyWhenUnfocused: true,
|
|
56
|
-
unfocusedActivityThresholdMs: 0,
|
|
57
|
-
tmuxSymbol: '',
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function emitEvent(pi: FakePi, event: string, payload?: unknown): void {
|
|
62
|
-
const set = pi.eventListeners.get(event)
|
|
63
|
-
if (!set) return
|
|
64
|
-
for (const listener of [...set]) listener(payload)
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
describe('EventsNotifier', () => {
|
|
68
|
-
it('notifies with the configured message when a custom event fires', () => {
|
|
69
|
-
const pi = makeFakePi()
|
|
70
|
-
const notifier = new EventsNotifier(
|
|
71
|
-
pi as unknown as ExtensionAPI,
|
|
72
|
-
makeConfig({
|
|
73
|
-
'my:custom:event': 'Custom event triggered',
|
|
74
|
-
}),
|
|
75
|
-
)
|
|
76
|
-
const bodies: string[] = []
|
|
77
|
-
notifier.register((body) => bodies.push(body))
|
|
78
|
-
|
|
79
|
-
emitEvent(pi, 'my:custom:event')
|
|
80
|
-
|
|
81
|
-
expect(bodies).toEqual(['Custom event triggered'])
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
it('does not notify for events disabled with false', () => {
|
|
85
|
-
const pi = makeFakePi()
|
|
86
|
-
const notifier = new EventsNotifier(
|
|
87
|
-
pi as unknown as ExtensionAPI,
|
|
88
|
-
makeConfig({
|
|
89
|
-
'my:custom:event': false,
|
|
90
|
-
}),
|
|
91
|
-
)
|
|
92
|
-
const bodies: string[] = []
|
|
93
|
-
notifier.register((body) => bodies.push(body))
|
|
94
|
-
|
|
95
|
-
emitEvent(pi, 'my:custom:event')
|
|
96
|
-
|
|
97
|
-
expect(bodies).toEqual([])
|
|
98
|
-
})
|
|
99
|
-
|
|
100
|
-
it('does not notify for events disabled with an empty string (backward compatibility)', () => {
|
|
101
|
-
const pi = makeFakePi()
|
|
102
|
-
const notifier = new EventsNotifier(
|
|
103
|
-
pi as unknown as ExtensionAPI,
|
|
104
|
-
makeConfig({
|
|
105
|
-
'my:custom:event': '',
|
|
106
|
-
}),
|
|
107
|
-
)
|
|
108
|
-
const bodies: string[] = []
|
|
109
|
-
notifier.register((body) => bodies.push(body))
|
|
110
|
-
|
|
111
|
-
emitEvent(pi, 'my:custom:event')
|
|
112
|
-
|
|
113
|
-
expect(bodies).toEqual([])
|
|
114
|
-
})
|
|
115
|
-
})
|
package/src/events.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import type { ExtensionAPI } from '@earendil-works/pi-coding-agent'
|
|
2
|
-
|
|
3
|
-
import type { ResolvedNotifyConfig } from './config.js'
|
|
4
|
-
import { Registrar } from './shared/registrar.js'
|
|
5
|
-
import type { NotifyAction } from './shared/types.js'
|
|
6
|
-
|
|
7
|
-
export const PI_NOTIFY_EVENT = 'pi-notify:notify'
|
|
8
|
-
|
|
9
|
-
export class EventsNotifier extends Registrar {
|
|
10
|
-
private readonly config: ResolvedNotifyConfig
|
|
11
|
-
|
|
12
|
-
constructor(pi: ExtensionAPI, config: ResolvedNotifyConfig) {
|
|
13
|
-
super(pi)
|
|
14
|
-
this.config = config
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
protected override setup(notify: NotifyAction): void {
|
|
18
|
-
for (const [channel, message] of Object.entries(this.config.events)) {
|
|
19
|
-
if (typeof message !== 'string' || message === '') continue
|
|
20
|
-
const unsubscribe = this.pi.events.on(channel, () => {
|
|
21
|
-
notify(message)
|
|
22
|
-
})
|
|
23
|
-
this.unsubscribes.push(unsubscribe)
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const customEventUnsub = this.pi.events.on(PI_NOTIFY_EVENT, (payload) => {
|
|
27
|
-
notify(String(payload))
|
|
28
|
-
})
|
|
29
|
-
this.unsubscribes.push(customEventUnsub)
|
|
30
|
-
}
|
|
31
|
-
}
|
package/src/idle.ts
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import type { ExtensionAPI } from '@earendil-works/pi-coding-agent'
|
|
2
|
-
|
|
3
|
-
import type { ResolvedNotifyConfig } from './config.js'
|
|
4
|
-
import { Registrar } from './shared/registrar.js'
|
|
5
|
-
import type { NotifyAction } from './shared/types.js'
|
|
6
|
-
import type { StateTracker } from './state-tracker.js'
|
|
7
|
-
|
|
8
|
-
export class IdleNotifier extends Registrar {
|
|
9
|
-
private readonly config: ResolvedNotifyConfig
|
|
10
|
-
private readonly stateTracker: StateTracker
|
|
11
|
-
private hasActivity = false
|
|
12
|
-
|
|
13
|
-
constructor(
|
|
14
|
-
pi: ExtensionAPI,
|
|
15
|
-
config: ResolvedNotifyConfig,
|
|
16
|
-
stateTracker: StateTracker,
|
|
17
|
-
) {
|
|
18
|
-
super(pi)
|
|
19
|
-
this.config = config
|
|
20
|
-
this.stateTracker = stateTracker
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
protected override setup(notify: NotifyAction): void {
|
|
24
|
-
if (!this.config.finished) return
|
|
25
|
-
|
|
26
|
-
this.pi.on('turn_start', () => {
|
|
27
|
-
this.hasActivity = true
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
this.unsubscribes.push(
|
|
31
|
-
this.stateTracker.events.on('idle', () => {
|
|
32
|
-
if (!this.hasActivity) return
|
|
33
|
-
notify('Idle')
|
|
34
|
-
}),
|
|
35
|
-
)
|
|
36
|
-
}
|
|
37
|
-
}
|
package/src/tool.ts
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { ExtensionAPI } from '@earendil-works/pi-coding-agent'
|
|
2
|
-
|
|
3
|
-
import type { ResolvedNotifyConfig } from './config.js'
|
|
4
|
-
import { Registrar } from './shared/registrar.js'
|
|
5
|
-
import type { NotifyAction } from './shared/types.js'
|
|
6
|
-
|
|
7
|
-
export class ToolCallNotifier extends Registrar {
|
|
8
|
-
private readonly config: ResolvedNotifyConfig
|
|
9
|
-
|
|
10
|
-
constructor(pi: ExtensionAPI, config: ResolvedNotifyConfig) {
|
|
11
|
-
super(pi)
|
|
12
|
-
this.config = config
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
protected override setup(notify: NotifyAction): void {
|
|
16
|
-
this.pi.on('tool_call', (event) => {
|
|
17
|
-
if (!this.config.notifyTools.has(event.toolName)) return
|
|
18
|
-
notify(`Tool call: ${event.toolName}`)
|
|
19
|
-
})
|
|
20
|
-
}
|
|
21
|
-
}
|