feat: operator command channel via Nostr (manual dispense)
Add a Nostr-native operator command channel using Kind 21003 (CLINK Manage) events. Operators listed in OPERATOR_PUBKEYS can send encrypted commands to the machine. Phase 1 implements manual dispense: operator sends a dispense command, machine verifies sender, checks it's idle, performs a direct HAL dispense (bypassing state machine), and records the transaction. When ref_txid is provided, the referenced failed transaction is updated to status 'remediated', closing the loop on dispense errors. Changes: - CLINK types: add 'machine' resource, MachineDispenseRequest type - CLINK client: support operator pubkey list (string | string[]) - Runtime config: VITE_OPERATOR_PUBKEYS env var - Schema v4→v5: manual_dispense type, remediated_by column - Lightning services: wire onManagement callback - ATM store: handleManagementCommand with idle check + remediation Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
88a52cf769
commit
e03782803b
11 changed files with 274 additions and 24 deletions
|
|
@ -17,6 +17,7 @@ import {
|
|||
setCassettes,
|
||||
getInventory,
|
||||
recordTransaction,
|
||||
remediateTransaction,
|
||||
emptyCashbox,
|
||||
getCashbox,
|
||||
} from './state-store.js'
|
||||
|
|
@ -180,6 +181,9 @@ ipcMain.handle('get-config', () => {
|
|||
// SECURITY: In production (packaged app), mock fallback is always disabled.
|
||||
// Only allow it in development mode, and only when explicitly opted in via env.
|
||||
allowMockFallback: isDev && process.env.VITE_ALLOW_MOCK_FALLBACK === 'true',
|
||||
|
||||
// Operator identity (comma-separated hex pubkeys)
|
||||
operatorPubkeys: process.env.VITE_OPERATOR_PUBKEYS || '',
|
||||
}
|
||||
})
|
||||
|
||||
|
|
@ -213,6 +217,9 @@ ipcMain.handle('state:get-inventory', () => getInventory())
|
|||
ipcMain.handle('state:get-cashbox', () => getCashbox())
|
||||
ipcMain.handle('state:record-transaction', (_event, tx) => recordTransaction(tx))
|
||||
ipcMain.handle('state:empty-cashbox', () => emptyCashbox())
|
||||
ipcMain.handle('state:remediate-transaction', (_event, txid: string, remediatedByTxid: string) =>
|
||||
remediateTransaction(txid, remediatedByTxid)
|
||||
)
|
||||
|
||||
// =============================================================================
|
||||
// HAL Hardware IPC Handlers
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue