/**
* pgh identity <subcommand>
*
* Subcommands:
* show — print root pubkey, device pubkey, chain depth, source
*
* Identity lives at ~/.hyperident/ and is loaded via hyper-identity. The
* `chain` field is the base64-encoded keet attestation proof; when
* present, the envelope verifier resolves signatures back to the root.
* When absent (legacy / raw fallback), pgh operates as a self-rooted
* anproto identity.
*/
import path from '#node:path'
import { homedir } from '#node:os'
import b4a from 'b4a'
import cenc from 'compact-encoding'
import { loadOrCreateIdentity } from '../identity.js'
const HYPERIDENT_HOME = path.join(homedir(), '.hyperident')
export const usage = `pgh identity — show this machine's identity
pgh identity show Root/device pubkey, chain depth, source
Identity lives at ~/.hyperident/ (loaded via hyper-identity).`
export async function run (_client, args, globals = {}) {
const sub = args[0] || 'show'
if (sub === 'show') return showIdentity(globals)
throw new Error('unknown identity subcommand: ' + sub + '\n' + usage)
}
async function showIdentity (globals) {
const identity = await loadOrCreateIdentity(HYPERIDENT_HOME)
// Decode chain depth directly via keet-identity-key's ProofEncoding.
// Kept out of identity.js so that module stays free of keet-identity-key.
let chainDepth = null
let chainValid = null
if (identity.chain) {
try {
const [{ ProofEncoding }, { default: IdentityKey }] = await Promise.all([
import('keet-identity-key/lib/encoding.js'),
import('keet-identity-key')
])
const proof = b4a.from(identity.chain, 'base64')
const decoded = cenc.decode(ProofEncoding, proof)
chainDepth = decoded.chain.length
chainValid = !!IdentityKey.verify(proof)
} catch {
// Leave chainDepth/chainValid at null — chain is present but we
// couldn't inspect it (old version skew, etc.)
}
}
const result = {
source: identity.source,
rootPubkey: identity.rootPubkeyHex || identity.publicKeyHex,
devicePubkey: identity.publicKeyHex,
chainPresent: !!identity.chain,
chainDepth,
chainValid,
createdAt: identity.createdAt
? new Date(identity.createdAt).toISOString()
: null
}
if (globals.format === 'json') return result
const self = result.rootPubkey === result.devicePubkey
const chainLine = result.chainPresent
? (result.chainDepth != null
? result.chainDepth + ' link(s)' + (result.chainValid === false ? ' (INVALID)' : '')
: 'present (unparseable)')
: 'none'
const lines = [
'identity (source: ' + result.source + ')',
' root pubkey: ' + (result.rootPubkey || '-'),
' device pubkey: ' + (result.devicePubkey || '-') + (self ? ' (self-rooted)' : ''),
' chain: ' + chainLine,
' created: ' + (result.createdAt || '-')
]
return lines.join('\n')
}