feat(archy): extend useArchy with wallet/files context, add ArchyAppsGrid component

- Add wallet (Lightning balance, channels) and files (Nextcloud) context
  categories to useArchy composable with AI prompt injection
- Create archy-apps.ts data file mapping all 18 Archy services
- Build ArchyAppsGrid component with live status from bridge
- Wire ArchyAppsGrid into ContentPanel when embedded in Archy

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-04 12:15:33 +00:00
co-authored by Claude Opus 4.6
parent fe94693ef6
commit 20ef35c8e3
4 changed files with 380 additions and 0 deletions
+56
View File
@@ -19,6 +19,21 @@ interface ArchyNetworkInfo {
connected?: boolean
}
export interface ArchyWalletInfo {
balanceSats?: number
channelCount?: number
totalCapacitySats?: number
nodePubkey?: string
}
export interface ArchyFileEntry {
name: string
path: string
size?: number
modified?: string
type: 'file' | 'folder'
}
// Singleton reactive state (shared across all components using this composable)
const isEmbedded = ref(false)
const isInitialized = ref(false)
@@ -27,6 +42,8 @@ const accentColor = ref<string | null>(null)
const installedApps = ref<ArchyApp[]>([])
const systemInfo = ref<ArchySystemInfo>({})
const networkInfo = ref<ArchyNetworkInfo>({})
const walletInfo = ref<ArchyWalletInfo>({})
const fileList = ref<ArchyFileEntry[]>([])
let cleanups: (() => void)[] = []
/**
@@ -98,6 +115,26 @@ export function useArchy() {
)
}
if (cats.includes('wallet')) {
fetches.push(
archyBridge.requestContext('wallet').then((res) => {
if (res.permitted && res.data) {
walletInfo.value = res.data as ArchyWalletInfo
}
}).catch(() => {}),
)
}
if (cats.includes('files')) {
fetches.push(
archyBridge.requestContext('files').then((res) => {
if (res.permitted && Array.isArray(res.data)) {
fileList.value = res.data as ArchyFileEntry[]
}
}).catch(() => {}),
)
}
await Promise.all(fetches)
}
@@ -141,6 +178,23 @@ export function useArchy() {
sections.push(`**Network:** ${net.connected ? 'Connected' : 'Disconnected'}`)
}
if (permissions.value.includes('wallet') && walletInfo.value.balanceSats !== undefined) {
const w = walletInfo.value
const balance = w.balanceSats!
const parts = [`Balance: ${balance.toLocaleString()} sats`]
if (w.channelCount !== undefined) parts.push(`${w.channelCount} channels`)
if (w.totalCapacitySats !== undefined) parts.push(`Total capacity: ${w.totalCapacitySats.toLocaleString()} sats`)
if (w.nodePubkey) parts.push(`Pubkey: ${w.nodePubkey.slice(0, 8)}...`)
sections.push(`**Lightning Wallet:** ${parts.join(' | ')}`)
}
if (permissions.value.includes('files') && fileList.value.length > 0) {
const files = fileList.value
const recent = files.slice(0, 20)
const fileNames = recent.map((f) => f.name).join(', ')
sections.push(`**Files:** ${files.length} files in Nextcloud. Recent: ${fileNames}`)
}
if (sections.length === 0) return ''
return `\n\n**Archy Node Context** (this user is running AIUI on their Archipelago node):\n${sections.join('\n')}\n\nYou can help the user manage their node. Available actions: open an app (open-app), install an app (install-app), navigate in Archy (navigate). When recommending apps, check if they're already installed.`
@@ -162,6 +216,8 @@ export function useArchy() {
installedApps: readonly(installedApps),
systemInfo: readonly(systemInfo),
networkInfo: readonly(networkInfo),
walletInfo: readonly(walletInfo),
fileList: readonly(fileList),
init,
destroy,
refreshContext,