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,
|
mergeHookFailureDigests,
|
||||||
buildAutomationScheduleDashboard,
|
buildAutomationScheduleDashboard,
|
||||||
buildAutomationHealthDashboard,
|
buildAutomationHealthDashboard,
|
||||||
|
buildDigestRelayHandoff,
|
||||||
computeArchivePeerHealthScore,
|
computeArchivePeerHealthScore,
|
||||||
computeArchiveFetchBackoffMs,
|
computeArchiveFetchBackoffMs,
|
||||||
HookFailureAlertStore
|
HookFailureAlertStore
|
||||||
@@ -58,7 +59,8 @@ const {
|
|||||||
buildWorkerLaunchScript,
|
buildWorkerLaunchScript,
|
||||||
buildWorkerInstallPlan,
|
buildWorkerInstallPlan,
|
||||||
getWorkerTemplate,
|
getWorkerTemplate,
|
||||||
WorkerReleaseHintStore
|
WorkerReleaseHintStore,
|
||||||
|
validateWorkerReleaseVersion
|
||||||
} = require('pearcord-integration-worker')
|
} = require('pearcord-integration-worker')
|
||||||
const { PearcordIntegrationWorker } = require('./integration-worker')
|
const { PearcordIntegrationWorker } = require('./integration-worker')
|
||||||
const { ACTION_TYPE_LIST, CATEGORY_OPTIONS } = require('pearcord-automation-export')
|
const { ACTION_TYPE_LIST, CATEGORY_OPTIONS } = require('pearcord-automation-export')
|
||||||
@@ -1170,6 +1172,7 @@ class PearcordPlatform extends EventEmitter {
|
|||||||
automationDigestNotifyPrefs =
|
automationDigestNotifyPrefs =
|
||||||
await this.deliveryReceipts.exportAutomationDigestNotifyPrefsSlice()
|
await this.deliveryReceipts.exportAutomationDigestNotifyPrefsSlice()
|
||||||
}
|
}
|
||||||
|
let digestRelayHandoff = null
|
||||||
const auditRecent = await this._exportAuditSyncSlice(guild.id)
|
const auditRecent = await this._exportAuditSyncSlice(guild.id)
|
||||||
let auditExportSchedule = null
|
let auditExportSchedule = null
|
||||||
let digestExportSchedule = null
|
let digestExportSchedule = null
|
||||||
@@ -1188,6 +1191,7 @@ class PearcordPlatform extends EventEmitter {
|
|||||||
await this.deliveryReceipts.exportAutomationDigestExportSnapshotsSlice(2)
|
await this.deliveryReceipts.exportAutomationDigestExportSnapshotsSlice(2)
|
||||||
auditExportArchives = await this.deliveryReceipts.exportAuditExportArchivesSlice(3)
|
auditExportArchives = await this.deliveryReceipts.exportAuditExportArchivesSlice(3)
|
||||||
archivePeerSeen = await this.deliveryReceipts.exportArchivePeerSeenSlice(16)
|
archivePeerSeen = await this.deliveryReceipts.exportArchivePeerSeenSlice(16)
|
||||||
|
digestRelayHandoff = await this.deliveryReceipts.exportDigestRelayHandoffSlice()
|
||||||
const digestSnap = await this.deliveryReceipts.getHookFailureDigestSnapshot()
|
const digestSnap = await this.deliveryReceipts.getHookFailureDigestSnapshot()
|
||||||
if (digestSnap) {
|
if (digestSnap) {
|
||||||
hookFailureDigest = {
|
hookFailureDigest = {
|
||||||
@@ -1244,6 +1248,7 @@ class PearcordPlatform extends EventEmitter {
|
|||||||
receiptRetention,
|
receiptRetention,
|
||||||
hookFailurePrefs,
|
hookFailurePrefs,
|
||||||
automationDigestNotifyPrefs,
|
automationDigestNotifyPrefs,
|
||||||
|
digestRelayHandoff,
|
||||||
auditRecent,
|
auditRecent,
|
||||||
auditExportSchedule,
|
auditExportSchedule,
|
||||||
digestExportSchedule,
|
digestExportSchedule,
|
||||||
@@ -1353,6 +1358,13 @@ class PearcordPlatform extends EventEmitter {
|
|||||||
payload.automationDigestNotifyPrefs
|
payload.automationDigestNotifyPrefs
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
if (payload.digestRelayHandoff) {
|
||||||
|
await this._initDeliveryReceipts(payload.guildId)
|
||||||
|
await this.deliveryReceipts.ingestDigestRelayHandoffSlice(
|
||||||
|
payload.guildId,
|
||||||
|
payload.digestRelayHandoff
|
||||||
|
)
|
||||||
|
}
|
||||||
if (payload.auditExportSchedule) {
|
if (payload.auditExportSchedule) {
|
||||||
await this._initDeliveryReceipts(payload.guildId)
|
await this._initDeliveryReceipts(payload.guildId)
|
||||||
await this.deliveryReceipts.ingestAuditExportScheduleSlice(
|
await this.deliveryReceipts.ingestAuditExportScheduleSlice(
|
||||||
@@ -2610,6 +2622,7 @@ class PearcordPlatform extends EventEmitter {
|
|||||||
deliveryMetrics = null
|
deliveryMetrics = null
|
||||||
}
|
}
|
||||||
const automationDigestNotifyPrefs = await this.getAutomationDigestNotifyPrefs()
|
const automationDigestNotifyPrefs = await this.getAutomationDigestNotifyPrefs()
|
||||||
|
const digestRelayHandoff = await this.getLastDigestRelayHandoff()
|
||||||
return buildAutomationHealthDashboard({
|
return buildAutomationHealthDashboard({
|
||||||
auditExportSchedule,
|
auditExportSchedule,
|
||||||
digestExportSchedule,
|
digestExportSchedule,
|
||||||
@@ -2618,13 +2631,27 @@ class PearcordPlatform extends EventEmitter {
|
|||||||
archiveFetchPeers,
|
archiveFetchPeers,
|
||||||
workerReleaseHint,
|
workerReleaseHint,
|
||||||
deliveryMetrics,
|
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 () {
|
async getAutomationDigestNotifyPrefs () {
|
||||||
if (!this.guild?.guild) {
|
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)
|
await this._initDeliveryReceipts(this.guild.guild.id)
|
||||||
const userId = this.identity.user?.id
|
const userId = this.identity.user?.id
|
||||||
@@ -2636,7 +2663,9 @@ class PearcordPlatform extends EventEmitter {
|
|||||||
notifyOnExport: guild.notifyOnExport !== false,
|
notifyOnExport: guild.notifyOnExport !== false,
|
||||||
guildMute: !!guild.muteNotifications,
|
guildMute: !!guild.muteNotifications,
|
||||||
userMute,
|
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) {
|
if (partial.muteNotifications != null) {
|
||||||
patch.muteNotifications = !!partial.muteNotifications
|
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)
|
await this.deliveryReceipts.setAutomationDigestNotifyPrefs(patch)
|
||||||
setTimeout(() => this._pushGuildSyncToMesh().catch(() => {}), 400)
|
setTimeout(() => this._pushGuildSyncToMesh().catch(() => {}), 400)
|
||||||
} else {
|
} else {
|
||||||
@@ -2733,10 +2768,59 @@ class PearcordPlatform extends EventEmitter {
|
|||||||
}
|
}
|
||||||
await this._notifyAutomationDigestExport({ exported, snap }).catch(() => {})
|
await this._notifyAutomationDigestExport({ exported, snap }).catch(() => {})
|
||||||
await this._fanoutAutomationDigestExportEvent({ 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)
|
setTimeout(() => this._pushGuildSyncToMesh().catch(() => {}), 400)
|
||||||
return { ...exported, snapshotId: snap?.id || null }
|
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 } = {}) {
|
async _notifyAutomationDigestExport ({ exported, snap } = {}) {
|
||||||
if (!this.notifications || !this.identity.user || !this.guild?.guild) return null
|
if (!this.notifications || !this.identity.user || !this.guild?.guild) return null
|
||||||
const roles = await this._memberRoles()
|
const roles = await this._memberRoles()
|
||||||
@@ -5549,13 +5633,20 @@ class PearcordPlatform extends EventEmitter {
|
|||||||
return this.workerReleaseHints.buildViewHint(this.guild.guild.id, this.appVersion)
|
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')
|
if (!this.guild?.guild) throw new Error('no guild')
|
||||||
const roles = await this._memberRoles()
|
const roles = await this._memberRoles()
|
||||||
if (!roleHasPermission(roles, PERMISSION.MANAGE_GUILD)) {
|
if (!roleHasPermission(roles, PERMISSION.MANAGE_GUILD)) {
|
||||||
throw new Error('no permission to announce worker release')
|
throw new Error('no permission to announce worker release')
|
||||||
}
|
}
|
||||||
const version = workerVersion || this.appVersion
|
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()
|
await this._initWorkerReleaseHints()
|
||||||
const row = await this.workerReleaseHints.setHint({
|
const row = await this.workerReleaseHints.setHint({
|
||||||
guildId: this.guild.guild.id,
|
guildId: this.guild.guild.id,
|
||||||
@@ -7082,6 +7173,7 @@ class PearcordPlatform extends EventEmitter {
|
|||||||
let automationScheduleDashboard = null
|
let automationScheduleDashboard = null
|
||||||
let automationHealthDashboard = null
|
let automationHealthDashboard = null
|
||||||
let automationDigestNotifyPrefs = null
|
let automationDigestNotifyPrefs = null
|
||||||
|
let digestRelayHandoff = null
|
||||||
let auditArchiveFetchPeers = null
|
let auditArchiveFetchPeers = null
|
||||||
let workerReleaseHint = null
|
let workerReleaseHint = null
|
||||||
let workerInstallPlan = null
|
let workerInstallPlan = null
|
||||||
@@ -7095,6 +7187,7 @@ class PearcordPlatform extends EventEmitter {
|
|||||||
automationHealthDashboard = await this.getAutomationHealthDashboard()
|
automationHealthDashboard = await this.getAutomationHealthDashboard()
|
||||||
automationScheduleDashboard = automationHealthDashboard
|
automationScheduleDashboard = automationHealthDashboard
|
||||||
automationDigestNotifyPrefs = await this.getAutomationDigestNotifyPrefs()
|
automationDigestNotifyPrefs = await this.getAutomationDigestNotifyPrefs()
|
||||||
|
digestRelayHandoff = await this.getLastDigestRelayHandoff()
|
||||||
auditArchiveFetchPeers = await this.listAuditArchiveFetchPeers()
|
auditArchiveFetchPeers = await this.listAuditArchiveFetchPeers()
|
||||||
workerReleaseHint = await this.getWorkerReleaseHint()
|
workerReleaseHint = await this.getWorkerReleaseHint()
|
||||||
this._lastWorkerReleaseHintView = workerReleaseHint
|
this._lastWorkerReleaseHintView = workerReleaseHint
|
||||||
@@ -7273,6 +7366,7 @@ class PearcordPlatform extends EventEmitter {
|
|||||||
automationScheduleDashboard,
|
automationScheduleDashboard,
|
||||||
automationHealthDashboard,
|
automationHealthDashboard,
|
||||||
automationDigestNotifyPrefs,
|
automationDigestNotifyPrefs,
|
||||||
|
digestRelayHandoff,
|
||||||
auditArchiveFetchPeers,
|
auditArchiveFetchPeers,
|
||||||
workerReleaseHint,
|
workerReleaseHint,
|
||||||
workerInstallPlan,
|
workerInstallPlan,
|
||||||
|
|||||||
Reference in New Issue
Block a user