feat(platform): Phase 491 automation span metadata (v0.8.454)
Add automation.hook, automation.manifest, and automation.hook.dryRun spans. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
@@ -39,6 +39,8 @@ Expose a single `EventEmitter` API the UI drives over IPC (`apps/pearcord/index.
|
||||
|
||||
**v0.8.430 (Phase 467):** `voice.leave` span `end` includes `leavingIsStage`; `screen.start` span `end` includes `label`. Bundle: `npm run test:phase467-voice-stage`. See [VOICE.md](../../docs/VOICE.md), [STAGE_CHANNELS.md](../../docs/STAGE_CHANNELS.md).
|
||||
|
||||
**v0.8.454 (Phase 491):** `automation.hook` / `automation.manifest` / `automation.hook.dryRun` spans + errors. UI automation compositor + hints. Bundle: `npm run test:phase491-automation`. See [AUTOMATION_EXPORT.md](../../docs/AUTOMATION_EXPORT.md).
|
||||
|
||||
**v0.8.453 (Phase 490):** `bot.token`/`bot.verify`/`bot.install`/`bot.message` span metadata extend. UI bot compositor + hints. Bundle: `npm run test:phase490-bots`. See [BOTS.md](../../docs/BOTS.md).
|
||||
|
||||
**v0.8.452 (Phase 489):** `slash.register` `customCount`; `slash.delete` `deleted`; `slash.invoke` `replyLen`/`commandFound`. UI slash compositor + hints. Bundle: `npm run test:phase489-slash`. See [SLASH_COMMANDS.md](../../docs/SLASH_COMMANDS.md).
|
||||
|
||||
@@ -6093,12 +6093,15 @@ class PearcordPlatform extends EventEmitter {
|
||||
}
|
||||
|
||||
async dryRunAutomationHook (hookId, eventType) {
|
||||
if (!this.guild?.guild) throw new Error('no guild')
|
||||
await this._initAutomationExport(this.guild.guild.id)
|
||||
const hook = await this.automationExport.getHook(hookId)
|
||||
if (!hook) throw new Error('hook not found')
|
||||
const sample = buildSampleAppEvent(this.guild.guild.id, eventType)
|
||||
const result = dryRunHook(hook, sample)
|
||||
const guildId = this.guild?.guild?.id || null
|
||||
const span = this.log.time('automation.hook.dryRun', { guildId, hookId, eventType })
|
||||
try {
|
||||
if (!this.guild?.guild) throw new Error('no guild')
|
||||
await this._initAutomationExport(this.guild.guild.id)
|
||||
const hook = await this.automationExport.getHook(hookId)
|
||||
if (!hook) throw new Error('hook not found')
|
||||
const sample = buildSampleAppEvent(this.guild.guild.id, eventType)
|
||||
const result = dryRunHook(hook, sample)
|
||||
if (hook.action?.type === 'digest-relay' && result.matches) {
|
||||
const last = await this.getLastDigestRelayHandoff()
|
||||
if (last) result.relayPreview = { ...result.relayPreview, lastHandoff: last }
|
||||
@@ -6128,7 +6131,24 @@ class PearcordPlatform extends EventEmitter {
|
||||
})
|
||||
}
|
||||
}
|
||||
return { sample, result }
|
||||
span.end({
|
||||
guildId,
|
||||
hookId,
|
||||
eventType,
|
||||
matches: !!result.matches,
|
||||
actionType: hook.action?.type || null
|
||||
})
|
||||
return { sample, result }
|
||||
} catch (err) {
|
||||
this.log.error('automation.hook.dryRun error', {
|
||||
guildId,
|
||||
hookId,
|
||||
eventType,
|
||||
error: err?.message || String(err)
|
||||
})
|
||||
span.fail(err)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
async dryRunAllAutomationHooks (eventType) {
|
||||
@@ -8918,54 +8938,103 @@ class PearcordPlatform extends EventEmitter {
|
||||
}
|
||||
|
||||
async upsertAutomationHook (hook = {}) {
|
||||
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 manage automations')
|
||||
const guildId = this.guild?.guild?.id || null
|
||||
const span = this.log.time('automation.hook', { guildId })
|
||||
try {
|
||||
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 manage automations')
|
||||
}
|
||||
await this._initAutomationExport(this.guild.guild.id)
|
||||
const row = await this.automationExport.upsertHook(hook)
|
||||
this.emit('automation-hook', row)
|
||||
span.end({
|
||||
guildId,
|
||||
hookId: row.id,
|
||||
hookName: String(row.name || '').slice(0, 48),
|
||||
actionType: row.action?.type || null,
|
||||
enabled: row.enabled !== false
|
||||
})
|
||||
return row
|
||||
} catch (err) {
|
||||
this.log.error('automation.hook error', {
|
||||
guildId,
|
||||
error: err?.message || String(err)
|
||||
})
|
||||
span.fail(err)
|
||||
throw err
|
||||
}
|
||||
await this._initAutomationExport(this.guild.guild.id)
|
||||
const row = await this.automationExport.upsertHook(hook)
|
||||
this.emit('automation-hook', row)
|
||||
return row
|
||||
}
|
||||
|
||||
async deleteAutomationHook (hookId) {
|
||||
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 manage automations')
|
||||
const guildId = this.guild?.guild?.id || null
|
||||
const span = this.log.time('automation.hook', { guildId, hookId, op: 'delete' })
|
||||
try {
|
||||
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 manage automations')
|
||||
}
|
||||
await this._initAutomationExport(this.guild.guild.id)
|
||||
const ok = await this.automationExport.deleteHook(hookId)
|
||||
if (ok) this.emit('automation-hook-delete', { hookId, guildId: this.guild.guild.id })
|
||||
span.end({ guildId, hookId, deleted: !!ok })
|
||||
return ok
|
||||
} catch (err) {
|
||||
this.log.error('automation.hook error', {
|
||||
guildId,
|
||||
hookId,
|
||||
error: err?.message || String(err)
|
||||
})
|
||||
span.fail(err)
|
||||
throw err
|
||||
}
|
||||
await this._initAutomationExport(this.guild.guild.id)
|
||||
const ok = await this.automationExport.deleteHook(hookId)
|
||||
if (ok) this.emit('automation-hook-delete', { hookId, guildId: this.guild.guild.id })
|
||||
return ok
|
||||
}
|
||||
|
||||
async exportAutomationManifest () {
|
||||
if (!this.guild?.guild) throw new Error('no guild')
|
||||
const user = this.identity.user
|
||||
if (!user) throw new Error('register first')
|
||||
const roles = await this._memberRoles()
|
||||
if (!roleHasPermission(roles, PERMISSION.MANAGE_GUILD)) {
|
||||
throw new Error('no permission to export automations')
|
||||
const guildId = this.guild?.guild?.id || null
|
||||
const span = this.log.time('automation.manifest', { guildId })
|
||||
try {
|
||||
if (!this.guild?.guild) throw new Error('no guild')
|
||||
const user = this.identity.user
|
||||
if (!user) throw new Error('register first')
|
||||
const roles = await this._memberRoles()
|
||||
if (!roleHasPermission(roles, PERMISSION.MANAGE_GUILD)) {
|
||||
throw new Error('no permission to export automations')
|
||||
}
|
||||
await this._ensureGuildModules()
|
||||
await this._initAutomationExport(this.guild.guild.id)
|
||||
const guild = this.guild.guild
|
||||
const automodConfig = await this.automod.getConfig()
|
||||
const slashCommands = this.slashCommands ? await this.slashCommands.list() : []
|
||||
const bots = await this.db.find(COLLECTIONS.GUILD_BOTS, { guildId: guild.id })
|
||||
const hooks = await this.automationExport.listHooks()
|
||||
const manifest = buildAutomationManifest({
|
||||
guildId: guild.id,
|
||||
guildName: guild.name,
|
||||
exportedBy: user.id,
|
||||
automodConfig,
|
||||
slashCommands,
|
||||
bots,
|
||||
hooks,
|
||||
appEventCategories: APP_EVENT_CATEGORIES.ALL
|
||||
})
|
||||
span.end({
|
||||
guildId,
|
||||
hookCount: hooks.length,
|
||||
botCount: bots.length,
|
||||
slashCount: slashCommands.length
|
||||
})
|
||||
return manifest
|
||||
} catch (err) {
|
||||
this.log.error('automation.manifest error', {
|
||||
guildId,
|
||||
error: err?.message || String(err)
|
||||
})
|
||||
span.fail(err)
|
||||
throw err
|
||||
}
|
||||
await this._ensureGuildModules()
|
||||
await this._initAutomationExport(this.guild.guild.id)
|
||||
const guild = this.guild.guild
|
||||
const automodConfig = await this.automod.getConfig()
|
||||
const slashCommands = this.slashCommands ? await this.slashCommands.list() : []
|
||||
const bots = await this.db.find(COLLECTIONS.GUILD_BOTS, { guildId: guild.id })
|
||||
const hooks = await this.automationExport.listHooks()
|
||||
return buildAutomationManifest({
|
||||
guildId: guild.id,
|
||||
guildName: guild.name,
|
||||
exportedBy: user.id,
|
||||
automodConfig,
|
||||
slashCommands,
|
||||
bots,
|
||||
hooks,
|
||||
appEventCategories: APP_EVENT_CATEGORIES.ALL
|
||||
})
|
||||
}
|
||||
|
||||
async importAutomationManifest (manifest, opts = {}) {
|
||||
|
||||
Reference in New Issue
Block a user