Phase 787: agentctl guild member roles mesh journey (v0.8.754)
Add memberCustomRolesIncludes and guildCustomRolesMin matchers, runGuildMeshMemberRolesJourney, and wait-diagnostics role counts. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
Agent control plane for Pearcord — send the same IPC messages the UI sends, read `view` snapshots, and run scripted journeys against a **live worker** or an in-process **headless** session.
|
Agent control plane for Pearcord — send the same IPC messages the UI sends, read `view` snapshots, and run scripted journeys against a **live worker** or an in-process **headless** session.
|
||||||
|
|
||||||
|
**Phase 787 (v0.8.754):** `runGuildMeshMemberRolesJourney` (2-peer custom role assign). Bundle: `npm run test:ci-phase787`.
|
||||||
|
|
||||||
**Phase 786 (v0.8.753):** `runGuildMeshTypingJourney` (2-peer typing gossip). Bundle: `npm run test:ci-phase786`.
|
**Phase 786 (v0.8.753):** `runGuildMeshTypingJourney` (2-peer typing gossip). Bundle: `npm run test:ci-phase786`.
|
||||||
|
|
||||||
**Phase 785 (v0.8.752):** `runGuildMeshVoiceOccupancyJourney` (2-peer voice occupancy). Bundle: `npm run test:ci-phase785`.
|
**Phase 785 (v0.8.752):** `runGuildMeshVoiceOccupancyJourney` (2-peer voice occupancy). Bundle: `npm run test:ci-phase785`.
|
||||||
|
|||||||
@@ -83,6 +83,17 @@ function matchView (view, spec) {
|
|||||||
if (!(view?.typingUsers || []).includes(uid)) return false
|
if (!(view?.typingUsers || []).includes(uid)) return false
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if (key === 'memberCustomRolesIncludes') {
|
||||||
|
const spec = expected && typeof expected === 'object' ? expected : {}
|
||||||
|
const mem = (view?.members || []).find((m) => m.userId === spec.userId)
|
||||||
|
const ids = (mem?.customRoleIds || []).map(String)
|
||||||
|
if (!ids.includes(String(spec.roleId || ''))) return false
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (key === 'guildCustomRolesMin') {
|
||||||
|
if ((view?.guildCustomRoles || []).length < Number(expected)) return false
|
||||||
|
continue
|
||||||
|
}
|
||||||
if (key === 'voiceChannelPeersMin') {
|
if (key === 'voiceChannelPeersMin') {
|
||||||
const spec = expected && typeof expected === 'object' ? expected : {}
|
const spec = expected && typeof expected === 'object' ? expected : {}
|
||||||
const n = (view?.voiceStatesByChannel?.[spec.channelId] || []).length
|
const n = (view?.voiceStatesByChannel?.[spec.channelId] || []).length
|
||||||
|
|||||||
+44
@@ -4803,6 +4803,50 @@ class HeadlessSession {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Phase 787: 2-peer mesh — host assigns custom role; guest member list reflects role. */
|
||||||
|
async runGuildMeshMemberRolesJourney () {
|
||||||
|
const { connectGuildMeshPeers } = require('./mesh-helpers')
|
||||||
|
const base = path.join(os.tmpdir(), `pearcord-agentctl-roles787-${Date.now()}`)
|
||||||
|
const host = new HeadlessSession({ storagePath: path.join(base, 'host') })
|
||||||
|
const guest = new HeadlessSession({ storagePath: path.join(base, 'guest') })
|
||||||
|
await host.start()
|
||||||
|
await guest.start()
|
||||||
|
try {
|
||||||
|
await host.registerUser({ username: 'rlhost787', displayName: 'Roles Host 787' })
|
||||||
|
await host.createGuild({ name: 'Roles Mesh 787', publicListing: false })
|
||||||
|
await host.wait({ mode: 'guild' }, 45000)
|
||||||
|
const invite = await host.platform.createInvite().catch(() => null)
|
||||||
|
const code = invite?.shareCode || invite?.code
|
||||||
|
if (!code) throw new Error('host invite missing')
|
||||||
|
await guest.registerUser({ username: 'rlguest787', displayName: 'Roles Guest 787' })
|
||||||
|
await guest.ipc({ type: 'join-invite', code })
|
||||||
|
await guest.wait({ mode: 'guild' }, 45000)
|
||||||
|
await connectGuildMeshPeers(host.platform, guest.platform, 45000)
|
||||||
|
await new Promise((r) => setTimeout(r, 2000))
|
||||||
|
const guestUserId = (await guest.refreshView()).user?.id
|
||||||
|
if (!guestUserId) throw new Error('guest user id missing')
|
||||||
|
const role = await host.createGuildCustomRole('Mesh Role 787', {
|
||||||
|
color: '#5865f2'
|
||||||
|
})
|
||||||
|
if (!role?.id) throw new Error('role create failed')
|
||||||
|
await host.setMemberCustomRoles(guestUserId, [role.id])
|
||||||
|
await guest.wait(
|
||||||
|
{ memberCustomRolesIncludes: { userId: guestUserId, roleId: role.id } },
|
||||||
|
60000
|
||||||
|
)
|
||||||
|
const gv = await guest.refreshView()
|
||||||
|
return {
|
||||||
|
roleId: role.id,
|
||||||
|
guestUserId,
|
||||||
|
guestRoles:
|
||||||
|
(gv.members || []).find((m) => m.userId === guestUserId)?.customRoleIds || []
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
await host.close()
|
||||||
|
await guest.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Phase 785: 2-peer mesh — host in voice visible on guest voiceStatesByChannel. */
|
/** Phase 785: 2-peer mesh — host in voice visible on guest voiceStatesByChannel. */
|
||||||
async runGuildMeshVoiceOccupancyJourney () {
|
async runGuildMeshVoiceOccupancyJourney () {
|
||||||
const { connectGuildMeshPeers } = require('./mesh-helpers')
|
const { connectGuildMeshPeers } = require('./mesh-helpers')
|
||||||
|
|||||||
@@ -35,6 +35,10 @@ function snapshotWaitDiagnostics (view, match) {
|
|||||||
? (view?.voiceStatesByChannel?.[view.myVoiceChannelId] || []).length
|
? (view?.voiceStatesByChannel?.[view.myVoiceChannelId] || []).length
|
||||||
: 0,
|
: 0,
|
||||||
typingUserCount: view?.typingUsers?.length ?? 0,
|
typingUserCount: view?.typingUsers?.length ?? 0,
|
||||||
|
guildCustomRoleCount: view?.guildCustomRoles?.length ?? 0,
|
||||||
|
membersWithCustomRoles:
|
||||||
|
(view?.members || []).filter((m) => (m.customRoleIds || []).length > 0)
|
||||||
|
.length ?? 0,
|
||||||
sessionReady: !!view?.sessionReady,
|
sessionReady: !!view?.sessionReady,
|
||||||
workerPoll: view?.workerPoll || null,
|
workerPoll: view?.workerPoll || null,
|
||||||
viewBuildStats: view?.viewBuildStats || null
|
viewBuildStats: view?.viewBuildStats || null
|
||||||
|
|||||||
Reference in New Issue
Block a user