mirror of
https://github.com/stablyai/orca.git
synced 2026-10-30 16:47:34 +00:00
feat(push): carry a notification's workspace server to the phone (#26516)
A desktop relays alerts for agents on its paired servers, but the push named only the server's worktree, so a tap opened it on the desktop and bounced. The gateway accepts an optional runtime execution host and forwards it. Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
This commit is contained in:
@@ -6,6 +6,7 @@ export type PushOrcaData = {
|
||||
hostFingerprint: string
|
||||
worktreeId?: string
|
||||
paneKey?: string
|
||||
executionHost?: string
|
||||
notificationId?: string
|
||||
notificationSeq: number
|
||||
notificationEpoch: string
|
||||
@@ -54,6 +55,9 @@ export function buildPushDelivery(input: {
|
||||
hostFingerprint,
|
||||
...(notification.paneKey === undefined ? {} : { paneKey: notification.paneKey }),
|
||||
...(notification.worktreeId === undefined ? {} : { worktreeId: notification.worktreeId }),
|
||||
...(notification.executionHost === undefined
|
||||
? {}
|
||||
: { executionHost: notification.executionHost }),
|
||||
...(notification.notificationId === undefined
|
||||
? {}
|
||||
: { notificationId: notification.notificationId }),
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import { expect, it } from 'vitest'
|
||||
import { PushNotificationSchema } from '@orca-cloud/push-contract'
|
||||
import { buildPushDelivery, orcaDataStrings } from './push-delivery-message.js'
|
||||
|
||||
const base = {
|
||||
notificationSeq: 1,
|
||||
notificationEpoch: 'epoch',
|
||||
source: 'agent-task-complete',
|
||||
agentState: 'finished',
|
||||
title: 'Done',
|
||||
body: '',
|
||||
worktreeId: 'repo-1::/srv/work'
|
||||
}
|
||||
|
||||
it('carries the workspace server to APNs and FCM, and accepts older messages without one', () => {
|
||||
const executionHost = 'runtime:env%201'
|
||||
for (const extra of [{}, { executionHost }]) {
|
||||
const delivery = buildPushDelivery({
|
||||
notification: PushNotificationSchema.parse({ ...base, ...extra }),
|
||||
hostFingerprint: 'host',
|
||||
registrationId: 'phone',
|
||||
expiresAt: Date.now() + 300000
|
||||
})
|
||||
const expected = 'executionHost' in extra ? executionHost : undefined
|
||||
expect(delivery.orca.executionHost).toBe(expected)
|
||||
expect(orcaDataStrings(delivery.orca).executionHost).toBe(expected)
|
||||
}
|
||||
})
|
||||
|
||||
it('accepts only runtime execution hosts', () => {
|
||||
const invalid = ['local', 'ssh:box', 'runtime:', 'runtime:a|b', `runtime:${'x'.repeat(2048)}`]
|
||||
for (const executionHost of invalid) {
|
||||
expect(PushNotificationSchema.safeParse({ ...base, executionHost }).success).toBe(false)
|
||||
}
|
||||
})
|
||||
@@ -27,7 +27,13 @@ export const PushNotificationSchema = z
|
||||
title: z.string().min(1).max(PUSH_LIMITS.titleMaxChars),
|
||||
body: z.string().max(PUSH_LIMITS.bodyMaxChars),
|
||||
worktreeId: z.string().min(1).max(2048).optional(),
|
||||
paneKey: z.string().min(1).max(2048).optional()
|
||||
paneKey: z.string().min(1).max(2048).optional(),
|
||||
// The workspace's server; mirrors the app's runtime host id (cannot import src/shared).
|
||||
executionHost: z
|
||||
.string()
|
||||
.max(2048)
|
||||
.regex(/^runtime:[^|\s]+$/)
|
||||
.optional()
|
||||
})
|
||||
.strict()
|
||||
.refine(
|
||||
|
||||
Reference in New Issue
Block a user