feat(platform): digest relay, inbox channel post, worker semver gate
Record digest relay handoffs, post digest summaries to configured inbox channels, validate worker versions on announce, sync digestRelayHandoff on GUILD_SYNC, and expose getLastDigestRelayHandoff (Phase 109 v0.8.73). Co-authored-by: Cursor <[email protected]>
This commit is contained in:
@@ -49,6 +49,7 @@ const {
|
||||
mergeHookFailureDigests,
|
||||
buildAutomationScheduleDashboard,
|
||||
buildAutomationHealthDashboard,
|
||||
buildDigestRelayHandoff,
|
||||
computeArchivePeerHealthScore,
|
||||
computeArchiveFetchBackoffMs,
|
||||
HookFailureAlertStore
|
||||
@@ -58,7 +59,8 @@ const {
|
||||
buildWorkerLaunchScript,
|
||||
buildWorkerInstallPlan,
|
||||
getWorkerTemplate,
|
||||
WorkerReleaseHintStore
|
||||
WorkerReleaseHintStore,
|
||||
validateWorkerReleaseVersion
|
||||
} = require('pearcord-integration-worker')
|
||||
const { PearcordIntegrationWorker } = require('./integration-worker')
|
||||
const { ACTION_TYPE_LIST, CATEGORY_OPTIONS } = require('pearcord-automation-export')
|
||||
@@ -1170,6 +1172,7 @@ class PearcordPlatform extends EventEmitter {
|
||||
automationDigestNotifyPrefs =
|
||||
await this.deliveryReceipts.exportAutomationDigestNotifyPrefsSlice()
|
||||
}
|
||||
let digestRelayHandoff = null
|
||||
const auditRecent = await this._exportAuditSyncSlice(guild.id)
|
||||
let auditExportSchedule = null
|
||||
let digestExportSchedule = null
|
||||
@@ -1188,6 +1191,7 @@ class PearcordPlatform extends EventEmitter {
|
||||
await this.deliveryReceipts.exportAutomationDigestExportSnapshotsSlice(2)
|
||||
auditExportArchives = await this.deliveryReceipts.exportAuditExportArchivesSlice(3)
|
||||
archivePeerSeen = await this.deliveryReceipts.exportArchivePeerSeenSlice(16)
|
||||
digestRelayHandoff = await this.deliveryReceipts.exportDigestRelayHandoffSlice()
|
||||
const digestSnap = await this.deliveryReceipts.getHookFailureDigestSnapshot()
|
||||
if (digestSnap) {
|
||||
hookFailureDigest = {
|
||||
@@ -1244,6 +1248,7 @@ class PearcordPlatform extends EventEmitter {
|
||||
receiptRetention,
|
||||
hookFailurePrefs,
|
||||
automationDigestNotifyPrefs,
|
||||
digestRelayHandoff,
|
||||
auditRecent,
|
||||
auditExportSchedule,
|
||||
digestExportSchedule,
|
||||
@@ -1353,6 +1358,13 @@ class PearcordPlatform extends EventEmitter {
|
||||
payload.automationDigestNotifyPrefs
|
||||
)
|
||||
}
|
||||
if (payload.digestRelayHandoff) {
|
||||
await this._initDeliveryReceipts(payload.guildId)
|
||||
await this.deliveryReceipts.ingestDigestRelayHandoffSlice(
|
||||
payload.guildId,
|
||||
payload.digestRelayHandoff
|
||||
)
|
||||
}
|
||||
if (payload.auditExportSchedule) {
|
||||
await this._initDeliveryReceipts(payload.guildId)
|
||||
await this.deliveryReceipts.ingestAuditExportScheduleSlice(
|
||||
@@ -2610,6 +2622,7 @@ class PearcordPlatform extends EventEmitter {
|
||||
deliveryMetrics = null
|
||||
}
|
||||
const automationDigestNotifyPrefs = await this.getAutomationDigestNotifyPrefs()
|
||||
const digestRelayHandoff = await this.getLastDigestRelayHandoff()
|
||||
return buildAutomationHealthDashboard({
|
||||
auditExportSchedule,
|
||||
digestExportSchedule,
|
||||
@@ -2618,13 +2631,27 @@ class PearcordPlatform extends EventEmitter {
|
||||
archiveFetchPeers,
|
||||
workerReleaseHint,
|
||||
deliveryMetrics,
|
||||
automationDigestNotifyPrefs
|
||||
automationDigestNotifyPrefs,
|
||||
digestRelayHandoff
|
||||
})
|
||||
}
|
||||
|
||||
async getLastDigestRelayHandoff () {
|
||||
if (!this.guild?.guild) return null
|
||||
await this._initDeliveryReceipts(this.guild.guild.id)
|
||||
return this.deliveryReceipts.getLastDigestRelayHandoff()
|
||||
}
|
||||
|
||||
async getAutomationDigestNotifyPrefs () {
|
||||
if (!this.guild?.guild) {
|
||||
return { notifyOnExport: true, userMute: false, guildMute: false, muteNotifications: false }
|
||||
return {
|
||||
notifyOnExport: true,
|
||||
userMute: false,
|
||||
guildMute: false,
|
||||
muteNotifications: false,
|
||||
digestInboxChannelId: null,
|
||||
digestRelayEnabled: false
|
||||
}
|
||||
}
|
||||
await this._initDeliveryReceipts(this.guild.guild.id)
|
||||
const userId = this.identity.user?.id
|
||||
@@ -2636,7 +2663,9 @@ class PearcordPlatform extends EventEmitter {
|
||||
notifyOnExport: guild.notifyOnExport !== false,
|
||||
guildMute: !!guild.muteNotifications,
|
||||
userMute,
|
||||
muteNotifications: !!guild.muteNotifications || userMute
|
||||
muteNotifications: !!guild.muteNotifications || userMute,
|
||||
digestInboxChannelId: guild.digestInboxChannelId || null,
|
||||
digestRelayEnabled: !!guild.digestRelayEnabled
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2656,6 +2685,12 @@ class PearcordPlatform extends EventEmitter {
|
||||
if (partial.muteNotifications != null) {
|
||||
patch.muteNotifications = !!partial.muteNotifications
|
||||
}
|
||||
if (partial.digestInboxChannelId !== undefined) {
|
||||
patch.digestInboxChannelId = partial.digestInboxChannelId || null
|
||||
}
|
||||
if (partial.digestRelayEnabled != null) {
|
||||
patch.digestRelayEnabled = !!partial.digestRelayEnabled
|
||||
}
|
||||
await this.deliveryReceipts.setAutomationDigestNotifyPrefs(patch)
|
||||
setTimeout(() => this._pushGuildSyncToMesh().catch(() => {}), 400)
|
||||
} else {
|
||||
@@ -2733,10 +2768,59 @@ class PearcordPlatform extends EventEmitter {
|
||||
}
|
||||
await this._notifyAutomationDigestExport({ exported, snap }).catch(() => {})
|
||||
await this._fanoutAutomationDigestExportEvent({ exported, snap }).catch(() => {})
|
||||
await this._recordDigestRelayHandoff({ exported, snap }).catch(() => {})
|
||||
await this._postDigestToInboxChannel({ exported, snap }).catch(() => {})
|
||||
setTimeout(() => this._pushGuildSyncToMesh().catch(() => {}), 400)
|
||||
return { ...exported, snapshotId: snap?.id || null }
|
||||
}
|
||||
|
||||
async _recordDigestRelayHandoff ({ exported, snap } = {}) {
|
||||
if (!this.guild?.guild) return null
|
||||
await this._initDeliveryReceipts(this.guild.guild.id)
|
||||
const prefs = await this.deliveryReceipts.getAutomationDigestNotifyPrefs()
|
||||
if (!prefs.digestRelayEnabled) return null
|
||||
const handoff = buildDigestRelayHandoff({
|
||||
guildId: this.guild.guild.id,
|
||||
guildName: this.guild.guild.name,
|
||||
exported,
|
||||
snapshot: snap
|
||||
})
|
||||
await this.deliveryReceipts.appendDigestRelayHandoff(handoff)
|
||||
this.emit('digest-relay-handoff', handoff)
|
||||
return handoff
|
||||
}
|
||||
|
||||
async _postDigestToInboxChannel ({ exported, snap } = {}) {
|
||||
if (!this.guild?.guild || !this.messages) return null
|
||||
const roles = await this._memberRoles()
|
||||
if (!roleHasPermission(roles, PERMISSION.MANAGE_GUILD)) return null
|
||||
await this._initDeliveryReceipts(this.guild.guild.id)
|
||||
const prefs = await this.deliveryReceipts.getAutomationDigestNotifyPrefs()
|
||||
const channelId = prefs.digestInboxChannelId
|
||||
if (!channelId) return null
|
||||
const ch = await this.db.get(COLLECTIONS.CHANNELS, {
|
||||
id: channelId,
|
||||
guildId: this.guild.guild.id
|
||||
})
|
||||
if (!ch || (ch.type !== 'text' && ch.type !== 'announcement')) return null
|
||||
const preview = String(exported.body || '').slice(0, 1600)
|
||||
const lines = [
|
||||
'**📋 Automation schedule digest export**',
|
||||
`Format: \`${exported.format || 'text'}\` · ${snap?.summaryLines || 0} lines`,
|
||||
'',
|
||||
preview,
|
||||
preview.length < (exported.body?.length || 0) ? '\n_(truncated — fetch full snapshot from mesh)_' : ''
|
||||
]
|
||||
const prev = this.activeChannelId
|
||||
await this.selectChannel(channelId)
|
||||
try {
|
||||
const msg = await this.sendMessage(lines.join('\n'))
|
||||
return msg
|
||||
} finally {
|
||||
if (prev) await this.selectChannel(prev)
|
||||
}
|
||||
}
|
||||
|
||||
async _notifyAutomationDigestExport ({ exported, snap } = {}) {
|
||||
if (!this.notifications || !this.identity.user || !this.guild?.guild) return null
|
||||
const roles = await this._memberRoles()
|
||||
@@ -5549,13 +5633,20 @@ class PearcordPlatform extends EventEmitter {
|
||||
return this.workerReleaseHints.buildViewHint(this.guild.guild.id, this.appVersion)
|
||||
}
|
||||
|
||||
async announceWorkerRelease ({ workerVersion, pearUri, releaseNotes } = {}) {
|
||||
async announceWorkerRelease ({ workerVersion, pearUri, releaseNotes, allowDowngrade } = {}) {
|
||||
if (!this.guild?.guild) throw new Error('no guild')
|
||||
const roles = await this._memberRoles()
|
||||
if (!roleHasPermission(roles, PERMISSION.MANAGE_GUILD)) {
|
||||
throw new Error('no permission to announce worker release')
|
||||
}
|
||||
const version = workerVersion || this.appVersion
|
||||
const check = validateWorkerReleaseVersion(this.appVersion, version, {
|
||||
allowDowngrade: !!allowDowngrade,
|
||||
allowSame: false
|
||||
})
|
||||
if (!check.ok) {
|
||||
throw new Error(check.message || 'invalid worker release version')
|
||||
}
|
||||
await this._initWorkerReleaseHints()
|
||||
const row = await this.workerReleaseHints.setHint({
|
||||
guildId: this.guild.guild.id,
|
||||
@@ -7082,6 +7173,7 @@ class PearcordPlatform extends EventEmitter {
|
||||
let automationScheduleDashboard = null
|
||||
let automationHealthDashboard = null
|
||||
let automationDigestNotifyPrefs = null
|
||||
let digestRelayHandoff = null
|
||||
let auditArchiveFetchPeers = null
|
||||
let workerReleaseHint = null
|
||||
let workerInstallPlan = null
|
||||
@@ -7095,6 +7187,7 @@ class PearcordPlatform extends EventEmitter {
|
||||
automationHealthDashboard = await this.getAutomationHealthDashboard()
|
||||
automationScheduleDashboard = automationHealthDashboard
|
||||
automationDigestNotifyPrefs = await this.getAutomationDigestNotifyPrefs()
|
||||
digestRelayHandoff = await this.getLastDigestRelayHandoff()
|
||||
auditArchiveFetchPeers = await this.listAuditArchiveFetchPeers()
|
||||
workerReleaseHint = await this.getWorkerReleaseHint()
|
||||
this._lastWorkerReleaseHintView = workerReleaseHint
|
||||
@@ -7273,6 +7366,7 @@ class PearcordPlatform extends EventEmitter {
|
||||
automationScheduleDashboard,
|
||||
automationHealthDashboard,
|
||||
automationDigestNotifyPrefs,
|
||||
digestRelayHandoff,
|
||||
auditArchiveFetchPeers,
|
||||
workerReleaseHint,
|
||||
workerInstallPlan,
|
||||
|
||||
Reference in New Issue
Block a user