feat(agentctl): DM friend-open and group-rename headless journeys (Phase 655)

Add runDmFriendOpenComposerFocusJourney and runGroupDmRenameJourney for
autonomous inbox regression alongside existing sidebar search journey.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Raven Scott
2026-06-02 00:25:18 -04:00
co-authored by Cursor
parent a053929245
commit a2728309dd
2 changed files with 32 additions and 2 deletions
+2 -2
View File
@@ -2,9 +2,9 @@
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 655 (v0.8.627):** Headless `runDmSidebarSearchJourney(peerUserId, peerDisplayName)` — open DM, send marker, assert preview. Smoke: `npm run test:agentctl-dm-sidebar-phase655` (app repo). **Phase 655 (v0.8.628):** Headless `runDmFriendOpenComposerFocusJourney`, `runGroupDmRenameJourney`; smokes `test:agentctl-dm-friend-focus-phase655`, `test:agentctl-group-rename-phase655`. Prior: `runDmSidebarSearchJourney` (v0.8.627).
**Phase 654 (current, 50 swarm/repl/sync items active):** Primary autonomous testing vehicle per core rules. Manual (non-automated) runs of headless scenarios + mesh smokes used to verify composer autofocus/send button/grow + swarm retry changes (adaptive + discovery aid). Extended journeys for global resilience soaks (12-peer, heal under churn, CRDT coverage). Direct bin requires app cwd for bare resolution (smokes succeed). See PLATFORM_ROADMAP.md P654 items + AGENTCTL.md. **Phase 654 (50 swarm/repl/sync items):** Primary autonomous testing vehicle per core rules.
## Mission ## Mission
+30
View File
@@ -663,6 +663,36 @@ class HeadlessSession {
return { channelId: v2.activeChannelId, preview: row.lastMessagePreview } return { channelId: v2.activeChannelId, preview: row.lastMessagePreview }
} }
/** Phase 655: friend-open path sets dm mode + active channel (composer focus via ui-flow). */
async runDmFriendOpenComposerFocusJourney (peerUserId, peerDisplayName) {
if (!this.platform) throw new Error('headless not started')
await this.openDmWithPeer(peerUserId, peerDisplayName)
const v = await this.refreshView()
if (v.mode !== 'dm') throw new Error('expected dm mode after friend open')
if (!v.activeChannelId) throw new Error('expected activeChannelId for composer focus path')
if (v.dmPeer !== peerUserId) {
throw new Error(`expected dmPeer ${peerUserId}, got ${v.dmPeer}`)
}
return { channelId: v.activeChannelId, dmPeer: v.dmPeer }
}
/** Phase 655: create group, rename, assert title in view. */
async runGroupDmRenameJourney (peerUserIds, initialName, nextName) {
if (!this.platform) throw new Error('headless not started')
const channel = await this.createGroupDm(peerUserIds, initialName)
if (!channel?.id) throw new Error('expected group channel id')
await this.platform.renameGroupDM({
channelId: channel.id,
displayName: nextName
})
const v = await this.refreshView()
if (v.mode !== 'dm' || !v.dmIsGroup) throw new Error('expected group dm mode')
if (v.dmTitle !== nextName) {
throw new Error(`expected dmTitle ${nextName}, got ${v.dmTitle}`)
}
return { channelId: channel.id, dmTitle: v.dmTitle }
}
async exportGuildAuditLog (opts = {}) { async exportGuildAuditLog (opts = {}) {
if (!this.platform) throw new Error('headless not started') if (!this.platform) throw new Error('headless not started')
const out = await this.platform.exportAuditLog(opts) const out = await this.platform.exportAuditLog(opts)