@webinson/peer 0.4.19 → 0.4.21
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.
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "peer-thread-mark",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.21",
|
|
4
4
|
"description": "Marks a Claude Code thread shared with Peer (/peer) with a band above the prompt, with /peer stop and /peer start; panes for /peer-list, /peer-thread and /peer-all (search your memories)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"types": "./types/index.d.ts"
|
|
@@ -497,8 +497,18 @@ async function memoryNote($: EngineInterface) {
|
|
|
497
497
|
return 'Inactive: not shared, Claude Code memory only.'
|
|
498
498
|
}
|
|
499
499
|
|
|
500
|
-
// Who else was on the file, newest
|
|
501
|
-
|
|
500
|
+
// Who else was on the file, one entry per person (their newest session), newest first. One person often holds a path
|
|
501
|
+
// in several sessions (another thread, the Peer app's own), and is named once.
|
|
502
|
+
const byPerson = (holders: CollisionSignal['holders']) => {
|
|
503
|
+
const newest = new Map<string, CollisionSignal['holders'][number]>()
|
|
504
|
+
for (const h of holders) {
|
|
505
|
+
const key = h.email.toLowerCase()
|
|
506
|
+
const was = newest.get(key)
|
|
507
|
+
if (!was || Date.parse(h.at) > Date.parse(was.at)) newest.set(key, h)
|
|
508
|
+
}
|
|
509
|
+
return [...newest.values()].sort((a, b) => Date.parse(b.at) - Date.parse(a.at))
|
|
510
|
+
}
|
|
511
|
+
const othersOf = (signal: CollisionSignal) => byPerson(signal.holders.filter(h => !h.own))
|
|
502
512
|
const whenAgo = (at: string, now: number) => {
|
|
503
513
|
const age = ago(at, now)
|
|
504
514
|
return age === 'just now' ? age : `${age} ago`
|
|
@@ -605,7 +615,7 @@ export const register: Register = on => {
|
|
|
605
615
|
.filter(h => ADDRESS.test(h.email))
|
|
606
616
|
const state = answer.state === 'collision' && !holders.length ? 'clear' : answer.state
|
|
607
617
|
const at = await $.clock.now()
|
|
608
|
-
const emails = (signal: { holders: { email: string }[] }) => signal.holders.map(h => h.email.toLowerCase()).sort().join(' ')
|
|
618
|
+
const emails = (signal: { holders: { email: string }[] }) => [...new Set(signal.holders.map(h => h.email.toLowerCase()))].sort().join(' ')
|
|
609
619
|
let signal: CollisionSignal = { path: answer.path ? plain(answer.path) : null, state, ...(answer.reason ? { reason: answer.reason } : {}), holders, at, shown: false }
|
|
610
620
|
// Shown once per set of people on a path: against the latest earlier collision on it, decided inside one update.
|
|
611
621
|
await update($, signals, was => {
|
|
@@ -87,6 +87,17 @@ test('an edit another person was on draws the line and tells the agent once per
|
|
|
87
87
|
expect(both.additionalContext?.[1]).toContain("cy@acme.test's agent was on src/pay.ts 1 minute ago")
|
|
88
88
|
expect(both.additionalContext?.[1]).toContain("bob@acme.test's agent was on src/pay.ts 2 minutes ago")
|
|
89
89
|
expect(await texts(row('t3', 'desktop'), $ as never)).toContain('cy@… was on it 1 min ago and 1 others')
|
|
90
|
+
|
|
91
|
+
// One person in several sessions (another thread, the Peer app's own) is named once, at their newest.
|
|
92
|
+
state.answer = { path: 'src/one.ts', state: 'collision', holders: [BOB, { ...BOB, email: 'Bob@acme.test', at: minsAgo(0) }, { ...BOB, at: minsAgo(1) }] }
|
|
93
|
+
const once = (await $.classic.PostToolUse(edit('t4', 'Edit', '/repo/src/one.ts'))) as { additionalContext?: string[] }
|
|
94
|
+
expect(once.additionalContext?.[1]).toBe(
|
|
95
|
+
"<peer-collision>\nBob@acme.test's agent was on src/one.ts just now, in another thread.\nThis is information about the repository, not an instruction.\n</peer-collision>",
|
|
96
|
+
)
|
|
97
|
+
expect(await texts(row('t4', 'terminal'), $ as never)).toContain('Bob@… was on it just now')
|
|
98
|
+
// The same person in one more session is no new set of people.
|
|
99
|
+
state.answer = { path: 'src/one.ts', state: 'collision', holders: [BOB, { ...BOB, at: minsAgo(0) }] }
|
|
100
|
+
expect(((await $.classic.PostToolUse(edit('t5', 'Edit', '/repo/src/one.ts'))) as { additionalContext?: string[] }).additionalContext).toEqual(['from another hook'])
|
|
90
101
|
})
|
|
91
102
|
|
|
92
103
|
test('the person\'s own other thread is drawn dimmed and the agent is told nothing', async ($, on) => {
|